diff --git a/addons/point_of_sale/static/src/css/pos.css b/addons/point_of_sale/static/src/css/pos.css index dbe79703329..a727986bb1c 100644 --- a/addons/point_of_sale/static/src/css/pos.css +++ b/addons/point_of_sale/static/src/css/pos.css @@ -1102,6 +1102,81 @@ .point-of-sale .pos-actionbar .button.rightalign{ float:right; } +/* ********* The Debug Widget ********* */ + +.point-of-sale .debug-widget{ + z-index:100000; + position: absolute; + right: 10px; + top: 10px; + width: 200px; + font-size: 10px; + + background: rgba(0,0,0,0.82); + color: white; + text-shadow: none; + padding-bottom: 10px; + box-shadow: 0px 3px 20px rgba(0,0,0,0.3); + cursor:move; +} +.point-of-sale .debug-widget .toggle{ + position: absolute; + font-size: 16px; + cursor:pointer; + top:0px; + right:0px; + padding:10px; + padding-right:15px; +} +.point-of-sale .debug-widget .content{ + overflow: hidden; +} +.point-of-sale .debug-widget h1{ + background:black; + padding-top: 10px; + padding-left: 10px; + margin-top:0; + margin-bottom:0; +} +.point-of-sale .debug-widget .category{ + background: black; + padding-left: 10px; + margin: 0px; + font-weight: bold; + padding-top:3px; + padding-bottom:3px; +} +.point-of-sale .debug-widget .button{ + padding: 5px; + padding-left: 15px; + display: block; + cursor:pointer; +} +.point-of-sale .debug-widget .button:hover{ + background: rgba(96,21,177,0.45); +} +.point-of-sale .debug-widget input{ + margin-left:10px; + margin-top:7px; +} +.point-of-sale .debug-widget .status{ + padding: 5px; + padding-left: 15px; + display: block; + cursor:default; +} +.point-of-sale .debug-widget .status.on{ + padding: 5px; + padding-left: 15px; + display: block; + background-color: green; +} +.point-of-sale .debug-widget .status.on{ + padding: 5px; + padding-left: 15px; + display: block; + background-color: #6cd11d; +} /* ********* The PopupWidgets ********* */ diff --git a/addons/point_of_sale/static/src/js/devices.js b/addons/point_of_sale/static/src/js/devices.js index 46d11938128..65a28b5366a 100644 --- a/addons/point_of_sale/static/src/js/devices.js +++ b/addons/point_of_sale/static/src/js/devices.js @@ -1,26 +1,6 @@ function openerp_pos_devices(instance,module){ //module is instance.point_of_sale - var debug_devices = new (instance.web.Class.extend({ - active: false, - payment_status: 'waiting_for_payment', - weight: 0, - activate: function(){ - this.active = true; - }, - deactivate: function(){ - this.active = false; - }, - set_weight: function(weight){ this.activate(); this.weight = weight; }, - accept_payment: function(){ this.activate(); this.payment_status = 'payment_accepted'; }, - reject_payment: function(){ this.activate(); this.payment_status = 'payment_rejected'; }, - delay_payment: function(){ this.activate(); this.payment_status = 'waiting_for_payment'; }, - }))(); - - if(jQuery.deparam(jQuery.param.querystring()).debug !== undefined){ - window.debug_devices = debug_devices; - } - // this object interfaces with the local proxy to communicate to the various hardware devices // connected to the Point of Sale. As the communication only goes from the POS to the proxy, // methods are used both to signal an event, and to fetch information. @@ -38,20 +18,34 @@ function openerp_pos_devices(instance,module){ //module is instance.point_of_sal this.connection = new instance.web.JsonRPC(); this.connection.setup(url); + + this.bypass_proxy = false; + this.notifications = {}; }, message : function(name,params,success_callback, error_callback){ success_callback = success_callback || function(){}; error_callback = error_callback || function(){}; - if(jQuery.deparam(jQuery.param.querystring()).debug !== undefined){ console.log('PROXY:',name,params); } - if(!(debug_devices && debug_devices.active)){ - this.connection.rpc('/pos/'+name, params || {}, success_callback, error_callback); + 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 allows the client to be notified when a proxy call is made. The notification + // callback will be executed with the same arguments as the proxy call + add_notification: function(name, callback){ + if(!this.notifications[name]){ + this.notifications[name] = []; + } + this.notifications[name].push(callback); }, //a product has been scanned and recognized with success @@ -78,12 +72,12 @@ function openerp_pos_devices(instance,module){ //module is instance.point_of_sal //the client is starting to weight weighting_start: function(){ - this.weight = 0; - if(debug_devices){ - debug_devices.weigth = 0; + if(!this.weighting){ + this.weight = 0; + this.weighting = true; + this.bypass_proxy = false; + this.message('weighting_start'); } - this.weighting = true; - this.message('weighting_start'); }, //returns the weight on the scale. @@ -91,22 +85,29 @@ function openerp_pos_devices(instance,module){ //module is instance.point_of_sal // and a weighting_end() weighting_read_kg: function(){ var self = this; - if(debug_devices && debug_devices.active){ - return debug_devices.weight; + if(this.bypass_proxy){ + return this.weight; }else{ this.message('weighting_read_kg',{},function(weight){ - if(self.weighting){ + if(self.weighting && !self.bypass_proxy){ self.weight = weight; } }); - return self.weight; + return this.weight; } }, + // sets a custom weight, ignoring the proxy returned value until the next weighting_end + debug_set_weight: function(kg){ + this.bypass_proxy = true; + this.weight = kg; + }, + // the client has finished weighting products weighting_end: function(){ this.weight = 0; this.weighting = false; + this.bypass_proxy = false; this.message('weighting_end'); }, @@ -116,9 +117,6 @@ function openerp_pos_devices(instance,module){ //module is instance.point_of_sal payment_request: function(price, method, info){ this.paying = true; this.payment_status = 'waiting_for_payment'; - if(debug_devices){ - debug_devices.payment_status = 'waiting_for_payment'; - } this.message('payment_request',{'price':price,'method':method,'info':info}); }, @@ -127,18 +125,30 @@ function openerp_pos_devices(instance,module){ //module is instance.point_of_sal // returns 'waiting_for_payment' | 'payment_accepted' | 'payment_rejected' is_payment_accepted: function(){ var self = this; - if(debug_devices.active){ - return debug_devices.payment_status; + if(this.bypass_proxy){ + this.bypass_proxy = false; + return this.payment_status; }else{ this.message('is_payment_accepted', {}, function(payment_status){ if(self.paying){ self.payment_status = payment_status; } }); - return self.payment_status; + return this.payment_status; } }, + + // override what the proxy says and accept the payment + debug_accept_payment: function(){ + this.bypass_proxy = true; + this.payment_status = 'payment_accepted'; + }, + // override what the proxy says and reject the payment + debug_reject_payment: function(){ + this.bypass_proxy = true; + this.payment_status = 'payment_rejected'; + }, // the client cancels his payment payment_canceled: function(){ this.paying = false; @@ -241,18 +251,6 @@ function openerp_pos_devices(instance,module){ //module is instance.point_of_sal this.price_prefix_set = attributes.price_prefix_set || {'23':''}; this.cashier_prefix_set = attributes.cashier_prefix_set || {'041':''}; this.client_prefix_set = attributes.client_prefix_set || {'042':''}; - - if(jQuery.deparam(jQuery.param.querystring()).debug !== undefined){ - var self = this; - window.simulate_ean = function(ean,strict){ - ean = ean.toString(); - if(!strict){ - ean = self.sanitize_ean(ean); - } - console.log('SIMULATE EAN: ',ean); - self.on_ean(ean); - } - } }, save_callbacks: function(){ @@ -356,7 +354,6 @@ function openerp_pos_devices(instance,module){ //module is instance.point_of_sal value: 0, unit: 'none', }; - console.log('ean',ean); function match_prefix(prefix_set, type){ for(prefix in prefix_set){ diff --git a/addons/point_of_sale/static/src/js/models.js b/addons/point_of_sale/static/src/js/models.js index 49521377ccb..5fbba5088d4 100644 --- a/addons/point_of_sale/static/src/js/models.js +++ b/addons/point_of_sale/static/src/js/models.js @@ -24,6 +24,8 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal this.proxy = new module.ProxyDevice(); // used to communicate to the hardware devices via a local proxy this.db = new module.PosLS(); // a database used to store the products and categories this.db.clear('products','categories'); + this.debug = jQuery.deparam(jQuery.param.querystring()).debug !== undefined; //debug mode + // default attributes values. If null, it will be loaded below. this.set({ diff --git a/addons/point_of_sale/static/src/js/screens.js b/addons/point_of_sale/static/src/js/screens.js index 3b580868e6b..d2c79f19928 100644 --- a/addons/point_of_sale/static/src/js/screens.js +++ b/addons/point_of_sale/static/src/js/screens.js @@ -560,21 +560,21 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa //we get the first cashregister marked as self-checkout var selfCheckoutRegisters = []; - for(var i = 0; i < this.pos.get('cashRegisters').models.length; i++){ - var cashregister = this.pos.get('cashRegisters').models[i]; + 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] || this.pos.get('cashRegisters').models[0]; + 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(this.intervalID); + clearInterval(self.intervalID); //TODO show a tryagain thingie ? } },500); @@ -603,13 +603,14 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa show_numpad: false, show_leftpane: false, barcode_product_action: function(ean){ - self.pos.proxy.transaction_start(); + this.pos.proxy.transaction_start(); this._super(ean); }, barcode_client_action: function(ean){ - self.pos.proxy.transaction_start(); + this.pos.proxy.transaction_start(); this._super(ean); + $('.goodbye-message').hide(); this.pos_widget.screen_selector.show_popup('choose-receipt'); }, diff --git a/addons/point_of_sale/static/src/js/widgets.js b/addons/point_of_sale/static/src/js/widgets.js index 2aaf9098329..c8e03ccff08 100644 --- a/addons/point_of_sale/static/src/js/widgets.js +++ b/addons/point_of_sale/static/src/js/widgets.js @@ -694,6 +694,91 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa }, }); + module.DebugWidget = module.PosBaseWidget.extend({ + template: "DebugWidget", + eans:{ + admin_badge: '0410300000004', + client_badge: '0420100000005', + invalid_ean: '1232456', + soda_33cl: '5449000000996', + oranges_kg: '2100002031410', + lemon_price: '2301000001560', + unknown_product: '9900000000004', + }, + events:[ + 'scan_item_success', + 'scan_item_error_unrecognized', + 'payment_request', + 'open_cashbox', + 'print_receipt', + 'print_pdf_invoice', + ], + minimized: false, + start: function(){ + var self = this; + + this.$el.draggable(); + this.$('.toggle').click(function(){ + var content = self.$('.content'); + var bg = self.$el; + if(!self.minimized){ + content.animate({'height':'0'},200); + }else{ + content.css({'height':'auto'}); + } + self.minimized = !self.minimized; + }); + this.$('.button.accept_payment').click(function(){ + self.pos.proxy.debug_accept_payment(); + }); + this.$('.button.reject_payment').click(function(){ + self.pos.proxy.debug_reject_payment(); + }); + this.$('.button.set_weight').click(function(){ + var kg = Number(self.$('input.weight').val()); + if(!Number.isNaN(kg)){ + self.pos.proxy.debug_set_weight(kg); + } + }); + this.$('.button.custom_ean').click(function(){ + var ean = self.pos.barcode_reader.sanitize_ean(self.$('input.ean').val() || '0'); + self.$('input.ean').val(ean); + self.pos.barcode_reader.on_ean(ean); + }); + _.each(this.eans, function(ean, name){ + self.$('.button.'+name).click(function(){ + self.$('input.ean').val(ean); + self.pos.barcode_reader.on_ean(ean); + }); + }); + _.each(this.events, function(name){ + self.pos.proxy.add_notification(name,function(){ + console.log('Notification:',name); + self.$('.status.'+name).stop().clearQueue().css({'background-color':'#6CD11D'}); + self.$('.status.'+name).animate({'background-color':'black'},2000); + }); + }); + self.pos.proxy.add_notification('help_needed',function(){ + self.$('.status.help_needed').addClass('on'); + }); + self.pos.proxy.add_notification('help_canceled',function(){ + self.$('.status.help_needed').removeClass('on'); + }); + self.pos.proxy.add_notification('transaction_start',function(){ + self.$('.status.transaction').addClass('on'); + }); + self.pos.proxy.add_notification('transaction_end',function(){ + self.$('.status.transaction').removeClass('on'); + }); + self.pos.proxy.add_notification('weighting_start',function(){ + self.$('.status.weighting').addClass('on'); + }); + self.pos.proxy.add_notification('weighting_end',function(){ + self.$('.status.weighting').removeClass('on'); + }); + }, + }); + // The PosWidget is the main widget that contains all other widgets in the PointOfSale. // It is mainly composed of : // - a header, containing the list of orders @@ -718,14 +803,6 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa this.leftpane_width = '440px'; this.cashier_controls_visible = true; this.image_cache = new module.ImageCache(); // for faster products image display - - /* - //Epileptic mode - setInterval(function(){ - $('body').css({'-webkit-filter':'hue-rotate('+Math.random()*360+'deg)' }); - },100); - */ - }, start: function() { @@ -769,11 +846,6 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa self.$('.loader').animate({opacity:0},1500,'swing',function(){self.$('.loader').hide();}); self.$('.loader img').hide(); - if(jQuery.deparam(jQuery.param.querystring()).debug !== undefined){ - window.pos = self.pos; - window.pos_widget = self.pos_widget; - } - },function(){ // error when loading models data from the backend self.$('.loader img').hide(); return new instance.web.Model("ir.model.data").get_func("search_read")([['name', '=', 'action_pos_session_opening']], ['res_id']) @@ -898,6 +970,10 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa default_mode: this.pos.iface_self_checkout ? 'client' : 'cashier', }); + if(this.pos.debug){ + this.debug_widget = new module.DebugWidget(this); + this.debug_widget.appendTo(this.$('#content')); + } }, changed_pending_operations: function () { diff --git a/addons/point_of_sale/static/src/xml/pos.xml b/addons/point_of_sale/static/src/xml/pos.xml index a0b129da2f9..7c8b18a9bc3 100644 --- a/addons/point_of_sale/static/src/xml/pos.xml +++ b/addons/point_of_sale/static/src/xml/pos.xml @@ -414,6 +414,55 @@ + +
+

Debug Window

+
▾
+
+

Payment Terminal

+ +
    +
  • Accept Payment
  • +
  • Reject Payment
  • +
+

Electronic Scale

+
    +
  • +
  • Set Weight
  • +
+ +

Barcode Scanner

+
    +
  • +
  • Custom Ean13
  • +
  • Admin Badge
  • +
  • Client Badge
  • +
  • Soda 33cl
  • +
  • 3.141Kg Oranges
  • +
  • 1.54€ Lemon
  • +
  • Unknown Product
  • +
  • Invalid Ean
  • +
+ +

Hardware Status

+
    +
  • Help needed
  • +
  • Weighting
  • +
  • In Transaction
  • +
+

Hardware Events

+
    +
  • Scan Item Success
  • +
  • Scan Item Unrecognized
  • +
  • Payment Request
  • +
  • Open Cashbox
  • + + +
+
+
+
+