Browse Source

[MIG] pos_pricelist: Migrate to v10 by backporting from v11 (#247)

This module included previously support for taxes and pricelists.

Taxes are now included in upstream Odoo v10, so that feature is removed.

The pricelist feature, however, is supported in upstream Odoo v11. Thus, to ease the migration path, that functionality has been scalpel-backported from there.

This also means a great diff between previous OCA-only code and current Odoo-backport-only code, but with the advantage that the end user gets exactly the behavior that he would have when updating to v11.

Since most of the code has been copied from Odoo, the addon now has to become LGPL, and Odoo has been added as an author.
pull/251/head
Jairo Llopis 7 years ago
committed by Pedro M. Baeza
parent
commit
280f0934a1
  1. 109
      pos_pricelist/README.rst
  2. 37
      pos_pricelist/__init__.py
  3. 47
      pos_pricelist/__manifest__.py
  4. 95
      pos_pricelist/demo/pos_pricelist_demo.yml
  5. 17
      pos_pricelist/hooks.py
  6. 200
      pos_pricelist/i18n/es.po
  7. 141
      pos_pricelist/i18n/pos_pricelist.pot
  8. 30
      pos_pricelist/migrations/8.0.1.1.0/post-migration.py
  9. 24
      pos_pricelist/models/__init__.py
  10. 160
      pos_pricelist/models/point_of_sale.py
  11. 123
      pos_pricelist/models/pos_config.py
  12. 15
      pos_pricelist/models/pos_order.py
  13. 28
      pos_pricelist/models/pos_pricelist.py
  14. 20
      pos_pricelist/models/res_partner.py
  15. 36
      pos_pricelist/report/report_receipt.xml
  16. 4
      pos_pricelist/security/ir.model.access.csv
  17. 150
      pos_pricelist/static/src/css/style.css
  18. 195
      pos_pricelist/static/src/js/db.js
  19. 24
      pos_pricelist/static/src/js/main.js
  20. 998
      pos_pricelist/static/src/js/models.js
  21. 191
      pos_pricelist/static/src/js/screens.js
  22. 184
      pos_pricelist/static/src/js/tests.js
  23. 87
      pos_pricelist/static/src/js/widgets.js
  24. 74
      pos_pricelist/static/src/xml/pos.xml
  25. 16
      pos_pricelist/templates/assets.xml
  26. 28
      pos_pricelist/test/test.py
  27. 28
      pos_pricelist/views/point_of_sale_view.xml
  28. 41
      pos_pricelist/views/pos_config_view.xml
  29. 29
      pos_pricelist/views/pos_pricelist_template.xml
  30. 15
      pos_pricelist/views/pos_pricelist_views.xml
  31. 1
      requirements.txt

109
pos_pricelist/README.rst

@ -1,101 +1,58 @@
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg
:alt: License: AGPL-3
.. image:: https://img.shields.io/badge/license-LGPL--3-blue.svg
:target: https://www.gnu.org/licenses/lgpl
:alt: License: LGPL-3
Dynamic Price for Odoo Point of Sale
====================================
Motivation
----------
Many issues report this feature. This why I took decision to start this module
Reported issues :
`odoo 8 POS price list discount has no effect. <https://github.com/odoo/odoo/issues/3579>`_
`ODOO POS Pricelist - Public Price & Discounted Price in Receipt. <https://github.com/odoo/odoo/issues/1758>`_
`V8.0 pos gives wrong price when using min qty in pos pricelist <https://github.com/odoo/odoo/issues/2297>`_
Goal of the module
------------------
The goal of this module is to bring the pricelist computation engine to the POS.
This module loads all the necessary data into the POS in order to have a coherent behaviour (offline/online/backend).
POS Pricelist
=============
Bring the pricelist computation engine to the Point of Sale.
Installation Installation
============ ============
Nothing special is needed to install this module.
You need this dependency::
pip install oca.decorators
Configuration Configuration
============= =============
You'll have new configuration parameters at Point of Sale > Configuration > Point of Sales
To configure a pricelist-enabled POS:
* Price with Taxes: Show prices with taxes in POS session or not
#. Go to *Point of Sale > Configuration > Point of Sale* and pick/create one.
#. Enable *Pricelists > Use pricelists*.
#. Set the *Available Pricelists* and choose a *Default Pricelist* from
among them.
#. You can use the *Pricelists* button to manage them easily, in case you need
more.
#. Save.
To see the effect, you should for instance apply the pricelist to a customer.
Usage Usage
===== =====
Implemented features at POS Session
-----------------------------------
1. Attached pricelist on partner will take effect on the POS, which means that if we attach a pricelist to a partner.
The POS will recognize it and will compute the price according to the rule defined.
2. Fiscal Position of each partner will also be present so taxes will be correctly computed
(conforming to the fiscal position).
- Implemented Rules are :
1. (-1) : Rule based on other pricelist
2. (-2) : Rule based on supplierinfo
3. (default) : Any price type which is set on the product form
3. An new option is introduced in the POS config to let the user show price with taxes in product widget.
the UI is updated when we change the customer in order to adapt the prices.
The computation take in account the pricelist and the fiscal position of the customer
4. When we mouseover the price tag, a tooltip is shown to indicate the computation depending on the quantity like this output :
1x -> 100 €
3x -> 70 €
5x -> 50 €
Implemented features at backend
-------------------------------
1. Tax details
- Tax details per order line
- Tax details aggregated by tax at order level
2. Ticket
- Tax details table added at end of printed ticket
#. Go to *Point of Sale > Dashboard* and open the POS session you configured.
#. Use the new pricelist button to change it on the fly.
#. When a new order is created, it always has the default pricelist.
#. When you change to a customer that has a different pricelist, the current
order and the listed product prices are updated accordingly.
Known issues / Roadmap Known issues / Roadmap
====================== ======================
Missing features
----------------
* As you may know, product template is not fully implemented in the POS, so I decided to drop it from this module.
* This module is a backport from Odoo 11.0 core pricelist functionalities. As
such, do not migrate it to that version or higher.
* Conflicts with ``pos_backend_partner`` make that when both are installed,
changing the partner does not change the pricelist.
Bug Tracker Bug Tracker
=========== ===========
Bugs are tracked on `GitHub Issues <https://github.com/OCA/pos/issues>`_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us smashing it by providing a detailed and welcomed feedback
`here <https://github.com/OCA/pos/issues/new?body=module:%20pos_pricelist%0Aversion:%208.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
Bugs are tracked on `GitHub Issues
<https://github.com/OCA/pos/issues>`_. In case of trouble, please
check there if your issue has already been reported. If you spotted it first,
help us smash it by providing detailed and welcomed feedback.
Credits Credits
======= =======
@ -106,7 +63,9 @@ Contributors
* Adil Houmadi <ah@taktik.be> * Adil Houmadi <ah@taktik.be>
* Pablo Cayuela <pablo.cayuela@aserti.es> * Pablo Cayuela <pablo.cayuela@aserti.es>
* Antonio Espinosa <antonioea@antiun.com> * Antonio Espinosa <antonioea@antiun.com>
* Odoo S.A.
* `Tecnativa <https://www.tecnativa.com>`_:
* Jairo Llopis <jairo.llopis@tecnativa.com>
Maintainer Maintainer
---------- ----------
@ -121,4 +80,4 @@ OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and mission is to support the collaborative development of Odoo features and
promote its widespread use. promote its widespread use.
To contribute to this module, please visit http://odoo-community.org.
To contribute to this module, please visit https://odoo-community.org.

37
pos_pricelist/__init__.py

@ -1,34 +1,5 @@
# -#- coding: utf-8 -#-
##############################################################################
# Point Of Sale - Pricelist for POS Odoo
# Copyright (C) 2014 Taktik (http://www.taktik.be)
# @author Adil Houmadi <ah@taktik.be>
#
# 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/>.
#
##############################################################################
from . import models
from openerp import SUPERUSER_ID
# -*- coding: utf-8 -*-
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl).
def set_pos_line_taxes(cr, registry):
"""Copy the product taxes to the pos.line"""
cr.execute("""insert into pline_tax_rel
select l.id, t.id
from pos_order_line l
join pos_order o on l.order_id = o.id
join product_product p on l.product_id = p.id
join product_template pt on pt.id = p.product_tmpl_id
join product_taxes_rel rel on rel.prod_id = pt.id
join account_tax t on rel.tax_id = t.id
where t.company_id = o.company_id""")
registry['pos.order']._install_tax_detail(cr, SUPERUSER_ID)
from .hooks import post_init_hook
from . import models

