Add packing slip PDF to invoice details page
Generates a no-price packing slip (items, color, qty + signature line) via QuestPDF. New DownloadPackingSlip action reuses existing invoice data pipeline; Packing Slip button opens inline in a new tab same as Print/PDF. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1782,6 +1782,59 @@ public class InvoicesController : Controller
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// GET: /Invoices/DownloadPackingSlip/5
|
||||
// -----------------------------------------------------------------------
|
||||
/// <summary>
|
||||
/// Generates a no-price packing slip PDF for physical pickup/delivery paperwork.
|
||||
/// Reuses the same company branding and invoice data pipeline as DownloadPdf but
|
||||
/// delegates to GeneratePackingSlipPdfAsync which omits all pricing columns.
|
||||
/// </summary>
|
||||
public async Task<IActionResult> DownloadPackingSlip(int? id, bool inline = false)
|
||||
{
|
||||
if (id == null) return NotFound();
|
||||
|
||||
try
|
||||
{
|
||||
var invoice = await LoadInvoiceForViewAsync(id.Value);
|
||||
if (invoice == null) return NotFound();
|
||||
|
||||
var currentUser = await _userManager.GetUserAsync(User);
|
||||
if (currentUser == null) return Unauthorized();
|
||||
|
||||
var company = await _unitOfWork.Companies.GetByIdAsync(currentUser.CompanyId);
|
||||
var companyInfo = new Application.DTOs.Company.CompanyInfoDto
|
||||
{
|
||||
CompanyName = company?.CompanyName ?? string.Empty,
|
||||
Phone = company?.Phone,
|
||||
Address = company?.Address,
|
||||
City = company?.City,
|
||||
State = company?.State,
|
||||
ZipCode = company?.ZipCode,
|
||||
PrimaryContactEmail = company?.PrimaryContactEmail
|
||||
};
|
||||
|
||||
var (logoData, logoContentType) = await LoadCompanyLogoAsync(company);
|
||||
var dto = await BuildInvoiceDtoAsync(invoice);
|
||||
var pdfBytes = await _pdfService.GeneratePackingSlipPdfAsync(dto, logoData, logoContentType, companyInfo);
|
||||
var fileName = $"PackingSlip-{invoice.InvoiceNumber}.pdf";
|
||||
|
||||
if (inline)
|
||||
{
|
||||
Response.Headers["Content-Disposition"] = $"inline; filename=\"{fileName}\"";
|
||||
return File(pdfBytes, "application/pdf");
|
||||
}
|
||||
|
||||
return File(pdfBytes, "application/pdf", fileName);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error generating packing slip for invoice {Id}", id);
|
||||
TempData["ErrorPermanent"] = $"Packing slip generation failed: {ex.Message}";
|
||||
return RedirectToAction(nameof(Details), new { id });
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// GET: /Invoices/ForJob/5 — redirect to existing or Create
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user