diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py index eb10decd702..67862520a83 100644 --- a/erpnext/controllers/stock_controller.py +++ b/erpnext/controllers/stock_controller.py @@ -612,6 +612,8 @@ class StockController(AccountsController): @frappe.whitelist() def show_accounting_ledger_preview(company: str, doctype: str, docname: str): + from erpnext.stock.services.ledger_preview import get_accounting_ledger_preview + filters = frappe._dict(company=company, include_dimensions=1) doc = frappe.get_lazy_doc(doctype, docname) doc.run_method("before_gl_preview") @@ -625,6 +627,8 @@ def show_accounting_ledger_preview(company: str, doctype: str, docname: str): @frappe.whitelist() def show_stock_ledger_preview(company: str, doctype: str, docname: str): + from erpnext.stock.services.ledger_preview import get_stock_ledger_preview + filters = frappe._dict(company=company) doc = frappe.get_lazy_doc(doctype, docname) doc.run_method("before_sl_preview") @@ -639,122 +643,6 @@ def show_stock_ledger_preview(company: str, doctype: str, docname: str): } -def get_accounting_ledger_preview(doc, filters): - from erpnext.accounts.report.general_ledger.general_ledger import get_columns as get_gl_columns - - gl_columns, gl_data = [], [] - fields = [ - "posting_date", - "account", - "debit", - "credit", - "against", - "party_type", - "party", - "cost_center", - "against_voucher_type", - "against_voucher", - ] - - doc.docstatus = 1 - - if doc.get("update_stock") or doc.doctype in ("Purchase Receipt", "Delivery Note", "Stock Entry"): - doc.update_stock_ledger() - - doc.make_gl_entries() - columns = get_gl_columns(filters) - gl_entries = get_gl_entries_for_preview(doc.doctype, doc.name, fields) - - gl_columns = get_columns(columns, fields) - gl_data = get_data(fields, gl_entries) - - return gl_columns, gl_data - - -def get_stock_ledger_preview(doc, filters): - from erpnext.stock.report.stock_ledger.stock_ledger import get_columns as get_sl_columns - - sl_columns, sl_data = [], [] - fields = [ - "item_code", - "stock_uom", - "actual_qty", - "qty_after_transaction", - "warehouse", - "incoming_rate", - "valuation_rate", - "stock_value", - "stock_value_difference", - ] - columns_fields = [ - "item_code", - "stock_uom", - "in_qty", - "out_qty", - "qty_after_transaction", - "warehouse", - "incoming_rate", - "in_out_rate", - "stock_value", - "stock_value_difference", - ] - - if doc.get("update_stock") or doc.doctype in ("Purchase Receipt", "Delivery Note", "Stock Entry"): - doc.docstatus = 1 - doc.make_bundle_using_old_serial_batch_fields() - doc.update_stock_ledger() - - columns = get_sl_columns(filters) - sl_entries = get_sl_entries_for_preview(doc.doctype, doc.name, fields) - - sl_columns = get_columns(columns, columns_fields) - sl_data = get_data(columns_fields, sl_entries) - - return sl_columns, sl_data - - -def get_sl_entries_for_preview(doctype, docname, fields): - sl_entries = frappe.get_all( - "Stock Ledger Entry", filters={"voucher_type": doctype, "voucher_no": docname}, fields=fields - ) - - for entry in sl_entries: - if entry.actual_qty > 0: - entry["in_qty"] = entry.actual_qty - entry["out_qty"] = 0 - else: - entry["out_qty"] = abs(entry.actual_qty) - entry["in_qty"] = 0 - - entry["in_out_rate"] = entry["valuation_rate"] - - return sl_entries - - -def get_gl_entries_for_preview(doctype, docname, fields): - return frappe.get_all("GL Entry", filters={"voucher_type": doctype, "voucher_no": docname}, fields=fields) - - -def get_columns(raw_columns, fields): - return [ - {"name": d.get("label"), "editable": False, "width": 110, "fieldtype": d.get("fieldtype")} - for d in raw_columns - if not d.get("hidden") and d.get("fieldname") in fields - ] - - -def get_data(raw_columns, raw_data): - datatable_data = [] - for row in raw_data: - data_row = [] - for column in raw_columns: - data_row.append(row.get(column) or "") - - datatable_data.append(data_row) - - return datatable_data - - def repost_required_for_queue(doc: StockController) -> bool: """check if stock document contains repeated item-warehouse with queue based valuation. diff --git a/erpnext/stock/services/ledger_preview.py b/erpnext/stock/services/ledger_preview.py new file mode 100644 index 00000000000..20c533c8ddd --- /dev/null +++ b/erpnext/stock/services/ledger_preview.py @@ -0,0 +1,129 @@ +# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +"""Read-side GL / Stock Ledger preview helpers for stock transactions. + +A dry-run consumer of the posting path: it submits-in-memory, reads the resulting +GL/SLE entries and formats them for the datatable preview, then the caller rolls +back. Lives separately from the posting services it orchestrates. The whitelisted +``show_*_preview`` entry points stay on ``stock_controller`` (their dotted path is +referenced from client JS). +""" + +import frappe + + +def get_accounting_ledger_preview(doc, filters): + from erpnext.accounts.report.general_ledger.general_ledger import get_columns as get_gl_columns + + gl_columns, gl_data = [], [] + fields = [ + "posting_date", + "account", + "debit", + "credit", + "against", + "party_type", + "party", + "cost_center", + "against_voucher_type", + "against_voucher", + ] + + doc.docstatus = 1 + + if doc.get("update_stock") or doc.doctype in ("Purchase Receipt", "Delivery Note", "Stock Entry"): + doc.update_stock_ledger() + + doc.make_gl_entries() + columns = get_gl_columns(filters) + gl_entries = get_gl_entries_for_preview(doc.doctype, doc.name, fields) + + gl_columns = get_columns(columns, fields) + gl_data = get_data(fields, gl_entries) + + return gl_columns, gl_data + + +def get_stock_ledger_preview(doc, filters): + from erpnext.stock.report.stock_ledger.stock_ledger import get_columns as get_sl_columns + + sl_columns, sl_data = [], [] + fields = [ + "item_code", + "stock_uom", + "actual_qty", + "qty_after_transaction", + "warehouse", + "incoming_rate", + "valuation_rate", + "stock_value", + "stock_value_difference", + ] + columns_fields = [ + "item_code", + "stock_uom", + "in_qty", + "out_qty", + "qty_after_transaction", + "warehouse", + "incoming_rate", + "in_out_rate", + "stock_value", + "stock_value_difference", + ] + + if doc.get("update_stock") or doc.doctype in ("Purchase Receipt", "Delivery Note", "Stock Entry"): + doc.docstatus = 1 + doc.make_bundle_using_old_serial_batch_fields() + doc.update_stock_ledger() + + columns = get_sl_columns(filters) + sl_entries = get_sl_entries_for_preview(doc.doctype, doc.name, fields) + + sl_columns = get_columns(columns, columns_fields) + sl_data = get_data(columns_fields, sl_entries) + + return sl_columns, sl_data + + +def get_sl_entries_for_preview(doctype, docname, fields): + sl_entries = frappe.get_all( + "Stock Ledger Entry", filters={"voucher_type": doctype, "voucher_no": docname}, fields=fields + ) + + for entry in sl_entries: + if entry.actual_qty > 0: + entry["in_qty"] = entry.actual_qty + entry["out_qty"] = 0 + else: + entry["out_qty"] = abs(entry.actual_qty) + entry["in_qty"] = 0 + + entry["in_out_rate"] = entry["valuation_rate"] + + return sl_entries + + +def get_gl_entries_for_preview(doctype, docname, fields): + return frappe.get_all("GL Entry", filters={"voucher_type": doctype, "voucher_no": docname}, fields=fields) + + +def get_columns(raw_columns, fields): + return [ + {"name": d.get("label"), "editable": False, "width": 110, "fieldtype": d.get("fieldtype")} + for d in raw_columns + if not d.get("hidden") and d.get("fieldname") in fields + ] + + +def get_data(raw_columns, raw_data): + datatable_data = [] + for row in raw_data: + data_row = [] + for column in raw_columns: + data_row.append(row.get(column) or "") + + datatable_data.append(data_row) + + return datatable_data