') != -1) {
try {
item_data.description = $(item_data.description).text();
} catch (error) {
item_data.description = item_data.description.replace(/
/g, ' ').replace(/<\/div>/g, ' ').replace(/ +/g, ' ');
}
}
item_data.description = frappe.ellipsis(item_data.description, 45);
return `
${item_data.description}
`
}
return ``;
}
}
scroll_to_item($item) {
if ($item.length === 0) return;
const scrollTop = $item.offset().top - this.$cart_items_wrapper.offset().top + this.$cart_items_wrapper.scrollTop();
this.$cart_items_wrapper.animate({ scrollTop });
}
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);
}
toggle_checkout_btn(show_checkout) {
if (show_checkout) {
this.$totals_section.find('.checkout-btn').removeClass('d-none');
this.$totals_section.find('.edit-cart-btn').addClass('d-none');
} else {
this.$totals_section.find('.checkout-btn').addClass('d-none');
this.$totals_section.find('.edit-cart-btn').removeClass('d-none');
}
}
highlight_checkout_btn(toggle) {
const has_primary_class = this.$totals_section.find('.checkout-btn').hasClass('bg-primary');
if (toggle && !has_primary_class) {
this.$totals_section.find('.checkout-btn').addClass('bg-primary text-white text-lg');
} else if (!toggle && has_primary_class) {
this.$totals_section.find('.checkout-btn').removeClass('bg-primary text-white text-lg');
}
}
update_empty_cart_section(no_of_cart_items) {
const $no_item_element = this.$cart_items_wrapper.find('.no-item-wrapper');
// if cart has items and no item is present
no_of_cart_items > 0 && $no_item_element && $no_item_element.remove()
&& this.$cart_items_wrapper.removeClass('mt-4 border-grey border-dashed') && this.$cart_header.removeClass('d-none');
no_of_cart_items === 0 && !$no_item_element.length && this.make_no_items_placeholder();
}
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_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 (first_click_event || field_to_edit_changed) {
this.prev_action = current_action;
} else if (action_is_pressed_twice) {
this.prev_action = undefined;
}
this.numpad_value = '';
} else if (current_action === 'checkout') {
this.prev_action = undefined;
this.toggle_item_highlight();
this.events.numpad_event(undefined, current_action);
return;
} else if (current_action === 'remove') {
this.prev_action = undefined;
this.toggle_item_highlight();
this.events.numpad_event(undefined, current_action);
return;
} else {
this.numpad_value = current_action === 'delete' ? this.numpad_value.slice(0, -1) : this.numpad_value + current_action;
this.numpad_value = this.numpad_value || 0;
}
const first_click_event_is_not_field_edit = !action_is_field_edit && first_click_event;
if (first_click_event_is_not_field_edit) {
frappe.show_alert({
indicator: 'red',
message: __('Please select a field to edit from numpad')
});
frappe.utils.play_sound("error");
return;
}
if (flt(this.numpad_value) > 100 && this.prev_action === 'discount_percentage') {
frappe.show_alert({
message: __('Discount cannot be greater than 100%'),
indicator: 'orange'
});
frappe.utils.play_sound("error");
this.numpad_value = current_action;
}
this.events.numpad_event(this.numpad_value, this.prev_action);
}
highlight_numpad_btn($btn, curr_action) {
const curr_action_is_highlighted = $btn.hasClass('shadow-inner');
const curr_action_is_action = ['qty', 'discount_percentage', 'rate', 'done'].includes(curr_action);
if (!curr_action_is_highlighted) {
$btn.addClass('shadow-inner bg-selected');
}
if (this.prev_action === curr_action && curr_action_is_highlighted) {
// if Qty is pressed twice
$btn.removeClass('shadow-inner bg-selected');
}
if (this.prev_action && this.prev_action !== curr_action && curr_action_is_action) {
// Order: Qty -> Rate then remove Qty highlight
const prev_btn = $(`[data-button-value='${this.prev_action}']`);
prev_btn.removeClass('shadow-inner bg-selected');
}
if (!curr_action_is_action || curr_action === 'done') {
// if numbers are clicked
setTimeout(() => {
$btn.removeClass('shadow-inner bg-selected');
}, 100);
}
}
toggle_numpad(show) {
if (show) {
this.$totals_section.addClass('d-none');
this.$numpad_section.removeClass('d-none');
} else {
this.$totals_section.removeClass('d-none');
this.$numpad_section.addClass('d-none');
}
this.reset_numpad();
}
reset_numpad() {
this.numpad_value = '';
this.prev_action = undefined;
this.$numpad_section.find('.shadow-inner').removeClass('shadow-inner bg-selected');
}
toggle_numpad_field_edit(fieldname) {
if (['qty', 'discount_percentage', 'rate'].includes(fieldname)) {
this.$numpad_section.find(`[data-button-value="${fieldname}"]`).click();
}
}
toggle_customer_info(show) {
if (show) {
this.$cart_container.addClass('d-none')
this.$customer_section.addClass('flex-1 scroll-y').removeClass('mb-0 border pr-4 pl-4')
this.$customer_section.find('.icon').addClass('w-24 h-24 text-2xl').removeClass('w-12 h-12 text-md')
this.$customer_section.find('.customer-header').removeClass('h-18');
this.$customer_section.find('.customer-details').addClass('sticky z-100 bg-white');
this.$customer_section.find('.customer-name').html(
`
${this.customer_info.customer}
`
)
this.$customer_section.find('.customer-details').append(
`
`
)
// transactions need to be in diff div from sticky elem for scrolling
this.$customer_section.append(`
`)
this.render_customer_info_form();
this.fetch_customer_transactions();
} else {
this.$cart_container.removeClass('d-none');
this.$customer_section.removeClass('flex-1 scroll-y').addClass('mb-0 border pr-4 pl-4');
this.$customer_section.find('.icon').addClass('w-12 h-12 text-md').removeClass('w-24 h-24 text-2xl');
this.$customer_section.find('.customer-header').addClass('h-18')
this.$customer_section.find('.customer-details').removeClass('sticky z-100 bg-white');
this.update_customer_section();
}
}
render_customer_info_form() {
const $customer_form = this.$customer_section.find('.customer-form');
const dfs = [{
fieldname: 'email_id',
label: __('Email'),
fieldtype: 'Data',
options: 'email',
placeholder: __("Enter customer's email")
},{
fieldname: 'mobile_no',
label: __('Phone Number'),
fieldtype: 'Data',
placeholder: __("Enter customer's phone number")
},{
fieldname: 'loyalty_program',
label: __('Loyalty Program'),
fieldtype: 'Link',
options: 'Loyalty Program',
placeholder: __("Select Loyalty Program")
},{
fieldname: 'loyalty_points',
label: __('Loyalty Points'),
fieldtype: 'Int',
read_only: 1
}];
const me = this;
dfs.forEach(df => {
this[`customer_${df.fieldname}_field`] = frappe.ui.form.make_control({
df: { ...df,
onchange: handle_customer_field_change,
},
parent: $customer_form.find(`.${df.fieldname}-field`),
render_input: true,
});
this[`customer_${df.fieldname}_field`].set_value(this.customer_info[df.fieldname]);
})
function handle_customer_field_change() {
const current_value = me.customer_info[this.df.fieldname];
const current_customer = me.customer_info.customer;
if (this.value && current_value != this.value && this.df.fieldname != 'loyalty_points') {
frappe.call({
method: 'erpnext.selling.page.point_of_sale.point_of_sale.set_customer_info',
args: {
fieldname: this.df.fieldname,
customer: current_customer,
value: this.value
},
callback: (r) => {
if(!r.exc) {
me.customer_info[this.df.fieldname] = this.value;
frappe.show_alert({
message: __("Customer contact updated successfully."),
indicator: 'green'
});
frappe.utils.play_sound("submit");
}
}
});
}
}
}
fetch_customer_transactions() {
frappe.db.get_list('POS Invoice', {
filters: { customer: this.customer_info.customer, docstatus: 1 },
fields: ['name', 'grand_total', 'status', 'posting_date', 'posting_time', 'currency'],
limit: 20
}).then((res) => {
const transaction_container = this.$customer_section.find('.customer-transactions');
if (!res.length) {
transaction_container.removeClass('flex-1 border rounded').html(
`
No recent transactions found
`
)
return;
};
const elapsed_time = moment(res[0].posting_date+" "+res[0].posting_time).fromNow();
this.$customer_section.find('.last-transacted-on').html(`Last transacted ${elapsed_time}`);
res.forEach(invoice => {
const posting_datetime = moment(invoice.posting_date+" "+invoice.posting_time).format("Do MMMM, h:mma");
let indicator_color = '';
if (in_list(['Paid', 'Consolidated'], invoice.status)) (indicator_color = 'green');
if (invoice.status === 'Draft') (indicator_color = 'red');
if (invoice.status === 'Return') (indicator_color = 'grey');
transaction_container.append(
`
${invoice.name}
${posting_datetime}
${format_currency(invoice.grand_total, invoice.currency, 0) || 0}
${invoice.status}
`
)
});
})
}
load_invoice() {
const frm = this.events.get_frm();
this.fetch_customer_details(frm.doc.customer).then(() => {
this.events.customer_details_updated(this.customer_info);
this.update_customer_section();
})
this.$cart_items_wrapper.html('');
if (frm.doc.items.length) {
frm.doc.items.forEach(item => {
this.update_item_html(item);
});
} else {
this.make_no_items_placeholder();
this.highlight_checkout_btn(false);
}
this.update_totals_section(frm);
if(frm.doc.docstatus === 1) {
this.$totals_section.find('.checkout-btn').addClass('d-none');
this.$totals_section.find('.edit-cart-btn').addClass('d-none');
this.$totals_section.find('.grand-total').removeClass('border-b-grey');
} else {
this.$totals_section.find('.checkout-btn').removeClass('d-none');
this.$totals_section.find('.edit-cart-btn').addClass('d-none');
this.$totals_section.find('.grand-total').addClass('border-b-grey');
}
this.toggle_component(true);
}
toggle_component(show) {
show ? this.$component.removeClass('d-none') : this.$component.addClass('d-none');
}
}