From 86aa072235655fb29c16e6a8002c5b2846944e0c Mon Sep 17 00:00:00 2001 From: Bhavan23 Date: Mon, 12 May 2025 12:44:18 +0530 Subject: [PATCH 1/2] fix: validate inter-company transaction address links (cherry picked from commit aed46ad5b96c08bbcddc9953029973c54bdfbeba) --- .../doctype/sales_invoice/sales_invoice.py | 73 ++++++++++++++----- .../doctype/delivery_note/delivery_note.py | 73 ++++++++++++++----- 2 files changed, 112 insertions(+), 34 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index 3d46d95f5aa..5c6ed7a1320 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -2286,6 +2286,18 @@ def make_inter_company_transaction(doctype, source_name, target_doc=None): set_purchase_references(target) def update_details(source_doc, target_doc, source_parent): + def _validate_address_link(address, link_doctype, link_name): + return frappe.db.get_value( + "Dynamic Link", + { + "parent": address, + "parenttype": "Address", + "link_doctype": link_doctype, + "link_name": link_name, + }, + "parent", + ) + target_doc.inter_company_invoice_reference = source_doc.name if target_doc.doctype in ["Purchase Invoice", "Purchase Order"]: currency = frappe.db.get_value("Supplier", details.get("party"), "default_currency") @@ -2296,16 +2308,34 @@ def make_inter_company_transaction(doctype, source_name, target_doc=None): target_doc.buying_price_list = source_doc.selling_price_list # Invert Addresses - update_address(target_doc, "supplier_address", "address_display", source_doc.company_address) - update_address( - target_doc, "dispatch_address", "dispatch_address_display", source_doc.dispatch_address_name - ) - update_address( - target_doc, "shipping_address", "shipping_address_display", source_doc.shipping_address_name - ) - update_address( - target_doc, "billing_address", "billing_address_display", source_doc.customer_address - ) + if source_doc.company_address and _validate_address_link( + source_doc.company_address, "Supplier", details.get("party") + ): + update_address(target_doc, "supplier_address", "address_display", source_doc.company_address) + if source_doc.dispatch_address_name and _validate_address_link( + source_doc.dispatch_address_name, "Company", details.get("company") + ): + update_address( + target_doc, + "dispatch_address", + "dispatch_address_display", + source_doc.dispatch_address_name, + ) + if source_doc.shipping_address_name and _validate_address_link( + source_doc.shipping_address_name, "Company", details.get("company") + ): + update_address( + target_doc, + "shipping_address", + "shipping_address_display", + source_doc.shipping_address_name, + ) + if source_doc.customer_address and _validate_address_link( + source_doc.customer_address, "Company", details.get("company") + ): + update_address( + target_doc, "billing_address", "billing_address_display", source_doc.customer_address + ) if currency: target_doc.currency = currency @@ -2326,13 +2356,22 @@ def make_inter_company_transaction(doctype, source_name, target_doc=None): target_doc.customer = details.get("party") target_doc.selling_price_list = source_doc.buying_price_list - update_address( - target_doc, "company_address", "company_address_display", source_doc.supplier_address - ) - update_address( - target_doc, "shipping_address_name", "shipping_address", source_doc.shipping_address - ) - update_address(target_doc, "customer_address", "address_display", source_doc.shipping_address) + if source_doc.supplier_address and _validate_address_link( + source_doc.supplier_address, "Company", details.get("company") + ): + update_address( + target_doc, "company_address", "company_address_display", source_doc.supplier_address + ) + if source_doc.shipping_address and _validate_address_link( + source_doc.shipping_address, "Customer", details.get("party") + ): + update_address( + target_doc, "shipping_address_name", "shipping_address", source_doc.shipping_address + ) + if source_doc.shipping_address and _validate_address_link( + source_doc.shipping_address, "Customer", details.get("party") + ): + update_address(target_doc, "customer_address", "address_display", source_doc.shipping_address) if currency: target_doc.currency = currency diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.py b/erpnext/stock/doctype/delivery_note/delivery_note.py index 689027d55bc..d423fc42ffc 100644 --- a/erpnext/stock/doctype/delivery_note/delivery_note.py +++ b/erpnext/stock/doctype/delivery_note/delivery_note.py @@ -1152,6 +1152,18 @@ def make_inter_company_transaction(doctype, source_name, target_doc=None): frappe.throw(_("All items have already been received")) def update_details(source_doc, target_doc, source_parent): + def _validate_address_link(address, link_doctype, link_name): + return frappe.db.get_value( + "Dynamic Link", + { + "parent": address, + "parenttype": "Address", + "link_doctype": link_doctype, + "link_name": link_name, + }, + "parent", + ) + target_doc.inter_company_invoice_reference = source_doc.name if target_doc.doctype == "Purchase Receipt": target_doc.company = details.get("company") @@ -1161,16 +1173,34 @@ def make_inter_company_transaction(doctype, source_name, target_doc=None): target_doc.inter_company_reference = source_doc.name # Invert the address on target doc creation - update_address(target_doc, "supplier_address", "address_display", source_doc.company_address) - update_address( - target_doc, "dispatch_address", "dispatch_address_display", source_doc.dispatch_address_name - ) - update_address( - target_doc, "shipping_address", "shipping_address_display", source_doc.shipping_address_name - ) - update_address( - target_doc, "billing_address", "billing_address_display", source_doc.customer_address - ) + if source_doc.company_address and _validate_address_link( + source_doc.company_address, "Supplier", details.get("party") + ): + update_address(target_doc, "supplier_address", "address_display", source_doc.company_address) + if source_doc.dispatch_address_name and _validate_address_link( + source_doc.dispatch_address_name, "Company", details.get("company") + ): + update_address( + target_doc, + "dispatch_address", + "dispatch_address_display", + source_doc.dispatch_address_name, + ) + if source_doc.shipping_address_name and _validate_address_link( + source_doc.shipping_address_name, "Company", details.get("company") + ): + update_address( + target_doc, + "shipping_address", + "shipping_address_display", + source_doc.shipping_address_name, + ) + if source_doc.customer_address and _validate_address_link( + source_doc.customer_address, "Company", details.get("company") + ): + update_address( + target_doc, "billing_address", "billing_address_display", source_doc.customer_address + ) update_taxes( target_doc, @@ -1190,13 +1220,22 @@ def make_inter_company_transaction(doctype, source_name, target_doc=None): target_doc.inter_company_reference = source_doc.name # Invert the address on target doc creation - update_address( - target_doc, "company_address", "company_address_display", source_doc.supplier_address - ) - update_address( - target_doc, "shipping_address_name", "shipping_address", source_doc.shipping_address - ) - update_address(target_doc, "customer_address", "address_display", source_doc.shipping_address) + if source_doc.supplier_address and _validate_address_link( + source_doc.supplier_address, "Company", details.get("company") + ): + update_address( + target_doc, "company_address", "company_address_display", source_doc.supplier_address + ) + if source_doc.shipping_address and _validate_address_link( + source_doc.shipping_address, "Customer", details.get("party") + ): + update_address( + target_doc, "shipping_address_name", "shipping_address", source_doc.shipping_address + ) + if source_doc.shipping_address and _validate_address_link( + source_doc.shipping_address, "Customer", details.get("party") + ): + update_address(target_doc, "customer_address", "address_display", source_doc.shipping_address) update_taxes( target_doc, From 8ee9a46d96a68f8b30af0dd33aa3b4bb49e7c5a2 Mon Sep 17 00:00:00 2001 From: Bhavan23 Date: Mon, 12 May 2025 12:48:27 +0530 Subject: [PATCH 2/2] test: add test case to validate inter-company transaction address links (cherry picked from commit 0caa757dd6cb92b583a39b585af5706b80532ad2) --- .../sales_invoice/test_sales_invoice.py | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index a1b42624592..5e9c799fb86 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -2581,6 +2581,62 @@ class TestSalesInvoice(FrappeTestCase): acc_settings.book_deferred_entries_based_on = "Days" acc_settings.save() + def test_validate_inter_company_transaction_address_links(self): + def _validate_address_link(address, link_doctype, link_name): + return frappe.db.get_value( + "Dynamic Link", + { + "parent": address, + "parenttype": "Address", + "link_doctype": link_doctype, + "link_name": link_name, + }, + "parent", + ) + + si = create_sales_invoice( + company="Wind Power LLC", + customer="_Test Internal Customer", + debit_to="Debtors - WP", + warehouse="Stores - WP", + income_account="Sales - WP", + expense_account="Cost of Goods Sold - WP", + cost_center="Main - WP", + currency="USD", + do_not_save=1, + ) + + si.selling_price_list = "_Test Price List Rest of the World" + si.submit() + + target_doc = make_inter_company_transaction("Sales Invoice", si.name) + target_doc.items[0].update( + { + "expense_account": "Cost of Goods Sold - _TC1", + "cost_center": "Main - _TC1", + "warehouse": "Stores - _TC1", + } + ) + target_doc.save() + + if target_doc.doctype in ["Purchase Invoice", "Purchase Order"]: + for details in [ + ("supplier_address", "Supplier", target_doc.supplier), + ("dispatch_address", "Company", target_doc.company), + ("shipping_address", "Company", target_doc.company), + ("billing_address", "Company", target_doc.company), + ]: + if address := target_doc.get(details[0]): + self.assertEqual(address, _validate_address_link(address, details[1], details[2])) + else: + for details in [ + ("company_address", "Company", target_doc.company), + ("shipping_address_name", "Customer", target_doc.customer), + ("customer_address", "Customer", target_doc.customer), + ]: + if address := target_doc.get(details[0]): + self.assertEqual(address, _validate_address_link(address, details[1], details[2])) + def test_inter_company_transaction(self): si = create_sales_invoice( company="Wind Power LLC",