@ -1,45 +0,0 @@ |
|||||
|
|
||||
POS Customer Pricelist v8 |
|
||||
========================= |
|
||||
|
|
||||
This module adds Pricelist to Point Of Sale Session. |
|
||||
|
|
||||
|
|
||||
* Use customer specific pricelist inside POS. |
|
||||
* Assign pricelist while creating customer from POS. |
|
||||
* User can also change pricelist in POS Session. |
|
||||
* Unique Ticket Id is specified for each ticket. |
|
||||
|
|
||||
|
|
||||
Installation |
|
||||
============ |
|
||||
|
|
||||
No extra module is required,other than the depending module POS. |
|
||||
|
|
||||
Usage |
|
||||
===== |
|
||||
|
|
||||
To use this module, you need to: |
|
||||
|
|
||||
* Go to Pont of sale main menu |
|
||||
* Select the Resume session/New session |
|
||||
* Click on 'Unknown customer'-->Edit/Create Customer, then Add pricelist for the customer |
|
||||
|
|
||||
|
|
||||
Implementation |
|
||||
============== |
|
||||
|
|
||||
User can assign POS pricelist from POS session for each customer. |
|
||||
Then price value of all the products in POS will be changed according to the customer selected. |
|
||||
If no pricelist is set for the customer,module will select default pricelist. |
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
@ -1,24 +0,0 @@ |
|||||
# -*- coding: utf-8 -*- |
|
||||
############################################################################## |
|
||||
# |
|
||||
# Cybrosys Technologies Pvt. Ltd. |
|
||||
# Copyright (C) 2010-TODAY Cybrosys Technologies(<http://www.cybrosys.com>). |
|
||||
# Author: Cybrosys Technologies(<http://www.cybrosys.com>) |
|
||||
# you can modify it under the terms of the GNU LESSER |
|
||||
# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. |
|
||||
# |
|
||||
# It is forbidden to publish, distribute, sublicense, or sell copies |
|
||||
# of the Software or modified copies of the Software. |
|
||||
# |
|
||||
# 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 LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. |
|
||||
# |
|
||||
# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE |
|
||||
# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. |
|
||||
# If not, see <http://www.gnu.org/licenses/>. |
|
||||
# |
|
||||
############################################################################## |
|
||||
|
|
||||
import models |
|
@ -1,43 +0,0 @@ |
|||||
# -*- coding: utf-8 -*- |
|
||||
############################################################################## |
|
||||
# |
|
||||
# Cybrosys Technologies Pvt. Ltd. |
|
||||
# Copyright (C) 2010-TODAY Cybrosys Technologies(<http://www.cybrosys.com>). |
|
||||
# Author: Cybrosys Technologies(<http://www.cybrosys.com>) |
|
||||
# you can modify it under the terms of the GNU LESSER |
|
||||
# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. |
|
||||
# |
|
||||
# It is forbidden to publish, distribute, sublicense, or sell copies |
|
||||
# of the Software or modified copies of the Software. |
|
||||
# |
|
||||
# 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 LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. |
|
||||
# |
|
||||
# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE |
|
||||
# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. |
|
||||
# If not, see <http://www.gnu.org/licenses/>. |
|
||||
# |
|
||||
############################################################################## |
|
||||
|
|
||||
{ |
|
||||
'name': 'Customer Pricelist In POS', |
|
||||
'version': '8.0.1.0.0', |
|
||||
'summary': 'Customer Pricelist in POS.', |
|
||||
'description': 'Pricelist operations to point of sale', |
|
||||
'category': 'Point of Sale', |
|
||||
'author': 'Cybrosys Techno Solutions', |
|
||||
'website': "http://www.cybrosys.com", |
|
||||
'company': 'Cybrosys Techno Solutions', |
|
||||
'depends': ['point_of_sale'], |
|
||||
'data': [ |
|
||||
"views/new_pricelist.xml", |
|
||||
"views/pos_pricelist_template.xml"], |
|
||||
'qweb': ['static/src/xml/pos.xml'], |
|
||||
'images': ['static/description/banner.jpg'], |
|
||||
'license': 'LGPL-3', |
|
||||
'installable': True, |
|
||||
'auto_install': False, |
|
||||
'application': False, |
|
||||
} |
|
@ -1,24 +0,0 @@ |
|||||
# -*- coding: utf-8 -*- |
|
||||
############################################################################## |
|
||||
# |
|
||||
# Cybrosys Technologies Pvt. Ltd. |
|
||||
# Copyright (C) 2010-TODAY Cybrosys Technologies(<http://www.cybrosys.com>). |
|
||||
# Author: Cybrosys Technologies(<http://www.cybrosys.com>) |
|
||||
# you can modify it under the terms of the GNU LESSER |
|
||||
# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. |
|
||||
# |
|
||||
# It is forbidden to publish, distribute, sublicense, or sell copies |
|
||||
# of the Software or modified copies of the Software. |
|
||||
# |
|
||||
# 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 LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. |
|
||||
# |
|
||||
# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE |
|
||||
# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. |
|
||||
# If not, see <http://www.gnu.org/licenses/>. |
|
||||
# |
|
||||
############################################################################## |
|
||||
|
|
||||
import model |
|
@ -1,30 +0,0 @@ |
|||||
# -*- coding: utf-8 -*- |
|
||||
############################################################################## |
|
||||
# |
|
||||
# Cybrosys Technologies Pvt. Ltd. |
|
||||
# Copyright (C) 2010-TODAY Cybrosys Technologies(<http://www.cybrosys.com>). |
|
||||
# Author: Cybrosys Technologies(<http://www.cybrosys.com>) |
|
||||
# you can modify it under the terms of the GNU LESSER |
|
||||
# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. |
|
||||
# |
|
||||
# It is forbidden to publish, distribute, sublicense, or sell copies |
|
||||
# of the Software or modified copies of the Software. |
|
||||
# |
|
||||
# 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 LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. |
|
||||
# |
|
||||
# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE |
|
||||
# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. |
|
||||
# If not, see <http://www.gnu.org/licenses/>. |
|
||||
# |
|
||||
############################################################################## |
|
||||
|
|
||||
from openerp import fields, models |
|
||||
|
|
||||
|
|
||||
class PosCustomerPricelist(models.Model): |
|
||||
_inherit = 'res.partner' |
|
||||
|
|
||||
pricelist = fields.Many2one('product.pricelist', string='POS Pricelist') |
|
Before Width: | Height: | Size: 54 KiB |
Before Width: | Height: | Size: 54 KiB |
Before Width: | Height: | Size: 56 KiB |
Before Width: | Height: | Size: 53 KiB |
Before Width: | Height: | Size: 55 KiB |
Before Width: | Height: | Size: 50 KiB |
Before Width: | Height: | Size: 12 KiB |
@ -1,117 +0,0 @@ |
|||||
<section class="oe_container"> |
|
||||
<div class="oe_row oe_spaced"> |
|
||||
<h2 class="oe_slogan">Customer Pricelist In POS</h2> |
|
||||
<p class='oe_mt32'> |
|
||||
This module helps to set customer pricelist in the point of sale module. Price of the product is based on the pricelist value |
|
||||
of the selected customer.The pricelist can be set from POS section or customer at backend.<br/>Some other features are as below: |
|
||||
</p> |
|
||||
<ul> |
|
||||
<li style="list-style:none !important;"><span style="color:green;"> ★</span> Use customer specific pricelist inside POS.</li> |
|
||||
<li style="list-style:none !important;"><span style="color:green;"> ★</span> Assign pricelist while creating customer from POS.</li> |
|
||||
<li style="list-style:none !important;"><span style="color:green;"> ★</span> User can also change pricelist of customer from POS session.</li> |
|
||||
<li style="list-style:none !important;"><span style="color:green;"> ★</span> Integrated with customer contact details.</li> |
|
||||
</ul> |
|
||||
</div> |
|
||||
</section> |
|
||||
|
|
||||
<section class="oe_container oe_dark"> |
|
||||
<div class="oe_row oe_padded"> |
|
||||
<h2 class="oe_slogan">Add Your Pricelist From POS</h2> |
|
||||
<div class="oe_span12"> |
|
||||
<p> |
|
||||
<h4>Point Of Sale >Resume session >Select customer >Set pricelist</h4> |
|
||||
</p> |
|
||||
</div> |
|
||||
<div class="oe_span13"> |
|
||||
<div class="oe_demo oe_screenshot"> |
|
||||
<img src="11.png"> |
|
||||
</div> |
|
||||
</div></div> |
|
||||
</section> |
|
||||
|
|
||||
<section class="oe_container"> |
|
||||
<div class="oe_row oe_padded"> |
|
||||
<h2 class="oe_slogan">Set Your Pricelist At Customer</h2> |
|
||||
<div class="oe_span12"> |
|
||||
<p> |
|
||||
<h4>Sales >Customer >Create/select any customer >Sales & Purchases >Add pricelist to field 'POS Pricelist'</h4> |
|
||||
</p> |
|
||||
</div> |
|
||||
<div class="oe_span13"> |
|
||||
<div class="oe_demo oe_screenshot"> |
|
||||
<img src="35.png"> |
|
||||
</div> |
|
||||
</div></div> |
|
||||
</section> |
|
||||
|
|
||||
<section class="oe_container oe_dark"> |
|
||||
<div class="oe_row"> |
|
||||
|
|
||||
<div class="oe_span12"> |
|
||||
<h2 class="oe_slogan">Change in Price </h2> |
|
||||
<h3 class="oe_slogan">When a Customer is Set</h3> |
|
||||
</div> |
|
||||
|
|
||||
<div class="oe_span12"> |
|
||||
<p> |
|
||||
<h4>No customer is selected</h4> |
|
||||
<p>The default pricelist is used when no customer is selected. |
|
||||
</p> |
|
||||
</p> |
|
||||
</div> |
|
||||
|
|
||||
<div class="oe_span13"> |
|
||||
<div class="oe_demo oe_screenshot"> |
|
||||
<img src="4.png"> |
|
||||
</div> |
|
||||
</div> |
|
||||
<div class="oe_span12"> |
|
||||
<p> |
|
||||
<h4>Customer is selected</h4> |
|
||||
<p> |
|
||||
Then price value of all the products in POS will be changed according to |
|
||||
the pricelist of the customer selected. |
|
||||
</p> |
|
||||
</p> |
|
||||
</div> |
|
||||
|
|
||||
<div class="oe_span13"> |
|
||||
<div class="oe_demo oe_screenshot"> |
|
||||
<img src="3.png"> |
|
||||
</div> |
|
||||
</div> |
|
||||
|
|
||||
</div> |
|
||||
</section> |
|
||||
|
|
||||
<section class="oe_container"> |
|
||||
<h2 class="oe_slogan" style="margin-top:20px;" >Need Any Help?</h2> |
|
||||
<div class="oe_slogan" style="margin-top:10px !important;"> |
|
||||
<div> |
|
||||
<a class="btn btn-primary btn-lg mt8" |
|
||||
style="color: #FFFFFF !important;border-radius: 0;" href="http://www.cybrosys.com"><i |
|
||||
class="fa fa-envelope"></i> Email </a> <a |
|
||||
class="btn btn-primary btn-lg mt8" style="color: #FFFFFF !important;border-radius: 0;" |
|
||||
href="http://www.cybrosys.com/contact/"><i |
|
||||
class="fa fa-phone"></i> Contact Us </a> <a |
|
||||
class="btn btn-primary btn-lg mt8" style="color: #FFFFFF !important;border-radius: 0;" |
|
||||
href="http://www.cybrosys.com/odoo-customization-and-installation/"><i |
|
||||
class="fa fa-check-square"></i> Request Customization </a> |
|
||||
</div> |
|
||||
<br> |
|
||||
<img src="cybro_logo.png" style="width: 190px; margin-bottom: 20px;" class="center-block"> |
|
||||
<div> |
|
||||
<a href="https://twitter.com/cybrosys" target="_blank"><i class="fa fa-2x fa-twitter" style="color:white;background: #00a0d1;width:35px;"></i></a></td> |
|
||||
<a href="https://www.linkedin.com/company/cybrosys-technologies-pvt-ltd" target="_blank"><i class="fa fa-2x fa-linkedin" style="color:white;background: #31a3d6;width:35px;padding-left: 3px;"></i></a></td> |
|
||||
<a href="https://www.facebook.com/cybrosystechnologies" target="_blank"><i class="fa fa-2x fa-facebook" style="color:white;background: #3b5998;width:35px;padding-left: 8px;"></i></a></td> |
|
||||
<a href="https://plus.google.com/106641282743045431892/about" target="_blank"><i class="fa fa-2x fa-google-plus" style="color:white;background: #c53c2c;width:35px;padding-left: 3px;"></i></a></td> |
|
||||
<a href="https://in.pinterest.com/cybrosys" target="_blank"><i class="fa fa-2x fa-pinterest" style="color:white;background: #ac0f18;width:35px;padding-left: 3px;"></i></a></td> |
|
||||
</div> |
|
||||
</div> |
|
||||
</section> |
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
@ -1,106 +0,0 @@ |
|||||
<section class="oe_container"> |
|
||||
<div class="oe_row oe_spaced"> |
|
||||
<h2 class="oe_slogan">Customer Pricelist In POS</h2> |
|
||||
<p class='oe_mt32'> |
|
||||
This module helps to set customer pricelist in the point of sale module. Price of the product is based on the pricelist value |
|
||||
of the selected customer.The pricelist can be set from POS section or customer at backend.<br/>Some other features are as below: |
|
||||
</p> |
|
||||
<ul> |
|
||||
<li style="list-style:none !important;"><span style="color:green;"> ★</span> Use customer specific pricelist inside POS.</li> |
|
||||
<li style="list-style:none !important;"><span style="color:green;"> ★</span> Assign pricelist while creating customer from POS.</li> |
|
||||
<li style="list-style:none !important;"><span style="color:green;"> ★</span> User can also change pricelist of customer from POS session.</li> |
|
||||
<li style="list-style:none !important;"><span style="color:green;"> ★</span> Integrated with customer contact details.</li> |
|
||||
</ul> |
|
||||
</div> |
|
||||
</section> |
|
||||
|
|
||||
<section class="oe_container oe_dark"> |
|
||||
<div class="oe_row oe_padded"> |
|
||||
<h2 class="oe_slogan">Add Your Pricelist From POS</h2> |
|
||||
<div class="oe_span12"> |
|
||||
<p> |
|
||||
<h4>Point Of Sale >Resume session >Select customer >Set pricelist</h4> |
|
||||
</p> |
|
||||
</div> |
|
||||
<div class="oe_span13"> |
|
||||
<div class="oe_demo oe_screenshot"> |
|
||||
<img src="11.png"> |
|
||||
</div> |
|
||||
</div></div> |
|
||||
</section> |
|
||||
|
|
||||
<section class="oe_container"> |
|
||||
<div class="oe_row oe_padded"> |
|
||||
<h2 class="oe_slogan">Set Your Pricelist At Customer</h2> |
|
||||
<div class="oe_span12"> |
|
||||
<p> |
|
||||
<h4>Sales >Customer >Create/select any customer >Sales & Purchases >Add pricelist to field 'POS Pricelist'</h4> |
|
||||
</p> |
|
||||
</div> |
|
||||
<div class="oe_span13"> |
|
||||
<div class="oe_demo oe_screenshot"> |
|
||||
<img src="35.png"> |
|
||||
</div> |
|
||||
</div></div> |
|
||||
</section> |
|
||||
|
|
||||
<section class="oe_container oe_dark"> |
|
||||
<div class="oe_row"> |
|
||||
|
|
||||
<div class="oe_span12"> |
|
||||
<h2 class="oe_slogan">Change in Price </h2> |
|
||||
<h3 class="oe_slogan">When a Customer is Set</h3> |
|
||||
</div> |
|
||||
|
|
||||
<div class="oe_span12"> |
|
||||
<p> |
|
||||
<h4>No customer is selected</h4> |
|
||||
<p>The default pricelist is used when no customer is selected. |
|
||||
</p> |
|
||||
</p> |
|
||||
</div> |
|
||||
|
|
||||
<div class="oe_span13"> |
|
||||
<div class="oe_demo oe_screenshot"> |
|
||||
<img src="4.png"> |
|
||||
</div> |
|
||||
</div> |
|
||||
<div class="oe_span12"> |
|
||||
<p> |
|
||||
<h4>Customer is selected</h4> |
|
||||
<p> |
|
||||
Then price value of all the products in POS will be changed according to |
|
||||
the pricelist of the customer selected. |
|
||||
</p> |
|
||||
</p> |
|
||||
</div> |
|
||||
|
|
||||
<div class="oe_span13"> |
|
||||
<div class="oe_demo oe_screenshot"> |
|
||||
<img src="3.png"> |
|
||||
</div> |
|
||||
</div> |
|
||||
|
|
||||
</div> |
|
||||
</section> |
|
||||
|
|
||||
|
|
||||
|
|
||||
<section class="oe_container"> |
|
||||
<h2 class="oe_slogan" style="margin-top:20px;" >Need Any Help?</h2> |
|
||||
<div class="oe_slogan" style="margin-top:10px !important;"> |
|
||||
<a class="btn btn-primary btn-lg mt8" |
|
||||
style="color: #FFFFFF !important;" href="http://www.cybrosys.com"><i |
|
||||
class="fa fa-envelope"></i> Email </a> <a |
|
||||
class="btn btn-primary btn-lg mt8" style="color: #FFFFFF !important;" |
|
||||
href="http://www.cybrosys.com/contact/"><i |
|
||||
class="fa fa-phone"></i> Contact Us </a> <a |
|
||||
class="btn btn-primary btn-lg mt8" style="color: #FFFFFF !important;" |
|
||||
href="http://www.cybrosys.com/odoo-customization-and-installation/"><i |
|
||||
class="fa fa-check-square"></i> Request Customization </a> |
|
||||
</div> |
|
||||
<img src="cybro_logo.png" style="width: 190px; margin-bottom: 20px;" class="center-block"> |
|
||||
</section> |
|
||||
|
|
||||
|
|
||||
|
|
Before Width: | Height: | Size: 80 KiB |
Before Width: | Height: | Size: 43 KiB |
@ -1,134 +0,0 @@ |
|||||
|
|
||||
.popover { |
|
||||
position: absolute; |
|
||||
top: 0; |
|
||||
left: 0; |
|
||||
z-index: 1060; |
|
||||
display: none; |
|
||||
max-width: 276px; |
|
||||
padding: 1px; |
|
||||
text-align: left; |
|
||||
white-space: normal; |
|
||||
background-color: #fff; |
|
||||
-webkit-background-clip: padding-box; |
|
||||
background-clip: padding-box; |
|
||||
border: 1px solid #ccc; |
|
||||
border: 1px solid rgba(0, 0, 0, .2); |
|
||||
border-radius: 6px; |
|
||||
-webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, .2); |
|
||||
box-shadow: 0 5px 10px rgba(0, 0, 0, .2); |
|
||||
} |
|
||||
.popover-title { |
|
||||
padding: 8px 14px; |
|
||||
margin: 0; |
|
||||
font-size: 14px; |
|
||||
font-weight: normal; |
|
||||
line-height: 18px; |
|
||||
background-color: #f7f7f7; |
|
||||
border-bottom: 1px solid #ebebeb; |
|
||||
border-radius: 5px 5px 0 0; |
|
||||
} |
|
||||
|
|
||||
/* ToolTip */ |
|
||||
.tooltip { |
|
||||
position: absolute; |
|
||||
z-index: 1070; |
|
||||
display: block; |
|
||||
font-size: 12px; |
|
||||
line-height: 1.4; |
|
||||
visibility: visible; |
|
||||
filter: alpha(opacity=0); |
|
||||
opacity: 0; |
|
||||
} |
|
||||
.tooltip.in { |
|
||||
filter: alpha(opacity=90); |
|
||||
opacity: .9; |
|
||||
} |
|
||||
.tooltip.top { |
|
||||
padding: 5px 0; |
|
||||
margin-top: -3px; |
|
||||
} |
|
||||
.tooltip.right { |
|
||||
padding: 0 5px; |
|
||||
margin-left: 3px; |
|
||||
} |
|
||||
.tooltip.bottom { |
|
||||
padding: 5px 0; |
|
||||
margin-top: 3px; |
|
||||
} |
|
||||
.tooltip.left { |
|
||||
padding: 0 5px; |
|
||||
margin-left: -3px; |
|
||||
} |
|
||||
.tooltip-inner { |
|
||||
max-width: 200px; |
|
||||
padding: 3px 8px; |
|
||||
color: #fff; |
|
||||
text-align: center; |
|
||||
text-decoration: none; |
|
||||
background-color: #000; |
|
||||
border-radius: 4px; |
|
||||
} |
|
||||
.tooltip-arrow { |
|
||||
position: absolute; |
|
||||
width: 0; |
|
||||
height: 0; |
|
||||
border-color: transparent; |
|
||||
border-style: solid; |
|
||||
} |
|
||||
.tooltip.top .tooltip-arrow { |
|
||||
bottom: 0; |
|
||||
left: 50%; |
|
||||
margin-left: -5px; |
|
||||
border-width: 5px 5px 0; |
|
||||
border-top-color: #000; |
|
||||
} |
|
||||
.tooltip.top-left .tooltip-arrow { |
|
||||
bottom: 0; |
|
||||
left: 5px; |
|
||||
border-width: 5px 5px 0; |
|
||||
border-top-color: #000; |
|
||||
} |
|
||||
.tooltip.top-right .tooltip-arrow { |
|
||||
right: 5px; |
|
||||
bottom: 0; |
|
||||
border-width: 5px 5px 0; |
|
||||
border-top-color: #000; |
|
||||
} |
|
||||
.tooltip.right .tooltip-arrow { |
|
||||
top: 50%; |
|
||||
left: 0; |
|
||||
margin-top: -5px; |
|
||||
border-width: 5px 5px 5px 0; |
|
||||
border-right-color: #000; |
|
||||
} |
|
||||
.tooltip.left .tooltip-arrow { |
|
||||
top: 50%; |
|
||||
right: 0; |
|
||||
margin-top: -5px; |
|
||||
border-width: 5px 0 5px 5px; |
|
||||
border-left-color: #000; |
|
||||
} |
|
||||
.tooltip.bottom .tooltip-arrow { |
|
||||
top: 0; |
|
||||
left: 50%; |
|
||||
margin-left: -5px; |
|
||||
border-width: 0 5px 5px; |
|
||||
border-bottom-color: #000; |
|
||||
} |
|
||||
.tooltip.bottom-left .tooltip-arrow { |
|
||||
top: 0; |
|
||||
left: 5px; |
|
||||
border-width: 0 5px 5px; |
|
||||
border-bottom-color: #000; |
|
||||
} |
|
||||
.tooltip.bottom-right .tooltip-arrow { |
|
||||
top: 0; |
|
||||
right: 5px; |
|
||||
border-width: 0 5px 5px; |
|
||||
border-bottom-color: #000; |
|
||||
} |
|
||||
.pos .pos-right-align { |
|
||||
text-align: right; |
|
||||
vertical-align: top; |
|
||||
} |
|
@ -1,179 +0,0 @@ |
|||||
|
|
||||
function customer_pos_pricelist_db(instance, module) { |
|
||||
|
|
||||
module.PosDB = module.PosDB.extend({ |
|
||||
init: function (options) { |
|
||||
options = options || {}; |
|
||||
this._super(options); |
|
||||
this.pricelist_by_id = {}; |
|
||||
this.pricelist_version_by_id = {}; |
|
||||
this.pricelist_item_by_id = {}; |
|
||||
this.pricelist_item_sorted = []; |
|
||||
this.product_category_by_id = {}; |
|
||||
this.product_category_children = {}; |
|
||||
this.product_category_ancestors = {}; |
|
||||
this.product_price_type_by_id = {}; |
|
||||
this.supplierinfo_by_id = {}; |
|
||||
this.pricelist_partnerinfo_by_id = {}; |
|
||||
this.fiscal_position_tax_by_id = {}; |
|
||||
}, |
|
||||
add_fiscal_position_taxes: function (fiscal_position_taxes) { |
|
||||
if (!(fiscal_position_taxes instanceof Array)) { |
|
||||
fiscal_position_taxes = [fiscal_position_taxes]; |
|
||||
} |
|
||||
var fiscal_position_tax; |
|
||||
while (fiscal_position_tax = fiscal_position_taxes.pop()) { |
|
||||
this.fiscal_position_tax_by_id[fiscal_position_tax.id] |
|
||||
= fiscal_position_tax; |
|
||||
} |
|
||||
}, |
|
||||
add_pricelist_partnerinfo: function (pricelist_partnerinfos) { |
|
||||
if (!(pricelist_partnerinfos instanceof Array)) { |
|
||||
pricelist_partnerinfos = [pricelist_partnerinfos]; |
|
||||
} |
|
||||
var partner_info; |
|
||||
while (partner_info = pricelist_partnerinfos.pop()) { |
|
||||
this.pricelist_partnerinfo_by_id[partner_info.id] |
|
||||
= partner_info; |
|
||||
} |
|
||||
}, |
|
||||
add_supplierinfo: function (supplierinfos) { |
|
||||
if (!(supplierinfos instanceof Array)) { |
|
||||
supplierinfos = [supplierinfos]; |
|
||||
} |
|
||||
var supplier_info; |
|
||||
while (supplier_info = supplierinfos.pop()) { |
|
||||
this.supplierinfo_by_id[supplier_info.id] = supplier_info; |
|
||||
} |
|
||||
}, |
|
||||
add_pricelists: function (pricelists) { |
|
||||
if (!(pricelists instanceof Array)) { |
|
||||
pricelists = [pricelists]; |
|
||||
} |
|
||||
var pricelist; |
|
||||
while (pricelist = pricelists.pop()) { |
|
||||
this.pricelist_by_id[pricelist.id] = pricelist; |
|
||||
} |
|
||||
}, |
|
||||
add_pricelist_versions: function (versions) { |
|
||||
if (!(versions instanceof Array)) { |
|
||||
versions = [versions]; |
|
||||
} |
|
||||
var version; |
|
||||
while (version = versions.pop()) { |
|
||||
this.pricelist_version_by_id[version.id] = version; |
|
||||
} |
|
||||
}, |
|
||||
add_pricelist_items: function (items) { |
|
||||
if (!(items instanceof Array)) { |
|
||||
items = [items]; |
|
||||
} |
|
||||
var item; |
|
||||
while (item = items.pop()) { |
|
||||
this.pricelist_item_by_id[item.id] = item; |
|
||||
} |
|
||||
this.pricelist_item_sorted = this._items_sorted(); |
|
||||
}, |
|
||||
add_price_types: function (price_types) { |
|
||||
if (!(price_types instanceof Array)) { |
|
||||
price_types = [price_types]; |
|
||||
} |
|
||||
var ptype; |
|
||||
while (ptype = price_types.pop()) { |
|
||||
this.product_price_type_by_id[ptype.id] = ptype; |
|
||||
} |
|
||||
}, |
|
||||
add_product_categories: function (categories) { |
|
||||
if (!(categories instanceof Array)) { |
|
||||
categories = [categories]; |
|
||||
} |
|
||||
var category; |
|
||||
while (category = categories.pop()) { |
|
||||
this.product_category_by_id[category.id] = category; |
|
||||
this.product_category_children[category.id] = |
|
||||
category.child_id; |
|
||||
} |
|
||||
this._make_ancestors(); |
|
||||
}, |
|
||||
_make_ancestors: function () { |
|
||||
var category, ancestors; |
|
||||
for (var id in this.product_category_by_id) { |
|
||||
category = this.product_category_by_id[id]; |
|
||||
ancestors = []; |
|
||||
while (category.parent_id) { |
|
||||
ancestors.push(category.parent_id[0]); |
|
||||
category = category.parent_id ? |
|
||||
this.product_category_by_id[category.parent_id[0]] : |
|
||||
false; |
|
||||
} |
|
||||
this.product_category_ancestors[parseInt(id)] = ancestors; |
|
||||
} |
|
||||
}, |
|
||||
_items_sorted: function () { |
|
||||
var items = this.pricelist_item_by_id; |
|
||||
var list = []; |
|
||||
for (var key in items) { |
|
||||
list.push(items[key]); |
|
||||
} |
|
||||
list.sort(function (a, b) { |
|
||||
if (a.sequence < b.sequence) return -1; |
|
||||
if (a.sequence > b.sequence) return 1; |
|
||||
if (a.min_quantity > b.min_quantity) return -1; |
|
||||
if (a.min_quantity < b.min_quantity) return 1; |
|
||||
return 0; |
|
||||
}); |
|
||||
return list; |
|
||||
}, |
|
||||
map_tax: function (fiscal_position_id, taxes_ids) { |
|
||||
var taxes = []; |
|
||||
var found_taxes = {}; |
|
||||
for (var id in this.fiscal_position_tax_by_id) { |
|
||||
var fp_line = this.fiscal_position_tax_by_id[id]; |
|
||||
if (fp_line && fp_line.position_id && |
|
||||
fp_line.position_id[0] == fiscal_position_id && |
|
||||
taxes_ids.indexOf(fp_line.tax_src_id[0]) > -1) { |
|
||||
taxes.push(fp_line.tax_dest_id[0]); |
|
||||
found_taxes[fp_line.tax_src_id[0]] = true; |
|
||||
} |
|
||||
} |
|
||||
for (var i = 0, len = taxes_ids.length; i < len; i++) { |
|
||||
var tax_id = taxes_ids[i]; |
|
||||
if (!(tax_id in found_taxes)) { |
|
||||
taxes.push(tax_id); |
|
||||
} |
|
||||
} |
|
||||
return taxes; |
|
||||
}, |
|
||||
add_products: function (products) { |
|
||||
this._super(products); |
|
||||
var pos = posmodel.pos_widget.pos; |
|
||||
for (var id in this.product_by_id) { |
|
||||
if (this.product_by_id.hasOwnProperty(id)) { |
|
||||
var product = this.product_by_id[id]; |
|
||||
var orderline = new openerp.point_of_sale.Orderline({}, { |
|
||||
pos: pos, |
|
||||
order: null, |
|
||||
product: product, |
|
||||
price: product.price |
|
||||
}); |
|
||||
var prices = orderline.get_all_prices(); |
|
||||
this.product_by_id[id].price_with_taxes |
|
||||
= prices['priceWithTax'] |
|
||||
} |
|
||||
} |
|
||||
}, |
|
||||
find_product_rules: function (product) { |
|
||||
var len = this.pricelist_item_sorted.length; |
|
||||
var rules = []; |
|
||||
for (var i = 0; i < len; i++) { |
|
||||
var rule = this.pricelist_item_sorted[i]; |
|
||||
if ((rule.product_id && rule.product_id[0] == product.id) || |
|
||||
(rule.categ_id && product.categ_id |
|
||||
&& rule.categ_id[0] == product.categ_id[0])) { |
|
||||
rules.push(rule); |
|
||||
} |
|
||||
} |
|
||||
return rules; |
|
||||
} |
|
||||
}) |
|
||||
} |
|
@ -1,8 +0,0 @@ |
|||||
|
|
||||
openerp.customer_pos_pricelist = function (instance) { |
|
||||
var module = instance.point_of_sale; |
|
||||
customer_pos_pricelist_db(instance, module); |
|
||||
customer_pos_pricelist_models(instance, module); |
|
||||
customer_pos_pricelist_screens(instance, module); |
|
||||
customer_pos_pricelist_widgets(instance, module); |
|
||||
}; |
|
@ -1,835 +0,0 @@ |
|||||
|
|
||||
function customer_pos_pricelist_models(instance, module) { |
|
||||
|
|
||||
var _t = instance.web._t; |
|
||||
var round_pr = instance.web.round_precision; |
|
||||
var round_di = instance.web.round_decimals; |
|
||||
|
|
||||
|
|
||||
var PosModelParent = module.PosModel; |
|
||||
module.PosModel = module.PosModel.extend({ |
|
||||
/** |
|
||||
* @param session |
|
||||
* @param attributes |
|
||||
*/ |
|
||||
initialize: function (session, attributes) { |
|
||||
PosModelParent.prototype.initialize.apply(this, arguments); |
|
||||
this.pricelist_engine = new module.PricelistEngine({ |
|
||||
'pos': this, |
|
||||
'db': this.db, |
|
||||
'pos_widget': this.pos_widget |
|
||||
}); |
|
||||
arrange_elements(this); |
|
||||
}, |
|
||||
/** |
|
||||
* find model based on name |
|
||||
* @param model_name |
|
||||
* @returns {{}} |
|
||||
*/ |
|
||||
find_model: function (model_name) { |
|
||||
var self = this; |
|
||||
var lookup = {}; |
|
||||
for (var i = 0, len = self.models.length; i < len; i++) { |
|
||||
if (self.models[i].model === model_name) { |
|
||||
lookup[i] = self.models[i] |
|
||||
} |
|
||||
} |
|
||||
return lookup |
|
||||
}, |
|
||||
/** |
|
||||
* @param removed_order |
|
||||
* @param index |
|
||||
* @param reason |
|
||||
*/ |
|
||||
on_removed_order: function (removed_order, index, reason) { |
|
||||
// console.log('removing the order.......')
|
|
||||
PosModelParent.prototype.on_removed_order.apply(this, arguments); |
|
||||
if ((reason === 'abandon' || removed_order.temporary) |
|
||||
&& this.get('orders').size() > 0) { |
|
||||
var current_order = (this.get('orders').at(index) |
|
||||
|| this.get('orders').last()); |
|
||||
var partner = current_order.get_client() ? |
|
||||
current_order.get_client() : |
|
||||
false; |
|
||||
this.pricelist_engine.update_products_ui(partner); |
|
||||
} |
|
||||
} |
|
||||
}); |
|
||||
|
|
||||
/** |
|
||||
* Extend the order |
|
||||
*/ |
|
||||
module.Order = module.Order.extend({ |
|
||||
/** |
|
||||
* override this method to merge lines |
|
||||
* TODO : Need some refactoring in the standard POS to Do it better |
|
||||
* TODO : from line 73 till 85, we need to move this to another method |
|
||||
* @param product |
|
||||
* @param options |
|
||||
*/ |
|
||||
addProduct: function (product, options) { |
|
||||
options = options || {}; |
|
||||
var attr = JSON.parse(JSON.stringify(product)); |
|
||||
attr.pos = this.pos; |
|
||||
attr.order = this; |
|
||||
var line = new module.Orderline({}, { |
|
||||
pos: this.pos, |
|
||||
order: this, |
|
||||
product: product |
|
||||
}); |
|
||||
var self = this; |
|
||||
var found = false; |
|
||||
|
|
||||
if (options.quantity !== undefined) { |
|
||||
line.set_quantity(options.quantity); |
|
||||
} |
|
||||
if (options.price !== undefined) { |
|
||||
line.set_unit_price(options.price); |
|
||||
} |
|
||||
if (options.discount !== undefined) { |
|
||||
line.set_discount(options.discount); |
|
||||
} |
|
||||
|
|
||||
var orderlines = []; |
|
||||
if (self.get('orderLines').models !== undefined) { |
|
||||
orderlines = self.get('orderLines').models; |
|
||||
} |
|
||||
for (var i = 0; i < orderlines.length; i++) { |
|
||||
var _line = orderlines[i]; |
|
||||
if (_line && _line.can_be_merged_with(line) && |
|
||||
options.merge !== false) { |
|
||||
_line.merge(line); |
|
||||
found = true; |
|
||||
break; |
|
||||
} |
|
||||
} |
|
||||
if (!found) { |
|
||||
this.get('orderLines').add(line); |
|
||||
} |
|
||||
this.selectLine(this.getLastOrderline()); |
|
||||
} |
|
||||
}); |
|
||||
|
|
||||
/** |
|
||||
* Extend the Order line |
|
||||
*/ |
|
||||
var OrderlineParent = module.Orderline; |
|
||||
module.Orderline = module.Orderline.extend({ |
|
||||
/** |
|
||||
* @param attr |
|
||||
* @param options |
|
||||
*/ |
|
||||
initialize: function (attr, options) { |
|
||||
OrderlineParent.prototype.initialize.apply(this, arguments); |
|
||||
this.manual_price = false; |
|
||||
if (this.product !== undefined) { |
|
||||
var qty = this.compute_qty(this.order, this.product); |
|
||||
var partner = this.order ? this.order.get_client() : null; |
|
||||
var product = this.product; |
|
||||
// console.log('orderline!!',product)
|
|
||||
var db = this.pos.db; |
|
||||
var price = this.pos.pricelist_engine.compute_price_all( |
|
||||
db, product, partner, qty |
|
||||
); |
|
||||
if (price !== false) { |
|
||||
this.price = round_di(parseFloat(price) || 0, this.pos.dp['Product Price']); |
|
||||
} |
|
||||
} |
|
||||
}, |
|
||||
/** |
|
||||
* @param state |
|
||||
*/ |
|
||||
set_manual_price: function (state) { |
|
||||
this.manual_price = state; |
|
||||
}, |
|
||||
/** |
|
||||
* @param quantity |
|
||||
*/ |
|
||||
set_quantity: function (quantity) { |
|
||||
var partner = this.order ? this.order.get_client() : null; |
|
||||
var product = this.product; |
|
||||
var db = this.pos.db; |
|
||||
var old_price = 0; |
|
||||
if (this.get_quantity()) { |
|
||||
// console.log('QTY!!!!!',this.get_quantity())
|
|
||||
old_price = this.pos.pricelist_engine.compute_price_all( |
|
||||
db, product, partner, this.get_quantity() |
|
||||
); |
|
||||
} |
|
||||
OrderlineParent.prototype.set_quantity.apply(this, arguments); |
|
||||
var price = this.pos.pricelist_engine.compute_price_all( |
|
||||
db, product, partner, quantity |
|
||||
); |
|
||||
/* Update the price if the unit price is actually different from |
|
||||
the unit price of the previous quantity, to preserve manually |
|
||||
entered prices as much as possible. */ |
|
||||
if (price !== false && price !== old_price) { |
|
||||
this.set_unit_price(price); |
|
||||
} |
|
||||
}, |
|
||||
/** |
|
||||
* override this method to take fiscal positions in consideration |
|
||||
* get all price |
|
||||
* TODO : find a better way to do it : need some refactoring |
|
||||
* in the pos standard |
|
||||
* @returns {{ |
|
||||
* priceWithTax: *, priceWithoutTax: *, tax: number, taxDetails: {} |
|
||||
* }} |
|
||||
*/ |
|
||||
get_all_prices: function () { |
|
||||
var base = this.get_base_price(); |
|
||||
var totalTax = base; |
|
||||
var totalNoTax = base; |
|
||||
var taxtotal = 0; |
|
||||
var taxdetail = {}; |
|
||||
var product_taxes = this.get_applicable_taxes_for_orderline(); |
|
||||
var all_taxes = _(this.compute_all(product_taxes, base)).flatten(); |
|
||||
_(all_taxes).each(function (tax) { |
|
||||
if (tax.price_include) { |
|
||||
totalNoTax -= tax.amount; |
|
||||
} else { |
|
||||
totalTax += tax.amount; |
|
||||
} |
|
||||
taxtotal += tax.amount; |
|
||||
taxdetail[tax.id] = tax.amount; |
|
||||
}); |
|
||||
totalNoTax = round_pr(totalNoTax, this.pos.currency.rounding); |
|
||||
return { |
|
||||
"priceWithTax": totalTax, |
|
||||
"priceWithoutTax": totalNoTax, |
|
||||
"tax": taxtotal, |
|
||||
"taxDetails": taxdetail |
|
||||
}; |
|
||||
}, |
|
||||
/** |
|
||||
* Override this method to avoid a return false |
|
||||
* if the price is different |
|
||||
* Check super method : (this.price !== orderline.price) |
|
||||
* is not necessary in our case |
|
||||
* @param orderline |
|
||||
* @returns {boolean} |
|
||||
*/ |
|
||||
can_be_merged_with: function (orderline) { |
|
||||
var result = OrderlineParent.prototype.can_be_merged_with.apply( |
|
||||
this, arguments |
|
||||
); |
|
||||
if (!result) { |
|
||||
if (!this.manual_price) { |
|
||||
return ( |
|
||||
this.get_product().id === orderline.get_product().id |
|
||||
); |
|
||||
} else { |
|
||||
return false; |
|
||||
} |
|
||||
} |
|
||||
return true; |
|
||||
}, |
|
||||
/** |
|
||||
* Override to set price |
|
||||
* @param orderline |
|
||||
*/ |
|
||||
merge: function (orderline) { |
|
||||
OrderlineParent.prototype.merge.apply(this, arguments); |
|
||||
this.set_unit_price(orderline.price); |
|
||||
}, |
|
||||
/** |
|
||||
* @param order |
|
||||
* @param product |
|
||||
* @returns {number} |
|
||||
*/ |
|
||||
compute_qty: function (order, product) { |
|
||||
var qty = 1; |
|
||||
var orderlines = []; |
|
||||
if (order && order.get('orderLines').models !== undefined) { |
|
||||
orderlines = order.get('orderLines').models; |
|
||||
} |
|
||||
for (var i = 0; i < orderlines.length; i++) { |
|
||||
if (orderlines[i].product.id === product.id |
|
||||
&& !orderlines[i].manual_price) { |
|
||||
qty += orderlines[i].quantity; |
|
||||
} |
|
||||
} |
|
||||
return qty; |
|
||||
}, |
|
||||
/** |
|
||||
* @returns {Array} |
|
||||
*/ |
|
||||
get_applicable_taxes_for_orderline: function () { |
|
||||
// find applicable taxes for this product and this customer
|
|
||||
var product = this.get_product(); |
|
||||
var product_tax_ids = product.taxes_id; |
|
||||
var product_taxes = []; |
|
||||
var taxes = this.pos.taxes; |
|
||||
var partner = this.order ? this.order.get_client() : null; |
|
||||
if (partner && partner.property_account_position) { |
|
||||
product_tax_ids = |
|
||||
this.pos.db.map_tax( |
|
||||
partner.property_account_position[0], product_tax_ids |
|
||||
); |
|
||||
} |
|
||||
for (var i = 0, ilen = product_tax_ids.length; |
|
||||
i < ilen; i++) { |
|
||||
var tax_id = product_tax_ids[i]; |
|
||||
var tax = _.detect(taxes, function (t) { |
|
||||
return t.id === tax_id; |
|
||||
}); |
|
||||
product_taxes.push(tax); |
|
||||
} |
|
||||
return product_taxes; |
|
||||
}, |
|
||||
get_display_unit_price: function(){ |
|
||||
var rounding = this.pos.currency.rounding; |
|
||||
if (this.pos.config.display_price_with_taxes) { |
|
||||
return round_pr(this.get_price_with_tax() / this.get_quantity(), rounding); |
|
||||
} else { |
|
||||
return round_pr(this.get_base_price() / this.get_quantity(), rounding); |
|
||||
} |
|
||||
}, |
|
||||
/** |
|
||||
* @returns {*} |
|
||||
*/ |
|
||||
get_display_price: function () { |
|
||||
if (this.pos.config.display_price_with_taxes) { |
|
||||
return this.get_price_with_tax(); |
|
||||
} |
|
||||
return OrderlineParent.prototype.get_display_price.apply( |
|
||||
this, arguments |
|
||||
); |
|
||||
}, |
|
||||
|
|
||||
export_as_JSON: function() { |
|
||||
var res = OrderlineParent.prototype.export_as_JSON.apply(this, arguments); |
|
||||
var product_tax_ids = this.get_product().taxes_id || []; |
|
||||
var partner = this.order ? this.order.get_client() : null; |
|
||||
if (partner && partner.property_account_position) { |
|
||||
product_tax_ids = |
|
||||
this.pos.db.map_tax( |
|
||||
partner.property_account_position[0], product_tax_ids |
|
||||
); |
|
||||
} |
|
||||
res["tax_ids"] = [[6, false, product_tax_ids]]; |
|
||||
return res; |
|
||||
} |
|
||||
}); |
|
||||
|
|
||||
/** |
|
||||
* Pricelist Engine to compute price |
|
||||
*/ |
|
||||
module.PricelistEngine = instance.web.Class.extend({ |
|
||||
/** |
|
||||
* @param options |
|
||||
*/ |
|
||||
init: function (options) { |
|
||||
options = options || {}; |
|
||||
this.pos = options.pos; |
|
||||
this.db = options.db; |
|
||||
this.pos_widget = options.pos_widget; |
|
||||
}, |
|
||||
/** |
|
||||
* compute price for all price list |
|
||||
* @param db |
|
||||
* @param product |
|
||||
* @param partner |
|
||||
* @param qty |
|
||||
* @returns {*} |
|
||||
*/ |
|
||||
compute_price_all: function (db, product, partner, qty) { |
|
||||
var price_list_id = false; |
|
||||
if (partner && partner.pricelist) { |
|
||||
price_list_id = partner.pricelist[0]; |
|
||||
} else { |
|
||||
price_list_id = this.pos.config.pricelist_id[0]; |
|
||||
} |
|
||||
return this.compute_price( |
|
||||
db, product, partner, qty, parseInt(price_list_id) |
|
||||
); |
|
||||
}, |
|
||||
/** |
|
||||
* loop find a valid version for the price list id given in param |
|
||||
* @param db |
|
||||
* @param pricelist_id |
|
||||
* @returns {boolean} |
|
||||
*/ |
|
||||
find_valid_pricelist_version: function (db, pricelist_id) { |
|
||||
|
|
||||
var date = new Date(); |
|
||||
var version = false; |
|
||||
var pricelist = db.pricelist_by_id[pricelist_id]; |
|
||||
// console.log('pricelisttttt!!!!!!!!!!!!!!',pricelist)
|
|
||||
for (var i = 0, len = pricelist.version_id.length; i < len; i++) { |
|
||||
var v = db.pricelist_version_by_id[pricelist.version_id[i]]; |
|
||||
if (((v.date_start == false) |
|
||||
|| (new Date(v.date_start) <= date)) && |
|
||||
((v.date_end == false) |
|
||||
|| (new Date(v.date_end) >= date))) { |
|
||||
version = v; |
|
||||
break; |
|
||||
} |
|
||||
} |
|
||||
return version; |
|
||||
}, |
|
||||
/** |
|
||||
* compute the price for the given product |
|
||||
* @param database |
|
||||
* @param product |
|
||||
* @param partner |
|
||||
* @param qty |
|
||||
* @param pricelist_id |
|
||||
* @returns {boolean} |
|
||||
*/ |
|
||||
compute_price: function (database, product, partner, qty, pricelist_id) { |
|
||||
|
|
||||
var self = this; |
|
||||
var db = database; |
|
||||
// console.log('DATABASE!!!',db)
|
|
||||
|
|
||||
// get a valid version
|
|
||||
var version = this.find_valid_pricelist_version(db, pricelist_id); |
|
||||
console.log('VERSION!!!',version) |
|
||||
if (version == false) { |
|
||||
var message = _t('Pricelist Error'); |
|
||||
var comment = _t('At least one pricelist has no active ' + |
|
||||
'version ! Please create or activate one.'); |
|
||||
show_error(this, message, comment); |
|
||||
return false; |
|
||||
} |
|
||||
|
|
||||
// get categories
|
|
||||
var categ_ids = []; |
|
||||
if (product.categ_id) { |
|
||||
categ_ids.push(product.categ_id[0]); |
|
||||
categ_ids = categ_ids.concat( |
|
||||
db.product_category_ancestors[product.categ_id[0]] |
|
||||
); |
|
||||
} |
|
||||
|
|
||||
// find items
|
|
||||
var items = [], i, len; |
|
||||
for (i = 0, len = db.pricelist_item_sorted.length; i < len; i++) { |
|
||||
var item = db.pricelist_item_sorted[i]; |
|
||||
if ((item.product_id === false |
|
||||
|| item.product_id[0] === product.id) && |
|
||||
(item.categ_id === false |
|
||||
|| categ_ids.indexOf(item.categ_id[0]) !== -1) && |
|
||||
(item.price_version_id[0] === version.id)) { |
|
||||
items.push(item); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
var results = {}; |
|
||||
results[product.id] = 0.0; |
|
||||
var price_types = {}; |
|
||||
var price = false; |
|
||||
|
|
||||
// loop through items
|
|
||||
for (i = 0, len = items.length; i < len; i++) { |
|
||||
var rule = items[i]; |
|
||||
|
|
||||
if (rule.min_quantity && qty < rule.min_quantity) { |
|
||||
continue; |
|
||||
} |
|
||||
if (rule.product_id && rule.product_id[0] |
|
||||
&& product.id != rule.product_id[0]) { |
|
||||
continue; |
|
||||
} |
|
||||
if (rule.categ_id) { |
|
||||
var cat_id = product.categ_id[0]; |
|
||||
while (cat_id) { |
|
||||
if (cat_id == rule.categ_id[0]) { |
|
||||
break; |
|
||||
} |
|
||||
cat_id = db.product_category_by_id[cat_id].parent_id[0] |
|
||||
} |
|
||||
if (!(cat_id)) { |
|
||||
continue; |
|
||||
} |
|
||||
} |
|
||||
// Based on field
|
|
||||
switch (rule.base) { |
|
||||
case -1: |
|
||||
if (rule.base_pricelist_id) { |
|
||||
price = self.compute_price( |
|
||||
db, product, false, qty, |
|
||||
rule.base_pricelist_id[0] |
|
||||
); |
|
||||
} |
|
||||
break; |
|
||||
case -2: |
|
||||
var seller = false; |
|
||||
for (var index in product.seller_ids) { |
|
||||
var seller_id = product.seller_ids[index]; |
|
||||
var _tmp_seller = db.supplierinfo_by_id[seller_id]; |
|
||||
if ((!partner) || (_tmp_seller.name.length |
|
||||
&& _tmp_seller.name[0] != partner.name)) |
|
||||
continue; |
|
||||
seller = _tmp_seller |
|
||||
} |
|
||||
if (!seller && product.seller_ids) { |
|
||||
seller = |
|
||||
db.supplierinfo_by_id[product.seller_ids[0]]; |
|
||||
} |
|
||||
if (seller) { |
|
||||
for (var _id in seller.pricelist_ids) { |
|
||||
var info_id = seller.pricelist_ids[_id]; |
|
||||
var line = |
|
||||
db.pricelist_partnerinfo_by_id[info_id]; |
|
||||
if (line.min_quantity <= qty) { |
|
||||
price = line.price |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
break; |
|
||||
default: |
|
||||
if (!price_types.hasOwnProperty(rule.base)) { |
|
||||
price_types[rule.base] = |
|
||||
db.product_price_type_by_id[rule.base]; |
|
||||
} |
|
||||
var price_type = price_types[rule.base]; |
|
||||
if (db.product_by_id[product.id] |
|
||||
.hasOwnProperty(price_type.field)) { |
|
||||
price = |
|
||||
db.product_by_id[product.id][price_type.field]; |
|
||||
if(price_type.field === 'list_price' && product.price_extra){ |
|
||||
price += product.price_extra; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
if (price !== false) { |
|
||||
var price_limit = price; |
|
||||
price = price * (1.0 + (rule['price_discount'] |
|
||||
? rule['price_discount'] |
|
||||
: 0.0)); |
|
||||
if (rule['price_round']) { |
|
||||
price = parseFloat(price.toFixed( |
|
||||
Math.ceil(Math.log(1.0 / rule['price_round']) |
|
||||
/ Math.log(10))) |
|
||||
); |
|
||||
} |
|
||||
price += (rule['price_surcharge'] |
|
||||
? rule['price_surcharge'] |
|
||||
: 0.0); |
|
||||
if (rule['price_min_margin']) { |
|
||||
price = Math.max( |
|
||||
price, price_limit + rule['price_min_margin'] |
|
||||
) |
|
||||
} |
|
||||
if (rule['price_max_margin']) { |
|
||||
price = Math.min( |
|
||||
price, price_limit + rule['price_min_margin'] |
|
||||
) |
|
||||
} |
|
||||
} |
|
||||
break; |
|
||||
} |
|
||||
return price |
|
||||
}, |
|
||||
/** |
|
||||
* @param partner |
|
||||
*/ |
|
||||
update_products_ui: function (partner) { |
|
||||
var db = this.db; |
|
||||
if (!this.pos_widget.product_screen) return; |
|
||||
var product_list_ui |
|
||||
= this.pos_widget.product_screen.$( |
|
||||
'.product-list span.product' |
|
||||
); |
|
||||
for (var i = 0, len = product_list_ui.length; i < len; i++) { |
|
||||
var product_ui = product_list_ui[i]; |
|
||||
var product_id = $(product_ui).data('product-id'); |
|
||||
var product = $.extend({}, db.get_product_by_id(product_id)); |
|
||||
var rules = db.find_product_rules(product); |
|
||||
var quantities = []; |
|
||||
quantities.push(1); |
|
||||
for (var j = 0; j < rules.length; j++) { |
|
||||
if ($.inArray(rules[j].min_quantity, quantities) === -1) { |
|
||||
quantities.push(rules[j].min_quantity); |
|
||||
} |
|
||||
} |
|
||||
quantities = quantities.sort(); |
|
||||
var prices_displayed = ''; |
|
||||
for (var k = 0; k < quantities.length; k++) { |
|
||||
var qty = quantities[k]; |
|
||||
var price = this.compute_price_all( |
|
||||
db, product, partner, qty |
|
||||
); |
|
||||
if (price !== false) { |
|
||||
if (this.pos.config.display_price_with_taxes) { |
|
||||
var prices = this.simulate_price( |
|
||||
product, partner, price, qty |
|
||||
); |
|
||||
price = prices['priceWithTax'] |
|
||||
} |
|
||||
price = round_di(parseFloat(price) |
|
||||
|| 0, this.pos.dp['Product Price']); |
|
||||
price = this.pos_widget.format_currency(price); |
|
||||
if (k == 0) { |
|
||||
$(product_ui).find('.price-tag').html(price); |
|
||||
} |
|
||||
// prices_displayed += qty
|
|
||||
// + 'x → ' + price + '<br/>';
|
|
||||
} |
|
||||
} |
|
||||
if (prices_displayed != '') { |
|
||||
$(product_ui).find('.price-tag').attr( |
|
||||
'data-original-title', prices_displayed |
|
||||
); |
|
||||
$(product_ui).find('.price-tag').attr( |
|
||||
'data-toggle', 'tooltip' |
|
||||
); |
|
||||
$(product_ui).find('.price-tag').tooltip( |
|
||||
{delay: {show: 50, hide: 100}} |
|
||||
); |
|
||||
} |
|
||||
} |
|
||||
}, |
|
||||
simulate_price: function (product, partner, price, qty) { |
|
||||
// create a fake order in order to get price
|
|
||||
// for this customer
|
|
||||
var order = new module.Order({pos: this.pos}); |
|
||||
order.set_client(partner); |
|
||||
var orderline = new openerp.point_of_sale.Orderline |
|
||||
({}, { |
|
||||
pos: this.pos, order: order, |
|
||||
product: product, price: price |
|
||||
}); |
|
||||
orderline.set_quantity(qty); |
|
||||
// reset the sequence
|
|
||||
this.pos.pos_session.sequence_number--; |
|
||||
var prices = orderline.get_all_prices(); |
|
||||
return prices; |
|
||||
}, |
|
||||
/** |
|
||||
* |
|
||||
* @param partner |
|
||||
* @param orderLines |
|
||||
*/ |
|
||||
update_ticket: function (partner, orderLines) { |
|
||||
var db = this.db; |
|
||||
for (var i = 0, len = orderLines.length; i < len; i++) { |
|
||||
var line = orderLines[i]; |
|
||||
var product = line.product; |
|
||||
var quantity = line.quantity; |
|
||||
var price = this.compute_price_all( |
|
||||
db, product, partner, quantity |
|
||||
); |
|
||||
if (price !== false) { |
|
||||
line.set_unit_price(price); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
}); |
|
||||
/** |
|
||||
* show error |
|
||||
* @param context |
|
||||
* @param message |
|
||||
* @param comment |
|
||||
*/ |
|
||||
function show_error(context, message, comment) { |
|
||||
context.pos.pos_widget.screen_selector.show_popup('error', { |
|
||||
'message': message, |
|
||||
'comment': comment |
|
||||
}); |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* patch models to load some entities |
|
||||
* @param pos_model |
|
||||
*/ |
|
||||
function arrange_elements(pos_model) { |
|
||||
|
|
||||
var product_model = pos_model.find_model('product.product'); |
|
||||
if (_.size(product_model) == 1) { |
|
||||
var product_index = parseInt(Object.keys(product_model)[0]); |
|
||||
pos_model.models[product_index].fields.push( |
|
||||
'categ_id', 'seller_ids', 'price_extra' |
|
||||
); |
|
||||
} |
|
||||
|
|
||||
var res_product_pricelist = pos_model.find_model('product.pricelist'); |
|
||||
if (_.size(res_product_pricelist) == 1) { |
|
||||
var pricelist_index = parseInt(Object.keys( |
|
||||
res_product_pricelist)[0] |
|
||||
); |
|
||||
pos_model.models.splice(++pricelist_index, 0, |
|
||||
{ |
|
||||
model: 'account.fiscal.position.tax', |
|
||||
fields: ['display_name', |
|
||||
'position_id', |
|
||||
'tax_src_id', |
|
||||
'tax_dest_id'], |
|
||||
domain: null, |
|
||||
loaded: function (self, fiscal_position_taxes) { |
|
||||
self.db.add_fiscal_position_taxes( |
|
||||
fiscal_position_taxes |
|
||||
); |
|
||||
} |
|
||||
}, |
|
||||
{ |
|
||||
model: 'pricelist.partnerinfo', |
|
||||
fields: ['display_name', |
|
||||
'min_quantity', |
|
||||
'name', |
|
||||
'price', |
|
||||
'suppinfo_id'], |
|
||||
domain: null, |
|
||||
loaded: function (self, pricelist_partnerinfos) { |
|
||||
self.db.add_pricelist_partnerinfo( |
|
||||
pricelist_partnerinfos |
|
||||
); |
|
||||
} |
|
||||
}, |
|
||||
{ |
|
||||
model: 'product.supplierinfo', |
|
||||
fields: ['delay', |
|
||||
'name', |
|
||||
'min_qty', |
|
||||
'pricelist_ids', |
|
||||
'product_code', |
|
||||
'product_name', |
|
||||
'sequence', |
|
||||
'qty', |
|
||||
'product_tmpl_id'], |
|
||||
domain: [['product_tmpl_id.available_in_pos','=',true]], |
|
||||
loaded: function (self, supplierinfos) { |
|
||||
self.db.add_supplierinfo(supplierinfos); |
|
||||
} |
|
||||
}, |
|
||||
{ |
|
||||
model: 'product.category', |
|
||||
fields: ['name', |
|
||||
'display_name', |
|
||||
'parent_id', |
|
||||
'child_id'], |
|
||||
domain: null, |
|
||||
loaded: function (self, categories) { |
|
||||
self.db.add_product_categories(categories); |
|
||||
|
|
||||
} |
|
||||
}, |
|
||||
{ |
|
||||
model: 'product.pricelist', |
|
||||
fields: ['display_name', |
|
||||
'name', |
|
||||
'version_id', |
|
||||
'currency_id'], |
|
||||
domain: function () { |
|
||||
return [ |
|
||||
['type', '=', 'sale'] |
|
||||
] |
|
||||
}, |
|
||||
loaded: function (self, pricelists) { |
|
||||
console.log("pricelists...",pricelists) |
|
||||
|
|
||||
self.db.add_pricelists(pricelists); |
|
||||
}}, |
|
||||
{ |
|
||||
model: 'product.pricelist', |
|
||||
fields: ['name'], |
|
||||
domain: function () { |
|
||||
return [ |
|
||||
['type', '=', 'sale'] |
|
||||
] |
|
||||
}, |
|
||||
loaded: function (self, pricelistss) { |
|
||||
console.log("pricelists...111",pricelistss) |
|
||||
self.pricelistss = pricelistss; |
|
||||
}}, |
|
||||
{ |
|
||||
model: 'pos.order', |
|
||||
fields: ['name'], |
|
||||
|
|
||||
loaded: function(self,orders){ |
|
||||
self.order = orders[0]; |
|
||||
},}, |
|
||||
|
|
||||
{ |
|
||||
model: 'res.partner', |
|
||||
fields: ['name','street','pricelist','city','state_id','country_id','vat','phone','zip','mobile','email','ean13','write_date'], |
|
||||
domain: [['customer','=',true]], |
|
||||
loaded: function(self,partners){ |
|
||||
console.log("partnerPOS...111",partners) |
|
||||
self.partners = partners; |
|
||||
// self.partner = partners[0]
|
|
||||
self.db.add_partners(partners); |
|
||||
}, |
|
||||
}, |
|
||||
{ |
|
||||
model: 'product.pricelist.version', |
|
||||
fields: ['name', |
|
||||
'pricelist_id', |
|
||||
'date_start', |
|
||||
'date_end', |
|
||||
'items'], |
|
||||
domain: null, |
|
||||
loaded: function (self, versions) { |
|
||||
console.log("versions...",versions) |
|
||||
self.versions = versions; |
|
||||
self.db.add_pricelist_versions(versions); |
|
||||
} |
|
||||
}, |
|
||||
{ |
|
||||
model: 'product.pricelist.item', |
|
||||
fields: ['name', |
|
||||
'base', |
|
||||
'base_pricelist_id', |
|
||||
'categ_id', |
|
||||
'min_quantity', |
|
||||
'price_discount', |
|
||||
'price_max_margin', |
|
||||
'price_min_margin', |
|
||||
'price_round', |
|
||||
'price_surcharge', |
|
||||
'price_version_id', |
|
||||
'product_id', |
|
||||
'product_tmpl_id', |
|
||||
'sequence' |
|
||||
], |
|
||||
domain: null, |
|
||||
loaded: function (self, items) { |
|
||||
self.db.add_pricelist_items(items); |
|
||||
} |
|
||||
}, |
|
||||
{ |
|
||||
model: 'product.price.type', |
|
||||
fields: ['name', 'field', 'currency_id'], |
|
||||
domain: null, |
|
||||
loaded: function (self, price_types) { |
|
||||
// we need to add price type
|
|
||||
// field to product.product model if not the case
|
|
||||
var product_model = |
|
||||
posmodel.find_model('product.product'); |
|
||||
for (var i = 0, len = price_types.length; |
|
||||
i < len; i++) { |
|
||||
var p_type = price_types[i].field; |
|
||||
if (_.size(product_model) == 1) { |
|
||||
var product_index = |
|
||||
parseInt(Object.keys(product_model)[0]); |
|
||||
if (posmodel.models[product_index] |
|
||||
.fields.indexOf(p_type) === -1) { |
|
||||
posmodel.models[product_index].fields.push( |
|
||||
p_type |
|
||||
); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
self.db.add_price_types(price_types); |
|
||||
} |
|
||||
} |
|
||||
); |
|
||||
} |
|
||||
|
|
||||
var res_partner_model = pos_model.find_model('res.partner'); |
|
||||
|
|
||||
var res_partner_index = |
|
||||
parseInt(Object.keys(res_partner_model)[0]); |
|
||||
pos_model.models[res_partner_index].fields.push( |
|
||||
'property_account_position', |
|
||||
'property_product_pricelist', |
|
||||
'pricelist', |
|
||||
console.log('AAAAAAAAAAA') |
|
||||
); |
|
||||
|
|
||||
|
|
||||
} |
|
||||
|
|
||||
} |
|
@ -1,16 +0,0 @@ |
|||||
|
|
||||
function customer_pos_pricelist_screens(instance, module) { |
|
||||
|
|
||||
module.ClientListScreenWidget = module.ClientListScreenWidget.extend({ |
|
||||
save_changes: function () { |
|
||||
this._super(); |
|
||||
if (this.has_client_changed()) { |
|
||||
var currentOrder = this.pos.get('selectedOrder'); |
|
||||
var orderLines = currentOrder.get('orderLines').models; |
|
||||
var partner = currentOrder.get_client(); |
|
||||
this.pos.pricelist_engine.update_products_ui(partner); |
|
||||
this.pos.pricelist_engine.update_ticket(partner, orderLines); |
|
||||
} |
|
||||
} |
|
||||
}); |
|
||||
} |
|
@ -1,71 +0,0 @@ |
|||||
|
|
||||
function customer_pos_pricelist_widgets(instance, module) { |
|
||||
|
|
||||
var round_di = instance.web.round_decimals; |
|
||||
|
|
||||
module.OrderWidget = module.OrderWidget.extend({ |
|
||||
set_value: function (val) { |
|
||||
this._super(val); |
|
||||
var order = this.pos.get('selectedOrder'); |
|
||||
if (this.editable && order.getSelectedLine()) { |
|
||||
var mode = this.numpad_state.get('mode'); |
|
||||
if (mode === 'price') { |
|
||||
order.getSelectedLine().set_manual_price(true); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
}); |
|
||||
|
|
||||
module.OrderButtonWidget = module.OrderButtonWidget.extend({ |
|
||||
selectOrder: function (event) { |
|
||||
this._super(event); |
|
||||
var partner = this.order.get_client() |
|
||||
? this.order.get_client() |
|
||||
: false; |
|
||||
this.pos.pricelist_engine.update_products_ui(partner); |
|
||||
} |
|
||||
}); |
|
||||
|
|
||||
instance.point_of_sale.ProductListWidget.include({ |
|
||||
init: function (parent, options) { |
|
||||
this._super(parent, options); |
|
||||
this.display_price_with_taxes = false; |
|
||||
if ( |
|
||||
posmodel |
|
||||
&& posmodel.config |
|
||||
&& posmodel.config.display_price_with_taxes |
|
||||
) { |
|
||||
this.display_price_with_taxes |
|
||||
= posmodel.config.display_price_with_taxes |
|
||||
} |
|
||||
}, |
|
||||
renderElement: function () { |
|
||||
this._super(); |
|
||||
var order = posmodel.get_order(); |
|
||||
var customer = null; |
|
||||
if(order) { |
|
||||
customer = order.get_client(); |
|
||||
} |
|
||||
this.pos.pricelist_engine.update_products_ui(customer); |
|
||||
} |
|
||||
}); |
|
||||
|
|
||||
module.PosBaseWidget.include({ |
|
||||
format_pr: function(amount, precision) { |
|
||||
// Do not call _super because no addon or XML is using this method
|
|
||||
var currency = (this.pos && this.pos.currency) ? this.pos.currency : {symbol:'$', position: 'after', rounding: 0.01, decimals: 2}; |
|
||||
var decimals = currency.decimals; |
|
||||
|
|
||||
if (precision && this.pos.dp[precision] !== undefined) { |
|
||||
decimals = this.pos.dp[precision]; |
|
||||
} |
|
||||
|
|
||||
if (typeof amount === 'number') { |
|
||||
amount = round_di(amount,decimals).toFixed(decimals); |
|
||||
amount = openerp.instances[this.session.name].web.format_value(round_di(amount, decimals), { type: 'float', digits: [69, decimals]}); |
|
||||
} |
|
||||
return amount |
|
||||
} |
|
||||
}); |
|
||||
} |
|
||||
|
|
@ -1,46 +0,0 @@ |
|||||
<?xml version="1.0" encoding="UTF-8"?> |
|
||||
<templates id="template" xml:space="preserve"> |
|
||||
<t t-extend="ClientDetailsEdit"> |
|
||||
<t t-jquery="div.client-details-left" t-operation="append"> |
|
||||
<t t-jquery="div.client-detail" t-operation="after"> |
|
||||
|
|
||||
<div class='client-detail'> |
|
||||
<span class='label'>Pricelist</span> |
|
||||
<select class='detail client-pricelist' name='pricelist'> |
|
||||
<option value=''>None</option> |
|
||||
<t t-foreach='widget.pos.pricelistss' t-as='pricelistt'> |
|
||||
<option t-att-value='pricelistt.id ' t-att-selected="partner.pricelist ? ((pricelistt.id === partner.pricelist[0]) ? true : undefined) : undefined"> |
|
||||
<t t-esc='pricelistt.name'/> |
|
||||
</option> |
|
||||
</t> |
|
||||
</select> |
|
||||
</div> |
|
||||
|
|
||||
</t></t></t> |
|
||||
|
|
||||
<t t-extend="ClientDetails"> |
|
||||
<t t-jquery="div.client-details-left" t-operation="append"> |
|
||||
<t t-jquery="div.client-detail" t-operation="after"> |
|
||||
<div class='client-detail'> |
|
||||
<span class='label'>Pricelist</span> |
|
||||
<t t-if='partner.pricelist'> |
|
||||
<span class='detail client-pricelist'><t t-esc='partner.pricelist' /></span> |
|
||||
</t> |
|
||||
<t t-if='!partner.pricelist'> |
|
||||
<span class='detail client-pricelist'>N/A</span> |
|
||||
</t> |
|
||||
|
|
||||
</div> |
|
||||
</t></t></t> |
|
||||
|
|
||||
<t t-extend="ClientListScreenWidget"> |
|
||||
<t t-jquery="tr" t-operation="append"> |
|
||||
<th>PriceList</th> |
|
||||
</t></t> |
|
||||
|
|
||||
<t t-extend="ClientLine"> |
|
||||
<t t-jquery="tr.client-line" t-operation="append"> |
|
||||
<td><t t-esc='partner.pricelist' /></td> |
|
||||
</t></t> |
|
||||
|
|
||||
</templates> |
|
@ -1,16 +0,0 @@ |
|||||
<?xml version="1.0" encoding="utf-8"?> |
|
||||
<openerp> |
|
||||
<data> |
|
||||
<record id="my_view_pricelist_inherit" model="ir.ui.view"> |
|
||||
<field name="name">my.view.pricelist.inherit</field> |
|
||||
<field name="model">res.partner</field> |
|
||||
<field name="inherit_id" ref="base.view_partner_form"/> |
|
||||
<field name="arch" type="xml"> |
|
||||
<xpath expr="//page[@name='sales_purchases']" position="inside"> |
|
||||
<group> |
|
||||
<field name="pricelist" placeholder="POS Pricelist" /></group> |
|
||||
</xpath> |
|
||||
</field> |
|
||||
</record> |
|
||||
</data> |
|
||||
</openerp> |
|
@ -1,29 +0,0 @@ |
|||||
<?xml version="1.0" encoding="utf-8"?> |
|
||||
|
|
||||
<openerp> |
|
||||
<data> |
|
||||
<template id="pos_pricelist_assets_backend" |
|
||||
name="pos_pricelist_assets_backend" |
|
||||
inherit_id="point_of_sale.assets_backend"> |
|
||||
<xpath expr="." position="inside"> |
|
||||
<script src="/customer_pos_pricelist/static/src/js/db.js" |
|
||||
type="text/javascript"></script> |
|
||||
<script src="/customer_pos_pricelist/static/src//js/models.js" |
|
||||
type="text/javascript"></script> |
|
||||
<script src="/customer_pos_pricelist/static/src/js/screens.js" |
|
||||
type="text/javascript"></script> |
|
||||
<script src="/customer_pos_pricelist/static/src/js/main.js" |
|
||||
type="text/javascript"></script> |
|
||||
<script src="/customer_pos_pricelist/static/src/js/widgets.js" |
|
||||
type="text/javascript"></script> |
|
||||
</xpath> |
|
||||
</template> |
|
||||
|
|
||||
<template id="pos_pricelist_assets" name="pos_pricelist_css" inherit_id="point_of_sale.index"> |
|
||||
<xpath expr="//script[@id='loading-script']" position="before"> |
|
||||
<link rel="stylesheet" href="/pos_customer_pricelist/static/src/css/style.css"/> |
|
||||
</xpath> |
|
||||
</template> |
|
||||
|
|
||||
</data> |
|
||||
</openerp> |
|