manage variants new doctype created

This commit is contained in:
Neil Trini Lasrado 2015-05-20 15:49:55 +05:30
parent ec44fa95ce
commit c8cc8b7115
13 changed files with 422 additions and 89 deletions

View File

@ -5,40 +5,6 @@ frappe.provide("erpnext.item");
frappe.ui.form.on("Item", {
onload: function(frm) {
var df = frappe.meta.get_docfield("Item Variant", "item_attribute_value");
df.on_make = function(field) {
$(field.input_area).addClass("ui-front");
field.$input.autocomplete({
minLength: 0,
minChars: 0,
source: function(request, response) {
frappe.call({
method:"frappe.client.get_list",
args:{
doctype:"Item Attribute Value",
filters: [
["parent","=", field.doc.item_attribute],
["attribute_value", "like", request.term + "%"]
],
fields: ["attribute_value"]
},
callback: function(r) {
response($.map(r.message, function(d) { return d.attribute_value; }));
}
});
},
select: function(event, ui) {
field.$input.val(ui.item.value);
field.$input.trigger("change");
},
focus: function( event, ui ) {
if(ui.item.action) {
return false;
}
},
});
}
erpnext.item.setup_queries(frm);
},
@ -64,6 +30,10 @@ frappe.ui.form.on("Item", {
frm.add_custom_button(__("Show Variants"), function() {
frappe.set_route("List", "Item", {"variant_of": frm.doc.name});
}, "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) {
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);
@ -114,6 +84,7 @@ frappe.ui.form.on("Item", {
method: "copy_specification_from_item_group"
});
},
is_stock_item: function(frm) {
erpnext.item.toggle_reqd(frm);
}

View File

@ -185,16 +185,6 @@
"precision": "",
"read_only": 0
},
{
"depends_on": "has_variants",
"description": "A new variant (Item) will be created for each attribute value combination",
"fieldname": "variants",
"fieldtype": "Table",
"label": "Variants",
"options": "Item Variant",
"permlevel": 0,
"precision": ""
},
{
"fieldname": "inventory",
"fieldtype": "Section Break",
@ -877,7 +867,7 @@
}
],
"icon": "icon-tag",
"idx": 1,
"idx": 1,
"max_attachments": 1,
"modified": "2015-06-26 17:20:18.204558",
"modified_by": "Administrator",

View File

@ -12,8 +12,6 @@ from frappe.website.doctype.website_slideshow.website_slideshow import get_slide
import copy
class WarehouseNotSet(frappe.ValidationError): pass
class DuplicateVariant(frappe.ValidationError): pass
class ItemTemplateCannotHaveStock(frappe.ValidationError): pass
class Item(WebsiteGenerator):
website = frappe._dict(
@ -63,7 +61,6 @@ class Item(WebsiteGenerator):
self.cant_change()
self.validate_reorder_level()
self.validate_warehouse_for_reorder()
self.validate_variants()
self.update_item_desc()
self.synced_with_hub = 0
@ -77,7 +74,6 @@ class Item(WebsiteGenerator):
invalidate_cache_for_item(self)
self.validate_name_with_item_group()
self.update_item_price()
self.sync_variants()
def get_context(self, context):
context["parent_groups"] = get_parent_item_groups(self.item_group) + \
@ -133,43 +129,6 @@ class Item(WebsiteGenerator):
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."))
def validate_variants(self):
self.validate_variants_are_unique()
self.validate_stock_for_template_must_be_zero()
def validate_stock_for_template_must_be_zero(self):
if self.has_variants:
stock_in = frappe.db.sql_list("""select warehouse from tabBin
where item_code=%s and ifnull(actual_qty, 0) > 0""", self.name)
if stock_in:
frappe.throw(_("Item Template cannot have stock and varaiants. Please remove stock from warehouses {0}").format(", ".join(stock_in)),
ItemTemplateCannotHaveStock)
def validate_variants_are_unique(self):
if not self.has_variants:
self.variants = []
return
if self.variants:
if self.variant_of:
frappe.throw(_("Item cannot be a variant of a variant"))
variants, attributes = [], {}
for d in self.variants:
key = (d.item_attribute, d.item_attribute_value)
if key in variants:
frappe.throw(_("{0} {1} is entered more than once in Item Variants table")
.format(d.item_attribute, d.item_attribute_value), DuplicateVariant)
variants.append(key)
attributes.setdefault(d.item_attribute, [t.attribute_value for t in frappe.db.get_all("Item Attribute Value",
fields=["attribute_value"], filters={"parent": d.item_attribute })])
if d.item_attribute_value not in attributes.get(d.item_attribute):
frappe.throw(_("Attribute value {0} does not exist in Item Attribute Master.").format(d.item_attribute_value))
else:
frappe.throw(_("Please enter atleast one attribute row in Item Variants table"))
def sync_variants(self):
variant_item_codes = self.get_variant_item_codes()
@ -460,9 +419,11 @@ class Item(WebsiteGenerator):
def update_item_desc(self):
if frappe.db.get_value('BOM',self.name, 'description') != self.description:
frappe.db.sql("""update `tabBOM` set description = %s where item = %s and docstatus < 2""",(self.description, self.name))
frappe.db.sql("""update `tabBOM Item` set description = %s where item_code = %s and docstatus < 2""",(self.description, self.name))
frappe.db.sql("""update `tabBOM Explosion Item` set description = %s where item_code = %s and docstatus < 2""",(self.description, self.name))
frappe.db.sql("""update `tabBOM Item` set description = %s where
item_code = %s and docstatus < 2""",(self.description, self.name))
frappe.db.sql("""update `tabBOM Explosion Item` set description = %s where
item_code = %s and docstatus < 2""",(self.description, self.name))
def validate_end_of_life(item_code, end_of_life=None, verbose=1):
if not end_of_life:
end_of_life = frappe.db.get_value("Item", item_code, "end_of_life")
@ -567,3 +528,4 @@ def invalidate_cache_for_item(doc):
if doc.get("old_item_group") and doc.get("old_item_group") != doc.item_group:
invalidate_cache_for(doc, doc.old_item_group)

View File

@ -0,0 +1,44 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
frappe.ui.form.on("Manage Variants", {
onload: function(frm) {
var df = frappe.meta.get_docfield("Variant Attribute", "attribute_value");
df.on_make = function(field) {
field.$input.autocomplete({
minLength: 0,
minChars: 0,
source: function(request, response) {
frappe.call({
method:"frappe.client.get_list",
args:{
doctype:"Variant Attribute",
filters: [
["parent","=", field.doc.attribute],
["attribute_value", "like", request.term + "%"]
],
fields: ["attribute_value"]
},
callback: function(r) {
response($.map(r.message, function(d) { return d.attribute_value; }));
}
});
},
select: function(event, ui) {
field.$input.val(ui.item.value);
field.$input.trigger("change");
},
focus: function( event, ui ) {
if(ui.manage_variants.action) {
return false;
}
},
});
}
},
refresh: function(frm) {
frm.disable_save();
}
});

View File

@ -0,0 +1,101 @@
{
"allow_copy": 0,
"allow_import": 0,
"allow_rename": 0,
"creation": "2015-05-19 05:39:59.345901",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "",
"fields": [
{
"fieldname": "item",
"fieldtype": "Link",
"label": "Item",
"options": "Item",
"permlevel": 0,
"precision": ""
},
{
"allow_on_submit": 0,
"fieldname": "attributes",
"fieldtype": "Table",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Attributes",
"no_copy": 0,
"options": "Variant Attribute",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0
},
{
"fieldname": "generate_combinations",
"fieldtype": "Button",
"label": "Generate Combinations",
"options": "generate_combinations",
"permlevel": 0,
"precision": ""
},
{
"fieldname": "section_break_4",
"fieldtype": "Section Break",
"permlevel": 0,
"precision": ""
},
{
"fieldname": "variants",
"fieldtype": "Table",
"label": "Variants",
"options": "Variant Item",
"permlevel": 0,
"precision": ""
},
{
"fieldname": "create_variants",
"fieldtype": "Button",
"label": "Create Variants",
"permlevel": 0,
"precision": ""
}
],
"hide_heading": 0,
"hide_toolbar": 0,
"in_create": 1,
"in_dialog": 0,
"is_submittable": 0,
"issingle": 1,
"istable": 0,
"modified": "2015-05-20 18:00:48.331950",
"modified_by": "Administrator",
"module": "Stock",
"name": "Manage Variants",
"name_case": "",
"owner": "Administrator",
"permissions": [
{
"create": 1,
"delete": 1,
"email": 1,
"export": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 0,
"role": "Material Master Manager",
"share": 1,
"write": 1
}
],
"read_only": 1,
"read_only_onload": 0,
"sort_field": "modified",
"sort_order": "DESC"
}

View File

@ -0,0 +1,77 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.model.document import Document
import copy
class DuplicateAttribute(frappe.ValidationError): pass
class ItemTemplateCannotHaveStock(frappe.ValidationError): pass
class ManageVariants(Document):
def generate_combinations(self):
self.validate_attributes()
self.validate_template_item()
self.validate_stock_for_template_must_be_zero()
self.validate_attributes_are_unique()
self.get_variant_item_codes()
def validate_attributes(self):
if not self.attributes:
frappe.throw("Enter atleast one Attribute & its Value in Attribute table.")
def validate_template_item(self):
template_item = frappe.get_doc("Item", self.item)
if not template_item.has_variants:
frappe.throw(_("Selected Item cannot have Variants."))
if template_item.variant_of:
frappe.throw(_("Item cannot be a variant of a variant"))
def validate_stock_for_template_must_be_zero(self):
stock_in = frappe.db.sql_list("""select warehouse from tabBin
where item_code=%s and ifnull(actual_qty, 0) > 0""", self.item)
if stock_in:
frappe.throw(_("Item Template cannot have stock and varaiants. Please remove \
stock from warehouses {0}").format(", ".join(stock_in)), ItemTemplateCannotHaveStock)
def validate_attributes_are_unique(self):
attributes = []
for d in self.attributes:
key = (d.attribute, d.attribute_value)
if key in attributes:
frappe.throw(_("{0} {1} is entered more than once in Attributes table")
.format(d.attribute, d.attribute_value), DuplicateAttribute)
attributes.append(key)
def get_variant_item_codes(self):
"""Get all possible suffixes for variants"""
variant_dict = {}
variant_item_codes = []
for d in self.attributes:
variant_dict.setdefault(d.attribute, []).append(d.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)
add_attribute_suffixes(self.item, [], attributes)
print variant_item_codes

View File

@ -0,0 +1,78 @@
{
"allow_copy": 0,
"allow_import": 1,
"allow_rename": 0,
"autoname": "",
"creation": "2015-05-19 05:12:30.344797",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "Other",
"fields": [
{
"allow_on_submit": 0,
"fieldname": "attribute",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Attribute",
"no_copy": 0,
"options": "Item Attribute",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0
},
{
"fieldname": "column_break_2",
"fieldtype": "Column Break",
"permlevel": 0,
"precision": ""
},
{
"allow_on_submit": 0,
"fieldname": "attribute_value",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Attribute Value",
"no_copy": 0,
"options": "",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0
}
],
"hide_heading": 0,
"hide_toolbar": 0,
"icon": "",
"in_create": 0,
"in_dialog": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 1,
"modified": "2015-05-20 06:16:16.803578",
"modified_by": "Administrator",
"module": "Stock",
"name": "Variant Attribute",
"name_case": "",
"owner": "Administrator",
"permissions": [],
"read_only": 0,
"read_only_onload": 0,
"sort_field": "modified",
"sort_order": "DESC"
}

View File

@ -0,0 +1,10 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
from frappe.model.document import Document
class VariantAttribute(Document):
pass

View File

@ -0,0 +1,90 @@
{
"allow_copy": 0,
"allow_import": 1,
"allow_rename": 0,
"autoname": "",
"creation": "2015-05-19 05:55:31.155672",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "Other",
"fields": [
{
"allow_on_submit": 0,
"fieldname": "varient",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Variant",
"no_copy": 0,
"options": "",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"read_only": 1,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0
},
{
"allow_on_submit": 0,
"fieldname": "column_break_2",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0
},
{
"allow_on_submit": 0,
"fieldname": "item_code",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Item Code",
"no_copy": 0,
"options": "",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0
}
],
"hide_heading": 0,
"hide_toolbar": 0,
"icon": "",
"in_create": 0,
"in_dialog": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 1,
"modified": "2015-05-20 18:20:10.555404",
"modified_by": "Administrator",
"module": "Stock",
"name": "Variant Item",
"name_case": "",
"owner": "Administrator",
"permissions": [],
"read_only": 0,
"read_only_onload": 0,
"sort_field": "modified",
"sort_order": "DESC"
}

View File

@ -0,0 +1,10 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
from frappe.model.document import Document
class VariantItem(Document):
pass