Initial commit
This commit is contained in:
@@ -0,0 +1,272 @@
|
||||
@using PowderCoating.Application.DTOs.PurchaseOrder
|
||||
@using PowderCoating.Core.Enums
|
||||
@model PurchaseOrderDto
|
||||
|
||||
@{
|
||||
ViewData["Title"] = $"PO {Model.PoNumber}";
|
||||
|
||||
string StatusBadge(PurchaseOrderStatus s) => s switch {
|
||||
PurchaseOrderStatus.Draft => "secondary",
|
||||
PurchaseOrderStatus.Submitted => "primary",
|
||||
PurchaseOrderStatus.PartiallyReceived => "warning",
|
||||
PurchaseOrderStatus.Received => "success",
|
||||
PurchaseOrderStatus.Cancelled => "danger",
|
||||
_ => "secondary"
|
||||
};
|
||||
}
|
||||
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<div>
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
<h4 class="mb-0">
|
||||
@Model.PoNumber
|
||||
<span class="badge bg-@StatusBadge(Model.Status) ms-2">@Model.Status</span>
|
||||
@if (Model.IsOverdue)
|
||||
{
|
||||
<span class="badge bg-danger ms-1">Overdue</span>
|
||||
}
|
||||
</h4>
|
||||
<a tabindex="0" class="help-icon" role="button"
|
||||
data-bs-toggle="popover" data-bs-placement="right" data-bs-trigger="focus"
|
||||
data-bs-title="Purchase Order"
|
||||
data-bs-content="PO lifecycle: Draft (editable) → Submit → Receive Goods (updates inventory) → Create Bill (creates a payable bill in Accounts Payable). Partially Received means some items have arrived; you can receive multiple partial shipments. Once fully received you can create a bill to pay the vendor. Cancelled POs can be deleted.">
|
||||
<i class="bi bi-question-circle"></i>
|
||||
</a>
|
||||
</div>
|
||||
<small class="text-muted">@Model.VendorName</small>
|
||||
</div>
|
||||
<div class="d-flex gap-2">
|
||||
<a asp-action="DownloadPdf" asp-route-id="@Model.Id" class="btn btn-sm btn-outline-secondary" target="_blank">
|
||||
<i class="bi bi-file-earmark-pdf me-1"></i> Download PDF
|
||||
</a>
|
||||
<a asp-action="Index" class="btn btn-sm btn-outline-secondary">
|
||||
<i class="bi bi-arrow-left"></i> Back to List
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row g-3">
|
||||
<!-- Left: Line Items -->
|
||||
<div class="col-lg-8">
|
||||
<div class="card border-0 shadow-sm">
|
||||
<div class="card-header bg-transparent fw-semibold">
|
||||
<i class="bi bi-list-ul me-1"></i> Line Items
|
||||
</div>
|
||||
<div class="card-body p-0">
|
||||
<div class="table-responsive">
|
||||
<table class="table mb-0">
|
||||
<thead class="table-light small">
|
||||
<tr>
|
||||
<th>Item</th>
|
||||
<th>SKU</th>
|
||||
<th class="text-center">Ordered</th>
|
||||
<th class="text-center">Received</th>
|
||||
<th class="text-end">Unit Cost</th>
|
||||
<th class="text-end">Line Total</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var item in Model.Items)
|
||||
{
|
||||
<tr class="@(item.IsFullyReceived ? "table-success" : "")">
|
||||
<td>
|
||||
@item.ItemName
|
||||
@if (!string.IsNullOrEmpty(item.Notes))
|
||||
{
|
||||
<br /><small class="text-muted">@item.Notes</small>
|
||||
}
|
||||
</td>
|
||||
<td class="text-muted small">@item.ItemSKU</td>
|
||||
<td class="text-center">@item.QuantityOrdered.ToString("G29") @item.UnitOfMeasure</td>
|
||||
<td class="text-center">
|
||||
@item.QuantityReceived.ToString("G29")
|
||||
@if (item.IsFullyReceived)
|
||||
{
|
||||
<i class="bi bi-check-circle-fill text-success ms-1"></i>
|
||||
}
|
||||
</td>
|
||||
<td class="text-end">$@item.UnitCost.ToString("N2")</td>
|
||||
<td class="text-end fw-semibold">$@item.LineTotal.ToString("N2")</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
<tfoot class="table-light">
|
||||
<tr>
|
||||
<td colspan="5" class="text-end">Subtotal</td>
|
||||
<td class="text-end fw-semibold">$@Model.SubTotal.ToString("N2")</td>
|
||||
</tr>
|
||||
@if (Model.ShippingCost > 0)
|
||||
{
|
||||
<tr>
|
||||
<td colspan="5" class="text-end text-muted">Shipping</td>
|
||||
<td class="text-end text-muted">$@Model.ShippingCost.ToString("N2")</td>
|
||||
</tr>
|
||||
}
|
||||
<tr>
|
||||
<td colspan="5" class="text-end fw-bold">Total</td>
|
||||
<td class="text-end fw-bold fs-5">$@Model.TotalAmount.ToString("N2")</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if (!string.IsNullOrEmpty(Model.Notes))
|
||||
{
|
||||
<div class="card border-0 shadow-sm mt-3">
|
||||
<div class="card-header bg-transparent fw-semibold"><i class="bi bi-chat-text me-1"></i> Notes</div>
|
||||
<div class="card-body">@Model.Notes</div>
|
||||
</div>
|
||||
}
|
||||
@if (!string.IsNullOrEmpty(Model.InternalNotes))
|
||||
{
|
||||
<div class="card border-0 shadow-sm mt-3 border-warning">
|
||||
<div class="card-header bg-transparent fw-semibold text-warning"><i class="bi bi-lock me-1"></i> Internal Notes</div>
|
||||
<div class="card-body">@Model.InternalNotes</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
<!-- Right: Actions + Info -->
|
||||
<div class="col-lg-4">
|
||||
|
||||
<!-- Actions -->
|
||||
<div class="card border-0 shadow-sm mb-3">
|
||||
<div class="card-header bg-transparent d-flex align-items-center gap-2">
|
||||
<span class="fw-semibold">Actions</span>
|
||||
<a tabindex="0" class="help-icon" role="button"
|
||||
data-bs-toggle="popover" data-bs-placement="left" data-bs-trigger="focus"
|
||||
data-bs-title="Actions"
|
||||
data-bs-content="Draft: Edit or Submit. Submit to lock line items and signal the order is placed. Submitted/Partially Received: Receive Goods to enter quantities arrived and update inventory. Cancel to void the order. Received: Create Bill converts this PO into a vendor bill for payment through Accounts Payable.">
|
||||
<i class="bi bi-question-circle"></i>
|
||||
</a>
|
||||
</div>
|
||||
<div class="card-body d-grid gap-2">
|
||||
@if (Model.Status == PurchaseOrderStatus.Draft)
|
||||
{
|
||||
<a asp-action="Edit" asp-route-id="@Model.Id" class="btn btn-outline-primary">
|
||||
<i class="bi bi-pencil me-1"></i> Edit
|
||||
</a>
|
||||
<form asp-action="Submit" asp-route-id="@Model.Id" method="post">
|
||||
@Html.AntiForgeryToken()
|
||||
<button type="submit" class="btn btn-primary w-100">
|
||||
<i class="bi bi-send me-1"></i> Submit PO
|
||||
</button>
|
||||
</form>
|
||||
<a asp-action="Delete" asp-route-id="@Model.Id" class="btn btn-outline-danger">
|
||||
<i class="bi bi-trash me-1"></i> Delete
|
||||
</a>
|
||||
}
|
||||
@if (Model.Status == PurchaseOrderStatus.Submitted || Model.Status == PurchaseOrderStatus.PartiallyReceived)
|
||||
{
|
||||
<a asp-action="Receive" asp-route-id="@Model.Id" class="btn btn-success">
|
||||
<i class="bi bi-box-arrow-in-down me-1"></i> Receive Goods
|
||||
</a>
|
||||
<form asp-action="Cancel" asp-route-id="@Model.Id" method="post">
|
||||
@Html.AntiForgeryToken()
|
||||
<button type="submit" class="btn btn-outline-danger w-100"
|
||||
onclick="return confirm('Cancel this purchase order?')">
|
||||
<i class="bi bi-x-circle me-1"></i> Cancel PO
|
||||
</button>
|
||||
</form>
|
||||
}
|
||||
@if (Model.Status == PurchaseOrderStatus.Received)
|
||||
{
|
||||
<div class="text-center text-success">
|
||||
<i class="bi bi-check-circle-fill fs-2"></i>
|
||||
<p class="mb-0 fw-semibold">Fully Received</p>
|
||||
@if (Model.ReceivedDate.HasValue)
|
||||
{
|
||||
<small class="text-muted">@Model.ReceivedDate.Value.ToString("MM/dd/yyyy")</small>
|
||||
}
|
||||
</div>
|
||||
@if (Model.BillId.HasValue)
|
||||
{
|
||||
<a asp-controller="Bills" asp-action="Details" asp-route-id="@Model.BillId" class="btn btn-outline-primary w-100">
|
||||
<i class="bi bi-receipt me-1"></i> View Bill @Model.BillNumber
|
||||
</a>
|
||||
}
|
||||
else
|
||||
{
|
||||
<a asp-controller="Bills" asp-action="CreateFromPurchaseOrder" asp-route-purchaseOrderId="@Model.Id"
|
||||
class="btn btn-primary w-100">
|
||||
<i class="bi bi-receipt me-1"></i> Create Bill
|
||||
</a>
|
||||
}
|
||||
}
|
||||
@if (Model.Status == PurchaseOrderStatus.PartiallyReceived && !Model.BillId.HasValue)
|
||||
{
|
||||
<a asp-controller="Bills" asp-action="CreateFromPurchaseOrder" asp-route-purchaseOrderId="@Model.Id"
|
||||
class="btn btn-outline-primary w-100">
|
||||
<i class="bi bi-receipt me-1"></i> Create Bill (Partial)
|
||||
</a>
|
||||
}
|
||||
@if (Model.BillId.HasValue && Model.Status == PurchaseOrderStatus.PartiallyReceived)
|
||||
{
|
||||
<a asp-controller="Bills" asp-action="Details" asp-route-id="@Model.BillId" class="btn btn-outline-primary w-100">
|
||||
<i class="bi bi-receipt me-1"></i> View Bill @Model.BillNumber
|
||||
</a>
|
||||
}
|
||||
@if (Model.Status == PurchaseOrderStatus.Cancelled)
|
||||
{
|
||||
<div class="text-center text-muted">
|
||||
<i class="bi bi-x-circle fs-2"></i>
|
||||
<p class="mb-0">Cancelled</p>
|
||||
</div>
|
||||
<a asp-action="Delete" asp-route-id="@Model.Id" class="btn btn-outline-danger btn-sm">
|
||||
<i class="bi bi-trash me-1"></i> Delete
|
||||
</a>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Vendor Info -->
|
||||
<div class="card border-0 shadow-sm mb-3">
|
||||
<div class="card-header bg-transparent fw-semibold"><i class="bi bi-truck me-1"></i> Vendor</div>
|
||||
<div class="card-body small">
|
||||
<p class="fw-semibold mb-1">@Model.VendorName</p>
|
||||
@if (!string.IsNullOrEmpty(Model.VendorEmail))
|
||||
{
|
||||
<p class="mb-1"><i class="bi bi-envelope me-1 text-muted"></i> @Model.VendorEmail</p>
|
||||
}
|
||||
@if (!string.IsNullOrEmpty(Model.VendorPhone))
|
||||
{
|
||||
<p class="mb-0"><i class="bi bi-telephone me-1 text-muted"></i> @Model.VendorPhone</p>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Dates -->
|
||||
<div class="card border-0 shadow-sm">
|
||||
<div class="card-header bg-transparent d-flex align-items-center gap-2">
|
||||
<span class="fw-semibold"><i class="bi bi-calendar3 me-1"></i> Dates</span>
|
||||
<a tabindex="0" class="help-icon" role="button"
|
||||
data-bs-toggle="popover" data-bs-placement="left" data-bs-trigger="focus"
|
||||
data-bs-title="Dates"
|
||||
data-bs-content="Order Date is when the PO was placed. Expected Delivery is when goods are due — if today's date is past this and the PO hasn't been fully received, the row shows as Overdue. Received date is set automatically when you record receipt of all items.">
|
||||
<i class="bi bi-question-circle"></i>
|
||||
</a>
|
||||
</div>
|
||||
<div class="card-body small">
|
||||
<div class="d-flex justify-content-between mb-2">
|
||||
<span class="text-muted">Order Date</span>
|
||||
<span>@Model.OrderDate.ToString("MM/dd/yyyy")</span>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between mb-2">
|
||||
<span class="text-muted">Expected Delivery</span>
|
||||
<span class="@(Model.IsOverdue ? "text-danger fw-semibold" : "")">
|
||||
@(Model.ExpectedDeliveryDate?.ToString("MM/dd/yyyy") ?? "—")
|
||||
</span>
|
||||
</div>
|
||||
@if (Model.ReceivedDate.HasValue)
|
||||
{
|
||||
<div class="d-flex justify-content-between">
|
||||
<span class="text-muted">Received</span>
|
||||
<span class="text-success">@Model.ReceivedDate.Value.ToString("MM/dd/yyyy")</span>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
Reference in New Issue
Block a user