Refactor sales pipeline: ShopPO, Invoice, SysConfig models
Major refactor replacing Sale/Order with ShopPO → Invoice → LoadingSheet flow. Removed legacy Sale/Order models and features; introduced ShopPO, ShopPOItem, Invoice, LoadingSheetOrder, and SysConfig models. Updated related entities, enums, repositories, and controllers. Added new migrations for schema changes and system config. Overhauled business logic and DI registrations. Updated documentation with migration plan.
This commit is contained in:
@@ -1,5 +1,4 @@
|
||||
using Distribution.Features.Sale;
|
||||
using Distribution.Features.Stock;
|
||||
using Distribution.Features.Invoice;
|
||||
using Distribution.Infra.Authorization;
|
||||
using Distribution.Infra.UoW;
|
||||
using Distribution.Models;
|
||||
@@ -8,51 +7,35 @@ namespace Distribution.Features.Payment;
|
||||
|
||||
public class PaymentService(
|
||||
IPaymentRepository repo,
|
||||
ISaleRepository saleRepo,
|
||||
IInvoiceRepository invoiceRepo,
|
||||
IUnitOfWork uow,
|
||||
ICurrentUserService currentUser)
|
||||
{
|
||||
private static PaymentResponse ToResponse(Models.Payment p) =>
|
||||
new(p.Id, p.FK_SaleId, p.FK_StoreId, p.Amount, p.Method, p.CollectedAt, p.CollectedBy, p.CreatedAt);
|
||||
new(p.Id, p.FK_InvoiceId, p.Amount, p.Method, p.CollectedAt, p.CollectedBy, p.CreatedAt);
|
||||
|
||||
public async Task<PagedResponse<PaymentResponse>> GetAllAsync(Guid? storeId, Guid? saleId, int page, int pageSize)
|
||||
public async Task<List<PaymentResponse>?> GetByInvoiceIdAsync(Guid invoiceId)
|
||||
{
|
||||
var total = await repo.GetCountAsync(storeId, saleId);
|
||||
var items = await repo.GetAllAsync(storeId, saleId, page, pageSize);
|
||||
return new PagedResponse<PaymentResponse>(page, pageSize, total, items.Select(ToResponse).ToList());
|
||||
}
|
||||
var invoice = await invoiceRepo.GetByIdAsync(invoiceId);
|
||||
if (invoice is null || !invoice.IsActive) return null;
|
||||
|
||||
public async Task<PaymentResponse?> GetByIdAsync(Guid id)
|
||||
{
|
||||
var payment = await repo.GetByIdAsync(id);
|
||||
return payment is null ? null : ToResponse(payment);
|
||||
}
|
||||
|
||||
public async Task<List<PaymentResponse>?> GetBySaleIdAsync(Guid saleId)
|
||||
{
|
||||
var sale = await saleRepo.GetByIdAsync(saleId);
|
||||
if (sale is null || !sale.IsActive) return null;
|
||||
|
||||
var payments = await repo.GetBySaleIdAsync(saleId);
|
||||
var payments = await repo.GetByInvoiceIdAsync(invoiceId);
|
||||
return payments.Select(ToResponse).ToList();
|
||||
}
|
||||
|
||||
public async Task<PaymentResponse?> CreateAsync(Guid saleId, CreatePaymentRequest request, CancellationToken ct = default)
|
||||
public async Task<PaymentResponse?> CreateAsync(Guid invoiceId, CreatePaymentRequest request, CancellationToken ct = default)
|
||||
{
|
||||
var sale = await saleRepo.GetByIdAsync(saleId);
|
||||
if (sale is null || !sale.IsActive) return null;
|
||||
if (sale.Status == SaleStatus.Cancelled)
|
||||
throw new InvalidOperationException("Cannot record a payment against a cancelled sale");
|
||||
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");
|
||||
|
||||
// TEMPORARY: currentUser.UserId is always unset due to the broken auth middleware
|
||||
// (testbug.md #28) — fall back to the explicitly supplied user until that's fixed.
|
||||
var userId = currentUser.UserId ?? request.CollectedByUserId
|
||||
?? throw new InvalidOperationException("CollectedByUserId is required while auth is unavailable");
|
||||
|
||||
var payment = new Models.Payment
|
||||
{
|
||||
FK_SaleId = saleId,
|
||||
FK_StoreId = sale.FK_StoreId,
|
||||
FK_InvoiceId = invoiceId,
|
||||
Amount = request.Amount,
|
||||
Method = request.Method,
|
||||
CollectedAt = DateTime.Now,
|
||||
@@ -64,17 +47,16 @@ public class PaymentService(
|
||||
{
|
||||
await repo.AddAsync(payment);
|
||||
|
||||
var allPayments = await repo.GetBySaleIdAsync(saleId);
|
||||
var allPayments = await repo.GetByInvoiceIdAsync(invoiceId);
|
||||
var total = allPayments.Sum(p => p.Amount) + request.Amount;
|
||||
|
||||
sale.PaymentStatus = total == 0
|
||||
invoice.PaymentStatus = total == 0
|
||||
? PaymentStatus.Pending
|
||||
: total < sale.TotalAmount
|
||||
: total < invoice.TotalAmount
|
||||
? PaymentStatus.PartiallyPaid
|
||||
: PaymentStatus.Paid;
|
||||
|
||||
saleRepo.Update(sale);
|
||||
|
||||
invoiceRepo.Update(invoice);
|
||||
await uow.CommitAsync(ct);
|
||||
}
|
||||
catch { await uow.RollbackAsync(ct); throw; }
|
||||
|
||||
Reference in New Issue
Block a user