mirror of
https://github.com/frappe/erpnext.git
synced 2026-05-27 08:54:45 +00:00
item variants, creation, deleation and update logic added.
logic added to copy changes in template to variants
This commit is contained in:
@@ -30,10 +30,6 @@ frappe.ui.form.on("Item", {
|
|||||||
frm.add_custom_button(__("Show Variants"), function() {
|
frm.add_custom_button(__("Show Variants"), function() {
|
||||||
frappe.set_route("List", "Item", {"variant_of": frm.doc.name});
|
frappe.set_route("List", "Item", {"variant_of": frm.doc.name});
|
||||||
}, "icon-list", "btn-default");
|
}, "icon-list", "btn-default");
|
||||||
frm.add_custom_button(__("Manage Variants"), function() {
|
|
||||||
frappe.route_options = {"item": frm.doc.name };
|
|
||||||
new_doc("Manage Variants");
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
if (frm.doc.variant_of) {
|
if (frm.doc.variant_of) {
|
||||||
frm.set_intro(__("This Item is a Variant of {0} (Template). Attributes will be copied over from the template unless 'No Copy' is set", [frm.doc.variant_of]), true);
|
frm.set_intro(__("This Item is a Variant of {0} (Template). Attributes will be copied over from the template unless 'No Copy' is set", [frm.doc.variant_of]), true);
|
||||||
@@ -87,6 +83,11 @@ frappe.ui.form.on("Item", {
|
|||||||
|
|
||||||
is_stock_item: function(frm) {
|
is_stock_item: function(frm) {
|
||||||
erpnext.item.toggle_reqd(frm);
|
erpnext.item.toggle_reqd(frm);
|
||||||
|
},
|
||||||
|
|
||||||
|
manage_variants: function(frm) {
|
||||||
|
frappe.route_options = {"item": frm.doc.name };
|
||||||
|
frappe.set_route("List", "Manage Variants");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
{
|
{
|
||||||
"fieldname": "name_and_description_section",
|
"fieldname": "name_and_description_section",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"label": "Name and Description",
|
"label": "",
|
||||||
"no_copy": 0,
|
"no_copy": 0,
|
||||||
"oldfieldtype": "Section Break",
|
"oldfieldtype": "Section Break",
|
||||||
"options": "icon-flag",
|
"options": "icon-flag",
|
||||||
@@ -167,16 +167,17 @@
|
|||||||
"search_index": 0
|
"search_index": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"depends_on": "eval:!!!doc.variant_of",
|
"depends_on": "eval:!doc.variant_of",
|
||||||
"fieldname": "variants_section",
|
"fieldname": "variants_section",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"label": "Variants",
|
"label": "Variant",
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
"precision": ""
|
"precision": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"default": "0",
|
"default": "0",
|
||||||
"description": "Automatically set. If this item has variants, then it cannot be selected in sales orders etc.",
|
"depends_on": "",
|
||||||
|
"description": "If this item has variants, then it cannot be selected in sales orders etc.",
|
||||||
"fieldname": "has_variants",
|
"fieldname": "has_variants",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"label": "Has Variants",
|
"label": "Has Variants",
|
||||||
@@ -185,6 +186,38 @@
|
|||||||
"precision": "",
|
"precision": "",
|
||||||
"read_only": 0
|
"read_only": 0
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "column_break_18",
|
||||||
|
"fieldtype": "Column Break",
|
||||||
|
"permlevel": 0,
|
||||||
|
"precision": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"depends_on": "has_variants",
|
||||||
|
"fieldname": "manage_variants",
|
||||||
|
"fieldtype": "Button",
|
||||||
|
"label": "Manage Variants",
|
||||||
|
"permlevel": 0,
|
||||||
|
"precision": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "section_break_20",
|
||||||
|
"fieldtype": "Section Break",
|
||||||
|
"permlevel": 0,
|
||||||
|
"precision": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"depends_on": "variant_of",
|
||||||
|
"fieldname": "attributes",
|
||||||
|
"fieldtype": "Table",
|
||||||
|
"hidden": 0,
|
||||||
|
"label": "Attributes",
|
||||||
|
"no_copy": 1,
|
||||||
|
"options": "Variant Attribute",
|
||||||
|
"permlevel": 0,
|
||||||
|
"precision": "",
|
||||||
|
"read_only": 0
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "inventory",
|
"fieldname": "inventory",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ from frappe.website.website_generator import WebsiteGenerator
|
|||||||
from erpnext.setup.doctype.item_group.item_group import invalidate_cache_for, get_parent_item_groups
|
from erpnext.setup.doctype.item_group.item_group import invalidate_cache_for, get_parent_item_groups
|
||||||
from frappe.website.render import clear_cache
|
from frappe.website.render import clear_cache
|
||||||
from frappe.website.doctype.website_slideshow.website_slideshow import get_slideshow
|
from frappe.website.doctype.website_slideshow.website_slideshow import get_slideshow
|
||||||
import copy
|
from erpnext.stock.doctype.manage_variants.manage_variants import update_variant
|
||||||
|
|
||||||
class WarehouseNotSet(frappe.ValidationError): pass
|
class WarehouseNotSet(frappe.ValidationError): pass
|
||||||
|
|
||||||
@@ -46,9 +46,6 @@ class Item(WebsiteGenerator):
|
|||||||
if self.image and not self.website_image:
|
if self.image and not self.website_image:
|
||||||
self.website_image = self.image
|
self.website_image = self.image
|
||||||
|
|
||||||
if self.variant_of:
|
|
||||||
self.copy_attributes_to_variant(frappe.get_doc("Item", self.variant_of), self)
|
|
||||||
|
|
||||||
self.check_warehouse_is_set_for_stock_item()
|
self.check_warehouse_is_set_for_stock_item()
|
||||||
self.check_stock_uom_with_bin()
|
self.check_stock_uom_with_bin()
|
||||||
self.add_default_uom_in_conversion_factor_table()
|
self.add_default_uom_in_conversion_factor_table()
|
||||||
@@ -63,6 +60,7 @@ class Item(WebsiteGenerator):
|
|||||||
self.validate_warehouse_for_reorder()
|
self.validate_warehouse_for_reorder()
|
||||||
self.update_item_desc()
|
self.update_item_desc()
|
||||||
self.synced_with_hub = 0
|
self.synced_with_hub = 0
|
||||||
|
self.validate_has_variants()
|
||||||
|
|
||||||
if not self.get("__islocal"):
|
if not self.get("__islocal"):
|
||||||
self.old_item_group = frappe.db.get_value(self.doctype, self.name, "item_group")
|
self.old_item_group = frappe.db.get_value(self.doctype, self.name, "item_group")
|
||||||
@@ -74,6 +72,7 @@ class Item(WebsiteGenerator):
|
|||||||
invalidate_cache_for_item(self)
|
invalidate_cache_for_item(self)
|
||||||
self.validate_name_with_item_group()
|
self.validate_name_with_item_group()
|
||||||
self.update_item_price()
|
self.update_item_price()
|
||||||
|
self.update_variants()
|
||||||
|
|
||||||
def get_context(self, context):
|
def get_context(self, context):
|
||||||
context["parent_groups"] = get_parent_item_groups(self.item_group) + \
|
context["parent_groups"] = get_parent_item_groups(self.item_group) + \
|
||||||
@@ -129,105 +128,6 @@ class Item(WebsiteGenerator):
|
|||||||
if not matched:
|
if not matched:
|
||||||
frappe.throw(_("Default Unit of Measure can not be changed directly because you have already made some transaction(s) with another UOM. To change default UOM, use 'UOM Replace Utility' tool under Stock module."))
|
frappe.throw(_("Default Unit of Measure can not be changed directly because you have already made some transaction(s) with another UOM. To change default UOM, use 'UOM Replace Utility' tool under Stock module."))
|
||||||
|
|
||||||
def sync_variants(self):
|
|
||||||
variant_item_codes = self.get_variant_item_codes()
|
|
||||||
|
|
||||||
# delete missing variants
|
|
||||||
existing_variants = [d.name for d in frappe.get_all("Item",
|
|
||||||
filters={"variant_of":self.name})]
|
|
||||||
|
|
||||||
updated, deleted = [], []
|
|
||||||
for existing_variant in existing_variants:
|
|
||||||
if existing_variant not in variant_item_codes:
|
|
||||||
frappe.delete_doc("Item", existing_variant)
|
|
||||||
deleted.append(existing_variant)
|
|
||||||
else:
|
|
||||||
self.update_variant(existing_variant)
|
|
||||||
updated.append(existing_variant)
|
|
||||||
|
|
||||||
inserted = []
|
|
||||||
for item_code in variant_item_codes:
|
|
||||||
if item_code not in existing_variants:
|
|
||||||
self.make_variant(item_code)
|
|
||||||
inserted.append(item_code)
|
|
||||||
|
|
||||||
if inserted:
|
|
||||||
frappe.msgprint(_("Item Variants {0} created").format(", ".join(inserted)))
|
|
||||||
|
|
||||||
if updated:
|
|
||||||
frappe.msgprint(_("Item Variants {0} updated").format(", ".join(updated)))
|
|
||||||
|
|
||||||
if deleted:
|
|
||||||
frappe.msgprint(_("Item Variants {0} deleted").format(", ".join(deleted)))
|
|
||||||
|
|
||||||
def get_variant_item_codes(self):
|
|
||||||
"""Get all possible suffixes for variants"""
|
|
||||||
if not self.variants:
|
|
||||||
return []
|
|
||||||
|
|
||||||
self.variant_attributes = {}
|
|
||||||
variant_dict = {}
|
|
||||||
variant_item_codes = []
|
|
||||||
|
|
||||||
for d in self.variants:
|
|
||||||
variant_dict.setdefault(d.item_attribute, []).append(d.item_attribute_value)
|
|
||||||
|
|
||||||
all_attributes = [d.name for d in frappe.get_all("Item Attribute", order_by = "priority asc")]
|
|
||||||
|
|
||||||
# sort attributes by their priority
|
|
||||||
attributes = filter(None, map(lambda d: d if d in variant_dict else None, all_attributes))
|
|
||||||
|
|
||||||
def add_attribute_suffixes(item_code, my_attributes, attributes):
|
|
||||||
attr = frappe.get_doc("Item Attribute", attributes[0])
|
|
||||||
for value in attr.item_attribute_values:
|
|
||||||
if value.attribute_value in variant_dict[attr.name]:
|
|
||||||
_my_attributes = copy.deepcopy(my_attributes)
|
|
||||||
_my_attributes.append([attr.name, value.attribute_value])
|
|
||||||
if len(attributes) > 1:
|
|
||||||
add_attribute_suffixes(item_code + "-" + value.abbr, _my_attributes, attributes[1:])
|
|
||||||
else:
|
|
||||||
variant_item_codes.append(item_code + "-" + value.abbr)
|
|
||||||
self.variant_attributes[item_code + "-" + value.abbr] = _my_attributes
|
|
||||||
|
|
||||||
add_attribute_suffixes(self.name, [], attributes)
|
|
||||||
|
|
||||||
return variant_item_codes
|
|
||||||
|
|
||||||
def make_variant(self, item_code):
|
|
||||||
item = frappe.new_doc("Item")
|
|
||||||
item.item_code = item_code
|
|
||||||
self.copy_attributes_to_variant(self, item, insert=True)
|
|
||||||
item.insert()
|
|
||||||
|
|
||||||
def update_variant(self, item_code):
|
|
||||||
item = frappe.get_doc("Item", item_code)
|
|
||||||
item.item_code = item_code
|
|
||||||
self.copy_attributes_to_variant(self, item)
|
|
||||||
item.save()
|
|
||||||
|
|
||||||
def copy_attributes_to_variant(self, template, variant, insert=False):
|
|
||||||
from frappe.model import no_value_fields
|
|
||||||
for field in self.meta.fields:
|
|
||||||
if field.fieldtype not in no_value_fields and (insert or not field.no_copy)\
|
|
||||||
and field.fieldname not in ("item_code", "item_name"):
|
|
||||||
if variant.get(field.fieldname) != template.get(field.fieldname):
|
|
||||||
variant.set(field.fieldname, template.get(field.fieldname))
|
|
||||||
variant.__dirty = True
|
|
||||||
|
|
||||||
variant.description += "\n"
|
|
||||||
|
|
||||||
if not getattr(template, "variant_attributes", None):
|
|
||||||
template.get_variant_item_codes()
|
|
||||||
|
|
||||||
for attr in template.variant_attributes[variant.item_code]:
|
|
||||||
variant.description += "<p>" + attr[0] + ": " + attr[1] + "</p>"
|
|
||||||
|
|
||||||
variant.item_name = self.item_name + variant.item_code[len(self.name):]
|
|
||||||
|
|
||||||
variant.variant_of = template.name
|
|
||||||
variant.has_variants = 0
|
|
||||||
variant.show_in_website = 0
|
|
||||||
|
|
||||||
def update_template_tables(self):
|
def update_template_tables(self):
|
||||||
template = frappe.get_doc("Item", self.variant_of)
|
template = frappe.get_doc("Item", self.variant_of)
|
||||||
|
|
||||||
@@ -320,7 +220,8 @@ class Item(WebsiteGenerator):
|
|||||||
vals.has_batch_no != self.has_batch_no or
|
vals.has_batch_no != self.has_batch_no or
|
||||||
cstr(vals.valuation_method) != cstr(self.valuation_method)):
|
cstr(vals.valuation_method) != cstr(self.valuation_method)):
|
||||||
if self.check_if_sle_exists() == "exists":
|
if self.check_if_sle_exists() == "exists":
|
||||||
frappe.throw(_("As there are existing stock transactions for this item, you can not change the values of 'Has Serial No', 'Has Batch No', 'Is Stock Item' and 'Valuation Method'"))
|
frappe.throw(_("As there are existing stock transactions for this item, \
|
||||||
|
you can not change the values of 'Has Serial No', 'Has Batch No', 'Is Stock Item' and 'Valuation Method'"))
|
||||||
|
|
||||||
def validate_reorder_level(self):
|
def validate_reorder_level(self):
|
||||||
if cint(self.apply_warehouse_wise_reorder_level):
|
if cint(self.apply_warehouse_wise_reorder_level):
|
||||||
@@ -423,6 +324,20 @@ class Item(WebsiteGenerator):
|
|||||||
item_code = %s and docstatus < 2""",(self.description, self.name))
|
item_code = %s and docstatus < 2""",(self.description, self.name))
|
||||||
frappe.db.sql("""update `tabBOM Explosion Item` set description = %s where
|
frappe.db.sql("""update `tabBOM Explosion Item` set description = %s where
|
||||||
item_code = %s and docstatus < 2""",(self.description, self.name))
|
item_code = %s and docstatus < 2""",(self.description, self.name))
|
||||||
|
|
||||||
|
def update_variants(self):
|
||||||
|
if self.has_variants:
|
||||||
|
updated = []
|
||||||
|
variants = frappe.db.get_all("Item", fields=["item_code"], filters={"variant_of": self.name })
|
||||||
|
for d in variants:
|
||||||
|
update_variant(self.item_code, d)
|
||||||
|
updated.append(d.item_code)
|
||||||
|
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}):
|
||||||
|
frappe.throw("Item has variants.")
|
||||||
|
|
||||||
def validate_end_of_life(item_code, end_of_life=None, verbose=1):
|
def validate_end_of_life(item_code, end_of_life=None, verbose=1):
|
||||||
if not end_of_life:
|
if not end_of_life:
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ frappe.ui.form.on("Manage Variants", {
|
|||||||
frappe.call({
|
frappe.call({
|
||||||
method:"frappe.client.get_list",
|
method:"frappe.client.get_list",
|
||||||
args:{
|
args:{
|
||||||
doctype:"Variant Attribute",
|
doctype:"Item Attribute Value",
|
||||||
filters: [
|
filters: [
|
||||||
["parent","=", field.doc.attribute],
|
["parent","=", field.doc.attribute],
|
||||||
["attribute_value", "like", request.term + "%"]
|
["attribute_value", "like", request.term + "%"]
|
||||||
@@ -39,6 +39,17 @@ frappe.ui.form.on("Manage Variants", {
|
|||||||
|
|
||||||
refresh: function(frm) {
|
refresh: function(frm) {
|
||||||
frm.disable_save();
|
frm.disable_save();
|
||||||
|
},
|
||||||
|
|
||||||
|
item:function(frm) {
|
||||||
|
return frappe.call({
|
||||||
|
method: "get_item_details",
|
||||||
|
doc:frm.doc,
|
||||||
|
callback: function(r) {
|
||||||
|
refresh_field('attributes');
|
||||||
|
refresh_field('variants');
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -14,7 +14,8 @@
|
|||||||
"label": "Item",
|
"label": "Item",
|
||||||
"options": "Item",
|
"options": "Item",
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
"precision": ""
|
"precision": "",
|
||||||
|
"reqd": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
@@ -74,7 +75,7 @@
|
|||||||
"is_submittable": 0,
|
"is_submittable": 0,
|
||||||
"issingle": 1,
|
"issingle": 1,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"modified": "2015-05-21 16:21:33.707125",
|
"modified": "2015-05-27 04:43:52.051367",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Stock",
|
"module": "Stock",
|
||||||
"name": "Manage Variants",
|
"name": "Manage Variants",
|
||||||
|
|||||||
@@ -7,12 +7,17 @@ import frappe
|
|||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
import copy
|
import copy
|
||||||
|
import json
|
||||||
|
|
||||||
class DuplicateAttribute(frappe.ValidationError): pass
|
class DuplicateAttribute(frappe.ValidationError): pass
|
||||||
class ItemTemplateCannotHaveStock(frappe.ValidationError): pass
|
class ItemTemplateCannotHaveStock(frappe.ValidationError): pass
|
||||||
|
|
||||||
class ManageVariants(Document):
|
class ManageVariants(Document):
|
||||||
|
|
||||||
|
def get_item_details(self):
|
||||||
|
self.get_attributes()
|
||||||
|
self.get_variants()
|
||||||
|
|
||||||
def generate_combinations(self):
|
def generate_combinations(self):
|
||||||
self.validate_attributes()
|
self.validate_attributes()
|
||||||
self.validate_template_item()
|
self.validate_template_item()
|
||||||
@@ -20,6 +25,31 @@ class ManageVariants(Document):
|
|||||||
self.validate_attribute_values()
|
self.validate_attribute_values()
|
||||||
self.validate_attributes_are_unique()
|
self.validate_attributes_are_unique()
|
||||||
self.get_variant_item_codes()
|
self.get_variant_item_codes()
|
||||||
|
|
||||||
|
def create_variants(self):
|
||||||
|
self.sync_variants()
|
||||||
|
|
||||||
|
def get_attributes(self):
|
||||||
|
attributes = {}
|
||||||
|
self.set('attributes', [])
|
||||||
|
for d in frappe.db.sql("""select attribute, attribute_value from `tabVariant Attribute` as attribute,
|
||||||
|
`tabItem` as item where attribute.parent= item.name and item.variant_of = %s""", self.item, as_dict=1):
|
||||||
|
attributes.setdefault(d.attribute, []).append(d.attribute_value)
|
||||||
|
for d in attributes:
|
||||||
|
attribute_values = set(attributes[d])
|
||||||
|
for value in attribute_values:
|
||||||
|
self.append('attributes',{"attribute": d, "attribute_value": value})
|
||||||
|
|
||||||
|
def get_variants(self):
|
||||||
|
self.set('variants', [])
|
||||||
|
variants = [d.name for d in frappe.get_all("Item",
|
||||||
|
filters={"variant_of":self.item})]
|
||||||
|
for d in variants:
|
||||||
|
variant_attributes, attributes = "", []
|
||||||
|
for attribute in frappe.db.sql("""select attribute, attribute_value from `tabVariant Attribute` where parent = %s""", d):
|
||||||
|
variant_attributes += attribute[1] + " "
|
||||||
|
attributes.append([attribute[0], attribute[1]])
|
||||||
|
self.append('variants',{"variant": d, "variant_attributes": variant_attributes, "attributes": json.dumps(attributes)})
|
||||||
|
|
||||||
def validate_attributes(self):
|
def validate_attributes(self):
|
||||||
if not self.attributes:
|
if not self.attributes:
|
||||||
@@ -61,7 +91,7 @@ class ManageVariants(Document):
|
|||||||
def get_variant_item_codes(self):
|
def get_variant_item_codes(self):
|
||||||
"""Get all possible suffixes for variants"""
|
"""Get all possible suffixes for variants"""
|
||||||
variant_dict = {}
|
variant_dict = {}
|
||||||
variant_item_codes = []
|
self.set('variants', [])
|
||||||
|
|
||||||
for d in self.attributes:
|
for d in self.attributes:
|
||||||
variant_dict.setdefault(d.attribute, []).append(d.attribute_value)
|
variant_dict.setdefault(d.attribute, []).append(d.attribute_value)
|
||||||
@@ -80,12 +110,76 @@ class ManageVariants(Document):
|
|||||||
if len(attributes) > 1:
|
if len(attributes) > 1:
|
||||||
add_attribute_suffixes(item_code + "-" + value.abbr, _my_attributes, attributes[1:])
|
add_attribute_suffixes(item_code + "-" + value.abbr, _my_attributes, attributes[1:])
|
||||||
else:
|
else:
|
||||||
variant_item_codes.append(item_code + "-" + value.abbr)
|
variant_attributes = ""
|
||||||
|
for d in _my_attributes:
|
||||||
|
variant_attributes += d[1] + " "
|
||||||
|
self.append('variants', {"variant": item_code + "-" + value.abbr,
|
||||||
|
"attributes": json.dumps(_my_attributes), "variant_attributes": variant_attributes})
|
||||||
|
|
||||||
add_attribute_suffixes(self.item, [], attributes)
|
add_attribute_suffixes(self.item, [], attributes)
|
||||||
|
|
||||||
for v in variant_item_codes:
|
def sync_variants(self):
|
||||||
self.append('variants', {"variant": v})
|
variant_item_codes = []
|
||||||
|
for v in self.variants:
|
||||||
def create_variants(self):
|
variant_item_codes.append(v.variant)
|
||||||
pass
|
|
||||||
|
existing_variants = [d.name for d in frappe.get_all("Item",
|
||||||
|
filters={"variant_of":self.item})]
|
||||||
|
|
||||||
|
inserted, updated, deleted = [], [], []
|
||||||
|
for existing_variant in existing_variants:
|
||||||
|
if existing_variant not in variant_item_codes:
|
||||||
|
frappe.delete_doc("Item", existing_variant)
|
||||||
|
deleted.append(existing_variant)
|
||||||
|
|
||||||
|
for item_code in variant_item_codes:
|
||||||
|
if item_code not in existing_variants:
|
||||||
|
make_variant(self.item, item_code, self.variants)
|
||||||
|
inserted.append(item_code)
|
||||||
|
else:
|
||||||
|
update_variant(self.item, existing_variant, self.variants)
|
||||||
|
updated.append(existing_variant)
|
||||||
|
|
||||||
|
if inserted:
|
||||||
|
frappe.msgprint(_("Item Variants {0} created").format(", ".join(inserted)))
|
||||||
|
|
||||||
|
if updated:
|
||||||
|
frappe.msgprint(_("Item Variants {0} updated").format(", ".join(updated)))
|
||||||
|
|
||||||
|
if deleted:
|
||||||
|
frappe.msgprint(_("Item Variants {0} deleted").format(", ".join(deleted)))
|
||||||
|
|
||||||
|
def make_variant(item, variant_code, variant_attribute):
|
||||||
|
variant = frappe.new_doc("Item")
|
||||||
|
variant.item_code = variant_code
|
||||||
|
template = frappe.get_doc("Item", item)
|
||||||
|
copy_attributes_to_variant(template, variant, variant_attribute, insert=True)
|
||||||
|
variant.insert()
|
||||||
|
|
||||||
|
def update_variant(item, variant_code, variant_attribute=None):
|
||||||
|
variant = frappe.get_doc("Item", variant_code)
|
||||||
|
template = frappe.get_doc("Item", item)
|
||||||
|
copy_attributes_to_variant(template, variant, variant_attribute, insert=True)
|
||||||
|
variant.save()
|
||||||
|
|
||||||
|
def copy_attributes_to_variant(template, variant, variant_attribute=None, insert=False):
|
||||||
|
from frappe.model import no_value_fields
|
||||||
|
for field in template.meta.fields:
|
||||||
|
if field.fieldtype not in no_value_fields and (insert or not field.no_copy)\
|
||||||
|
and field.fieldname not in ("item_code", "item_name"):
|
||||||
|
if variant.get(field.fieldname) != template.get(field.fieldname):
|
||||||
|
variant.set(field.fieldname, template.get(field.fieldname))
|
||||||
|
variant.item_name = template.item_name + variant.item_code[len(template.name):]
|
||||||
|
variant.variant_of = template.name
|
||||||
|
variant.has_variants = 0
|
||||||
|
variant.show_in_website = 0
|
||||||
|
if variant_attribute:
|
||||||
|
for d in variant_attribute:
|
||||||
|
if d.variant == variant.item_code:
|
||||||
|
variant.attributes= []
|
||||||
|
for a in json.loads(d.attributes):
|
||||||
|
variant.append('attributes', {"attribute": a[0], "attribute_value": a[1]})
|
||||||
|
if variant.attributes:
|
||||||
|
variant.description += "\n"
|
||||||
|
for d in variant.attributes:
|
||||||
|
variant.description += "<p>" + d.attribute + ": " + d.attribute_value + "</p>"
|
||||||
@@ -8,7 +8,7 @@ from frappe import _
|
|||||||
from frappe.utils import flt, getdate, add_days, formatdate
|
from frappe.utils import flt, getdate, add_days, formatdate
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from datetime import date
|
from datetime import date
|
||||||
from erpnext.stock.doctype.item.item import ItemTemplateCannotHaveStock
|
from erpnext.stock.doctype.manage_variants.manage_variants import ItemTemplateCannotHaveStock
|
||||||
|
|
||||||
class StockFreezeError(frappe.ValidationError): pass
|
class StockFreezeError(frappe.ValidationError): pass
|
||||||
|
|
||||||
|
|||||||
@@ -28,6 +28,30 @@
|
|||||||
"reqd": 1,
|
"reqd": 1,
|
||||||
"search_index": 0,
|
"search_index": 0,
|
||||||
"set_only_once": 0
|
"set_only_once": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "column_break_2",
|
||||||
|
"fieldtype": "Column Break",
|
||||||
|
"permlevel": 0,
|
||||||
|
"precision": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "variant_attributes",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Variant Attributes",
|
||||||
|
"permlevel": 0,
|
||||||
|
"precision": "",
|
||||||
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "attributes",
|
||||||
|
"fieldtype": "Text",
|
||||||
|
"hidden": 1,
|
||||||
|
"label": "attributes",
|
||||||
|
"permlevel": 0,
|
||||||
|
"precision": "",
|
||||||
|
"read_only": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"hide_heading": 0,
|
"hide_heading": 0,
|
||||||
@@ -38,7 +62,7 @@
|
|||||||
"is_submittable": 0,
|
"is_submittable": 0,
|
||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"modified": "2015-05-21 16:18:16.605271",
|
"modified": "2015-05-28 04:58:20.495616",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Stock",
|
"module": "Stock",
|
||||||
"name": "Variant Item",
|
"name": "Variant Item",
|
||||||
|
|||||||
Reference in New Issue
Block a user