Browse Source

Merge pull request #3 from grap/7.0-pos_select_customer

[ADD] 7.0 'pos_select_customer' to select customer in Front End POS
pull/14/head
Sylvain LE GAL 10 years ago
parent
commit
0db2791aac
  1. 22
      pos_select_customer/__init__.py
  2. 76
      pos_select_customer/__openerp__.py
  3. 74
      pos_select_customer/i18n/fr.po
  4. 168
      pos_select_customer/static/src/css/psc.css
  5. BIN
      pos_select_customer/static/src/img/icon.png
  6. 309
      pos_select_customer/static/src/js/psc.js
  7. 103
      pos_select_customer/static/src/xml/psc.xml

22
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 <http://www.gnu.org/licenses/>.
#
##############################################################################

76
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 <http://www.gnu.org/licenses/>.
#
##############################################################################
{
'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',
],
}

74
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 <http://www.gnu.org/licenses/>.
#
##############################################################################
# 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"

168
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 <http://www.gnu.org/licenses/>.
******************************************************************************/
/* ********* 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;
}

BIN
pos_select_customer/static/src/img/icon.png

After

Width: 64  |  Height: 64  |  Size: 3.6 KiB

309
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 <http://www.gnu.org/licenses/>.
******************************************************************************/
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;
},
});
};

103
pos_select_customer/static/src/xml/psc.xml

@ -0,0 +1,103 @@
<?xml version="1.0" 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 <http://www.gnu.org/licenses/>. -->
<!-- ********************************************************************** -->
<templates id="template" xml:space="preserve">
<t t-name="CustomerOrderWidget">
<div class="extra-label">
<span class="placeholder-SelectCustomerButton" />
</div>
<div id="customer-name" class="extra-label">
<div class="extra-text">
<t t-esc="widget.get_name()" />
</div>
</div>
<div id="remove-customer-button" class="extra-label">
<span class="placeholder-RemoveCustomerButton" />
</div>
</t>
<t t-name="SelectCustomerPopupWidget">
<div class="modal-dialog">
<div class="popup popup-select-customer">
<div class="customer-header">
<div id="customer-title">
Customer Selection
</div>
<div class="customer-searchbox">
<input placeholder="Search Customers" />
<img class="customer-search-clear" src="/point_of_sale/static/src/img/search_reset.gif" />
</div>
<div id="customer-cancel" class="button">
Cancel
</div>
</div>
<div class="content-container">
<span class="placeholder-CustomerListScreenWidget" />
</div>
</div>
</div>
</t>
<t t-name="CustomerListScreenWidget">
<div class='customer-list-container'>
<div class="customer-list-scroller">
<ol id="customer-screen-ol" class="customer-list">
</ol>
</div>
<div class="shadow-top"></div>
<span class="placeholder-ScrollbarWidget" />
</div>
</t>
<t t-name="CustomerWidget">
<li class='customer'>
<a href="#">
<div class="customer-img">
<img sr='' />
</div>
<div class="customer-name">
<t t-esc="widget.model.get('name')"/>
</div>
<div class="customer-email">
<t t-if="widget.model.get('email')">
<t t-esc="widget.model.get('email')"/>
</t>
</div>
<div class="customer-address">
<t t-if="widget.model.get('contact_address')">
<t t-esc="widget.model.get('contact_address')"/>
</t>
</div>
<div class="customer-phone">
<t t-if="widget.model.get('phone')">
<t t-esc="widget.model.get('phone')"/>
</t>
</div>
<div class="customer-mobile">
<t t-if="widget.model.get('mobile')">
<t t-esc="widget.model.get('mobile')"/>
</t>
</div>
</a>
</li>
</t>
</templates>
Loading…
Cancel
Save