using Core.Interfaces; using Domain.Constants; using Domain.Dtos.Sales; using Domain.Entities; using Models.Interfaces; namespace Core.Services { public class SalesDocumentService(IPhSSalesDocumentRepository salesDocumentRepository) : ISalesDocumentDom { private readonly IPhSSalesDocumentRepository _salesDocumentRepository = salesDocumentRepository; public async Task CreateAsync(SalesDocumentCreateRequest request) { ArgumentNullException.ThrowIfNull(request); if (request.CustomerId <= 0) throw new ArgumentException("Debe seleccionar un cliente.", nameof(request.CustomerId)); if (request.BillToCustomerId <= 0) throw new ArgumentException("Debe seleccionar un cliente de facturación.", nameof(request.BillToCustomerId)); if (string.IsNullOrWhiteSpace(request.Currency)) throw new ArgumentException("La moneda es obligatoria.", nameof(request.Currency)); if (request.Details is null || request.Details.Count == 0) throw new InvalidOperationException("Debe incluir al menos un detail."); if (request.Coverage is null || request.Coverage.Count == 0) throw new InvalidOperationException("Debe incluir coverage."); var netAmount = request.Details.Sum(x => x.NetAmount); var taxAmount = request.Details.Sum(x => x.TaxAmount); var totalAmount = request.Details.Sum(x => x.TotalAmount); if (totalAmount <= 0) throw new InvalidOperationException("El total del documento debe ser mayor a cero."); var now = DateTime.Now; var entity = new ESalesDocument { FormseriesId = request.FormseriesId, DocumentType = request.DocumentType, FiscalVoucherType = request.FiscalVoucherType, FiscalVoucherLetter = request.FiscalVoucherLetter, Status = (int)SalesDocumentStatus.Draft, QuoteId = request.QuoteId, CustomerId = request.CustomerId, BillToCustomerId = request.BillToCustomerId, IssueDate = request.IssueDate ?? now, Currency = request.Currency.Trim(), ExchangeRate = request.ExchangeRate <= 0 ? 1 : request.ExchangeRate, NetAmount = netAmount, TaxAmount = taxAmount, TotalAmount = totalAmount, AssociatedDocumentType = request.AssociatedDocumentType, AssociatedDocumentNumber = request.AssociatedDocumentNumber, AssociatedDocumentDate = request.AssociatedDocumentDate, Observations = request.Observations, ExtraInfoJson = request.ExtraInfoJson, PeriodFrom = request.PeriodFrom, PeriodTo = request.PeriodTo, Createdat = now, PhSSalesDocumentDetails = request.Details.Select(x => new ESalesDocumentDetail { LineNumber = x.LineNumber, OriginType = x.OriginType.ToString(), OriginId = x.OriginId, QuoteDetailId = x.QuoteDetailId, ProductId = x.ProductId, Description = x.Description.Trim(), Quantity = x.Quantity, AuthorizedUnitPrice = x.AuthorizedUnitPrice, AuthorizedAmount = x.AuthorizedAmount, BilledPercentage = x.BilledPercentage, UnitPrice = x.UnitPrice, NetAmount = x.NetAmount, TaxAmount = x.TaxAmount, TotalAmount = x.TotalAmount, OriginSnapshotJson = x.OriginSnapshotJson, Createdat = now }).ToList(), PhSSalesDocumentCoverages = request.Coverage.Select(x => new ESalesDocumentCoverage { QuoteId = x.QuoteId, QuoteDetailId = x.QuoteDetailId, CoverageType = x.CoverageType, CoveragePercentage = x.CoveragePercentage, CoverageAmount = x.CoverageAmount, PeriodFrom = x.PeriodFrom, PeriodTo = x.PeriodTo, Notes = x.Notes, Createdat = now }).ToList() }; var created = await _salesDocumentRepository.CreateAsync(entity); return new SalesDocumentCreateResponse { Id = created.Id, InternalDocumentNumber = created.InternalDocumentNumber }; } public Task GetDtoByIdAsync(int id) { if (id <= 0) throw new ArgumentOutOfRangeException(nameof(id)); return _salesDocumentRepository.GetDtoByIdAsync(id); } } }