* fix: validate duplicate SBB (cherry picked from commit 094ecc1f62a97d6580a72c9a9fdf176a6d7dc959) * test: duplicate SBB (cherry picked from commit 55e66db315518bda82e4eb77d8fc74f5b2c7d14d) --------- Co-authored-by: s-aga-r <sagarsharma.s312@gmail.com>
This commit is contained in:
parent
92e6017a29
commit
a2f1a964f1
@ -46,6 +46,9 @@ class BatchExpiredError(frappe.ValidationError):
|
|||||||
class StockController(AccountsController):
|
class StockController(AccountsController):
|
||||||
def validate(self):
|
def validate(self):
|
||||||
super(StockController, self).validate()
|
super(StockController, self).validate()
|
||||||
|
|
||||||
|
if self.docstatus == 0:
|
||||||
|
self.validate_duplicate_serial_and_batch_bundle()
|
||||||
if not self.get("is_return"):
|
if not self.get("is_return"):
|
||||||
self.validate_inspection()
|
self.validate_inspection()
|
||||||
self.validate_serialized_batch()
|
self.validate_serialized_batch()
|
||||||
@ -55,6 +58,32 @@ class StockController(AccountsController):
|
|||||||
self.validate_internal_transfer()
|
self.validate_internal_transfer()
|
||||||
self.validate_putaway_capacity()
|
self.validate_putaway_capacity()
|
||||||
|
|
||||||
|
def validate_duplicate_serial_and_batch_bundle(self):
|
||||||
|
if sbb_list := [
|
||||||
|
item.get("serial_and_batch_bundle")
|
||||||
|
for item in self.items
|
||||||
|
if item.get("serial_and_batch_bundle")
|
||||||
|
]:
|
||||||
|
SLE = frappe.qb.DocType("Stock Ledger Entry")
|
||||||
|
data = (
|
||||||
|
frappe.qb.from_(SLE)
|
||||||
|
.select(SLE.voucher_type, SLE.voucher_no, SLE.serial_and_batch_bundle)
|
||||||
|
.where(
|
||||||
|
(SLE.docstatus == 1)
|
||||||
|
& (SLE.serial_and_batch_bundle.notnull())
|
||||||
|
& (SLE.serial_and_batch_bundle.isin(sbb_list))
|
||||||
|
)
|
||||||
|
.limit(1)
|
||||||
|
).run(as_dict=True)
|
||||||
|
|
||||||
|
if data:
|
||||||
|
data = data[0]
|
||||||
|
frappe.throw(
|
||||||
|
_("Serial and Batch Bundle {0} is already used in {1} {2}.").format(
|
||||||
|
frappe.bold(data.serial_and_batch_bundle), data.voucher_type, data.voucher_no
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
def make_gl_entries(self, gl_entries=None, from_repost=False):
|
def make_gl_entries(self, gl_entries=None, from_repost=False):
|
||||||
if self.docstatus == 2:
|
if self.docstatus == 2:
|
||||||
make_reverse_gl_entries(voucher_type=self.doctype, voucher_no=self.name)
|
make_reverse_gl_entries(voucher_type=self.doctype, voucher_no=self.name)
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
import json
|
import json
|
||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
from frappe.tests.utils import FrappeTestCase
|
from frappe.tests.utils import FrappeTestCase, change_settings
|
||||||
from frappe.utils import add_days, add_to_date, flt, nowdate, nowtime, today
|
from frappe.utils import add_days, add_to_date, flt, nowdate, nowtime, today
|
||||||
|
|
||||||
from erpnext.stock.doctype.item.test_item import make_item
|
from erpnext.stock.doctype.item.test_item import make_item
|
||||||
@ -521,6 +521,24 @@ class TestSerialandBatchBundle(FrappeTestCase):
|
|||||||
make_serial_nos(item_code, serial_nos)
|
make_serial_nos(item_code, serial_nos)
|
||||||
self.assertTrue(frappe.db.exists("Serial No", serial_no_id))
|
self.assertTrue(frappe.db.exists("Serial No", serial_no_id))
|
||||||
|
|
||||||
|
@change_settings("Stock Settings", {"auto_create_serial_and_batch_bundle_for_outward": 1})
|
||||||
|
def test_duplicate_serial_and_batch_bundle(self):
|
||||||
|
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt
|
||||||
|
|
||||||
|
item_code = make_item(properties={"is_stock_item": 1, "has_serial_no": 1}).name
|
||||||
|
|
||||||
|
serial_no = f"{item_code}-001"
|
||||||
|
serial_nos = [{"serial_no": serial_no, "qty": 1}]
|
||||||
|
make_serial_nos(item_code, serial_nos)
|
||||||
|
|
||||||
|
pr1 = make_purchase_receipt(item=item_code, qty=1, rate=500, serial_no=[serial_no])
|
||||||
|
pr2 = make_purchase_receipt(item=item_code, qty=1, rate=500, do_not_save=True)
|
||||||
|
|
||||||
|
pr1.reload()
|
||||||
|
pr2.items[0].serial_and_batch_bundle = pr1.items[0].serial_and_batch_bundle
|
||||||
|
|
||||||
|
self.assertRaises(frappe.exceptions.ValidationError, pr2.save)
|
||||||
|
|
||||||
|
|
||||||
def get_batch_from_bundle(bundle):
|
def get_batch_from_bundle(bundle):
|
||||||
from erpnext.stock.serial_batch_bundle import get_batch_nos
|
from erpnext.stock.serial_batch_bundle import get_batch_nos
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user