Initial commit
This commit is contained in:
@@ -0,0 +1,216 @@
|
||||
@model PowderCoating.Application.DTOs.Accounting.ProfitAndLossDto
|
||||
@{
|
||||
ViewData["Title"] = "Profit & Loss";
|
||||
ViewData["PageIcon"] = "bi-graph-up-arrow";
|
||||
var today = DateTime.Today;
|
||||
var ytdFrom = new DateTime(today.Year, 1, 1).ToString("yyyy-MM-dd");
|
||||
var ytdTo = today.ToString("yyyy-MM-dd");
|
||||
var q1From = new DateTime(today.Year, 1, 1).ToString("yyyy-MM-dd");
|
||||
var q1To = new DateTime(today.Year, 3, 31).ToString("yyyy-MM-dd");
|
||||
var lastYrFrom = new DateTime(today.Year - 1, 1, 1).ToString("yyyy-MM-dd");
|
||||
var lastYrTo = new DateTime(today.Year - 1, 12, 31).ToString("yyyy-MM-dd");
|
||||
var thisMonthFrom = new DateTime(today.Year, today.Month, 1).ToString("yyyy-MM-dd");
|
||||
var thisMonthTo = today.ToString("yyyy-MM-dd");
|
||||
}
|
||||
|
||||
<style>
|
||||
@@media print {
|
||||
.no-print { display: none !important; }
|
||||
.card { border: 1px solid #dee2e6 !important; box-shadow: none !important; }
|
||||
body { font-size: 12px; }
|
||||
}
|
||||
.report-section-header { background: #f8f9fa; font-weight: 600; }
|
||||
.report-total-row { border-top: 2px solid #dee2e6; font-weight: 700; }
|
||||
.report-subtotal-row { border-top: 1px solid #dee2e6; font-weight: 600; }
|
||||
.report-net-row { background: #e8f5e9; font-weight: 700; font-size: 1.05em; }
|
||||
.report-net-negative { background: #fdecea; }
|
||||
</style>
|
||||
|
||||
<!-- Header -->
|
||||
<div class="d-flex align-items-center gap-2 mb-3 no-print">
|
||||
<a asp-action="Index" class="btn btn-sm btn-outline-secondary"><i class="bi bi-arrow-left"></i></a>
|
||||
<p class="text-muted mb-0">Income Statement — @Model.From.ToString("MMM d") – @Model.To.ToString("MMM d, yyyy")</p>
|
||||
<div class="ms-auto d-flex gap-2">
|
||||
<a href="@Url.Action("ProfitAndLossPdf", new { from = Model.From.ToString("yyyy-MM-dd"), to = Model.To.ToString("yyyy-MM-dd") })"
|
||||
class="btn btn-sm btn-outline-danger no-print" target="_blank">
|
||||
<i class="bi bi-file-pdf me-1"></i>Download PDF
|
||||
</a>
|
||||
<a href="@Url.Action("ProfitAndLossPdf", new { from = Model.From.ToString("yyyy-MM-dd"), to = Model.To.ToString("yyyy-MM-dd"), inline = true })"
|
||||
class="btn btn-sm btn-outline-secondary no-print" target="_blank">
|
||||
<i class="bi bi-printer me-1"></i>Print
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Date filter -->
|
||||
<div class="card shadow-sm mb-4 no-print">
|
||||
<div class="card-body py-3">
|
||||
<form method="get" class="row g-2 align-items-end">
|
||||
<div class="col-auto">
|
||||
<label class="form-label form-label-sm mb-1">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 form-label-sm mb-1">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-primary btn-sm"><i class="bi bi-funnel me-1"></i>Run Report</button>
|
||||
</div>
|
||||
<div class="col-auto ms-2">
|
||||
<div class="btn-group btn-group-sm">
|
||||
<a href="@Url.Action("ProfitAndLoss", new { from = thisMonthFrom, to = thisMonthTo })" class="btn btn-outline-secondary">This Month</a>
|
||||
<a href="@Url.Action("ProfitAndLoss", new { from = ytdFrom, to = ytdTo })" class="btn btn-outline-secondary">YTD</a>
|
||||
<a href="@Url.Action("ProfitAndLoss", new { from = lastYrFrom, to = lastYrTo })" class="btn btn-outline-secondary">Last Year</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Print header -->
|
||||
<div class="text-center mb-4 d-none d-print-block">
|
||||
<h4 class="fw-bold">@Model.CompanyName</h4>
|
||||
<h5>Profit & Loss</h5>
|
||||
<p class="text-muted">@Model.From.ToString("MMMM d, yyyy") – @Model.To.ToString("MMMM d, yyyy")</p>
|
||||
</div>
|
||||
|
||||
<!-- KPI Summary -->
|
||||
<div class="row g-3 mb-4 no-print">
|
||||
<div class="col-6 col-md-3">
|
||||
<div class="card shadow-sm text-center h-100">
|
||||
<div class="card-body py-3">
|
||||
<div class="h5 text-success mb-1">@Model.TotalRevenue.ToString("C")</div>
|
||||
<div class="text-muted small">Total Revenue</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-6 col-md-3">
|
||||
<div class="card shadow-sm text-center h-100">
|
||||
<div class="card-body py-3">
|
||||
<div class="h5 text-warning mb-1">@Model.TotalCogs.ToString("C")</div>
|
||||
<div class="text-muted small">Cost of Goods</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-6 col-md-3">
|
||||
<div class="card shadow-sm text-center h-100">
|
||||
<div class="card-body py-3">
|
||||
<div class="h5 text-danger mb-1">@Model.TotalExpenses.ToString("C")</div>
|
||||
<div class="text-muted small">Operating Expenses</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-6 col-md-3">
|
||||
<div class="card shadow-sm text-center h-100 @(Model.NetIncome >= 0 ? "border-success border-opacity-50" : "border-danger border-opacity-50")">
|
||||
<div class="card-body py-3">
|
||||
<div class="h5 fw-bold @(Model.NetIncome >= 0 ? "text-success" : "text-danger") mb-1">@Model.NetIncome.ToString("C")</div>
|
||||
<div class="text-muted small">Net Income</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- P&L Statement -->
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
<span class="fw-semibold"><i class="bi bi-file-earmark-bar-graph me-1"></i>Income Statement</span>
|
||||
<span class="text-muted small">@Model.From.ToString("MMM d") – @Model.To.ToString("MMM d, yyyy")</span>
|
||||
</div>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-sm align-middle mb-0">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>Account</th>
|
||||
<th class="text-end" style="width:160px">Amount</th>
|
||||
<th class="text-end" style="width:120px">% of Revenue</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<!-- Revenue -->
|
||||
<tr class="report-section-header">
|
||||
<td colspan="3" class="py-2"><i class="bi bi-graph-up-arrow text-success me-2"></i>Revenue</td>
|
||||
</tr>
|
||||
@if (!Model.RevenueLines.Any())
|
||||
{
|
||||
<tr><td colspan="3" class="text-muted ps-4 small">No revenue recorded for this period.</td></tr>
|
||||
}
|
||||
@foreach (var line in Model.RevenueLines)
|
||||
{
|
||||
<tr>
|
||||
<td class="ps-4">@line.AccountNumber <span class="text-muted">@line.AccountName</span></td>
|
||||
<td class="text-end">@line.Amount.ToString("C")</td>
|
||||
<td class="text-end text-muted small">@(Model.TotalRevenue == 0 ? "—" : (line.Amount / Model.TotalRevenue * 100).ToString("F1") + "%")</td>
|
||||
</tr>
|
||||
}
|
||||
<tr class="report-subtotal-row">
|
||||
<td class="ps-4 fw-semibold">Total Revenue</td>
|
||||
<td class="text-end fw-semibold text-success">@Model.TotalRevenue.ToString("C")</td>
|
||||
<td class="text-end text-muted small">100%</td>
|
||||
</tr>
|
||||
|
||||
<!-- COGS -->
|
||||
@if (Model.CogsLines.Any())
|
||||
{
|
||||
<tr><td colspan="3" class="py-1"></td></tr>
|
||||
<tr class="report-section-header">
|
||||
<td colspan="3" class="py-2"><i class="bi bi-box-seam text-warning me-2"></i>Cost of Goods Sold</td>
|
||||
</tr>
|
||||
@foreach (var line in Model.CogsLines)
|
||||
{
|
||||
<tr>
|
||||
<td class="ps-4">@line.AccountNumber <span class="text-muted">@line.AccountName</span></td>
|
||||
<td class="text-end">@line.Amount.ToString("C")</td>
|
||||
<td class="text-end text-muted small">@(Model.TotalRevenue == 0 ? "—" : (line.Amount / Model.TotalRevenue * 100).ToString("F1") + "%")</td>
|
||||
</tr>
|
||||
}
|
||||
<tr class="report-subtotal-row">
|
||||
<td class="ps-4 fw-semibold">Total COGS</td>
|
||||
<td class="text-end fw-semibold text-warning">(@Model.TotalCogs.ToString("C"))</td>
|
||||
<td class="text-end text-muted small">@(Model.TotalRevenue == 0 ? "—" : (Model.TotalCogs / Model.TotalRevenue * 100).ToString("F1") + "%")</td>
|
||||
</tr>
|
||||
<tr class="report-subtotal-row">
|
||||
<td class="ps-2 fw-semibold">Gross Profit</td>
|
||||
<td class="text-end fw-semibold @(Model.GrossProfit >= 0 ? "text-success" : "text-danger")">@Model.GrossProfit.ToString("C")</td>
|
||||
<td class="text-end text-muted small">@(Model.TotalRevenue == 0 ? "—" : Model.GrossMarginPercent.ToString("F1") + "%")</td>
|
||||
</tr>
|
||||
}
|
||||
|
||||
<!-- Expenses -->
|
||||
<tr><td colspan="3" class="py-1"></td></tr>
|
||||
<tr class="report-section-header">
|
||||
<td colspan="3" class="py-2"><i class="bi bi-receipt-cutoff text-danger me-2"></i>Operating Expenses</td>
|
||||
</tr>
|
||||
@if (!Model.ExpenseLines.Any())
|
||||
{
|
||||
<tr><td colspan="3" class="text-muted ps-4 small">No expenses recorded for this period.</td></tr>
|
||||
}
|
||||
@foreach (var line in Model.ExpenseLines)
|
||||
{
|
||||
<tr>
|
||||
<td class="ps-4">@line.AccountNumber <span class="text-muted">@line.AccountName</span></td>
|
||||
<td class="text-end">@line.Amount.ToString("C")</td>
|
||||
<td class="text-end text-muted small">@(Model.TotalRevenue == 0 ? "—" : (line.Amount / Model.TotalRevenue * 100).ToString("F1") + "%")</td>
|
||||
</tr>
|
||||
}
|
||||
<tr class="report-subtotal-row">
|
||||
<td class="ps-4 fw-semibold">Total Expenses</td>
|
||||
<td class="text-end fw-semibold text-danger">(@Model.TotalExpenses.ToString("C"))</td>
|
||||
<td class="text-end text-muted small">@(Model.TotalRevenue == 0 ? "—" : (Model.TotalExpenses / Model.TotalRevenue * 100).ToString("F1") + "%")</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr class="report-net-row @(Model.NetIncome < 0 ? "report-net-negative" : "")">
|
||||
<td class="ps-2">Net Income</td>
|
||||
<td class="text-end @(Model.NetIncome >= 0 ? "text-success" : "text-danger")">@Model.NetIncome.ToString("C")</td>
|
||||
<td class="text-end text-muted small">@(Model.TotalRevenue == 0 ? "—" : (Model.NetIncome / Model.TotalRevenue * 100).ToString("F1") + "%")</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="text-muted small mt-2 no-print">
|
||||
<i class="bi bi-info-circle me-1"></i>
|
||||
Generated @DateTime.Now.ToString("MMM d, yyyy h:mm tt") · Accrual basis · Revenue from sent/paid invoices; expenses from bills and direct expenses.
|
||||
</div>
|
||||
Reference in New Issue
Block a user