From 8b3c809cb68ed9badb4d9fa4defc083b38bd4184 Mon Sep 17 00:00:00 2001 From: SherinKR Date: Thu, 22 Feb 2024 15:56:58 +0530 Subject: [PATCH 01/27] fix: account validation error on bank account after editing existing bank account --- erpnext/accounts/doctype/bank_account/bank_account.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/bank_account/bank_account.py b/erpnext/accounts/doctype/bank_account/bank_account.py index ece27e77ee9..ec3fa831200 100644 --- a/erpnext/accounts/doctype/bank_account/bank_account.py +++ b/erpnext/accounts/doctype/bank_account/bank_account.py @@ -30,7 +30,7 @@ class BankAccount(Document): def validate_account(self): if self.account: - if accounts := frappe.db.get_all("Bank Account", filters={"account": self.account}, as_list=1): + if accounts := frappe.db.get_all("Bank Account", filters={"account": self.account, 'name':['!=', self.name]}, as_list=1): frappe.throw( _("'{0}' account is already used by {1}. Use another account.").format( frappe.bold(self.account), From c8b817c87a9e510a865c48ad9e2890c892246e8e Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Wed, 28 Feb 2024 18:01:27 +0530 Subject: [PATCH 02/27] fix: make warning for previously existing SO an alert (cherry picked from commit 24dcd64c16eaea2f7ab0585235dfaf64cfe47bf3) --- erpnext/selling/doctype/sales_order/sales_order.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py index 82680368181..3821a237161 100755 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -102,7 +102,8 @@ class SalesOrder(SellingController): frappe.msgprint( _("Warning: Sales Order {0} already exists against Customer's Purchase Order {1}").format( frappe.bold(so[0][0]), frappe.bold(self.po_no) - ) + ), + alert=True, ) else: frappe.throw( From 035c90c3b84934711f82ee61242b737a7d1a1290 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Thu, 29 Feb 2024 11:34:23 +0530 Subject: [PATCH 03/27] fix(setup): avoid duplicate entry for Analytics role (backport #40183) (#40184) fix(setup): avoid duplicate entry for Analytics role (#40183) (cherry picked from commit 29f91a7919210640f4d460167ee215817689ab52) Co-authored-by: Rucha Mahabal --- erpnext/setup/install.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/erpnext/setup/install.py b/erpnext/setup/install.py index 71b1ca7c058..d217bfa5219 100644 --- a/erpnext/setup/install.py +++ b/erpnext/setup/install.py @@ -19,7 +19,9 @@ default_mail_footer = """
Date: Fri, 26 Jan 2024 21:46:19 +0530 Subject: [PATCH 04/27] fix: provisional reverse entry amount (cherry picked from commit 3e59c668064c037548c7c29c4d944efbcb37ff7b) --- .../doctype/purchase_invoice/purchase_invoice.py | 6 +++--- .../stock/doctype/purchase_receipt/purchase_receipt.py | 9 ++++++--- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py index f6fcd7e70e0..7ad9417173e 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -869,7 +869,7 @@ class PurchaseInvoice(BuyingController): purchase_receipt_doc_map[item.purchase_receipt] = purchase_receipt_doc # Post reverse entry for Stock-Received-But-Not-Billed if it is booked in Purchase Receipt - expense_booked_in_pr = frappe.db.get_value( + expense_booked_in_pr, credit = frappe.db.get_value( "GL Entry", { "is_cancelled": 0, @@ -878,13 +878,13 @@ class PurchaseInvoice(BuyingController): "voucher_detail_no": item.pr_detail, "account": provisional_account, }, - ["name"], + ["name", "credit"], ) if expense_booked_in_pr: # Intentionally passing purchase invoice item to handle partial billing purchase_receipt_doc.add_provisional_gl_entry( - item, gl_entries, self.posting_date, provisional_account, reverse=1 + item, gl_entries, self.posting_date, provisional_account, reverse=1, item_amount=credit ) if not self.is_internal_transfer(): diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py index bf5f9f4d1d4..79e6ab84d95 100644 --- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py @@ -615,16 +615,19 @@ class PurchaseReceipt(BuyingController): ) def add_provisional_gl_entry( - self, item, gl_entries, posting_date, provisional_account, reverse=0 + self, item, gl_entries, posting_date, provisional_account, reverse=0, item_amount=None ): credit_currency = get_account_currency(provisional_account) expense_account = item.expense_account debit_currency = get_account_currency(item.expense_account) remarks = self.get("remarks") or _("Accounting Entry for Service") multiplication_factor = 1 + amount = item.base_amount if reverse: multiplication_factor = -1 + # Post reverse entry for previously posted amount + amount = item_amount expense_account = frappe.db.get_value( "Purchase Receipt Item", {"name": item.get("pr_detail")}, ["expense_account"] ) @@ -634,7 +637,7 @@ class PurchaseReceipt(BuyingController): account=provisional_account, cost_center=item.cost_center, debit=0.0, - credit=multiplication_factor * item.base_amount, + credit=multiplication_factor * amount, remarks=remarks, against_account=expense_account, account_currency=credit_currency, @@ -648,7 +651,7 @@ class PurchaseReceipt(BuyingController): gl_entries=gl_entries, account=expense_account, cost_center=item.cost_center, - debit=multiplication_factor * item.base_amount, + debit=multiplication_factor * amount, credit=0.0, remarks=remarks, against_account=provisional_account, From 5f23614960aa0f41b11d8b5f651d85cbfbf2753c Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Mon, 29 Jan 2024 11:34:06 +0530 Subject: [PATCH 05/27] fix: handle partial invoice against provisional entry (cherry picked from commit 2a46799188a0267d76bdd292062f5a5f82429493) --- .../purchase_invoice/purchase_invoice.py | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py index 7ad9417173e..bede2641f15 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -859,9 +859,12 @@ class PurchaseInvoice(BuyingController): if provisional_accounting_for_non_stock_items: if item.purchase_receipt: - provisional_account = frappe.db.get_value( - "Purchase Receipt Item", item.pr_detail, "provisional_expense_account" - ) or self.get_company_default("default_provisional_account") + provisional_account, pr_base_rate = frappe.get_cached_value( + "Purchase Receipt Item", item.pr_detail, ["provisional_expense_account", "base_rate"] + ) + provisional_account = provisional_account or self.get_company_default( + "default_provisional_account" + ) purchase_receipt_doc = purchase_receipt_doc_map.get(item.purchase_receipt) if not purchase_receipt_doc: @@ -869,7 +872,7 @@ class PurchaseInvoice(BuyingController): purchase_receipt_doc_map[item.purchase_receipt] = purchase_receipt_doc # Post reverse entry for Stock-Received-But-Not-Billed if it is booked in Purchase Receipt - expense_booked_in_pr, credit = frappe.db.get_value( + expense_booked_in_pr = frappe.db.get_value( "GL Entry", { "is_cancelled": 0, @@ -878,13 +881,18 @@ class PurchaseInvoice(BuyingController): "voucher_detail_no": item.pr_detail, "account": provisional_account, }, - ["name", "credit"], + "name", ) if expense_booked_in_pr: # Intentionally passing purchase invoice item to handle partial billing purchase_receipt_doc.add_provisional_gl_entry( - item, gl_entries, self.posting_date, provisional_account, reverse=1, item_amount=credit + item, + gl_entries, + self.posting_date, + provisional_account, + reverse=1, + item_amount=(item.qty * pr_base_rate), ) if not self.is_internal_transfer(): From 14d9d29913e78a585230763b3f25a2e903c263a7 Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Mon, 5 Feb 2024 15:52:46 +0530 Subject: [PATCH 06/27] fix: over billing qty along with rate (cherry picked from commit cc96d2b50cbce3c137eebd754956344718cd1771) --- .../accounts/doctype/purchase_invoice/purchase_invoice.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py index bede2641f15..cfaaf767786 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -859,8 +859,10 @@ class PurchaseInvoice(BuyingController): if provisional_accounting_for_non_stock_items: if item.purchase_receipt: - provisional_account, pr_base_rate = frappe.get_cached_value( - "Purchase Receipt Item", item.pr_detail, ["provisional_expense_account", "base_rate"] + provisional_account, pr_qty, pr_base_rate = frappe.get_cached_value( + "Purchase Receipt Item", + item.pr_detail, + ["provisional_expense_account", "qty", "base_rate"], ) provisional_account = provisional_account or self.get_company_default( "default_provisional_account" @@ -892,7 +894,7 @@ class PurchaseInvoice(BuyingController): self.posting_date, provisional_account, reverse=1, - item_amount=(item.qty * pr_base_rate), + item_amount=(min(item.qty, pr_qty) * pr_base_rate), ) if not self.is_internal_transfer(): From aa52cd67bdeddc54303151180529250519f882c8 Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Mon, 5 Feb 2024 15:55:17 +0530 Subject: [PATCH 07/27] test: overbilling for provisional accounting (cherry picked from commit ff3ca50a4b1787cd557dffefda4997a7f20cd643) --- .../purchase_invoice/test_purchase_invoice.py | 89 ++++++++++++++++--- 1 file changed, 75 insertions(+), 14 deletions(-) diff --git a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py index 6942e28726f..1ce5a81eae5 100644 --- a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py @@ -1520,18 +1520,7 @@ class TestPurchaseInvoice(FrappeTestCase, StockTestMixin): self.assertEqual(payment_entry.taxes[0].allocated_amount, 0) def test_provisional_accounting_entry(self): - create_item("_Test Non Stock Item", is_stock_item=0) - - provisional_account = create_account( - account_name="Provision Account", - parent_account="Current Liabilities - _TC", - company="_Test Company", - ) - - company = frappe.get_doc("Company", "_Test Company") - company.enable_provisional_accounting_for_non_stock_items = 1 - company.default_provisional_account = provisional_account - company.save() + setup_provisional_accounting() pr = make_purchase_receipt( item_code="_Test Non Stock Item", posting_date=add_days(nowdate(), -2) @@ -1575,8 +1564,58 @@ class TestPurchaseInvoice(FrappeTestCase, StockTestMixin): self, pr.name, expected_gle_for_purchase_receipt_post_pi_cancel, pr.posting_date ) - company.enable_provisional_accounting_for_non_stock_items = 0 - company.save() + toggle_provisional_accounting_setting() + + def test_provisional_accounting_entry_for_over_billing(self): + setup_provisional_accounting() + + # Configure Buying Settings to allow rate change + frappe.db.set_single_value("Buying Settings", "maintain_same_rate", 0) + + # Create PR: rate = 1000, qty = 5 + pr = make_purchase_receipt( + item_code="_Test Non Stock Item", rate=1000, posting_date=add_days(nowdate(), -2) + ) + + # Overbill PR: rate = 2000, qty = 10 + pi = create_purchase_invoice_from_receipt(pr.name) + pi.set_posting_time = 1 + pi.posting_date = add_days(pr.posting_date, -1) + pi.items[0].qty = 10 + pi.items[0].rate = 2000 + pi.items[0].expense_account = "Cost of Goods Sold - _TC" + pi.save() + pi.submit() + + expected_gle = [ + ["Cost of Goods Sold - _TC", 20000, 0, add_days(pr.posting_date, -1)], + ["Creditors - _TC", 0, 20000, add_days(pr.posting_date, -1)], + ] + + check_gl_entries(self, pi.name, expected_gle, pi.posting_date) + + expected_gle_for_purchase_receipt = [ + ["Provision Account - _TC", 5000, 0, pr.posting_date], + ["_Test Account Cost for Goods Sold - _TC", 0, 5000, pr.posting_date], + ["Provision Account - _TC", 0, 5000, pi.posting_date], + ["_Test Account Cost for Goods Sold - _TC", 5000, 0, pi.posting_date], + ] + + check_gl_entries(self, pr.name, expected_gle_for_purchase_receipt, pr.posting_date) + + # Cancel purchase invoice to check reverse provisional entry cancellation + pi.cancel() + + expected_gle_for_purchase_receipt_post_pi_cancel = [ + ["Provision Account - _TC", 0, 5000, pi.posting_date], + ["_Test Account Cost for Goods Sold - _TC", 5000, 0, pi.posting_date], + ] + + check_gl_entries( + self, pr.name, expected_gle_for_purchase_receipt_post_pi_cancel, pr.posting_date + ) + + toggle_provisional_accounting_setting() def test_adjust_incoming_rate(self): frappe.db.set_single_value("Buying Settings", "maintain_same_rate", 0) @@ -2091,4 +2130,26 @@ def make_purchase_invoice_against_cost_center(**args): return pi +def setup_provisional_accounting(**args): + args = frappe._dict(args) + create_item("_Test Non Stock Item", is_stock_item=0) + company = args.company or "_Test Company" + provisional_account = create_account( + account_name=args.account_name or "Provision Account", + parent_account=args.parent_account or "Current Liabilities - _TC", + company=company, + ) + toggle_provisional_accounting_setting( + enable=1, company=company, provisional_account=provisional_account + ) + + +def toggle_provisional_accounting_setting(**args): + args = frappe._dict(args) + company = frappe.get_doc("Company", args.company or "_Test Company") + company.enable_provisional_accounting_for_non_stock_items = args.enable or 0 + company.default_provisional_account = args.provisional_account + company.save() + + test_records = frappe.get_test_records("Purchase Invoice") From c8b31833f5fff9b77455cf71eac85e5f599947b0 Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Mon, 5 Feb 2024 15:58:06 +0530 Subject: [PATCH 08/27] test: partial billing for provisional accounting (cherry picked from commit c5770f2eccc62c27f18a108ad60ae4f42946a9d6) --- .../purchase_invoice/test_purchase_invoice.py | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py index 1ce5a81eae5..ba97fc685a3 100644 --- a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py @@ -1617,6 +1617,45 @@ class TestPurchaseInvoice(FrappeTestCase, StockTestMixin): toggle_provisional_accounting_setting() + def test_provisional_accounting_entry_for_partial_billing(self): + setup_provisional_accounting() + + # Configure Buying Settings to allow rate change + frappe.db.set_single_value("Buying Settings", "maintain_same_rate", 0) + + # Create PR: rate = 1000, qty = 5 + pr = make_purchase_receipt( + item_code="_Test Non Stock Item", rate=1000, posting_date=add_days(nowdate(), -2) + ) + + # Partially bill PR: rate = 500, qty = 2 + pi = create_purchase_invoice_from_receipt(pr.name) + pi.set_posting_time = 1 + pi.posting_date = add_days(pr.posting_date, -1) + pi.items[0].qty = 2 + pi.items[0].rate = 500 + pi.items[0].expense_account = "Cost of Goods Sold - _TC" + pi.save() + pi.submit() + + expected_gle = [ + ["Cost of Goods Sold - _TC", 1000, 0, add_days(pr.posting_date, -1)], + ["Creditors - _TC", 0, 1000, add_days(pr.posting_date, -1)], + ] + + check_gl_entries(self, pi.name, expected_gle, pi.posting_date) + + expected_gle_for_purchase_receipt = [ + ["Provision Account - _TC", 5000, 0, pr.posting_date], + ["_Test Account Cost for Goods Sold - _TC", 0, 5000, pr.posting_date], + ["Provision Account - _TC", 0, 1000, pi.posting_date], + ["_Test Account Cost for Goods Sold - _TC", 1000, 0, pi.posting_date], + ] + + check_gl_entries(self, pr.name, expected_gle_for_purchase_receipt, pr.posting_date) + + toggle_provisional_accounting_setting() + def test_adjust_incoming_rate(self): frappe.db.set_single_value("Buying Settings", "maintain_same_rate", 0) From 646b55eeea46f6d9b2597e2beb3a1cdad461df8a Mon Sep 17 00:00:00 2001 From: barredterra <14891507+barredterra@users.noreply.github.com> Date: Thu, 29 Feb 2024 16:44:46 +0100 Subject: [PATCH 09/27] fix(Project): filter department by company (cherry picked from commit 5e736f0d061b05db8cdc0fd324fa3530079e7a07) --- erpnext/projects/doctype/project/project.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/erpnext/projects/doctype/project/project.js b/erpnext/projects/doctype/project/project.js index 8f7437fef8a..0cdd9c10e7f 100644 --- a/erpnext/projects/doctype/project/project.js +++ b/erpnext/projects/doctype/project/project.js @@ -35,6 +35,14 @@ frappe.ui.form.on("Project", { }; }); + frm.set_query("department", function (doc) { + return { + filters: { + "company": doc.company, + } + }; + }); + // sales order frm.set_query('sales_order', function () { var filters = { From 1b5a23709a751f925d78c476bd5e51b743135d3f Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Tue, 27 Feb 2024 15:34:34 +0530 Subject: [PATCH 10/27] fix: incorrect exchange rate if JE has multi parties (cherry picked from commit 694c17487d76ddc38764d58311ff2153a15d1ee5) --- .../payment_reconciliation/payment_reconciliation.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py index 5605d068187..33f736fe915 100644 --- a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py +++ b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py @@ -566,7 +566,12 @@ class PaymentReconciliation(Document): journals_map = frappe._dict( frappe.db.get_all( "Journal Entry Account", - filters={"parent": ("in", journals), "account": ("in", [self.receivable_payable_account])}, + filters={ + "parent": ("in", journals), + "account": ("in", [self.receivable_payable_account]), + "party_type": self.party_type, + "party": self.party, + }, fields=[ "parent as `name`", "exchange_rate", From e25ec4156e894c855d6b7bef8b9b5868d29420cc Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Wed, 28 Feb 2024 17:07:37 +0530 Subject: [PATCH 11/27] fix: don't override reference exchange rate (cherry picked from commit eaac02655b174cca9daa2d16ba85c335e70879c3) --- erpnext/accounts/doctype/payment_entry/payment_entry.py | 7 ++++++- erpnext/accounts/utils.py | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py index b89854b172a..d04f0ac7f3c 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.py +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py @@ -335,7 +335,10 @@ class PaymentEntry(AccountsController): ) def set_missing_ref_details( - self, force: bool = False, update_ref_details_only_for: list | None = None + self, + force: bool = False, + update_ref_details_only_for: list | None = None, + ref_exchange_rate: float | None = None, ) -> None: for d in self.get("references"): if d.allocated_amount: @@ -347,6 +350,8 @@ class PaymentEntry(AccountsController): ref_details = get_reference_details( d.reference_doctype, d.reference_name, self.party_account_currency ) + if ref_exchange_rate: + ref_details.update({"exchange_rate": ref_exchange_rate}) for field, value in ref_details.items(): if d.exchange_gain_loss: diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py index 280cf338f70..4f1f967f202 100644 --- a/erpnext/accounts/utils.py +++ b/erpnext/accounts/utils.py @@ -682,7 +682,7 @@ def update_reference_in_payment_entry( payment_entry.setup_party_account_field() payment_entry.set_missing_values() if not skip_ref_details_update_for_pe: - payment_entry.set_missing_ref_details() + payment_entry.set_missing_ref_details(ref_exchange_rate=d.exchange_rate or None) payment_entry.set_amounts() payment_entry.make_exchange_gain_loss_journal( From 572def058f9a995ff31fe3daac19ea40efdf2e76 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Wed, 28 Feb 2024 17:07:57 +0530 Subject: [PATCH 12/27] test: exchange rate fetch on JE with multiple forex parties (cherry picked from commit ed95d41a51687208e603ffc355fa717018d14185) --- .../test_payment_reconciliation.py | 100 ++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/erpnext/accounts/doctype/payment_reconciliation/test_payment_reconciliation.py b/erpnext/accounts/doctype/payment_reconciliation/test_payment_reconciliation.py index fb75a0f7caf..eb4396a5c6f 100644 --- a/erpnext/accounts/doctype/payment_reconciliation/test_payment_reconciliation.py +++ b/erpnext/accounts/doctype/payment_reconciliation/test_payment_reconciliation.py @@ -56,6 +56,7 @@ class TestPaymentReconciliation(FrappeTestCase): self.expense_account = "Cost of Goods Sold - _PR" self.debit_to = "Debtors - _PR" self.creditors = "Creditors - _PR" + self.cash = "Cash - _PR" # create bank account if frappe.db.exists("Account", "HDFC - _PR"): @@ -486,6 +487,91 @@ class TestPaymentReconciliation(FrappeTestCase): self.assertEqual(len(pr.get("invoices")), 0) self.assertEqual(len(pr.get("payments")), 0) + def test_payment_against_foreign_currency_journal(self): + transaction_date = nowdate() + + self.supplier = "_Test Supplier USD" + self.supplier2 = make_supplier("_Test Supplier2 USD", "USD") + amount = 100 + exc_rate1 = 80 + exc_rate2 = 83 + + je = frappe.new_doc("Journal Entry") + je.posting_date = transaction_date + je.company = self.company + je.user_remark = "test" + je.multi_currency = 1 + je.set( + "accounts", + [ + { + "account": self.creditors_usd, + "party_type": "Supplier", + "party": self.supplier, + "exchange_rate": exc_rate1, + "cost_center": self.cost_center, + "credit": amount * exc_rate1, + "credit_in_account_currency": amount, + }, + { + "account": self.creditors_usd, + "party_type": "Supplier", + "party": self.supplier2, + "exchange_rate": exc_rate2, + "cost_center": self.cost_center, + "credit": amount * exc_rate2, + "credit_in_account_currency": amount, + }, + { + "account": self.expense_account, + "cost_center": self.cost_center, + "debit": (amount * exc_rate1) + (amount * exc_rate2), + "debit_in_account_currency": (amount * exc_rate1) + (amount * exc_rate2), + }, + ], + ) + je.save().submit() + + pe = self.create_payment_entry(amount=amount, posting_date=transaction_date) + pe.payment_type = "Pay" + pe.party_type = "Supplier" + pe.party = self.supplier + pe.paid_to = self.creditors_usd + pe.paid_from = self.cash + pe.paid_amount = 8000 + pe.received_amount = 100 + pe.target_exchange_rate = exc_rate1 + pe.paid_to_account_currency = "USD" + pe.save().submit() + + pr = self.create_payment_reconciliation(party_is_customer=False) + pr.receivable_payable_account = self.creditors_usd + pr.minimum_invoice_amount = pr.maximum_invoice_amount = amount + pr.from_invoice_date = pr.to_invoice_date = transaction_date + pr.from_payment_date = pr.to_payment_date = transaction_date + + pr.get_unreconciled_entries() + invoices = [x.as_dict() for x in pr.get("invoices")] + payments = [x.as_dict() for x in pr.get("payments")] + pr.allocate_entries(frappe._dict({"invoices": invoices, "payments": payments})) + + # There should no difference_amount as the Journal and Payment have same exchange rate - 'exc_rate1' + for row in pr.allocation: + self.assertEqual(flt(row.get("difference_amount")), 0.0) + + pr.reconcile() + + # check PR tool output + self.assertEqual(len(pr.get("invoices")), 0) + self.assertEqual(len(pr.get("payments")), 0) + + journals = frappe.db.get_all( + "Journal Entry Account", + filters={"reference_type": je.doctype, "reference_name": je.name, "docstatus": 1}, + fields=["parent"], + ) + self.assertEqual([], journals) + def test_journal_against_invoice(self): transaction_date = nowdate() amount = 100 @@ -1248,3 +1334,17 @@ def make_customer(customer_name, currency=None): return customer.name else: return customer_name + + +def make_supplier(supplier_name, currency=None): + if not frappe.db.exists("Supplier", supplier_name): + supplier = frappe.new_doc("Supplier") + supplier.supplier_name = supplier_name + supplier.type = "Individual" + supplier.supplier_group = "Local" + if currency: + supplier.default_currency = currency + supplier.save() + return supplier.name + else: + return supplier_name From 64bf52899f0cf69922a9640699271cd060eb2088 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Sat, 2 Mar 2024 14:57:48 +0530 Subject: [PATCH 13/27] chore: resolve linter --- erpnext/accounts/doctype/bank_account/bank_account.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/bank_account/bank_account.py b/erpnext/accounts/doctype/bank_account/bank_account.py index ec3fa831200..28a4a41e28e 100644 --- a/erpnext/accounts/doctype/bank_account/bank_account.py +++ b/erpnext/accounts/doctype/bank_account/bank_account.py @@ -30,7 +30,9 @@ class BankAccount(Document): def validate_account(self): if self.account: - if accounts := frappe.db.get_all("Bank Account", filters={"account": self.account, 'name':['!=', self.name]}, as_list=1): + if accounts := frappe.db.get_all( + "Bank Account", filters={"account": self.account, "name": ["!=", self.name]}, as_list=1 + ): frappe.throw( _("'{0}' account is already used by {1}. Use another account.").format( frappe.bold(self.account), From c1a0ac655ea5fd3b9d8d00f36c5ea15ca5af3038 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Fri, 1 Mar 2024 17:36:56 +0530 Subject: [PATCH 14/27] fix: make use of 'flt' to prevent really low precision exc gain/loss (cherry picked from commit 0aa72f841dbfb4a19fc6f7802172dcc5667369d7) --- erpnext/controllers/accounts_controller.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index 560e7715e68..0795ab0f747 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -45,6 +45,7 @@ from erpnext.accounts.party import ( from erpnext.accounts.utils import ( create_gain_loss_journal, get_account_currency, + get_currency_precision, get_fiscal_years, validate_fiscal_year, ) @@ -1169,10 +1170,12 @@ class AccountsController(TransactionBase): # These are generated by Sales/Purchase Invoice during reconciliation and advance allocation. # and below logic is only for such scenarios if args: + precision = get_currency_precision() for arg in args: # Advance section uses `exchange_gain_loss` and reconciliation uses `difference_amount` if ( - arg.get("difference_amount", 0) != 0 or arg.get("exchange_gain_loss", 0) != 0 + flt(arg.get("difference_amount", 0), precision) != 0 + or flt(arg.get("exchange_gain_loss", 0), precision) != 0 ) and arg.get("difference_account"): party_account = arg.get("account") From 52e1c2f48b6750767fe1e047ff31499b727dcef9 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Fri, 1 Mar 2024 17:46:42 +0530 Subject: [PATCH 15/27] fix: allow gain/loss for Journals against Journals (cherry picked from commit 5b67631d40ddebcc6111aecb9c2f8882903d88f9) # Conflicts: # erpnext/accounts/doctype/journal_entry/journal_entry.py --- .../doctype/journal_entry/journal_entry.py | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py index 6e3019bb8f0..3f427332276 100644 --- a/erpnext/accounts/doctype/journal_entry/journal_entry.py +++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py @@ -475,17 +475,33 @@ class JournalEntry(AccountsController): elif d.party_type == "Supplier" and flt(d.credit) > 0: frappe.throw(_("Row {0}: Advance against Supplier must be debit").format(d.idx)) + def system_generated_gain_loss(self): + return ( + self.voucher_type == "Exchange Gain Or Loss" + and self.multi_currency + and self.is_system_generated + ) + def validate_against_jv(self): for d in self.get("accounts"): if d.reference_type == "Journal Entry": +<<<<<<< HEAD account_root_type = frappe.db.get_value("Account", d.account, "root_type") if account_root_type == "Asset" and flt(d.debit) > 0: +======= + account_root_type = frappe.get_cached_value("Account", d.account, "root_type") + if account_root_type == "Asset" and flt(d.debit) > 0 and not self.system_generated_gain_loss(): +>>>>>>> 5b67631d40 (fix: allow gain/loss for Journals against Journals) frappe.throw( _( "Row #{0}: For {1}, you can select reference document only if account gets credited" ).format(d.idx, d.account) ) - elif account_root_type == "Liability" and flt(d.credit) > 0: + elif ( + account_root_type == "Liability" + and flt(d.credit) > 0 + and not self.system_generated_gain_loss() + ): frappe.throw( _( "Row #{0}: For {1}, you can select reference document only if account gets debited" @@ -517,7 +533,7 @@ class JournalEntry(AccountsController): for jvd in against_entries: if flt(jvd[dr_or_cr]) > 0: valid = True - if not valid: + if not valid and not self.system_generated_gain_loss(): frappe.throw( _("Against Journal Entry {0} does not have any unmatched {1} entry").format( d.reference_name, dr_or_cr From 46063518d75601d8cea175c1739de28b9d885169 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Fri, 1 Mar 2024 17:53:51 +0530 Subject: [PATCH 16/27] test: gain/loss on Journals against Journals (cherry picked from commit 8a5078b826e9390bc63069fefff3cf3de8bae449) # Conflicts: # erpnext/controllers/tests/test_accounts_controller.py --- .../tests/test_accounts_controller.py | 81 +++++++++++++++++-- 1 file changed, 76 insertions(+), 5 deletions(-) diff --git a/erpnext/controllers/tests/test_accounts_controller.py b/erpnext/controllers/tests/test_accounts_controller.py index 0c9d34d82a2..daea1d8b399 100644 --- a/erpnext/controllers/tests/test_accounts_controller.py +++ b/erpnext/controllers/tests/test_accounts_controller.py @@ -56,7 +56,8 @@ class TestAccountsController(FrappeTestCase): 20 series - Sales Invoice against Journals 30 series - Sales Invoice against Credit Notes 40 series - Company default Cost center is unset - 50 series - Dimension inheritence + 50 series = Journals against Journals + 90 series - Dimension inheritence """ def setUp(self): @@ -1306,7 +1307,7 @@ class TestAccountsController(FrappeTestCase): dimension1.disabled = 1 dimension1.save() - def test_50_dimensions_filter(self): + def test_90_dimensions_filter(self): """ Test workings of dimension filters """ @@ -1378,7 +1379,7 @@ class TestAccountsController(FrappeTestCase): self.assertEqual(len(pr.payments), 1) self.disable_dimensions() - def test_51_cr_note_should_inherit_dimension(self): + def test_91_cr_note_should_inherit_dimension(self): self.setup_dimensions() rate_in_account_currency = 1 @@ -1421,7 +1422,7 @@ class TestAccountsController(FrappeTestCase): ) self.disable_dimensions() - def test_52_dimension_inhertiance_exc_gain_loss(self): + def test_92_dimension_inhertiance_exc_gain_loss(self): # Sales Invoice in Foreign Currency self.setup_dimensions() rate = 80 @@ -1460,7 +1461,7 @@ class TestAccountsController(FrappeTestCase): ) self.disable_dimensions() - def test_53_dimension_inheritance_on_advance(self): + def test_93_dimension_inheritance_on_advance(self): self.setup_dimensions() dpt = "Research & Development" @@ -1505,4 +1506,74 @@ class TestAccountsController(FrappeTestCase): pluck="department", ), ) +<<<<<<< HEAD self.disable_dimensions() +======= + + def test_50_journal_against_journal(self): + # Invoice in Foreign Currency + journal_as_invoice = self.create_journal_entry( + acc1=self.debit_usd, + acc1_exc_rate=83, + acc2=self.cash, + acc1_amount=1, + acc2_amount=83, + acc2_exc_rate=1, + ) + journal_as_invoice.accounts[0].party_type = "Customer" + journal_as_invoice.accounts[0].party = self.customer + journal_as_invoice = journal_as_invoice.save().submit() + + # Payment + journal_as_payment = self.create_journal_entry( + acc1=self.debit_usd, + acc1_exc_rate=75, + acc2=self.cash, + acc1_amount=-1, + acc2_amount=-75, + acc2_exc_rate=1, + ) + journal_as_payment.accounts[0].party_type = "Customer" + journal_as_payment.accounts[0].party = self.customer + journal_as_payment = journal_as_payment.save().submit() + + # Reconcile the remaining amount + pr = self.create_payment_reconciliation() + # pr.receivable_payable_account = self.debit_usd + pr.get_unreconciled_entries() + self.assertEqual(len(pr.invoices), 1) + self.assertEqual(len(pr.payments), 1) + invoices = [x.as_dict() for x in pr.invoices] + payments = [x.as_dict() for x in pr.payments] + pr.allocate_entries(frappe._dict({"invoices": invoices, "payments": payments})) + pr.reconcile() + self.assertEqual(len(pr.invoices), 0) + self.assertEqual(len(pr.payments), 0) + + # There should be no outstanding in both currencies + journal_as_invoice.reload() + self.assert_ledger_outstanding(journal_as_invoice.doctype, journal_as_invoice.name, 0.0, 0.0) + + # Exchange Gain/Loss Journal should've been created. + exc_je_for_si = self.get_journals_for(journal_as_invoice.doctype, journal_as_invoice.name) + exc_je_for_je = self.get_journals_for(journal_as_payment.doctype, journal_as_payment.name) + self.assertNotEqual(exc_je_for_si, []) + self.assertEqual( + len(exc_je_for_si), 2 + ) # payment also has reference. so, there are 2 journals referencing invoice + self.assertEqual(len(exc_je_for_je), 1) + self.assertIn(exc_je_for_je[0], exc_je_for_si) + + # Cancel Payment + journal_as_payment.reload() + journal_as_payment.cancel() + + journal_as_invoice.reload() + self.assert_ledger_outstanding(journal_as_invoice.doctype, journal_as_invoice.name, 83.0, 1.0) + + # Exchange Gain/Loss Journal should've been cancelled + exc_je_for_si = self.get_journals_for(journal_as_invoice.doctype, journal_as_invoice.name) + exc_je_for_je = self.get_journals_for(journal_as_payment.doctype, journal_as_payment.name) + self.assertEqual(exc_je_for_si, []) + self.assertEqual(exc_je_for_je, []) +>>>>>>> 8a5078b826 (test: gain/loss on Journals against Journals) From 753223da7851fffc43bb0697d9ff9b1755c6d1c0 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Sat, 2 Mar 2024 15:59:48 +0530 Subject: [PATCH 17/27] chore: resolve merge conflict --- erpnext/accounts/doctype/journal_entry/journal_entry.py | 5 ----- erpnext/controllers/tests/test_accounts_controller.py | 3 --- 2 files changed, 8 deletions(-) diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py index 3f427332276..7ea21c9f134 100644 --- a/erpnext/accounts/doctype/journal_entry/journal_entry.py +++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py @@ -485,13 +485,8 @@ class JournalEntry(AccountsController): def validate_against_jv(self): for d in self.get("accounts"): if d.reference_type == "Journal Entry": -<<<<<<< HEAD - account_root_type = frappe.db.get_value("Account", d.account, "root_type") - if account_root_type == "Asset" and flt(d.debit) > 0: -======= account_root_type = frappe.get_cached_value("Account", d.account, "root_type") if account_root_type == "Asset" and flt(d.debit) > 0 and not self.system_generated_gain_loss(): ->>>>>>> 5b67631d40 (fix: allow gain/loss for Journals against Journals) frappe.throw( _( "Row #{0}: For {1}, you can select reference document only if account gets credited" diff --git a/erpnext/controllers/tests/test_accounts_controller.py b/erpnext/controllers/tests/test_accounts_controller.py index daea1d8b399..e39d03dccb9 100644 --- a/erpnext/controllers/tests/test_accounts_controller.py +++ b/erpnext/controllers/tests/test_accounts_controller.py @@ -1506,9 +1506,7 @@ class TestAccountsController(FrappeTestCase): pluck="department", ), ) -<<<<<<< HEAD self.disable_dimensions() -======= def test_50_journal_against_journal(self): # Invoice in Foreign Currency @@ -1576,4 +1574,3 @@ class TestAccountsController(FrappeTestCase): exc_je_for_je = self.get_journals_for(journal_as_payment.doctype, journal_as_payment.name) self.assertEqual(exc_je_for_si, []) self.assertEqual(exc_je_for_je, []) ->>>>>>> 8a5078b826 (test: gain/loss on Journals against Journals) From b937c4be4f25d079a5340402f8702515005b698e Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Sat, 2 Mar 2024 16:49:40 +0530 Subject: [PATCH 18/27] fix: rate change on changing of the qty (backport #40241) (#40242) fix: rate change on changing of the qty (#40241) (cherry picked from commit e7d707797aeab2f5d209690c959e88851c9a6999) Co-authored-by: rohitwaghchaure --- erpnext/public/js/controllers/taxes_and_totals.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/public/js/controllers/taxes_and_totals.js b/erpnext/public/js/controllers/taxes_and_totals.js index c179928b511..186c342a75e 100644 --- a/erpnext/public/js/controllers/taxes_and_totals.js +++ b/erpnext/public/js/controllers/taxes_and_totals.js @@ -22,7 +22,7 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments { item_rate = flt(item.rate_with_margin , precision("rate", item)); - if (item.discount_percentage) { + if (item.discount_percentage && !item.discount_amount) { item.discount_amount = flt(item.rate_with_margin) * flt(item.discount_percentage) / 100; } From 89e7ad790fd2c135299b465d1483443d01a3ada0 Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Sun, 3 Mar 2024 18:00:10 +0530 Subject: [PATCH 19/27] chore: linting issue --- erpnext/accounts/doctype/bank_account/bank_account.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/bank_account/bank_account.py b/erpnext/accounts/doctype/bank_account/bank_account.py index ec3fa831200..28a4a41e28e 100644 --- a/erpnext/accounts/doctype/bank_account/bank_account.py +++ b/erpnext/accounts/doctype/bank_account/bank_account.py @@ -30,7 +30,9 @@ class BankAccount(Document): def validate_account(self): if self.account: - if accounts := frappe.db.get_all("Bank Account", filters={"account": self.account, 'name':['!=', self.name]}, as_list=1): + if accounts := frappe.db.get_all( + "Bank Account", filters={"account": self.account, "name": ["!=", self.name]}, as_list=1 + ): frappe.throw( _("'{0}' account is already used by {1}. Use another account.").format( frappe.bold(self.account), From 38baf8d4061969f08aecbedba4b456e6551b1678 Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Sun, 3 Mar 2024 18:08:23 +0530 Subject: [PATCH 20/27] feat: add company filter to child table field (cherry picked from commit 51909077bd90fe86ab3e1c916412a18e183ab823) --- .../cost_center_allocation.js | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/erpnext/accounts/doctype/cost_center_allocation/cost_center_allocation.js b/erpnext/accounts/doctype/cost_center_allocation/cost_center_allocation.js index ab0baab24a0..0da90161f51 100644 --- a/erpnext/accounts/doctype/cost_center_allocation/cost_center_allocation.js +++ b/erpnext/accounts/doctype/cost_center_allocation/cost_center_allocation.js @@ -3,16 +3,21 @@ frappe.ui.form.on('Cost Center Allocation', { setup: function(frm) { - let filters = {"is_group": 0}; - if (frm.doc.company) { - $.extend(filters, { - "company": frm.doc.company - }); - } - frm.set_query('main_cost_center', function() { return { - filters: filters + filters: { + company: frm.doc.company, + is_group: 0 + } + }; + }); + + frm.set_query('cost_center', 'allocation_percentages', function() { + return { + filters: { + company: frm.doc.company, + is_group: 0 + } }; }); } From 85a7ce6d30e7481409469d2e07cb221904ea64dc Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Thu, 12 Oct 2023 11:54:12 +0530 Subject: [PATCH 21/27] refactor: remove balance fields from jv account --- .../journal_entry_account.json | 21 ------------------- 1 file changed, 21 deletions(-) diff --git a/erpnext/accounts/doctype/journal_entry_account/journal_entry_account.json b/erpnext/accounts/doctype/journal_entry_account/journal_entry_account.json index 3132fe9b12b..94a050a9004 100644 --- a/erpnext/accounts/doctype/journal_entry_account/journal_entry_account.json +++ b/erpnext/accounts/doctype/journal_entry_account/journal_entry_account.json @@ -9,12 +9,10 @@ "field_order": [ "account", "account_type", - "balance", "col_break1", "bank_account", "party_type", "party", - "party_balance", "accounting_dimensions_section", "cost_center", "dimension_col_break", @@ -63,17 +61,6 @@ "label": "Account Type", "print_hide": 1 }, - { - "fieldname": "balance", - "fieldtype": "Currency", - "label": "Account Balance", - "no_copy": 1, - "oldfieldname": "balance", - "oldfieldtype": "Data", - "options": "account_currency", - "print_hide": 1, - "read_only": 1 - }, { "default": ":Company", "description": "If Income or Expense", @@ -107,14 +94,6 @@ "label": "Party", "options": "party_type" }, - { - "fieldname": "party_balance", - "fieldtype": "Currency", - "label": "Party Balance", - "options": "account_currency", - "print_hide": 1, - "read_only": 1 - }, { "fieldname": "currency_section", "fieldtype": "Section Break", From d715c29edc3246e5b16c554fa64aa04c1700c018 Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Thu, 12 Oct 2023 12:04:44 +0530 Subject: [PATCH 22/27] refactor: remove balance formatter --- .../doctype/journal_entry/journal_entry.js | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.js b/erpnext/accounts/doctype/journal_entry/journal_entry.js index f86320d917a..948e2d47d95 100644 --- a/erpnext/accounts/doctype/journal_entry/journal_entry.js +++ b/erpnext/accounts/doctype/journal_entry/journal_entry.js @@ -184,7 +184,6 @@ var update_jv_details = function(doc, r) { $.each(r, function(i, d) { var row = frappe.model.add_child(doc, "Journal Entry Account", "accounts"); frappe.model.set_value(row.doctype, row.name, "account", d.account) - frappe.model.set_value(row.doctype, row.name, "balance", d.balance) }); refresh_field("accounts"); } @@ -193,7 +192,6 @@ erpnext.accounts.JournalEntry = class JournalEntry extends frappe.ui.form.Contro onload() { this.load_defaults(); this.setup_queries(); - this.setup_balance_formatter(); erpnext.accounts.dimensions.setup_dimension_filters(this.frm, this.frm.doctype); } @@ -292,19 +290,6 @@ erpnext.accounts.JournalEntry = class JournalEntry extends frappe.ui.form.Contro } - setup_balance_formatter() { - const formatter = function(value, df, options, doc) { - var currency = frappe.meta.get_field_currency(df, doc); - var dr_or_cr = value ? ('') : ""; - return "
" - + ((value==null || value==="") ? "" : format_currency(Math.abs(value), currency)) - + " " + dr_or_cr - + "
"; - }; - this.frm.fields_dict.accounts.grid.update_docfield_property('balance', 'formatter', formatter); - this.frm.fields_dict.accounts.grid.update_docfield_property('party_balance', 'formatter', formatter); - } - reference_name(doc, cdt, cdn) { var d = frappe.get_doc(cdt, cdn); From a1c22811a246a41082817f64ea980425eae8a7b2 Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Thu, 12 Oct 2023 12:07:36 +0530 Subject: [PATCH 23/27] refactor: exclude balance while setting acc details --- erpnext/accounts/doctype/journal_entry/journal_entry.js | 9 ++++----- erpnext/accounts/doctype/journal_entry/journal_entry.py | 5 ++--- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.js b/erpnext/accounts/doctype/journal_entry/journal_entry.js index 948e2d47d95..8196589829d 100644 --- a/erpnext/accounts/doctype/journal_entry/journal_entry.js +++ b/erpnext/accounts/doctype/journal_entry/journal_entry.js @@ -397,11 +397,11 @@ frappe.ui.form.on("Journal Entry Account", { } }, cost_center: function(frm, dt, dn) { - erpnext.journal_entry.set_account_balance(frm, dt, dn); + erpnext.journal_entry.set_account_details(frm, dt, dn); }, account: function(frm, dt, dn) { - erpnext.journal_entry.set_account_balance(frm, dt, dn); + erpnext.journal_entry.set_account_details(frm, dt, dn); }, debit_in_account_currency: function(frm, cdt, cdn) { @@ -585,14 +585,14 @@ $.extend(erpnext.journal_entry, { }); $.extend(erpnext.journal_entry, { - set_account_balance: function(frm, dt, dn) { + set_account_details: function(frm, dt, dn) { var d = locals[dt][dn]; if(d.account) { if(!frm.doc.company) frappe.throw(__("Please select Company first")); if(!frm.doc.posting_date) frappe.throw(__("Please select Posting Date first")); return frappe.call({ - method: "erpnext.accounts.doctype.journal_entry.journal_entry.get_account_balance_and_party_type", + method: "erpnext.accounts.doctype.journal_entry.journal_entry.get_account_details_and_party_type", args: { account: d.account, date: frm.doc.posting_date, @@ -600,7 +600,6 @@ $.extend(erpnext.journal_entry, { debit: flt(d.debit_in_account_currency), credit: flt(d.credit_in_account_currency), exchange_rate: d.exchange_rate, - cost_center: d.cost_center }, callback: function(r) { if(r.message) { diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py index 7ea21c9f134..0fbeb302aeb 100644 --- a/erpnext/accounts/doctype/journal_entry/journal_entry.py +++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py @@ -1425,8 +1425,8 @@ def get_party_account_and_balance(company, party_type, party, cost_center=None): @frappe.whitelist() -def get_account_balance_and_party_type( - account, date, company, debit=None, credit=None, exchange_rate=None, cost_center=None +def get_account_details_and_party_type( + account, date, company, debit=None, credit=None, exchange_rate=None ): """Returns dict of account balance and party type to be set in Journal Entry on selection of account.""" if not frappe.has_permission("Account"): @@ -1448,7 +1448,6 @@ def get_account_balance_and_party_type( party_type = "" grid_values = { - "balance": get_balance_on(account, date, cost_center=cost_center), "party_type": party_type, "account_type": account_details.account_type, "account_currency": account_details.account_currency or company_currency, From e3d6f70eeecc212559b877e01a1acf40f651bac3 Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Thu, 12 Oct 2023 12:09:58 +0530 Subject: [PATCH 24/27] refactor: exclude balances while setting currency --- .../accounts/doctype/journal_entry/journal_entry.js | 3 +-- .../accounts/doctype/journal_entry/journal_entry.py | 11 ++--------- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.js b/erpnext/accounts/doctype/journal_entry/journal_entry.js index 8196589829d..5f59f036ef9 100644 --- a/erpnext/accounts/doctype/journal_entry/journal_entry.js +++ b/erpnext/accounts/doctype/journal_entry/journal_entry.js @@ -385,13 +385,12 @@ frappe.ui.form.on("Journal Entry Account", { if(!d.account && d.party_type && d.party) { if(!frm.doc.company) frappe.throw(__("Please select Company")); return frm.call({ - method: "erpnext.accounts.doctype.journal_entry.journal_entry.get_party_account_and_balance", + method: "erpnext.accounts.doctype.journal_entry.journal_entry.get_party_account_and_currency", child: d, args: { company: frm.doc.company, party_type: d.party_type, party: d.party, - cost_center: d.cost_center } }); } diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py index 0fbeb302aeb..fa20ecfd64e 100644 --- a/erpnext/accounts/doctype/journal_entry/journal_entry.py +++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py @@ -1405,22 +1405,15 @@ def get_outstanding(args): @frappe.whitelist() -def get_party_account_and_balance(company, party_type, party, cost_center=None): +def get_party_account_and_currency(company, party_type, party): if not frappe.has_permission("Account"): frappe.msgprint(_("No Permission"), raise_exception=1) account = get_party_account(party_type, party, company) - account_balance = get_balance_on(account=account, cost_center=cost_center) - party_balance = get_balance_on( - party_type=party_type, party=party, company=company, cost_center=cost_center - ) - return { "account": account, - "balance": account_balance, - "party_balance": party_balance, - "account_currency": frappe.db.get_value("Account", account, "account_currency"), + "account_currency": frappe.get_cached_value("Account", account, "account_currency"), } From 2f8fe17b60848bf5568d9677dc02f32a6c28001e Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Thu, 12 Oct 2023 12:13:21 +0530 Subject: [PATCH 25/27] refactor: remove controller logic for setting balances --- .../doctype/journal_entry/journal_entry.py | 20 +------------------ 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py index fa20ecfd64e..88388128653 100644 --- a/erpnext/accounts/doctype/journal_entry/journal_entry.py +++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py @@ -68,7 +68,6 @@ class JournalEntry(AccountsController): self.set_print_format_fields() self.validate_credit_debit_note() self.validate_empty_accounts_table() - self.set_account_and_party_balance() self.validate_inter_company_accounts() self.validate_depr_entry_voucher_type() @@ -1076,21 +1075,6 @@ class JournalEntry(AccountsController): if not self.get("accounts"): frappe.throw(_("Accounts table cannot be blank.")) - def set_account_and_party_balance(self): - account_balance = {} - party_balance = {} - for d in self.get("accounts"): - if d.account not in account_balance: - account_balance[d.account] = get_balance_on(account=d.account, date=self.posting_date) - - if (d.party_type, d.party) not in party_balance: - party_balance[(d.party_type, d.party)] = get_balance_on( - party_type=d.party_type, party=d.party, date=self.posting_date, company=self.company - ) - - d.account_balance = account_balance[d.account] - d.party_balance = party_balance[(d.party_type, d.party)] - @frappe.whitelist() def get_default_bank_cash_account(company, account_type=None, mode_of_payment=None, account=None): @@ -1256,8 +1240,6 @@ def get_payment_entry(ref_doc, args): "account_type": frappe.db.get_value("Account", args.get("party_account"), "account_type"), "account_currency": args.get("party_account_currency") or get_account_currency(args.get("party_account")), - "balance": get_balance_on(args.get("party_account")), - "party_balance": get_balance_on(party=args.get("party"), party_type=args.get("party_type")), "exchange_rate": exchange_rate, args.get("amount_field_party"): args.get("amount"), "is_advance": args.get("is_advance"), @@ -1421,7 +1403,7 @@ def get_party_account_and_currency(company, party_type, party): def get_account_details_and_party_type( account, date, company, debit=None, credit=None, exchange_rate=None ): - """Returns dict of account balance and party type to be set in Journal Entry on selection of account.""" + """Returns dict of account details and party type to be set in Journal Entry on selection of account.""" if not frappe.has_permission("Account"): frappe.msgprint(_("No Permission"), raise_exception=1) From 091d6f330a8ecc48e1797955dd36a70587ddb698 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Mon, 4 Mar 2024 13:14:32 +0530 Subject: [PATCH 26/27] fix: do not allow to cancel incomplete reposting (backport #40224) (#40229) * fix: do not allow to cancel incomplete reposting (#40224) (cherry picked from commit 72ac56b6c4366910f7fc4f561811240ad0694965) # Conflicts: # erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py * chore: fix conflicts --------- Co-authored-by: rohitwaghchaure --- .../repost_item_valuation/repost_item_valuation.py | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py index 5d087a46242..4d3e9f0aaf6 100644 --- a/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py +++ b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py @@ -173,14 +173,9 @@ class RepostItemValuation(Document): if self.status not in ("Queued", "In Progress"): return - if not (self.voucher_no and self.voucher_no): - return - - transaction_status = frappe.db.get_value(self.voucher_type, self.voucher_no, "docstatus") - if transaction_status == 2: - msg = _("Cannot cancel as processing of cancelled documents is pending.") - msg += "
" + _("Please try again in an hour.") - frappe.throw(msg, title=_("Pending processing")) + msg = _("Cannot cancel as processing of cancelled documents is pending.") + msg += "
" + _("Please try again in an hour.") + frappe.throw(msg, title=_("Pending processing")) @frappe.whitelist() def restart_reposting(self): From af568464dbb05d5dc3922daffbf8b57a956f85c6 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Tue, 5 Mar 2024 14:46:24 +0530 Subject: [PATCH 27/27] fix: incorrect TCS on customer and suppliers with same name (cherry picked from commit 9904a9868c346028fa3b1809ac575ea1e1c6632b) --- .../tax_withholding_category/tax_withholding_category.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py index 943c0057f99..1d1955e3d51 100644 --- a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py +++ b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py @@ -522,6 +522,7 @@ def get_tcs_amount(parties, inv, tax_details, vouchers, adv_vouchers): "GL Entry", { "is_cancelled": 0, + "party_type": "Customer", "party": ["in", parties], "company": inv.company, "voucher_no": ["in", vouchers], @@ -536,6 +537,7 @@ def get_tcs_amount(parties, inv, tax_details, vouchers, adv_vouchers): conditions = [] conditions.append(ple.amount.lt(0)) conditions.append(ple.delinked == 0) + conditions.append(ple.party_type == "Customer") conditions.append(ple.party.isin(parties)) conditions.append(ple.voucher_no == ple.against_voucher_no) conditions.append(ple.company == inv.company) @@ -555,6 +557,7 @@ def get_tcs_amount(parties, inv, tax_details, vouchers, adv_vouchers): { "is_cancelled": 0, "credit": [">", 0], + "party_type": "Customer", "party": ["in", parties], "posting_date": ["between", (tax_details.from_date, tax_details.to_date)], "company": inv.company,