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>
This commit is contained in:
@@ -1124,6 +1124,74 @@ public class ReportsController : Controller
|
||||
return inline ? File(pdfBytes, "application/pdf") : File(pdfBytes, "application/pdf", $"SalesAndIncome-{fromDate:yyyyMMdd}-{toDate:yyyyMMdd}.pdf");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sales Tax Liability report (invoice basis). Shows taxable vs non-taxable sales,
|
||||
/// total tax billed, breakdown by tax account and by month, and a full invoice detail grid.
|
||||
/// Gated behind <see cref="AllowAccounting"/>.
|
||||
/// </summary>
|
||||
// GET: /Reports/SalesTax
|
||||
public async Task<IActionResult> SalesTax(DateTime? from, DateTime? to)
|
||||
{
|
||||
if (!AllowAccounting()) return RedirectToAction(nameof(Landing));
|
||||
var fromDate = (from ?? new DateTime(DateTime.Today.Year, 1, 1)).Date;
|
||||
var toDate = (to ?? DateTime.Today).Date;
|
||||
var companyId = int.TryParse(User.FindFirst("CompanyId")?.Value, out var cid) ? cid : 0;
|
||||
var dto = await _financialReports.GetSalesTaxReportAsync(companyId, fromDate, toDate);
|
||||
return View(dto);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// PDF export of the Sales Tax Liability report. Same inline/attachment pattern as other PDF actions.
|
||||
/// Gated behind <see cref="AllowAccounting"/>.
|
||||
/// </summary>
|
||||
// GET: /Reports/SalesTaxPdf
|
||||
public async Task<IActionResult> SalesTaxPdf(DateTime? from, DateTime? to, bool inline = false)
|
||||
{
|
||||
if (!AllowAccounting()) return RedirectToAction(nameof(Landing));
|
||||
var fromDate = (from ?? new DateTime(DateTime.Today.Year, 1, 1)).Date;
|
||||
var toDate = (to ?? DateTime.Today).Date;
|
||||
var companyId = int.TryParse(User.FindFirst("CompanyId")?.Value, out var cid) ? cid : 0;
|
||||
var dto = await _financialReports.GetSalesTaxReportAsync(companyId, fromDate, toDate);
|
||||
var pdfBytes = await _pdfService.GenerateSalesTaxReportPdfAsync(dto);
|
||||
return inline ? File(pdfBytes, "application/pdf") : File(pdfBytes, "application/pdf", $"SalesTaxReport-{fromDate:yyyyMMdd}-{toDate:yyyyMMdd}.pdf");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// CSV export of the Sales Tax Liability report. Returns one row per invoice, suitable
|
||||
/// for handing to an accountant or importing into tax filing software.
|
||||
/// Gated behind <see cref="AllowAccounting"/>.
|
||||
/// </summary>
|
||||
// GET: /Reports/SalesTaxCsv
|
||||
public async Task<IActionResult> SalesTaxCsv(DateTime? from, DateTime? to)
|
||||
{
|
||||
if (!AllowAccounting()) return RedirectToAction(nameof(Landing));
|
||||
var fromDate = (from ?? new DateTime(DateTime.Today.Year, 1, 1)).Date;
|
||||
var toDate = (to ?? DateTime.Today).Date;
|
||||
var companyId = int.TryParse(User.FindFirst("CompanyId")?.Value, out var cid) ? cid : 0;
|
||||
var dto = await _financialReports.GetSalesTaxReportAsync(companyId, fromDate, toDate);
|
||||
|
||||
var sb = new System.Text.StringBuilder();
|
||||
sb.AppendLine("Invoice #,Customer,Date,Status,Subtotal,Tax %,Tax Amount,Total,Amount Paid,Balance Due,Tax Account");
|
||||
foreach (var inv in dto.Invoices)
|
||||
{
|
||||
sb.AppendLine(string.Join(",",
|
||||
$"\"{inv.InvoiceNumber}\"",
|
||||
$"\"{inv.CustomerName.Replace("\"", "\"\"")}\"",
|
||||
inv.InvoiceDate.ToString("yyyy-MM-dd"),
|
||||
$"\"{inv.Status}\"",
|
||||
inv.SubTotal.ToString("F2"),
|
||||
inv.TaxPercent.ToString("F4"),
|
||||
inv.TaxAmount.ToString("F2"),
|
||||
inv.Total.ToString("F2"),
|
||||
inv.AmountPaid.ToString("F2"),
|
||||
inv.BalanceDue.ToString("F2"),
|
||||
$"\"{inv.TaxAccountName.Replace("\"", "\"\"")}\""));
|
||||
}
|
||||
|
||||
var bytes = System.Text.Encoding.UTF8.GetPreamble().Concat(System.Text.Encoding.UTF8.GetBytes(sb.ToString())).ToArray();
|
||||
return File(bytes, "text/csv", $"SalesTaxReport-{fromDate:yyyyMMdd}-{toDate:yyyyMMdd}.csv");
|
||||
}
|
||||
|
||||
// ── INDIVIDUAL REPORT PAGES ──────────────────────────────────────────────
|
||||
|
||||
/// <summary>
|
||||
|
||||
Reference in New Issue
Block a user