mirror of
https://github.com/frappe/erpnext.git
synced 2026-02-17 00:25:01 +00:00
Merge pull request #45486 from rohitwaghchaure/fixed-SABB-performance-issue
perf: stock entry with batch
This commit is contained in:
@@ -238,9 +238,6 @@ class TestPOSClosingEntry(IntegrationTestCase):
|
||||
pos_inv2.payments[0].amount = pos_inv2.grand_total
|
||||
pos_inv2.submit()
|
||||
|
||||
batch_qty = frappe.db.get_value("Batch", batch_no, "batch_qty")
|
||||
self.assertEqual(batch_qty, 10)
|
||||
|
||||
batch_qty_with_pos = get_batch_qty(batch_no, "_Test Warehouse - _TC", item_code)
|
||||
self.assertEqual(batch_qty_with_pos, 0.0)
|
||||
|
||||
@@ -270,9 +267,6 @@ class TestPOSClosingEntry(IntegrationTestCase):
|
||||
pcv_doc.reload()
|
||||
pcv_doc.cancel()
|
||||
|
||||
batch_qty = frappe.db.get_value("Batch", batch_no, "batch_qty")
|
||||
self.assertEqual(batch_qty, 10)
|
||||
|
||||
batch_qty_with_pos = get_batch_qty(batch_no, "_Test Warehouse - _TC", item_code)
|
||||
self.assertEqual(batch_qty_with_pos, 0.0)
|
||||
|
||||
|
||||
@@ -924,9 +924,11 @@ class StockController(AccountsController):
|
||||
row.db_set(dimension.source_fieldname, sl_dict[dimension.target_fieldname])
|
||||
|
||||
def make_sl_entries(self, sl_entries, allow_negative_stock=False, via_landed_cost_voucher=False):
|
||||
from erpnext.stock.serial_batch_bundle import update_batch_qty
|
||||
from erpnext.stock.stock_ledger import make_sl_entries
|
||||
|
||||
make_sl_entries(sl_entries, allow_negative_stock, via_landed_cost_voucher)
|
||||
update_batch_qty(self.doctype, self.name, via_landed_cost_voucher=via_landed_cost_voucher)
|
||||
|
||||
def make_gl_entries_on_cancel(self):
|
||||
cancel_exchange_gain_loss_journal(frappe._dict(doctype=self.doctype, name=self.name))
|
||||
|
||||
@@ -455,10 +455,14 @@ def get_available_batches(kwargs):
|
||||
|
||||
batches = get_auto_batch_nos(kwargs)
|
||||
for batch in batches:
|
||||
if batch.get("batch_no") not in batchwise_qty:
|
||||
batchwise_qty[batch.get("batch_no")] = batch.get("qty")
|
||||
key = batch.get("batch_no")
|
||||
if kwargs.get("based_on_warehouse"):
|
||||
key = (batch.get("batch_no"), batch.get("warehouse"))
|
||||
|
||||
if key not in batchwise_qty:
|
||||
batchwise_qty[key] = batch.get("qty")
|
||||
else:
|
||||
batchwise_qty[batch.get("batch_no")] += batch.get("qty")
|
||||
batchwise_qty[key] += batch.get("qty")
|
||||
|
||||
return batchwise_qty
|
||||
|
||||
|
||||
@@ -101,7 +101,10 @@ class SerialandBatchBundle(Document):
|
||||
self.set_is_outward()
|
||||
self.calculate_total_qty()
|
||||
self.set_warehouse()
|
||||
self.set_incoming_rate()
|
||||
|
||||
if self.voucher_type != "Stock Entry" or not self.voucher_no or self.docstatus == 1:
|
||||
self.set_incoming_rate()
|
||||
|
||||
self.calculate_qty_and_amount()
|
||||
|
||||
def allow_existing_serial_nos(self):
|
||||
@@ -1026,7 +1029,6 @@ class SerialandBatchBundle(Document):
|
||||
self.set_purchase_document_no()
|
||||
|
||||
def on_submit(self):
|
||||
self.validate_batch_inventory()
|
||||
self.validate_serial_nos_inventory()
|
||||
|
||||
def set_purchase_document_no(self):
|
||||
@@ -1053,25 +1055,9 @@ class SerialandBatchBundle(Document):
|
||||
self.validate_batch_inventory()
|
||||
|
||||
def validate_batch_inventory(self):
|
||||
if (
|
||||
self.voucher_type in ["Purchase Invoice", "Purchase Receipt"]
|
||||
and frappe.db.get_value(self.voucher_type, self.voucher_no, "docstatus") == 1
|
||||
):
|
||||
return
|
||||
|
||||
if self.voucher_type in ["Sales Invoice", "Delivery Note"] and self.type_of_transaction == "Inward":
|
||||
return
|
||||
|
||||
if not self.has_batch_no:
|
||||
return
|
||||
|
||||
if (
|
||||
self.voucher_type == "Stock Reconciliation"
|
||||
and self.type_of_transaction == "Outward"
|
||||
and frappe.db.get_value("Stock Reconciliation Item", self.voucher_detail_no, "qty") > 0
|
||||
):
|
||||
return
|
||||
|
||||
batches = [d.batch_no for d in self.entries if d.batch_no]
|
||||
if not batches:
|
||||
return
|
||||
|
||||
@@ -302,9 +302,6 @@ class SerialBatchBundle:
|
||||
):
|
||||
self.set_batch_no_in_serial_nos()
|
||||
|
||||
if self.item_details.has_batch_no == 1:
|
||||
self.update_batch_qty()
|
||||
|
||||
if self.sle.is_cancelled and self.sle.serial_and_batch_bundle:
|
||||
self.cancel_serial_and_batch_bundle()
|
||||
|
||||
@@ -410,26 +407,6 @@ class SerialBatchBundle:
|
||||
.where(sn_table.name.isin(serial_nos))
|
||||
).run()
|
||||
|
||||
def update_batch_qty(self):
|
||||
from erpnext.stock.doctype.batch.batch import get_available_batches
|
||||
|
||||
batches = get_batch_nos(self.sle.serial_and_batch_bundle)
|
||||
if not self.sle.serial_and_batch_bundle and self.sle.batch_no:
|
||||
batches = frappe._dict({self.sle.batch_no: self.sle.actual_qty})
|
||||
|
||||
batches_qty = get_available_batches(
|
||||
frappe._dict(
|
||||
{
|
||||
"item_code": self.item_code,
|
||||
"batch_no": list(batches.keys()),
|
||||
"consider_negative_batches": 1,
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
for batch_no in batches:
|
||||
frappe.db.set_value("Batch", batch_no, "batch_qty", batches_qty.get(batch_no, 0))
|
||||
|
||||
|
||||
def get_serial_nos(serial_and_batch_bundle, serial_nos=None):
|
||||
if not serial_and_batch_bundle:
|
||||
@@ -1258,3 +1235,53 @@ def get_serial_nos_batch(serial_nos):
|
||||
as_list=1,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def update_batch_qty(voucher_type, voucher_no, via_landed_cost_voucher=False):
|
||||
from erpnext.stock.doctype.batch.batch import get_available_batches
|
||||
|
||||
batches = get_distinct_batches(voucher_type, voucher_no)
|
||||
if not batches:
|
||||
return
|
||||
|
||||
precision = frappe.get_precision("Batch", "batch_qty")
|
||||
batch_data = get_available_batches(
|
||||
frappe._dict({"batch_no": batches, "consider_negative_batches": 1, "based_on_warehouse": True})
|
||||
)
|
||||
batchwise_qty = defaultdict(float)
|
||||
|
||||
for (batch_no, warehouse), qty in batch_data.items():
|
||||
if not via_landed_cost_voucher and flt(qty, precision) < 0:
|
||||
throw_negative_batch_validation(batch_no, warehouse, qty)
|
||||
|
||||
batchwise_qty[batch_no] += qty
|
||||
|
||||
for batch_no in batches:
|
||||
qty = flt(batchwise_qty.get(batch_no, 0), precision)
|
||||
frappe.db.set_value("Batch", batch_no, "batch_qty", qty)
|
||||
|
||||
|
||||
def throw_negative_batch_validation(batch_no, warehouse, qty):
|
||||
frappe.throw(
|
||||
_("The Batch {0} has negative quantity {1} in warehouse {2}. Please correct the quantity.").format(
|
||||
bold(batch_no), bold(qty), bold(warehouse)
|
||||
),
|
||||
title=_("Negative Batch Quantity"),
|
||||
)
|
||||
|
||||
|
||||
def get_distinct_batches(voucher_type, voucher_no):
|
||||
bundles = frappe.get_all(
|
||||
"Serial and Batch Bundle",
|
||||
filters={"voucher_no": voucher_no, "voucher_type": voucher_type},
|
||||
pluck="name",
|
||||
)
|
||||
if not bundles:
|
||||
return
|
||||
|
||||
return frappe.get_all(
|
||||
"Serial and Batch Entry",
|
||||
filters={"parent": ("in", bundles), "batch_no": ("is", "set")},
|
||||
group_by="batch_no",
|
||||
pluck="batch_no",
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user