Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: link items to supplier / customer #27281

Merged
merged 17 commits into from
Sep 14, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions erpnext/buying/doctype/supplier/supplier.json
Original file line number Diff line number Diff line change
Expand Up @@ -433,12 +433,12 @@
"image_field": "image",
"links": [
{
"group": "Item Group",
"link_doctype": "Supplier Item Group",
"link_fieldname": "supplier"
"group": "Allowed Items",
"link_doctype": "Party Specific Item",
"link_fieldname": "party"
}
],
"modified": "2021-08-27 18:02:44.314077",
"modified": "2021-09-06 17:37:56.522233",
"modified_by": "Administrator",
"module": "Buying",
"name": "Supplier",
Expand Down

This file was deleted.

This file was deleted.

This file was deleted.

30 changes: 21 additions & 9 deletions erpnext/controllers/queries.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from collections import defaultdict

import frappe
from frappe import scrub
from frappe.desk.reportview import get_filters_cond, get_match_cond
from frappe.utils import nowdate, unique

Expand Down Expand Up @@ -223,18 +224,29 @@ def item_query(doctype, txt, searchfield, start, page_len, filters, as_dict=Fals
if not field in searchfields]
searchfields = " or ".join([field + " like %(txt)s" for field in searchfields])

if filters and isinstance(filters, dict) and filters.get('supplier'):
item_group_list = frappe.get_all('Supplier Item Group',
filters = {'supplier': filters.get('supplier')}, fields = ['item_group'])
if filters and isinstance(filters, dict):
if filters.get('customer') or filters.get('supplier'):
party = filters.get('customer') or filters.get('supplier')
item_rules_list = frappe.get_all('Party Specific Item',
filters = {'party': party}, fields = ['restrict_based_on', 'based_on_value'])

item_groups = []
for i in item_group_list:
item_groups.append(i.item_group)
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] = []

del filters['supplier']
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)] = ['in', filters_dict[filter]]

if filters.get('customer'):
del filters['customer']
else:
del filters['supplier']

if item_groups:
filters['item_group'] = ['in', item_groups]

description_cond = ''
if frappe.db.count('Item', cache=True) < 50000:
Expand Down
1 change: 1 addition & 0 deletions erpnext/patches.txt
Original file line number Diff line number Diff line change
Expand Up @@ -304,5 +304,6 @@ erpnext.patches.v13_0.set_operation_time_based_on_operating_cost
erpnext.patches.v13_0.validate_options_for_data_field
erpnext.patches.v13_0.create_gst_payment_entry_fields
erpnext.patches.v14_0.delete_shopify_doctypes
erpnext.patches.v13_0.replace_supplier_item_group_with_party_specific_item
erpnext.patches.v13_0.update_dates_in_tax_withholding_category
erpnext.patches.v14_0.update_opportunity_currency_fields
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Copyright (c) 2019, Frappe and Contributors
# License: GNU General Public License v3. See license.txt

import frappe


