[WIP] point_of_sale: more progress on ipadification: the app now is in a separate...
authorFrédéric van der Essen <fva@openerp.com>
Wed, 27 Nov 2013 14:44:27 +0000 (15:44 +0100)
committerFrédéric van der Essen <fva@openerp.com>
Wed, 27 Nov 2013 14:44:27 +0000 (15:44 +0100)
bzr revid: fva@openerp.com-20131127144427-odf37v9dthuw4yrm

addons/point_of_sale/controllers/main.py
addons/point_of_sale/static/src/css/pos.css
addons/point_of_sale/static/src/img/touch-icon-ipad-retina.png [new file with mode: 0644]
addons/point_of_sale/static/src/img/touch-icon-ipad.png [new file with mode: 0644]
addons/point_of_sale/static/src/img/touch-icon-iphone-retina.png [new file with mode: 0644]
addons/point_of_sale/static/src/img/touch-icon-iphone.png [new file with mode: 0644]
addons/point_of_sale/static/src/img/touch-icon.svg [new file with mode: 0644]
addons/point_of_sale/static/src/js/models.js
addons/point_of_sale/static/src/js/screens.js
addons/point_of_sale/static/src/js/widgets.js
addons/point_of_sale/static/src/xml/pos.xml

index 2461fe9..76dd705 100644 (file)
@@ -8,182 +8,73 @@ import random
 
 from openerp import http
 from openerp.http import request
-from openerp.addons.web.controllers.main import manifest_list, module_boot, html_template
+from openerp.addons.web.controllers.main import manifest_list, module_boot 
 
 _logger = logging.getLogger(__name__)
 
-class PointOfSaleController(http.Controller):
-    def __init__(self):
-        self.scale = 'closed'
-        self.scale_weight = 0.0
-
-    @http.route('/pos/app', type='http', auth='admin')
-    def app(self):
-        js = "\n        ".join('<script type="text/javascript" src="%s"></script>' % i for i in manifest_list('js',db=request.db))
-        css = "\n        ".join('<link rel="stylesheet" href="%s">' % i for i in manifest_list('css',db=request.db))
-
-        cookie = request.httprequest.cookies.get("instance0|session_id")
-        session_id = cookie.replace("%22","")
-        template = html_template.replace('<html','<html manifest="/pos/manifest?session_id=%s"' % request.session_id)
+html_template = """<!DOCTYPE html>
+<html>
+    <head>
+        <title>OpenERP Point of Sale</title>
+
+        <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>
+        <meta http-equiv="content-type" content="text/html, charset=utf-8" />
+
+        <meta name="viewport" content=" width=1024, user-scalable=no">
+        <meta name="apple-mobile-web-app-capable" content="yes">
+
+        <link rel="apple-touch-icon"                 href="/point_of_sale/static/src/img/touch-icon-iphone.png">
+        <link rel="apple-touch-icon" sizes="76x76"   href="/point_of_sale/static/src/img/touch-icon-ipad.png">
+        <link rel="apple-touch-icon" sizes="120x120" href="/point_of_sale/static/src/img/touch-icon-iphone-retina.png">
+        <link rel="apple-touch-icon" sizes="152x152" href="/point_of_sale/static/src/img/touch-icon-ipad-retina.png">
+
+        <link rel="shortcut icon" href="/web/static/src/img/favicon.ico" type="image/x-icon"/>
+        <link rel="stylesheet" href="/web/static/src/css/full.css" />
+        %(css)s
+        %(js)s
+        <script type="text/javascript">
+            $(function() {
+                var s = new openerp.init(%(modules)s);
+                %(init)s
+            });
+        </script>
+    </head>
+    <body>
+        <!--[if lte IE 8]>
+        <script src="//ajax.googleapis.com/ajax/libs/chrome-frame/1/CFInstall.min.js"></script>
+        <script>CFInstall.check({mode: "overlay"});</script>
+        <![endif]-->
+    </body>
+</html>
+"""
+
+class PosController(http.Controller):
+
+    @http.route('/pos/web', type='http', auth='none')
+    def a(self, debug=False, **k):
+        js_list = manifest_list('js',db=request.db, debug=debug)
+        css_list =   manifest_list('css',db=request.db, debug=debug)
+        
+        print css_list
+        print js_list
 
