function pos_screens(instance, module){ //module is instance.point_of_sale var QWeb = instance.web.qweb, _t = instance.web._t; var round_pr = instance.web.round_precision module.ClientListScreenWidget = module.ScreenWidget.extend({ template: 'ClientListScreenWidget', init: function(parent, options){ this._super(parent, options); }, show_leftpane: false, auto_back: true, show: function(){ var self = this; this._super(); this.renderElement(); this.details_visible = false; this.old_client = this.pos.get('selectedOrder').get('client'); this.new_client = this.old_client; this.$('.back').click(function(){ self.pos_widget.screen_selector.back(); }); this.$('.next').click(function(){ self.save_changes(); self.pos_widget.screen_selector.back(); }); this.$('.new-customer').click(function(){ self.display_client_details('edit',{ 'country_id': self.pos.company.country_id, }); }); var partners = this.pos.db.get_partners_sorted(1000); this.render_list(partners); this.reload_partners(); if( this.old_client ){ this.display_client_details('show',this.old_client,0); } this.$('.client-list-contents').delegate('.client-line','click',function(event){ self.line_select(event,$(this),parseInt($(this).data('id'))); }); var search_timeout = null; if(this.pos.config.iface_vkeyboard && this.pos_widget.onscreen_keyboard){ this.pos_widget.onscreen_keyboard.connect(this.$('.searchbox input')); } this.$('.searchbox input').on('keyup',function(event){ clearTimeout(search_timeout); var query = this.value; search_timeout = setTimeout(function(){ self.perform_search(query,event.which === 13); },70); }); this.$('.searchbox .search-clear').click(function(){ self.clear_search(); }); }, barcode_client_action: function(code){ if (this.editing_client) { this.$('.detail.barcode').val(code.code); } else if (this.pos.db.get_partner_by_ean13(code.code)) { this.display_client_details('show',this.pos.db.get_partner_by_ean13(code.code)); } }, perform_search: function(query, associate_result){ var customers; if(query){ customers = this.pos.db.search_partner(query); this.display_client_details('hide'); if ( associate_result && customers.length === 1){ this.new_client = customers[0]; this.save_changes(); this.pos_widget.screen_selector.back(); } this.render_list(customers); }else{ customers = this.pos.db.get_partners_sorted(); this.render_list(customers); } }, clear_search: function(){ var customers = this.pos.db.get_partners_sorted(1000); this.render_list(customers); this.$('.searchbox input')[0].value = ''; this.$('.searchbox input').focus(); }, render_list: function(partners){ var contents = this.$el[0].querySelector('.client-list-contents'); contents.innerHTML = ""; for(var i = 0, len = Math.min(partners.length,1000); i < len; i++){ var partner = partners[i]; var clientline_html = QWeb.render('ClientLine',{widget: this, partner:partners[i]}); var clientline = document.createElement('tbody'); clientline.innerHTML = clientline_html; clientline = clientline.childNodes[1]; if( partners === this.new_client ){ clientline.classList.add('highlight'); }else{ clientline.classList.remove('highlight'); } contents.appendChild(clientline); } }, save_changes: function(){ if( this.has_client_changed() ){ this.pos.get('selectedOrder').set_client(this.new_client); } }, has_client_changed: function(){ if( this.old_client && this.new_client ){ return this.old_client.id !== this.new_client.id; }else{ return !!this.old_client !== !!this.new_client; } }, toggle_save_button: function(){ var $button = this.$('.button.next'); if (this.editing_client) { $button.addClass('oe_hidden'); return; } else if( this.new_client ){ if( !this.old_client){ $button.text(_t('Set Customer')); }else{ $button.text(_t('Change Customer')); } }else{ $button.text(_t('Deselect Customer')); } $button.toggleClass('oe_hidden',!this.has_client_changed()); }, line_select: function(event,$line,id){ var partner = this.pos.db.get_partner_by_id(id); this.$('.client-list .lowlight').removeClass('lowlight'); if ( $line.hasClass('highlight') ){ $line.removeClass('highlight'); $line.addClass('lowlight'); this.display_client_details('hide',partner); this.new_client = null; this.toggle_save_button(); }else{ this.$('.client-list .highlight').removeClass('highlight'); $line.addClass('highlight'); var y = event.pageY - $line.parent().offset().top this.display_client_details('show',partner,y); this.new_client = partner; this.toggle_save_button(); } }, partner_icon_url: function(id){ return '/web/binary/image?model=res.partner&id='+id+'&field=image_small'; }, // ui handle for the 'edit selected customer' action edit_client_details: function(partner) { this.display_client_details('edit',partner); }, // ui handle for the 'cancel customer edit changes' action undo_client_details: function(partner) { if (!partner.id) { this.display_client_details('hide'); } else { this.display_client_details('show',partner); } }, // what happens when we save the changes on the client edit form -> we fetch the fields, sanitize them, // send them to the backend for update, and call saved_client_details() when the server tells us the // save was successfull. save_client_details: function(partner) { var self = this; var fields = {} this.$('.client-details-contents .detail').each(function(idx,el){ fields[el.name] = el.value; }); if (!fields.name) { this.pos_widget.screen_selector.show_popup('error',{ message: _t('A Customer Name Is Required'), }); return; } if (this.uploaded_picture) { fields.image = this.uploaded_picture; } fields.id = partner.id || false; fields.country_id = fields.country_id || false; fields.ean13 = fields.ean13 ? this.pos.barcode_reader.sanitize_ean(fields.ean13) : false; new instance.web.Model('res.partner').call('create_from_ui',[fields]).then(function(partner_id){ self.saved_client_details(partner_id, fields); },function(err,event){ event.preventDefault(); self.pos_widget.screen_selector.show_popup('error',{ 'message':_t('Error: Could not Save Changes'), 'comment':_t('Your Internet connection is probably down.'), }); }); }, // what happens when we've just pushed modifications for a partner of id partner_id saved_client_details: function(partner_id, fields){ var self = this; this.reload_partners().then(function(){ var partner = self.pos.db.get_partner_by_id(partner_id); partner['ruc'] = fields.ruc; if (partner) { self.new_client = partner; self.toggle_save_button(); self.display_client_details('show',partner); } else { // should never happen, because create_from_ui must return the id of the partner it // has created, and reload_partner() must have loaded the newly created partner. self.display_client_details('hide'); } }); }, // resizes an image, keeping the aspect ratio intact, // the resize is useful to avoid sending 12Mpixels jpegs // over a wireless connection. resize_image_to_dataurl: function(img, maxwidth, maxheight, callback){ img.onload = function(){ var png = new Image(); var canvas = document.createElement('canvas'); var ctx = canvas.getContext('2d'); var ratio = 1; if (img.width > maxwidth) { ratio = maxwidth / img.width; } if (img.height * ratio > maxheight) { ratio = maxheight / img.height; } var width = Math.floor(img.width * ratio); var height = Math.floor(img.height * ratio); canvas.width = width; canvas.height = height; ctx.drawImage(img,0,0,width,height); var dataurl = canvas.toDataURL(); callback(dataurl); } }, // Loads and resizes a File that contains an image. // callback gets a dataurl in case of success. load_image_file: function(file, callback){ var self = this; if (!file.type.match(/image.*/)) { this.pos_widget.screen_selector.show_popup('error',{ message:_t('Unsupported File Format'), comment:_t('Only web-compatible Image formats such as .png or .jpeg are supported'), }); return; } var reader = new FileReader(); reader.onload = function(event){ var dataurl = event.target.result; var img = new Image(); img.src = dataurl; self.resize_image_to_dataurl(img,800,600,callback); } reader.onerror = function(){ self.pos_widget.screen_selector.show_popup('error',{ message:_t('Could Not Read Image'), comment:_t('The provided file could not be read due to an unknown error'), }); }; reader.readAsDataURL(file); }, // This fetches partner changes on the server, and in case of changes, // rerenders the affected views reload_partners: function(){ var self = this; return this.pos.load_new_partners().then(function(){ self.render_list(self.pos.db.get_partners_sorted(1000)); // update the currently assigned client if it has been changed in db. var curr_client = self.pos.get_order().get_client(); if (curr_client) { self.pos.get_order().set_client(self.pos.db.get_partner_by_id(curr_client.id)); } }); }, // Shows,hides or edit the customer details box : // visibility: 'show', 'hide' or 'edit' // partner: the partner object to show or edit // clickpos: the height of the click on the list (in pixel), used // to maintain consistent scroll. display_client_details: function(visibility,partner,clickpos){ var self = this; var contents = this.$('.client-details-contents'); var parent = this.$('.client-list').parent(); var scroll = parent.scrollTop(); var height = contents.height(); contents.off('click','.button.edit'); contents.off('click','.button.save'); contents.off('click','.button.undo'); contents.on('click','.button.edit',function(){ self.edit_client_details(partner); }); contents.on('click','.button.save',function(){ self.save_client_details(partner); }); contents.on('click','.button.undo',function(){ self.undo_client_details(partner); }); this.editing_client = false; this.uploaded_picture = null; if(visibility === 'show'){ contents.empty(); contents.append($(QWeb.render('ClientDetails',{widget:this,partner:partner}))); var new_height = contents.height(); if(!this.details_visible){ if(clickpos < scroll + new_height + 20 ){ parent.scrollTop( clickpos - 20 ); }else{ parent.scrollTop(parent.scrollTop() + new_height); } }else{ parent.scrollTop(parent.scrollTop() - height + new_height); } this.details_visible = true; this.toggle_save_button(); } else if (visibility === 'edit') { this.editing_client = true; contents.empty(); contents.append($(QWeb.render('ClientDetailsEdit',{widget:this,partner:partner}))); this.toggle_save_button(); contents.find('.image-uploader').on('change',function(event){ self.load_image_file(event.target.files[0],function(res){ if (res) { contents.find('.client-picture img, .client-picture .fa').remove(); contents.find('.client-picture').append(""); contents.find('.detail.picture').remove(); self.uploaded_picture = res; } }); }); } else if (visibility === 'hide') { contents.empty(); if( height > scroll ){ contents.css({height:height+'px'}); contents.animate({height:0},400,function(){ contents.css({height:''}); }); }else{ parent.scrollTop( parent.scrollTop() - height); } this.details_visible = false; this.toggle_save_button(); } }, close: function(){ this._super(); }, }); module.ReceiptScreenWidget = module.ScreenWidget.extend({ template: 'ReceiptScreenWidget', show_numpad: false, show_leftpane: false, show: function(){ this._super(); var self = this; var print_button = this.add_action_button({ label: _t('Print'), icon: '/point_of_sale/static/src/img/icons/png48/printer.png', click: function(){ self.print(); }, }); var finish_button = this.add_action_button({ label: _t('Next Order'), icon: '/point_of_sale/static/src/img/icons/png48/go-next.png', click: function() { self.finishOrder(); }, }); this.refresh(); finish_button.set_disabled(true); setTimeout(function(){ finish_button.set_disabled(false); }, 2000); }, print: function() { this.pos.get('selectedOrder')._printed = true; window.print(); }, finishOrder: function() { this.pos.get('selectedOrder').destroy(); }, refresh: function() { var order = this.pos.get('selectedOrder'); $('.pos-receipt-container', this.$el).html(QWeb.render('PosTicket',{ widget:this, order: order, orderlines: order.get('orderLines').models, paymentlines: order.get('paymentLines').models, logo: order.pos.company_logo_base64 })); }, close: function(){ this._super(); } }); }