Merge pull request #45486 from rohitwaghchaure/fixed-SABB-performance-issue

perf: stock entry with batch
This commit is contained in:
rohitwaghchaure
2025-01-29 20:49:09 +05:30
committed by GitHub
5 changed files with 63 additions and 50 deletions

View File

@@ -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)

View File

@@ -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))

View File

@@ -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

View File

@@ -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

View File

@@ -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",
)