47
pos_pricelist/__manifest__.py

@ -1,46 +1,31 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
##############################################################################
# Point Of Sale - Pricelist for POS Odoo
# Copyright (C) 2014 Taktik (http://www.taktik.be)
# @author Adil Houmadi <ah@taktik.be>
#
# 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/>.
#
##############################################################################
# Copyright 2018 Tecnativa - Jairo Llopis
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl).
{ {
'name': 'POS Pricelist', 'name': 'POS Pricelist',
'version': '8.0.1.2.0',
'version': '10.0.1.0.0',
'category': 'Point Of Sale', 'category': 'Point Of Sale',
'sequence': 1,
'author': "Adil Houmadi @Taktik,Odoo Community Association (OCA)",
'author': "Tecnativa, "
"Odoo SA, "
"Odoo Community Association (OCA)",
'summary': 'Pricelist for Point of sale', 'summary': 'Pricelist for Point of sale',
'license': 'LGPL-3',
'post_init_hook': 'post_init_hook',
'depends': [ 'depends': [
"point_of_sale", "point_of_sale",
], ],
"external_dependencies": {
"python": [
"oca.decorators",
],
},
'data': [ 'data': [
"views/pos_pricelist_template.xml",
"views/pos_pricelist_views.xml",
"views/point_of_sale_view.xml",
"report/report_receipt.xml",
"security/ir.model.access.csv", "security/ir.model.access.csv",
],
'demo': [
'demo/pos_pricelist_demo.yml',
"templates/assets.xml",
"views/pos_config_view.xml",
], ],
'qweb': [ 'qweb': [
'static/src/xml/pos.xml' 'static/src/xml/pos.xml'
], ],
'post_init_hook': "set_pos_line_taxes",
'installable': False,
'application': False,
'auto_install': False,
} }

95
pos_pricelist/demo/pos_pricelist_demo.yml

@ -1,95 +0,0 @@
-
This product will have two rule (min_qty:3 => 10%, min_qty:5 => 30%)
-
!record {model: product.product, id: pos_product_product_1}:
default_code: ABC123
name: POS Product 1
type: product
categ_id: product.product_category_1
list_price: 100.0
standard_price: 50.0
uom_id: product.product_uom_unit
uom_po_id: product.product_uom_unit
available_in_pos: True
-
This product will have one rule (min_qty:2 => 10%)
-
!record {model: product.product, id: pos_product_product_2}:
default_code: ABC124
name: POS Product 2
type: product
categ_id: product.product_category_1
list_price: 100.0
standard_price: 100.0
uom_id: product.product_uom_unit
uom_po_id: product.product_uom_unit
available_in_pos: True
-
This product will have a rule that (based on supplier discount)
-
!record {model: product.product, id: pos_product_product_3}:
default_code: ABC125
name: POS Product 3
type: product
categ_id: product.product_category_1
list_price: 100.0
standard_price: 50.0
uom_id: product.product_uom_unit
uom_po_id: product.product_uom_unit
available_in_pos: True
seller_ids:
- delay: 1
name: base.res_partner_3
pricelist_ids:
- min_quantity : 2.0
price : 80
-
This product belgon to computer category (5% dicount)
-
!record {model: product.product, id: pos_product_product_4}:
default_code: ABC125
name: POS Product 4
type: product
categ_id: product.product_category_4
list_price: 100.0
standard_price: 50.0
uom_id: product.product_uom_unit
uom_po_id: product.product_uom_unit
available_in_pos: True
-
Prepare pricelist items
-
!record {model: product.pricelist.version, id: product.ver0}:
items_id:
- name: 10% Discount on POS Product 1 (Qty 3)
sequence: 2
product_id: pos_product_product_1
base: 1
price_discount: -0.10
min_quantity: 3
- name: 30% Discount on POS Product 1 (Qty 5)
sequence: 1
product_id: pos_product_product_1
min_quantity: 5
base: 1
price_discount: -0.30
- name: 10% Discount (POS Product 2)
sequence: 1
product_id: pos_product_product_2
base: 2
price_discount: -0.10
min_quantity: 2
- name: 20% Discount given by supplier
sequence: 1
min_quantity: 2
product_id: pos_product_product_3
base: -2
- name: 5% Discount on all Computer related products (Qty 2)
sequence: 1
min_quantity: 2
base: 1
categ_id: product.product_category_4
price_discount: -0.05

17
pos_pricelist/hooks.py

@ -0,0 +1,17 @@
# -*- coding: utf-8 -*-
# Copyright 2018 Tecnativa - Jairo Llopis
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl).
from odoo import api, SUPERUSER_ID
def post_init_hook(cr, registry):
"""Set default pricelists for existing POS configurations"""
with api.Environment.manage():
env = api.Environment(cr, SUPERUSER_ID, {})
nopricelist = env["pos.config"].search([
("available_pricelist_ids", "=", False),
])
for one in nopricelist:
one.available_pricelist_ids = (one.pricelist_id or
one._default_pricelist())

200
pos_pricelist/i18n/es.po

