diff --git a/addons/point_of_sale/controllers/main.py b/addons/point_of_sale/controllers/main.py index 6657341c230..af55b9dfd93 100644 --- a/addons/point_of_sale/controllers/main.py +++ b/addons/point_of_sale/controllers/main.py @@ -4,7 +4,7 @@ import werkzeug.utils from openerp import http from openerp.http import request -from openerp.addons.web.controllers.main import login_redirect +from openerp.addons.web.controllers.main import login_redirect, abort_and_redirect _logger = logging.getLogger(__name__) @@ -15,6 +15,7 @@ class PosController(http.Controller): def a(self, debug=False, **k): cr, uid, context, session = request.cr, request.uid, request.context, request.session + # if user not logged in, log him in if not session.uid: return login_redirect() @@ -25,3 +26,4 @@ class PosController(http.Controller): PosSession.login(cr, uid, pos_session_ids, context=context) return request.render('point_of_sale.index') + diff --git a/addons/point_of_sale/point_of_sale.py b/addons/point_of_sale/point_of_sale.py index d644850b798..6b6fa8a9821 100644 --- a/addons/point_of_sale/point_of_sale.py +++ b/addons/point_of_sale/point_of_sale.py @@ -77,6 +77,7 @@ class pos_config(osv.osv): 'iface_print_auto': fields.boolean('Automatic Receipt Printing', help='The receipt will automatically be printed at the end of each order'), 'iface_precompute_cash': fields.boolean('Prefill Cash Payment', help='The payment input will behave similarily to bank payment input, and will be prefilled with the exact due amount'), 'iface_tax_included': fields.boolean('Include Taxes in Prices', help='The displayed prices will always include all taxes, even if the taxes have been setup differently'), + 'iface_start_categ_id': fields.many2one('pos.category','Start Category', help='The point of sale will display this product category by default. If no category is specified, all available products will be shown'), 'receipt_header': fields.text('Receipt Header',help="A short text that will be inserted as a header in the printed receipt"), 'receipt_footer': fields.text('Receipt Footer',help="A short text that will be inserted as a footer in the printed receipt"), 'proxy_ip': fields.char('IP Address', help='The hostname or ip address of the hardware proxy, Will be autodetected if left empty', size=45), @@ -93,6 +94,7 @@ class pos_config(osv.osv): 'barcode_nomenclature_id': fields.many2one('barcode.nomenclature','Barcodes', help='Defines what kind of barcodes are available and how they are assigned to products, customers and cashiers', required=True), 'group_pos_manager_id': fields.many2one('res.groups','Point of Sale Manager Group', help='This field is there to pass the id of the pos manager group to the point of sale client'), 'group_pos_user_id': fields.many2one('res.groups','Point of Sale User Group', help='This field is there to pass the id of the pos user group to the point of sale client'), + 'tip_product_id': fields.many2one('product.product','Tip Product', help="The product used to encode the customer tip. Leave empty if you do not accept tips."), } def _check_cash_control(self, cr, uid, ids, context=None): diff --git a/addons/point_of_sale/point_of_sale_view.xml b/addons/point_of_sale/point_of_sale_view.xml index 7b1a44c2ffb..9ea04a12d5b 100644 --- a/addons/point_of_sale/point_of_sale_view.xml +++ b/addons/point_of_sale/point_of_sale_view.xml @@ -22,7 +22,7 @@ - + @@ -699,6 +699,8 @@ + + diff --git a/addons/point_of_sale/static/src/css/pos.css b/addons/point_of_sale/static/src/css/pos.css index 8fc53f5c1a3..b1dcec00c12 100644 --- a/addons/point_of_sale/static/src/css/pos.css +++ b/addons/point_of_sale/static/src/css/pos.css @@ -365,6 +365,11 @@ td { cursor: pointer; min-width: 45px; } + +.pos .order-button:first-child { + margin-left: 0px; +} + .pos .order-button.selected{ font-weight: 900; background: #EEEEEE; @@ -419,7 +424,7 @@ td { display: -webkit-flex; display: flex; vertical-align: top; - margin-left: 8px; + margin-left: 0px; overflow: hidden; overflow-x: auto; -webkit-overflow-scrolling: touch; @@ -513,23 +518,29 @@ td { top:0px; bottom:0; border-right: solid 1px #CECBCB; + border-right: solid 3px #787878; + background: #e2e2e2; } + .pos .leftpane .pads { - background: #F0EEEE; - white-space: nowrap; + border-top: solid 3px rgb(110, 200, 155); } + /* ********* The control buttons ********* */ .pos .control-buttons { + display: -webkit-flex; display: flex; + -webkit-flex-flow: row wrap; flex-flow: row wrap; - padding: 8px 13px 0px 11px; + padding: 8px 16px 0px 11px; margin-bottom: -6px; } .pos .control-button { - flex: 1; + -webkit-flex-grow: 1; + flex-grow: 1; background: #e2e2e2; - border: solid 1px #cacaca; + border: solid 1px #bfbfbf; display: inline-block; line-height: 38px; min-width: 80px; @@ -541,22 +552,41 @@ td { margin-bottom: 6px; cursor: pointer; overflow: hidden; + transition: all linear 150ms; +} +.pos .control-button:hover { + background: #efefef; +} +.pos .control-button:active { + background: black; + color: white; + border-color: black; } .pos .control-button .fa{ margin-right: 4px; } +.pos .control-button .control-button-number { + color: rgb(226, 226, 226); + background: rgb(85, 85, 85); + display: inline-block; + height: 28px; + vertical-align: middle; + font-weight: bold; + line-height: 28px; + width: 28px; + border-radius: 50%; + text-align: center; + margin-left: -16px; + margin-right: 4px; +} .pos .control-button.highlight, .pos .button.highlight { background: #6EC89B !important; - border: solid 1px #6EC89B !important; + /* border: solid 1px #6EC89B !important; */ + border: solid 1px #64AF8A !important; color: white !important; } -.pos .control-button:active { - background: #7F82AC; - border: solid 1px #7F82AC; - color: white; -} .pos .control-button.disabled, .pos .control-button.disabled:active{ background: #e2e2e2; @@ -569,27 +599,54 @@ td { /* ********* The actionpad (payment, set customer) ********* */ .pos .actionpad { - padding: 8px 3px 8px 19px; display: inline-block; + float: left; + padding: 0; + margin: 16px; + margin-top: 8px; + margin-right: 0; text-align: center; vertical-align: top; - width: 183px; - max-height: 350px; - overflow-y: auto; - overflow-x: hidden; + width: 188px; + border: none; + border-radius: 0; + border-top: 1px solid; + border-left: 1px solid; + border-color: #bfbfbf; + border-top-left-radius: 4px; + border-bottom-left-radius: 4px; } .pos .actionpad .button { - height: 50px; display: block; + height: 54px; width: 100%; - margin: 0px -6px 4px -2px; font-weight: bold; vertical-align: middle; color: #555555; font-size: 14px; + border-radius: 0; + border: none; + border-right: 1px solid; + border-bottom: 1px solid; + border-color: #bfbfbf; + transition: all 150ms linear; +} +.pos .actionpad .button:hover { + background: #efefef; +} +.pos .actionpad .button:active { + background: black; + border-color: black; + color: white; +} +.pos .actionpad .button:first-child { + border-top-left-radius: 4px; +} +.pos .actionpad .button:last-child { + border-bottom-left-radius: 4px; } .pos .actionpad .button.pay { - height: 158px; + height: 162px; } .pos .actionpad .button.pay .fa { display: block; @@ -607,23 +664,46 @@ td { /* ********* The Numpad ********* */ .pos .numpad { - padding: 8px 8px 8px 4px; display: inline-block; + float: right; text-align: center; + margin: 16px; + margin-top: 8px; + margin-left: 0px; + border: none; + border-radius: 0; + border-top: 1px solid; + border-color: #bfbfbf; + border-top-right-radius: 4px; } .pos .numpad button { - height: 50px; - width: 50px; - margin: 0px 3px 4px 0px; + float: left; + height: 54px; + width: 54px; font-weight: bold; vertical-align: middle; color: #555555; + border-radius: 0; + border: none; + border-right: 1px solid; + border-bottom: 1px solid; + border-color: #bfbfbf; + transition: all 150ms linear; +} +.pos .numpad button:hover { + background: #efefef; } .pos .numpad button:active { background: black; color: white; border-color: transparent; } +.pos .numpad button:nth-child(4) { + border-top-right-radius: 4px; +} +.pos .numpad button:last-child { + border-bottom-right-radius: 4px; +} .pos .input-button { font-size: 24px; } @@ -755,6 +835,7 @@ td { .pos .categories { position: relative; + border-bottom: solid 3px rgb(110, 200, 155); } .pos .categories h4 { display: inline-block; @@ -810,7 +891,7 @@ td { } .pos .category-simple-button:active{ color: white; - background: #7f82ac; + background: black; -webkit-transition-property: background, border; -webkit-transition-duration: 0.2s; @@ -860,9 +941,9 @@ td { display: inline-block; line-height: 100px; font-size: 11px; - margin: 5px !important; - width: 120px; - height:120px; + margin: 8px !important; + width: 122px; + height:115px; background:#fff; border: 1px solid #e2e2e2; border-radius: 3px; @@ -962,6 +1043,14 @@ td { overflow: hidden; position: relative; } + +@media screen and (min-width: 1024px) { + .screen .screen-content{ + border-left: dashed 1px rgb(215,215,215); + border-right: dashed 1px rgb(215,215,215); + } +} + .screen .top-content{ position: absolute; left: 0px; top: 0px; right: 0px; @@ -980,12 +1069,24 @@ td { border-radius: 3px; border: solid 1px rgb(209, 209, 209); cursor: pointer; + transition: all 150ms linear; } -.screen .top-content .button.highlight{ +.screen .top-content .button:hover { + background: #efefef; +} +.screen .top-content .button:active { + background: black; + border-color: black; + color: white; +} +.screen .top-content .button.highlight { background: rgb(110,200,155); color: white; border: solid 1px rgb(110,200,155); } +.screen .top-content .button.highlight:hover { + background: rgb(120,210,165); +} .screen .top-content .button.back { left: 0px; margin-left: 16px; @@ -1068,14 +1169,31 @@ td { display: inline-block; width: 50%; box-sizing: border-box; - padding: 8px; + padding: 16px; text-align: center; float: left; } -.pos .payment-numpad .numpad button { - width: 66px; - height: 66px; +.pos .payment-numpad .numpad { + float: none; + border-radius: 4px; + border-top: 1px solid; + border-left: 1px solid; + border-color: #cacaca; + width: 296px; + overflow: hidden; + margin: 0; } +.pos .payment-numpad .numpad button { + width: 74px; + height: 74px; +} +.pos .payment-numpad .numpad button:first-child { + border-top-left-radius: 4px; +} +.pos .payment-numpad .numpad button:nth-child(16) { + border-bottom-left-radius: 4px; +} + .pos .paymentlines-container { padding: 16px; padding-top: 0; @@ -1121,6 +1239,11 @@ td { .pos .paymentline .col-change { min-width: 90px; } +.pos .paymentline.extra .col-due { + border-radius: 0 0 6px 6px; + border-top: solid 1px rgb(230, 230, 230); + font-weight: bold; +} .pos .paymentline .col-change.highlight { background: rgb(184, 152, 204); } @@ -1136,18 +1259,65 @@ td { width: 50%; box-sizing: border-box; padding: 16px; + padding-left: 0; float: right; } .payment-screen .payment-buttons .button { - background: rgb(220,220,220); - line-height: 48px; - margin-bottom: 4px; - border-radius: 3px; + background: #e2e2e2; + line-height: 73px; font-size: 16px; padding: 0px 8px; border: solid 1px rgb(200,200,200); + border-top-width: 0; cursor: pointer; text-align: center; + position: relative; + transition: background-color, border-color, color 150ms linear; +} +.payment-screen .payment-buttons .button:hover { + background-color: #efefef; +} +.payment-screen .payment-buttons .button:first-child { + border-top-left-radius: 3px; + border-top-right-radius: 3px; + border-top-width: 1px; +} +.payment-screen .payment-buttons .button:last-child { + border-bottom-left-radius: 3px; + border-bottom-right-radius: 3px; +} +.payment-screen .payment-buttons .button.highlight:not(:first-child) { + margin-top: -1px; + border-top: solid 1px; +} +.payment-screen .payment-buttons .button:active { + background: black; + border-color: black; + color: white; +} +.payment-screen .payment-buttons .button.highlight .fa { + border-color: rgba(0, 0, 0, 0.109804); + background: rgba(0, 0, 0, 0.0980392); +} +.payment-screen .payment-buttons .button .fa { + position: absolute; + left: 11px; + top: 50%; + width: 48px; + height: 48px; + line-height: 48px; + margin-top: -25px; + vertical-align: middle; + border-radius: 26px; + border: 1px solid rgba(0,0,0,0.2); + border-image-source: initial; + border-image-slice: initial; + border-image-width: initial; + border-image-outset: initial; + border-image-repeat: initial; + background: rgba(255,255,255,0.4); + font-size: 20px; + transition: all 150ms linear; } .payment-screen .paymentlines-empty .total { text-align: center; @@ -1486,7 +1656,7 @@ td { top: 0px; width:100%; height: 100%; - background: #F0EEEE; + background: white; } .pos .order-scroller{ @@ -1505,26 +1675,24 @@ td { .pos .order{ background: white; - padding-bottom:15px; - padding-top:15px; - margin-left:16px; - margin-right:16px; - margin-top:16px; - margin-bottom:16px; - font-size:16px; - border-radius: 3px; - border: solid 1px rgb(220,220,220); + padding-bottom: 8px; + padding-top: 8px; + font-size: 16px; text-align: left; max-width: 500px; -webkit-transform: translate3d(0,0,0); } -.pos .order .empty{ - text-align:center; - margin-top: 15px; - margin-bottom: 5px; - color:#999; - font-weight: normal; +.pos .order .order-empty { + text-align: center; + margin: 48px; + color: #DDD; +} +.pos .order .order-empty .fa { + font-size: 64px; +} +.pos .order .order-empty h1 { + font-size: 20px; } .pos .order .summary{ @@ -1542,8 +1710,11 @@ td { border-top: solid 2px; border-color:#777; } +.pos .order .summary .total { + font-size: 22px; +} .pos .order .summary .line .subentry{ - font-size: 14px; + font-size: 16px; font-weight: normal; text-align: center; } @@ -1642,6 +1813,21 @@ td { text-shadow: 0px 2px white, 0px 2px 2px rgba(0, 0, 0, 0.27); border-bottom: dashed 1px rgb(215,215,215); } +.pos .splitbill-screen .order { + background: white; + padding-bottom:15px; + padding-top:15px; + margin-left:16px; + margin-right:16px; + margin-top:16px; + margin-bottom:16px; + font-size:16px; + border-radius: 3px; + border: solid 1px rgb(220,220,220); + text-align: left; + max-width: 500px; + -webkit-transform: translate3d(0,0,0); +} .splitbill-screen .order .orderline.selected{ background: rgb(110,200,155); color: white; @@ -1661,23 +1847,33 @@ td { font-size: 24px; vertical-align: top; } -.splitbill-screen .paymentmethods, -.payment-screen .paymentmethods { +.paymentmethods { margin: 16px; } -.splitbill-screen .paymentmethods .button, -.payment-screen .paymentmethods .button { - background: rgb(221, 221, 221); - line-height: 40px; - margin-bottom: 4px; - border-radius: 3px; +.paymentmethods .button { + background: #e2e2e2; + line-height: 49px; font-size: 16px; border: solid 1px rgb(202, 202, 202); + border-top-width: 0px; cursor: pointer; text-align: center; } -.splitbill-screen .paymentmethod.active, -.payment-screen .paymentmethod.active { +.paymentmethods .button:first-child { + border-top-width: 1px; + border-top-left-radius: 3px; + border-top-right-radius: 3px; +} +.paymentmethods .button:last-child { + border-bottom-left-radius: 3px; + border-bottom-right-radius: 3px; +} +.paymentmethods .button:active { + background: black; + border-color: black; + color: white; +} +.paymentmethod .button.active { background: #6EC89B; color: white; border-color: #6EC89B; @@ -1907,8 +2103,8 @@ td { } .pos .popup .button:active{ color: white; - background: #7f82ac; - border: 1px solid #7f82ac; + background: black; + border: 1px solid black; -webkit-transition-property: background, border; -webkit-transition-duration: 0.2s; @@ -1949,6 +2145,9 @@ td { box-sizing: border-box; width: 80%; } +.pos .popup-number .popup-input { + text-align: center; +} .pos .popup input:focus, .pos .popup-input.active { outline: none; @@ -2039,8 +2238,8 @@ td { /* ********* The Webkit Scrollbar ********* */ .pos *::-webkit-scrollbar{ - width: 10px; - height: 10px; + width: 4px; + height: 4px; } .pos *::-webkit-scrollbar-track{ background: rgb(224,224,224); @@ -2048,6 +2247,7 @@ td { } .pos *::-webkit-scrollbar-thumb{ background: rgb(168,168,168); + background: #393939; min-height: 30px; } diff --git a/addons/point_of_sale/static/src/js/chrome.js b/addons/point_of_sale/static/src/js/chrome.js index 69aa3c7f902..a0dc5a6076f 100644 --- a/addons/point_of_sale/static/src/js/chrome.js +++ b/addons/point_of_sale/static/src/js/chrome.js @@ -157,13 +157,10 @@ openerp.point_of_sale.load_chrome = function load_chrome(instance, module){ //mo 'print_receipt', 'scale_read', ], - minimized: false, init: function(parent,options){ this._super(parent,options); var self = this; - this.minimized = false; - // for dragging the debug widget around this.dragging = false; this.dragpos = {x:0, y:0}; @@ -202,8 +199,24 @@ openerp.point_of_sale.load_chrome = function load_chrome(instance, module){ //mo event.stopPropagation(); }; }, + show: function() { + var self = this; + this.$el.css({opacity:0}); + this.$el.removeClass('oe_hidden'); + this.$el.animate({opacity:1},250,'swing'); + }, + hide: function() { + var self = this; + this.$el.animate({opacity:0,},250,'swing',function(){ + self.$el.addClass('oe_hidden'); + }); + }, start: function(){ var self = this; + + if (this.pos.debug) { + this.show(); + } this.el.addEventListener('mouseleave', this.dragend_handler); this.el.addEventListener('mouseup', this.dragend_handler); @@ -215,14 +228,7 @@ openerp.point_of_sale.load_chrome = function load_chrome(instance, module){ //mo this.el.addEventListener('touchmove', this.dragmove_handler); 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; + self.hide(); }); this.$('.button.set_weight').click(function(){ var kg = Number(self.$('input.weight').val()); @@ -409,6 +415,9 @@ openerp.point_of_sale.load_chrome = function load_chrome(instance, module){ //mo this.chrome = this; // So that chrome's childs have chrome set automatically this.pos.gui = this.gui; + this.logo_click_time = 0; + this.logo_click_count = 0; + this.widget = {}; // contains references to subwidgets instances this.cleanup_dom(); @@ -437,17 +446,45 @@ openerp.point_of_sale.load_chrome = function load_chrome(instance, module){ //mo }, build_chrome: function() { + var self = this; FastClick.attach(document.body); instance.webclient.set_content_full_screen(true); this.renderElement(); + this.$('.pos-logo').click(function(){ + self.click_logo(); + }); + if(this.pos.config.iface_big_scrollbars){ this.$el.addClass('big-scrollbars'); } }, + click_logo: function() { + if (this.pos.debug) { + this.widget.debug.show(); + } else { + var self = this; + var time = (new Date()).getTime(); + var delay = 500; + if (this.logo_click_time + 500 < time) { + this.logo_click_time = time; + this.logo_click_count = 1; + } else { + this.logo_click_time = time; + this.logo_click_count += 1; + if (this.logo_click_count >= 6) { + this.logo_click_count = 0; + this.gui.sudo().then(function(){ + self.widget.debug.show(); + }); + } + } + } + }, + disable_rubberbanding: function(){ // prevent the pos body from being scrollable. document.body.addEventListener('touchmove',function(event){ @@ -521,7 +558,6 @@ openerp.point_of_sale.load_chrome = function load_chrome(instance, module){ //mo loading_show: function(){ this.$('.loader').removeClass('oe_hidden').animate({opacity:1},150,'swing'); }, - widgets: [ { 'name': 'order_selector', @@ -570,7 +606,6 @@ openerp.point_of_sale.load_chrome = function load_chrome(instance, module){ //mo 'name': 'debug', 'widget': module.DebugWidget, 'append': '.pos-content', - 'condition': function(){ return this.pos.debug }, }, ], diff --git a/addons/point_of_sale/static/src/js/models.js b/addons/point_of_sale/static/src/js/models.js index 71d593961de..e409145f2f0 100644 --- a/addons/point_of_sale/static/src/js/models.js +++ b/addons/point_of_sale/static/src/js/models.js @@ -1470,6 +1470,33 @@ openerp.point_of_sale.load_models = function load_models(instance, module){ //mo get_last_orderline: function(){ return this.orderlines.at(this.orderlines.length -1); }, + get_tip: function() { + var tip_product = this.pos.db.get_product_by_id(this.pos.config.tip_product_id[0]); + var lines = this.get_orderlines(); + if (!tip_product) { + return 0; + } else { + for (var i = 0; i < lines.length; i++) { + if (lines[i].get_product() === tip_product) { + return lines[i].get_unit_price(); + } + } + return 0; + } + }, + set_tip: function(tip) { + var tip_product = this.pos.db.get_product_by_id(this.pos.config.tip_product_id[0]); + var lines = this.get_orderlines(); + if (tip_product) { + for (var i = 0; i < lines.length; i++) { + if (lines[i].get_product() === tip_product) { + lines[i].set_unit_price(tip); + return; + } + } + this.add_product(tip_product, {quantity: 1, price: tip }); + } + }, remove_orderline: function( line ){ this.assert_editable(); this.orderlines.remove(line); diff --git a/addons/point_of_sale/static/src/js/popups.js b/addons/point_of_sale/static/src/js/popups.js index e0db66f5392..314dc8556c8 100644 --- a/addons/point_of_sale/static/src/js/popups.js +++ b/addons/point_of_sale/static/src/js/popups.js @@ -194,7 +194,7 @@ openerp.point_of_sale.load_popups = function load_popups(instance, module) { var self = this; this._super(options); - this.inputbuffer = options.value || ''; + this.inputbuffer = '' + options.value || ''; this.renderElement(); this.firstinput = true; }, diff --git a/addons/point_of_sale/static/src/js/screens.js b/addons/point_of_sale/static/src/js/screens.js index e6bf2624db7..9fc2fd53d52 100644 --- a/addons/point_of_sale/static/src/js/screens.js +++ b/addons/point_of_sale/static/src/js/screens.js @@ -400,8 +400,7 @@ openerp.point_of_sale.load_screens = function load_screens(instance, module){ // this.pos.bind('change:selectedOrder', this.change_selected_order, this); this.line_click_handler = function(event){ - self.pos.get_order().select_orderline(this.orderline); - self.numpad_state.reset(); + self.click_line(this.orderline, event); }; if (this.pos.get_order()) { @@ -409,6 +408,10 @@ openerp.point_of_sale.load_screens = function load_screens(instance, module){ // } }, + click_line: function(orderline, event) { + this.pos.get_order().select_orderline(orderline); + this.numpad_state.reset(); + }, set_value: function(val) { var order = this.pos.get_order(); if (order.get_selected_orderline()) { @@ -519,6 +522,10 @@ openerp.point_of_sale.load_screens = function load_screens(instance, module){ // }, update_summary: function(){ var order = this.pos.get_order(); + if (!order.get_orderlines().length) { + return; + } + var total = order ? order.get_total_with_tax() : 0; var taxes = order ? total - order.get_total_without_tax() : 0; @@ -548,7 +555,8 @@ openerp.point_of_sale.load_screens = function load_screens(instance, module){ // this.subcategories = []; this.product_list_widget = options.product_list_widget || null; this.category_cache = new module.DomCache(); - this.set_category(); + this.start_categ_id = this.pos.config.iface_start_categ_id ? this.pos.config.iface_start_categ_id[0] : 0; + this.set_category(this.pos.db.get_category_by_id(this.start_categ_id)); this.switch_category_handler = function(event){ self.set_category(self.pos.db.get_category_by_id(Number(this.dataset['categoryId']))); @@ -645,12 +653,14 @@ openerp.point_of_sale.load_screens = function load_screens(instance, module){ // this.el = el_node; var hasimages = false; //if none of the subcategories have images, we don't display buttons with icons + /* for(var i = 0; i < this.subcategories.length; i++){ if(this.subcategories[i].image){ hasimages = true; break; } } + */ var list_container = el_node.querySelector('.category-list'); if (list_container) { @@ -683,7 +693,7 @@ openerp.point_of_sale.load_screens = function load_screens(instance, module){ // // resets the current category to the root category reset_category: function(){ - this.set_category(); + this.set_category(this.pos.db.get_category_by_id(this.start_categ_id)); this.renderElement(); }, @@ -1510,12 +1520,19 @@ openerp.point_of_sale.load_screens = function load_screens(instance, module){ // } var lines = order.get_paymentlines(); + var due = order.get_due(); + var extradue = 0; + if (due && lines.length && due !== order.get_due(lines[lines.length-1])) { + extradue = due; + } + this.$('.paymentlines-container').empty(); var lines = $(QWeb.render('PaymentScreen-Paymentlines', { widget: this, order: order, paymentlines: lines, + extradue: extradue, })); lines.on('click','.delete-button',function(){ @@ -1557,6 +1574,27 @@ openerp.point_of_sale.load_screens = function load_screens(instance, module){ // this.$('.js_invoice').removeClass('highlight'); } }, + click_tip: function(){ + var self = this; + var order = this.pos.get_order(); + var tip = order.get_tip(); + var change = order.get_change(); + var value = tip; + + if (tip === 0 && change > 0 ) { + value = change; + } + + this.gui.show_popup('number',{ + 'title': tip ? _t('Change Tip') : _t('Add Tip'), + 'value': value, + 'confirm': function(value) { + order.set_tip(Number(value)); + self.order_changes(); + self.render_paymentlines(); + } + }); + }, click_set_customer: function(){ this.gui.show_screen('clientlist'); }, @@ -1586,6 +1624,10 @@ openerp.point_of_sale.load_screens = function load_screens(instance, module){ // this.$('.js_set_customer').click(function(){ self.click_set_customer(); }); + + this.$('.js_tip').click(function(){ + self.click_tip(); + }); this.$('.js_invoice').click(function(){ self.click_invoice(); }); diff --git a/addons/point_of_sale/static/src/xml/pos.xml b/addons/point_of_sale/static/src/xml/pos.xml index 955cde86837..8aaba0bf1ff 100644 --- a/addons/point_of_sale/static/src/xml/pos.xml +++ b/addons/point_of_sale/static/src/xml/pos.xml @@ -131,7 +131,6 @@ -
@@ -512,6 +511,11 @@ + + + + + @@ -541,7 +545,6 @@ -
@@ -595,6 +598,11 @@ + +
+ Tip +
+
Open Cashbox @@ -668,6 +676,9 @@
Served by
+ +
Guests:
+


