Multiple variant creation dialog (#11608)

* Multiple variant creation dialog

* variant dialog codacy fixes

* [multiple variants] show_alert, and other minors
This commit is contained in:
Prateeksha Singh 2017-11-16 18:06:26 +05:30 committed by Nabin Hait
parent 1749b7c16b
commit 8f43d2514c
2 changed files with 222 additions and 13 deletions

View File

@ -169,6 +169,74 @@ def create_variant(item, args):
return variant
@frappe.whitelist()
def enqueue_multiple_variant_creation(item, args):
# There can be innumerable attribute combinations, enqueue
frappe.enqueue("erpnext.controllers.item_variant.create_multiple_variants",
item=item, args=args, now=frappe.flags.in_test);
def create_multiple_variants(item, args):
if isinstance(args, basestring):
args = json.loads(args)
args_set = generate_keyed_value_combinations(args)
for attribute_values in args_set:
if not get_variant(item, args=attribute_values):
variant = create_variant(item, attribute_values)
variant.save()
def generate_keyed_value_combinations(args):
"""
From this:
args = {"attr1": ["a", "b", "c"], "attr2": ["1", "2"], "attr3": ["A"]}
To this:
[
{u'attr1': u'a', u'attr2': u'1', u'attr3': u'A'},
{u'attr1': u'b', u'attr2': u'1', u'attr3': u'A'},
{u'attr1': u'c', u'attr2': u'1', u'attr3': u'A'},
{u'attr1': u'a', u'attr2': u'2', u'attr3': u'A'},
{u'attr1': u'b', u'attr2': u'2', u'attr3': u'A'},
{u'attr1': u'c', u'attr2': u'2', u'attr3': u'A'}
]
"""
# Return empty list if empty
if not args:
return []
# Turn `args` into a list of lists of key-value tuples:
# [
# [(u'attr2', u'1'), (u'attr2', u'2')],
# [(u'attr3', u'A')],
# [(u'attr1', u'a'), (u'attr1', u'b'), (u'attr1', u'c')]
# ]
key_value_lists = [[(key, val) for val in args[key]] for key in args.keys()]
# Store the first, but as objects
# [{u'attr2': u'1'}, {u'attr2': u'2'}]
results = key_value_lists.pop(0)
results = [{d[0]: d[1]} for d in results]
# Iterate the remaining
# Take the next list to fuse with existing results
for l in key_value_lists:
new_results = []
for res in results:
for key_val in l:
# create a new clone of object in result
obj = copy.deepcopy(res)
# to be used with every incoming new value
obj[key_val[0]] = key_val[1]
# and pushed into new_results
new_results.append(obj)
results = new_results
return results
def copy_attributes_to_variant(item, variant):
from frappe.model import no_value_fields
@ -208,7 +276,7 @@ def copy_attributes_to_variant(item, variant):
attributes_description = ""
for d in variant.attributes:
attributes_description += "<div>" + d.attribute + ": " + cstr(d.attribute_value) + "</div>"
if attributes_description not in variant.description:
variant.description += attributes_description

View File

@ -57,9 +57,19 @@ frappe.ui.form.on("Item", {
frappe.set_route("List", "Item", {"variant_of": frm.doc.name});
}, __("View"));
frm.add_custom_button(__("Variant"), function() {
erpnext.item.make_variant(frm);
}, __("Make"));
if(frm.doc.variant_based_on==="Item Attribute") {
frm.add_custom_button(__("Single Variant"), function() {
erpnext.item.show_single_variant_dialog(frm);
}, __("Make"));
frm.add_custom_button(__("Multiple Variants"), function() {
erpnext.item.show_multiple_variants_dialog(frm);
}, __("Make"));
} else {
frm.add_custom_button(__("Variant"), function() {
erpnext.item.show_modal_for_manufacturers(frm);
}, __("Make"));
}
frm.page.set_inner_btn_group_as_primary(__("Make"));
}
if (frm.doc.variant_of) {
@ -263,14 +273,6 @@ $.extend(erpnext.item, {
}
},
make_variant: function(frm) {
if(frm.doc.variant_based_on==="Item Attribute") {
erpnext.item.show_modal_for_item_attribute_selection(frm);
} else {
erpnext.item.show_modal_for_manufacturers(frm);
}
},
show_modal_for_manufacturers: function(frm) {
var dialog = new frappe.ui.Dialog({
fields: [
@ -301,7 +303,146 @@ $.extend(erpnext.item, {
dialog.show();
},
show_modal_for_item_attribute_selection: function(frm) {
show_multiple_variants_dialog: function(frm) {
var me = this;
if(me.multiple_variant_dialog) {
me.multiple_variant_dialog.show();
return;
}
let promises = [];
let attr_val_fields = {};
function make_fields_from_attribute_values(attr_dict) {
let fields = [];
Object.keys(attr_dict).forEach((name, i) => {
if(i % 3 === 0){
fields.push({fieldtype: 'Section Break'});
}
fields.push({fieldtype: 'Column Break', label: name});
attr_dict[name].forEach(value => {
fields.push({
fieldtype: 'Check',
label: value,
fieldname: value,
default: 0,
onchange: function() {
let selected_attributes = get_selected_attributes();
let lengths = [];
Object.keys(selected_attributes).map(key => {
lengths.push(selected_attributes[key].length);
});
if(lengths.includes(0)) {
me.multiple_variant_dialog.get_primary_btn().html(__("Make Variants"));
me.multiple_variant_dialog.disable_primary_action();
} else {
let no_of_combinations = lengths.reduce((a, b) => a * b, 1);
me.multiple_variant_dialog.get_primary_btn()
.html(__(
`Make ${no_of_combinations} Variant
${no_of_combinations === 1 ? '' : 's'}`
));
me.multiple_variant_dialog.enable_primary_action();
}
}
});
});
});
return fields;
}
function make_and_show_dialog(fields) {
me.multiple_variant_dialog = new frappe.ui.Dialog({
title: __("Select Attribute Values"),
fields: [
{
fieldtype: "HTML",
fieldname: "help",
options: `<label class="control-label">
${__("Select at least one value from each of the attributes.")}
</label>`,
}
].concat(fields)
});
me.multiple_variant_dialog.set_primary_action(__("Make Variants"), () => {
let selected_attributes = get_selected_attributes();
me.multiple_variant_dialog.hide();
frappe.call({
method:"erpnext.controllers.item_variant.enqueue_multiple_variant_creation",
args: {
"item": frm.doc.name,
"args": selected_attributes
},
callback: function() {
frappe.show_alert({
message: __("Variant creation has been queued."),
indicator: 'orange'
});
}
});
});
$($(me.multiple_variant_dialog.$wrapper.find('.form-column'))
.find('.frappe-control')).css('margin-bottom', '0px');
me.multiple_variant_dialog.disable_primary_action();
me.multiple_variant_dialog.clear();
me.multiple_variant_dialog.show();
}
function get_selected_attributes() {
let selected_attributes = {};
me.multiple_variant_dialog.$wrapper.find('.form-column').each((i, col) => {
if(i===0) return;
let attribute_name = $(col).find('label').html();
selected_attributes[attribute_name] = [];
let checked_opts = $(col).find('.checkbox input');
checked_opts.each((i, opt) => {
if($(opt).is(':checked')) {
selected_attributes[attribute_name].push($(opt).attr('data-fieldname'));
}
});
});
return selected_attributes;
}
let attribute_names = frm.doc.attributes.map(d => d.attribute);
attribute_names.forEach(function(attribute) {
let p = new Promise(resolve => {
frappe.call({
method:"frappe.client.get_list",
args:{
doctype:"Item Attribute Value",
filters: [
["parent","=", attribute]
],
fields: ["attribute_value"]
}
}).then((r) => {
if(r.message) {
attr_val_fields[attribute] = r.message.map(function(d) { return d.attribute_value; });
resolve();
}
});
});
promises.push(p);
}, this);
Promise.all(promises).then(() => {
let fields = make_fields_from_attribute_values(attr_val_fields);
make_and_show_dialog(fields);
})
},
show_single_variant_dialog: function(frm) {
var fields = []
for(var i=0;i< frm.doc.attributes.length;i++){