diff --git a/erpnext/stock/report/incorrect_serial_no_valuation/incorrect_serial_no_valuation.py b/erpnext/stock/report/incorrect_serial_no_valuation/incorrect_serial_no_valuation.py index 39d84a7d5bed93bd56713e41629e2d5b59d8fac2..9f597cede15f779e3546f5c1de60c75190115be7 100644 --- a/erpnext/stock/report/incorrect_serial_no_valuation/incorrect_serial_no_valuation.py +++ b/erpnext/stock/report/incorrect_serial_no_valuation/incorrect_serial_no_valuation.py @@ -18,16 +18,41 @@ def execute(filters=None): def get_data(filters): data = get_stock_ledger_entries(filters) - serial_nos_data = prepare_serial_nos(data) + bundles = get_bundles(data) + serial_nos_data = prepare_serial_nos(data, bundles) data = get_incorrect_serial_nos(serial_nos_data) return data -def prepare_serial_nos(data): +def get_bundles(data): + bundles = [d.serial_and_batch_bundle for d in data if d.serial_and_batch_bundle] + bundle_dict = frappe._dict() + serial_nos_data = frappe.get_all( + "Serial and Batch Entry", + fields=["parent", "serial_no", "incoming_rate", "qty"], + filters={"parent": ("in", bundles), "serial_no": ("is", "set")}, + ) + + for entry in serial_nos_data: + bundle_dict.setdefault(entry.parent, []).append(entry) + + return bundle_dict + + +def prepare_serial_nos(data, bundles): serial_no_wise_data = {} for row in data: - if not row.serial_nos: + if not row.serial_nos and not row.serial_and_batch_bundle: + continue + + if row.serial_and_batch_bundle: + for bundle in bundles.get(row.serial_and_batch_bundle, []): + sle = copy.deepcopy(row) + sle.serial_no = bundle.serial_no + sle.qty = bundle.qty + sle.valuation_rate = bundle.incoming_rate * (1 if sle.qty > 0 else -1) + serial_no_wise_data.setdefault(bundle.serial_no, []).append(sle) continue for serial_no in get_serial_nos(row.serial_nos): @@ -43,9 +68,7 @@ def prepare_serial_nos(data): def get_incorrect_serial_nos(serial_nos_data): result = [] - total_value = frappe._dict( - {"qty": 0, "valuation_rate": 0, "serial_no": frappe.bold(_("Balance"))} - ) + total_value = frappe._dict({"qty": 0, "valuation_rate": 0, "serial_no": frappe.bold(_("Balance"))}) for serial_no, data in serial_nos_data.items(): total_dict = frappe._dict({"qty": 0, "valuation_rate": 0, "serial_no": frappe.bold(_("Total"))}) @@ -56,6 +79,9 @@ def get_incorrect_serial_nos(serial_nos_data): total_value.qty += total_dict.qty total_value.valuation_rate += total_dict.valuation_rate + if total_dict.qty == 0 and abs(total_dict.valuation_rate) == 0: + continue + result.append(total_dict) result.append({}) @@ -83,6 +109,7 @@ def get_stock_ledger_entries(report_filters): "voucher_no", "item_code", "serial_no as serial_nos", + "serial_and_batch_bundle", "actual_qty", "posting_date", "posting_time", @@ -91,7 +118,8 @@ def get_stock_ledger_entries(report_filters): "(stock_value_difference / actual_qty) as valuation_rate", ] - filters = {"serial_no": ("is", "set"), "is_cancelled": 0} + filters = {"is_cancelled": 0} + or_filters = {"serial_no": ("is", "set"), "serial_and_batch_bundle": ("is", "set")} if report_filters.get("item_code"): filters["item_code"] = report_filters.get("item_code") @@ -106,6 +134,7 @@ def get_stock_ledger_entries(report_filters): "Stock Ledger Entry", fields=fields, filters=filters, + or_filters=or_filters, order_by="posting_date asc, posting_time asc, creation asc", )