From 4f0aa54c09d3fcd693cac64ecc754357d3c10368 Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Mon, 10 Jul 2023 13:38:30 +0530 Subject: [PATCH 01/26] feat: add check for fetching PE along with Invoice details in Purchase Register --- .../purchase_register/purchase_register.js | 6 ++ .../purchase_register/purchase_register.py | 75 +++++++++++++++---- 2 files changed, 65 insertions(+), 16 deletions(-) diff --git a/erpnext/accounts/report/purchase_register/purchase_register.js b/erpnext/accounts/report/purchase_register/purchase_register.js index aaf76c4299..ddf84d05ce 100644 --- a/erpnext/accounts/report/purchase_register/purchase_register.js +++ b/erpnext/accounts/report/purchase_register/purchase_register.js @@ -52,6 +52,12 @@ frappe.query_reports["Purchase Register"] = { "label": __("Item Group"), "fieldtype": "Link", "options": "Item Group" + }, + { + "fieldname": "include_payments", + "label": __("Include Payments"), + "fieldtype": "Check", + "default": 0 } ] } diff --git a/erpnext/accounts/report/purchase_register/purchase_register.py b/erpnext/accounts/report/purchase_register/purchase_register.py index a05d581207..3e178a63b8 100644 --- a/erpnext/accounts/report/purchase_register/purchase_register.py +++ b/erpnext/accounts/report/purchase_register/purchase_register.py @@ -21,6 +21,8 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum filters = {} invoice_list = get_invoices(filters, additional_query_columns) + if filters.get("include_payments") and filters.include_payments: + invoice_list += get_payments(filters, additional_query_columns) columns, expense_accounts, tax_accounts, unrealized_profit_loss_accounts = get_columns( invoice_list, additional_table_columns ) @@ -54,11 +56,11 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum row.append(inv.get(col)) row += [ - supplier_details.get(inv.supplier), # supplier_group - inv.tax_id, + supplier_details.get(inv.supplier)[0], # supplier_group + supplier_details.get(inv.supplier)[1], inv.credit_to, inv.mode_of_payment, - ", ".join(project), + ", ".join(project) if inv.doctype == "Purchase Invoice" else inv.project, inv.bill_no, inv.bill_date, inv.remarks, @@ -141,9 +143,10 @@ def get_columns(invoice_list, additional_table_columns): tax_accounts = frappe.db.sql_list( """select distinct account_head - from `tabPurchase Taxes and Charges` where parenttype = 'Purchase Invoice' - and docstatus = 1 and (account_head is not null and account_head != '') - and category in ('Total', 'Valuation and Total') + from (select account_head, parent, docstatus from `tabPurchase Taxes and Charges` where parenttype = 'Purchase Invoice' + and category in ('Total', 'Valuation and Total') union select account_head, parent, docstatus + from `tabAdvance Taxes and Charges` where parenttype = 'Payment Entry' and charge_type in ('On Paid Amount', 'Actual')) a + where docstatus = 1 and (account_head is not null and account_head != '') and parent in (%s) order by account_head""" % ", ".join(["%s"] * len(invoice_list)), tuple(inv.name for inv in invoice_list), @@ -185,13 +188,13 @@ def get_columns(invoice_list, additional_table_columns): return columns, expense_accounts, tax_accounts, unrealized_profit_loss_accounts -def get_conditions(filters): +def get_conditions(filters, payments=False): conditions = "" if filters.get("company"): conditions += " and company=%(company)s" if filters.get("supplier"): - conditions += " and supplier = %(supplier)s" + conditions += " and party = %(supplier)s" if payments else " and supplier = %(supplier)s" if filters.get("from_date"): conditions += " and posting_date>=%(from_date)s" @@ -202,16 +205,19 @@ def get_conditions(filters): conditions += " and ifnull(mode_of_payment, '') = %(mode_of_payment)s" if filters.get("cost_center"): - conditions += """ and exists(select name from `tabPurchase Invoice Item` - where parent=`tabPurchase Invoice`.name - and ifnull(`tabPurchase Invoice Item`.cost_center, '') = %(cost_center)s)""" + if payments: + conditions += " and cost_center = %(cost_center)s" + else: + conditions += """ and exists(select name from `tabPurchase Invoice Item` + where parent=`tabPurchase Invoice`.name + and ifnull(`tabPurchase Invoice Item`.cost_center, '') = %(cost_center)s)""" - if filters.get("warehouse"): + if filters.get("warehouse") and not payments: conditions += """ and exists(select name from `tabPurchase Invoice Item` where parent=`tabPurchase Invoice`.name and ifnull(`tabPurchase Invoice Item`.warehouse, '') = %(warehouse)s)""" - if filters.get("item_group"): + if filters.get("item_group") and not payments: conditions += """ and exists(select name from `tabPurchase Invoice Item` where parent=`tabPurchase Invoice`.name and ifnull(`tabPurchase Invoice Item`.item_group, '') = %(item_group)s)""" @@ -251,7 +257,7 @@ def get_invoices(filters, additional_query_columns): return frappe.db.sql( """ select - name, posting_date, credit_to, supplier, supplier_name, tax_id, bill_no, bill_date, + 'Purchase Invoice' as doctype, name, posting_date, credit_to, supplier, supplier_name, tax_id, bill_no, bill_date, remarks, base_net_total, base_grand_total, outstanding_amount, mode_of_payment {0} from `tabPurchase Invoice` @@ -265,6 +271,28 @@ def get_invoices(filters, additional_query_columns): ) +def get_payments(filters, additional_query_columns): + if additional_query_columns: + additional_query_columns = ", " + ", ".join(additional_query_columns) + + conditions = get_conditions(filters, payments=True) + return frappe.db.sql( + """ + select + 'Payment Entry' as doctype, name, posting_date, paid_to as credit_to, party as supplier, party_name as supplier_name, + remarks, paid_amount as base_net_total, paid_amount_after_tax as base_grand_total, + mode_of_payment {0}, project + from `tabPayment Entry` + where party_type = 'Supplier' %s + order by posting_date desc, name desc""".format( + additional_query_columns or "" + ) + % conditions, + filters, + as_dict=1, + ) + + def get_invoice_expense_map(invoice_list): expense_details = frappe.db.sql( """ @@ -319,6 +347,21 @@ def get_invoice_tax_map(invoice_list, invoice_expense_map, expense_accounts): as_dict=1, ) + advance_tax_details = frappe.db.sql( + """ + select parent, account_head, case add_deduct_tax when "Add" then sum(base_tax_amount) + else sum(base_tax_amount) * -1 end as tax_amount + from `tabAdvance Taxes and Charges` + where parent in (%s) and charge_type in ('On Paid Amount', 'Actual') + and base_tax_amount != 0 + group by parent, account_head, add_deduct_tax + """ + % ", ".join(["%s"] * len(invoice_list)), + tuple(inv.name for inv in invoice_list), + as_dict=1, + ) + tax_details += advance_tax_details + invoice_tax_map = {} for d in tax_details: if d.account_head in expense_accounts: @@ -391,12 +434,12 @@ def get_account_details(invoice_list): def get_supplier_details(suppliers): supplier_details = {} for supp in frappe.db.sql( - """select name, supplier_group from `tabSupplier` + """select name, supplier_group, tax_id from `tabSupplier` where name in (%s)""" % ", ".join(["%s"] * len(suppliers)), tuple(suppliers), as_dict=1, ): - supplier_details.setdefault(supp.name, supp.supplier_group) + supplier_details.setdefault(supp.name, [supp.supplier_group, supp.tax_id]) return supplier_details From 44493707e26c28b354055e0975b3bf61f45d6f5c Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Mon, 10 Jul 2023 14:37:33 +0530 Subject: [PATCH 02/26] refactor: use single qb query for PE and PI --- .../purchase_register/purchase_register.py | 45 ++++++++++++++----- 1 file changed, 34 insertions(+), 11 deletions(-) diff --git a/erpnext/accounts/report/purchase_register/purchase_register.py b/erpnext/accounts/report/purchase_register/purchase_register.py index 3e178a63b8..0477182ba5 100644 --- a/erpnext/accounts/report/purchase_register/purchase_register.py +++ b/erpnext/accounts/report/purchase_register/purchase_register.py @@ -24,7 +24,7 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum if filters.get("include_payments") and filters.include_payments: invoice_list += get_payments(filters, additional_query_columns) columns, expense_accounts, tax_accounts, unrealized_profit_loss_accounts = get_columns( - invoice_list, additional_table_columns + invoice_list, additional_table_columns, filters.get("include_payments") ) if not invoice_list: @@ -101,7 +101,7 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum return columns, data -def get_columns(invoice_list, additional_table_columns): +def get_columns(invoice_list, additional_table_columns, include_payments): """return columns based on filters""" columns = [ _("Invoice") + ":Link/Purchase Invoice:120", @@ -141,16 +141,18 @@ def get_columns(invoice_list, additional_table_columns): tuple([inv.name for inv in invoice_list]), ) - tax_accounts = frappe.db.sql_list( - """select distinct account_head - from (select account_head, parent, docstatus from `tabPurchase Taxes and Charges` where parenttype = 'Purchase Invoice' - and category in ('Total', 'Valuation and Total') union select account_head, parent, docstatus - from `tabAdvance Taxes and Charges` where parenttype = 'Payment Entry' and charge_type in ('On Paid Amount', 'Actual')) a - where docstatus = 1 and (account_head is not null and account_head != '') - and parent in (%s) order by account_head""" - % ", ".join(["%s"] * len(invoice_list)), - tuple(inv.name for inv in invoice_list), + purchase_taxes_query = get_taxes_query( + invoice_list, "Purchase Taxes and Charges", "Purchase Invoice" ) + purchase_tax_accounts = purchase_taxes_query.run(as_dict=True, pluck="account_head") + tax_accounts = purchase_tax_accounts + + if include_payments: + advance_taxes_query = get_taxes_query( + invoice_list, "Advance Taxes and Charges", "Payment Entry" + ) + advance_tax_accounts = advance_taxes_query.run(as_dict=True, pluck="account_head") + tax_accounts = set(tax_accounts + advance_tax_accounts) unrealized_profit_loss_accounts = frappe.db.sql_list( """SELECT distinct unrealized_profit_loss_account @@ -188,6 +190,27 @@ def get_columns(invoice_list, additional_table_columns): return columns, expense_accounts, tax_accounts, unrealized_profit_loss_accounts +def get_taxes_query(invoice_list, doctype, parenttype): + taxes = frappe.qb.DocType(doctype) + + query = ( + frappe.qb.from_(taxes) + .select(taxes.account_head) + .distinct() + .where( + (taxes.parenttype == parenttype) + & (taxes.docstatus == 1) + & (taxes.account_head.isnotnull()) + & (taxes.parent.isin([inv.name for inv in invoice_list])) + ) + .orderby(taxes.account_head) + ) + + if doctype == "Purchase Taxes and Charges": + return query.where(taxes.category.isin(["Total", "Valuation and Total"])) + return query.where(taxes.charge_type.isin(["On Paid", "Actual"])) + + def get_conditions(filters, payments=False): conditions = "" From d7ffad1dd395a6a073f18eaa7d004cbc44d5bb19 Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Mon, 10 Jul 2023 18:07:55 +0530 Subject: [PATCH 03/26] feat: fetch PE along with SI --- .../purchase_register/purchase_register.py | 49 ++++---- .../report/sales_register/sales_register.js | 6 + .../report/sales_register/sales_register.py | 116 +++++++++++++++--- 3 files changed, 131 insertions(+), 40 deletions(-) diff --git a/erpnext/accounts/report/purchase_register/purchase_register.py b/erpnext/accounts/report/purchase_register/purchase_register.py index 0477182ba5..72d720959f 100644 --- a/erpnext/accounts/report/purchase_register/purchase_register.py +++ b/erpnext/accounts/report/purchase_register/purchase_register.py @@ -20,11 +20,12 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum if not filters: filters = {} + include_payments = filters.get("include_payments") invoice_list = get_invoices(filters, additional_query_columns) - if filters.get("include_payments") and filters.include_payments: + if filters.get("include_payments"): invoice_list += get_payments(filters, additional_query_columns) columns, expense_accounts, tax_accounts, unrealized_profit_loss_accounts = get_columns( - invoice_list, additional_table_columns, filters.get("include_payments") + invoice_list, additional_table_columns, include_payments ) if not invoice_list: @@ -34,7 +35,7 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum invoice_expense_map = get_invoice_expense_map(invoice_list) internal_invoice_map = get_internal_invoice_map(invoice_list) invoice_expense_map, invoice_tax_map = get_invoice_tax_map( - invoice_list, invoice_expense_map, expense_accounts + invoice_list, invoice_expense_map, expense_accounts, include_payments ) invoice_po_pr_map = get_invoice_po_pr_map(invoice_list) suppliers = list(set(d.supplier for d in invoice_list)) @@ -101,7 +102,7 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum return columns, data -def get_columns(invoice_list, additional_table_columns, include_payments): +def get_columns(invoice_list, additional_table_columns, include_payments=False): """return columns based on filters""" columns = [ _("Invoice") + ":Link/Purchase Invoice:120", @@ -208,7 +209,7 @@ def get_taxes_query(invoice_list, doctype, parenttype): if doctype == "Purchase Taxes and Charges": return query.where(taxes.category.isin(["Total", "Valuation and Total"])) - return query.where(taxes.charge_type.isin(["On Paid", "Actual"])) + return query.where(taxes.charge_type.isin(["On Paid Amount", "Actual"])) def get_conditions(filters, payments=False): @@ -301,10 +302,9 @@ def get_payments(filters, additional_query_columns): conditions = get_conditions(filters, payments=True) return frappe.db.sql( """ - select - 'Payment Entry' as doctype, name, posting_date, paid_to as credit_to, party as supplier, party_name as supplier_name, - remarks, paid_amount as base_net_total, paid_amount_after_tax as base_grand_total, - mode_of_payment {0}, project + select 'Payment Entry' as doctype, name, posting_date, paid_to as credit_to, + party as supplier, party_name as supplier_name, remarks, paid_amount as base_net_total, paid_amount_after_tax as base_grand_total, + mode_of_payment {0}, project from `tabPayment Entry` where party_type = 'Supplier' %s order by posting_date desc, name desc""".format( @@ -355,7 +355,9 @@ def get_internal_invoice_map(invoice_list): return internal_invoice_map -def get_invoice_tax_map(invoice_list, invoice_expense_map, expense_accounts): +def get_invoice_tax_map( + invoice_list, invoice_expense_map, expense_accounts, include_payments=False +): tax_details = frappe.db.sql( """ select parent, account_head, case add_deduct_tax when "Add" then sum(base_tax_amount_after_discount_amount) @@ -370,20 +372,21 @@ def get_invoice_tax_map(invoice_list, invoice_expense_map, expense_accounts): as_dict=1, ) - advance_tax_details = frappe.db.sql( + if include_payments: + advance_tax_details = frappe.db.sql( + """ + select parent, account_head, case add_deduct_tax when "Add" then sum(base_tax_amount) + else sum(base_tax_amount) * -1 end as tax_amount + from `tabAdvance Taxes and Charges` + where parent in (%s) and charge_type in ('On Paid Amount', 'Actual') + and base_tax_amount != 0 + group by parent, account_head, add_deduct_tax """ - select parent, account_head, case add_deduct_tax when "Add" then sum(base_tax_amount) - else sum(base_tax_amount) * -1 end as tax_amount - from `tabAdvance Taxes and Charges` - where parent in (%s) and charge_type in ('On Paid Amount', 'Actual') - and base_tax_amount != 0 - group by parent, account_head, add_deduct_tax - """ - % ", ".join(["%s"] * len(invoice_list)), - tuple(inv.name for inv in invoice_list), - as_dict=1, - ) - tax_details += advance_tax_details + % ", ".join(["%s"] * len(invoice_list)), + tuple(inv.name for inv in invoice_list), + as_dict=1, + ) + tax_details += advance_tax_details invoice_tax_map = {} for d in tax_details: diff --git a/erpnext/accounts/report/sales_register/sales_register.js b/erpnext/accounts/report/sales_register/sales_register.js index 2c9b01bbaa..3c879cac7a 100644 --- a/erpnext/accounts/report/sales_register/sales_register.js +++ b/erpnext/accounts/report/sales_register/sales_register.js @@ -64,6 +64,12 @@ frappe.query_reports["Sales Register"] = { "label": __("Item Group"), "fieldtype": "Link", "options": "Item Group" + }, + { + "fieldname": "include_payments", + "label": __("Include Payments"), + "fieldtype": "Check", + "default": 0 } ] } diff --git a/erpnext/accounts/report/sales_register/sales_register.py b/erpnext/accounts/report/sales_register/sales_register.py index b333901d7b..a2bba5578e 100644 --- a/erpnext/accounts/report/sales_register/sales_register.py +++ b/erpnext/accounts/report/sales_register/sales_register.py @@ -21,9 +21,12 @@ def _execute(filters, additional_table_columns=None, additional_query_columns=No if not filters: filters = frappe._dict({}) + include_payments = filters.get("include_payments") invoice_list = get_invoices(filters, additional_query_columns) + if filters.get("include_payments"): + invoice_list += get_payments(filters, additional_query_columns) columns, income_accounts, tax_accounts, unrealized_profit_loss_accounts = get_columns( - invoice_list, additional_table_columns + invoice_list, additional_table_columns, include_payments ) if not invoice_list: @@ -33,13 +36,15 @@ def _execute(filters, additional_table_columns=None, additional_query_columns=No invoice_income_map = get_invoice_income_map(invoice_list) internal_invoice_map = get_internal_invoice_map(invoice_list) invoice_income_map, invoice_tax_map = get_invoice_tax_map( - invoice_list, invoice_income_map, income_accounts + invoice_list, invoice_income_map, income_accounts, include_payments ) # Cost Center & Warehouse Map invoice_cc_wh_map = get_invoice_cc_wh_map(invoice_list) invoice_so_dn_map = get_invoice_so_dn_map(invoice_list) company_currency = frappe.get_cached_value("Company", filters.get("company"), "default_currency") mode_of_payments = get_mode_of_payments([inv.name for inv in invoice_list]) + customers = list(set(d.customer for d in invoice_list)) + customer_details = get_customer_details(customers) data = [] for inv in invoice_list: @@ -62,9 +67,9 @@ def _execute(filters, additional_table_columns=None, additional_query_columns=No row.update( { - "customer_group": inv.get("customer_group"), - "territory": inv.get("territory"), - "tax_id": inv.get("tax_id"), + "customer_group": customer_details.get(inv.customer)[0], + "territory": customer_details.get(inv.customer)[1], + "tax_id": customer_details.get(inv.customer)[2], "receivable_account": inv.debit_to, "mode_of_payment": ", ".join(mode_of_payments.get(inv.name, [])), "project": inv.project, @@ -128,7 +133,7 @@ def _execute(filters, additional_table_columns=None, additional_query_columns=No return columns, data -def get_columns(invoice_list, additional_table_columns): +def get_columns(invoice_list, additional_table_columns, include_payments=False): """return columns based on filters""" columns = [ { @@ -237,14 +242,16 @@ def get_columns(invoice_list, additional_table_columns): tuple(inv.name for inv in invoice_list), ) - tax_accounts = frappe.db.sql_list( - """select distinct account_head - from `tabSales Taxes and Charges` where parenttype = 'Sales Invoice' - and docstatus = 1 and base_tax_amount_after_discount_amount != 0 - and parent in (%s) order by account_head""" - % ", ".join(["%s"] * len(invoice_list)), - tuple(inv.name for inv in invoice_list), - ) + sales_taxes_query = get_taxes_query(invoice_list, "Sales Taxes and Charges", "Sales Invoice") + sales_tax_accounts = sales_taxes_query.run(as_dict=True, pluck="account_head") + tax_accounts = sales_tax_accounts + + if include_payments: + advance_taxes_query = get_taxes_query( + invoice_list, "Advance Taxes and Charges", "Payment Entry" + ) + advance_tax_accounts = advance_taxes_query.run(as_dict=True, debug=True, pluck="account_head") + tax_accounts = set(tax_accounts + advance_tax_accounts) unrealized_profit_loss_accounts = frappe.db.sql_list( """SELECT distinct unrealized_profit_loss_account @@ -343,7 +350,28 @@ def get_columns(invoice_list, additional_table_columns): return columns, income_accounts, tax_accounts, unrealized_profit_loss_accounts -def get_conditions(filters): +def get_taxes_query(invoice_list, doctype, parenttype): + taxes = frappe.qb.DocType(doctype) + + query = ( + frappe.qb.from_(taxes) + .select(taxes.account_head) + .distinct() + .where( + (taxes.parenttype == parenttype) + & (taxes.docstatus == 1) + & (taxes.account_head.isnotnull()) + & (taxes.parent.isin([inv.name for inv in invoice_list])) + ) + .orderby(taxes.account_head) + ) + + if doctype == "Sales Taxes and Charges": + return query.where(taxes.charge_type.isin(["Total", "Valuation and Total"])) + return query.where(taxes.charge_type.isin(["On Paid Amount", "Actual"])) + + +def get_conditions(filters, payments=False): conditions = "" accounting_dimensions = get_accounting_dimensions(as_list=False) or [] @@ -353,7 +381,7 @@ def get_conditions(filters): conditions += " and company=%(company)s" if filters.get("customer") and "customer" not in accounting_dimensions_list: - conditions += " and customer = %(customer)s" + conditions += " and party = %(customer)s" if payments else " and customer = %(customer)s" if filters.get("from_date"): conditions += " and posting_date >= %(from_date)s" @@ -422,6 +450,28 @@ def get_invoices(filters, additional_query_columns): ) +def get_payments(filters, additional_query_columns): + if additional_query_columns: + additional_query_columns = ", " + ", ".join(additional_query_columns) + + conditions = get_conditions(filters, payments=True) + return frappe.db.sql( + """ + select 'Payment Entry' as doctype, name, posting_date, paid_to as debit_to, + party as customer, party_name as customer_name, remarks, + paid_amount as base_net_total, paid_amount_after_tax as base_grand_total, + mode_of_payment {0}, project + from `tabPayment Entry` + where party_type = 'Customer' %s + order by posting_date desc, name desc""".format( + additional_query_columns or "" + ) + % conditions, + filters, + as_dict=1, + ) + + def get_invoice_income_map(invoice_list): income_details = frappe.db.sql( """select parent, income_account, sum(base_net_amount) as amount @@ -457,7 +507,7 @@ def get_internal_invoice_map(invoice_list): return internal_invoice_map -def get_invoice_tax_map(invoice_list, invoice_income_map, income_accounts): +def get_invoice_tax_map(invoice_list, invoice_income_map, income_accounts, include_payments=False): tax_details = frappe.db.sql( """select parent, account_head, sum(base_tax_amount_after_discount_amount) as tax_amount @@ -467,6 +517,22 @@ def get_invoice_tax_map(invoice_list, invoice_income_map, income_accounts): as_dict=1, ) + if include_payments: + advance_tax_details = frappe.db.sql( + """ + select parent, account_head, case add_deduct_tax when "Add" then sum(base_tax_amount) + else sum(base_tax_amount) * -1 end as tax_amount + from `tabAdvance Taxes and Charges` + where parent in (%s) and charge_type in ('On Paid Amount', 'Actual') + and base_tax_amount != 0 + group by parent, account_head, add_deduct_tax + """ + % ", ".join(["%s"] * len(invoice_list)), + tuple(inv.name for inv in invoice_list), + as_dict=1, + ) + tax_details += advance_tax_details + invoice_tax_map = {} for d in tax_details: if d.account_head in income_accounts: @@ -556,3 +622,19 @@ def get_mode_of_payments(invoice_list): mode_of_payments.setdefault(d.parent, []).append(d.mode_of_payment) return mode_of_payments + + +def get_customer_details(customers): + customer_details = {} + for customer in frappe.db.sql( + """select name, customer_group, territory, tax_id from `tabCustomer` + where name in (%s)""" + % ", ".join(["%s"] * len(customers)), + tuple(customers), + as_dict=1, + ): + customer_details.setdefault( + customer.name, [customer.customer_group, customer.territory, customer.tax_id] + ) + + return customer_details From cbef6c30c3f87f212e2dbfd0c89b2fc276404fbb Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Mon, 10 Jul 2023 18:39:35 +0530 Subject: [PATCH 04/26] refactor: move repeating code to common controller --- .../purchase_register/purchase_register.py | 42 ++-------------- .../report/sales_register/sales_register.py | 48 +++---------------- erpnext/accounts/report/utils.py | 38 +++++++++++++++ 3 files changed, 48 insertions(+), 80 deletions(-) diff --git a/erpnext/accounts/report/purchase_register/purchase_register.py b/erpnext/accounts/report/purchase_register/purchase_register.py index 72d720959f..c8f1906dba 100644 --- a/erpnext/accounts/report/purchase_register/purchase_register.py +++ b/erpnext/accounts/report/purchase_register/purchase_register.py @@ -10,6 +10,7 @@ from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import ( get_accounting_dimensions, get_dimension_with_children, ) +from erpnext.accounts.report.utils import get_party_details, get_taxes_query def execute(filters=None): @@ -39,7 +40,7 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum ) invoice_po_pr_map = get_invoice_po_pr_map(invoice_list) suppliers = list(set(d.supplier for d in invoice_list)) - supplier_details = get_supplier_details(suppliers) + supplier_details = get_party_details("Supplier", suppliers) company_currency = frappe.get_cached_value("Company", filters.company, "default_currency") @@ -57,8 +58,8 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum row.append(inv.get(col)) row += [ - supplier_details.get(inv.supplier)[0], # supplier_group - supplier_details.get(inv.supplier)[1], + supplier_details.get(inv.supplier).get("supplier_group"), # supplier_group + supplier_details.get(inv.supplier).get("tax_id"), inv.credit_to, inv.mode_of_payment, ", ".join(project) if inv.doctype == "Purchase Invoice" else inv.project, @@ -191,27 +192,6 @@ def get_columns(invoice_list, additional_table_columns, include_payments=False): return columns, expense_accounts, tax_accounts, unrealized_profit_loss_accounts -def get_taxes_query(invoice_list, doctype, parenttype): - taxes = frappe.qb.DocType(doctype) - - query = ( - frappe.qb.from_(taxes) - .select(taxes.account_head) - .distinct() - .where( - (taxes.parenttype == parenttype) - & (taxes.docstatus == 1) - & (taxes.account_head.isnotnull()) - & (taxes.parent.isin([inv.name for inv in invoice_list])) - ) - .orderby(taxes.account_head) - ) - - if doctype == "Purchase Taxes and Charges": - return query.where(taxes.category.isin(["Total", "Valuation and Total"])) - return query.where(taxes.charge_type.isin(["On Paid Amount", "Actual"])) - - def get_conditions(filters, payments=False): conditions = "" @@ -455,17 +435,3 @@ def get_account_details(invoice_list): account_map[acc.name] = acc.parent_account return account_map - - -def get_supplier_details(suppliers): - supplier_details = {} - for supp in frappe.db.sql( - """select name, supplier_group, tax_id from `tabSupplier` - where name in (%s)""" - % ", ".join(["%s"] * len(suppliers)), - tuple(suppliers), - as_dict=1, - ): - supplier_details.setdefault(supp.name, [supp.supplier_group, supp.tax_id]) - - return supplier_details diff --git a/erpnext/accounts/report/sales_register/sales_register.py b/erpnext/accounts/report/sales_register/sales_register.py index a2bba5578e..1ecfbfe2c6 100644 --- a/erpnext/accounts/report/sales_register/sales_register.py +++ b/erpnext/accounts/report/sales_register/sales_register.py @@ -11,6 +11,7 @@ from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import ( get_accounting_dimensions, get_dimension_with_children, ) +from erpnext.accounts.report.utils import get_party_details, get_taxes_query def execute(filters=None): @@ -44,7 +45,7 @@ def _execute(filters, additional_table_columns=None, additional_query_columns=No company_currency = frappe.get_cached_value("Company", filters.get("company"), "default_currency") mode_of_payments = get_mode_of_payments([inv.name for inv in invoice_list]) customers = list(set(d.customer for d in invoice_list)) - customer_details = get_customer_details(customers) + customer_details = get_party_details("Customer", customers) data = [] for inv in invoice_list: @@ -67,9 +68,9 @@ def _execute(filters, additional_table_columns=None, additional_query_columns=No row.update( { - "customer_group": customer_details.get(inv.customer)[0], - "territory": customer_details.get(inv.customer)[1], - "tax_id": customer_details.get(inv.customer)[2], + "customer_group": customer_details.get(inv.customer).get("customer_group"), + "territory": customer_details.get(inv.customer).get("territory"), + "tax_id": customer_details.get(inv.customer).get("tax_id"), "receivable_account": inv.debit_to, "mode_of_payment": ", ".join(mode_of_payments.get(inv.name, [])), "project": inv.project, @@ -250,7 +251,7 @@ def get_columns(invoice_list, additional_table_columns, include_payments=False): advance_taxes_query = get_taxes_query( invoice_list, "Advance Taxes and Charges", "Payment Entry" ) - advance_tax_accounts = advance_taxes_query.run(as_dict=True, debug=True, pluck="account_head") + advance_tax_accounts = advance_taxes_query.run(as_dict=True, pluck="account_head") tax_accounts = set(tax_accounts + advance_tax_accounts) unrealized_profit_loss_accounts = frappe.db.sql_list( @@ -350,27 +351,6 @@ def get_columns(invoice_list, additional_table_columns, include_payments=False): return columns, income_accounts, tax_accounts, unrealized_profit_loss_accounts -def get_taxes_query(invoice_list, doctype, parenttype): - taxes = frappe.qb.DocType(doctype) - - query = ( - frappe.qb.from_(taxes) - .select(taxes.account_head) - .distinct() - .where( - (taxes.parenttype == parenttype) - & (taxes.docstatus == 1) - & (taxes.account_head.isnotnull()) - & (taxes.parent.isin([inv.name for inv in invoice_list])) - ) - .orderby(taxes.account_head) - ) - - if doctype == "Sales Taxes and Charges": - return query.where(taxes.charge_type.isin(["Total", "Valuation and Total"])) - return query.where(taxes.charge_type.isin(["On Paid Amount", "Actual"])) - - def get_conditions(filters, payments=False): conditions = "" @@ -622,19 +602,3 @@ def get_mode_of_payments(invoice_list): mode_of_payments.setdefault(d.parent, []).append(d.mode_of_payment) return mode_of_payments - - -def get_customer_details(customers): - customer_details = {} - for customer in frappe.db.sql( - """select name, customer_group, territory, tax_id from `tabCustomer` - where name in (%s)""" - % ", ".join(["%s"] * len(customers)), - tuple(customers), - as_dict=1, - ): - customer_details.setdefault( - customer.name, [customer.customer_group, customer.territory, customer.tax_id] - ) - - return customer_details diff --git a/erpnext/accounts/report/utils.py b/erpnext/accounts/report/utils.py index 97cc1c4a13..e049301add 100644 --- a/erpnext/accounts/report/utils.py +++ b/erpnext/accounts/report/utils.py @@ -151,3 +151,41 @@ def get_invoiced_item_gross_margin( result = sum(d.gross_profit for d in result) return result + + +def get_party_details(party_type, party_list): + party_details = {} + party = frappe.qb.DocType(party_type) + query = frappe.qb.from_(party).select(party.name, party.tax_id).where(party.name.isin(party_list)) + if party_type == "Supplier": + query = query.select(party.supplier_group) + else: + query = query.select(party.customer_group, party.territory) + + party_detail_list = query.run(as_dict=True) + for party_dict in party_detail_list: + party_details[party_dict.name] = party_dict + return party_details + + +def get_taxes_query(invoice_list, doctype, parenttype): + taxes = frappe.qb.DocType(doctype) + + query = ( + frappe.qb.from_(taxes) + .select(taxes.account_head) + .distinct() + .where( + (taxes.parenttype == parenttype) + & (taxes.docstatus == 1) + & (taxes.account_head.isnotnull()) + & (taxes.parent.isin([inv.name for inv in invoice_list])) + ) + .orderby(taxes.account_head) + ) + + if doctype == "Purchase Taxes and Charges": + return query.where(taxes.category.isin(["Total", "Valuation and Total"])) + elif doctype == "Sales Taxes and Charges": + return query.where(taxes.charge_type.isin(["Total", "Valuation and Total"])) + return query.where(taxes.charge_type.isin(["On Paid Amount", "Actual"])) From 9c87997dae1c3ebc483ae82cc70365d597b1a3c4 Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Mon, 10 Jul 2023 19:12:19 +0530 Subject: [PATCH 05/26] fix: fetch cost center for PE --- .../report/purchase_register/purchase_register.py | 2 +- erpnext/accounts/report/sales_register/sales_register.py | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/erpnext/accounts/report/purchase_register/purchase_register.py b/erpnext/accounts/report/purchase_register/purchase_register.py index c8f1906dba..bd92826a09 100644 --- a/erpnext/accounts/report/purchase_register/purchase_register.py +++ b/erpnext/accounts/report/purchase_register/purchase_register.py @@ -100,7 +100,7 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum row += [total_tax, inv.base_grand_total, flt(inv.base_grand_total, 0), inv.outstanding_amount] data.append(row) - return columns, data + return columns, sorted(data, key=lambda x: x[1]) def get_columns(invoice_list, additional_table_columns, include_payments=False): diff --git a/erpnext/accounts/report/sales_register/sales_register.py b/erpnext/accounts/report/sales_register/sales_register.py index 1ecfbfe2c6..a13354b861 100644 --- a/erpnext/accounts/report/sales_register/sales_register.py +++ b/erpnext/accounts/report/sales_register/sales_register.py @@ -78,7 +78,7 @@ def _execute(filters, additional_table_columns=None, additional_query_columns=No "remarks": inv.remarks, "sales_order": ", ".join(sales_order), "delivery_note": ", ".join(delivery_note), - "cost_center": ", ".join(cost_center), + "cost_center": ", ".join(cost_center) if inv.doctype == "Sales Invoice" else inv.cost_center, "warehouse": ", ".join(warehouse), "currency": company_currency, } @@ -131,7 +131,7 @@ def _execute(filters, additional_table_columns=None, additional_query_columns=No data.append(row) - return columns, data + return columns, sorted(data, key=lambda x: x["posting_date"]) def get_columns(invoice_list, additional_table_columns, include_payments=False): @@ -416,7 +416,7 @@ def get_invoices(filters, additional_query_columns): conditions = get_conditions(filters) return frappe.db.sql( """ - select name, posting_date, debit_to, project, customer, + select 'Sales Invoice' as doctype, name, posting_date, debit_to, project, customer, customer_name, owner, remarks, territory, tax_id, customer_group, base_net_total, base_grand_total, base_rounded_total, outstanding_amount, is_internal_customer, represents_company, company {0} @@ -440,7 +440,7 @@ def get_payments(filters, additional_query_columns): select 'Payment Entry' as doctype, name, posting_date, paid_to as debit_to, party as customer, party_name as customer_name, remarks, paid_amount as base_net_total, paid_amount_after_tax as base_grand_total, - mode_of_payment {0}, project + mode_of_payment {0}, project, cost_center from `tabPayment Entry` where party_type = 'Customer' %s order by posting_date desc, name desc""".format( From d5aa0e325ee868b81c65dee5545fa0ae4de4f8f3 Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Tue, 11 Jul 2023 14:47:23 +0530 Subject: [PATCH 06/26] feat: fetch JV with PE --- .../purchase_register/purchase_register.py | 39 ++++++++------- .../report/sales_register/sales_register.py | 49 +++++++++++-------- erpnext/accounts/report/utils.py | 44 +++++++++++++++++ 3 files changed, 93 insertions(+), 39 deletions(-) diff --git a/erpnext/accounts/report/purchase_register/purchase_register.py b/erpnext/accounts/report/purchase_register/purchase_register.py index bd92826a09..8a845cf70a 100644 --- a/erpnext/accounts/report/purchase_register/purchase_register.py +++ b/erpnext/accounts/report/purchase_register/purchase_register.py @@ -10,7 +10,12 @@ from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import ( get_accounting_dimensions, get_dimension_with_children, ) -from erpnext.accounts.report.utils import get_party_details, get_taxes_query +from erpnext.accounts.report.utils import ( + get_journal_entries, + get_party_details, + get_payment_entries, + get_taxes_query, +) def execute(filters=None): @@ -51,7 +56,7 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum purchase_receipt = list(set(invoice_po_pr_map.get(inv.name, {}).get("purchase_receipt", []))) project = list(set(invoice_po_pr_map.get(inv.name, {}).get("project", []))) - row = [inv.name, inv.posting_date, inv.supplier, inv.supplier_name] + row = [inv.doctype, inv.name, inv.posting_date, inv.supplier, inv.supplier_name] if additional_query_columns: for col in additional_query_columns: @@ -100,13 +105,14 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum row += [total_tax, inv.base_grand_total, flt(inv.base_grand_total, 0), inv.outstanding_amount] data.append(row) - return columns, sorted(data, key=lambda x: x[1]) + return columns, sorted(data, key=lambda x: x[2]) def get_columns(invoice_list, additional_table_columns, include_payments=False): """return columns based on filters""" columns = [ - _("Invoice") + ":Link/Purchase Invoice:120", + _("Voucher Type") + ":Data:120", + _("Voucher No") + ":Dynamic Link/voucher_type:120", _("Posting Date") + ":Date:80", _("Supplier Id") + "::120", _("Supplier Name") + "::120", @@ -117,7 +123,7 @@ def get_columns(invoice_list, additional_table_columns, include_payments=False): columns += [ _("Supplier Group") + ":Link/Supplier Group:120", - _("Tax Id") + "::80", + _("Tax Id") + "::50", _("Payable Account") + ":Link/Account:120", _("Mode of Payment") + ":Link/Mode of Payment:80", _("Project") + ":Link/Project:80", @@ -280,20 +286,17 @@ def get_payments(filters, additional_query_columns): additional_query_columns = ", " + ", ".join(additional_query_columns) conditions = get_conditions(filters, payments=True) - return frappe.db.sql( - """ - select 'Payment Entry' as doctype, name, posting_date, paid_to as credit_to, - party as supplier, party_name as supplier_name, remarks, paid_amount as base_net_total, paid_amount_after_tax as base_grand_total, - mode_of_payment {0}, project - from `tabPayment Entry` - where party_type = 'Supplier' %s - order by posting_date desc, name desc""".format( - additional_query_columns or "" - ) - % conditions, - filters, - as_dict=1, + args = frappe._dict( + account="credit_to", + party="supplier", + party_name="supplier_name", + additional_query_columns="" if not additional_query_columns else additional_query_columns, + party_type="Supplier", + conditions=conditions, ) + payment_entries = get_payment_entries(filters, args) + journal_entries = get_journal_entries(filters, args) + return payment_entries + journal_entries def get_invoice_expense_map(invoice_list): diff --git a/erpnext/accounts/report/sales_register/sales_register.py b/erpnext/accounts/report/sales_register/sales_register.py index a13354b861..5965a1a2b1 100644 --- a/erpnext/accounts/report/sales_register/sales_register.py +++ b/erpnext/accounts/report/sales_register/sales_register.py @@ -11,7 +11,12 @@ from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import ( get_accounting_dimensions, get_dimension_with_children, ) -from erpnext.accounts.report.utils import get_party_details, get_taxes_query +from erpnext.accounts.report.utils import ( + get_journal_entries, + get_party_details, + get_payment_entries, + get_taxes_query, +) def execute(filters=None): @@ -56,6 +61,7 @@ def _execute(filters, additional_table_columns=None, additional_query_columns=No warehouse = list(set(invoice_cc_wh_map.get(inv.name, {}).get("warehouse", []))) row = { + "voucher_type": inv.doctype, "invoice": inv.name, "posting_date": inv.posting_date, "customer": inv.customer, @@ -138,10 +144,15 @@ def get_columns(invoice_list, additional_table_columns, include_payments=False): """return columns based on filters""" columns = [ { - "label": _("Invoice"), + "label": _("Voucher Type"), + "fieldname": "voucher_type", + "width": 120, + }, + { + "label": _("Voucher"), "fieldname": "invoice", - "fieldtype": "Link", - "options": "Sales Invoice", + "fieldtype": "Dynamic Link", + "options": "voucher_type", "width": 120, }, {"label": _("Posting Date"), "fieldname": "posting_date", "fieldtype": "Date", "width": 80}, @@ -173,13 +184,13 @@ def get_columns(invoice_list, additional_table_columns, include_payments=False): "options": "Territory", "width": 80, }, - {"label": _("Tax Id"), "fieldname": "tax_id", "fieldtype": "Data", "width": 120}, + {"label": _("Tax Id"), "fieldname": "tax_id", "fieldtype": "Data", "width": 80}, { "label": _("Receivable Account"), "fieldname": "receivable_account", "fieldtype": "Link", "options": "Account", - "width": 80, + "width": 100, }, { "label": _("Mode Of Payment"), @@ -194,7 +205,7 @@ def get_columns(invoice_list, additional_table_columns, include_payments=False): "options": "Project", "width": 80, }, - {"label": _("Owner"), "fieldname": "owner", "fieldtype": "Data", "width": 150}, + {"label": _("Owner"), "fieldname": "owner", "fieldtype": "Data", "width": 100}, {"label": _("Remarks"), "fieldname": "remarks", "fieldtype": "Data", "width": 150}, { "label": _("Sales Order"), @@ -435,21 +446,17 @@ def get_payments(filters, additional_query_columns): additional_query_columns = ", " + ", ".join(additional_query_columns) conditions = get_conditions(filters, payments=True) - return frappe.db.sql( - """ - select 'Payment Entry' as doctype, name, posting_date, paid_to as debit_to, - party as customer, party_name as customer_name, remarks, - paid_amount as base_net_total, paid_amount_after_tax as base_grand_total, - mode_of_payment {0}, project, cost_center - from `tabPayment Entry` - where party_type = 'Customer' %s - order by posting_date desc, name desc""".format( - additional_query_columns or "" - ) - % conditions, - filters, - as_dict=1, + args = frappe._dict( + account="debit_to", + party="customer", + party_name="customer_name", + additional_query_columns="" if not additional_query_columns else additional_query_columns, + party_type="Customer", + conditions=conditions, ) + payment_entries = get_payment_entries(filters, args) + journal_entries = get_journal_entries(filters, args) + return payment_entries + journal_entries def get_invoice_income_map(invoice_list): diff --git a/erpnext/accounts/report/utils.py b/erpnext/accounts/report/utils.py index e049301add..c6b9883512 100644 --- a/erpnext/accounts/report/utils.py +++ b/erpnext/accounts/report/utils.py @@ -189,3 +189,47 @@ def get_taxes_query(invoice_list, doctype, parenttype): elif doctype == "Sales Taxes and Charges": return query.where(taxes.charge_type.isin(["Total", "Valuation and Total"])) return query.where(taxes.charge_type.isin(["On Paid Amount", "Actual"])) + + +def get_journal_entries(filters, args): + return frappe.db.sql( + """ + select je.voucher_type as doctype, je.name, je.posting_date, + jea.account as {0}, jea.party as {1}, jea.party as {2}, + je.bill_no, je.bill_date, je.remark, je.total_amount as base_net_total, + je.total_amount as base_grand_total, je.mode_of_payment, jea.project {3} + from `tabJournal Entry` je left join `tabJournal Entry Account` jea on jea.parent=je.name + where je.voucher_type='Journal Entry' and jea.party_type='{4}' {5} + order by je.posting_date desc, je.name desc""".format( + args.account, + args.party, + args.party_name, + args.additional_query_columns, + args.party_type, + args.conditions, + ), + filters, + as_dict=1, + ) + + +def get_payment_entries(filters, args): + return frappe.db.sql( + """ + select 'Payment Entry' as doctype, name, posting_date, paid_to as {0}, + party as {1}, party_name as {2}, remarks, + paid_amount as base_net_total, paid_amount_after_tax as base_grand_total, + mode_of_payment, project, cost_center {3} + from `tabPayment Entry` + where party_type='{4}' {5} + order by posting_date desc, name desc""".format( + args.account, + args.party, + args.party_name, + args.additional_query_columns, + args.party_type, + args.conditions, + ), + filters, + as_dict=1, + ) From 7650b0073a271c8f4799992a205f4da1c66e6e2e Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Tue, 11 Jul 2023 15:18:28 +0530 Subject: [PATCH 07/26] fix: validate party filter for fetching payments --- .../report/purchase_register/purchase_register.py | 3 ++- erpnext/accounts/report/sales_register/sales_register.py | 3 ++- erpnext/accounts/report/utils.py | 8 ++++---- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/erpnext/accounts/report/purchase_register/purchase_register.py b/erpnext/accounts/report/purchase_register/purchase_register.py index 8a845cf70a..4b4c5cb559 100644 --- a/erpnext/accounts/report/purchase_register/purchase_register.py +++ b/erpnext/accounts/report/purchase_register/purchase_register.py @@ -29,6 +29,8 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum include_payments = filters.get("include_payments") invoice_list = get_invoices(filters, additional_query_columns) if filters.get("include_payments"): + if not filters.get("supplier"): + frappe.throw(_("Please select a supplier for fetching payments.")) invoice_list += get_payments(filters, additional_query_columns) columns, expense_accounts, tax_accounts, unrealized_profit_loss_accounts = get_columns( invoice_list, additional_table_columns, include_payments @@ -291,7 +293,6 @@ def get_payments(filters, additional_query_columns): party="supplier", party_name="supplier_name", additional_query_columns="" if not additional_query_columns else additional_query_columns, - party_type="Supplier", conditions=conditions, ) payment_entries = get_payment_entries(filters, args) diff --git a/erpnext/accounts/report/sales_register/sales_register.py b/erpnext/accounts/report/sales_register/sales_register.py index 5965a1a2b1..76611a0aaa 100644 --- a/erpnext/accounts/report/sales_register/sales_register.py +++ b/erpnext/accounts/report/sales_register/sales_register.py @@ -30,6 +30,8 @@ def _execute(filters, additional_table_columns=None, additional_query_columns=No include_payments = filters.get("include_payments") invoice_list = get_invoices(filters, additional_query_columns) if filters.get("include_payments"): + if not filters.get("customer"): + frappe.throw(_("Please select a customer for fetching payments.")) invoice_list += get_payments(filters, additional_query_columns) columns, income_accounts, tax_accounts, unrealized_profit_loss_accounts = get_columns( invoice_list, additional_table_columns, include_payments @@ -451,7 +453,6 @@ def get_payments(filters, additional_query_columns): party="customer", party_name="customer_name", additional_query_columns="" if not additional_query_columns else additional_query_columns, - party_type="Customer", conditions=conditions, ) payment_entries = get_payment_entries(filters, args) diff --git a/erpnext/accounts/report/utils.py b/erpnext/accounts/report/utils.py index c6b9883512..474ae3490a 100644 --- a/erpnext/accounts/report/utils.py +++ b/erpnext/accounts/report/utils.py @@ -199,13 +199,13 @@ def get_journal_entries(filters, args): je.bill_no, je.bill_date, je.remark, je.total_amount as base_net_total, je.total_amount as base_grand_total, je.mode_of_payment, jea.project {3} from `tabJournal Entry` je left join `tabJournal Entry Account` jea on jea.parent=je.name - where je.voucher_type='Journal Entry' and jea.party_type='{4}' {5} + where je.voucher_type='Journal Entry' and jea.party='{4}' {5} order by je.posting_date desc, je.name desc""".format( args.account, args.party, args.party_name, args.additional_query_columns, - args.party_type, + filters.get(args.party), args.conditions, ), filters, @@ -221,13 +221,13 @@ def get_payment_entries(filters, args): paid_amount as base_net_total, paid_amount_after_tax as base_grand_total, mode_of_payment, project, cost_center {3} from `tabPayment Entry` - where party_type='{4}' {5} + where party='{4}' {5} order by posting_date desc, name desc""".format( args.account, args.party, args.party_name, args.additional_query_columns, - args.party_type, + filters.get(args.party), args.conditions, ), filters, From 1e8b8b5b297622c3e9fcb70e58ac0c30f580048d Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Wed, 12 Jul 2023 11:14:03 +0530 Subject: [PATCH 08/26] fix: linting issues --- .../report/purchase_register/purchase_register.py | 9 ++++----- erpnext/accounts/report/sales_register/sales_register.py | 7 +++---- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/erpnext/accounts/report/purchase_register/purchase_register.py b/erpnext/accounts/report/purchase_register/purchase_register.py index 226447c3f2..9e545dc2a1 100644 --- a/erpnext/accounts/report/purchase_register/purchase_register.py +++ b/erpnext/accounts/report/purchase_register/purchase_register.py @@ -10,16 +10,15 @@ from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import ( get_accounting_dimensions, get_dimension_with_children, ) - from erpnext.accounts.report.utils import ( get_journal_entries, get_party_details, get_payment_entries, + get_query_columns, get_taxes_query, + get_values_for_columns, ) -from erpnext.accounts.report.utils import get_query_columns, get_values_for_columns - def execute(filters=None): return _execute(filters) @@ -34,7 +33,7 @@ def _execute(filters=None, additional_table_columns=None): if filters.get("include_payments"): if not filters.get("supplier"): frappe.throw(_("Please select a supplier for fetching payments.")) - invoice_list += get_payments(filters, additional_query_columns) + invoice_list += get_payments(filters, additional_table_columns) columns, expense_accounts, tax_accounts, unrealized_profit_loss_accounts = get_columns( invoice_list, additional_table_columns, include_payments @@ -63,7 +62,7 @@ def _execute(filters=None, additional_table_columns=None): project = list(set(invoice_po_pr_map.get(inv.name, {}).get("project", []))) row = [ - inv.doctype, + inv.doctype, inv.name, inv.posting_date, inv.supplier, diff --git a/erpnext/accounts/report/sales_register/sales_register.py b/erpnext/accounts/report/sales_register/sales_register.py index 8de9bb2bb1..ec35039308 100644 --- a/erpnext/accounts/report/sales_register/sales_register.py +++ b/erpnext/accounts/report/sales_register/sales_register.py @@ -11,16 +11,15 @@ from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import ( get_accounting_dimensions, get_dimension_with_children, ) - from erpnext.accounts.report.utils import ( get_journal_entries, get_party_details, get_payment_entries, + get_query_columns, get_taxes_query, + get_values_for_columns, ) -from erpnext.accounts.report.utils import get_query_columns, get_values_for_columns - def execute(filters=None): return _execute(filters) @@ -35,7 +34,7 @@ def _execute(filters, additional_table_columns=None): if filters.get("include_payments"): if not filters.get("customer"): frappe.throw(_("Please select a customer for fetching payments.")) - invoice_list += get_payments(filters, additional_query_columns) + invoice_list += get_payments(filters, additional_table_columns) columns, income_accounts, tax_accounts, unrealized_profit_loss_accounts = get_columns( invoice_list, additional_table_columns, include_payments From 6c11ca1b75adeceaef9f3b65205886c3e824119d Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Wed, 12 Jul 2023 14:43:18 +0530 Subject: [PATCH 09/26] refactor: use qb to fetch PE JV and Inv --- .../purchase_register/purchase_register.py | 116 ++++------- .../report/sales_register/sales_register.py | 121 +++++------- erpnext/accounts/report/utils.py | 187 ++++++++++++------ 3 files changed, 206 insertions(+), 218 deletions(-) diff --git a/erpnext/accounts/report/purchase_register/purchase_register.py b/erpnext/accounts/report/purchase_register/purchase_register.py index 9e545dc2a1..6e35c9dbe8 100644 --- a/erpnext/accounts/report/purchase_register/purchase_register.py +++ b/erpnext/accounts/report/purchase_register/purchase_register.py @@ -4,13 +4,15 @@ import frappe from frappe import _, msgprint +from frappe.query_builder.custom import ConstantColumn from frappe.utils import flt +from pypika import Order from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import ( get_accounting_dimensions, - get_dimension_with_children, ) from erpnext.accounts.report.utils import ( + get_conditions, get_journal_entries, get_party_details, get_payment_entries, @@ -203,99 +205,53 @@ def get_columns(invoice_list, additional_table_columns, include_payments=False): return columns, expense_accounts, tax_accounts, unrealized_profit_loss_accounts -def get_conditions(filters, payments=False): - conditions = "" - - if filters.get("company"): - conditions += " and company=%(company)s" - if filters.get("supplier"): - conditions += " and party = %(supplier)s" if payments else " and supplier = %(supplier)s" - - if filters.get("from_date"): - conditions += " and posting_date>=%(from_date)s" - if filters.get("to_date"): - conditions += " and posting_date<=%(to_date)s" - - if filters.get("mode_of_payment"): - conditions += " and ifnull(mode_of_payment, '') = %(mode_of_payment)s" - - if filters.get("cost_center"): - if payments: - conditions += " and cost_center = %(cost_center)s" - else: - conditions += """ and exists(select name from `tabPurchase Invoice Item` - where parent=`tabPurchase Invoice`.name - and ifnull(`tabPurchase Invoice Item`.cost_center, '') = %(cost_center)s)""" - - if filters.get("warehouse") and not payments: - conditions += """ and exists(select name from `tabPurchase Invoice Item` - where parent=`tabPurchase Invoice`.name - and ifnull(`tabPurchase Invoice Item`.warehouse, '') = %(warehouse)s)""" - - if filters.get("item_group") and not payments: - conditions += """ and exists(select name from `tabPurchase Invoice Item` - where parent=`tabPurchase Invoice`.name - and ifnull(`tabPurchase Invoice Item`.item_group, '') = %(item_group)s)""" - - accounting_dimensions = get_accounting_dimensions(as_list=False) - - if accounting_dimensions: - common_condition = """ - and exists(select name from `tabPurchase Invoice Item` - where parent=`tabPurchase Invoice`.name - """ - for dimension in accounting_dimensions: - if filters.get(dimension.fieldname): - if frappe.get_cached_value("DocType", dimension.document_type, "is_tree"): - filters[dimension.fieldname] = get_dimension_with_children( - dimension.document_type, filters.get(dimension.fieldname) - ) - - conditions += ( - common_condition - + "and ifnull(`tabPurchase Invoice`.{0}, '') in %({0})s)".format(dimension.fieldname) - ) - else: - conditions += ( - common_condition - + "and ifnull(`tabPurchase Invoice`.{0}, '') in %({0})s)".format(dimension.fieldname) - ) - - return conditions - - def get_invoices(filters, additional_query_columns): - conditions = get_conditions(filters) - return frappe.db.sql( - """ - select - 'Purchase Invoice' as doctype, name, posting_date, credit_to, supplier, supplier_name, tax_id, bill_no, bill_date, - remarks, base_net_total, base_grand_total, outstanding_amount, - mode_of_payment {0} - from `tabPurchase Invoice` - where docstatus = 1 {1} - order by posting_date desc, name desc""".format( - additional_query_columns, conditions - ), - filters, - as_dict=1, + accounting_dimensions = get_accounting_dimensions(as_list=False) + pi = frappe.qb.DocType("Purchase Invoice") + invoice_item = frappe.qb.DocType("Purchase Invoice Item") + query = ( + frappe.qb.from_(pi) + .inner_join(invoice_item) + .on(pi.name == invoice_item.parent) + .select( + ConstantColumn("Purchase Invoice").as_("doctype"), + pi.name, + pi.posting_date, + pi.credit_to, + pi.supplier, + pi.supplier_name, + pi.tax_id, + pi.bill_no, + pi.bill_date, + pi.remarks, + pi.base_net_total, + pi.base_grand_total, + pi.outstanding_amount, + pi.mode_of_payment, + ) + .where((pi.docstatus == 1)) + .orderby(pi.posting_date, pi.name, order=Order.desc) ) + if filters.get("supplier"): + query = query.where(pi.supplier == filters.supplier) + query = get_conditions(filters, query, [pi, invoice_item], accounting_dimensions) + invoices = query.run(as_dict=True, debug=True) + return invoices def get_payments(filters, additional_query_columns): if additional_query_columns: additional_query_columns = ", " + ", ".join(additional_query_columns) - conditions = get_conditions(filters, payments=True) args = frappe._dict( account="credit_to", party="supplier", party_name="supplier_name", additional_query_columns="" if not additional_query_columns else additional_query_columns, - conditions=conditions, ) - payment_entries = get_payment_entries(filters, args) - journal_entries = get_journal_entries(filters, args) + accounting_dimensions = get_accounting_dimensions(as_list=False) + payment_entries = get_payment_entries(filters, accounting_dimensions, args) + journal_entries = get_journal_entries(filters, accounting_dimensions, args) return payment_entries + journal_entries diff --git a/erpnext/accounts/report/sales_register/sales_register.py b/erpnext/accounts/report/sales_register/sales_register.py index ec35039308..2460cd7ab6 100644 --- a/erpnext/accounts/report/sales_register/sales_register.py +++ b/erpnext/accounts/report/sales_register/sales_register.py @@ -5,13 +5,15 @@ import frappe from frappe import _, msgprint from frappe.model.meta import get_field_precision +from frappe.query_builder.custom import ConstantColumn from frappe.utils import flt +from pypika import Order from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import ( get_accounting_dimensions, - get_dimension_with_children, ) from erpnext.accounts.report.utils import ( + get_conditions, get_journal_entries, get_party_details, get_payment_entries, @@ -359,96 +361,61 @@ def get_columns(invoice_list, additional_table_columns, include_payments=False): return columns, income_accounts, tax_accounts, unrealized_profit_loss_accounts -def get_conditions(filters, payments=False): - conditions = "" - - accounting_dimensions = get_accounting_dimensions(as_list=False) or [] - accounting_dimensions_list = [d.fieldname for d in accounting_dimensions] - - if filters.get("company"): - conditions += " and company=%(company)s" - - if filters.get("customer") and "customer" not in accounting_dimensions_list: - conditions += " and party = %(customer)s" if payments else " and customer = %(customer)s" - - if filters.get("from_date"): - conditions += " and posting_date >= %(from_date)s" - if filters.get("to_date"): - conditions += " and posting_date <= %(to_date)s" - - if filters.get("owner"): - conditions += " and owner = %(owner)s" - - def get_sales_invoice_item_field_condition(field, table="Sales Invoice Item") -> str: - if not filters.get(field) or field in accounting_dimensions_list: - return "" - return f""" and exists(select name from `tab{table}` - where parent=`tabSales Invoice`.name - and ifnull(`tab{table}`.{field}, '') = %({field})s)""" - - conditions += get_sales_invoice_item_field_condition("mode_of_payment", "Sales Invoice Payment") - conditions += get_sales_invoice_item_field_condition("cost_center") - conditions += get_sales_invoice_item_field_condition("warehouse") - conditions += get_sales_invoice_item_field_condition("brand") - conditions += get_sales_invoice_item_field_condition("item_group") - - if accounting_dimensions: - common_condition = """ - and exists(select name from `tabSales Invoice Item` - where parent=`tabSales Invoice`.name - """ - for dimension in accounting_dimensions: - if filters.get(dimension.fieldname): - if frappe.get_cached_value("DocType", dimension.document_type, "is_tree"): - filters[dimension.fieldname] = get_dimension_with_children( - dimension.document_type, filters.get(dimension.fieldname) - ) - - conditions += ( - common_condition - + "and ifnull(`tabSales Invoice`.{0}, '') in %({0})s)".format(dimension.fieldname) - ) - else: - conditions += ( - common_condition - + "and ifnull(`tabSales Invoice`.{0}, '') in %({0})s)".format(dimension.fieldname) - ) - - return conditions - - def get_invoices(filters, additional_query_columns): - conditions = get_conditions(filters) - return frappe.db.sql( - """ - select 'Sales Invoice' as doctype, name, posting_date, debit_to, project, customer, - customer_name, owner, remarks, territory, tax_id, customer_group, - base_net_total, base_grand_total, base_rounded_total, outstanding_amount, - is_internal_customer, represents_company, company {0} - from `tabSales Invoice` - where docstatus = 1 {1} - order by posting_date desc, name desc""".format( - additional_query_columns, conditions - ), - filters, - as_dict=1, + accounting_dimensions = get_accounting_dimensions(as_list=False) + si = frappe.qb.DocType("Sales Invoice") + invoice_item = frappe.qb.DocType("Sales Invoice Item") + invoice_payment = frappe.qb.DocType("Sales Invoice Payment") + query = ( + frappe.qb.from_(si) + .inner_join(invoice_item) + .on(si.name == invoice_item.parent) + .left_join(invoice_payment) + .on(si.name == invoice_payment.parent) + .select( + ConstantColumn("Sales Invoice").as_("doctype"), + si.name, + si.posting_date, + si.debit_to, + si.project, + si.customer, + si.customer_name, + si.owner, + si.remarks, + si.territory, + si.tax_id, + si.customer_group, + si.base_net_total, + si.base_grand_total, + si.base_rounded_total, + si.outstanding_amount, + si.is_internal_customer, + si.represents_company, + si.company, + ) + .where((si.docstatus == 1)) + .orderby(si.posting_date, si.name, order=Order.desc) ) + if filters.get("customer"): + query = query.where(si.customer == filters.customer) + query = get_conditions(filters, query, [si, invoice_item, invoice_payment], accounting_dimensions) + invoices = query.run(as_dict=True, debug=True) + return invoices def get_payments(filters, additional_query_columns): if additional_query_columns: additional_query_columns = ", " + ", ".join(additional_query_columns) - conditions = get_conditions(filters, payments=True) args = frappe._dict( account="debit_to", party="customer", party_name="customer_name", additional_query_columns="" if not additional_query_columns else additional_query_columns, - conditions=conditions, ) - payment_entries = get_payment_entries(filters, args) - journal_entries = get_journal_entries(filters, args) + accounting_dimensions = get_accounting_dimensions(as_list=False) + payment_entries = get_payment_entries(filters, accounting_dimensions, args) + journal_entries = get_journal_entries(filters, accounting_dimensions, args) return payment_entries + journal_entries diff --git a/erpnext/accounts/report/utils.py b/erpnext/accounts/report/utils.py index 8711e7ee23..6617f9ae25 100644 --- a/erpnext/accounts/report/utils.py +++ b/erpnext/accounts/report/utils.py @@ -1,7 +1,12 @@ import frappe +from frappe.query_builder.custom import ConstantColumn from frappe.utils import flt, formatdate, get_datetime_str, get_table_name +from pypika import Order from erpnext import get_company_currency, get_default_company +from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import ( + get_dimension_with_children, +) from erpnext.accounts.doctype.fiscal_year.fiscal_year import get_from_and_to_date from erpnext.setup.utils import get_exchange_rate @@ -152,6 +157,35 @@ def get_invoiced_item_gross_margin( return result +def get_query_columns(report_columns): + if not report_columns: + return "" + + columns = [] + for column in report_columns: + fieldname = column["fieldname"] + + if doctype := column.get("_doctype"): + columns.append(f"`{get_table_name(doctype)}`.`{fieldname}`") + else: + columns.append(fieldname) + + return ", " + ", ".join(columns) + + +def get_values_for_columns(report_columns, report_row): + values = {} + + if not report_columns: + return values + + for column in report_columns: + fieldname = column["fieldname"] + values[fieldname] = report_row.get(fieldname) + + return values + + def get_party_details(party_type, party_list): party_details = {} party = frappe.qb.DocType(party_type) @@ -190,74 +224,105 @@ def get_taxes_query(invoice_list, doctype, parenttype): return query.where(taxes.charge_type.isin(["On Paid Amount", "Actual"])) -def get_journal_entries(filters, args): - return frappe.db.sql( - """ - select je.voucher_type as doctype, je.name, je.posting_date, - jea.account as {0}, jea.party as {1}, jea.party as {2}, - je.bill_no, je.bill_date, je.remark, je.total_amount as base_net_total, - je.total_amount as base_grand_total, je.mode_of_payment, jea.project {3} - from `tabJournal Entry` je left join `tabJournal Entry Account` jea on jea.parent=je.name - where je.voucher_type='Journal Entry' and jea.party='{4}' {5} - order by je.posting_date desc, je.name desc""".format( - args.account, - args.party, - args.party_name, - args.additional_query_columns, - filters.get(args.party), - args.conditions, - ), - filters, - as_dict=1, +def get_journal_entries(filters, accounting_dimensions, args): + je = frappe.qb.DocType("Journal Entry") + journal_account = frappe.qb.DocType("Journal Entry Account") + query = ( + frappe.qb.from_(je) + .inner_join(journal_account) + .on(je.name == journal_account.parent) + .select( + je.voucher_type.as_("doctype"), + je.name, + je.posting_date, + journal_account.account.as_(args.account), + journal_account.party.as_(args.party), + journal_account.party.as_(args.party_name), + je.bill_no, + je.bill_date, + je.remark.as_("remarks"), + je.total_amount.as_("base_net_total"), + je.total_amount.as_("base_grand_total"), + je.mode_of_payment, + journal_account.project, + ) + .where((je.voucher_type == "Journal Entry") & (journal_account.party == filters.get(args.party))) + .orderby(je.posting_date, je.name, order=Order.desc) ) + query = get_conditions(filters, query, [je], accounting_dimensions, payments=True) + journal_entries = query.run(as_dict=True, debug=True) + return journal_entries -def get_payment_entries(filters, args): - return frappe.db.sql( - """ - select 'Payment Entry' as doctype, name, posting_date, paid_to as {0}, - party as {1}, party_name as {2}, remarks, - paid_amount as base_net_total, paid_amount_after_tax as base_grand_total, - mode_of_payment, project, cost_center {3} - from `tabPayment Entry` - where party='{4}' {5} - order by posting_date desc, name desc""".format( - args.account, - args.party, - args.party_name, - args.additional_query_columns, - filters.get(args.party), - args.conditions, - ), - filters, - as_dict=1, +def get_payment_entries(filters, accounting_dimensions, args): + pe = frappe.qb.DocType("Payment Entry") + query = ( + frappe.qb.from_(pe) + .select( + ConstantColumn("Payment Entry").as_("doctype"), + pe.name, + pe.posting_date, + pe.paid_to.as_(args.account), + pe.party.as_(args.party), + pe.party_name.as_(args.party_name), + pe.remarks, + pe.paid_amount.as_("base_net_total"), + pe.paid_amount_after_tax.as_("base_grand_total"), + pe.mode_of_payment, + pe.project, + pe.cost_center, + ) + .where((pe.party == filters.get(args.party))) + .orderby(pe.posting_date, pe.name, order=Order.desc) ) + query = get_conditions(filters, query, [pe], accounting_dimensions, payments=True) + payment_entries = query.run(as_dict=True, debug=True) + return payment_entries -def get_query_columns(report_columns): - if not report_columns: - return "" +def get_conditions(filters, query, docs, accounting_dimensions, payments=False): + parent_doc = docs[0] + if not payments: + child_doc = docs[1] - columns = [] - for column in report_columns: - fieldname = column["fieldname"] + if parent_doc.get_table_name() == "tabSales Invoice": + if filters.get("owner"): + query = query.where(parent_doc.owner == filters.owner) + if filters.get("mode_of_payment"): + payment_doc = docs[2] + query = query.where(payment_doc.mode_of_payment == filters.mode_of_payment) + if not payments: + if filters.get("brand"): + query = query.where(child_doc.brand == filters.brand) + else: + if filters.get("mode_of_payment"): + query = query.where(parent_doc.mode_of_payment == filters.mode_of_payment) - if doctype := column.get("_doctype"): - columns.append(f"`{get_table_name(doctype)}`.`{fieldname}`") - else: - columns.append(fieldname) + if filters.get("company"): + query = query.where(parent_doc.company == filters.company) + if filters.get("from_date"): + query = query.where(parent_doc.posting_date >= filters.from_date) + if filters.get("to_date"): + query = query.where(parent_doc.posting_date <= filters.to_date) - return ", " + ", ".join(columns) + if payments: + if filters.get("cost_center"): + query = query.where(parent_doc.cost_center == filters.cost_center) + else: + if filters.get("cost_center"): + query = query.where(child_doc.cost_center == filters.cost_center) + if filters.get("warehouse"): + query = query.where(child_doc.warehouse == filters.warehouse) + if filters.get("item_group"): + query = query.where(child_doc.item_group == filters.item_group) - -def get_values_for_columns(report_columns, report_row): - values = {} - - if not report_columns: - return values - - for column in report_columns: - fieldname = column["fieldname"] - values[fieldname] = report_row.get(fieldname) - - return values + if accounting_dimensions: + for dimension in accounting_dimensions: + if filters.get(dimension.fieldname): + if frappe.get_cached_value("DocType", dimension.document_type, "is_tree"): + filters[dimension.fieldname] = get_dimension_with_children( + dimension.document_type, filters.get(dimension.fieldname) + ) + fieldname = dimension.fieldname + query = query.where(parent_doc.fieldname.isin(filters.fieldname)) + return query From f5027fdcaf6051441f0803263f92d701f2a004b2 Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Wed, 12 Jul 2023 16:42:58 +0530 Subject: [PATCH 10/26] refactor: move fn to fetch advance taxes to utils & use qb --- .../purchase_register/purchase_register.py | 18 ++---------- .../report/sales_register/sales_register.py | 20 ++++--------- erpnext/accounts/report/utils.py | 29 +++++++++++++++++-- 3 files changed, 34 insertions(+), 33 deletions(-) diff --git a/erpnext/accounts/report/purchase_register/purchase_register.py b/erpnext/accounts/report/purchase_register/purchase_register.py index 6e35c9dbe8..93dadc67fa 100644 --- a/erpnext/accounts/report/purchase_register/purchase_register.py +++ b/erpnext/accounts/report/purchase_register/purchase_register.py @@ -12,6 +12,7 @@ from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import ( get_accounting_dimensions, ) from erpnext.accounts.report.utils import ( + get_advance_taxes_and_charges, get_conditions, get_journal_entries, get_party_details, @@ -235,7 +236,7 @@ def get_invoices(filters, additional_query_columns): if filters.get("supplier"): query = query.where(pi.supplier == filters.supplier) query = get_conditions(filters, query, [pi, invoice_item], accounting_dimensions) - invoices = query.run(as_dict=True, debug=True) + invoices = query.run(as_dict=True) return invoices @@ -312,20 +313,7 @@ def get_invoice_tax_map( ) if include_payments: - advance_tax_details = frappe.db.sql( - """ - select parent, account_head, case add_deduct_tax when "Add" then sum(base_tax_amount) - else sum(base_tax_amount) * -1 end as tax_amount - from `tabAdvance Taxes and Charges` - where parent in (%s) and charge_type in ('On Paid Amount', 'Actual') - and base_tax_amount != 0 - group by parent, account_head, add_deduct_tax - """ - % ", ".join(["%s"] * len(invoice_list)), - tuple(inv.name for inv in invoice_list), - as_dict=1, - ) - tax_details += advance_tax_details + tax_details += get_advance_taxes_and_charges(invoice_list) invoice_tax_map = {} for d in tax_details: diff --git a/erpnext/accounts/report/sales_register/sales_register.py b/erpnext/accounts/report/sales_register/sales_register.py index 2460cd7ab6..1daf524704 100644 --- a/erpnext/accounts/report/sales_register/sales_register.py +++ b/erpnext/accounts/report/sales_register/sales_register.py @@ -13,6 +13,7 @@ from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import ( get_accounting_dimensions, ) from erpnext.accounts.report.utils import ( + get_advance_taxes_and_charges, get_conditions, get_journal_entries, get_party_details, @@ -42,6 +43,7 @@ def _execute(filters, additional_table_columns=None): invoice_list, additional_table_columns, include_payments ) + print("Accounts", tax_accounts) if not invoice_list: msgprint(_("No record found")) return columns, invoice_list @@ -120,6 +122,7 @@ def _execute(filters, additional_table_columns=None): or 2 ) tax_amount = flt(invoice_tax_map.get(inv.name, {}).get(tax_acc), tax_amount_precision) + print(tax_amount) total_tax += tax_amount row.update({frappe.scrub(tax_acc): tax_amount}) @@ -399,7 +402,7 @@ def get_invoices(filters, additional_query_columns): if filters.get("customer"): query = query.where(si.customer == filters.customer) query = get_conditions(filters, query, [si, invoice_item, invoice_payment], accounting_dimensions) - invoices = query.run(as_dict=True, debug=True) + invoices = query.run(as_dict=True) return invoices @@ -465,20 +468,7 @@ def get_invoice_tax_map(invoice_list, invoice_income_map, income_accounts, inclu ) if include_payments: - advance_tax_details = frappe.db.sql( - """ - select parent, account_head, case add_deduct_tax when "Add" then sum(base_tax_amount) - else sum(base_tax_amount) * -1 end as tax_amount - from `tabAdvance Taxes and Charges` - where parent in (%s) and charge_type in ('On Paid Amount', 'Actual') - and base_tax_amount != 0 - group by parent, account_head, add_deduct_tax - """ - % ", ".join(["%s"] * len(invoice_list)), - tuple(inv.name for inv in invoice_list), - as_dict=1, - ) - tax_details += advance_tax_details + tax_details += get_advance_taxes_and_charges(invoice_list) invoice_tax_map = {} for d in tax_details: diff --git a/erpnext/accounts/report/utils.py b/erpnext/accounts/report/utils.py index 6617f9ae25..8b58a46cdf 100644 --- a/erpnext/accounts/report/utils.py +++ b/erpnext/accounts/report/utils.py @@ -1,5 +1,6 @@ import frappe from frappe.query_builder.custom import ConstantColumn +from frappe.query_builder.functions import Sum from frappe.utils import flt, formatdate, get_datetime_str, get_table_name from pypika import Order @@ -220,7 +221,7 @@ def get_taxes_query(invoice_list, doctype, parenttype): if doctype == "Purchase Taxes and Charges": return query.where(taxes.category.isin(["Total", "Valuation and Total"])) elif doctype == "Sales Taxes and Charges": - return query.where(taxes.charge_type.isin(["Total", "Valuation and Total"])) + return query return query.where(taxes.charge_type.isin(["On Paid Amount", "Actual"])) @@ -250,7 +251,7 @@ def get_journal_entries(filters, accounting_dimensions, args): .orderby(je.posting_date, je.name, order=Order.desc) ) query = get_conditions(filters, query, [je], accounting_dimensions, payments=True) - journal_entries = query.run(as_dict=True, debug=True) + journal_entries = query.run(as_dict=True) return journal_entries @@ -276,7 +277,7 @@ def get_payment_entries(filters, accounting_dimensions, args): .orderby(pe.posting_date, pe.name, order=Order.desc) ) query = get_conditions(filters, query, [pe], accounting_dimensions, payments=True) - payment_entries = query.run(as_dict=True, debug=True) + payment_entries = query.run(as_dict=True) return payment_entries @@ -326,3 +327,25 @@ def get_conditions(filters, query, docs, accounting_dimensions, payments=False): fieldname = dimension.fieldname query = query.where(parent_doc.fieldname.isin(filters.fieldname)) return query + + +def get_advance_taxes_and_charges(invoice_list): + adv_taxes = frappe.qb.DocType("Advance Taxes and Charges") + return ( + frappe.qb.from_(adv_taxes) + .select( + adv_taxes.parent, + adv_taxes.account_head, + ( + frappe.qb.terms.Case() + .when(adv_taxes.add_deduct_tax == "Add", Sum(adv_taxes.base_tax_amount)) + .else_(Sum(adv_taxes.base_tax_amount) * -1) + ).as_("tax_amount"), + ) + .where( + (adv_taxes.parent.isin([inv.name for inv in invoice_list])) + & (adv_taxes.charge_type.isin(["On Paid Amount", "Actual"])) + & (adv_taxes.base_tax_amount != 0) + ) + .groupby(adv_taxes.parent, adv_taxes.account_head, adv_taxes.add_deduct_tax) + ).run(as_dict=True, debug=True) From bf08aa7529145053d3c80a3213a255d5e8b0f44a Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Wed, 12 Jul 2023 17:17:58 +0530 Subject: [PATCH 11/26] fix: filtering through accounting dimensions --- .../purchase_register/purchase_register.py | 13 ++++--- .../report/sales_register/sales_register.py | 13 ++++--- erpnext/accounts/report/utils.py | 39 +++++++++++-------- 3 files changed, 39 insertions(+), 26 deletions(-) diff --git a/erpnext/accounts/report/purchase_register/purchase_register.py b/erpnext/accounts/report/purchase_register/purchase_register.py index 93dadc67fa..8e733cc58a 100644 --- a/erpnext/accounts/report/purchase_register/purchase_register.py +++ b/erpnext/accounts/report/purchase_register/purchase_register.py @@ -12,6 +12,7 @@ from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import ( get_accounting_dimensions, ) from erpnext.accounts.report.utils import ( + filter_invoices_based_on_dimensions, get_advance_taxes_and_charges, get_conditions, get_journal_entries, @@ -38,6 +39,10 @@ def _execute(filters=None, additional_table_columns=None): frappe.throw(_("Please select a supplier for fetching payments.")) invoice_list += get_payments(filters, additional_table_columns) + accounting_dimensions = get_accounting_dimensions(as_list=False) + if len(invoice_list) > 0 and accounting_dimensions: + invoice_list = filter_invoices_based_on_dimensions(filters, accounting_dimensions, invoice_list) + columns, expense_accounts, tax_accounts, unrealized_profit_loss_accounts = get_columns( invoice_list, additional_table_columns, include_payments ) @@ -207,7 +212,6 @@ def get_columns(invoice_list, additional_table_columns, include_payments=False): def get_invoices(filters, additional_query_columns): - accounting_dimensions = get_accounting_dimensions(as_list=False) pi = frappe.qb.DocType("Purchase Invoice") invoice_item = frappe.qb.DocType("Purchase Invoice Item") query = ( @@ -235,7 +239,7 @@ def get_invoices(filters, additional_query_columns): ) if filters.get("supplier"): query = query.where(pi.supplier == filters.supplier) - query = get_conditions(filters, query, [pi, invoice_item], accounting_dimensions) + query = get_conditions(filters, query, [pi, invoice_item]) invoices = query.run(as_dict=True) return invoices @@ -250,9 +254,8 @@ def get_payments(filters, additional_query_columns): party_name="supplier_name", additional_query_columns="" if not additional_query_columns else additional_query_columns, ) - accounting_dimensions = get_accounting_dimensions(as_list=False) - payment_entries = get_payment_entries(filters, accounting_dimensions, args) - journal_entries = get_journal_entries(filters, accounting_dimensions, args) + payment_entries = get_payment_entries(filters, args) + journal_entries = get_journal_entries(filters, args) return payment_entries + journal_entries diff --git a/erpnext/accounts/report/sales_register/sales_register.py b/erpnext/accounts/report/sales_register/sales_register.py index 1daf524704..42fc5b34a7 100644 --- a/erpnext/accounts/report/sales_register/sales_register.py +++ b/erpnext/accounts/report/sales_register/sales_register.py @@ -13,6 +13,7 @@ from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import ( get_accounting_dimensions, ) from erpnext.accounts.report.utils import ( + filter_invoices_based_on_dimensions, get_advance_taxes_and_charges, get_conditions, get_journal_entries, @@ -39,6 +40,10 @@ def _execute(filters, additional_table_columns=None): frappe.throw(_("Please select a customer for fetching payments.")) invoice_list += get_payments(filters, additional_table_columns) + accounting_dimensions = get_accounting_dimensions(as_list=False) + if len(invoice_list) > 0 and accounting_dimensions: + invoice_list = filter_invoices_based_on_dimensions(filters, accounting_dimensions, invoice_list) + columns, income_accounts, tax_accounts, unrealized_profit_loss_accounts = get_columns( invoice_list, additional_table_columns, include_payments ) @@ -365,7 +370,6 @@ def get_columns(invoice_list, additional_table_columns, include_payments=False): def get_invoices(filters, additional_query_columns): - accounting_dimensions = get_accounting_dimensions(as_list=False) si = frappe.qb.DocType("Sales Invoice") invoice_item = frappe.qb.DocType("Sales Invoice Item") invoice_payment = frappe.qb.DocType("Sales Invoice Payment") @@ -401,7 +405,7 @@ def get_invoices(filters, additional_query_columns): ) if filters.get("customer"): query = query.where(si.customer == filters.customer) - query = get_conditions(filters, query, [si, invoice_item, invoice_payment], accounting_dimensions) + query = get_conditions(filters, query, [si, invoice_item, invoice_payment]) invoices = query.run(as_dict=True) return invoices @@ -416,9 +420,8 @@ def get_payments(filters, additional_query_columns): party_name="customer_name", additional_query_columns="" if not additional_query_columns else additional_query_columns, ) - accounting_dimensions = get_accounting_dimensions(as_list=False) - payment_entries = get_payment_entries(filters, accounting_dimensions, args) - journal_entries = get_journal_entries(filters, accounting_dimensions, args) + payment_entries = get_payment_entries(filters, args) + journal_entries = get_journal_entries(filters, args) return payment_entries + journal_entries diff --git a/erpnext/accounts/report/utils.py b/erpnext/accounts/report/utils.py index 8b58a46cdf..32ca9fa7ed 100644 --- a/erpnext/accounts/report/utils.py +++ b/erpnext/accounts/report/utils.py @@ -225,7 +225,7 @@ def get_taxes_query(invoice_list, doctype, parenttype): return query.where(taxes.charge_type.isin(["On Paid Amount", "Actual"])) -def get_journal_entries(filters, accounting_dimensions, args): +def get_journal_entries(filters, args): je = frappe.qb.DocType("Journal Entry") journal_account = frappe.qb.DocType("Journal Entry Account") query = ( @@ -250,12 +250,12 @@ def get_journal_entries(filters, accounting_dimensions, args): .where((je.voucher_type == "Journal Entry") & (journal_account.party == filters.get(args.party))) .orderby(je.posting_date, je.name, order=Order.desc) ) - query = get_conditions(filters, query, [je], accounting_dimensions, payments=True) + query = get_conditions(filters, query, [je], payments=True) journal_entries = query.run(as_dict=True) return journal_entries -def get_payment_entries(filters, accounting_dimensions, args): +def get_payment_entries(filters, args): pe = frappe.qb.DocType("Payment Entry") query = ( frappe.qb.from_(pe) @@ -276,12 +276,12 @@ def get_payment_entries(filters, accounting_dimensions, args): .where((pe.party == filters.get(args.party))) .orderby(pe.posting_date, pe.name, order=Order.desc) ) - query = get_conditions(filters, query, [pe], accounting_dimensions, payments=True) + query = get_conditions(filters, query, [pe], payments=True) payment_entries = query.run(as_dict=True) return payment_entries -def get_conditions(filters, query, docs, accounting_dimensions, payments=False): +def get_conditions(filters, query, docs, payments=False): parent_doc = docs[0] if not payments: child_doc = docs[1] @@ -316,16 +316,6 @@ def get_conditions(filters, query, docs, accounting_dimensions, payments=False): query = query.where(child_doc.warehouse == filters.warehouse) if filters.get("item_group"): query = query.where(child_doc.item_group == filters.item_group) - - if accounting_dimensions: - for dimension in accounting_dimensions: - if filters.get(dimension.fieldname): - if frappe.get_cached_value("DocType", dimension.document_type, "is_tree"): - filters[dimension.fieldname] = get_dimension_with_children( - dimension.document_type, filters.get(dimension.fieldname) - ) - fieldname = dimension.fieldname - query = query.where(parent_doc.fieldname.isin(filters.fieldname)) return query @@ -348,4 +338,21 @@ def get_advance_taxes_and_charges(invoice_list): & (adv_taxes.base_tax_amount != 0) ) .groupby(adv_taxes.parent, adv_taxes.account_head, adv_taxes.add_deduct_tax) - ).run(as_dict=True, debug=True) + ).run(as_dict=True) + + +def filter_invoices_based_on_dimensions(filters, accounting_dimensions, invoices): + invoices_with_acc_dimensions = [] + for inv in invoices: + for dimension in accounting_dimensions: + if filters.get(dimension.fieldname): + if frappe.get_cached_value("DocType", dimension.document_type, "is_tree"): + filters[dimension.fieldname] = get_dimension_with_children( + dimension.document_type, filters.get(dimension.fieldname) + ) + fieldname = dimension.fieldname + if inv.fieldname != filters[fieldname]: + break + else: + invoices_with_acc_dimensions.append(inv) + return invoices_with_acc_dimensions From c973e3c746739fc5f69eb663bff9dfbe6290fbd3 Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Wed, 12 Jul 2023 17:40:27 +0530 Subject: [PATCH 12/26] chore: remove debugging print statements --- erpnext/accounts/report/sales_register/sales_register.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/erpnext/accounts/report/sales_register/sales_register.py b/erpnext/accounts/report/sales_register/sales_register.py index 42fc5b34a7..fd82555d91 100644 --- a/erpnext/accounts/report/sales_register/sales_register.py +++ b/erpnext/accounts/report/sales_register/sales_register.py @@ -48,7 +48,6 @@ def _execute(filters, additional_table_columns=None): invoice_list, additional_table_columns, include_payments ) - print("Accounts", tax_accounts) if not invoice_list: msgprint(_("No record found")) return columns, invoice_list @@ -127,7 +126,6 @@ def _execute(filters, additional_table_columns=None): or 2 ) tax_amount = flt(invoice_tax_map.get(inv.name, {}).get(tax_acc), tax_amount_precision) - print(tax_amount) total_tax += tax_amount row.update({frappe.scrub(tax_acc): tax_amount}) From 944244ceffdb7bde9ca3bddb0901d0b07a0a2ea5 Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Fri, 14 Jul 2023 10:50:12 +0530 Subject: [PATCH 13/26] fix: modify rows and columns for ledger view --- .../purchase_register/purchase_register.js | 2 +- .../purchase_register/purchase_register.py | 168 ++++++---- .../report/sales_register/sales_register.js | 2 +- .../report/sales_register/sales_register.py | 291 ++++++++++-------- erpnext/accounts/report/utils.py | 24 +- 5 files changed, 306 insertions(+), 181 deletions(-) diff --git a/erpnext/accounts/report/purchase_register/purchase_register.js b/erpnext/accounts/report/purchase_register/purchase_register.js index ddf84d05ce..57cb703bae 100644 --- a/erpnext/accounts/report/purchase_register/purchase_register.js +++ b/erpnext/accounts/report/purchase_register/purchase_register.js @@ -55,7 +55,7 @@ frappe.query_reports["Purchase Register"] = { }, { "fieldname": "include_payments", - "label": __("Include Payments"), + "label": __("Show Ledger View"), "fieldtype": "Check", "default": 0 } diff --git a/erpnext/accounts/report/purchase_register/purchase_register.py b/erpnext/accounts/report/purchase_register/purchase_register.py index 8e733cc58a..46bfa43ac3 100644 --- a/erpnext/accounts/report/purchase_register/purchase_register.py +++ b/erpnext/accounts/report/purchase_register/purchase_register.py @@ -5,17 +5,19 @@ import frappe from frappe import _, msgprint from frappe.query_builder.custom import ConstantColumn -from frappe.utils import flt +from frappe.utils import flt, getdate from pypika import Order from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import ( get_accounting_dimensions, ) +from erpnext.accounts.party import get_party_account from erpnext.accounts.report.utils import ( filter_invoices_based_on_dimensions, get_advance_taxes_and_charges, get_conditions, get_journal_entries, + get_opening_row, get_party_details, get_payment_entries, get_query_columns, @@ -33,10 +35,10 @@ def _execute(filters=None, additional_table_columns=None): filters = {} include_payments = filters.get("include_payments") + if filters.get("include_payments") and not filters.get("supplier"): + frappe.throw(_("Please select a supplier for fetching payments.")) invoice_list = get_invoices(filters, get_query_columns(additional_table_columns)) if filters.get("include_payments"): - if not filters.get("supplier"): - frappe.throw(_("Please select a supplier for fetching payments.")) invoice_list += get_payments(filters, additional_table_columns) accounting_dimensions = get_accounting_dimensions(as_list=False) @@ -62,6 +64,21 @@ def _execute(filters=None, additional_table_columns=None): company_currency = frappe.get_cached_value("Company", filters.company, "default_currency") + res = [] + if include_payments: + opening_row = get_opening_row( + "Supplier", filters.supplier, getdate(filters.from_date), filters.company + )[0] + print(opening_row) + res.append( + { + "payable_account": opening_row.account, + "debit": flt(opening_row.debit), + "credit": flt(opening_row.credit), + "balance": flt(opening_row.balance), + } + ) + running_balance = flt(opening_row.balance) data = [] for inv in invoice_list: # invoice details @@ -69,25 +86,23 @@ def _execute(filters=None, additional_table_columns=None): purchase_receipt = list(set(invoice_po_pr_map.get(inv.name, {}).get("purchase_receipt", []))) project = list(set(invoice_po_pr_map.get(inv.name, {}).get("project", []))) - row = [ - inv.doctype, - inv.name, - inv.posting_date, - inv.supplier, - inv.supplier_name, - *get_values_for_columns(additional_table_columns, inv).values(), - supplier_details.get(inv.supplier).get("supplier_group"), - supplier_details.get(inv.supplier).get("tax_id"), - inv.credit_to, - inv.mode_of_payment, - ", ".join(project) if inv.doctype == "Purchase Invoice" else inv.project, - inv.bill_no, - inv.bill_date, - inv.remarks, - ", ".join(purchase_order), - ", ".join(purchase_receipt), - company_currency, - ] + row = { + "voucher_type": inv.doctype, + "voucher_no": inv.name, + "posting_date": inv.posting_date, + "supplier_id": inv.supplier, + "supplier_name": inv.supplier_name, + **get_values_for_columns(additional_table_columns, inv), + "supplier_group": supplier_details.get(inv.supplier).get("supplier_group"), + "tax_id": supplier_details.get(inv.supplier).get("tax_id"), + "payable_account": inv.credit_to, + "mode_of_payment": inv.mode_of_payment, + "project": ", ".join(project) if inv.doctype == "Purchase Invoice" else inv.project, + "remarks": inv.remarks, + "purchase_order": ", ".join(purchase_order), + "purchase_receipt": ", ".join(purchase_receipt), + "currency": company_currency, + } # map expense values base_net_total = 0 @@ -97,14 +112,16 @@ def _execute(filters=None, additional_table_columns=None): else: expense_amount = flt(invoice_expense_map.get(inv.name, {}).get(expense_acc)) base_net_total += expense_amount - row.append(expense_amount) + row.update({frappe.scrub(expense_acc): expense_amount}) # Add amount in unrealized account for account in unrealized_profit_loss_accounts: - row.append(flt(internal_invoice_map.get((inv.name, account)))) + row.update( + {frappe.scrub(account + "_unrealized"): flt(internal_invoice_map.get((inv.name, account)))} + ) # net total - row.append(base_net_total or inv.base_net_total) + row.update({"net_total": base_net_total or inv.base_net_total}) # tax account total_tax = 0 @@ -112,13 +129,29 @@ def _execute(filters=None, additional_table_columns=None): if tax_acc not in expense_accounts: tax_amount = flt(invoice_tax_map.get(inv.name, {}).get(tax_acc)) total_tax += tax_amount - row.append(tax_amount) + row.update({frappe.scrub(tax_acc): tax_amount}) # total tax, grand total, rounded total & outstanding amount - row += [total_tax, inv.base_grand_total, flt(inv.base_grand_total, 0), inv.outstanding_amount] + row.update( + { + "total_tax": total_tax, + "garnd_total": inv.base_grand_total, + "rounded_total": inv.base_rounded_total, + "outstanding_amount": inv.outstanding_amount, + } + ) + + if inv.doctype == "Purchase Invoice": + row.update({"debit": inv.base_grand_total, "credit": 0.0}) + else: + row.update({"debit": 0.0, "credit": inv.base_grand_total}) + if include_payments: + running_balance += row["debit"] - row["credit"] + row.update({"balance": running_balance}) data.append(row) - return columns, sorted(data, key=lambda x: x[2]) + res += sorted(data, key=lambda x: x["posting_date"]) + return columns, res, None, None, None, include_payments def get_columns(invoice_list, additional_table_columns, include_payments=False): @@ -134,20 +167,48 @@ def get_columns(invoice_list, additional_table_columns, include_payments=False): if additional_table_columns: columns += additional_table_columns - columns += [ - _("Supplier Group") + ":Link/Supplier Group:120", - _("Tax Id") + "::50", - _("Payable Account") + ":Link/Account:120", - _("Mode of Payment") + ":Link/Mode of Payment:80", - _("Project") + ":Link/Project:80", - _("Bill No") + "::120", - _("Bill Date") + ":Date:80", - _("Remarks") + "::150", - _("Purchase Order") + ":Link/Purchase Order:100", - _("Purchase Receipt") + ":Link/Purchase Receipt:100", - {"fieldname": "currency", "label": _("Currency"), "fieldtype": "Data", "width": 80}, - ] + if not include_payments: + columns += [ + _("Supplier Group") + ":Link/Supplier Group:120", + _("Tax Id") + "::50", + _("Payable Account") + ":Link/Account:120", + _("Mode of Payment") + ":Link/Mode of Payment:80", + _("Project") + ":Link/Project:80", + _("Bill No") + "::120", + _("Bill Date") + ":Date:80", + _("Purchase Order") + ":Link/Purchase Order:100", + _("Purchase Receipt") + ":Link/Purchase Receipt:100", + {"fieldname": "currency", "label": _("Currency"), "fieldtype": "Data", "width": 80}, + ] + else: + columns += [ + _("Payable Account") + ":Link/Account:120", + _("Debit") + ":Currency/currency:120", + _("Credit") + ":Currency/currency:120", + _("Balance") + ":Currency/currency:120", + ] + account_columns, accounts = get_account_columns(invoice_list, include_payments) + + columns = ( + columns + + account_columns[0] + + account_columns[1] + + [_("Net Total") + ":Currency/currency:120"] + + account_columns[2] + + [_("Total Tax") + ":Currency/currency:120"] + ) + + if not include_payments: + columns += [ + _("Rounded Total") + ":Currency/currency:120", + _("Outstanding Amount") + ":Currency/currency:120", + ] + columns += [_("Remarks") + "::120"] + return columns, accounts[0], accounts[2], accounts[1] + + +def get_account_columns(invoice_list, include_payments): expense_accounts = [] tax_accounts = [] unrealized_profit_loss_accounts = [] @@ -194,21 +255,10 @@ def get_columns(invoice_list, additional_table_columns, include_payments=False): if account not in expense_accounts ] - columns = ( - columns - + expense_columns - + unrealized_profit_loss_account_columns - + [_("Net Total") + ":Currency/currency:120"] - + tax_columns - + [ - _("Total Tax") + ":Currency/currency:120", - _("Grand Total") + ":Currency/currency:120", - _("Rounded Total") + ":Currency/currency:120", - _("Outstanding Amount") + ":Currency/currency:120", - ] - ) + columns = [expense_columns, unrealized_profit_loss_account_columns, tax_columns] + accounts = [expense_accounts, unrealized_profit_loss_accounts, tax_accounts] - return columns, expense_accounts, tax_accounts, unrealized_profit_loss_accounts + return columns, accounts def get_invoices(filters, additional_query_columns): @@ -240,6 +290,11 @@ def get_invoices(filters, additional_query_columns): if filters.get("supplier"): query = query.where(pi.supplier == filters.supplier) query = get_conditions(filters, query, [pi, invoice_item]) + if filters.get("include_payments"): + party_account = get_party_account( + "Supplier", filters.get("supplier"), filters.get("company"), include_advance=True + ) + query = query.where(pi.credit_to.isin(party_account)) invoices = query.run(as_dict=True) return invoices @@ -252,6 +307,9 @@ def get_payments(filters, additional_query_columns): account="credit_to", party="supplier", party_name="supplier_name", + party_account=get_party_account( + "Supplier", filters.supplier, filters.company, include_advance=True + ), additional_query_columns="" if not additional_query_columns else additional_query_columns, ) payment_entries = get_payment_entries(filters, args) diff --git a/erpnext/accounts/report/sales_register/sales_register.js b/erpnext/accounts/report/sales_register/sales_register.js index 3c879cac7a..1a41172a97 100644 --- a/erpnext/accounts/report/sales_register/sales_register.js +++ b/erpnext/accounts/report/sales_register/sales_register.js @@ -67,7 +67,7 @@ frappe.query_reports["Sales Register"] = { }, { "fieldname": "include_payments", - "label": __("Include Payments"), + "label": __("Show Ledger View"), "fieldtype": "Check", "default": 0 } diff --git a/erpnext/accounts/report/sales_register/sales_register.py b/erpnext/accounts/report/sales_register/sales_register.py index fd82555d91..6112219bdd 100644 --- a/erpnext/accounts/report/sales_register/sales_register.py +++ b/erpnext/accounts/report/sales_register/sales_register.py @@ -6,17 +6,19 @@ import frappe from frappe import _, msgprint from frappe.model.meta import get_field_precision from frappe.query_builder.custom import ConstantColumn -from frappe.utils import flt +from frappe.utils import flt, getdate from pypika import Order from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import ( get_accounting_dimensions, ) +from erpnext.accounts.party import get_party_account from erpnext.accounts.report.utils import ( filter_invoices_based_on_dimensions, get_advance_taxes_and_charges, get_conditions, get_journal_entries, + get_opening_row, get_party_details, get_payment_entries, get_query_columns, @@ -34,10 +36,10 @@ def _execute(filters, additional_table_columns=None): filters = frappe._dict({}) include_payments = filters.get("include_payments") + if filters.get("include_payments") and not filters.get("customer"): + frappe.throw(_("Please select a customer for fetching payments.")) invoice_list = get_invoices(filters, get_query_columns(additional_table_columns)) if filters.get("include_payments"): - if not filters.get("customer"): - frappe.throw(_("Please select a customer for fetching payments.")) invoice_list += get_payments(filters, additional_table_columns) accounting_dimensions = get_accounting_dimensions(as_list=False) @@ -65,6 +67,20 @@ def _execute(filters, additional_table_columns=None): customers = list(set(d.customer for d in invoice_list)) customer_details = get_party_details("Customer", customers) + res = [] + if include_payments: + opening_row = get_opening_row( + "Customer", filters.customer, getdate(filters.from_date), filters.company + )[0] + res.append( + { + "receivable_account": opening_row, + "debit": flt(opening_row.debit), + "credit": flt(opening_row.credit), + "balance": flt(opening_row.balance), + } + ) + running_balance = flt(opening_row.balance) data = [] for inv in invoice_list: # invoice details @@ -75,7 +91,7 @@ def _execute(filters, additional_table_columns=None): row = { "voucher_type": inv.doctype, - "invoice": inv.name, + "voucher_no": inv.name, "posting_date": inv.posting_date, "customer": inv.customer, "customer_name": inv.customer_name, @@ -140,9 +156,17 @@ def _execute(filters, additional_table_columns=None): } ) + if inv.doctype == "Sales Invoice": + row.update({"debit": inv.base_grand_total, "credit": 0.0}) + else: + row.update({"debit": 0.0, "credit": inv.base_grand_total}) + if include_payments: + running_balance += row["debit"] - row["credit"] + row.update({"balance": running_balance}) data.append(row) - return columns, sorted(data, key=lambda x: x["posting_date"]) + res += sorted(data, key=lambda x: x["posting_date"]) + return columns, res, None, None, None, include_payments def get_columns(invoice_list, additional_table_columns, include_payments=False): @@ -155,7 +179,7 @@ def get_columns(invoice_list, additional_table_columns, include_payments=False): }, { "label": _("Voucher"), - "fieldname": "invoice", + "fieldname": "voucher_no", "fieldtype": "Dynamic Link", "options": "voucher_type", "width": 120, @@ -174,80 +198,147 @@ def get_columns(invoice_list, additional_table_columns, include_payments=False): if additional_table_columns: columns += additional_table_columns - columns += [ + if not include_payments: + columns += [ + { + "label": _("Customer Group"), + "fieldname": "customer_group", + "fieldtype": "Link", + "options": "Customer Group", + "width": 120, + }, + { + "label": _("Territory"), + "fieldname": "territory", + "fieldtype": "Link", + "options": "Territory", + "width": 80, + }, + {"label": _("Tax Id"), "fieldname": "tax_id", "fieldtype": "Data", "width": 80}, + { + "label": _("Receivable Account"), + "fieldname": "receivable_account", + "fieldtype": "Link", + "options": "Account", + "width": 100, + }, + { + "label": _("Mode Of Payment"), + "fieldname": "mode_of_payment", + "fieldtype": "Data", + "width": 120, + }, + { + "label": _("Project"), + "fieldname": "project", + "fieldtype": "Link", + "options": "Project", + "width": 80, + }, + {"label": _("Owner"), "fieldname": "owner", "fieldtype": "Data", "width": 100}, + { + "label": _("Sales Order"), + "fieldname": "sales_order", + "fieldtype": "Link", + "options": "Sales Order", + "width": 100, + }, + { + "label": _("Delivery Note"), + "fieldname": "delivery_note", + "fieldtype": "Link", + "options": "Delivery Note", + "width": 100, + }, + { + "label": _("Cost Center"), + "fieldname": "cost_center", + "fieldtype": "Link", + "options": "Cost Center", + "width": 100, + }, + { + "label": _("Warehouse"), + "fieldname": "warehouse", + "fieldtype": "Link", + "options": "Warehouse", + "width": 100, + }, + {"fieldname": "currency", "label": _("Currency"), "fieldtype": "Data", "width": 80}, + ] + else: + columns += [ + _("Receivable Account") + ":Link/Account:120", + _("Debit") + ":Currency/currency:120", + _("Credit") + ":Currency/currency:120", + _("Balance") + ":Currency/currency:120", + ] + + account_columns, accounts = get_account_columns(invoice_list, include_payments) + + net_total_column = [ { - "label": _("Customer Group"), - "fieldname": "customer_group", - "fieldtype": "Link", - "options": "Customer Group", + "label": _("Net Total"), + "fieldname": "net_total", + "fieldtype": "Currency", + "options": "currency", "width": 120, - }, - { - "label": _("Territory"), - "fieldname": "territory", - "fieldtype": "Link", - "options": "Territory", - "width": 80, - }, - {"label": _("Tax Id"), "fieldname": "tax_id", "fieldtype": "Data", "width": 80}, - { - "label": _("Receivable Account"), - "fieldname": "receivable_account", - "fieldtype": "Link", - "options": "Account", - "width": 100, - }, - { - "label": _("Mode Of Payment"), - "fieldname": "mode_of_payment", - "fieldtype": "Data", - "width": 120, - }, - { - "label": _("Project"), - "fieldname": "project", - "fieldtype": "Link", - "options": "Project", - "width": 80, - }, - {"label": _("Owner"), "fieldname": "owner", "fieldtype": "Data", "width": 100}, - {"label": _("Remarks"), "fieldname": "remarks", "fieldtype": "Data", "width": 150}, - { - "label": _("Sales Order"), - "fieldname": "sales_order", - "fieldtype": "Link", - "options": "Sales Order", - "width": 100, - }, - { - "label": _("Delivery Note"), - "fieldname": "delivery_note", - "fieldtype": "Link", - "options": "Delivery Note", - "width": 100, - }, - { - "label": _("Cost Center"), - "fieldname": "cost_center", - "fieldtype": "Link", - "options": "Cost Center", - "width": 100, - }, - { - "label": _("Warehouse"), - "fieldname": "warehouse", - "fieldtype": "Link", - "options": "Warehouse", - "width": 100, - }, - {"fieldname": "currency", "label": _("Currency"), "fieldtype": "Data", "width": 80}, + } ] + total_columns = [ + { + "label": _("Tax Total"), + "fieldname": "tax_total", + "fieldtype": "Currency", + "options": "currency", + "width": 120, + } + ] + if not include_payments: + total_columns += [ + { + "label": _("Grand Total"), + "fieldname": "grand_total", + "fieldtype": "Currency", + "options": "currency", + "width": 120, + }, + { + "label": _("Rounded Total"), + "fieldname": "rounded_total", + "fieldtype": "Currency", + "options": "currency", + "width": 120, + }, + { + "label": _("Outstanding Amount"), + "fieldname": "outstanding_amount", + "fieldtype": "Currency", + "options": "currency", + "width": 120, + }, + ] + + columns = ( + columns + + account_columns[0] + + account_columns[2] + + net_total_column + + account_columns[1] + + total_columns + ) + columns += [{"label": _("Remarks"), "fieldname": "remarks", "fieldtype": "Data", "width": 150}] + return columns, accounts[0], accounts[1], accounts[2] + + +def get_account_columns(invoice_list, include_payments): income_accounts = [] tax_accounts = [] + unrealized_profit_loss_accounts = [] + income_columns = [] tax_columns = [] - unrealized_profit_loss_accounts = [] unrealized_profit_loss_account_columns = [] if invoice_list: @@ -314,57 +405,10 @@ def get_columns(invoice_list, additional_table_columns, include_payments=False): } ) - net_total_column = [ - { - "label": _("Net Total"), - "fieldname": "net_total", - "fieldtype": "Currency", - "options": "currency", - "width": 120, - } - ] + columns = [income_columns, unrealized_profit_loss_account_columns, tax_columns] + accounts = [income_accounts, unrealized_profit_loss_accounts, tax_accounts] - total_columns = [ - { - "label": _("Tax Total"), - "fieldname": "tax_total", - "fieldtype": "Currency", - "options": "currency", - "width": 120, - }, - { - "label": _("Grand Total"), - "fieldname": "grand_total", - "fieldtype": "Currency", - "options": "currency", - "width": 120, - }, - { - "label": _("Rounded Total"), - "fieldname": "rounded_total", - "fieldtype": "Currency", - "options": "currency", - "width": 120, - }, - { - "label": _("Outstanding Amount"), - "fieldname": "outstanding_amount", - "fieldtype": "Currency", - "options": "currency", - "width": 120, - }, - ] - - columns = ( - columns - + income_columns - + unrealized_profit_loss_account_columns - + net_total_column - + tax_columns - + total_columns - ) - - return columns, income_accounts, tax_accounts, unrealized_profit_loss_accounts + return columns, accounts def get_invoices(filters, additional_query_columns): @@ -416,6 +460,9 @@ def get_payments(filters, additional_query_columns): account="debit_to", party="customer", party_name="customer_name", + party_account=get_party_account( + "Customer", filters.customer, filters.company, include_advance=True + ), additional_query_columns="" if not additional_query_columns else additional_query_columns, ) payment_entries = get_payment_entries(filters, args) diff --git a/erpnext/accounts/report/utils.py b/erpnext/accounts/report/utils.py index 32ca9fa7ed..6c7338e724 100644 --- a/erpnext/accounts/report/utils.py +++ b/erpnext/accounts/report/utils.py @@ -9,6 +9,7 @@ from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import ( get_dimension_with_children, ) from erpnext.accounts.doctype.fiscal_year.fiscal_year import get_from_and_to_date +from erpnext.accounts.party import get_party_account from erpnext.setup.utils import get_exchange_rate __exchange_rates = {} @@ -247,7 +248,11 @@ def get_journal_entries(filters, args): je.mode_of_payment, journal_account.project, ) - .where((je.voucher_type == "Journal Entry") & (journal_account.party == filters.get(args.party))) + .where( + (je.voucher_type == "Journal Entry") + & (journal_account.party == filters.get(args.party)) + & (journal_account.account.isin(args.party_account)) + ) .orderby(je.posting_date, je.name, order=Order.desc) ) query = get_conditions(filters, query, [je], payments=True) @@ -273,7 +278,7 @@ def get_payment_entries(filters, args): pe.project, pe.cost_center, ) - .where((pe.party == filters.get(args.party))) + .where((pe.party == filters.get(args.party)) & (pe.paid_to.isin(args.party_account))) .orderby(pe.posting_date, pe.name, order=Order.desc) ) query = get_conditions(filters, query, [pe], payments=True) @@ -356,3 +361,18 @@ def filter_invoices_based_on_dimensions(filters, accounting_dimensions, invoices else: invoices_with_acc_dimensions.append(inv) return invoices_with_acc_dimensions + + +def get_opening_row(party_type, party, from_date, company): + party_account = get_party_account(party_type, party, company, include_advance=True) + gle = frappe.qb.DocType("GL Entry") + return ( + frappe.qb.from_(gle) + .select( + ConstantColumn("Opening").as_("account"), + Sum(gle.debit).as_("debit"), + Sum(gle.credit).as_("credit"), + (Sum(gle.debit) - Sum(gle.credit)).as_("balance"), + ) + .where((gle.account.isin(party_account)) & (gle.posting_date < from_date)) + ).run(as_dict=True) From c084fe6b3fa061e55b1b3bf1e6849f94364530ec Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Fri, 14 Jul 2023 11:05:50 +0530 Subject: [PATCH 14/26] refactor: filter accounting dimensions using qb --- .../purchase_register/purchase_register.py | 8 -------- .../report/sales_register/sales_register.py | 8 -------- erpnext/accounts/report/utils.py | 17 +++++++++-------- 3 files changed, 9 insertions(+), 24 deletions(-) diff --git a/erpnext/accounts/report/purchase_register/purchase_register.py b/erpnext/accounts/report/purchase_register/purchase_register.py index 46bfa43ac3..1f25a05155 100644 --- a/erpnext/accounts/report/purchase_register/purchase_register.py +++ b/erpnext/accounts/report/purchase_register/purchase_register.py @@ -8,12 +8,8 @@ from frappe.query_builder.custom import ConstantColumn from frappe.utils import flt, getdate from pypika import Order -from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import ( - get_accounting_dimensions, -) from erpnext.accounts.party import get_party_account from erpnext.accounts.report.utils import ( - filter_invoices_based_on_dimensions, get_advance_taxes_and_charges, get_conditions, get_journal_entries, @@ -41,10 +37,6 @@ def _execute(filters=None, additional_table_columns=None): if filters.get("include_payments"): invoice_list += get_payments(filters, additional_table_columns) - accounting_dimensions = get_accounting_dimensions(as_list=False) - if len(invoice_list) > 0 and accounting_dimensions: - invoice_list = filter_invoices_based_on_dimensions(filters, accounting_dimensions, invoice_list) - columns, expense_accounts, tax_accounts, unrealized_profit_loss_accounts = get_columns( invoice_list, additional_table_columns, include_payments ) diff --git a/erpnext/accounts/report/sales_register/sales_register.py b/erpnext/accounts/report/sales_register/sales_register.py index 6112219bdd..94a7bee4fd 100644 --- a/erpnext/accounts/report/sales_register/sales_register.py +++ b/erpnext/accounts/report/sales_register/sales_register.py @@ -9,12 +9,8 @@ from frappe.query_builder.custom import ConstantColumn from frappe.utils import flt, getdate from pypika import Order -from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import ( - get_accounting_dimensions, -) from erpnext.accounts.party import get_party_account from erpnext.accounts.report.utils import ( - filter_invoices_based_on_dimensions, get_advance_taxes_and_charges, get_conditions, get_journal_entries, @@ -42,10 +38,6 @@ def _execute(filters, additional_table_columns=None): if filters.get("include_payments"): invoice_list += get_payments(filters, additional_table_columns) - accounting_dimensions = get_accounting_dimensions(as_list=False) - if len(invoice_list) > 0 and accounting_dimensions: - invoice_list = filter_invoices_based_on_dimensions(filters, accounting_dimensions, invoice_list) - columns, income_accounts, tax_accounts, unrealized_profit_loss_accounts = get_columns( invoice_list, additional_table_columns, include_payments ) diff --git a/erpnext/accounts/report/utils.py b/erpnext/accounts/report/utils.py index 6c7338e724..462ef21c82 100644 --- a/erpnext/accounts/report/utils.py +++ b/erpnext/accounts/report/utils.py @@ -6,6 +6,7 @@ from pypika import Order from erpnext import get_company_currency, get_default_company from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import ( + get_accounting_dimensions, get_dimension_with_children, ) from erpnext.accounts.doctype.fiscal_year.fiscal_year import get_from_and_to_date @@ -321,6 +322,9 @@ def get_conditions(filters, query, docs, payments=False): query = query.where(child_doc.warehouse == filters.warehouse) if filters.get("item_group"): query = query.where(child_doc.item_group == filters.item_group) + + if parent_doc.get_table_name() != "tabJournal Entry": + query = filter_invoices_based_on_dimensions(filters, query, parent_doc) return query @@ -346,9 +350,9 @@ def get_advance_taxes_and_charges(invoice_list): ).run(as_dict=True) -def filter_invoices_based_on_dimensions(filters, accounting_dimensions, invoices): - invoices_with_acc_dimensions = [] - for inv in invoices: +def filter_invoices_based_on_dimensions(filters, query, parent_doc): + accounting_dimensions = get_accounting_dimensions(as_list=False) + if accounting_dimensions: for dimension in accounting_dimensions: if filters.get(dimension.fieldname): if frappe.get_cached_value("DocType", dimension.document_type, "is_tree"): @@ -356,11 +360,8 @@ def filter_invoices_based_on_dimensions(filters, accounting_dimensions, invoices dimension.document_type, filters.get(dimension.fieldname) ) fieldname = dimension.fieldname - if inv.fieldname != filters[fieldname]: - break - else: - invoices_with_acc_dimensions.append(inv) - return invoices_with_acc_dimensions + query = query.where(parent_doc[fieldname] == filters.fieldname) + return query def get_opening_row(party_type, party, from_date, company): From 0d89bfacdbff88d5072297c7578a310650df40db Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Fri, 14 Jul 2023 13:03:22 +0530 Subject: [PATCH 15/26] fix: show additional table cols from india compliance api call --- .../report/purchase_register/purchase_register.py | 13 ++++++------- .../report/sales_register/sales_register.py | 13 ++++++------- erpnext/accounts/report/utils.py | 2 +- 3 files changed, 13 insertions(+), 15 deletions(-) diff --git a/erpnext/accounts/report/purchase_register/purchase_register.py b/erpnext/accounts/report/purchase_register/purchase_register.py index 1f25a05155..00f6527fa0 100644 --- a/erpnext/accounts/report/purchase_register/purchase_register.py +++ b/erpnext/accounts/report/purchase_register/purchase_register.py @@ -35,7 +35,7 @@ def _execute(filters=None, additional_table_columns=None): frappe.throw(_("Please select a supplier for fetching payments.")) invoice_list = get_invoices(filters, get_query_columns(additional_table_columns)) if filters.get("include_payments"): - invoice_list += get_payments(filters, additional_table_columns) + invoice_list += get_payments(filters) columns, expense_accounts, tax_accounts, unrealized_profit_loss_accounts = get_columns( invoice_list, additional_table_columns, include_payments @@ -156,7 +156,7 @@ def get_columns(invoice_list, additional_table_columns, include_payments=False): _("Supplier Name") + "::120", ] - if additional_table_columns: + if additional_table_columns and not include_payments: columns += additional_table_columns if not include_payments: @@ -279,6 +279,9 @@ def get_invoices(filters, additional_query_columns): .where((pi.docstatus == 1)) .orderby(pi.posting_date, pi.name, order=Order.desc) ) + if additional_query_columns: + for col in additional_query_columns: + query = query.select(col) if filters.get("supplier"): query = query.where(pi.supplier == filters.supplier) query = get_conditions(filters, query, [pi, invoice_item]) @@ -291,10 +294,7 @@ def get_invoices(filters, additional_query_columns): return invoices -def get_payments(filters, additional_query_columns): - if additional_query_columns: - additional_query_columns = ", " + ", ".join(additional_query_columns) - +def get_payments(filters): args = frappe._dict( account="credit_to", party="supplier", @@ -302,7 +302,6 @@ def get_payments(filters, additional_query_columns): party_account=get_party_account( "Supplier", filters.supplier, filters.company, include_advance=True ), - additional_query_columns="" if not additional_query_columns else additional_query_columns, ) payment_entries = get_payment_entries(filters, args) journal_entries = get_journal_entries(filters, args) diff --git a/erpnext/accounts/report/sales_register/sales_register.py b/erpnext/accounts/report/sales_register/sales_register.py index 94a7bee4fd..32f25bd81a 100644 --- a/erpnext/accounts/report/sales_register/sales_register.py +++ b/erpnext/accounts/report/sales_register/sales_register.py @@ -36,7 +36,7 @@ def _execute(filters, additional_table_columns=None): frappe.throw(_("Please select a customer for fetching payments.")) invoice_list = get_invoices(filters, get_query_columns(additional_table_columns)) if filters.get("include_payments"): - invoice_list += get_payments(filters, additional_table_columns) + invoice_list += get_payments(filters) columns, income_accounts, tax_accounts, unrealized_profit_loss_accounts = get_columns( invoice_list, additional_table_columns, include_payments @@ -187,7 +187,7 @@ def get_columns(invoice_list, additional_table_columns, include_payments=False): {"label": _("Customer Name"), "fieldname": "customer_name", "fieldtype": "Data", "width": 120}, ] - if additional_table_columns: + if additional_table_columns and not include_payments: columns += additional_table_columns if not include_payments: @@ -437,6 +437,9 @@ def get_invoices(filters, additional_query_columns): .where((si.docstatus == 1)) .orderby(si.posting_date, si.name, order=Order.desc) ) + if additional_query_columns: + for col in additional_query_columns: + query = query.select(col) if filters.get("customer"): query = query.where(si.customer == filters.customer) query = get_conditions(filters, query, [si, invoice_item, invoice_payment]) @@ -444,10 +447,7 @@ def get_invoices(filters, additional_query_columns): return invoices -def get_payments(filters, additional_query_columns): - if additional_query_columns: - additional_query_columns = ", " + ", ".join(additional_query_columns) - +def get_payments(filters): args = frappe._dict( account="debit_to", party="customer", @@ -455,7 +455,6 @@ def get_payments(filters, additional_query_columns): party_account=get_party_account( "Customer", filters.customer, filters.company, include_advance=True ), - additional_query_columns="" if not additional_query_columns else additional_query_columns, ) payment_entries = get_payment_entries(filters, args) journal_entries = get_journal_entries(filters, args) diff --git a/erpnext/accounts/report/utils.py b/erpnext/accounts/report/utils.py index 462ef21c82..91a6e7fd9f 100644 --- a/erpnext/accounts/report/utils.py +++ b/erpnext/accounts/report/utils.py @@ -173,7 +173,7 @@ def get_query_columns(report_columns): else: columns.append(fieldname) - return ", " + ", ".join(columns) + return columns def get_values_for_columns(report_columns, report_row): From b8a83f57b725fd387e1622eeef45de2b32bd2e50 Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Fri, 14 Jul 2023 16:25:58 +0530 Subject: [PATCH 16/26] chore: fix typo --- erpnext/accounts/report/purchase_register/purchase_register.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/erpnext/accounts/report/purchase_register/purchase_register.py b/erpnext/accounts/report/purchase_register/purchase_register.py index 00f6527fa0..616dca42bb 100644 --- a/erpnext/accounts/report/purchase_register/purchase_register.py +++ b/erpnext/accounts/report/purchase_register/purchase_register.py @@ -127,7 +127,7 @@ def _execute(filters=None, additional_table_columns=None): row.update( { "total_tax": total_tax, - "garnd_total": inv.base_grand_total, + "grand_total": inv.base_grand_total, "rounded_total": inv.base_rounded_total, "outstanding_amount": inv.outstanding_amount, } @@ -193,6 +193,7 @@ def get_columns(invoice_list, additional_table_columns, include_payments=False): if not include_payments: columns += [ + _("Grand Total") + ":Currency/currency:120", _("Rounded Total") + ":Currency/currency:120", _("Outstanding Amount") + ":Currency/currency:120", ] From a93d7633d47083087748d6189b5a44e302619403 Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Fri, 14 Jul 2023 17:16:39 +0530 Subject: [PATCH 17/26] test: purchase register and ledger view --- .../purchase_register/purchase_register.py | 1 - .../test_purchase_register.py | 128 ++++++++++++++++++ 2 files changed, 128 insertions(+), 1 deletion(-) create mode 100644 erpnext/accounts/report/purchase_register/test_purchase_register.py diff --git a/erpnext/accounts/report/purchase_register/purchase_register.py b/erpnext/accounts/report/purchase_register/purchase_register.py index 616dca42bb..a6d0ea04e4 100644 --- a/erpnext/accounts/report/purchase_register/purchase_register.py +++ b/erpnext/accounts/report/purchase_register/purchase_register.py @@ -61,7 +61,6 @@ def _execute(filters=None, additional_table_columns=None): opening_row = get_opening_row( "Supplier", filters.supplier, getdate(filters.from_date), filters.company )[0] - print(opening_row) res.append( { "payable_account": opening_row.account, diff --git a/erpnext/accounts/report/purchase_register/test_purchase_register.py b/erpnext/accounts/report/purchase_register/test_purchase_register.py new file mode 100644 index 0000000000..6903662e68 --- /dev/null +++ b/erpnext/accounts/report/purchase_register/test_purchase_register.py @@ -0,0 +1,128 @@ +# Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and Contributors +# MIT License. See license.txt + +import frappe +from frappe.tests.utils import FrappeTestCase +from frappe.utils import add_months, getdate, today + +from erpnext.accounts.report.purchase_register.purchase_register import execute + + +class TestPurchaseRegister(FrappeTestCase): + def test_purchase_register(self): + frappe.db.sql("delete from `tabPurchase Invoice` where company='_Test Company 6'") + frappe.db.sql("delete from `tabGL Entry` where company='_Test Company 6'") + + filters = frappe._dict( + company="_Test Company 6", from_date=add_months(today(), -1), to_date=today() + ) + + pi = make_purchase_invoice() + + report_results = execute(filters) + first_row = frappe._dict(report_results[1][0]) + self.assertEqual(first_row.voucher_type, "Purchase Invoice") + self.assertEqual(first_row.voucher_no, pi.name) + self.assertEqual(first_row.payable_account, "Creditors - _TC6") + self.assertEqual(first_row.net_total, 1000) + self.assertEqual(first_row.total_tax, 100) + self.assertEqual(first_row.grand_total, 1100) + + def test_purchase_register_ledger_view(self): + frappe.db.sql("delete from `tabPurchase Invoice` where company='_Test Company 6'") + frappe.db.sql("delete from `tabGL Entry` where company='_Test Company 6'") + + filters = frappe._dict( + company="_Test Company 6", + from_date=add_months(today(), -1), + to_date=today(), + include_payments=True, + supplier="_Test Supplier", + ) + + pi = make_purchase_invoice() + pe = make_payment_entry() + + report_results = execute(filters) + first_row = frappe._dict(report_results[1][2]) + self.assertEqual(first_row.voucher_type, "Payment Entry") + self.assertEqual(first_row.voucher_no, pe.name) + self.assertEqual(first_row.payable_account, "Creditors - _TC6") + self.assertEqual(first_row.debit, 0) + self.assertEqual(first_row.credit, 600) + self.assertEqual(first_row.balance, 500) + + +def make_purchase_invoice(): + from erpnext.accounts.doctype.account.test_account import create_account + from erpnext.accounts.doctype.cost_center.test_cost_center import create_cost_center + from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse + + gst_acc = create_account( + account_name="GST", + account_type="Tax", + parent_account="Duties and Taxes - _TC6", + company="_Test Company 6", + account_currency="INR", + ) + create_warehouse(warehouse_name="_Test Warehouse - _TC6", company="_Test Company 6") + create_cost_center(cost_center_name="_Test Cost Center", company="_Test Company 6") + pi = create_purchase_invoice_with_taxes() + pi.submit() + return pi + + +def create_purchase_invoice_with_taxes(): + return frappe.get_doc( + { + "doctype": "Purchase Invoice", + "posting_date": today(), + "supplier": "_Test Supplier", + "company": "_Test Company 6", + "cost_center": "_Test Cost Center - _TC6", + "taxes_and_charges": "", + "currency": "INR", + "credit_to": "Creditors - _TC6", + "items": [ + { + "doctype": "Purchase Invoice Item", + "cost_center": "_Test Cost Center - _TC6", + "item_code": "_Test Item", + "qty": 1, + "rate": 1000, + "expense_account": "Stock Received But Not Billed - _TC6", + } + ], + "taxes": [ + { + "account_head": "GST - _TC6", + "cost_center": "_Test Cost Center - _TC6", + "add_deduct_tax": "Add", + "category": "Valuation and Total", + "charge_type": "Actual", + "description": "Shipping Charges", + "doctype": "Purchase Taxes and Charges", + "parentfield": "taxes", + "rate": 100, + "tax_amount": 100.0, + } + ], + } + ) + + +def make_payment_entry(): + frappe.set_user("Administrator") + from erpnext.accounts.doctype.payment_entry.test_payment_entry import create_payment_entry + + return create_payment_entry( + company="_Test Company 6", + party_type="Supplier", + party="_Test Supplier", + payment_type="Pay", + paid_from="Cash - _TC6", + paid_to="Creditors - _TC6", + paid_amount=600, + save=1, + submit=1, + ) From 2f7b112736bf28e376b5b5c7d58c20d225e4be43 Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Wed, 19 Jul 2023 12:36:44 +0530 Subject: [PATCH 18/26] fix: filter by party in opening row calculation --- erpnext/accounts/report/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/accounts/report/utils.py b/erpnext/accounts/report/utils.py index 91a6e7fd9f..5e915869fb 100644 --- a/erpnext/accounts/report/utils.py +++ b/erpnext/accounts/report/utils.py @@ -375,5 +375,5 @@ def get_opening_row(party_type, party, from_date, company): Sum(gle.credit).as_("credit"), (Sum(gle.debit) - Sum(gle.credit)).as_("balance"), ) - .where((gle.account.isin(party_account)) & (gle.posting_date < from_date)) + .where((gle.account.isin(party_account)) & (gle.party == party) & (gle.posting_date < from_date)) ).run(as_dict=True) From 33f8f7d7b37ef2b0a251980af952437cf5bcfce1 Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Fri, 21 Jul 2023 10:57:55 +0530 Subject: [PATCH 19/26] fix: exclude cancelled gl entries for opening balance --- erpnext/accounts/report/utils.py | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/erpnext/accounts/report/utils.py b/erpnext/accounts/report/utils.py index 5e915869fb..ed85ae709e 100644 --- a/erpnext/accounts/report/utils.py +++ b/erpnext/accounts/report/utils.py @@ -256,7 +256,7 @@ def get_journal_entries(filters, args): ) .orderby(je.posting_date, je.name, order=Order.desc) ) - query = get_conditions(filters, query, [je], payments=True) + query = get_conditions(filters, query, doctype="Journal Entry", payments=True) journal_entries = query.run(as_dict=True) return journal_entries @@ -282,21 +282,21 @@ def get_payment_entries(filters, args): .where((pe.party == filters.get(args.party)) & (pe.paid_to.isin(args.party_account))) .orderby(pe.posting_date, pe.name, order=Order.desc) ) - query = get_conditions(filters, query, [pe], payments=True) + query = get_conditions(filters, query, doctype="Payment Entry", payments=True) payment_entries = query.run(as_dict=True) return payment_entries -def get_conditions(filters, query, docs, payments=False): - parent_doc = docs[0] - if not payments: - child_doc = docs[1] +def get_conditions(filters, query, doctype, child_doctype=None, payments=False): + parent_doc = frappe.qb.DocType(doctype) + if child_doctype: + child_doc = frappe.qb.DocType(child_doctype) if parent_doc.get_table_name() == "tabSales Invoice": if filters.get("owner"): query = query.where(parent_doc.owner == filters.owner) if filters.get("mode_of_payment"): - payment_doc = docs[2] + payment_doc = frappe.qb.DocType("Sales Invoice Payment") query = query.where(payment_doc.mode_of_payment == filters.mode_of_payment) if not payments: if filters.get("brand"): @@ -375,5 +375,10 @@ def get_opening_row(party_type, party, from_date, company): Sum(gle.credit).as_("credit"), (Sum(gle.debit) - Sum(gle.credit)).as_("balance"), ) - .where((gle.account.isin(party_account)) & (gle.party == party) & (gle.posting_date < from_date)) + .where( + (gle.account.isin(party_account)) + & (gle.party == party) + & (gle.posting_date < from_date) + & (gle.docstatus == 1) + ) ).run(as_dict=True) From 1c033ce6355c16784bbb162c8f46a0e0910dbdb3 Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Fri, 21 Jul 2023 11:00:19 +0530 Subject: [PATCH 20/26] chore: change column format for report --- .../purchase_register/purchase_register.py | 189 ++++++++++++++---- .../report/sales_register/sales_register.py | 18 +- 2 files changed, 168 insertions(+), 39 deletions(-) diff --git a/erpnext/accounts/report/purchase_register/purchase_register.py b/erpnext/accounts/report/purchase_register/purchase_register.py index a6d0ea04e4..720b5ea883 100644 --- a/erpnext/accounts/report/purchase_register/purchase_register.py +++ b/erpnext/accounts/report/purchase_register/purchase_register.py @@ -148,11 +148,27 @@ def _execute(filters=None, additional_table_columns=None): def get_columns(invoice_list, additional_table_columns, include_payments=False): """return columns based on filters""" columns = [ - _("Voucher Type") + ":Data:120", - _("Voucher No") + ":Dynamic Link/voucher_type:120", - _("Posting Date") + ":Date:80", - _("Supplier Id") + "::120", - _("Supplier Name") + "::120", + { + "label": _("Voucher Type"), + "fieldname": "voucher_type", + "width": 120, + }, + { + "label": _("Voucher"), + "fieldname": "voucher_no", + "fieldtype": "Dynamic Link", + "options": "voucher_type", + "width": 120, + }, + {"label": _("Posting Date"), "fieldname": "posting_date", "fieldtype": "Date", "width": 80}, + { + "label": _("Supplier"), + "fieldname": "supplier_id", + "fieldtype": "Link", + "options": "Supplier", + "width": 120, + }, + {"label": _("Supplier Name"), "fieldname": "supplier_name", "fieldtype": "Data", "width": 120}, ] if additional_table_columns and not include_payments: @@ -160,23 +176,64 @@ def get_columns(invoice_list, additional_table_columns, include_payments=False): if not include_payments: columns += [ - _("Supplier Group") + ":Link/Supplier Group:120", - _("Tax Id") + "::50", - _("Payable Account") + ":Link/Account:120", - _("Mode of Payment") + ":Link/Mode of Payment:80", - _("Project") + ":Link/Project:80", - _("Bill No") + "::120", - _("Bill Date") + ":Date:80", - _("Purchase Order") + ":Link/Purchase Order:100", - _("Purchase Receipt") + ":Link/Purchase Receipt:100", + { + "label": _("Supplier Group"), + "fieldname": "supplier_group", + "fieldtype": "Link", + "options": "Supplier Group", + "width": 120, + }, + {"label": _("Tax Id"), "fieldname": "tax_id", "fieldtype": "Data", "width": 80}, + { + "label": _("Payable Account"), + "fieldname": "payable_account", + "fieldtype": "Link", + "options": "Account", + "width": 100, + }, + { + "label": _("Mode Of Payment"), + "fieldname": "mode_of_payment", + "fieldtype": "Data", + "width": 120, + }, + { + "label": _("Project"), + "fieldname": "project", + "fieldtype": "Link", + "options": "Project", + "width": 80, + }, + {"label": _("Bill No"), "fieldname": "bill_no", "fieldtype": "Data", "width": 120}, + {"label": _("Bill Date"), "fieldname": "bill_date", "fieldtype": "Date", "width": 80}, + { + "label": _("Purchase Order"), + "fieldname": "purchase_order", + "fieldtype": "Link", + "options": "Purchase Order", + "width": 100, + }, + { + "label": _("Purchase Receipt"), + "fieldname": "purchase_receipt", + "fieldtype": "Link", + "options": "Purchase Receipt", + "width": 100, + }, {"fieldname": "currency", "label": _("Currency"), "fieldtype": "Data", "width": 80}, ] else: columns += [ - _("Payable Account") + ":Link/Account:120", - _("Debit") + ":Currency/currency:120", - _("Credit") + ":Currency/currency:120", - _("Balance") + ":Currency/currency:120", + { + "fieldname": "payable_account", + "label": _("Payable Account"), + "fieldtype": "Link", + "options": "Account", + "width": 120, + }, + {"fieldname": "debit", "label": _("Debit"), "fieldtype": "Currency", "width": 120}, + {"fieldname": "credit", "label": _("Credit"), "fieldtype": "Currency", "width": 120}, + {"fieldname": "balance", "label": _("Balance"), "fieldtype": "Currency", "width": 120}, ] account_columns, accounts = get_account_columns(invoice_list, include_payments) @@ -185,18 +242,52 @@ def get_columns(invoice_list, additional_table_columns, include_payments=False): columns + account_columns[0] + account_columns[1] - + [_("Net Total") + ":Currency/currency:120"] + + [ + { + "label": _("Net Total"), + "fieldname": "net_total", + "fieldtype": "Currency", + "options": "currency", + "width": 120, + } + ] + account_columns[2] - + [_("Total Tax") + ":Currency/currency:120"] + + [ + { + "label": _("Total Tax"), + "fieldname": "total_tax", + "fieldtype": "Currency", + "options": "currency", + "width": 120, + } + ] ) if not include_payments: columns += [ - _("Grand Total") + ":Currency/currency:120", - _("Rounded Total") + ":Currency/currency:120", - _("Outstanding Amount") + ":Currency/currency:120", + { + "label": _("Grand Total"), + "fieldname": "grand_total", + "fieldtype": "Currency", + "options": "currency", + "width": 120, + }, + { + "label": _("Rounded Total"), + "fieldname": "rounded_total", + "fieldtype": "Currency", + "options": "currency", + "width": 120, + }, + { + "label": _("Outstanding Amount"), + "fieldname": "outstanding_amount", + "fieldtype": "Currency", + "options": "currency", + "width": 120, + }, ] - columns += [_("Remarks") + "::120"] + columns += [{"label": _("Remarks"), "fieldname": "remarks", "fieldtype": "Data", "width": 120}] return columns, accounts[0], accounts[2], accounts[1] @@ -205,6 +296,10 @@ def get_account_columns(invoice_list, include_payments): tax_accounts = [] unrealized_profit_loss_accounts = [] + expense_columns = [] + tax_columns = [] + unrealized_profit_loss_account_columns = [] + if invoice_list: expense_accounts = frappe.db.sql_list( """select distinct expense_account @@ -237,15 +332,39 @@ def get_account_columns(invoice_list, include_payments): tuple(inv.name for inv in invoice_list), ) - expense_columns = [(account + ":Currency/currency:120") for account in expense_accounts] - unrealized_profit_loss_account_columns = [ - (account + ":Currency/currency:120") for account in unrealized_profit_loss_accounts - ] - tax_columns = [ - (account + ":Currency/currency:120") - for account in tax_accounts - if account not in expense_accounts - ] + for account in expense_accounts: + expense_columns.append( + { + "label": account, + "fieldname": frappe.scrub(account), + "fieldtype": "Currency", + "options": "currency", + "width": 120, + } + ) + + for account in tax_accounts: + if account not in expense_accounts: + tax_columns.append( + { + "label": account, + "fieldname": frappe.scrub(account), + "fieldtype": "Currency", + "options": "currency", + "width": 120, + } + ) + + for account in unrealized_profit_loss_accounts: + unrealized_profit_loss_account_columns.append( + { + "label": account, + "fieldname": frappe.scrub(account), + "fieldtype": "Currency", + "options": "currency", + "width": 120, + } + ) columns = [expense_columns, unrealized_profit_loss_account_columns, tax_columns] accounts = [expense_accounts, unrealized_profit_loss_accounts, tax_accounts] @@ -284,7 +403,9 @@ def get_invoices(filters, additional_query_columns): query = query.select(col) if filters.get("supplier"): query = query.where(pi.supplier == filters.supplier) - query = get_conditions(filters, query, [pi, invoice_item]) + query = get_conditions( + filters, query, doctype="Purchase Invoice", child_doctype="Purchase Invoice Item" + ) if filters.get("include_payments"): party_account = get_party_account( "Supplier", filters.get("supplier"), filters.get("company"), include_advance=True diff --git a/erpnext/accounts/report/sales_register/sales_register.py b/erpnext/accounts/report/sales_register/sales_register.py index 32f25bd81a..dca84a5dc5 100644 --- a/erpnext/accounts/report/sales_register/sales_register.py +++ b/erpnext/accounts/report/sales_register/sales_register.py @@ -260,10 +260,16 @@ def get_columns(invoice_list, additional_table_columns, include_payments=False): ] else: columns += [ - _("Receivable Account") + ":Link/Account:120", - _("Debit") + ":Currency/currency:120", - _("Credit") + ":Currency/currency:120", - _("Balance") + ":Currency/currency:120", + { + "fieldname": "receivable_account", + "label": _("Receivable Account"), + "fieldtype": "Link", + "options": "Account", + "width": 120, + }, + {"fieldname": "debit", "label": _("Debit"), "fieldtype": "Currency", "width": 120}, + {"fieldname": "credit", "label": _("Credit"), "fieldtype": "Currency", "width": 120}, + {"fieldname": "balance", "label": _("Balance"), "fieldtype": "Currency", "width": 120}, ] account_columns, accounts = get_account_columns(invoice_list, include_payments) @@ -442,7 +448,9 @@ def get_invoices(filters, additional_query_columns): query = query.select(col) if filters.get("customer"): query = query.where(si.customer == filters.customer) - query = get_conditions(filters, query, [si, invoice_item, invoice_payment]) + query = get_conditions( + filters, query, doctype="Sales Invoice", child_doctype="Sales Invoice Item" + ) invoices = query.run(as_dict=True) return invoices From 59a2a04fccf2daa4a04806ba996f1cdd8008d81c Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Fri, 21 Jul 2023 13:22:01 +0530 Subject: [PATCH 21/26] fix: check gl entry status using is_cancelled --- erpnext/accounts/report/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/accounts/report/utils.py b/erpnext/accounts/report/utils.py index ed85ae709e..68a4281bf1 100644 --- a/erpnext/accounts/report/utils.py +++ b/erpnext/accounts/report/utils.py @@ -379,6 +379,6 @@ def get_opening_row(party_type, party, from_date, company): (gle.account.isin(party_account)) & (gle.party == party) & (gle.posting_date < from_date) - & (gle.docstatus == 1) + & (gle.is_cancelled == 0) ) ).run(as_dict=True) From db49d53aafb6e50aa70f736d6cc3f8df965e02b1 Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Mon, 24 Jul 2023 17:42:13 +0530 Subject: [PATCH 22/26] fix: running balance after sorting --- .../report/purchase_register/purchase_register.py | 12 ++++++++---- .../report/sales_register/sales_register.py | 14 +++++++++----- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/erpnext/accounts/report/purchase_register/purchase_register.py b/erpnext/accounts/report/purchase_register/purchase_register.py index 720b5ea883..819da78291 100644 --- a/erpnext/accounts/report/purchase_register/purchase_register.py +++ b/erpnext/accounts/report/purchase_register/purchase_register.py @@ -69,7 +69,7 @@ def _execute(filters=None, additional_table_columns=None): "balance": flt(opening_row.balance), } ) - running_balance = flt(opening_row.balance) + data = [] for inv in invoice_list: # invoice details @@ -136,12 +136,16 @@ def _execute(filters=None, additional_table_columns=None): row.update({"debit": inv.base_grand_total, "credit": 0.0}) else: row.update({"debit": 0.0, "credit": inv.base_grand_total}) - if include_payments: - running_balance += row["debit"] - row["credit"] - row.update({"balance": running_balance}) data.append(row) res += sorted(data, key=lambda x: x["posting_date"]) + + if include_payments: + running_balance = flt(opening_row.balance) + for row in range(1, len(res)): + running_balance += res[row]["debit"] - res[row]["credit"] + res[row].update({"balance": running_balance}) + return columns, res, None, None, None, include_payments diff --git a/erpnext/accounts/report/sales_register/sales_register.py b/erpnext/accounts/report/sales_register/sales_register.py index dca84a5dc5..b84f2597b6 100644 --- a/erpnext/accounts/report/sales_register/sales_register.py +++ b/erpnext/accounts/report/sales_register/sales_register.py @@ -66,13 +66,13 @@ def _execute(filters, additional_table_columns=None): )[0] res.append( { - "receivable_account": opening_row, + "receivable_account": opening_row.account, "debit": flt(opening_row.debit), "credit": flt(opening_row.credit), "balance": flt(opening_row.balance), } ) - running_balance = flt(opening_row.balance) + data = [] for inv in invoice_list: # invoice details @@ -152,12 +152,16 @@ def _execute(filters, additional_table_columns=None): row.update({"debit": inv.base_grand_total, "credit": 0.0}) else: row.update({"debit": 0.0, "credit": inv.base_grand_total}) - if include_payments: - running_balance += row["debit"] - row["credit"] - row.update({"balance": running_balance}) data.append(row) res += sorted(data, key=lambda x: x["posting_date"]) + + if include_payments: + running_balance = flt(opening_row.balance) + for row in range(1, len(res)): + running_balance += res[row]["debit"] - res[row]["credit"] + res[row].update({"balance": running_balance}) + return columns, res, None, None, None, include_payments From e6d66fe5b0c3088147289494ff1356b291c2cd27 Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Tue, 25 Jul 2023 12:14:37 +0530 Subject: [PATCH 23/26] fix: gst itemised registers for india compliance api call --- .../item_wise_purchase_register.py | 4 ++-- .../item_wise_sales_register/item_wise_sales_register.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py b/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py index 050e6bc5d2..6bcce7bc99 100644 --- a/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py +++ b/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py @@ -309,7 +309,7 @@ def get_conditions(filters): def get_items(filters, additional_query_columns): conditions = get_conditions(filters) - + additional_query_columns = ",".join(additional_query_columns) return frappe.db.sql( """ select @@ -324,7 +324,7 @@ def get_items(filters, additional_query_columns): `tabPurchase Invoice Item`.`purchase_receipt`, `tabPurchase Invoice Item`.`po_detail`, `tabPurchase Invoice Item`.`expense_account`, `tabPurchase Invoice Item`.`stock_qty`, `tabPurchase Invoice Item`.`stock_uom`, `tabPurchase Invoice Item`.`base_net_amount`, - `tabPurchase Invoice`.`supplier_name`, `tabPurchase Invoice`.`mode_of_payment` {0} + `tabPurchase Invoice`.`supplier_name`, `tabPurchase Invoice`.`mode_of_payment`, {0} from `tabPurchase Invoice`, `tabPurchase Invoice Item`, `tabItem` where `tabPurchase Invoice`.name = `tabPurchase Invoice Item`.`parent` and `tabItem`.name = `tabPurchase Invoice Item`.`item_code` and diff --git a/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py b/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py index 4d24dd9076..e6b5640f45 100644 --- a/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py +++ b/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py @@ -381,7 +381,7 @@ def get_group_by_conditions(filters, doctype): def get_items(filters, additional_query_columns, additional_conditions=None): conditions = get_conditions(filters, additional_conditions) - + additional_query_columns = ",".join(additional_query_columns) return frappe.db.sql( """ select @@ -401,7 +401,7 @@ def get_items(filters, additional_query_columns, additional_conditions=None): `tabSales Invoice Item`.stock_qty, `tabSales Invoice Item`.stock_uom, `tabSales Invoice Item`.base_net_rate, `tabSales Invoice Item`.base_net_amount, `tabSales Invoice`.customer_name, `tabSales Invoice`.customer_group, `tabSales Invoice Item`.so_detail, - `tabSales Invoice`.update_stock, `tabSales Invoice Item`.uom, `tabSales Invoice Item`.qty {0} + `tabSales Invoice`.update_stock, `tabSales Invoice Item`.uom, `tabSales Invoice Item`.qty, {0} from `tabSales Invoice`, `tabSales Invoice Item`, `tabItem` where `tabSales Invoice`.name = `tabSales Invoice Item`.parent and `tabItem`.name = `tabSales Invoice Item`.`item_code` and From 95c6f4d40d81b4f14b7c14986d1b0c709b16dd54 Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Tue, 25 Jul 2023 14:32:24 +0530 Subject: [PATCH 24/26] fix: additional query cols for gst itemised registers --- .../item_wise_purchase_register.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py b/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py index 6bcce7bc99..cf5294ed07 100644 --- a/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py +++ b/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py @@ -309,7 +309,8 @@ def get_conditions(filters): def get_items(filters, additional_query_columns): conditions = get_conditions(filters) - additional_query_columns = ",".join(additional_query_columns) + if additional_query_columns: + additional_query_columns = "," + ",".join(additional_query_columns) return frappe.db.sql( """ select @@ -324,7 +325,7 @@ def get_items(filters, additional_query_columns): `tabPurchase Invoice Item`.`purchase_receipt`, `tabPurchase Invoice Item`.`po_detail`, `tabPurchase Invoice Item`.`expense_account`, `tabPurchase Invoice Item`.`stock_qty`, `tabPurchase Invoice Item`.`stock_uom`, `tabPurchase Invoice Item`.`base_net_amount`, - `tabPurchase Invoice`.`supplier_name`, `tabPurchase Invoice`.`mode_of_payment`, {0} + `tabPurchase Invoice`.`supplier_name`, `tabPurchase Invoice`.`mode_of_payment` {0} from `tabPurchase Invoice`, `tabPurchase Invoice Item`, `tabItem` where `tabPurchase Invoice`.name = `tabPurchase Invoice Item`.`parent` and `tabItem`.name = `tabPurchase Invoice Item`.`item_code` and @@ -334,6 +335,7 @@ def get_items(filters, additional_query_columns): ), filters, as_dict=1, + debug=True, ) From 341709aa0a4bb28b8c1cb4b8f54ea42d02b382d1 Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Tue, 25 Jul 2023 15:57:17 +0530 Subject: [PATCH 25/26] fix: additional query cols for sales register --- .../item_wise_purchase_register.py | 1 - .../item_wise_sales_register/item_wise_sales_register.py | 5 +++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py b/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py index cf5294ed07..8b929bf472 100644 --- a/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py +++ b/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py @@ -335,7 +335,6 @@ def get_items(filters, additional_query_columns): ), filters, as_dict=1, - debug=True, ) diff --git a/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py b/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py index e6b5640f45..1e7ac33c32 100644 --- a/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py +++ b/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py @@ -381,7 +381,8 @@ def get_group_by_conditions(filters, doctype): def get_items(filters, additional_query_columns, additional_conditions=None): conditions = get_conditions(filters, additional_conditions) - additional_query_columns = ",".join(additional_query_columns) + if additional_query_columns: + additional_query_columns = "," + ",".join(additional_query_columns) return frappe.db.sql( """ select @@ -401,7 +402,7 @@ def get_items(filters, additional_query_columns, additional_conditions=None): `tabSales Invoice Item`.stock_qty, `tabSales Invoice Item`.stock_uom, `tabSales Invoice Item`.base_net_rate, `tabSales Invoice Item`.base_net_amount, `tabSales Invoice`.customer_name, `tabSales Invoice`.customer_group, `tabSales Invoice Item`.so_detail, - `tabSales Invoice`.update_stock, `tabSales Invoice Item`.uom, `tabSales Invoice Item`.qty, {0} + `tabSales Invoice`.update_stock, `tabSales Invoice Item`.uom, `tabSales Invoice Item`.qty {0} from `tabSales Invoice`, `tabSales Invoice Item`, `tabItem` where `tabSales Invoice`.name = `tabSales Invoice Item`.parent and `tabItem`.name = `tabSales Invoice Item`.`item_code` and From b1818137e7f4cdc145e2d84a8247af27c93c975a Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Thu, 27 Jul 2023 10:08:26 +0530 Subject: [PATCH 26/26] fix: PE in sales register --- .../accounts/report/purchase_register/purchase_register.py | 1 + erpnext/accounts/report/sales_register/sales_register.py | 1 + erpnext/accounts/report/utils.py | 6 ++++-- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/report/purchase_register/purchase_register.py b/erpnext/accounts/report/purchase_register/purchase_register.py index 819da78291..c7b7e2f7c1 100644 --- a/erpnext/accounts/report/purchase_register/purchase_register.py +++ b/erpnext/accounts/report/purchase_register/purchase_register.py @@ -422,6 +422,7 @@ def get_invoices(filters, additional_query_columns): def get_payments(filters): args = frappe._dict( account="credit_to", + account_fieldname="paid_to", party="supplier", party_name="supplier_name", party_account=get_party_account( diff --git a/erpnext/accounts/report/sales_register/sales_register.py b/erpnext/accounts/report/sales_register/sales_register.py index b84f2597b6..c2d2944408 100644 --- a/erpnext/accounts/report/sales_register/sales_register.py +++ b/erpnext/accounts/report/sales_register/sales_register.py @@ -462,6 +462,7 @@ def get_invoices(filters, additional_query_columns): def get_payments(filters): args = frappe._dict( account="debit_to", + account_fieldname="paid_from", party="customer", party_name="customer_name", party_account=get_party_account( diff --git a/erpnext/accounts/report/utils.py b/erpnext/accounts/report/utils.py index 68a4281bf1..0753fff834 100644 --- a/erpnext/accounts/report/utils.py +++ b/erpnext/accounts/report/utils.py @@ -269,7 +269,7 @@ def get_payment_entries(filters, args): ConstantColumn("Payment Entry").as_("doctype"), pe.name, pe.posting_date, - pe.paid_to.as_(args.account), + pe[args.account_fieldname].as_(args.account), pe.party.as_(args.party), pe.party_name.as_(args.party_name), pe.remarks, @@ -279,7 +279,9 @@ def get_payment_entries(filters, args): pe.project, pe.cost_center, ) - .where((pe.party == filters.get(args.party)) & (pe.paid_to.isin(args.party_account))) + .where( + (pe.party == filters.get(args.party)) & (pe[args.account_fieldname].isin(args.party_account)) + ) .orderby(pe.posting_date, pe.name, order=Order.desc) ) query = get_conditions(filters, query, doctype="Payment Entry", payments=True)