@ -1,141 +1,141 @@
# Translation of Odoo Server. # Translation of Odoo Server.
# This file contains the translation of the following modules: # This file contains the translation of the following modules:
# * pos_pricelist
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 8.0\n"
# * point_of_sale
"Project-Id-Version: Odoo Server 11.0\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-07-24 14:44+0000\n"
"PO-Revision-Date: 2015-07-24 14:44+0000\n"
"Last-Translator: <>\n"
"Language-Team: \n"
"POT-Creation-Date: 2018-02-15 09:10+0000\n"
"PO-Revision-Date: 2018-02-15 09:18+0000\n"
"Last-Translator: Jairo Llopis <yajo.sk8@gmail.com>\n"
"Language-Team: Spanish (https://www.transifex.com/odoo/teams/41243/es/)\n"
"Language: es\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: Poedit 2.0.3\n"
#. module: pos_pricelist #. module: pos_pricelist
#: field:pos.order.tax,amount:0
#: view:website:point_of_sale.report_receipt
msgid "Amount"
msgstr "Cuota"
#. module: pos_pricelist
#. openerp-web
#: code:addons/pos_pricelist/static/src/js/models.js:386
#: code:addons/pos_pricelist/models/pos_config.py:57
#, python-format #, python-format
msgid "At least one pricelist has no active version ! Please create or activate one."
msgstr "¡Al menos una lista de precios no tiene ua versión activa! Por favor, cree o active una."
#. module: pos_pricelist
#: field:pos.order.tax,base:0
#: view:website:point_of_sale.report_receipt
msgid "Base"
msgstr "Base imponible"
#. module: pos_pricelist
#: field:pos.order.tax,create_uid:0
msgid "Created by"
msgstr "Creado por"
#. module: pos_pricelist
#: field:pos.order.tax,create_date:0
msgid "Created on"
msgstr "Creado en"
#. module: pos_pricelist
#: help:pos.config,display_price_with_taxes:0
msgid "Display Prices with taxes on POS"
msgstr "Mostrar los precios con impuestos incluidos en el TPV"
#. module: pos_pricelist
#: field:pos.order.tax,id:0
msgid "ID"
msgstr "ID"
msgid ""
"All available pricelists must be in the same currency as the company or as "
"the Sales Journal set on this point of sale if you use the Accounting "
"application."
msgstr ""
"Todas las tarifas deben estar en la misma moneda que la compañía o el diario "
"de ventas escogido para este punto de venta si usted está usando la "
"aplicación de contabilidad."
#. module: pos_pricelist #. module: pos_pricelist
#: field:pos.order.tax,write_uid:0
msgid "Last Updated by"
msgstr "Última actualización por"
#: code:addons/pos_pricelist/models/pos_config.py:69
#, python-format
msgid ""
"All payment methods must be in the same currency as the Sales Journal or the "
"company currency if that is not set."
msgstr ""
"Todos los métodos de pago deben estar en la misma moneda que el diario de "
"ventas o, si no lo hay, de la compañía."
#. module: pos_pricelist #. module: pos_pricelist
#: field:pos.order.tax,write_date:0
msgid "Last Updated on"
msgstr "Última actualización en"
#: model:ir.model.fields,help:pos_pricelist.field_pos_config_group_sale_pricelist
msgid ""
"Allows to manage different prices based on rules per category of customers. "
"Example: 10% for retailers, promotion of 5 EUR on this product, etc."
msgstr ""
"Permite gestionar diferentes precios basándose en reglas por categoría de "
"clientes. Por ejemplo: 10% para minoristas, promoción de 5€ en este "
"producto, etc."
#. module: pos_pricelist #. module: pos_pricelist
#: model:ir.model,name:pos_pricelist.model_pos_order_line
msgid "Lines of Point of Sale"
msgstr "Líneas del Terminal Punto de Venta"
#: model:ir.model.fields,field_description:pos_pricelist.field_pos_config_available_pricelist_ids
msgid "Available Pricelists"
msgstr "Listas de Precio Disponibles"
#. module: pos_pricelist #. module: pos_pricelist
#: field:pos.order.tax,pos_order:0
msgid "POS Order"
msgstr "Pedido"
#: model:ir.model.fields,help:pos_pricelist.field_pos_config_available_pricelist_ids
msgid ""
"Make several pricelists available in the Point of Sale. You can also apply a "
"pricelist to specific customers from their contact form (in Sales tab). To "
"be valid, this pricelist must be listed here as an available pricelist. "
"Otherwise the default pricelist will apply."
msgstr ""
"Hacer disponibles varias tarifas en este punto de venta. También puede "
"aplicar una tarifa a clientes específicos desde su formulario de contacto "
"(en la pestaña de ventas). Para que sea válida, esa tarifa debe estar "
"disponible aquí. En caso contrario, se le aplicará la tarifa por defecto."
#. module: pos_pricelist #. module: pos_pricelist
#: model:product.template,name:pos_pricelist.pos_product_product_1_product_template
msgid "POS Product 1"
msgstr "TPV Producto 1"
#. openerp-web
#: code:addons/pos_pricelist/static/src/xml/pos.xml:36
#, python-format
msgid "N/A"
msgstr "N/A"
#. module: pos_pricelist #. module: pos_pricelist
#: model:product.template,name:pos_pricelist.pos_product_product_2_product_template
msgid "POS Product 2"
msgstr "TPV Producto 2"
#: model:ir.model,name:pos_pricelist.model_pos_order
msgid "Point of Sale Orders"
msgstr "Pedidos del TPV"
#. module: pos_pricelist #. module: pos_pricelist
#: model:product.template,name:pos_pricelist.pos_product_product_3_product_template
msgid "POS Product 3"
msgstr "TPV Producto 3"
#. openerp-web
#: code:addons/pos_pricelist/static/src/js/screens.js:186
#: code:addons/pos_pricelist/static/src/xml/pos.xml:15
#: code:addons/pos_pricelist/static/src/xml/pos.xml:31
#, python-format
msgid "Pricelist"
msgstr "Tarifa"
#. module: pos_pricelist #. module: pos_pricelist
#: model:product.template,name:pos_pricelist.pos_product_product_4_product_template
msgid "POS Product 4"
msgstr "TPV Producto 4"
#: model:ir.ui.view,arch_db:pos_pricelist.view_pos_config_form
msgid "Pricelists"
msgstr "Tarifas"
#. module: pos_pricelist #. module: pos_pricelist
#: view:pos.order:pos_pricelist.view_pos_pos_form
msgid "Payments"
msgstr "Pagos"
#. openerp-web
#: code:addons/pos_pricelist/static/src/js/screens.js:173
#, python-format
msgid "Select pricelist"
msgstr "Seleccionar tarifa"
#. module: pos_pricelist #. module: pos_pricelist
#: model:ir.model,name:pos_pricelist.model_pos_order
msgid "Point of Sale"
msgstr "Terminal Punto de Venta"
#: model:ir.model.fields,help:pos_pricelist.field_pos_config_use_pricelist
msgid "Set shop-specific prices, seasonal discounts, etc."
msgstr ""
"Establecer precios específicos por tienda, descuentos por campaña especial, "
"etc."
#. module: pos_pricelist #. module: pos_pricelist
#: field:pos.config,display_price_with_taxes:0
msgid "Price With Taxes"
msgstr "Precios con impuestos incluidos"
#: model:ir.model.fields,field_description:pos_pricelist.field_pos_config_group_pricelist_item
msgid "Show pricelists to customers"
msgstr "Mostrar tarifas a los clientes"
#. module: pos_pricelist #. module: pos_pricelist
#. openerp-web
#: code:addons/pos_pricelist/static/src/js/models.js:385
#: code:addons/pos_pricelist/models/pos_config.py:52
#, python-format #, python-format
msgid "Pricelist Error"
msgstr "Error en lista de precios"
msgid "The default pricelist must be included in the available pricelists."
msgstr "La tarifa por defecto debe estar incluida entre las disponibles."
#. module: pos_pricelist #. module: pos_pricelist
#: field:pos.order.tax,tax:0
#: view:website:point_of_sale.report_receipt
msgid "Tax"
msgstr "Impuesto"
#: code:addons/pos_pricelist/models/pos_config.py:63
#, python-format
msgid ""
"The invoice journal must be in the same currency as the Sales Journal or the "
"company currency if that is not set."
msgstr ""
"El diario de facturación debe estar en la misma moneda que el de ventas o, "
"si no lo hay, que la compañía."
#. module: pos_pricelist #. module: pos_pricelist
#: field:pos.order.tax,name:0
msgid "Tax Description"
msgstr "Descripción del impuesto"
#: model:ir.model.fields,field_description:pos_pricelist.field_pos_config_use_pricelist
msgid "Use pricelists"
msgstr "Usar tarifas"
#. module: pos_pricelist #. module: pos_pricelist
#: view:pos.order:pos_pricelist.view_pos_pos_form
#: field:pos.order,taxes:0
#: field:pos.order.line,tax_ids:0
msgid "Taxes"
msgstr "Impuestos"
#: model:ir.model.fields,field_description:pos_pricelist.field_pos_config_group_sale_pricelist
msgid "Use pricelists to adapt your price per customers"
msgstr "Usar tarifas para adaptar los precios a cada cliente"
#. module: pos_pricelist #. module: pos_pricelist
#: view:pos.order:pos_pricelist.view_pos_pos_form
msgid "Taxes detail"
msgstr "Detalle de impuestos"
#: model:ir.model,name:pos_pricelist.model_pos_config
msgid "pos.config"
msgstr "pos.config"

