From 2edf083c3589a45c74d89f26138b23072d33bef0 Mon Sep 17 00:00:00 2001 From: Mihir Kandoi Date: Wed, 5 Feb 2025 18:48:52 +0530 Subject: [PATCH 1/8] feat: added option to enforce free item qty in pricing rule (cherry picked from commit 19c01b145765fbbd2be95e914c818c44697b7d76) # Conflicts: # erpnext/accounts/doctype/pricing_rule/pricing_rule.py --- .../doctype/pricing_rule/pricing_rule.json | 10 +- .../doctype/pricing_rule/pricing_rule.py | 112 ++++++++++++++++++ .../accounts/doctype/pricing_rule/utils.py | 3 +- 3 files changed, 123 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.json b/erpnext/accounts/doctype/pricing_rule/pricing_rule.json index ee9dd2be8c3..473e9b837ae 100644 --- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.json +++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.json @@ -53,6 +53,7 @@ "column_break_42", "free_item_uom", "round_free_qty", + "enforce_free_item_qty", "is_recursive", "recurse_for", "apply_recursion_over", @@ -643,12 +644,19 @@ "fieldname": "has_priority", "fieldtype": "Check", "label": "Has Priority" + }, + { + "default": "0", + "depends_on": "eval:doc.price_or_product_discount == 'Product'", + "fieldname": "enforce_free_item_qty", + "fieldtype": "Check", + "label": "Enforce Free Item Qty" } ], "icon": "fa fa-gift", "idx": 1, "links": [], - "modified": "2024-09-16 18:14:51.314765", + "modified": "2025-02-05 18:05:03.886828", "modified_by": "Administrator", "module": "Accounts", "name": "Pricing Rule", diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py index 902af5c2a77..4913bcb8ed9 100644 --- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py +++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py @@ -18,6 +18,118 @@ other_fields = ["other_item_code", "other_item_group", "other_brand"] class PricingRule(Document): +<<<<<<< HEAD +======= + # begin: auto-generated types + # This code is auto-generated. Do not modify anything in this block. + + from typing import TYPE_CHECKING + + if TYPE_CHECKING: + from frappe.types import DF + + from erpnext.accounts.doctype.pricing_rule_brand.pricing_rule_brand import PricingRuleBrand + from erpnext.accounts.doctype.pricing_rule_item_code.pricing_rule_item_code import PricingRuleItemCode + from erpnext.accounts.doctype.pricing_rule_item_group.pricing_rule_item_group import ( + PricingRuleItemGroup, + ) + + applicable_for: DF.Literal[ + "", + "Customer", + "Customer Group", + "Territory", + "Sales Partner", + "Campaign", + "Supplier", + "Supplier Group", + ] + apply_discount_on: DF.Literal["Grand Total", "Net Total"] + apply_discount_on_rate: DF.Check + apply_multiple_pricing_rules: DF.Check + apply_on: DF.Literal["", "Item Code", "Item Group", "Brand", "Transaction"] + apply_recursion_over: DF.Float + apply_rule_on_other: DF.Literal["", "Item Code", "Item Group", "Brand"] + brands: DF.Table[PricingRuleBrand] + buying: DF.Check + campaign: DF.Link | None + company: DF.Link | None + condition: DF.Code | None + coupon_code_based: DF.Check + currency: DF.Link + customer: DF.Link | None + customer_group: DF.Link | None + disable: DF.Check + discount_amount: DF.Currency + discount_percentage: DF.Float + enforce_free_item_qty: DF.Check + for_price_list: DF.Link | None + free_item: DF.Link | None + free_item_rate: DF.Currency + free_item_uom: DF.Link | None + free_qty: DF.Float + has_priority: DF.Check + is_cumulative: DF.Check + is_recursive: DF.Check + item_groups: DF.Table[PricingRuleItemGroup] + items: DF.Table[PricingRuleItemCode] + margin_rate_or_amount: DF.Float + margin_type: DF.Literal["", "Percentage", "Amount"] + max_amt: DF.Currency + max_qty: DF.Float + min_amt: DF.Currency + min_qty: DF.Float + mixed_conditions: DF.Check + naming_series: DF.Literal["PRLE-.####"] + other_brand: DF.Link | None + other_item_code: DF.Link | None + other_item_group: DF.Link | None + price_or_product_discount: DF.Literal["Price", "Product"] + priority: DF.Literal[ + "", + "1", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9", + "10", + "11", + "12", + "13", + "14", + "15", + "16", + "17", + "18", + "19", + "20", + ] + promotional_scheme: DF.Link | None + promotional_scheme_id: DF.Data | None + rate: DF.Currency + rate_or_discount: DF.Literal["", "Rate", "Discount Percentage", "Discount Amount"] + recurse_for: DF.Float + round_free_qty: DF.Check + rule_description: DF.SmallText | None + sales_partner: DF.Link | None + same_item: DF.Check + selling: DF.Check + supplier: DF.Link | None + supplier_group: DF.Link | None + territory: DF.Link | None + threshold_percentage: DF.Percent + title: DF.Data + valid_from: DF.Date | None + valid_upto: DF.Date | None + validate_applied_rule: DF.Check + warehouse: DF.Link | None + # end: auto-generated types + +>>>>>>> 19c01b1457 (feat: added option to enforce free item qty in pricing rule) def validate(self): self.validate_mandatory() self.validate_duplicate_apply_on() diff --git a/erpnext/accounts/doctype/pricing_rule/utils.py b/erpnext/accounts/doctype/pricing_rule/utils.py index bec4d2407de..f0f8f0698e1 100644 --- a/erpnext/accounts/doctype/pricing_rule/utils.py +++ b/erpnext/accounts/doctype/pricing_rule/utils.py @@ -691,7 +691,8 @@ def apply_pricing_rule_for_free_items(doc, pricing_rule_args): args.pop((item.item_code, item.pricing_rules)) for free_item in args.values(): - doc.append("items", free_item) + if frappe.get_value("Pricing Rule", free_item["pricing_rules"], "enforce_free_item_qty"): + doc.append("items", free_item) def get_pricing_rule_items(pr_doc, other_items=False) -> list: From e515b919885abbc4dec276a121019c9b8c421d48 Mon Sep 17 00:00:00 2001 From: Mihir Kandoi Date: Wed, 5 Feb 2025 19:18:01 +0530 Subject: [PATCH 2/8] fix: tests (cherry picked from commit 366ae85d855c130c89fa1f151a2cca5b1e7dbdd8) # Conflicts: # erpnext/stock/doctype/pick_list/test_pick_list.py --- .../doctype/pricing_rule/pricing_rule.py | 2 +- .../doctype/pricing_rule/test_pricing_rule.py | 5 + .../stock/doctype/pick_list/test_pick_list.py | 96 +++++++++++++++++++ 3 files changed, 102 insertions(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py index 4913bcb8ed9..fa84c4c0e6b 100644 --- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py +++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py @@ -665,7 +665,7 @@ def remove_pricing_rule_for_item(pricing_rules, item_details, item_code=None, ra if pricing_rule.margin_type in ["Percentage", "Amount"]: item_details.margin_rate_or_amount = 0.0 item_details.margin_type = None - elif pricing_rule.get("free_item"): + elif pricing_rule.get("free_item") and pricing_rule.get("enforce_free_item_qty"): item_details.remove_free_item = ( item_code if pricing_rule.get("same_item") else pricing_rule.get("free_item") ) diff --git a/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py b/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py index 57f2d791199..62f37a78c11 100644 --- a/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py +++ b/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py @@ -386,6 +386,7 @@ class TestPricingRule(FrappeTestCase): "price_or_product_discount": "Product", "same_item": 1, "free_qty": 1, + "enforce_free_item_qty": 1, "company": "_Test Company", } frappe.get_doc(test_record.copy()).insert() @@ -418,6 +419,7 @@ class TestPricingRule(FrappeTestCase): "same_item": 0, "free_item": "_Test Item 2", "free_qty": 1, + "enforce_free_item_qty": 1, "company": "_Test Company", } frappe.get_doc(test_record.copy()).insert() @@ -961,6 +963,7 @@ class TestPricingRule(FrappeTestCase): "price_or_product_discount": "Product", "same_item": 1, "free_qty": 1, + "enforce_free_item_qty": 1, "round_free_qty": 1, "is_recursive": 1, "recurse_for": 2, @@ -1006,6 +1009,7 @@ class TestPricingRule(FrappeTestCase): "price_or_product_discount": "Product", "same_item": 1, "free_qty": 10, + "enforce_free_item_qty": 1, "round_free_qty": 1, "is_recursive": 1, "recurse_for": 100, @@ -1239,6 +1243,7 @@ def make_pricing_rule(**args): "discount_amount": args.discount_amount or 0.0, "apply_multiple_pricing_rules": args.apply_multiple_pricing_rules or 0, "has_priority": args.has_priority or 0, + "enforce_free_item_qty": args.enforce_free_item_qty or 1, } ) diff --git a/erpnext/stock/doctype/pick_list/test_pick_list.py b/erpnext/stock/doctype/pick_list/test_pick_list.py index f679d28c2b2..95a79f6caea 100644 --- a/erpnext/stock/doctype/pick_list/test_pick_list.py +++ b/erpnext/stock/doctype/pick_list/test_pick_list.py @@ -846,6 +846,102 @@ class TestPickList(FrappeTestCase): self.assertRaises(frappe.ValidationError, pl.save) +<<<<<<< HEAD +======= + def test_over_allowance_picking(self): + warehouse = "_Test Warehouse - _TC" + item = make_item( + "Test Over Allowance Picking Item", + properties={ + "is_stock_item": 1, + }, + ).name + + make_stock_entry(item=item, to_warehouse=warehouse, qty=100) + + so = make_sales_order(item_code=item, qty=10, rate=100) + + pl_doc = create_pick_list(so.name) + pl_doc.save() + self.assertEqual(pl_doc.locations[0].qty, 10) + + pl_doc.locations[0].qty = 15 + pl_doc.locations[0].stock_qty = 15 + pl_doc.save() + + self.assertEqual(pl_doc.locations[0].qty, 15) + self.assertRaises(frappe.ValidationError, pl_doc.submit) + + frappe.db.set_single_value("Stock Settings", "over_picking_allowance", 50) + + pl_doc.reload() + pl_doc.submit() + + frappe.db.set_single_value("Stock Settings", "over_picking_allowance", 0) + + def test_ignore_pricing_rule_in_pick_list(self): + frappe.flags.print_stmt = False + warehouse = "_Test Warehouse - _TC" + item = make_item( + properties={ + "is_stock_item": 1, + "has_batch_no": 1, + "batch_number_series": "IPR-PICKLT-.######", + "create_new_batch": 1, + } + ).name + + make_stock_entry( + item=item, + to_warehouse=warehouse, + qty=2, + basic_rate=100, + ) + + pricing_rule = frappe.get_doc( + { + "doctype": "Pricing Rule", + "title": "Same Free Item", + "price_or_product_discount": "Product", + "selling": 1, + "apply_on": "Item Code", + "items": [ + { + "item_code": item, + } + ], + "same_item": 1, + "is_recursive": 1, + "recurse_for": 2, + "free_qty": 1, + "enforce_free_item_qty": 1, + "company": "_Test Company", + "customer": "_Test Customer", + } + ) + + pricing_rule.save() + frappe.flags.print_stmt = True + + so = make_sales_order(item_code=item, qty=2, rate=100, do_not_save=True) + so.set_warehouse = warehouse + so.submit() + + self.assertEqual(len(so.items), 2) + self.assertTrue(so.items[1].is_free_item) + + pl = create_pick_list(so.name) + pl.ignore_pricing_rule = 1 + pl.save() + pl.submit() + + self.assertEqual(len(pl.locations), 1) + + delivery_note = create_delivery_note(pl.name) + + self.assertEqual(len(delivery_note.items), 1) + +>>>>>>> 366ae85d85 (fix: tests) def test_pick_list_not_reset_batch(self): warehouse = "_Test Warehouse - _TC" item = make_item( From 116798df9645bd30a33368d934fe5d790f9422ac Mon Sep 17 00:00:00 2001 From: Mihir Kandoi Date: Wed, 5 Feb 2025 21:34:19 +0530 Subject: [PATCH 3/8] test: added test (cherry picked from commit ac3259b8f156131e2d5ab27e411f9d735f835626) --- .../doctype/pricing_rule/pricing_rule.json | 4 +- .../doctype/pricing_rule/test_pricing_rule.py | 52 +++++++++++++++++-- 2 files changed, 50 insertions(+), 6 deletions(-) diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.json b/erpnext/accounts/doctype/pricing_rule/pricing_rule.json index 473e9b837ae..3b743c796af 100644 --- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.json +++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.json @@ -646,7 +646,7 @@ "label": "Has Priority" }, { - "default": "0", + "default": "1", "depends_on": "eval:doc.price_or_product_discount == 'Product'", "fieldname": "enforce_free_item_qty", "fieldtype": "Check", @@ -656,7 +656,7 @@ "icon": "fa fa-gift", "idx": 1, "links": [], - "modified": "2025-02-05 18:05:03.886828", + "modified": "2025-02-05 21:03:22.103044", "modified_by": "Administrator", "module": "Accounts", "name": "Pricing Rule", diff --git a/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py b/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py index 62f37a78c11..8729bd6b81d 100644 --- a/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py +++ b/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py @@ -386,7 +386,6 @@ class TestPricingRule(FrappeTestCase): "price_or_product_discount": "Product", "same_item": 1, "free_qty": 1, - "enforce_free_item_qty": 1, "company": "_Test Company", } frappe.get_doc(test_record.copy()).insert() @@ -419,7 +418,6 @@ class TestPricingRule(FrappeTestCase): "same_item": 0, "free_item": "_Test Item 2", "free_qty": 1, - "enforce_free_item_qty": 1, "company": "_Test Company", } frappe.get_doc(test_record.copy()).insert() @@ -430,6 +428,54 @@ class TestPricingRule(FrappeTestCase): self.assertEqual(so.items[1].is_free_item, 1) self.assertEqual(so.items[1].item_code, "_Test Item 2") + def test_enforce_free_item_qty(self): + # this test is only for testing non-enforcement as all other tests in this file already test with enforcement + frappe.delete_doc_if_exists("Pricing Rule", "_Test Pricing Rule") + test_record = { + "doctype": "Pricing Rule", + "title": "_Test Pricing Rule", + "apply_on": "Item Code", + "currency": "USD", + "items": [ + { + "item_code": "_Test Item", + } + ], + "selling": 1, + "rate_or_discount": "Discount Percentage", + "rate": 0, + "min_qty": 0, + "max_qty": 7, + "discount_percentage": 17.5, + "price_or_product_discount": "Product", + "same_item": 0, + "free_item": "_Test Item 2", + "free_qty": 1, + "company": "_Test Company", + } + pricing_rule = frappe.get_doc(test_record.copy()).insert() + + # With enforcement + so = make_sales_order(item_code="_Test Item", qty=1, do_not_submit=True) + self.assertEqual(so.items[1].is_free_item, 1) + self.assertEqual(so.items[1].item_code, "_Test Item 2") + + # Test 1 : Saving a document with an item with pricing list without it's corresponding free item will cause it the free item to be refetched on save + so.items.pop(1) + so.save() + so.reload() + self.assertEqual(len(so.items), 2) + + # Without enforcement + pricing_rule.enforce_free_item_qty = 0 + pricing_rule.save() + + # Test 2 : Deleted free item will not be fetched again on save without enfrocement + so.items.pop(1) + so.save() + so.reload() + self.assertEqual(len(so.items), 1) + def test_cumulative_pricing_rule(self): frappe.delete_doc_if_exists("Pricing Rule", "_Test Cumulative Pricing Rule") test_record = { @@ -963,7 +1009,6 @@ class TestPricingRule(FrappeTestCase): "price_or_product_discount": "Product", "same_item": 1, "free_qty": 1, - "enforce_free_item_qty": 1, "round_free_qty": 1, "is_recursive": 1, "recurse_for": 2, @@ -1009,7 +1054,6 @@ class TestPricingRule(FrappeTestCase): "price_or_product_discount": "Product", "same_item": 1, "free_qty": 10, - "enforce_free_item_qty": 1, "round_free_qty": 1, "is_recursive": 1, "recurse_for": 100, From ef37388993686243924b445e3d215d500762bdea Mon Sep 17 00:00:00 2001 From: Mihir Kandoi Date: Tue, 11 Feb 2025 16:29:01 +0530 Subject: [PATCH 4/8] fix: add is_new in if condition (cherry picked from commit 4dcac564863ee3fed391adccc5898f3cd07f4ccf) --- erpnext/accounts/doctype/pricing_rule/utils.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/pricing_rule/utils.py b/erpnext/accounts/doctype/pricing_rule/utils.py index f0f8f0698e1..7fb26402125 100644 --- a/erpnext/accounts/doctype/pricing_rule/utils.py +++ b/erpnext/accounts/doctype/pricing_rule/utils.py @@ -691,7 +691,9 @@ def apply_pricing_rule_for_free_items(doc, pricing_rule_args): args.pop((item.item_code, item.pricing_rules)) for free_item in args.values(): - if frappe.get_value("Pricing Rule", free_item["pricing_rules"], "enforce_free_item_qty"): + if doc.is_new() or frappe.get_value( + "Pricing Rule", free_item["pricing_rules"], "enforce_free_item_qty" + ): doc.append("items", free_item) From 1ff0edd492146633d89503ce2fae3ef778450d05 Mon Sep 17 00:00:00 2001 From: Mihir Kandoi Date: Mon, 17 Feb 2025 18:21:22 +0530 Subject: [PATCH 5/8] refactor: rename field (cherry picked from commit f3d598881c9b1135d5afca01059e27056a62b305) --- erpnext/accounts/doctype/pricing_rule/pricing_rule.json | 8 ++++---- erpnext/accounts/doctype/pricing_rule/pricing_rule.py | 4 ++-- .../accounts/doctype/pricing_rule/test_pricing_rule.py | 8 ++++---- erpnext/accounts/doctype/pricing_rule/utils.py | 4 ++-- erpnext/stock/doctype/pick_list/test_pick_list.py | 2 +- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.json b/erpnext/accounts/doctype/pricing_rule/pricing_rule.json index 3b743c796af..d1697f10903 100644 --- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.json +++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.json @@ -53,7 +53,7 @@ "column_break_42", "free_item_uom", "round_free_qty", - "enforce_free_item_qty", + "dont_enforce_free_item_qty", "is_recursive", "recurse_for", "apply_recursion_over", @@ -648,15 +648,15 @@ { "default": "1", "depends_on": "eval:doc.price_or_product_discount == 'Product'", - "fieldname": "enforce_free_item_qty", + "fieldname": "dont_enforce_free_item_qty", "fieldtype": "Check", - "label": "Enforce Free Item Qty" + "label": "Don't Enforce Free Item Qty" } ], "icon": "fa fa-gift", "idx": 1, "links": [], - "modified": "2025-02-05 21:03:22.103044", + "modified": "2025-02-17 18:15:39.824639", "modified_by": "Administrator", "module": "Accounts", "name": "Pricing Rule", diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py index fa84c4c0e6b..ba52735cf7e 100644 --- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py +++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py @@ -62,7 +62,7 @@ class PricingRule(Document): disable: DF.Check discount_amount: DF.Currency discount_percentage: DF.Float - enforce_free_item_qty: DF.Check + dont_enforce_free_item_qty: DF.Check for_price_list: DF.Link | None free_item: DF.Link | None free_item_rate: DF.Currency @@ -665,7 +665,7 @@ def remove_pricing_rule_for_item(pricing_rules, item_details, item_code=None, ra if pricing_rule.margin_type in ["Percentage", "Amount"]: item_details.margin_rate_or_amount = 0.0 item_details.margin_type = None - elif pricing_rule.get("free_item") and pricing_rule.get("enforce_free_item_qty"): + elif pricing_rule.get("free_item") and not pricing_rule.get("dont_enforce_free_item_qty"): item_details.remove_free_item = ( item_code if pricing_rule.get("same_item") else pricing_rule.get("free_item") ) diff --git a/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py b/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py index 8729bd6b81d..d4e39a1315b 100644 --- a/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py +++ b/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py @@ -428,7 +428,7 @@ class TestPricingRule(FrappeTestCase): self.assertEqual(so.items[1].is_free_item, 1) self.assertEqual(so.items[1].item_code, "_Test Item 2") - def test_enforce_free_item_qty(self): + def test_dont_enforce_free_item_qty(self): # this test is only for testing non-enforcement as all other tests in this file already test with enforcement frappe.delete_doc_if_exists("Pricing Rule", "_Test Pricing Rule") test_record = { @@ -467,10 +467,10 @@ class TestPricingRule(FrappeTestCase): self.assertEqual(len(so.items), 2) # Without enforcement - pricing_rule.enforce_free_item_qty = 0 + pricing_rule.dont_enforce_free_item_qty = 1 pricing_rule.save() - # Test 2 : Deleted free item will not be fetched again on save without enfrocement + # Test 2 : Deleted free item will not be fetched again on save without enforcement so.items.pop(1) so.save() so.reload() @@ -1287,7 +1287,7 @@ def make_pricing_rule(**args): "discount_amount": args.discount_amount or 0.0, "apply_multiple_pricing_rules": args.apply_multiple_pricing_rules or 0, "has_priority": args.has_priority or 0, - "enforce_free_item_qty": args.enforce_free_item_qty or 1, + "enforce_free_item_qty": args.dont_enforce_free_item_qty or 0, } ) diff --git a/erpnext/accounts/doctype/pricing_rule/utils.py b/erpnext/accounts/doctype/pricing_rule/utils.py index 7fb26402125..fe81945ad41 100644 --- a/erpnext/accounts/doctype/pricing_rule/utils.py +++ b/erpnext/accounts/doctype/pricing_rule/utils.py @@ -691,8 +691,8 @@ def apply_pricing_rule_for_free_items(doc, pricing_rule_args): args.pop((item.item_code, item.pricing_rules)) for free_item in args.values(): - if doc.is_new() or frappe.get_value( - "Pricing Rule", free_item["pricing_rules"], "enforce_free_item_qty" + if doc.is_new() or not frappe.get_value( + "Pricing Rule", free_item["pricing_rules"], "dont_enforce_free_item_qty" ): doc.append("items", free_item) diff --git a/erpnext/stock/doctype/pick_list/test_pick_list.py b/erpnext/stock/doctype/pick_list/test_pick_list.py index 95a79f6caea..3a043ff9fca 100644 --- a/erpnext/stock/doctype/pick_list/test_pick_list.py +++ b/erpnext/stock/doctype/pick_list/test_pick_list.py @@ -914,7 +914,7 @@ class TestPickList(FrappeTestCase): "is_recursive": 1, "recurse_for": 2, "free_qty": 1, - "enforce_free_item_qty": 1, + "dont_enforce_free_item_qty": 0, "company": "_Test Company", "customer": "_Test Customer", } From 4b16272a018ef78c1842ca254411f4284f494bec Mon Sep 17 00:00:00 2001 From: Mihir Kandoi Date: Mon, 17 Feb 2025 18:47:35 +0530 Subject: [PATCH 6/8] fix: set default value to 0 as per new logic (cherry picked from commit 844f1636c0a82dd6e0d0e6e6e3a86bc6652e3ad9) --- erpnext/accounts/doctype/pricing_rule/pricing_rule.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.json b/erpnext/accounts/doctype/pricing_rule/pricing_rule.json index d1697f10903..c4825a6d519 100644 --- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.json +++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.json @@ -646,7 +646,7 @@ "label": "Has Priority" }, { - "default": "1", + "default": "0", "depends_on": "eval:doc.price_or_product_discount == 'Product'", "fieldname": "dont_enforce_free_item_qty", "fieldtype": "Check", From 0cf9c94a3703d129495c22fc683bbba2f1c48d60 Mon Sep 17 00:00:00 2001 From: rohitwaghchaure Date: Wed, 19 Feb 2025 15:10:34 +0530 Subject: [PATCH 7/8] chore: fix conflicts --- .../doctype/pricing_rule/pricing_rule.py | 112 ------------------ 1 file changed, 112 deletions(-) diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py index ba52735cf7e..afd27325820 100644 --- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py +++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py @@ -18,118 +18,6 @@ other_fields = ["other_item_code", "other_item_group", "other_brand"] class PricingRule(Document): -<<<<<<< HEAD -======= - # begin: auto-generated types - # This code is auto-generated. Do not modify anything in this block. - - from typing import TYPE_CHECKING - - if TYPE_CHECKING: - from frappe.types import DF - - from erpnext.accounts.doctype.pricing_rule_brand.pricing_rule_brand import PricingRuleBrand - from erpnext.accounts.doctype.pricing_rule_item_code.pricing_rule_item_code import PricingRuleItemCode - from erpnext.accounts.doctype.pricing_rule_item_group.pricing_rule_item_group import ( - PricingRuleItemGroup, - ) - - applicable_for: DF.Literal[ - "", - "Customer", - "Customer Group", - "Territory", - "Sales Partner", - "Campaign", - "Supplier", - "Supplier Group", - ] - apply_discount_on: DF.Literal["Grand Total", "Net Total"] - apply_discount_on_rate: DF.Check - apply_multiple_pricing_rules: DF.Check - apply_on: DF.Literal["", "Item Code", "Item Group", "Brand", "Transaction"] - apply_recursion_over: DF.Float - apply_rule_on_other: DF.Literal["", "Item Code", "Item Group", "Brand"] - brands: DF.Table[PricingRuleBrand] - buying: DF.Check - campaign: DF.Link | None - company: DF.Link | None - condition: DF.Code | None - coupon_code_based: DF.Check - currency: DF.Link - customer: DF.Link | None - customer_group: DF.Link | None - disable: DF.Check - discount_amount: DF.Currency - discount_percentage: DF.Float - dont_enforce_free_item_qty: DF.Check - for_price_list: DF.Link | None - free_item: DF.Link | None - free_item_rate: DF.Currency - free_item_uom: DF.Link | None - free_qty: DF.Float - has_priority: DF.Check - is_cumulative: DF.Check - is_recursive: DF.Check - item_groups: DF.Table[PricingRuleItemGroup] - items: DF.Table[PricingRuleItemCode] - margin_rate_or_amount: DF.Float - margin_type: DF.Literal["", "Percentage", "Amount"] - max_amt: DF.Currency - max_qty: DF.Float - min_amt: DF.Currency - min_qty: DF.Float - mixed_conditions: DF.Check - naming_series: DF.Literal["PRLE-.####"] - other_brand: DF.Link | None - other_item_code: DF.Link | None - other_item_group: DF.Link | None - price_or_product_discount: DF.Literal["Price", "Product"] - priority: DF.Literal[ - "", - "1", - "2", - "3", - "4", - "5", - "6", - "7", - "8", - "9", - "10", - "11", - "12", - "13", - "14", - "15", - "16", - "17", - "18", - "19", - "20", - ] - promotional_scheme: DF.Link | None - promotional_scheme_id: DF.Data | None - rate: DF.Currency - rate_or_discount: DF.Literal["", "Rate", "Discount Percentage", "Discount Amount"] - recurse_for: DF.Float - round_free_qty: DF.Check - rule_description: DF.SmallText | None - sales_partner: DF.Link | None - same_item: DF.Check - selling: DF.Check - supplier: DF.Link | None - supplier_group: DF.Link | None - territory: DF.Link | None - threshold_percentage: DF.Percent - title: DF.Data - valid_from: DF.Date | None - valid_upto: DF.Date | None - validate_applied_rule: DF.Check - warehouse: DF.Link | None - # end: auto-generated types - ->>>>>>> 19c01b1457 (feat: added option to enforce free item qty in pricing rule) def validate(self): self.validate_mandatory() self.validate_duplicate_apply_on() From 57a0717778abd8eead806f2a17fcae1839e6edd3 Mon Sep 17 00:00:00 2001 From: rohitwaghchaure Date: Wed, 19 Feb 2025 15:12:08 +0530 Subject: [PATCH 8/8] chore: fix conflicts --- .../stock/doctype/pick_list/test_pick_list.py | 96 ------------------- 1 file changed, 96 deletions(-) diff --git a/erpnext/stock/doctype/pick_list/test_pick_list.py b/erpnext/stock/doctype/pick_list/test_pick_list.py index 3a043ff9fca..f679d28c2b2 100644 --- a/erpnext/stock/doctype/pick_list/test_pick_list.py +++ b/erpnext/stock/doctype/pick_list/test_pick_list.py @@ -846,102 +846,6 @@ class TestPickList(FrappeTestCase): self.assertRaises(frappe.ValidationError, pl.save) -<<<<<<< HEAD -======= - def test_over_allowance_picking(self): - warehouse = "_Test Warehouse - _TC" - item = make_item( - "Test Over Allowance Picking Item", - properties={ - "is_stock_item": 1, - }, - ).name - - make_stock_entry(item=item, to_warehouse=warehouse, qty=100) - - so = make_sales_order(item_code=item, qty=10, rate=100) - - pl_doc = create_pick_list(so.name) - pl_doc.save() - self.assertEqual(pl_doc.locations[0].qty, 10) - - pl_doc.locations[0].qty = 15 - pl_doc.locations[0].stock_qty = 15 - pl_doc.save() - - self.assertEqual(pl_doc.locations[0].qty, 15) - self.assertRaises(frappe.ValidationError, pl_doc.submit) - - frappe.db.set_single_value("Stock Settings", "over_picking_allowance", 50) - - pl_doc.reload() - pl_doc.submit() - - frappe.db.set_single_value("Stock Settings", "over_picking_allowance", 0) - - def test_ignore_pricing_rule_in_pick_list(self): - frappe.flags.print_stmt = False - warehouse = "_Test Warehouse - _TC" - item = make_item( - properties={ - "is_stock_item": 1, - "has_batch_no": 1, - "batch_number_series": "IPR-PICKLT-.######", - "create_new_batch": 1, - } - ).name - - make_stock_entry( - item=item, - to_warehouse=warehouse, - qty=2, - basic_rate=100, - ) - - pricing_rule = frappe.get_doc( - { - "doctype": "Pricing Rule", - "title": "Same Free Item", - "price_or_product_discount": "Product", - "selling": 1, - "apply_on": "Item Code", - "items": [ - { - "item_code": item, - } - ], - "same_item": 1, - "is_recursive": 1, - "recurse_for": 2, - "free_qty": 1, - "dont_enforce_free_item_qty": 0, - "company": "_Test Company", - "customer": "_Test Customer", - } - ) - - pricing_rule.save() - frappe.flags.print_stmt = True - - so = make_sales_order(item_code=item, qty=2, rate=100, do_not_save=True) - so.set_warehouse = warehouse - so.submit() - - self.assertEqual(len(so.items), 2) - self.assertTrue(so.items[1].is_free_item) - - pl = create_pick_list(so.name) - pl.ignore_pricing_rule = 1 - pl.save() - pl.submit() - - self.assertEqual(len(pl.locations), 1) - - delivery_note = create_delivery_note(pl.name) - - self.assertEqual(len(delivery_note.items), 1) - ->>>>>>> 366ae85d85 (fix: tests) def test_pick_list_not_reset_batch(self): warehouse = "_Test Warehouse - _TC" item = make_item(