Credit AR for gift-certificate redemptions in balance recompute (audit O7)
ApplyGiftCertificate posts DR 2500 Gift Certificate Liability / CR AR, but the AR recompute only subtracted payments and credit-memo applications — so the redemption's 2500 debit was recomputed while its AR credit was not, leaving the Trial Balance out of balance by the total gift-certificate amount redeemed and overstating AR on the Balance Sheet. Subtract GC redemptions from AR in both recompute engines: - FinancialReportService: Balance Sheet (gcRedeemedBs) and Trial Balance (gcRedeemedTb) - LedgerService: AR section (dated rows) and ComputePriorBalanceAsync (prior balance) AR Aging was already correct (uses BalanceDue, which includes GiftCertificateRedeemed). Adds a LedgerService regression test. Build clean; 292 unit tests pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -619,6 +619,42 @@ public class LedgerServiceTests
|
||||
Assert.Equal(-150m, ledger.ClosingBalance);
|
||||
}
|
||||
|
||||
// ── Gift-certificate redemptions credit AR (DR 2500 / CR AR) — must appear in the AR ──
|
||||
// ── recompute or the trial balance is left out of balance by the redeemed amount (O7). ──
|
||||
|
||||
[Fact]
|
||||
public async Task GetAccountLedgerAsync_AR_GiftCertificateRedemption_CreditsAccountsReceivable()
|
||||
{
|
||||
await using var context = CreateContext();
|
||||
SeedAccount(context, id: 1, AccountSubType.AccountsReceivable);
|
||||
SeedCustomer(context, id: 1);
|
||||
context.Invoices.Add(new Invoice
|
||||
{
|
||||
Id = 10, CompanyId = 1, InvoiceNumber = "INV-GC", CustomerId = 1,
|
||||
Status = InvoiceStatus.Sent, InvoiceDate = InPeriod, Total = 200m
|
||||
});
|
||||
context.GiftCertificates.Add(new GiftCertificate
|
||||
{
|
||||
Id = 5, CompanyId = 1, CertificateCode = "GC-5", OriginalAmount = 50m, RedeemedAmount = 50m,
|
||||
IssueDate = InPeriod, Status = GiftCertificateStatus.FullyRedeemed
|
||||
});
|
||||
context.GiftCertificateRedemptions.Add(new GiftCertificateRedemption
|
||||
{
|
||||
Id = 1, CompanyId = 1, GiftCertificateId = 5, InvoiceId = 10,
|
||||
AmountRedeemed = 50m, RedeemedDate = InPeriod
|
||||
});
|
||||
await context.SaveChangesAsync();
|
||||
|
||||
var ledger = await CreateService(context).GetAccountLedgerAsync(1, PeriodStart, PeriodEnd);
|
||||
|
||||
var invoiceEntry = ledger!.Entries.Single(e => e.Source == "Invoice");
|
||||
var gcEntry = ledger.Entries.Single(e => e.Source == "Gift Certificate");
|
||||
Assert.Equal(200m, invoiceEntry.Debit);
|
||||
Assert.Equal(50m, gcEntry.Credit);
|
||||
Assert.Equal(0m, gcEntry.Debit);
|
||||
Assert.Equal(150m, ledger.ClosingBalance); // debit-normal AR: 200 invoiced − 50 redeemed
|
||||
}
|
||||
|
||||
private static LedgerService CreateService(ApplicationDbContext context)
|
||||
=> new LedgerService(context, Mock.Of<ILogger<LedgerService>>());
|
||||
|
||||
|
||||
Reference in New Issue
Block a user