using Distribution.Features.Invoice; using Distribution.Infra.Authorization; using Distribution.Infra.UoW; using Distribution.Models; namespace Distribution.Features.Payment; public class PaymentService( IPaymentRepository repo, IInvoiceRepository invoiceRepo, IUnitOfWork uow, ICurrentUserService currentUser) { private static PaymentResponse ToResponse(Models.Payment p) => new(p.Id, p.FK_InvoiceId, p.Amount, p.Method, p.CollectedAt, p.CollectedBy, p.CreatedAt); public async Task?> GetByInvoiceIdAsync(Guid invoiceId) { var invoice = await invoiceRepo.GetByIdAsync(invoiceId); if (invoice is null || !invoice.IsActive) return null; var payments = await repo.GetByInvoiceIdAsync(invoiceId); return payments.Select(ToResponse).ToList(); } public async Task CreateAsync(Guid invoiceId, CreatePaymentRequest request, CancellationToken ct = default) { var invoice = await invoiceRepo.GetByIdAsync(invoiceId); if (invoice is null || !invoice.IsActive) return null; if (invoice.Status == InvoiceStatus.Finalized) throw new InvalidOperationException("Cannot record a payment against a finalized invoice"); var userId = currentUser.UserId ?? request.CollectedByUserId ?? throw new InvalidOperationException("CollectedByUserId is required while auth is unavailable"); var payment = new Models.Payment { FK_InvoiceId = invoiceId, Amount = request.Amount, Method = request.Method, CollectedAt = DateTime.Now, CollectedBy = userId }; await uow.BeginAsync(ct); try { await repo.AddAsync(payment); var allPayments = await repo.GetByInvoiceIdAsync(invoiceId); var total = allPayments.Sum(p => p.Amount) + request.Amount; invoice.PaymentStatus = total == 0 ? PaymentStatus.Pending : total < invoice.TotalAmount ? PaymentStatus.PartiallyPaid : PaymentStatus.Paid; invoiceRepo.Update(invoice); await uow.CommitAsync(ct); } catch { await uow.RollbackAsync(ct); throw; } return ToResponse(payment); } }