From 7ac4916191c3b038ebd67f18c2f96dfc4f4ba112 Mon Sep 17 00:00:00 2001 From: Frappe PR Bot Date: Wed, 25 Aug 2021 16:59:03 +0530 Subject: [PATCH] feat: unreconcile on cancellation of bank transaction (#27109) (#27137) --- .../bank_transaction/bank_transaction.py | 35 +++++++++++++------ .../bank_transaction/bank_transaction_list.js | 6 ++-- .../bank_transaction/test_bank_transaction.py | 9 ++++- erpnext/controllers/status_updater.py | 3 +- 4 files changed, 38 insertions(+), 15 deletions(-) diff --git a/erpnext/accounts/doctype/bank_transaction/bank_transaction.py b/erpnext/accounts/doctype/bank_transaction/bank_transaction.py index 31cfb2da1da6..0544a469d60d 100644 --- a/erpnext/accounts/doctype/bank_transaction/bank_transaction.py +++ b/erpnext/accounts/doctype/bank_transaction/bank_transaction.py @@ -21,6 +21,10 @@ def on_update_after_submit(self): self.update_allocations() self.clear_linked_payment_entries() self.set_status(update=True) + + def on_cancel(self): + self.clear_linked_payment_entries(for_cancel=True) + self.set_status(update=True) def update_allocations(self): if self.payment_entries: @@ -41,21 +45,30 @@ def update_allocations(self): frappe.db.set_value(self.doctype, self.name, "status", "Reconciled") self.reload() - - def clear_linked_payment_entries(self): + + def clear_linked_payment_entries(self, for_cancel=False): for payment_entry in self.payment_entries: if payment_entry.payment_document in ["Payment Entry", "Journal Entry", "Purchase Invoice", "Expense Claim"]: - self.clear_simple_entry(payment_entry) + self.clear_simple_entry(payment_entry, for_cancel=for_cancel) elif payment_entry.payment_document == "Sales Invoice": - self.clear_sales_invoice(payment_entry) - - def clear_simple_entry(self, payment_entry): - frappe.db.set_value(payment_entry.payment_document, payment_entry.payment_entry, "clearance_date", self.date) - - def clear_sales_invoice(self, payment_entry): - frappe.db.set_value("Sales Invoice Payment", dict(parenttype=payment_entry.payment_document, - parent=payment_entry.payment_entry), "clearance_date", self.date) + self.clear_sales_invoice(payment_entry, for_cancel=for_cancel) + + def clear_simple_entry(self, payment_entry, for_cancel=False): + clearance_date = self.date if not for_cancel else None + frappe.db.set_value( + payment_entry.payment_document, payment_entry.payment_entry, + "clearance_date", clearance_date) + + def clear_sales_invoice(self, payment_entry, for_cancel=False): + clearance_date = self.date if not for_cancel else None + frappe.db.set_value( + "Sales Invoice Payment", + dict( + parenttype=payment_entry.payment_document, + parent=payment_entry.payment_entry + ), + "clearance_date", clearance_date) def get_total_allocated_amount(payment_entry): return frappe.db.sql(""" diff --git a/erpnext/accounts/doctype/bank_transaction/bank_transaction_list.js b/erpnext/accounts/doctype/bank_transaction/bank_transaction_list.js index bff41d5539bf..2585ee9c9237 100644 --- a/erpnext/accounts/doctype/bank_transaction/bank_transaction_list.js +++ b/erpnext/accounts/doctype/bank_transaction/bank_transaction_list.js @@ -4,10 +4,12 @@ frappe.listview_settings['Bank Transaction'] = { add_fields: ["unallocated_amount"], get_indicator: function(doc) { - if(flt(doc.unallocated_amount)>0) { - return [__("Unreconciled"), "orange", "unallocated_amount,>,0"]; + if(doc.docstatus == 2) { + return [__("Cancelled"), "red", "docstatus,=,2"]; } else if(flt(doc.unallocated_amount)<=0) { return [__("Reconciled"), "green", "unallocated_amount,=,0"]; + } else if(flt(doc.unallocated_amount)>0) { + return [__("Unreconciled"), "orange", "unallocated_amount,>,0"]; } } }; diff --git a/erpnext/accounts/doctype/bank_transaction/test_bank_transaction.py b/erpnext/accounts/doctype/bank_transaction/test_bank_transaction.py index ce149f96e6f0..439d4891194f 100644 --- a/erpnext/accounts/doctype/bank_transaction/test_bank_transaction.py +++ b/erpnext/accounts/doctype/bank_transaction/test_bank_transaction.py @@ -25,7 +25,8 @@ def setUpClass(cls): def tearDownClass(cls): for bt in frappe.get_all("Bank Transaction"): doc = frappe.get_doc("Bank Transaction", bt.name) - doc.cancel() + if doc.docstatus == 1: + doc.cancel() doc.delete() # Delete directly in DB to avoid validation errors for countries not allowing deletion @@ -57,6 +58,12 @@ def test_reconcile(self): clearance_date = frappe.db.get_value("Payment Entry", payment.name, "clearance_date") self.assertTrue(clearance_date is not None) + bank_transaction.reload() + bank_transaction.cancel() + + clearance_date = frappe.db.get_value("Payment Entry", payment.name, "clearance_date") + self.assertFalse(clearance_date) + # Check if ERPNext can correctly filter a linked payments based on the debit/credit amount def test_debit_credit_output(self): bank_transaction = frappe.get_doc("Bank Transaction", dict(description="Auszahlung Karte MC/000002916 AUTOMAT 698769 K002 27.10. 14:07")) diff --git a/erpnext/controllers/status_updater.py b/erpnext/controllers/status_updater.py index b1f89b08d792..7b24e50b1439 100644 --- a/erpnext/controllers/status_updater.py +++ b/erpnext/controllers/status_updater.py @@ -86,7 +86,8 @@ def validate_status(status, options): ], "Bank Transaction": [ ["Unreconciled", "eval:self.docstatus == 1 and self.unallocated_amount>0"], - ["Reconciled", "eval:self.docstatus == 1 and self.unallocated_amount<=0"] + ["Reconciled", "eval:self.docstatus == 1 and self.unallocated_amount<=0"], + ["Cancelled", "eval:self.docstatus == 2"] ], "POS Opening Entry": [ ["Draft", None],