odoo/addons/point_of_sale/static/src/js/screens.js

1010 lines
39 KiB
JavaScript

// this file contains the screens definitions. Screens are the
// content of the right pane of the pos, containing the main functionalities.
// screens are contained in the PosWidget, in pos_widget.js
// all screens are present in the dom at all time, but only one is shown at the
// same time.
//
// transition between screens is made possible by the use of the screen_selector,
// which is responsible of hiding and showing the screens, as well as maintaining
// the state of the screens between different orders.
//
// all screens inherit from ScreenWidget. the only addition from the base widgets
// are show() and hide() which shows and hides the screen but are also used to
// bind and unbind actions on widgets and devices. The screen_selector guarantees
// that only one screen is shown at the same time and that show() is called after all
// hide()s
function openerp_pos_screens(instance, module){ //module is instance.point_of_sale
var QWeb = instance.web.qweb,
_t = instance.web._t;
module.ScreenSelector = instance.web.Class.extend({
init: function(options){
this.pos = options.pos;
this.screen_set = options.screen_set || {};
this.popup_set = options.popup_set || {};
this.default_client_screen = options.default_client_screen;
this.default_cashier_screen = options.default_cashier_screen;
this.current_popup = null;
this.current_mode = options.default_mode || 'client';
this.current_screen = null;
for(screen_name in this.screen_set){
this.screen_set[screen_name].hide();
}
for(popup_name in this.popup_set){
this.popup_set[popup_name].hide();
}
this.selected_order = this.pos.get('selectedOrder');
this.selected_order.set_screen_data({
client_screen: this.default_client_screen,
cashier_screen: this.default_cashier_screen,
});
this.pos.bind('change:selectedOrder', this.load_saved_screen, this);
},
add_screen: function(screen_name, screen){
screen.hide();
this.screen_set[screen_name] = screen;
return this;
},
show_popup: function(name){
if(this.current_popup){
this.close_popup();
}
this.current_popup = this.popup_set[name];
this.current_popup.show();
},
close_popup: function(){
if(this.current_popup){
this.current_popup.close();
this.current_popup.hide();
this.current_popup = null;
}
},
load_saved_screen: function(){
this.close_popup();
var selectedOrder = this.pos.get('selectedOrder');
if(this.current_mode === 'client'){
this.set_current_screen(selectedOrder.get_screen_data('client_screen') || this.default_client_screen,null,'refresh');
}else if(this.current_mode === 'cashier'){
this.set_current_screen(selectedOrder.get_screen_data('cashier_screen') || this.default_cashier_screen,null,'refresh');
}
this.selected_order = selectedOrder;
},
set_user_mode: function(user_mode){
if(user_mode !== this.current_mode){
this.close_popup();
this.current_mode = user_mode;
this.load_saved_screen();
}
},
get_user_mode: function(){
return this.current_mode;
},
set_current_screen: function(screen_name,params,refresh){
var screen = this.screen_set[screen_name];
if(!screen){
console.error("ERROR: set_current_screen("+screen_name+") : screen not found");
}
this.close_popup();
var selectedOrder = this.pos.get('selectedOrder');
if(this.current_mode === 'client'){
selectedOrder.set_screen_data('client_screen',screen_name);
if(params){
selectedOrder.set_screen_data('client_screen_params',params);
}
}else{
selectedOrder.set_screen_data('cashier_screen',screen_name);
if(params){
selectedOrder.set_screen_data('cashier_screen_params',params);
}
}
if(screen && (refresh || screen !== this.current_screen)){
if(this.current_screen){
this.current_screen.close();
this.current_screen.hide();
}
this.current_screen = screen;
this.current_screen.show();
}
},
get_current_screen_param: function(param){
var selected_order = this.pos.get('selectedOrder');
if(this.current_mode === 'client'){
var params = selected_order.get_screen_data('client_screen_params');
}else{
var params = selected_order.get_screen_data('cashier_screen_params');
}
if(params){
return params[param];
}else{
return undefined;
}
},
set_default_screen: function(){
this.set_current_screen(this.current_mode === 'client' ? this.default_client_screen : this.default_cashier_screen);
},
});
module.ScreenWidget = module.PosBaseWidget.extend({
show_numpad: true,
show_leftpane: true,
init: function(parent,options){
this._super(parent,options);
this.hidden = false;
},
help_button_action: function(){
this.pos_widget.screen_selector.show_popup('help');
},
barcode_product_screen: 'products', //if defined, this screen will be loaded when a product is scanned
barcode_product_error_popup: 'error-product', //if defined, this popup will be loaded when there's an error in the popup
// what happens when a product is scanned :
// it will add the product to the order and go to barcode_product_screen. Or show barcode_product_error_popup if
// there's an error.
barcode_product_action: function(ean){
var self = this;
if(self.pos.scan_product(ean)){
self.pos.proxy.scan_item_success(ean);
if(self.barcode_product_screen){
self.pos_widget.screen_selector.set_current_screen(self.barcode_product_screen);
}
}else{
self.pos.proxy.scan_item_error_unrecognized(ean);
if(self.barcode_product_error_popup && self.pos_widget.screen_selector.get_user_mode() !== 'cashier'){
self.pos_widget.screen_selector.show_popup(self.barcode_product_error_popup);
}
}
},
// what happens when a cashier id barcode is scanned.
// the default behavior is the following :
// - if there's a user with a matching ean, put it as the active 'cashier', go to cashier mode, and return true
// - else : do nothing and return false. You probably want to extend this to show and appropriate error popup...
barcode_cashier_action: function(ean){
var users = this.pos.get('user_list');
for(var i = 0, len = users.length; i < len; i++){
if(users[i].ean13 === ean.ean){
this.pos.set('cashier',users[i]);
this.pos_widget.username.refresh();
this.pos.proxy.cashier_mode_activated();
this.pos_widget.screen_selector.set_user_mode('cashier');
return true;
}
}
this.pos.proxy.scan_item_error_unrecognized(ean);
return false;
},
// what happens when a client id barcode is scanned.
// the default behavior is the following :
// - if there's a user with a matching ean, put it as the active 'client' and return true
// - else : return false.
barcode_client_action: function(ean){
var partners = this.pos.get('partner_list');
for(var i = 0, len = partners.length; i < len; i++){
if(partners[i].ean13 === ean.ean){
this.pos.get('selectedOrder').set_client(partners[i]);
this.pos_widget.username.refresh();
this.pos.proxy.scan_item_success(ean);
return true;
}
}
this.pos.proxy.scan_item_error_unrecognized(ean);
return false;
//TODO start the transaction
},
// what happens when a discount barcode is scanned : the default behavior
// is to set the discount on the last order.
barcode_discount_action: function(ean){
this.pos.proxy.scan_item_success(ean);
var last_orderline = this.pos.get('selectedOrder').getLastOrderline();
if(last_orderline){
last_orderline.set_discount(ean.value)
}
},
// shows an action bar on the screen. The actionbar is automatically shown when you add a button
// with add_action_button()
show_action_bar: function(){
this.pos_widget.action_bar.show();
this.$el.css({'bottom':'105px'});
},
// hides the action bar. The actionbar is automatically hidden when it is empty
hide_action_bar: function(){
this.pos_widget.action_bar.hide();
this.$el.css({'bottom':'0px'});
},
// adds a new button to the action bar. The button definition takes three parameters, all optional :
// - label: the text below the button
// - icon: a small icon that will be shown
// - click: a callback that will be executed when the button is clicked.
// the method returns a reference to the button widget, and automatically show the actionbar.
add_action_button: function(button_def){
this.show_action_bar();
return this.pos_widget.action_bar.add_new_button(button_def);
},
// this method shows the screen and sets up all the widget related to this screen. Extend this method
// if you want to alter the behavior of the screen.
show: function(){
var self = this;
this.hidden = false;
if(this.$el){
this.$el.show();
}
if(this.pos_widget.action_bar.get_button_count() > 0){
this.show_action_bar();
}else{
this.hide_action_bar();
}
// we add the help button by default. we do this because the buttons are cleared on each refresh so that
// the button stay local to each screen
this.pos_widget.left_action_bar.add_new_button({
label: _t('Help'),
icon: '/point_of_sale/static/src/img/icons/png48/help.png',
click: function(){ self.help_button_action(); },
});
var self = this;
var cashier_mode = this.pos_widget.screen_selector.get_user_mode() === 'cashier';
this.pos_widget.set_numpad_visible(this.show_numpad && cashier_mode);
this.pos_widget.set_leftpane_visible(this.show_leftpane);
this.pos_widget.set_left_action_bar_visible(this.show_leftpane && !cashier_mode);
this.pos_widget.set_cashier_controls_visible(cashier_mode);
if(cashier_mode && this.pos.iface_self_checkout){
this.pos_widget.client_button.show();
}else{
this.pos_widget.client_button.hide();
}
if(cashier_mode){
this.pos_widget.close_button.show();
}else{
this.pos_widget.close_button.hide();
}
this.pos_widget.username.set_user_mode(this.pos_widget.screen_selector.get_user_mode());
this.pos.barcode_reader.set_action_callback({
'cashier': self.barcode_cashier_action ? function(ean){ self.barcode_cashier_action(ean); } : undefined ,
'product': self.barcode_product_action ? function(ean){ self.barcode_product_action(ean); } : undefined ,
'client' : self.barcode_client_action ? function(ean){ self.barcode_client_action(ean); } : undefined ,
'discount': self.barcode_discount_action ? function(ean){ self.barcode_discount_action(ean); } : undefined,
});
},
// this method is called when the screen is closed to make place for a new screen. this is a good place
// to put your cleanup stuff as it is guaranteed that for each show() there is one and only one close()
close: function(){
if(this.pos.barcode_reader){
this.pos.barcode_reader.reset_action_callbacks();
}
this.pos_widget.action_bar.destroy_buttons();
this.pos_widget.left_action_bar.destroy_buttons();
},
// this methods hides the screen. It's not a good place to put your cleanup stuff as it is called on the
// POS initialization.
hide: function(){
this.hidden = true;
if(this.$el){
this.$el.hide();
}
},
// we need this because some screens re-render themselves when they are hidden
// (due to some events, or magic, or both...) we must make sure they remain hidden.
// the good solution would probably be to make them not re-render themselves when they
// are hidden.
renderElement: function(){
this._super();
if(this.hidden){
if(this.$el){
this.$el.hide();
}
}
},
});
module.PopUpWidget = module.PosBaseWidget.extend({
show: function(){
if(this.$el){
this.$el.show();
}
},
/* called before hide, when a popup is closed */
close: function(){
},
/* hides the popup. keep in mind that this is called in the initialization pass of the
* pos instantiation, so you don't want to do anything fancy in here */
hide: function(){
if(this.$el){
this.$el.hide();
}
},
});
module.HelpPopupWidget = module.PopUpWidget.extend({
template:'HelpPopupWidget',
show: function(){
this._super();
this.pos.proxy.help_needed();
var self = this;
this.$el.find('.button').off('click').click(function(){
self.pos_widget.screen_selector.close_popup();
});
},
close:function(){
this.pos.proxy.help_canceled();
},
});
module.ChooseReceiptPopupWidget = module.PopUpWidget.extend({
template:'ChooseReceiptPopupWidget',
show: function(){
this._super();
this.renderElement();
var self = this;
var currentOrder = self.pos.get('selectedOrder');
this.$('.button.receipt').off('click').click(function(){
currentOrder.set_receipt_type('receipt');
self.pos_widget.screen_selector.set_current_screen('products');
});
this.$('.button.invoice').off('click').click(function(){
currentOrder.set_receipt_type('invoice');
self.pos_widget.screen_selector.set_current_screen('products');
});
},
get_client_name: function(){
var client = this.pos.get('selectedOrder').get_client();
if( client ){
return client.name;
}else{
return '';
}
},
});
module.ErrorPopupWidget = module.PopUpWidget.extend({
template:'ErrorPopupWidget',
show: function(){
var self = this;
this._super();
this.pos.proxy.help_needed();
this.pos.proxy.scan_item_error_unrecognized();
this.pos.barcode_reader.save_callbacks();
this.pos.barcode_reader.reset_action_callbacks();
this.pos.barcode_reader.set_action_callback({
'cashier': function(ean){
clearInterval(this.intervalID);
self.pos.proxy.cashier_mode_activated();
self.pos_widget.screen_selector.set_user_mode('cashier');
},
});
this.$('.footer .button').off('click').click(function(){
self.pos_widget.screen_selector.close_popup();
});
},
close:function(){
this._super();
this.pos.proxy.help_canceled();
this.pos.barcode_reader.restore_callbacks();
},
});
module.ProductErrorPopupWidget = module.ErrorPopupWidget.extend({
template:'ProductErrorPopupWidget',
});
module.ErrorSessionPopupWidget = module.ErrorPopupWidget.extend({
template:'ErrorSessionPopupWidget',
});
module.ErrorNegativePricePopupWidget = module.ErrorPopupWidget.extend({
template:'ErrorNegativePricePopupWidget',
});
module.ScaleInviteScreenWidget = module.ScreenWidget.extend({
template:'ScaleInviteScreenWidget',
next_screen:'scale',
previous_screen:'products',
show: function(){
this._super();
var self = this;
self.pos.proxy.weighting_start();
this.intervalID = setInterval(function(){
var weight = self.pos.proxy.weighting_read_kg();
if(weight > 0.001){
clearInterval(this.intervalID);
self.pos_widget.screen_selector.set_current_screen(self.next_screen);
}
},500);
this.add_action_button({
label: _t('Back'),
icon: '/point_of_sale/static/src/img/icons/png48/go-previous.png',
click: function(){
clearInterval(this.intervalID);
self.pos_widget.screen_selector.set_current_screen(self.previous_screen);
}
});
},
close: function(){
this._super();
clearInterval(this.intervalID);
this.pos.proxy.weighting_end();
},
});
module.ScaleScreenWidget = module.ScreenWidget.extend({
template:'ScaleScreenWidget',
next_screen: 'products',
previous_screen: 'products',
show: function(){
this._super();
this.renderElement();
var self = this;
this.add_action_button({
label: _t('Back'),
icon: '/point_of_sale/static/src/img/icons/png48/go-previous.png',
click: function(){
self.pos_widget.screen_selector.set_current_screen(self.previous_screen);
}
});
this.validate_button = this.add_action_button({
label: _t('Validate'),
icon: '/point_of_sale/static/src/img/icons/png48/validate.png',
click: function(){
self.order_product();
self.pos_widget.screen_selector.set_current_screen(self.next_screen);
},
});
this.pos.proxy.weighting_start();
this.intervalID = setInterval(function(){
var weight = self.pos.proxy.weighting_read_kg();
if(weight != self.weight){
self.weight = weight;
self.renderElement();
}
},200);
},
renderElement: function(){
var self = this;
this._super();
this.$('.product-picture').click(function(){
self.order_product();
self.pos_widget.screen_selector.set_current_screen(self.next_screen);
});
},
get_product: function(){
var ss = this.pos_widget.screen_selector;
if(ss){
return ss.get_current_screen_param('product');
}else{
return undefined;
}
},
order_product: function(){
var weight = this.pos.proxy.weighting_read_kg();
this.pos.get('selectedOrder').addProduct(this.get_product(),{ quantity:weight });
},
get_product_name: function(){
var product = this.get_product();
return (product ? product.get('name') : undefined) || 'Unnamed Product';
},
get_product_price: function(){
var product = this.get_product();
return (product ? product.get('price') : 0) || 0;
},
get_product_weight: function(){
return this.weight || 0;
},
close: function(){
this._super();
clearInterval(this.intervalID);
this.pos.proxy.weighting_end();
},
});
// the JobQueue schedules a sequence of 'jobs'. each job is
// a function returning a deferred. the queue waits for each job to finish
// before launching the next. Each job can also be scheduled with a delay.
// the queue jobqueue is used to prevent parallel requests to the payment terminal.
module.JobQueue = function(){
var queue = [];
var running = false;
var run = function(){
if(queue.length > 0){
running = true;
var job = queue.shift();
setTimeout(function(){
var def = job.fun();
if(def){
def.done(run);
}else{
run();
}
},job.delay || 0);
}else{
running = false;
}
};
// adds a job to the schedule.
this.schedule = function(fun, delay){
queue.push({fun:fun, delay:delay});
if(!running){
run();
}
}
// remove all jobs from the schedule
this.clear = function(){
queue = [];
};
};
module.ClientPaymentScreenWidget = module.ScreenWidget.extend({
template:'ClientPaymentScreenWidget',
next_screen: 'welcome',
previous_screen: 'products',
show: function(){
this._super();
var self = this;
this.queue = new module.JobQueue();
this.canceled = false;
this.paid = false;
// initiates the connection to the payment terminal and starts the update requests
this.start = function(){
var def = new $.Deferred();
self.pos.proxy.payment_request(self.pos.get('selectedOrder').getDueLeft())
.done(function(ack){
if(ack === 'ok'){
self.queue.schedule(self.update);
}else if(ack.indexOf('error') === 0){
console.error('cannot make payment. TODO');
}else{
console.error('unknown payment request return value:',ack);
}
def.resolve();
});
return def;
};
// gets updated status from the payment terminal and performs the appropriate consequences
this.update = function(){
var def = new $.Deferred();
if(self.canceled){
return def.resolve();
}
self.pos.proxy.payment_status()
.done(function(status){
if(status.status === 'paid'){
var currentOrder = self.pos.get('selectedOrder');
//we get the first cashregister marked as self-checkout
var selfCheckoutRegisters = [];
for(var i = 0; i < self.pos.get('cashRegisters').models.length; i++){
var cashregister = self.pos.get('cashRegisters').models[i];
if(cashregister.self_checkout_payment_method){
selfCheckoutRegisters.push(cashregister);
}
}
var cashregister = selfCheckoutRegisters[0] || self.pos.get('cashRegisters').models[0];
currentOrder.addPaymentLine(cashregister);
self.pos.push_order(currentOrder.exportAsJSON())
currentOrder.destroy();
self.pos.proxy.transaction_end();
self.pos_widget.screen_selector.set_current_screen(self.next_screen);
self.paid = true;
}else if(status.status.indexOf('error') === 0){
console.error('error in payment request. TODO');
}else if(status.status === 'waiting'){
self.queue.schedule(self.update,200);
}else{
console.error('unknown status value:',status.status);
}
def.resolve();
});
return def;
}
// cancels a payment.
this.cancel = function(){
if(!self.paid && !self.canceled){
self.canceled = true;
self.pos.proxy.payment_cancel();
self.pos_widget.screen_selector.set_current_screen(self.previous_screen);
self.queue.clear();
}
return (new $.Deferred()).resolve();
}
if(this.pos.get('selectedOrder').getDueLeft() <= 0){
this.pos_widget.screen_selector.show_popup('error-negative-price');
}else{
this.queue.schedule(this.start);
}
this.add_action_button({
label: _t('Back'),
icon: '/point_of_sale/static/src/img/icons/png48/go-previous.png',
click: function(){
self.queue.schedule(self.cancel);
}
});
},
close: function(){
if(this.queue){
this.queue.schedule(this.cancel);
}
//TODO CANCEL
this._super();
},
});
module.WelcomeScreenWidget = module.ScreenWidget.extend({
template:'WelcomeScreenWidget',
next_screen: 'products',
show_numpad: false,
show_leftpane: false,
barcode_product_action: function(ean){
this.pos.proxy.transaction_start();
this._super(ean);
},
barcode_client_action: function(ean){
this.pos.proxy.transaction_start();
this._super(ean);
$('.goodbye-message').hide();
this.pos_widget.screen_selector.show_popup('choose-receipt');
},
show: function(){
this._super();
var self = this;
this.add_action_button({
label: _t('Help'),
icon: '/point_of_sale/static/src/img/icons/png48/help.png',
click: function(){
$('.goodbye-message').css({opacity:1}).hide();
self.help_button_action();
},
});
$('.goodbye-message').css({opacity:1}).show();
setTimeout(function(){
$('.goodbye-message').animate({opacity:0},500,'swing',function(){$('.goodbye-message').hide();});
},5000);
},
});
module.ProductScreenWidget = module.ScreenWidget.extend({
template:'ProductScreenWidget',
scale_screen: 'scale_invite',
client_next_screen: 'client_payment',
show_numpad: true,
show_leftpane: true,
start: function(){ //FIXME this should work as renderElement... but then the categories aren't properly set. explore why
var self = this;
this.product_categories_widget = new module.ProductCategoriesWidget(this,{});
this.product_categories_widget.replace($('.placeholder-ProductCategoriesWidget'));
this.product_list_widget = new module.ProductListWidget(this,{
click_product_action: function(product){
if(product.get('to_weight') && self.pos.iface_electronic_scale){
self.pos_widget.screen_selector.set_current_screen(self.scale_screen, {product: product});
}else{
self.pos.get('selectedOrder').addProduct(product);
}
},
});
this.product_list_widget.replace($('.placeholder-ProductListWidget'));
},
show: function(){
this._super();
var self = this;
this.product_categories_widget.reset_category();
this.pos_widget.order_widget.set_numpad_state(this.pos_widget.numpad.state);
if(this.pos_widget.screen_selector.current_mode === 'client'){
this.add_action_button({
label: _t('Pay'),
icon: '/point_of_sale/static/src/img/icons/png48/go-next.png',
click: function(){
self.pos_widget.screen_selector.set_current_screen(self.client_next_screen);
}
});
}
},
close: function(){
this._super();
this.pos_widget.order_widget.set_numpad_state(null);
this.pos_widget.payment_screen.set_numpad_state(null);
if(this.pos.iface_vkeyboard && this.pos_widget.onscreen_keyboard){
this.pos_widget.onscreen_keyboard.hide();
}
},
});
module.ReceiptScreenWidget = module.ScreenWidget.extend({
template: 'ReceiptScreenWidget',
show_numpad: true,
show_leftpane: true,
init: function(parent, options) {
this._super(parent,options);
this.model = options.model;
this.user = this.pos.get('user');
this.company = this.pos.get('company');
this.shop_obj = this.pos.get('shop');
},
renderElement: function() {
this._super();
this.pos.bind('change:selectedOrder', this.change_selected_order, this);
this.change_selected_order();
},
show: function(){
this._super();
var self = this;
this.add_action_button({
label: _t('Print'),
icon: '/point_of_sale/static/src/img/icons/png48/printer.png',
click: function(){ self.print(); },
});
this.add_action_button({
label: _t('Next Order'),
icon: '/point_of_sale/static/src/img/icons/png48/go-next.png',
click: function() { self.finishOrder(); },
});
this.print();
},
print: function() {
window.print();
},
finishOrder: function() {
this.pos.get('selectedOrder').destroy();
},
change_selected_order: function() {
if (this.currentOrderLines)
this.currentOrderLines.unbind();
this.currentOrderLines = (this.pos.get('selectedOrder')).get('orderLines');
this.currentOrderLines.bind('add', this.refresh, this);
this.currentOrderLines.bind('change', this.refresh, this);
this.currentOrderLines.bind('remove', this.refresh, this);
if (this.currentPaymentLines)
this.currentPaymentLines.unbind();
this.currentPaymentLines = (this.pos.get('selectedOrder')).get('paymentLines');
this.currentPaymentLines.bind('all', this.refresh, this);
this.refresh();
},
refresh: function() {
this.currentOrder = this.pos.get('selectedOrder');
$('.pos-receipt-container', this.$el).html(QWeb.render('PosTicket',{widget:this}));
},
});
module.PaymentScreenWidget = module.ScreenWidget.extend({
template: 'PaymentScreenWidget',
back_screen: 'products',
next_screen: 'receipt',
init: function(parent, options) {
this._super(parent,options);
this.model = options.model;
this.pos.bind('change:selectedOrder', this.change_selected_order, this);
this.bindPaymentLineEvents();
this.bind_orderline_events();
this.paymentlinewidgets = [];
this.focusedLine = null;
},
show: function(){
this._super();
var self = this;
if(this.pos.iface_cashdrawer){
this.pos.proxy.open_cashbox();
}
this.set_numpad_state(this.pos_widget.numpad.state);
this.back_button = this.add_action_button({
label: _t('Back'),
icon: '/point_of_sale/static/src/img/icons/png48/go-previous.png',
click: function(){
self.pos_widget.screen_selector.set_current_screen(self.back_screen);
},
});
this.validate_button = this.add_action_button({
label: _t('Validate'),
name: 'validation',
icon: '/point_of_sale/static/src/img/icons/png48/validate.png',
click: function(){
self.validateCurrentOrder();
},
});
this.updatePaymentSummary();
this.line_refocus();
},
close: function(){
this._super();
this.pos_widget.order_widget.set_numpad_state(null);
this.pos_widget.payment_screen.set_numpad_state(null);
},
back: function() {
this.pos_widget.screen_selector.set_current_screen(self.back_screen);
},
validateCurrentOrder: function() {
var currentOrder = this.pos.get('selectedOrder');
this.pos.push_order(currentOrder.exportAsJSON())
if(this.pos.iface_print_via_proxy){
this.pos.proxy.print_receipt(currentOrder.export_for_printing());
this.pos.get('selectedOrder').destroy(); //finish order and go back to scan screen
}else{
this.pos_widget.screen_selector.set_current_screen(this.next_screen);
}
},
bindPaymentLineEvents: function() {
this.currentPaymentLines = (this.pos.get('selectedOrder')).get('paymentLines');
this.currentPaymentLines.bind('add', this.addPaymentLine, this);
this.currentPaymentLines.bind('remove', this.renderElement, this);
this.currentPaymentLines.bind('all', this.updatePaymentSummary, this);
},
bind_orderline_events: function() {
this.currentOrderLines = (this.pos.get('selectedOrder')).get('orderLines');
this.currentOrderLines.bind('all', this.updatePaymentSummary, this);
},
change_selected_order: function() {
this.currentPaymentLines.unbind();
this.bindPaymentLineEvents();
this.currentOrderLines.unbind();
this.bind_orderline_events();
this.renderElement();
},
line_refocus: function(lineWidget){
if(lineWidget){
if(this.focusedLine !== lineWidget){
this.focusedLine = lineWidget;
}
}
if(this.focusedLine){
this.focusedLine.focus();
}
},
addPaymentLine: function(newPaymentLine) {
var self = this;
var l = new module.PaymentlineWidget(this, {
payment_line: newPaymentLine,
});
l.on('delete_payment_line', self, function(r) {
self.deleteLine(r);
});
l.appendTo(this.$('#paymentlines'));
this.paymentlinewidgets.push(l);
if(this.numpadState){
this.numpadState.resetValue();
}
this.line_refocus(l);
},
renderElement: function() {
this._super();
this.$('#paymentlines').empty();
for(var i = 0, len = this.paymentlinewidgets.length; i < len; i++){
this.paymentlinewidgets[i].destroy();
}
this.paymentlinewidgets = [];
this.currentPaymentLines.each(_.bind( function(paymentLine) {
this.addPaymentLine(paymentLine);
}, this));
this.updatePaymentSummary();
},
deleteLine: function(lineWidget) {
this.currentPaymentLines.remove([lineWidget.payment_line]);
lineWidget.destroy();
},
updatePaymentSummary: 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', remaining > 0.000001);
}
},
set_numpad_state: function(numpadState) {
if (this.numpadState) {
this.numpadState.unbind('set_value', this.set_value);
this.numpadState.unbind('change:mode', this.setNumpadMode);
}
this.numpadState = numpadState;
if (this.numpadState) {
this.numpadState.bind('set_value', this.set_value, this);
this.numpadState.bind('change:mode', this.setNumpadMode, this);
this.numpadState.reset();
this.setNumpadMode();
}
},
setNumpadMode: function() {
this.numpadState.set({mode: 'payment'});
},
set_value: function(val) {
this.currentPaymentLines.last().set_amount(val);
},
});
}