From e5a1189becad071f54c727bc6c0dba16bea2a12f Mon Sep 17 00:00:00 2001 From: sonali Date: Thu, 8 Dec 2022 13:29:28 +0530 Subject: [PATCH 01/25] Update bank_reconciliation_tool.py Applying date filter on transactions and all the bank entries and also gives the filter the bank entries as per reference date. Sorted all transactions and entries as per date in ascending order. Also added posting date columns in all bank entries and default checkbox tick of journal entry, hide the sales invoice and purchase invoice checkbox. --- .../bank_reconciliation_tool.py | 188 +++++++++++++----- erpnext/hooks.py | 4 +- .../dialog_manager.js | 7 + 3 files changed, 144 insertions(+), 55 deletions(-) diff --git a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py index d353270b45..cd99d38d05 100644 --- a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py +++ b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py @@ -25,6 +25,8 @@ class BankReconciliationTool(Document): @frappe.whitelist() def get_bank_transactions(bank_account, from_date=None, to_date=None): # returns bank transactions for a bank account + from_date = frappe.db.get_single_value('Bank Reconciliation Tool','bank_statement_from_date') + to_date = frappe.db.get_single_value('Bank Reconciliation Tool','bank_statement_to_date') filters = [] filters.append(["bank_account", "=", bank_account]) filters.append(["docstatus", "=", 1]) @@ -51,9 +53,11 @@ def get_bank_transactions(bank_account, from_date=None, to_date=None): ], filters=filters, ) + transactions= sorted(transactions, key=lambda x: x['date']) if transactions else [] return transactions + @frappe.whitelist() def get_account_balance(bank_account, till_date): # returns account balance till the specified date @@ -340,6 +344,7 @@ def get_linked_payments(bank_transaction_name, document_types=None): def check_matching(bank_account, company, transaction, document_types): # combine all types of vouchers + filtered_by_reference_date = frappe.db.get_single_value('Bank Reconciliation Tool','filtered_by_reference_date') subquery = get_queries(bank_account, company, transaction, document_types) filters = { "amount": transaction.unallocated_amount, @@ -361,8 +366,12 @@ def check_matching(bank_account, company, transaction, document_types): filters, ) ) - - return sorted(matching_vouchers, key=lambda x: x[0], reverse=True) if matching_vouchers else [] + matching_vouchers_with_ref_no = tuple(ele for ele in matching_vouchers if frappe.as_json(ele[5]) != "null") + if filtered_by_reference_date: + matching_vouchers = sorted(matching_vouchers_with_ref_no , key=lambda x: x[5]) if matching_vouchers else [] + else: + matching_vouchers = sorted(matching_vouchers, key=lambda x: x[8]) if matching_vouchers else [] + return matching_vouchers def get_queries(bank_account, company, transaction, document_types): @@ -506,33 +515,72 @@ def get_lr_matching_query(bank_account, amount_condition, filters): def get_pe_matching_query(amount_condition, account_from_to, transaction): # get matching payment entries query + from_date = frappe.db.get_single_value('Bank Reconciliation Tool','bank_statement_from_date') + to_date = frappe.db.get_single_value('Bank Reconciliation Tool','bank_statement_to_date') + from_reference_date = frappe.db.get_single_value('Bank Reconciliation Tool','from_reference_date') + to_reference_date = frappe.db.get_single_value('Bank Reconciliation Tool','to_reference_date') + filtered_by_reference_date = frappe.db.get_single_value('Bank Reconciliation Tool','filtered_by_reference_date') if transaction.deposit > 0: currency_field = "paid_to_account_currency as currency" else: currency_field = "paid_from_account_currency as currency" - return f""" - SELECT - (CASE WHEN reference_no=%(reference_no)s THEN 1 ELSE 0 END - + CASE WHEN (party_type = %(party_type)s AND party = %(party)s ) THEN 1 ELSE 0 END - + 1 ) AS rank, - 'Payment Entry' as doctype, - name, - paid_amount, - reference_no, - reference_date, - party, - party_type, - posting_date, - {currency_field} - FROM - `tabPayment Entry` - WHERE - paid_amount {amount_condition} %(amount)s - AND docstatus = 1 - AND payment_type IN (%(payment_type)s, 'Internal Transfer') - AND ifnull(clearance_date, '') = "" - AND {account_from_to} = %(bank_account)s - """ + if (filtered_by_reference_date): + pe_data= f""" + SELECT + (CASE WHEN reference_no=%(reference_no)s THEN 1 ELSE 0 END + + CASE WHEN (party_type = %(party_type)s AND party = %(party)s ) THEN 1 ELSE 0 END + + 1 ) AS rank, + 'Payment Entry' as doctype, + name, + paid_amount, + reference_no, + reference_date, + party, + party_type, + posting_date, + {currency_field} + FROM + `tabPayment Entry` + WHERE + paid_amount {amount_condition} %(amount)s + AND docstatus = 1 + AND payment_type IN (%(payment_type)s, 'Internal Transfer') + AND ifnull(clearance_date, '') = "" + AND {account_from_to} = %(bank_account)s + AND reference_date >= '{from_reference_date}' + AND reference_date <= '{to_reference_date}' + + """ + else: + pe_data= f""" + SELECT + (CASE WHEN reference_no=%(reference_no)s THEN 1 ELSE 0 END + + CASE WHEN (party_type = %(party_type)s AND party = %(party)s ) THEN 1 ELSE 0 END + + 1 ) AS rank, + 'Payment Entry' as doctype, + name, + paid_amount, + reference_no, + reference_date, + party, + party_type, + posting_date, + {currency_field} + FROM + `tabPayment Entry` + WHERE + paid_amount {amount_condition} %(amount)s + AND docstatus = 1 + AND payment_type IN (%(payment_type)s, 'Internal Transfer') + AND ifnull(clearance_date, '') = "" + AND {account_from_to} = %(bank_account)s + AND posting_date >= '{from_date}' + AND posting_date <= '{to_date}' + + """ + return pe_data + + def get_je_matching_query(amount_condition, transaction): @@ -541,35 +589,69 @@ def get_je_matching_query(amount_condition, transaction): # We have mapping at the bank level # So one bank could have both types of bank accounts like asset and liability # So cr_or_dr should be judged only on basis of withdrawal and deposit and not account type + from_date = frappe.db.get_single_value('Bank Reconciliation Tool','bank_statement_from_date') + to_date = frappe.db.get_single_value('Bank Reconciliation Tool','bank_statement_to_date') + from_reference_date = frappe.db.get_single_value('Bank Reconciliation Tool','from_reference_date') + to_reference_date = frappe.db.get_single_value('Bank Reconciliation Tool','to_reference_date') + filtered_by_reference_date = frappe.db.get_single_value('Bank Reconciliation Tool','filtered_by_reference_date') cr_or_dr = "credit" if transaction.withdrawal > 0 else "debit" - - return f""" - - SELECT - (CASE WHEN je.cheque_no=%(reference_no)s THEN 1 ELSE 0 END - + 1) AS rank , - 'Journal Entry' as doctype, - je.name, - jea.{cr_or_dr}_in_account_currency as paid_amount, - je.cheque_no as reference_no, - je.cheque_date as reference_date, - je.pay_to_recd_from as party, - jea.party_type, - je.posting_date, - jea.account_currency as currency - FROM - `tabJournal Entry Account` as jea - JOIN - `tabJournal Entry` as je - ON - jea.parent = je.name - WHERE - (je.clearance_date is null or je.clearance_date='0000-00-00') - AND jea.account = %(bank_account)s - AND jea.{cr_or_dr}_in_account_currency {amount_condition} %(amount)s - AND je.docstatus = 1 - """ - + if (filtered_by_reference_date==1): + je_data = f""" + SELECT + (CASE WHEN je.cheque_no=%(reference_no)s THEN 1 ELSE 0 END + + 1) AS rank , + 'Journal Entry' as doctype, + je.name, + jea.{cr_or_dr}_in_account_currency as paid_amount, + je.cheque_no as reference_no, + je.cheque_date as reference_date, + je.pay_to_recd_from as party, + jea.party_type, + je.posting_date, + jea.account_currency as currency + FROM + `tabJournal Entry Account` as jea + JOIN + `tabJournal Entry` as je + ON + jea.parent = je.name + WHERE + (je.clearance_date is null or je.clearance_date='0000-00-00') + AND jea.account = %(bank_account)s + AND jea.{cr_or_dr}_in_account_currency {amount_condition} %(amount)s + AND je.docstatus = 1 + AND je.cheque_date >= '{from_reference_date}' + AND je.cheque_date <= '{to_reference_date}' + """ + else: + je_data = f""" + SELECT + (CASE WHEN je.cheque_no=%(reference_no)s THEN 1 ELSE 0 END + + 1) AS rank , + 'Journal Entry' as doctype, + je.name, + jea.{cr_or_dr}_in_account_currency as paid_amount, + je.cheque_no as reference_no, + je.cheque_date as reference_date, + je.pay_to_recd_from as party, + jea.party_type, + je.posting_date, + jea.account_currency as currency + FROM + `tabJournal Entry Account` as jea + JOIN + `tabJournal Entry` as je + ON + jea.parent = je.name + WHERE + (je.clearance_date is null or je.clearance_date='0000-00-00') + AND jea.account = %(bank_account)s + AND jea.{cr_or_dr}_in_account_currency {amount_condition} %(amount)s + AND je.docstatus = 1 + AND je.posting_date >= '{from_date}' + AND je.posting_date <= '{to_date}' + """ + return je_data def get_si_matching_query(amount_condition): # get matchin sales invoice query diff --git a/erpnext/hooks.py b/erpnext/hooks.py index 92601b3444..1efc82e301 100644 --- a/erpnext/hooks.py +++ b/erpnext/hooks.py @@ -469,8 +469,8 @@ period_closing_doctypes = [ bank_reconciliation_doctypes = [ "Payment Entry", "Journal Entry", - "Purchase Invoice", - "Sales Invoice", + # "Purchase Invoice", + # "Sales Invoice", "Loan Repayment", "Loan Disbursement", ] diff --git a/erpnext/public/js/bank_reconciliation_tool/dialog_manager.js b/erpnext/public/js/bank_reconciliation_tool/dialog_manager.js index ca01f68140..bd003747dd 100644 --- a/erpnext/public/js/bank_reconciliation_tool/dialog_manager.js +++ b/erpnext/public/js/bank_reconciliation_tool/dialog_manager.js @@ -35,6 +35,7 @@ erpnext.accounts.bank_reconciliation.DialogManager = class DialogManager { if (r.message) { this.bank_transaction = r.message; r.message.payment_entry = 1; + r.message.journal_entry = 1; this.dialog.set_values(r.message); this.dialog.show(); } @@ -66,6 +67,7 @@ erpnext.accounts.bank_reconciliation.DialogManager = class DialogManager { row[1], row[2], reference_date, + row[8], format_currency(row[3], row[9]), row[6], row[4], @@ -101,6 +103,11 @@ erpnext.accounts.bank_reconciliation.DialogManager = class DialogManager { editable: false, width: 120, }, + { + name: "Posting Date", + editable: false, + width: 120, + }, { name: __("Amount"), editable: false, From 447272aa4d1f49428717b1b0ae8e34a21fd0e752 Mon Sep 17 00:00:00 2001 From: sonali Date: Thu, 8 Dec 2022 16:11:53 +0530 Subject: [PATCH 02/25] Filters on Bank Reconciliation Applying date filter on transactions and all the bank entries and also gives the filter the bank entries as per reference date. Sorted all transactions and entries as per date in ascending order. Also added posting date columns in all bank entries and default checkbox tick of journal entry, hide the sales invoice and purchase invoice checkbox. --- .../bank_reconciliation_tool.py | 70 ++- .../dialog_manager.js | 576 ++++++++++++++++++ 2 files changed, 617 insertions(+), 29 deletions(-) diff --git a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py index cd99d38d05..70962042f7 100644 --- a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py +++ b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py @@ -25,8 +25,8 @@ class BankReconciliationTool(Document): @frappe.whitelist() def get_bank_transactions(bank_account, from_date=None, to_date=None): # returns bank transactions for a bank account - from_date = frappe.db.get_single_value('Bank Reconciliation Tool','bank_statement_from_date') - to_date = frappe.db.get_single_value('Bank Reconciliation Tool','bank_statement_to_date') + from_date = frappe.db.get_single_value("Bank Reconciliation Tool", "bank_statement_from_date") + to_date = frappe.db.get_single_value("Bank Reconciliation Tool", "bank_statement_to_date") filters = [] filters.append(["bank_account", "=", bank_account]) filters.append(["docstatus", "=", 1]) @@ -53,11 +53,10 @@ def get_bank_transactions(bank_account, from_date=None, to_date=None): ], filters=filters, ) - transactions= sorted(transactions, key=lambda x: x['date']) if transactions else [] + transactions = sorted(transactions, key=lambda x: x["date"]) if transactions else [] return transactions - @frappe.whitelist() def get_account_balance(bank_account, till_date): # returns account balance till the specified date @@ -344,7 +343,9 @@ def get_linked_payments(bank_transaction_name, document_types=None): def check_matching(bank_account, company, transaction, document_types): # combine all types of vouchers - filtered_by_reference_date = frappe.db.get_single_value('Bank Reconciliation Tool','filtered_by_reference_date') + filtered_by_reference_date = frappe.db.get_single_value( + "Bank Reconciliation Tool", "filtered_by_reference_date" + ) subquery = get_queries(bank_account, company, transaction, document_types) filters = { "amount": transaction.unallocated_amount, @@ -366,9 +367,13 @@ def check_matching(bank_account, company, transaction, document_types): filters, ) ) - matching_vouchers_with_ref_no = tuple(ele for ele in matching_vouchers if frappe.as_json(ele[5]) != "null") + matching_vouchers_with_ref_no = tuple( + ele for ele in matching_vouchers if frappe.as_json(ele[5]) != "null" + ) if filtered_by_reference_date: - matching_vouchers = sorted(matching_vouchers_with_ref_no , key=lambda x: x[5]) if matching_vouchers else [] + matching_vouchers = ( + sorted(matching_vouchers_with_ref_no, key=lambda x: x[5]) if matching_vouchers else [] + ) else: matching_vouchers = sorted(matching_vouchers, key=lambda x: x[8]) if matching_vouchers else [] return matching_vouchers @@ -515,17 +520,21 @@ def get_lr_matching_query(bank_account, amount_condition, filters): def get_pe_matching_query(amount_condition, account_from_to, transaction): # get matching payment entries query - from_date = frappe.db.get_single_value('Bank Reconciliation Tool','bank_statement_from_date') - to_date = frappe.db.get_single_value('Bank Reconciliation Tool','bank_statement_to_date') - from_reference_date = frappe.db.get_single_value('Bank Reconciliation Tool','from_reference_date') - to_reference_date = frappe.db.get_single_value('Bank Reconciliation Tool','to_reference_date') - filtered_by_reference_date = frappe.db.get_single_value('Bank Reconciliation Tool','filtered_by_reference_date') + from_date = frappe.db.get_single_value("Bank Reconciliation Tool", "bank_statement_from_date") + to_date = frappe.db.get_single_value("Bank Reconciliation Tool", "bank_statement_to_date") + from_reference_date = frappe.db.get_single_value( + "Bank Reconciliation Tool", "from_reference_date" + ) + to_reference_date = frappe.db.get_single_value("Bank Reconciliation Tool", "to_reference_date") + filtered_by_reference_date = frappe.db.get_single_value( + "Bank Reconciliation Tool", "filtered_by_reference_date" + ) if transaction.deposit > 0: currency_field = "paid_to_account_currency as currency" else: currency_field = "paid_from_account_currency as currency" - if (filtered_by_reference_date): - pe_data= f""" + if filtered_by_reference_date: + pe_data = f""" SELECT (CASE WHEN reference_no=%(reference_no)s THEN 1 ELSE 0 END + CASE WHEN (party_type = %(party_type)s AND party = %(party)s ) THEN 1 ELSE 0 END @@ -548,11 +557,11 @@ def get_pe_matching_query(amount_condition, account_from_to, transaction): AND ifnull(clearance_date, '') = "" AND {account_from_to} = %(bank_account)s AND reference_date >= '{from_reference_date}' - AND reference_date <= '{to_reference_date}' - + AND reference_date <= '{to_reference_date}' + """ else: - pe_data= f""" + pe_data = f""" SELECT (CASE WHEN reference_no=%(reference_no)s THEN 1 ELSE 0 END + CASE WHEN (party_type = %(party_type)s AND party = %(party)s ) THEN 1 ELSE 0 END @@ -575,13 +584,11 @@ def get_pe_matching_query(amount_condition, account_from_to, transaction): AND ifnull(clearance_date, '') = "" AND {account_from_to} = %(bank_account)s AND posting_date >= '{from_date}' - AND posting_date <= '{to_date}' - + AND posting_date <= '{to_date}' + """ return pe_data - - def get_je_matching_query(amount_condition, transaction): # get matching journal entry query @@ -589,14 +596,18 @@ def get_je_matching_query(amount_condition, transaction): # We have mapping at the bank level # So one bank could have both types of bank accounts like asset and liability # So cr_or_dr should be judged only on basis of withdrawal and deposit and not account type - from_date = frappe.db.get_single_value('Bank Reconciliation Tool','bank_statement_from_date') - to_date = frappe.db.get_single_value('Bank Reconciliation Tool','bank_statement_to_date') - from_reference_date = frappe.db.get_single_value('Bank Reconciliation Tool','from_reference_date') - to_reference_date = frappe.db.get_single_value('Bank Reconciliation Tool','to_reference_date') - filtered_by_reference_date = frappe.db.get_single_value('Bank Reconciliation Tool','filtered_by_reference_date') + from_date = frappe.db.get_single_value("Bank Reconciliation Tool", "bank_statement_from_date") + to_date = frappe.db.get_single_value("Bank Reconciliation Tool", "bank_statement_to_date") + from_reference_date = frappe.db.get_single_value( + "Bank Reconciliation Tool", "from_reference_date" + ) + to_reference_date = frappe.db.get_single_value("Bank Reconciliation Tool", "to_reference_date") + filtered_by_reference_date = frappe.db.get_single_value( + "Bank Reconciliation Tool", "filtered_by_reference_date" + ) cr_or_dr = "credit" if transaction.withdrawal > 0 else "debit" - if (filtered_by_reference_date==1): - je_data = f""" + if filtered_by_reference_date == 1: + je_data = f""" SELECT (CASE WHEN je.cheque_no=%(reference_no)s THEN 1 ELSE 0 END + 1) AS rank , @@ -624,7 +635,7 @@ def get_je_matching_query(amount_condition, transaction): AND je.cheque_date <= '{to_reference_date}' """ else: - je_data = f""" + je_data = f""" SELECT (CASE WHEN je.cheque_no=%(reference_no)s THEN 1 ELSE 0 END + 1) AS rank , @@ -653,6 +664,7 @@ def get_je_matching_query(amount_condition, transaction): """ return je_data + def get_si_matching_query(amount_condition): # get matchin sales invoice query return f""" diff --git a/erpnext/public/js/bank_reconciliation_tool/dialog_manager.js b/erpnext/public/js/bank_reconciliation_tool/dialog_manager.js index bd003747dd..d7c0e61fc0 100644 --- a/erpnext/public/js/bank_reconciliation_tool/dialog_manager.js +++ b/erpnext/public/js/bank_reconciliation_tool/dialog_manager.js @@ -42,7 +42,583 @@ erpnext.accounts.bank_reconciliation.DialogManager = class DialogManager { }, }); } + frappe.provide("erpnext.accounts.bank_reconciliation"); + erpnext.accounts.bank_reconciliation.DialogManager = class DialogManager { + constructor(company, bank_account) { + this.bank_account = bank_account; + this.company = company; + this.make_dialog(); + } + + show_dialog(bank_transaction_name, update_dt_cards) { + this.bank_transaction_name = bank_transaction_name; + this.update_dt_cards = update_dt_cards; + frappe.call({ + method: "frappe.client.get_value", + args: { + doctype: "Bank Transaction", + filters: { name: this.bank_transaction_name }, + fieldname: [ + "date as reference_date", + "deposit", + "withdrawal", + "currency", + "description", + "name", + "bank_account", + "company", + "reference_number", + "party_type", + "party", + "unallocated_amount", + "allocated_amount", + ], + }, + callback: (r) => { + if (r.message) { + this.bank_transaction = r.message; + r.message.payment_entry = 1; + r.message.journal_entry = 1; + this.dialog.set_values(r.message); + this.dialog.show(); + } + }, + }); + } + + get_linked_vouchers(document_types) { + frappe.call({ + method: + "erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.get_linked_payments", + args: { + bank_transaction_name: this.bank_transaction_name, + document_types: document_types, + }, + + callback: (result) => { + const data = result.message; + + + if (data && data.length > 0) { + const proposals_wrapper = this.dialog.fields_dict.payment_proposals.$wrapper; + proposals_wrapper.show(); + this.dialog.fields_dict.no_matching_vouchers.$wrapper.hide(); + this.data = []; + data.forEach((row) => { + const reference_date = row[5] ? row[5] : row[8]; + this.data.push([ + row[1], + row[2], + reference_date, + row[8], + format_currency(row[3], row[9]), + row[6], + row[4], + ]); + }); + this.get_dt_columns(); + this.get_datatable(proposals_wrapper); + } else { + const proposals_wrapper = this.dialog.fields_dict.payment_proposals.$wrapper; + proposals_wrapper.hide(); + this.dialog.fields_dict.no_matching_vouchers.$wrapper.show(); + + } + this.dialog.show(); + }, + }); + } + + get_dt_columns() { + this.columns = [ + { + name: __("Document Type"), + editable: false, + width: 125, + }, + { + name: __("Document Name"), + editable: false, + width: 150, + }, + { + name: __("Reference Date"), + editable: false, + width: 120, + }, + { + name: "Posting Date", + editable: false, + width: 120, + }, + { + name: __("Amount"), + editable: false, + width: 100, + }, + { + name: __("Party"), + editable: false, + width: 120, + }, + + { + name: __("Reference Number"), + editable: false, + width: 140, + }, + ]; + } + + get_datatable(proposals_wrapper) { + if (!this.datatable) { + const datatable_options = { + columns: this.columns, + data: this.data, + dynamicRowHeight: true, + checkboxColumn: true, + inlineFilters: true, + }; + this.datatable = new frappe.DataTable( + proposals_wrapper.get(0), + datatable_options + ); + } else { + this.datatable.refresh(this.data, this.columns); + this.datatable.rowmanager.checkMap = []; + } + } + + make_dialog() { + const me = this; + me.selected_payment = null; + + const fields = [ + { + label: __("Action"), + fieldname: "action", + fieldtype: "Select", + options: `Match Against Voucher\nCreate Voucher\nUpdate Bank Transaction`, + default: "Match Against Voucher", + }, + { + fieldname: "column_break_4", + fieldtype: "Column Break", + }, + { + label: __("Document Type"), + fieldname: "document_type", + fieldtype: "Select", + options: `Payment Entry\nJournal Entry`, + default: "Payment Entry", + depends_on: "eval:doc.action=='Create Voucher'", + }, + { + fieldtype: "Section Break", + fieldname: "section_break_1", + label: __("Filters"), + depends_on: "eval:doc.action=='Match Against Voucher'", + }, + ]; + + frappe.call({ + method: "erpnext.accounts.doctype.bank_transaction.bank_transaction.get_doctypes_for_bank_reconciliation", + callback: (r) => { + $.each(r.message, (_i, entry) => { + if (_i % 3 == 0) { + fields.push({ + fieldtype: "Column Break", + }); + } + fields.push({ + fieldtype: "Check", + label: entry, + fieldname: frappe.scrub(entry), + onchange: () => this.update_options(), + }); + }); + + fields.push(...this.get_voucher_fields()); + + me.dialog = new frappe.ui.Dialog({ + title: __("Reconcile the Bank Transaction"), + fields: fields, + size: "large", + primary_action: (values) => + this.reconciliation_dialog_primary_action(values), + }); + } + }); + } + + get_voucher_fields() { + return [ + { + fieldtype: "Check", + label: "Show Only Exact Amount", + fieldname: "exact_match", + onchange: () => this.update_options(), + }, + { + fieldtype: "Section Break", + fieldname: "section_break_1", + label: __("Select Vouchers to Match"), + depends_on: "eval:doc.action=='Match Against Voucher'", + }, + { + fieldtype: "HTML", + fieldname: "payment_proposals", + }, + { + fieldtype: "HTML", + fieldname: "no_matching_vouchers", + options: __("
{0}
", [__("No Matching Vouchers Found")]) + }, + { + fieldtype: "Section Break", + fieldname: "details", + label: "Details", + depends_on: "eval:doc.action!='Match Against Voucher'", + }, + { + fieldname: "reference_number", + fieldtype: "Data", + label: "Reference Number", + mandatory_depends_on: "eval:doc.action=='Create Voucher'", + }, + { + default: "Today", + fieldname: "posting_date", + fieldtype: "Date", + label: "Posting Date", + reqd: 1, + depends_on: "eval:doc.action=='Create Voucher'", + }, + { + fieldname: "reference_date", + fieldtype: "Date", + label: "Cheque/Reference Date", + mandatory_depends_on: "eval:doc.action=='Create Voucher'", + depends_on: "eval:doc.action=='Create Voucher'", + reqd: 1, + }, + { + fieldname: "mode_of_payment", + fieldtype: "Link", + label: "Mode of Payment", + options: "Mode of Payment", + depends_on: "eval:doc.action=='Create Voucher'", + }, + { + fieldname: "edit_in_full_page", + fieldtype: "Button", + label: "Edit in Full Page", + click: () => { + this.edit_in_full_page(); + }, + depends_on: + "eval:doc.action=='Create Voucher'", + }, + { + fieldname: "column_break_7", + fieldtype: "Column Break", + }, + { + default: "Journal Entry Type", + fieldname: "journal_entry_type", + fieldtype: "Select", + label: "Journal Entry Type", + options: + "Journal Entry\nInter Company Journal Entry\nBank Entry\nCash Entry\nCredit Card Entry\nDebit Note\nCredit Note\nContra Entry\nExcise Entry\nWrite Off Entry\nOpening Entry\nDepreciation Entry\nExchange Rate Revaluation\nDeferred Revenue\nDeferred Expense", + depends_on: + "eval:doc.action=='Create Voucher' && doc.document_type=='Journal Entry'", + mandatory_depends_on: + "eval:doc.action=='Create Voucher' && doc.document_type=='Journal Entry'", + }, + { + fieldname: "second_account", + fieldtype: "Link", + label: "Account", + options: "Account", + depends_on: + "eval:doc.action=='Create Voucher' && doc.document_type=='Journal Entry'", + mandatory_depends_on: + "eval:doc.action=='Create Voucher' && doc.document_type=='Journal Entry'", + get_query: () => { + return { + filters: { + is_group: 0, + company: this.company, + }, + }; + }, + }, + { + fieldname: "party_type", + fieldtype: "Link", + label: "Party Type", + options: "DocType", + mandatory_depends_on: + "eval:doc.action=='Create Voucher' && doc.document_type=='Payment Entry'", + get_query: function () { + return { + filters: { + name: [ + "in", + Object.keys(frappe.boot.party_account_types), + ], + }, + }; + }, + }, + { + fieldname: "party", + fieldtype: "Dynamic Link", + label: "Party", + options: "party_type", + mandatory_depends_on: + "eval:doc.action=='Create Voucher' && doc.document_type=='Payment Entry'", + }, + { + fieldname: "project", + fieldtype: "Link", + label: "Project", + options: "Project", + depends_on: + "eval:doc.action=='Create Voucher' && doc.document_type=='Payment Entry'", + }, + { + fieldname: "cost_center", + fieldtype: "Link", + label: "Cost Center", + options: "Cost Center", + depends_on: + "eval:doc.action=='Create Voucher' && doc.document_type=='Payment Entry'", + }, + { + fieldtype: "Section Break", + fieldname: "details_section", + label: "Transaction Details", + collapsible: 1, + }, + { + fieldname: "deposit", + fieldtype: "Currency", + label: "Deposit", + read_only: 1, + }, + { + fieldname: "withdrawal", + fieldtype: "Currency", + label: "Withdrawal", + read_only: 1, + }, + { + fieldname: "description", + fieldtype: "Small Text", + label: "Description", + read_only: 1, + }, + { + fieldname: "column_break_17", + fieldtype: "Column Break", + read_only: 1, + }, + { + fieldname: "allocated_amount", + fieldtype: "Currency", + label: "Allocated Amount", + read_only: 1, + }, + + { + fieldname: "unallocated_amount", + fieldtype: "Currency", + label: "Unallocated Amount", + read_only: 1, + }, + ]; + } + + get_selected_attributes() { + let selected_attributes = []; + this.dialog.$wrapper.find(".checkbox input").each((i, col) => { + if ($(col).is(":checked")) { + selected_attributes.push($(col).attr("data-fieldname")); + } + }); + + return selected_attributes; + } + + update_options() { + let selected_attributes = this.get_selected_attributes(); + this.get_linked_vouchers(selected_attributes); + } + + reconciliation_dialog_primary_action(values) { + if (values.action == "Match Against Voucher") this.match(values); + if ( + values.action == "Create Voucher" && + values.document_type == "Payment Entry" + ) + this.add_payment_entry(values); + if ( + values.action == "Create Voucher" && + values.document_type == "Journal Entry" + ) + this.add_journal_entry(values); + else if (values.action == "Update Bank Transaction") + this.update_transaction(values); + } + + match() { + var selected_map = this.datatable.rowmanager.checkMap; + let rows = []; + selected_map.forEach((val, index) => { + if (val == 1) rows.push(this.datatable.datamanager.rows[index]); + }); + let vouchers = []; + rows.forEach((x) => { + vouchers.push({ + payment_doctype: x[2].content, + payment_name: x[3].content, + amount: x[5].content, + }); + }); + frappe.call({ + method: + "erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.reconcile_vouchers", + args: { + bank_transaction_name: this.bank_transaction.name, + vouchers: vouchers, + }, + callback: (response) => { + const alert_string = __("Bank Transaction {0} Matched", [this.bank_transaction.name]); + frappe.show_alert(alert_string); + this.update_dt_cards(response.message); + this.dialog.hide(); + }, + }); + } + + add_payment_entry(values) { + frappe.call({ + method: + "erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.create_payment_entry_bts", + args: { + bank_transaction_name: this.bank_transaction.name, + reference_number: values.reference_number, + reference_date: values.reference_date, + party_type: values.party_type, + party: values.party, + posting_date: values.posting_date, + mode_of_payment: values.mode_of_payment, + project: values.project, + cost_center: values.cost_center, + }, + callback: (response) => { + const alert_string = __("Bank Transaction {0} added as Payment Entry", [this.bank_transaction.name]); + frappe.show_alert(alert_string); + this.update_dt_cards(response.message); + this.dialog.hide(); + }, + }); + } + + add_journal_entry(values) { + frappe.call({ + method: + "erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.create_journal_entry_bts", + args: { + bank_transaction_name: this.bank_transaction.name, + reference_number: values.reference_number, + reference_date: values.reference_date, + party_type: values.party_type, + party: values.party, + posting_date: values.posting_date, + mode_of_payment: values.mode_of_payment, + entry_type: values.journal_entry_type, + second_account: values.second_account, + }, + callback: (response) => { + const alert_string = __("Bank Transaction {0} added as Journal Entry", [this.bank_transaction.name]); + frappe.show_alert(alert_string); + this.update_dt_cards(response.message); + this.dialog.hide(); + }, + }); + } + + update_transaction(values) { + frappe.call({ + method: + "erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.update_bank_transaction", + args: { + bank_transaction_name: this.bank_transaction.name, + reference_number: values.reference_number, + party_type: values.party_type, + party: values.party, + }, + callback: (response) => { + const alert_string = __("Bank Transaction {0} updated", [this.bank_transaction.name]); + frappe.show_alert(alert_string); + this.update_dt_cards(response.message); + this.dialog.hide(); + }, + }); + } + + edit_in_full_page() { + const values = this.dialog.get_values(true); + if (values.document_type == "Payment Entry") { + frappe.call({ + method: + "erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.create_payment_entry_bts", + args: { + bank_transaction_name: this.bank_transaction.name, + reference_number: values.reference_number, + reference_date: values.reference_date, + party_type: values.party_type, + party: values.party, + posting_date: values.posting_date, + mode_of_payment: values.mode_of_payment, + project: values.project, + cost_center: values.cost_center, + allow_edit: true + }, + callback: (r) => { + const doc = frappe.model.sync(r.message); + frappe.set_route("Form", doc[0].doctype, doc[0].name); + }, + }); + } else { + frappe.call({ + method: + "erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.create_journal_entry_bts", + args: { + bank_transaction_name: this.bank_transaction.name, + reference_number: values.reference_number, + reference_date: values.reference_date, + party_type: values.party_type, + party: values.party, + posting_date: values.posting_date, + mode_of_payment: values.mode_of_payment, + entry_type: values.journal_entry_type, + second_account: values.second_account, + allow_edit: true + }, + callback: (r) => { + var doc = frappe.model.sync(r.message); + frappe.set_route("Form", doc[0].doctype, doc[0].name); + }, + }); + } + } + + }; + get_linked_vouchers(document_types) { frappe.call({ method: From 8e7c8a648221bdd35b9ecde52a9b56d78b412206 Mon Sep 17 00:00:00 2001 From: sonali Date: Thu, 8 Dec 2022 17:23:08 +0530 Subject: [PATCH 03/25] Update bank_reconciliation_tool.json Adding fields in bank reconciliation tool --- .../bank_reconciliation_tool.json | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.json b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.json index f666101d3f..1d49c9de25 100644 --- a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.json +++ b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.json @@ -83,6 +83,24 @@ "fieldname": "no_bank_transactions", "fieldtype": "HTML" } + { + "depends_on": "eval:doc.filtered_by_reference_date", + "fieldname": "from_reference_date", + "fieldtype": "Date", + "label": "From Reference Date" + }, + { + "depends_on": "eval:doc.filtered_by_reference_date", + "fieldname": "to_reference_date", + "fieldtype": "Date", + "label": "To Reference Date" + }, + { + "default": "0", + "fieldname": "filtered_by_reference_date", + "fieldtype": "Check", + "label": "Filtered by Reference Date" + } ], "hide_toolbar": 1, "index_web_pages_for_search": 1, From 408c89df030998fe36df135570c9edd90a522996 Mon Sep 17 00:00:00 2001 From: sonali Date: Thu, 15 Dec 2022 18:09:57 +0530 Subject: [PATCH 04/25] Feat:Filter on Payment Entries and Journal Entries Applying filters on Payement entries and Journal Entries as per reference date and posting date --- .../bank_reconciliation_tool.py | 207 ++++++++---------- 1 file changed, 95 insertions(+), 112 deletions(-) diff --git a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py index 70962042f7..30cc56b488 100644 --- a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py +++ b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py @@ -533,66 +533,58 @@ def get_pe_matching_query(amount_condition, account_from_to, transaction): currency_field = "paid_to_account_currency as currency" else: currency_field = "paid_from_account_currency as currency" - if filtered_by_reference_date: - pe_data = f""" - SELECT - (CASE WHEN reference_no=%(reference_no)s THEN 1 ELSE 0 END - + CASE WHEN (party_type = %(party_type)s AND party = %(party)s ) THEN 1 ELSE 0 END - + 1 ) AS rank, - 'Payment Entry' as doctype, - name, - paid_amount, - reference_no, - reference_date, - party, - party_type, - posting_date, - {currency_field} - FROM - `tabPayment Entry` - WHERE - paid_amount {amount_condition} %(amount)s - AND docstatus = 1 - AND payment_type IN (%(payment_type)s, 'Internal Transfer') - AND ifnull(clearance_date, '') = "" - AND {account_from_to} = %(bank_account)s - AND reference_date >= '{from_reference_date}' - AND reference_date <= '{to_reference_date}' - - """ - else: - pe_data = f""" - SELECT - (CASE WHEN reference_no=%(reference_no)s THEN 1 ELSE 0 END - + CASE WHEN (party_type = %(party_type)s AND party = %(party)s ) THEN 1 ELSE 0 END - + 1 ) AS rank, - 'Payment Entry' as doctype, - name, - paid_amount, - reference_no, - reference_date, - party, - party_type, - posting_date, - {currency_field} - FROM - `tabPayment Entry` - WHERE - paid_amount {amount_condition} %(amount)s - AND docstatus = 1 - AND payment_type IN (%(payment_type)s, 'Internal Transfer') - AND ifnull(clearance_date, '') = "" - AND {account_from_to} = %(bank_account)s - AND posting_date >= '{from_date}' - AND posting_date <= '{to_date}' - - """ + cond_filtered_from_ref_date = "" + cond_filtered_to_ref_date = "" + cond_filtered_from_posting_date = "" + cond_filtered_to_posting_date = "" + from_ref_date ="" + to_ref_date ="" + from_post_date = "" + to_post_date = "" + if(filtered_by_reference_date): + cond_filtered_from_ref_date = " AND reference_date >=" + cond_filtered_to_ref_date = " AND reference_date <=" + from_ref_date = from_reference_date + to_ref_date = to_reference_date + elif(not filtered_by_reference_date): + cond_filtered_from_posting_date = " AND posting_date >=" + cond_filtered_to_posting_date = " AND posting_date <=" + from_post_date = from_date + to_post_date = to_date + + pe_data= f""" + SELECT + (CASE WHEN reference_no=%(reference_no)s THEN 1 ELSE 0 END + + CASE WHEN (party_type = %(party_type)s AND party = %(party)s ) THEN 1 ELSE 0 END + + 1 ) AS rank, + 'Payment Entry' as doctype, + name, + paid_amount, + reference_no, + reference_date, + party, + party_type, + posting_date, + {currency_field} + FROM + `tabPayment Entry` + WHERE + paid_amount {amount_condition} %(amount)s + AND docstatus = 1 + AND payment_type IN (%(payment_type)s, 'Internal Transfer') + AND ifnull(clearance_date, '') = "" + AND {account_from_to} = %(bank_account)s + AND reference_no = '{transaction.reference_number}' + {cond_filtered_from_ref_date} "{from_ref_date}" + {cond_filtered_to_ref_date} "{to_ref_date}" + {cond_filtered_from_posting_date} "{from_post_date}" + {cond_filtered_to_posting_date} "{to_post_date}" + """ return pe_data def get_je_matching_query(amount_condition, transaction): # get matching journal entry query - # We have mapping at the bank level # So one bank could have both types of bank accounts like asset and liability # So cr_or_dr should be judged only on basis of withdrawal and deposit and not account type @@ -606,65 +598,56 @@ def get_je_matching_query(amount_condition, transaction): "Bank Reconciliation Tool", "filtered_by_reference_date" ) cr_or_dr = "credit" if transaction.withdrawal > 0 else "debit" - if filtered_by_reference_date == 1: - je_data = f""" - SELECT - (CASE WHEN je.cheque_no=%(reference_no)s THEN 1 ELSE 0 END - + 1) AS rank , - 'Journal Entry' as doctype, - je.name, - jea.{cr_or_dr}_in_account_currency as paid_amount, - je.cheque_no as reference_no, - je.cheque_date as reference_date, - je.pay_to_recd_from as party, - jea.party_type, - je.posting_date, - jea.account_currency as currency - FROM - `tabJournal Entry Account` as jea - JOIN - `tabJournal Entry` as je - ON - jea.parent = je.name - WHERE - (je.clearance_date is null or je.clearance_date='0000-00-00') - AND jea.account = %(bank_account)s - AND jea.{cr_or_dr}_in_account_currency {amount_condition} %(amount)s - AND je.docstatus = 1 - AND je.cheque_date >= '{from_reference_date}' - AND je.cheque_date <= '{to_reference_date}' - """ - else: - je_data = f""" - SELECT - (CASE WHEN je.cheque_no=%(reference_no)s THEN 1 ELSE 0 END - + 1) AS rank , - 'Journal Entry' as doctype, - je.name, - jea.{cr_or_dr}_in_account_currency as paid_amount, - je.cheque_no as reference_no, - je.cheque_date as reference_date, - je.pay_to_recd_from as party, - jea.party_type, - je.posting_date, - jea.account_currency as currency - FROM - `tabJournal Entry Account` as jea - JOIN - `tabJournal Entry` as je - ON - jea.parent = je.name - WHERE - (je.clearance_date is null or je.clearance_date='0000-00-00') - AND jea.account = %(bank_account)s - AND jea.{cr_or_dr}_in_account_currency {amount_condition} %(amount)s - AND je.docstatus = 1 - AND je.posting_date >= '{from_date}' - AND je.posting_date <= '{to_date}' - """ + cond_filtered_from_ref_date = "" + cond_filtered_to_ref_date = "" + cond_filtered_from_posting_date = "" + cond_filtered_to_posting_date = "" + from_ref_date ="" + to_ref_date ="" + from_post_date = "" + to_post_date = "" + if(filtered_by_reference_date): + cond_filtered_from_ref_date = " AND je.cheque_date >=" + cond_filtered_to_ref_date = " AND je.cheque_date <=" + from_ref_date = from_reference_date + to_ref_date = to_reference_date + elif(not filtered_by_reference_date): + cond_filtered_from_posting_date = " AND je.posting_date>=" + cond_filtered_to_posting_date = " AND je.posting_date <=" + from_post_date = from_date + to_post_date = to_date + je_data = f""" + SELECT + (CASE WHEN je.cheque_no=%(reference_no)s THEN 1 ELSE 0 END + + 1) AS rank , + 'Journal Entry' as doctype, + je.name, + jea.{cr_or_dr}_in_account_currency as paid_amount, + je.cheque_no as reference_no, + je.cheque_date as reference_date, + je.pay_to_recd_from as party, + jea.party_type, + je.posting_date, + jea.account_currency as currency + FROM + `tabJournal Entry Account` as jea + JOIN + `tabJournal Entry` as je + ON + jea.parent = je.name + WHERE + (je.clearance_date is null or je.clearance_date='0000-00-00') + AND jea.account = %(bank_account)s + AND jea.{cr_or_dr}_in_account_currency {amount_condition} %(amount)s + AND je.docstatus = 1 + AND je.cheque_no = '{transaction.reference_number}' + {cond_filtered_from_ref_date} "{from_ref_date}" + {cond_filtered_to_ref_date} "{to_ref_date}" + {cond_filtered_from_posting_date} "{from_post_date}" + {cond_filtered_to_posting_date} "{to_post_date}" + """ return je_data - def get_si_matching_query(amount_condition): # get matchin sales invoice query return f""" From 05b6fce03d58d75df557f5dc5285da30b8baab38 Mon Sep 17 00:00:00 2001 From: sonali Date: Sat, 17 Dec 2022 17:15:28 +0530 Subject: [PATCH 05/25] feat:filters on bank reconciliation Added date filters on bank transactions, payment entries and journal entries and sorted list as per date in ascending order. --- .../bank_reconciliation_tool.js | 3 + .../bank_reconciliation_tool.py | 225 ++++++++++-------- erpnext/hooks.py | 4 +- .../data_table_manager.js | 9 +- .../dialog_manager.js | 64 ++--- 5 files changed, 179 insertions(+), 126 deletions(-) diff --git a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.js b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.js index 28e79b5d2c..3d2b54ce72 100644 --- a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.js +++ b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.js @@ -160,6 +160,9 @@ frappe.ui.form.on("Bank Reconciliation Tool", { ).$wrapper, bank_statement_from_date: frm.doc.bank_statement_from_date, bank_statement_to_date: frm.doc.bank_statement_to_date, + filtered_by_reference_date:frm.doc.filtered_by_reference_date, + from_reference_date:frm.doc.from_reference_date, + to_reference_date:frm.doc.to_reference_date, bank_statement_closing_balance: frm.doc.bank_statement_closing_balance, cards_manager: frm.cards_manager, diff --git a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py index 30cc56b488..44583c1777 100644 --- a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py +++ b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py @@ -25,8 +25,6 @@ class BankReconciliationTool(Document): @frappe.whitelist() def get_bank_transactions(bank_account, from_date=None, to_date=None): # returns bank transactions for a bank account - from_date = frappe.db.get_single_value("Bank Reconciliation Tool", "bank_statement_from_date") - to_date = frappe.db.get_single_value("Bank Reconciliation Tool", "bank_statement_to_date") filters = [] filters.append(["bank_account", "=", bank_account]) filters.append(["docstatus", "=", 1]) @@ -52,8 +50,8 @@ def get_bank_transactions(bank_account, from_date=None, to_date=None): "party", ], filters=filters, + order_by="date", ) - transactions = sorted(transactions, key=lambda x: x["date"]) if transactions else [] return transactions @@ -330,23 +328,58 @@ def reconcile_vouchers(bank_transaction_name, vouchers): @frappe.whitelist() -def get_linked_payments(bank_transaction_name, document_types=None): +def get_linked_payments( + bank_transaction_name, + document_types=None, + from_date=None, + to_date=None, + filtered_by_reference_date=None, + from_reference_date=None, + to_reference_date=None, +): # get all matching payments for a bank transaction transaction = frappe.get_doc("Bank Transaction", bank_transaction_name) bank_account = frappe.db.get_values( "Bank Account", transaction.bank_account, ["account", "company"], as_dict=True )[0] (account, company) = (bank_account.account, bank_account.company) - matching = check_matching(account, company, transaction, document_types) + matching = check_matching( + account, + company, + transaction, + document_types, + from_date, + to_date, + filtered_by_reference_date, + from_reference_date, + to_reference_date, + ) return matching -def check_matching(bank_account, company, transaction, document_types): +def check_matching( + bank_account, + company, + transaction, + document_types, + from_date, + to_date, + filtered_by_reference_date, + from_reference_date, + to_reference_date, +): # combine all types of vouchers - filtered_by_reference_date = frappe.db.get_single_value( - "Bank Reconciliation Tool", "filtered_by_reference_date" + subquery = get_queries( + bank_account, + company, + transaction, + document_types, + from_date, + to_date, + filtered_by_reference_date, + from_reference_date, + to_reference_date, ) - subquery = get_queries(bank_account, company, transaction, document_types) filters = { "amount": transaction.unallocated_amount, "payment_type": "Receive" if transaction.deposit > 0 else "Pay", @@ -367,19 +400,20 @@ def check_matching(bank_account, company, transaction, document_types): filters, ) ) - matching_vouchers_with_ref_no = tuple( - ele for ele in matching_vouchers if frappe.as_json(ele[5]) != "null" - ) - if filtered_by_reference_date: - matching_vouchers = ( - sorted(matching_vouchers_with_ref_no, key=lambda x: x[5]) if matching_vouchers else [] - ) - else: - matching_vouchers = sorted(matching_vouchers, key=lambda x: x[8]) if matching_vouchers else [] - return matching_vouchers + return sorted(matching_vouchers, key=lambda x: x[0], reverse=True) if matching_vouchers else [] -def get_queries(bank_account, company, transaction, document_types): +def get_queries( + bank_account, + company, + transaction, + document_types, + from_date, + to_date, + filtered_by_reference_date, + from_reference_date, + to_reference_date, +): # get queries to get matching vouchers amount_condition = "=" if "exact_match" in document_types else "<=" account_from_to = "paid_to" if transaction.deposit > 0 else "paid_from" @@ -395,6 +429,11 @@ def get_queries(bank_account, company, transaction, document_types): document_types, amount_condition, account_from_to, + from_date, + to_date, + filtered_by_reference_date, + from_reference_date, + to_reference_date, ) or [] ) @@ -403,15 +442,42 @@ def get_queries(bank_account, company, transaction, document_types): def get_matching_queries( - bank_account, company, transaction, document_types, amount_condition, account_from_to + bank_account, + company, + transaction, + document_types, + amount_condition, + account_from_to, + from_date, + to_date, + filtered_by_reference_date, + from_reference_date, + to_reference_date, ): queries = [] if "payment_entry" in document_types: - pe_amount_matching = get_pe_matching_query(amount_condition, account_from_to, transaction) + pe_amount_matching = get_pe_matching_query( + amount_condition, + account_from_to, + transaction, + from_date, + to_date, + filtered_by_reference_date, + from_reference_date, + to_reference_date, + ) queries.extend([pe_amount_matching]) if "journal_entry" in document_types: - je_amount_matching = get_je_matching_query(amount_condition, transaction) + je_amount_matching = get_je_matching_query( + amount_condition, + transaction, + from_date, + to_date, + filtered_by_reference_date, + from_reference_date, + to_reference_date, + ) queries.extend([je_amount_matching]) if transaction.deposit > 0 and "sales_invoice" in document_types: @@ -518,41 +584,27 @@ def get_lr_matching_query(bank_account, amount_condition, filters): return vouchers -def get_pe_matching_query(amount_condition, account_from_to, transaction): +def get_pe_matching_query( + amount_condition, + account_from_to, + transaction, + from_date, + to_date, + filtered_by_reference_date, + from_reference_date, + to_reference_date, +): # get matching payment entries query - from_date = frappe.db.get_single_value("Bank Reconciliation Tool", "bank_statement_from_date") - to_date = frappe.db.get_single_value("Bank Reconciliation Tool", "bank_statement_to_date") - from_reference_date = frappe.db.get_single_value( - "Bank Reconciliation Tool", "from_reference_date" - ) - to_reference_date = frappe.db.get_single_value("Bank Reconciliation Tool", "to_reference_date") - filtered_by_reference_date = frappe.db.get_single_value( - "Bank Reconciliation Tool", "filtered_by_reference_date" - ) if transaction.deposit > 0: currency_field = "paid_to_account_currency as currency" else: currency_field = "paid_from_account_currency as currency" - cond_filtered_from_ref_date = "" - cond_filtered_to_ref_date = "" - cond_filtered_from_posting_date = "" - cond_filtered_to_posting_date = "" - from_ref_date ="" - to_ref_date ="" - from_post_date = "" - to_post_date = "" - if(filtered_by_reference_date): - cond_filtered_from_ref_date = " AND reference_date >=" - cond_filtered_to_ref_date = " AND reference_date <=" - from_ref_date = from_reference_date - to_ref_date = to_reference_date - elif(not filtered_by_reference_date): - cond_filtered_from_posting_date = " AND posting_date >=" - cond_filtered_to_posting_date = " AND posting_date <=" - from_post_date = from_date - to_post_date = to_date - - pe_data= f""" + filter_by_date = f"AND posting_date between '{from_date}' and '{to_date}'" + order_by = " posting_date" + if filtered_by_reference_date == "1": + filter_by_date = f"AND reference_date between '{from_reference_date}' and '{to_reference_date}'" + order_by = " reference_date" + return f""" SELECT (CASE WHEN reference_no=%(reference_no)s THEN 1 ELSE 0 END + CASE WHEN (party_type = %(party_type)s AND party = %(party)s ) THEN 1 ELSE 0 END @@ -574,49 +626,33 @@ def get_pe_matching_query(amount_condition, account_from_to, transaction): AND payment_type IN (%(payment_type)s, 'Internal Transfer') AND ifnull(clearance_date, '') = "" AND {account_from_to} = %(bank_account)s - AND reference_no = '{transaction.reference_number}' - {cond_filtered_from_ref_date} "{from_ref_date}" - {cond_filtered_to_ref_date} "{to_ref_date}" - {cond_filtered_from_posting_date} "{from_post_date}" - {cond_filtered_to_posting_date} "{to_post_date}" - """ - return pe_data + {filter_by_date} + order by{order_by} + + """ -def get_je_matching_query(amount_condition, transaction): +def get_je_matching_query( + amount_condition, + transaction, + from_date, + to_date, + filtered_by_reference_date, + from_reference_date, + to_reference_date, +): # get matching journal entry query # We have mapping at the bank level # So one bank could have both types of bank accounts like asset and liability # So cr_or_dr should be judged only on basis of withdrawal and deposit and not account type - from_date = frappe.db.get_single_value("Bank Reconciliation Tool", "bank_statement_from_date") - to_date = frappe.db.get_single_value("Bank Reconciliation Tool", "bank_statement_to_date") - from_reference_date = frappe.db.get_single_value( - "Bank Reconciliation Tool", "from_reference_date" - ) - to_reference_date = frappe.db.get_single_value("Bank Reconciliation Tool", "to_reference_date") - filtered_by_reference_date = frappe.db.get_single_value( - "Bank Reconciliation Tool", "filtered_by_reference_date" - ) cr_or_dr = "credit" if transaction.withdrawal > 0 else "debit" - cond_filtered_from_ref_date = "" - cond_filtered_to_ref_date = "" - cond_filtered_from_posting_date = "" - cond_filtered_to_posting_date = "" - from_ref_date ="" - to_ref_date ="" - from_post_date = "" - to_post_date = "" - if(filtered_by_reference_date): - cond_filtered_from_ref_date = " AND je.cheque_date >=" - cond_filtered_to_ref_date = " AND je.cheque_date <=" - from_ref_date = from_reference_date - to_ref_date = to_reference_date - elif(not filtered_by_reference_date): - cond_filtered_from_posting_date = " AND je.posting_date>=" - cond_filtered_to_posting_date = " AND je.posting_date <=" - from_post_date = from_date - to_post_date = to_date - je_data = f""" + # filter_by_date = f"AND je.posting_date between '{from_date}' and '{to_date}'" + order_by = " je.posting_date" + if filtered_by_reference_date == "1": + filter_by_date = f"AND je.cheque_date between '{from_reference_date}' and '{to_reference_date}'" + order_by = " je.cheque_date" + + return f""" SELECT (CASE WHEN je.cheque_no=%(reference_no)s THEN 1 ELSE 0 END + 1) AS rank , @@ -640,13 +676,10 @@ def get_je_matching_query(amount_condition, transaction): AND jea.account = %(bank_account)s AND jea.{cr_or_dr}_in_account_currency {amount_condition} %(amount)s AND je.docstatus = 1 - AND je.cheque_no = '{transaction.reference_number}' - {cond_filtered_from_ref_date} "{from_ref_date}" - {cond_filtered_to_ref_date} "{to_ref_date}" - {cond_filtered_from_posting_date} "{from_post_date}" - {cond_filtered_to_posting_date} "{to_post_date}" - """ - return je_data + {filter_by_date} + order by {order_by} + """ + def get_si_matching_query(amount_condition): # get matchin sales invoice query diff --git a/erpnext/hooks.py b/erpnext/hooks.py index 1efc82e301..92601b3444 100644 --- a/erpnext/hooks.py +++ b/erpnext/hooks.py @@ -469,8 +469,8 @@ period_closing_doctypes = [ bank_reconciliation_doctypes = [ "Payment Entry", "Journal Entry", - # "Purchase Invoice", - # "Sales Invoice", + "Purchase Invoice", + "Sales Invoice", "Loan Repayment", "Loan Disbursement", ] diff --git a/erpnext/public/js/bank_reconciliation_tool/data_table_manager.js b/erpnext/public/js/bank_reconciliation_tool/data_table_manager.js index 9ef8ce6b63..e1914b4819 100644 --- a/erpnext/public/js/bank_reconciliation_tool/data_table_manager.js +++ b/erpnext/public/js/bank_reconciliation_tool/data_table_manager.js @@ -5,7 +5,12 @@ erpnext.accounts.bank_reconciliation.DataTableManager = class DataTableManager { Object.assign(this, opts); this.dialog_manager = new erpnext.accounts.bank_reconciliation.DialogManager( this.company, - this.bank_account + this.bank_account, + this.bank_statement_from_date, + this.bank_statement_to_date, + this.filtered_by_reference_date, + this.from_reference_date, + this.to_reference_date ); this.make_dt(); } @@ -17,6 +22,8 @@ erpnext.accounts.bank_reconciliation.DataTableManager = class DataTableManager { "erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.get_bank_transactions", args: { bank_account: this.bank_account, + from_date:this.bank_statement_from_date, + to_date:this.bank_statement_to_date }, callback: function (response) { me.format_data(response.message); diff --git a/erpnext/public/js/bank_reconciliation_tool/dialog_manager.js b/erpnext/public/js/bank_reconciliation_tool/dialog_manager.js index d7c0e61fc0..5d59497487 100644 --- a/erpnext/public/js/bank_reconciliation_tool/dialog_manager.js +++ b/erpnext/public/js/bank_reconciliation_tool/dialog_manager.js @@ -5,6 +5,11 @@ erpnext.accounts.bank_reconciliation.DialogManager = class DialogManager { this.bank_account = bank_account; this.company = company; this.make_dialog(); + this.bank_statement_from_date = bank_statement_from_date; + this.bank_statement_to_date = bank_statement_to_date; + this.filtered_by_reference_date = filtered_by_reference_date; + this.from_reference_date = from_reference_date; + this.to_reference_date = to_reference_date; } show_dialog(bank_transaction_name, update_dt_cards) { @@ -50,7 +55,7 @@ erpnext.accounts.bank_reconciliation.DialogManager = class DialogManager { this.company = company; this.make_dialog(); } - + show_dialog(bank_transaction_name, update_dt_cards) { this.bank_transaction_name = bank_transaction_name; this.update_dt_cards = update_dt_cards; @@ -86,7 +91,7 @@ erpnext.accounts.bank_reconciliation.DialogManager = class DialogManager { }, }); } - + get_linked_vouchers(document_types) { frappe.call({ method: @@ -94,12 +99,17 @@ erpnext.accounts.bank_reconciliation.DialogManager = class DialogManager { args: { bank_transaction_name: this.bank_transaction_name, document_types: document_types, + from_date: this.bank_statement_from_date, + to_date: this.bank_statement_to_date, + filtered_by_reference_date: this.filtered_by_reference_date, + from_reference_date:this.from_reference_date, + to_reference_date:this.to_reference_date }, - + callback: (result) => { const data = result.message; - - + + if (data && data.length > 0) { const proposals_wrapper = this.dialog.fields_dict.payment_proposals.$wrapper; proposals_wrapper.show(); @@ -123,13 +133,13 @@ erpnext.accounts.bank_reconciliation.DialogManager = class DialogManager { const proposals_wrapper = this.dialog.fields_dict.payment_proposals.$wrapper; proposals_wrapper.hide(); this.dialog.fields_dict.no_matching_vouchers.$wrapper.show(); - + } this.dialog.show(); }, }); } - + get_dt_columns() { this.columns = [ { @@ -162,7 +172,7 @@ erpnext.accounts.bank_reconciliation.DialogManager = class DialogManager { editable: false, width: 120, }, - + { name: __("Reference Number"), editable: false, @@ -170,7 +180,7 @@ erpnext.accounts.bank_reconciliation.DialogManager = class DialogManager { }, ]; } - + get_datatable(proposals_wrapper) { if (!this.datatable) { const datatable_options = { @@ -189,11 +199,11 @@ erpnext.accounts.bank_reconciliation.DialogManager = class DialogManager { this.datatable.rowmanager.checkMap = []; } } - + make_dialog() { const me = this; me.selected_payment = null; - + const fields = [ { label: __("Action"), @@ -221,7 +231,7 @@ erpnext.accounts.bank_reconciliation.DialogManager = class DialogManager { depends_on: "eval:doc.action=='Match Against Voucher'", }, ]; - + frappe.call({ method: "erpnext.accounts.doctype.bank_transaction.bank_transaction.get_doctypes_for_bank_reconciliation", callback: (r) => { @@ -238,9 +248,9 @@ erpnext.accounts.bank_reconciliation.DialogManager = class DialogManager { onchange: () => this.update_options(), }); }); - + fields.push(...this.get_voucher_fields()); - + me.dialog = new frappe.ui.Dialog({ title: __("Reconcile the Bank Transaction"), fields: fields, @@ -251,7 +261,7 @@ erpnext.accounts.bank_reconciliation.DialogManager = class DialogManager { } }); } - + get_voucher_fields() { return [ { @@ -431,7 +441,7 @@ erpnext.accounts.bank_reconciliation.DialogManager = class DialogManager { label: "Allocated Amount", read_only: 1, }, - + { fieldname: "unallocated_amount", fieldtype: "Currency", @@ -440,7 +450,7 @@ erpnext.accounts.bank_reconciliation.DialogManager = class DialogManager { }, ]; } - + get_selected_attributes() { let selected_attributes = []; this.dialog.$wrapper.find(".checkbox input").each((i, col) => { @@ -448,15 +458,15 @@ erpnext.accounts.bank_reconciliation.DialogManager = class DialogManager { selected_attributes.push($(col).attr("data-fieldname")); } }); - + return selected_attributes; } - + update_options() { let selected_attributes = this.get_selected_attributes(); this.get_linked_vouchers(selected_attributes); } - + reconciliation_dialog_primary_action(values) { if (values.action == "Match Against Voucher") this.match(values); if ( @@ -472,7 +482,7 @@ erpnext.accounts.bank_reconciliation.DialogManager = class DialogManager { else if (values.action == "Update Bank Transaction") this.update_transaction(values); } - + match() { var selected_map = this.datatable.rowmanager.checkMap; let rows = []; @@ -502,7 +512,7 @@ erpnext.accounts.bank_reconciliation.DialogManager = class DialogManager { }, }); } - + add_payment_entry(values) { frappe.call({ method: @@ -526,7 +536,7 @@ erpnext.accounts.bank_reconciliation.DialogManager = class DialogManager { }, }); } - + add_journal_entry(values) { frappe.call({ method: @@ -550,7 +560,7 @@ erpnext.accounts.bank_reconciliation.DialogManager = class DialogManager { }, }); } - + update_transaction(values) { frappe.call({ method: @@ -569,7 +579,7 @@ erpnext.accounts.bank_reconciliation.DialogManager = class DialogManager { }, }); } - + edit_in_full_page() { const values = this.dialog.get_values(true); if (values.document_type == "Payment Entry") { @@ -616,9 +626,9 @@ erpnext.accounts.bank_reconciliation.DialogManager = class DialogManager { }); } } - + }; - + get_linked_vouchers(document_types) { frappe.call({ method: From 645869e6ffec48b605cfdb68d763a7c9f21e3eec Mon Sep 17 00:00:00 2001 From: sonali Date: Wed, 21 Dec 2022 12:58:30 +0530 Subject: [PATCH 06/25] feat: added arguments of posting date and reference date --- .../dialog_manager.js | 590 +----------------- 1 file changed, 7 insertions(+), 583 deletions(-) diff --git a/erpnext/public/js/bank_reconciliation_tool/dialog_manager.js b/erpnext/public/js/bank_reconciliation_tool/dialog_manager.js index 5d59497487..31c70b5386 100644 --- a/erpnext/public/js/bank_reconciliation_tool/dialog_manager.js +++ b/erpnext/public/js/bank_reconciliation_tool/dialog_manager.js @@ -11,7 +11,6 @@ erpnext.accounts.bank_reconciliation.DialogManager = class DialogManager { this.from_reference_date = from_reference_date; this.to_reference_date = to_reference_date; } - show_dialog(bank_transaction_name, update_dt_cards) { this.bank_transaction_name = bank_transaction_name; this.update_dt_cards = update_dt_cards; @@ -47,588 +46,6 @@ erpnext.accounts.bank_reconciliation.DialogManager = class DialogManager { }, }); } - frappe.provide("erpnext.accounts.bank_reconciliation"); - - erpnext.accounts.bank_reconciliation.DialogManager = class DialogManager { - constructor(company, bank_account) { - this.bank_account = bank_account; - this.company = company; - this.make_dialog(); - } - - show_dialog(bank_transaction_name, update_dt_cards) { - this.bank_transaction_name = bank_transaction_name; - this.update_dt_cards = update_dt_cards; - frappe.call({ - method: "frappe.client.get_value", - args: { - doctype: "Bank Transaction", - filters: { name: this.bank_transaction_name }, - fieldname: [ - "date as reference_date", - "deposit", - "withdrawal", - "currency", - "description", - "name", - "bank_account", - "company", - "reference_number", - "party_type", - "party", - "unallocated_amount", - "allocated_amount", - ], - }, - callback: (r) => { - if (r.message) { - this.bank_transaction = r.message; - r.message.payment_entry = 1; - r.message.journal_entry = 1; - this.dialog.set_values(r.message); - this.dialog.show(); - } - }, - }); - } - - get_linked_vouchers(document_types) { - frappe.call({ - method: - "erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.get_linked_payments", - args: { - bank_transaction_name: this.bank_transaction_name, - document_types: document_types, - from_date: this.bank_statement_from_date, - to_date: this.bank_statement_to_date, - filtered_by_reference_date: this.filtered_by_reference_date, - from_reference_date:this.from_reference_date, - to_reference_date:this.to_reference_date - }, - - callback: (result) => { - const data = result.message; - - - if (data && data.length > 0) { - const proposals_wrapper = this.dialog.fields_dict.payment_proposals.$wrapper; - proposals_wrapper.show(); - this.dialog.fields_dict.no_matching_vouchers.$wrapper.hide(); - this.data = []; - data.forEach((row) => { - const reference_date = row[5] ? row[5] : row[8]; - this.data.push([ - row[1], - row[2], - reference_date, - row[8], - format_currency(row[3], row[9]), - row[6], - row[4], - ]); - }); - this.get_dt_columns(); - this.get_datatable(proposals_wrapper); - } else { - const proposals_wrapper = this.dialog.fields_dict.payment_proposals.$wrapper; - proposals_wrapper.hide(); - this.dialog.fields_dict.no_matching_vouchers.$wrapper.show(); - - } - this.dialog.show(); - }, - }); - } - - get_dt_columns() { - this.columns = [ - { - name: __("Document Type"), - editable: false, - width: 125, - }, - { - name: __("Document Name"), - editable: false, - width: 150, - }, - { - name: __("Reference Date"), - editable: false, - width: 120, - }, - { - name: "Posting Date", - editable: false, - width: 120, - }, - { - name: __("Amount"), - editable: false, - width: 100, - }, - { - name: __("Party"), - editable: false, - width: 120, - }, - - { - name: __("Reference Number"), - editable: false, - width: 140, - }, - ]; - } - - get_datatable(proposals_wrapper) { - if (!this.datatable) { - const datatable_options = { - columns: this.columns, - data: this.data, - dynamicRowHeight: true, - checkboxColumn: true, - inlineFilters: true, - }; - this.datatable = new frappe.DataTable( - proposals_wrapper.get(0), - datatable_options - ); - } else { - this.datatable.refresh(this.data, this.columns); - this.datatable.rowmanager.checkMap = []; - } - } - - make_dialog() { - const me = this; - me.selected_payment = null; - - const fields = [ - { - label: __("Action"), - fieldname: "action", - fieldtype: "Select", - options: `Match Against Voucher\nCreate Voucher\nUpdate Bank Transaction`, - default: "Match Against Voucher", - }, - { - fieldname: "column_break_4", - fieldtype: "Column Break", - }, - { - label: __("Document Type"), - fieldname: "document_type", - fieldtype: "Select", - options: `Payment Entry\nJournal Entry`, - default: "Payment Entry", - depends_on: "eval:doc.action=='Create Voucher'", - }, - { - fieldtype: "Section Break", - fieldname: "section_break_1", - label: __("Filters"), - depends_on: "eval:doc.action=='Match Against Voucher'", - }, - ]; - - frappe.call({ - method: "erpnext.accounts.doctype.bank_transaction.bank_transaction.get_doctypes_for_bank_reconciliation", - callback: (r) => { - $.each(r.message, (_i, entry) => { - if (_i % 3 == 0) { - fields.push({ - fieldtype: "Column Break", - }); - } - fields.push({ - fieldtype: "Check", - label: entry, - fieldname: frappe.scrub(entry), - onchange: () => this.update_options(), - }); - }); - - fields.push(...this.get_voucher_fields()); - - me.dialog = new frappe.ui.Dialog({ - title: __("Reconcile the Bank Transaction"), - fields: fields, - size: "large", - primary_action: (values) => - this.reconciliation_dialog_primary_action(values), - }); - } - }); - } - - get_voucher_fields() { - return [ - { - fieldtype: "Check", - label: "Show Only Exact Amount", - fieldname: "exact_match", - onchange: () => this.update_options(), - }, - { - fieldtype: "Section Break", - fieldname: "section_break_1", - label: __("Select Vouchers to Match"), - depends_on: "eval:doc.action=='Match Against Voucher'", - }, - { - fieldtype: "HTML", - fieldname: "payment_proposals", - }, - { - fieldtype: "HTML", - fieldname: "no_matching_vouchers", - options: __("
{0}
", [__("No Matching Vouchers Found")]) - }, - { - fieldtype: "Section Break", - fieldname: "details", - label: "Details", - depends_on: "eval:doc.action!='Match Against Voucher'", - }, - { - fieldname: "reference_number", - fieldtype: "Data", - label: "Reference Number", - mandatory_depends_on: "eval:doc.action=='Create Voucher'", - }, - { - default: "Today", - fieldname: "posting_date", - fieldtype: "Date", - label: "Posting Date", - reqd: 1, - depends_on: "eval:doc.action=='Create Voucher'", - }, - { - fieldname: "reference_date", - fieldtype: "Date", - label: "Cheque/Reference Date", - mandatory_depends_on: "eval:doc.action=='Create Voucher'", - depends_on: "eval:doc.action=='Create Voucher'", - reqd: 1, - }, - { - fieldname: "mode_of_payment", - fieldtype: "Link", - label: "Mode of Payment", - options: "Mode of Payment", - depends_on: "eval:doc.action=='Create Voucher'", - }, - { - fieldname: "edit_in_full_page", - fieldtype: "Button", - label: "Edit in Full Page", - click: () => { - this.edit_in_full_page(); - }, - depends_on: - "eval:doc.action=='Create Voucher'", - }, - { - fieldname: "column_break_7", - fieldtype: "Column Break", - }, - { - default: "Journal Entry Type", - fieldname: "journal_entry_type", - fieldtype: "Select", - label: "Journal Entry Type", - options: - "Journal Entry\nInter Company Journal Entry\nBank Entry\nCash Entry\nCredit Card Entry\nDebit Note\nCredit Note\nContra Entry\nExcise Entry\nWrite Off Entry\nOpening Entry\nDepreciation Entry\nExchange Rate Revaluation\nDeferred Revenue\nDeferred Expense", - depends_on: - "eval:doc.action=='Create Voucher' && doc.document_type=='Journal Entry'", - mandatory_depends_on: - "eval:doc.action=='Create Voucher' && doc.document_type=='Journal Entry'", - }, - { - fieldname: "second_account", - fieldtype: "Link", - label: "Account", - options: "Account", - depends_on: - "eval:doc.action=='Create Voucher' && doc.document_type=='Journal Entry'", - mandatory_depends_on: - "eval:doc.action=='Create Voucher' && doc.document_type=='Journal Entry'", - get_query: () => { - return { - filters: { - is_group: 0, - company: this.company, - }, - }; - }, - }, - { - fieldname: "party_type", - fieldtype: "Link", - label: "Party Type", - options: "DocType", - mandatory_depends_on: - "eval:doc.action=='Create Voucher' && doc.document_type=='Payment Entry'", - get_query: function () { - return { - filters: { - name: [ - "in", - Object.keys(frappe.boot.party_account_types), - ], - }, - }; - }, - }, - { - fieldname: "party", - fieldtype: "Dynamic Link", - label: "Party", - options: "party_type", - mandatory_depends_on: - "eval:doc.action=='Create Voucher' && doc.document_type=='Payment Entry'", - }, - { - fieldname: "project", - fieldtype: "Link", - label: "Project", - options: "Project", - depends_on: - "eval:doc.action=='Create Voucher' && doc.document_type=='Payment Entry'", - }, - { - fieldname: "cost_center", - fieldtype: "Link", - label: "Cost Center", - options: "Cost Center", - depends_on: - "eval:doc.action=='Create Voucher' && doc.document_type=='Payment Entry'", - }, - { - fieldtype: "Section Break", - fieldname: "details_section", - label: "Transaction Details", - collapsible: 1, - }, - { - fieldname: "deposit", - fieldtype: "Currency", - label: "Deposit", - read_only: 1, - }, - { - fieldname: "withdrawal", - fieldtype: "Currency", - label: "Withdrawal", - read_only: 1, - }, - { - fieldname: "description", - fieldtype: "Small Text", - label: "Description", - read_only: 1, - }, - { - fieldname: "column_break_17", - fieldtype: "Column Break", - read_only: 1, - }, - { - fieldname: "allocated_amount", - fieldtype: "Currency", - label: "Allocated Amount", - read_only: 1, - }, - - { - fieldname: "unallocated_amount", - fieldtype: "Currency", - label: "Unallocated Amount", - read_only: 1, - }, - ]; - } - - get_selected_attributes() { - let selected_attributes = []; - this.dialog.$wrapper.find(".checkbox input").each((i, col) => { - if ($(col).is(":checked")) { - selected_attributes.push($(col).attr("data-fieldname")); - } - }); - - return selected_attributes; - } - - update_options() { - let selected_attributes = this.get_selected_attributes(); - this.get_linked_vouchers(selected_attributes); - } - - reconciliation_dialog_primary_action(values) { - if (values.action == "Match Against Voucher") this.match(values); - if ( - values.action == "Create Voucher" && - values.document_type == "Payment Entry" - ) - this.add_payment_entry(values); - if ( - values.action == "Create Voucher" && - values.document_type == "Journal Entry" - ) - this.add_journal_entry(values); - else if (values.action == "Update Bank Transaction") - this.update_transaction(values); - } - - match() { - var selected_map = this.datatable.rowmanager.checkMap; - let rows = []; - selected_map.forEach((val, index) => { - if (val == 1) rows.push(this.datatable.datamanager.rows[index]); - }); - let vouchers = []; - rows.forEach((x) => { - vouchers.push({ - payment_doctype: x[2].content, - payment_name: x[3].content, - amount: x[5].content, - }); - }); - frappe.call({ - method: - "erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.reconcile_vouchers", - args: { - bank_transaction_name: this.bank_transaction.name, - vouchers: vouchers, - }, - callback: (response) => { - const alert_string = __("Bank Transaction {0} Matched", [this.bank_transaction.name]); - frappe.show_alert(alert_string); - this.update_dt_cards(response.message); - this.dialog.hide(); - }, - }); - } - - add_payment_entry(values) { - frappe.call({ - method: - "erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.create_payment_entry_bts", - args: { - bank_transaction_name: this.bank_transaction.name, - reference_number: values.reference_number, - reference_date: values.reference_date, - party_type: values.party_type, - party: values.party, - posting_date: values.posting_date, - mode_of_payment: values.mode_of_payment, - project: values.project, - cost_center: values.cost_center, - }, - callback: (response) => { - const alert_string = __("Bank Transaction {0} added as Payment Entry", [this.bank_transaction.name]); - frappe.show_alert(alert_string); - this.update_dt_cards(response.message); - this.dialog.hide(); - }, - }); - } - - add_journal_entry(values) { - frappe.call({ - method: - "erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.create_journal_entry_bts", - args: { - bank_transaction_name: this.bank_transaction.name, - reference_number: values.reference_number, - reference_date: values.reference_date, - party_type: values.party_type, - party: values.party, - posting_date: values.posting_date, - mode_of_payment: values.mode_of_payment, - entry_type: values.journal_entry_type, - second_account: values.second_account, - }, - callback: (response) => { - const alert_string = __("Bank Transaction {0} added as Journal Entry", [this.bank_transaction.name]); - frappe.show_alert(alert_string); - this.update_dt_cards(response.message); - this.dialog.hide(); - }, - }); - } - - update_transaction(values) { - frappe.call({ - method: - "erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.update_bank_transaction", - args: { - bank_transaction_name: this.bank_transaction.name, - reference_number: values.reference_number, - party_type: values.party_type, - party: values.party, - }, - callback: (response) => { - const alert_string = __("Bank Transaction {0} updated", [this.bank_transaction.name]); - frappe.show_alert(alert_string); - this.update_dt_cards(response.message); - this.dialog.hide(); - }, - }); - } - - edit_in_full_page() { - const values = this.dialog.get_values(true); - if (values.document_type == "Payment Entry") { - frappe.call({ - method: - "erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.create_payment_entry_bts", - args: { - bank_transaction_name: this.bank_transaction.name, - reference_number: values.reference_number, - reference_date: values.reference_date, - party_type: values.party_type, - party: values.party, - posting_date: values.posting_date, - mode_of_payment: values.mode_of_payment, - project: values.project, - cost_center: values.cost_center, - allow_edit: true - }, - callback: (r) => { - const doc = frappe.model.sync(r.message); - frappe.set_route("Form", doc[0].doctype, doc[0].name); - }, - }); - } else { - frappe.call({ - method: - "erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.create_journal_entry_bts", - args: { - bank_transaction_name: this.bank_transaction.name, - reference_number: values.reference_number, - reference_date: values.reference_date, - party_type: values.party_type, - party: values.party, - posting_date: values.posting_date, - mode_of_payment: values.mode_of_payment, - entry_type: values.journal_entry_type, - second_account: values.second_account, - allow_edit: true - }, - callback: (r) => { - var doc = frappe.model.sync(r.message); - frappe.set_route("Form", doc[0].doctype, doc[0].name); - }, - }); - } - } - - }; - get_linked_vouchers(document_types) { frappe.call({ method: @@ -636,6 +53,11 @@ erpnext.accounts.bank_reconciliation.DialogManager = class DialogManager { args: { bank_transaction_name: this.bank_transaction_name, document_types: document_types, + from_date: this.bank_statement_from_date, + to_date: this.bank_statement_to_date, + filtered_by_reference_date: this.filtered_by_reference_date, + from_reference_date:this.from_reference_date, + to_reference_date:this.to_reference_date }, callback: (result) => { @@ -1160,3 +582,5 @@ erpnext.accounts.bank_reconciliation.DialogManager = class DialogManager { } }; + + \ No newline at end of file From 6b5276398ef90a1a362ce709a92f47f4219f0134 Mon Sep 17 00:00:00 2001 From: sonali Date: Wed, 21 Dec 2022 13:32:16 +0530 Subject: [PATCH 07/25] fix: linters --- erpnext/public/js/bank_reconciliation_tool/dialog_manager.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/erpnext/public/js/bank_reconciliation_tool/dialog_manager.js b/erpnext/public/js/bank_reconciliation_tool/dialog_manager.js index 31c70b5386..693041f47b 100644 --- a/erpnext/public/js/bank_reconciliation_tool/dialog_manager.js +++ b/erpnext/public/js/bank_reconciliation_tool/dialog_manager.js @@ -581,6 +581,4 @@ erpnext.accounts.bank_reconciliation.DialogManager = class DialogManager { } } -}; - - \ No newline at end of file +}; \ No newline at end of file From 81e5f711725e42b25eb84f41790024798f6c535e Mon Sep 17 00:00:00 2001 From: sonali Date: Wed, 21 Dec 2022 14:02:54 +0530 Subject: [PATCH 08/25] fix: json issue --- .../bank_reconciliation_tool.json | 209 +++++++++--------- 1 file changed, 107 insertions(+), 102 deletions(-) diff --git a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.json b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.json index 1d49c9de25..a1269489ed 100644 --- a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.json +++ b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.json @@ -1,129 +1,134 @@ { - "actions": [], - "creation": "2020-12-02 10:13:02.148040", - "doctype": "DocType", - "editable_grid": 1, - "engine": "InnoDB", - "field_order": [ - "company", - "bank_account", - "column_break_1", - "bank_statement_from_date", - "bank_statement_to_date", - "column_break_2", - "account_opening_balance", - "bank_statement_closing_balance", - "section_break_1", - "reconciliation_tool_cards", - "reconciliation_tool_dt", - "no_bank_transactions" - ], - "fields": [ + "actions": [], + "creation": "2020-12-02 10:13:02.148040", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "company", + "bank_account", + "column_break_1", + "bank_statement_from_date", + "bank_statement_to_date", + "column_break_2", + "filtered_by_reference_date", + "from_reference_date", + "to_reference_date", + "account_opening_balance", + "bank_statement_closing_balance", + "section_break_1", + "reconciliation_tool_cards", + "reconciliation_tool_dt", + "no_bank_transactions" + ], + "fields": [ { - "fieldname": "company", - "fieldtype": "Link", - "label": "Company", - "options": "Company" + "fieldname": "company", + "fieldtype": "Link", + "label": "Company", + "options": "Company" }, { - "fieldname": "bank_account", - "fieldtype": "Link", - "label": "Bank Account", - "options": "Bank Account" + "fieldname": "bank_account", + "fieldtype": "Link", + "label": "Bank Account", + "options": "Bank Account" }, { - "fieldname": "column_break_1", - "fieldtype": "Column Break" + "fieldname": "column_break_1", + "fieldtype": "Column Break" }, { - "depends_on": "eval: doc.bank_account", - "fieldname": "bank_statement_from_date", - "fieldtype": "Date", - "label": "From Date" + "depends_on": "eval: doc.bank_account", + "fieldname": "bank_statement_from_date", + "fieldtype": "Date", + "label": "From Date" }, { - "depends_on": "eval: doc.bank_statement_from_date", - "fieldname": "bank_statement_to_date", - "fieldtype": "Date", - "label": "To Date" + "depends_on": "eval: doc.bank_statement_from_date", + "fieldname": "bank_statement_to_date", + "fieldtype": "Date", + "label": "To Date" }, { - "fieldname": "column_break_2", - "fieldtype": "Column Break" + "fieldname": "column_break_2", + "fieldtype": "Column Break" }, { - "depends_on": "eval: doc.bank_statement_from_date", - "fieldname": "account_opening_balance", - "fieldtype": "Currency", - "label": "Account Opening Balance", - "options": "Currency", - "read_only": 1 + "depends_on": "eval: doc.bank_statement_from_date", + "fieldname": "account_opening_balance", + "fieldtype": "Currency", + "label": "Account Opening Balance", + "options": "Currency", + "read_only": 1 }, { - "depends_on": "eval: doc.bank_statement_to_date", - "fieldname": "bank_statement_closing_balance", - "fieldtype": "Currency", - "label": "Closing Balance", - "options": "Currency" + "depends_on": "eval: doc.bank_statement_to_date", + "fieldname": "bank_statement_closing_balance", + "fieldtype": "Currency", + "label": "Closing Balance", + "options": "Currency" }, { - "fieldname": "section_break_1", - "fieldtype": "Section Break", - "label": "Reconcile" + "fieldname": "section_break_1", + "fieldtype": "Section Break", + "label": "Reconcile" }, { - "fieldname": "reconciliation_tool_cards", - "fieldtype": "HTML" + "fieldname": "reconciliation_tool_cards", + "fieldtype": "HTML" }, { - "fieldname": "reconciliation_tool_dt", - "fieldtype": "HTML" + "fieldname": "reconciliation_tool_dt", + "fieldtype": "HTML" }, { - "fieldname": "no_bank_transactions", - "fieldtype": "HTML" + "fieldname": "no_bank_transactions", + "fieldtype": "HTML", + "options": "
No Matching Bank Transactions Found
" + }, + { + "depends_on": "eval:doc.filtered_by_reference_date", + "fieldname": "from_reference_date", + "fieldtype": "Date", + "label": "From Reference Date" + }, + { + "depends_on": "eval:doc.filtered_by_reference_date", + "fieldname": "to_reference_date", + "fieldtype": "Date", + "label": "To Reference Date" + }, + { + "default": "0", + "fieldname": "filtered_by_reference_date", + "fieldtype": "Check", + "label": "Filtered by Reference Date" } + ], + "hide_toolbar": 1, + "index_web_pages_for_search": 1, + "issingle": 1, + "links": [], + "modified": "2022-12-03 15:40:05.330083", + "modified_by": "Administrator", + "module": "Accounts", + "name": "Bank Reconciliation Tool", + "owner": "Administrator", + "permissions": [ { - "depends_on": "eval:doc.filtered_by_reference_date", - "fieldname": "from_reference_date", - "fieldtype": "Date", - "label": "From Reference Date" - }, - { - "depends_on": "eval:doc.filtered_by_reference_date", - "fieldname": "to_reference_date", - "fieldtype": "Date", - "label": "To Reference Date" - }, - { - "default": "0", - "fieldname": "filtered_by_reference_date", - "fieldtype": "Check", - "label": "Filtered by Reference Date" - } - ], - "hide_toolbar": 1, - "index_web_pages_for_search": 1, - "issingle": 1, - "links": [], - "modified": "2021-04-21 11:13:49.831769", - "modified_by": "Administrator", - "module": "Accounts", - "name": "Bank Reconciliation Tool", - "owner": "Administrator", - "permissions": [ - { - "create": 1, - "delete": 1, - "email": 1, - "print": 1, - "read": 1, - "role": "System Manager", - "share": 1, - "write": 1 + "create": 1, + "delete": 1, + "email": 1, + "print": 1, + "read": 1, + "role": "System Manager", + "share": 1, + "write": 1 } - ], - "quick_entry": 1, - "sort_field": "modified", - "sort_order": "DESC" -} + ], + "quick_entry": 1, + "sort_field": "modified", + "sort_order": "DESC", + "states": [] + } \ No newline at end of file From 3aaa2f5326b13dbf390d86da9917fbb5def447ae Mon Sep 17 00:00:00 2001 From: sonali Date: Thu, 29 Dec 2022 12:05:22 +0530 Subject: [PATCH 09/25] fix: filtered as per reference date On bank reconciliation, transactions will be filtered as per date selected in 'from_date' and 'to_date' fields , In dialog, all the bank entries will be fetched as per the posting date selected and if filtered by reference date checkbox is tick then then there will be two fields 'from_reference_date' and 'to_reference_date' then all bank entries in dialog box came as per reference date, selected. And by default journal entry checkbox is tick. Also sorted the bank transactions and bank entries as per ascending order date wise. --- .../bank_reconciliation_tool/bank_reconciliation_tool.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py index 44583c1777..3d78ea300f 100644 --- a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py +++ b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py @@ -8,7 +8,7 @@ import frappe from frappe import _ from frappe.model.document import Document from frappe.query_builder.custom import ConstantColumn -from frappe.utils import flt +from frappe.utils import flt , cint from erpnext.accounts.doctype.bank_transaction.bank_transaction import get_paid_amount from erpnext.accounts.report.bank_reconciliation_statement.bank_reconciliation_statement import ( @@ -601,7 +601,7 @@ def get_pe_matching_query( currency_field = "paid_from_account_currency as currency" filter_by_date = f"AND posting_date between '{from_date}' and '{to_date}'" order_by = " posting_date" - if filtered_by_reference_date == "1": + if cint(filtered_by_reference_date): filter_by_date = f"AND reference_date between '{from_reference_date}' and '{to_reference_date}'" order_by = " reference_date" return f""" @@ -648,7 +648,7 @@ def get_je_matching_query( cr_or_dr = "credit" if transaction.withdrawal > 0 else "debit" # filter_by_date = f"AND je.posting_date between '{from_date}' and '{to_date}'" order_by = " je.posting_date" - if filtered_by_reference_date == "1": + if cint(filtered_by_reference_date): filter_by_date = f"AND je.cheque_date between '{from_reference_date}' and '{to_reference_date}'" order_by = " je.cheque_date" From e2614b8a21117f47c0661f1e0080ed5f95d2e4f8 Mon Sep 17 00:00:00 2001 From: sonali Date: Thu, 29 Dec 2022 12:21:45 +0530 Subject: [PATCH 10/25] fix: pre-commit --- .../bank_reconciliation_tool/bank_reconciliation_tool.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py index 3d78ea300f..19bccbc5bb 100644 --- a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py +++ b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py @@ -8,7 +8,7 @@ import frappe from frappe import _ from frappe.model.document import Document from frappe.query_builder.custom import ConstantColumn -from frappe.utils import flt , cint +from frappe.utils import cint, flt from erpnext.accounts.doctype.bank_transaction.bank_transaction import get_paid_amount from erpnext.accounts.report.bank_reconciliation_statement.bank_reconciliation_statement import ( From f1810803e1d874a22a49b5bd9b3351fbd2b5b843 Mon Sep 17 00:00:00 2001 From: sonali Date: Thu, 29 Dec 2022 13:07:06 +0530 Subject: [PATCH 11/25] fix: passing from_date and to_date filters in test cases passing from_date and to_date filters in test_linked_payments and test_debit_credit_output for unit testing --- .../doctype/bank_transaction/test_bank_transaction.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/erpnext/accounts/doctype/bank_transaction/test_bank_transaction.py b/erpnext/accounts/doctype/bank_transaction/test_bank_transaction.py index a5d0413799..3e28610744 100644 --- a/erpnext/accounts/doctype/bank_transaction/test_bank_transaction.py +++ b/erpnext/accounts/doctype/bank_transaction/test_bank_transaction.py @@ -6,7 +6,7 @@ import unittest import frappe from frappe.tests.utils import FrappeTestCase - +from frappe import utils from erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool import ( get_linked_payments, reconcile_vouchers, @@ -40,7 +40,7 @@ class TestBankTransaction(FrappeTestCase): "Bank Transaction", dict(description="Re 95282925234 FE/000002917 AT171513000281183046 Conrad Electronic"), ) - linked_payments = get_linked_payments(bank_transaction.name, ["payment_entry", "exact_match"]) + linked_payments = get_linked_payments(bank_transaction.name, ["payment_entry", "exact_match"],from_date= bank_transaction.date, to_date=utils.today()) self.assertTrue(linked_payments[0][6] == "Conrad Electronic") # This test validates a simple reconciliation leading to the clearance of the bank transaction and the payment @@ -81,7 +81,7 @@ class TestBankTransaction(FrappeTestCase): "Bank Transaction", dict(description="Auszahlung Karte MC/000002916 AUTOMAT 698769 K002 27.10. 14:07"), ) - linked_payments = get_linked_payments(bank_transaction.name, ["payment_entry", "exact_match"]) + linked_payments = get_linked_payments(bank_transaction.name, ["payment_entry", "exact_match"],from_date= bank_transaction.date, to_date=utils.today()) self.assertTrue(linked_payments[0][3]) # Check error if already reconciled From 35c29e02267eafade500bdb91fb67a53ec554641 Mon Sep 17 00:00:00 2001 From: sonali Date: Thu, 29 Dec 2022 13:45:15 +0530 Subject: [PATCH 12/25] fix: pre-commit --- .../bank_transaction/test_bank_transaction.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/erpnext/accounts/doctype/bank_transaction/test_bank_transaction.py b/erpnext/accounts/doctype/bank_transaction/test_bank_transaction.py index 3e28610744..55dcb5a099 100644 --- a/erpnext/accounts/doctype/bank_transaction/test_bank_transaction.py +++ b/erpnext/accounts/doctype/bank_transaction/test_bank_transaction.py @@ -5,8 +5,9 @@ import json import unittest import frappe -from frappe.tests.utils import FrappeTestCase from frappe import utils +from frappe.tests.utils import FrappeTestCase + from erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool import ( get_linked_payments, reconcile_vouchers, @@ -40,7 +41,12 @@ class TestBankTransaction(FrappeTestCase): "Bank Transaction", dict(description="Re 95282925234 FE/000002917 AT171513000281183046 Conrad Electronic"), ) - linked_payments = get_linked_payments(bank_transaction.name, ["payment_entry", "exact_match"],from_date= bank_transaction.date, to_date=utils.today()) + linked_payments = get_linked_payments( + bank_transaction.name, + ["payment_entry", "exact_match"], + from_date=bank_transaction.date, + to_date=utils.today(), + ) self.assertTrue(linked_payments[0][6] == "Conrad Electronic") # This test validates a simple reconciliation leading to the clearance of the bank transaction and the payment @@ -81,7 +87,12 @@ class TestBankTransaction(FrappeTestCase): "Bank Transaction", dict(description="Auszahlung Karte MC/000002916 AUTOMAT 698769 K002 27.10. 14:07"), ) - linked_payments = get_linked_payments(bank_transaction.name, ["payment_entry", "exact_match"],from_date= bank_transaction.date, to_date=utils.today()) + linked_payments = get_linked_payments( + bank_transaction.name, + ["payment_entry", "exact_match"], + from_date=bank_transaction.date, + to_date=utils.today(), + ) self.assertTrue(linked_payments[0][3]) # Check error if already reconciled @@ -442,4 +453,4 @@ def create_loan_and_repayment(): 500, ) repayment_entry.submit() - return repayment_entry + return repayment_entry \ No newline at end of file From c764f14f53e4b6d87263681be9786166cd7998f9 Mon Sep 17 00:00:00 2001 From: sonali Date: Thu, 29 Dec 2022 13:58:06 +0530 Subject: [PATCH 13/25] fix: pre-commit --- .../accounts/doctype/bank_transaction/test_bank_transaction.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/bank_transaction/test_bank_transaction.py b/erpnext/accounts/doctype/bank_transaction/test_bank_transaction.py index 55dcb5a099..f900e0775c 100644 --- a/erpnext/accounts/doctype/bank_transaction/test_bank_transaction.py +++ b/erpnext/accounts/doctype/bank_transaction/test_bank_transaction.py @@ -453,4 +453,4 @@ def create_loan_and_repayment(): 500, ) repayment_entry.submit() - return repayment_entry \ No newline at end of file + return repayment_entry From d65243eb65fe53d5f5fad0bcb9ffeb1fce7e727a Mon Sep 17 00:00:00 2001 From: sonali Date: Thu, 29 Dec 2022 16:12:25 +0530 Subject: [PATCH 14/25] feat: consolidated auto bank reconciliation Added a button of Auto Reconcile, to reconcile the bank entries as per the matching reference number with the bank transaction and count of transactions reconciled message will be pop up on clicking the auto reconcile button. --- .../bank_reconciliation_tool.js | 18 ++++ .../bank_reconciliation_tool.py | 87 ++++++++++++++++++- 2 files changed, 103 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.js b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.js index 3d2b54ce72..a1dca06d1e 100644 --- a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.js +++ b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.js @@ -25,6 +25,24 @@ frappe.ui.form.on("Bank Reconciliation Tool", { frappe.require("bank-reconciliation-tool.bundle.js", () => frm.trigger("make_reconciliation_tool") ); + cur_frm.add_custom_button(__('Auto Reconcile'), function(){ + frappe.call({ + method:"erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.auto_reconcile_vouchers", + args: { + bank_account:frm.doc.bank_account, + from_date: frm.doc.bank_statement_from_date, + to_date: frm.doc.bank_statement_to_date, + filtered_by_reference_date:frm.doc.filtered_by_reference_date, + from_reference_date:frm.doc.from_reference_date, + to_reference_date:frm.doc.to_reference_date, + }, + callback: function (r) { + } + }) + + + } + ), frm.upload_statement_button = frm.page.set_secondary_action( __("Upload Bank Statement"), () => diff --git a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py index 19bccbc5bb..5d8d584829 100644 --- a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py +++ b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py @@ -266,6 +266,82 @@ def create_payment_entry_bts( return reconcile_vouchers(bank_transaction.name, vouchers) +@frappe.whitelist() +def auto_reconcile_vouchers( + bank_account, + from_date=None, + to_date=None, + filtered_by_reference_date=None, + from_reference_date=None, + to_reference_date=None, +): + frappe.flags.auto_reconcile_vouchers = True + document_types = ["payment_entry", "journal_entry"] + bank_transactions = get_bank_transactions(bank_account) + matched_transaction = [] + for transaction in bank_transactions: + linked_payments = get_linked_payments( + transaction.name, + document_types, + from_date, + to_date, + filtered_by_reference_date, + from_reference_date, + to_reference_date, + ) + vouchers = [] + for r in linked_payments: + vouchers.append( + { + "payment_doctype": r[1], + "payment_name": r[2], + "amount": r[4], + } + ) + # vouchers = frappe.as_json(voucherss) + # vouchers = json.loads(voucherss) + transaction = frappe.get_doc("Bank Transaction", transaction.name) + account = frappe.db.get_value("Bank Account", transaction.bank_account, "account") + matched_trans = 0 + for voucher in vouchers: + gl_entry = frappe.db.get_value( + "GL Entry", + dict( + account=account, voucher_type=voucher["payment_doctype"], voucher_no=voucher["payment_name"] + ), + ["credit", "debit"], + as_dict=1, + ) + gl_amount, transaction_amount = ( + (gl_entry.credit, transaction.deposit) + if gl_entry.credit > 0 + else (gl_entry.debit, transaction.withdrawal) + ) + allocated_amount = gl_amount if gl_amount >= transaction_amount else transaction_amount + transaction.append( + "payment_entries", + { + "payment_document": voucher["payment_doctype"], + "payment_entry": voucher["payment_name"], + "allocated_amount": allocated_amount, + }, + ) + matched_transaction.append(str(transaction.name)) + transaction.save() + transaction.update_allocations() + matched_transaction_len = len(set(matched_transaction)) + if matched_transaction_len == 0: + frappe.msgprint(_("There is no any matched reference number for reconciliation")) + elif matched_transaction_len == 1: + frappe.msgprint(_(f"{matched_transaction_len} transaction is reconcilied")) + else: + frappe.msgprint(_(f"{matched_transaction_len} transactions are reconcilied")) + + frappe.flags.auto_reconcile_vouchers = False + + return frappe.get_doc("Bank Transaction", transaction.name) + + @frappe.whitelist() def reconcile_vouchers(bank_transaction_name, vouchers): # updated clear date of all the vouchers based on the bank transaction @@ -601,9 +677,12 @@ def get_pe_matching_query( currency_field = "paid_from_account_currency as currency" filter_by_date = f"AND posting_date between '{from_date}' and '{to_date}'" order_by = " posting_date" + filter_by_reference_no = "" if cint(filtered_by_reference_date): filter_by_date = f"AND reference_date between '{from_reference_date}' and '{to_reference_date}'" order_by = " reference_date" + if frappe.flags.auto_reconcile_vouchers == True: + filter_by_reference_no = f"AND reference_no = '{transaction.reference_number}'" return f""" SELECT (CASE WHEN reference_no=%(reference_no)s THEN 1 ELSE 0 END @@ -627,6 +706,7 @@ def get_pe_matching_query( AND ifnull(clearance_date, '') = "" AND {account_from_to} = %(bank_account)s {filter_by_date} + {filter_by_reference_no} order by{order_by} """ @@ -646,12 +726,14 @@ def get_je_matching_query( # So one bank could have both types of bank accounts like asset and liability # So cr_or_dr should be judged only on basis of withdrawal and deposit and not account type cr_or_dr = "credit" if transaction.withdrawal > 0 else "debit" - # filter_by_date = f"AND je.posting_date between '{from_date}' and '{to_date}'" + filter_by_date = f"AND je.posting_date between '{from_date}' and '{to_date}'" order_by = " je.posting_date" + filter_by_reference_no = "" if cint(filtered_by_reference_date): filter_by_date = f"AND je.cheque_date between '{from_reference_date}' and '{to_reference_date}'" order_by = " je.cheque_date" - + if frappe.flags.auto_reconcile_vouchers == True: + filter_by_reference_no = f"AND je.cheque_no = '{transaction.reference_number}'" return f""" SELECT (CASE WHEN je.cheque_no=%(reference_no)s THEN 1 ELSE 0 END @@ -677,6 +759,7 @@ def get_je_matching_query( AND jea.{cr_or_dr}_in_account_currency {amount_condition} %(amount)s AND je.docstatus = 1 {filter_by_date} + {filter_by_reference_no} order by {order_by} """ From 12822f7c36fd8a3f5aeea146b0d5e7be46f14a47 Mon Sep 17 00:00:00 2001 From: sonali Date: Fri, 30 Dec 2022 14:06:19 +0530 Subject: [PATCH 15/25] fix: data format --- .../bank_reconciliation_tool/bank_reconciliation_tool.js | 2 +- .../bank_reconciliation_tool/bank_reconciliation_tool.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.js b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.js index a1dca06d1e..f142549810 100644 --- a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.js +++ b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.js @@ -25,7 +25,7 @@ frappe.ui.form.on("Bank Reconciliation Tool", { frappe.require("bank-reconciliation-tool.bundle.js", () => frm.trigger("make_reconciliation_tool") ); - cur_frm.add_custom_button(__('Auto Reconcile'), function(){ + frm.add_custom_button(__('Auto Reconcile'), function(){ frappe.call({ method:"erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.auto_reconcile_vouchers", args: { diff --git a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py index 5d8d584829..f71855a872 100644 --- a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py +++ b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py @@ -333,9 +333,9 @@ def auto_reconcile_vouchers( if matched_transaction_len == 0: frappe.msgprint(_("There is no any matched reference number for reconciliation")) elif matched_transaction_len == 1: - frappe.msgprint(_(f"{matched_transaction_len} transaction is reconcilied")) + frappe.msgprint(_("{0} transaction is reconcilied").format(matched_transaction_len)) else: - frappe.msgprint(_(f"{matched_transaction_len} transactions are reconcilied")) + frappe.msgprint(_("{0} transactions are reconcilied").format(matched_transaction_len)) frappe.flags.auto_reconcile_vouchers = False From 917b2190aa25fff735ea3442cee797112147ccb1 Mon Sep 17 00:00:00 2001 From: sonali Date: Mon, 9 Jan 2023 20:07:24 +0530 Subject: [PATCH 16/25] fix: remove comments --- .../bank_reconciliation_tool.js | 18 +++++++++--------- .../bank_reconciliation_tool.py | 4 +--- .../data_table_manager.js | 4 ++-- 3 files changed, 12 insertions(+), 14 deletions(-) diff --git a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.js b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.js index f142549810..8e4214f202 100644 --- a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.js +++ b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.js @@ -25,16 +25,16 @@ frappe.ui.form.on("Bank Reconciliation Tool", { frappe.require("bank-reconciliation-tool.bundle.js", () => frm.trigger("make_reconciliation_tool") ); - frm.add_custom_button(__('Auto Reconcile'), function(){ + frm.add_custom_button(__('Auto Reconcile'), function() { frappe.call({ - method:"erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.auto_reconcile_vouchers", + method: "erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.auto_reconcile_vouchers", args: { - bank_account:frm.doc.bank_account, + bank_account: frm.doc.bank_account, from_date: frm.doc.bank_statement_from_date, to_date: frm.doc.bank_statement_to_date, - filtered_by_reference_date:frm.doc.filtered_by_reference_date, - from_reference_date:frm.doc.from_reference_date, - to_reference_date:frm.doc.to_reference_date, + filtered_by_reference_date: frm.doc.filtered_by_reference_date, + from_reference_date: frm.doc.from_reference_date, + to_reference_date: frm.doc.to_reference_date, }, callback: function (r) { } @@ -178,9 +178,9 @@ frappe.ui.form.on("Bank Reconciliation Tool", { ).$wrapper, bank_statement_from_date: frm.doc.bank_statement_from_date, bank_statement_to_date: frm.doc.bank_statement_to_date, - filtered_by_reference_date:frm.doc.filtered_by_reference_date, - from_reference_date:frm.doc.from_reference_date, - to_reference_date:frm.doc.to_reference_date, + filtered_by_reference_date: frm.doc.filtered_by_reference_date, + from_reference_date: frm.doc.from_reference_date, + to_reference_date: frm.doc.to_reference_date, bank_statement_closing_balance: frm.doc.bank_statement_closing_balance, cards_manager: frm.cards_manager, diff --git a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py index f71855a872..053641d310 100644 --- a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py +++ b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py @@ -298,8 +298,6 @@ def auto_reconcile_vouchers( "amount": r[4], } ) - # vouchers = frappe.as_json(voucherss) - # vouchers = json.loads(voucherss) transaction = frappe.get_doc("Bank Transaction", transaction.name) account = frappe.db.get_value("Bank Account", transaction.bank_account, "account") matched_trans = 0 @@ -331,7 +329,7 @@ def auto_reconcile_vouchers( transaction.update_allocations() matched_transaction_len = len(set(matched_transaction)) if matched_transaction_len == 0: - frappe.msgprint(_("There is no any matched reference number for reconciliation")) + frappe.msgprint(_("No matching references found for auto reconciliation")) elif matched_transaction_len == 1: frappe.msgprint(_("{0} transaction is reconcilied").format(matched_transaction_len)) else: diff --git a/erpnext/public/js/bank_reconciliation_tool/data_table_manager.js b/erpnext/public/js/bank_reconciliation_tool/data_table_manager.js index e1914b4819..532f6a9f50 100644 --- a/erpnext/public/js/bank_reconciliation_tool/data_table_manager.js +++ b/erpnext/public/js/bank_reconciliation_tool/data_table_manager.js @@ -22,8 +22,8 @@ erpnext.accounts.bank_reconciliation.DataTableManager = class DataTableManager { "erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.get_bank_transactions", args: { bank_account: this.bank_account, - from_date:this.bank_statement_from_date, - to_date:this.bank_statement_to_date + from_date: this.bank_statement_from_date, + to_date: this.bank_statement_to_date }, callback: function (response) { me.format_data(response.message); From be05aea101fe34de22bd3ff14b71daa7fcf5af29 Mon Sep 17 00:00:00 2001 From: Smit Vora Date: Wed, 11 Jan 2023 05:21:13 +0000 Subject: [PATCH 17/25] fix: better comparision of difference value between stock and account --- .../stock_and_account_value_comparison.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/stock/report/stock_and_account_value_comparison/stock_and_account_value_comparison.py b/erpnext/stock/report/stock_and_account_value_comparison/stock_and_account_value_comparison.py index 99f820ecac..106e877c4c 100644 --- a/erpnext/stock/report/stock_and_account_value_comparison/stock_and_account_value_comparison.py +++ b/erpnext/stock/report/stock_and_account_value_comparison/stock_and_account_value_comparison.py @@ -41,7 +41,7 @@ def get_data(report_filters): key = (d.voucher_type, d.voucher_no) gl_data = voucher_wise_gl_data.get(key) or {} d.account_value = gl_data.get("account_value", 0) - d.difference_value = abs(d.stock_value - d.account_value) + d.difference_value = d.stock_value - d.account_value if abs(d.difference_value) > 0.1: data.append(d) From 434aa594d57b986d078fb98025eda65f75b65e26 Mon Sep 17 00:00:00 2001 From: s-aga-r Date: Sun, 8 Jan 2023 11:49:40 +0530 Subject: [PATCH 18/25] fix: `ZeroDivisionError: float division by zero` in SCR --- .../doctype/subcontracting_receipt/subcontracting_receipt.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py index bce53608be..4436c1f1e1 100644 --- a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py +++ b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py @@ -157,7 +157,7 @@ class SubcontractingReceipt(SubcontractingController): total_qty = total_amount = 0 for item in self.items: - if item.name in rm_supp_cost: + if item.qty and item.name in rm_supp_cost: item.rm_supp_cost = rm_supp_cost[item.name] item.rm_cost_per_qty = item.rm_supp_cost / item.qty rm_supp_cost.pop(item.name) From 6878f40d1df268fd179d7c5558e858387b27ae0a Mon Sep 17 00:00:00 2001 From: s-aga-r Date: Sun, 8 Jan 2023 12:01:58 +0530 Subject: [PATCH 19/25] chore: add row-index in error msgs --- erpnext/controllers/subcontracting_controller.py | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/erpnext/controllers/subcontracting_controller.py b/erpnext/controllers/subcontracting_controller.py index 335d92f43f..a588847ad5 100644 --- a/erpnext/controllers/subcontracting_controller.py +++ b/erpnext/controllers/subcontracting_controller.py @@ -74,24 +74,19 @@ class SubcontractingController(StockController): ) if not is_stock_item: - msg = f"Item {item.item_name} must be a stock item." - frappe.throw(_(msg)) + frappe.throw(_(f"Row {item.idx}: Item {item.item_name} must be a stock item.")) if not is_sub_contracted_item: - msg = f"Item {item.item_name} must be a subcontracted item." - frappe.throw(_(msg)) + frappe.throw(_(f"Row {item.idx}: Item {item.item_name} must be a subcontracted item.")) if item.bom: bom = frappe.get_doc("BOM", item.bom) if not bom.is_active: - msg = f"Please select an active BOM for Item {item.item_name}." - frappe.throw(_(msg)) + frappe.throw(_(f"Row {item.idx}: Please select an active BOM for Item {item.item_name}.")) if bom.item != item.item_code: - msg = f"Please select an valid BOM for Item {item.item_name}." - frappe.throw(_(msg)) + frappe.throw(_(f"Row {item.idx}: Please select an valid BOM for Item {item.item_name}.")) else: - msg = f"Please select a BOM for Item {item.item_name}." - frappe.throw(_(msg)) + frappe.throw(_(f"Row {item.idx}: Please select a BOM for Item {item.item_name}.")) def __get_data_before_save(self): item_dict = {} From a0e2a93f3f502c29cb161736ef091a4e98c3dd53 Mon Sep 17 00:00:00 2001 From: s-aga-r Date: Thu, 12 Jan 2023 12:09:28 +0530 Subject: [PATCH 20/25] chore: update error msgs for Subcontracted PO --- .../buying/doctype/purchase_order/purchase_order.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py index 5a4168a573..2415aec8cb 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.py +++ b/erpnext/buying/doctype/purchase_order/purchase_order.py @@ -219,20 +219,16 @@ class PurchaseOrder(BuyingController): else: if not frappe.get_value("Item", item.fg_item, "is_sub_contracted_item"): frappe.throw( - _( - "Row #{0}: Finished Good Item {1} must be a sub-contracted item for service item {2}" - ).format(item.idx, item.fg_item, item.item_code) + _("Row #{0}: Finished Good Item {1} must be a sub-contracted item").format( + item.idx, item.fg_item + ) ) elif not frappe.get_value("Item", item.fg_item, "default_bom"): frappe.throw( _("Row #{0}: Default BOM not found for FG Item {1}").format(item.idx, item.fg_item) ) if not item.fg_item_qty: - frappe.throw( - _("Row #{0}: Finished Good Item Qty is not specified for service item {0}").format( - item.idx, item.item_code - ) - ) + frappe.throw(_("Row #{0}: Finished Good Item Qty can not be zero").format(item.idx)) else: for item in self.items: item.set("fg_item", None) From f028bd6e69a571d0053f124334a0021904a7f365 Mon Sep 17 00:00:00 2001 From: s-aga-r Date: Thu, 12 Jan 2023 12:23:40 +0530 Subject: [PATCH 21/25] fix: validate accepted and rejected qty in SCR Item --- .../subcontracting_receipt/subcontracting_receipt.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py index 4436c1f1e1..dd4ae04c16 100644 --- a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py +++ b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py @@ -57,6 +57,7 @@ class SubcontractingReceipt(SubcontractingController): def before_validate(self): super(SubcontractingReceipt, self).before_validate() + self.validate_items_qty() self.set_items_bom() self.set_items_cost_center() self.set_items_expense_account() @@ -194,6 +195,13 @@ class SubcontractingReceipt(SubcontractingController): ).format(item.idx) ) + def validate_items_qty(self): + for item in self.items: + if not (item.qty or item.rejected_qty): + frappe.throw( + _(f"Row {item.idx}: Accepted Qty and Rejected Qty can't be zero at the same time.") + ) + def set_items_bom(self): if self.is_return: for item in self.items: From 391f42db0438fafb9f5b6200d11e012fdcd2555e Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Thu, 12 Jan 2023 13:16:05 +0530 Subject: [PATCH 22/25] fix: Updating SO throws ordered_qty not allowed to change after submission --- erpnext/selling/doctype/sales_order_item/sales_order_item.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/erpnext/selling/doctype/sales_order_item/sales_order_item.json b/erpnext/selling/doctype/sales_order_item/sales_order_item.json index d0dabad5c9..134b5eafd0 100644 --- a/erpnext/selling/doctype/sales_order_item/sales_order_item.json +++ b/erpnext/selling/doctype/sales_order_item/sales_order_item.json @@ -638,6 +638,7 @@ "width": "70px" }, { + "allow_on_submit": 1, "fieldname": "ordered_qty", "fieldtype": "Float", "label": "Ordered Qty", @@ -864,7 +865,7 @@ "idx": 1, "istable": 1, "links": [], - "modified": "2022-12-25 02:51:10.247569", + "modified": "2023-01-12 13:13:28.691585", "modified_by": "Administrator", "module": "Selling", "name": "Sales Order Item", From b26e96cdf40d4306faa158ad74644c5c2abce8c7 Mon Sep 17 00:00:00 2001 From: s-aga-r Date: Thu, 12 Jan 2023 13:41:53 +0530 Subject: [PATCH 23/25] chore: linter --- erpnext/controllers/subcontracting_controller.py | 16 +++++++++++----- .../subcontracting_receipt.py | 2 +- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/erpnext/controllers/subcontracting_controller.py b/erpnext/controllers/subcontracting_controller.py index a588847ad5..a9561fe2da 100644 --- a/erpnext/controllers/subcontracting_controller.py +++ b/erpnext/controllers/subcontracting_controller.py @@ -74,19 +74,25 @@ class SubcontractingController(StockController): ) if not is_stock_item: - frappe.throw(_(f"Row {item.idx}: Item {item.item_name} must be a stock item.")) + frappe.throw(_("Row {0}: Item {1} must be a stock item.").format(item.idx, item.item_name)) if not is_sub_contracted_item: - frappe.throw(_(f"Row {item.idx}: Item {item.item_name} must be a subcontracted item.")) + frappe.throw( + _("Row {0}: Item {1} must be a subcontracted item.").format(item.idx, item.item_name) + ) if item.bom: bom = frappe.get_doc("BOM", item.bom) if not bom.is_active: - frappe.throw(_(f"Row {item.idx}: Please select an active BOM for Item {item.item_name}.")) + frappe.throw( + _("Row {0}: Please select an active BOM for Item {1}.").format(item.idx, item.item_name) + ) if bom.item != item.item_code: - frappe.throw(_(f"Row {item.idx}: Please select an valid BOM for Item {item.item_name}.")) + frappe.throw( + _("Row {0}: Please select an valid BOM for Item {1}.").format(item.idx, item.item_name) + ) else: - frappe.throw(_(f"Row {item.idx}: Please select a BOM for Item {item.item_name}.")) + frappe.throw(_("Row {0}: Please select a BOM for Item {1}.").format(item.idx, item.item_name)) def __get_data_before_save(self): item_dict = {} diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py index dd4ae04c16..7e1915bb71 100644 --- a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py +++ b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py @@ -199,7 +199,7 @@ class SubcontractingReceipt(SubcontractingController): for item in self.items: if not (item.qty or item.rejected_qty): frappe.throw( - _(f"Row {item.idx}: Accepted Qty and Rejected Qty can't be zero at the same time.") + _("Row {0}: Accepted Qty and Rejected Qty can't be zero at the same time.").format(item.idx) ) def set_items_bom(self): From cfb0bb1eaa31c23ae8ce4c87c5a11c3e46d83789 Mon Sep 17 00:00:00 2001 From: Ritwik Puri Date: Thu, 12 Jan 2023 17:25:50 +0530 Subject: [PATCH 24/25] fix: only group similar items in print format if group_same_items is checked in pick list (#33627) * fix: only group similar items if group same items is checked in pick list * test: non grouping of locations if group_same_items is false Co-authored-by: Sagar Sharma --- erpnext/stock/doctype/pick_list/pick_list.py | 3 ++- erpnext/stock/doctype/pick_list/test_pick_list.py | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/erpnext/stock/doctype/pick_list/pick_list.py b/erpnext/stock/doctype/pick_list/pick_list.py index 65a792fb46..9e6aead02d 100644 --- a/erpnext/stock/doctype/pick_list/pick_list.py +++ b/erpnext/stock/doctype/pick_list/pick_list.py @@ -230,7 +230,8 @@ class PickList(Document): frappe.throw(_("Qty of Finished Goods Item should be greater than 0.")) def before_print(self, settings=None): - self.group_similar_items() + if self.group_same_items: + self.group_similar_items() def group_similar_items(self): group_item_qty = defaultdict(float) diff --git a/erpnext/stock/doctype/pick_list/test_pick_list.py b/erpnext/stock/doctype/pick_list/test_pick_list.py index f552299806..71663e8ff4 100644 --- a/erpnext/stock/doctype/pick_list/test_pick_list.py +++ b/erpnext/stock/doctype/pick_list/test_pick_list.py @@ -445,6 +445,20 @@ class TestPickList(FrappeTestCase): pl.before_print() self.assertEqual(len(pl.locations), 4) + # grouping should not happen if group_same_items is False + pl = frappe.get_doc( + doctype="Pick List", + group_same_items=False, + locations=[ + _dict(item_code="A", warehouse="X", qty=5, picked_qty=1), + _dict(item_code="B", warehouse="Y", qty=4, picked_qty=2), + _dict(item_code="A", warehouse="X", qty=3, picked_qty=2), + _dict(item_code="B", warehouse="Y", qty=2, picked_qty=2), + ], + ) + pl.before_print() + self.assertEqual(len(pl.locations), 4) + # grouping should halve the number of items pl = frappe.get_doc( doctype="Pick List", From 232726288acb230c49ddb023d453ad055a8b8215 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Thu, 12 Jan 2023 17:44:07 +0530 Subject: [PATCH 25/25] chore: fix fieldnames and order --- .../bank_reconciliation_tool.js | 47 ++-- .../bank_reconciliation_tool.json | 202 +++++++++--------- .../bank_reconciliation_tool.py | 30 +-- .../data_table_manager.js | 2 +- .../dialog_manager.js | 4 +- 5 files changed, 145 insertions(+), 140 deletions(-) diff --git a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.js b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.js index 8e4214f202..c083189eb2 100644 --- a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.js +++ b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.js @@ -21,31 +21,22 @@ frappe.ui.form.on("Bank Reconciliation Tool", { frm.trigger('bank_account'); }, + filter_by_reference_date: function (frm) { + if (frm.doc.filter_by_reference_date) { + frm.set_value("bank_statement_from_date", ""); + frm.set_value("bank_statement_to_date", ""); + } else { + frm.set_value("from_reference_date", ""); + frm.set_value("to_reference_date", ""); + } + }, + refresh: function (frm) { frappe.require("bank-reconciliation-tool.bundle.js", () => frm.trigger("make_reconciliation_tool") ); - frm.add_custom_button(__('Auto Reconcile'), function() { - frappe.call({ - method: "erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.auto_reconcile_vouchers", - args: { - bank_account: frm.doc.bank_account, - from_date: frm.doc.bank_statement_from_date, - to_date: frm.doc.bank_statement_to_date, - filtered_by_reference_date: frm.doc.filtered_by_reference_date, - from_reference_date: frm.doc.from_reference_date, - to_reference_date: frm.doc.to_reference_date, - }, - callback: function (r) { - } - }) - - } - ), - frm.upload_statement_button = frm.page.set_secondary_action( - __("Upload Bank Statement"), - () => + frm.add_custom_button(__("Upload Bank Statement"), () => frappe.call({ method: "erpnext.accounts.doctype.bank_statement_import.bank_statement_import.upload_bank_statement", @@ -67,6 +58,20 @@ frappe.ui.form.on("Bank Reconciliation Tool", { }, }) ); + + frm.add_custom_button(__('Auto Reconcile'), function() { + frappe.call({ + method: "erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.auto_reconcile_vouchers", + args: { + bank_account: frm.doc.bank_account, + from_date: frm.doc.bank_statement_from_date, + to_date: frm.doc.bank_statement_to_date, + filter_by_reference_date: frm.doc.filter_by_reference_date, + from_reference_date: frm.doc.from_reference_date, + to_reference_date: frm.doc.to_reference_date, + }, + }) + }); }, after_save: function (frm) { @@ -178,7 +183,7 @@ frappe.ui.form.on("Bank Reconciliation Tool", { ).$wrapper, bank_statement_from_date: frm.doc.bank_statement_from_date, bank_statement_to_date: frm.doc.bank_statement_to_date, - filtered_by_reference_date: frm.doc.filtered_by_reference_date, + filter_by_reference_date: frm.doc.filter_by_reference_date, from_reference_date: frm.doc.from_reference_date, to_reference_date: frm.doc.to_reference_date, bank_statement_closing_balance: diff --git a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.json b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.json index a1269489ed..80993d6608 100644 --- a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.json +++ b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.json @@ -1,134 +1,134 @@ { - "actions": [], - "creation": "2020-12-02 10:13:02.148040", - "doctype": "DocType", - "editable_grid": 1, - "engine": "InnoDB", - "field_order": [ - "company", - "bank_account", - "column_break_1", - "bank_statement_from_date", - "bank_statement_to_date", - "column_break_2", - "filtered_by_reference_date", - "from_reference_date", - "to_reference_date", - "account_opening_balance", - "bank_statement_closing_balance", - "section_break_1", - "reconciliation_tool_cards", - "reconciliation_tool_dt", - "no_bank_transactions" - ], - "fields": [ + "actions": [], + "creation": "2020-12-02 10:13:02.148040", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "company", + "bank_account", + "column_break_1", + "bank_statement_from_date", + "bank_statement_to_date", + "from_reference_date", + "to_reference_date", + "filter_by_reference_date", + "column_break_2", + "account_opening_balance", + "bank_statement_closing_balance", + "section_break_1", + "reconciliation_tool_cards", + "reconciliation_tool_dt", + "no_bank_transactions" + ], + "fields": [ { - "fieldname": "company", - "fieldtype": "Link", - "label": "Company", - "options": "Company" + "fieldname": "company", + "fieldtype": "Link", + "label": "Company", + "options": "Company" }, { - "fieldname": "bank_account", - "fieldtype": "Link", - "label": "Bank Account", - "options": "Bank Account" + "fieldname": "bank_account", + "fieldtype": "Link", + "label": "Bank Account", + "options": "Bank Account" }, { - "fieldname": "column_break_1", - "fieldtype": "Column Break" + "fieldname": "column_break_1", + "fieldtype": "Column Break" }, { - "depends_on": "eval: doc.bank_account", - "fieldname": "bank_statement_from_date", - "fieldtype": "Date", - "label": "From Date" + "depends_on": "eval: doc.bank_account && !doc.filter_by_reference_date", + "fieldname": "bank_statement_from_date", + "fieldtype": "Date", + "label": "From Date" }, { - "depends_on": "eval: doc.bank_statement_from_date", - "fieldname": "bank_statement_to_date", - "fieldtype": "Date", - "label": "To Date" + "depends_on": "eval: doc.bank_account && !doc.filter_by_reference_date", + "fieldname": "bank_statement_to_date", + "fieldtype": "Date", + "label": "To Date" }, { - "fieldname": "column_break_2", - "fieldtype": "Column Break" + "fieldname": "column_break_2", + "fieldtype": "Column Break" }, { - "depends_on": "eval: doc.bank_statement_from_date", - "fieldname": "account_opening_balance", - "fieldtype": "Currency", - "label": "Account Opening Balance", - "options": "Currency", - "read_only": 1 + "depends_on": "eval: doc.bank_statement_from_date", + "fieldname": "account_opening_balance", + "fieldtype": "Currency", + "label": "Account Opening Balance", + "options": "Currency", + "read_only": 1 }, { - "depends_on": "eval: doc.bank_statement_to_date", - "fieldname": "bank_statement_closing_balance", - "fieldtype": "Currency", - "label": "Closing Balance", - "options": "Currency" + "depends_on": "eval: doc.bank_statement_to_date", + "fieldname": "bank_statement_closing_balance", + "fieldtype": "Currency", + "label": "Closing Balance", + "options": "Currency" }, { - "fieldname": "section_break_1", - "fieldtype": "Section Break", - "label": "Reconcile" + "fieldname": "section_break_1", + "fieldtype": "Section Break", + "label": "Reconcile" }, { - "fieldname": "reconciliation_tool_cards", - "fieldtype": "HTML" + "fieldname": "reconciliation_tool_cards", + "fieldtype": "HTML" }, { - "fieldname": "reconciliation_tool_dt", - "fieldtype": "HTML" + "fieldname": "reconciliation_tool_dt", + "fieldtype": "HTML" }, { - "fieldname": "no_bank_transactions", - "fieldtype": "HTML", - "options": "
No Matching Bank Transactions Found
" + "fieldname": "no_bank_transactions", + "fieldtype": "HTML", + "options": "
No Matching Bank Transactions Found
" }, { - "depends_on": "eval:doc.filtered_by_reference_date", - "fieldname": "from_reference_date", - "fieldtype": "Date", - "label": "From Reference Date" + "depends_on": "eval:doc.filter_by_reference_date", + "fieldname": "from_reference_date", + "fieldtype": "Date", + "label": "From Reference Date" }, { - "depends_on": "eval:doc.filtered_by_reference_date", - "fieldname": "to_reference_date", - "fieldtype": "Date", - "label": "To Reference Date" + "depends_on": "eval:doc.filter_by_reference_date", + "fieldname": "to_reference_date", + "fieldtype": "Date", + "label": "To Reference Date" }, { - "default": "0", - "fieldname": "filtered_by_reference_date", - "fieldtype": "Check", - "label": "Filtered by Reference Date" + "default": "0", + "fieldname": "filter_by_reference_date", + "fieldtype": "Check", + "label": "Filter by Reference Date" } - ], - "hide_toolbar": 1, - "index_web_pages_for_search": 1, - "issingle": 1, - "links": [], - "modified": "2022-12-03 15:40:05.330083", - "modified_by": "Administrator", - "module": "Accounts", - "name": "Bank Reconciliation Tool", - "owner": "Administrator", - "permissions": [ + ], + "hide_toolbar": 1, + "index_web_pages_for_search": 1, + "issingle": 1, + "links": [], + "modified": "2023-01-13 13:00:02.022919", + "modified_by": "Administrator", + "module": "Accounts", + "name": "Bank Reconciliation Tool", + "owner": "Administrator", + "permissions": [ { - "create": 1, - "delete": 1, - "email": 1, - "print": 1, - "read": 1, - "role": "System Manager", - "share": 1, - "write": 1 + "create": 1, + "delete": 1, + "email": 1, + "print": 1, + "read": 1, + "role": "System Manager", + "share": 1, + "write": 1 } - ], - "quick_entry": 1, - "sort_field": "modified", - "sort_order": "DESC", - "states": [] - } \ No newline at end of file + ], + "quick_entry": 1, + "sort_field": "modified", + "sort_order": "DESC", + "states": [] +} \ No newline at end of file diff --git a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py index 053641d310..558a1071a3 100644 --- a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py +++ b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py @@ -271,7 +271,7 @@ def auto_reconcile_vouchers( bank_account, from_date=None, to_date=None, - filtered_by_reference_date=None, + filter_by_reference_date=None, from_reference_date=None, to_reference_date=None, ): @@ -285,7 +285,7 @@ def auto_reconcile_vouchers( document_types, from_date, to_date, - filtered_by_reference_date, + filter_by_reference_date, from_reference_date, to_reference_date, ) @@ -407,7 +407,7 @@ def get_linked_payments( document_types=None, from_date=None, to_date=None, - filtered_by_reference_date=None, + filter_by_reference_date=None, from_reference_date=None, to_reference_date=None, ): @@ -424,7 +424,7 @@ def get_linked_payments( document_types, from_date, to_date, - filtered_by_reference_date, + filter_by_reference_date, from_reference_date, to_reference_date, ) @@ -438,7 +438,7 @@ def check_matching( document_types, from_date, to_date, - filtered_by_reference_date, + filter_by_reference_date, from_reference_date, to_reference_date, ): @@ -450,7 +450,7 @@ def check_matching( document_types, from_date, to_date, - filtered_by_reference_date, + filter_by_reference_date, from_reference_date, to_reference_date, ) @@ -484,7 +484,7 @@ def get_queries( document_types, from_date, to_date, - filtered_by_reference_date, + filter_by_reference_date, from_reference_date, to_reference_date, ): @@ -505,7 +505,7 @@ def get_queries( account_from_to, from_date, to_date, - filtered_by_reference_date, + filter_by_reference_date, from_reference_date, to_reference_date, ) @@ -524,7 +524,7 @@ def get_matching_queries( account_from_to, from_date, to_date, - filtered_by_reference_date, + filter_by_reference_date, from_reference_date, to_reference_date, ): @@ -536,7 +536,7 @@ def get_matching_queries( transaction, from_date, to_date, - filtered_by_reference_date, + filter_by_reference_date, from_reference_date, to_reference_date, ) @@ -548,7 +548,7 @@ def get_matching_queries( transaction, from_date, to_date, - filtered_by_reference_date, + filter_by_reference_date, from_reference_date, to_reference_date, ) @@ -664,7 +664,7 @@ def get_pe_matching_query( transaction, from_date, to_date, - filtered_by_reference_date, + filter_by_reference_date, from_reference_date, to_reference_date, ): @@ -676,7 +676,7 @@ def get_pe_matching_query( filter_by_date = f"AND posting_date between '{from_date}' and '{to_date}'" order_by = " posting_date" filter_by_reference_no = "" - if cint(filtered_by_reference_date): + if cint(filter_by_reference_date): filter_by_date = f"AND reference_date between '{from_reference_date}' and '{to_reference_date}'" order_by = " reference_date" if frappe.flags.auto_reconcile_vouchers == True: @@ -715,7 +715,7 @@ def get_je_matching_query( transaction, from_date, to_date, - filtered_by_reference_date, + filter_by_reference_date, from_reference_date, to_reference_date, ): @@ -727,7 +727,7 @@ def get_je_matching_query( filter_by_date = f"AND je.posting_date between '{from_date}' and '{to_date}'" order_by = " je.posting_date" filter_by_reference_no = "" - if cint(filtered_by_reference_date): + if cint(filter_by_reference_date): filter_by_date = f"AND je.cheque_date between '{from_reference_date}' and '{to_reference_date}'" order_by = " je.cheque_date" if frappe.flags.auto_reconcile_vouchers == True: diff --git a/erpnext/public/js/bank_reconciliation_tool/data_table_manager.js b/erpnext/public/js/bank_reconciliation_tool/data_table_manager.js index 532f6a9f50..f7c19a1b7f 100644 --- a/erpnext/public/js/bank_reconciliation_tool/data_table_manager.js +++ b/erpnext/public/js/bank_reconciliation_tool/data_table_manager.js @@ -8,7 +8,7 @@ erpnext.accounts.bank_reconciliation.DataTableManager = class DataTableManager { this.bank_account, this.bank_statement_from_date, this.bank_statement_to_date, - this.filtered_by_reference_date, + this.filter_by_reference_date, this.from_reference_date, this.to_reference_date ); diff --git a/erpnext/public/js/bank_reconciliation_tool/dialog_manager.js b/erpnext/public/js/bank_reconciliation_tool/dialog_manager.js index 693041f47b..4295c6909f 100644 --- a/erpnext/public/js/bank_reconciliation_tool/dialog_manager.js +++ b/erpnext/public/js/bank_reconciliation_tool/dialog_manager.js @@ -7,7 +7,7 @@ erpnext.accounts.bank_reconciliation.DialogManager = class DialogManager { this.make_dialog(); this.bank_statement_from_date = bank_statement_from_date; this.bank_statement_to_date = bank_statement_to_date; - this.filtered_by_reference_date = filtered_by_reference_date; + this.filter_by_reference_date = filter_by_reference_date; this.from_reference_date = from_reference_date; this.to_reference_date = to_reference_date; } @@ -55,7 +55,7 @@ erpnext.accounts.bank_reconciliation.DialogManager = class DialogManager { document_types: document_types, from_date: this.bank_statement_from_date, to_date: this.bank_statement_to_date, - filtered_by_reference_date: this.filtered_by_reference_date, + filter_by_reference_date: this.filter_by_reference_date, from_reference_date:this.from_reference_date, to_reference_date:this.to_reference_date },