mirror of
https://github.com/frappe/erpnext.git
synced 2026-05-18 20:49:19 +00:00
Merge pull request #55014 from frappe/mergify/bp/version-15-hotfix/pr-55001
fix: remove sql procedure method from AR report (backport #55001)
This commit is contained in:
@@ -30,16 +30,6 @@ frappe.ui.form.on("Accounts Settings", {
|
|||||||
add_taxes_from_item_tax_template(frm) {
|
add_taxes_from_item_tax_template(frm) {
|
||||||
toggle_tax_settings(frm, "add_taxes_from_item_tax_template");
|
toggle_tax_settings(frm, "add_taxes_from_item_tax_template");
|
||||||
},
|
},
|
||||||
|
|
||||||
drop_ar_procedures: function (frm) {
|
|
||||||
frm.call({
|
|
||||||
doc: frm.doc,
|
|
||||||
method: "drop_ar_sql_procedures",
|
|
||||||
callback: function (r) {
|
|
||||||
frappe.show_alert(__("Procedures dropped"), 5);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
function toggle_tax_settings(frm, field_name) {
|
function toggle_tax_settings(frm, field_name) {
|
||||||
|
|||||||
@@ -95,7 +95,6 @@
|
|||||||
"receivable_payable_fetch_method",
|
"receivable_payable_fetch_method",
|
||||||
"default_ageing_range",
|
"default_ageing_range",
|
||||||
"column_break_ntmi",
|
"column_break_ntmi",
|
||||||
"drop_ar_procedures",
|
|
||||||
"legacy_section",
|
"legacy_section",
|
||||||
"ignore_is_opening_check_for_reporting",
|
"ignore_is_opening_check_for_reporting",
|
||||||
"payment_request_settings",
|
"payment_request_settings",
|
||||||
@@ -561,7 +560,7 @@
|
|||||||
"fieldname": "receivable_payable_fetch_method",
|
"fieldname": "receivable_payable_fetch_method",
|
||||||
"fieldtype": "Select",
|
"fieldtype": "Select",
|
||||||
"label": "Data Fetch Method",
|
"label": "Data Fetch Method",
|
||||||
"options": "Buffered Cursor\nUnBuffered Cursor\nRaw SQL"
|
"options": "Buffered Cursor\nUnBuffered Cursor"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "accounts_receivable_payable_tuning_section",
|
"fieldname": "accounts_receivable_payable_tuning_section",
|
||||||
@@ -623,13 +622,6 @@
|
|||||||
"fieldname": "column_break_ntmi",
|
"fieldname": "column_break_ntmi",
|
||||||
"fieldtype": "Column Break"
|
"fieldtype": "Column Break"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"depends_on": "eval:doc.receivable_payable_fetch_method == \"Raw SQL\"",
|
|
||||||
"description": "Drops existing SQL Procedures and Function setup by Accounts Receivable report",
|
|
||||||
"fieldname": "drop_ar_procedures",
|
|
||||||
"fieldtype": "Button",
|
|
||||||
"label": "Drop Procedures"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"default": "0",
|
"default": "0",
|
||||||
"fieldname": "fetch_valuation_rate_for_internal_transaction",
|
"fieldname": "fetch_valuation_rate_for_internal_transaction",
|
||||||
@@ -671,7 +663,7 @@
|
|||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"issingle": 1,
|
"issingle": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2026-03-06 14:49:11.467716",
|
"modified": "2026-05-18 12:16:33.679345",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Accounts Settings",
|
"name": "Accounts Settings",
|
||||||
@@ -701,4 +693,4 @@
|
|||||||
"sort_order": "ASC",
|
"sort_order": "ASC",
|
||||||
"states": [],
|
"states": [],
|
||||||
"track_changes": 1
|
"track_changes": 1
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ class AccountsSettings(Document):
|
|||||||
merge_similar_account_heads: DF.Check
|
merge_similar_account_heads: DF.Check
|
||||||
over_billing_allowance: DF.Currency
|
over_billing_allowance: DF.Currency
|
||||||
post_change_gl_entries: DF.Check
|
post_change_gl_entries: DF.Check
|
||||||
receivable_payable_fetch_method: DF.Literal["Buffered Cursor", "UnBuffered Cursor", "Raw SQL"]
|
receivable_payable_fetch_method: DF.Literal["Buffered Cursor", "UnBuffered Cursor"]
|
||||||
receivable_payable_remarks_length: DF.Int
|
receivable_payable_remarks_length: DF.Int
|
||||||
reconciliation_queue_size: DF.Int
|
reconciliation_queue_size: DF.Int
|
||||||
role_allowed_to_over_bill: DF.Link | None
|
role_allowed_to_over_bill: DF.Link | None
|
||||||
@@ -170,10 +170,3 @@ class AccountsSettings(Document):
|
|||||||
),
|
),
|
||||||
title=_("Auto Tax Settings Error"),
|
title=_("Auto Tax Settings Error"),
|
||||||
)
|
)
|
||||||
|
|
||||||
@frappe.whitelist()
|
|
||||||
def drop_ar_sql_procedures(self):
|
|
||||||
from erpnext.accounts.report.accounts_receivable.accounts_receivable import InitSQLProceduresForAR
|
|
||||||
|
|
||||||
frappe.db.sql(f"drop procedure if exists {InitSQLProceduresForAR.init_procedure_name}")
|
|
||||||
frappe.db.sql(f"drop procedure if exists {InitSQLProceduresForAR.allocate_procedure_name}")
|
|
||||||
|
|||||||
@@ -129,8 +129,6 @@ class ReceivablePayableReport:
|
|||||||
self.fetch_ple_in_buffered_cursor()
|
self.fetch_ple_in_buffered_cursor()
|
||||||
elif self.ple_fetch_method == "UnBuffered Cursor":
|
elif self.ple_fetch_method == "UnBuffered Cursor":
|
||||||
self.fetch_ple_in_unbuffered_cursor()
|
self.fetch_ple_in_unbuffered_cursor()
|
||||||
elif self.ple_fetch_method == "Raw SQL":
|
|
||||||
self.fetch_ple_in_sql_procedures()
|
|
||||||
|
|
||||||
# Build delivery note map against all sales invoices
|
# Build delivery note map against all sales invoices
|
||||||
self.build_delivery_note_map()
|
self.build_delivery_note_map()
|
||||||
@@ -321,81 +319,6 @@ class ReceivablePayableReport:
|
|||||||
row.paid -= amount
|
row.paid -= amount
|
||||||
row.paid_in_account_currency -= amount_in_account_currency
|
row.paid_in_account_currency -= amount_in_account_currency
|
||||||
|
|
||||||
def fetch_ple_in_sql_procedures(self):
|
|
||||||
self.proc = InitSQLProceduresForAR()
|
|
||||||
|
|
||||||
build_balance = f"""
|
|
||||||
begin not atomic
|
|
||||||
declare done boolean default false;
|
|
||||||
declare rec1 row type of `{self.proc._row_def_table_name}`;
|
|
||||||
declare ple cursor for {self.ple_query.get_sql()};
|
|
||||||
declare continue handler for not found set done = true;
|
|
||||||
|
|
||||||
open ple;
|
|
||||||
fetch ple into rec1;
|
|
||||||
while not done do
|
|
||||||
call {self.proc.init_procedure_name}(rec1);
|
|
||||||
fetch ple into rec1;
|
|
||||||
end while;
|
|
||||||
close ple;
|
|
||||||
|
|
||||||
set done = false;
|
|
||||||
open ple;
|
|
||||||
fetch ple into rec1;
|
|
||||||
while not done do
|
|
||||||
call {self.proc.allocate_procedure_name}(rec1);
|
|
||||||
fetch ple into rec1;
|
|
||||||
end while;
|
|
||||||
close ple;
|
|
||||||
end;
|
|
||||||
"""
|
|
||||||
frappe.db.sql(build_balance)
|
|
||||||
|
|
||||||
balances = frappe.db.sql(
|
|
||||||
f"""select
|
|
||||||
name,
|
|
||||||
voucher_type,
|
|
||||||
voucher_no,
|
|
||||||
party,
|
|
||||||
party_account `account`,
|
|
||||||
posting_date,
|
|
||||||
account_currency,
|
|
||||||
cost_center,
|
|
||||||
project,
|
|
||||||
sum(invoiced) `invoiced`,
|
|
||||||
sum(paid) `paid`,
|
|
||||||
sum(credit_note) `credit_note`,
|
|
||||||
sum(invoiced) - sum(paid) - sum(credit_note) `outstanding`,
|
|
||||||
sum(invoiced_in_account_currency) `invoiced_in_account_currency`,
|
|
||||||
sum(paid_in_account_currency) `paid_in_account_currency`,
|
|
||||||
sum(credit_note_in_account_currency) `credit_note_in_account_currency`,
|
|
||||||
sum(invoiced_in_account_currency) - sum(paid_in_account_currency) - sum(credit_note_in_account_currency) `outstanding_in_account_currency`
|
|
||||||
from `{self.proc._voucher_balance_name}` group by name order by posting_date;""",
|
|
||||||
as_dict=True,
|
|
||||||
)
|
|
||||||
for x in balances:
|
|
||||||
if self.filters.get("ignore_accounts"):
|
|
||||||
key = (x.voucher_type, x.voucher_no, x.party)
|
|
||||||
else:
|
|
||||||
key = (x.account, x.voucher_type, x.voucher_no, x.party)
|
|
||||||
|
|
||||||
_d = self.build_voucher_dict(x)
|
|
||||||
for field in [
|
|
||||||
"invoiced",
|
|
||||||
"paid",
|
|
||||||
"credit_note",
|
|
||||||
"outstanding",
|
|
||||||
"invoiced_in_account_currency",
|
|
||||||
"paid_in_account_currency",
|
|
||||||
"credit_note_in_account_currency",
|
|
||||||
"outstanding_in_account_currency",
|
|
||||||
"cost_center",
|
|
||||||
"project",
|
|
||||||
]:
|
|
||||||
_d[field] = x.get(field)
|
|
||||||
|
|
||||||
self.voucher_balance[key] = _d
|
|
||||||
|
|
||||||
def update_sub_total_row(self, row, party):
|
def update_sub_total_row(self, row, party):
|
||||||
total_row = self.total_row_map.get(party)
|
total_row = self.total_row_map.get(party)
|
||||||
|
|
||||||
@@ -1390,120 +1313,3 @@ def get_party_group_with_children(party, party_groups):
|
|||||||
frappe.throw(_("{0}: {1} does not exist").format(group_dtype, d))
|
frappe.throw(_("{0}: {1} does not exist").format(group_dtype, d))
|
||||||
|
|
||||||
return list(set(all_party_groups))
|
return list(set(all_party_groups))
|
||||||
|
|
||||||
|
|
||||||
class InitSQLProceduresForAR:
|
|
||||||
"""
|
|
||||||
Initialize SQL Procedures, Functions and Temporary tables to build Receivable / Payable report
|
|
||||||
"""
|
|
||||||
|
|
||||||
_varchar_type = get_definition("Data")
|
|
||||||
_currency_type = get_definition("Currency")
|
|
||||||
# Temporary Tables
|
|
||||||
_voucher_balance_name = "_ar_voucher_balance"
|
|
||||||
_voucher_balance_definition = f"""
|
|
||||||
create temporary table `{_voucher_balance_name}`(
|
|
||||||
name {_varchar_type},
|
|
||||||
voucher_type {_varchar_type},
|
|
||||||
voucher_no {_varchar_type},
|
|
||||||
party {_varchar_type},
|
|
||||||
party_account {_varchar_type},
|
|
||||||
posting_date date,
|
|
||||||
account_currency {_varchar_type},
|
|
||||||
cost_center {_varchar_type},
|
|
||||||
project {_varchar_type},
|
|
||||||
invoiced {_currency_type},
|
|
||||||
paid {_currency_type},
|
|
||||||
credit_note {_currency_type},
|
|
||||||
invoiced_in_account_currency {_currency_type},
|
|
||||||
paid_in_account_currency {_currency_type},
|
|
||||||
credit_note_in_account_currency {_currency_type}) engine=memory;
|
|
||||||
"""
|
|
||||||
|
|
||||||
_row_def_table_name = "_ar_ple_row"
|
|
||||||
_row_def_table_definition = f"""
|
|
||||||
create temporary table `{_row_def_table_name}`(
|
|
||||||
name {_varchar_type},
|
|
||||||
account {_varchar_type},
|
|
||||||
voucher_type {_varchar_type},
|
|
||||||
voucher_no {_varchar_type},
|
|
||||||
against_voucher_type {_varchar_type},
|
|
||||||
against_voucher_no {_varchar_type},
|
|
||||||
party_type {_varchar_type},
|
|
||||||
cost_center {_varchar_type},
|
|
||||||
project {_varchar_type},
|
|
||||||
party {_varchar_type},
|
|
||||||
posting_date date,
|
|
||||||
due_date date,
|
|
||||||
account_currency {_varchar_type},
|
|
||||||
amount {_currency_type},
|
|
||||||
amount_in_account_currency {_currency_type}) engine=memory;
|
|
||||||
"""
|
|
||||||
|
|
||||||
# Procedures
|
|
||||||
init_procedure_name = "ar_init_tmp_table"
|
|
||||||
init_procedure_sql = f"""
|
|
||||||
create procedure ar_init_tmp_table(in ple row type of `{_row_def_table_name}`)
|
|
||||||
begin
|
|
||||||
if not exists (select name from `{_voucher_balance_name}` where name = sha1(concat_ws(',', ple.account, ple.against_voucher_type, ple.against_voucher_no, ple.party)))
|
|
||||||
then
|
|
||||||
insert into `{_voucher_balance_name}` values (sha1(concat_ws(',', ple.account, ple.against_voucher_type, ple.against_voucher_no, ple.party)), ple.voucher_type, ple.voucher_no, ple.party, ple.account, ple.posting_date, ple.account_currency, ple.cost_center, 0, 0, 0, 0, 0, 0);
|
|
||||||
end if;
|
|
||||||
end;
|
|
||||||
"""
|
|
||||||
|
|
||||||
allocate_procedure_name = "ar_allocate_to_tmp_table"
|
|
||||||
allocate_procedure_sql = f"""
|
|
||||||
create procedure ar_allocate_to_tmp_table(in ple row type of `{_row_def_table_name}`)
|
|
||||||
begin
|
|
||||||
declare invoiced {_currency_type} default 0;
|
|
||||||
declare invoiced_in_account_currency {_currency_type} default 0;
|
|
||||||
declare paid {_currency_type} default 0;
|
|
||||||
declare paid_in_account_currency {_currency_type} default 0;
|
|
||||||
declare credit_note {_currency_type} default 0;
|
|
||||||
declare credit_note_in_account_currency {_currency_type} default 0;
|
|
||||||
|
|
||||||
|
|
||||||
if ple.amount > 0 then
|
|
||||||
if (ple.voucher_type in ("Journal Entry", "Payment Entry") and (ple.voucher_no != ple.against_voucher_no)) then
|
|
||||||
set paid = -1 * ple.amount;
|
|
||||||
set paid_in_account_currency = -1 * ple.amount_in_account_currency;
|
|
||||||
else
|
|
||||||
set invoiced = ple.amount;
|
|
||||||
set invoiced_in_account_currency = ple.amount_in_account_currency;
|
|
||||||
end if;
|
|
||||||
else
|
|
||||||
|
|
||||||
if ple.voucher_type in ("Sales Invoice", "Purchase Invoice") then
|
|
||||||
if (ple.voucher_no = ple.against_voucher_no) then
|
|
||||||
set paid = -1 * ple.amount;
|
|
||||||
set paid_in_account_currency = -1 * ple.amount_in_account_currency;
|
|
||||||
else
|
|
||||||
set credit_note = -1 * ple.amount;
|
|
||||||
set credit_note_in_account_currency = -1 * ple.amount_in_account_currency;
|
|
||||||
end if;
|
|
||||||
else
|
|
||||||
set paid = -1 * ple.amount;
|
|
||||||
set paid_in_account_currency = -1 * ple.amount_in_account_currency;
|
|
||||||
end if;
|
|
||||||
|
|
||||||
end if;
|
|
||||||
|
|
||||||
insert into `{_voucher_balance_name}` values (sha1(concat_ws(',', ple.account, ple.voucher_type, ple.voucher_no, ple.party)), ple.against_voucher_type, ple.against_voucher_no, ple.party, ple.account, ple.posting_date, ple.account_currency,'', invoiced, paid, 0, invoiced_in_account_currency, paid_in_account_currency, 0);
|
|
||||||
end;
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
existing_procedures = frappe.db.get_routines()
|
|
||||||
|
|
||||||
if self.init_procedure_name not in existing_procedures:
|
|
||||||
frappe.db.sql(self.init_procedure_sql)
|
|
||||||
|
|
||||||
if self.allocate_procedure_name not in existing_procedures:
|
|
||||||
frappe.db.sql(self.allocate_procedure_sql)
|
|
||||||
|
|
||||||
frappe.db.sql(f"drop table if exists `{self._voucher_balance_name}`")
|
|
||||||
frappe.db.sql(self._voucher_balance_definition)
|
|
||||||
|
|
||||||
frappe.db.sql(f"drop table if exists `{self._row_def_table_name}`")
|
|
||||||
frappe.db.sql(self._row_def_table_definition)
|
|
||||||
|
|||||||
@@ -433,3 +433,4 @@ erpnext.patches.v15_0.replace_http_with_https_in_sales_partner
|
|||||||
erpnext.patches.v16_0.add_portal_redirects
|
erpnext.patches.v16_0.add_portal_redirects
|
||||||
erpnext.patches.v16_0.update_order_qty_and_requested_qty_based_on_mr_and_po
|
erpnext.patches.v16_0.update_order_qty_and_requested_qty_based_on_mr_and_po
|
||||||
erpnext.patches.v16_0.depends_on_inv_dimensions
|
erpnext.patches.v16_0.depends_on_inv_dimensions
|
||||||
|
erpnext.patches.v16_0.clear_procedures_from_receivable_report
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import frappe
|
||||||
|
|
||||||
|
|
||||||
|
def execute():
|
||||||
|
if frappe.db.get_single_value("Accounts Settings", "receivable_payable_fetch_method") == "Raw SQL":
|
||||||
|
frappe.db.set_single_value(
|
||||||
|
"Accounts Settings", "receivable_payable_fetch_method", "UnBuffered Cursor"
|
||||||
|
)
|
||||||
|
|
||||||
|
frappe.db.sql("drop function if exists ar_genkey")
|
||||||
|
frappe.db.sql("drop procedure if exists ar_init_tmp_table")
|
||||||
|
frappe.db.sql("drop procedure if exists ar_allocate_to_tmp_table")
|
||||||
Reference in New Issue
Block a user