From b0b6aa9124bab869f70022aedf1d3985408123b5 Mon Sep 17 00:00:00 2001 From: Saqib Ansari Date: Mon, 23 Nov 2020 12:57:06 +0530 Subject: [PATCH] refactor: past order list and summary with new ui --- erpnext/public/scss/point-of-sale.scss | 249 +++++++++++++- .../page/point_of_sale/pos_controller.js | 2 +- .../page/point_of_sale/pos_item_cart.js | 43 ++- .../page/point_of_sale/pos_item_selector.js | 2 +- .../page/point_of_sale/pos_past_order_list.js | 51 ++- .../point_of_sale/pos_past_order_summary.js | 310 ++++++------------ 6 files changed, 385 insertions(+), 272 deletions(-) diff --git a/erpnext/public/scss/point-of-sale.scss b/erpnext/public/scss/point-of-sale.scss index 61be422e48..60043bf110 100644 --- a/erpnext/public/scss/point-of-sale.scss +++ b/erpnext/public/scss/point-of-sale.scss @@ -75,7 +75,14 @@ background-color: var(--gray-50); } + .sticky-element { + position: sticky; + top: -1px; + z-index: 1; + } + > .items-selector { + @extend .pos-card; grid-column: span 6 / span 6; display: flex; flex-direction: column; @@ -83,12 +90,10 @@ overflow-x: hidden; > .filter-section { + @extend .sticky-element; display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); background-color: var(--fg-color); - position: sticky; - top: -1px; - z-index: 1; padding: var(--padding-lg); padding-bottom: var(--padding-sm); align-items: center; @@ -124,6 +129,10 @@ @extend .pointer-no-select; border-radius: var(--border-radius-md); box-shadow: var(--shadow-base); + + &:hover { + transform: scale(1.02, 1.02); + } .item-display { display: flex; @@ -180,14 +189,13 @@ > .customer-field { display: flex; align-items: center; + padding-top: var(--padding-xs); } > .customer-details { + @extend .sticky-element; display: flex; flex-direction: column; - position: sticky; - top: -1px; - z-index: 1; background-color: var(--fg-color); > .header { @@ -263,6 +271,7 @@ display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); margin-top: var(--margin-sm); + gap: var(--padding-sm); } > .transactions-label { @@ -445,7 +454,7 @@ padding: 3px var(--padding-sm); border-radius: var(--border-radius-sm); background-color: var(--green-100); - color: var(--green-700); + color: var(--dark-green-500); font-size: var(--text-sm); font-weight: 700; } @@ -462,19 +471,14 @@ > .taxes-container { display: none; - align-items: center; - justify-content: space-between; + flex-direction: column; padding: var(--padding-sm) 0px; font-weight: 500; font-size: var(--text-md); - > .tax-label { + > .tax-row { display: flex; - align-items: center; - - > .tax-desc { - margin-left: var(--margin-md); - } + justify-content: space-between; } } @@ -702,7 +706,7 @@ padding: 3px var(--padding-sm); border-radius: var(--border-radius-sm); background-color: var(--green-100); - color: var(--green-700); + color: var(--dark-green-500); font-size: var(--text-sm); font-weight: 700; } @@ -849,6 +853,219 @@ display: none; } } + } + > .past-order-list { + @extend .pos-card; + grid-column: span 4 / span 4; + display: none; + flex-direction: column; + overflow-y: scroll; + overflow-x: hidden; + + > .filter-section { + @extend .sticky-element; + display: flex; + flex-direction: column; + background-color: var(--fg-color); + padding: var(--padding-lg); + + > .search-field { + width: 100%; + display: flex; + align-items: center; + margin-top: var(--margin-sm); + margin-bottom: var(--margin-xs); + } + + > .status-field { + width: 100%; + display: flex; + align-items: center; + } + } + + > .invoices-container { + padding: var(--padding-lg); + padding-top: 0px; + } + } + + > .past-order-summary { + // @extend .pos-card; + display: none; + grid-column: span 6 / span 6; + flex-direction: column; + align-items: center; + justify-content: center; + padding: var(--padding-lg); + + > .no-summary-placeholder { + display: flex; + align-items: center; + justify-content: center; + width: 100%; + height: 100%; + background-color: var(--gray-50); + font-weight: 500; + border-radius: var(--border-radius-md); + } + + > .invoice-summary-wrapper { + @extend .pos-card; + display: none; + position: relative; + width: 31rem; + height: 100%; + + > .abs-container { + position: absolute; + display: flex; + flex-direction: column; + width: 100%; + height: 100%; + padding: var(--padding-lg); + + > .upper-section { + display: flex; + justify-content: space-between; + width: 100%; + margin-bottom: var(--margin-md); + + > .left-section { + display: flex; + flex-direction: column; + align-items: flex-start; + justify-content: flex-end; + padding-right: var(--padding-sm); + + > .customer-name { + font-size: var(--text-2xl); + font-weight: 700; + } + + > .customer-email { + font-size: var(--text-md); + font-weight: 500; + color: var(--gray-600); + } + + > .cashier { + font-size: var(--text-md); + font-weight: 500; + color: var(--gray-600); + margin-top: auto; + } + } + + > .right-section { + display: flex; + flex-direction: column; + align-items: flex-end; + justify-content: space-between; + + > .paid-amount { + font-size: var(--text-2xl); + font-weight: 700; + } + + > .invoice-name { + font-size: var(--text-md); + font-weight: 500; + color: var(--gray-600); + margin-bottom: var(--margin-sm); + } + } + } + + > .summary-container { + display: flex; + flex-direction: column; + border-radius: var(--border-radius-md); + background-color: var(--gray-50); + margin: var(--margin-md) 0px; + + > .summary-row-wrapper { + display: flex; + align-items: center; + justify-content: space-between; + padding: var(--padding-sm) var(--padding-md); + // border-bottom: 1px solid var(--gray-300); + } + + > .taxes-wrapper { + display: flex; + flex-direction: column; + padding: var(--padding-sm) var(--padding-md); + // border-bottom: 1px solid var(--gray-300); + + > .tax-row { + display: flex; + justify-content: space-between; + } + } + + > .item-row-wrapper { + display: flex; + align-items: center; + padding: var(--padding-sm) var(--padding-md); + // border-bottom: 1px solid var(--gray-300); + + > .item-name { + @extend .nowrap; + font-weight: 500; + margin-right: var(--margin-md); + } + + > .item-qty { + font-weight: 500; + margin-left: auto; + } + + > .item-rate-disc { + display: flex; + text-align: right; + margin-left: var(--margin-md); + + > .item-disc { + color: var(--dark-green-500); + } + + > .item-rate { + font-weight: 500; + margin-left: var(--margin-md); + } + } + } + + > .grand-total { + // font-size: var(--text-lg); + font-weight: 700; + padding: var(--padding-md); + } + + > .payments { + font-weight: 700; + } + } + + + > .summary-btns { + display: flex; + justify-content: space-between; + + > .summary-btn { + flex: 1; + margin: 0px var(--margin-xs); + } + + > .new-btn { + background-color: var(--blue-500); + color:white; + font-weight: 500; + } + } + } + } } } \ No newline at end of file diff --git a/erpnext/selling/page/point_of_sale/pos_controller.js b/erpnext/selling/page/point_of_sale/pos_controller.js index 4875ec061f..9a7ddd9a57 100644 --- a/erpnext/selling/page/point_of_sale/pos_controller.js +++ b/erpnext/selling/page/point_of_sale/pos_controller.js @@ -190,7 +190,7 @@ erpnext.PointOfSale.Controller = class { } toggle_recent_order() { - const show = this.recent_order_list.$component.hasClass('d-none'); + const show = this.recent_order_list.$component.is(':hidden'); this.toggle_recent_order_list(show); } diff --git a/erpnext/selling/page/point_of_sale/pos_item_cart.js b/erpnext/selling/page/point_of_sale/pos_item_cart.js index 867cd2df63..955111439b 100644 --- a/erpnext/selling/page/point_of_sale/pos_item_cart.js +++ b/erpnext/selling/page/point_of_sale/pos_item_cart.js @@ -159,7 +159,7 @@ erpnext.PointOfSale.ItemCart = class { }); this.$customer_section.on('click', '.customer-display', function(e) { - if ($(this).find('.reset-customer-btn').length == 0) return; + if ($(e.target).closest('.reset-customer-btn').length) return; const show = me.$cart_container.is(':visible'); me.toggle_customer_info(show); @@ -495,20 +495,17 @@ erpnext.PointOfSale.ItemCart = class { if (taxes.length) { const currency = this.events.get_frm().doc.currency; this.$totals_section.find('.taxes-container').css('display', 'flex').html( - `
-
Tax Charges
-
- ${ - taxes.map((t, i) => { - let margin_left = ''; - if (i !== 0) margin_left = '10px'; - const description = /[0-9]+/.test(t.description) ? t.description : `${t.description} @ ${t.rate}%`; - return `${description}` - }).join('') - } -
-
-
${format_currency(value, currency)}
` + `${ + taxes.map((t, i) => { + const description = /[0-9]+/.test(t.description) ? t.description : `${t.description} @ ${t.rate}%`; + return `
+
+ ${description} +
+
${format_currency(value, currency)}
+
` + }).join('') + }` ) } else { this.$totals_section.find('.taxes-container').css('display', 'none').html(''); @@ -926,11 +923,12 @@ erpnext.PointOfSale.ItemCart = class { 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'); + let indicator_color = { + 'Paid': 'green', + 'Draft': 'red', + 'Return': 'gray', + 'Consolidated': 'blue' + }; transaction_container.append( `
@@ -943,8 +941,9 @@ erpnext.PointOfSale.ItemCart = class { ${format_currency(invoice.grand_total, invoice.currency, 0) || 0}
- - ${invoice.status} + + ${invoice.status} +
diff --git a/erpnext/selling/page/point_of_sale/pos_item_selector.js b/erpnext/selling/page/point_of_sale/pos_item_selector.js index e2a2365e32..38fe645a65 100644 --- a/erpnext/selling/page/point_of_sale/pos_item_selector.js +++ b/erpnext/selling/page/point_of_sale/pos_item_selector.js @@ -17,7 +17,7 @@ erpnext.PointOfSale.ItemSelector = class { prepare_dom() { this.wrapper.append( - `
+ `
All Items
diff --git a/erpnext/selling/page/point_of_sale/pos_past_order_list.js b/erpnext/selling/page/point_of_sale/pos_past_order_list.js index b256247924..166d9cf0ce 100644 --- a/erpnext/selling/page/point_of_sale/pos_past_order_list.js +++ b/erpnext/selling/page/point_of_sale/pos_past_order_list.js @@ -14,17 +14,13 @@ erpnext.PointOfSale.PastOrderList = class { prepare_dom() { this.wrapper.append( - `
-
-
-
-
-
-
-
RECENT ORDERS
-
-
+ `
+
+
Recent Orders
+
+
+
` ); @@ -77,10 +73,6 @@ erpnext.PointOfSale.PastOrderList = class { this.status_field.set_value('Draft'); } - toggle_component(show) { - show ? this.$component.removeClass('d-none') && this.refresh_list() : this.$component.addClass('d-none'); - } - refresh_list() { frappe.dom.freeze(); this.events.reset_summary(); @@ -106,23 +98,26 @@ erpnext.PointOfSale.PastOrderList = class { get_invoice_html(invoice) { const posting_datetime = moment(invoice.posting_date+" "+invoice.posting_time).format("Do MMMM, h:mma"); return ( - `
-
-
${invoice.name}
-
-
- - - - ${invoice.customer} -
+ `
+
+
${invoice.name}
+
+ + + + ${invoice.customer}
-
-
${format_currency(invoice.grand_total, invoice.currency, 0) || 0}
-
${posting_datetime}
+
+
${format_currency(invoice.grand_total, invoice.currency, 0) || 0}
+
${posting_datetime}
-
` +
+
` ); } + + toggle_component(show) { + show ? this.$component.css('display', 'flex') && this.refresh_list() : this.$component.css('display', 'none'); + } }; \ No newline at end of file diff --git a/erpnext/selling/page/point_of_sale/pos_past_order_summary.js b/erpnext/selling/page/point_of_sale/pos_past_order_summary.js index 6fd4c26bea..2e94ecefa1 100644 --- a/erpnext/selling/page/point_of_sale/pos_past_order_summary.js +++ b/erpnext/selling/page/point_of_sale/pos_past_order_summary.js @@ -8,85 +8,39 @@ erpnext.PointOfSale.PastOrderSummary = class { init_component() { this.prepare_dom(); - this.init_child_components(); + this.init_email_print_dialog(); this.bind_events(); this.attach_shortcuts(); } prepare_dom() { this.wrapper.append( - `
-
-
-
Select an invoice to load summary data
-
+ `
+
+ Select an invoice to load summary data
-
-
+
+
+
+
Items
+
+
Totals
+
+
Payments
+
+
+
` ); this.$component = this.wrapper.find('.past-order-summary'); - this.$summary_wrapper = this.$component.find('.summary-wrapper'); - this.$summary_container = this.$component.find('.summary-container'); - } - - init_child_components() { - this.init_upper_section(); - this.init_items_summary(); - this.init_totals_summary(); - this.init_payments_summary(); - this.init_summary_buttons(); - this.init_email_print_dialog(); - } - - init_upper_section() { - this.$summary_container.append( - `
` - ); - + this.$summary_wrapper = this.$component.find('.invoice-summary-wrapper'); + this.$summary_container = this.$component.find('.abs-container'); this.$upper_section = this.$summary_container.find('.upper-section'); - } - - init_items_summary() { - this.$summary_container.append( - `
-
ITEMS
-
-
` - ); - - this.$items_summary_container = this.$summary_container.find('.items-summary-container'); - } - - init_totals_summary() { - this.$summary_container.append( - `
-
TOTALS
-
-
` - ); - - this.$totals_summary_container = this.$summary_container.find('.summary-totals-container'); - } - - init_payments_summary() { - this.$summary_container.append( - `
-
PAYMENTS
-
-
` - ); - - this.$payment_summary_container = this.$summary_container.find('.payments-summary-container'); - } - - init_summary_buttons() { - this.$summary_container.append( - `
` - ); - + this.$items_container = this.$summary_container.find('.items-container'); + this.$totals_container = this.$summary_container.find('.totals-container'); + this.$payment_container = this.$summary_container.find('.payments-container'); this.$summary_btns = this.$summary_container.find('.summary-btns'); } @@ -121,132 +75,88 @@ erpnext.PointOfSale.PastOrderSummary = class { } get_upper_section_html(doc) { - const { status } = doc; let indicator_color = ''; + const { status } = doc; + let indicator_color = ''; in_list(['Paid', 'Consolidated'], status) && (indicator_color = 'green'); status === 'Draft' && (indicator_color = 'red'); status === 'Return' && (indicator_color = 'grey'); - return `
-
${doc.customer}
-
${this.customer_email}
-
Sold by: ${doc.owner}
+ return `
+
${doc.customer}
+
${this.customer_email}
+
Sold by: ${doc.owner}
-
-
${format_currency(doc.paid_amount, doc.currency)}
-
-
${doc.name}
-
${doc.status}
-
+
+ +
${doc.name}
+ ${doc.status}
`; } + get_item_html(doc, item_data) { + return `
+
${item_data.item_name}
+
${item_data.qty || 0}
+
${get_rate_discount_html()}
+
`; + + function get_rate_discount_html() { + if (item_data.rate && item_data.price_list_rate && item_data.rate !== item_data.price_list_rate) { + return `(${item_data.discount_percentage}% off) +
${format_currency(item_data.rate, doc.currency)}
`; + } else { + return `
${format_currency(item_data.price_list_rate || item_data.rate, doc.currency)}
`; + } + } + } + get_discount_html(doc) { if (doc.discount_amount) { - return `
-
-
- Discount -
- (${doc.additional_discount_percentage} %) -
-
-
${format_currency(doc.discount_amount, doc.currency)}
-
-
`; + return `
+
Discount (${doc.additional_discount_percentage} %)
+
${format_currency(doc.discount_amount, doc.currency)}
+
`; } else { return ``; } } get_net_total_html(doc) { - return `
-
-
- Net Total -
-
-
-
${format_currency(doc.net_total, doc.currency)}
-
+ return `
+
Net Total
+
${format_currency(doc.net_total, doc.currency)}
`; } get_taxes_html(doc) { - const taxes = doc.taxes.map((t, i) => { - let margin_left = ''; - if (i !== 0) margin_left = 'ml-2'; - return `${t.description} @${t.rate}%`; - }).join(''); + if (!doc.taxes.length) return ''; return ` -
-
-
Tax Charges
-
${taxes}
-
-
-
- ${format_currency(doc.base_total_taxes_and_charges, doc.currency)} -
-
+
+ ${ + doc.taxes.map((t, i) => { + const description = /[0-9]+/.test(t.description) ? t.description : `${t.description} @ ${t.rate}%`; + return `
+
${description}
+
${format_currency(t.tax_amount_after_discount_amount, doc.currency)}
+
` + }).join('') + }
`; } get_grand_total_html(doc) { - return `
-
-
- Grand Total -
-
-
-
${format_currency(doc.grand_total, doc.currency)}
-
+ return `
+
Grand Total
+
${format_currency(doc.grand_total, doc.currency)}
`; } - get_item_html(doc, item_data) { - return `
-
- ${item_data.qty || 0} -
-
-
- ${item_data.item_name} -
-
-
- ${get_rate_discount_html()} -
-
`; - - function get_rate_discount_html() { - if (item_data.rate && item_data.price_list_rate && item_data.rate !== item_data.price_list_rate) { - return ` - (${item_data.discount_percentage}% off) - -
- ${format_currency(item_data.rate, doc.currency)} -
`; - } else { - return `
- ${format_currency(item_data.price_list_rate || item_data.rate, doc.currency)} -
`; - } - } - } - get_payment_html(doc, payment) { - return `
-
-
- ${payment.mode_of_payment} -
-
-
-
${format_currency(payment.amount, doc.currency)}
-
+ return `
+
${payment.mode_of_payment}
+
${format_currency(payment.amount, doc.currency)}
`; } @@ -254,22 +164,22 @@ erpnext.PointOfSale.PastOrderSummary = class { this.$summary_container.on('click', '.return-btn', () => { this.events.process_return(this.doc.name); this.toggle_component(false); - this.$component.find('.no-summary-placeholder').removeClass('d-none'); - this.$summary_wrapper.addClass('d-none'); + this.$component.find('.no-summary-placeholder').css('display', 'flex'); + this.$summary_wrapper.css('display', 'none'); }); this.$summary_container.on('click', '.edit-btn', () => { this.events.edit_order(this.doc.name); this.toggle_component(false); - this.$component.find('.no-summary-placeholder').removeClass('d-none'); - this.$summary_wrapper.addClass('d-none'); + this.$component.find('.no-summary-placeholder').css('display', 'flex'); + this.$summary_wrapper.css('display', 'none'); }); this.$summary_container.on('click', '.new-btn', () => { this.events.new_order(); this.toggle_component(false); - this.$component.find('.no-summary-placeholder').removeClass('d-none'); - this.$summary_wrapper.addClass('d-none'); + this.$component.find('.no-summary-placeholder').css('display', 'flex'); + this.$summary_wrapper.css('display', 'none'); }); this.$summary_container.on('click', '.email-btn', () => { @@ -312,10 +222,6 @@ erpnext.PointOfSale.PastOrderSummary = class { }); } - toggle_component(show) { - show ? this.$component.removeClass('d-none') : this.$component.addClass('d-none'); - } - send_email() { const frm = this.events.get_frm(); const recipients = this.email_dialog.get_values().recipients; @@ -338,8 +244,10 @@ erpnext.PointOfSale.PastOrderSummary = class { if(!r.exc) { frappe.utils.play_sound("email"); if(r.message["emails_not_sent_to"]) { - frappe.msgprint(__("Email not sent to {0} (unsubscribed / disabled)", - [ frappe.utils.escape_html(r.message["emails_not_sent_to"]) ]) ); + frappe.msgprint(__( + "Email not sent to {0} (unsubscribed / disabled)", + [ frappe.utils.escape_html(r.message["emails_not_sent_to"]) ] + )); } else { frappe.show_alert({ message: __('Email sent successfully.'), @@ -361,9 +269,7 @@ erpnext.PointOfSale.PastOrderSummary = class { m.visible_btns.forEach(b => { const class_name = b.split(' ')[0].toLowerCase(); this.$summary_btns.append( - `
- ${b} -
` + `
${b}
` ); }); } @@ -372,28 +278,20 @@ erpnext.PointOfSale.PastOrderSummary = class { } show_summary_placeholder() { - this.$summary_wrapper.addClass("d-none"); - this.$component.find('.no-summary-placeholder').removeClass('d-none'); + this.$summary_wrapper.css('display', 'none'); + this.$component.find('.no-summary-placeholder').css('display', 'flex'); } switch_to_post_submit_summary() { - // switch to full width view - this.$component.removeClass('col-span-6').addClass('col-span-10'); - this.$summary_wrapper.removeClass('w-66').addClass('w-40'); - // switch place holder with summary container - this.$component.find('.no-summary-placeholder').addClass('d-none'); - this.$summary_wrapper.removeClass('d-none'); + this.$component.find('.no-summary-placeholder').css('display', 'none'); + this.$summary_wrapper.css('display', 'flex'); } switch_to_recent_invoice_summary() { - // switch full width view with 60% view - this.$component.removeClass('col-span-10').addClass('col-span-6'); - this.$summary_wrapper.removeClass('w-40').addClass('w-66'); - // switch place holder with summary container - this.$component.find('.no-summary-placeholder').addClass('d-none'); - this.$summary_wrapper.removeClass('d-none'); + this.$component.find('.no-summary-placeholder').css('display', 'none'); + this.$summary_wrapper.css('display', 'flex'); } get_condition_btn_map(after_submission) { @@ -410,8 +308,8 @@ erpnext.PointOfSale.PastOrderSummary = class { load_summary_of(doc, after_submission=false) { this.$summary_wrapper.removeClass("d-none"); - after_submission ? - this.switch_to_post_submit_summary() : this.switch_to_recent_invoice_summary(); + // after_submission ? + // this.switch_to_post_submit_summary() : this.switch_to_recent_invoice_summary(); this.doc = doc; @@ -437,19 +335,19 @@ erpnext.PointOfSale.PastOrderSummary = class { } attach_items_info(doc) { - this.$items_summary_container.html(''); - doc.items.forEach(item => { + this.$items_container.html(''); + doc.items.forEach((item, i) => { const item_dom = this.get_item_html(doc, item); - this.$items_summary_container.append(item_dom); + this.$items_container.append(item_dom); }); } attach_payments_info(doc) { - this.$payment_summary_container.html(''); + this.$payment_container.html(''); doc.payments.forEach(p => { if (p.amount) { const payment_dom = this.get_payment_html(doc, p); - this.$payment_summary_container.append(payment_dom); + this.$payment_container.append(payment_dom); } }); if (doc.redeem_loyalty_points && doc.loyalty_amount) { @@ -457,20 +355,24 @@ erpnext.PointOfSale.PastOrderSummary = class { mode_of_payment: 'Loyalty Points', amount: doc.loyalty_amount, }); - this.$payment_summary_container.append(payment_dom); + this.$payment_container.append(payment_dom); } } attach_totals_info(doc) { - this.$totals_summary_container.html(''); + this.$totals_container.html(''); - const discount_dom = this.get_discount_html(doc); const net_total_dom = this.get_net_total_html(doc); const taxes_dom = this.get_taxes_html(doc); + const discount_dom = this.get_discount_html(doc); const grand_total_dom = this.get_grand_total_html(doc); - this.$totals_summary_container.append(discount_dom); - this.$totals_summary_container.append(net_total_dom); - this.$totals_summary_container.append(taxes_dom); - this.$totals_summary_container.append(grand_total_dom); + this.$totals_container.append(net_total_dom); + this.$totals_container.append(taxes_dom); + this.$totals_container.append(discount_dom); + this.$totals_container.append(grand_total_dom); + } + + toggle_component(show) { + show ? this.$component.css('display', 'flex') : this.$component.css('display', 'none'); } }; \ No newline at end of file