diff --git a/src/PowderCoating.Infrastructure/Services/FinancialReportService.cs b/src/PowderCoating.Infrastructure/Services/FinancialReportService.cs index 43181b1..0ce8cce 100644 --- a/src/PowderCoating.Infrastructure/Services/FinancialReportService.cs +++ b/src/PowderCoating.Infrastructure/Services/FinancialReportService.cs @@ -89,7 +89,7 @@ public class FinancialReportService : IFinancialReportService var isCash = accountingMethod == AccountingMethod.Cash; var revenueAccounts = await _context.Accounts - .Where(a => a.AccountType == AccountType.Revenue && a.IsActive) + .Where(a => a.CompanyId == companyId && a.AccountType == AccountType.Revenue && a.IsActive) .ToDictionaryAsync(a => a.Id); var revenueLines = new List(); @@ -98,7 +98,7 @@ public class FinancialReportService : IFinancialReportService { // Cash basis: total payments received in period (not split by revenue account) var cashRevenue = await _context.Payments - .Where(p => p.PaymentDate >= from && p.PaymentDate <= toEnd + .Where(p => p.CompanyId == companyId && p.PaymentDate >= from && p.PaymentDate <= toEnd && p.Invoice.Status != InvoiceStatus.Voided) .SumAsync(p => (decimal?)p.Amount) ?? 0; if (cashRevenue > 0) @@ -106,7 +106,7 @@ public class FinancialReportService : IFinancialReportService // Cash refunds are cash paid back out — they reduce cash-basis revenue. var cashRefunds = await _context.Refunds - .Where(r => !r.IsDeleted && r.RefundMethod != PaymentMethod.StoreCredit + .Where(r => r.CompanyId == companyId && !r.IsDeleted && r.RefundMethod != PaymentMethod.StoreCredit && r.RefundDate >= from && r.RefundDate <= toEnd) .SumAsync(r => (decimal?)r.Amount) ?? 0m; if (cashRefunds > 0) @@ -116,7 +116,8 @@ public class FinancialReportService : IFinancialReportService { // Accrual basis: revenue = invoice item amounts by invoice date var accrualRevenue = await _context.InvoiceItems - .Where(ii => ii.RevenueAccountId != null + .Where(ii => ii.CompanyId == companyId + && ii.RevenueAccountId != null && ii.Invoice.Status != InvoiceStatus.Draft && ii.Invoice.Status != InvoiceStatus.Voided && ii.Invoice.InvoiceDate >= from && ii.Invoice.InvoiceDate <= toEnd) @@ -136,7 +137,8 @@ public class FinancialReportService : IFinancialReportService .OrderBy(l => l.AccountNumber)); var unlinkedRevenue = await _context.InvoiceItems - .Where(ii => ii.RevenueAccountId == null + .Where(ii => ii.CompanyId == companyId + && ii.RevenueAccountId == null && ii.Invoice.Status != InvoiceStatus.Draft && ii.Invoice.Status != InvoiceStatus.Voided && ii.Invoice.InvoiceDate >= from && ii.Invoice.InvoiceDate <= toEnd) @@ -146,7 +148,7 @@ public class FinancialReportService : IFinancialReportService // Contra-revenue: discounts granted and credit memos applied reduce gross revenue. var periodDiscounts = await _context.Invoices - .Where(i => i.Status != InvoiceStatus.Draft && i.Status != InvoiceStatus.Voided + .Where(i => i.CompanyId == companyId && i.Status != InvoiceStatus.Draft && i.Status != InvoiceStatus.Voided && i.DiscountAmount > 0 && i.InvoiceDate >= from && i.InvoiceDate <= toEnd) .SumAsync(i => (decimal?)i.DiscountAmount) ?? 0m; // Credit-memo contra-revenue is recognized at issue (DR Sales Discounts). Net for the period = @@ -171,7 +173,7 @@ public class FinancialReportService : IFinancialReportService // Cash refunds reverse the sale — the revenue portion is contra-revenue (the tax portion // relieves Sales Tax Payable, not revenue). Store-credit refunds are excluded (no GL posting). var periodRefunds = await _context.Refunds - .Where(r => !r.IsDeleted && r.Invoice != null && r.RefundMethod != PaymentMethod.StoreCredit + .Where(r => r.CompanyId == companyId && !r.IsDeleted && r.Invoice != null && r.RefundMethod != PaymentMethod.StoreCredit && r.RefundDate >= from && r.RefundDate <= toEnd) .Select(r => new { r.Amount, r.Invoice!.TaxAmount, r.Invoice.Total }) .ToListAsync(); @@ -186,7 +188,8 @@ public class FinancialReportService : IFinancialReportService // GC sales are deferred to GC Liability at issuance; revenue is recognized on redemption. var periodGcReclassified = await _context.InvoiceItems - .Where(ii => ii.IsGiftCertificate + .Where(ii => ii.CompanyId == companyId + && ii.IsGiftCertificate && ii.Invoice.Status != InvoiceStatus.Draft && ii.Invoice.Status != InvoiceStatus.Voided && ii.Invoice.InvoiceDate >= from && ii.Invoice.InvoiceDate <= toEnd) @@ -201,7 +204,7 @@ public class FinancialReportService : IFinancialReportService // Voided GCs with remaining balance are breakage income (liability extinguished). var periodGcBreakage = await _context.GiftCertificates - .Where(gc => !gc.IsDeleted && gc.Status == GiftCertificateStatus.Voided + .Where(gc => gc.CompanyId == companyId && !gc.IsDeleted && gc.Status == GiftCertificateStatus.Voided && gc.UpdatedAt >= from && gc.UpdatedAt <= toEnd && gc.OriginalAmount > gc.RedeemedAmount) .SumAsync(gc => (decimal?)(gc.OriginalAmount - gc.RedeemedAmount)) ?? 0m; @@ -220,7 +223,7 @@ public class FinancialReportService : IFinancialReportService if (isCash) { var cashExpenses = await _context.Expenses - .Where(e => e.Date >= from && e.Date <= toEnd) + .Where(e => e.CompanyId == companyId && e.Date >= from && e.Date <= toEnd) .GroupBy(e => e.ExpenseAccountId) .Select(g => new { AccountId = g.Key, Amount = g.Sum(e => e.Amount) }) .ToListAsync(); @@ -229,7 +232,7 @@ public class FinancialReportService : IFinancialReportService // Pro-rate paid bill line items by payment fraction (bill total may be partial) var paidBillLines = await _context.BillPayments - .Where(bp => bp.PaymentDate >= from && bp.PaymentDate <= toEnd) + .Where(bp => bp.CompanyId == companyId && bp.PaymentDate >= from && bp.PaymentDate <= toEnd) .Include(bp => bp.Bill).ThenInclude(b => b.LineItems) .ToListAsync(); foreach (var bp in paidBillLines) @@ -242,7 +245,7 @@ public class FinancialReportService : IFinancialReportService else { var accrualExpenses = await _context.Expenses - .Where(e => e.Date >= from && e.Date <= toEnd) + .Where(e => e.CompanyId == companyId && e.Date >= from && e.Date <= toEnd) .GroupBy(e => e.ExpenseAccountId) .Select(g => new { AccountId = g.Key, Amount = g.Sum(e => e.Amount) }) .ToListAsync(); @@ -250,7 +253,8 @@ public class FinancialReportService : IFinancialReportService expenseAmounts[e.AccountId] = expenseAmounts.GetValueOrDefault(e.AccountId) + e.Amount; var accrualBillLines = await _context.BillLineItems - .Where(bli => bli.AccountId != null + .Where(bli => bli.CompanyId == companyId + && bli.AccountId != null && bli.Bill.Status != BillStatus.Draft && bli.Bill.Status != BillStatus.Voided && bli.Bill.BillDate >= from && bli.Bill.BillDate <= toEnd) @@ -262,7 +266,7 @@ public class FinancialReportService : IFinancialReportService } var expAccounts = await _context.Accounts - .Where(a => (a.AccountType == AccountType.Expense || a.AccountType == AccountType.CostOfGoods) && a.IsActive) + .Where(a => a.CompanyId == companyId && (a.AccountType == AccountType.Expense || a.AccountType == AccountType.CostOfGoods) && a.IsActive) .ToDictionaryAsync(a => a.Id); var cogsLines = new List(); @@ -302,7 +306,7 @@ public class FinancialReportService : IFinancialReportService // Pre-compute balance contributions per account (batch GROUP BY queries avoid N+1) var depositsByAcct = await _context.Payments - .Where(p => p.PaymentDate <= asOfEnd && p.DepositAccountId != null + .Where(p => p.CompanyId == companyId && p.PaymentDate <= asOfEnd && p.DepositAccountId != null && p.Invoice.Status != InvoiceStatus.Voided && p.Invoice.Status != InvoiceStatus.WrittenOff) .GroupBy(p => p.DepositAccountId!.Value) @@ -310,38 +314,38 @@ public class FinancialReportService : IFinancialReportService .ToDictionaryAsync(g => g.Id, g => g.Amount); var expFromByAcct = await _context.Expenses - .Where(e => e.Date <= asOfEnd) + .Where(e => e.CompanyId == companyId && e.Date <= asOfEnd) .GroupBy(e => e.PaymentAccountId) .Select(g => new { Id = g.Key, Amount = g.Sum(e => e.Amount) }) .ToDictionaryAsync(g => g.Id, g => g.Amount); var bpFromByAcct = await _context.BillPayments - .Where(bp => bp.PaymentDate <= asOfEnd) + .Where(bp => bp.CompanyId == companyId && bp.PaymentDate <= asOfEnd) .GroupBy(bp => bp.BankAccountId) .Select(g => new { Id = g.Key, Amount = g.Sum(bp => bp.Amount) }) .ToDictionaryAsync(g => g.Id, g => g.Amount); var billsByApAcct = await _context.Bills - .Where(b => b.Status != BillStatus.Draft && b.Status != BillStatus.Voided && b.BillDate <= asOfEnd) + .Where(b => b.CompanyId == companyId && b.Status != BillStatus.Draft && b.Status != BillStatus.Voided && b.BillDate <= asOfEnd) .GroupBy(b => b.APAccountId) .Select(g => new { Id = g.Key, Amount = g.Sum(b => b.Total) }) .ToDictionaryAsync(g => g.Id, g => g.Amount); var bpByApAcct = await _context.BillPayments - .Where(bp => bp.PaymentDate <= asOfEnd) + .Where(bp => bp.CompanyId == companyId && bp.PaymentDate <= asOfEnd) .GroupBy(bp => bp.Bill.APAccountId) .Select(g => new { Id = g.Key, Amount = g.Sum(bp => bp.Amount) }) .ToDictionaryAsync(g => g.Id, g => g.Amount); // AP: vendor credit applications reduce AP (DR side) when matched against specific bills. var vcByApAcctBs = await _context.VendorCreditApplications - .Where(vca => vca.AppliedDate <= asOfEnd) + .Where(vca => vca.CompanyId == companyId && vca.AppliedDate <= asOfEnd) .GroupBy(vca => vca.VendorCredit.APAccountId) .Select(g => new { Id = g.Key, Amount = g.Sum(vca => vca.Amount) }) .ToDictionaryAsync(g => g.Id, g => g.Amount); var taxByAcct = await _context.Invoices - .Where(i => i.SalesTaxAccountId != null && i.TaxAmount > 0 + .Where(i => i.CompanyId == companyId && i.SalesTaxAccountId != null && i.TaxAmount > 0 && i.Status != InvoiceStatus.Draft && i.Status != InvoiceStatus.Voided && i.InvoiceDate <= asOfEnd) .GroupBy(i => i.SalesTaxAccountId!.Value) @@ -349,16 +353,16 @@ public class FinancialReportService : IFinancialReportService .ToDictionaryAsync(g => g.Id, g => g.Amount); var arDebits = await _context.Invoices - .Where(i => i.Status != InvoiceStatus.Draft && i.Status != InvoiceStatus.Voided && i.InvoiceDate <= asOfEnd) + .Where(i => i.CompanyId == companyId && i.Status != InvoiceStatus.Draft && i.Status != InvoiceStatus.Voided && i.InvoiceDate <= asOfEnd) .SumAsync(i => (decimal?)i.Total) ?? 0; var arCredits = await _context.Payments - .Where(p => p.PaymentDate <= asOfEnd + .Where(p => p.CompanyId == companyId && p.PaymentDate <= asOfEnd && p.Invoice.Status != InvoiceStatus.Voided && p.Invoice.Status != InvoiceStatus.WrittenOff) .SumAsync(p => (decimal?)p.Amount) ?? 0; // Credit memo applications reduce open AR (CR AR when a credit is applied to an invoice). var cmAppliedBs = await _context.CreditMemoApplications - .Where(a => a.AppliedDate <= asOfEnd && a.Invoice.Status != InvoiceStatus.Voided) + .Where(a => a.CompanyId == companyId && a.AppliedDate <= asOfEnd && a.Invoice.Status != InvoiceStatus.Voided) .SumAsync(a => (decimal?)a.AmountApplied) ?? 0; arCredits += cmAppliedBs; @@ -369,7 +373,7 @@ public class FinancialReportService : IFinancialReportService .Where(m => m.CompanyId == companyId && m.Status != CreditMemoStatus.Voided && m.IssueDate <= asOfEnd) .SumAsync(m => (decimal?)m.Amount) ?? 0m; var cmAppliedNonVoidedBs = await _context.CreditMemoApplications - .Where(a => a.AppliedDate <= asOfEnd && a.Invoice.Status != InvoiceStatus.Voided + .Where(a => a.CompanyId == companyId && a.AppliedDate <= asOfEnd && a.Invoice.Status != InvoiceStatus.Voided && a.CreditMemo.Status != CreditMemoStatus.Voided) .SumAsync(a => (decimal?)a.AmountApplied) ?? 0m; var cmContraRevenueBs = cmIssuedNonVoidedBs + (cmAppliedBs - cmAppliedNonVoidedBs); @@ -380,7 +384,7 @@ public class FinancialReportService : IFinancialReportService // tax portion relieves Sales Tax Payable, cash leaves the bank (refundsByAcctBs). AR is untouched. // Store-credit refunds post via CreditMemo, not the GL, so are excluded. var saleReversingRefundsBs = await _context.Refunds - .Where(r => r.RefundDate <= asOfEnd && !r.IsDeleted && r.Invoice != null + .Where(r => r.CompanyId == companyId && r.RefundDate <= asOfEnd && !r.IsDeleted && r.Invoice != null && r.RefundMethod != PaymentMethod.StoreCredit) .Select(r => new { r.Amount, r.Invoice!.TaxAmount, r.Invoice.Total, r.Invoice.SalesTaxAccountId }) .ToListAsync(); @@ -396,14 +400,14 @@ public class FinancialReportService : IFinancialReportService // Refunds by bank account: money that left the account (CR to checking/bank). var refundsByAcctBs = await _context.Refunds - .Where(r => r.RefundDate <= asOfEnd && !r.IsDeleted && r.DepositAccountId != null) + .Where(r => r.CompanyId == companyId && r.RefundDate <= asOfEnd && !r.IsDeleted && r.DepositAccountId != null) .GroupBy(r => r.DepositAccountId!.Value) .Select(g => new { Id = g.Key, Amount = g.Sum(r => r.Amount) }) .ToDictionaryAsync(g => g.Id, g => g.Amount); // Deposits by bank account: cash received at deposit recording time (DR bank). var depositsByAcctDepBs = await _context.Deposits - .Where(d => !d.IsDeleted && d.DepositAccountId != null && d.ReceivedDate <= asOfEnd) + .Where(d => d.CompanyId == companyId && !d.IsDeleted && d.DepositAccountId != null && d.ReceivedDate <= asOfEnd) .GroupBy(d => d.DepositAccountId!.Value) .Select(g => new { Id = g.Key, Amount = g.Sum(d => d.Amount) }) .ToDictionaryAsync(g => g.Id, g => g.Amount); @@ -414,11 +418,11 @@ public class FinancialReportService : IFinancialReportService .Select(a => (int?)a.Id).FirstOrDefaultAsync(); var custDepositsCreditsBs = custDepositsAcctIdBs.HasValue ? (await _context.Deposits - .Where(d => !d.IsDeleted && d.ReceivedDate <= asOfEnd) + .Where(d => d.CompanyId == companyId && !d.IsDeleted && d.ReceivedDate <= asOfEnd) .SumAsync(d => (decimal?)d.Amount) ?? 0m) : 0m; var custDepositsDebitsBs = custDepositsAcctIdBs.HasValue ? (await _context.Deposits - .Where(d => !d.IsDeleted && d.AppliedToInvoiceId != null && d.AppliedDate <= asOfEnd) + .Where(d => d.CompanyId == companyId && !d.IsDeleted && d.AppliedToInvoiceId != null && d.AppliedDate <= asOfEnd) .SumAsync(d => (decimal?)d.Amount) ?? 0m) : 0m; // Gift Certificate Liability (2500): balance driven by GC issuances, redemptions, and voids. @@ -427,14 +431,14 @@ public class FinancialReportService : IFinancialReportService .Select(a => (int?)a.Id).FirstOrDefaultAsync(); var gcLiabilityCreditsBs = gcLiabilityAcctIdBs.HasValue ? (await _context.GiftCertificates - .Where(gc => !gc.IsDeleted && gc.IssueDate <= asOfEnd) + .Where(gc => gc.CompanyId == companyId && !gc.IsDeleted && gc.IssueDate <= asOfEnd) .SumAsync(gc => (decimal?)gc.OriginalAmount) ?? 0m) : 0m; var gcLiabilityDebitsBs = gcLiabilityAcctIdBs.HasValue ? ((await _context.GiftCertificateRedemptions - .Where(r => !r.IsDeleted && r.RedeemedDate <= asOfEnd) + .Where(r => r.CompanyId == companyId && !r.IsDeleted && r.RedeemedDate <= asOfEnd) .SumAsync(r => (decimal?)r.AmountRedeemed) ?? 0m) + (await _context.GiftCertificates - .Where(gc => !gc.IsDeleted && gc.Status == GiftCertificateStatus.Voided + .Where(gc => gc.CompanyId == companyId && !gc.IsDeleted && gc.Status == GiftCertificateStatus.Voided && gc.UpdatedAt <= asOfEnd && gc.OriginalAmount > gc.RedeemedAmount) .SumAsync(gc => (decimal?)(gc.OriginalAmount - gc.RedeemedAmount)) ?? 0m)) : 0m; @@ -443,21 +447,21 @@ public class FinancialReportService : IFinancialReportService // plus (5) the net effect of any posted journal entries on revenue/expense/COGS accounts // (accruals, depreciation, year-end closes, and other adjustments not in the tables above). var lifetimeRevenue = await _context.InvoiceItems - .Where(ii => ii.Invoice.Status != InvoiceStatus.Draft && ii.Invoice.Status != InvoiceStatus.Voided && ii.Invoice.InvoiceDate <= asOfEnd) + .Where(ii => ii.CompanyId == companyId && ii.Invoice.Status != InvoiceStatus.Draft && ii.Invoice.Status != InvoiceStatus.Voided && ii.Invoice.InvoiceDate <= asOfEnd) .SumAsync(ii => (decimal?)ii.TotalPrice) ?? 0; var lifetimeDiscounts = isCash ? 0m : (await _context.Invoices - .Where(i => i.Status != InvoiceStatus.Draft && i.Status != InvoiceStatus.Voided + .Where(i => i.CompanyId == companyId && i.Status != InvoiceStatus.Draft && i.Status != InvoiceStatus.Voided && i.DiscountAmount > 0 && i.InvoiceDate <= asOfEnd) .SumAsync(i => (decimal?)i.DiscountAmount) ?? 0m); // Credit memos are contra-revenue recognized at issue (DR Sales Discounts). Net revenue is // reduced by the issued amount (active memos in full + applied portion of voided memos). var lifetimeCreditMemos = isCash ? 0m : cmContraRevenueBs; var lifetimeDirectExp = await _context.Expenses - .Where(e => e.Date <= asOfEnd) + .Where(e => e.CompanyId == companyId && e.Date <= asOfEnd) .SumAsync(e => (decimal?)e.Amount) ?? 0; var lifetimeBillCosts = await _context.BillLineItems - .Where(bli => bli.Bill.Status != BillStatus.Draft && bli.Bill.Status != BillStatus.Voided && bli.Bill.BillDate <= asOfEnd) + .Where(bli => bli.CompanyId == companyId && bli.Bill.Status != BillStatus.Draft && bli.Bill.Status != BillStatus.Voided && bli.Bill.BillDate <= asOfEnd) .SumAsync(bli => (decimal?)bli.Amount) ?? 0; // JE net effect on revenue accounts (positive = additional revenue recognised via manual JE) @@ -489,14 +493,14 @@ public class FinancialReportService : IFinancialReportService // GC items sold via invoices are reclassified to GC Liability and not yet earned income. var lifetimeGcReclassified = await _context.InvoiceItems - .Where(ii => ii.IsGiftCertificate + .Where(ii => ii.CompanyId == companyId && ii.IsGiftCertificate && ii.Invoice.Status != InvoiceStatus.Draft && ii.Invoice.Status != InvoiceStatus.Voided && ii.Invoice.InvoiceDate <= asOfEnd) .SumAsync(ii => (decimal?)ii.TotalPrice) ?? 0m; // Voided GCs with remaining balance become breakage income (the liability is extinguished). var lifetimeGcBreakage = await _context.GiftCertificates - .Where(gc => !gc.IsDeleted && gc.Status == GiftCertificateStatus.Voided + .Where(gc => gc.CompanyId == companyId && !gc.IsDeleted && gc.Status == GiftCertificateStatus.Voided && gc.UpdatedAt <= asOfEnd && gc.OriginalAmount > gc.RedeemedAmount) .SumAsync(gc => (decimal?)(gc.OriginalAmount - gc.RedeemedAmount)) ?? 0m; @@ -511,7 +515,7 @@ public class FinancialReportService : IFinancialReportService - jeExpNet; var accounts = await _context.Accounts - .Where(a => a.IsActive) + .Where(a => a.CompanyId == companyId && a.IsActive) .OrderBy(a => a.AccountNumber) .ToListAsync(); @@ -619,7 +623,8 @@ public class FinancialReportService : IFinancialReportService var openInvoices = await _context.Invoices .Include(i => i.Customer) - .Where(i => i.Status != InvoiceStatus.Draft + .Where(i => i.CompanyId == companyId + && i.Status != InvoiceStatus.Draft && i.Status != InvoiceStatus.Voided && i.Status != InvoiceStatus.Paid && i.InvoiceDate <= asOfEnd @@ -699,14 +704,15 @@ public class FinancialReportService : IFinancialReportService var invoices = await _context.Invoices .Include(i => i.Customer) .Include(i => i.Payments) - .Where(i => i.Status != InvoiceStatus.Draft + .Where(i => i.CompanyId == companyId + && i.Status != InvoiceStatus.Draft && i.Status != InvoiceStatus.Voided && i.InvoiceDate >= from && i.InvoiceDate <= toEnd) .OrderBy(i => i.InvoiceDate) .ToListAsync(); var collectedInPeriod = await _context.Payments - .Where(p => p.PaymentDate >= from && p.PaymentDate <= toEnd) + .Where(p => p.CompanyId == companyId && p.PaymentDate >= from && p.PaymentDate <= toEnd) .SumAsync(p => (decimal?)p.Amount) ?? 0; var byCustomer = invoices @@ -971,7 +977,7 @@ public class FinancialReportService : IFinancialReportService // Bank/cash: customer payments deposited here (DR) var depositsByAcct = await _context.Payments - .Where(p => p.PaymentDate <= asOfEnd && p.DepositAccountId != null + .Where(p => p.CompanyId == companyId && p.PaymentDate <= asOfEnd && p.DepositAccountId != null && p.Invoice.Status != InvoiceStatus.Voided && p.Invoice.Status != InvoiceStatus.WrittenOff) .GroupBy(p => p.DepositAccountId!.Value) @@ -981,42 +987,42 @@ public class FinancialReportService : IFinancialReportService // AP: vendor credit applications reduce AP (DR) — credits are applied when a vendor // issues a credit note and it is matched against a specific bill. var vcByApAcct = await _context.VendorCreditApplications - .Where(vca => vca.AppliedDate <= asOfEnd) + .Where(vca => vca.CompanyId == companyId && vca.AppliedDate <= asOfEnd) .GroupBy(vca => vca.VendorCredit.APAccountId) .Select(g => new { Id = g.Key, Amt = g.Sum(vca => vca.Amount) }) .ToDictionaryAsync(g => g.Id, g => g.Amt); // Bank/cash: expenses paid from here (CR) var expFromByAcct = await _context.Expenses - .Where(e => e.Date <= asOfEnd) + .Where(e => e.CompanyId == companyId && e.Date <= asOfEnd) .GroupBy(e => e.PaymentAccountId) .Select(g => new { Id = g.Key, Amt = g.Sum(e => e.Amount) }) .ToDictionaryAsync(g => g.Id, g => g.Amt); // Bank/cash: bill payments made from here (CR) var bpFromByAcct = await _context.BillPayments - .Where(bp => bp.PaymentDate <= asOfEnd) + .Where(bp => bp.CompanyId == companyId && bp.PaymentDate <= asOfEnd) .GroupBy(bp => bp.BankAccountId) .Select(g => new { Id = g.Key, Amt = g.Sum(bp => bp.Amount) }) .ToDictionaryAsync(g => g.Id, g => g.Amt); // AP: bills increase AP (CR) var billsByApAcct = await _context.Bills - .Where(b => b.Status != BillStatus.Draft && b.Status != BillStatus.Voided && b.BillDate <= asOfEnd) + .Where(b => b.CompanyId == companyId && b.Status != BillStatus.Draft && b.Status != BillStatus.Voided && b.BillDate <= asOfEnd) .GroupBy(b => b.APAccountId) .Select(g => new { Id = g.Key, Amt = g.Sum(b => b.Total) }) .ToDictionaryAsync(g => g.Id, g => g.Amt); // AP: bill payments reduce AP (DR) var bpByApAcct = await _context.BillPayments - .Where(bp => bp.PaymentDate <= asOfEnd) + .Where(bp => bp.CompanyId == companyId && bp.PaymentDate <= asOfEnd) .GroupBy(bp => bp.Bill.APAccountId) .Select(g => new { Id = g.Key, Amt = g.Sum(bp => bp.Amount) }) .ToDictionaryAsync(g => g.Id, g => g.Amt); // Tax liability: sales tax collected (CR) var taxByAcct = await _context.Invoices - .Where(i => i.SalesTaxAccountId != null && i.TaxAmount > 0 + .Where(i => i.CompanyId == companyId && i.SalesTaxAccountId != null && i.TaxAmount > 0 && i.Status != InvoiceStatus.Draft && i.Status != InvoiceStatus.Voided && i.InvoiceDate <= asOfEnd) .GroupBy(i => i.SalesTaxAccountId!.Value) @@ -1025,7 +1031,7 @@ public class FinancialReportService : IFinancialReportService // Revenue accounts: invoice line items (CR) var revenueByAcct = await _context.InvoiceItems - .Where(ii => ii.RevenueAccountId != null + .Where(ii => ii.CompanyId == companyId && ii.RevenueAccountId != null && ii.Invoice.Status != InvoiceStatus.Draft && ii.Invoice.Status != InvoiceStatus.Voided && ii.Invoice.InvoiceDate <= asOfEnd) @@ -1035,14 +1041,14 @@ public class FinancialReportService : IFinancialReportService // Expense accounts: direct expenses (DR) var expenseByAcct = await _context.Expenses - .Where(e => e.Date <= asOfEnd) + .Where(e => e.CompanyId == companyId && e.Date <= asOfEnd) .GroupBy(e => e.ExpenseAccountId) .Select(g => new { Id = g.Key, Amt = g.Sum(e => e.Amount) }) .ToDictionaryAsync(g => g.Id, g => g.Amt); // Expense/COGS accounts: vendor bill line items (DR) var billLinesByAcct = await _context.BillLineItems - .Where(bli => bli.AccountId != null + .Where(bli => bli.CompanyId == companyId && bli.AccountId != null && bli.Bill.Status != BillStatus.Draft && bli.Bill.Status != BillStatus.Voided && bli.Bill.BillDate <= asOfEnd) @@ -1064,7 +1070,7 @@ public class FinancialReportService : IFinancialReportService .FirstOrDefaultAsync(); var cmApplied = await _context.CreditMemoApplications - .Where(a => a.AppliedDate <= asOfEnd + .Where(a => a.CompanyId == companyId && a.AppliedDate <= asOfEnd && a.Invoice.Status != InvoiceStatus.Voided) .SumAsync(a => (decimal?)a.AmountApplied) ?? 0m; @@ -1076,7 +1082,7 @@ public class FinancialReportService : IFinancialReportService .Where(m => m.CompanyId == companyId && m.Status != CreditMemoStatus.Voided && m.IssueDate <= asOfEnd) .SumAsync(m => (decimal?)m.Amount) ?? 0m; var cmAppliedNonVoided = await _context.CreditMemoApplications - .Where(a => a.AppliedDate <= asOfEnd + .Where(a => a.CompanyId == companyId && a.AppliedDate <= asOfEnd && a.Invoice.Status != InvoiceStatus.Voided && a.CreditMemo.Status != CreditMemoStatus.Voided) .SumAsync(a => (decimal?)a.AmountApplied) ?? 0m; @@ -1089,7 +1095,7 @@ public class FinancialReportService : IFinancialReportService if (discountAcctId.HasValue) { var totalDiscounts = await _context.Invoices - .Where(i => i.DiscountAmount > 0 + .Where(i => i.CompanyId == companyId && i.DiscountAmount > 0 && i.Status != InvoiceStatus.Draft && i.Status != InvoiceStatus.Voided && i.InvoiceDate <= asOfEnd) @@ -1100,14 +1106,14 @@ public class FinancialReportService : IFinancialReportService // JE lines: posted entries debit/credit all account types var jeDebitsByAcct = await _context.JournalEntryLines - .Where(l => l.JournalEntry.Status == JournalEntryStatus.Posted + .Where(l => l.CompanyId == companyId && l.JournalEntry.Status == JournalEntryStatus.Posted && l.JournalEntry.EntryDate <= asOfEnd) .GroupBy(l => l.AccountId) .Select(g => new { Id = g.Key, Amt = g.Sum(l => l.DebitAmount) }) .ToDictionaryAsync(g => g.Id, g => g.Amt); var jeCreditsByAcct = await _context.JournalEntryLines - .Where(l => l.JournalEntry.Status == JournalEntryStatus.Posted + .Where(l => l.CompanyId == companyId && l.JournalEntry.Status == JournalEntryStatus.Posted && l.JournalEntry.EntryDate <= asOfEnd) .GroupBy(l => l.AccountId) .Select(g => new { Id = g.Key, Amt = g.Sum(l => l.CreditAmount) }) @@ -1117,11 +1123,11 @@ public class FinancialReportService : IFinancialReportService // Credits include both cash payments and credit memo applications (which reduce open AR // when a customer credit is applied against a specific invoice). var arTotalDebits = await _context.Invoices - .Where(i => i.Status != InvoiceStatus.Draft && i.Status != InvoiceStatus.Voided + .Where(i => i.CompanyId == companyId && i.Status != InvoiceStatus.Draft && i.Status != InvoiceStatus.Voided && i.InvoiceDate <= asOfEnd) .SumAsync(i => (decimal?)i.Total) ?? 0m; var arTotalCredits = await _context.Payments - .Where(p => p.PaymentDate <= asOfEnd + .Where(p => p.CompanyId == companyId && p.PaymentDate <= asOfEnd && p.Invoice.Status != InvoiceStatus.Voided && p.Invoice.Status != InvoiceStatus.WrittenOff) .SumAsync(p => (decimal?)p.Amount) ?? 0m; @@ -1131,7 +1137,7 @@ public class FinancialReportService : IFinancialReportService // DR Sales Tax Payable (relieves the liability), cash → CR bank (refundsByAcct below). They no // longer touch AR. Store-credit refunds post via CreditMemo, not the GL, so are excluded. var saleReversingRefunds = await _context.Refunds - .Where(r => r.RefundDate <= asOfEnd && !r.IsDeleted && r.Invoice != null + .Where(r => r.CompanyId == companyId && r.RefundDate <= asOfEnd && !r.IsDeleted && r.Invoice != null && r.RefundMethod != PaymentMethod.StoreCredit) .Select(r => new { r.Amount, r.Invoice!.TaxAmount, r.Invoice.Total, r.Invoice.SalesTaxAccountId }) .ToListAsync(); @@ -1152,7 +1158,7 @@ public class FinancialReportService : IFinancialReportService // Refunds by bank account: money leaving the account (CR to checking/bank). var refundsByAcct = await _context.Refunds - .Where(r => r.RefundDate <= asOfEnd && !r.IsDeleted && r.DepositAccountId != null) + .Where(r => r.CompanyId == companyId && r.RefundDate <= asOfEnd && !r.IsDeleted && r.DepositAccountId != null) .GroupBy(r => r.DepositAccountId!.Value) .Select(g => new { Id = g.Key, Amt = g.Sum(r => r.Amount) }) .ToDictionaryAsync(g => g.Id, g => g.Amt); @@ -1160,7 +1166,7 @@ public class FinancialReportService : IFinancialReportService // Deposits by bank account: cash received at deposit recording time (DR bank). // Deposit-sourced Payments have DepositAccountId = null, so there is no double-count with depositsByAcct. var depositsByAcctDep = await _context.Deposits - .Where(d => !d.IsDeleted && d.DepositAccountId != null && d.ReceivedDate <= asOfEnd) + .Where(d => d.CompanyId == companyId && !d.IsDeleted && d.DepositAccountId != null && d.ReceivedDate <= asOfEnd) .GroupBy(d => d.DepositAccountId!.Value) .Select(g => new { Id = g.Key, Amt = g.Sum(d => d.Amount) }) .ToDictionaryAsync(g => g.Id, g => g.Amt); @@ -1171,11 +1177,11 @@ public class FinancialReportService : IFinancialReportService .Select(a => (int?)a.Id).FirstOrDefaultAsync(); var custDepositsCredits = custDepositsAcctId.HasValue ? (await _context.Deposits - .Where(d => !d.IsDeleted && d.ReceivedDate <= asOfEnd) + .Where(d => d.CompanyId == companyId && !d.IsDeleted && d.ReceivedDate <= asOfEnd) .SumAsync(d => (decimal?)d.Amount) ?? 0m) : 0m; var custDepositsDebits = custDepositsAcctId.HasValue ? (await _context.Deposits - .Where(d => !d.IsDeleted && d.AppliedToInvoiceId != null && d.AppliedDate <= asOfEnd) + .Where(d => d.CompanyId == companyId && !d.IsDeleted && d.AppliedToInvoiceId != null && d.AppliedDate <= asOfEnd) .SumAsync(d => (decimal?)d.Amount) ?? 0m) : 0m; // Gift Certificate Liability (2500): balance driven by GC issuances, redemptions, and voids. @@ -1184,14 +1190,14 @@ public class FinancialReportService : IFinancialReportService .Select(a => (int?)a.Id).FirstOrDefaultAsync(); var gcLiabilityCredits = gcLiabilityAcctId.HasValue ? (await _context.GiftCertificates - .Where(gc => !gc.IsDeleted && gc.IssueDate <= asOfEnd) + .Where(gc => gc.CompanyId == companyId && !gc.IsDeleted && gc.IssueDate <= asOfEnd) .SumAsync(gc => (decimal?)gc.OriginalAmount) ?? 0m) : 0m; var gcLiabilityDebits = gcLiabilityAcctId.HasValue ? ((await _context.GiftCertificateRedemptions - .Where(r => !r.IsDeleted && r.RedeemedDate <= asOfEnd) + .Where(r => r.CompanyId == companyId && !r.IsDeleted && r.RedeemedDate <= asOfEnd) .SumAsync(r => (decimal?)r.AmountRedeemed) ?? 0m) + (await _context.GiftCertificates - .Where(gc => !gc.IsDeleted && gc.Status == GiftCertificateStatus.Voided + .Where(gc => gc.CompanyId == companyId && !gc.IsDeleted && gc.Status == GiftCertificateStatus.Voided && gc.UpdatedAt <= asOfEnd && gc.OriginalAmount > gc.RedeemedAmount) .SumAsync(gc => (decimal?)(gc.OriginalAmount - gc.RedeemedAmount)) ?? 0m)) : 0m; @@ -1337,17 +1343,17 @@ public class FinancialReportService : IFinancialReportService // Opening balance: invoiced − paid before period start var preInvoiced = await _context.Invoices - .Where(i => i.CustomerId == customerId + .Where(i => i.CompanyId == companyId && i.CustomerId == customerId && i.Status != InvoiceStatus.Draft && i.Status != InvoiceStatus.Voided && i.InvoiceDate < from) .SumAsync(i => (decimal?)i.Total) ?? 0; var prePaid = await _context.Payments - .Where(p => p.Invoice.CustomerId == customerId + .Where(p => p.CompanyId == companyId && p.Invoice.CustomerId == customerId && p.Invoice.Status != InvoiceStatus.Voided && p.PaymentDate < from) .SumAsync(p => (decimal?)p.Amount) ?? 0; var preCredits = await _context.CreditMemoApplications - .Where(a => a.Invoice.CustomerId == customerId && a.AppliedDate < from) + .Where(a => a.CompanyId == companyId && a.Invoice.CustomerId == customerId && a.AppliedDate < from) .SumAsync(a => (decimal?)a.AmountApplied) ?? 0; var openingBalance = preInvoiced - prePaid - preCredits; @@ -1356,7 +1362,7 @@ public class FinancialReportService : IFinancialReportService var lines = new List(); var periodInvoices = await _context.Invoices - .Where(i => i.CustomerId == customerId + .Where(i => i.CompanyId == companyId && i.CustomerId == customerId && i.Status != InvoiceStatus.Draft && i.Status != InvoiceStatus.Voided && i.InvoiceDate >= from && i.InvoiceDate <= toEnd) .AsNoTracking().ToListAsync(); @@ -1373,7 +1379,7 @@ public class FinancialReportService : IFinancialReportService var periodPayments = await _context.Payments .Include(p => p.Invoice) - .Where(p => p.Invoice.CustomerId == customerId + .Where(p => p.CompanyId == companyId && p.Invoice.CustomerId == customerId && p.Invoice.Status != InvoiceStatus.Voided && p.PaymentDate >= from && p.PaymentDate <= toEnd) .AsNoTracking().ToListAsync(); @@ -1391,7 +1397,7 @@ public class FinancialReportService : IFinancialReportService var periodCredits = await _context.CreditMemoApplications .Include(a => a.Invoice) .Include(a => a.CreditMemo) - .Where(a => a.Invoice.CustomerId == customerId + .Where(a => a.CompanyId == companyId && a.Invoice.CustomerId == customerId && a.AppliedDate >= from && a.AppliedDate <= toEnd) .AsNoTracking().ToListAsync(); @@ -1442,15 +1448,15 @@ public class FinancialReportService : IFinancialReportService // Opening balance: bills − payments − credits before period start var preBills = await _context.Bills - .Where(b => b.VendorId == vendorId + .Where(b => b.CompanyId == companyId && b.VendorId == vendorId && b.Status != BillStatus.Draft && b.Status != BillStatus.Voided && b.BillDate < from) .SumAsync(b => (decimal?)b.Total) ?? 0; var prePayments = await _context.BillPayments - .Where(bp => bp.Bill.VendorId == vendorId && bp.PaymentDate < from) + .Where(bp => bp.CompanyId == companyId && bp.Bill.VendorId == vendorId && bp.PaymentDate < from) .SumAsync(bp => (decimal?)bp.Amount) ?? 0; var preVcApplied = await _context.VendorCreditApplications - .Where(vca => vca.Bill.VendorId == vendorId && vca.AppliedDate < from) + .Where(vca => vca.CompanyId == companyId && vca.Bill.VendorId == vendorId && vca.AppliedDate < from) .SumAsync(vca => (decimal?)vca.Amount) ?? 0; var openingBalance = preBills - prePayments - preVcApplied; @@ -1458,7 +1464,7 @@ public class FinancialReportService : IFinancialReportService var lines = new List(); var periodBills = await _context.Bills - .Where(b => b.VendorId == vendorId + .Where(b => b.CompanyId == companyId && b.VendorId == vendorId && b.Status != BillStatus.Draft && b.Status != BillStatus.Voided && b.BillDate >= from && b.BillDate <= toEnd) .AsNoTracking().ToListAsync(); @@ -1475,7 +1481,7 @@ public class FinancialReportService : IFinancialReportService var periodPayments = await _context.BillPayments .Include(bp => bp.Bill) - .Where(bp => bp.Bill.VendorId == vendorId + .Where(bp => bp.CompanyId == companyId && bp.Bill.VendorId == vendorId && bp.PaymentDate >= from && bp.PaymentDate <= toEnd) .AsNoTracking().ToListAsync(); @@ -1492,7 +1498,7 @@ public class FinancialReportService : IFinancialReportService var periodVcApplied = await _context.VendorCreditApplications .Include(vca => vca.VendorCredit) .Include(vca => vca.Bill) - .Where(vca => vca.Bill.VendorId == vendorId + .Where(vca => vca.CompanyId == companyId && vca.Bill.VendorId == vendorId && vca.AppliedDate >= from && vca.AppliedDate <= toEnd) .AsNoTracking().ToListAsync();