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 cd99d38d051..70962042f77 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 bd003747dda..d7c0e61fc0a 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: __("