Sylvain LE GAL
10 years ago
9 changed files with 1047 additions and 0 deletions
-
21pos_product_template/__init__.py
-
67pos_product_template/__openerp__.py
-
36pos_product_template/demo/product_product.yml
-
25pos_product_template/demo/res_groups.yml
-
166pos_product_template/static/src/css/ppt.css
-
BINpos_product_template/static/src/img/icon.png
-
565pos_product_template/static/src/js/ppt.js
-
130pos_product_template/static/src/xml/ppt.xml
-
37pos_product_template/view/view.xml
@ -0,0 +1,21 @@ |
|||||
|
# -*- encoding: utf-8 -*- |
||||
|
############################################################################## |
||||
|
# |
||||
|
# Point Of Sale - Product Template module for Odoo |
||||
|
# Copyright (C) 2014-Today Akretion (http://www.akretion.com) |
||||
|
# @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/>. |
||||
|
# |
||||
|
############################################################################## |
@ -0,0 +1,67 @@ |
|||||
|
# -*- encoding: utf-8 -*- |
||||
|
############################################################################## |
||||
|
# |
||||
|
# Point Of Sale - Product Template module for Odoo |
||||
|
# Copyright (C) 2014-Today Akretion (http://www.akretion.com) |
||||
|
# @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 - Product Template', |
||||
|
'summary': 'Manage Product Template in Front End Point Of Sale', |
||||
|
'version': '0.1', |
||||
|
'category': 'Point Of Sale', |
||||
|
'description': """ |
||||
|
Manage Product Template in Front End Point Of Sale |
||||
|
================================================== |
||||
|
|
||||
|
Functionality: |
||||
|
-------------- |
||||
|
* |
||||
|
|
||||
|
Possible improvements and fix: |
||||
|
------------------------------ |
||||
|
* Display product template name in ProductList; |
||||
|
* Display attributes; |
||||
|
* Improve Template display; |
||||
|
|
||||
|
NON Covered features: |
||||
|
--------------------- |
||||
|
* |
||||
|
|
||||
|
Copyright, Authors and Licence: |
||||
|
------------------------------- |
||||
|
* Copyright: 2014-Today, Akretion; |
||||
|
* Author: |
||||
|
* Sylvain LE GAL (https://twitter.com/legalsylvain); |
||||
|
* Licence: AGPL-3 (http://www.gnu.org/licenses/);""", |
||||
|
'author': 'Akretion', |
||||
|
'website': 'http://www.akretion.com', |
||||
|
'license': 'AGPL-3', |
||||
|
'depends': [ |
||||
|
'point_of_sale', |
||||
|
], |
||||
|
'data': [ |
||||
|
'view/view.xml', |
||||
|
], |
||||
|
'qweb': [ |
||||
|
'static/src/xml/ppt.xml', |
||||
|
], |
||||
|
'demo': [ |
||||
|
'demo/product_product.yml', |
||||
|
'demo/res_groups.yml', |
||||
|
], |
||||
|
} |
@ -0,0 +1,36 @@ |
|||||
|
# -*- encoding: utf-8 -*- |
||||
|
############################################################################## |
||||
|
# |
||||
|
# Point Of Sale - Product Template module for Odoo |
||||
|
# Copyright (C) 2014-Today Akretion (http://www.akretion.com) |
||||
|
# @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/>. |
||||
|
# |
||||
|
############################################################################## |
||||
|
|
||||
|
- !record {model: product.product, id: product.product_product_4}: |
||||
|
available_in_pos: True |
||||
|
|
||||
|
- !record {model: product.product, id: product.product_product_4b}: |
||||
|
available_in_pos: True |
||||
|
|
||||
|
- !record {model: product.product, id: product.product_product_4c}: |
||||
|
available_in_pos: True |
||||
|
|
||||
|
- !record {model: product.product, id: product.product_product_11}: |
||||
|
available_in_pos: True |
||||
|
|
||||
|
- !record {model: product.product, id: product.product_product_11b}: |
||||
|
available_in_pos: True |
@ -0,0 +1,25 @@ |
|||||
|
# -*- encoding: utf-8 -*- |
||||
|
############################################################################## |
||||
|
# |
||||
|
# Point Of Sale - Product Template module for Odoo |
||||
|
# Copyright (C) 2014-Today Akretion (http://www.akretion.com) |
||||
|
# @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/>. |
||||
|
# |
||||
|
############################################################################## |
||||
|
|
||||
|
- !record {model: res.groups, id: base.group_no_one}: |
||||
|
users: |
||||
|
- base.user_root |
@ -0,0 +1,166 @@ |
|||||
|
/****************************************************************************** |
||||
|
Point Of Sale - Product Template module for Odoo |
||||
|
Copyright (C) 2014-Today Akretion (http://www.akretion.com) |
||||
|
@author Sylvain LE GAL (https://twitter.com/legalsylvain) |
||||
|
|
||||
|
Some part of code from Odoo Project, |
||||
|
Copyright (C) 2004-Today Odoo SA. (<http://odoo.com>). |
||||
|
|
||||
|
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/>. |
||||
|
******************************************************************************/ |
||||
|
|
||||
|
/* ********* Variant Selector PopUp ************************************** */ |
||||
|
.pos .modal-dialog .popup-select-variant{ |
||||
|
margin-left:0; |
||||
|
margin-top:0; |
||||
|
left:5%; |
||||
|
width: 90%; |
||||
|
top:5%; |
||||
|
height:85%; |
||||
|
} |
||||
|
|
||||
|
.pos .modal-dialog .popup-select-variant .variant-title{ |
||||
|
height: 8%; |
||||
|
} |
||||
|
|
||||
|
.pos .modal-dialog .popup-select-variant .variant-title #variant-popup-cancel{ |
||||
|
margin: -10px 3px 3px 3px; |
||||
|
} |
||||
|
|
||||
|
.pos .modal-dialog .popup-select-variant .container-attribute-list{ |
||||
|
width:100%; |
||||
|
height:30%; /*FIXME */ |
||||
|
overflow: hidden; |
||||
|
overflow-y: auto; |
||||
|
border-bottom: 1px dashed #444; |
||||
|
-webkit-overflow-scrolling: touch; |
||||
|
} |
||||
|
|
||||
|
.pos .modal-dialog .popup-select-variant .container-variant-list{ |
||||
|
width:100%; |
||||
|
height:60%; /*FIXME */ |
||||
|
overflow: hidden; |
||||
|
overflow-y: auto; |
||||
|
-webkit-overflow-scrolling: touch; |
||||
|
} |
||||
|
|
||||
|
.pos .variant-list { |
||||
|
padding: 10px; |
||||
|
text-align: left; |
||||
|
-webkit-transform: translate3d(0,0,0); |
||||
|
} |
||||
|
|
||||
|
/* ********* Attribut Display ******************************************** */ |
||||
|
.pos .attribute { |
||||
|
position:relative; |
||||
|
width: 100%; |
||||
|
height:50px; |
||||
|
vertical-align: top; |
||||
|
display: inline-block; |
||||
|
} |
||||
|
|
||||
|
.pos .attribute .attribute-name{ |
||||
|
float: left; |
||||
|
width: 20%; |
||||
|
} |
||||
|
|
||||
|
.pos .attribute .value-list-container{ |
||||
|
width:78%; |
||||
|
float: left; |
||||
|
} |
||||
|
.pos .attribute .selected{ |
||||
|
background-color: white; |
||||
|
} |
||||
|
|
||||
|
.pos .attribute .attribute-value { |
||||
|
float: left; |
||||
|
width: 150px; |
||||
|
} |
||||
|
|
||||
|
/* ********* Variant Display ********************************************* */ |
||||
|
/* This part is a copy past from Odoo Project, with some values changed */ |
||||
|
.pos .variant { |
||||
|
position:relative; |
||||
|
vertical-align: top; |
||||
|
display: inline-block; |
||||
|
line-height: 100px; |
||||
|
font-size: 11px; |
||||
|
margin: 5px !important; |
||||
|
width: 240px; |
||||
|
height:60px; |
||||
|
background:#fff; |
||||
|
border: 1px solid #e2e2e2; |
||||
|
border-radius: 3px; |
||||
|
border-bottom-width: 3px; |
||||
|
overflow: hidden; |
||||
|
cursor: pointer; |
||||
|
} |
||||
|
|
||||
|
.pos .variant .variant-header { |
||||
|
position: relative; |
||||
|
width: 240px; |
||||
|
height: 30px; |
||||
|
background: white; |
||||
|
text-align: center; |
||||
|
} |
||||
|
|
||||
|
.pos .variant .price-tag { |
||||
|
position: absolute; |
||||
|
top: 2px; |
||||
|
right: 2px; |
||||
|
vertical-align: top; |
||||
|
color: white; |
||||
|
line-height: 13px; |
||||
|
background: #7f82ac; |
||||
|
padding: 2px 5px; |
||||
|
border-radius: 2px; |
||||
|
} |
||||
|
|
||||
|
.pos .variant .variant-name { |
||||
|
font-weight: normal; |
||||
|
position: absolute; |
||||
|
-webkit-box-sizing: border-box; |
||||
|
-moz-box-sizing: border-box; |
||||
|
-ms-box-sizing: border-box; |
||||
|
box-sizing: border-box; |
||||
|
bottom:0; |
||||
|
top:auto; |
||||
|
line-height: 14px; |
||||
|
width:100%; |
||||
|
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)); |
||||
|
/* troublesome in latest webkit |
||||
|
background: linear-gradient(-90deg,rgba(255,255,255,0),rgba(255,255,255,1), rgba(255,255,255,1)); |
||||
|
*/ |
||||
|
/*background:#FFF;*/ |
||||
|
padding: 3px; |
||||
|
padding-top:15px; |
||||
|
} |
||||
|
|
||||
|
/*.pos .variant-list-scroller{*/ |
||||
|
/* -webkit-box-sizing: border-box;*/ |
||||
|
/* -moz-box-sizing: border-box;*/ |
||||
|
/* -ms-box-sizing: border-box;*/ |
||||
|
/* box-sizing: border-box;*/ |
||||
|
/* width:50%;*/ |
||||
|
/* height:50%;*/ |
||||
|
/* overflow: hidden;*/ |
||||
|
/* overflow-y: auto;*/ |
||||
|
/* -webkit-overflow-scrolling: touch;*/ |
||||
|
/* -webkit-transform: translate3d(0,0,0);*/ |
||||
|
|
||||
|
/*}*/ |
After Width: 64 | Height: 64 | Size: 4.2 KiB |
@ -0,0 +1,565 @@ |
|||||
|
/****************************************************************************** |
||||
|
Point Of Sale - Product Template module for Odoo |
||||
|
Copyright (C) 2014-Today Akretion (http://www.akretion.com)
|
||||
|
@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_product_template = function (instance) { |
||||
|
module = instance.point_of_sale; |
||||
|
var QWeb = instance.web.qweb; |
||||
|
var _t = instance.web._t; |
||||
|
|
||||
|
/* ******************************************************** |
||||
|
Overload: point_of_sale.ProductListWidget |
||||
|
|
||||
|
- The overload will: |
||||
|
- display only product template; |
||||
|
- Add an extra behaviour on click on a template, if template has many |
||||
|
variant, displaying an extra scren to select the variant; |
||||
|
*********************************************************** */ |
||||
|
module.ProductListWidget = module.ProductListWidget.extend({ |
||||
|
|
||||
|
init: function(parent, options) { |
||||
|
this._super(parent,options); |
||||
|
var self = this; |
||||
|
// OVERWRITE 'click_product_handler' function to do
|
||||
|
// a different behaviour if template with one or many variants
|
||||
|
// are selected.
|
||||
|
this.click_product_handler = function(event){ |
||||
|
var product = self.pos.db.get_product_by_id(this.dataset['productId']); |
||||
|
|
||||
|
if (product.product_variant_count == 1) { |
||||
|
// Normal behaviour, The template has only one variant
|
||||
|
options.click_product_action(product); |
||||
|
} |
||||
|
else{ |
||||
|
// Display for selection all the variants of a template
|
||||
|
self.pos.pos_widget.screen_selector.show_popup('select-variant-popup', product.product_tmpl_id); |
||||
|
} |
||||
|
}; |
||||
|
}, |
||||
|
|
||||
|
/* ************************************************ |
||||
|
Overload: 'set_product_list' |
||||
|
|
||||
|
'set_product_list' is a function called before displaying Products. |
||||
|
(at the beginning, after a category selection, after a research, etc. |
||||
|
we just splice all products that are not the 'primary variant' |
||||
|
*/ |
||||
|
set_product_list: function(product_list){ |
||||
|
for (var i = product_list.length - 1; i >= 0; i--){ |
||||
|
if (!product_list[i].is_primary_variant){ |
||||
|
product_list.splice(i, 1); |
||||
|
} |
||||
|
} |
||||
|
this._super(product_list); |
||||
|
}, |
||||
|
}); |
||||
|
|
||||
|
var _render_product_ = module.ProductListWidget.prototype.render_product; |
||||
|
module.ProductListWidget.prototype.render_product = function(product){ |
||||
|
self = this; |
||||
|
|
||||
|
if (product.product_variant_count == 1){ |
||||
|
// Normal Display
|
||||
|
return _render_product_.call(this, product); |
||||
|
} |
||||
|
else{ |
||||
|
var cached = this.product_cache.get_node(product.id); |
||||
|
if(!cached){ |
||||
|
var image_url = this.get_product_image_url(product); |
||||
|
var product_html = QWeb.render('Template',{ |
||||
|
widget: this, |
||||
|
product: product, |
||||
|
image_url: this.get_product_image_url(product), |
||||
|
}); |
||||
|
var product_node = document.createElement('div'); |
||||
|
product_node.innerHTML = product_html; |
||||
|
product_node = product_node.childNodes[1]; |
||||
|
this.product_cache.cache_node(product.id,product_node); |
||||
|
return product_node; |
||||
|
} |
||||
|
return cached; |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
/* ******************************************************** |
||||
|
Overload: point_of_sale.PosWidget |
||||
|
|
||||
|
- Add a new PopUp 'SelectVariantPopupWidget'; |
||||
|
*********************************************************** */ |
||||
|
module.PosWidget = module.PosWidget.extend({ |
||||
|
|
||||
|
/* Overload Section */ |
||||
|
build_widgets: function(){ |
||||
|
this._super(); |
||||
|
this.select_variant_popup = new module.SelectVariantPopupWidget(this, {}); |
||||
|
this.select_variant_popup.appendTo($(this.$el)); |
||||
|
this.screen_selector.popup_set['select-variant-popup'] = this.select_variant_popup; |
||||
|
// Hide the popup because all pop up are displayed at the
|
||||
|
// beginning by default
|
||||
|
this.select_variant_popup.hide(); |
||||
|
}, |
||||
|
}); |
||||
|
|
||||
|
/* ******************************************************** |
||||
|
Define : pos_product_template.SelectVariantPopupWidget |
||||
|
|
||||
|
- This widget that display a pop up to select a variant of a Template; |
||||
|
*********************************************************** */ |
||||
|
module.SelectVariantPopupWidget = module.PopUpWidget.extend({ |
||||
|
template:'SelectVariantPopupWidget', |
||||
|
|
||||
|
init: function(parent, options) { |
||||
|
this._super(parent,options); |
||||
|
this.template_name = ''; |
||||
|
}, |
||||
|
|
||||
|
start: function(){ |
||||
|
var self = this; |
||||
|
// Define Variant Widget
|
||||
|
this.variant_list_widget = new module.VariantListWidget(this,{}); |
||||
|
this.variant_list_widget.replace(this.$('.placeholder-VariantListWidget')); |
||||
|
|
||||
|
// Define Attribute Widget
|
||||
|
this.attribute_list_widget = new module.AttributeListWidget(this,{}); |
||||
|
this.attribute_list_widget.replace(this.$('.placeholder-AttributeListWidget')); |
||||
|
|
||||
|
// Add behaviour on Cancel Button
|
||||
|
this.$('#variant-popup-cancel').off('click').click(function(){ |
||||
|
self.hide(); |
||||
|
}); |
||||
|
}, |
||||
|
|
||||
|
show: function(product_tmpl_id){ |
||||
|
var self = this; |
||||
|
var template = this.pos.db.template_by_id[product_tmpl_id]; |
||||
|
|
||||
|
// Display Name of Template
|
||||
|
this.template_name = template.name; |
||||
|
this.$('#variant-title-name').html(template.name); |
||||
|
|
||||
|
// Render Variants
|
||||
|
var variant_ids = this.pos.db.template_by_id[product_tmpl_id].product_variant_ids; |
||||
|
var variant_list = []; |
||||
|
for (var i = 0, len = variant_ids.length; i < len; i++) { |
||||
|
variant_list.push(this.pos.db.get_product_by_id(variant_ids[i])); |
||||
|
} |
||||
|
this.variant_list_widget.filters = {} |
||||
|
this.variant_list_widget.set_variant_list(variant_list); |
||||
|
|
||||
|
// Render Attributes
|
||||
|
var attribute_ids = this.pos.db.attribute_by_template_id(template.id); |
||||
|
var attribute_list = []; |
||||
|
for (var i = 0, len = attribute_ids.length; i < len; i++) { |
||||
|
attribute_list.push(this.pos.db.get_product_attribute_by_id(attribute_ids[i])); |
||||
|
} |
||||
|
this.attribute_list_widget.set_attribute_list(attribute_list, template); |
||||
|
this._super(); |
||||
|
}, |
||||
|
}); |
||||
|
|
||||
|
/* ******************************************************** |
||||
|
Define: pos_product_template.VariantListWidget |
||||
|
|
||||
|
- This widget will display a list of Variants; |
||||
|
- This widget has some part of code that come from point_of_sale.ProductListWidget; |
||||
|
*********************************************************** */ |
||||
|
module.VariantListWidget = module.PosBaseWidget.extend({ |
||||
|
template:'VariantListWidget', |
||||
|
|
||||
|
init: function(parent, options) { |
||||
|
var self = this; |
||||
|
this._super(parent, options); |
||||
|
this.variant_list = []; |
||||
|
this.filter_variant_list = []; |
||||
|
this.filters = {}; |
||||
|
this.click_variant_handler = function(event){ |
||||
|
var variant = self.pos.db.get_product_by_id(this.dataset['variantId']); |
||||
|
if(variant.to_weight && self.pos.config.iface_electronic_scale){ |
||||
|
self.__parentedParent.hide(); |
||||
|
self.pos_widget.screen_selector.set_current_screen('scale',{product: variant}); |
||||
|
}else{ |
||||
|
self.__parentedParent.hide(); |
||||
|
self.pos.get('selectedOrder').addProduct(variant); |
||||
|
} |
||||
|
}; |
||||
|
}, |
||||
|
|
||||
|
replace: function($target){ |
||||
|
this.renderElement(); |
||||
|
var target = $target[0]; |
||||
|
target.parentNode.replaceChild(this.el,target); |
||||
|
}, |
||||
|
|
||||
|
set_filter: function(attribute_id, value_id){ |
||||
|
this.filters[attribute_id] = value_id; |
||||
|
this.filter_variant(); |
||||
|
}, |
||||
|
|
||||
|
reset_filter: function(attribute_id){ |
||||
|
if (attribute_id in this.filters){ |
||||
|
delete this.filters[attribute_id]; |
||||
|
} |
||||
|
this.filter_variant(); |
||||
|
}, |
||||
|
|
||||
|
filter_variant: function(){ |
||||
|
value_list = [] |
||||
|
for (var item in this.filters){ |
||||
|
value_list.push(parseInt(this.filters[item])); |
||||
|
} |
||||
|
this.filter_variant_list = []; |
||||
|
for (index in this.variant_list){ |
||||
|
variant = this.variant_list[index]; |
||||
|
found = true; |
||||
|
for (var i = 0; i < value_list.length; i++){ |
||||
|
found = found && (variant.attribute_value_ids.indexOf(value_list[i]) != -1); |
||||
|
} |
||||
|
if (found){ |
||||
|
this.filter_variant_list.push(variant); |
||||
|
} |
||||
|
} |
||||
|
this.renderElement(); |
||||
|
}, |
||||
|
|
||||
|
set_variant_list: function(variant_list){ |
||||
|
this.variant_list = variant_list; |
||||
|
this.filter_variant_list = variant_list; |
||||
|
this.renderElement(); |
||||
|
}, |
||||
|
|
||||
|
render_variant: function(variant){ |
||||
|
var variant_html = QWeb.render('VariantWidget', { |
||||
|
widget: this, |
||||
|
variant: variant, |
||||
|
}); |
||||
|
var variant_node = document.createElement('div'); |
||||
|
variant_node.innerHTML = variant_html; |
||||
|
variant_node = variant_node.childNodes[1]; |
||||
|
return variant_node; |
||||
|
}, |
||||
|
|
||||
|
renderElement: function() { |
||||
|
var self = this; |
||||
|
var el_html = openerp.qweb.render(this.template, {widget: this}); |
||||
|
var el_node = document.createElement('div'); |
||||
|
el_node.innerHTML = el_html; |
||||
|
el_node = el_node.childNodes[1]; |
||||
|
if(this.el && this.el.parentNode){ |
||||
|
this.el.parentNode.replaceChild(el_node,this.el); |
||||
|
} |
||||
|
this.el = el_node; |
||||
|
var list_container = el_node.querySelector('.variant-list'); |
||||
|
for(var i = 0, len = this.filter_variant_list.length; i < len; i++){ |
||||
|
var variant_node = this.render_variant(this.filter_variant_list[i]); |
||||
|
variant_node.addEventListener('click',this.click_variant_handler); |
||||
|
list_container.appendChild(variant_node); |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
}); |
||||
|
|
||||
|
/* ******************************************************** |
||||
|
Define: pos_product_template.AttributeListWidget |
||||
|
|
||||
|
- This widget will display a list of Attribute; |
||||
|
*********************************************************** */ |
||||
|
module.AttributeListWidget = module.PosBaseWidget.extend({ |
||||
|
template:'AttributeListWidget', |
||||
|
|
||||
|
init: function(parent, options) { |
||||
|
var self = this; |
||||
|
this.attribute_list = []; |
||||
|
this.product_template = null; |
||||
|
this.click_set_attribute_handler = function(event){ |
||||
|
/*TODO: Refactor this function with elegant DOM manipulation */ |
||||
|
// remove selected item
|
||||
|
parent = this.parentElement.parentElement.parentElement; |
||||
|
parent.children[0].classList.remove('selected'); |
||||
|
for (var i = 0 ; i < parent.children[1].children[0].children.length; i ++){ |
||||
|
elem = parent.children[1].children[0].children[i]; |
||||
|
elem.children[0].classList.remove('selected'); |
||||
|
} |
||||
|
// add selected item
|
||||
|
this.children[0].classList.add('selected'); |
||||
|
self.__parentedParent.variant_list_widget.set_filter(this.dataset['attributeId'], this.dataset['attributeValueId']); |
||||
|
}; |
||||
|
this.click_reset_attribute_handler = function(event){ |
||||
|
/*TODO: Refactor this function with elegant DOM manipulation */ |
||||
|
// remove selected item
|
||||
|
parent = this.parentElement; |
||||
|
parent.children[0].classList.remove('selected'); |
||||
|
for (var i = 0 ; i < parent.children[1].children[0].children.length; i ++){ |
||||
|
elem = parent.children[1].children[0].children[i]; |
||||
|
elem.children[0].classList.remove('selected'); |
||||
|
} |
||||
|
// add selected item
|
||||
|
this.classList.add('selected'); |
||||
|
self.__parentedParent.variant_list_widget.reset_filter(this.dataset['attributeId']); |
||||
|
}; |
||||
|
this._super(parent, options); |
||||
|
}, |
||||
|
|
||||
|
replace: function($target){ |
||||
|
this.renderElement(); |
||||
|
var target = $target[0]; |
||||
|
target.parentNode.replaceChild(this.el,target); |
||||
|
}, |
||||
|
|
||||
|
set_attribute_list: function(attribute_list, product_template){ |
||||
|
this.attribute_list = attribute_list; |
||||
|
this.product_template = product_template; |
||||
|
this.renderElement(); |
||||
|
}, |
||||
|
|
||||
|
render_attribute: function(attribute){ |
||||
|
var attribute_html = QWeb.render('AttributeWidget',{ |
||||
|
widget: this, |
||||
|
attribute: attribute, |
||||
|
}); |
||||
|
var attribute_node = document.createElement('div'); |
||||
|
attribute_node.innerHTML = attribute_html; |
||||
|
attribute_node = attribute_node.childNodes[1]; |
||||
|
|
||||
|
var list_container = attribute_node.querySelector('.value-list'); |
||||
|
for(var i = 0, len = attribute.value_ids.length; i < len; i++){ |
||||
|
var value = this.pos.db.get_product_attribute_value_by_id(attribute.value_ids[i]); |
||||
|
var value_node = this.render_value(attribute, value); |
||||
|
value_node.addEventListener('click', this.click_set_attribute_handler); |
||||
|
list_container.appendChild(value_node); |
||||
|
}; |
||||
|
return attribute_node; |
||||
|
}, |
||||
|
|
||||
|
render_value: function(attribute, value){ |
||||
|
product_list = this.pos.db.get_product_by_ids(this.product_template.product_variant_ids); |
||||
|
subproduct_list = this.pos.db.get_product_by_value_and_products(value.id, product_list); |
||||
|
variant_qty = subproduct_list.length; |
||||
|
var value_html = QWeb.render('AttributeValueWidget',{ |
||||
|
widget: this, |
||||
|
value: value, |
||||
|
variant_qty: variant_qty, |
||||
|
}); |
||||
|
var value_node = document.createElement('div'); |
||||
|
value_node.innerHTML = value_html; |
||||
|
value_node = value_node.childNodes[1]; |
||||
|
return value_node; |
||||
|
}, |
||||
|
|
||||
|
|
||||
|
renderElement: function() { |
||||
|
var self = this; |
||||
|
var el_html = openerp.qweb.render(this.template, {widget: this}); |
||||
|
var el_node = document.createElement('div'); |
||||
|
el_node.innerHTML = el_html; |
||||
|
el_node = el_node.childNodes[1]; |
||||
|
if(this.el && this.el.parentNode){ |
||||
|
this.el.parentNode.replaceChild(el_node,this.el); |
||||
|
} |
||||
|
this.el = el_node; |
||||
|
|
||||
|
var list_container = el_node.querySelector('.attribute-list'); |
||||
|
for(var i = 0, len = this.attribute_list.length; i < len; i++){ |
||||
|
var attribute_node = this.render_attribute(this.attribute_list[i]); |
||||
|
attribute_node.querySelector('.attribute-name').addEventListener('click', this.click_reset_attribute_handler); |
||||
|
// attribute_node.addEventListener('click', this.click_reset_attribute_handler);
|
||||
|
list_container.appendChild(attribute_node); |
||||
|
}; |
||||
|
}, |
||||
|
|
||||
|
}); |
||||
|
|
||||
|
|
||||
|
/* ******************************************************** |
||||
|
Overload: point_of_sale.PosDB |
||||
|
|
||||
|
- Add to local storage Product Templates Data. |
||||
|
- Link Product Variants to Product Templates. |
||||
|
- Add an extra field 'is_primary_variant' on product object. the product |
||||
|
will be display on product list, only if it is the primary variant; |
||||
|
Otherwise, the product will be displayed only on Template Screen. |
||||
|
- Add an extra field 'product_variant_count' on product object that |
||||
|
indicates the number of variant of the template of the product. |
||||
|
*********************************************************** */ |
||||
|
module.PosDB = module.PosDB.extend({ |
||||
|
init: function(options){ |
||||
|
this.template_by_id = {}; |
||||
|
this.product_attribute_by_id = {}; |
||||
|
this.product_attribute_value_by_id = {}; |
||||
|
this._super(options); |
||||
|
}, |
||||
|
|
||||
|
get_product_by_value_and_products: function(value_id, products){ |
||||
|
var list = []; |
||||
|
for (var i = 0, len = products.length; i < len; i++) { |
||||
|
if (products[i].attribute_value_ids.indexOf(value_id) != -1){ |
||||
|
list.push(products[i]); |
||||
|
} |
||||
|
} |
||||
|
return list; |
||||
|
}, |
||||
|
|
||||
|
get_product_attribute_by_id: function(attribute_id){ |
||||
|
return this.product_attribute_by_id[attribute_id]; |
||||
|
}, |
||||
|
|
||||
|
get_product_attribute_value_by_id: function(attribute_value_id){ |
||||
|
return this.product_attribute_value_by_id[attribute_value_id]; |
||||
|
}, |
||||
|
|
||||
|
get_product_by_ids: function(product_ids){ |
||||
|
var list = []; |
||||
|
for (var i = 0, len = product_ids.length; i < len; i++) { |
||||
|
list.push(this.product_by_id[product_ids[i]]); |
||||
|
} |
||||
|
return list; |
||||
|
}, |
||||
|
|
||||
|
|
||||
|
attribute_by_template_id: function(template_id){ |
||||
|
template = this.template_by_id[template_id]; |
||||
|
return this.attribute_by_attribute_value_ids(template.attribute_value_ids); |
||||
|
}, |
||||
|
|
||||
|
attribute_by_attribute_value_ids: function(value_ids){ |
||||
|
attribute_ids = []; |
||||
|
for (var i = 0; i < value_ids.length; i++){ |
||||
|
var value = this.product_attribute_value_by_id[value_ids[i]]; |
||||
|
if (attribute_ids.indexOf(value.attribute_id[0])==-1){ |
||||
|
attribute_ids.push(value.attribute_id[0]); |
||||
|
} |
||||
|
} |
||||
|
return attribute_ids; |
||||
|
}, |
||||
|
|
||||
|
add_templates: function(templates){ |
||||
|
for(var i=0 ; i < templates.length; i++){ |
||||
|
var attribute_value_ids = []; |
||||
|
// store Templates
|
||||
|
this.template_by_id[templates[i].id] = templates[i]; |
||||
|
|
||||
|
// Update Product information
|
||||
|
for (var j = 0; j <templates[i].product_variant_ids.length; j++){ |
||||
|
var product = this.product_by_id[templates[i].product_variant_ids[j]] |
||||
|
for (var k = 0; k < product.attribute_value_ids.length; k++){ |
||||
|
if (attribute_value_ids.indexOf(product.attribute_value_ids[k])==-1){ |
||||
|
attribute_value_ids.push(product.attribute_value_ids[k]); |
||||
|
} |
||||
|
} |
||||
|
product.product_variant_count = templates[i].product_variant_count; |
||||
|
product.is_primary_variant = (j==0); |
||||
|
} |
||||
|
this.template_by_id[templates[i].id].attribute_value_ids = attribute_value_ids; |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
add_product_attributes: function(product_attributes){ |
||||
|
for(var i=0 ; i < product_attributes.length; i++){ |
||||
|
// store Product Attributes
|
||||
|
this.product_attribute_by_id[product_attributes[i].id] = product_attributes[i]; |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
add_product_attribute_values: function(product_attribute_values){ |
||||
|
for(var i=0 ; i < product_attribute_values.length; i++){ |
||||
|
// store Product Attribute Values
|
||||
|
this.product_attribute_value_by_id[product_attribute_values[i].id] = product_attribute_values[i]; |
||||
|
} |
||||
|
}, |
||||
|
}); |
||||
|
|
||||
|
|
||||
|
/* ******************************************************** |
||||
|
Overload: point_of_sale.PosModel |
||||
|
|
||||
|
- Overload module.PosModel.initialize function to load extra-data |
||||
|
- Load 'name' field of model product.product; |
||||
|
- Load product.template model; |
||||
|
*********************************************************** */ |
||||
|
var _initialize_ = module.PosModel.prototype.initialize; |
||||
|
module.PosModel.prototype.initialize = function(session, attributes){ |
||||
|
self = this; |
||||
|
// Add the load of the field product_product.name
|
||||
|
// that is the name of the template
|
||||
|
// Add the load of attribute values
|
||||
|
for (var i = 0 ; i < this.models.length; i++){ |
||||
|
if (this.models[i].model == 'product.product'){ |
||||
|
if (this.models[i].fields.indexOf('name') == -1) { |
||||
|
this.models[i].fields.push('name'); |
||||
|
} |
||||
|
if (this.models[i].fields.indexOf('attribute_value_ids') == -1) { |
||||
|
this.models[i].fields.push('attribute_value_ids'); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// Load Product Template
|
||||
|
model = { |
||||
|
model: 'product.template', |
||||
|
fields: [ |
||||
|
'name', |
||||
|
'display_name', |
||||
|
'list_price', //?
|
||||
|
'product_variant_ids', |
||||
|
'product_variant_count', |
||||
|
], |
||||
|
domain: function(self){ |
||||
|
return [ |
||||
|
['sale_ok','=',true], |
||||
|
['available_in_pos','=',true], |
||||
|
];}, |
||||
|
context: function(self){ |
||||
|
return { |
||||
|
pricelist: self.pricelist.id, |
||||
|
display_default_code: false, |
||||
|
};}, |
||||
|
loaded: function(self, templates){ |
||||
|
self.db.add_templates(templates); |
||||
|
}, |
||||
|
} |
||||
|
this.models.push(model); |
||||
|
|
||||
|
// Load Product Attribute
|
||||
|
model = { |
||||
|
model: 'product.attribute', |
||||
|
fields: [ |
||||
|
'name', |
||||
|
'value_ids', |
||||
|
], |
||||
|
loaded: function(self, attributes){ |
||||
|
self.db.add_product_attributes(attributes); |
||||
|
}, |
||||
|
} |
||||
|
this.models.push(model); |
||||
|
|
||||
|
// Load Product Attribute Value
|
||||
|
model = { |
||||
|
model: 'product.attribute.value', |
||||
|
fields: [ |
||||
|
'name', |
||||
|
'attribute_id', |
||||
|
], |
||||
|
loaded: function(self, values){ |
||||
|
self.db.add_product_attribute_values(values); |
||||
|
}, |
||||
|
} |
||||
|
this.models.push(model); |
||||
|
|
||||
|
return _initialize_.call(this, session, attributes); |
||||
|
}; |
||||
|
}; |
@ -0,0 +1,130 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<!-- ********************************************************************** --> |
||||
|
<!--Point Of Sale - Product Template module for Odoo --> |
||||
|
<!--Copyright (C) 2014-Today Akretion (http://www.akretion.com) --> |
||||
|
<!--@author Sylvain LE GAL (https://twitter.com/legalsylvain) --> |
||||
|
|
||||
|
<!--Some part of code come from Odoo Project. --> |
||||
|
<!--Copyright (C) 2004-Today Odoo SA. (<http://odoo.com>). --> |
||||
|
|
||||
|
<!--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/>. --> |
||||
|
<!-- ********************************************************************** --> |
||||
|
<template> |
||||
|
|
||||
|
<!-- Pop Up Widget --> |
||||
|
<t t-name="SelectVariantPopupWidget"> |
||||
|
<div class="modal-dialog"> |
||||
|
<div class="popup popup-select-variant"> |
||||
|
<div class="variant-title"> |
||||
|
Variants Selection of <span id="variant-title-name" /> |
||||
|
<span id="variant-popup-cancel" class="button"> |
||||
|
Cancel |
||||
|
</span> |
||||
|
|
||||
|
</div> |
||||
|
<div class="content-container container-attribute-list"> |
||||
|
<span class="placeholder-AttributeListWidget" /> |
||||
|
</div> |
||||
|
<div class="content-container container-variant-list"> |
||||
|
<span class="placeholder-VariantListWidget" /> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</t> |
||||
|
|
||||
|
<!-- Product Template Widget --> |
||||
|
<!-- This code come from Odoo Project --> |
||||
|
<!-- Changes: |
||||
|
* Display 'name' field instead of display_name field; |
||||
|
* Display variant quantity instead of price; |
||||
|
--> |
||||
|
<t t-name="Template"> |
||||
|
<span class='product' t-att-data-product-id="product.id"> |
||||
|
<div class="product-img"> |
||||
|
<img t-att-src='image_url' /> |
||||
|
<span class="price-tag"> |
||||
|
<t t-esc="product.product_variant_count"/> Variants |
||||
|
</span> |
||||
|
</div> |
||||
|
<div class="product-name"> |
||||
|
<t t-esc="product.name"/> |
||||
|
</div> |
||||
|
</span> |
||||
|
</t> |
||||
|
|
||||
|
<!-- Attribute and Attributes list Widgets --> |
||||
|
<t t-name="AttributeListWidget"> |
||||
|
<div class='attribute-list-container'> |
||||
|
<div class="attribute-list-scroller touch-scrollable"> |
||||
|
<div class="attribute-list"> |
||||
|
</div> |
||||
|
</div> |
||||
|
<span class="placeholder-ScrollbarWidget" /> |
||||
|
</div> |
||||
|
</t> |
||||
|
|
||||
|
<t t-name="AttributeWidget"> |
||||
|
<span class='attribute' t-att-data-attribute-id="attribute.id"> |
||||
|
<div class="attribute-name button selected" t-att-data-attribute-id="attribute.id"> |
||||
|
<t t-esc="attribute.name"/> |
||||
|
</div> |
||||
|
<div class='value-list-container'> |
||||
|
<div class="value-list"> |
||||
|
</div> |
||||
|
|
||||
|
</div> |
||||
|
</span> |
||||
|
</t> |
||||
|
|
||||
|
<t t-name="AttributeValueWidget"> |
||||
|
<span class='attribute-value' t-att-data-attribute-id="value.attribute_id[0]" t-att-data-attribute-value-id="value.id"> |
||||
|
<div class="button attribute-value-name"> |
||||
|
<t t-esc="value.name"/> (<t t-esc="variant_qty"/>) |
||||
|
</div> |
||||
|
</span> |
||||
|
</t> |
||||
|
|
||||
|
|
||||
|
<!-- Variant and Variants List Widgets --> |
||||
|
<t t-name="VariantListWidget"> |
||||
|
<div class='variant-list-container'> |
||||
|
<div class="variant-list-scroller touch-scrollable"> |
||||
|
<div class="variant-list"> |
||||
|
</div> |
||||
|
</div> |
||||
|
<span class="placeholder-ScrollbarWidget" /> |
||||
|
</div> |
||||
|
</t> |
||||
|
|
||||
|
<t t-name="VariantWidget"> |
||||
|
<span class='variant' t-att-data-variant-id="variant.id"> |
||||
|
<div class="variant-header"> |
||||
|
<t t-if="!variant.to_weight"> |
||||
|
<span class="price-tag"> |
||||
|
<t t-esc="widget.format_currency(variant.price,'Product Price')"/> |
||||
|
</span> |
||||
|
</t> |
||||
|
<t t-if="variant.to_weight"> |
||||
|
<span class="price-tag"> |
||||
|
<t t-esc="widget.format_currency(variant.price,'Product Price')+'/Kg'"/> |
||||
|
</span> |
||||
|
</t> |
||||
|
</div> |
||||
|
<div class="variant-name"> |
||||
|
<t t-esc="variant.display_name"/> |
||||
|
</div> |
||||
|
</span> |
||||
|
</t> |
||||
|
|
||||
|
</template> |
@ -0,0 +1,37 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<!-- ********************************************************************** --> |
||||
|
<!--Point Of Sale - Product Template module for Odoo --> |
||||
|
<!--Copyright (C) 2014-Today Akretion (http://www.akretion.com) --> |
||||
|
<!--@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> |
||||
|
<data> |
||||
|
<!-- Add: JS Files --> |
||||
|
<template id="assets_backend" name="point_of_sale assets2" inherit_id="web.assets_backend"> |
||||
|
<xpath expr="." position="inside"> |
||||
|
<script type="text/javascript" src="/pos_product_template/static/src/js/ppt.js"></script> |
||||
|
</xpath> |
||||
|
</template> |
||||
|
|
||||
|
<!-- Add: CSS Files --> |
||||
|
<template id="index" name="pos_product_template index" inherit_id="point_of_sale.index"> |
||||
|
<xpath expr="//link[@id='pos-stylesheet']" position="after"> |
||||
|
<link rel="stylesheet" href="/pos_product_template/static/src/css/ppt.css" id="pos_product_template-stylesheet"/> |
||||
|
</xpath> |
||||
|
</template> |
||||
|
|
||||
|
</data> |
||||
|
</openerp> |
Write
Preview
Loading…
Cancel
Save
Reference in new issue