Phase H: Add Cash Flow Statement (direct / cash-basis method)
- CashFlowStatementDto (Operating, Investing, Financing sections; BeginningCash/EndingCash) - CashFlowLineDto for Investing/Financing line items - GetCashFlowStatementAsync on IFinancialReportService + implementation in FinancialReportService - GenerateCashFlowStatementPdfAsync on IPdfService + QuestPDF implementation in PdfService - ReportsController.CashFlowStatement GET + CashFlowStatementPdf GET with inline/download mode - CashFlowStatement.cshtml view with date filter, 3-section cards, summary sidebar, methodology note - Reports Landing page: Cash Flow Statement card added to Accounting section Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,224 @@
|
||||
@model PowderCoating.Application.DTOs.Accounting.CashFlowStatementDto
|
||||
@using PowderCoating.Core.Enums
|
||||
@{
|
||||
ViewData["Title"] = "Cash Flow Statement";
|
||||
|
||||
string AmountClass(decimal v) => v < 0 ? "text-danger" : "text-body";
|
||||
string Fmt(decimal v) => v.ToString("C");
|
||||
}
|
||||
|
||||
<div class="d-flex align-items-center justify-content-between mb-4">
|
||||
<div>
|
||||
<h4 class="fw-bold mb-0"><i class="bi bi-water me-2 text-info"></i>Cash Flow Statement</h4>
|
||||
<p class="text-muted small mb-0">
|
||||
@Model.From.ToString("MMMM d, yyyy") – @Model.To.ToString("MMMM d, yyyy")
|
||||
· Direct Method (Cash Basis)
|
||||
</p>
|
||||
</div>
|
||||
<div class="d-flex gap-2">
|
||||
<a asp-action="CashFlowStatementPdf"
|
||||
asp-route-from="@Model.From.ToString("yyyy-MM-dd")"
|
||||
asp-route-to="@Model.To.ToString("yyyy-MM-dd")"
|
||||
class="btn btn-outline-secondary btn-sm">
|
||||
<i class="bi bi-download me-1"></i>PDF
|
||||
</a>
|
||||
<a asp-action="CashFlowStatementPdf"
|
||||
asp-route-from="@Model.From.ToString("yyyy-MM-dd")"
|
||||
asp-route-to="@Model.To.ToString("yyyy-MM-dd")"
|
||||
asp-route-inline="true"
|
||||
target="_blank"
|
||||
class="btn btn-outline-primary btn-sm">
|
||||
<i class="bi bi-eye me-1"></i>Preview
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Date range filter -->
|
||||
<form method="get" asp-action="CashFlowStatement" class="card shadow-sm mb-4">
|
||||
<div class="card-body">
|
||||
<div class="row g-3 align-items-end">
|
||||
<div class="col-auto">
|
||||
<label class="form-label fw-semibold small">From</label>
|
||||
<input type="date" name="from" class="form-control form-control-sm" value="@Model.From.ToString("yyyy-MM-dd")" />
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<label class="form-label fw-semibold small">To</label>
|
||||
<input type="date" name="to" class="form-control form-control-sm" value="@Model.To.ToString("yyyy-MM-dd")" />
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<button type="submit" class="btn btn-sm btn-primary">Update</button>
|
||||
</div>
|
||||
<!-- Quick date presets -->
|
||||
@{
|
||||
var y = DateTime.Today.Year;
|
||||
var presets = new[]
|
||||
{
|
||||
("YTD", new DateTime(y, 1, 1).ToString("yyyy-MM-dd"), DateTime.Today.ToString("yyyy-MM-dd")),
|
||||
("This Qtr", new DateTime(y, ((DateTime.Today.Month - 1) / 3) * 3 + 1, 1).ToString("yyyy-MM-dd"), DateTime.Today.ToString("yyyy-MM-dd")),
|
||||
("Last Year", new DateTime(y-1, 1, 1).ToString("yyyy-MM-dd"), new DateTime(y-1, 12, 31).ToString("yyyy-MM-dd")),
|
||||
};
|
||||
}
|
||||
@foreach (var (label, f, t) in presets)
|
||||
{
|
||||
<div class="col-auto">
|
||||
<a asp-action="CashFlowStatement" asp-route-from="@f" asp-route-to="@t"
|
||||
class="btn btn-sm btn-outline-secondary">@label</a>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="row g-4">
|
||||
<!-- Main statement -->
|
||||
<div class="col-lg-8">
|
||||
|
||||
<!-- Operating Activities -->
|
||||
<div class="card shadow-sm mb-3">
|
||||
<div class="card-header d-flex align-items-center justify-content-between">
|
||||
<span class="fw-semibold"><i class="bi bi-gear me-2 text-info"></i>Operating Activities</span>
|
||||
<span class="badge @(Model.NetOperating >= 0 ? "bg-success" : "bg-danger")">@Fmt(Model.NetOperating)</span>
|
||||
</div>
|
||||
<div class="card-body p-0">
|
||||
<table class="table table-sm mb-0">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="ps-3 text-body-secondary">Cash received from customers</td>
|
||||
<td class="text-end pe-3 text-success fw-semibold">@Fmt(Model.CashFromCustomers)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="ps-3 text-body-secondary">Cash paid to vendors (bills)</td>
|
||||
<td class="text-end pe-3 @AmountClass(-Model.CashToVendors)">(@Fmt(Model.CashToVendors))</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="ps-3 text-body-secondary">Cash paid for direct expenses</td>
|
||||
<td class="text-end pe-3 @AmountClass(-Model.CashForExpenses)">(@Fmt(Model.CashForExpenses))</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<tfoot class="table-light">
|
||||
<tr>
|
||||
<td class="ps-3 fw-semibold">Net Cash from Operating Activities</td>
|
||||
<td class="text-end pe-3 fw-bold @AmountClass(Model.NetOperating)">@Fmt(Model.NetOperating)</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Investing Activities -->
|
||||
<div class="card shadow-sm mb-3">
|
||||
<div class="card-header d-flex align-items-center justify-content-between">
|
||||
<span class="fw-semibold"><i class="bi bi-building me-2 text-primary"></i>Investing Activities</span>
|
||||
<span class="badge @(Model.NetInvesting >= 0 ? "bg-success" : "bg-danger")">@Fmt(Model.NetInvesting)</span>
|
||||
</div>
|
||||
<div class="card-body p-0">
|
||||
<table class="table table-sm mb-0">
|
||||
<tbody>
|
||||
@if (!Model.InvestingLines.Any())
|
||||
{
|
||||
<tr>
|
||||
<td class="ps-3 text-muted" colspan="2">
|
||||
<i class="bi bi-dash-circle me-1"></i>No investing activities recorded in this period.
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
else
|
||||
{
|
||||
@foreach (var line in Model.InvestingLines)
|
||||
{
|
||||
<tr>
|
||||
<td class="ps-3 text-body-secondary">@line.Label</td>
|
||||
<td class="text-end pe-3 @AmountClass(line.Amount)">@Fmt(line.Amount)</td>
|
||||
</tr>
|
||||
}
|
||||
}
|
||||
</tbody>
|
||||
<tfoot class="table-light">
|
||||
<tr>
|
||||
<td class="ps-3 fw-semibold">Net Cash from Investing Activities</td>
|
||||
<td class="text-end pe-3 fw-bold @AmountClass(Model.NetInvesting)">@Fmt(Model.NetInvesting)</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Financing Activities -->
|
||||
<div class="card shadow-sm mb-3">
|
||||
<div class="card-header d-flex align-items-center justify-content-between">
|
||||
<span class="fw-semibold"><i class="bi bi-bank me-2 text-secondary"></i>Financing Activities</span>
|
||||
<span class="badge @(Model.NetFinancing >= 0 ? "bg-success" : "bg-danger")">@Fmt(Model.NetFinancing)</span>
|
||||
</div>
|
||||
<div class="card-body p-0">
|
||||
<table class="table table-sm mb-0">
|
||||
<tbody>
|
||||
@if (!Model.FinancingLines.Any())
|
||||
{
|
||||
<tr>
|
||||
<td class="ps-3 text-muted" colspan="2">
|
||||
<i class="bi bi-dash-circle me-1"></i>No financing activities recorded in this period.
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
else
|
||||
{
|
||||
@foreach (var line in Model.FinancingLines)
|
||||
{
|
||||
<tr>
|
||||
<td class="ps-3 text-body-secondary">@line.Label</td>
|
||||
<td class="text-end pe-3 @AmountClass(line.Amount)">@Fmt(line.Amount)</td>
|
||||
</tr>
|
||||
}
|
||||
}
|
||||
</tbody>
|
||||
<tfoot class="table-light">
|
||||
<tr>
|
||||
<td class="ps-3 fw-semibold">Net Cash from Financing Activities</td>
|
||||
<td class="text-end pe-3 fw-bold @AmountClass(Model.NetFinancing)">@Fmt(Model.NetFinancing)</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Summary sidebar -->
|
||||
<div class="col-lg-4">
|
||||
<div class="card shadow-sm mb-3">
|
||||
<div class="card-header fw-semibold"><i class="bi bi-calculator me-2 text-info"></i>Cash Summary</div>
|
||||
<div class="card-body">
|
||||
<dl class="row mb-0">
|
||||
<dt class="col-8 text-muted small fw-normal">Beginning Cash</dt>
|
||||
<dd class="col-4 text-end fw-semibold mb-2">@Fmt(Model.BeginningCash)</dd>
|
||||
|
||||
<dt class="col-8 text-muted small fw-normal">Operating</dt>
|
||||
<dd class="col-4 text-end fw-semibold mb-1 @AmountClass(Model.NetOperating)">@Fmt(Model.NetOperating)</dd>
|
||||
|
||||
<dt class="col-8 text-muted small fw-normal">Investing</dt>
|
||||
<dd class="col-4 text-end fw-semibold mb-1 @AmountClass(Model.NetInvesting)">@Fmt(Model.NetInvesting)</dd>
|
||||
|
||||
<dt class="col-8 text-muted small fw-normal">Financing</dt>
|
||||
<dd class="col-4 text-end fw-semibold mb-2 @AmountClass(Model.NetFinancing)">@Fmt(Model.NetFinancing)</dd>
|
||||
|
||||
<dt class="col-8 text-muted small fw-normal">Net Change in Cash</dt>
|
||||
<dd class="col-4 text-end fw-semibold mb-3 @AmountClass(Model.NetChangeInCash)">@Fmt(Model.NetChangeInCash)</dd>
|
||||
|
||||
<dt class="col-8 fw-bold">Ending Cash Balance</dt>
|
||||
<dd class="col-4 text-end fw-bold fs-5 @AmountClass(Model.EndingCash)">@Fmt(Model.EndingCash)</dd>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-header fw-semibold small"><i class="bi bi-info-circle me-2"></i>Methodology</div>
|
||||
<div class="card-body small text-muted">
|
||||
<p class="mb-2">This statement uses the <strong>direct (cash basis)</strong> method for Operating Activities:</p>
|
||||
<ul class="mb-2 ps-3">
|
||||
<li>Inflows = customer invoice payments received</li>
|
||||
<li>Outflows = vendor bill payments + direct expense payments</li>
|
||||
</ul>
|
||||
<p class="mb-0">Beginning Cash is approximated from all cash inflows and outflows recorded prior to the start date plus account opening balances. For the most accurate beginning balance, reconcile your bank accounts first.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -204,6 +204,14 @@
|
||||
<p>All active accounts with debit and credit balances — validates that your books are in balance.</p>
|
||||
<div class="report-arrow">Open report <i class="bi bi-arrow-right"></i></div>
|
||||
</a>
|
||||
<a asp-controller="Reports" asp-action="CashFlowStatement" class="report-card">
|
||||
<div class="report-card-icon" style="background:#ecfeff;color:#0891b2;">
|
||||
<i class="bi bi-water"></i>
|
||||
</div>
|
||||
<h5>Cash Flow Statement</h5>
|
||||
<p>Track actual cash in/out across operating, investing, and financing activities with beginning and ending cash balance.</p>
|
||||
<div class="report-arrow">Open report <i class="bi bi-arrow-right"></i></div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user