diff --git a/pos_select_customer/__init__.py b/pos_select_customer/__init__.py new file mode 100644 index 00000000..b0eb36b9 --- /dev/null +++ b/pos_select_customer/__init__.py @@ -0,0 +1,22 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# Point Of Sale - Select Customer module for OpenERP +# Copyright (C) 2013-2014 GRAP (http://www.grap.coop) +# @author Julien WESTE +# @author Sylvain LE GAL (https://twitter.com/legalsylvain) +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## diff --git a/pos_select_customer/__openerp__.py b/pos_select_customer/__openerp__.py new file mode 100644 index 00000000..78127ef6 --- /dev/null +++ b/pos_select_customer/__openerp__.py @@ -0,0 +1,76 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# Point Of Sale - Select Customer module for OpenERP +# Copyright (C) 2014 GRAP (http://www.grap.coop) +# @author Julien WESTE +# @author Sylvain LE GAL (https://twitter.com/legalsylvain) +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +{ + 'name': 'Point Of Sale - Select Customers', + 'summary': 'Allow users to select a customer in Front End Point Of Sale', + 'version': '0.1', + 'category': 'Point Of Sale', + 'description': """ +Allow users to select a customer in Front End Point Of Sale +=========================================================== + +Functionality: +-------------- + * Allow user to set a customer to a pos order in front end views; + +Possible improvements and fix: +------------------------------ + * This module displays all the customers. That can be long to display + if there are a lot of customers in database; Display only 80 could be a + solution; + * Images of customers are loaded each time; Similar behaviour as + products image management (with cache) could be developped; + +NON Covered features: +--------------------- + * Possibility to create customers in front end views; + * Possibility to change price if customer has a list price different as + the default list price; (Big stuff); + * Possibility to see if the partner has not the default price list; + * Possibility to invoice in front-end views; + +Copyright, Authors and Licence: +------------------------------- + * Copyright: 2014, GRAP: Groupement Régional Alimentaire de Proximité; + * Author: + * Julien WESTE; + * Sylvain LE GAL (https://twitter.com/legalsylvain); + * Licence: AGPL-3 (http://www.gnu.org/licenses/);""", + 'author': 'GRAP', + 'website': 'http://www.grap.coop', + 'license': 'AGPL-3', + 'depends': [ + 'point_of_sale', + 'pos_second_header', + ], + 'qweb': [ + 'static/src/xml/psc.xml', + ], + 'js': [ + 'static/src/js/psc.js', + ], + 'css': [ + 'static/src/css/psc.css', + ], +} diff --git a/pos_select_customer/i18n/fr.po b/pos_select_customer/i18n/fr.po new file mode 100644 index 00000000..995255f7 --- /dev/null +++ b/pos_select_customer/i18n/fr.po @@ -0,0 +1,74 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# Point Of Sale - Select Customer module for OpenERP +# Copyright (C) 2013-2014 GRAP (http://www.grap.coop) +# @author Julien WESTE +# @author Sylvain LE GAL (https://twitter.com/legalsylvain) +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## +# Translation of OpenERP Server. +# This file contains the translation of the following modules: +# * pos_select_customer +# +msgid "" +msgstr "" +"Project-Id-Version: OpenERP Server 7.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2014-04-16 16:31+0000\n" +"PO-Revision-Date: 2014-04-16 16:31+0000\n" +"Last-Translator: <>\n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: pos_select_customer +#. openerp-web +#: code:addons/pos_select_customer/static/src/xml/psc.xml:48 +#, python-format +msgid "Cancel" +msgstr "Annuler" + +#. module: pos_select_customer +#. openerp-web +#: code:addons/pos_select_customer/static/src/js/psc.js:57 +#, python-format +msgid "Customer" +msgstr "Client" + +#. module: pos_select_customer +#. openerp-web +#: code:addons/pos_select_customer/static/src/xml/psc.xml:41 +#, python-format +msgid "Customer Selection" +msgstr "Sélection d'un client" + +#. module: pos_select_customer +#. openerp-web +#: code:addons/pos_select_customer/static/src/js/psc.js:68 +#, python-format +msgid "Del." +msgstr "Suppr." + +#. module: pos_select_customer +#. openerp-web +#: code:addons/pos_select_customer/static/src/xml/psc.xml:45 +#, python-format +msgid "Search Customers" +msgstr "Rechercher des clients" + diff --git a/pos_select_customer/static/src/css/psc.css b/pos_select_customer/static/src/css/psc.css new file mode 100644 index 00000000..b1129433 --- /dev/null +++ b/pos_select_customer/static/src/css/psc.css @@ -0,0 +1,168 @@ +/****************************************************************************** + Point Of Sale - Select Customer module for OpenERP + Copyright (C) 2014 GRAP (http://www.grap.coop) + @author Julien WESTE + @author Sylvain LE GAL (https://twitter.com/legalsylvain) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +******************************************************************************/ + +/* ********* Current customer name ********* */ + +.point-of-sale #rightheader #customer-name{ + width:200px; +} +.point-of-sale #rightheader #remove-customer-button{ + width:80px; +} + +/* ********* Customer PopUp ********* */ +.point-of-sale .modal-dialog .popup-select-customer{ + margin-left:0; + margin-top:0; + left:5%; + width: 90%; + top:5%; + height:90%; +} +.point-of-sale .modal-dialog .popup-select-customer .customer-header{ + height:65px; +} + +.point-of-sale .modal-dialog .popup-select-customer #customer-title{ +/* text-align:left;*/ +} +.point-of-sale .modal-dialog .popup-select-customer .customer-searchbox{ + float:left; + top: 20px; + position: absolute; + left: 10px; +} +.point-of-sale .modal-dialog .popup-select-customer #customer-cancel{ + top: 0px; + position: absolute; + right: 10px; +} +/* ********* Customer List ********* */ + +.point-of-sale .customer-list { + padding:10px !important; +} + +.point-of-sale .customer-list-container { + position:absolute; + top:70px; + bottom:0px; + left:0px; + right:0px; +} + +.point-of-sale .customer-list-scroller{ + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + -ms-box-sizing: border-box; + box-sizing: border-box; + width:100%; + height:100%; + overflow: hidden; +} + +/* ********* Customer Scrollbar ********* */ +/* Fix incorrect display of buttons.*/ +/* TODO: found why it is necessary and remove top,bottom and left values*/ +.point-of-sale .customer-list-container .scrollbar .up-button{ + top: -10px; + left: -5px; +} +.point-of-sale .customer-list-container .scrollbar .down-button { + left: -5px; + bottom: -5px; +} + +/* ********* Customer Item ********* */ + +.point-of-sale .customer { + position:relative; + vertical-align: top; + display: inline-block; + font-size: 11px; + margin: 5px !important; + width: 200px; + height:110px; + background:#fff; + border: 1px solid #fff; + border-radius: 3px; + overflow: hidden; + -webkit-box-shadow: 0px 2px 0px #dad8e4, 0px 1px 8px #636480; + -moz-box-shadow: 0px 2px 0px #dad8e4, 0px 1px 8px #636480; + box-shadow: 0px 2px 0px #dad8e4, 0px 1px 8px #636480; +} + +.point-of-sale .customer .customer-name, + .point-of-sale .customer .customer-email, + .point-of-sale .customer .customer-address, + .point-of-sale .customer .customer-phone, + .point-of-sale .customer .customer-mobile{ + position: absolute; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + -ms-box-sizing: border-box; + box-sizing: border-box; + + text-align:left; + overflow: hidden; + text-overflow: ellipsis; + background: -webkit-linear-gradient(-90deg,rgba(255,255,255,0),rgba(255,255,255,1), rgba(255,255,255,1)); + background: -moz-linear-gradient(-90deg,rgba(255,255,255,0),rgba(255,255,255,1), rgba(255,255,255,1)); + background: -ms-linear-gradient(-90deg,rgba(255,255,255,0),rgba(255,255,255,1), rgba(255,255,255,1)); + padding: 3px; +} +.point-of-sale .customer .customer-name{ + font-size: 13px; + width:100%; + top:0px; + height: 20px; +} +.point-of-sale .customer .customer-email{ + width:100%; + top:24px; + height: 16px; +} +.point-of-sale .customer .customer-img { + position: absolute; + top: 44px; + left: 0px; + width: 64px; + height: 64px; + background: white; + text-align: center; +} +.point-of-sale .customer .customer-address{ + width:135px; + top:44px; + left: 65px; + height: 32px; +} +.point-of-sale .customer .customer-phone{ + width:135px; + top:76px; + left: 65px; + height: 16px; +} +.point-of-sale .customer .customer-mobile{ + width:135px; + top:92px; + left: 65px; + height: 16px; +} diff --git a/pos_select_customer/static/src/img/icon.png b/pos_select_customer/static/src/img/icon.png new file mode 100644 index 00000000..c33037bb Binary files /dev/null and b/pos_select_customer/static/src/img/icon.png differ diff --git a/pos_select_customer/static/src/js/psc.js b/pos_select_customer/static/src/js/psc.js new file mode 100644 index 00000000..05491b94 --- /dev/null +++ b/pos_select_customer/static/src/js/psc.js @@ -0,0 +1,309 @@ +/****************************************************************************** + Point Of Sale - Select Customer module for OpenERP + Copyright (C) 2014 GRAP (http://www.grap.coop) + @author Julien WESTE + @author Sylvain LE GAL (https://twitter.com/legalsylvain) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +******************************************************************************/ + +openerp.pos_select_customer = function (instance) { + module = instance.point_of_sale; + _t = instance.web._t; + + /************************************************************************* + Define : CustomerOrderWidget that display the name of the customer + of the current pos order and display button to select of remove it. + */ + module.CustomerOrderWidget = module.PosBaseWidget.extend({ + template: 'CustomerOrderWidget', + + /* Overload Section */ + init: function(parent, options){ + this._super(parent,options); + this.pos.bind('change:selectedOrder', this.refresh, this); + }, + + start: function(){ + this._super(); + this._build_widgets(); + }, + + /* Custom Section */ + refresh: function(){ + this.renderElement(); + this._build_widgets(); + }, + + _build_widgets: function(){ + // Create a button to open the customer popup + this.select_customer_button = new module.HeaderButtonWidget(this,{ + label:_t('Customer'), + action: function(){ + self.screen_selector.show_popup('select-customer'); + }, + }); + this.select_customer_button.replace($('.placeholder-SelectCustomerButton')); + this.select_customer_button.renderElement(); + + if (this.get_name() !== ''){ + // Create a button to remove the current customer + this.remove_customer_button = new module.HeaderButtonWidget(this,{ + label:_t('Del.'), + action: function(){ + this.pos.get('selectedOrder').set_client(undefined); + this.pos_widget.customer_order.refresh(); + this.hide(); + }, + }); + this.remove_customer_button.replace($('.placeholder-RemoveCustomerButton')); + this.remove_customer_button.renderElement(); + } + }, + + get_name: function(){ + customer = this.pos.get('selectedOrder').get_client(); + if(customer){ + return customer.name; + }else{ + return ""; + } + }, + }); + + /************************************************************************* + Define : CustomerWidget that display a customer + */ + module.CustomerWidget = module.PosBaseWidget.extend({ + template: 'CustomerWidget', + + /* Overload Section */ + init: function(parent, options) { + this._super(parent,options); + this.model = options.model; + }, + + renderElement: function() { + this._super(); + this.$('img').replaceWith(this.pos_widget.image_cache.get_image(this.model.get_image_small_url())); + var self = this; + $("a", this.$el).click(function(e){ + self.pos.get('selectedOrder').set_client(self.model.toJSON()); + self.pos_widget.customer_order.refresh(); + self.pos_widget.screen_selector.set_current_screen('products'); + }); + }, + }); + + /************************************************************************* + Define : CustomerListScreenWidget that display a list of customers. + */ + module.CustomerListScreenWidget = module.ScreenWidget.extend({ + template:'CustomerListScreenWidget', + + init: function(parent, options) { + this._super(parent,options); + this.customer_list = []; + }, + + start: function() { + this._super(); + var self = this; + }, + + renderElement: function() { + this._super(); + var self = this; + // Delete old customers widget and display refreshed customers list + for(var i = 0, len = this.customer_list.length; i < len; i++){ + this.customer_list[i].destroy(); + } + this.customer_list = []; + var customers = this.pos.get('customer_list_filter') || []; + for(var i = 0, len = customers.models.length; i < len; i++){ + var customer = new module.CustomerWidget(this, { + model: customers.models[i], + click_product_action: this.click_product_action, + }); + this.customer_list.push(customer); + customer.appendTo(this.$('.customer-list')); + } + + // Delete old scrollbar widget and display refreshed scrollbar + if(this.scrollbar){ + this.scrollbar.destroy(); + } + this.scrollbar = new module.ScrollbarWidget(this,{ + target_widget: this, + target_selector: '.customer-list-scroller', + on_show: function(){ + self.$('.customer-list-scroller').css({'padding-right':'62px'},100); + }, + on_hide: function(){ + self.$('.customer-list-scroller').css({'padding-right':'0px'},100); + }, + }); + this.scrollbar.replace(this.$('.placeholder-ScrollbarWidget')); + }, + }), + + /************************************************************************* + Define : SelectCustomerPopupWidget that display a pop up to search + and select customers. + */ + module.SelectCustomerPopupWidget = module.PopUpWidget.extend({ + template:'SelectCustomerPopupWidget', + + start: function(){ + this._super(); + var self = this; + this.customer_list_widget = new module.CustomerListScreenWidget(this,{}); + }, + + show: function(){ + this._super(); + var self = this; + this.reset_customers(); + this.customer_list_widget.replace($('.placeholder-CustomerListScreenWidget')); + this.$('#customer-cancel').off('click').click(function(){ + self.pos_widget.screen_selector.set_current_screen('products'); + }); + // filter customers according to the search string + this.$('.customer-searchbox input').keyup(function(event){ + pattern = $(this).val().toLowerCase(); + if(pattern){ + var customers = self.pos.get('customer_list').search_customer(pattern); + self.pos.set({'customer_list_filter' : customers}); + self.$('.customer-search-clear').fadeIn(); + self.customer_list_widget.renderElement(); + } + else{ + self.reset_customers(); + } + }); + //reset the search when clicking on reset + this.$('.customer-search-clear').click(function(){ + self.reset_customers(); + }); + }, + + reset_customers: function(){ + this.pos.set({'customer_list_filter' : this.pos.get('customer_list')}); + this.$('.customer-search-clear').fadeOut(); + this.customer_list_widget.renderElement(); + this.$('.customer-searchbox input').val('').focus(); + }, + + }); + + + /************************************************************************* + Overload : PosWidget to include button in PosOrderHeaderWidget widget + to select or unselect customers + */ + module.PosWidget = module.PosWidget.extend({ + + build_widgets: function(){ + this._super(); + var self = this; + + // Add a widget to manage customer + this.customer_order = new module.CustomerOrderWidget(this,{}); + this.customer_order.appendTo(this.$('#pos_order_header')); + + // create a pop up 'select-customer' to search and select customers + this.select_customer_popup = new module.SelectCustomerPopupWidget(this, {}); + this.select_customer_popup.appendTo($('.point-of-sale')); + this.select_customer_popup.hide(); + this.screen_selector.popup_set['select-customer'] = this.select_customer_popup; + + }, + }); + + /************************************************************************* + Define : New Model 'Customer' + */ + module.Customer = Backbone.Model.extend({ + get_image_small_url: function(){ + return instance.session.url('/web/binary/image', {model: 'res.partner', field: 'image_small', id: this.get('id')}); + }, + }); + + module.CustomerCollection = Backbone.Collection.extend({ + model: module.Customer, + + search_customer: function(pattern){ + res = new module.CustomerCollection(); + var reg = RegExp(pattern,"i"); + for(var i = 0, len = this.models.length; i < len; i++){ + res_reg = reg.exec(this.models[i].attributes.name); + if (res_reg){ + res.push(this.models[i]); + } + } + return res; + }, + }); + + /* + Overload: PosModel.initialize() to define two new lists. + 'customer_list' are the list of all customers available; + 'customer_list_filter' are a sub-list according to the current filter + selection. + */ + var _initialize_ = module.PosModel.prototype.initialize; + module.PosModel.prototype.initialize = function(session, attributes){ + _initialize_.call(this, session, attributes); + this.set({ + 'customer_list': new module.CustomerCollection(), + 'customer_list_filter': new module.CustomerCollection(), + }); + }; + + /* + Overload: PosModel.load_server_data() function to get in memory + customers. + The function will load all usefull informations even if any + informations won't be used in this module, to allow further modules + to use them. + */ + var _load_server_data_ = module.PosModel.prototype.load_server_data; + module.PosModel.prototype.load_server_data = function(){ + var self = this; + var load_def = _load_server_data_.call(self).done(self.load_customers_data()); + return load_def; + }, + + module.PosModel = module.PosModel.extend({ + load_customers_data: function(){ + var self = this; + var loaded = self.fetch( + 'res.partner', + ['name','display_name','title','function','type', + 'parent_id','is_company', + 'lang','company_id','ean13','color', + 'contact_address','street','street2','city','zip','state_id','country_id', + 'property_product_pricelist','vat','debit_limit','credit_limit', + 'email','website','fax','phone','mobile',], + [['customer', '=', true]]) + .then(function(customers){ + console.log(customers); + self.set({'customer_list' : new module.CustomerCollection(customers)}); + self.set({'customer_list_filter' : new module.CustomerCollection(customers)}); + }); + return loaded; + }, + }); +}; + diff --git a/pos_select_customer/static/src/xml/psc.xml b/pos_select_customer/static/src/xml/psc.xml new file mode 100644 index 00000000..0558f17f --- /dev/null +++ b/pos_select_customer/static/src/xml/psc.xml @@ -0,0 +1,103 @@ + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+
+ +
+
+
+ +
+
+ + + + + + +
+
+
    +
+
+
+ +
+
+ + +
  • + +
    + +
    +
    + +
    +
    + + + +
    +
    + + + +
    +
    + + + +
    +
    + + + +
    +
    +
  • +
    + +