brotherton-erpnext/erpnext/manufacturing/page/bom_comparison_tool/bom_comparison_tool.js
2020-03-19 10:07:27 +05:30

228 lines
5.5 KiB
JavaScript

frappe.pages['bom-comparison-tool'].on_page_load = function(wrapper) {
var page = frappe.ui.make_app_page({
parent: wrapper,
title: __('BOM Comparison Tool'),
single_column: true
});
new erpnext.BOMComparisonTool(page);
}
erpnext.BOMComparisonTool = class BOMComparisonTool {
constructor(page) {
this.page = page;
this.make_form();
}
make_form() {
this.form = new frappe.ui.FieldGroup({
fields: [
{
label: __('BOM 1'),
fieldname: 'name1',
fieldtype: 'Link',
options: 'BOM',
change: () => this.fetch_and_render(),
get_query: () => {
return {
filters: {
"name": ["not in", [this.form.get_value("name2") || ""]]
}
}
}
},
{
fieldtype: 'Column Break'
},
{
label: __('BOM 2'),
fieldname: 'name2',
fieldtype: 'Link',
options: 'BOM',
change: () => this.fetch_and_render(),
get_query: () => {
return {
filters: {
"name": ["not in", [this.form.get_value("name1") || ""]]
}
}
}
},
{
fieldtype: 'Section Break'
},
{
fieldtype: 'HTML',
fieldname: 'preview'
}
],
body: this.page.body
});
this.form.make();
}
fetch_and_render() {
let { name1, name2 } = this.form.get_values();
if (!(name1 && name2)) {
this.form.get_field('preview').html('');
return;
}
// set working state
this.form.get_field('preview').html(`
<div class="text-muted margin-top">
${__("Fetching...")}
</div>
`);
frappe.call('erpnext.manufacturing.doctype.bom.bom.get_bom_diff', {
bom1: name1,
bom2: name2
}).then(r => {
let diff = r.message;
frappe.model.with_doctype('BOM', () => {
this.render('BOM', name1, name2, diff);
});
});
}
render(doctype, name1, name2, diff) {
let change_html = (title, doctype, changed) => {
let values_changed = this.get_changed_values(doctype, changed)
.map(change => {
let [fieldname, value1, value2] = change;
return `
<tr>
<td>${frappe.meta.get_label(doctype, fieldname)}</td>
<td>${value1}</td>
<td>${value2}</td>
</tr>
`;
})
.join('');
return `
<h4 class="margin-top">${title}</h4>
<div>
<table class="table table-bordered">
<tr>
<th width="33%">${__('Field')}</th>
<th width="33%">${name1}</th>
<th width="33%">${name2}</th>
</tr>
${values_changed}
</table>
</div>
`;
}
let value_changes = change_html(__('Values Changed'), doctype, diff.changed);
let row_changes_by_fieldname = group_items(diff.row_changed, change => change[0]);
let table_changes = Object.keys(row_changes_by_fieldname).map(fieldname => {
let changes = row_changes_by_fieldname[fieldname];
let df = frappe.meta.get_docfield(doctype, fieldname);
let html = changes.map(change => {
let [fieldname,, item_code, changes] = change;
let df = frappe.meta.get_docfield(doctype, fieldname);
let child_doctype = df.options;
let values_changed = this.get_changed_values(child_doctype, changes);
return values_changed.map((change, i) => {
let [fieldname, value1, value2] = change;
let th = i === 0
? `<th rowspan="${values_changed.length}">${item_code}</th>`
: '';
return `
<tr>
${th}
<td>${frappe.meta.get_label(child_doctype, fieldname)}</td>
<td>${value1}</td>
<td>${value2}</td>
</tr>
`;
}).join('');
}).join('');
return `
<h4 class="margin-top">${__('Changes in {0}', [df.label])}</h4>
<table class="table table-bordered">
<tr>
<th width="25%">${__('Item Code')}</th>
<th width="25%">${__('Field')}</th>
<th width="25%">${name1}</th>
<th width="25%">${name2}</th>
</tr>
${html}
</table>
`;
}).join('');
let get_added_removed_html = (title, grouped_items) => {
return Object.keys(grouped_items).map(fieldname => {
let rows = grouped_items[fieldname];
let df = frappe.meta.get_docfield(doctype, fieldname);
let fields = frappe.meta.get_docfields(df.options)
.filter(df => df.in_list_view);
let html = rows.map(row => {
let [, doc] = row;
let cells = fields
.map(df => `<td>${doc[df.fieldname]}</td>`)
.join('');
return `<tr>${cells}</tr>`;
}).join('');
let header = fields.map(df => `<th>${df.label}</th>`).join('');
return `
<h4 class="margin-top">${$.format(title, [df.label])}</h4>
<table class="table table-bordered">
<tr>${header}</tr>
${html}
</table>
`;
}).join('');
};
let added_by_fieldname = group_items(diff.added, change => change[0]);
let removed_by_fieldname = group_items(diff.removed, change => change[0]);
let added_html = get_added_removed_html(__('Rows Added in {0}'), added_by_fieldname);
let removed_html = get_added_removed_html(__('Rows Removed in {0}'), removed_by_fieldname);
let html = `
${value_changes}
${table_changes}
${added_html}
${removed_html}
`;
this.form.get_field('preview').html(html);
}
get_changed_values(doctype, changed) {
return changed.filter(change => {
let [fieldname, value1, value2] = change;
if (!value1) value1 = '';
if (!value2) value2 = '';
if (value1 === value2) return false;
let df = frappe.meta.get_docfield(doctype, fieldname);
if (!df) return false;
if (df.hidden) return false;
return true;
});
}
};
function group_items(array, fn) {
return array.reduce((acc, item) => {
let key = fn(item);
acc[key] = acc[key] || [];
acc[key].push(item);
return acc;
}, {});
}