Fix dashoard issues #85
@@ -9,6 +9,7 @@ public interface IInvoiceRepository
|
||||
Task<List<Models.Invoice>> GetAllAsync(Guid? agentId, Guid? routeId, Guid? shopId, InvoiceStatus? status, PaymentStatus? paymentStatus, int page, int pageSize);
|
||||
Task<int> GetCountAsync(Guid? agentId, Guid? routeId, Guid? shopId, InvoiceStatus? status, PaymentStatus? paymentStatus);
|
||||
Task<List<Models.Invoice>> GetOutstandingAsync();
|
||||
Task<decimal> GetSchemeDiscountAsync(Guid shopPOId);
|
||||
Task AddAsync(Models.Invoice invoice);
|
||||
Task<Models.Item?> GetItemAsync(Guid itemId);
|
||||
Task AddItemsAsync(IEnumerable<InvoiceItem> items);
|
||||
|
||||
@@ -45,6 +45,7 @@ public record InvoiceResponse(
|
||||
DateTime? FinalizedAt,
|
||||
Guid? FinalizedBy,
|
||||
decimal TotalAmount,
|
||||
decimal DiscountAmount,
|
||||
decimal PaidAmount,
|
||||
bool IsActive,
|
||||
DateTime CreatedAt,
|
||||
|
||||
@@ -51,6 +51,11 @@ public class InvoiceRepository(AppDBContext context) : IInvoiceRepository
|
||||
.Where(i => i.IsActive && i.PaymentStatus != PaymentStatus.Paid)
|
||||
.ToListAsync();
|
||||
|
||||
public async Task<decimal> GetSchemeDiscountAsync(Guid shopPOId) =>
|
||||
await context.SchemeRedemptions
|
||||
.Where(r => r.FK_ShopPOId == shopPOId)
|
||||
.SumAsync(r => r.DiscountAmount) ?? 0m;
|
||||
|
||||
public async Task AddAsync(Models.Invoice invoice) =>
|
||||
await context.Invoices.AddAsync(invoice);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user