Files

80 lines
3.1 KiB
C#

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.EntryMode, p.ChequeNumber, p.ChequeDate,
p.CollectedAt, p.CollectedBy, p.RecordedBy, p.CreatedAt);
public async Task<List<PaymentResponse>?> 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<PaymentResponse?> 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");
if (request.Method == PaymentMethod.Cheque &&
(string.IsNullOrWhiteSpace(request.ChequeNumber) || request.ChequeDate is null))
throw new InvalidOperationException("ChequeNumber and ChequeDate are required when Method is Cheque");
var recorderId = currentUser.UserId ?? request.CollectedByUserId
?? throw new InvalidOperationException("CollectedByUserId is required while auth is unavailable");
var collectedBy = request.CollectedByUserId ?? recorderId;
var recordedBy = request.EntryMode == EntryMode.DayEndManual && collectedBy != recorderId
? recorderId
: (Guid?)null;
var payment = new Models.Payment
{
FK_InvoiceId = invoiceId,
Amount = request.Amount,
Method = request.Method,
EntryMode = request.EntryMode,
ChequeNumber = request.Method == PaymentMethod.Cheque ? request.ChequeNumber : null,
ChequeDate = request.Method == PaymentMethod.Cheque ? request.ChequeDate : null,
CollectedAt = DateTime.Now,
CollectedBy = collectedBy,
RecordedBy = recordedBy
};
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);
}
}