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 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+