Scope every FinancialReportService query by CompanyId (defense in depth)
Audit finding #7: most report queries relied on the global tenant query filter, which is bypassed for SuperAdmin users — so a SuperAdmin (or any multi-company account) running P&L / Balance Sheet / Trial Balance / aging / statements could pull data across companies. The cash-flow method was the only one doing it right (IgnoreQueryFilters + explicit CompanyId). Adds an explicit `CompanyId == companyId` predicate to every DB query across GetProfitAndLossAsync, GetBalanceSheetAsync, GetTrialBalanceAsync, GetArAgingAsync, GetSalesAndIncomeAsync, GetBalanceReconciliationAsync, and the customer/vendor statements (Sales Tax and AP aging already had it). The remaining in-memory filters operate on collections already loaded with the predicate. Matches the repo's standing rule (explicit CompanyId on every query, never the global filter alone). Build clean; 284 unit tests pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -89,7 +89,7 @@ public class FinancialReportService : IFinancialReportService
|
|||||||
var isCash = accountingMethod == AccountingMethod.Cash;
|
var isCash = accountingMethod == AccountingMethod.Cash;
|
||||||
|
|
||||||
var revenueAccounts = await _context.Accounts
|
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);
|
.ToDictionaryAsync(a => a.Id);
|
||||||
|
|
||||||
var revenueLines = new List<FinancialReportLine>();
|
var revenueLines = new List<FinancialReportLine>();
|
||||||
@@ -98,7 +98,7 @@ public class FinancialReportService : IFinancialReportService
|
|||||||
{
|
{
|
||||||
// Cash basis: total payments received in period (not split by revenue account)
|
// Cash basis: total payments received in period (not split by revenue account)
|
||||||
var cashRevenue = await _context.Payments
|
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)
|
&& p.Invoice.Status != InvoiceStatus.Voided)
|
||||||
.SumAsync(p => (decimal?)p.Amount) ?? 0;
|
.SumAsync(p => (decimal?)p.Amount) ?? 0;
|
||||||
if (cashRevenue > 0)
|
if (cashRevenue > 0)
|
||||||
@@ -106,7 +106,7 @@ public class FinancialReportService : IFinancialReportService
|
|||||||
|
|
||||||
// Cash refunds are cash paid back out — they reduce cash-basis revenue.
|
// Cash refunds are cash paid back out — they reduce cash-basis revenue.
|
||||||
var cashRefunds = await _context.Refunds
|
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)
|
&& r.RefundDate >= from && r.RefundDate <= toEnd)
|
||||||
.SumAsync(r => (decimal?)r.Amount) ?? 0m;
|
.SumAsync(r => (decimal?)r.Amount) ?? 0m;
|
||||||
if (cashRefunds > 0)
|
if (cashRefunds > 0)
|
||||||
@@ -116,7 +116,8 @@ public class FinancialReportService : IFinancialReportService
|
|||||||
{
|
{
|
||||||
// Accrual basis: revenue = invoice item amounts by invoice date
|
// Accrual basis: revenue = invoice item amounts by invoice date
|
||||||
var accrualRevenue = await _context.InvoiceItems
|
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.Draft
|
||||||
&& ii.Invoice.Status != InvoiceStatus.Voided
|
&& ii.Invoice.Status != InvoiceStatus.Voided
|
||||||
&& ii.Invoice.InvoiceDate >= from && ii.Invoice.InvoiceDate <= toEnd)
|
&& ii.Invoice.InvoiceDate >= from && ii.Invoice.InvoiceDate <= toEnd)
|
||||||
@@ -136,7 +137,8 @@ public class FinancialReportService : IFinancialReportService
|
|||||||
.OrderBy(l => l.AccountNumber));
|
.OrderBy(l => l.AccountNumber));
|
||||||
|
|
||||||
var unlinkedRevenue = await _context.InvoiceItems
|
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.Draft
|
||||||
&& ii.Invoice.Status != InvoiceStatus.Voided
|
&& ii.Invoice.Status != InvoiceStatus.Voided
|
||||||
&& ii.Invoice.InvoiceDate >= from && ii.Invoice.InvoiceDate <= toEnd)
|
&& 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.
|
// Contra-revenue: discounts granted and credit memos applied reduce gross revenue.
|
||||||
var periodDiscounts = await _context.Invoices
|
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)
|
&& i.DiscountAmount > 0 && i.InvoiceDate >= from && i.InvoiceDate <= toEnd)
|
||||||
.SumAsync(i => (decimal?)i.DiscountAmount) ?? 0m;
|
.SumAsync(i => (decimal?)i.DiscountAmount) ?? 0m;
|
||||||
// Credit-memo contra-revenue is recognized at issue (DR Sales Discounts). Net for the period =
|
// 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
|
// 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).
|
// relieves Sales Tax Payable, not revenue). Store-credit refunds are excluded (no GL posting).
|
||||||
var periodRefunds = await _context.Refunds
|
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)
|
&& r.RefundDate >= from && r.RefundDate <= toEnd)
|
||||||
.Select(r => new { r.Amount, r.Invoice!.TaxAmount, r.Invoice.Total })
|
.Select(r => new { r.Amount, r.Invoice!.TaxAmount, r.Invoice.Total })
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
@@ -186,7 +188,8 @@ public class FinancialReportService : IFinancialReportService
|
|||||||
|
|
||||||
// GC sales are deferred to GC Liability at issuance; revenue is recognized on redemption.
|
// GC sales are deferred to GC Liability at issuance; revenue is recognized on redemption.
|
||||||
var periodGcReclassified = await _context.InvoiceItems
|
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.Draft
|
||||||
&& ii.Invoice.Status != InvoiceStatus.Voided
|
&& ii.Invoice.Status != InvoiceStatus.Voided
|
||||||
&& ii.Invoice.InvoiceDate >= from && ii.Invoice.InvoiceDate <= toEnd)
|
&& 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).
|
// Voided GCs with remaining balance are breakage income (liability extinguished).
|
||||||
var periodGcBreakage = await _context.GiftCertificates
|
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.UpdatedAt >= from && gc.UpdatedAt <= toEnd
|
||||||
&& gc.OriginalAmount > gc.RedeemedAmount)
|
&& gc.OriginalAmount > gc.RedeemedAmount)
|
||||||
.SumAsync(gc => (decimal?)(gc.OriginalAmount - gc.RedeemedAmount)) ?? 0m;
|
.SumAsync(gc => (decimal?)(gc.OriginalAmount - gc.RedeemedAmount)) ?? 0m;
|
||||||
@@ -220,7 +223,7 @@ public class FinancialReportService : IFinancialReportService
|
|||||||
if (isCash)
|
if (isCash)
|
||||||
{
|
{
|
||||||
var cashExpenses = await _context.Expenses
|
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)
|
.GroupBy(e => e.ExpenseAccountId)
|
||||||
.Select(g => new { AccountId = g.Key, Amount = g.Sum(e => e.Amount) })
|
.Select(g => new { AccountId = g.Key, Amount = g.Sum(e => e.Amount) })
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
@@ -229,7 +232,7 @@ public class FinancialReportService : IFinancialReportService
|
|||||||
|
|
||||||
// Pro-rate paid bill line items by payment fraction (bill total may be partial)
|
// Pro-rate paid bill line items by payment fraction (bill total may be partial)
|
||||||
var paidBillLines = await _context.BillPayments
|
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)
|
.Include(bp => bp.Bill).ThenInclude(b => b.LineItems)
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
foreach (var bp in paidBillLines)
|
foreach (var bp in paidBillLines)
|
||||||
@@ -242,7 +245,7 @@ public class FinancialReportService : IFinancialReportService
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
var accrualExpenses = await _context.Expenses
|
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)
|
.GroupBy(e => e.ExpenseAccountId)
|
||||||
.Select(g => new { AccountId = g.Key, Amount = g.Sum(e => e.Amount) })
|
.Select(g => new { AccountId = g.Key, Amount = g.Sum(e => e.Amount) })
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
@@ -250,7 +253,8 @@ public class FinancialReportService : IFinancialReportService
|
|||||||
expenseAmounts[e.AccountId] = expenseAmounts.GetValueOrDefault(e.AccountId) + e.Amount;
|
expenseAmounts[e.AccountId] = expenseAmounts.GetValueOrDefault(e.AccountId) + e.Amount;
|
||||||
|
|
||||||
var accrualBillLines = await _context.BillLineItems
|
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.Draft
|
||||||
&& bli.Bill.Status != BillStatus.Voided
|
&& bli.Bill.Status != BillStatus.Voided
|
||||||
&& bli.Bill.BillDate >= from && bli.Bill.BillDate <= toEnd)
|
&& bli.Bill.BillDate >= from && bli.Bill.BillDate <= toEnd)
|
||||||
@@ -262,7 +266,7 @@ public class FinancialReportService : IFinancialReportService
|
|||||||
}
|
}
|
||||||
|
|
||||||
var expAccounts = await _context.Accounts
|
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);
|
.ToDictionaryAsync(a => a.Id);
|
||||||
|
|
||||||
var cogsLines = new List<FinancialReportLine>();
|
var cogsLines = new List<FinancialReportLine>();
|
||||||
@@ -302,7 +306,7 @@ public class FinancialReportService : IFinancialReportService
|
|||||||
// Pre-compute balance contributions per account (batch GROUP BY queries avoid N+1)
|
// Pre-compute balance contributions per account (batch GROUP BY queries avoid N+1)
|
||||||
|
|
||||||
var depositsByAcct = await _context.Payments
|
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.Voided
|
||||||
&& p.Invoice.Status != InvoiceStatus.WrittenOff)
|
&& p.Invoice.Status != InvoiceStatus.WrittenOff)
|
||||||
.GroupBy(p => p.DepositAccountId!.Value)
|
.GroupBy(p => p.DepositAccountId!.Value)
|
||||||
@@ -310,38 +314,38 @@ public class FinancialReportService : IFinancialReportService
|
|||||||
.ToDictionaryAsync(g => g.Id, g => g.Amount);
|
.ToDictionaryAsync(g => g.Id, g => g.Amount);
|
||||||
|
|
||||||
var expFromByAcct = await _context.Expenses
|
var expFromByAcct = await _context.Expenses
|
||||||
.Where(e => e.Date <= asOfEnd)
|
.Where(e => e.CompanyId == companyId && e.Date <= asOfEnd)
|
||||||
.GroupBy(e => e.PaymentAccountId)
|
.GroupBy(e => e.PaymentAccountId)
|
||||||
.Select(g => new { Id = g.Key, Amount = g.Sum(e => e.Amount) })
|
.Select(g => new { Id = g.Key, Amount = g.Sum(e => e.Amount) })
|
||||||
.ToDictionaryAsync(g => g.Id, g => g.Amount);
|
.ToDictionaryAsync(g => g.Id, g => g.Amount);
|
||||||
|
|
||||||
var bpFromByAcct = await _context.BillPayments
|
var bpFromByAcct = await _context.BillPayments
|
||||||
.Where(bp => bp.PaymentDate <= asOfEnd)
|
.Where(bp => bp.CompanyId == companyId && bp.PaymentDate <= asOfEnd)
|
||||||
.GroupBy(bp => bp.BankAccountId)
|
.GroupBy(bp => bp.BankAccountId)
|
||||||
.Select(g => new { Id = g.Key, Amount = g.Sum(bp => bp.Amount) })
|
.Select(g => new { Id = g.Key, Amount = g.Sum(bp => bp.Amount) })
|
||||||
.ToDictionaryAsync(g => g.Id, g => g.Amount);
|
.ToDictionaryAsync(g => g.Id, g => g.Amount);
|
||||||
|
|
||||||
var billsByApAcct = await _context.Bills
|
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)
|
.GroupBy(b => b.APAccountId)
|
||||||
.Select(g => new { Id = g.Key, Amount = g.Sum(b => b.Total) })
|
.Select(g => new { Id = g.Key, Amount = g.Sum(b => b.Total) })
|
||||||
.ToDictionaryAsync(g => g.Id, g => g.Amount);
|
.ToDictionaryAsync(g => g.Id, g => g.Amount);
|
||||||
|
|
||||||
var bpByApAcct = await _context.BillPayments
|
var bpByApAcct = await _context.BillPayments
|
||||||
.Where(bp => bp.PaymentDate <= asOfEnd)
|
.Where(bp => bp.CompanyId == companyId && bp.PaymentDate <= asOfEnd)
|
||||||
.GroupBy(bp => bp.Bill.APAccountId)
|
.GroupBy(bp => bp.Bill.APAccountId)
|
||||||
.Select(g => new { Id = g.Key, Amount = g.Sum(bp => bp.Amount) })
|
.Select(g => new { Id = g.Key, Amount = g.Sum(bp => bp.Amount) })
|
||||||
.ToDictionaryAsync(g => g.Id, g => g.Amount);
|
.ToDictionaryAsync(g => g.Id, g => g.Amount);
|
||||||
|
|
||||||
// AP: vendor credit applications reduce AP (DR side) when matched against specific bills.
|
// AP: vendor credit applications reduce AP (DR side) when matched against specific bills.
|
||||||
var vcByApAcctBs = await _context.VendorCreditApplications
|
var vcByApAcctBs = await _context.VendorCreditApplications
|
||||||
.Where(vca => vca.AppliedDate <= asOfEnd)
|
.Where(vca => vca.CompanyId == companyId && vca.AppliedDate <= asOfEnd)
|
||||||
.GroupBy(vca => vca.VendorCredit.APAccountId)
|
.GroupBy(vca => vca.VendorCredit.APAccountId)
|
||||||
.Select(g => new { Id = g.Key, Amount = g.Sum(vca => vca.Amount) })
|
.Select(g => new { Id = g.Key, Amount = g.Sum(vca => vca.Amount) })
|
||||||
.ToDictionaryAsync(g => g.Id, g => g.Amount);
|
.ToDictionaryAsync(g => g.Id, g => g.Amount);
|
||||||
|
|
||||||
var taxByAcct = await _context.Invoices
|
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.Status != InvoiceStatus.Draft && i.Status != InvoiceStatus.Voided
|
||||||
&& i.InvoiceDate <= asOfEnd)
|
&& i.InvoiceDate <= asOfEnd)
|
||||||
.GroupBy(i => i.SalesTaxAccountId!.Value)
|
.GroupBy(i => i.SalesTaxAccountId!.Value)
|
||||||
@@ -349,16 +353,16 @@ public class FinancialReportService : IFinancialReportService
|
|||||||
.ToDictionaryAsync(g => g.Id, g => g.Amount);
|
.ToDictionaryAsync(g => g.Id, g => g.Amount);
|
||||||
|
|
||||||
var arDebits = await _context.Invoices
|
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;
|
.SumAsync(i => (decimal?)i.Total) ?? 0;
|
||||||
var arCredits = await _context.Payments
|
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.Voided
|
||||||
&& p.Invoice.Status != InvoiceStatus.WrittenOff)
|
&& p.Invoice.Status != InvoiceStatus.WrittenOff)
|
||||||
.SumAsync(p => (decimal?)p.Amount) ?? 0;
|
.SumAsync(p => (decimal?)p.Amount) ?? 0;
|
||||||
// Credit memo applications reduce open AR (CR AR when a credit is applied to an invoice).
|
// Credit memo applications reduce open AR (CR AR when a credit is applied to an invoice).
|
||||||
var cmAppliedBs = await _context.CreditMemoApplications
|
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;
|
.SumAsync(a => (decimal?)a.AmountApplied) ?? 0;
|
||||||
arCredits += cmAppliedBs;
|
arCredits += cmAppliedBs;
|
||||||
|
|
||||||
@@ -369,7 +373,7 @@ public class FinancialReportService : IFinancialReportService
|
|||||||
.Where(m => m.CompanyId == companyId && m.Status != CreditMemoStatus.Voided && m.IssueDate <= asOfEnd)
|
.Where(m => m.CompanyId == companyId && m.Status != CreditMemoStatus.Voided && m.IssueDate <= asOfEnd)
|
||||||
.SumAsync(m => (decimal?)m.Amount) ?? 0m;
|
.SumAsync(m => (decimal?)m.Amount) ?? 0m;
|
||||||
var cmAppliedNonVoidedBs = await _context.CreditMemoApplications
|
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)
|
&& a.CreditMemo.Status != CreditMemoStatus.Voided)
|
||||||
.SumAsync(a => (decimal?)a.AmountApplied) ?? 0m;
|
.SumAsync(a => (decimal?)a.AmountApplied) ?? 0m;
|
||||||
var cmContraRevenueBs = cmIssuedNonVoidedBs + (cmAppliedBs - cmAppliedNonVoidedBs);
|
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.
|
// 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.
|
// Store-credit refunds post via CreditMemo, not the GL, so are excluded.
|
||||||
var saleReversingRefundsBs = await _context.Refunds
|
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)
|
&& r.RefundMethod != PaymentMethod.StoreCredit)
|
||||||
.Select(r => new { r.Amount, r.Invoice!.TaxAmount, r.Invoice.Total, r.Invoice.SalesTaxAccountId })
|
.Select(r => new { r.Amount, r.Invoice!.TaxAmount, r.Invoice.Total, r.Invoice.SalesTaxAccountId })
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
@@ -396,14 +400,14 @@ public class FinancialReportService : IFinancialReportService
|
|||||||
|
|
||||||
// Refunds by bank account: money that left the account (CR to checking/bank).
|
// Refunds by bank account: money that left the account (CR to checking/bank).
|
||||||
var refundsByAcctBs = await _context.Refunds
|
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)
|
.GroupBy(r => r.DepositAccountId!.Value)
|
||||||
.Select(g => new { Id = g.Key, Amount = g.Sum(r => r.Amount) })
|
.Select(g => new { Id = g.Key, Amount = g.Sum(r => r.Amount) })
|
||||||
.ToDictionaryAsync(g => g.Id, g => g.Amount);
|
.ToDictionaryAsync(g => g.Id, g => g.Amount);
|
||||||
|
|
||||||
// Deposits by bank account: cash received at deposit recording time (DR bank).
|
// Deposits by bank account: cash received at deposit recording time (DR bank).
|
||||||
var depositsByAcctDepBs = await _context.Deposits
|
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)
|
.GroupBy(d => d.DepositAccountId!.Value)
|
||||||
.Select(g => new { Id = g.Key, Amount = g.Sum(d => d.Amount) })
|
.Select(g => new { Id = g.Key, Amount = g.Sum(d => d.Amount) })
|
||||||
.ToDictionaryAsync(g => g.Id, g => g.Amount);
|
.ToDictionaryAsync(g => g.Id, g => g.Amount);
|
||||||
@@ -414,11 +418,11 @@ public class FinancialReportService : IFinancialReportService
|
|||||||
.Select(a => (int?)a.Id).FirstOrDefaultAsync();
|
.Select(a => (int?)a.Id).FirstOrDefaultAsync();
|
||||||
var custDepositsCreditsBs = custDepositsAcctIdBs.HasValue
|
var custDepositsCreditsBs = custDepositsAcctIdBs.HasValue
|
||||||
? (await _context.Deposits
|
? (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;
|
.SumAsync(d => (decimal?)d.Amount) ?? 0m) : 0m;
|
||||||
var custDepositsDebitsBs = custDepositsAcctIdBs.HasValue
|
var custDepositsDebitsBs = custDepositsAcctIdBs.HasValue
|
||||||
? (await _context.Deposits
|
? (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;
|
.SumAsync(d => (decimal?)d.Amount) ?? 0m) : 0m;
|
||||||
|
|
||||||
// Gift Certificate Liability (2500): balance driven by GC issuances, redemptions, and voids.
|
// 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();
|
.Select(a => (int?)a.Id).FirstOrDefaultAsync();
|
||||||
var gcLiabilityCreditsBs = gcLiabilityAcctIdBs.HasValue
|
var gcLiabilityCreditsBs = gcLiabilityAcctIdBs.HasValue
|
||||||
? (await _context.GiftCertificates
|
? (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;
|
.SumAsync(gc => (decimal?)gc.OriginalAmount) ?? 0m) : 0m;
|
||||||
var gcLiabilityDebitsBs = gcLiabilityAcctIdBs.HasValue
|
var gcLiabilityDebitsBs = gcLiabilityAcctIdBs.HasValue
|
||||||
? ((await _context.GiftCertificateRedemptions
|
? ((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)
|
.SumAsync(r => (decimal?)r.AmountRedeemed) ?? 0m)
|
||||||
+ (await _context.GiftCertificates
|
+ (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)
|
&& gc.UpdatedAt <= asOfEnd && gc.OriginalAmount > gc.RedeemedAmount)
|
||||||
.SumAsync(gc => (decimal?)(gc.OriginalAmount - gc.RedeemedAmount)) ?? 0m)) : 0m;
|
.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
|
// 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).
|
// (accruals, depreciation, year-end closes, and other adjustments not in the tables above).
|
||||||
var lifetimeRevenue = await _context.InvoiceItems
|
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;
|
.SumAsync(ii => (decimal?)ii.TotalPrice) ?? 0;
|
||||||
var lifetimeDiscounts = isCash ? 0m
|
var lifetimeDiscounts = isCash ? 0m
|
||||||
: (await _context.Invoices
|
: (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)
|
&& i.DiscountAmount > 0 && i.InvoiceDate <= asOfEnd)
|
||||||
.SumAsync(i => (decimal?)i.DiscountAmount) ?? 0m);
|
.SumAsync(i => (decimal?)i.DiscountAmount) ?? 0m);
|
||||||
// Credit memos are contra-revenue recognized at issue (DR Sales Discounts). Net revenue is
|
// 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).
|
// reduced by the issued amount (active memos in full + applied portion of voided memos).
|
||||||
var lifetimeCreditMemos = isCash ? 0m : cmContraRevenueBs;
|
var lifetimeCreditMemos = isCash ? 0m : cmContraRevenueBs;
|
||||||
var lifetimeDirectExp = await _context.Expenses
|
var lifetimeDirectExp = await _context.Expenses
|
||||||
.Where(e => e.Date <= asOfEnd)
|
.Where(e => e.CompanyId == companyId && e.Date <= asOfEnd)
|
||||||
.SumAsync(e => (decimal?)e.Amount) ?? 0;
|
.SumAsync(e => (decimal?)e.Amount) ?? 0;
|
||||||
var lifetimeBillCosts = await _context.BillLineItems
|
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;
|
.SumAsync(bli => (decimal?)bli.Amount) ?? 0;
|
||||||
|
|
||||||
// JE net effect on revenue accounts (positive = additional revenue recognised via manual JE)
|
// 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.
|
// GC items sold via invoices are reclassified to GC Liability and not yet earned income.
|
||||||
var lifetimeGcReclassified = await _context.InvoiceItems
|
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.Draft
|
||||||
&& ii.Invoice.Status != InvoiceStatus.Voided
|
&& ii.Invoice.Status != InvoiceStatus.Voided
|
||||||
&& ii.Invoice.InvoiceDate <= asOfEnd)
|
&& ii.Invoice.InvoiceDate <= asOfEnd)
|
||||||
.SumAsync(ii => (decimal?)ii.TotalPrice) ?? 0m;
|
.SumAsync(ii => (decimal?)ii.TotalPrice) ?? 0m;
|
||||||
// Voided GCs with remaining balance become breakage income (the liability is extinguished).
|
// Voided GCs with remaining balance become breakage income (the liability is extinguished).
|
||||||
var lifetimeGcBreakage = await _context.GiftCertificates
|
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)
|
&& gc.UpdatedAt <= asOfEnd && gc.OriginalAmount > gc.RedeemedAmount)
|
||||||
.SumAsync(gc => (decimal?)(gc.OriginalAmount - gc.RedeemedAmount)) ?? 0m;
|
.SumAsync(gc => (decimal?)(gc.OriginalAmount - gc.RedeemedAmount)) ?? 0m;
|
||||||
|
|
||||||
@@ -511,7 +515,7 @@ public class FinancialReportService : IFinancialReportService
|
|||||||
- jeExpNet;
|
- jeExpNet;
|
||||||
|
|
||||||
var accounts = await _context.Accounts
|
var accounts = await _context.Accounts
|
||||||
.Where(a => a.IsActive)
|
.Where(a => a.CompanyId == companyId && a.IsActive)
|
||||||
.OrderBy(a => a.AccountNumber)
|
.OrderBy(a => a.AccountNumber)
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
|
|
||||||
@@ -619,7 +623,8 @@ public class FinancialReportService : IFinancialReportService
|
|||||||
|
|
||||||
var openInvoices = await _context.Invoices
|
var openInvoices = await _context.Invoices
|
||||||
.Include(i => i.Customer)
|
.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.Voided
|
||||||
&& i.Status != InvoiceStatus.Paid
|
&& i.Status != InvoiceStatus.Paid
|
||||||
&& i.InvoiceDate <= asOfEnd
|
&& i.InvoiceDate <= asOfEnd
|
||||||
@@ -699,14 +704,15 @@ public class FinancialReportService : IFinancialReportService
|
|||||||
var invoices = await _context.Invoices
|
var invoices = await _context.Invoices
|
||||||
.Include(i => i.Customer)
|
.Include(i => i.Customer)
|
||||||
.Include(i => i.Payments)
|
.Include(i => i.Payments)
|
||||||
.Where(i => i.Status != InvoiceStatus.Draft
|
.Where(i => i.CompanyId == companyId
|
||||||
|
&& i.Status != InvoiceStatus.Draft
|
||||||
&& i.Status != InvoiceStatus.Voided
|
&& i.Status != InvoiceStatus.Voided
|
||||||
&& i.InvoiceDate >= from && i.InvoiceDate <= toEnd)
|
&& i.InvoiceDate >= from && i.InvoiceDate <= toEnd)
|
||||||
.OrderBy(i => i.InvoiceDate)
|
.OrderBy(i => i.InvoiceDate)
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
|
|
||||||
var collectedInPeriod = await _context.Payments
|
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;
|
.SumAsync(p => (decimal?)p.Amount) ?? 0;
|
||||||
|
|
||||||
var byCustomer = invoices
|
var byCustomer = invoices
|
||||||
@@ -971,7 +977,7 @@ public class FinancialReportService : IFinancialReportService
|
|||||||
|
|
||||||
// Bank/cash: customer payments deposited here (DR)
|
// Bank/cash: customer payments deposited here (DR)
|
||||||
var depositsByAcct = await _context.Payments
|
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.Voided
|
||||||
&& p.Invoice.Status != InvoiceStatus.WrittenOff)
|
&& p.Invoice.Status != InvoiceStatus.WrittenOff)
|
||||||
.GroupBy(p => p.DepositAccountId!.Value)
|
.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
|
// 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.
|
// issues a credit note and it is matched against a specific bill.
|
||||||
var vcByApAcct = await _context.VendorCreditApplications
|
var vcByApAcct = await _context.VendorCreditApplications
|
||||||
.Where(vca => vca.AppliedDate <= asOfEnd)
|
.Where(vca => vca.CompanyId == companyId && vca.AppliedDate <= asOfEnd)
|
||||||
.GroupBy(vca => vca.VendorCredit.APAccountId)
|
.GroupBy(vca => vca.VendorCredit.APAccountId)
|
||||||
.Select(g => new { Id = g.Key, Amt = g.Sum(vca => vca.Amount) })
|
.Select(g => new { Id = g.Key, Amt = g.Sum(vca => vca.Amount) })
|
||||||
.ToDictionaryAsync(g => g.Id, g => g.Amt);
|
.ToDictionaryAsync(g => g.Id, g => g.Amt);
|
||||||
|
|
||||||
// Bank/cash: expenses paid from here (CR)
|
// Bank/cash: expenses paid from here (CR)
|
||||||
var expFromByAcct = await _context.Expenses
|
var expFromByAcct = await _context.Expenses
|
||||||
.Where(e => e.Date <= asOfEnd)
|
.Where(e => e.CompanyId == companyId && e.Date <= asOfEnd)
|
||||||
.GroupBy(e => e.PaymentAccountId)
|
.GroupBy(e => e.PaymentAccountId)
|
||||||
.Select(g => new { Id = g.Key, Amt = g.Sum(e => e.Amount) })
|
.Select(g => new { Id = g.Key, Amt = g.Sum(e => e.Amount) })
|
||||||
.ToDictionaryAsync(g => g.Id, g => g.Amt);
|
.ToDictionaryAsync(g => g.Id, g => g.Amt);
|
||||||
|
|
||||||
// Bank/cash: bill payments made from here (CR)
|
// Bank/cash: bill payments made from here (CR)
|
||||||
var bpFromByAcct = await _context.BillPayments
|
var bpFromByAcct = await _context.BillPayments
|
||||||
.Where(bp => bp.PaymentDate <= asOfEnd)
|
.Where(bp => bp.CompanyId == companyId && bp.PaymentDate <= asOfEnd)
|
||||||
.GroupBy(bp => bp.BankAccountId)
|
.GroupBy(bp => bp.BankAccountId)
|
||||||
.Select(g => new { Id = g.Key, Amt = g.Sum(bp => bp.Amount) })
|
.Select(g => new { Id = g.Key, Amt = g.Sum(bp => bp.Amount) })
|
||||||
.ToDictionaryAsync(g => g.Id, g => g.Amt);
|
.ToDictionaryAsync(g => g.Id, g => g.Amt);
|
||||||
|
|
||||||
// AP: bills increase AP (CR)
|
// AP: bills increase AP (CR)
|
||||||
var billsByApAcct = await _context.Bills
|
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)
|
.GroupBy(b => b.APAccountId)
|
||||||
.Select(g => new { Id = g.Key, Amt = g.Sum(b => b.Total) })
|
.Select(g => new { Id = g.Key, Amt = g.Sum(b => b.Total) })
|
||||||
.ToDictionaryAsync(g => g.Id, g => g.Amt);
|
.ToDictionaryAsync(g => g.Id, g => g.Amt);
|
||||||
|
|
||||||
// AP: bill payments reduce AP (DR)
|
// AP: bill payments reduce AP (DR)
|
||||||
var bpByApAcct = await _context.BillPayments
|
var bpByApAcct = await _context.BillPayments
|
||||||
.Where(bp => bp.PaymentDate <= asOfEnd)
|
.Where(bp => bp.CompanyId == companyId && bp.PaymentDate <= asOfEnd)
|
||||||
.GroupBy(bp => bp.Bill.APAccountId)
|
.GroupBy(bp => bp.Bill.APAccountId)
|
||||||
.Select(g => new { Id = g.Key, Amt = g.Sum(bp => bp.Amount) })
|
.Select(g => new { Id = g.Key, Amt = g.Sum(bp => bp.Amount) })
|
||||||
.ToDictionaryAsync(g => g.Id, g => g.Amt);
|
.ToDictionaryAsync(g => g.Id, g => g.Amt);
|
||||||
|
|
||||||
// Tax liability: sales tax collected (CR)
|
// Tax liability: sales tax collected (CR)
|
||||||
var taxByAcct = await _context.Invoices
|
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.Status != InvoiceStatus.Draft && i.Status != InvoiceStatus.Voided
|
||||||
&& i.InvoiceDate <= asOfEnd)
|
&& i.InvoiceDate <= asOfEnd)
|
||||||
.GroupBy(i => i.SalesTaxAccountId!.Value)
|
.GroupBy(i => i.SalesTaxAccountId!.Value)
|
||||||
@@ -1025,7 +1031,7 @@ public class FinancialReportService : IFinancialReportService
|
|||||||
|
|
||||||
// Revenue accounts: invoice line items (CR)
|
// Revenue accounts: invoice line items (CR)
|
||||||
var revenueByAcct = await _context.InvoiceItems
|
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.Draft
|
||||||
&& ii.Invoice.Status != InvoiceStatus.Voided
|
&& ii.Invoice.Status != InvoiceStatus.Voided
|
||||||
&& ii.Invoice.InvoiceDate <= asOfEnd)
|
&& ii.Invoice.InvoiceDate <= asOfEnd)
|
||||||
@@ -1035,14 +1041,14 @@ public class FinancialReportService : IFinancialReportService
|
|||||||
|
|
||||||
// Expense accounts: direct expenses (DR)
|
// Expense accounts: direct expenses (DR)
|
||||||
var expenseByAcct = await _context.Expenses
|
var expenseByAcct = await _context.Expenses
|
||||||
.Where(e => e.Date <= asOfEnd)
|
.Where(e => e.CompanyId == companyId && e.Date <= asOfEnd)
|
||||||
.GroupBy(e => e.ExpenseAccountId)
|
.GroupBy(e => e.ExpenseAccountId)
|
||||||
.Select(g => new { Id = g.Key, Amt = g.Sum(e => e.Amount) })
|
.Select(g => new { Id = g.Key, Amt = g.Sum(e => e.Amount) })
|
||||||
.ToDictionaryAsync(g => g.Id, g => g.Amt);
|
.ToDictionaryAsync(g => g.Id, g => g.Amt);
|
||||||
|
|
||||||
// Expense/COGS accounts: vendor bill line items (DR)
|
// Expense/COGS accounts: vendor bill line items (DR)
|
||||||
var billLinesByAcct = await _context.BillLineItems
|
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.Draft
|
||||||
&& bli.Bill.Status != BillStatus.Voided
|
&& bli.Bill.Status != BillStatus.Voided
|
||||||
&& bli.Bill.BillDate <= asOfEnd)
|
&& bli.Bill.BillDate <= asOfEnd)
|
||||||
@@ -1064,7 +1070,7 @@ public class FinancialReportService : IFinancialReportService
|
|||||||
.FirstOrDefaultAsync();
|
.FirstOrDefaultAsync();
|
||||||
|
|
||||||
var cmApplied = await _context.CreditMemoApplications
|
var cmApplied = await _context.CreditMemoApplications
|
||||||
.Where(a => a.AppliedDate <= asOfEnd
|
.Where(a => a.CompanyId == companyId && a.AppliedDate <= asOfEnd
|
||||||
&& a.Invoice.Status != InvoiceStatus.Voided)
|
&& a.Invoice.Status != InvoiceStatus.Voided)
|
||||||
.SumAsync(a => (decimal?)a.AmountApplied) ?? 0m;
|
.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)
|
.Where(m => m.CompanyId == companyId && m.Status != CreditMemoStatus.Voided && m.IssueDate <= asOfEnd)
|
||||||
.SumAsync(m => (decimal?)m.Amount) ?? 0m;
|
.SumAsync(m => (decimal?)m.Amount) ?? 0m;
|
||||||
var cmAppliedNonVoided = await _context.CreditMemoApplications
|
var cmAppliedNonVoided = await _context.CreditMemoApplications
|
||||||
.Where(a => a.AppliedDate <= asOfEnd
|
.Where(a => a.CompanyId == companyId && a.AppliedDate <= asOfEnd
|
||||||
&& a.Invoice.Status != InvoiceStatus.Voided
|
&& a.Invoice.Status != InvoiceStatus.Voided
|
||||||
&& a.CreditMemo.Status != CreditMemoStatus.Voided)
|
&& a.CreditMemo.Status != CreditMemoStatus.Voided)
|
||||||
.SumAsync(a => (decimal?)a.AmountApplied) ?? 0m;
|
.SumAsync(a => (decimal?)a.AmountApplied) ?? 0m;
|
||||||
@@ -1089,7 +1095,7 @@ public class FinancialReportService : IFinancialReportService
|
|||||||
if (discountAcctId.HasValue)
|
if (discountAcctId.HasValue)
|
||||||
{
|
{
|
||||||
var totalDiscounts = await _context.Invoices
|
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.Draft
|
||||||
&& i.Status != InvoiceStatus.Voided
|
&& i.Status != InvoiceStatus.Voided
|
||||||
&& i.InvoiceDate <= asOfEnd)
|
&& i.InvoiceDate <= asOfEnd)
|
||||||
@@ -1100,14 +1106,14 @@ public class FinancialReportService : IFinancialReportService
|
|||||||
|
|
||||||
// JE lines: posted entries debit/credit all account types
|
// JE lines: posted entries debit/credit all account types
|
||||||
var jeDebitsByAcct = await _context.JournalEntryLines
|
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)
|
&& l.JournalEntry.EntryDate <= asOfEnd)
|
||||||
.GroupBy(l => l.AccountId)
|
.GroupBy(l => l.AccountId)
|
||||||
.Select(g => new { Id = g.Key, Amt = g.Sum(l => l.DebitAmount) })
|
.Select(g => new { Id = g.Key, Amt = g.Sum(l => l.DebitAmount) })
|
||||||
.ToDictionaryAsync(g => g.Id, g => g.Amt);
|
.ToDictionaryAsync(g => g.Id, g => g.Amt);
|
||||||
|
|
||||||
var jeCreditsByAcct = await _context.JournalEntryLines
|
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)
|
&& l.JournalEntry.EntryDate <= asOfEnd)
|
||||||
.GroupBy(l => l.AccountId)
|
.GroupBy(l => l.AccountId)
|
||||||
.Select(g => new { Id = g.Key, Amt = g.Sum(l => l.CreditAmount) })
|
.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
|
// Credits include both cash payments and credit memo applications (which reduce open AR
|
||||||
// when a customer credit is applied against a specific invoice).
|
// when a customer credit is applied against a specific invoice).
|
||||||
var arTotalDebits = await _context.Invoices
|
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)
|
&& i.InvoiceDate <= asOfEnd)
|
||||||
.SumAsync(i => (decimal?)i.Total) ?? 0m;
|
.SumAsync(i => (decimal?)i.Total) ?? 0m;
|
||||||
var arTotalCredits = await _context.Payments
|
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.Voided
|
||||||
&& p.Invoice.Status != InvoiceStatus.WrittenOff)
|
&& p.Invoice.Status != InvoiceStatus.WrittenOff)
|
||||||
.SumAsync(p => (decimal?)p.Amount) ?? 0m;
|
.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
|
// 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.
|
// longer touch AR. Store-credit refunds post via CreditMemo, not the GL, so are excluded.
|
||||||
var saleReversingRefunds = await _context.Refunds
|
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)
|
&& r.RefundMethod != PaymentMethod.StoreCredit)
|
||||||
.Select(r => new { r.Amount, r.Invoice!.TaxAmount, r.Invoice.Total, r.Invoice.SalesTaxAccountId })
|
.Select(r => new { r.Amount, r.Invoice!.TaxAmount, r.Invoice.Total, r.Invoice.SalesTaxAccountId })
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
@@ -1152,7 +1158,7 @@ public class FinancialReportService : IFinancialReportService
|
|||||||
|
|
||||||
// Refunds by bank account: money leaving the account (CR to checking/bank).
|
// Refunds by bank account: money leaving the account (CR to checking/bank).
|
||||||
var refundsByAcct = await _context.Refunds
|
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)
|
.GroupBy(r => r.DepositAccountId!.Value)
|
||||||
.Select(g => new { Id = g.Key, Amt = g.Sum(r => r.Amount) })
|
.Select(g => new { Id = g.Key, Amt = g.Sum(r => r.Amount) })
|
||||||
.ToDictionaryAsync(g => g.Id, g => g.Amt);
|
.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).
|
// 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.
|
// Deposit-sourced Payments have DepositAccountId = null, so there is no double-count with depositsByAcct.
|
||||||
var depositsByAcctDep = await _context.Deposits
|
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)
|
.GroupBy(d => d.DepositAccountId!.Value)
|
||||||
.Select(g => new { Id = g.Key, Amt = g.Sum(d => d.Amount) })
|
.Select(g => new { Id = g.Key, Amt = g.Sum(d => d.Amount) })
|
||||||
.ToDictionaryAsync(g => g.Id, g => g.Amt);
|
.ToDictionaryAsync(g => g.Id, g => g.Amt);
|
||||||
@@ -1171,11 +1177,11 @@ public class FinancialReportService : IFinancialReportService
|
|||||||
.Select(a => (int?)a.Id).FirstOrDefaultAsync();
|
.Select(a => (int?)a.Id).FirstOrDefaultAsync();
|
||||||
var custDepositsCredits = custDepositsAcctId.HasValue
|
var custDepositsCredits = custDepositsAcctId.HasValue
|
||||||
? (await _context.Deposits
|
? (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;
|
.SumAsync(d => (decimal?)d.Amount) ?? 0m) : 0m;
|
||||||
var custDepositsDebits = custDepositsAcctId.HasValue
|
var custDepositsDebits = custDepositsAcctId.HasValue
|
||||||
? (await _context.Deposits
|
? (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;
|
.SumAsync(d => (decimal?)d.Amount) ?? 0m) : 0m;
|
||||||
|
|
||||||
// Gift Certificate Liability (2500): balance driven by GC issuances, redemptions, and voids.
|
// 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();
|
.Select(a => (int?)a.Id).FirstOrDefaultAsync();
|
||||||
var gcLiabilityCredits = gcLiabilityAcctId.HasValue
|
var gcLiabilityCredits = gcLiabilityAcctId.HasValue
|
||||||
? (await _context.GiftCertificates
|
? (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;
|
.SumAsync(gc => (decimal?)gc.OriginalAmount) ?? 0m) : 0m;
|
||||||
var gcLiabilityDebits = gcLiabilityAcctId.HasValue
|
var gcLiabilityDebits = gcLiabilityAcctId.HasValue
|
||||||
? ((await _context.GiftCertificateRedemptions
|
? ((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)
|
.SumAsync(r => (decimal?)r.AmountRedeemed) ?? 0m)
|
||||||
+ (await _context.GiftCertificates
|
+ (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)
|
&& gc.UpdatedAt <= asOfEnd && gc.OriginalAmount > gc.RedeemedAmount)
|
||||||
.SumAsync(gc => (decimal?)(gc.OriginalAmount - gc.RedeemedAmount)) ?? 0m)) : 0m;
|
.SumAsync(gc => (decimal?)(gc.OriginalAmount - gc.RedeemedAmount)) ?? 0m)) : 0m;
|
||||||
|
|
||||||
@@ -1337,17 +1343,17 @@ public class FinancialReportService : IFinancialReportService
|
|||||||
|
|
||||||
// Opening balance: invoiced − paid before period start
|
// Opening balance: invoiced − paid before period start
|
||||||
var preInvoiced = await _context.Invoices
|
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.Status != InvoiceStatus.Draft && i.Status != InvoiceStatus.Voided
|
||||||
&& i.InvoiceDate < from)
|
&& i.InvoiceDate < from)
|
||||||
.SumAsync(i => (decimal?)i.Total) ?? 0;
|
.SumAsync(i => (decimal?)i.Total) ?? 0;
|
||||||
var prePaid = await _context.Payments
|
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.Invoice.Status != InvoiceStatus.Voided
|
||||||
&& p.PaymentDate < from)
|
&& p.PaymentDate < from)
|
||||||
.SumAsync(p => (decimal?)p.Amount) ?? 0;
|
.SumAsync(p => (decimal?)p.Amount) ?? 0;
|
||||||
var preCredits = await _context.CreditMemoApplications
|
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;
|
.SumAsync(a => (decimal?)a.AmountApplied) ?? 0;
|
||||||
|
|
||||||
var openingBalance = preInvoiced - prePaid - preCredits;
|
var openingBalance = preInvoiced - prePaid - preCredits;
|
||||||
@@ -1356,7 +1362,7 @@ public class FinancialReportService : IFinancialReportService
|
|||||||
var lines = new List<StatementLineDto>();
|
var lines = new List<StatementLineDto>();
|
||||||
|
|
||||||
var periodInvoices = await _context.Invoices
|
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.Status != InvoiceStatus.Draft && i.Status != InvoiceStatus.Voided
|
||||||
&& i.InvoiceDate >= from && i.InvoiceDate <= toEnd)
|
&& i.InvoiceDate >= from && i.InvoiceDate <= toEnd)
|
||||||
.AsNoTracking().ToListAsync();
|
.AsNoTracking().ToListAsync();
|
||||||
@@ -1373,7 +1379,7 @@ public class FinancialReportService : IFinancialReportService
|
|||||||
|
|
||||||
var periodPayments = await _context.Payments
|
var periodPayments = await _context.Payments
|
||||||
.Include(p => p.Invoice)
|
.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.Invoice.Status != InvoiceStatus.Voided
|
||||||
&& p.PaymentDate >= from && p.PaymentDate <= toEnd)
|
&& p.PaymentDate >= from && p.PaymentDate <= toEnd)
|
||||||
.AsNoTracking().ToListAsync();
|
.AsNoTracking().ToListAsync();
|
||||||
@@ -1391,7 +1397,7 @@ public class FinancialReportService : IFinancialReportService
|
|||||||
var periodCredits = await _context.CreditMemoApplications
|
var periodCredits = await _context.CreditMemoApplications
|
||||||
.Include(a => a.Invoice)
|
.Include(a => a.Invoice)
|
||||||
.Include(a => a.CreditMemo)
|
.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)
|
&& a.AppliedDate >= from && a.AppliedDate <= toEnd)
|
||||||
.AsNoTracking().ToListAsync();
|
.AsNoTracking().ToListAsync();
|
||||||
|
|
||||||
@@ -1442,15 +1448,15 @@ public class FinancialReportService : IFinancialReportService
|
|||||||
|
|
||||||
// Opening balance: bills − payments − credits before period start
|
// Opening balance: bills − payments − credits before period start
|
||||||
var preBills = await _context.Bills
|
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.Status != BillStatus.Draft && b.Status != BillStatus.Voided
|
||||||
&& b.BillDate < from)
|
&& b.BillDate < from)
|
||||||
.SumAsync(b => (decimal?)b.Total) ?? 0;
|
.SumAsync(b => (decimal?)b.Total) ?? 0;
|
||||||
var prePayments = await _context.BillPayments
|
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;
|
.SumAsync(bp => (decimal?)bp.Amount) ?? 0;
|
||||||
var preVcApplied = await _context.VendorCreditApplications
|
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;
|
.SumAsync(vca => (decimal?)vca.Amount) ?? 0;
|
||||||
|
|
||||||
var openingBalance = preBills - prePayments - preVcApplied;
|
var openingBalance = preBills - prePayments - preVcApplied;
|
||||||
@@ -1458,7 +1464,7 @@ public class FinancialReportService : IFinancialReportService
|
|||||||
var lines = new List<StatementLineDto>();
|
var lines = new List<StatementLineDto>();
|
||||||
|
|
||||||
var periodBills = await _context.Bills
|
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.Status != BillStatus.Draft && b.Status != BillStatus.Voided
|
||||||
&& b.BillDate >= from && b.BillDate <= toEnd)
|
&& b.BillDate >= from && b.BillDate <= toEnd)
|
||||||
.AsNoTracking().ToListAsync();
|
.AsNoTracking().ToListAsync();
|
||||||
@@ -1475,7 +1481,7 @@ public class FinancialReportService : IFinancialReportService
|
|||||||
|
|
||||||
var periodPayments = await _context.BillPayments
|
var periodPayments = await _context.BillPayments
|
||||||
.Include(bp => bp.Bill)
|
.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)
|
&& bp.PaymentDate >= from && bp.PaymentDate <= toEnd)
|
||||||
.AsNoTracking().ToListAsync();
|
.AsNoTracking().ToListAsync();
|
||||||
|
|
||||||
@@ -1492,7 +1498,7 @@ public class FinancialReportService : IFinancialReportService
|
|||||||
var periodVcApplied = await _context.VendorCreditApplications
|
var periodVcApplied = await _context.VendorCreditApplications
|
||||||
.Include(vca => vca.VendorCredit)
|
.Include(vca => vca.VendorCredit)
|
||||||
.Include(vca => vca.Bill)
|
.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)
|
&& vca.AppliedDate >= from && vca.AppliedDate <= toEnd)
|
||||||
.AsNoTracking().ToListAsync();
|
.AsNoTracking().ToListAsync();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user