Initial commit
This commit is contained in:
@@ -0,0 +1,236 @@
|
||||
@model List<PowderCoating.Application.DTOs.Accounting.BillExpenseListDto>
|
||||
|
||||
@{
|
||||
ViewData["Title"] = "Bills / Expenses";
|
||||
ViewData["PageIcon"] = "bi-receipt-cutoff";
|
||||
}
|
||||
|
||||
<div class="d-flex justify-content-end mb-4">
|
||||
<div class="btn-group">
|
||||
<a asp-controller="Bills" asp-action="Create" class="btn btn-primary">
|
||||
<i class="bi bi-plus-lg me-1"></i>New Bill
|
||||
</a>
|
||||
<button type="button" class="btn btn-primary dropdown-toggle dropdown-toggle-split" data-bs-toggle="dropdown">
|
||||
<span class="visually-hidden">Toggle dropdown</span>
|
||||
</button>
|
||||
<ul class="dropdown-menu dropdown-menu-end">
|
||||
<li>
|
||||
<a asp-controller="Bills" asp-action="Create" class="dropdown-item">
|
||||
<i class="bi bi-file-text me-2"></i>New Bill <span class="text-muted small">(pay later)</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a asp-controller="Expenses" asp-action="Create" class="dropdown-item">
|
||||
<i class="bi bi-receipt me-2"></i>New Expense <span class="text-muted small">(already paid)</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if (TempData["Success"] != null)
|
||||
{
|
||||
<div class="alert alert-success alert-dismissible fade show">
|
||||
<i class="bi bi-check-circle me-2"></i>@TempData["Success"]
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
||||
</div>
|
||||
}
|
||||
@if (TempData["Error"] != null)
|
||||
{
|
||||
<div class="alert alert-danger alert-dismissible fade show">
|
||||
<i class="bi bi-exclamation-triangle me-2"></i>@TempData["Error"]
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
||||
</div>
|
||||
}
|
||||
|
||||
@if ((decimal)ViewBag.TotalOwed > 0)
|
||||
{
|
||||
<div class="alert alert-warning d-flex align-items-center gap-2 mb-4">
|
||||
<i class="bi bi-exclamation-circle fs-5"></i>
|
||||
<span>Outstanding bills: <strong>@(((decimal)ViewBag.TotalOwed).ToString("C"))</strong></span>
|
||||
<a asp-action="Index" asp-route-status="Unpaid" class="btn btn-sm btn-warning ms-auto">
|
||||
<i class="bi bi-funnel me-1"></i>Show unpaid
|
||||
</a>
|
||||
</div>
|
||||
}
|
||||
|
||||
<div class="card shadow-sm mb-3">
|
||||
<div class="card-body py-2">
|
||||
<form method="get" class="row g-2 align-items-end">
|
||||
<div class="col-md-4">
|
||||
<input type="search" name="search" value="@ViewBag.Search" class="form-control"
|
||||
placeholder="Search by #, vendor, memo, amount…" />
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<select name="type" class="form-select">
|
||||
<option value="">Bills & Expenses</option>
|
||||
<option value="Bill" selected="@(ViewBag.TypeFilter == "Bill")">Bills only</option>
|
||||
<option value="Expense" selected="@(ViewBag.TypeFilter == "Expense")">Expenses only</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<select name="status" class="form-select">
|
||||
<option value="">All statuses</option>
|
||||
<option value="Unpaid" selected="@(ViewBag.StatusFilter == "Unpaid")">Unpaid</option>
|
||||
<option value="Overdue" selected="@(ViewBag.StatusFilter == "Overdue")">Overdue</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<button type="submit" class="btn btn-outline-primary">
|
||||
<i class="bi bi-search me-1"></i>Filter
|
||||
</button>
|
||||
<a asp-action="Index" class="btn btn-outline-secondary ms-1">Clear</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if (Model.Any())
|
||||
{
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-body p-0">
|
||||
<table class="table table-hover mb-0">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th style="width:90px">Type</th>
|
||||
<th>Number</th>
|
||||
<th>Vendor</th>
|
||||
<th>Memo / Account</th>
|
||||
<th>Date</th>
|
||||
<th>Due Date</th>
|
||||
<th>Status</th>
|
||||
<th class="text-end">Amount</th>
|
||||
<th class="text-end">Balance Due</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var entry in Model)
|
||||
{
|
||||
<tr class="@(entry.IsOverdue ? "table-warning" : "")">
|
||||
<td>
|
||||
@if (entry.EntryType == "Bill")
|
||||
{
|
||||
<span class="badge bg-primary-subtle text-primary border border-primary-subtle">
|
||||
<i class="bi bi-file-text me-1"></i>Bill
|
||||
</span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<span class="badge bg-secondary-subtle text-secondary border border-secondary-subtle">
|
||||
<i class="bi bi-receipt me-1"></i>Expense
|
||||
</span>
|
||||
}
|
||||
</td>
|
||||
<td>
|
||||
@if (entry.EntryType == "Bill")
|
||||
{
|
||||
<a asp-controller="Bills" asp-action="Details" asp-route-id="@entry.Id"
|
||||
class="fw-medium text-decoration-none">@entry.Number</a>
|
||||
}
|
||||
else
|
||||
{
|
||||
<a asp-controller="Expenses" asp-action="Details" asp-route-id="@entry.Id"
|
||||
class="fw-medium text-decoration-none">@entry.Number</a>
|
||||
}
|
||||
</td>
|
||||
<td>@entry.VendorName</td>
|
||||
<td class="text-muted small">
|
||||
@(entry.EntryType == "Bill" ? entry.Memo : entry.AccountName)
|
||||
@if (entry.HasReceipt)
|
||||
{
|
||||
<i class="bi bi-paperclip ms-1" title="Has receipt"></i>
|
||||
}
|
||||
</td>
|
||||
<td>@entry.Date.ToString("MMM d, yyyy")</td>
|
||||
<td>
|
||||
@if (entry.DueDate.HasValue)
|
||||
{
|
||||
<span class="@(entry.IsOverdue ? "text-danger fw-medium" : "")">
|
||||
@entry.DueDate.Value.ToString("MMM d, yyyy")
|
||||
@if (entry.IsOverdue) { <i class="bi bi-exclamation-circle ms-1"></i> }
|
||||
</span>
|
||||
}
|
||||
else if (entry.EntryType == "Expense")
|
||||
{
|
||||
<span class="text-muted">—</span>
|
||||
}
|
||||
</td>
|
||||
<td><span class="badge bg-@entry.StatusColor">@entry.StatusLabel</span></td>
|
||||
<td class="text-end">@entry.Total.ToString("C")</td>
|
||||
<td class="text-end fw-medium @(entry.BalanceDue > 0 ? "text-danger" : "text-muted")">
|
||||
@(entry.EntryType == "Bill" ? entry.BalanceDue.ToString("C") : "—")
|
||||
</td>
|
||||
<td>
|
||||
@if (entry.EntryType == "Bill")
|
||||
{
|
||||
<a asp-controller="Bills" asp-action="Details" asp-route-id="@entry.Id"
|
||||
class="btn btn-sm btn-outline-primary"><i class="bi bi-eye"></i></a>
|
||||
}
|
||||
else
|
||||
{
|
||||
<a asp-controller="Expenses" asp-action="Details" asp-route-id="@entry.Id"
|
||||
class="btn btn-sm btn-outline-secondary"><i class="bi bi-eye"></i></a>
|
||||
}
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="text-center py-5 text-muted">
|
||||
<i class="bi bi-inbox fs-1 d-block mb-2"></i>
|
||||
No entries found.
|
||||
<div class="mt-2">
|
||||
<a asp-controller="Bills" asp-action="Create" class="btn btn-primary btn-sm me-2">
|
||||
<i class="bi bi-plus-lg me-1"></i>New Bill
|
||||
</a>
|
||||
<a asp-controller="Expenses" asp-action="Create" class="btn btn-outline-secondary btn-sm">
|
||||
<i class="bi bi-plus-lg me-1"></i>New Expense
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
@if ((int)ViewBag.TotalPages > 1)
|
||||
{
|
||||
<nav class="mt-3">
|
||||
<ul class="pagination justify-content-center">
|
||||
<li class="page-item @((int)ViewBag.Page <= 1 ? "disabled" : "")">
|
||||
<a class="page-link" asp-action="Index"
|
||||
asp-route-type="@ViewBag.TypeFilter"
|
||||
asp-route-status="@ViewBag.StatusFilter"
|
||||
asp-route-search="@ViewBag.Search"
|
||||
asp-route-page="@((int)ViewBag.Page - 1)"
|
||||
asp-route-pageSize="@ViewBag.PageSize">‹ Prev</a>
|
||||
</li>
|
||||
@for (var p = 1; p <= (int)ViewBag.TotalPages; p++)
|
||||
{
|
||||
<li class="page-item @(p == (int)ViewBag.Page ? "active" : "")">
|
||||
<a class="page-link" asp-action="Index"
|
||||
asp-route-type="@ViewBag.TypeFilter"
|
||||
asp-route-status="@ViewBag.StatusFilter"
|
||||
asp-route-search="@ViewBag.Search"
|
||||
asp-route-page="@p"
|
||||
asp-route-pageSize="@ViewBag.PageSize">@p</a>
|
||||
</li>
|
||||
}
|
||||
<li class="page-item @((int)ViewBag.Page >= (int)ViewBag.TotalPages ? "disabled" : "")">
|
||||
<a class="page-link" asp-action="Index"
|
||||
asp-route-type="@ViewBag.TypeFilter"
|
||||
asp-route-status="@ViewBag.StatusFilter"
|
||||
asp-route-search="@ViewBag.Search"
|
||||
asp-route-page="@((int)ViewBag.Page + 1)"
|
||||
asp-route-pageSize="@ViewBag.PageSize">Next ›</a>
|
||||
</li>
|
||||
</ul>
|
||||
<p class="text-center text-muted small">
|
||||
Showing @(((int)ViewBag.Page - 1) * (int)ViewBag.PageSize + 1)–@(Math.Min((int)ViewBag.Page * (int)ViewBag.PageSize, (int)ViewBag.TotalCount))
|
||||
of @ViewBag.TotalCount entries
|
||||
</p>
|
||||
</nav>
|
||||
}
|
||||
Reference in New Issue
Block a user