mirror of
https://github.com/frappe/erpnext.git
synced 2026-05-19 21:19:19 +00:00
Merge branch 'version-15-hotfix' into mergify/bp/version-15-hotfix/pr-53994
This commit is contained in:
@@ -264,6 +264,7 @@ frappe.ui.form.on("BOM", {
|
|||||||
reqd: 1,
|
reqd: 1,
|
||||||
default: 1,
|
default: 1,
|
||||||
onchange: () => {
|
onchange: () => {
|
||||||
|
if (!cur_dialog) return;
|
||||||
const { quantity, items: rm } = frm.doc;
|
const { quantity, items: rm } = frm.doc;
|
||||||
const variant_items_map = rm.reduce((acc, item) => {
|
const variant_items_map = rm.reduce((acc, item) => {
|
||||||
acc[item.item_code] = item.qty;
|
acc[item.item_code] = item.qty;
|
||||||
|
|||||||
@@ -63,6 +63,13 @@ frappe.ui.form.on("Sales Order", {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
transaction_date(frm) {
|
||||||
|
prevent_past_delivery_dates(frm);
|
||||||
|
frm.set_value("delivery_date", "");
|
||||||
|
frm.doc.items.forEach((d) => {
|
||||||
|
frappe.model.set_value(d.doctype, d.name, "delivery_date", "");
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
refresh: function (frm) {
|
refresh: function (frm) {
|
||||||
if (frm.doc.docstatus === 1) {
|
if (frm.doc.docstatus === 1) {
|
||||||
|
|||||||
@@ -1479,6 +1479,7 @@ class SerialandBatchBundle(Document):
|
|||||||
def on_cancel(self):
|
def on_cancel(self):
|
||||||
self.validate_voucher_no_docstatus()
|
self.validate_voucher_no_docstatus()
|
||||||
self.validate_batch_quantity()
|
self.validate_batch_quantity()
|
||||||
|
self.remove_source_document_no()
|
||||||
|
|
||||||
def validate_batch_quantity(self):
|
def validate_batch_quantity(self):
|
||||||
if not self.has_batch_no:
|
if not self.has_batch_no:
|
||||||
@@ -1497,6 +1498,19 @@ class SerialandBatchBundle(Document):
|
|||||||
if flt(available_qty, precision) < 0:
|
if flt(available_qty, precision) < 0:
|
||||||
self.throw_negative_batch(d.batch_no, available_qty, precision)
|
self.throw_negative_batch(d.batch_no, available_qty, precision)
|
||||||
|
|
||||||
|
def remove_source_document_no(self):
|
||||||
|
if not self.has_serial_no:
|
||||||
|
return
|
||||||
|
|
||||||
|
if self.total_qty > 0:
|
||||||
|
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.purchase_document_no, None)
|
||||||
|
.where((sn_table.name.isin(serial_nos)) & (sn_table.purchase_document_no == self.voucher_no))
|
||||||
|
).run()
|
||||||
|
|
||||||
def throw_negative_batch(self, batch_no, available_qty, precision, posting_datetime=None):
|
def throw_negative_batch(self, batch_no, available_qty, precision, posting_datetime=None):
|
||||||
from erpnext.stock.stock_ledger import NegativeStockError
|
from erpnext.stock.stock_ledger import NegativeStockError
|
||||||
|
|
||||||
|
|||||||
@@ -1159,6 +1159,38 @@ class TestSerialandBatchBundle(FrappeTestCase):
|
|||||||
# FIFO removes from front: [10, 100] -> [5, 100], rest unchanged
|
# FIFO removes from front: [10, 100] -> [5, 100], rest unchanged
|
||||||
self.assertEqual(json.loads(return_sle.stock_queue), [[5, 100], [20, 200], [5, 300]])
|
self.assertEqual(json.loads(return_sle.stock_queue), [[5, 100], [20, 200], [5, 300]])
|
||||||
|
|
||||||
|
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, "purchase_document_no"), se.name)
|
||||||
|
|
||||||
|
se.cancel()
|
||||||
|
self.assertIsNone(frappe.get_value("Serial No", serial_no, "purchase_document_no"))
|
||||||
|
|
||||||
|
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, "purchase_document_no"), se1.name)
|
||||||
|
|
||||||
|
|
||||||
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
|
||||||
|
|||||||
@@ -183,6 +183,13 @@ class StockEntry(StockController):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def onload(self):
|
def onload(self):
|
||||||
|
self.update_items_from_bin_details()
|
||||||
|
|
||||||
|
def before_print(self, settings=None):
|
||||||
|
super().before_print(settings)
|
||||||
|
self.update_items_from_bin_details()
|
||||||
|
|
||||||
|
def update_items_from_bin_details(self):
|
||||||
for item in self.get("items"):
|
for item in self.get("items"):
|
||||||
item.update(get_bin_details(item.item_code, item.s_warehouse))
|
item.update(get_bin_details(item.item_code, item.s_warehouse))
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user