141
pos_pricelist/i18n/pos_pricelist.pot

@ -1,141 +0,0 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * pos_pricelist
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 8.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-07-24 14:44+0000\n"
"PO-Revision-Date: 2015-07-24 14:44+0000\n"
"Last-Translator: <>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: pos_pricelist
#: field:pos.order.tax,amount:0
#: view:website:point_of_sale.report_receipt
msgid "Amount"
msgstr ""
#. module: pos_pricelist
#. openerp-web
#: code:addons/pos_pricelist/static/src/js/models.js:386
#, python-format
msgid "At least one pricelist has no active version ! Please create or activate one."
msgstr ""
#. module: pos_pricelist
#: field:pos.order.tax,base:0
#: view:website:point_of_sale.report_receipt
msgid "Base"
msgstr ""
#. module: pos_pricelist
#: field:pos.order.tax,create_uid:0
msgid "Created by"
msgstr ""
#. module: pos_pricelist
#: field:pos.order.tax,create_date:0
msgid "Created on"
msgstr ""
#. module: pos_pricelist
#: help:pos.config,display_price_with_taxes:0
msgid "Display Prices with taxes on POS"
msgstr ""
#. module: pos_pricelist
#: field:pos.order.tax,id:0
msgid "ID"
msgstr ""
#. module: pos_pricelist
#: field:pos.order.tax,write_uid:0
msgid "Last Updated by"
msgstr ""
#. module: pos_pricelist
#: field:pos.order.tax,write_date:0
msgid "Last Updated on"
msgstr ""
#. module: pos_pricelist
#: model:ir.model,name:pos_pricelist.model_pos_order_line
msgid "Lines of Point of Sale"
msgstr ""
#. module: pos_pricelist
#: field:pos.order.tax,pos_order:0
msgid "POS Order"
msgstr ""
#. module: pos_pricelist
#: model:product.template,name:pos_pricelist.pos_product_product_1_product_template
msgid "POS Product 1"
msgstr ""
#. module: pos_pricelist
#: model:product.template,name:pos_pricelist.pos_product_product_2_product_template
msgid "POS Product 2"
msgstr ""
#. module: pos_pricelist
#: model:product.template,name:pos_pricelist.pos_product_product_3_product_template
msgid "POS Product 3"
msgstr ""
#. module: pos_pricelist
#: model:product.template,name:pos_pricelist.pos_product_product_4_product_template
msgid "POS Product 4"
msgstr ""
#. module: pos_pricelist
#: view:pos.order:pos_pricelist.view_pos_pos_form
msgid "Payments"
msgstr ""
#. module: pos_pricelist
#: model:ir.model,name:pos_pricelist.model_pos_order
msgid "Point of Sale"
msgstr ""
#. module: pos_pricelist
#: field:pos.config,display_price_with_taxes:0
msgid "Price With Taxes"
msgstr ""
#. module: pos_pricelist
#. openerp-web
#: code:addons/pos_pricelist/static/src/js/models.js:385
#, python-format
msgid "Pricelist Error"
msgstr ""
#. module: pos_pricelist
#: field:pos.order.tax,tax:0
#: view:website:point_of_sale.report_receipt
msgid "Tax"
msgstr ""
#. module: pos_pricelist
#: field:pos.order.tax,name:0
msgid "Tax Description"
msgstr ""
#. module: pos_pricelist
#: view:pos.order:pos_pricelist.view_pos_pos_form
#: field:pos.order,taxes:0
#: field:pos.order.line,tax_ids:0
msgid "Taxes"
msgstr ""
#. module: pos_pricelist
#: view:pos.order:pos_pricelist.view_pos_pos_form
msgid "Taxes detail"
msgstr ""

30
pos_pricelist/migrations/8.0.1.1.0/post-migration.py

@ -1,30 +0,0 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (C) 2015 Aserti Global Solutions (http://www.aserti.es/).
#
# 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__ = "Copy the product taxes to the pos.line"
def migrate(cr, version):
cr.execute("""insert into pline_tax_rel
select l.id, t.id
from pos_order_line l
join pos_order o on l.order_id = o.id
join product_taxes_rel rel on rel.prod_id = l.product_id
join account_tax t on rel.tax_id = t.id
where t.company_id = o.company_id""")

24
pos_pricelist/models/__init__.py

@ -1,20 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
##############################################################################
# Point Of Sale - Pricelist for POS Odoo
# Copyright (C) 2015 Taktik (http://www.taktik.be)
# @author Adil Houmadi <ah@taktik.be>
#
# 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/>.
#
##############################################################################
from . import pos_pricelist
from . import point_of_sale
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl).
from . import pos_config
from . import pos_order
from . import res_partner

160
pos_pricelist/models/point_of_sale.py

