Files
PowderCoatingLogix/src/PowderCoating.Application/DTOs/Accounting/FinancialReportDtos.cs
T
spouliot ca4fb959aa Add Sales Tax Liability report with PDF and CSV export
Invoice-basis report showing taxable vs non-taxable sales, tax billed
by GL account, monthly trend table/chart, and full invoice detail grid.
Non-taxable invoice rows shaded grey for easy scanning. Quick-preset
date buttons (This Month, Last Month, YTD, Last Year) for common filing
periods. CSV export formatted for accountants and tax-filing software.
Gated behind AllowAccounting() like other financial reports.

- SalesTaxReportDto + 3 supporting DTOs in FinancialReportDtos.cs
- GetSalesTaxReportAsync on IFinancialReportService + implementation
- GenerateSalesTaxReportPdfAsync on IPdfService + QuestPDF implementation
- SalesTax / SalesTaxPdf / SalesTaxCsv actions in ReportsController
- Views/Reports/SalesTax.cshtml with Chart.js monthly trend chart
- Landing page card added to Finance section
- HelpKnowledgeBase and Help/Reports.cshtml updated with full docs

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 12:27:08 -04:00

224 lines
8.6 KiB
C#

using PowderCoating.Core.Enums;
namespace PowderCoating.Application.DTOs.Accounting;
// ── Profit & Loss ─────────────────────────────────────────────────────────────
public class ProfitAndLossDto
{
public DateTime From { get; set; }
public DateTime To { get; set; }
public string CompanyName { get; set; } = string.Empty;
public List<FinancialReportLine> RevenueLines { get; set; } = new();
public decimal TotalRevenue { get; set; }
public List<FinancialReportLine> CogsLines { get; set; } = new();
public decimal TotalCogs { get; set; }
public decimal GrossProfit => TotalRevenue - TotalCogs;
public decimal GrossMarginPercent => TotalRevenue == 0 ? 0 : Math.Round(GrossProfit / TotalRevenue * 100, 1);
public List<FinancialReportLine> ExpenseLines { get; set; } = new();
public decimal TotalExpenses { get; set; }
public decimal OperatingIncome => GrossProfit - TotalExpenses;
public decimal NetIncome => OperatingIncome; // Extend later for other income/tax
}
public class FinancialReportLine
{
public int AccountId { get; set; }
public string AccountNumber { get; set; } = string.Empty;
public string AccountName { get; set; } = string.Empty;
public decimal Amount { get; set; }
}
// ── Balance Sheet ─────────────────────────────────────────────────────────────
public class BalanceSheetDto
{
public DateTime AsOf { get; set; }
public string CompanyName { get; set; } = string.Empty;
// Assets
public List<FinancialReportLine> CurrentAssets { get; set; } = new();
public List<FinancialReportLine> FixedAssets { get; set; } = new();
public List<FinancialReportLine> OtherAssets { get; set; } = new();
public decimal TotalAssets { get; set; }
// Liabilities
public List<FinancialReportLine> CurrentLiabilities { get; set; } = new();
public List<FinancialReportLine> LongTermLiabilities { get; set; } = new();
public decimal TotalLiabilities { get; set; }
// Equity
public List<FinancialReportLine> EquityLines { get; set; } = new();
public decimal RetainedEarnings { get; set; } // Computed net income to date
public decimal TotalEquity { get; set; }
public decimal TotalLiabilitiesAndEquity => TotalLiabilities + TotalEquity;
// Helper: is the sheet balanced?
public bool IsBalanced => Math.Abs(TotalAssets - TotalLiabilitiesAndEquity) < 0.01m;
}
// ── AR Aging ──────────────────────────────────────────────────────────────────
public class ArAgingReportDto
{
public DateTime AsOf { get; set; }
public string CompanyName { get; set; } = string.Empty;
public List<ArAgingCustomerDto> Customers { get; set; } = new();
public decimal TotalCurrent { get; set; }
public decimal Total1to30 { get; set; }
public decimal Total31to60 { get; set; }
public decimal Total61to90 { get; set; }
public decimal TotalOver90 { get; set; }
public decimal TotalOutstanding => TotalCurrent + Total1to30 + Total31to60 + Total61to90 + TotalOver90;
}
public class ArAgingCustomerDto
{
public int CustomerId { get; set; }
public string CustomerName { get; set; } = string.Empty;
public List<ArAgingInvoiceDto> Invoices { get; set; } = new();
public decimal TotalCurrent { get; set; }
public decimal Total1to30 { get; set; }
public decimal Total31to60 { get; set; }
public decimal Total61to90 { get; set; }
public decimal TotalOver90 { get; set; }
public decimal TotalBalance => TotalCurrent + Total1to30 + Total31to60 + Total61to90 + TotalOver90;
}
public class ArAgingInvoiceDto
{
public int InvoiceId { get; set; }
public string InvoiceNumber { get; set; } = string.Empty;
public DateTime InvoiceDate { get; set; }
public DateTime? DueDate { get; set; }
public decimal BalanceDue { get; set; }
public int DaysOverdue { get; set; }
}
// ── Sales & Income ────────────────────────────────────────────────────────────
public class SalesIncomeReportDto
{
public DateTime From { get; set; }
public DateTime To { get; set; }
public string CompanyName { get; set; } = string.Empty;
public decimal TotalInvoiced { get; set; }
public decimal TotalCollected { get; set; }
public decimal TotalTax { get; set; }
public decimal TotalDiscount { get; set; }
public decimal NetRevenue => TotalInvoiced - TotalDiscount;
public int InvoiceCount { get; set; }
public int CustomerCount { get; set; }
public decimal AverageInvoiceValue => InvoiceCount == 0 ? 0 : Math.Round(TotalInvoiced / InvoiceCount, 2);
public List<SalesByCustomerDto> ByCustomer { get; set; } = new();
public List<SalesByMonthDto> ByMonth { get; set; } = new();
public List<SalesInvoiceLineDto> Invoices { get; set; } = new();
}
public class SalesByCustomerDto
{
public int CustomerId { get; set; }
public string CustomerName { get; set; } = string.Empty;
public int InvoiceCount { get; set; }
public decimal TotalInvoiced { get; set; }
public decimal TotalPaid { get; set; }
public decimal BalanceDue { get; set; }
}
public class SalesByMonthDto
{
public int Year { get; set; }
public int Month { get; set; }
public string Label { get; set; } = string.Empty;
public decimal TotalInvoiced { get; set; }
public decimal TotalCollected { get; set; }
public int InvoiceCount { get; set; }
}
public class SalesInvoiceLineDto
{
public int InvoiceId { get; set; }
public string InvoiceNumber { get; set; } = string.Empty;
public string CustomerName { get; set; } = string.Empty;
public DateTime InvoiceDate { get; set; }
public DateTime? DueDate { get; set; }
public string Status { get; set; } = string.Empty;
public decimal SubTotal { get; set; }
public decimal TaxAmount { get; set; }
public decimal Total { get; set; }
public decimal AmountPaid { get; set; }
public decimal BalanceDue { get; set; }
}
// ============================================================
// SALES TAX REPORT
// ============================================================
public class SalesTaxReportDto
{
public DateTime From { get; set; }
public DateTime To { get; set; }
public string CompanyName { get; set; } = string.Empty;
/// <summary>Subtotal of invoices where TaxAmount > 0.</summary>
public decimal TotalTaxableSales { get; set; }
/// <summary>Subtotal of invoices where TaxAmount == 0.</summary>
public decimal TotalNonTaxableSales { get; set; }
/// <summary>Sum of all TaxAmount values across the period.</summary>
public decimal TotalTaxBilled { get; set; }
public int TaxableInvoiceCount { get; set; }
public int NonTaxableInvoiceCount { get; set; }
public decimal EffectiveTaxRate => TotalTaxableSales == 0 ? 0
: Math.Round(TotalTaxBilled / TotalTaxableSales * 100, 2);
public List<SalesTaxByAccountDto> ByAccount { get; set; } = new();
public List<SalesTaxByMonthDto> ByMonth { get; set; } = new();
public List<SalesTaxInvoiceLineDto> Invoices { get; set; } = new();
}
public class SalesTaxByAccountDto
{
public int? AccountId { get; set; }
public string AccountName { get; set; } = string.Empty;
public string AccountNumber { get; set; } = string.Empty;
public decimal TaxableSales { get; set; }
public decimal TaxBilled { get; set; }
public int InvoiceCount { get; set; }
}
public class SalesTaxByMonthDto
{
public int Year { get; set; }
public int Month { get; set; }
public string Label { get; set; } = string.Empty;
public decimal TaxableSales { get; set; }
public decimal TaxBilled { get; set; }
public int InvoiceCount { get; set; }
}
public class SalesTaxInvoiceLineDto
{
public int InvoiceId { get; set; }
public string InvoiceNumber { get; set; } = string.Empty;
public string CustomerName { get; set; } = string.Empty;
public DateTime InvoiceDate { get; set; }
public string Status { get; set; } = string.Empty;
public decimal SubTotal { get; set; }
public decimal TaxPercent { get; set; }
public decimal TaxAmount { get; set; }
public decimal Total { get; set; }
public decimal AmountPaid { get; set; }
public decimal BalanceDue { get; set; }
public string TaxAccountName { get; set; } = string.Empty;
}