From 6d99039bc17304fd64447da50b9af1c8efb50404 Mon Sep 17 00:00:00 2001 From: SowmyaArunachalam Date: Fri, 27 Feb 2026 01:09:09 +0530 Subject: [PATCH] fix: fetch payment terms from quotation (cherry picked from commit 99ed1c34f35344613aca48c82a2fa18b4a204c45) # Conflicts: # erpnext/accounts/doctype/accounts_settings/accounts_settings.json # erpnext/controllers/accounts_controller.py # erpnext/selling/doctype/sales_order/sales_order.json # erpnext/selling/doctype/selling_settings/selling_settings.json --- .../accounts_settings/accounts_settings.json | 6 +- erpnext/controllers/accounts_controller.py | 24 +++++- erpnext/public/js/controllers/transaction.js | 1 + .../selling/doctype/quotation/quotation.py | 38 ++++----- .../doctype/sales_order/sales_order.json | 85 +++++++++++++++++++ .../doctype/sales_order/sales_order.py | 1 + .../selling_settings/selling_settings.json | 8 +- .../selling_settings/selling_settings.py | 1 - 8 files changed, 138 insertions(+), 26 deletions(-) diff --git a/erpnext/accounts/doctype/accounts_settings/accounts_settings.json b/erpnext/accounts/doctype/accounts_settings/accounts_settings.json index 15badf105f8..d6c30f65b60 100644 --- a/erpnext/accounts/doctype/accounts_settings/accounts_settings.json +++ b/erpnext/accounts/doctype/accounts_settings/accounts_settings.json @@ -216,7 +216,7 @@ "description": "Payment Terms from orders will be fetched into the invoices as is", "fieldname": "automatically_fetch_payment_terms", "fieldtype": "Check", - "label": "Automatically Fetch Payment Terms from Order" + "label": "Automatically Fetch Payment Terms from Order/Quotation" }, { "description": "The percentage you are allowed to bill more against the amount ordered. For example, if the order value is $100 for an item and tolerance is set as 10%, then you are allowed to bill up to $110 ", @@ -671,7 +671,11 @@ "index_web_pages_for_search": 1, "issingle": 1, "links": [], +<<<<<<< HEAD "modified": "2025-12-26 19:46:55.093717", +======= + "modified": "2026-02-27 01:04:09.415288", +>>>>>>> 99ed1c34f3 (fix: fetch payment terms from quotation) "modified_by": "Administrator", "module": "Accounts", "name": "Accounts Settings", diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index 008402eeb53..6b5ac6826a4 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -2502,13 +2502,14 @@ class AccountsController(TransactionBase): grand_total = self.get("rounded_total") or self.grand_total automatically_fetch_payment_terms = 0 - if self.doctype in ("Sales Invoice", "Purchase Invoice"): - base_grand_total = base_grand_total - flt(self.base_write_off_amount) - grand_total = grand_total - flt(self.write_off_amount) + if self.doctype in ("Sales Invoice", "Purchase Invoice", "Sales Order"): po_or_so, doctype, fieldname = self.get_order_details() automatically_fetch_payment_terms = cint( frappe.db.get_single_value("Accounts Settings", "automatically_fetch_payment_terms") ) + if self.doctype != "Sales Order": + base_grand_total = base_grand_total - flt(self.base_write_off_amount) + grand_total = grand_total - flt(self.write_off_amount) if self.get("total_advance"): if party_account_currency == self.company_currency: @@ -2524,7 +2525,7 @@ class AccountsController(TransactionBase): if not self.get("payment_schedule"): if ( - self.doctype in ["Sales Invoice", "Purchase Invoice"] + self.doctype in ["Sales Invoice", "Purchase Invoice", "Sales Order"] and automatically_fetch_payment_terms and self.linked_order_has_payment_terms(po_or_so, fieldname, doctype) ): @@ -2580,6 +2581,7 @@ class AccountsController(TransactionBase): def get_order_details(self): if self.doctype == "Sales Invoice": +<<<<<<< HEAD po_or_so = self.get("items") and self.get("items")[0].get("sales_order") po_or_so_doctype = "Sales Order" po_or_so_doctype_name = "sales_order" @@ -2590,6 +2592,20 @@ class AccountsController(TransactionBase): po_or_so_doctype_name = "purchase_order" return po_or_so, po_or_so_doctype, po_or_so_doctype_name +======= + prev_doc = self.get("items")[0].get("sales_order") + prev_doctype = "Sales Order" + prev_doctype_name = "sales_order" + elif self.doctype == "Purchase Invoice": + prev_doc = self.get("items")[0].get("purchase_order") + prev_doctype = "Purchase Order" + prev_doctype_name = "purchase_order" + else: + prev_doc = self.get("items")[0].get("prevdoc_docname") + prev_doctype = "Quotation" + prev_doctype_name = "prevdoc_docname" + return prev_doc, prev_doctype, prev_doctype_name +>>>>>>> 99ed1c34f3 (fix: fetch payment terms from quotation) def linked_order_has_payment_terms(self, po_or_so, fieldname, doctype): if po_or_so and self.all_items_have_same_po_or_so(po_or_so, fieldname): diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js index ef727eec8d8..b0b1281aeff 100644 --- a/erpnext/public/js/controllers/transaction.js +++ b/erpnext/public/js/controllers/transaction.js @@ -1052,6 +1052,7 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe if (this.frm.doc.transaction_date) { this.frm.transaction_date = this.frm.doc.transaction_date; frappe.ui.form.trigger(this.frm.doc.doctype, "currency"); + this.recalculate_terms(); } } diff --git a/erpnext/selling/doctype/quotation/quotation.py b/erpnext/selling/doctype/quotation/quotation.py index 0fe0f54bd2a..b4e433ac805 100644 --- a/erpnext/selling/doctype/quotation/quotation.py +++ b/erpnext/selling/doctype/quotation/quotation.py @@ -443,35 +443,35 @@ def _make_sales_order(source_name, target_doc=None, ignore_permissions=False, ar return child_filter automatically_fetch_payment_terms = cint( - frappe.get_single_value("Selling Settings", "automatically_fetch_payment_terms_from_quotation") + frappe.get_single_value("Accounts Settings", "automatically_fetch_payment_terms") ) - mapping = { - "Quotation": {"doctype": "Sales Order", "validation": {"docstatus": ["=", 1]}}, - "Quotation Item": { - "doctype": "Sales Order Item", - "field_map": {"parent": "prevdoc_docname", "name": "quotation_item"}, - "postprocess": update_item, - "condition": lambda d: can_map_row(d) and select_item(d), - }, - "Sales Taxes and Charges": {"doctype": "Sales Taxes and Charges", "reset_value": True}, - "Sales Team": {"doctype": "Sales Team", "add_if_empty": True}, - } - - if automatically_fetch_payment_terms: - mapping["Payment Schedule"] = {"doctype": "Payment Schedule", "add_if_empty": True} - else: - mapping["Quotation"]["field_no_map"] = ["payment_terms_template"] - doclist = get_mapped_doc( "Quotation", source_name, - mapping, + { + "Quotation": { + "doctype": "Sales Order", + "validation": {"docstatus": ["=", 1]}, + "field_no_map": ["payment_terms_template"], + }, + "Quotation Item": { + "doctype": "Sales Order Item", + "field_map": {"parent": "prevdoc_docname", "name": "quotation_item"}, + "postprocess": update_item, + "condition": lambda d: can_map_row(d) and select_item(d), + }, + "Sales Taxes and Charges": {"doctype": "Sales Taxes and Charges", "reset_value": True}, + "Sales Team": {"doctype": "Sales Team", "add_if_empty": True}, + }, target_doc, set_missing_values, ignore_permissions=ignore_permissions, ) + if automatically_fetch_payment_terms: + doclist.set_payment_schedule() + return doclist diff --git a/erpnext/selling/doctype/sales_order/sales_order.json b/erpnext/selling/doctype/sales_order/sales_order.json index 4bbdb20d311..6fe3d03c0af 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.json +++ b/erpnext/selling/doctype/sales_order/sales_order.json @@ -120,6 +120,7 @@ "company_contact_person", "payment_schedule_section", "payment_terms_section", + "ignore_default_payment_terms_template", "payment_terms_template", "payment_schedule", "terms_section_break", @@ -1665,13 +1666,97 @@ "fieldtype": "Data", "is_virtual": 1, "label": "Last Scanned Warehouse" +<<<<<<< HEAD +======= + }, + { + "default": "0", + "fieldname": "is_subcontracted", + "fieldtype": "Check", + "label": "Is Subcontracted", + "print_hide": 1 + }, + { + "fieldname": "item_wise_tax_details", + "fieldtype": "Table", + "hidden": 1, + "label": "Item Wise Tax Details", + "no_copy": 1, + "options": "Item Wise Tax Detail", + "print_hide": 1 + }, + { + "fieldname": "totals_section", + "fieldtype": "Section Break", + "hide_days": 1, + "hide_seconds": 1, + "label": "Totals", + "oldfieldtype": "Section Break", + "options": "fa fa-money", + "print_hide": 1 + }, + { + "fieldname": "base_totals_section", + "fieldtype": "Section Break", + "label": "Totals (Company Currency)" + }, + { + "fieldname": "column_break_nuxg", + "fieldtype": "Column Break" + }, + { + "fieldname": "column_break_bgfw", + "fieldtype": "Column Break" + }, + { + "fieldname": "section_break_efew", + "fieldtype": "Section Break" + }, + { + "collapsible": 1, + "fieldname": "additional_discount_section", + "fieldtype": "Section Break", + "hide_days": 1, + "hide_seconds": 1, + "label": "Additional Discount" + }, + { + "fieldname": "column_break_ijxt", + "fieldtype": "Column Break" + }, + { + "collapsible": 1, + "fieldname": "utm_analytics_section", + "fieldtype": "Section Break", + "label": "UTM Analytics" + }, + { + "default": "Now", + "depends_on": "is_internal_customer", + "fieldname": "transaction_time", + "fieldtype": "Time", + "label": "Time", + "mandatory_depends_on": "is_internal_customer" + }, + { + "default": "0", + "fieldname": "ignore_default_payment_terms_template", + "fieldtype": "Check", + "hidden": 1, + "label": "Ignore Default Payment Terms Template", + "read_only": 1 +>>>>>>> 99ed1c34f3 (fix: fetch payment terms from quotation) } ], "icon": "fa fa-file-text", "idx": 105, "is_submittable": 1, "links": [], +<<<<<<< HEAD "modified": "2026-02-06 11:06:16.092658", +======= + "modified": "2026-03-04 18:04:05.873483", +>>>>>>> 99ed1c34f3 (fix: fetch payment terms from quotation) "modified_by": "Administrator", "module": "Selling", "name": "Sales Order", diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py index 7ceba32232f..3beb070b452 100755 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -111,6 +111,7 @@ class SalesOrder(SellingController): grand_total: DF.Currency group_same_items: DF.Check has_unit_price_items: DF.Check + ignore_default_payment_terms_template: DF.Check ignore_pricing_rule: DF.Check in_words: DF.Data | None incoterm: DF.Link | None diff --git a/erpnext/selling/doctype/selling_settings/selling_settings.json b/erpnext/selling/doctype/selling_settings/selling_settings.json index 24b29054961..069b141374e 100644 --- a/erpnext/selling/doctype/selling_settings/selling_settings.json +++ b/erpnext/selling/doctype/selling_settings/selling_settings.json @@ -40,7 +40,6 @@ "set_zero_rate_for_expired_batch" ======= "set_zero_rate_for_expired_batch", - "automatically_fetch_payment_terms_from_quotation", "section_break_avhb", "enable_utm", "experimental_section", @@ -268,6 +267,7 @@ "fieldname": "enable_utm", "fieldtype": "Check", "label": "Enable UTM" +<<<<<<< HEAD }, { "default": "1", @@ -275,6 +275,8 @@ "fieldtype": "Check", "label": "Automatically Fetch Payment Terms from Quotation" >>>>>>> 70b401e610 (feat(selling-settings): add checkbox to recalculate payment date) +======= +>>>>>>> 99ed1c34f3 (fix: fetch payment terms from quotation) } ], "grid_page_length": 50, @@ -283,11 +285,15 @@ "index_web_pages_for_search": 1, "issingle": 1, "links": [], +<<<<<<< HEAD <<<<<<< HEAD "modified": "2026-01-24 00:04:33.105916", ======= "modified": "2026-02-18 21:25:56.307468", >>>>>>> 8b9e02fd44 (fix: set default to 1) +======= + "modified": "2026-02-27 00:47:46.003305", +>>>>>>> 99ed1c34f3 (fix: fetch payment terms from quotation) "modified_by": "Administrator", "module": "Selling", "name": "Selling Settings", diff --git a/erpnext/selling/doctype/selling_settings/selling_settings.py b/erpnext/selling/doctype/selling_settings/selling_settings.py index 68b27cfda21..cad8385ab73 100644 --- a/erpnext/selling/doctype/selling_settings/selling_settings.py +++ b/erpnext/selling/doctype/selling_settings/selling_settings.py @@ -26,7 +26,6 @@ class SellingSettings(Document): allow_sales_order_creation_for_expired_quotation: DF.Check allow_zero_qty_in_quotation: DF.Check allow_zero_qty_in_sales_order: DF.Check - automatically_fetch_payment_terms_from_quotation: DF.Check blanket_order_allowance: DF.Float cust_master_name: DF.Literal["Customer Name", "Naming Series", "Auto Name"] customer_group: DF.Link | None