Merge branch 'develop' of https://github.com/frappe/erpnext into ledger_preview
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
index 8cb2950..1ef0c51 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
@@ -88,6 +88,7 @@
}
this.show_general_ledger();
+ this.show_ledger_preview();
if(doc.update_stock) this.show_stock_ledger();
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
index ab4aab3..f0d3f72 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
@@ -2157,7 +2157,7 @@
"link_fieldname": "consolidated_invoice"
}
],
- "modified": "2023-06-19 16:02:05.309332",
+ "modified": "2023-06-21 16:02:18.988799",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice",
diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py
index cdbf6c7..0b057bc 100644
--- a/erpnext/controllers/stock_controller.py
+++ b/erpnext/controllers/stock_controller.py
@@ -845,6 +845,135 @@
gl_entries.append(self.get_gl_dict(gl_entry, item=item))
+@frappe.whitelist()
+def show_ledger_preview(company, doctype, docname):
+ frappe.db.savepoint("show_ledger_preview")
+
+ filters = {"company": company}
+ doc = frappe.get_doc(doctype, docname)
+
+ sl_columns, sl_data = get_stock_ledger_preview(doc, filters)
+ gl_columns, gl_data = get_accounting_ledger_preview(doc, filters)
+
+ frappe.db.rollback(save_point="show_ledger_preview")
+
+ return {
+ "gl_columns": gl_columns,
+ "gl_data": gl_data,
+ "sl_columns": sl_columns,
+ "sl_data": sl_data,
+ }
+
+
+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",
+ "party_type",
+ "against_voucher_type",
+ "against_voucher",
+ ]
+
+ doc.docstatus = 1
+ 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",
+ "valuation_rate",
+ "stock_value",
+ "stock_value_difference",
+ ]
+
+ if doc.update_stock or doc.doctype in ("Purchase Receipt", "Delivery Note"):
+ doc.docstatus = 1
+ 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
+
+ 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}
+ 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/public/js/controllers/stock_controller.js b/erpnext/public/js/controllers/stock_controller.js
index d346357..ff59348 100644
--- a/erpnext/public/js/controllers/stock_controller.js
+++ b/erpnext/public/js/controllers/stock_controller.js
@@ -66,7 +66,7 @@
}
show_general_ledger() {
- var me = this;
+ let me = this;
if(this.frm.doc.docstatus > 0) {
cur_frm.add_custom_button(__('Accounting Ledger'), function() {
frappe.route_options = {
@@ -81,4 +81,69 @@
}, __("View"));
}
}
+
+ show_ledger_preview() {
+ let me = this
+ if(this.frm.doc.docstatus == 0) {
+ cur_frm.add_custom_button(__('Accounting Ledger Preview'), function() {
+ frappe.call({
+ "method": "erpnext.controllers.stock_controller.show_ledger_preview",
+ "args": {
+ "company": me.frm.doc.company,
+ "doctype": me.frm.doc.doctype,
+ "docname": me.frm.doc.name
+ },
+ "callback": function(response) {
+ me.make_dialog(response.message);
+ }
+ })
+ }, __("View"));
+ }
+ }
+
+ make_dialog(data) {
+ let me = this;
+ let gl_columns = data.gl_columns;
+ let gl_data = data.gl_data;
+ let sl_columns = data.sl_columns;
+ let sl_data = data.sl_data;
+
+ let dialog = new frappe.ui.Dialog({
+ "size": "extra-large",
+ "title": __("Ledger Preview"),
+ "fields": [
+ {
+ "fieldtype": "HTML",
+ "fieldname": "accounting_ledger_preview_html",
+ "label": __("Accounting Ledger"),
+ },
+ {
+ "fieldtype": "HTML",
+ "fieldname": "stock_ledger_preview_html",
+ "label": __("Stock Ledger"),
+ }
+ ]
+ });
+
+ setTimeout(function() {
+ me.get_datatable(gl_columns, gl_data, dialog.get_field("accounting_ledger_preview_html").wrapper);
+ }, 200);
+
+ dialog.show();
+ }
+
+ get_datatable(columns, data, wrapper) {
+ const datatable_options = {
+ columns: columns,
+ data: data,
+ dynamicRowHeight: true,
+ checkboxColumn: false,
+ inlineFilters: true,
+ };
+
+ new frappe.DataTable(
+ wrapper,
+ datatable_options
+ );
+ }
};