-        r = template % {
+        js = "\n".join('<script type="text/javascript" src="%s"></script>' % i for i in js_list)
+        css = "\n".join('<link rel="stylesheet" href="%s">' % i for i in css_list)
+        r = html_template % {
             'js': js,
             'css': css,
-            'modules': simplejson.dumps(module_boot(request)),
-            'init': 'var wc = new s.web.WebClient();wc.appendTo($(document.body));'
+            'modules': simplejson.dumps(module_boot(request.db)),
+            'init': """
+                     window.navigator.standalone = true;
+                     var wc = new s.web.WebClient();
+                     wc.appendTo($(document.body));
+                     wc.show_application = function(){
+                         wc.action_manager.do_action("pos.ui");
+                     };
+                     wc.show_login = function(){
+                         window.location.href = '/';
+                     }
+                     """
         }
         return r
 
-    @http.route('/pos/manifest',type='http', auth='admin')
-    def manifest(self):
-        """ This generates a HTML5 cache manifest files that preloads the categories and products thumbnails 
-            and other ressources necessary for the point of sale to work offline """
-
-        ml = ["CACHE MANIFEST"]
-
-        # loading all the images in the static/src/img/* directories
-        def load_css_img(srcdir,dstdir):
-            for f in os.listdir(srcdir):
-                path = os.path.join(srcdir,f)
-                dstpath = os.path.join(dstdir,f)
-                if os.path.isdir(path) :
-                    load_css_img(path,dstpath)
-                elif f.endswith(('.png','.PNG','.jpg','.JPG','.jpeg','.JPEG','.gif','.GIF')):
-                    ml.append(dstpath)
-
-        imgdir = openerp.modules.get_module_resource('point_of_sale','static/src/img');
-        load_css_img(imgdir,'/point_of_sale/static/src/img')
-        
-        products = request.registry.get('product.product')
-        for p in products.search_read(request.cr, request.uid, [('pos_categ_id','!=',False)], ['name']):
-            product_id = p['id']
-            url = "/web/binary/image?session_id=%s&model=product.product&field=image&id=%s" % (request.session_id, product_id)
-            ml.append(url)
-        
-        categories = request.registry.get('pos.category')
-        for c in categories.search_read(request.cr, request.uid, [], ['name']):
-            category_id = c['id']
-            url = "/web/binary/image?session_id=%s&model=pos.category&field=image&id=%s" % (request.session_id, category_id)
-            ml.append(url)
-
-        ml += ["NETWORK:","*"]
-        m = "\n".join(ml)
-
-        return m
-
-    @http.route('/pos/test_connection', type='json', auth='admin')
-    def test_connection(self):
-        _logger.info('Received Connection Test from the Point of Sale');
-
-    @http.route('/pos/scan_item_success', type='json', auth='admin')
-    def scan_item_success(self, ean):
-        """
-        A product has been scanned with success
-        """
-        print 'scan_item_success: ' + str(ean)
-
-    @http.route('/pos/scan_item_error_unrecognized', type='json', auth='admin')
-    def scan_item_error_unrecognized(self, ean):
-        """
-        A product has been scanned without success
-        """
-        print 'scan_item_error_unrecognized: ' + str(ean)
-
-    @http.route('/pos/help_needed', type='json', auth='admin')
-    def help_needed(self):
-        """
-        The user wants an help (ex: light is on)
-        """
-        print "help_needed"
-
-    @http.route('/pos/help_canceled', type='json', auth='admin')
-    def help_canceled(self):
-        """
-        The user stops the help request
-        """
-        print "help_canceled"
-
-    @http.route('/pos/weighting_start', type='json', auth='admin')
-    def weighting_start(self):
-        if self.scale == 'closed':
-            print "Opening (Fake) Connection to Scale..."
-            self.scale = 'open'
-            self.scale_weight = 0.0
-            time.sleep(0.1)
-            print "... Scale Open."
-        else:
-            print "WARNING: Scale already Connected !!!"
-
-    @http.route('/pos/weighting_read_kg', type='json', auth='admin')
-    def weighting_read_kg(self):
-        if self.scale == 'open':
-            print "Reading Scale..."
-            time.sleep(0.025)
-            self.scale_weight += 0.01
-            print "... Done."
-            return self.scale_weight
-        else:
-            print "WARNING: Reading closed scale !!!"
-            return 0.0
-
-    @http.route('/pos/weighting_end', type='json', auth='admin')
-    def weighting_end(self):
-        if self.scale == 'open':
-            print "Closing Connection to Scale ..."
-            self.scale = 'closed'
-            self.scale_weight = 0.0
-            time.sleep(0.1)
-            print "... Scale Closed."
-        else:
-            print "WARNING: Scale already Closed !!!"
-
-    @http.route('/pos/payment_request', type='json', auth='admin')
-    def payment_request(self, price):
-        """
-        The PoS will activate the method payment 
-        """
-        print "payment_request: price:"+str(price)
-        return 'ok'
-
-    @http.route('/pos/payment_status', type='json', auth='admin')
-    def payment_status(self):
-        print "payment_status"
-        return { 'status':'waiting' } 
-
-    @http.route('/pos/payment_cancel', type='json', auth='admin')
-    def payment_cancel(self):
-        print "payment_cancel"
-
-    @http.route('/pos/transaction_start', type='json', auth='admin')
-    def transaction_start(self):
-        print 'transaction_start'
-
-    @http.route('/pos/transaction_end', type='json', auth='admin')
-    def transaction_end(self):
-        print 'transaction_end'
-
-    @http.route('/pos/cashier_mode_activated', type='json', auth='admin')
-    def cashier_mode_activated(self):
-        print 'cashier_mode_activated'
-
-    @http.route('/pos/cashier_mode_deactivated', type='json', auth='admin')
-    def cashier_mode_deactivated(self):
-        print 'cashier_mode_deactivated'
-
-    @http.route('/pos/open_cashbox', type='json', auth='admin')
-    def open_cashbox(self):
-        print 'open_cashbox'
-
-    @http.route('/pos/print_receipt', type='json', auth='admin')
-    def print_receipt(self, receipt):
-        print 'print_receipt' + str(receipt)
-
-    @http.route('/pos/log', type='json', auth='admin')
-    def log(self, arguments):
-        _logger.info(' '.join(str(v) for v in arguments))
-
-    @http.route('/pos/print_pdf_invoice', type='json', auth='admin')
-    def print_pdf_invoice(self, pdfinvoice):
-        print 'print_pdf_invoice' + str(pdfinvoice)
-
-
index 8e1fcb8..8935e6d 100644 (file)
     -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
 }
 
