Skip to content

Commit 435c852

Browse files
rohitwaghchauremergify[bot]
authored andcommitted
chore: fix conflicts
Added a method to prepare stock reconciliation voucher-wise count and updated logic for handling stock reconciliation entries. (cherry picked from commit cc6fbde)
1 parent bba0a6d commit 435c852

1 file changed

Lines changed: 32 additions & 202 deletions

File tree

erpnext/stock/report/stock_balance/stock_balance.py

Lines changed: 32 additions & 202 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,8 @@
77

88
import frappe
99
from frappe import _
10-
<<<<<<< HEAD
1110
from frappe.query_builder import Order
12-
from frappe.query_builder.functions import Coalesce
13-
=======
1411
from frappe.query_builder.functions import Coalesce, Count
15-
>>>>>>> 0874cbc268 (fix: old stock reco entries causing issue in the stock balance report)
1612
from frappe.utils import add_days, cint, date_diff, flt, getdate
1713
from frappe.utils.nestedset import get_descendants_of
1814

@@ -159,6 +155,8 @@ def get_item_warehouse_map(self):
159155
if self.filters.get("show_stock_ageing_data"):
160156
self.sle_entries = self.sle_query.run(as_dict=True)
161157

158+
self.prepare_stock_reco_voucher_wise_count()
159+
162160
# HACK: This is required to avoid causing db query in flt
163161
_system_settings = frappe.get_cached_doc("System Settings")
164162
with frappe.db.unbuffered_cursor():
@@ -185,6 +183,30 @@ def get_item_warehouse_map(self):
185183

186184
return item_warehouse_map
187185

