mirror of
https://github.com/frappe/erpnext.git
synced 2026-04-13 03:45:08 +00:00
fix: system was allowing credit notes with serial numbers for any customer
(cherry picked from commit e073075834)
# Conflicts:
# erpnext/stock/doctype/delivery_note/delivery_note.py
# erpnext/stock/doctype/serial_no/serial_no.json
This commit is contained in:
committed by
Mergify
parent
0151733a25
commit
4b6444e93b
@@ -461,6 +461,7 @@ class SalesInvoice(SellingController):
|
|||||||
self.make_bundle_for_sales_purchase_return(table_name)
|
self.make_bundle_for_sales_purchase_return(table_name)
|
||||||
self.make_bundle_using_old_serial_batch_fields(table_name)
|
self.make_bundle_using_old_serial_batch_fields(table_name)
|
||||||
|
|
||||||
|
self.validate_standalone_serial_nos_customer()
|
||||||
self.update_stock_reservation_entries()
|
self.update_stock_reservation_entries()
|
||||||
self.update_stock_ledger()
|
self.update_stock_ledger()
|
||||||
|
|
||||||
|
|||||||
@@ -36,6 +36,17 @@ def validate_return_against(doc):
|
|||||||
|
|
||||||
party_type = "customer" if doc.doctype in ("Sales Invoice", "Delivery Note") else "supplier"
|
party_type = "customer" if doc.doctype in ("Sales Invoice", "Delivery Note") else "supplier"
|
||||||
|
|
||||||
|
if ref_doc.get(party_type) != doc.get(party_type):
|
||||||
|
frappe.throw(
|
||||||
|
_("The {0} {1} does not match with the {0} {2} in the {3} {4}").format(
|
||||||
|
doc.meta.get_label(party_type),
|
||||||
|
doc.get(party_type),
|
||||||
|
ref_doc.get(party_type),
|
||||||
|
ref_doc.doctype,
|
||||||
|
ref_doc.name,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
if (
|
if (
|
||||||
ref_doc.company == doc.company
|
ref_doc.company == doc.company
|
||||||
and ref_doc.get(party_type) == doc.get(party_type)
|
and ref_doc.get(party_type) == doc.get(party_type)
|
||||||
|
|||||||
@@ -57,6 +57,35 @@ class SellingController(StockController):
|
|||||||
if self.get(table_field):
|
if self.get(table_field):
|
||||||
self.set_serial_and_batch_bundle(table_field)
|
self.set_serial_and_batch_bundle(table_field)
|
||||||
|
|
||||||
|
def validate_standalone_serial_nos_customer(self):
|
||||||
|
if not self.is_return or self.return_against:
|
||||||
|
return
|
||||||
|
|
||||||
|
if self.doctype in ["Sales Invoice", "Delivery Note"]:
|
||||||
|
bundle_ids = [d.serial_and_batch_bundle for d in self.get("items") if d.serial_and_batch_bundle]
|
||||||
|
if not bundle_ids:
|
||||||
|
return
|
||||||
|
|
||||||
|
serial_nos = frappe.get_all(
|
||||||
|
"Serial and Batch Entry",
|
||||||
|
filters={"parent": ("in", bundle_ids)},
|
||||||
|
pluck="serial_no",
|
||||||
|
)
|
||||||
|
|
||||||
|
if serial_nos := frappe.get_all(
|
||||||
|
"Serial No",
|
||||||
|
filters={"name": ("in", serial_nos), "customer": ("is", "set")},
|
||||||
|
fields=["name", "customer"],
|
||||||
|
):
|
||||||
|
for sn in serial_nos:
|
||||||
|
if sn.customer and sn.customer != self.customer:
|
||||||
|
frappe.throw(
|
||||||
|
_(
|
||||||
|
"Serial No {0} is already assigned to customer {1}. Can only be returned against the customer {1}"
|
||||||
|
).format(frappe.bold(sn.name), frappe.bold(sn.customer)),
|
||||||
|
title=_("Serial No Already Assigned"),
|
||||||
|
)
|
||||||
|
|
||||||
def set_missing_values(self, for_validate=False):
|
def set_missing_values(self, for_validate=False):
|
||||||
super().set_missing_values(for_validate)
|
super().set_missing_values(for_validate)
|
||||||
|
|
||||||
|
|||||||
@@ -466,6 +466,12 @@ class DeliveryNote(SellingController):
|
|||||||
self.make_bundle_for_sales_purchase_return(table_name)
|
self.make_bundle_for_sales_purchase_return(table_name)
|
||||||
self.make_bundle_using_old_serial_batch_fields(table_name)
|
self.make_bundle_using_old_serial_batch_fields(table_name)
|
||||||
|
|
||||||
|
<<<<<<< HEAD
|
||||||
|
=======
|
||||||
|
self.validate_standalone_serial_nos_customer()
|
||||||
|
self.update_stock_reservation_entries()
|
||||||
|
|
||||||
|
>>>>>>> e073075834 (fix: system was allowing credit notes with serial numbers for any customer)
|
||||||
# Updating stock ledger should always be called after updating prevdoc status,
|
# Updating stock ledger should always be called after updating prevdoc status,
|
||||||
# because updating reserved qty in bin depends upon updated delivered qty in SO
|
# because updating reserved qty in bin depends upon updated delivered qty in SO
|
||||||
self.update_stock_ledger()
|
self.update_stock_ledger()
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
"batch_no",
|
"batch_no",
|
||||||
"warehouse",
|
"warehouse",
|
||||||
"purchase_rate",
|
"purchase_rate",
|
||||||
|
"customer",
|
||||||
"column_break1",
|
"column_break1",
|
||||||
"status",
|
"status",
|
||||||
"item_name",
|
"item_name",
|
||||||
@@ -267,12 +268,25 @@
|
|||||||
"label": "Creation Document No",
|
"label": "Creation Document No",
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"read_only": 1
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "customer",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"label": "Customer",
|
||||||
|
"no_copy": 1,
|
||||||
|
"options": "Customer",
|
||||||
|
"print_hide": 1,
|
||||||
|
"read_only": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"icon": "fa fa-barcode",
|
"icon": "fa fa-barcode",
|
||||||
"idx": 1,
|
"idx": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
|
<<<<<<< HEAD
|
||||||
"modified": "2025-01-15 16:22:49.873889",
|
"modified": "2025-01-15 16:22:49.873889",
|
||||||
|
=======
|
||||||
|
"modified": "2025-07-15 13:36:21.938700",
|
||||||
|
>>>>>>> e073075834 (fix: system was allowing credit notes with serial numbers for any customer)
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Stock",
|
"module": "Stock",
|
||||||
"name": "Serial No",
|
"name": "Serial No",
|
||||||
@@ -310,6 +324,7 @@
|
|||||||
"role": "Stock User"
|
"role": "Stock User"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"row_format": "Dynamic",
|
||||||
"search_fields": "item_code",
|
"search_fields": "item_code",
|
||||||
"show_name_in_global_search": 1,
|
"show_name_in_global_search": 1,
|
||||||
"sort_field": "modified",
|
"sort_field": "modified",
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ class SerialNo(StockController):
|
|||||||
batch_no: DF.Link | None
|
batch_no: DF.Link | None
|
||||||
brand: DF.Link | None
|
brand: DF.Link | None
|
||||||
company: DF.Link
|
company: DF.Link
|
||||||
|
customer: DF.Link | None
|
||||||
description: DF.Text | None
|
description: DF.Text | None
|
||||||
employee: DF.Link | None
|
employee: DF.Link | None
|
||||||
item_code: DF.Link
|
item_code: DF.Link
|
||||||
|
|||||||
@@ -377,6 +377,10 @@ class SerialBatchBundle:
|
|||||||
]:
|
]:
|
||||||
status = "Consumed"
|
status = "Consumed"
|
||||||
|
|
||||||
|
customer = None
|
||||||
|
if sle.voucher_type in ["Sales Invoice", "Delivery Note"] and sle.actual_qty < 0:
|
||||||
|
customer = frappe.get_cached_value(sle.voucher_type, sle.voucher_no, "customer")
|
||||||
|
|
||||||
sn_table = frappe.qb.DocType("Serial No")
|
sn_table = frappe.qb.DocType("Serial No")
|
||||||
|
|
||||||
query = (
|
query = (
|
||||||
@@ -387,10 +391,11 @@ class SerialBatchBundle:
|
|||||||
"Active"
|
"Active"
|
||||||
if warehouse
|
if warehouse
|
||||||
else status
|
else status
|
||||||
if (sn_table.purchase_document_no != sle.voucher_no and sle.is_cancelled != 1)
|
if (sn_table.purchase_document_no != sle.voucher_no or sle.is_cancelled != 1)
|
||||||
else "Inactive",
|
else "Inactive",
|
||||||
)
|
)
|
||||||
.set(sn_table.company, sle.company)
|
.set(sn_table.company, sle.company)
|
||||||
|
.set(sn_table.customer, customer)
|
||||||
.where(sn_table.name.isin(serial_nos))
|
.where(sn_table.name.isin(serial_nos))
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user