feat(selling): keep cancelled proformas visible with their PDF

Cancelling a proforma should void it, not erase history.

- Persist the Cancelled status on cancel (db_set) and keep the PDF attached
- Proforma tab now lists cancelled proformas with a red status badge, so the
  voided document and its PDF stay reachable for audit
This commit is contained in:
Nabin Hait
2026-07-17 11:58:51 +05:30
parent 473c655cb2
commit f711375885
3 changed files with 16 additions and 3 deletions

View File

@@ -189,7 +189,8 @@ Object.assign(erpnext.proforma, {
const list = new frappe.ui.EmbeddedList({
wrapper,
doctype: "Proforma Invoice",
filters: { sales_order: frm.doc.name, docstatus: 1 },
// Include cancelled (docstatus 2) so voided proformas stay visible for audit.
filters: { sales_order: frm.doc.name, docstatus: ["in", [1, 2]] },
fields: ["name", "proforma_date", "grand_total", "status", "proforma_pdf", "sent_on", "currency"],
order_by: "creation desc",
empty_message: __("No proforma invoices yet."),
@@ -218,7 +219,7 @@ Object.assign(erpnext.proforma, {
label: __("Status"),
type: "badge",
fieldname: "status",
color: (row) => (row.status === "Issued" ? "green" : "gray"),
color: (row) => (row.status === "Cancelled" ? "red" : "green"),
},
{
type: "actions",

View File

@@ -52,7 +52,7 @@ class ProformaInvoice(Document):
self.generate_and_attach_pdf()
def on_cancel(self) -> None:
self.status = "Cancelled"
self.db_set("status", "Cancelled")
def set_total_qty(self) -> None:
self.total_qty = sum(flt(item.qty) for item in self.items)

View File

@@ -80,6 +80,18 @@ class TestProformaInvoice(ERPNextTestSuite):
self.assertEqual(flt(item.amount), 250)
self.assertEqual(flt(proforma.grand_total), 250)
def test_cancelled_proforma_keeps_pdf(self):
"""Cancelling voids the proforma but keeps its PDF and status for the audit trail."""
sales_order = make_sales_order(qty=10)
proforma = self.create_proforma(sales_order, [(sales_order.items[0].name, 4)])
pdf = proforma.proforma_pdf
self.assertTrue(pdf)
proforma.cancel()
proforma.reload()
self.assertEqual(proforma.status, "Cancelled")
self.assertEqual(proforma.proforma_pdf, pdf)
def test_feature_toggle_is_enforced(self):
sales_order = make_sales_order(qty=10)
frappe.db.set_single_value("Selling Settings", "enable_proforma_invoice", 0)