+.pos input::-webkit-outer-spin-button,
+.pos input::-webkit-inner-spin-button {
+    -webkit-appearance: none;
+    margin: 0;
+}
+
 .pos button{
     box-shadow: none;
     outline: none;
diff --git a/addons/point_of_sale/static/src/img/touch-icon-ipad-retina.png b/addons/point_of_sale/static/src/img/touch-icon-ipad-retina.png
new file mode 100644 (file)
index 0000000..4f1e1db
Binary files /dev/null and b/addons/point_of_sale/static/src/img/touch-icon-ipad-retina.png differ
diff --git a/addons/point_of_sale/static/src/img/touch-icon-ipad.png b/addons/point_of_sale/static/src/img/touch-icon-ipad.png
new file mode 100644 (file)
index 0000000..8b8c111
Binary files /dev/null and b/addons/point_of_sale/static/src/img/touch-icon-ipad.png differ
diff --git a/addons/point_of_sale/static/src/img/touch-icon-iphone-retina.png b/addons/point_of_sale/static/src/img/touch-icon-iphone-retina.png
new file mode 100644 (file)
index 0000000..593c150
Binary files /dev/null and b/addons/point_of_sale/static/src/img/touch-icon-iphone-retina.png differ
diff --git a/addons/point_of_sale/static/src/img/touch-icon-iphone.png b/addons/point_of_sale/static/src/img/touch-icon-iphone.png
new file mode 100644 (file)
index 0000000..4122e61
Binary files /dev/null and b/addons/point_of_sale/static/src/img/touch-icon-iphone.png differ
diff --git a/addons/point_of_sale/static/src/img/touch-icon.svg b/addons/point_of_sale/static/src/img/touch-icon.svg
new file mode 100644 (file)
index 0000000..8ce5f30
--- /dev/null
@@ -0,0 +1,199 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   id="svg3162"
+   version="1.1"
+   inkscape:version="0.48.3.1 r9886"
+   width="152"
+   height="152"
+   sodipodi:docname="ios7-icon.png"
+   inkscape:export-filename="/home/fva/Code/openerp/point_of_sale/touch-icon-ipad-retina.png"
+   inkscape:export-xdpi="90"
+   inkscape:export-ydpi="90">
+  <metadata
+     id="metadata3168">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs3166">
+    <linearGradient
+       id="linearGradient3944">
+      <stop
+         style="stop-color:#483c98;stop-opacity:1;"
+         offset="0"
+         id="stop3946" />
+      <stop
+         style="stop-color:#8075c9;stop-opacity:1;"
+         offset="1"
+         id="stop3948" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3944"
+       id="linearGradient3950"
+       x1="116.83051"
+       y1="0.49999994"
+       x2="115.35169"
+       y2="227.45763"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.67555556,0,0,0.67555556,0,-0.67555559)" />
+  </defs>
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="1920"
+     inkscape:window-height="1111"
+     id="namedview3164"
+     showgrid="true"
+     inkscape:zoom="1"
+     inkscape:cx="39.575132"
+     inkscape:cy="237.57664"
+     inkscape:window-x="0"
+     inkscape:window-y="27"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="svg3162">
+    <inkscape:grid
+       type="xygrid"
+       id="grid3942"
+       empspacing="5"
+       visible="true"
+       enabled="true"
+       snapvisiblegridlinesonly="true" />
+  </sodipodi:namedview>
+  <rect
+     style="fill:url(#linearGradient3950);fill-opacity:1;fill-rule:evenodd;stroke:none"
+     id="rect3172"
+     width="152"
+     height="152"
+     x="0"
+     y="-3.9968029e-15"
+     ry="34.723557" />
+  <rect
+     style="fill:#ffffff;fill-opacity:1;stroke:none"
+     id="rect3952"
+     width="5"
+     height="80"
+     x="25"
+     y="37"
+     ry="1" />
+  <rect
+     ry="1"
+     y="37"
+     x="35"
+     height="80"
+     width="3.0532093"
+     id="rect3954"
+     style="fill:#ffffff;fill-opacity:1;stroke:none" />
+  <rect
+     style="fill:#ffffff;fill-opacity:1;stroke:none"
+     id="rect3956"
+     width="5.0000033"
+     height="80"
+     x="45"
+     y="37"
+     ry="1" />
+  <rect
+     ry="1"
+     y="37"
+     x="54.999996"
+     height="80"
+     width="3.0000036"
+     id="rect3958"
+     style="fill:#ffffff;fill-opacity:1;stroke:none" />
+  <rect
+     style="fill:#ffffff;fill-opacity:1;stroke:none"
+     id="rect3960"
+     width="3.0000036"
+     height="80"
+     x="65"
+     y="37"
+     ry="1" />
+  <rect
+     ry="1"
+     y="37"
+     x="75"
+     height="80"
+     width="3.0000036"
+     id="rect3962"
+     style="fill:#ffffff;fill-opacity:1;stroke:none" />
+  <rect
+     style="fill:#ffffff;fill-opacity:1;stroke:none"
+     id="rect3964"
+     width="5.0000057"
+     height="80"
+     x="80"
+     y="37"
+     ry="1" />
+  <rect
+     ry="1"
+     y="37"
+     x="90"
+     height="80"
+     width="3.0000036"
+     id="rect3966"
+     style="fill:#ffffff;fill-opacity:1;stroke:none" />
+  <rect
+     ry="1"
+     y="37"
+     x="100.02039"
+     height="80"
+     width="5.0000057"
+     id="rect3968"
+     style="fill:#ffffff;fill-opacity:1;stroke:none" />
+  <rect
+     style="fill:#ffffff;fill-opacity:1;stroke:none"
+     id="rect3970"
+     width="3.0000036"
+     height="80"
+     x="107"
+     y="37"
+     ry="1" />
+  <rect
+     ry="1"
+     y="37"
+     x="114.99999"
+     height="80"
+     width="5.0000057"
+     id="rect3972"
+     style="fill:#ffffff;fill-opacity:1;stroke:none" />
+  <rect
+     style="fill:#ffffff;fill-opacity:1;stroke:none"
+     id="rect3974"
+     width="3.0532093"
+     height="80"
+     x="122"
+     y="37"
+     ry="1" />
+  <rect
+     style="fill:#f80000;fill-opacity:1;stroke:none"
+     id="rect3976"
+     width="2.0000024"
+     height="110"
+     x="-103.85593"
+     y="20"
+     ry="1.375"
+     transform="matrix(0,-1,1,0,0,0)" />
+</svg>
index 3de24b2..68acd4b 100644 (file)
@@ -378,7 +378,7 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
         _flush_order: function(order_id, options){
             var self   = this;
             options = options || {};
-            timeout = typeof options.timeout === 'number' ? options.timeout : 5000;
+            timeout = typeof options.timeout === 'number' ? options.timeout : 7500;
 
             var order  = this.db.get_order(order_id);
             order.to_invoice = options.to_invoice || false;
index 4c5f224..88a83fc 100644 (file)
@@ -812,6 +812,8 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa
             this._super();
             var self = this;
 
+            this.pos_widget.set_numpad_visible(false);
+
             var print_button = this.add_action_button({
                     label: _t('Print'),
                     icon: '/point_of_sale/static/src/img/icons/png48/printer.png',
@@ -872,6 +874,10 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa
             this.currentOrder = this.pos.get('selectedOrder');
             $('.pos-receipt-container', this.$el).html(QWeb.render('PosTicket',{widget:this}));
         },
+        close: function(){
+            this._super();
+            this.pos_widget.set_numpad_visible(true);
+        }
     });
 
     module.PaymentScreenWidget = module.ScreenWidget.extend({
@@ -1006,6 +1012,11 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa
                     this.pos_widget.screen_selector.set_current_screen(this.next_screen);
                 }
             }
