[item variants] make variants, bom updates
This commit is contained in:
@@ -165,6 +165,7 @@ def item_query(doctype, txt, searchfield, start, page_len, filters):
|
|||||||
concat(substr(tabItem.description, 1, 40), "..."), description) as decription
|
concat(substr(tabItem.description, 1, 40), "..."), description) as decription
|
||||||
from tabItem
|
from tabItem
|
||||||
where tabItem.docstatus < 2
|
where tabItem.docstatus < 2
|
||||||
|
and ifnull(tabItem.has_variants, 0)=0
|
||||||
and (tabItem.end_of_life > %(today)s or ifnull(tabItem.end_of_life, '0000-00-00')='0000-00-00')
|
and (tabItem.end_of_life > %(today)s or ifnull(tabItem.end_of_life, '0000-00-00')='0000-00-00')
|
||||||
and (tabItem.`{key}` LIKE %(txt)s
|
and (tabItem.`{key}` LIKE %(txt)s
|
||||||
or tabItem.item_name LIKE %(txt)s
|
or tabItem.item_name LIKE %(txt)s
|
||||||
|
|||||||
@@ -182,10 +182,7 @@ erpnext.bom.calculate_total = function(doc) {
|
|||||||
|
|
||||||
cur_frm.fields_dict['item'].get_query = function(doc) {
|
cur_frm.fields_dict['item'].get_query = function(doc) {
|
||||||
return{
|
return{
|
||||||
query: "erpnext.controllers.queries.item_query",
|
query: "erpnext.controllers.queries.item_query"
|
||||||
filters:{
|
|
||||||
'is_manufactured_item': 'Yes'
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ class BOM(Document):
|
|||||||
def get_item_det(self, item_code):
|
def get_item_det(self, item_code):
|
||||||
item = frappe.db.sql("""select name, is_asset_item, is_purchase_item,
|
item = frappe.db.sql("""select name, is_asset_item, is_purchase_item,
|
||||||
docstatus, description, is_sub_contracted_item, stock_uom, default_bom,
|
docstatus, description, is_sub_contracted_item, stock_uom, default_bom,
|
||||||
last_purchase_rate, is_manufactured_item
|
last_purchase_rate
|
||||||
from `tabItem` where name=%s""", item_code, as_dict = 1)
|
from `tabItem` where name=%s""", item_code, as_dict = 1)
|
||||||
|
|
||||||
return item
|
return item
|
||||||
@@ -149,14 +149,19 @@ class BOM(Document):
|
|||||||
if self.is_default and self.is_active:
|
if self.is_default and self.is_active:
|
||||||
from frappe.model.utils import set_default
|
from frappe.model.utils import set_default
|
||||||
set_default(self, "item")
|
set_default(self, "item")
|
||||||
frappe.db.set_value("Item", self.item, "default_bom", self.name)
|
item = frappe.get_doc("Item", self.item)
|
||||||
|
if item.default_bom != self.name:
|
||||||
|
item.default_bom = self.name
|
||||||
|
item.save()
|
||||||
|
|
||||||
else:
|
else:
|
||||||
if not self.is_active:
|
if not self.is_active:
|
||||||
frappe.db.set(self, "is_default", 0)
|
frappe.db.set(self, "is_default", 0)
|
||||||
|
|
||||||
frappe.db.sql("update `tabItem` set default_bom = null where name = %s and default_bom = %s",
|
item = frappe.get_doc("Item", self.item)
|
||||||
(self.item, self.name))
|
if item.default_bom == self.name:
|
||||||
|
item.default_bom = None
|
||||||
|
item.save()
|
||||||
|
|
||||||
def clear_operations(self):
|
def clear_operations(self):
|
||||||
if not self.with_operations:
|
if not self.with_operations:
|
||||||
@@ -169,9 +174,6 @@ class BOM(Document):
|
|||||||
item = self.get_item_det(self.item)
|
item = self.get_item_det(self.item)
|
||||||
if not item:
|
if not item:
|
||||||
frappe.throw(_("Item {0} does not exist in the system or has expired").format(self.item))
|
frappe.throw(_("Item {0} does not exist in the system or has expired").format(self.item))
|
||||||
elif item[0]['is_manufactured_item'] != 'Yes' \
|
|
||||||
and item[0]['is_sub_contracted_item'] != 'Yes':
|
|
||||||
frappe.throw(_("Item {0} must be manufactured or sub-contracted").format(self.item))
|
|
||||||
else:
|
else:
|
||||||
ret = frappe.db.get_value("Item", self.item, ["description", "stock_uom"])
|
ret = frappe.db.get_value("Item", self.item, ["description", "stock_uom"])
|
||||||
self.description = ret[0]
|
self.description = ret[0]
|
||||||
@@ -195,16 +197,9 @@ class BOM(Document):
|
|||||||
if self.with_operations and cstr(m.operation_no) not in self.op:
|
if self.with_operations and cstr(m.operation_no) not in self.op:
|
||||||
frappe.throw(_("Operation {0} not present in Operations Table").format(m.operation_no))
|
frappe.throw(_("Operation {0} not present in Operations Table").format(m.operation_no))
|
||||||
|
|
||||||
item = self.get_item_det(m.item_code)
|
if m.bom:
|
||||||
if item[0]['is_manufactured_item'] == 'Yes':
|
|
||||||
if not m.bom_no:
|
|
||||||
frappe.throw(_("BOM number is required for manufactured Item {0} in row {1}").format(m.item_code, m.idx))
|
|
||||||
else:
|
|
||||||
self.validate_bom_no(m.item_code, m.bom_no, m.idx)
|
self.validate_bom_no(m.item_code, m.bom_no, m.idx)
|
||||||
|
|
||||||
elif m.bom_no:
|
|
||||||
frappe.throw(_("BOM number not allowed for non-manufactured Item {0} in row {1}").format(m.item_code, m.idx))
|
|
||||||
|
|
||||||
if flt(m.qty) <= 0:
|
if flt(m.qty) <= 0:
|
||||||
frappe.throw(_("Quantity required for Item {0} in row {1}").format(m.item_code, m.idx))
|
frappe.throw(_("Quantity required for Item {0} in row {1}").format(m.item_code, m.idx))
|
||||||
|
|
||||||
|
|||||||
@@ -28,3 +28,15 @@ class TestBOM(unittest.TestCase):
|
|||||||
def test_get_items_list(self):
|
def test_get_items_list(self):
|
||||||
from erpnext.manufacturing.doctype.bom.bom import get_bom_items
|
from erpnext.manufacturing.doctype.bom.bom import get_bom_items
|
||||||
self.assertEquals(len(get_bom_items(bom="BOM/_Test FG Item 2/001", qty=1, fetch_exploded=1)), 3)
|
self.assertEquals(len(get_bom_items(bom="BOM/_Test FG Item 2/001", qty=1, fetch_exploded=1)), 3)
|
||||||
|
|
||||||
|
def test_default_bom(self):
|
||||||
|
bom = frappe.get_doc("BOM", "BOM/_Test FG Item 2/001")
|
||||||
|
bom.is_active = 0
|
||||||
|
bom.save()
|
||||||
|
|
||||||
|
self.assertEqual(frappe.db.get_value("Item", "_Test FG Item 2", "default_bom"), "")
|
||||||
|
|
||||||
|
bom.is_active = 1
|
||||||
|
bom.save()
|
||||||
|
|
||||||
|
self.assertTrue(frappe.db.get_value("Item", "_Test FG Item 2", "default_bom"), "BOM/_Test FG Item 2/001")
|
||||||
|
|||||||
@@ -80,16 +80,6 @@ cur_frm.cscript.item_code = function(doc) {
|
|||||||
cur_frm.set_value("description", doc.item_code);
|
cur_frm.set_value("description", doc.item_code);
|
||||||
}
|
}
|
||||||
|
|
||||||
cur_frm.fields_dict['default_bom'].get_query = function(doc) {
|
|
||||||
return {
|
|
||||||
filters: {
|
|
||||||
'item': doc.item_code,
|
|
||||||
'is_active': 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Expense Account
|
// Expense Account
|
||||||
// ---------------------------------
|
// ---------------------------------
|
||||||
cur_frm.fields_dict['expense_account'].get_query = function(doc) {
|
cur_frm.fields_dict['expense_account'].get_query = function(doc) {
|
||||||
|
|||||||
@@ -312,7 +312,7 @@
|
|||||||
"fieldname": "serial_no_series",
|
"fieldname": "serial_no_series",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"label": "Serial Number Series",
|
"label": "Serial Number Series",
|
||||||
"no_copy": 1,
|
"no_copy": 0,
|
||||||
"permlevel": 0
|
"permlevel": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -431,7 +431,7 @@
|
|||||||
"fieldname": "lead_time_days",
|
"fieldname": "lead_time_days",
|
||||||
"fieldtype": "Int",
|
"fieldtype": "Int",
|
||||||
"label": "Lead Time Days",
|
"label": "Lead Time Days",
|
||||||
"no_copy": 1,
|
"no_copy": 0,
|
||||||
"oldfieldname": "lead_time_days",
|
"oldfieldname": "lead_time_days",
|
||||||
"oldfieldtype": "Int",
|
"oldfieldtype": "Int",
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
@@ -860,7 +860,7 @@
|
|||||||
"icon": "icon-tag",
|
"icon": "icon-tag",
|
||||||
"idx": 1,
|
"idx": 1,
|
||||||
"max_attachments": 1,
|
"max_attachments": 1,
|
||||||
"modified": "2014-09-26 06:04:48.683214",
|
"modified": "2014-09-30 14:34:50.101879",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Stock",
|
"module": "Stock",
|
||||||
"name": "Item",
|
"name": "Item",
|
||||||
|
|||||||
@@ -63,7 +63,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.make_variants()
|
self.sync_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) + \
|
||||||
@@ -118,6 +118,12 @@ class Item(WebsiteGenerator):
|
|||||||
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 validate_variants_are_unique(self):
|
def validate_variants_are_unique(self):
|
||||||
|
if not self.has_variants:
|
||||||
|
self.item_variants = []
|
||||||
|
|
||||||
|
if self.item_variants and self.variant_of:
|
||||||
|
frappe.throw(_("Item cannot be a variant of a variant"))
|
||||||
|
|
||||||
variants = []
|
variants = []
|
||||||
for d in self.item_variants:
|
for d in self.item_variants:
|
||||||
key = (d.item_attribute, d.item_attribute_value)
|
key = (d.item_attribute, d.item_attribute_value)
|
||||||
@@ -126,35 +132,87 @@ class Item(WebsiteGenerator):
|
|||||||
d.item_attribute_value), DuplicateVariant)
|
d.item_attribute_value), DuplicateVariant)
|
||||||
variants.append(key)
|
variants.append(key)
|
||||||
|
|
||||||
def make_variants(self):
|
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",
|
||||||
|
{"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):
|
||||||
|
if not self.item_variants:
|
||||||
|
return []
|
||||||
|
|
||||||
variant_dict = {}
|
variant_dict = {}
|
||||||
variant_item_codes = []
|
variant_item_codes = []
|
||||||
|
|
||||||
for d in self.item_variants:
|
for d in self.item_variants:
|
||||||
variant_dict.setdefault(d.item_attribute, []).append(d.item_attribute_value)
|
variant_dict.setdefault(d.item_attribute, []).append(d.item_attribute_value)
|
||||||
|
|
||||||
attributes = variant_dict.keys()
|
all_attributes = [d.name for d in frappe.get_all("Item Attribute", order_by = "priority asc")]
|
||||||
for d in frappe.get_list("Item Attribute", order_by = "priority asc", ignore_permissions=True):
|
|
||||||
if d.name in attributes:
|
|
||||||
attr = frappe.get_doc("Item Attribute", d.name)
|
|
||||||
abbr = dict((d.attribute_value, d.abbr) for d in attr.item_attribute_values)
|
|
||||||
for value in variant_dict[d.name]:
|
|
||||||
variant_item_codes.append(self.name + "-" + abbr[value])
|
|
||||||
|
|
||||||
# delete missing variants
|
# sort attributes by their priority
|
||||||
existing_variants = [d.name for d in frappe.get_list("Item",
|
attributes = filter(None, map(lambda d: d if d in variant_dict else None, all_attributes))
|
||||||
filters={"variant_of":self.name}, ignore_permissions=True)]
|
|
||||||
|
|
||||||
for existing_variant in existing_variants:
|
def add_attribute_suffixes(item_code, attributes):
|
||||||
if existing_variant.name not in variant_item_codes:
|
attr = frappe.get_doc("Item Attribute", attributes[0])
|
||||||
frappe.delete_doc("Item", existing_variant.name)
|
for value in attr.item_attribute_values:
|
||||||
|
if value.attribute_value in variant_dict[attr.name]:
|
||||||
|
if len(attributes) > 1:
|
||||||
|
add_attribute_suffixes(item_code + "-" + value.abbr, attributes[1:])
|
||||||
else:
|
else:
|
||||||
# update mandatory fields
|
variant_item_codes.append(item_code + "-" + value.abbr)
|
||||||
pass
|
|
||||||
|
|
||||||
# for item_code in variant_item_codes:
|
add_attribute_suffixes(self.name, attributes)
|
||||||
# for
|
|
||||||
|
|
||||||
|
return variant_item_codes
|
||||||
|
|
||||||
|
def make_variant(self, item_code):
|
||||||
|
item = frappe.new_doc("Item")
|
||||||
|
self.copy_attributes_to_variant(item, insert=True)
|
||||||
|
item.item_code = item_code
|
||||||
|
item.insert()
|
||||||
|
|
||||||
|
def update_variant(self, item_code):
|
||||||
|
item = frappe.get_doc("Item", item_code)
|
||||||
|
self.copy_attributes_to_variant(item)
|
||||||
|
item.save()
|
||||||
|
|
||||||
|
def copy_attributes_to_variant(self, 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):
|
||||||
|
if variant.get(field.fieldname) != self.get(field.fieldname):
|
||||||
|
variant.set(field.fieldname, self.get(field.fieldname))
|
||||||
|
variant.__dirty = True
|
||||||
|
|
||||||
|
variant.variant_of = self.name
|
||||||
|
variant.has_variants = 0
|
||||||
|
variant.show_in_website = 0
|
||||||
|
|
||||||
def validate_conversion_factor(self):
|
def validate_conversion_factor(self):
|
||||||
check_list = []
|
check_list = []
|
||||||
@@ -168,9 +226,6 @@ class Item(WebsiteGenerator):
|
|||||||
frappe.throw(_("Conversion factor for default Unit of Measure must be 1 in row {0}").format(d.idx))
|
frappe.throw(_("Conversion factor for default Unit of Measure must be 1 in row {0}").format(d.idx))
|
||||||
|
|
||||||
def validate_item_type(self):
|
def validate_item_type(self):
|
||||||
if cstr(self.is_manufactured_item) == "No":
|
|
||||||
self.is_pro_applicable = "No"
|
|
||||||
|
|
||||||
if self.is_pro_applicable == 'Yes' and self.is_stock_item == 'No':
|
if self.is_pro_applicable == 'Yes' and self.is_stock_item == 'No':
|
||||||
frappe.throw(_("As Production Order can be made for this item, it must be a stock item."))
|
frappe.throw(_("As Production Order can be made for this item, it must be a stock item."))
|
||||||
|
|
||||||
@@ -182,6 +237,11 @@ class Item(WebsiteGenerator):
|
|||||||
|
|
||||||
|
|
||||||
def check_for_active_boms(self):
|
def check_for_active_boms(self):
|
||||||
|
if self.default_bom:
|
||||||
|
bom_item = frappe.db.get_value("BOM", self.default_bom, "item")
|
||||||
|
if bom_item not in (self.name, self.variant_of):
|
||||||
|
frappe.throw(_("Default BOM must be for this item or its template"))
|
||||||
|
|
||||||
if self.is_purchase_item != "Yes":
|
if self.is_purchase_item != "Yes":
|
||||||
bom_mat = frappe.db.sql("""select distinct t1.parent
|
bom_mat = frappe.db.sql("""select distinct t1.parent
|
||||||
from `tabBOM Item` t1, `tabBOM` t2 where t2.name = t1.parent
|
from `tabBOM Item` t1, `tabBOM` t2 where t2.name = t1.parent
|
||||||
@@ -191,12 +251,6 @@ class Item(WebsiteGenerator):
|
|||||||
if bom_mat and bom_mat[0][0]:
|
if bom_mat and bom_mat[0][0]:
|
||||||
frappe.throw(_("Item must be a purchase item, as it is present in one or many Active BOMs"))
|
frappe.throw(_("Item must be a purchase item, as it is present in one or many Active BOMs"))
|
||||||
|
|
||||||
if self.is_manufactured_item != "Yes":
|
|
||||||
bom = frappe.db.sql("""select name from `tabBOM` where item = %s
|
|
||||||
and is_active = 1""", (self.name,))
|
|
||||||
if bom and bom[0][0]:
|
|
||||||
frappe.throw(_("""Allow Bill of Materials should be 'Yes'. Because one or many active BOMs present for this item"""))
|
|
||||||
|
|
||||||
def fill_customer_code(self):
|
def fill_customer_code(self):
|
||||||
""" Append all the customer codes and insert into "customer_code" field of item table """
|
""" Append all the customer codes and insert into "customer_code" field of item table """
|
||||||
cust_code=[]
|
cust_code=[]
|
||||||
@@ -264,6 +318,8 @@ class Item(WebsiteGenerator):
|
|||||||
def on_trash(self):
|
def on_trash(self):
|
||||||
super(Item, self).on_trash()
|
super(Item, self).on_trash()
|
||||||
frappe.db.sql("""delete from tabBin where item_code=%s""", self.item_code)
|
frappe.db.sql("""delete from tabBin where item_code=%s""", self.item_code)
|
||||||
|
for variant_of in frappe.get_all("Item", {"variant_of": self.name}):
|
||||||
|
frappe.delete_doc("Item", variant_of.name)
|
||||||
|
|
||||||
def before_rename(self, olddn, newdn, merge=False):
|
def before_rename(self, olddn, newdn, merge=False):
|
||||||
if merge:
|
if merge:
|
||||||
|
|||||||
@@ -26,11 +26,11 @@
|
|||||||
<i class="icon-shopping-cart text-muted"></i>
|
<i class="icon-shopping-cart text-muted"></i>
|
||||||
</span>
|
</span>
|
||||||
{% } %}
|
{% } %}
|
||||||
{% if(doc.is_manufactured_item==="Yes") { %}
|
{% if(doc.default_bom==="Yes") { %}
|
||||||
<span style="margin-right: 8px;"
|
<span style="margin-right: 8px;"
|
||||||
title="{%= __("Manufactured Item") %}" class="filterable"
|
title="{%= __("Manufactured Item") %}" class="filterable"
|
||||||
data-filter="is_manufactured_item,=,Yes">
|
data-filter="default_bom,=,{%= doc.default_bom %}">
|
||||||
<i class="icon-wrench text-muted"></i>
|
<i class="icon-site-map text-muted"></i>
|
||||||
</span>
|
</span>
|
||||||
{% } %}
|
{% } %}
|
||||||
{% if(doc.show_in_website) { %}
|
{% if(doc.show_in_website) { %}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
frappe.listview_settings['Item'] = {
|
frappe.listview_settings['Item'] = {
|
||||||
add_fields: ["`tabItem`.`item_name`", "`tabItem`.`stock_uom`", "`tabItem`.`item_group`", "`tabItem`.`image`",
|
add_fields: ["item_name", "stock_uom", "item_group", "image",
|
||||||
"`tabItem`.`is_stock_item`", "`tabItem`.`is_sales_item`", "`tabItem`.`is_purchase_item`",
|
"is_stock_item", "is_sales_item", "is_purchase_item", "show_in_website",
|
||||||
"`tabItem`.`is_manufactured_item`", "`tabItem`.`show_in_website`"]
|
"default_bom"]
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -17,6 +17,25 @@ class TestItem(unittest.TestCase):
|
|||||||
item.append("item_variants", {"item_attribute": "Test Size", "item_attribute_value": "Small"})
|
item.append("item_variants", {"item_attribute": "Test Size", "item_attribute_value": "Small"})
|
||||||
self.assertRaises(DuplicateVariant, item.insert)
|
self.assertRaises(DuplicateVariant, item.insert)
|
||||||
|
|
||||||
|
def test_variant_item_codes(self):
|
||||||
|
frappe.delete_doc("Item", test_records[11].get("item_code"))
|
||||||
|
item = frappe.copy_doc(test_records[11])
|
||||||
|
item.insert()
|
||||||
|
variants = ['_Test Variant Item-S', '_Test Variant Item-M', '_Test Variant Item-L']
|
||||||
|
self.assertEqual(item.get_variant_item_codes(), variants)
|
||||||
|
for v in variants:
|
||||||
|
self.assertTrue(frappe.db.get_value("Item", {"variant_of": item.name, "name": v}))
|
||||||
|
|
||||||
|
item.append("item_variants", {"item_attribute": "Test Colour", "item_attribute_value": "Red"})
|
||||||
|
item.append("item_variants", {"item_attribute": "Test Colour", "item_attribute_value": "Blue"})
|
||||||
|
item.append("item_variants", {"item_attribute": "Test Colour", "item_attribute_value": "Green"})
|
||||||
|
|
||||||
|
self.assertEqual(item.get_variant_item_codes(), ['_Test Variant Item-S-R',
|
||||||
|
'_Test Variant Item-S-G', '_Test Variant Item-S-B',
|
||||||
|
'_Test Variant Item-M-R', '_Test Variant Item-M-G',
|
||||||
|
'_Test Variant Item-M-B', '_Test Variant Item-L-R',
|
||||||
|
'_Test Variant Item-L-G', '_Test Variant Item-L-B'])
|
||||||
|
|
||||||
def test_item_creation(self):
|
def test_item_creation(self):
|
||||||
frappe.delete_doc("Item", test_records[11].get("item_code"))
|
frappe.delete_doc("Item", test_records[11].get("item_code"))
|
||||||
item = frappe.copy_doc(test_records[11])
|
item = frappe.copy_doc(test_records[11])
|
||||||
@@ -33,7 +52,7 @@ class TestItem(unittest.TestCase):
|
|||||||
to_check = {
|
to_check = {
|
||||||
"item_code": "_Test Item",
|
"item_code": "_Test Item",
|
||||||
"item_name": "_Test Item",
|
"item_name": "_Test Item",
|
||||||
"description": "_Test Item",
|
"description": "_Test Item 1",
|
||||||
"warehouse": "_Test Warehouse - _TC",
|
"warehouse": "_Test Warehouse - _TC",
|
||||||
"income_account": "Sales - _TC",
|
"income_account": "Sales - _TC",
|
||||||
"expense_account": "_Test Account Cost for Goods Sold - _TC",
|
"expense_account": "_Test Account Cost for Goods Sold - _TC",
|
||||||
|
|||||||
@@ -243,6 +243,7 @@
|
|||||||
"is_service_item": "No",
|
"is_service_item": "No",
|
||||||
"is_stock_item": "Yes",
|
"is_stock_item": "Yes",
|
||||||
"is_sub_contracted_item": "Yes",
|
"is_sub_contracted_item": "Yes",
|
||||||
|
"is_manufactured_item": "Yes",
|
||||||
"item_code": "_Test FG Item 2",
|
"item_code": "_Test FG Item 2",
|
||||||
"item_group": "_Test Item Group Desktops",
|
"item_group": "_Test Item Group Desktops",
|
||||||
"item_name": "_Test FG Item 2",
|
"item_name": "_Test FG Item 2",
|
||||||
@@ -268,6 +269,7 @@
|
|||||||
"item_group": "_Test Item Group Desktops",
|
"item_group": "_Test Item Group Desktops",
|
||||||
"item_name": "_Test Variant Item",
|
"item_name": "_Test Variant Item",
|
||||||
"stock_uom": "_Test UOM",
|
"stock_uom": "_Test UOM",
|
||||||
|
"has_variants": 1,
|
||||||
"item_variants": [
|
"item_variants": [
|
||||||
{"item_attribute": "Test Size", "item_attribute_value": "Small"},
|
{"item_attribute": "Test Size", "item_attribute_value": "Small"},
|
||||||
{"item_attribute": "Test Size", "item_attribute_value": "Medium"},
|
{"item_attribute": "Test Size", "item_attribute_value": "Medium"},
|
||||||
|
|||||||
@@ -4,9 +4,9 @@
|
|||||||
"attribute_name": "Test Size",
|
"attribute_name": "Test Size",
|
||||||
"priority": 1,
|
"priority": 1,
|
||||||
"item_attribute_values": [
|
"item_attribute_values": [
|
||||||
{"attribute_value": "Small", "abbr": "SM"},
|
{"attribute_value": "Small", "abbr": "S"},
|
||||||
{"attribute_value": "Medium", "abbr": "MD"},
|
{"attribute_value": "Medium", "abbr": "M"},
|
||||||
{"attribute_value": "Large", "abbr": "LG"}
|
{"attribute_value": "Large", "abbr": "L"}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user