feat: add scheme discount calculation to invoice processing

This commit is contained in:
2026-10-22 10:39:01 +05:30
parent 872fd42c4a
commit 2be2928ad1
4 changed files with 26 additions and 6 deletions
@@ -19,7 +19,7 @@ public class InvoiceService(
i.Status, i.PaymentStatus, i.CreatedBy,
i.PrintedAt, i.PrintedBy,
i.FinalizedAt, i.FinalizedBy,
i.TotalAmount,
i.TotalAmount, i.DiscountAmount,
i.Payments?.Where(p => p.IsActive).Sum(p => p.Amount) ?? 0m,
i.IsActive, i.CreatedAt,
i.Items.Where(x => x.IsActive).Select(x =>
@@ -30,6 +30,15 @@ public class InvoiceService(
private static decimal BillableTotal(IEnumerable<InvoiceItem> items) =>
items.Where(i => i.IsActive && !i.IsRemoved).Sum(i => i.Quantity * i.UnitPrice);
// TotalAmount = billable lines - scheme discount redeemed on the PO. Re-derived whenever lines change
// and at finalize, so a scheme applied after the invoice was drafted is still picked up before it locks.
private async Task ApplyTotalsAsync(Models.Invoice invoice, IEnumerable<InvoiceItem> items)
{
var billable = BillableTotal(items);
invoice.DiscountAmount = Math.Min(await repo.GetSchemeDiscountAsync(invoice.FK_ShopPOId), billable);
invoice.TotalAmount = billable - invoice.DiscountAmount;
}
// Immutable copy of the invoice lines as they stand right now.
public static InvoiceVersion BuildVersion(Models.Invoice invoice, IEnumerable<InvoiceItem> items, int versionNumber, InvoiceVersionStage stage, Guid userId) =>
new()
@@ -115,15 +124,15 @@ public class InvoiceService(
FK_ShopPOId = po.Id,
Status = InvoiceStatus.Draft,
PaymentStatus = PaymentStatus.Pending,
CreatedBy = createdBy,
TotalAmount = po.TotalAmount
CreatedBy = createdBy
};
var lines = BuildItemsFromShopPO(po, invoice.Id);
await ApplyTotalsAsync(invoice, lines);
await uow.BeginAsync(ct);
try
{
await repo.AddAsync(invoice);
var lines = BuildItemsFromShopPO(po, invoice.Id);
await repo.AddItemsAsync(lines);
await repo.AddVersionAsync(BuildVersion(invoice, lines, 1, InvoiceVersionStage.Created, createdBy));
po.InvoiceId = invoice.Id;
@@ -192,7 +201,7 @@ public class InvoiceService(
throw new InvalidOperationException("Each edit needs an invoiceItemId (existing line) or an itemId (new line)");
}
invoice.TotalAmount = BillableTotal(invoice.Items.Concat(newLines));
await ApplyTotalsAsync(invoice, invoice.Items.Concat(newLines));
await uow.BeginAsync(ct);
try
@@ -223,6 +232,10 @@ public class InvoiceService(
if (invoice.Status != InvoiceStatus.Draft)
throw new InvalidOperationException($"Cannot print an invoice in {invoice.Status} status");
// Printing fixes the amount the customer sees, so pick up any scheme discount applied since the last edit.
var lines = invoice.Items.Where(i => i.IsActive).ToList();
if (lines.Count > 0) await ApplyTotalsAsync(invoice, lines);
invoice.Status = InvoiceStatus.Printed;
invoice.PrintedAt = DateTime.Now;
invoice.PrintedBy = printedBy;
@@ -265,7 +278,7 @@ public class InvoiceService(
}
if (items.Count > 0)
invoice.TotalAmount = BillableTotal(items);
await ApplyTotalsAsync(invoice, items);
invoice.Status = InvoiceStatus.Finalized;
invoice.FinalizedAt = DateTime.Now;