+            // hide onscreen (iOS) keyboard 
+            setTimeout(function(){
+                document.activeElement.blur();
+                $("input").blur();
+            },250);
         },
         bindPaymentLineEvents: function() {
             this.currentPaymentLines = (this.pos.get('selectedOrder')).get('paymentLines');
@@ -1068,8 +1079,8 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa
         },
         isPaymentPaid: function(){
             var currentOrder = this.pos.get('selectedOrder');
-            return (currentOrder.getTotalTaxIncluded < 0.000001 
-                   && currentOrder.getPaidTotal() + 0.000001 < currentOrder.getTotalTaxIncluded());
+            return (currentOrder.getTotalTaxIncluded() >= 0.000001 
+                   && currentOrder.getPaidTotal() + 0.000001 >= currentOrder.getTotalTaxIncluded());
 
         },
         updatePaymentSummary: function() {
@@ -1088,8 +1099,8 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa
             }
                 
             if(this.pos_widget.action_bar){
-                this.pos_widget.action_bar.set_button_disabled('validation', this.isPaymentPaid());
-                this.pos_widget.action_bar.set_button_disabled('invoice', this.isPaymentPaid());
+                this.pos_widget.action_bar.set_button_disabled('validation', !this.isPaymentPaid());
+                this.pos_widget.action_bar.set_button_disabled('invoice', !this.isPaymentPaid());
             }
         },
         set_numpad_state: function(numpadState) {
index 6a222cd..2939eb3 100644 (file)
@@ -213,13 +213,13 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
             var scroller = this.$('.order-scroller')[0];
             var scrollbottom = true;
             var scrollTop = 0;
-            /*if(scroller){
+            if(scroller){
                 var overflow_bottom = scroller.scrollHeight - scroller.clientHeight;
                 scrollTop = scroller.scrollTop;
                 if( !goto_bottom && scrollTop < 0.9 * overflow_bottom){
                     scrollbottom = false;
                 }
-            }*/
+            }
             this._super();
 
             // freeing subwidgets
