diff --git a/erpnext/accounts/doctype/pos_invoice_item/pos_invoice_item.json b/erpnext/accounts/doctype/pos_invoice_item/pos_invoice_item.json index 828fc30db6e..0a0be67edc2 100644 --- a/erpnext/accounts/doctype/pos_invoice_item/pos_invoice_item.json +++ b/erpnext/accounts/doctype/pos_invoice_item/pos_invoice_item.json @@ -37,6 +37,7 @@ "column_break_19", "discount_percentage", "discount_amount", + "distributed_discount_amount", "base_rate_with_margin", "section_break1", "rate", @@ -847,11 +848,17 @@ { "fieldname": "column_break_ciit", "fieldtype": "Column Break" + }, + { + "fieldname": "distributed_discount_amount", + "fieldtype": "Currency", + "label": "Distributed Discount Amount", + "options": "currency" } ], "istable": 1, "links": [], - "modified": "2024-05-07 15:56:53.343317", + "modified": "2024-05-07 15:56:54.343317", "modified_by": "Administrator", "module": "Accounts", "name": "POS Invoice Item", diff --git a/erpnext/accounts/doctype/pos_invoice_item/pos_invoice_item.py b/erpnext/accounts/doctype/pos_invoice_item/pos_invoice_item.py index c24db1d6a03..429f340a4f5 100644 --- a/erpnext/accounts/doctype/pos_invoice_item/pos_invoice_item.py +++ b/erpnext/accounts/doctype/pos_invoice_item/pos_invoice_item.py @@ -39,6 +39,7 @@ class POSInvoiceItem(Document): description: DF.TextEditor discount_amount: DF.Currency discount_percentage: DF.Percent + distributed_discount_amount: DF.Currency dn_detail: DF.Data | None enable_deferred_revenue: DF.Check expense_account: DF.Link | None diff --git a/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json b/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json index eb218708b8e..69d5da7b9a3 100644 --- a/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json +++ b/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json @@ -38,6 +38,7 @@ "column_break_30", "discount_percentage", "discount_amount", + "distributed_discount_amount", "base_rate_with_margin", "sec_break2", "rate", @@ -840,7 +841,7 @@ }, { "collapsible": 1, - "collapsible_depends_on": "eval: doc.margin_type || doc.discount_amount", + "collapsible_depends_on": "eval: doc.margin_type || doc.discount_amount || doc.distributed_discount_amount", "fieldname": "section_break_26", "fieldtype": "Section Break", "label": "Discount and Margin" @@ -971,12 +972,18 @@ "no_copy": 1, "options": "Company:company:default_currency", "print_hide": 1 + }, + { + "fieldname": "distributed_discount_amount", + "fieldtype": "Currency", + "label": "Distributed Discount Amount", + "options": "currency" } ], "idx": 1, "istable": 1, "links": [], - "modified": "2025-03-12 16:33:12.453290", + "modified": "2025-03-12 16:33:13.453290", "modified_by": "Administrator", "module": "Accounts", "name": "Purchase Invoice Item", diff --git a/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.py b/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.py index a8f844c6c1c..96db9d66f05 100644 --- a/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.py +++ b/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.py @@ -34,6 +34,7 @@ class PurchaseInvoiceItem(Document): description: DF.TextEditor | None discount_amount: DF.Currency discount_percentage: DF.Percent + distributed_discount_amount: DF.Currency enable_deferred_expense: DF.Check expense_account: DF.Link | None from_warehouse: DF.Link | None diff --git a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json index 3d0998851fb..a5b93eae931 100644 --- a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json +++ b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json @@ -37,6 +37,7 @@ "column_break_19", "discount_percentage", "discount_amount", + "distributed_discount_amount", "base_rate_with_margin", "section_break1", "rate", @@ -259,7 +260,7 @@ }, { "collapsible": 1, - "collapsible_depends_on": "eval: doc.margin_type || doc.discount_amount", + "collapsible_depends_on": "eval: doc.margin_type || doc.discount_amount || doc.distributed_discount_amount", "fieldname": "discount_and_margin", "fieldtype": "Section Break", "label": "Discount and Margin" @@ -932,6 +933,12 @@ "fieldname": "column_break_ytgd", "fieldtype": "Column Break" }, + { + "fieldname": "distributed_discount_amount", + "fieldtype": "Currency", + "label": "Distributed Discount Amount", + "options": "currency" + }, { "fieldname": "available_quantity_section", "fieldtype": "Section Break", @@ -976,7 +983,7 @@ "idx": 1, "istable": 1, "links": [], - "modified": "2025-03-12 16:33:52.503777", + "modified": "2025-03-12 16:33:55.503777", "modified_by": "Administrator", "module": "Accounts", "name": "Sales Invoice Item", diff --git a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.py b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.py index 943f08871a1..65d82a4deb3 100644 --- a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.py +++ b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.py @@ -40,6 +40,7 @@ class SalesInvoiceItem(Document): discount_account: DF.Link | None discount_amount: DF.Currency discount_percentage: DF.Percent + distributed_discount_amount: DF.Currency dn_detail: DF.Data | None enable_deferred_revenue: DF.Check expense_account: DF.Link | None diff --git a/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json b/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json index 4473d021635..e0e0990c103 100644 --- a/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json +++ b/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json @@ -43,6 +43,7 @@ "column_break_28", "discount_percentage", "discount_amount", + "distributed_discount_amount", "base_rate_with_margin", "sec_break2", "rate", @@ -781,7 +782,7 @@ }, { "collapsible": 1, - "collapsible_depends_on": "eval: doc.margin_type || doc.discount_amount", + "collapsible_depends_on": "eval: doc.margin_type || doc.discount_amount || doc.distributed_discount_amount", "fieldname": "discount_and_margin_section", "fieldtype": "Section Break", "label": "Discount and Margin" @@ -911,6 +912,12 @@ "fieldname": "column_break_fyqr", "fieldtype": "Column Break" }, + { + "fieldname": "distributed_discount_amount", + "fieldtype": "Currency", + "label": "Distributed Discount Amount", + "options": "currency" + }, { "allow_on_submit": 1, "depends_on": "eval:parent.is_subcontracted && !parent.is_old_subcontracting_flow", @@ -927,7 +934,7 @@ "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2025-03-13 17:27:43.468602", + "modified": "2025-03-13 17:27:44.468602", "modified_by": "Administrator", "module": "Buying", "name": "Purchase Order Item", diff --git a/erpnext/buying/doctype/purchase_order_item/purchase_order_item.py b/erpnext/buying/doctype/purchase_order_item/purchase_order_item.py index 5e4ce19d340..451ea97d11f 100644 --- a/erpnext/buying/doctype/purchase_order_item/purchase_order_item.py +++ b/erpnext/buying/doctype/purchase_order_item/purchase_order_item.py @@ -37,6 +37,7 @@ class PurchaseOrderItem(Document): description: DF.TextEditor | None discount_amount: DF.Currency discount_percentage: DF.Percent + distributed_discount_amount: DF.Currency expected_delivery_date: DF.Date | None expense_account: DF.Link | None fg_item: DF.Link | None diff --git a/erpnext/buying/doctype/supplier_quotation_item/supplier_quotation_item.json b/erpnext/buying/doctype/supplier_quotation_item/supplier_quotation_item.json index a6229b5950b..91019104949 100644 --- a/erpnext/buying/doctype/supplier_quotation_item/supplier_quotation_item.json +++ b/erpnext/buying/doctype/supplier_quotation_item/supplier_quotation_item.json @@ -32,6 +32,7 @@ "price_list_rate", "discount_percentage", "discount_amount", + "distributed_discount_amount", "col_break_price_list", "base_price_list_rate", "sec_break1", @@ -565,13 +566,19 @@ { "fieldname": "dimension_col_break", "fieldtype": "Column Break" + }, + { + "fieldname": "distributed_discount_amount", + "fieldtype": "Currency", + "label": "Distributed Discount Amount", + "options": "currency" } ], "idx": 1, "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2023-11-17 12:25:26.235367", + "modified": "2024-06-02 06:22:18.864822", "modified_by": "Administrator", "module": "Buying", "name": "Supplier Quotation Item", diff --git a/erpnext/buying/doctype/supplier_quotation_item/supplier_quotation_item.py b/erpnext/buying/doctype/supplier_quotation_item/supplier_quotation_item.py index d2f4a59930b..a51b9500fd8 100644 --- a/erpnext/buying/doctype/supplier_quotation_item/supplier_quotation_item.py +++ b/erpnext/buying/doctype/supplier_quotation_item/supplier_quotation_item.py @@ -26,6 +26,7 @@ class SupplierQuotationItem(Document): description: DF.TextEditor | None discount_amount: DF.Currency discount_percentage: DF.Percent + distributed_discount_amount: DF.Currency expected_delivery_date: DF.Date | None image: DF.Attach | None is_free_item: DF.Check diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index 46418ca8a63..eab0064a85e 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -1841,8 +1841,11 @@ class AccountsController(TransactionBase): and self.get("discount_amount") and self.get("additional_discount_account") ): - amount = item.amount - base_amount = item.base_amount + amount += item.distributed_discount_amount + base_amount += flt( + item.distributed_discount_amount * self.get("conversion_rate"), + item.precision("distributed_discount_amount"), + ) return amount, base_amount diff --git a/erpnext/controllers/taxes_and_totals.py b/erpnext/controllers/taxes_and_totals.py index 955c9261031..5e35dd5028e 100644 --- a/erpnext/controllers/taxes_and_totals.py +++ b/erpnext/controllers/taxes_and_totals.py @@ -695,6 +695,9 @@ class calculate_taxes_and_totals: adjusted_net_amount = item.net_amount - distributed_amount expected_net_total += adjusted_net_amount item.net_amount = flt(adjusted_net_amount, item.precision("net_amount")) + item.distributed_discount_amount = flt( + distributed_amount, item.precision("distributed_discount_amount") + ) net_total += item.net_amount # discount amount rounding adjustment @@ -704,6 +707,10 @@ class calculate_taxes_and_totals: item.net_amount = flt( item.net_amount + rounding_difference, item.precision("net_amount") ) + item.distributed_discount_amount = flt( + distributed_amount + rounding_difference, + item.precision("distributed_discount_amount"), + ) net_total += rounding_difference item.net_rate = ( diff --git a/erpnext/controllers/tests/test_distributed_discount.py b/erpnext/controllers/tests/test_distributed_discount.py new file mode 100644 index 00000000000..e4dbdbb1480 --- /dev/null +++ b/erpnext/controllers/tests/test_distributed_discount.py @@ -0,0 +1,61 @@ +from frappe.tests.utils import FrappeTestCase + +from erpnext.accounts.test.accounts_mixin import AccountsTestMixin +from erpnext.controllers.taxes_and_totals import calculate_taxes_and_totals +from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order + + +class TestTaxesAndTotals(AccountsTestMixin, FrappeTestCase): + def test_distributed_discount_amount(self): + so = make_sales_order(do_not_save=1) + so.apply_discount_on = "Net Total" + so.discount_amount = 100 + so.items[0].qty = 5 + so.items[0].rate = 100 + so.append("items", so.items[0].as_dict()) + so.items[1].qty = 5 + so.items[1].rate = 200 + so.save() + + calculate_taxes_and_totals(so) + + self.assertAlmostEqual(so.items[0].distributed_discount_amount, 33.33, places=2) + self.assertAlmostEqual(so.items[1].distributed_discount_amount, 66.67, places=2) + self.assertAlmostEqual(so.items[0].net_amount, 466.67, places=2) + self.assertAlmostEqual(so.items[1].net_amount, 933.33, places=2) + self.assertEqual(so.total, 1500) + self.assertEqual(so.net_total, 1400) + self.assertEqual(so.grand_total, 1400) + + def test_distributed_discount_amount_with_taxes(self): + so = make_sales_order(do_not_save=1) + so.apply_discount_on = "Grand Total" + so.discount_amount = 100 + so.items[0].qty = 5 + so.items[0].rate = 100 + so.append("items", so.items[0].as_dict()) + so.items[1].qty = 5 + so.items[1].rate = 200 + so.append( + "taxes", + { + "charge_type": "On Net Total", + "account_head": "_Test Account VAT - _TC", + "cost_center": "_Test Cost Center - _TC", + "description": "VAT", + "included_in_print_rate": True, + "rate": 10, + }, + ) + so.save() + + calculate_taxes_and_totals(so) + + # like in test_distributed_discount_amount, but reduced by the included tax + self.assertAlmostEqual(so.items[0].distributed_discount_amount, 33.33 / 1.1, places=2) + self.assertAlmostEqual(so.items[1].distributed_discount_amount, 66.67 / 1.1, places=2) + self.assertAlmostEqual(so.items[0].net_amount, 466.67 / 1.1, places=2) + self.assertAlmostEqual(so.items[1].net_amount, 933.33 / 1.1, places=2) + self.assertEqual(so.total, 1500) + self.assertAlmostEqual(so.net_total, 1272.73, places=2) + self.assertEqual(so.grand_total, 1400) diff --git a/erpnext/selling/doctype/quotation_item/quotation_item.json b/erpnext/selling/doctype/quotation_item/quotation_item.json index 9dd65a8b4f8..2818b49913d 100644 --- a/erpnext/selling/doctype/quotation_item/quotation_item.json +++ b/erpnext/selling/doctype/quotation_item/quotation_item.json @@ -38,6 +38,7 @@ "column_break_18", "discount_percentage", "discount_amount", + "distributed_discount_amount", "base_rate_with_margin", "section_break1", "rate", @@ -238,7 +239,7 @@ }, { "collapsible": 1, - "collapsible_depends_on": "eval: doc.margin_type || doc.discount_amount", + "collapsible_depends_on": "eval: doc.margin_type || doc.discount_amount || doc.distributed_discount_amount", "fieldname": "discount_and_margin", "fieldtype": "Section Break", "label": "Discount and Margin" @@ -668,6 +669,12 @@ "print_hide": 1, "read_only": 1 }, + { + "fieldname": "distributed_discount_amount", + "fieldtype": "Currency", + "label": "Distributed Discount Amount", + "options": "currency" + }, { "fieldname": "available_quantity_section", "fieldtype": "Section Break", @@ -691,7 +698,7 @@ "idx": 1, "istable": 1, "links": [], - "modified": "2024-12-12 13:49:17.765883", + "modified": "2024-12-12 13:49:18.765883", "modified_by": "Administrator", "module": "Selling", "name": "Quotation Item", diff --git a/erpnext/selling/doctype/quotation_item/quotation_item.py b/erpnext/selling/doctype/quotation_item/quotation_item.py index 7d68eaf07ba..bbdd8643593 100644 --- a/erpnext/selling/doctype/quotation_item/quotation_item.py +++ b/erpnext/selling/doctype/quotation_item/quotation_item.py @@ -33,6 +33,7 @@ class QuotationItem(Document): description: DF.TextEditor | None discount_amount: DF.Currency discount_percentage: DF.Percent + distributed_discount_amount: DF.Currency gross_profit: DF.Currency has_alternative_item: DF.Check image: DF.Attach | None diff --git a/erpnext/selling/doctype/sales_order_item/sales_order_item.json b/erpnext/selling/doctype/sales_order_item/sales_order_item.json index ea1a646ba2d..21054a9d81b 100644 --- a/erpnext/selling/doctype/sales_order_item/sales_order_item.json +++ b/erpnext/selling/doctype/sales_order_item/sales_order_item.json @@ -40,6 +40,7 @@ "column_break_19", "discount_percentage", "discount_amount", + "distributed_discount_amount", "base_rate_with_margin", "section_break_simple1", "rate", @@ -287,7 +288,7 @@ }, { "collapsible": 1, - "collapsible_depends_on": "eval: doc.margin_type || doc.discount_amount", + "collapsible_depends_on": "eval: doc.margin_type || doc.discount_amount || doc.distributed_discount_amount", "fieldname": "discount_and_margin", "fieldtype": "Section Break", "label": "Discount and Margin" @@ -913,6 +914,12 @@ "print_hide": 1, "report_hide": 1 }, + { + "fieldname": "distributed_discount_amount", + "fieldtype": "Currency", + "label": "Distributed Discount Amount", + "options": "currency" + }, { "allow_on_submit": 1, "fieldname": "company_total_stock", @@ -964,7 +971,7 @@ "idx": 1, "istable": 1, "links": [], - "modified": "2025-02-28 09:45:43.934947", + "modified": "2025-02-28 09:45:44.934947", "modified_by": "Administrator", "module": "Selling", "name": "Sales Order Item", diff --git a/erpnext/selling/doctype/sales_order_item/sales_order_item.py b/erpnext/selling/doctype/sales_order_item/sales_order_item.py index 2fa06ac7299..731cff665da 100644 --- a/erpnext/selling/doctype/sales_order_item/sales_order_item.py +++ b/erpnext/selling/doctype/sales_order_item/sales_order_item.py @@ -40,6 +40,7 @@ class SalesOrderItem(Document): description: DF.TextEditor | None discount_amount: DF.Currency discount_percentage: DF.Percent + distributed_discount_amount: DF.Currency ensure_delivery_based_on_produced_serial_no: DF.Check grant_commission: DF.Check gross_profit: DF.Currency diff --git a/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json b/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json index ff64db8ee76..e951aaf1e18 100644 --- a/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json +++ b/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json @@ -40,6 +40,7 @@ "column_break_19", "discount_percentage", "discount_amount", + "distributed_discount_amount", "base_rate_with_margin", "section_break_1", "rate", @@ -277,7 +278,7 @@ }, { "collapsible": 1, - "collapsible_depends_on": "eval: doc.margin_type || doc.discount_amount", + "collapsible_depends_on": "eval: doc.margin_type || doc.discount_amount || doc.distributed_discount_amount", "fieldname": "discount_and_margin", "fieldtype": "Section Break", "label": "Discount and Margin" @@ -912,6 +913,12 @@ "fieldname": "column_break_rxvc", "fieldtype": "Column Break" }, + { + "fieldname": "distributed_discount_amount", + "fieldtype": "Currency", + "label": "Distributed Discount Amount", + "options": "currency" + }, { "allow_on_submit": 1, "fieldname": "company_total_stock", @@ -934,7 +941,7 @@ "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2025-02-05 14:28:32.322181", + "modified": "2025-02-05 14:28:33.322181", "modified_by": "Administrator", "module": "Stock", "name": "Delivery Note Item", diff --git a/erpnext/stock/doctype/delivery_note_item/delivery_note_item.py b/erpnext/stock/doctype/delivery_note_item/delivery_note_item.py index 716cd7d4856..7fb0e24be0b 100644 --- a/erpnext/stock/doctype/delivery_note_item/delivery_note_item.py +++ b/erpnext/stock/doctype/delivery_note_item/delivery_note_item.py @@ -37,6 +37,7 @@ class DeliveryNoteItem(Document): description: DF.TextEditor | None discount_amount: DF.Currency discount_percentage: DF.Float + distributed_discount_amount: DF.Currency dn_detail: DF.Data | None expense_account: DF.Link | None grant_commission: DF.Check diff --git a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json index 810c08a545e..5f8a9b58e91 100644 --- a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json +++ b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json @@ -48,6 +48,7 @@ "column_break_37", "discount_percentage", "discount_amount", + "distributed_discount_amount", "base_rate_with_margin", "sec_break1", "rate", @@ -911,7 +912,7 @@ }, { "collapsible": 1, - "collapsible_depends_on": "eval: doc.margin_type || doc.discount_amount", + "collapsible_depends_on": "eval: doc.margin_type || doc.discount_amount || doc.distributed_discount_amount", "fieldname": "discount_and_margin_section", "fieldtype": "Section Break", "label": "Discount and Margin" @@ -1128,6 +1129,12 @@ "options": "Company:company:default_currency", "print_hide": 1 }, + { + "fieldname": "distributed_discount_amount", + "fieldtype": "Currency", + "label": "Distributed Discount Amount", + "options": "currency" + }, { "fieldname": "amount_difference_with_purchase_invoice", "fieldtype": "Currency", @@ -1140,7 +1147,7 @@ "idx": 1, "istable": 1, "links": [], - "modified": "2025-03-12 17:10:42.780622", + "modified": "2025-03-12 17:10:43.780622", "modified_by": "Administrator", "module": "Stock", "name": "Purchase Receipt Item", diff --git a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.py b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.py index 0db866f52c1..9f65ae56a83 100644 --- a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.py +++ b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.py @@ -37,6 +37,7 @@ class PurchaseReceiptItem(Document): description: DF.TextEditor | None discount_amount: DF.Currency discount_percentage: DF.Percent + distributed_discount_amount: DF.Currency expense_account: DF.Link | None from_warehouse: DF.Link | None has_item_scanned: DF.Check