module.ReceiptScreenWidget = module.ScreenWidget.extend({
template: 'ReceiptScreenWidget',
-
- show_numpad: true,
- show_leftpane: true,
+ show_numpad: false,
+ show_leftpane: false,
show: function(){
this._super();
});
- module.NewPaymentScreenWidget = module.ScreenWidget.extend({
- template: 'NewPaymentScreenWidget',
+ module.PaymentScreenWidget = module.ScreenWidget.extend({
+ template: 'PaymentScreenWidget',
back_screen: 'product',
next_screen: 'receipt',
show_leftpane: false,
show_numpad: false,
init: function(parent, options) {
+ var self = this;
this._super(parent, options);
+
this.pos.bind('change:selectedOrder',function(){
- this.bind_events();
this.renderElement();
+ this.watch_order_changes();
},this);
+ this.watch_order_changes();
+
+ this.inputbuffer = "";
+ this.keyboard_handler = function(event){
+ var key = '';
+ if ( event.keyCode === 13 ) { // Enter
+ self.validate_order();
+ } else if ( event.keyCode === 190 ) { // Dot
+ key = '.';
+ } else if ( event.keyCode === 46 ) { // Delete
+ key = 'CLEAR';
+ } else if ( event.keyCode === 8 ) { // Backspace
+ key = 'BACKSPACE';
+ event.preventDefault(); // Prevents history back nav
+ } else if ( event.keyCode >= 48 && event.keyCode <= 57 ){ // Numbers
+ key = '' + (event.keyCode - 48);
+ } else if ( event.keyCode >= 96 && event.keyCode <= 105 ){ // Numpad Numbers
+ key = '' + (event.keyCode - 96);
+ } else if ( event.keyCode === 189 || event.keyCode === 109 ) { // Minus
+ key = '-';
+ } else if ( event.keyCode === 107 ) { // Plus
+ key = '+';
+ }
+
+ self.payment_input(key);
+
+ };
+ },
+ // resets the current input buffer
+ reset_input: function(){
+ this.inputbuffer = "";
+ },
+ // handle both keyboard and numpad input. Accepts
+ // a string that represents the key pressed.
+ payment_input: function(input) {
+ var oldbuf = this.inputbuffer.slice(0);
+
+ if (input === '.') {
+ if (!this.inputbuffer.length || this.inputbuffer === '-') {
+ this.inputbuffer += "0.";
+ } else if (this.inputbuffer.indexOf('.') < 0){
+ this.inputbuffer = this.inputbuffer + '.';
+ }
+ } else if (input === 'CLEAR') {
+ this.inputbuffer = "";
+ } else if (input === 'BACKSPACE') {
+ this.inputbuffer = this.inputbuffer.substring(0,this.inputbuffer.length - 1);
+ } else if (input === '+') {
+ if ( this.inputbuffer[0] === '-' ) {
+ this.inputbuffer = this.inputbuffer.substring(1,this.inputbuffer.length);
+ }
+ } else if (input === '-') {
+ if ( this.inputbuffer[0] === '-' ) {
+ this.inputbuffer = this.inputbuffer.substring(1,this.inputbuffer.length);
+ } else {
+ this.inputbuffer = '-' + this.inputbuffer;
+ }
+ } else if (input[0] === '+' && !isNaN(parseFloat(input))) {
+ this.inputbuffer = '' + ((parseFloat(this.inputbuffer) || 0) + parseFloat(input));
+ } else if (!isNaN(parseInt(input))) {
+ this.inputbuffer += input;
+ }
+
+ if (this.inputbuffer !== oldbuf) {
+ var order = this.pos.get_order();
+ if (order.selected_paymentline) {
+ order.selected_paymentline.set_amount(parseFloat(this.inputbuffer));
+ this.order_changes();
+ this.render_paymentlines();
+ this.$('.paymentline.selected .edit').text(this.inputbuffer);
+ }
+ }
},
- click_numpad: function(button){
- console.log(button);
+ click_numpad: function(button) {
+ this.payment_input(button.data('action'));
},
render_numpad: function() {
+ var self = this;
var numpad = $(QWeb.render('PaymentScreen-Numpad', { widget:this }));
+ numpad.on('click','button',function(){
+ self.click_numpad($(this));
+ });
return numpad;
},
click_delete_paymentline: function(cid){
for ( var i = 0; i < lines.length; i++ ) {
if (lines[i].cid === cid) {
this.pos.get_order().removePaymentline(lines[i]);
+ this.reset_input();
+ this.render_paymentlines();
+ return;
+ }
+ }
+ },
+ click_paymentline: function(cid){
+ var lines = this.pos.get_order().get('paymentLines').models;
+ for ( var i = 0; i < lines.length; i++ ) {
+ if (lines[i].cid === cid) {
+ this.pos.get_order().selectPaymentline(lines[i]);
+ this.reset_input();
this.render_paymentlines();
return;
}
lines.on('click','.delete-button',function(){
self.click_delete_paymentline($(this).data('cid'));
});
+
+ lines.on('click','.paymentline',function(){
+ self.click_paymentline($(this).data('cid'));
+ });
lines.appendTo(this.$('.paymentlines-container'));
},
- click_paymentmethods: function(id){
+ click_paymentmethods: function(id) {
var cashregister = null;
for ( var i = 0; i < this.pos.cashregisters.length; i++ ) {
if ( this.pos.cashregisters[i].journal_id[0] === id ){
}
}
this.pos.get_order().addPaymentline( cashregister );
+ this.reset_input();
this.render_paymentlines();
},
render_paymentmethods: function() {
self.pos_widget.screen_selector.back();
});
- },
- show: function(){
- this.pos.get_order().clean_empty_paymentlines();
- this.render_paymentlines();
- this._super();
- },
-
- });
-
- module.PaymentScreenWidget = module.ScreenWidget.extend({
- template: 'PaymentScreenWidget',
- back_screen: 'products',
- next_screen: 'receipt',
- init: function(parent, options) {
- var self = this;
- this._super(parent,options);
-
- this.pos.bind('change:selectedOrder',function(){
- this.bind_events();
- this.renderElement();
- },this);
-
- this.bind_events();
-
- this.line_delete_handler = function(event){
- var node = this;
- while(node && !node.classList.contains('paymentline')){
- node = node.parentNode;
- }
- if(node){
- self.pos.get('selectedOrder').removePaymentline(node.line)
- }
- event.stopPropagation();
- };
-
- this.line_change_handler = function(event){
- var node = this;
- while(node && !node.classList.contains('paymentline')){
- node = node.parentNode;
- }
- if(node){
- node.line.set_amount(this.value);
- }
- };
-
- this.line_click_handler = function(event){
- var node = this;
- while(node && !node.classList.contains('paymentline')){
- node = node.parentNode;
- }
- if(node){
- self.pos.get('selectedOrder').selectPaymentline(node.line);
- }
- };
+ this.$('.next').click(function(){
+ self.validate_order();
+ });
- this.hotkey_handler = function(event){
- if(event.which === 13){
- self.validate_order();
- }else if(event.which === 27){
- self.back();
- }
- };
+ this.$('.js_invoice').click(function(){
+ self.validate_order({invoice: true});
+ });
},
show: function(){
+ this.pos.get_order().clean_empty_paymentlines();
+ this.reset_input();
+ this.render_paymentlines();
+ window.document.body.addEventListener('keydown',this.keyboard_handler);
this._super();
- var self = this;
-
- this.enable_numpad();
- this.focus_selected_line();
-
- document.body.addEventListener('keyup', this.hotkey_handler);
-
- this.add_action_button({
- label: _t('Back'),
- icon: '/point_of_sale/static/src/img/icons/png48/go-previous.png',
- click: function(){
- self.back();
- },
- });
-
- this.add_action_button({
- label: _t('Validate'),
- name: 'validation',
- icon: '/point_of_sale/static/src/img/icons/png48/validate.png',
- click: function(){
- self.validate_order();
- },
- });
-
- if( this.pos.config.iface_invoicing ){
- this.add_action_button({
- label: 'Invoice',
- name: 'invoice',
- icon: '/point_of_sale/static/src/img/icons/png48/invoice.png',
- click: function(){
- self.validate_order({invoice: true});
- },
- });
- }
-
- if( this.pos.config.iface_cashdrawer ){
- this.add_action_button({
- label: _t('Cash'),
- name: 'cashbox',
- icon: '/point_of_sale/static/src/img/open-cashbox.png',
- click: function(){
- self.pos.proxy.open_cashbox();
- },
- });
- }
-
- this.update_payment_summary();
-
},
- close: function(){
+ hide: function(){
+ window.document.body.removeEventListener('keydown',this.keyboard_handler);
this._super();
- this.disable_numpad();
- document.body.removeEventListener('keyup',this.hotkey_handler);
- },
- remove_empty_lines: function(){
- var order = this.pos.get('selectedOrder');
- var lines = order.get('paymentLines').models.slice(0);
- for(var i = 0; i < lines.length; i++){
- var line = lines[i];
- if(line.get_amount() === 0){
- order.removePaymentline(line);
- }
- }
- },
- back: function() {
- this.remove_empty_lines();
- this.pos_widget.screen_selector.set_current_screen(this.back_screen);
},
- bind_events: function() {
+ // sets up listeners to watch for order changes
+ watch_order_changes: function() {
+ var self = this;
+ var order = this.pos.get_order();
if(this.old_order){
this.old_order.unbind(null,null,this);
}
- var order = this.pos.get('selectedOrder');
- order.bind('change:selected_paymentline',this.focus_selected_line,this);
-
+ order.bind('all',function(){
+ self.order_changes();
+ });
this.old_order = order;
-
- if(this.old_paymentlines){
- this.old_paymentlines.unbind(null,null,this);
- }
- var paymentlines = order.get('paymentLines');
- paymentlines.bind('add', this.add_paymentline, this);
- paymentlines.bind('change:selected', this.rerender_paymentline, this);
- paymentlines.bind('change:amount', function(line){
- if(!line.selected && line.node){
- line.node.value = line.amount.toFixed(2);
- }
- this.update_payment_summary();
- },this);
- paymentlines.bind('remove', this.remove_paymentline, this);
- paymentlines.bind('all', this.update_payment_summary, this);
-
- this.old_paymentlines = paymentlines;
-
- if(this.old_orderlines){
- this.old_orderlines.unbind(null,null,this);
- }
- var orderlines = order.get('orderLines');
- orderlines.bind('all', this.update_payment_summary, this);
-
- this.old_orderlines = orderlines;
},
- focus_selected_line: function(){
- var line = this.pos.get('selectedOrder').selected_paymentline;
- if(line){
- var input = line.node.querySelector('input');
- if(!input){
- return;
- }
- var value = input.value;
- input.focus();
-
- if(this.numpad_state){
- this.numpad_state.reset();
- }
-
- if(Number(value) === 0){
- input.value = '';
- }else{
- input.value = value;
- input.select();
- }
- }
- },
- add_paymentline: function(line) {
- var list_container = this.el.querySelector('.payment-lines');
- list_container.appendChild(this.render_paymentline(line));
-
- if(this.numpad_state){
- this.numpad_state.reset();
- }
- },
- render_paymentline: function(line){
- var el_html = openerp.qweb.render('Paymentline',{widget: this, line: line});
- el_html = _.str.trim(el_html);
-
- var el_node = document.createElement('tbody');
- el_node.innerHTML = el_html;
- el_node = el_node.childNodes[0];
- el_node.line = line;
- el_node.querySelector('.paymentline-delete')
- .addEventListener('click', this.line_delete_handler);
- el_node.addEventListener('click', this.line_click_handler);
- el_node.querySelector('input')
- .addEventListener('keyup', this.line_change_handler);
-
- line.node = el_node;
-
- return el_node;
- },
- rerender_paymentline: function(line){
- var old_node = line.node;
- var new_node = this.render_paymentline(line);
-
- old_node.parentNode.replaceChild(new_node,old_node);
- },
- remove_paymentline: function(line){
- line.node.parentNode.removeChild(line.node);
- line.node = undefined;
- },
- renderElement: function(){
- this._super();
-
- var paymentlines = this.pos.get('selectedOrder').get('paymentLines').models;
- var list_container = this.el.querySelector('.payment-lines');
-
- for(var i = 0; i < paymentlines.length; i++){
- list_container.appendChild(this.render_paymentline(paymentlines[i]));
- }
-
- this.update_payment_summary();
- },
- update_payment_summary: function() {
- var currentOrder = this.pos.get('selectedOrder');
- var paidTotal = currentOrder.getPaidTotal();
- var dueTotal = currentOrder.getTotalTaxIncluded();
- var remaining = dueTotal > paidTotal ? dueTotal - paidTotal : 0;
- var change = paidTotal > dueTotal ? paidTotal - dueTotal : 0;
-
- this.$('.payment-due-total').html(this.format_currency(dueTotal));
- this.$('.payment-paid-total').html(this.format_currency(paidTotal));
- this.$('.payment-remaining').html(this.format_currency(remaining));
- this.$('.payment-change').html(this.format_currency(change));
- if(currentOrder.selected_orderline === undefined){
- remaining = 1; // What is this ?
- }
-
- if(this.pos_widget.action_bar){
- this.pos_widget.action_bar.set_button_disabled('validation', !this.is_paid());
- this.pos_widget.action_bar.set_button_disabled('invoice', !this.is_paid());
+ // called when the order is changed, used to show if
+ // the order is paid or not
+ order_changes: function(){
+ var order = this.pos.get_order();
+ console.log('change!');
+ if (order.isPaid()) {
+ self.$('.next').addClass('highlight');
+ }else{
+ self.$('.next').removeClass('highlight');
}
},
- is_paid: function(){
- var currentOrder = this.pos.get('selectedOrder');
- return (currentOrder.getTotalTaxIncluded() < 0.000001
- || currentOrder.getPaidTotal() + 0.000001 >= currentOrder.getTotalTaxIncluded());
-
- },
+ // Check if the order is paid, then sends it to the backend,
+ // and complete the sale process
validate_order: function(options) {
var self = this;
options = options || {};
- var currentOrder = this.pos.get('selectedOrder');
+ var order = this.pos.get_order();
- if(!this.is_paid()){
+ if (!order.isPaid() || this.invoicing) {
return;
}
- if( this.pos.config.iface_cashdrawer
- && this.pos.get('selectedOrder').get('paymentLines').find( function(pl){
- return pl.cashregister.journal.type === 'cash';
- })){
+ if (order.isPaidWithCash() && this.pos.config.iface_cashdrawer) {
this.pos.proxy.open_cashbox();
}
- if(options.invoice){
- // deactivate the validation button while we try to send the order
- this.pos_widget.action_bar.set_button_disabled('validation',true);
- this.pos_widget.action_bar.set_button_disabled('invoice',true);
-
- var invoiced = this.pos.push_and_invoice_order(currentOrder);
+ if (options.invoice) {
+ var invoiced = this.pos.push_and_invoice_order(order);
+ this.invoicing = true;
invoiced.fail(function(error){
- if(error === 'error-no-client'){
+ self.invoicing = false;
+ if (error === 'error-no-client') {
self.pos_widget.screen_selector.show_popup('error-no-client');
- }else{
+ } else {
self.pos_widget.screen_selector.show_popup('error-invoice-transfer');
}
- self.pos_widget.action_bar.set_button_disabled('validation',false);
- self.pos_widget.action_bar.set_button_disabled('invoice',false);
});
invoiced.done(function(){
- self.pos_widget.action_bar.set_button_disabled('validation',false);
- self.pos_widget.action_bar.set_button_disabled('invoice',false);
- self.pos.get('selectedOrder').destroy();
+ self.invoicing = false;
+ order.finalize();
});
-
- }else{
- this.pos.push_order(currentOrder)
- if(this.pos.config.iface_print_via_proxy){
+ } else {
+ this.pos.push_order(order)
+ if (this.pos.config.iface_print_via_proxy) {
var receipt = currentOrder.export_for_printing();
this.pos.proxy.print_receipt(QWeb.render('XmlReceipt',{
receipt: receipt, widget: self,
}));
- this.pos.get('selectedOrder').destroy(); //finish order and go back to scan screen
- }else{
+ order.finalize(); //finish order and go back to scan screen
+ } else {
this.pos_widget.screen_selector.set_current_screen(this.next_screen);
}
}
-
- // hide onscreen (iOS) keyboard
- setTimeout(function(){
- document.activeElement.blur();
- $("input").blur();
- },250);
- },
- enable_numpad: function(){
- this.disable_numpad(); //ensure we don't register the callbacks twice
- this.numpad_state = this.pos_widget.numpad.state;
- if(this.numpad_state){
- this.numpad_state.reset();
- this.numpad_state.changeMode('payment');
- this.numpad_state.bind('set_value', this.set_value, this);
- this.numpad_state.bind('change:mode', this.set_mode_back_to_payment, this);
- }
-
- },
- disable_numpad: function(){
- if(this.numpad_state){
- this.numpad_state.unbind('set_value', this.set_value);
- this.numpad_state.unbind('change:mode',this.set_mode_back_to_payment);
- }
- },
- set_mode_back_to_payment: function() {
- this.numpad_state.set({mode: 'payment'});
- },
- set_value: function(val) {
- var selected_line =this.pos.get('selectedOrder').selected_paymentline;
- if(selected_line){
- selected_line.set_amount(val);
- selected_line.node.querySelector('input').value = selected_line.amount.toFixed(2);
- }
},
});
+
}
<t t-foreach='paymentlines' t-as='line'>
<t t-if='line.selected'>
<tr class='paymentline selected'>
- <td> <t t-esc='widget.format_currency_no_symbol(order.getDueLeft(line))' /> </td>
- <td class='edit'> <t t-esc='line.get_amount()' /> </td>
- <td> <t t-esc='widget.format_currency_no_symbol(order.getChange(line))' /> </td>
- <td> <t t-esc='line.name' /> </td>
+ <td class='col-due'> <t t-esc='widget.format_currency_no_symbol(order.getDueLeft(line))' /> </td>
+ <td class='col-tendered edit'> <t t-esc='line.get_amount()' /> </td>
+ <t t-if='order.getChange(line)'>
+ <td class='col-change highlight' > <t t-esc='widget.format_currency_no_symbol(order.getChange(line))' /> </td>
+ </t>
+ <t t-if='!order.getChange(line)'>
+ <td class='col-change' ></td>
+ </t>
+
+ <td class='col-name' > <t t-esc='line.name' /> </td>
<td class='delete-button' t-att-data-cid='line.cid'> <i class='fa fa-times-circle' /> </td>
</tr>
</t>
<t t-if='!line.selected'>
- <tr class='paymentline'>
- <td> <t t-esc='widget.format_currency_no_symbol(order.getDueLeft(line))' /> </td>
- <td> <t t-esc='widget.format_currency_no_symbol(line.get_amount())' /> </td>
- <td> <t t-esc='widget.format_currency_no_symbol(order.getChange(line))' /> </td>
- <td> <t t-esc='line.name' /> </td>
+ <tr class='paymentline' t-att-data-cid='line.cid'>
+ <td class='col-due'> <t t-esc='widget.format_currency_no_symbol(order.getDueLeft(line))' /> </td>
+ <td class='col-tendered'> <t t-esc='widget.format_currency_no_symbol(line.get_amount())' /> </td>
+ <td class='col-change'>
+ <t t-if='order.getChange(line)'>
+ <t t-esc='widget.format_currency_no_symbol(order.getChange(line))' />
+ </t>
+ </td>
+ <td class='col-name'> <t t-esc='line.name' /> </td>
<td class='delete-button' t-att-data-cid='line.cid'> <i class='fa fa-times-circle' /> </td>
</tr>
</t>
<t t-name="PaymentScreen-Numpad">
<div class="numpad">
- <button class="input-button number-char">1</button>
- <button class="input-button number-char">2</button>
- <button class="input-button number-char">3</button>
- <button class="mode-button" data-action='currency' data-value='5' >5€</button>
+ <button class="input-button number-char" data-action='1'>1</button>
+ <button class="input-button number-char" data-action='2'>2</button>
+ <button class="input-button number-char" data-action='3'>3</button>
+ <button class="mode-button" data-action='+5'>+5</button>
<br />
- <button class="input-button number-char">4</button>
- <button class="input-button number-char">5</button>
- <button class="input-button number-char">6</button>
- <button class="mode-button" data-action='currency' data-value='10' >10€</button>
+ <button class="input-button number-char" data-action='4'>4</button>
+ <button class="input-button number-char" data-action='5'>5</button>
+ <button class="input-button number-char" data-action='6'>6</button>
+ <button class="mode-button" data-action='+10'>+10</button>
<br />
- <button class="input-button number-char">7</button>
- <button class="input-button number-char">8</button>
- <button class="input-button number-char">9</button>
- <button class="mode-button" data-action='currency' data-value='20' >20€</button>
+ <button class="input-button number-char" data-action='7'>7</button>
+ <button class="input-button number-char" data-action='8'>8</button>
+ <button class="input-button number-char" data-action='9'>9</button>
+ <button class="mode-button" data-action='+20'>+20</button>
<br />
- <button class="input-button numpad-char" data-action='clear' >C</button>
- <button class="input-button number-char">0</button>
- <button class="input-button number-char">.</button>
- <button class="input-button numpad-backspace" data-action='backspace' >
+ <button class="input-button numpad-char" data-action='CLEAR' >C</button>
+ <button class="input-button number-char" data-action='0'>0</button>
+ <button class="input-button number-char" data-action='.'>.</button>
+ <button class="input-button numpad-backspace" data-action='BACKSPACE' >
<img src="/point_of_sale/static/src/img/backspace.png" width="24" height="21" />
</button>
<br />
</div>
</t>
- <t t-name="NewPaymentScreenWidget">
+ <t t-name="PaymentScreenWidget">
<div class='payment-screen screen'>
<div class='screen-content'>
<div class='top-content'>
</t>
- <t t-name="PaymentScreenWidget">
- <div class="payment-screen screen touch-scrollable">
- <div class="pos-payment-container">
- <div class='payment-due-total'></div>
- <div class='payment-lines'></div>
- <div class='payment-info'>
- <div class="infoline">
- <span class='left-block'>
- Paid:
- </span>
- <span class="right-block payment-paid-total"></span>
- </div>
- <div class="infoline">
- <span class='left-block'>
- Remaining:
- </span>
- <span class="right-block payment-remaining"></span>
- </div>
- <div class="infoline bigger" >
- <span class='left-block'>
- Change:
- </span>
- <span class="right-block payment-change"></span>
- </div>
- </div>
- </div>
- </div>
- </t>
-
<t t-name="ReceiptScreenWidget">
<div class="receipt-screen screen touch-scrollable" >
<div class="pos-step-container">