Add BatchId to GiftCertificate for persistent bulk batch tracking

BatchId (Guid?) is stamped on every certificate in a bulk run so the batch
is permanently addressable. BulkResult is now a bookmarkable GET by batchId
rather than TempData, so users can return to re-download at any time.
BatchDownloadPdf is a GET link (no form POST needed). Index shows a Batch
badge on bulk certs that links directly back to the batch result page.

Migration: AddGiftCertificateBatchId

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-14 20:32:56 -04:00
parent 4ec55e7290
commit 38748c2152
8 changed files with 10889 additions and 62 deletions
@@ -2,41 +2,35 @@
@using PowderCoating.Core.Enums
@{
ViewData["Title"] = "Batch Created";
ViewData["Title"] = "Batch Gift Certificates";
ViewData["PageIcon"] = "bi-gift";
var count = ViewBag.CertCount as int? ?? Model.Count;
var amount = ViewBag.CertAmount as string ?? "0.00";
var ids = ViewBag.CertIds as List<int> ?? Model.Select(c => c.Id).ToList();
var batchId = Model.FirstOrDefault()?.BatchId ?? Guid.Empty;
var count = Model.Count;
var amount = Model.FirstOrDefault()?.OriginalAmount ?? 0m;
}
<div class="alert alert-success alert-permanent mb-4">
<i class="bi bi-check-circle-fill me-2"></i>
<strong>@count gift certificates created</strong> &mdash; each worth $@amount.
Download the PDF below to print the full batch.
<strong>@count gift certificates created</strong> &mdash; each worth @amount.ToString("C").
Download the PDF below to print the full batch. This page is bookmarkable &mdash; you can return here any time to re-download.
</div>
<div class="card border-0 shadow-sm mb-4">
<div class="card-header bg-white border-bottom d-flex justify-content-between align-items-center py-3">
<h5 class="mb-0">
<i class="bi bi-collection me-2 text-primary"></i>Batch Certificates (@count)
<span class="text-muted small fw-normal ms-2 font-monospace">@batchId.ToString("N")[..8]&hellip;</span>
</h5>
<form asp-action="BulkDownloadPdf" method="post">
@Html.AntiForgeryToken()
@foreach (var id in ids)
{
<input type="hidden" name="certIds" value="@id" />
}
<button type="submit" class="btn btn-primary">
<i class="bi bi-file-pdf me-2"></i>Download All as PDF
</button>
</form>
<a asp-action="BatchDownloadPdf" asp-route-batchId="@batchId" class="btn btn-primary">
<i class="bi bi-file-pdf me-2"></i>Download All as PDF
</a>
</div>
<div class="card-body p-0">
<div class="table-responsive">
<table class="table table-hover mb-0">
<thead class="table-light">
<tr>
<th>Certificate Code</th>
<th class="ps-3">Certificate Code</th>
<th>Face Value</th>
<th>Issued</th>
<th>Expiry</th>
@@ -48,7 +42,7 @@
@foreach (var cert in Model)
{
<tr>
<td class="fw-mono fw-semibold">@cert.CertificateCode</td>
<td class="ps-3 fw-semibold font-monospace">@cert.CertificateCode</td>
<td>@cert.OriginalAmount.ToString("C")</td>
<td>@cert.IssueDate.ToLocalTime().ToString("MMM d, yyyy")</td>
<td>
@@ -58,7 +52,7 @@
</td>
<td><span class="badge bg-success">Active</span></td>
<td class="text-end">
<a asp-action="Details" asp-route-id="@cert.Id" class="btn btn-sm btn-outline-secondary">
<a asp-action="Details" asp-route-id="@cert.Id" class="btn btn-sm btn-outline-secondary" title="View details">
<i class="bi bi-eye"></i>
</a>
<a asp-action="DownloadPdf" asp-route-id="@cert.Id" class="btn btn-sm btn-outline-secondary" title="Download single PDF">
@@ -75,15 +69,8 @@
<a asp-action="Index" class="btn btn-outline-secondary">
<i class="bi bi-arrow-left me-1"></i>Back to Gift Certificates
</a>
<form asp-action="BulkDownloadPdf" method="post">
@Html.AntiForgeryToken()
@foreach (var id in ids)
{
<input type="hidden" name="certIds" value="@id" />
}
<button type="submit" class="btn btn-primary">
<i class="bi bi-printer me-2"></i>Print Batch PDF (@count pages)
</button>
</form>
<a asp-action="BatchDownloadPdf" asp-route-batchId="@batchId" class="btn btn-primary">
<i class="bi bi-printer me-2"></i>Print Batch PDF (@count pages)
</a>
</div>
</div>