@ -1,160 +0,0 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (C) 2015 Aserti Global Solutions (http://www.aserti.es/).
#
# 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/>.
#
##############################################################################
from openerp import models, fields, api
from openerp.addons import decimal_precision as dp
import logging
_logger = logging.getLogger(__name__)
class PosOrderTax(models.Model):
_name = 'pos.order.tax'
pos_order = fields.Many2one('pos.order', string='POS Order',
ondelete='cascade', index=True)
tax = fields.Many2one('account.tax', string='Tax')
name = fields.Char(string='Tax Description', required=True)
base = fields.Float(string='Base', digits=dp.get_precision('Account'))
amount = fields.Float(string='Amount', digits=dp.get_precision('Account'))
class PosOrderLine(models.Model):
_inherit = "pos.order.line"
@api.multi
def _compute_taxes(self):
res = {
'total': 0,
'total_included': 0,
'taxes': [],
}
for line in self:
price = line.price_unit * (1 - (line.discount or 0.0) / 100.0)
taxes = line.tax_ids.compute_all(
price, line.qty, product=line.product_id,
partner=line.order_id.partner_id)
res['total'] += taxes['total']
res['total_included'] += taxes['total_included']
res['taxes'] += taxes['taxes']
return res
@api.one
@api.depends('tax_ids', 'qty', 'price_unit',
'product_id', 'discount', 'order_id.partner_id')
def _amount_line_all(self):
taxes = self._compute_taxes()
self.price_subtotal = taxes['total']
self.price_subtotal_incl = taxes['total_included']
tax_ids = fields.Many2many(
'account.tax', 'pline_tax_rel', 'pos_line_id', 'tax_id',
"Taxes", domain=[('type_tax_use', '=', 'sale')])
price_subtotal = fields.Float(compute="_amount_line_all", store=True)
price_subtotal_incl = fields.Float(compute="_amount_line_all", store=True)
class PosOrder(models.Model):
_inherit = "pos.order"
taxes = fields.One2many(comodel_name='pos.order.tax',
inverse_name='pos_order', readonly=True)
@api.model
def _amount_line_tax(self, line):
price = line.price_unit * (1 - (line.discount or 0.0) / 100.0)
taxes = line.tax_ids.compute_all(
price, line.qty, product=line.product_id,
partner=line.order_id.partner_id)['taxes']
val = 0.0
for c in taxes:
val += c.get('amount', 0.0)
return val
@api.multi
def _tax_list_get(self):
agg_taxes = {}
tax_lines = []
for order in self:
for line in order.lines:
tax_lines.append({
'base': line.price_subtotal,
'taxes': line._compute_taxes()['taxes']
})
for tax_line in tax_lines:
base = tax_line['base']
for tax in tax_line['taxes']:
tax_id = str(tax['id'])
if tax_id in agg_taxes:
agg_taxes[tax_id]['base'] += base
agg_taxes[tax_id]['amount'] += tax['amount']
else:
agg_taxes[tax_id] = {
'tax_id': tax_id,
'name': tax['name'],
'base': base,
'amount': tax['amount'],
}
return agg_taxes
@api.multi
def compute_tax_detail(self):
taxes_to_delete = False
for order in self:
taxes_to_delete = self.env['pos.order.tax'].search(
[('pos_order', '=', order.id)])
# Update order taxes list
for key, tax in order._tax_list_get().iteritems():
current = taxes_to_delete.filtered(
lambda r: r.tax.id == tax['tax_id'])
if current:
current.write({
'base': tax['base'],
'amount': tax['amount'],
})
taxes_to_delete -= current
else:
self.env['pos.order.tax'].create({
'pos_order': order.id,
'tax': tax['tax_id'],
'name': tax['name'],
'base': tax['base'],
'amount': tax['amount'],
})
if taxes_to_delete:
taxes_to_delete.unlink()
@api.multi
def action_paid(self):
result = super(PosOrder, self).action_paid()
self.compute_tax_detail()
return result
@api.model
def _install_tax_detail(self):
"""Create tax details to pos.order's already paid, done or invoiced.
"""
# Find orders with state : paid, done or invoiced
orders = self.search([('state', 'in', ('paid', 'done', 'invoiced')),
('taxes', '=', False)])
# Compute tax detail
orders.compute_tax_detail()
_logger.info("%d orders computed installing module.", len(orders))

123
pos_pricelist/models/pos_config.py

@ -0,0 +1,123 @@
# -*- coding: utf-8 -*-
# Copyright 2018 Tecnativa - Jairo Llopis
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl).
from odoo import _, api, fields, models
from odoo.exceptions import ValidationError
import logging
_logger = logging.getLogger(__name__)
try:
from oca.decorators import foreach
except ImportError: # pragma: no-cover
_logger.warn("Missing dependency", exc_info=True)
class PosConfig(models.Model):
_inherit = 'pos.config'
# Redefine preexisting field
pricelist_id = fields.Many2one(
string="Default Pricelist",
help="The pricelist used if no customer is selected or if the "
"customer has no Sale Pricelist configured.",
)
# New fields
available_pricelist_ids = fields.Many2many(
'product.pricelist',
string='Available Pricelists',
default=lambda self: self._default_pricelist(),
help="Make several pricelists available in the Point of Sale. "
"You can also apply a pricelist to specific customers from "
"their contact form (in Sales tab). To be valid, this pricelist "
"must be listed here as an available pricelist. Otherwise the "
"default pricelist will apply.",
)
use_pricelist = fields.Boolean(
"Use pricelists",
help="Set shop-specific prices, seasonal discounts, etc.",
)
group_sale_pricelist = fields.Boolean(
"Use pricelists to adapt your price per customers",
implied_group='product.group_sale_pricelist',
help="Allows to manage different prices based on rules per "
"category of customers. Example: 10% for retailers, promotion "
"of 5 EUR on this product, etc.",
)
group_pricelist_item = fields.Boolean(
"Show pricelists to customers",
implied_group='product.group_pricelist_item',
)
@api.constrains('pricelist_id', 'available_pricelist_ids', 'journal_id',
'invoice_journal_id', 'journal_ids')
@foreach()
def _check_currencies(self):
if self.pricelist_id not in self.available_pricelist_ids:
raise ValidationError(_(
"The default pricelist must be included in "
"the available pricelists."))
if self.available_pricelist_ids.filtered(
lambda pricelist: pricelist.currency_id != self.currency_id):
raise ValidationError(_(
"All available pricelists must be in the same currency "
"as the company or as the Sales Journal set on this "
"point of sale if you use the Accounting application."))
if (self.invoice_journal_id.currency_id and
self.invoice_journal_id.currency_id != self.currency_id):
raise ValidationError(_(
"The invoice journal must be in the same currency as the "
"Sales Journal or the company currency if that is not set."))
if self.journal_ids.filtered(
lambda journal: (journal.currency_id and
journal.currency_id != self.currency_id)):
raise ValidationError(_(
"All payment methods must be in the same currency as the "
"Sales Journal or the company currency if that is not set."))
@api.onchange('use_pricelist')
def _onchange_use_pricelist(self):
"""If the 'pricelist' box is unchecked, reset the pricelist_id
This makes the posbox to stop using a pricelist.
"""
if not self.use_pricelist:
self.pricelist_id = self.available_pricelist_ids = \
self._default_pricelist()
else:
self.update({
'group_sale_pricelist': True,
'group_pricelist_item': True,
})
@api.onchange('available_pricelist_ids')
def _onchange_available_pricelist_ids(self):
if self.pricelist_id not in self.available_pricelist_ids:
self.pricelist_id = False
@foreach()
def _check_groups_implied(self):
for field_name in (f for f in self.fields_get_keys()
if f.startswith('group_')):
field = self._fields[field_name]
if (field.type in {'boolean', 'selection'} and
hasattr(field, 'implied_group')):
field_group_xmlids = getattr(
field, 'group', 'base.group_user').split(',')
field_groups = self.env['res.groups'].concat(
*(self.env.ref(it) for it in field_group_xmlids))
field_groups.write({
'implied_ids': [(4, self.env.ref(field.implied_group).id)],
})
@api.model
def create(self, vals):
result = super(PosConfig, self).create(vals)
result.sudo()._check_groups_implied()
return result
def write(self, vals):
result = super(PosConfig, self).write(vals)
self.sudo()._check_groups_implied()
return result

