diff --git a/addons/point_of_sale/controllers/main.py b/addons/point_of_sale/controllers/main.py
index e6976dd319c..3d80fd53e24 100644
--- a/addons/point_of_sale/controllers/main.py
+++ b/addons/point_of_sale/controllers/main.py
@@ -119,21 +119,21 @@ class PointOfSaleController(openerpweb.Controller):
return
@openerpweb.jsonrequest
- def payment_request(self, request, price, method, info):
+ def payment_request(self, request, price):
"""
The PoS will activate the method payment
"""
- print "payment_request: price:"+str(price)+" method:"+str(method)+" info:"+str(info)
- return
+ print "payment_request: price:"+str(price)
+ return 'ok'
@openerpweb.jsonrequest
- def is_payment_accepted(self, request):
- print "is_payment_accepted"
- return 'waiting_for_payment'
+ def payment_status(self, request):
+ print "payment_status"
+ return { 'status':'waiting' }
@openerpweb.jsonrequest
- def payment_canceled(self, request):
- print "payment_canceled"
+ def payment_cancel(self, request):
+ print "payment_cancel"
return
@openerpweb.jsonrequest
diff --git a/addons/point_of_sale/static/src/js/devices.js b/addons/point_of_sale/static/src/js/devices.js
index a26d8ca7154..142d35bd340 100644
--- a/addons/point_of_sale/static/src/js/devices.js
+++ b/addons/point_of_sale/static/src/js/devices.js
@@ -14,7 +14,14 @@ function openerp_pos_devices(instance,module){ //module is instance.point_of_sal
this.weighting = false;
this.paying = false;
- this.payment_status = 'waiting_for_payment';
+ this.default_payment_status = {
+ status: 'waiting',
+ message: '',
+ payment_method: undefined,
+ receipt_client: undefined,
+ receipt_shop: undefined,
+ };
+ this.custom_payment_status = this.default_payment_status;
this.connection = new instance.web.JsonRPC();
this.connection.setup(url);
@@ -23,16 +30,21 @@ function openerp_pos_devices(instance,module){ //module is instance.point_of_sal
this.notifications = {};
},
- message : function(name,params,success_callback, error_callback){
- success_callback = success_callback || function(){};
- error_callback = error_callback || function(){};
-
+ message : function(name,params){
+ var ret = new $.Deferred();
var callbacks = this.notifications[name] || [];
for(var i = 0; i < callbacks.length; i++){
callbacks[i](params);
}
- this.connection.rpc('/pos/'+name, params || {}, success_callback, error_callback);
+ this.connection.rpc('/pos/'+name, params || {},
+ function(result){
+ ret.resolve(result);
+ },
+ function(error){
+ ret.reject(error);
+ });
+ return ret;
},
// this allows the client to be notified when a proxy call is made. The notification
@@ -47,23 +59,23 @@ function openerp_pos_devices(instance,module){ //module is instance.point_of_sal
//a product has been scanned and recognized with success
// ean is a parsed ean object
scan_item_success: function(ean){
- this.message('scan_item_success',{ean: ean});
+ return this.message('scan_item_success',{ean: ean});
},
// a product has been scanned but not recognized
// ean is a parsed ean object
scan_item_error_unrecognized: function(ean){
- this.message('scan_item_error_unrecognized',{ean: ean});
+ return this.message('scan_item_error_unrecognized',{ean: ean});
},
//the client is asking for help
help_needed: function(){
- this.message('help_needed');
+ return this.message('help_needed');
},
//the client does not need help anymore
help_canceled: function(){
- this.message('help_canceled');
+ return this.message('help_canceled');
},
//the client is starting to weight
@@ -72,7 +84,7 @@ function openerp_pos_devices(instance,module){ //module is instance.point_of_sal
this.weight = 0;
this.weighting = true;
this.bypass_proxy = false;
- this.message('weighting_start');
+ return this.message('weighting_start');
}
},
@@ -84,11 +96,12 @@ function openerp_pos_devices(instance,module){ //module is instance.point_of_sal
if(this.bypass_proxy){
return this.weight;
}else{
- this.message('weighting_read_kg',{},function(weight){
- if(self.weighting && !self.bypass_proxy){
- self.weight = weight;
- }
- });
+ this.message('weighting_read_kg',{})
+ .then(function(weight){
+ if(self.weighting && !self.bypass_proxy){
+ self.weight = weight;
+ }
+ });
return this.weight;
}
},
@@ -104,77 +117,76 @@ function openerp_pos_devices(instance,module){ //module is instance.point_of_sal
this.weight = 0;
this.weighting = false;
this.bypass_proxy = false;
- this.message('weighting_end');
+ return this.message('weighting_end');
},
// the pos asks the client to pay 'price' units
- // method: 'mastercard' | 'cash' | ... ? TBD
- // info: 'extra information to display on the payment terminal' ... ? TBD
- payment_request: function(price, method, info){
+ payment_request: function(price){
+ var ret = new $.Deferred();
this.paying = true;
- this.payment_status = 'waiting_for_payment';
- this.message('payment_request',{'price':price,'method':method,'info':info});
+ this.custom_payment_status = this.default_payment_status;
+ return this.message('payment_request',{'price':price});
},
- // is called at regular interval after a payment request to see if the client
- // has paid the required money
- // returns 'waiting_for_payment' | 'payment_accepted' | 'payment_rejected'
- is_payment_accepted: function(){
- var self = this;
+ payment_status: function(){
if(this.bypass_proxy){
this.bypass_proxy = false;
- return this.payment_status;
+ return (new $.Deferred()).resolve(this.custom_payment_status);
}else{
- this.message('is_payment_accepted', {}, function(payment_status){
- if(self.paying){
- self.payment_status = payment_status;
- }
- });
- return this.payment_status;
+ return this.message('payment_status');
}
},
// override what the proxy says and accept the payment
debug_accept_payment: function(){
this.bypass_proxy = true;
- this.payment_status = 'payment_accepted';
+ this.custom_payment_status = {
+ status: 'paid',
+ message: 'Successfull Payment, have a nice day',
+ payment_method: 'AMEX',
+ receipt_client: 'bla',
+ receipt_shop: 'bla',
+ };
},
// override what the proxy says and reject the payment
debug_reject_payment: function(){
this.bypass_proxy = true;
- this.payment_status = 'payment_rejected';
+ this.custom_payment_status = {
+ status: 'error-rejected',
+ message: 'Sorry you don\'t have enough money :(',
+ };
},
// the client cancels his payment
- payment_canceled: function(){
+ payment_cancel: function(){
this.paying = false;
- this.payment_status = 'waiting_for_payment';
- this.message('payment_canceled');
+ this.custom_payment_status = 'waiting_for_payment';
+ return this.message('payment_cancel');
},
// called when the client logs in or starts to scan product
transaction_start: function(){
- this.message('transaction_start');
+ return this.message('transaction_start');
},
// called when the clients has finished his interaction with the machine
transaction_end: function(){
- this.message('transaction_end');
+ return this.message('transaction_end');
},
// called when the POS turns to cashier mode
cashier_mode_activated: function(){
- this.message('cashier_mode_activated');
+ return this.message('cashier_mode_activated');
},
// called when the POS turns to client mode
cashier_mode_deactivated: function(){
- this.message('cashier_mode_deactivated');
+ return this.message('cashier_mode_deactivated');
},
// ask for the cashbox (the physical box where you store the cash) to be opened
open_cashbox: function(){
- this.message('open_cashbox');
+ return this.message('open_cashbox');
},
/* ask the printer to print a receipt
@@ -216,12 +228,12 @@ function openerp_pos_devices(instance,module){ //module is instance.point_of_sal
* }
*/
print_receipt: function(receipt){
- this.message('print_receipt',{receipt: receipt});
+ return this.message('print_receipt',{receipt: receipt});
},
// asks the proxy to print an invoice in pdf form ( used to print invoices generated by the server )
print_pdf_invoice: function(pdfinvoice){
- this.message('print_pdf_invoice',{pdfinvoice: pdfinvoice});
+ return this.message('print_pdf_invoice',{pdfinvoice: pdfinvoice});
},
});
diff --git a/addons/point_of_sale/static/src/js/screens.js b/addons/point_of_sale/static/src/js/screens.js
index d2c79f19928..1ad03c5ead1 100644
--- a/addons/point_of_sale/static/src/js/screens.js
+++ b/addons/point_of_sale/static/src/js/screens.js
@@ -154,7 +154,7 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa
},
barcode_product_screen: 'products', //if defined, this screen will be loaded when a product is scanned
- barcode_product_error_popup: 'error', //if defined, this popup will be loaded when there's an error in the popup
+ 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
@@ -411,6 +411,9 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa
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();
@@ -419,12 +422,12 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa
},
});
- module.ErrorProductNotRecognizedPopupWidget = module.ErrorPopupWidget.extend({
- template:'ErrorProductNotRecognizedPopupWidget',
+ module.ProductErrorPopupWidget = module.ErrorPopupWidget.extend({
+ template:'ProductErrorPopupWidget',
});
- module.ErrorNoSessionPopupWidget = module.ErrorPopupWidget.extend({
- template:'ErrorNoSessionPopupWidget',
+ module.ErrorSessionPopupWidget = module.ErrorPopupWidget.extend({
+ template:'ErrorSessionPopupWidget',
});
module.ScaleInviteScreenWidget = module.ScreenWidget.extend({
@@ -539,6 +542,60 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa
},
});
+ // 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.then(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.BasicPaymentScreen = module.ScreenWidget.extend({
+ queue: new JobQueue(),
+ start_payment_transaction: function(){
+ },
+ update_payment_transaction: function(){
+ },
+ cancel_payment_transaction: function(){
+ },
+ show: function(){
+ this._super();
+ },
+ });
+ */
+
module.ClientPaymentScreenWidget = module.ScreenWidget.extend({
template:'ClientPaymentScreenWidget',
@@ -548,50 +605,102 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa
show: function(){
this._super();
var self = this;
+
+ this.queue = new module.JobQueue();
+ this.canceled = false;
+ this.paid = false;
- this.pos.proxy.payment_request(this.pos.get('selectedOrder').getDueLeft(),'card','info'); //TODO TOTAL
-
- this.intervalID = setInterval(function(){
- var payment = self.pos.proxy.is_payment_accepted();
- if(payment === 'payment_accepted'){
- clearInterval(this.intervalID);
-
- 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);
+ // initiates the connection to the payment terminal and starts the update requests
+ this.start = function(){
+ var def = new $.Deferred();
+ console.log("START");
+ self.pos.proxy.payment_request(self.pos.get('selectedOrder').getDueLeft())
+ .then(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);
}
- }
-
- 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);
- }else if(payment === 'payment_rejected'){
- clearInterval(self.intervalID);
- //TODO show a tryagain thingie ?
+ console.log("START_END");
+ def.resolve();
+ });
+ return def;
+ };
+
+ // gets updated status from the payment terminal and performs the appropriate consequences
+ this.update = function(){
+ console.log("UPDATE");
+ var def = new $.Deferred();
+ if(self.canceled){
+ console.log("UPDATE_END");
+ return def.resolve();
}
- },500);
+ self.pos.proxy.payment_status()
+ .then(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);
+ }
+ console.log("UPDATE_END");
+ def.resolve();
+ });
+ return def;
+ }
+
+ // cancels a payment.
+ this.cancel = function(){
+ console.log("CANCEL");
+ 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();
+ }
+ console.log("CANCEL_END");
+ return (new $.Deferred()).resolve();
+ }
+
+ this.queue.schedule(this.start);
this.add_action_button({
label: 'back',
icon: '/point_of_sale/static/src/img/icons/png48/go-previous.png',
click: function(){
- clearInterval(this.intervalID);
- self.pos.proxy.payment_canceled();
- self.pos_widget.screen_selector.set_current_screen(self.previous_screen);
+ self.queue.schedule(self.cancel);
}
});
},
close: function(){
+ if(this.queue){
+ this.queue.schedule(this.cancel);
+ }
+ //TODO CANCEL
this._super();
- clearInterval(this.intervalID);
},
});
diff --git a/addons/point_of_sale/static/src/js/widgets.js b/addons/point_of_sale/static/src/js/widgets.js
index f4d16b527c8..47a527a010d 100644
--- a/addons/point_of_sale/static/src/js/widgets.js
+++ b/addons/point_of_sale/static/src/js/widgets.js
@@ -687,7 +687,7 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
'print_receipt',
'print_pdf_invoice',
'weighting_read_kg',
- 'is_payment_accepted',
+ 'payment_status',
],
minimized: false,
start: function(){
@@ -898,10 +898,10 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
this.error_popup = new module.ErrorPopupWidget(this, {});
this.error_popup.appendTo($('.point-of-sale'));
- this.error_product_popup = new module.ErrorProductNotRecognizedPopupWidget(this, {});
+ this.error_product_popup = new module.ProductErrorPopupWidget(this, {});
this.error_product_popup.appendTo($('.point-of-sale'));
- this.error_session_popup = new module.ErrorNoSessionPopupWidget(this, {});
+ this.error_session_popup = new module.ErrorSessionPopupWidget(this, {});
this.error_session_popup.appendTo($('.point-of-sale'));
this.choose_receipt_popup = new module.ChooseReceiptPopupWidget(this, {});
diff --git a/addons/point_of_sale/static/src/xml/pos.xml b/addons/point_of_sale/static/src/xml/pos.xml
index 7af3c2c2255..53177b5ac4e 100644
--- a/addons/point_of_sale/static/src/xml/pos.xml
+++ b/addons/point_of_sale/static/src/xml/pos.xml
@@ -327,15 +327,20 @@
-
+
+
-
+