Skip to content

Commit dd0613a

Browse files
kavin-114rohitwaghchaure
authored andcommitted
fix(stock): handle legacy single sle recon entries
(cherry picked from commit 7e6bbcc)
1 parent d723751 commit dd0613a

1 file changed

Lines changed: 65 additions & 6 deletions

File tree

erpnext/stock/report/stock_ageing/stock_ageing.py

Lines changed: 65 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
import frappe
99
from frappe import _
10+
from frappe.query_builder.functions import Count
1011
from frappe.utils import cint, date_diff, flt, get_datetime
1112

1213
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
@@ -240,9 +241,9 @@ def generate(self) -> dict:
240241
Returns dict of the foll.g structure:
241242
Key = Item A / (Item A, Warehouse A)
242243
Key: {
243-
'details' -> Dict: ** item details **,
244-
'fifo_queue' -> List: ** list of lists containing entries/slots for existing stock,
245-
consumed/updated and maintained via FIFO. **
244+
'details' -> Dict: ** item details **,
245+
'fifo_queue' -> List: ** list of lists containing entries/slots for existing stock,
246+
consumed/updated and maintained via FIFO. **
246247
}
247248
"""
248249
from erpnext.stock.serial_batch_bundle import get_serial_nos_from_bundle
@@ -253,16 +254,33 @@ def generate(self) -> dict:
253254
if stock_ledger_entries is None:
254255
bundle_wise_serial_nos = self.__get_bundle_wise_serial_nos()
255256

257+
# prepare single sle voucher detail lookup
258+
self.prepare_stock_reco_voucher_wise_count()
259+
256260
with frappe.db.unbuffered_cursor():
257261
if stock_ledger_entries is None:
258262
stock_ledger_entries = self.__get_stock_ledger_entries()
259263

260264
for d in stock_ledger_entries:
261265
key, fifo_queue, transferred_item_key = self.__init_key_stores(d)
266+
prev_balance_qty = self.item_details[key].get("qty_after_transaction", 0)
267+
268+
if d.voucher_type == "Stock Reconciliation" and (
269+
not d.batch_no or d.serial_no or d.serial_and_batch_bundle
270+
):
271+
if d.voucher_detail_no in self.stock_reco_voucher_wise_count:
272+
# for legacy recon with single sle has qty_after_transaction and stock_value_difference without outward entry
273+
# for exisitng handle emptying the existing queue and details.
274+
d.stock_value_difference = flt(d.qty_after_transaction * d.valuation_rate)
275+
d.actual_qty = d.qty_after_transaction
276+
self.item_details[key]["qty_after_transaction"] = 0
277+
self.item_details[key]["total_qty"] = 0
278+
fifo_queue.clear()
279+
else:
280+
d.actual_qty = flt(d.qty_after_transaction) - flt(prev_balance_qty)
262281

263-
if d.voucher_type == "Stock Reconciliation":
282+
elif d.voucher_type == "Stock Reconciliation":
264283
# get difference in qty shift as actual qty
265-
prev_balance_qty = self.item_details[key].get("qty_after_transaction", 0)
266284
d.actual_qty = flt(d.qty_after_transaction) - flt(prev_balance_qty)
267285

268286
serial_nos = get_serial_nos(d.serial_no) if d.serial_no else []
@@ -280,6 +298,14 @@ def generate(self) -> dict:
280298

281299
self.__update_balances(d, key)
282300

301+
# handle serial nos misconsumption
302+
if d.has_serial_no:
303+
qty_after = cint(self.item_details[key]["qty_after_transaction"])
304+
if qty_after <= 0:
305+
fifo_queue.clear()
306+
elif len(fifo_queue) > qty_after:
307+
fifo_queue[:] = fifo_queue[:qty_after]
308+
283309
# Note that stock_ledger_entries is an iterator, you can not reuse it like a list
284310
del stock_ledger_entries
285311

@@ -406,7 +432,6 @@ def add_to_fifo_queue(slot):
406432

407433
def __update_balances(self, row: dict, key: tuple | str):
408434
self.item_details[key]["qty_after_transaction"] = row.qty_after_transaction
409-
410435
if "total_qty" not in self.item_details[key]:
411436
self.item_details[key]["total_qty"] = row.actual_qty
412437
else:
@@ -462,6 +487,7 @@ def __get_stock_ledger_entries(self) -> Iterator[dict]:
462487
sle.posting_date,
463488
sle.voucher_type,
464489
sle.voucher_no,
490+
sle.voucher_detail_no,
465491
sle.serial_no,
466492
sle.batch_no,
467493
sle.qty_after_transaction,
@@ -558,3 +584,36 @@ def __get_warehouse_conditions(self, sle, sle_query) -> str:
558584
warehouse_results = [x[0] for x in warehouse_results]
559585

560586
return sle_query.where(sle.warehouse.isin(warehouse_results))
587+
588+
def prepare_stock_reco_voucher_wise_count(self):
589+
self.stock_reco_voucher_wise_count = frappe._dict()
590+
591+
doctype = frappe.qb.DocType("Stock Ledger Entry")
592+
item = frappe.qb.DocType("Item")
593+
594+
query = (
595+
frappe.qb.from_(doctype)
596+
.inner_join(item)
597+
.on(doctype.item_code == item.name)
598+
.select(doctype.voucher_detail_no, Count(doctype.name).as_("count"))
599+
.where(
600+
(doctype.voucher_type == "Stock Reconciliation")
601+
& (doctype.docstatus < 2)
602+
& (doctype.is_cancelled == 0)
603+
)
604+
.groupby(doctype.voucher_detail_no)
605+
)
606+
607+
data = query.run(as_dict=True)
608+
if not data:
609+
return
610+
611+
for row in data:
612+
if row.count != 1:
613+
continue
614+
615+
sr_item = frappe.db.get_value(
616+
"Stock Reconciliation Item", row.voucher_detail_no, ["current_qty", "qty"], as_dict=True
617+
)
618+
if sr_item.qty and sr_item.current_qty:
619+
self.stock_reco_voucher_wise_count[row.voucher_detail_no] = sr_item.current_qty

0 commit comments

Comments
 (0)