From 9b7c49f662ecb6812fd877c39fee570c07a076d4 Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Wed, 1 Nov 2023 06:10:54 -0400 Subject: [PATCH 01/13] fix: remove validation for negative outstanding invoices --- .../doctype/payment_entry/payment_entry.py | 35 ------------------- 1 file changed, 35 deletions(-) diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py index 6d9565fb21cc..4bd6ef71ba53 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.py +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py @@ -79,7 +79,6 @@ def validate(self): self.apply_taxes() self.set_amounts_after_tax() self.clear_unallocated_reference_document_rows() - self.validate_payment_against_negative_invoice() self.validate_transaction_reference() self.set_title() self.set_remarks() @@ -948,40 +947,6 @@ def clear_unallocated_reference_document_rows(self): self.name, ) - def validate_payment_against_negative_invoice(self): - if (self.payment_type != "Pay" or self.party_type != "Customer") and ( - self.payment_type != "Receive" or self.party_type != "Supplier" - ): - return - - total_negative_outstanding = flt( - sum( - abs(flt(d.outstanding_amount)) - for d in self.get("references") - if flt(d.outstanding_amount) < 0 - ), - self.references[0].precision("outstanding_amount") if self.references else None, - ) - - paid_amount = self.paid_amount if self.payment_type == "Receive" else self.received_amount - additional_charges = sum(flt(d.amount) for d in self.deductions) - - if not total_negative_outstanding: - if self.party_type == "Customer": - msg = _("Cannot pay to Customer without any negative outstanding invoice") - else: - msg = _("Cannot receive from Supplier without any negative outstanding invoice") - - frappe.throw(msg, InvalidPaymentEntry) - - elif paid_amount - additional_charges > total_negative_outstanding: - frappe.throw( - _("Paid Amount cannot be greater than total negative outstanding amount {0}").format( - fmt_money(total_negative_outstanding) - ), - InvalidPaymentEntry, - ) - def set_title(self): if frappe.flags.in_import and self.title: # do not set title dynamically if title exists during data import. From 9b3d05bfe2c41fd28334e85c17bd980c8d1a0a09 Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Thu, 2 Nov 2023 12:08:43 +0000 Subject: [PATCH 02/13] fix: test for invoice returns --- erpnext/accounts/doctype/payment_entry/payment_entry.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py index 4bd6ef71ba53..1e82a2a6ae0f 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.py +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py @@ -1072,8 +1072,8 @@ def add_party_gl_entries(self, gl_entries): gle.update( { - dr_or_cr + "_in_account_currency": d.allocated_amount, - dr_or_cr: allocated_amount_in_company_currency, + dr_or_cr + "_in_account_currency": abs(d.allocated_amount), + dr_or_cr: abs(allocated_amount_in_company_currency), } ) From 1524a9d6b36d7d52c7d5515de436da2c4b7917de Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Thu, 2 Nov 2023 12:09:27 +0000 Subject: [PATCH 03/13] test: receive payments from payable party --- .../payment_entry/test_payment_entry.py | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/erpnext/accounts/doctype/payment_entry/test_payment_entry.py b/erpnext/accounts/doctype/payment_entry/test_payment_entry.py index 79b1cd40b1c2..17447f614615 100644 --- a/erpnext/accounts/doctype/payment_entry/test_payment_entry.py +++ b/erpnext/accounts/doctype/payment_entry/test_payment_entry.py @@ -1438,6 +1438,39 @@ def test_delete_linked_exchange_gain_loss_journal(self): self.assertRaises(frappe.DoesNotExistError, frappe.get_doc, pe.doctype, pe.name) self.assertRaises(frappe.DoesNotExistError, frappe.get_doc, "Journal Entry", jv[0]) + def test_receive_payment_from_payable_party_type(self): + pe = create_payment_entry( + party_type="Supplier", + party="_Test Supplier", + payment_type="Receive", + paid_from="Creditors - _TC", + paid_to="_Test Cash - _TC", + save=True, + submit=True, + ) + self.voucher_no = pe.name + self.expected_gle = [ + {"account": "_Test Cash - _TC", "debit": 1000.0, "credit": 0.0}, + {"account": "Creditors - _TC", "debit": 0.0, "credit": 1000.0}, + ] + self.check_gl_entries() + + def check_gl_entries(self): + gle = frappe.qb.DocType("GL Entry") + gl_entries = ( + frappe.qb.from_(gle) + .select( + gle.account, + gle.debit, + gle.credit, + ) + .where((gle.voucher_no == self.voucher_no) & (gle.is_cancelled == 0)) + .orderby(gle.account) + ).run(as_dict=True) + for row in range(len(self.expected_gle)): + for field in ["account", "debit", "credit"]: + self.assertEqual(self.expected_gle[row][field], gl_entries[row][field]) + def create_payment_entry(**args): payment_entry = frappe.new_doc("Payment Entry") From ba0b00e77628d32be6970cba3469734b73dac02d Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Fri, 3 Nov 2023 02:28:25 -0400 Subject: [PATCH 04/13] fix: credit note receive payment entry --- .../doctype/payment_entry/payment_entry.py | 19 +++++++++++++++++-- erpnext/accounts/utils.py | 4 ++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py index 1e82a2a6ae0f..69dd0a865098 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.py +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py @@ -31,6 +31,7 @@ get_account_currency, get_balance_on, get_outstanding_invoices, + get_party_types_from_account_type, ) from erpnext.controllers.accounts_controller import ( AccountsController, @@ -1070,10 +1071,24 @@ def add_party_gl_entries(self, gl_entries): allocated_amount_in_company_currency = self.calculate_base_allocated_amount_for_reference(d) + reverse_dr_or_cr = 0 + if d.reference_doctype in ["Sales Invoice", "Purchase Invoice"]: + is_return = frappe.db.get_value(d.reference_doctype, d.reference_name, "is_return") + payable_party_types = get_party_types_from_account_type("Payable") + receivable_party_types = get_party_types_from_account_type("Receivable") + if is_return and self.party_type in receivable_party_types and self.payment_type == "Pay": + reverse_dr_or_cr = 1 + elif is_return and self.party_type in payable_party_types and self.payment_type == "Receive": + reverse_dr_or_cr = 1 + gle.update( { - dr_or_cr + "_in_account_currency": abs(d.allocated_amount), - dr_or_cr: abs(allocated_amount_in_company_currency), + dr_or_cr: abs(allocated_amount_in_company_currency) + if reverse_dr_or_cr + else allocated_amount_in_company_currency, + dr_or_cr + "_in_account_currency": abs(d.allocated_amount) + if reverse_dr_or_cr + else d.allocated_amount, } ) diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py index 10f30512c0b6..f9b13dc359ef 100644 --- a/erpnext/accounts/utils.py +++ b/erpnext/accounts/utils.py @@ -2133,6 +2133,10 @@ def create_gain_loss_journal( return journal_entry.name +def get_party_types_from_account_type(account_type): + return frappe.db.get_list("Party Type", {"account_type": account_type}, pluck="name") + + def run_ledger_health_checks(): health_monitor_settings = frappe.get_doc("Ledger Health Monitor") if health_monitor_settings.enable_health_monitor: From eff49b7c0848634442a492029d7f4e4dad0c015a Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Fri, 3 Nov 2023 02:30:56 -0400 Subject: [PATCH 05/13] test: receive payments from payable party --- .../report/accounts_receivable/accounts_receivable.py | 4 ++-- .../accounts_receivable_summary.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py index 5ef39755ca56..db91700240de 100644 --- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py +++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py @@ -14,7 +14,7 @@ get_accounting_dimensions, get_dimension_with_children, ) -from erpnext.accounts.utils import get_currency_precision +from erpnext.accounts.utils import get_currency_precision, get_party_types_from_account_type # This report gives a summary of all Outstanding Invoices considering the following @@ -68,7 +68,7 @@ def set_defaults(self): self.currency_precision = get_currency_precision() or 2 self.dr_or_cr = "debit" if self.filters.account_type == "Receivable" else "credit" self.account_type = self.filters.account_type - self.party_type = frappe.db.get_all("Party Type", {"account_type": self.account_type}, pluck="name") + self.party_type = get_party_types_from_account_type(self.account_type) self.party_details = {} self.invoices = set() self.skip_total_row = 0 diff --git a/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py b/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py index b1c02b384525..6a1b1057724d 100644 --- a/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py +++ b/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py @@ -8,7 +8,7 @@ from erpnext.accounts.party import get_partywise_advanced_payment_amount from erpnext.accounts.report.accounts_receivable.accounts_receivable import ReceivablePayableReport -from erpnext.accounts.utils import get_currency_precision +from erpnext.accounts.utils import get_currency_precision, get_party_types_from_account_type def execute(filters=None): @@ -23,7 +23,7 @@ def execute(filters=None): class AccountsReceivableSummary(ReceivablePayableReport): def run(self, args): self.account_type = args.get("account_type") - self.party_type = frappe.db.get_all("Party Type", {"account_type": self.account_type}, pluck="name") + self.party_type = get_party_types_from_account_type(self.account_type) self.party_naming_by = frappe.db.get_value(args.get("naming_by")[0], None, args.get("naming_by")[1]) self.get_columns() self.get_data(args) From 2595020e5b3c43dfa6fb4a52e63dde9d0bd05c8a Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Mon, 6 Nov 2023 09:51:26 +0530 Subject: [PATCH 06/13] fix: skip check for removed validation --- .../doctype/payment_entry/test_payment_entry.py | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/erpnext/accounts/doctype/payment_entry/test_payment_entry.py b/erpnext/accounts/doctype/payment_entry/test_payment_entry.py index 17447f614615..987318131bdf 100644 --- a/erpnext/accounts/doctype/payment_entry/test_payment_entry.py +++ b/erpnext/accounts/doctype/payment_entry/test_payment_entry.py @@ -681,17 +681,6 @@ def test_internal_transfer_usd_to_inr(self): self.validate_gl_entries(pe.name, expected_gle) def test_payment_against_negative_sales_invoice(self): - pe1 = frappe.new_doc("Payment Entry") - pe1.payment_type = "Pay" - pe1.company = "_Test Company" - pe1.party_type = "Customer" - pe1.party = "_Test Customer" - pe1.paid_from = "_Test Cash - _TC" - pe1.paid_amount = 100 - pe1.received_amount = 100 - - self.assertRaises(InvalidPaymentEntry, pe1.validate) - si1 = create_sales_invoice() # create full payment entry against si1 @@ -749,8 +738,6 @@ def test_payment_against_negative_sales_invoice(self): # pay more than outstanding against si1 pe3 = get_payment_entry("Sales Invoice", si1.name, bank_account="_Test Cash - _TC") - pe3.paid_amount = pe3.received_amount = 300 - self.assertRaises(InvalidPaymentEntry, pe3.validate) # pay negative outstanding against si1 pe3.paid_to = "Debtors - _TC" From 276f36982bc3069c2591e4319a715d64a20e58fb Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Mon, 6 Nov 2023 04:23:11 +0000 Subject: [PATCH 07/13] fix: handle gle for standalone credit and debit notes --- .../doctype/payment_entry/payment_entry.py | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py index 69dd0a865098..125a2aa3cee0 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.py +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py @@ -1071,24 +1071,27 @@ def add_party_gl_entries(self, gl_entries): allocated_amount_in_company_currency = self.calculate_base_allocated_amount_for_reference(d) - reverse_dr_or_cr = 0 + reverse_dr_or_cr = standalone_note = 0 if d.reference_doctype in ["Sales Invoice", "Purchase Invoice"]: - is_return = frappe.db.get_value(d.reference_doctype, d.reference_name, "is_return") + is_return, return_against = frappe.db.get_value( + d.reference_doctype, d.reference_name, ["is_return", "return_against"] + ) payable_party_types = get_party_types_from_account_type("Payable") receivable_party_types = get_party_types_from_account_type("Receivable") - if is_return and self.party_type in receivable_party_types and self.payment_type == "Pay": + if is_return and self.party_type in receivable_party_types and (self.payment_type == "Pay"): reverse_dr_or_cr = 1 - elif is_return and self.party_type in payable_party_types and self.payment_type == "Receive": + elif ( + is_return and self.party_type in payable_party_types and (self.payment_type == "Receive") + ): reverse_dr_or_cr = 1 + if is_return and not return_against and not reverse_dr_or_cr: + dr_or_cr = "debit" if dr_or_cr == "credit" else "credit" + gle.update( { - dr_or_cr: abs(allocated_amount_in_company_currency) - if reverse_dr_or_cr - else allocated_amount_in_company_currency, - dr_or_cr + "_in_account_currency": abs(d.allocated_amount) - if reverse_dr_or_cr - else d.allocated_amount, + dr_or_cr: abs(allocated_amount_in_company_currency), + dr_or_cr + "_in_account_currency": abs(d.allocated_amount), } ) From 0ec3031daefe26055521e036dc7ceaf7ed9cdeb9 Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Wed, 8 Nov 2023 02:00:24 -0500 Subject: [PATCH 08/13] fix: use get_all instead of get_list --- erpnext/accounts/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py index f9b13dc359ef..61356052215d 100644 --- a/erpnext/accounts/utils.py +++ b/erpnext/accounts/utils.py @@ -2134,7 +2134,7 @@ def create_gain_loss_journal( def get_party_types_from_account_type(account_type): - return frappe.db.get_list("Party Type", {"account_type": account_type}, pluck="name") + return frappe.db.get_all("Party Type", {"account_type": account_type}, pluck="name") def run_ledger_health_checks(): From 39247d4e1af6cd21333b82cc97ebfbc588541e52 Mon Sep 17 00:00:00 2001 From: Devin Slauenwhite Date: Wed, 13 Dec 2023 19:47:20 -0500 Subject: [PATCH 09/13] refactor: use different GL build logic # Reference: https://github.com/frappe/erpnext/commit/58114e7b24788f0244b89401235a6a20721b9603 --- .../doctype/payment_entry/payment_entry.py | 24 +++++++------------ 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py index 125a2aa3cee0..4a050c37328f 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.py +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py @@ -1052,30 +1052,19 @@ def add_party_gl_entries(self, gl_entries): item=self, ) - dr_or_cr = ( - "credit" if erpnext.get_party_account_type(self.party_type) == "Receivable" else "debit" - ) - for d in self.get("references"): + dr_or_cr = "credit" if self.payment_type == "Receive" else "debit" cost_center = self.cost_center if d.reference_doctype == "Sales Invoice" and not cost_center: cost_center = frappe.db.get_value(d.reference_doctype, d.reference_name, "cost_center") + gle = party_gl_dict.copy() - gle.update( - { - "against_voucher_type": d.reference_doctype, - "against_voucher": d.reference_name, - "cost_center": cost_center, - } - ) allocated_amount_in_company_currency = self.calculate_base_allocated_amount_for_reference(d) + reverse_dr_or_cr = 0 - reverse_dr_or_cr = standalone_note = 0 if d.reference_doctype in ["Sales Invoice", "Purchase Invoice"]: - is_return, return_against = frappe.db.get_value( - d.reference_doctype, d.reference_name, ["is_return", "return_against"] - ) + is_return = frappe.db.get_value(d.reference_doctype, d.reference_name, "is_return") payable_party_types = get_party_types_from_account_type("Payable") receivable_party_types = get_party_types_from_account_type("Receivable") if is_return and self.party_type in receivable_party_types and (self.payment_type == "Pay"): @@ -1085,13 +1074,16 @@ def add_party_gl_entries(self, gl_entries): ): reverse_dr_or_cr = 1 - if is_return and not return_against and not reverse_dr_or_cr: + if is_return and not reverse_dr_or_cr: dr_or_cr = "debit" if dr_or_cr == "credit" else "credit" gle.update( { dr_or_cr: abs(allocated_amount_in_company_currency), dr_or_cr + "_in_account_currency": abs(d.allocated_amount), + "against_voucher_type": d.reference_doctype, + "against_voucher": d.reference_name, + "cost_center": cost_center, } ) From 8705ca6920683ee176a67c385cf56ab76daa99f0 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Tue, 28 Nov 2023 14:34:47 +0000 Subject: [PATCH 10/13] refactor: redefine dr_or_cr for unallocated amount --- erpnext/accounts/doctype/payment_entry/payment_entry.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py index 4a050c37328f..8f416849ca32 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.py +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py @@ -1089,9 +1089,10 @@ def add_party_gl_entries(self, gl_entries): gl_entries.append(gle) - if self.unallocated_amount: - exchange_rate = self.get_exchange_rate() - base_unallocated_amount = self.unallocated_amount * exchange_rate + if self.unallocated_amount: + dr_or_cr = "credit" if self.payment_type == "Receive" else "debit" + exchange_rate = self.get_exchange_rate() + base_unallocated_amount = self.unallocated_amount * exchange_rate gle = party_gl_dict.copy() From e22d504a1ff3c0b22568be0cf932d244e58671ca Mon Sep 17 00:00:00 2001 From: Devin Slauenwhite Date: Thu, 14 Dec 2023 16:52:36 +0000 Subject: [PATCH 11/13] fix: indentation error # Reference: https://github.com/frappe/erpnext/commit/58114e7b24788f0244b89401235a6a20721b9603 --- erpnext/accounts/doctype/payment_entry/payment_entry.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py index 8f416849ca32..376a580354dd 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.py +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py @@ -1089,13 +1089,12 @@ def add_party_gl_entries(self, gl_entries): gl_entries.append(gle) - if self.unallocated_amount: - dr_or_cr = "credit" if self.payment_type == "Receive" else "debit" - exchange_rate = self.get_exchange_rate() - base_unallocated_amount = self.unallocated_amount * exchange_rate + if self.unallocated_amount: + dr_or_cr = "credit" if self.payment_type == "Receive" else "debit" + exchange_rate = self.get_exchange_rate() + base_unallocated_amount = self.unallocated_amount * exchange_rate gle = party_gl_dict.copy() - gle.update( { dr_or_cr + "_in_account_currency": self.unallocated_amount, From 9e8465bf9ed206f0fc7fda4d726e3552a12adfc9 Mon Sep 17 00:00:00 2001 From: Devin Slauenwhite Date: Tue, 3 Sep 2024 18:07:02 -0400 Subject: [PATCH 12/13] chore: linter --- .../accounts/doctype/payment_entry/payment_entry.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py index 376a580354dd..ab277ee854ca 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.py +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py @@ -1067,10 +1067,16 @@ def add_party_gl_entries(self, gl_entries): is_return = frappe.db.get_value(d.reference_doctype, d.reference_name, "is_return") payable_party_types = get_party_types_from_account_type("Payable") receivable_party_types = get_party_types_from_account_type("Receivable") - if is_return and self.party_type in receivable_party_types and (self.payment_type == "Pay"): + if ( + is_return + and self.party_type in receivable_party_types + and (self.payment_type == "Pay") + ): reverse_dr_or_cr = 1 elif ( - is_return and self.party_type in payable_party_types and (self.payment_type == "Receive") + is_return + and self.party_type in payable_party_types + and (self.payment_type == "Receive") ): reverse_dr_or_cr = 1 From 1c3ea83aa99a2341c7bf98b72e797cdecb5922fe Mon Sep 17 00:00:00 2001 From: Devin Slauenwhite Date: Fri, 4 Oct 2024 15:48:25 -0400 Subject: [PATCH 13/13] fix: remove validate negative outstanding --- .../doctype/payment_entry/payment_entry.js | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.js b/erpnext/accounts/doctype/payment_entry/payment_entry.js index 2f9d5be07e7a..7d2836a6d2da 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.js +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.js @@ -886,20 +886,7 @@ frappe.ui.form.on('Payment Entry', { var allocated_positive_outstanding = paid_amount + allocated_negative_outstanding; } else if (["Customer", "Supplier"].includes(frm.doc.party_type)) { total_negative_outstanding = flt(total_negative_outstanding, precision("outstanding_amount")) - if(paid_amount > total_negative_outstanding) { - if(total_negative_outstanding == 0) { - frappe.msgprint( - __("Cannot {0} {1} {2} without any negative outstanding invoice", [frm.doc.payment_type, - (frm.doc.party_type=="Customer" ? "to" : "from"), frm.doc.party_type]) - ); - return false - } else { - frappe.msgprint( - __("Paid Amount cannot be greater than total negative outstanding amount {0}", [total_negative_outstanding]) - ); - return false; - } - } else { + if(paid_amount < total_negative_outstanding) { allocated_positive_outstanding = total_negative_outstanding - paid_amount; allocated_negative_outstanding = paid_amount + (total_positive_outstanding_including_order < allocated_positive_outstanding ?