From 8c2bfe1d5c0deee1011623d0af6382319e483028 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Wed, 11 May 2022 13:39:47 +0530 Subject: [PATCH 1/2] chore: fifo queue vs qty after transaction comparison report (cherry picked from commit f6d6463a33ce386823275d3dfc6ee957d85ed699) --- .../__init__.py | 0 ...eue_vs_qty_after_transaction_comparison.js | 53 +++++ ...e_vs_qty_after_transaction_comparison.json | 27 +++ ...eue_vs_qty_after_transaction_comparison.py | 212 ++++++++++++++++++ erpnext/stock/report/test_reports.py | 2 + 5 files changed, 294 insertions(+) create mode 100644 erpnext/stock/report/fifo_queue_vs_qty_after_transaction_comparison/__init__.py create mode 100644 erpnext/stock/report/fifo_queue_vs_qty_after_transaction_comparison/fifo_queue_vs_qty_after_transaction_comparison.js create mode 100644 erpnext/stock/report/fifo_queue_vs_qty_after_transaction_comparison/fifo_queue_vs_qty_after_transaction_comparison.json create mode 100644 erpnext/stock/report/fifo_queue_vs_qty_after_transaction_comparison/fifo_queue_vs_qty_after_transaction_comparison.py diff --git a/erpnext/stock/report/fifo_queue_vs_qty_after_transaction_comparison/__init__.py b/erpnext/stock/report/fifo_queue_vs_qty_after_transaction_comparison/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/erpnext/stock/report/fifo_queue_vs_qty_after_transaction_comparison/fifo_queue_vs_qty_after_transaction_comparison.js b/erpnext/stock/report/fifo_queue_vs_qty_after_transaction_comparison/fifo_queue_vs_qty_after_transaction_comparison.js new file mode 100644 index 000000000000..0b8f49653dd7 --- /dev/null +++ b/erpnext/stock/report/fifo_queue_vs_qty_after_transaction_comparison/fifo_queue_vs_qty_after_transaction_comparison.js @@ -0,0 +1,53 @@ +// Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors +// For license information, please see license.txt +/* eslint-disable */ + +const DIFFERNCE_FIELD_NAMES = [ + "fifo_qty_diff", + "fifo_value_diff", +]; + +frappe.query_reports["FIFO Queue vs Qty After Transaction Comparison"] = { + "filters": [ + { + "fieldname": "item_code", + "fieldtype": "Link", + "label": "Item", + "options": "Item", + get_query: function() { + return { + filters: {is_stock_item: 1, has_serial_no: 0} + } + } + }, + { + "fieldname": "item_group", + "fieldtype": "Link", + "label": "Item Group", + "options": "Item Group", + }, + { + "fieldname": "warehouse", + "fieldtype": "Link", + "label": "Warehouse", + "options": "Warehouse", + }, + { + "fieldname": "from_date", + "fieldtype": "Date", + "label": "From Posting Date", + }, + { + "fieldname": "to_date", + "fieldtype": "Date", + "label": "From Posting Date", + } + ], + formatter (value, row, column, data, default_formatter) { + value = default_formatter(value, row, column, data); + if (DIFFERNCE_FIELD_NAMES.includes(column.fieldname) && Math.abs(data[column.fieldname]) > 0.001) { + value = "" + value + ""; + } + return value; + }, +}; diff --git a/erpnext/stock/report/fifo_queue_vs_qty_after_transaction_comparison/fifo_queue_vs_qty_after_transaction_comparison.json b/erpnext/stock/report/fifo_queue_vs_qty_after_transaction_comparison/fifo_queue_vs_qty_after_transaction_comparison.json new file mode 100644 index 000000000000..5e958aa1b03a --- /dev/null +++ b/erpnext/stock/report/fifo_queue_vs_qty_after_transaction_comparison/fifo_queue_vs_qty_after_transaction_comparison.json @@ -0,0 +1,27 @@ +{ + "add_total_row": 0, + "columns": [], + "creation": "2022-05-11 04:09:13.460652", + "disable_prepared_report": 0, + "disabled": 0, + "docstatus": 0, + "doctype": "Report", + "filters": [], + "idx": 0, + "is_standard": "Yes", + "letter_head": "abc", + "modified": "2022-05-11 04:09:20.232177", + "modified_by": "Administrator", + "module": "Stock", + "name": "FIFO Queue vs Qty After Transaction Comparison", + "owner": "Administrator", + "prepared_report": 0, + "ref_doctype": "Stock Ledger Entry", + "report_name": "FIFO Queue vs Qty After Transaction Comparison", + "report_type": "Script Report", + "roles": [ + { + "role": "Administrator" + } + ] +} \ No newline at end of file diff --git a/erpnext/stock/report/fifo_queue_vs_qty_after_transaction_comparison/fifo_queue_vs_qty_after_transaction_comparison.py b/erpnext/stock/report/fifo_queue_vs_qty_after_transaction_comparison/fifo_queue_vs_qty_after_transaction_comparison.py new file mode 100644 index 000000000000..9e140336c9ac --- /dev/null +++ b/erpnext/stock/report/fifo_queue_vs_qty_after_transaction_comparison/fifo_queue_vs_qty_after_transaction_comparison.py @@ -0,0 +1,212 @@ +# Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + +import json + +import frappe +from frappe import _ +from frappe.utils import flt +from frappe.utils.nestedset import get_descendants_of + +SLE_FIELDS = ( + "name", + "item_code", + "warehouse", + "posting_date", + "posting_time", + "creation", + "voucher_type", + "voucher_no", + "actual_qty", + "qty_after_transaction", + "stock_queue", + "batch_no", + "stock_value", + "valuation_rate", +) + + +def execute(filters=None): + columns = get_columns() + data = get_data(filters) + return columns, data + + +def get_data(filters): + if not any([filters.warehouse, filters.item_code, filters.item_group]): + frappe.throw(_("Any one of following filters required: warehouse, Item Code, Item Group")) + sles = get_stock_ledger_entries(filters) + return find_first_bad_queue(sles) + + +def get_stock_ledger_entries(filters): + + sle_filters = {"is_cancelled": 0} + + if filters.warehouse: + children = get_descendants_of("Warehouse", filters.warehouse) + sle_filters["warehouse"] = ("in", children + [filters.warehouse]) + + if filters.item_code: + sle_filters["item_code"] = filters.item_code + elif filters.get("item_group"): + item_group = filters.get("item_group") + children = get_descendants_of("Item Group", item_group) + item_group_filter = {"item_group": ("in", children + [item_group])} + sle_filters["item_code"] = ( + "in", + frappe.get_all("Item", filters=item_group_filter, pluck="name", order_by=None), + ) + + if filters.from_date: + sle_filters["posting_date"] = (">=", filters.from_date) + if filters.to_date: + sle_filters["posting_date"] = ("<=", filters.to_date) + + return frappe.get_all( + "Stock Ledger Entry", + fields=SLE_FIELDS, + filters=sle_filters, + order_by="timestamp(posting_date, posting_time), creation", + ) + + +def find_first_bad_queue(sles): + item_warehouse_sles = {} + for sle in sles: + item_warehouse_sles.setdefault((sle.item_code, sle.warehouse), []).append(sle) + + data = [] + + for _item_wh, sles in item_warehouse_sles.items(): + for idx, sle in enumerate(sles): + queue = json.loads(sle.stock_queue or "[]") + + sle.fifo_queue_qty = 0.0 + sle.fifo_stock_value = 0.0 + for qty, rate in queue: + sle.fifo_queue_qty += flt(qty) + sle.fifo_stock_value += flt(qty) * flt(rate) + + sle.fifo_qty_diff = sle.qty_after_transaction - sle.fifo_queue_qty + sle.fifo_value_diff = sle.stock_value - sle.fifo_stock_value + + if sle.batch_no: + sle.use_batchwise_valuation = frappe.db.get_value( + "Batch", sle.batch_no, "use_batchwise_valuation", cache=True + ) + + if abs(sle.fifo_qty_diff) > 0.001 or abs(sle.fifo_value_diff) > 0.1: + if idx: + data.append(sles[idx - 1]) + data.append(sle) + data.append({}) + break + + return data + + +def get_columns(): + return [ + { + "fieldname": "name", + "fieldtype": "Link", + "label": _("Stock Ledger Entry"), + "options": "Stock Ledger Entry", + }, + { + "fieldname": "item_code", + "fieldtype": "Link", + "label": _("Item Code"), + "options": "Item", + }, + { + "fieldname": "warehouse", + "fieldtype": "Link", + "label": _("Warehouse"), + "options": "Warehouse", + }, + { + "fieldname": "posting_date", + "fieldtype": "Data", + "label": _("Posting Date"), + }, + { + "fieldname": "posting_time", + "fieldtype": "Data", + "label": _("Posting Time"), + }, + { + "fieldname": "creation", + "fieldtype": "Data", + "label": _("Creation"), + }, + { + "fieldname": "voucher_type", + "fieldtype": "Link", + "label": _("Voucher Type"), + "options": "DocType", + }, + { + "fieldname": "voucher_no", + "fieldtype": "Dynamic Link", + "label": _("Voucher No"), + "options": "voucher_type", + }, + { + "fieldname": "batch_no", + "fieldtype": "Link", + "label": _("Batch"), + "options": "Batch", + }, + { + "fieldname": "use_batchwise_valuation", + "fieldtype": "Check", + "label": _("Batchwise Valuation"), + }, + { + "fieldname": "actual_qty", + "fieldtype": "Float", + "label": _("Qty Change"), + }, + { + "fieldname": "qty_after_transaction", + "fieldtype": "Float", + "label": _("(A) Qty After Transaction"), + }, + { + "fieldname": "stock_queue", + "fieldtype": "Data", + "label": _("FIFO/LIFO Queue"), + }, + { + "fieldname": "fifo_queue_qty", + "fieldtype": "Float", + "label": _("(C) Total qty in queue"), + }, + { + "fieldname": "fifo_qty_diff", + "fieldtype": "Float", + "label": _("A - C"), + }, + { + "fieldname": "stock_value", + "fieldtype": "Float", + "label": _("(D) Balance Stock Value"), + }, + { + "fieldname": "fifo_stock_value", + "fieldtype": "Float", + "label": _("(E) Balance Stock Value in Queue"), + }, + { + "fieldname": "fifo_value_diff", + "fieldtype": "Float", + "label": _("D - E"), + }, + { + "fieldname": "valuation_rate", + "fieldtype": "Float", + "label": _("(H) Valuation Rate"), + }, + ] diff --git a/erpnext/stock/report/test_reports.py b/erpnext/stock/report/test_reports.py index 4be492c0fd44..7e69718614fa 100644 --- a/erpnext/stock/report/test_reports.py +++ b/erpnext/stock/report/test_reports.py @@ -52,6 +52,8 @@ ("Batch Item Expiry Status", {}), ("Stock Ageing", {"range1": 30, "range2": 60, "range3": 90, "_optional": True}), ("Stock Ledger Invariant Check", {"warehouse": "_Test Warehouse - _TC", "item": "_Test Item"}), + ("FIFO Queue vs Qty After Transaction Comparison", {"warehouse": "_Test Warehouse - _TC"}), + ("FIFO Queue vs Qty After Transaction Comparison", {"item_group": "All Item Groups"}), ] OPTIONAL_FILTERS = { From 78f694ca4e027bce9f887df4d3265f812f90601c Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Wed, 11 May 2022 15:19:07 +0530 Subject: [PATCH 2/2] chore: incompatible changes --- .../fifo_queue_vs_qty_after_transaction_comparison.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/erpnext/stock/report/fifo_queue_vs_qty_after_transaction_comparison/fifo_queue_vs_qty_after_transaction_comparison.py b/erpnext/stock/report/fifo_queue_vs_qty_after_transaction_comparison/fifo_queue_vs_qty_after_transaction_comparison.py index 9e140336c9ac..91ded6260e6b 100644 --- a/erpnext/stock/report/fifo_queue_vs_qty_after_transaction_comparison/fifo_queue_vs_qty_after_transaction_comparison.py +++ b/erpnext/stock/report/fifo_queue_vs_qty_after_transaction_comparison/fifo_queue_vs_qty_after_transaction_comparison.py @@ -91,11 +91,6 @@ def find_first_bad_queue(sles): sle.fifo_qty_diff = sle.qty_after_transaction - sle.fifo_queue_qty sle.fifo_value_diff = sle.stock_value - sle.fifo_stock_value - if sle.batch_no: - sle.use_batchwise_valuation = frappe.db.get_value( - "Batch", sle.batch_no, "use_batchwise_valuation", cache=True - ) - if abs(sle.fifo_qty_diff) > 0.001 or abs(sle.fifo_value_diff) > 0.1: if idx: data.append(sles[idx - 1])