@@ -983,17 +994,29 @@ - + + + + +
- + + + + +
- + + + + +
@@ -1004,12 +1027,12 @@
@@ -1074,21 +1097,23 @@
-
    - -
  • - Your shopping cart is empty -
  • -
    -
-
-
-
- Total: 0.00 € -
Taxes: 0.00€
+ +
+ +

Your shopping cart is empty

+
+
+ +
    +
    +
    +
    + Total: 0.00 € +
    Taxes: 0.00€
    +
    -
    +
    @@ -1097,9 +1122,9 @@ -
    +

    Debug Window

    -
    ▾
    +

    Electronic Scale

      diff --git a/addons/pos_restaurant/restaurant.py b/addons/pos_restaurant/restaurant.py index d11bf26ad31..512b1e7cdc3 100644 --- a/addons/pos_restaurant/restaurant.py +++ b/addons/pos_restaurant/restaurant.py @@ -31,34 +31,41 @@ _logger = logging.getLogger(__name__) class restaurant_floor(osv.osv): _name = 'restaurant.floor' _columns = { - 'name': fields.char('Floor Name', size=32, required=True, help='An internal identification of the restaurant floor'), + 'name': fields.char('Floor Name', required=True, help='An internal identification of the restaurant floor'), 'pos_config_id': fields.many2one('pos.config','Point of Sale'), 'background_image': fields.binary('Background Image', help='A background image used to display a floor layout in the point of sale interface'), + 'background_color': fields.char('Background Color', help='The background color of the floor layout, (must be specified in a html-compatible format)'), 'table_ids': fields.one2many('restaurant.table','floor_id','Tables', help='The list of tables in this floor'), 'sequence': fields.integer('Sequence',help='Used to sort Floors'), } _defaults = { 'sequence': 1, + 'background_color': 'rgb(210, 210, 210)', } + def set_background_color(self, cr, uid, id, background, context=None): + self.write(cr, uid, [id], {'background_color': background}, context=context) + class restaurant_table(osv.osv): _name = 'restaurant.table' _columns = { 'name': fields.char('Table Name', size=32, required=True, help='An internal identification of a table'), 'floor_id': fields.many2one('restaurant.floor','Floor'), 'shape': fields.selection([('square','Square'),('round','Round')],'Shape', required=True), - 'position_h': fields.float('Horizontal Position', help="The table's horizontal position from the left side to the table's center, in percentage of the floor's width"), - 'position_v': fields.float('Vertical Position', help="The table's vertical position from the top to the table's center, in percentage of the floor's height"), - 'width': fields.float('Width', help="The table's width in percentage of the floor's width"), - 'height': fields.float('Height', help="The table's height in percentage of the floor's height"), - 'color': fields.char('Color', size=32, help="The table's color"), + 'position_h': fields.float('Horizontal Position', help="The table's horizontal position from the left side to the table's center, in pixels"), + 'position_v': fields.float('Vertical Position', help="The table's vertical position from the top to the table's center, in pixels"), + 'width': fields.float('Width', help="The table's width in pixels"), + 'height': fields.float('Height', help="The table's height in pixels"), + 'seats': fields.integer('Seats', help="The default number of customer served at this table."), + 'color': fields.char('Color', help="The table's color, expressed as a valid 'background' CSS property value"), 'active': fields.boolean('Active',help='If false, the table is deactivated and will not be available in the point of sale'), 'pos_order_ids':fields.one2many('pos.order','table_id','Pos Orders', help='The orders served at this table'), } _defaults = { 'shape': 'square', + 'seats': 1, 'position_h': 10, 'position_v': 10, 'height': 50, @@ -116,4 +123,11 @@ class pos_order(osv.osv): _inherit = 'pos.order' _columns = { 'table_id': fields.many2one('restaurant.table','Table', help='The table where this order was served'), + 'customer_count' : fields.integer('Guests', help='The amount of customers that have been served by this order.'), } + + def _order_fields(self, cr, uid, ui_order, context=None): + fields = super(pos_order,self)._order_fields(cr,uid,ui_order,context) + fields['table_id'] = ui_order.get('table_id',0) + fields['customer_count'] = ui_order.get('customer_count',0) + return fields diff --git a/addons/pos_restaurant/restaurant_view.xml b/addons/pos_restaurant/restaurant_view.xml index b676db3f8f3..27f323651b7 100644 --- a/addons/pos_restaurant/restaurant_view.xml +++ b/addons/pos_restaurant/restaurant_view.xml @@ -2,6 +2,21 @@ + + + + + pos.order.form.view.inherit + pos.order + + + + + + + + + @@ -14,10 +29,12 @@ + + @@ -61,10 +78,12 @@
      + + + + - - diff --git a/addons/pos_restaurant/static/src/css/restaurant.css b/addons/pos_restaurant/static/src/css/restaurant.css index 1bbac339406..ec6c2f2f365 100644 --- a/addons/pos_restaurant/static/src/css/restaurant.css +++ b/addons/pos_restaurant/static/src/css/restaurant.css @@ -2,7 +2,6 @@ .screen .screen-content-flexbox { margin: 0px auto; - max-width: 1024px; text-align: left; height: 100%; overflow: hidden; @@ -49,25 +48,21 @@ background-repeat: no-repeat; overflow: hidden; background-size: cover; + transition: all 300ms ease-in-out; } +.floor-map .tables { + position: relative; +} @media screen and (min-width: 1024px) { - .floor-map { - margin: 8px; - border-radius: 3px; - } - .floor-selector { - margin: 8px; - margin-bottom: 0; - box-sizing: border-box; - width: auto; - border: none; - } - .floor-selector .button { - border-left: none; - } - .floor-selector .button.active{ - border-radius: 3px; + .floor-map .tables { + max-width: 1024px; + margin: auto; + max-height: 540px; + border-radius: 0px 0px 6px 6px; + border: dashed 2px rgba(0,0,0,0.1); + border-top: none; + height: 100%; } } @@ -80,11 +75,42 @@ border-radius: 3px; cursor: pointer; box-shadow: 0px 3px rgba(0,0,0,0.07); + transition: background, background-color 300ms ease-in-out; +} +.floor-map .table .table-cover { + display: block; + position: absolute; + left: 0; right: 0; bottom: 0; + border-radius: 0px 0px 3px 3px; + background: rgba(0,0,0,0.2); +} +.floor-map .table .table-cover.full { + border-radius: 3px 3px 3px 3px; +} +.floor-map .table .table-seats { + position: absolute; + display: inline-block; + bottom: 0; + left: 50%; + height: 20px; + width: 20px; + line-height: 20px; + font-size: 16px; + border-radius: 50%; + margin-left: -10px; + margin-bottom: 4px; + background: black; + color: white; + opacity: 0.2; + z-index: 3; } .floor-map .table .label { display: block; max-height: 100%; overflow: hidden; + position: relative; + bottom: 5px; + z-index: 5; } .floor-map .table.selected { outline: solid rgba(255,255,255,0.3); @@ -96,7 +122,7 @@ top: 0; right: 0; font-size: 20px; - margin: 4px; + margin: 8px; line-height: 32px; width: 32px; text-align: center; @@ -106,20 +132,21 @@ } .floor-map .edit-button.editing.active { background: #444; + border-color: transparent; color: white; } .floor-map .edit-bar { position: absolute; top: 0; right: 40px; - margin: 4px; - line-height: 32px; + margin: 8px; + line-height: 34px; text-align: center; border-radius: 5px; cursor: pointer; font-size: 20px; - border: solid 1px rgba(0,0,0,0.2); - background: #F0EEEE; + background: rgba(255,255,255,0.5); + z-index: 100; } .floor-map .edit-bar .edit-button { position: relative; @@ -127,14 +154,15 @@ display: inline-block; cursor: pointer; margin-right: -4px; - border-right: solid 1px rgba(0,0,0,0.1); + border-right: solid 1px rgba(0,0,0,0.2); transition: all 150ms linear; } .floor-map .edit-bar .edit-button.disabled { - opacity: 0.5; - border-right: solid 1px rgba(0,0,0,0.2); cursor: default; } +.floor-map .edit-bar .edit-button.disabled > * { + opacity: 0.5; +} .floor-map .edit-bar .color-picker { position: absolute; left: -106px; @@ -192,6 +220,7 @@ box-shadow: 0px 2px 3px rgba(0,0,0,0.2); cursor: grab; transition: all 150ms linear; + z-index: 100; } .floor-map .table.selected .table-handle:hover { width: 20px; @@ -217,6 +246,7 @@ line-height: 20px; border-radius: 10px; font-size: 16px; + z-index: 10; } .floor-map .table .order-count.notify-printing { background: red; @@ -239,6 +269,18 @@ .pos .order-button.floor-button .fa{ font-size: 24px; } +/* ------ ORDER LINE STATUS ------- */ + +.pos .order .orderline.dirty { + border-left: solid 6px #6EC89B; + color: #6EC89B; + padding-left: 9px; +} +.pos .order .orderline.skip { + border-left: solid 6px #7F82AC; + color: #7F82AC; + padding-left: 9px; +} /* ------ ORDER NOTES ------- */ diff --git a/addons/pos_restaurant/static/src/js/floors.js b/addons/pos_restaurant/static/src/js/floors.js index 8a43c91f00f..d8caffd162e 100644 --- a/addons/pos_restaurant/static/src/js/floors.js +++ b/addons/pos_restaurant/static/src/js/floors.js @@ -5,7 +5,7 @@ openerp.pos_restaurant.load_floors = function(instance,module){ // At POS Startup, load the floors, and add them to the pos model module.load_models({ model: 'restaurant.floor', - fields: ['name','background_image','table_ids','sequence'], + fields: ['name','background_color','table_ids','sequence'], domain: function(self){ return [['pos_config_id','=',self.config.id]] }, loaded: function(self,floors){ self.floors = floors; @@ -27,7 +27,7 @@ openerp.pos_restaurant.load_floors = function(instance,module){ // them with their floor. module.load_models({ model: 'restaurant.table', - fields: ['name','width','height','position_h','position_v','shape','floor_id','color'], + fields: ['name','width','height','position_h','position_v','shape','floor_id','color','seats'], loaded: function(self,tables){ self.tables_by_id = {}; for (var i = 0; i < tables.length; i++) { @@ -161,8 +161,8 @@ openerp.pos_restaurant.load_floors = function(instance,module){ } }, set_table_color: function(color){ - this.table.color = color; - this.renderElement(); + this.table.color = _.escape(color); + this.$el.css({'background': this.table.color}); }, set_table_name: function(name){ if (name) { @@ -170,6 +170,12 @@ openerp.pos_restaurant.load_floors = function(instance,module){ this.renderElement(); } }, + set_table_seats: function(seats){ + if (seats) { + this.table.seats = Number(seats); + this.renderElement(); + } + }, // The table's positioning is handled via css absolute positioning, // which is handled here. table_style: function(){ @@ -187,7 +193,7 @@ openerp.pos_restaurant.load_floors = function(instance,module){ unit(Math.max(table.width,table.height)/2) : '3px', }; if (table.color) { - style['background-color'] = table.color; + style['background'] = table.color; } if (table.height >= 150 && table.width >= 150) { style['font-size'] = '32px'; @@ -238,6 +244,13 @@ openerp.pos_restaurant.load_floors = function(instance,module){ } self.renderElement(); }); + }, function(err,event) { + self.gui.show_popup('error',{ + 'title':_t('Changes could not be saved'), + 'body': _t('Check your internet connection and access rights'), + }); + event.stopPropagation(); + event.preventDefault(); }); }, // destroy the table. We do not really destroy it, we set it @@ -283,8 +296,10 @@ openerp.pos_restaurant.load_floors = function(instance,module){ }, renderElement: function(){ var self = this; - this.order_count = this.pos.get_table_orders(this.table).length; - this.notifications = this.get_notifications(); + this.order_count = this.pos.get_table_orders(this.table).length; + this.customer_count = this.pos.get_customer_count(this.table); + this.fill = Math.min(1,Math.max(0,this.customer_count / this.table.seats)); + this.notifications = this.get_notifications(); this._super(); this.$el.on('mouseup', function(event){ self.click_handler(event,$(this)); }); @@ -347,6 +362,29 @@ openerp.pos_restaurant.load_floors = function(instance,module){ background_image_url: function(floor) { return '/web/binary/image?model=restaurant.floor&id='+floor.id+'&field=background_image'; }, + get_floor_style: function() { + var style = ""; + if (this.floor.background_image) { + style += "background-image: url(" + this.background_image_url(this.floor) + "); "; + } + if (this.floor.background_color) { + style += "background-color: " + _.escape(this.floor.background_color) + ";"; + } + return style; + }, + set_background_color: function(background) { + this.floor.background_color = background; + (new instance.web.Model('restaurant.floor')) + .call('set_background_color',[this.floor.id, background]).fail(function(err,event){ + self.gui.show_popup('error',{ + 'title':_t('Changes could not be saved'), + 'body': _t('Check your internet connection and access rights'), + }); + event.stopPropagation(); + event.preventDefault(); + }); + this.$('.floor-map').css({"background-color": _.escape(background)}); + }, deselect_tables: function(){ for (var i = 0; i < this.table_widgets.length; i++) { var table = this.table_widgets[i]; @@ -378,13 +416,18 @@ openerp.pos_restaurant.load_floors = function(instance,module){ } }, tool_colorpicker_open: function(){ + this.$('.color-picker').addClass('oe_hidden'); if (this.selected_table) { - this.$('.color-picker').removeClass('oe_hidden'); + this.$('.color-picker.fg-picker').removeClass('oe_hidden'); + } else { + this.$('.color-picker.bg-picker').removeClass('oe_hidden'); } }, tool_colorpicker_pick: function(event,$el){ if (this.selected_table) { this.selected_table.set_table_color($el[0].style['background-color']); + } else { + this.set_background_color($el[0].style['background-color']); } }, tool_colorpicker_close: function(){ @@ -402,6 +445,19 @@ openerp.pos_restaurant.load_floors = function(instance,module){ }); } }, + tool_change_seats: function(){ + var self = this; + if (this.selected_table) { + this.gui.show_popup('number',{ + 'title':_t('Number of Seats ?'), + 'cheap': true, + 'value': this.selected_table.table.seats, + 'confirm': function(value) { + self.selected_table.set_table_seats(value); + }, + }); + } + }, tool_duplicate_table: function(){ if (this.selected_table) { var tw = this.create_table(this.selected_table.table); @@ -413,20 +469,36 @@ openerp.pos_restaurant.load_floors = function(instance,module){ }, tool_new_table: function(){ var tw = this.create_table({ - 'position_v': 50, - 'position_h': 50, - 'width': 50, - 'height': 50, - 'name': 'T1', + 'position_v': 100, + 'position_h': 100, + 'width': 75, + 'height': 75, 'shape': 'square', + 'seats': 1, }); this.select_table(tw); }, + new_table_name: function(name){ + if (name) { + var num = Number((name.match(/\d+/g) || [])[0] || 0); + var str = (name.replace(/\d+/g,'')); + var n = {num: num, str:str}; + n.num += 1; + this.last_name = n; + } else if (this.last_name) { + this.last_name.num += 1; + } else { + this.last_name = {num: 1, str:'T'}; + } + return '' + this.last_name.str + this.last_name.num; + }, create_table: function(params) { var table = {}; for (var p in params) { table[p] = params[p]; } + + table.name = this.new_table_name(params.name); delete table['id']; table.floor_id = [this.floor.id,'']; @@ -434,7 +506,7 @@ openerp.pos_restaurant.load_floors = function(instance,module){ this.floor.tables.push(table); var tw = new module.TableWidget(this,{table: table}); - tw.appendTo('.floor-map'); + tw.appendTo('.floor-map .tables'); this.table_widgets.push(tw); return tw; }, @@ -499,7 +571,7 @@ openerp.pos_restaurant.load_floors = function(instance,module){ var tw = new module.TableWidget(this,{ table: this.floor.tables[i], }); - tw.appendTo(this.$('.floor-map')); + tw.appendTo(this.$('.floor-map .tables')); this.table_widgets.push(tw); } @@ -527,6 +599,10 @@ openerp.pos_restaurant.load_floors = function(instance,module){ self.tool_rename_table(); }); + this.$('.edit-button.seats').click(function(event){ + self.tool_change_seats(); + }); + this.$('.edit-button.trash').click(function(event){ self.tool_trash_table(); }); @@ -538,7 +614,6 @@ openerp.pos_restaurant.load_floors = function(instance,module){ this.$('.color-picker .color').click(function(event){ self.tool_colorpicker_pick(event,$(this)); - self.tool_colorpicker_close(); event.stopPropagation(); }); @@ -546,8 +621,9 @@ openerp.pos_restaurant.load_floors = function(instance,module){ self.toggle_editing(); }); - this.$('.floor-map').click(function(event){ - if (event.target === self.$('.floor-map')[0]) { + this.$('.floor-map,.floor-map .tables').click(function(event){ + if (event.target === self.$('.floor-map')[0] || + event.target === self.$('.floor-map .tables')[0]) { self.deselect_tables(); } }); @@ -589,6 +665,13 @@ openerp.pos_restaurant.load_floors = function(instance,module){ if (!this.table) { this.table = this.pos.table; } + if (!this.customer_count) { + if (this.table) { + this.customer_count = this.table.seats; + } else { + this.customer_count = 1; + } + } this.save_to_db(); }, export_as_JSON: function() { @@ -597,19 +680,29 @@ openerp.pos_restaurant.load_floors = function(instance,module){ json.table_id = this.table ? this.table.id : false; json.floor = this.table ? this.table.floor.name : false; json.floor_id = this.table ? this.table.floor.id : false; + json.customer_count = this.customer_count; return json; }, init_from_JSON: function(json) { _super_order.init_from_JSON.apply(this,arguments); this.table = this.pos.tables_by_id[json.table_id]; this.floor = this.table ? this.pos.floors_by_id[json.floor_id] : undefined; + this.customer_count = json.customer_count || 1; }, export_for_printing: function() { var json = _super_order.export_for_printing.apply(this,arguments); json.table = this.table ? this.table.name : undefined; json.floor = this.table ? this.table.floor.name : undefined; + json.customer_count = this.get_customer_count(); return json; }, + get_customer_count: function(){ + return this.customer_count; + }, + set_customer_count: function(count) { + this.customer_count = Math.max(count,0); + this.trigger('change'); + }, }); // We need to modify the OrderSelector to hide itself when we're on @@ -724,6 +817,16 @@ openerp.pos_restaurant.load_floors = function(instance,module){ return t_orders; }, + // get customer count at table + get_customer_count: function(table) { + var orders = this.get_table_orders(table); + var count = 0; + for (var i = 0; i < orders.length; i++) { + count += orders[i].get_customer_count(); + } + return count; + }, + // When we validate an order we go back to the floor plan. // When we cancel an order and there is multiple orders // on the table, stay on the table. @@ -740,6 +843,50 @@ openerp.pos_restaurant.load_floors = function(instance,module){ _super_posmodel.on_removed_order.apply(this,arguments); } }, + + + }); + + module.TableGuestsButton = module.ActionButtonWidget.extend({ + template: 'TableGuestsButton', + guests: function() { + if (this.pos.get_order()) { + return this.pos.get_order().customer_count; + } else { + return 0; + } + }, + button_click: function() { + var self = this; + this.gui.show_popup('number', { + 'title': _t('Guests ?'), + 'cheap': true, + 'value': this.pos.get_order().customer_count, + 'confirm': function(value) { + value = Math.max(1,Number(value)); + self.pos.get_order().set_customer_count(value); + self.renderElement(); + }, + }); + }, + }); + + module.OrderWidget.include({ + update_summary: function(){ + this._super(); + if (this.getParent().action_buttons && + this.getParent().action_buttons.guests) { + this.getParent().action_buttons.guests.renderElement(); + } + }, + }); + + module.define_action_button({ + 'name': 'guests', + 'widget': module.TableGuestsButton, + 'condition': function(){ + return this.pos.config.iface_floorplan; + }, }); }; diff --git a/addons/pos_restaurant/static/src/js/multiprint.js b/addons/pos_restaurant/static/src/js/multiprint.js index 61b8c1663a4..9d04d1b7c8f 100644 --- a/addons/pos_restaurant/static/src/js/multiprint.js +++ b/addons/pos_restaurant/static/src/js/multiprint.js @@ -51,10 +51,65 @@ openerp.pos_restaurant.load_multiprint = function(instance,module){ self.printers.push(printer); } } + self.config.iface_printers = !!self.printers.length; }, }); + var _super_orderline = module.Orderline.prototype; module.Orderline = module.Orderline.extend({ + initialize: function(args) { + _super_orderline.initialize.apply(this,arguments); + if (!this.pos.config.iface_printers) { + return; + } + if (typeof this.mp_dirty === 'undefined') { + // mp dirty is true if this orderline has changed + // since the last kitchen print + this.mp_dirty = true; + } + if (!this.mp_skip) { + // mp_skip is true if the cashier want this orderline + // not to be sent to the kitchen + this.mp_skip = false; + } + }, + init_from_JSON: function(json) { + _super_orderline.init_from_JSON.apply(this,arguments); + this.mp_dirty = json.mp_dirty; + this.mp_skip = json.mp_skip; + }, + export_as_JSON: function() { + var json = _super_orderline.export_as_JSON.apply(this,arguments); + json.mp_dirty = this.mp_dirty; + json.mp_skip = this.mp_skip; + return json; + }, + set_quantity: function(quantity) { + if (this.pos.config.iface_printers && quantity !== this.quantity) { + this.mp_dirty = true; + } + _super_orderline.set_quantity.apply(this,arguments); + }, + can_be_merged_with: function(orderline) { + return (!this.mp_skip) && + (!orderline.mp_skip) && + _super_orderline.can_be_merged_with.apply(this,arguments); + }, + set_skip: function(skip) { + if (this.mp_dirty && skip && !this.mp_skip) { + this.mp_skip = true; + this.trigger('change',this); + } + if (this.mp_skip && !skip) { + this.mp_dirty = true; + this.mp_skip = false; + this.trigger('change',this); + } + }, + set_dirty: function(dirty) { + this.mp_dirty = dirty; + this.trigger('change',this); + }, get_line_diff_hash: function(){ if (this.get_note()) { return this.get_product().id + '|' + this.get_note(); @@ -64,11 +119,44 @@ openerp.pos_restaurant.load_multiprint = function(instance,module){ }, }); + module.OrderWidget.include({ + render_orderline: function(orderline) { + var node = this._super(orderline); + if (this.pos.config.iface_printers) { + if (orderline.mp_skip) { + node.classList.add('skip'); + } else if (orderline.mp_dirty) { + node.classList.add('dirty'); + } + } + return node; + }, + click_line: function(line, event) { + if (!this.pos.config.iface_printers) { + this._super(line, event); + } else if (this.pos.get_order().selected_orderline !== line) { + this.mp_dbclk_time = (new Date()).getTime(); + } else if (!this.mp_dbclk_time) { + this.mp_dbclk_time = (new Date()).getTime(); + } else if (this.mp_dbclk_time + 500 > (new Date()).getTime()) { + line.set_skip(!line.mp_skip); + this.mp_dbclk_time = 0; + } else { + this.mp_dbclk_time = (new Date()).getTime(); + } + + this._super(line, event); + }, + }); + var _super_order = module.Order.prototype; module.Order = module.Order.extend({ build_line_resume: function(){ var resume = {}; this.orderlines.each(function(line){ + if (line.mp_skip) { + return; + } var line_hash = line.get_line_diff_hash(); var qty = Number(line.get_quantity()); var note = line.get_note(); @@ -85,6 +173,9 @@ openerp.pos_restaurant.load_multiprint = function(instance,module){ }, saveChanges: function(){ this.saved_resume = this.build_line_resume(); + this.orderlines.each(function(line){ + line.set_dirty(false); + }); this.trigger('change',this); }, computeChanges: function(categories){ @@ -229,13 +320,6 @@ openerp.pos_restaurant.load_multiprint = function(instance,module){ order.saveChanges(); } }, - hilight: function(hi){ - if (hi) { - this.$el.addClass('highlight'); - } else { - this.$el.removeClass('highlight'); - } - }, }); module.define_action_button({ diff --git a/addons/pos_restaurant/static/src/js/splitbill.js b/addons/pos_restaurant/static/src/js/splitbill.js index cc640599512..f3d672ca7ac 100644 --- a/addons/pos_restaurant/static/src/js/splitbill.js +++ b/addons/pos_restaurant/static/src/js/splitbill.js @@ -125,6 +125,9 @@ openerp.pos_restaurant.load_splitbill = function(instance, module){ neworder.saveChanges(); } + neworder.set_customer_count(1); + order.set_customer_count(order.get_customer_count() - 1); + this.pos.get('orders').add(neworder); this.pos.set('selectedOrder',neworder); } diff --git a/addons/pos_restaurant/static/src/xml/floors.xml b/addons/pos_restaurant/static/src/xml/floors.xml index dc8ba35eccb..63a5574291e 100644 --- a/addons/pos_restaurant/static/src/xml/floors.xml +++ b/addons/pos_restaurant/static/src/xml/floors.xml @@ -17,15 +17,30 @@ + +
      + + + + Guests +
      +
      +
      + +
      @@ -33,6 +48,7 @@ + @@ -70,7 +86,8 @@
    -
    +
    +
    @@ -82,25 +99,42 @@ + + + - + -
    +
    - - - + + + - - - + + + +
    +
    +
    + +
    + + + + + + + + +