fix: merge similar entries for serialized items in stock reconciliation (#19408)
This commit is contained in:
parent
3a72cb46bc
commit
ba8fc21594
@ -52,9 +52,10 @@ class StockReconciliation(StockController):
|
|||||||
def _changed(item):
|
def _changed(item):
|
||||||
item_dict = get_stock_balance_for(item.item_code, item.warehouse,
|
item_dict = get_stock_balance_for(item.item_code, item.warehouse,
|
||||||
self.posting_date, self.posting_time, batch_no=item.batch_no)
|
self.posting_date, self.posting_time, batch_no=item.batch_no)
|
||||||
if (((item.qty is None or item.qty==item_dict.get("qty")) and
|
|
||||||
(item.valuation_rate is None or item.valuation_rate==item_dict.get("rate")) and not item.serial_no)
|
if ((item.qty is None or item.qty==item_dict.get("qty")) and
|
||||||
or (item.serial_no and item.serial_no == item_dict.get("serial_nos"))):
|
(item.valuation_rate is None or item.valuation_rate==item_dict.get("rate")) and
|
||||||
|
(not item.serial_no or (item.serial_no == item_dict.get("serial_nos")) )):
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
# set default as current rates
|
# set default as current rates
|
||||||
@ -182,9 +183,11 @@ class StockReconciliation(StockController):
|
|||||||
from erpnext.stock.stock_ledger import get_previous_sle
|
from erpnext.stock.stock_ledger import get_previous_sle
|
||||||
|
|
||||||
sl_entries = []
|
sl_entries = []
|
||||||
|
has_serial_no = False
|
||||||
for row in self.items:
|
for row in self.items:
|
||||||
item = frappe.get_doc("Item", row.item_code)
|
item = frappe.get_doc("Item", row.item_code)
|
||||||
if item.has_serial_no or item.has_batch_no:
|
if item.has_serial_no or item.has_batch_no:
|
||||||
|
has_serial_no = True
|
||||||
self.get_sle_for_serialized_items(row, sl_entries)
|
self.get_sle_for_serialized_items(row, sl_entries)
|
||||||
else:
|
else:
|
||||||
previous_sle = get_previous_sle({
|
previous_sle = get_previous_sle({
|
||||||
@ -212,8 +215,14 @@ class StockReconciliation(StockController):
|
|||||||
sl_entries.append(self.get_sle_for_items(row))
|
sl_entries.append(self.get_sle_for_items(row))
|
||||||
|
|
||||||
if sl_entries:
|
if sl_entries:
|
||||||
|
if has_serial_no:
|
||||||
|
sl_entries = self.merge_similar_item_serial_nos(sl_entries)
|
||||||
|
|
||||||
self.make_sl_entries(sl_entries)
|
self.make_sl_entries(sl_entries)
|
||||||
|
|
||||||
|
if has_serial_no and sl_entries:
|
||||||
|
self.update_valuation_rate_for_serial_no()
|
||||||
|
|
||||||
def get_sle_for_serialized_items(self, row, sl_entries):
|
def get_sle_for_serialized_items(self, row, sl_entries):
|
||||||
from erpnext.stock.stock_ledger import get_previous_sle
|
from erpnext.stock.stock_ledger import get_previous_sle
|
||||||
|
|
||||||
@ -275,8 +284,18 @@ class StockReconciliation(StockController):
|
|||||||
# update valuation rate
|
# update valuation rate
|
||||||
self.update_valuation_rate_for_serial_nos(row, serial_nos)
|
self.update_valuation_rate_for_serial_nos(row, serial_nos)
|
||||||
|
|
||||||
|
def update_valuation_rate_for_serial_no(self):
|
||||||
|
for d in self.items:
|
||||||
|
if not d.serial_no: continue
|
||||||
|
|
||||||
|
serial_nos = get_serial_nos(d.serial_no)
|
||||||
|
self.update_valuation_rate_for_serial_nos(d, serial_nos)
|
||||||
|
|
||||||
def update_valuation_rate_for_serial_nos(self, row, serial_nos):
|
def update_valuation_rate_for_serial_nos(self, row, serial_nos):
|
||||||
valuation_rate = row.valuation_rate if self.docstatus == 1 else row.current_valuation_rate
|
valuation_rate = row.valuation_rate if self.docstatus == 1 else row.current_valuation_rate
|
||||||
|
if valuation_rate is None:
|
||||||
|
return
|
||||||
|
|
||||||
for d in serial_nos:
|
for d in serial_nos:
|
||||||
frappe.db.set_value("Serial No", d, 'purchase_rate', valuation_rate)
|
frappe.db.set_value("Serial No", d, 'purchase_rate', valuation_rate)
|
||||||
|
|
||||||
@ -321,11 +340,17 @@ class StockReconciliation(StockController):
|
|||||||
where voucher_type=%s and voucher_no=%s""", (self.doctype, self.name))
|
where voucher_type=%s and voucher_no=%s""", (self.doctype, self.name))
|
||||||
|
|
||||||
sl_entries = []
|
sl_entries = []
|
||||||
|
|
||||||
|
has_serial_no = False
|
||||||
for row in self.items:
|
for row in self.items:
|
||||||
if row.serial_no or row.batch_no or row.current_serial_no:
|
if row.serial_no or row.batch_no or row.current_serial_no:
|
||||||
|
has_serial_no = True
|
||||||
self.get_sle_for_serialized_items(row, sl_entries)
|
self.get_sle_for_serialized_items(row, sl_entries)
|
||||||
|
|
||||||
if sl_entries:
|
if sl_entries:
|
||||||
|
if has_serial_no:
|
||||||
|
sl_entries = self.merge_similar_item_serial_nos(sl_entries)
|
||||||
|
|
||||||
sl_entries.reverse()
|
sl_entries.reverse()
|
||||||
allow_negative_stock = frappe.db.get_value("Stock Settings", None, "allow_negative_stock")
|
allow_negative_stock = frappe.db.get_value("Stock Settings", None, "allow_negative_stock")
|
||||||
self.make_sl_entries(sl_entries, allow_negative_stock=allow_negative_stock)
|
self.make_sl_entries(sl_entries, allow_negative_stock=allow_negative_stock)
|
||||||
@ -339,6 +364,35 @@ class StockReconciliation(StockController):
|
|||||||
"posting_time": self.posting_time
|
"posting_time": self.posting_time
|
||||||
})
|
})
|
||||||
|
|
||||||
|
def merge_similar_item_serial_nos(self, sl_entries):
|
||||||
|
# If user has put the same item in multiple row with different serial no
|
||||||
|
new_sl_entries = []
|
||||||
|
merge_similar_entries = {}
|
||||||
|
|
||||||
|
for d in sl_entries:
|
||||||
|
if not d.serial_no or d.actual_qty < 0:
|
||||||
|
new_sl_entries.append(d)
|
||||||
|
continue
|
||||||
|
|
||||||
|
key = (d.item_code, d.warehouse)
|
||||||
|
if key not in merge_similar_entries:
|
||||||
|
merge_similar_entries[key] = d
|
||||||
|
elif d.serial_no:
|
||||||
|
data = merge_similar_entries[key]
|
||||||
|
data.actual_qty += d.actual_qty
|
||||||
|
data.qty_after_transaction += d.qty_after_transaction
|
||||||
|
|
||||||
|
data.valuation_rate = (data.valuation_rate + d.valuation_rate) / data.actual_qty
|
||||||
|
data.serial_no += '\n' + d.serial_no
|
||||||
|
|
||||||
|
if data.incoming_rate:
|
||||||
|
data.incoming_rate = (data.incoming_rate + d.incoming_rate) / data.actual_qty
|
||||||
|
|
||||||
|
for key, value in merge_similar_entries.items():
|
||||||
|
new_sl_entries.append(value)
|
||||||
|
|
||||||
|
return new_sl_entries
|
||||||
|
|
||||||
def get_gl_entries(self, warehouse_account=None):
|
def get_gl_entries(self, warehouse_account=None):
|
||||||
if not self.cost_center:
|
if not self.cost_center:
|
||||||
msgprint(_("Please enter Cost Center"), raise_exception=1)
|
msgprint(_("Please enter Cost Center"), raise_exception=1)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user