@@ -244,14 +244,13 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
             this.update_summary();
 
             scroller = this.$('.order-scroller')[0];
+
             if(scroller){
-                //scroller.scrollTop = 1000000;
-                /*
                 if(scrollbottom){
                     scroller.scrollTop = scroller.scrollHeight - scroller.clientHeight;
                 }else{
                     scroller.scrollTop = scrollTop;
-                }*/
+                }
             }
         },
         update_summary: function(){
@@ -313,8 +312,12 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
         focus: function(){
             var val = this.$('input')[0].value;
             this.$('input')[0].focus();
-            this.$('input')[0].value = val;
-            this.$('input')[0].select();
+            if(Number(val) === 0){
+                this.$('input')[0].value = '';
+            }else{
+                this.$('input')[0].value = val;
+                this.$('input')[0].select();
+            }
         },
     });
 
@@ -863,16 +866,8 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
 
                 self.screen_selector.set_default_screen();
 
-
                 self.pos.barcode_reader.connect();
 
-                if(!$('#oe-fullscreenwidget-viewport').length){
-                    $('head').append('<meta id="oe-pos-viewport" name="viewport" content=" width=1024px; user-scalable=no;">');
-                    $('head').append('<meta id="oe-pos-apple-mobile" name="apple-mobile-web-capable" content="yes">');
-                }
-
-                $('.oe_leftbar').addClass('oe_hidden');
-
                 instance.webclient.set_content_full_screen(true);
 
                 if (!self.pos.get('pos_session')) {
@@ -1104,7 +1099,6 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
                     return this.rpc('/web/action/load', {'action_id': res[0]['res_id']}).pipe(_.bind(function(result) {
                         var action = result;
                         action.context = _.extend(action.context || {}, {'cancel_action': {type: 'ir.actions.client', tag: 'reload'}});
-                        //self.destroy();
                         this.do_action(action);
                     }, this));
                 }, self));
@@ -1124,9 +1118,6 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
         destroy: function() {
             this.pos.destroy();
             instance.webclient.set_content_full_screen(false);
-            $('.oe_leftbar').removeClass('oe_hidden');
-            $('#oe-pos-viewport').remove();
-            $('#oe-pos-apple-mobile').remove();
             this._super();
         }
     });
index 42e5b7e..4eaf9e5 100644 (file)
                 <t t-esc="widget.name"/>
             </td>
             <td class="paymentline-amount pos-right-align">
-                <input type="number" t-att-value="widget.payment_line.get_amount().toFixed(2)" />
+                <input type="number" step="0.01" t-att-value="widget.payment_line.get_amount().toFixed(2)" />
                 <a href='javascript:void(0)' class='delete-payment-line'><img src="/point_of_sale/static/src/img/search_reset.gif" /></a>
             </td>
         </tr>