mirror of
https://github.com/frappe/erpnext.git
synced 2026-05-05 14:38:26 +00:00
Merge pull request #43067 from frappe/mergify/bp/version-15-hotfix/pr-41721
fix: distributed discounts on si (backport #41721)
This commit is contained in:
@@ -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",
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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 = (
|
||||
|
||||
61
erpnext/controllers/tests/test_distributed_discount.py
Normal file
61
erpnext/controllers/tests/test_distributed_discount.py
Normal file
@@ -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)
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user