fix(pos): cannot add same item with different rates

This commit is contained in:
Saqib Ansari 2021-05-27 13:49:45 +05:30
parent 349ef8274b
commit 45a89a7c67
4 changed files with 62 additions and 34 deletions

View File

@ -241,10 +241,8 @@ erpnext.PointOfSale.Controller = class {
events: {
get_frm: () => this.frm,
cart_item_clicked: (item_code, batch_no, uom) => {
const search_field = batch_no ? 'batch_no' : 'item_code';
const search_value = batch_no || item_code;
const item_row = this.frm.doc.items.find(i => i[search_field] === search_value && i.uom === uom);
cart_item_clicked: (item_code, batch_no, uom, rate) => {
const item_row = this.get_item_from_frm(item_code, batch_no, uom, rate)
this.item_details.toggle_item_details_section(item_row);
},
@ -275,18 +273,25 @@ erpnext.PointOfSale.Controller = class {
this.cart.toggle_numpad(minimize);
},
form_updated: async (cdt, cdn, fieldname, value) => {
form_updated: (cdt, cdn, fieldname, value) => {
const item_row = frappe.model.get_doc(cdt, cdn);
if (item_row && item_row[fieldname] != value) {
const { item_code, batch_no, uom } = this.item_details.current_item;
const { item_code, batch_no, uom, rate } = this.item_details.current_item;
const event = {
field: fieldname,
value,
item: { item_code, batch_no, uom }
item: { item_code, batch_no, uom, rate }
}
return this.on_cart_update(event)
}
return Promise.resolve();
},
highlight_cart_item: (item) => {
const cart_item = this.cart.get_cart_item(item);
this.cart.toggle_item_highlight(cart_item);
},
item_field_focused: (fieldname) => {
@ -501,8 +506,8 @@ erpnext.PointOfSale.Controller = class {
let item_row = undefined;
try {
let { field, value, item } = args;
const { item_code, batch_no, serial_no, uom } = item;
item_row = this.get_item_from_frm(item_code, batch_no, uom);
const { item_code, batch_no, serial_no, uom, rate } = item;
item_row = this.get_item_from_frm(item_code, batch_no, uom, rate);
const item_selected_from_selector = field === 'qty' && value === "+1"
@ -535,7 +540,7 @@ erpnext.PointOfSale.Controller = class {
item_selected_from_selector && (value = flt(value))
const args = { item_code, batch_no, [field]: value };
const args = { item_code, batch_no, rate, [field]: value };
if (serial_no) {
await this.check_serial_no_availablilty(item_code, this.frm.doc.set_warehouse, serial_no);
@ -551,8 +556,10 @@ erpnext.PointOfSale.Controller = class {
await this.trigger_new_item_events(item_row);
this.check_serial_batch_selection_needed(item_row) && this.edit_item_details_of(item_row);
this.update_cart_html(item_row);
this.item_details.$component.is(':visible') && this.edit_item_details_of(item_row);
this.check_serial_batch_selection_needed(item_row) && this.edit_item_details_of(item_row);
}
} catch (error) {
@ -563,12 +570,13 @@ erpnext.PointOfSale.Controller = class {
}
}
get_item_from_frm(item_code, batch_no, uom) {
get_item_from_frm(item_code, batch_no, uom, rate) {
const has_batch_no = batch_no;
return this.frm.doc.items.find(
i => i.item_code === item_code
&& (!has_batch_no || (has_batch_no && i.batch_no === batch_no))
&& (i.uom === uom)
&& (i.rate == rate)
);
}

View File

@ -184,7 +184,8 @@ erpnext.PointOfSale.ItemCart = class {
const item_code = unescape($cart_item.attr('data-item-code'));
const batch_no = unescape($cart_item.attr('data-batch-no'));
const uom = unescape($cart_item.attr('data-uom'));
me.events.cart_item_clicked(item_code, batch_no, uom);
const rate = unescape($cart_item.attr('data-rate'));
me.events.cart_item_clicked(item_code, batch_no, uom, rate);
this.numpad_value = '';
});
@ -520,28 +521,34 @@ erpnext.PointOfSale.ItemCart = class {
}
}
get_cart_item({ item_code, batch_no, uom }) {
get_cart_item({ item_code, batch_no, uom, rate }) {
const batch_attr = `[data-batch-no="${escape(batch_no)}"]`;
const item_code_attr = `[data-item-code="${escape(item_code)}"]`;
const uom_attr = `[data-uom="${escape(uom)}"]`;
const rate_attr = `[data-rate="${escape(rate)}"]`;
const item_selector = batch_no ?
`.cart-item-wrapper${batch_attr}${uom_attr}` : `.cart-item-wrapper${item_code_attr}${uom_attr}`;
`.cart-item-wrapper${batch_attr}${uom_attr}${rate_attr}` : `.cart-item-wrapper${item_code_attr}${uom_attr}${rate_attr}`;
return this.$cart_items_wrapper.find(item_selector);
}
get_item_from_frm(item) {
const doc = this.events.get_frm().doc;
const { item_code, batch_no, uom, rate } = item;
const search_field = batch_no ? 'batch_no' : 'item_code';
const search_value = batch_no || item_code;
return doc.items.find(i => i[search_field] === search_value && i.uom === uom && i.rate === rate);
}
update_item_html(item, remove_item) {
const $item = this.get_cart_item(item);
if (remove_item) {
$item && $item.next().remove() && $item.remove();
} else {
const { item_code, batch_no, uom } = item;
const search_field = batch_no ? 'batch_no' : 'item_code';
const search_value = batch_no || item_code;
const item_row = this.events.get_frm().doc.items.find(i => i[search_field] === search_value && i.uom === uom);
const item_row = this.get_item_from_frm(item);
this.render_cart_item(item_row, $item);
}
@ -559,7 +566,7 @@ erpnext.PointOfSale.ItemCart = class {
this.$cart_items_wrapper.append(
`<div class="cart-item-wrapper"
data-item-code="${escape(item_data.item_code)}" data-uom="${escape(item_data.uom)}"
data-batch-no="${escape(item_data.batch_no || '')}">
data-batch-no="${escape(item_data.batch_no || '')}" data-rate="${escape(item_data.rate)}">
</div>
<div class="seperator"></div>`
)

View File

@ -54,13 +54,24 @@ erpnext.PointOfSale.ItemDetails = class {
this.$dicount_section = this.$component.find('.discount-section');
}
toggle_item_details_section(item) {
const { item_code, batch_no, uom } = this.current_item;
has_item_has_changed(item) {
const { item_code, batch_no, uom, rate } = this.current_item;
const item_code_is_same = item && item_code === item.item_code;
const batch_is_same = item && batch_no == item.batch_no;
const uom_is_same = item && uom === item.uom;
const rate_is_same = item && rate === item.rate;
this.item_has_changed = !item ? false : item_code_is_same && batch_is_same && uom_is_same ? false : true;
if (!item)
return false
if (item_code_is_same && batch_is_same && uom_is_same && rate_is_same)
return false
return true;
}
toggle_item_details_section(item) {
this.item_has_changed = this.has_item_has_changed(item)
this.events.toggle_item_selector(this.item_has_changed);
this.toggle_component(this.item_has_changed);
@ -72,11 +83,12 @@ erpnext.PointOfSale.ItemDetails = class {
this.item_row = item;
this.currency = this.events.get_frm().doc.currency;
this.current_item = { item_code: item.item_code, batch_no: item.batch_no, uom: item.uom };
this.current_item = { item_code: item.item_code, batch_no: item.batch_no, uom: item.uom, rate: item.rate };
this.render_dom(item);
this.render_discount_dom(item);
this.render_form(item);
this.events.highlight_cart_item(item);
} else {
this.validate_serial_batch_item();
this.current_item = {};
@ -198,12 +210,14 @@ erpnext.PointOfSale.ItemDetails = class {
if (this.allow_rate_change) {
this.rate_control.df.onchange = function() {
if (this.value || flt(this.value) === 0) {
me.events.set_value_in_current_cart_item('rate', this.value);
me.events.form_updated(me.doctype, me.name, 'rate', this.value).then(() => {
const item_row = frappe.get_doc(me.doctype, me.name);
const doc = me.events.get_frm().doc;
me.$item_price.html(format_currency(item_row.rate, doc.currency));
me.render_discount_dom(item_row);
});
me.current_item.rate = this.value;
}
};
} else {
@ -292,11 +306,7 @@ erpnext.PointOfSale.ItemDetails = class {
frappe.model.on("POS Invoice Item", "*", (fieldname, value, item_row) => {
const field_control = this[`${fieldname}_control`];
const { item_code, batch_no, uom } = this.current_item;
const item_code_is_same = item_code === item_row.item_code;
const batch_is_same = batch_no == item_row.batch_no;
const uom_is_same = uom === item_row.uom;
const item_is_same = item_code_is_same && batch_is_same && uom_is_same ? true : false;
const item_is_same = !this.has_item_has_changed(item_row);
if (item_is_same && field_control && field_control.get_value() !== value) {
field_control.set_value(value);

View File

@ -78,7 +78,7 @@ erpnext.PointOfSale.ItemSelector = class {
get_item_html(item) {
const me = this;
// eslint-disable-next-line no-unused-vars
const { item_image, serial_no, batch_no, barcode, actual_qty, stock_uom } = item;
const { item_image, serial_no, batch_no, barcode, actual_qty, stock_uom, price_list_rate } = item;
const indicator_color = actual_qty > 10 ? "green" : actual_qty <= 0 ? "red" : "orange";
let qty_to_display = actual_qty;
@ -108,6 +108,7 @@ erpnext.PointOfSale.ItemSelector = class {
`<div class="item-wrapper"
data-item-code="${escape(item.item_code)}" data-serial-no="${escape(serial_no)}"
data-batch-no="${escape(batch_no)}" data-uom="${escape(stock_uom)}"
data-rate="${escape(price_list_rate)}"
title="${item.item_name}">
${get_item_image_html()}
@ -116,7 +117,7 @@ erpnext.PointOfSale.ItemSelector = class {
<div class="item-name">
${frappe.ellipsis(item.item_name, 18)}
</div>
<div class="item-rate">${format_currency(item.price_list_rate, item.currency, 0) || 0}</div>
<div class="item-rate">${format_currency(price_list_rate, item.currency, 0) || 0}</div>
</div>
</div>`
);
@ -213,13 +214,15 @@ erpnext.PointOfSale.ItemSelector = class {
let batch_no = unescape($item.attr('data-batch-no'));
let serial_no = unescape($item.attr('data-serial-no'));
let uom = unescape($item.attr('data-uom'));
let rate = unescape($item.attr('data-rate'));
// escape(undefined) returns "undefined" then unescape returns "undefined"
batch_no = batch_no === "undefined" ? undefined : batch_no;
serial_no = serial_no === "undefined" ? undefined : serial_no;
uom = uom === "undefined" ? undefined : uom;
rate = rate === "undefined" ? undefined : rate;
me.events.item_selected({ field: 'qty', value: "+1", item: { item_code, batch_no, serial_no, uom }});
me.events.item_selected({ field: 'qty', value: "+1", item: { item_code, batch_no, serial_no, uom, rate }});
me.set_search_value('');
});