15
pos_pricelist/models/pos_order.py

@ -0,0 +1,15 @@
# -*- coding: utf-8 -*-
# Copyright 2018 Tecnativa - Jairo Llopis
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl).
from odoo import api, models
class PosOrder(models.Model):
_inherit = "pos.order"
@api.model
def _order_fields(self, ui_order):
result = super(PosOrder, self)._order_fields(ui_order)
result.setdefault('pricelist_id', ui_order['pricelist_id'])
return result

28
pos_pricelist/models/pos_pricelist.py

@ -1,28 +0,0 @@
# -*- coding: utf-8 -*-
##############################################################################
# Point Of Sale - Pricelist for POS Odoo
# Copyright (C) 2015 Taktik (http://www.taktik.be)
# @author Adil Houmadi <ah@taktik.be>
#
# 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/>.
#
##############################################################################
from openerp import models, fields
class PosPriceListConfig(models.Model):
_inherit = 'pos.config'
display_price_with_taxes = fields.Boolean(
string='Price With Taxes',
help="Display Prices with taxes on POS"
)

20
pos_pricelist/models/res_partner.py

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Copyright 2018 Tecnativa - Jairo Llopis
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl).
from odoo import api, models
class ResPartner(models.Model):
_inherit = "res.partner"
@api.model
def create_from_ui(self, partner):
try:
# If there's an incoming pricelist, it must be an int
partner["property_product_pricelist"] = \
int(partner["property_product_pricelist"])
except KeyError:
# There's no incoming pricelist, no problem
pass
return super(ResPartner, self).create_from_ui(partner)

36
pos_pricelist/report/report_receipt.xml

@ -1,36 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<template id="report_receipt"
inherit_id="point_of_sale.report_receipt"
name="Add taxes detail">
<xpath expr="//div[@class='page']" position="inside">
<table class="table table-condensed">
<thead>
<tr>
<th>Tax</th>
<th class="text-right">Base</th>
<th class="text-right">Amount</th>
</tr>
</thead>
<tbody>
<tr t-foreach="o.taxes" t-as="tax">
<td>
<span t-esc="tax.name"/>
</td>
<td class="text-right">
<span t-esc="formatLang(tax.base, currency_obj=res_company.currency_id)"/>
</td>
<td class="text-right">
<span t-esc="formatLang(tax.amount, currency_obj=res_company.currency_id)"/>
</td>
</tr>
</tbody>
</table>
</xpath>
</template>
</data>
</openerp>

4
pos_pricelist/security/ir.model.access.csv

@ -1,3 +1,3 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_pos_order_tax,pos.order.tax,model_pos_order_tax,point_of_sale.group_pos_user,1,0,0,0
access_pos_order_tax_manager,pos.order.tax manager,model_pos_order_tax,point_of_sale.group_pos_manager,1,1,1,1
access_product_pricelist_manager,product.pricelist manager,product.model_product_pricelist,point_of_sale.group_pos_manager,1,1,1,1
access_product_pricelist_user,product.pricelist user,product.model_product_pricelist,point_of_sale.group_pos_user,1,0,0,0

150
pos_pricelist/static/src/css/style.css

@ -1,150 +0,0 @@
/******************************************************************************
* Point Of Sale - Pricelist for POS Odoo
* Copyright (C) 2014 Taktik (http://www.taktik.be)
* @author Adil Houmadi <ah@taktik.be>
*
* 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/>.
*
******************************************************************************/
.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;
}

195
pos_pricelist/static/src/js/db.js

@ -1,195 +0,0 @@
/******************************************************************************
* Point Of Sale - Pricelist for POS Odoo
* Copyright (C) 2014 Taktik (http://www.taktik.be)
* @author Adil Houmadi <ah@taktik.be>
*
* 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/>.
*
******************************************************************************/
function 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;
}
})
}

24
pos_pricelist/static/src/js/main.js

@ -1,24 +0,0 @@
/******************************************************************************
* Point Of Sale - Pricelist for POS Odoo
* Copyright (C) 2014 Taktik (http://www.taktik.be)
* @author Adil Houmadi <ah@taktik.be>
*
* 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_pricelist = function (instance) {
var module = instance.point_of_sale;
pos_pricelist_db(instance, module);
pos_pricelist_models(instance, module);
pos_pricelist_screens(instance, module);
pos_pricelist_widgets(instance, module);
};

998
pos_pricelist/static/src/js/models.js
File diff suppressed because it is too large
View File

191
pos_pricelist/static/src/js/screens.js

@ -1,32 +1,167 @@
/******************************************************************************
* Point Of Sale - Pricelist for POS Odoo
* Copyright (C) 2014 Taktik (http://www.taktik.be)
* @author Adil Houmadi <ah@taktik.be>
*
* 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/>.
*
******************************************************************************/
function pos_pricelist_screens(instance, module) {
module.ClientListScreenWidget = module.ClientListScreenWidget.extend({
/* Copyright 2018 Tecnativa - Jairo Llopis
License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl). */
odoo.define("pos_pricelist.screens", function (require) {
"use strict";
var core = require("web.core");
var screens = require("point_of_sale.screens");
var _t = core._t;
var exports = {};
screens.ScaleScreenWidget.include({
_get_active_pricelist: function() {
var current_order = this.pos.get_order();
var current_pricelist = this.pos.default_pricelist;
if (current_order) {
current_pricelist = current_order.pricelist;
}
return current_pricelist;
},
get_product_price: function () {
var result = this._super.apply(this, arguments);
var product = this.get_product();
if (product) {
var pricelist = this._get_active_pricelist();
result = product.get_price(pricelist, this.weight) || result;
}
return result;
},
});
screens.DomCache.include({
init: function () {
this._super.apply(this, arguments);
this.key_wrapper = function (key) {
return key;
};
},
cache_node: function () {
arguments[0] = this.key_wrapper(arguments[0]);
return this._super.apply(this, arguments);
},
clear_node: function() {
arguments[0] = this.key_wrapper(arguments[0]);
return this._super.apply(this, arguments);
},
get_node: function() {
arguments[0] = this.key_wrapper(arguments[0]);
return this._super.apply(this, arguments);
},
});
screens.ProductListWidget.include({
init: function () {
this._super.apply(this, arguments);
this.pos.get('orders').bind(
'add remove change',
$.proxy(this, "renderElement")
);
this.pos.bind(
'change:selectedOrder',
$.proxy(this, "renderElement")
);
this.product_cache.key_wrapper = $.proxy(
this,
"calculate_cache_key"
);
},
calculate_cache_key: function (product) {
var result = product + ',' + this._get_active_pricelist().id;
return result;
},
_get_active_pricelist: function () {
var current_order = this.pos.get_order();
var current_pricelist = this.pos.default_pricelist;
if (current_order) {
current_pricelist = current_order.pricelist;
}
return current_pricelist;
},
});
screens.ClientListScreenWidget.include({
save_changes: function () { save_changes: function () {
this._super();
if (this.has_client_changed()) { 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);
var order = this.pos.get_order(),
pricelist = false;
if (this.new_client) {
pricelist = _.findWhere(
this.pos.pricelists,
{'id': this.new_client.property_product_pricelist[0]}
);
}
order.set_pricelist(pricelist || this.pos.default_pricelist);
}
return this._super.apply(this, arguments);
},
});
exports.set_pricelist_button = screens.ActionButtonWidget.extend({
template: 'SetPricelistButton',
init: function (parent, options) {
this._super(parent, options);
this.pos.get('orders').bind('add remove change', function () {
this.renderElement();
}, this);
this.pos.bind('change:selectedOrder', function () {
this.renderElement();
}, this);
},
button_click: function () {
var self = this;
var pricelists = _.map(self.pos.pricelists, function (pricelist) {
return {
label: pricelist.name,
item: pricelist
};
});
self.gui.show_popup('selection', {
title: _t('Select pricelist'),
list: pricelists,
confirm: function (pricelist) {
var order = self.pos.get_order();
order.set_pricelist(pricelist);
},
is_selected: function (pricelist) {
return pricelist.id === self.pos.get_order().pricelist.id;
}
});
},
get_current_pricelist_name: function () {
var name = _t('Pricelist');
var order = this.pos.get_order();
if (order) {
var pricelist = order.pricelist;
if (pricelist) {
name = pricelist.display_name;
}
} }
}
return name;
},
});
screens.define_action_button({
'name': 'set_pricelist',
'widget': exports.set_pricelist_button,
'condition': function () {
return this.pos.pricelists.length > 1;
},
}); });
}
return exports;
});

