21b39161a3
Replace literal Unicode chars (em dash, ellipsis, angle quotes, box-drawing) with HTML entities to prevent corruption from AI tools and Windows encoding. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
153 lines
9.9 KiB
Plaintext
153 lines
9.9 KiB
Plaintext
@model PowderCoating.Application.DTOs.Accounting.EditExpenseDto
|
|
@* Note: ReceiptFilePath is carried via hidden field to detect existing receipt *@
|
|
|
|
@{
|
|
ViewData["Title"] = "Edit Expense";
|
|
ViewData["PageIcon"] = "bi-pencil-square";
|
|
ViewData["PageHelpTitle"] = "Edit Expense";
|
|
ViewData["PageHelpContent"] = "All fields are editable. Uploading a new receipt replaces the existing one. To remove a receipt without replacing it, use the Delete Receipt button on the Details page.";
|
|
}
|
|
|
|
<div class="d-flex justify-content-start mb-4">
|
|
<a asp-action="Details" asp-route-id="@Model.Id" class="btn btn-sm btn-outline-secondary"><i class="bi bi-arrow-left"></i></a>
|
|
</div>
|
|
|
|
<div class="row justify-content-center">
|
|
<div class="col-lg-7">
|
|
<div class="card shadow-sm">
|
|
<div class="card-body">
|
|
<form asp-action="Edit" asp-route-id="@Model.Id" method="post" enctype="multipart/form-data">
|
|
@Html.AntiForgeryToken()
|
|
<input asp-for="Id" type="hidden" />
|
|
<input asp-for="ReceiptFilePath" type="hidden" />
|
|
<div asp-validation-summary="ModelOnly" class="alert alert-danger alert-permanent mb-3"></div>
|
|
|
|
<div class="row g-3">
|
|
<div class="col-sm-6">
|
|
<label asp-for="Date" class="form-label fw-medium">Date <span class="text-danger">*</span></label>
|
|
<input asp-for="Date" type="date" class="form-control" />
|
|
</div>
|
|
<div class="col-sm-6">
|
|
<label asp-for="Amount" class="form-label fw-medium">Amount <span class="text-danger">*</span></label>
|
|
<div class="input-group">
|
|
<span class="input-group-text">$</span>
|
|
<input asp-for="Amount" type="number" step="0.01" min="0.01" class="form-control" />
|
|
</div>
|
|
</div>
|
|
<div class="col-12">
|
|
<div class="d-flex align-items-center gap-1 mb-1">
|
|
<label asp-for="ExpenseAccountId" class="form-label fw-medium mb-0">Expense Account <span class="text-danger">*</span></label>
|
|
<a tabindex="0" class="help-icon" role="button"
|
|
data-bs-toggle="popover" data-bs-placement="right" data-bs-trigger="focus"
|
|
data-bs-title="Expense Account"
|
|
data-bs-content="The expense category this purchase belongs to — e.g. Supplies, Materials, Utilities, Fuel. This account is debited when the expense is saved. Choose the most specific account that fits to keep your reports accurate.">
|
|
<i class="bi bi-question-circle"></i>
|
|
</a>
|
|
</div>
|
|
<select asp-for="ExpenseAccountId" asp-items="ViewBag.ExpenseAccounts" class="form-select">
|
|
<option value="">— Select Account —</option>
|
|
</select>
|
|
</div>
|
|
<div class="col-sm-6">
|
|
<div class="d-flex align-items-center gap-1 mb-1">
|
|
<label asp-for="PaymentAccountId" class="form-label fw-medium mb-0">Paid From <span class="text-danger">*</span></label>
|
|
<a tabindex="0" class="help-icon" role="button"
|
|
data-bs-toggle="popover" data-bs-placement="right" data-bs-trigger="focus"
|
|
data-bs-title="Paid From"
|
|
data-bs-content="The bank or cash account the money came out of — e.g. Business Checking, Petty Cash, Company Credit Card. This account is credited when the expense is saved. Used for bank reconciliation.">
|
|
<i class="bi bi-question-circle"></i>
|
|
</a>
|
|
</div>
|
|
<select asp-for="PaymentAccountId" asp-items="ViewBag.PaymentAccounts" class="form-select">
|
|
<option value="">— Select Account —</option>
|
|
</select>
|
|
</div>
|
|
<div class="col-sm-6">
|
|
<label asp-for="PaymentMethod" class="form-label fw-medium">Payment Method <span class="text-danger">*</span></label>
|
|
<select asp-for="PaymentMethod" asp-items="ViewBag.PaymentMethods" class="form-select"></select>
|
|
</div>
|
|
<div class="col-sm-6">
|
|
<label asp-for="VendorId" class="form-label fw-medium">Vendor</label>
|
|
<select asp-for="VendorId" asp-items="ViewBag.Vendors" class="form-select"
|
|
data-quick-add-url="/Vendors/Create" data-quick-add-title="Add New Vendor">
|
|
<option value="">— None —</option>
|
|
<option value="__new__">+ Add New Vendor…</option>
|
|
</select>
|
|
</div>
|
|
<div class="col-sm-6">
|
|
<div class="d-flex align-items-center gap-1 mb-1">
|
|
<label asp-for="JobId" class="form-label fw-medium mb-0">Job</label>
|
|
<a tabindex="0" class="help-icon" role="button"
|
|
data-bs-toggle="popover" data-bs-placement="right" data-bs-trigger="focus"
|
|
data-bs-title="Linked Job"
|
|
data-bs-content="Attach this expense to a specific job to track its true cost. Job-linked expenses roll up in job profitability reports, helping you see whether a job was profitable after all direct costs.">
|
|
<i class="bi bi-question-circle"></i>
|
|
</a>
|
|
</div>
|
|
<select asp-for="JobId" asp-items="ViewBag.Jobs" class="form-select">
|
|
<option value="">— None —</option>
|
|
</select>
|
|
</div>
|
|
<div class="col-12">
|
|
<label asp-for="Memo" class="form-label fw-medium">Memo</label>
|
|
<textarea asp-for="Memo" class="form-control" rows="2"></textarea>
|
|
</div>
|
|
|
|
<div class="col-12">
|
|
<div class="d-flex align-items-center gap-1 mb-1">
|
|
<label class="form-label fw-medium mb-0">Receipt</label>
|
|
<a tabindex="0" class="help-icon" role="button"
|
|
data-bs-toggle="popover" data-bs-placement="right" data-bs-trigger="focus"
|
|
data-bs-title="Receipt"
|
|
data-bs-content="Uploading a new file here replaces the existing receipt. To remove a receipt without replacing it, use the Delete Receipt button on the Details page. Supports JPG, PNG, and PDF up to 10 MB.">
|
|
<i class="bi bi-question-circle"></i>
|
|
</a>
|
|
</div>
|
|
@if (!string.IsNullOrEmpty(Model.ReceiptFilePath))
|
|
{
|
|
<div class="d-flex align-items-center gap-3 mb-2 p-2 border rounded bg-light">
|
|
<i class="bi bi-paperclip text-muted fs-5"></i>
|
|
<span class="small text-muted flex-grow-1">Receipt attached</span>
|
|
<a asp-action="ViewReceipt" asp-route-id="@Model.Id"
|
|
class="btn btn-sm btn-outline-secondary" target="_blank">
|
|
<i class="bi bi-eye me-1"></i>View
|
|
</a>
|
|
</div>
|
|
<div class="form-text mb-2">Upload a new file below to replace the existing receipt.</div>
|
|
}
|
|
<input type="file" name="receiptFile" id="receiptFile" class="form-control"
|
|
accept=".jpg,.jpeg,.png,.gif,.webp,.pdf" />
|
|
<div class="form-text">Image or PDF, up to 10 MB.</div>
|
|
<div id="receiptPreview" class="mt-2 d-none">
|
|
<img id="previewImg" src="" alt="Receipt preview" class="img-thumbnail" style="max-height:200px;" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="d-flex gap-2 mt-4">
|
|
<button type="submit" class="btn btn-primary"><i class="bi bi-check-lg me-1"></i>Save Changes</button>
|
|
<a asp-action="Details" asp-route-id="@Model.Id" class="btn btn-outline-secondary">Cancel</a>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
@section Scripts {
|
|
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
|
|
<script>
|
|
document.getElementById('receiptFile').addEventListener('change', function () {
|
|
const file = this.files[0];
|
|
const preview = document.getElementById('receiptPreview');
|
|
const img = document.getElementById('previewImg');
|
|
if (file && file.type.startsWith('image/')) {
|
|
img.src = URL.createObjectURL(file);
|
|
preview.classList.remove('d-none');
|
|
} else {
|
|
preview.classList.add('d-none');
|
|
}
|
|
});
|
|
</script>
|
|
}
|