fix(pos): multiple pos fixes and additions (#24227)

* fix: make custom fields in pos invoice similar to sales invoice

* feat: allow/disallow rate & discount change

* fix: any pos profile can be selected while creating pos opening

* fix: cannot add item to cart

* fix: validate phone payment only if payment request exists

* fix: replace pos payment method patch

* chore: rearrange item & customer group filter

* fix: allow/disallow invoice level discount

* fix: updating qty of item with uom having space char

* fix: move configuration checbox to config section

* fix: invalid item rate trigger

* fix: cannot remove item from draft invoices

* fix: customer currency not set in pos invoice

* fix: duplicate item error message

* fix: sales uom not fetched in pos invoice

* fix: cannot add taxes to pos invoice for uae region

* fix: cannot merge pos invoice into credit note

* fix: tax calculation while merging pos invoices

* feat: delete draft orders from order list

* fix: merging of pos invoice with pricing rules
This commit is contained in:
Saqib
2021-01-28 17:58:55 +05:30
committed by GitHub
parent 0d9a8ae4d2
commit ac9e6ff704
22 changed files with 194 additions and 65 deletions

View File

@@ -69,6 +69,10 @@ erpnext.PointOfSale.Controller = class {
dialog.fields_dict.balance_details.grid.refresh();
});
}
const pos_profile_query = {
query: 'erpnext.accounts.doctype.pos_profile.pos_profile.pos_profile_query',
filters: { company: frappe.defaults.get_default('company') }
}
const dialog = new frappe.ui.Dialog({
title: __('Create POS Opening Entry'),
static: true,
@@ -80,6 +84,7 @@ erpnext.PointOfSale.Controller = class {
{
fieldtype: 'Link', label: __('POS Profile'),
options: 'POS Profile', fieldname: 'pos_profile', reqd: 1,
get_query: () => pos_profile_query,
onchange: () => fetch_pos_payment_methods()
},
{
@@ -124,9 +129,8 @@ erpnext.PointOfSale.Controller = class {
});
frappe.db.get_doc("POS Profile", this.pos_profile).then((profile) => {
Object.assign(this.settings, profile);
this.settings.customer_groups = profile.customer_groups.map(group => group.customer_group);
this.settings.hide_images = profile.hide_images;
this.settings.auto_add_item_to_cart = profile.auto_add_item_to_cart;
this.make_app();
});
}
@@ -255,11 +259,9 @@ erpnext.PointOfSale.Controller = class {
get_frm: () => this.frm,
cart_item_clicked: (item_code, batch_no, uom) => {
const item_row = this.frm.doc.items.find(
i => i.item_code === item_code
&& i.uom === uom
&& (!batch_no || (batch_no && i.batch_no === batch_no))
);
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);
this.item_details.toggle_item_details_section(item_row);
},
@@ -281,6 +283,7 @@ erpnext.PointOfSale.Controller = class {
init_item_details() {
this.item_details = new erpnext.PointOfSale.ItemDetails({
wrapper: this.$components_wrapper,
settings: this.settings,
events: {
get_frm: () => this.frm,
@@ -415,6 +418,11 @@ erpnext.PointOfSale.Controller = class {
() => this.item_selector.toggle_component(true)
]);
},
delete_order: (name) => {
frappe.model.delete_doc(this.frm.doc.doctype, name, () => {
this.recent_order_list.refresh_list();
});
},
new_order: () => {
frappe.run_serially([
() => frappe.dom.freeze(),
@@ -696,14 +704,14 @@ erpnext.PointOfSale.Controller = class {
frappe.dom.freeze();
const { doctype, name, current_item } = this.item_details;
frappe.model.set_value(doctype, name, 'qty', 0);
this.frm.script_manager.trigger('qty', doctype, name).then(() => {
frappe.model.clear_doc(doctype, name);
this.update_cart_html(current_item, true);
this.item_details.toggle_item_details_section(undefined);
frappe.dom.unfreeze();
})
frappe.model.set_value(doctype, name, 'qty', 0)
.then(() => {
frappe.model.clear_doc(doctype, name);
this.update_cart_html(current_item, true);
this.item_details.toggle_item_details_section(undefined);
frappe.dom.unfreeze();
})
.catch(e => console.log(e));
}
}

View File

@@ -5,6 +5,8 @@ erpnext.PointOfSale.ItemCart = class {
this.customer_info = undefined;
this.hide_images = settings.hide_images;
this.allowed_customer_groups = settings.customer_groups;
this.allow_rate_change = settings.allow_rate_change;
this.allow_discount_change = settings.allow_discount_change;
this.init_component();
}
@@ -201,7 +203,7 @@ erpnext.PointOfSale.ItemCart = class {
me.events.checkout();
me.toggle_checkout_btn(false);
me.$add_discount_elem.removeClass("d-none");
me.allow_discount_change && me.$add_discount_elem.removeClass("d-none");
});
this.$totals_section.on('click', '.edit-cart-btn', () => {
@@ -479,11 +481,15 @@ erpnext.PointOfSale.ItemCart = class {
update_totals_section(frm) {
if (!frm) frm = this.events.get_frm();
this.render_net_total(frm.doc.base_net_total);
this.render_grand_total(frm.doc.base_grand_total);
this.render_net_total(frm.doc.net_total);
this.render_grand_total(frm.doc.grand_total);
const taxes = frm.doc.taxes.map(t => { return { description: t.description, rate: t.rate }})
this.render_taxes(frm.doc.base_total_taxes_and_charges, taxes);
const taxes = frm.doc.taxes.map(t => {
return {
description: t.description, rate: t.rate
}
});
this.render_taxes(frm.doc.total_taxes_and_charges, taxes);
}
render_net_total(value) {
@@ -545,7 +551,7 @@ erpnext.PointOfSale.ItemCart = class {
get_cart_item({ item_code, batch_no, uom }) {
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 uom_attr = `[data-uom="${escape(uom)}"]`;
const item_selector = batch_no ?
`.cart-item-wrapper${batch_attr}${uom_attr}` : `.cart-item-wrapper${item_code_attr}${uom_attr}`;
@@ -667,7 +673,7 @@ erpnext.PointOfSale.ItemCart = class {
update_selector_value_in_cart_item(selector, value, item) {
const $item_to_update = this.get_cart_item(item);
$item_to_update.attr(`data-${selector}`, value);
$item_to_update.attr(`data-${selector}`, escape(value));
}
toggle_checkout_btn(show_checkout) {
@@ -702,14 +708,26 @@ erpnext.PointOfSale.ItemCart = class {
on_numpad_event($btn) {
const current_action = $btn.attr('data-button-value');
const action_is_field_edit = ['qty', 'discount_percentage', 'rate'].includes(current_action);
this.highlight_numpad_btn($btn, current_action);
const action_is_allowed = action_is_field_edit ? (
(current_action == 'rate' && this.allow_rate_change) ||
(current_action == 'discount_percentage' && this.allow_discount_change) ||
(current_action == 'qty')) : true;
const action_is_pressed_twice = this.prev_action === current_action;
const first_click_event = !this.prev_action;
const field_to_edit_changed = this.prev_action && this.prev_action != current_action;
if (action_is_field_edit) {
if (!action_is_allowed) {
const label = current_action == 'rate' ? 'Rate'.bold() : 'Discount'.bold();
const message = __('Editing {0} is not allowed as per POS Profile settings', [label]);
frappe.show_alert({
indicator: 'red',
message: message
});
frappe.utils.play_sound("error");
return;
}
if (first_click_event || field_to_edit_changed) {
this.prev_action = current_action;
@@ -753,6 +771,7 @@ erpnext.PointOfSale.ItemCart = class {
this.numpad_value = current_action;
}
this.highlight_numpad_btn($btn, current_action);
this.events.numpad_event(this.numpad_value, this.prev_action);
}

View File

@@ -1,7 +1,9 @@
erpnext.PointOfSale.ItemDetails = class {
constructor({ wrapper, events }) {
constructor({ wrapper, events, settings }) {
this.wrapper = wrapper;
this.events = events;
this.allow_rate_change = settings.allow_rate_change;
this.allow_discount_change = settings.allow_discount_change;
this.current_item = {};
this.init_component();
@@ -207,17 +209,27 @@ erpnext.PointOfSale.ItemDetails = class {
bind_custom_control_change_event() {
const me = this;
if (this.rate_control) {
this.rate_control.df.onchange = function() {
if (this.value || flt(this.value) === 0) {
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);
});
}
if (this.allow_rate_change) {
this.rate_control.df.onchange = function() {
if (this.value || flt(this.value) === 0) {
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);
});
}
};
} else {
this.rate_control.df.read_only = 1;
}
this.rate_control.refresh();
}
if (this.discount_percentage_control && !this.allow_discount_change) {
this.discount_percentage_control.df.read_only = 1;
this.discount_percentage_control.refresh();
}
if (this.warehouse_control) {
@@ -294,8 +306,16 @@ erpnext.PointOfSale.ItemDetails = class {
}
frappe.model.on("POS Invoice Item", "*", (fieldname, value, item_row) => {
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;
// check if current_item is same as item_row
const item_is_same = item_code_is_same && batch_is_same && uom_is_same ? true : false;
const field_control = me[`${fieldname}_control`];
if (field_control) {
if (item_is_same && field_control && field_control.get_value() !== value) {
field_control.set_value(value);
cur_pos.update_cart_html(item_row);
}

View File

@@ -265,6 +265,14 @@ erpnext.PointOfSale.PastOrderSummary = class {
this.$summary_wrapper.addClass('d-none');
});
this.$summary_container.on('click', '.delete-btn', () => {
this.events.delete_order(this.doc.name);
this.show_summary_placeholder();
// this.toggle_component(false);
// this.$component.find('.no-summary-placeholder').removeClass('d-none');
// this.$summary_wrapper.addClass('d-none');
});
this.$summary_container.on('click', '.new-btn', () => {
this.events.new_order();
this.toggle_component(false);
@@ -401,7 +409,7 @@ erpnext.PointOfSale.PastOrderSummary = class {
return [{ condition: true, visible_btns: ['Print Receipt', 'Email Receipt', 'New Order'] }];
return [
{ condition: this.doc.docstatus === 0, visible_btns: ['Edit Order'] },
{ condition: this.doc.docstatus === 0, visible_btns: ['Edit Order', 'Delete Order'] },
{ condition: !this.doc.is_return && this.doc.docstatus === 1, visible_btns: ['Print Receipt', 'Email Receipt', 'Return']},
{ condition: this.doc.is_return && this.doc.docstatus === 1, visible_btns: ['Print Receipt', 'Email Receipt']}
];