184
pos_pricelist/static/src/js/tests.js

@ -1,184 +0,0 @@
/******************************************************************************
* Point Of Sale - Pricelist for POS Odoo
* Copyright (C) 2014 Taktik (http://www.taktik.be)
* @author Adil Houmadi <ah@taktik.be>
*
* 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/>.
*
******************************************************************************/
(function () {
'use strict';
openerp.Tour.register({
id: 'pos_pricelist_order',
name: 'Complete a order trough the Front-End using POS Pricelist',
path: '/web#model=pos.session.opening&action=point_of_sale.action_pos_session_opening',
mode: 'test',
steps: [
{
wait: 2000,
title: 'Wait for screen to be ready'
},
{
wait: 2000,
title: 'Load the Session',
waitNot: '.oe_loading:visible',
element: 'span:contains("Resume Session"),' +
'span:contains("Start Session")'
},
{
title: 'Loading Screen',
waitFor: '.loader'
},
{
wait: 2000,
title: 'The Point of Sale',
waitFor: '.pos'
},
{
title: "We will buy some Products!, let's add (POS Product 1)",
element: '.product-list ' +
'.product-name:contains("POS Product 1")'
},
{
wait: 5000,
title: 'The order total has been ' +
'updated to the correct value : 100€',
waitFor: '.order .total .value:contains("100.00 €")'
},
{
wait: 5000,
title: 'We will add one more unit!',
element: '.product-list ' +
'.product-name:contains("POS Product 1")'
},
{
wait: 4000,
title: 'We will add another unit',
element: '.product-list ' +
'.product-name:contains("POS Product 1")'
},
{
wait: 4000,
title: 'The order total should be updated ' +
': 270€ which means 90€/Unit (Rule 10% Discount from 3 Units)',
waitFor: '.order .total .value:contains("270.00 €")'
},
{
wait: 8000,
title: 'We will add another product',
element: '.product-list ' +
'.product-name:contains("POS Product 2")'
},
{
wait: 4000,
title: 'We will add another unit for this product ' +
'(POS Product 2)',
element: '.product-list ' +
'.product-name:contains("POS Product 2")'
},
{
wait: 4000,
title: "Let's verify the total that we should pay," +
" it's should be equal to : 450€, which means that <br>" +
"10% Discount if offered if we buy 2 units of " +
"(POS Product 2), Rule based on standard price",
waitFor: '.order .total .value:contains("450.00 €")'
},
{
wait: 10000,
title: "Now, we will add (POS Product 3), for this " +
"product if we buy more then 2 units <br>" +
"20% Discount is given by supplier to our customers",
element: '.product-list .product-name:contains("POS Product 3")'
},
{
wait: 10000,
title: 'We will add another unit for ' +
'this product (POS Product 3)',
element: '.product-list ' +
'.product-name:contains("POS Product 3")'
},
{
wait: 5000,
title: "Let's check the total (610€)",
waitFor: '.order .total .value:contains("610.00 €")'
},
{
wait: 5000,
title: "Now, we will add (POS Product 4), this product " +
"belong to (Comptuer) category in which " +
"we apply 5% if customer buy more then 2 products",
element: '.product-list ' +
'.product-name:contains("POS Product 4")'
},
{
wait: 10000,
title: 'We will add another unit for ' +
'this product (POS Product 4)',
element: '.product-list ' +
'.product-name:contains("POS Product 4")'
},
{
wait: 5000,
title: "Let's check the total again (800€)",
waitFor: '.order .total .value:contains("800.00 €")'
},
{
wait: 5000,
title: "Let's pay the order",
element: ".paypad-button:contains('Bank')"
},
{
wait: 1000,
title: "Let's accept the payment",
onload: function () {
window._print = window.print;
window.print = function () {
console.log('Print!')
};
},
element: ".button .iconlabel:contains('Validate'):visible"
},
{
wait: 1000,
title: "Let's finish the order",
element: ".button:not(.disabled) " +
".iconlabel:contains('Next'):visible"
},
{
wait: 1000,
onload: function () {
window.print = window._print;
window._print = undefined;
},
title: "Let's wait for the order posting",
waitFor: ".oe_status.js_synch .js_connected:visible"
},
{
wait: 1000,
title: "Let's close the Point of Sale",
element: ".header-button:contains('Close')"
},
{
title: "Let's confirm",
element: ".header-button.confirm:contains('Confirm')"
},
{
title: "Wait for the backend to ready itself",
element: 'span:contains("Resume Session"),' +
'span:contains("Start Session")'
}
]
});
})();

87
pos_pricelist/static/src/js/widgets.js

@ -1,87 +0,0 @@
/******************************************************************************
* Point Of Sale - Pricelist for POS Odoo
* Copyright (C) 2014 Taktik (http://www.taktik.be)
* @author Adil Houmadi <ah@taktik.be>
*
* 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/>.
*
******************************************************************************/
function 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 && (typeof 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
}
});
}

74
pos_pricelist/static/src/xml/pos.xml

