[Enahance] Update variants fields defined in the Item Varianst Settings, if template updated
This commit is contained in:
parent
ab5b03011d
commit
0e28fccb34
@ -105,6 +105,11 @@ def get_data():
|
||||
"name": "Pricing Rule",
|
||||
"description": _("Rules for applying pricing and discount.")
|
||||
},
|
||||
{
|
||||
"type": "doctype",
|
||||
"name": "Item Variant Settings",
|
||||
"description": _("Item Variant Settings."),
|
||||
},
|
||||
|
||||
]
|
||||
},
|
||||
|
@ -180,10 +180,10 @@ def copy_attributes_to_variant(item, variant):
|
||||
# don't copy manufacturer values if based on part no
|
||||
exclude_fields += ['manufacturer', 'manufacturer_part_no']
|
||||
|
||||
allow_fields = [d.field_name for d in frappe.get_all("Variant Field", fields = ['field_name'])]
|
||||
for field in item.meta.fields:
|
||||
# "Table" is part of `no_value_field` but we shouldn't ignore tables
|
||||
if (field.fieldtype == 'Table' or field.fieldtype not in no_value_fields) \
|
||||
and (not field.no_copy) and field.fieldname not in exclude_fields:
|
||||
if (field.reqd or field.fieldname in allow_fields) and field.fieldname not in exclude_fields:
|
||||
if variant.get(field.fieldname) != item.get(field.fieldname):
|
||||
variant.set(field.fieldname, item.get(field.fieldname))
|
||||
variant.variant_of = item.name
|
||||
|
@ -4,6 +4,7 @@ import frappe
|
||||
import json
|
||||
import unittest
|
||||
|
||||
from erpnext.stock.doctype.item.test_item import set_item_variant_settings
|
||||
from erpnext.controllers.item_variant import copy_attributes_to_variant, make_variant_item_code
|
||||
|
||||
# python 3 compatibility stuff
|
||||
@ -54,5 +55,7 @@ def make_item_variant():
|
||||
|
||||
class TestItemVariant(unittest.TestCase):
|
||||
def test_tables_in_template_copied_to_variant(self):
|
||||
fields = [{'field_name': 'quality_parameters'}]
|
||||
set_item_variant_settings(fields)
|
||||
variant = make_item_variant()
|
||||
self.assertNotEqual(variant.get("quality_parameters"), [])
|
||||
|
BIN
erpnext/docs/assets/img/stock/item_variants_settings.png
Normal file
BIN
erpnext/docs/assets/img/stock/item_variants_settings.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 45 KiB |
@ -48,4 +48,11 @@ When you make a new Variant, the system will prompt you to select a Manufacturer
|
||||
<img class='screenshot' alt='Setup Item Variant by Manufacturer'
|
||||
src='/docs/assets/img/stock/set-variant-by-mfg.png'>
|
||||
|
||||
The naming of the variant will be the name (ID) of the template Item with a number suffix. e.g. "ITEM000" will have variant "ITEM000-1"
|
||||
The naming of the variant will be the name (ID) of the template Item with a number suffix. e.g. "ITEM000" will have variant "ITEM000-1"
|
||||
|
||||
### Update Variants Based on Template
|
||||
To update the value in the variants items from the template item, select the respective fields first in the Item Variant Settings page. After that system will update the value of that fields in the variants if that values has been changed in the template item.
|
||||
|
||||
To set the fields Goto Stock > Item Variant Settings
|
||||
<img class='screenshot' alt='Item Variant Settings'
|
||||
src='/docs/assets/img/stock/item_variants_settings.png'>
|
||||
|
@ -97,6 +97,12 @@ frappe.ui.form.on("Item", {
|
||||
}
|
||||
frappe.set_route('Form', 'Item', new_item.name);
|
||||
});
|
||||
|
||||
if(frm.doc.has_variants) {
|
||||
frm.add_custom_button(__("Item Variant Settings"), function() {
|
||||
frappe.set_route("Form", "Item Variant Settings");
|
||||
}, __("View"));
|
||||
}
|
||||
},
|
||||
|
||||
validate: function(frm){
|
||||
|
@ -100,6 +100,7 @@ class Item(WebsiteGenerator):
|
||||
def on_update(self):
|
||||
invalidate_cache_for_item(self)
|
||||
self.validate_name_with_item_group()
|
||||
self.update_variants()
|
||||
self.update_item_price()
|
||||
self.update_template_item()
|
||||
|
||||
@ -607,9 +608,24 @@ class Item(WebsiteGenerator):
|
||||
|
||||
if not template_item.show_in_website:
|
||||
template_item.show_in_website = 1
|
||||
template_item.flags.dont_update_variants = True
|
||||
template_item.flags.ignore_permissions = True
|
||||
template_item.save()
|
||||
|
||||
def update_variants(self):
|
||||
if self.flags.dont_update_variants:
|
||||
return
|
||||
if self.has_variants:
|
||||
updated = []
|
||||
variants = frappe.db.get_all("Item", fields=["item_code"], filters={"variant_of": self.name })
|
||||
for d in variants:
|
||||
variant = frappe.get_doc("Item", d)
|
||||
copy_attributes_to_variant(self, variant)
|
||||
variant.save()
|
||||
updated.append(d.item_code)
|
||||
if updated:
|
||||
frappe.msgprint(_("Item Variants {0} updated").format(", ".join(updated)))
|
||||
|
||||
def validate_has_variants(self):
|
||||
if not self.has_variants and frappe.db.get_value("Item", self.name, "has_variants"):
|
||||
if frappe.db.exists("Item", {"variant_of": self.name}):
|
||||
|
@ -119,6 +119,37 @@ class TestItem(unittest.TestCase):
|
||||
variant.item_code = "_Test Variant Item-L-duplicate"
|
||||
self.assertRaises(ItemVariantExistsError, variant.save)
|
||||
|
||||
def test_copy_fields_from_template_to_variants(self):
|
||||
fields = [{'field_name': 'item_group'}, {'field_name': 'is_stock_item'}]
|
||||
allow_fields = [d.get('field_name') for d in fields]
|
||||
set_item_variant_settings(fields)
|
||||
|
||||
if not frappe.db.get_value('Item Attribute Value',
|
||||
{'parent': 'Test Size', 'attribute_value': 'Extra Large'}, 'name'):
|
||||
item_attribute = frappe.get_doc('Item Attribute', 'Test Size')
|
||||
item_attribute.append('item_attribute_values', {
|
||||
'attribute_value' : 'Extra Large',
|
||||
'abbr': 'XL'
|
||||
})
|
||||
item_attribute.save()
|
||||
|
||||
variant = create_variant("_Test Variant Item", {"Test Size": "Extra Large"})
|
||||
variant.item_code = "_Test Variant Item-XL"
|
||||
variant.item_name = "_Test Variant Item-XL"
|
||||
variant.save()
|
||||
|
||||
template = frappe.get_doc('Item', '_Test Variant Item')
|
||||
template.item_group = "_Test Item Group D"
|
||||
template.save()
|
||||
|
||||
variant = frappe.get_doc('Item', '_Test Variant Item-XL')
|
||||
for fieldname in allow_fields:
|
||||
self.assertEquals(template.get(fieldname), variant.get(fieldname))
|
||||
|
||||
template = frappe.get_doc('Item', '_Test Variant Item')
|
||||
template.item_group = "_Test Item Group Desktops"
|
||||
template.save()
|
||||
|
||||
def test_make_item_variant_with_numeric_values(self):
|
||||
# cleanup
|
||||
for d in frappe.db.get_all('Item', filters={'variant_of':
|
||||
@ -194,6 +225,9 @@ class TestItem(unittest.TestCase):
|
||||
{"item_code": "Test Item for Merging 2", "warehouse": "_Test Warehouse 1 - _TC"}))
|
||||
|
||||
def test_item_variant_by_manufacturer(self):
|
||||
fields = [{'field_name': 'description'}, {'field_name': 'variant_based_on'}]
|
||||
set_item_variant_settings(fields)
|
||||
|
||||
if frappe.db.exists('Item', '_Test Variant Mfg'):
|
||||
frappe.delete_doc('Item', '_Test Variant Mfg')
|
||||
if frappe.db.exists('Item', '_Test Variant Mfg-1'):
|
||||
@ -227,6 +261,10 @@ class TestItem(unittest.TestCase):
|
||||
self.assertEquals(variant.manufacturer, 'MSG1')
|
||||
self.assertEquals(variant.manufacturer_part_no, '007')
|
||||
|
||||
def set_item_variant_settings(fields):
|
||||
doc = frappe.get_doc('Item Variant Settings')
|
||||
doc.set('fields', fields)
|
||||
doc.save()
|
||||
|
||||
def make_item_variant():
|
||||
if not frappe.db.exists("Item", "_Test Variant Item-S"):
|
||||
|
@ -0,0 +1,18 @@
|
||||
// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Item Variant Settings', {
|
||||
setup: function(frm) {
|
||||
const allow_fields = [];
|
||||
frappe.model.with_doctype('Item', () => {
|
||||
frappe.get_meta('Item').fields.forEach(d => {
|
||||
if(!in_list(['HTML', 'Section Break', 'Column Break', 'Button'], d.fieldtype) && !d.no_copy) {
|
||||
allow_fields.push(d.fieldname);
|
||||
}
|
||||
});
|
||||
|
||||
const child = frappe.meta.get_docfield("Variant Field", "field_name", frm.doc.name);
|
||||
child.options = allow_fields;
|
||||
});
|
||||
}
|
||||
});
|
@ -0,0 +1,143 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
"beta": 0,
|
||||
"creation": "2017-08-29 16:38:31.173830",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "variant_fields",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Variant Fields",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "fields",
|
||||
"fieldtype": "Table",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Fields",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Variant Field",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"idx": 0,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
"is_submittable": 0,
|
||||
"issingle": 1,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2017-08-29 16:38:49.467749",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Item Variant Settings",
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"amend": 0,
|
||||
"apply_user_permissions": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 0,
|
||||
"email": 1,
|
||||
"export": 0,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 0,
|
||||
"role": "System Manager",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"amend": 0,
|
||||
"apply_user_permissions": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 0,
|
||||
"email": 1,
|
||||
"export": 0,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 0,
|
||||
"role": "Item Manager",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 1,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1,
|
||||
"track_seen": 0
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
from frappe.model.document import Document
|
||||
|
||||
class ItemVariantSettings(Document):
|
||||
pass
|
@ -0,0 +1,23 @@
|
||||
/* eslint-disable */
|
||||
// rename this file from _test_[name] to test_[name] to activate
|
||||
// and remove above this line
|
||||
|
||||
QUnit.test("test: Item Variant Settings", function (assert) {
|
||||
let done = assert.async();
|
||||
|
||||
// number of asserts
|
||||
assert.expect(1);
|
||||
|
||||
frappe.run_serially([
|
||||
// insert a new Item Variant Settings
|
||||
() => frappe.tests.make('Item Variant Settings', [
|
||||
// values to be set
|
||||
{key: 'value'}
|
||||
]),
|
||||
() => {
|
||||
assert.equal(cur_frm.doc.key, 'value');
|
||||
},
|
||||
() => done()
|
||||
]);
|
||||
|
||||
});
|
@ -11,6 +11,7 @@ from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt \
|
||||
from erpnext.stock.doctype.stock_ledger_entry.stock_ledger_entry import StockFreezeError
|
||||
from erpnext.stock.stock_ledger import get_previous_sle
|
||||
from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import create_stock_reconciliation
|
||||
from erpnext.stock.doctype.item.test_item import set_item_variant_settings
|
||||
from frappe.tests.test_permissions import set_user_permission_doctypes
|
||||
from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
|
||||
from erpnext.accounts.doctype.account.test_account import get_inventory_account
|
||||
@ -79,6 +80,19 @@ class TestStockEntry(unittest.TestCase):
|
||||
self._test_auto_material_request("_Test Item", material_request_type="Transfer")
|
||||
|
||||
def test_auto_material_request_for_variant(self):
|
||||
fields = [{'field_name': 'reorder_levels'}]
|
||||
set_item_variant_settings(fields)
|
||||
template = frappe.get_doc("Item", "_Test Variant Item")
|
||||
|
||||
if not template.reorder_levels:
|
||||
template.append('reorder_levels', {
|
||||
"material_request_type": "Purchase",
|
||||
"warehouse": "_Test Warehouse - _TC",
|
||||
"warehouse_reorder_level": 20,
|
||||
"warehouse_reorder_qty": 20
|
||||
})
|
||||
|
||||
template.save()
|
||||
self._test_auto_material_request("_Test Variant Item-S")
|
||||
|
||||
def test_auto_material_request_for_warehouse_group(self):
|
||||
|
0
erpnext/stock/doctype/variant_field/__init__.py
Normal file
0
erpnext/stock/doctype/variant_field/__init__.py
Normal file
23
erpnext/stock/doctype/variant_field/test_variant_field.js
Normal file
23
erpnext/stock/doctype/variant_field/test_variant_field.js
Normal file
@ -0,0 +1,23 @@
|
||||
/* eslint-disable */
|
||||
// rename this file from _test_[name] to test_[name] to activate
|
||||
// and remove above this line
|
||||
|
||||
QUnit.test("test: Variant Field", function (assert) {
|
||||
let done = assert.async();
|
||||
|
||||
// number of asserts
|
||||
assert.expect(1);
|
||||
|
||||
frappe.run_serially([
|
||||
// insert a new Variant Field
|
||||
() => frappe.tests.make('Variant Field', [
|
||||
// values to be set
|
||||
{key: 'value'}
|
||||
]),
|
||||
() => {
|
||||
assert.equal(cur_frm.doc.key, 'value');
|
||||
},
|
||||
() => done()
|
||||
]);
|
||||
|
||||
});
|
@ -0,0 +1,9 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# See license.txt
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import unittest
|
||||
|
||||
class TestVariantField(unittest.TestCase):
|
||||
pass
|
8
erpnext/stock/doctype/variant_field/variant_field.js
Normal file
8
erpnext/stock/doctype/variant_field/variant_field.js
Normal file
@ -0,0 +1,8 @@
|
||||
// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Variant Field', {
|
||||
refresh: function() {
|
||||
|
||||
}
|
||||
});
|
72
erpnext/stock/doctype/variant_field/variant_field.json
Normal file
72
erpnext/stock/doctype/variant_field/variant_field.json
Normal file
@ -0,0 +1,72 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
"beta": 0,
|
||||
"creation": "2017-08-29 16:33:33.978574",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "field_name",
|
||||
"fieldtype": "Select",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Field Name",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"idx": 0,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 1,
|
||||
"max_attachments": 0,
|
||||
"modified": "2017-08-29 17:19:20.353197",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Variant Field",
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"quick_entry": 1,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1,
|
||||
"track_seen": 0
|
||||
}
|
9
erpnext/stock/doctype/variant_field/variant_field.py
Normal file
9
erpnext/stock/doctype/variant_field/variant_field.py
Normal file
@ -0,0 +1,9 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
from frappe.model.document import Document
|
||||
|
||||
class VariantField(Document):
|
||||
pass
|
Loading…
x
Reference in New Issue
Block a user