186+
def prepare_stock_reco_voucher_wise_count(self):
187+
self.stock_reco_voucher_wise_count = frappe._dict()
188+
189+
doctype = frappe.qb.DocType("Stock Ledger Entry")
190+
item = frappe.qb.DocType("Item")
191+
192+
query = (
193+
frappe.qb.from_(doctype)
194+
.inner_join(item)
195+
.on(doctype.item_code == item.name)
196+
.select(doctype.voucher_detail_no, Count(doctype.name).as_("count"))
197+
.where(
198+
(doctype.voucher_type == "Stock Reconciliation")
199+
& (doctype.docstatus < 2)
200+
& (doctype.is_cancelled == 0)
201+
& (item.has_serial_no == 1)
202+
)
203+
.groupby(doctype.voucher_detail_no)
204+
)
205+
206+
data = query.run(as_list=True)
207+
if data:
208+
self.stock_reco_voucher_wise_count = frappe._dict(data)
209+
188210
def get_sre_reserved_qty_details(self) -> dict:
189211
from erpnext.stock.doctype.stock_reservation_entry.stock_reservation_entry import (
190212
get_sre_reserved_qty_for_items_and_warehouses as get_reserved_qty_details,
@@ -203,9 +225,13 @@ def prepare_item_warehouse_map(self, item_warehouse_map, entry, group_by_key):
203225
qty_dict[field] = entry.get(field)
204226

205227
if entry.voucher_type == "Stock Reconciliation" and (
206-
not entry.batch_no and not entry.serial_no and not entry.serial_and_batch_bundle
228+
not entry.batch_no or entry.serial_no or entry.serial_and_batch_bundle
207229
):
208-
qty_diff = flt(entry.qty_after_transaction) - flt(qty_dict.bal_qty)
230+
if entry.serial_no and self.stock_reco_voucher_wise_count.get(entry.voucher_detail_no, 0) == 1:
231+
qty_dict.bal_qty = 0.0
232+
qty_diff = flt(entry.actual_qty)
233+
else:
234+
qty_diff = flt(entry.qty_after_transaction) - flt(qty_dict.bal_qty)
209235
else:
210236
qty_diff = flt(entry.actual_qty)
211237

@@ -342,202 +368,6 @@ def prepare_stock_ledger_entries(self):
342368

343369
self.sle_query = query
344370

345-
<<<<<<< HEAD
346-
=======
347-
def prepare_item_warehouse_map_for_current_period(self):
348-
self.opening_vouchers = self.get_opening_vouchers()
349-
350-
if self.filters.get("show_stock_ageing_data"):
351-
self.sle_entries = self.sle_query.run(as_dict=True)
352-
353-
self.prepare_stock_reco_voucher_wise_count()
354-
355-
# HACK: This is required to avoid causing db query in flt
356-
_system_settings = frappe.get_cached_doc("System Settings")
357-
with frappe.db.unbuffered_cursor():
358-
if not self.filters.get("show_stock_ageing_data"):
359-
self.sle_entries = self.sle_query.run(as_dict=True, as_iterator=True)
360-
361-
for entry in self.sle_entries:
362-
group_by_key = self.get_group_by_key(entry)
363-
if group_by_key not in self.item_warehouse_map:
364-
self.initialize_data(group_by_key, entry)
365-
366-
self.prepare_item_warehouse_map(entry, group_by_key)
367-
368-
self.item_warehouse_map = filter_items_with_no_transactions(
369-
self.item_warehouse_map, self.float_precision, self.inventory_dimensions
370-
)
371-
372-
def prepare_stock_reco_voucher_wise_count(self):
373-
self.stock_reco_voucher_wise_count = frappe._dict()
374-
375-
doctype = frappe.qb.DocType("Stock Ledger Entry")
376-
item = frappe.qb.DocType("Item")
377-
378-
query = (
379-
frappe.qb.from_(doctype)
380-
.inner_join(item)
381-
.on(doctype.item_code == item.name)
382-
.select(doctype.voucher_detail_no, Count(doctype.name).as_("count"))
383-
.where(
384-
(doctype.voucher_type == "Stock Reconciliation")
385-
& (doctype.docstatus < 2)
386-
& (doctype.is_cancelled == 0)
387-
& (item.has_serial_no == 1)
388-
)
389-
.groupby(doctype.voucher_detail_no)
390-
)
391-
392-
data = query.run(as_list=True)
393-
if data:
394-
self.stock_reco_voucher_wise_count = frappe._dict(data)
395-
396-
def prepare_new_data(self):
397-
if self.filters.get("show_stock_ageing_data"):
398-
self.filters["show_warehouse_wise_stock"] = True
399-
item_wise_fifo_queue = FIFOSlots(self.filters).generate()
400-
401-
_func = itemgetter(1)
402-
403-
del self.sle_entries
404-
405-
sre_details = self.get_sre_reserved_qty_details()
406-
407-
variant_values = {}
408-
if self.filters.get("show_variant_attributes"):
409-
variant_values = self.get_variant_values_for()
410-
411-
for _key, report_data in self.item_warehouse_map.items():
412-
if variant_data := variant_values.get(report_data.item_code):
413-
report_data.update(variant_data)
414-
415-
if self.filters.get("show_stock_ageing_data"):
416-
opening_fifo_queue = self.get_opening_fifo_queue(report_data) or []
417-
418-
fifo_queue = []
419-
if fifo_queue := item_wise_fifo_queue.get((report_data.item_code, report_data.warehouse)):
420-
fifo_queue = fifo_queue.get("fifo_queue")
421-
422-
if fifo_queue:
423-
opening_fifo_queue.extend(fifo_queue)
424-
425-
stock_ageing_data = {"average_age": 0, "earliest_age": 0, "latest_age": 0}
426-
427-
if opening_fifo_queue:
428-
fifo_queue = sorted(filter(_func, opening_fifo_queue), key=_func)
429-
if not fifo_queue:
430-
continue
431-
432-
to_date = self.to_date
433-
stock_ageing_data["average_age"] = get_average_age(fifo_queue, to_date)
434-
stock_ageing_data["earliest_age"] = date_diff(to_date, fifo_queue[0][1])
435-
stock_ageing_data["latest_age"] = date_diff(to_date, fifo_queue[-1][1])
436-
stock_ageing_data["fifo_queue"] = fifo_queue
437-
438-
report_data.update(stock_ageing_data)
439-
440-
report_data.update(
441-
{"reserved_stock": sre_details.get((report_data.item_code, report_data.warehouse), 0.0)}
442-
)
443-
444-
if (
445-
not self.filters.get("include_zero_stock_items")
446-
and report_data
447-
and report_data.bal_qty == 0
448-
and report_data.bal_val == 0
449-
):
450-
continue
451-
452-
self.data.append(report_data)
453-
454-
def get_sre_reserved_qty_details(self) -> dict:
455-
from erpnext.stock.doctype.stock_reservation_entry.stock_reservation_entry import (
456-
get_sre_reserved_qty_for_items_and_warehouses as get_reserved_qty_details,
457-
)
458-
459-
item_code_list, warehouse_list = [], []
460-
for d in self.item_warehouse_map:
461-
item_code_list.append(d[0])
462-
warehouse_list.append(d[1])
463-
464-
return get_reserved_qty_details(item_code_list, warehouse_list)
465-
466-
def prepare_item_warehouse_map(self, entry, group_by_key):
467-
qty_dict = self.item_warehouse_map[group_by_key]
468-
for field in self.inventory_dimensions:
469-
qty_dict[field] = entry.get(field)
470-
471-
if entry.voucher_type == "Stock Reconciliation" and (
472-
not entry.batch_no or entry.serial_no or entry.serial_and_batch_bundle
473-
):
474-
if entry.serial_no and self.stock_reco_voucher_wise_count.get(entry.voucher_detail_no, 0) == 1:
475-
qty_dict.bal_qty = 0.0
476-
qty_diff = flt(entry.actual_qty)
477-
else:
478-
qty_diff = flt(entry.qty_after_transaction) - flt(qty_dict.bal_qty)
479-
else:
480-
qty_diff = flt(entry.actual_qty)
481-
482-
value_diff = flt(entry.stock_value_difference)
483-
484-
if entry.posting_date < self.from_date or entry.voucher_no in self.opening_vouchers.get(
485-
entry.voucher_type, []
486-
):
487-
qty_dict.opening_qty += qty_diff
488-
qty_dict.opening_val += value_diff
489-
490-
elif entry.posting_date >= self.from_date and entry.posting_date <= self.to_date:
491-
if flt(qty_diff, self.float_precision) >= 0:
492-
qty_dict.in_qty += qty_diff
493-
else:
494-
qty_dict.out_qty += abs(qty_diff)
495-
496-
if flt(value_diff, self.float_precision) >= 0:
497-
qty_dict.in_val += value_diff
498-
else:
499-
qty_dict.out_val += abs(value_diff)
500-
501-
qty_dict.val_rate = entry.valuation_rate
502-
qty_dict.bal_qty += qty_diff
503-
qty_dict.bal_val += value_diff
504-
505-
def initialize_data(self, group_by_key, entry):
506-
self.item_warehouse_map[group_by_key] = frappe._dict(
507-
{
508-
"item_code": entry.item_code,
509-
"warehouse": entry.warehouse,
510-
"item_group": entry.item_group,
511-
"company": entry.company,
512-
"currency": self.company_currency,
513-
"stock_uom": entry.stock_uom,
514-
"item_name": entry.item_name,
515-
"opening_qty": 0.0,
516-
"opening_val": 0.0,
517-
"opening_fifo_queue": [],
518-
"in_qty": 0.0,
519-
"in_val": 0.0,
520-
"out_qty": 0.0,
521-
"out_val": 0.0,
522-
"bal_qty": 0.0,
523-
"bal_val": 0.0,
524-
"val_rate": 0.0,
525-
}
526-
)
527-
528-
def get_group_by_key(self, row) -> tuple:
529-
group_by_key = [row.item_code, row.warehouse]
530-
531-
for fieldname in self.inventory_dimensions:
532-
if not row.get(fieldname):
533-
continue
534-
535-
if self.filters.get(fieldname) or self.filters.get("show_dimension_wise_stock"):
536-
group_by_key.append(row.get(fieldname))
537-
538-
return tuple(group_by_key)
539-
540-
>>>>>>> 0874cbc268 (fix: old stock reco entries causing issue in the stock balance report)
541371
def apply_inventory_dimensions_filters(self, query, sle) -> str:
542372
inventory_dimension_fields = self.get_inventory_dimension_fields()
543373
if inventory_dimension_fields:

0 commit comments

Comments
 (0)