def execute():
if frappe.db.table_exists('Supplier Item Group'):
frappe.reload_doc("selling", "doctype", "party_specific_item")
sig = frappe.db.get_all("Supplier Item Group", fields=["name", "supplier", "item_group"])
for item in sig:
psi = frappe.new_doc("Party Specific Item")
psi.party_type = "Supplier"
psi.party = item.supplier
psi.restrict_based_on = "Item Group"
psi.based_on_value = item.item_group
psi.insert()
22 changes: 10 additions & 12 deletions erpnext/selling/doctype/customer/customer.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
"tax_withholding_category",
"default_bank_account",
"lead_name",
"prospect",
"opportunity_name",
"image",
"column_break0",
Expand Down Expand Up @@ -214,7 +213,8 @@
"fieldtype": "Link",
"ignore_user_permissions": 1,
"label": "Represents Company",
"options": "Company"
"options": "Company",
"unique": 1
},
{
"depends_on": "represents_company",
Expand Down Expand Up @@ -497,14 +497,6 @@
"label": "Tax Withholding Category",
"options": "Tax Withholding Category"
},
{
"fieldname": "prospect",
"fieldtype": "Link",
"label": "Prospect",
"no_copy": 1,
"options": "Prospect",
"print_hide": 1
},
{
"fieldname": "opportunity_name",
"fieldtype": "Link",
Expand All @@ -518,8 +510,14 @@
"idx": 363,
"image_field": "image",
"index_web_pages_for_search": 1,
"links": [],
"modified": "2021-08-25 18:56:09.929905",
"links": [
{
"group": "Allowed Items",
"link_doctype": "Party Specific Item",
"link_fieldname": "party"
}
],
"modified": "2021-09-06 17:38:54.196663",
"modified_by": "Administrator",
"module": "Selling",
"name": "Customer",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt

frappe.ui.form.on('Supplier Item Group', {
frappe.ui.form.on('Party Specific Item', {
// refresh: function(frm) {

// }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
{
"actions": [],
"creation": "2021-08-27 19:28:07.559978",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"party_type",
"party",
"column_break_3",
"restrict_based_on",
"based_on_value"
],
"fields": [
{
"fieldname": "party_type",
"fieldtype": "Select",
"in_list_view": 1,
"label": "Party Type",
"options": "Customer\nSupplier",
"reqd": 1
},
{
"fieldname": "party",
"fieldtype": "Dynamic Link",
"in_list_view": 1,
"label": "Party Name",
"options": "party_type",
"reqd": 1
},
{
"fieldname": "restrict_based_on",
"fieldtype": "Select",
"in_list_view": 1,
"label": "Restrict Items Based On",
"options": "Item\nItem Group\nBrand",
"reqd": 1
},
{
"fieldname": "column_break_3",
"fieldtype": "Column Break"
},
{
"fieldname": "based_on_value",
"fieldtype": "Dynamic Link",
"in_list_view": 1,
"label": "Based On Value",
"options": "restrict_based_on",
"reqd": 1
}
],
"index_web_pages_for_search": 1,
"links": [],
"modified": "2021-09-14 13:27:58.612334",
"modified_by": "Administrator",
"module": "Selling",
"name": "Party Specific Item",
"owner": "Administrator",
"permissions": [
{
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"share": 1,
"write": 1
}
],
"sort_field": "modified",
"sort_order": "DESC",
"title_field": "party",
"track_changes": 1
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt

import frappe
from frappe import _
from frappe.model.document import Document


class PartySpecificItem(Document):
def validate(self):
exists = frappe.db.exists({
'doctype': 'Party Specific Item',
'party_type': self.party_type,
'party': self.party,
'restrict_based_on': self.restrict_based_on,
'based_on': self.based_on_value,
})
if exists:
frappe.throw(_("This item filter has already been applied for the {0}").format(self.party_type))
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt

import unittest

import frappe

from erpnext.controllers.queries import item_query

test_dependencies = ['Item', 'Customer', 'Supplier']

def create_party_specific_item(**args):
psi = frappe.new_doc("Party Specific Item")
psi.party_type = args.get('party_type')
psi.party = args.get('party')
psi.restrict_based_on = args.get('restrict_based_on')
psi.based_on_value = args.get('based_on_value')
psi.insert()

class TestPartySpecificItem(unittest.TestCase):
def setUp(self):
self.customer = frappe.get_last_doc("Customer")
self.supplier = frappe.get_last_doc("Supplier")
self.item = frappe.get_last_doc("Item")

def test_item_query_for_customer(self):
create_party_specific_item(party_type='Customer', party=self.customer.name, restrict_based_on='Item', based_on_value=self.item.name)
filters = {'is_sales_item': 1, 'customer': self.customer.name}
items = item_query(doctype= 'Item', txt= '', searchfield= 'name', start= 0, page_len= 20,filters=filters, as_dict= False)
for item in items:
self.assertEqual(item[0], self.item.name)

def test_item_query_for_supplier(self):
create_party_specific_item(party_type='Supplier', party=self.supplier.name, restrict_based_on='Item Group', based_on_value=self.item.item_group)
filters = {'supplier': self.supplier.name, 'is_purchase_item': 1}
items = item_query(doctype= 'Item', txt= '', searchfield= 'name', start= 0, page_len= 20,filters=filters, as_dict= False)
for item in items:
self.assertEqual(item[2], self.item.item_group)
Loading