diff --git a/erpnext/controllers/queries.py b/erpnext/controllers/queries.py index 8de84a3044f..931d6361efe 100644 --- a/erpnext/controllers/queries.py +++ b/erpnext/controllers/queries.py @@ -216,11 +216,8 @@ def item_query(doctype, txt, searchfield, start, page_len, filters, as_dict=Fals group = "Customer Group" if filters.get("customer") else "Supplier Group" item_rules_list = frappe.get_all( "Party Specific Item", - filters={ - "party": ["!=", party], - "party_type": party_type, - }, - fields=["restrict_based_on", "based_on_value"], + filters={"party_type": party_type}, + fields=["party", "restrict_based_on", "based_on_value"], ) party_group_rules_list = frappe.get_all( @@ -229,21 +226,30 @@ def item_query(doctype, txt, searchfield, start, page_len, filters, as_dict=Fals fields=["party as party_group", "restrict_based_on", "based_on_value"], ) current_party_group = frappe.get_value(party_type, party, frappe.scrub(group)) + + restricted_items = defaultdict(set) + allowed_items = defaultdict(set) + + for rule in item_rules_list: + restrict_based_on = "name" if rule.restrict_based_on == "Item" else rule.restrict_based_on + + if rule.party == party: + allowed_items[restrict_based_on].add(rule.based_on_value) + else: + restricted_items[restrict_based_on].add(rule.based_on_value) + for rule in party_group_rules_list: - if current_party_group != rule.party_group: - item_rules_list.append(rule) + restrict_based_on = "name" if rule.restrict_based_on == "Item" else rule.restrict_based_on - filters_dict = {} - for rule in item_rules_list: - if rule["restrict_based_on"] == "Item": - rule["restrict_based_on"] = "name" - filters_dict[rule.restrict_based_on] = [] + if current_party_group == rule.party_group: + allowed_items[restrict_based_on].add(rule.based_on_value) + else: + restricted_items[restrict_based_on].add(rule.based_on_value) - for rule in item_rules_list: - filters_dict[rule.restrict_based_on].append(rule.based_on_value) - - for filter in filters_dict: - filters[scrub(filter)] = ["not in", filters_dict[filter]] + for field, restricted_values in restricted_items.items(): + values_to_exclude = restricted_values - allowed_items[field] + if values_to_exclude: + filters[scrub(field)] = ["not in", list(values_to_exclude)] if filters.get("customer"): del filters["customer"] diff --git a/erpnext/selling/doctype/party_specific_item/test_party_specific_item.py b/erpnext/selling/doctype/party_specific_item/test_party_specific_item.py index eaa68232d27..008d465dc87 100644 --- a/erpnext/selling/doctype/party_specific_item/test_party_specific_item.py +++ b/erpnext/selling/doctype/party_specific_item/test_party_specific_item.py @@ -16,6 +16,36 @@ def create_party_specific_item(**args): psi.insert() +def create_supplier(supplier_name): + if frappe.db.exists("Supplier", supplier_name): + return frappe.get_doc("Supplier", supplier_name) + + return frappe.get_doc( + { + "doctype": "Supplier", + "supplier_name": supplier_name, + "supplier_group": "Services", + "supplier_type": "Company", + } + ).insert() + + +def create_item(item_code): + if frappe.db.exists("Item", item_code): + return frappe.get_doc("Item", item_code) + + return frappe.get_doc( + { + "doctype": "Item", + "item_code": item_code, + "item_name": item_code, + "description": item_code, + "item_group": "Products", + "is_purchase_item": 1, + } + ).insert() + + class TestPartySpecificItem(ERPNextTestSuite): def test_item_query_for_customer(self): customer = "_Test Customer With Template" @@ -49,6 +79,34 @@ class TestPartySpecificItem(ERPNextTestSuite): ) self.assertTrue(item in flatten(items)) + def test_item_query_for_supplier_with_item_restricted_to_multiple_suppliers(self): + item = f"Party Specific Item {frappe.generate_hash(length=8)}" + supplier1 = f"Party Specific Supplier {frappe.generate_hash(length=8)}" + supplier2 = f"Party Specific Supplier {frappe.generate_hash(length=8)}" + + create_item(item) + create_supplier(supplier1) + create_supplier(supplier2) + + for supplier in (supplier1, supplier2): + create_party_specific_item( + party_type="Supplier", + party=supplier, + restrict_based_on="Item", + based_on_value=item, + ) + + items = item_query( + doctype="Item", + txt=item, + searchfield="name", + start=0, + page_len=20, + filters={"supplier": supplier1, "is_purchase_item": 1}, + as_dict=False, + ) + self.assertIn(item, flatten(items)) + def test_party_group(self): customer = "_Test Customer With Template" item = "_Test Item"