fix: remove reference in serial/batch when document is cancelled (backport #53979) (#53989)

This commit is contained in:
mergify[bot]
2026-04-02 08:11:20 +00:00
committed by GitHub
parent 53fc0beae5
commit 5aaca83fe4
2 changed files with 70 additions and 0 deletions

View File

@@ -1489,6 +1489,7 @@ class SerialandBatchBundle(Document):
def on_cancel(self):
self.validate_voucher_no_docstatus()
self.validate_batch_quantity()
self.remove_source_document_no()
def validate_batch_quantity(self):
if not self.has_batch_no:
@@ -1507,6 +1508,43 @@ class SerialandBatchBundle(Document):
if flt(available_qty, precision) < 0:
self.throw_negative_batch(d.batch_no, available_qty, precision)
def remove_source_document_no(self):
if not self.has_serial_no and not self.has_batch_no:
return
if self.total_qty <= 0:
return
if self.has_serial_no:
serial_nos = [d.serial_no for d in self.entries if d.serial_no]
sn_table = frappe.qb.DocType("Serial No")
(
frappe.qb.update(sn_table)
.set(sn_table.reference_doctype, None)
.set(sn_table.reference_name, None)
.set(sn_table.posting_date, None)
.where(
(sn_table.name.isin(serial_nos))
& (sn_table.reference_doctype == self.voucher_type)
& (sn_table.reference_name == self.voucher_no)
& (sn_table.posting_date == getdate(self.posting_datetime))
)
).run()
if self.has_batch_no:
batch_nos = [d.batch_no for d in self.entries if d.batch_no]
batch_table = frappe.qb.DocType("Batch")
(
frappe.qb.update(batch_table)
.set(batch_table.reference_doctype, None)
.set(batch_table.reference_name, None)
.where(
(batch_table.name.isin(batch_nos))
& (batch_table.reference_doctype == self.voucher_type)
& (batch_table.reference_name == self.voucher_no)
)
).run()
def throw_negative_batch(self, batch_no, available_qty, precision, posting_datetime=None):
from erpnext.stock.stock_ledger import NegativeStockError

View File

@@ -1077,6 +1077,38 @@ class TestSerialandBatchBundle(ERPNextTestSuite):
self.assertTrue(bundle_doc.docstatus == 0)
self.assertRaises(frappe.ValidationError, bundle_doc.submit)
def test_reference_voucher_on_cancel(self):
"""
When a source document is cancelled, the reference voucher field
in the respective serial or batch document should be nullified.
"""
item_code = make_item(
"Serial Item",
properties={
"is_stock_item": 1,
"has_serial_no": 1,
"serial_no_series": "SERIAL.#####",
},
).name
se = make_stock_entry(
item_code=item_code,
qty=1,
target="_Test Warehouse - _TC",
)
serial_no = get_serial_nos_from_bundle(se.items[0].serial_and_batch_bundle)[0]
self.assertEqual(frappe.get_value("Serial No", serial_no, "reference_name"), se.name)
se.cancel()
self.assertIsNone(frappe.get_value("Serial No", serial_no, "reference_name"))
se1 = frappe.copy_doc(se, ignore_no_copy=False)
se1.items[0].serial_no = serial_no
se1.submit()
self.assertEqual(frappe.get_value("Serial No", serial_no, "reference_name"), se1.name)
def get_batch_from_bundle(bundle):
from erpnext.stock.serial_batch_bundle import get_batch_nos