diff --git a/erpnext/stock/deprecated_serial_batch.py b/erpnext/stock/deprecated_serial_batch.py index e43e6f21c92c..d10833b6d463 100644 --- a/erpnext/stock/deprecated_serial_batch.py +++ b/erpnext/stock/deprecated_serial_batch.py @@ -1,3 +1,6 @@ +import datetime +from collections import defaultdict + import frappe from frappe.query_builder.functions import CombineDatetime, Sum from frappe.utils import flt @@ -8,12 +11,7 @@ class DeprecatedSerialNoValuation: @deprecated def calculate_stock_value_from_deprecarated_ledgers(self): - if not frappe.db.get_all( - "Stock Ledger Entry", - fields=["name"], - filters={"serial_no": ("is", "set"), "is_cancelled": 0, "item_code": self.sle.item_code}, - limit=1, - ): + if not has_sle_for_serial_nos(self.sle.item_code): return serial_nos = self.get_filterd_serial_nos() @@ -82,6 +80,20 @@ def get_incoming_value_for_serial_nos(self, serial_nos): return incoming_values +@frappe.request_cache +def has_sle_for_serial_nos(item_code): + serial_nos = frappe.db.get_all( + "Stock Ledger Entry", + fields=["name"], + filters={"serial_no": ("is", "set"), "is_cancelled": 0, "item_code": item_code}, + limit=1, + ) + if serial_nos: + return True + + return False + + class DeprecatedBatchNoValuation: @deprecated def calculate_avg_rate_from_deprecarated_ledgers(self): @@ -92,19 +104,25 @@ def calculate_avg_rate_from_deprecarated_ledgers(self): @deprecated def get_sle_for_batches(self): + from erpnext.stock.utils import get_combine_datetime + if not self.batchwise_valuation_batches: return [] sle = frappe.qb.DocType("Stock Ledger Entry") - timestamp_condition = CombineDatetime(sle.posting_date, sle.posting_time) < CombineDatetime( - self.sle.posting_date, self.sle.posting_time - ) - if self.sle.creation: - timestamp_condition |= ( - CombineDatetime(sle.posting_date, sle.posting_time) - == CombineDatetime(self.sle.posting_date, self.sle.posting_time) - ) & (sle.creation < self.sle.creation) + timestamp_condition = None + if self.sle.posting_date and self.sle.posting_time: + posting_datetime = get_combine_datetime(self.sle.posting_date, self.sle.posting_time) + if not self.sle.creation: + posting_datetime = posting_datetime + datetime.timedelta(milliseconds=1) + + timestamp_condition = sle.posting_datetime < posting_datetime + + if self.sle.creation: + timestamp_condition |= (sle.posting_datetime == posting_datetime) & ( + sle.creation < self.sle.creation + ) query = ( frappe.qb.from_(sle) @@ -120,10 +138,12 @@ def get_sle_for_batches(self): & (sle.batch_no.isnotnull()) & (sle.is_cancelled == 0) ) - .where(timestamp_condition) .groupby(sle.batch_no) ) + if timestamp_condition: + query = query.where(timestamp_condition) + if self.sle.name: query = query.where(sle.name != self.sle.name) @@ -134,8 +154,8 @@ def calculate_avg_rate_for_non_batchwise_valuation(self): if not self.non_batchwise_valuation_batches: return - self.non_batchwise_balance_value = 0.0 - self.non_batchwise_balance_qty = 0.0 + self.non_batchwise_balance_value = defaultdict(float) + self.non_batchwise_balance_qty = defaultdict(float) self.set_balance_value_for_non_batchwise_valuation_batches() @@ -146,12 +166,12 @@ def calculate_avg_rate_for_non_batchwise_valuation(self): if not self.non_batchwise_balance_qty: continue - if self.non_batchwise_balance_value == 0: + if self.non_batchwise_balance_qty.get(batch_no) == 0: self.batch_avg_rate[batch_no] = 0.0 self.stock_value_differece[batch_no] = 0.0 else: self.batch_avg_rate[batch_no] = ( - self.non_batchwise_balance_value / self.non_batchwise_balance_qty + self.non_batchwise_balance_value[batch_no] / self.non_batchwise_balance_qty[batch_no] ) self.stock_value_differece[batch_no] = self.non_batchwise_balance_value @@ -174,17 +194,21 @@ def set_balance_value_for_non_batchwise_valuation_batches(self): @deprecated def set_balance_value_from_sl_entries(self) -> None: + from erpnext.stock.utils import get_combine_datetime + sle = frappe.qb.DocType("Stock Ledger Entry") batch = frappe.qb.DocType("Batch") - timestamp_condition = CombineDatetime(sle.posting_date, sle.posting_time) < CombineDatetime( - self.sle.posting_date, self.sle.posting_time - ) + posting_datetime = get_combine_datetime(self.sle.posting_date, self.sle.posting_time) + if not self.sle.creation: + posting_datetime = posting_datetime + datetime.timedelta(milliseconds=1) + + timestamp_condition = sle.posting_datetime < posting_datetime + if self.sle.creation: - timestamp_condition |= ( - CombineDatetime(sle.posting_date, sle.posting_time) - == CombineDatetime(self.sle.posting_date, self.sle.posting_time) - ) & (sle.creation < self.sle.creation) + timestamp_condition |= (sle.posting_datetime == posting_datetime) & ( + sle.creation < self.sle.creation + ) query = ( frappe.qb.from_(sle) @@ -201,6 +225,7 @@ def set_balance_value_from_sl_entries(self) -> None: & (sle.batch_no.isnotnull()) & (batch.use_batchwise_valuation == 0) & (sle.is_cancelled == 0) + & (sle.batch_no.isin(self.non_batchwise_valuation_batches)) ) .where(timestamp_condition) .groupby(sle.batch_no) @@ -210,8 +235,8 @@ def set_balance_value_from_sl_entries(self) -> None: query = query.where(sle.name != self.sle.name) for d in query.run(as_dict=True): - self.non_batchwise_balance_value += flt(d.batch_value) - self.non_batchwise_balance_qty += flt(d.batch_qty) + self.non_batchwise_balance_value[d.batch_no] += flt(d.batch_value) + self.non_batchwise_balance_qty[d.batch_no] += flt(d.batch_qty) self.available_qty[d.batch_no] += flt(d.batch_qty) @deprecated @@ -249,6 +274,7 @@ def set_balance_value_from_bundle(self) -> None: & (bundle.is_cancelled == 0) & (bundle.docstatus == 1) & (bundle.type_of_transaction.isin(["Inward", "Outward"])) + & (bundle_child.batch_no.isin(self.non_batchwise_valuation_batches)) ) .where(timestamp_condition) .groupby(bundle_child.batch_no) @@ -260,6 +286,6 @@ def set_balance_value_from_bundle(self) -> None: query = query.where(bundle.voucher_type != "Pick List") for d in query.run(as_dict=True): - self.non_batchwise_balance_value += flt(d.batch_value) - self.non_batchwise_balance_qty += flt(d.batch_qty) + self.non_batchwise_balance_value[d.batch_no] += flt(d.batch_value) + self.non_batchwise_balance_qty[d.batch_no] += flt(d.batch_qty) self.available_qty[d.batch_no] += flt(d.batch_qty) diff --git a/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py index a41db6cf611e..48d67c2cf465 100644 --- a/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py +++ b/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py @@ -647,7 +647,7 @@ def test_serial_no_batch_no_item(self): "has_serial_no": 1, "has_batch_no": 1, "serial_no_series": "SRS9.####", - "batch_number_series": "BNS9.####", + "batch_number_series": "BNS90.####", "create_new_batch": 1, }, ) @@ -680,7 +680,7 @@ def test_backdated_stock_reco_entry(self): { "is_stock_item": 1, "has_batch_no": 1, - "batch_number_series": "BNS9.####", + "batch_number_series": "BNS91.####", "create_new_batch": 1, }, ).name diff --git a/erpnext/stock/utils.py b/erpnext/stock/utils.py index eca01a576402..f2388e5737aa 100644 --- a/erpnext/stock/utils.py +++ b/erpnext/stock/utils.py @@ -276,11 +276,7 @@ def get_incoming_rate(args, raise_error_if_no_rate=True): sn_obj = SerialNoValuation(sle=args, warehouse=args.get("warehouse"), item_code=args.get("item_code")) return sn_obj.get_incoming_rate() - elif ( - args.get("batch_no") - and frappe.db.get_value("Batch", args.get("batch_no"), "use_batchwise_valuation", cache=True) - and not args.get("serial_and_batch_bundle") - ): + elif args.get("batch_no") and not args.get("serial_and_batch_bundle"): args.actual_qty = args.qty args.batch_nos = frappe._dict({args.batch_no: args}) diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt/test_subcontracting_receipt.py b/erpnext/subcontracting/doctype/subcontracting_receipt/test_subcontracting_receipt.py index 81662a6257bf..0f5fe7ab9580 100644 --- a/erpnext/subcontracting/doctype/subcontracting_receipt/test_subcontracting_receipt.py +++ b/erpnext/subcontracting/doctype/subcontracting_receipt/test_subcontracting_receipt.py @@ -623,8 +623,8 @@ def test_subcontracting_receipt_valuation_with_auto_created_serial_batch_bundle( "has_batch_no": 1, "has_serial_no": 1, "create_new_batch": 1, - "batch_number_series": "BNGS-.####", - "serial_no_series": "BNSS-.####", + "batch_number_series": "BNGS0-.####", + "serial_no_series": "BNSS90-.####", } ).name @@ -715,8 +715,8 @@ def test_subcontracting_receipt_valuation_for_fg_with_auto_created_serial_batch_ "has_batch_no": 1, "has_serial_no": 1, "create_new_batch": 1, - "batch_number_series": "BNGS-.####", - "serial_no_series": "BNSS-.####", + "batch_number_series": "BNGS91-.####", + "serial_no_series": "BNSS91-.####", } ).name