@ -1,37 +1,51 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates id="template" xml:space="preserve">
<t t-extend="Product">
<t t-jquery=".product-img" t-operation="replace">
<div class="product-img">
<img t-att-src='image_url' />
<t t-if="!product.to_weight">
<span class="price-tag">
<t t-if="widget.display_price_with_taxes">
<t t-esc="widget.format_currency(product.price_with_taxes,'Product Price')"/>
</t>
<t t-if="!widget.display_price_with_taxes">
<t t-esc="widget.format_currency(product.price,'Product Price')"/>
</t>
</span>
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2018 Tecnativa - Jairo Llopis
License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl). -->
<templates>
<t t-name="SetPricelistButton">
<div class='control-button o_pricelist_button'>
<i class='fa fa-th-list' /> <t t-esc='widget.get_current_pricelist_name()'/>
</div>
</t>
<t t-extend="ClientDetailsEdit">
<t t-jquery=".client-details-right" t-operation="append">
<div t-attf-class='client-detail #{widget.pos.pricelists.length &lt;= 1 ? "oe_hidden" : ""}'>
<span class='label'>Pricelist</span>
<select class='detail needsclick' name='property_product_pricelist'>
<t t-foreach='widget.pos.pricelists' t-as='pricelist'>
<option t-att-value='pricelist.id'
t-att-selected="partner.property_product_pricelist ? (pricelist.id === partner.property_product_pricelist[0] ? true : undefined) : undefined">
<t t-esc='pricelist.display_name'/>
</option>
</t>
</select>
</div>
</t>
</t>
<t t-extend="ClientDetails">
<t t-jquery=".client-details-right" t-operation="append">
<div t-attf-class='client-detail #{widget.pos.pricelists.length &lt;= 1 ? "oe_hidden" : ""}'>
<span class='label'>Pricelist</span>
<t t-if='partner.property_product_pricelist'>
<span class='detail property_product_pricelist'><t t-esc='partner.property_product_pricelist[1]'/></span>
</t> </t>
<t t-if="product.to_weight">
<span class="price-tag">
<t t-if="widget.display_price_with_taxes">
<t t-esc="widget.format_currency(product.price_with_taxes,'Product Price')+'/Kg'"/>
</t>
<t t-if="!widget.display_price_with_taxes">
<t t-esc="widget.format_currency(product.price,'Product Price')+'/Kg'"/>
</t>
</span>
<t t-if='!partner.property_product_pricelist'>
<span class='detail property_product_pricelist empty'>N/A</span>
</t> </t>
</div> </div>
</t> </t>
</t> </t>
<t t-extend="PosTicket">
<t t-jquery="t[t-esc='orderline.get_quantity_str_with_unit()']" t-operation="after">
<t t-if="orderline.quantity != 1">
x<t t-esc="widget.format_pr(orderline.get_display_unit_price())"/>
</t>
<t t-extend="Product">
<t t-jquery=".price-tag:eq(0)" t-operation="inner">
<t t-esc="widget.format_currency(product.get_price(widget._get_active_pricelist(), 1),'Product Price')"/>
</t>
<t t-jquery=".price-tag:eq(0)" t-operation="inner">
<t t-esc="widget.format_currency(product.get_price(widget._get_active_pricelist(), 1),'Product Price')+'/'+widget.pos.units_by_id[product.uom_id[0]].name"/>
</t> </t>
</t> </t>
</templates>
</templates>

16
pos_pricelist/templates/assets.xml

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2018 Tecnativa - Jairo Llopis
License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl). -->
<odoo>
<template id="assets" inherit_id="point_of_sale.assets">
<xpath expr=".">
<script
type="text/javascript"
src="/pos_pricelist/static/src/js/models.js"/>
<script
type="text/javascript"
src="/pos_pricelist/static/src/js/screens.js"/>
</xpath>
</template>
</odoo>

28
pos_pricelist/test/test.py

@ -1,28 +0,0 @@
# -*- coding: utf-8 -*-
##############################################################################
# Point Of Sale - Pricelist for POS Odoo
# Copyright (C) 2014 Taktik (http://www.taktik.be)
# @author Adil Houmadi <ah@taktik.be>
#
# 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/>.
#
##############################################################################
import openerp.tests
@openerp.tests.common.at_install(False)
@openerp.tests.common.post_install(True)
class TestPOS(openerp.tests.HttpCase):
def test_01_pos(self):
self.phantom_js("/", "openerp.Tour.run('pos_pricelist_order', 'test')",
"openerp.Tour.tours.pos_pricelist_order",
login="admin")

28
pos_pricelist/views/point_of_sale_view.xml

@ -1,28 +0,0 @@
<?xml version="1.0"?>
<openerp>
<data>
<record id="view_pos_pos_form" model="ir.ui.view">
<field name="name">pos.order</field>
<field name="model">pos.order</field>
<field name="inherit_id" ref="point_of_sale.view_pos_pos_form"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='lines']/tree/field[@name='discount']" position="after">
<field name="tax_ids" widget="many2many_tags"/>
</xpath>
<page string="Payments" position="after">
<page string="Taxes">
<field name="taxes">
<tree editable="bottom" string="Taxes detail">
<field name="name"/>
<field name="base"/>
<field name="amount"/>
</tree>
</field>
</page>
</page>
</field>
</record>
</data>
</openerp>

41
pos_pricelist/views/pos_config_view.xml

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2018 Tecnativa - Jairo Llopis
License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl). -->
<odoo>
<record id="view_pos_config_form" model="ir.ui.view">
<field name="name">pos.config.form.view</field>
<field name="model">pos.config</field>
<field name="priority">100</field>
<field name="inherit_id" ref="point_of_sale.view_pos_config_form"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='pricelist_id']" position="replace"/>
<xpath expr="//sheet">
<group
name="pricelist_setting"
string="Pricelists"
groups="product.group_sale_pricelist">
<group>
<field name="use_pricelist"/>
</group>
<group attrs="{'invisible': [('use_pricelist','=',False)], 'required' : [('use_pricelist', '=', True)]}">
<field
name="available_pricelist_ids"
widget="many2many_tags"/>
<field
name="pricelist_id"
domain="[('id', 'in', available_pricelist_ids)]"
options="{'no_create': True}"/>
<button
name="%(product.product_pricelist_action2)d"
icon="fa-arrow-right"
type="action"
string="Pricelists"
class="btn-link"/>
</group>
</group>
</xpath>
</field>
</record>
</odoo>

29
pos_pricelist/views/pos_pricelist_template.xml

@ -1,29 +0,0 @@
<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="/pos_pricelist/static/src/js/db.js"
type="text/javascript"></script>
<script src="/pos_pricelist/static/src/js/models.js"
type="text/javascript"></script>
<script src="/pos_pricelist/static/src/js/widgets.js"
type="text/javascript"></script>
<script src="/pos_pricelist/static/src/js/screens.js"
type="text/javascript"></script>
<script src="/pos_pricelist/static/src/js/tests.js"
type="text/javascript"></script>
<script src="/pos_pricelist/static/src/js/main.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_pricelist/static/src/css/style.css"/>
</xpath>
</template>
</data>
</openerp>

15
pos_pricelist/views/pos_pricelist_views.xml

@ -1,15 +0,0 @@
<?xml version="1.0"?>
<openerp>
<data>
<record id="view_pos_config_form_pos_pricelist" model="ir.ui.view">
<field name="name">view.pos.config.form.pos.pricelist</field>
<field name="model">pos.config</field>
<field name="inherit_id" ref="point_of_sale.view_pos_config_form"/>
<field name="arch" type="xml">
<field name="iface_big_scrollbars" position="after">
<field name="display_price_with_taxes"/>
</field>
</field>
</record>
</data>
</openerp>

1
requirements.txt

@ -0,0 +1 @@
oca.decorators
Loading…
Cancel
Save