I’m experiencing a really strange issue when trying to create multiple item variants in sequence, using a custom module for ERPNext.
The function I’m calling is create_variant
from erpnext.controllers.item_variant
. The first variant is created seamlessly, but the second one refuses to validate the attributes provided. Upon digging into this, it became clear that the second variant is being validated against the attributes of the product specified in the first variant.
Here’s the simplest code I could concoct to demonstrate the issue:
from erpnext.controllers.item_variant import create_variant
@frappe.whitelist()
def item_variant_test():
# creates two item variants in squence using create_variant from erpnext.controllers.item_variant
# create the item variant
# Brace has 3 attributes, Width - in, Height - in, Length - ft
item_variant_1_template = 'Brace'
item_variant_1_attributes = {
'Width - in': 12,
'Height - in': 12,
'Length - ft': 48
}
item_variant_1 = create_variant(item_variant_1_template, item_variant_1_attributes)
item_variant_1.insert()
# create the second item variant
# Tenon has 2 attributes, Width - in, Length - in
item_variant_2_template = 'Tenon'
item_variant_2_attributes = {
'Width - in': 12,
'Length - in': 100
}
item_variant_2 = create_variant(item_variant_2_template, item_variant_2_attributes)
item_variant_2.insert()
As you can see, there are a separate list of issues for both items. I call this on the frontend with a button, using this Javascript:
// button for the item_variant_test function
var item_variant_test_button = page.add_button('Item Variant Test', function () {
frappe.call({
method: 'cadwork_import.cadwork_import.page.bom_import.bom_import.item_variant_test',
args: {
data: bom_import_form.get_values(true)
},
callback: function (r) {
if (r.message) {
frappe.msgprint(r.message);
}
}
});
}
);
As it stands, this produces the error:
100 is not a valid Value for Attribute Length - in of Item Tenon-12-100.
This is not accurate, so I started digging to see where the error was originating and landed on the validate_item_variant_attributes
function in apps/erpnext/erpnext/controllers/item_variant.py
.
In this case, the “is not a valid Value for Attribute” error is being triggered based on the validate_item_attribute_value
function, but that shouldn’t even be running since the Attributes are all numeric and if attribute.lower() in numeric_values
should evaluate to true
. So I added frappe.msgprint(str(numeric_values))
to see what is present in that variable, as follows:
def validate_item_variant_attributes(item, args=None):
if isinstance(item, string_types):
item = frappe.get_doc("Item", item)
if not args:
args = {d.attribute.lower(): d.attribute_value for d in item.attributes}
attribute_values, numeric_values = get_attribute_values(item)
frappe.msgprint(str(numeric_values))
for attribute, value in args.items():
if not value:
continue
if attribute.lower() in numeric_values:
numeric_attribute = numeric_values[attribute.lower()]
validate_is_incremental(numeric_attribute, attribute, value, item.name)
else:
attributes_list = attribute_values.get(attribute.lower(), [])
validate_item_attribute_value(attributes_list, attribute, value, item.name, from_variant=True)
Here’s where I got the surprise. Both runs of the function are returning the same parent attributes:
What’s going on here? Is it simply a bug, or am I supposed to be “unloading” one item/doc before creating a second one?