diff --git a/sale_product_pack/README.rst b/sale_product_pack/README.rst new file mode 100644 index 000000000..31efb67aa --- /dev/null +++ b/sale_product_pack/README.rst @@ -0,0 +1,135 @@ +================= +Sale Product Pack +================= + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:ef6b1970eeb7ec721ff9dc1a25df8405f64d7b864febeeb4146a4aa13d0855f4 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fproduct--pack-lightgray.png?logo=github + :target: https://github.com/OCA/product-pack/tree/17.0/sale_product_pack + :alt: OCA/product-pack +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/product-pack-17-0/product-pack-17-0-sale_product_pack + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png + :target: https://runboat.odoo-community.org/builds?repo=OCA/product-pack&target_branch=17.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module adds *Product Pack* functionality to sales orders. You can +choose a *Pack* in *sales order lines* and see different behaviors +depending on "Pack type" and "Pack component price" fields options +selected on this *Pack*. + +**Table of contents** + +.. contents:: + :local: + +Usage +===== + +To use this module, you need to: + +1. Go to *Sales > Products > Products*, create or select a product and + check *Is Pack?* +2. Set "Product type" and "Pack component price" fields in the *Pack* + page. +3. Add the products to be included in it. +4. Go to *Sales > Orders > Quotations* and create a Quotation. +5. Add a product that has checked "Is Pack?" +6. Save data and you will see an specific behavior depending on "Pack + type" and "Pack component price" fields options selected on this + *Pack*. For example, for products that has *Detailed* option selected + in "Pack type" field you will see one *sale order line* per component + that belong to this Pack. (See *Product pack* module README.rst file) + +Known issues / Roadmap +====================== + +- If this module is installed and stock module is installed too, when + you create a Sale order for a *Non detailed* Pack and you confirm it, + a *Stock picking* is not created with the storable components of that + Pack. So, add a new module called *sale_stock_product_pack* that adds + that feature. + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +------- + +* NaN·tic +* ADHOC SA +* Tecnativa + +Contributors +------------ + +- `Tecnativa `__: + + - Ernesto Tejeda + - Pedro M. Baeza + +- `Akretion `__: + + - Raphaël Reverdy + +- `Open Source Integrators `__: + + - Daniel Reis + +- `Acsone `__: + + - Maxime Franco + +- `ADHOC SA `__: + + - Bruno Zanotti + +Maintainers +----------- + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +.. |maintainer-ernestotejeda| image:: https://github.com/ernestotejeda.png?size=40px + :target: https://github.com/ernestotejeda + :alt: ernestotejeda + +Current `maintainer `__: + +|maintainer-ernestotejeda| + +This module is part of the `OCA/product-pack `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/sale_product_pack/__init__.py b/sale_product_pack/__init__.py new file mode 100644 index 000000000..cb45f2710 --- /dev/null +++ b/sale_product_pack/__init__.py @@ -0,0 +1,2 @@ +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +from . import models diff --git a/sale_product_pack/__manifest__.py b/sale_product_pack/__manifest__.py new file mode 100644 index 000000000..97729727e --- /dev/null +++ b/sale_product_pack/__manifest__.py @@ -0,0 +1,19 @@ +# Copyright 2019 NaN (http://www.nan-tic.com) - Àngel Àlvarez +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +{ + "name": "Sale Product Pack", + "version": "17.0.1.0.0", + "category": "Sales", + "summary": "This module allows you to sell product packs", + "website": "https://github.com/OCA/product-pack", + "author": "NaN·tic, ADHOC SA, Tecnativa, Odoo Community Association (OCA)", + "maintainers": ["ernestotejeda"], + "license": "AGPL-3", + "depends": ["product_pack", "sale"], + "data": ["security/ir.model.access.csv", "views/product_pack_line_views.xml"], + "demo": [ + "demo/product_pack_line_demo.xml", + "demo/sale_pack_demo.xml", + ], + "installable": True, +} diff --git a/sale_product_pack/demo/product_pack_line_demo.xml b/sale_product_pack/demo/product_pack_line_demo.xml new file mode 100644 index 000000000..b40178bdf --- /dev/null +++ b/sale_product_pack/demo/product_pack_line_demo.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/sale_product_pack/demo/sale_pack_demo.xml b/sale_product_pack/demo/sale_pack_demo.xml new file mode 100644 index 000000000..285721302 --- /dev/null +++ b/sale_product_pack/demo/sale_pack_demo.xml @@ -0,0 +1,108 @@ + + + + + + + + + + + + + + + + + + + Detailed Displayed Components Price + line_section + 1 + + + + + 2 + + + + + Detailed Totalized Components Price + line_section + 3 + + + + + 4 + + + + + Detailed Ignored Components Price + line_section + 5 + + + + + 6 + + + + + Not Detailed - Totalized Components Price + line_section + 7 + + + + + 8 + + + + + COMPONENTS + line_section + 9 + + + + + 10 + + + + + + 11 + + + + + + 12 + + + + diff --git a/sale_product_pack/i18n/ca.po b/sale_product_pack/i18n/ca.po new file mode 100644 index 000000000..c509a18d5 --- /dev/null +++ b/sale_product_pack/i18n/ca.po @@ -0,0 +1,180 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * sale_product_pack +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2022-02-28 13:17+0000\n" +"Last-Translator: Noel estudillo \n" +"Language-Team: none\n" +"Language: ca\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.3.2\n" + +#. module: sale_product_pack +#: model:ir.model.fields,field_description:sale_product_pack.field_sale_order_line__pack_depth +msgid "Depth" +msgstr "Profunditat" + +#. module: sale_product_pack +#: model:ir.model.fields,help:sale_product_pack.field_sale_order_line__pack_depth +msgid "Depth of the product if it is part of a pack." +msgstr "Profunditat del producte si forma part d’un pack." + +#. module: sale_product_pack +#: model:ir.model.fields,field_description:sale_product_pack.field_sale_order_line__do_no_expand_pack_lines +msgid "Do No Expand Pack Lines" +msgstr "" + +#. module: sale_product_pack +#: model:ir.model.fields,field_description:sale_product_pack.field_sale_order_line__pack_child_line_ids +msgid "Lines in pack" +msgstr "Línies en pack" + +#. module: sale_product_pack +#: model:ir.model.fields,help:sale_product_pack.field_sale_order_line__pack_component_price +msgid "" +"On sale orders or purchase orders:\n" +"* Detailed per component: Detail lines with prices.\n" +"* Totalized in main product: Detail lines merging lines prices on pack " +"(don't show component prices).\n" +"* Ignored: Use product pack price (ignore detail line prices)." +msgstr "" +"Comandes de venda o comandes de compra:\n" +"* Detall per component: Línies de detall amb preus.\n" +"* Totalitzat en producte principal: línies de detalls fusionen els preus de " +"les línies en el pack (no mostren els preus dels components).\n" +"* Ignorat: utilitza el preu del pack de producte (ignora els preus de la " +"línia de detalls)." + +#. module: sale_product_pack +#: model:ir.model.fields,help:sale_product_pack.field_sale_order_line__pack_type +msgid "" +"On sale orders or purchase orders:\n" +"* Detailed: Display components individually in the sale order.\n" +"* Non Detailed: Do not display components individually in the sale order." +msgstr "" +"Comandes de venda o comandes de compra:\n" +"* Detallat: mostra els components de forma individual en la comanda de " +"venda.\n" +"* No detallat: no mostren els components de forma individual en la comanda " +"de venda." + +#. module: sale_product_pack +#: model:ir.model.fields,field_description:sale_product_pack.field_sale_order_line__pack_parent_line_id +msgid "Pack" +msgstr "Pack" + +#. module: sale_product_pack +#: model:ir.model.fields,field_description:sale_product_pack.field_sale_order_line__pack_component_price +msgid "Pack Component Price" +msgstr "" + +#. module: sale_product_pack +#: model:ir.model.fields,field_description:sale_product_pack.field_sale_order_line__pack_type +msgid "Pack Display Type" +msgstr "Tipus de pantalla de paquet" + +#. module: sale_product_pack +#: model:ir.model.fields,field_description:sale_product_pack.field_sale_order_line__pack_modifiable +msgid "Pack Modifiable" +msgstr "Paquet modificable" + +#. module: sale_product_pack +#: model_terms:ir.ui.view,arch_db:sale_product_pack.view_order_form +msgid "Parent Pack is not modifiable" +msgstr "El paquet de pares no es pot modificar" + +#. module: sale_product_pack +#. odoo-python +#: code:addons/sale_product_pack/models/sale_order_line.py:0 +#, python-format +msgid "Parent Product" +msgstr "Producte principal" + +#. module: sale_product_pack +#: model:ir.model,name:sale_product_pack.model_product_pack_line +msgid "Product pack line" +msgstr "Línia de pack" + +#. module: sale_product_pack +#: model:ir.model.fields,field_description:sale_product_pack.field_product_pack_line__sale_discount +msgid "Sale discount (%)" +msgstr "Descompte per vendes" + +#. module: sale_product_pack +#: model:ir.model,name:sale_product_pack.model_sale_order +msgid "Sales Order" +msgstr "Comanda de venda" + +#. module: sale_product_pack +#: model:ir.model,name:sale_product_pack.model_sale_order_line +msgid "Sales Order Line" +msgstr "Línia de comandes de vendes" + +#. module: sale_product_pack +#: model:ir.model.fields,help:sale_product_pack.field_sale_order_line__pack_parent_line_id +msgid "The pack that contains this product." +msgstr "El pack que conté aquest producte." + +#. module: sale_product_pack +#: model:ir.model.fields,help:sale_product_pack.field_sale_order_line__pack_modifiable +msgid "The parent pack is modifiable" +msgstr "El paquet principal és modificable" + +#. module: sale_product_pack +#: model:ir.model.fields,help:sale_product_pack.field_sale_order_line__do_no_expand_pack_lines +msgid "" +"This is a technical field in order to check if pack lines has to be expanded" +msgstr "" + +#. module: sale_product_pack +#. odoo-python +#: code:addons/sale_product_pack/models/sale_order_line.py:0 +#, python-format +msgid "" +"You can not change this line because is part of a pack included in this order" +msgstr "" +"No podeu canviar aquesta línia perquè forma part d’un pack inclòs en aquest " +"ordre" + +#. module: sale_product_pack +#. odoo-python +#: code:addons/sale_product_pack/models/sale_order.py:0 +#, python-format +msgid "" +"You cannot delete this line because is part of a pack in this sale order. In " +"order to delete this line you need to delete the pack itself" +msgstr "" +"No podeu suprimir aquesta línia perquè forma part d'un paquet d'aquesta " +"comanda de venda. Per eliminar aquesta línia, heu d'esborrar el paquet en si" + +#~ msgid "Display Name" +#~ msgstr "Nom de visualització" + +#~ msgid "ID" +#~ msgstr "ID" + +#~ msgid "Last Modified on" +#~ msgstr "Última modificació el" + +#~ msgid "Pack component price" +#~ msgstr "Preu dels components" + +#~ msgid "Pack Type" +#~ msgstr "Tipus de pack" + +#~ msgid "Sale Order" +#~ msgstr "Comanda de venda" + +#~ msgid "" +#~ "You can not delete this line because is part of a pack in this sale " +#~ "order. In order to delete this line you need to delete the pack itself" +#~ msgstr "" +#~ "No podeu suprimir aquesta línia perquè forma part d’un pack d’aquesta " +#~ "comanda de venda. Per eliminar aquesta línia, heu de suprimir el pack" diff --git a/sale_product_pack/i18n/ca_ES.po b/sale_product_pack/i18n/ca_ES.po new file mode 100644 index 000000000..8f5c29c27 --- /dev/null +++ b/sale_product_pack/i18n/ca_ES.po @@ -0,0 +1,138 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * sale_product_pack +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: ca_ES\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +#. module: sale_product_pack +#: model:ir.model.fields,field_description:sale_product_pack.field_sale_order_line__pack_depth +msgid "Depth" +msgstr "" + +#. module: sale_product_pack +#: model:ir.model.fields,help:sale_product_pack.field_sale_order_line__pack_depth +msgid "Depth of the product if it is part of a pack." +msgstr "" + +#. module: sale_product_pack +#: model:ir.model.fields,field_description:sale_product_pack.field_sale_order_line__do_no_expand_pack_lines +msgid "Do No Expand Pack Lines" +msgstr "" + +#. module: sale_product_pack +#: model:ir.model.fields,field_description:sale_product_pack.field_sale_order_line__pack_child_line_ids +msgid "Lines in pack" +msgstr "" + +#. module: sale_product_pack +#: model:ir.model.fields,help:sale_product_pack.field_sale_order_line__pack_component_price +msgid "" +"On sale orders or purchase orders:\n" +"* Detailed per component: Detail lines with prices.\n" +"* Totalized in main product: Detail lines merging lines prices on pack " +"(don't show component prices).\n" +"* Ignored: Use product pack price (ignore detail line prices)." +msgstr "" + +#. module: sale_product_pack +#: model:ir.model.fields,help:sale_product_pack.field_sale_order_line__pack_type +msgid "" +"On sale orders or purchase orders:\n" +"* Detailed: Display components individually in the sale order.\n" +"* Non Detailed: Do not display components individually in the sale order." +msgstr "" + +#. module: sale_product_pack +#: model:ir.model.fields,field_description:sale_product_pack.field_sale_order_line__pack_parent_line_id +msgid "Pack" +msgstr "" + +#. module: sale_product_pack +#: model:ir.model.fields,field_description:sale_product_pack.field_sale_order_line__pack_component_price +msgid "Pack Component Price" +msgstr "" + +#. module: sale_product_pack +#: model:ir.model.fields,field_description:sale_product_pack.field_sale_order_line__pack_type +msgid "Pack Display Type" +msgstr "" + +#. module: sale_product_pack +#: model:ir.model.fields,field_description:sale_product_pack.field_sale_order_line__pack_modifiable +msgid "Pack Modifiable" +msgstr "" + +#. module: sale_product_pack +#: model_terms:ir.ui.view,arch_db:sale_product_pack.view_order_form +msgid "Parent Pack is not modifiable" +msgstr "" + +#. module: sale_product_pack +#. odoo-python +#: code:addons/sale_product_pack/models/sale_order_line.py:0 +#, python-format +msgid "Parent Product" +msgstr "" + +#. module: sale_product_pack +#: model:ir.model,name:sale_product_pack.model_product_pack_line +msgid "Product pack line" +msgstr "" + +#. module: sale_product_pack +#: model:ir.model.fields,field_description:sale_product_pack.field_product_pack_line__sale_discount +msgid "Sale discount (%)" +msgstr "" + +#. module: sale_product_pack +#: model:ir.model,name:sale_product_pack.model_sale_order +msgid "Sales Order" +msgstr "" + +#. module: sale_product_pack +#: model:ir.model,name:sale_product_pack.model_sale_order_line +msgid "Sales Order Line" +msgstr "" + +#. module: sale_product_pack +#: model:ir.model.fields,help:sale_product_pack.field_sale_order_line__pack_parent_line_id +msgid "The pack that contains this product." +msgstr "" + +#. module: sale_product_pack +#: model:ir.model.fields,help:sale_product_pack.field_sale_order_line__pack_modifiable +msgid "The parent pack is modifiable" +msgstr "" + +#. module: sale_product_pack +#: model:ir.model.fields,help:sale_product_pack.field_sale_order_line__do_no_expand_pack_lines +msgid "" +"This is a technical field in order to check if pack lines has to be expanded" +msgstr "" + +#. module: sale_product_pack +#. odoo-python +#: code:addons/sale_product_pack/models/sale_order_line.py:0 +#, python-format +msgid "" +"You can not change this line because is part of a pack included in this order" +msgstr "" + +#. module: sale_product_pack +#. odoo-python +#: code:addons/sale_product_pack/models/sale_order.py:0 +#, python-format +msgid "" +"You cannot delete this line because is part of a pack in this sale order. In " +"order to delete this line you need to delete the pack itself" +msgstr "" diff --git a/sale_product_pack/i18n/es.po b/sale_product_pack/i18n/es.po new file mode 100644 index 000000000..cce829b72 --- /dev/null +++ b/sale_product_pack/i18n/es.po @@ -0,0 +1,174 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * sale_product_pack +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-09-20 22:46+0000\n" +"PO-Revision-Date: 2023-09-03 13:43+0000\n" +"Last-Translator: Ivorra78 \n" +"Language-Team: \n" +"Language: es\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.17\n" + +#. module: sale_product_pack +#: model:ir.model.fields,field_description:sale_product_pack.field_sale_order_line__pack_depth +msgid "Depth" +msgstr "Profundidad" + +#. module: sale_product_pack +#: model:ir.model.fields,help:sale_product_pack.field_sale_order_line__pack_depth +msgid "Depth of the product if it is part of a pack." +msgstr "Profundidad del producto si forma parte de un pack." + +#. module: sale_product_pack +#: model:ir.model.fields,field_description:sale_product_pack.field_sale_order_line__do_no_expand_pack_lines +msgid "Do No Expand Pack Lines" +msgstr "No ampliar las líneas de embalaje" + +#. module: sale_product_pack +#: model:ir.model.fields,field_description:sale_product_pack.field_sale_order_line__pack_child_line_ids +msgid "Lines in pack" +msgstr "Líneas en el pack" + +#. module: sale_product_pack +#: model:ir.model.fields,help:sale_product_pack.field_sale_order_line__pack_component_price +msgid "" +"On sale orders or purchase orders:\n" +"* Detailed per component: Detail lines with prices.\n" +"* Totalized in main product: Detail lines merging lines prices on pack " +"(don't show component prices).\n" +"* Ignored: Use product pack price (ignore detail line prices)." +msgstr "" +"En órdenes de venta u órdenes de compra:\n" +"* Detallado por componente: Detalla las líneas con precios.\n" +"* Totalizado en el producto principal: Detalla las líneas mezclando sus " +"precios en el Pack (No muestra los precios de los componentes).\n" +"* Ignorado: Se usa el precio el Pack (los precios de las líneas son " +"ignorados)." + +#. module: sale_product_pack +#: model:ir.model.fields,help:sale_product_pack.field_sale_order_line__pack_type +msgid "" +"On sale orders or purchase orders:\n" +"* Detailed: Display components individually in the sale order.\n" +"* Non Detailed: Do not display components individually in the sale order." +msgstr "" +"En órdenes de venta u órdenes de compra:\n" +"* Detallado: Muestra los componentes individualmente en líneas de la Orden " +"de Venta/Orden de Compra\n" +"* No Detallado: No muestra los componentes individualmente en líneas de la " +"Orden de Venta/Orden de Compra." + +#. module: sale_product_pack +#: model:ir.model.fields,field_description:sale_product_pack.field_sale_order_line__pack_parent_line_id +msgid "Pack" +msgstr "Paquete" + +#. module: sale_product_pack +#: model:ir.model.fields,field_description:sale_product_pack.field_sale_order_line__pack_component_price +msgid "Pack Component Price" +msgstr "Precio de los componentes del paquete" + +#. module: sale_product_pack +#: model:ir.model.fields,field_description:sale_product_pack.field_sale_order_line__pack_type +msgid "Pack Display Type" +msgstr "Tipo de visualización del paquete" + +#. module: sale_product_pack +#: model:ir.model.fields,field_description:sale_product_pack.field_sale_order_line__pack_modifiable +msgid "Pack Modifiable" +msgstr "Pack modificable" + +#. module: sale_product_pack +#: model_terms:ir.ui.view,arch_db:sale_product_pack.view_order_form +msgid "Parent Pack is not modifiable" +msgstr "El paquete parental no es modificable" + +#. module: sale_product_pack +#. odoo-python +#: code:addons/sale_product_pack/models/sale_order_line.py:0 +#, python-format +msgid "Parent Product" +msgstr "Producto Parental" + +#. module: sale_product_pack +#: model:ir.model,name:sale_product_pack.model_product_pack_line +msgid "Product pack line" +msgstr "Linea de pack" + +#. module: sale_product_pack +#: model:ir.model.fields,field_description:sale_product_pack.field_product_pack_line__sale_discount +msgid "Sale discount (%)" +msgstr "Descuento para ventas" + +#. module: sale_product_pack +#: model:ir.model,name:sale_product_pack.model_sale_order +msgid "Sales Order" +msgstr "Órdenes de venta" + +#. module: sale_product_pack +#: model:ir.model,name:sale_product_pack.model_sale_order_line +msgid "Sales Order Line" +msgstr "Línea de pedido de venta" + +#. module: sale_product_pack +#: model:ir.model.fields,help:sale_product_pack.field_sale_order_line__pack_parent_line_id +msgid "The pack that contains this product." +msgstr "El pack que contiene este producto." + +#. module: sale_product_pack +#: model:ir.model.fields,help:sale_product_pack.field_sale_order_line__pack_modifiable +msgid "The parent pack is modifiable" +msgstr "El paquete parental es modificable" + +#. module: sale_product_pack +#: model:ir.model.fields,help:sale_product_pack.field_sale_order_line__do_no_expand_pack_lines +msgid "" +"This is a technical field in order to check if pack lines has to be expanded" +msgstr "" +"Se trata de un campo técnico para comprobar si es necesario ampliar las " +"líneas de envasado" + +#. module: sale_product_pack +#. odoo-python +#: code:addons/sale_product_pack/models/sale_order_line.py:0 +#, python-format +msgid "" +"You can not change this line because is part of a pack included in this order" +msgstr "" +"No puedes cambiar esta línea porque es parte de un pack incluido en este " +"orden" + +#. module: sale_product_pack +#. odoo-python +#: code:addons/sale_product_pack/models/sale_order.py:0 +#, python-format +msgid "" +"You cannot delete this line because is part of a pack in this sale order. In " +"order to delete this line you need to delete the pack itself" +msgstr "" +"No puede eliminar esta línea porque forma parte de un paquete en este pedido " +"de venta. Para eliminar esta línea debe eliminar el propio paquete" + +#~ msgid "Pack component price" +#~ msgstr "Precio de los componentes" + +#~ msgid "Pack Type" +#~ msgstr "Tipo de Pack" + +#~ msgid "Sale Order" +#~ msgstr "Pedido de venta" + +#~ msgid "" +#~ "You can not delete this line because is part of a pack in this sale " +#~ "order. In order to delete this line you need to delete the pack itself" +#~ msgstr "" +#~ "No puede eliminar esta línea porque forma parte de un pack en esta orden " +#~ "de venta. Para eliminar esta línea necesitas eliminar el pack" diff --git a/sale_product_pack/i18n/fr.po b/sale_product_pack/i18n/fr.po new file mode 100644 index 000000000..c7348ba4c --- /dev/null +++ b/sale_product_pack/i18n/fr.po @@ -0,0 +1,168 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * sale_product_pack +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2020-05-28 12:19+0000\n" +"Last-Translator: Yann Papouin \n" +"Language-Team: none\n" +"Language: fr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n > 1;\n" +"X-Generator: Weblate 3.10\n" + +#. module: sale_product_pack +#: model:ir.model.fields,field_description:sale_product_pack.field_sale_order_line__pack_depth +msgid "Depth" +msgstr "Niveau" + +#. module: sale_product_pack +#: model:ir.model.fields,help:sale_product_pack.field_sale_order_line__pack_depth +msgid "Depth of the product if it is part of a pack." +msgstr "Niveau de l'article s'il fait partie d'un pack." + +#. module: sale_product_pack +#: model:ir.model.fields,field_description:sale_product_pack.field_sale_order_line__do_no_expand_pack_lines +msgid "Do No Expand Pack Lines" +msgstr "" + +#. module: sale_product_pack +#: model:ir.model.fields,field_description:sale_product_pack.field_sale_order_line__pack_child_line_ids +msgid "Lines in pack" +msgstr "Lignes rattachées à un pack" + +#. module: sale_product_pack +#: model:ir.model.fields,help:sale_product_pack.field_sale_order_line__pack_component_price +msgid "" +"On sale orders or purchase orders:\n" +"* Detailed per component: Detail lines with prices.\n" +"* Totalized in main product: Detail lines merging lines prices on pack " +"(don't show component prices).\n" +"* Ignored: Use product pack price (ignore detail line prices)." +msgstr "" +"Sur les commandes clients ou fournisseurs :\n" +"* Détaillé par composant : lignes détaillées avec prix.\n" +"* Totalisé dans l'article principal : lignes détaillées mais le prix est " +"additionné sur celui du pack (n'affiche pas les prix par composant).\n" +"* Ignoré : utilise le prix du pack d'articles (ignore les prix des " +"composants)." + +#. module: sale_product_pack +#: model:ir.model.fields,help:sale_product_pack.field_sale_order_line__pack_type +msgid "" +"On sale orders or purchase orders:\n" +"* Detailed: Display components individually in the sale order.\n" +"* Non Detailed: Do not display components individually in the sale order." +msgstr "" +"Sur les commandes clients ou fournisseurs :\n" +"* Détaillé : affiche les composants individuellement dans la commande.\n" +"* Non détaillé : n'affiche pas les composants dans la commande." + +#. module: sale_product_pack +#: model:ir.model.fields,field_description:sale_product_pack.field_sale_order_line__pack_parent_line_id +msgid "Pack" +msgstr "Pack" + +#. module: sale_product_pack +#: model:ir.model.fields,field_description:sale_product_pack.field_sale_order_line__pack_component_price +msgid "Pack Component Price" +msgstr "" + +#. module: sale_product_pack +#: model:ir.model.fields,field_description:sale_product_pack.field_sale_order_line__pack_type +msgid "Pack Display Type" +msgstr "" + +#. module: sale_product_pack +#: model:ir.model.fields,field_description:sale_product_pack.field_sale_order_line__pack_modifiable +msgid "Pack Modifiable" +msgstr "Pack modifiable" + +#. module: sale_product_pack +#: model_terms:ir.ui.view,arch_db:sale_product_pack.view_order_form +msgid "Parent Pack is not modifiable" +msgstr "Le pack parent n'est pas modifiable" + +#. module: sale_product_pack +#. odoo-python +#: code:addons/sale_product_pack/models/sale_order_line.py:0 +#, python-format +msgid "Parent Product" +msgstr "Article parent" + +#. module: sale_product_pack +#: model:ir.model,name:sale_product_pack.model_product_pack_line +msgid "Product pack line" +msgstr "Ligne d'article de pack" + +#. module: sale_product_pack +#: model:ir.model.fields,field_description:sale_product_pack.field_product_pack_line__sale_discount +msgid "Sale discount (%)" +msgstr "Remise de vente (%)" + +#. module: sale_product_pack +#: model:ir.model,name:sale_product_pack.model_sale_order +msgid "Sales Order" +msgstr "" + +#. module: sale_product_pack +#: model:ir.model,name:sale_product_pack.model_sale_order_line +msgid "Sales Order Line" +msgstr "Ligne de bons de commande" + +#. module: sale_product_pack +#: model:ir.model.fields,help:sale_product_pack.field_sale_order_line__pack_parent_line_id +msgid "The pack that contains this product." +msgstr "Le pack qui contient cet article." + +#. module: sale_product_pack +#: model:ir.model.fields,help:sale_product_pack.field_sale_order_line__pack_modifiable +msgid "The parent pack is modifiable" +msgstr "Le pack parent est modifiable" + +#. module: sale_product_pack +#: model:ir.model.fields,help:sale_product_pack.field_sale_order_line__do_no_expand_pack_lines +msgid "" +"This is a technical field in order to check if pack lines has to be expanded" +msgstr "" + +#. module: sale_product_pack +#. odoo-python +#: code:addons/sale_product_pack/models/sale_order_line.py:0 +#, python-format +msgid "" +"You can not change this line because is part of a pack included in this order" +msgstr "" +"Vous ne pouvez pas modifier cette ligne car elle fait partie d'un pack " +"inclus dans cette commande" + +#. module: sale_product_pack +#. odoo-python +#: code:addons/sale_product_pack/models/sale_order.py:0 +#, python-format +msgid "" +"You cannot delete this line because is part of a pack in this sale order. In " +"order to delete this line you need to delete the pack itself" +msgstr "" + +#~ msgid "Pack component price" +#~ msgstr "Prix d'un composant du pack" + +#~ msgid "Pack Type" +#~ msgstr "Type de pack" + +#~ msgid "Sale Order" +#~ msgstr "Bon de commande" + +#~ msgid "" +#~ "You can not delete this line because is part of a pack in this sale " +#~ "order. In order to delete this line you need to delete the pack itself" +#~ msgstr "" +#~ "Vous ne pouvez pas supprimer cette ligne car elle fait partie d'un pack " +#~ "dans ce bon de commande. Pour supprimer cette ligne, vous devez supprimer " +#~ "le pack lui-même" diff --git a/sale_product_pack/i18n/it.po b/sale_product_pack/i18n/it.po new file mode 100644 index 000000000..fc9c6afbf --- /dev/null +++ b/sale_product_pack/i18n/it.po @@ -0,0 +1,156 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * sale_product_pack +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2023-11-10 11:38+0000\n" +"Last-Translator: mymage \n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.17\n" + +#. module: sale_product_pack +#: model:ir.model.fields,field_description:sale_product_pack.field_sale_order_line__pack_depth +msgid "Depth" +msgstr "Profondità" + +#. module: sale_product_pack +#: model:ir.model.fields,help:sale_product_pack.field_sale_order_line__pack_depth +msgid "Depth of the product if it is part of a pack." +msgstr "Profondità di un prodotto se fa parte di un collo." + +#. module: sale_product_pack +#: model:ir.model.fields,field_description:sale_product_pack.field_sale_order_line__do_no_expand_pack_lines +msgid "Do No Expand Pack Lines" +msgstr "Non espandere le righe del collo" + +#. module: sale_product_pack +#: model:ir.model.fields,field_description:sale_product_pack.field_sale_order_line__pack_child_line_ids +msgid "Lines in pack" +msgstr "Righe nel collo" + +#. module: sale_product_pack +#: model:ir.model.fields,help:sale_product_pack.field_sale_order_line__pack_component_price +msgid "" +"On sale orders or purchase orders:\n" +"* Detailed per component: Detail lines with prices.\n" +"* Totalized in main product: Detail lines merging lines prices on pack (don't show component prices).\n" +"* Ignored: Use product pack price (ignore detail line prices)." +msgstr "" +"Negli ordini di vendita o di acquisto:\n" +"* Dettagliato per componente: dettaglio righe con prezzi.\n" +"* Totalizzate nel prodotto principale: dettaglio righe unendo i prezzi delle " +"righe nel collo (non mostra i prezzi dei componenti).\n" +"* Ignorate: usa il prezzo prodotto del collo (ignora il dettaglio prezzi " +"riga)." + +#. module: sale_product_pack +#: model:ir.model.fields,help:sale_product_pack.field_sale_order_line__pack_type +msgid "" +"On sale orders or purchase orders:\n" +"* Detailed: Display components individually in the sale order.\n" +"* Non Detailed: Do not display components individually in the sale order." +msgstr "" +"Negli ordini di ventita o di acquisto:\n" +"* Dettagliati: visualizza i singoli componenti nell'ordine di vendita.\n" +"* Non detagliati: non visualizza i singoli componenti nell'ordine di vendita." + +#. module: sale_product_pack +#: model:ir.model.fields,field_description:sale_product_pack.field_sale_order_line__pack_parent_line_id +msgid "Pack" +msgstr "Collo" + +#. module: sale_product_pack +#: model:ir.model.fields,field_description:sale_product_pack.field_sale_order_line__pack_component_price +msgid "Pack Component Price" +msgstr "Prezzo componente collo" + +#. module: sale_product_pack +#: model:ir.model.fields,field_description:sale_product_pack.field_sale_order_line__pack_type +msgid "Pack Display Type" +msgstr "Visualizza tipo collo" + +#. module: sale_product_pack +#: model:ir.model.fields,field_description:sale_product_pack.field_sale_order_line__pack_modifiable +msgid "Pack Modifiable" +msgstr "Collo modificabile" + +#. module: sale_product_pack +#: model_terms:ir.ui.view,arch_db:sale_product_pack.view_order_form +msgid "Parent Pack is not modifiable" +msgstr "Il collo padre non è modificabIle" + +#. module: sale_product_pack +#. odoo-python +#: code:addons/sale_product_pack/models/sale_order_line.py:0 +#, python-format +msgid "Parent Product" +msgstr "Prodotto padre" + +#. module: sale_product_pack +#: model:ir.model,name:sale_product_pack.model_product_pack_line +msgid "Product pack line" +msgstr "Riga collo prodotto" + +#. module: sale_product_pack +#: model:ir.model.fields,field_description:sale_product_pack.field_product_pack_line__sale_discount +msgid "Sale discount (%)" +msgstr "Sconto vendita (%)" + +#. module: sale_product_pack +#: model:ir.model,name:sale_product_pack.model_sale_order +msgid "Sales Order" +msgstr "Ordine di vendita" + +#. module: sale_product_pack +#: model:ir.model,name:sale_product_pack.model_sale_order_line +msgid "Sales Order Line" +msgstr "Riga ordine di vendita" + +#. module: sale_product_pack +#: model:ir.model.fields,help:sale_product_pack.field_sale_order_line__pack_parent_line_id +msgid "The pack that contains this product." +msgstr "Il collo che contiene questo prodotto." + +#. module: sale_product_pack +#: model:ir.model.fields,help:sale_product_pack.field_sale_order_line__pack_modifiable +msgid "The parent pack is modifiable" +msgstr "Il collo padre è modificabile" + +#. module: sale_product_pack +#: model:ir.model.fields,help:sale_product_pack.field_sale_order_line__do_no_expand_pack_lines +msgid "" +"This is a technical field in order to check if pack lines has to be expanded" +msgstr "" +"Questo è un campo tecnico per controllare se le righe del collo devono " +"essere espanse" + +#. module: sale_product_pack +#. odoo-python +#: code:addons/sale_product_pack/models/sale_order_line.py:0 +#, python-format +msgid "" +"You can not change this line because is part of a pack included in this " +"order" +msgstr "" +"Non si può modificare questa riga perché è parte di un collo incluso in " +"questo ordine" + +#. module: sale_product_pack +#. odoo-python +#: code:addons/sale_product_pack/models/sale_order.py:0 +#, python-format +msgid "" +"You cannot delete this line because is part of a pack in this sale order. In" +" order to delete this line you need to delete the pack itself" +msgstr "" +"Non si può cancellare questa riga perché è parte di un collo dello stesso " +"ordine di vendita. Per poter cancellare questa riga bisogna cancellare il " +"collo stesso" diff --git a/sale_product_pack/i18n/nl.po b/sale_product_pack/i18n/nl.po new file mode 100644 index 000000000..48bee455a --- /dev/null +++ b/sale_product_pack/i18n/nl.po @@ -0,0 +1,145 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * sale_product_pack +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 13.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2020-12-14 00:28+0000\n" +"Last-Translator: Bosd \n" +"Language-Team: none\n" +"Language: nl\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.3.2\n" + +#. module: sale_product_pack +#: model:ir.model.fields,field_description:sale_product_pack.field_sale_order_line__pack_depth +msgid "Depth" +msgstr "Diepte" + +#. module: sale_product_pack +#: model:ir.model.fields,help:sale_product_pack.field_sale_order_line__pack_depth +msgid "Depth of the product if it is part of a pack." +msgstr "" + +#. module: sale_product_pack +#: model:ir.model.fields,field_description:sale_product_pack.field_sale_order_line__do_no_expand_pack_lines +msgid "Do No Expand Pack Lines" +msgstr "" + +#. module: sale_product_pack +#: model:ir.model.fields,field_description:sale_product_pack.field_sale_order_line__pack_child_line_ids +msgid "Lines in pack" +msgstr "regels in verpakking" + +#. module: sale_product_pack +#: model:ir.model.fields,help:sale_product_pack.field_sale_order_line__pack_component_price +msgid "" +"On sale orders or purchase orders:\n" +"* Detailed per component: Detail lines with prices.\n" +"* Totalized in main product: Detail lines merging lines prices on pack " +"(don't show component prices).\n" +"* Ignored: Use product pack price (ignore detail line prices)." +msgstr "" + +#. module: sale_product_pack +#: model:ir.model.fields,help:sale_product_pack.field_sale_order_line__pack_type +msgid "" +"On sale orders or purchase orders:\n" +"* Detailed: Display components individually in the sale order.\n" +"* Non Detailed: Do not display components individually in the sale order." +msgstr "" + +#. module: sale_product_pack +#: model:ir.model.fields,field_description:sale_product_pack.field_sale_order_line__pack_parent_line_id +msgid "Pack" +msgstr "Verpakking" + +#. module: sale_product_pack +#: model:ir.model.fields,field_description:sale_product_pack.field_sale_order_line__pack_component_price +msgid "Pack Component Price" +msgstr "" + +#. module: sale_product_pack +#: model:ir.model.fields,field_description:sale_product_pack.field_sale_order_line__pack_type +msgid "Pack Display Type" +msgstr "" + +#. module: sale_product_pack +#: model:ir.model.fields,field_description:sale_product_pack.field_sale_order_line__pack_modifiable +msgid "Pack Modifiable" +msgstr "Aanpasbare verpakking" + +#. module: sale_product_pack +#: model_terms:ir.ui.view,arch_db:sale_product_pack.view_order_form +msgid "Parent Pack is not modifiable" +msgstr "" + +#. module: sale_product_pack +#. odoo-python +#: code:addons/sale_product_pack/models/sale_order_line.py:0 +#, python-format +msgid "Parent Product" +msgstr "" + +#. module: sale_product_pack +#: model:ir.model,name:sale_product_pack.model_product_pack_line +msgid "Product pack line" +msgstr "" + +#. module: sale_product_pack +#: model:ir.model.fields,field_description:sale_product_pack.field_product_pack_line__sale_discount +msgid "Sale discount (%)" +msgstr "" + +#. module: sale_product_pack +#: model:ir.model,name:sale_product_pack.model_sale_order +msgid "Sales Order" +msgstr "Verkooporder" + +#. module: sale_product_pack +#: model:ir.model,name:sale_product_pack.model_sale_order_line +msgid "Sales Order Line" +msgstr "" + +#. module: sale_product_pack +#: model:ir.model.fields,help:sale_product_pack.field_sale_order_line__pack_parent_line_id +msgid "The pack that contains this product." +msgstr "" + +#. module: sale_product_pack +#: model:ir.model.fields,help:sale_product_pack.field_sale_order_line__pack_modifiable +msgid "The parent pack is modifiable" +msgstr "De hoofdverpakking is aanpasbaar" + +#. module: sale_product_pack +#: model:ir.model.fields,help:sale_product_pack.field_sale_order_line__do_no_expand_pack_lines +msgid "" +"This is a technical field in order to check if pack lines has to be expanded" +msgstr "" + +#. module: sale_product_pack +#. odoo-python +#: code:addons/sale_product_pack/models/sale_order_line.py:0 +#, python-format +msgid "" +"You can not change this line because is part of a pack included in this order" +msgstr "" +"Deze regel kan niet worden aangepast omdat een verpakking is gebruikt in " +"deze verkoop order" + +#. module: sale_product_pack +#. odoo-python +#: code:addons/sale_product_pack/models/sale_order.py:0 +#, python-format +msgid "" +"You cannot delete this line because is part of a pack in this sale order. In " +"order to delete this line you need to delete the pack itself" +msgstr "" + +#~ msgid "Pack Type" +#~ msgstr "Verpakkingstype" diff --git a/sale_product_pack/i18n/pt.po b/sale_product_pack/i18n/pt.po new file mode 100644 index 000000000..d572c00dd --- /dev/null +++ b/sale_product_pack/i18n/pt.po @@ -0,0 +1,167 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * sale_product_pack +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2019-12-12 22:05+0000\n" +"Last-Translator: Pedro Castro Silva \n" +"Language-Team: none\n" +"Language: pt\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n > 1;\n" +"X-Generator: Weblate 3.9.1\n" + +#. module: sale_product_pack +#: model:ir.model.fields,field_description:sale_product_pack.field_sale_order_line__pack_depth +msgid "Depth" +msgstr "Profundidade" + +#. module: sale_product_pack +#: model:ir.model.fields,help:sale_product_pack.field_sale_order_line__pack_depth +msgid "Depth of the product if it is part of a pack." +msgstr "Profundidade do produto se é parte de um pack." + +#. module: sale_product_pack +#: model:ir.model.fields,field_description:sale_product_pack.field_sale_order_line__do_no_expand_pack_lines +msgid "Do No Expand Pack Lines" +msgstr "" + +#. module: sale_product_pack +#: model:ir.model.fields,field_description:sale_product_pack.field_sale_order_line__pack_child_line_ids +msgid "Lines in pack" +msgstr "Linhas no pack" + +#. module: sale_product_pack +#: model:ir.model.fields,help:sale_product_pack.field_sale_order_line__pack_component_price +msgid "" +"On sale orders or purchase orders:\n" +"* Detailed per component: Detail lines with prices.\n" +"* Totalized in main product: Detail lines merging lines prices on pack " +"(don't show component prices).\n" +"* Ignored: Use product pack price (ignore detail line prices)." +msgstr "" +"Em encomendas de compra ou venda:\n" +"* Detalhado por componente: Linha de detalhes com preços.\n" +"* Totalizado no produto principal: Linhas de detalhes fundindo os preços das " +"linhas no pack (não mostrar preços dos componentes).\n" +"* Ignorado: Usar o preço do pack de produtos (ignorar preços das linhas de " +"detalhes)." + +#. module: sale_product_pack +#: model:ir.model.fields,help:sale_product_pack.field_sale_order_line__pack_type +msgid "" +"On sale orders or purchase orders:\n" +"* Detailed: Display components individually in the sale order.\n" +"* Non Detailed: Do not display components individually in the sale order." +msgstr "" +"Em encomendas de compra ou venda:\n" +"* Detalhado: Exibir os componentes individualmente na encomenda.\n" +"*Não Detalhado: Não exibir os componentes individualmente na encomenda." + +#. module: sale_product_pack +#: model:ir.model.fields,field_description:sale_product_pack.field_sale_order_line__pack_parent_line_id +msgid "Pack" +msgstr "" + +#. module: sale_product_pack +#: model:ir.model.fields,field_description:sale_product_pack.field_sale_order_line__pack_component_price +msgid "Pack Component Price" +msgstr "" + +#. module: sale_product_pack +#: model:ir.model.fields,field_description:sale_product_pack.field_sale_order_line__pack_type +msgid "Pack Display Type" +msgstr "" + +#. module: sale_product_pack +#: model:ir.model.fields,field_description:sale_product_pack.field_sale_order_line__pack_modifiable +msgid "Pack Modifiable" +msgstr "" + +#. module: sale_product_pack +#: model_terms:ir.ui.view,arch_db:sale_product_pack.view_order_form +msgid "Parent Pack is not modifiable" +msgstr "" + +#. module: sale_product_pack +#. odoo-python +#: code:addons/sale_product_pack/models/sale_order_line.py:0 +#, python-format +msgid "Parent Product" +msgstr "" + +#. module: sale_product_pack +#: model:ir.model,name:sale_product_pack.model_product_pack_line +msgid "Product pack line" +msgstr "Linha de pack de produto" + +#. module: sale_product_pack +#: model:ir.model.fields,field_description:sale_product_pack.field_product_pack_line__sale_discount +msgid "Sale discount (%)" +msgstr "Desconto de venda (%)" + +#. module: sale_product_pack +#: model:ir.model,name:sale_product_pack.model_sale_order +msgid "Sales Order" +msgstr "" + +#. module: sale_product_pack +#: model:ir.model,name:sale_product_pack.model_sale_order_line +msgid "Sales Order Line" +msgstr "Linha de Encomenda de Venda" + +#. module: sale_product_pack +#: model:ir.model.fields,help:sale_product_pack.field_sale_order_line__pack_parent_line_id +msgid "The pack that contains this product." +msgstr "O pack que contém este produto." + +#. module: sale_product_pack +#: model:ir.model.fields,help:sale_product_pack.field_sale_order_line__pack_modifiable +msgid "The parent pack is modifiable" +msgstr "" + +#. module: sale_product_pack +#: model:ir.model.fields,help:sale_product_pack.field_sale_order_line__do_no_expand_pack_lines +msgid "" +"This is a technical field in order to check if pack lines has to be expanded" +msgstr "" + +#. module: sale_product_pack +#. odoo-python +#: code:addons/sale_product_pack/models/sale_order_line.py:0 +#, python-format +msgid "" +"You can not change this line because is part of a pack included in this order" +msgstr "" +"Não pode alterar esta linha porque é parte de um pack incluído nesta " +"encomenda" + +#. module: sale_product_pack +#. odoo-python +#: code:addons/sale_product_pack/models/sale_order.py:0 +#, python-format +msgid "" +"You cannot delete this line because is part of a pack in this sale order. In " +"order to delete this line you need to delete the pack itself" +msgstr "" + +#~ msgid "Pack component price" +#~ msgstr "Preço do componente do pack" + +#~ msgid "Pack Type" +#~ msgstr "Tipo de Pack" + +#~ msgid "Sale Order" +#~ msgstr "Encomenda de Venda" + +#~ msgid "" +#~ "You can not delete this line because is part of a pack in this sale " +#~ "order. In order to delete this line you need to delete the pack itself" +#~ msgstr "" +#~ "Não pode eliminar esta linha porque é parte de um pack incluído nesta " +#~ "encomenda. Para a eliminar, precisa de eliminar o próprio pack" diff --git a/sale_product_pack/i18n/sale_product_pack.pot b/sale_product_pack/i18n/sale_product_pack.pot new file mode 100644 index 000000000..03d271ead --- /dev/null +++ b/sale_product_pack/i18n/sale_product_pack.pot @@ -0,0 +1,137 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * sale_product_pack +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \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: sale_product_pack +#: model:ir.model.fields,field_description:sale_product_pack.field_sale_order_line__pack_depth +msgid "Depth" +msgstr "" + +#. module: sale_product_pack +#: model:ir.model.fields,help:sale_product_pack.field_sale_order_line__pack_depth +msgid "Depth of the product if it is part of a pack." +msgstr "" + +#. module: sale_product_pack +#: model:ir.model.fields,field_description:sale_product_pack.field_sale_order_line__do_no_expand_pack_lines +msgid "Do No Expand Pack Lines" +msgstr "" + +#. module: sale_product_pack +#: model:ir.model.fields,field_description:sale_product_pack.field_sale_order_line__pack_child_line_ids +msgid "Lines in pack" +msgstr "" + +#. module: sale_product_pack +#: model:ir.model.fields,help:sale_product_pack.field_sale_order_line__pack_component_price +msgid "" +"On sale orders or purchase orders:\n" +"* Detailed per component: Detail lines with prices.\n" +"* Totalized in main product: Detail lines merging lines prices on pack (don't show component prices).\n" +"* Ignored: Use product pack price (ignore detail line prices)." +msgstr "" + +#. module: sale_product_pack +#: model:ir.model.fields,help:sale_product_pack.field_sale_order_line__pack_type +msgid "" +"On sale orders or purchase orders:\n" +"* Detailed: Display components individually in the sale order.\n" +"* Non Detailed: Do not display components individually in the sale order." +msgstr "" + +#. module: sale_product_pack +#: model:ir.model.fields,field_description:sale_product_pack.field_sale_order_line__pack_parent_line_id +msgid "Pack" +msgstr "" + +#. module: sale_product_pack +#: model:ir.model.fields,field_description:sale_product_pack.field_sale_order_line__pack_component_price +msgid "Pack Component Price" +msgstr "" + +#. module: sale_product_pack +#: model:ir.model.fields,field_description:sale_product_pack.field_sale_order_line__pack_type +msgid "Pack Display Type" +msgstr "" + +#. module: sale_product_pack +#: model:ir.model.fields,field_description:sale_product_pack.field_sale_order_line__pack_modifiable +msgid "Pack Modifiable" +msgstr "" + +#. module: sale_product_pack +#: model_terms:ir.ui.view,arch_db:sale_product_pack.view_order_form +msgid "Parent Pack is not modifiable" +msgstr "" + +#. module: sale_product_pack +#. odoo-python +#: code:addons/sale_product_pack/models/sale_order_line.py:0 +#, python-format +msgid "Parent Product" +msgstr "" + +#. module: sale_product_pack +#: model:ir.model,name:sale_product_pack.model_product_pack_line +msgid "Product pack line" +msgstr "" + +#. module: sale_product_pack +#: model:ir.model.fields,field_description:sale_product_pack.field_product_pack_line__sale_discount +msgid "Sale discount (%)" +msgstr "" + +#. module: sale_product_pack +#: model:ir.model,name:sale_product_pack.model_sale_order +msgid "Sales Order" +msgstr "" + +#. module: sale_product_pack +#: model:ir.model,name:sale_product_pack.model_sale_order_line +msgid "Sales Order Line" +msgstr "" + +#. module: sale_product_pack +#: model:ir.model.fields,help:sale_product_pack.field_sale_order_line__pack_parent_line_id +msgid "The pack that contains this product." +msgstr "" + +#. module: sale_product_pack +#: model:ir.model.fields,help:sale_product_pack.field_sale_order_line__pack_modifiable +msgid "The parent pack is modifiable" +msgstr "" + +#. module: sale_product_pack +#: model:ir.model.fields,help:sale_product_pack.field_sale_order_line__do_no_expand_pack_lines +msgid "" +"This is a technical field in order to check if pack lines has to be expanded" +msgstr "" + +#. module: sale_product_pack +#. odoo-python +#: code:addons/sale_product_pack/models/sale_order_line.py:0 +#, python-format +msgid "" +"You can not change this line because is part of a pack included in this " +"order" +msgstr "" + +#. module: sale_product_pack +#. odoo-python +#: code:addons/sale_product_pack/models/sale_order.py:0 +#, python-format +msgid "" +"You cannot delete this line because is part of a pack in this sale order. In" +" order to delete this line you need to delete the pack itself" +msgstr "" diff --git a/sale_product_pack/models/__init__.py b/sale_product_pack/models/__init__.py new file mode 100644 index 000000000..cd9997169 --- /dev/null +++ b/sale_product_pack/models/__init__.py @@ -0,0 +1,5 @@ +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from . import product_pack_line +from . import sale_order_line +from . import sale_order diff --git a/sale_product_pack/models/product_pack_line.py b/sale_product_pack/models/product_pack_line.py new file mode 100644 index 000000000..522727695 --- /dev/null +++ b/sale_product_pack/models/product_pack_line.py @@ -0,0 +1,51 @@ +# Copyright 2019 Tecnativa - Ernesto Tejeda +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +from odoo import fields, models + + +class ProductPack(models.Model): + _inherit = "product.pack.line" + + sale_discount = fields.Float( + "Sale discount (%)", + digits="Discount", + ) + + def get_sale_order_line_vals(self, line, order): + self.ensure_one() + quantity = self.quantity * line.product_uom_qty + line_vals = { + "order_id": order.id, + "sequence": line.sequence, + "product_id": self.product_id.id or False, + "pack_parent_line_id": line.id, + "pack_depth": line.pack_depth + 1, + "company_id": order.company_id.id, + "pack_modifiable": line.product_id.pack_modifiable, + "product_uom_qty": quantity, + } + sol = line.new(line_vals) + sol._onchange_product_id_warning() + vals = sol._convert_to_write(sol._cache) + pack_price_types = {"totalized", "ignored"} + sale_discount = 0.0 + if line.product_id.pack_component_price == "detailed": + sale_discount = 100.0 - ( + (100.0 - sol.discount) * (100.0 - self.sale_discount) / 100.0 + ) + elif ( + line.product_id.pack_type == "detailed" + and line.product_id.pack_component_price in pack_price_types + ): + vals["price_unit"] = 0.0 + vals.update( + { + "discount": sale_discount, + "name": "{}{}".format("> " * (line.pack_depth + 1), sol.name), + } + ) + return vals + + def get_price(self): + self.ensure_one() + return super().get_price() * (1 - self.sale_discount / 100.0) diff --git a/sale_product_pack/models/sale_order.py b/sale_product_pack/models/sale_order.py new file mode 100644 index 000000000..5e7d4298b --- /dev/null +++ b/sale_product_pack/models/sale_order.py @@ -0,0 +1,71 @@ +# Copyright 2019 Tecnativa - Ernesto Tejeda +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +from odoo import _, api, models +from odoo.exceptions import UserError + + +class SaleOrder(models.Model): + _inherit = "sale.order" + + def copy(self, default=None): + sale_copy = super().copy(default) + # we unlink pack lines that should not be copied + pack_copied_lines = sale_copy.order_line.filtered( + lambda line: line.pack_parent_line_id.order_id == self + ) + pack_copied_lines.unlink() + return sale_copy + + @api.onchange("order_line") + def check_pack_line_unlink(self): + """At least on embeded tree editable view odoo returns a recordset on + _origin.order_line only when lines are unlinked and this is exactly + what we need + """ + origin_line_ids = self._origin.order_line.ids + line_ids = self.order_line.ids + removed_line_ids = list(set(origin_line_ids) - set(line_ids)) + removed_line = self.env["sale.order.line"].browse(removed_line_ids) + if removed_line.filtered( + lambda x: x.pack_parent_line_id + and not x.pack_parent_line_id.product_id.pack_modifiable + ): + raise UserError( + _( + "You cannot delete this line because is part of a pack in" + " this sale order. In order to delete this line you need to" + " delete the pack itself" + ) + ) + + def write(self, vals): + if "order_line" in vals: + to_delete_ids = [e[1] for e in vals["order_line"] if e[0] == 2] + subpacks_to_delete_ids = ( + self.env["sale.order.line"] + .search( + [("id", "child_of", to_delete_ids), ("id", "not in", to_delete_ids)] + ) + .ids + ) + if subpacks_to_delete_ids: + for cmd in vals["order_line"]: + if cmd[1] in subpacks_to_delete_ids: + if cmd[0] != 2: + cmd[0] = 2 + subpacks_to_delete_ids.remove(cmd[1]) + for to_delete_id in subpacks_to_delete_ids: + vals["order_line"].append([2, to_delete_id, False]) + return super().write(vals) + + def _get_update_prices_lines(self): + res = super()._get_update_prices_lines() + result = self.order_line.browse() + index = 0 + while index < len(res): + line = res[index] + result |= line + index += 1 + if line.product_id.pack_ok and line.pack_type == "detailed": + index += len(line.product_id.pack_line_ids) + return result diff --git a/sale_product_pack/models/sale_order_line.py b/sale_product_pack/models/sale_order_line.py new file mode 100644 index 000000000..57e4a2092 --- /dev/null +++ b/sale_product_pack/models/sale_order_line.py @@ -0,0 +1,129 @@ +# Copyright 2019 Tecnativa - Ernesto Tejeda +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +from odoo import _, api, fields, models +from odoo.exceptions import UserError +from odoo.fields import first + + +class SaleOrderLine(models.Model): + _inherit = "sale.order.line" + _parent_name = "pack_parent_line_id" + + pack_type = fields.Selection( + related="product_id.pack_type", + ) + pack_component_price = fields.Selection( + related="product_id.pack_component_price", + ) + + # Fields for common packs + pack_depth = fields.Integer( + "Depth", help="Depth of the product if it is part of a pack." + ) + pack_parent_line_id = fields.Many2one( + "sale.order.line", + "Pack", + help="The pack that contains this product.", + ) + pack_child_line_ids = fields.One2many( + "sale.order.line", "pack_parent_line_id", "Lines in pack" + ) + pack_modifiable = fields.Boolean(help="The parent pack is modifiable") + + do_no_expand_pack_lines = fields.Boolean( + compute="_compute_do_no_expand_pack_lines", + help="This is a technical field in order to check if pack lines has to be " + "expanded", + ) + + @api.depends_context("update_prices", "update_pricelist") + def _compute_do_no_expand_pack_lines(self): + do_not_expand = self.env.context.get("update_prices") or self.env.context.get( + "update_pricelist", False + ) + self.update( + { + "do_no_expand_pack_lines": do_not_expand, + } + ) + + def expand_pack_line(self, write=False): + self.ensure_one() + # if we are using update_pricelist or checking out on ecommerce we + # only want to update prices + vals_list = [] + if self.product_id.pack_ok and self.pack_type == "detailed": + for subline in self.product_id.get_pack_lines(): + vals = subline.get_sale_order_line_vals(self, self.order_id) + if write: + existing_subline = first( + self.pack_child_line_ids.filtered( + lambda child, s=subline: child.product_id == s.product_id + ) + ) + # if subline already exists we update, if not we create + if existing_subline: + if self.do_no_expand_pack_lines: + vals.pop("product_uom_qty", None) + vals.pop("discount", None) + existing_subline.write(vals) + elif not self.do_no_expand_pack_lines: + vals_list.append(vals) + else: + vals_list.append(vals) + if vals_list: + self.create(vals_list) + + @api.model_create_multi + def create(self, vals_list): + new_vals = [] + res = self.browse() + for elem in vals_list: + product = self.env["product.product"].browse(elem.get("product_id")) + if product and product.pack_ok and product.pack_type != "non_detailed": + line = super().create([elem]) + line.expand_pack_line() + res |= line + else: + new_vals.append(elem) + res |= super().create(new_vals) + return res + + def write(self, vals): + res = super().write(vals) + if "product_id" in vals or "product_uom_qty" in vals: + for record in self: + record.expand_pack_line(write=True) + return res + + @api.onchange( + "product_id", + "product_uom_qty", + "product_uom", + "price_unit", + "discount", + "name", + "tax_id", + ) + def check_pack_line_modify(self): + """Do not let to edit a sale order line if this one belongs to pack""" + if self._origin.pack_parent_line_id and not self._origin.pack_modifiable: + raise UserError( + _( + "You can not change this line because is part of a pack" + " included in this order" + ) + ) + + def action_open_parent_pack_product_view(self): + domain = [ + ("id", "in", self.mapped("pack_parent_line_id").mapped("product_id").ids) + ] + return { + "name": _("Parent Product"), + "type": "ir.actions.act_window", + "res_model": "product.product", + "view_type": "form", + "view_mode": "tree,form", + "domain": domain, + } diff --git a/sale_product_pack/pyproject.toml b/sale_product_pack/pyproject.toml new file mode 100644 index 000000000..4231d0ccc --- /dev/null +++ b/sale_product_pack/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/sale_product_pack/readme/CONTRIBUTORS.md b/sale_product_pack/readme/CONTRIBUTORS.md new file mode 100644 index 000000000..3153b91d3 --- /dev/null +++ b/sale_product_pack/readme/CONTRIBUTORS.md @@ -0,0 +1,11 @@ +- [Tecnativa](https://www.tecnativa.com): + - Ernesto Tejeda + - Pedro M. Baeza +- [Akretion](https://akretion.com): + - Raphaël Reverdy +- [Open Source Integrators](https://opensourceintegrators.eu): + - Daniel Reis \<\> +- [Acsone](https://www.acsone.eu/): + - Maxime Franco +- [ADHOC SA](https://www.adhoc.com.ar): + - Bruno Zanotti diff --git a/sale_product_pack/readme/DESCRIPTION.md b/sale_product_pack/readme/DESCRIPTION.md new file mode 100644 index 000000000..802631cf0 --- /dev/null +++ b/sale_product_pack/readme/DESCRIPTION.md @@ -0,0 +1,4 @@ +This module adds *Product Pack* functionality to sales orders. You can +choose a *Pack* in *sales order lines* and see different behaviors +depending on "Pack type" and "Pack component price" fields options +selected on this *Pack*. diff --git a/sale_product_pack/readme/ROADMAP.md b/sale_product_pack/readme/ROADMAP.md new file mode 100644 index 000000000..02047557f --- /dev/null +++ b/sale_product_pack/readme/ROADMAP.md @@ -0,0 +1,5 @@ +- If this module is installed and stock module is installed too, when + you create a Sale order for a *Non detailed* Pack and you confirm it, + a *Stock picking* is not created with the storable components of that + Pack. So, add a new module called *sale_stock_product_pack* that adds + that feature. diff --git a/sale_product_pack/readme/USAGE.md b/sale_product_pack/readme/USAGE.md new file mode 100644 index 000000000..62b6ac783 --- /dev/null +++ b/sale_product_pack/readme/USAGE.md @@ -0,0 +1,15 @@ +To use this module, you need to: + +1. Go to *Sales \> Products \> Products*, create or select a product + and check *Is Pack?* +2. Set "Product type" and "Pack component price" fields in the *Pack* + page. +3. Add the products to be included in it. +4. Go to *Sales \> Orders \> Quotations* and create a Quotation. +5. Add a product that has checked "Is Pack?" +6. Save data and you will see an specific behavior depending on "Pack + type" and "Pack component price" fields options selected on this + *Pack*. For example, for products that has *Detailed* option + selected in "Pack type" field you will see one *sale order line* per + component that belong to this Pack. (See *Product pack* module + README.rst file) diff --git a/sale_product_pack/security/ir.model.access.csv b/sale_product_pack/security/ir.model.access.csv new file mode 100644 index 000000000..6b968d84d --- /dev/null +++ b/sale_product_pack/security/ir.model.access.csv @@ -0,0 +1,2 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_product_pack_line_sale_manager,product.pack.line,model_product_pack_line,sales_team.group_sale_manager,1,1,1,1 diff --git a/sale_product_pack/static/description/icon.png b/sale_product_pack/static/description/icon.png new file mode 100644 index 000000000..3a0328b51 Binary files /dev/null and b/sale_product_pack/static/description/icon.png differ diff --git a/sale_product_pack/static/description/index.html b/sale_product_pack/static/description/index.html new file mode 100644 index 000000000..0c46acdfb --- /dev/null +++ b/sale_product_pack/static/description/index.html @@ -0,0 +1,477 @@ + + + + + +Sale Product Pack + + + +
+

Sale Product Pack

+ + +

Beta License: AGPL-3 OCA/product-pack Translate me on Weblate Try me on Runboat

+

This module adds Product Pack functionality to sales orders. You can +choose a Pack in sales order lines and see different behaviors +depending on “Pack type” and “Pack component price” fields options +selected on this Pack.

+

Table of contents

+ +
+

Usage

+

To use this module, you need to:

+
    +
  1. Go to Sales > Products > Products, create or select a product and +check Is Pack?
  2. +
  3. Set “Product type” and “Pack component price” fields in the Pack +page.
  4. +
  5. Add the products to be included in it.
  6. +
  7. Go to Sales > Orders > Quotations and create a Quotation.
  8. +
  9. Add a product that has checked “Is Pack?”
  10. +
  11. Save data and you will see an specific behavior depending on “Pack +type” and “Pack component price” fields options selected on this +Pack. For example, for products that has Detailed option selected +in “Pack type” field you will see one sale order line per component +that belong to this Pack. (See Product pack module README.rst file)
  12. +
+
+
+

Known issues / Roadmap

+
    +
  • If this module is installed and stock module is installed too, when +you create a Sale order for a Non detailed Pack and you confirm it, +a Stock picking is not created with the storable components of that +Pack. So, add a new module called sale_stock_product_pack that adds +that feature.
  • +
+
+
+

Bug Tracker

+

Bugs are tracked on GitHub Issues. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +feedback.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • NaN·tic
  • +
  • ADHOC SA
  • +
  • Tecnativa
  • +
+
+
+

Contributors

+ +
+
+

Maintainers

+

This module is maintained by the OCA.

+Odoo Community Association +

OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use.

+

Current maintainer:

+

ernestotejeda

+

This module is part of the OCA/product-pack project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+ + diff --git a/sale_product_pack/tests/__init__.py b/sale_product_pack/tests/__init__.py new file mode 100644 index 000000000..365edcb3d --- /dev/null +++ b/sale_product_pack/tests/__init__.py @@ -0,0 +1,3 @@ +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from . import test_sale_product_pack diff --git a/sale_product_pack/tests/test_sale_product_pack.py b/sale_product_pack/tests/test_sale_product_pack.py new file mode 100644 index 000000000..d8de12221 --- /dev/null +++ b/sale_product_pack/tests/test_sale_product_pack.py @@ -0,0 +1,275 @@ +# Copyright 2019 Tecnativa - Ernesto Tejeda +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo.tests.common import TransactionCase + + +class TestSaleProductPack(TransactionCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + pricelist = cls.env["product.pricelist"].create( + { + "name": "Test", + "company_id": cls.env.company.id, + "item_ids": [ + ( + 0, + 0, + { + "applied_on": "3_global", + "compute_price": "formula", + "base": "list_price", + }, + ) + ], + } + ) + cls.discount_pricelist = cls.env["product.pricelist"].create( + { + "name": "Discount", + "company_id": cls.env.company.id, + "item_ids": [ + ( + 0, + 0, + { + "applied_on": "3_global", + "compute_price": "percentage", + "percent_price": 10, + }, + ) + ], + } + ) + cls.sale_order = cls.env["sale.order"].create( + { + "company_id": cls.env.company.id, + "partner_id": cls.env.ref("base.res_partner_12").id, + "pricelist_id": pricelist.id, + } + ) + + def _get_component_prices_sum(self, product_pack): + component_prices = 0.0 + for pack_line in product_pack.get_pack_lines(): + product_line_price = pack_line.product_id.list_price * ( + 1 - (pack_line.sale_discount or 0.0) / 100.0 + ) + component_prices += product_line_price * pack_line.quantity + return component_prices + + def test_create_components_price_order_line(self): + product_cp = self.env.ref("product_pack.product_pack_cpu_detailed_components") + line = self.env["sale.order.line"].create( + { + "order_id": self.sale_order.id, + "name": product_cp.name, + "product_id": product_cp.id, + "product_uom_qty": 1, + } + ) + # After create, there will be four lines + self.assertEqual(len(self.sale_order.order_line), 4) + pack_line = self.sale_order.order_line.filtered( + lambda pline: pline.product_id == product_cp + ) + # Check if sequence is the same as pack product one + sequence = pack_line.sequence + self.assertEqual( + [sequence, sequence, sequence, sequence], + self.sale_order.order_line.mapped("sequence"), + ) + # The products of those four lines are the main product pack and its + # product components + self.assertEqual( + self.sale_order.order_line.mapped("product_id"), + product_cp | product_cp.get_pack_lines().mapped("product_id"), + ) + # Price before update pricelist + self.assertAlmostEqual(line.price_subtotal, 30.75) + self.assertEqual( + (self.sale_order.order_line - line).mapped("price_subtotal"), + [1755.0, 22.5, 885.0], + ) + # Update pricelist with a discount + self.sale_order.pricelist_id = self.discount_pricelist + self.sale_order.action_update_prices() + self.assertAlmostEqual(line.price_subtotal, 27.68) + self.assertEqual( + (self.sale_order.order_line - line).mapped("price_subtotal"), + [1755.0, 22.5, 885.0], + ) + + def test_create_ignored_price_order_line(self): + product_tp = self.env.ref("product_pack.product_pack_cpu_detailed_ignored") + line = self.env["sale.order.line"].create( + { + "order_id": self.sale_order.id, + "name": product_tp.name, + "product_id": product_tp.id, + "product_uom_qty": 1, + } + ) + # After create, there will be four lines + self.assertEqual(len(self.sale_order.order_line), 4) + # The products of those four lines are the main product pack and its + # product components + self.assertEqual( + self.sale_order.order_line.mapped("product_id"), + product_tp | product_tp.get_pack_lines().mapped("product_id"), + ) + # All component lines have zero as subtotal + self.assertEqual( + (self.sale_order.order_line - line).mapped("price_subtotal"), [0, 0, 0] + ) + # Pack price is different from the sum of component prices + self.assertAlmostEqual(line.price_subtotal, 30.75) + self.assertNotEqual(self._get_component_prices_sum(product_tp), 30.75) + + # Update pricelist with a discount + self.sale_order.pricelist_id = self.discount_pricelist + self.sale_order.action_update_prices() + self.assertAlmostEqual(line.price_subtotal, 27.68) + self.assertEqual( + (self.sale_order.order_line - line).mapped("price_subtotal"), [0, 0, 0] + ) + + def test_create_totalized_price_order_line(self): + product_tp = self.env.ref("product_pack.product_pack_cpu_detailed_totalized") + line = self.env["sale.order.line"].create( + { + "order_id": self.sale_order.id, + "name": product_tp.name, + "product_id": product_tp.id, + "product_uom_qty": 1, + } + ) + # After create, there will be four lines + self.assertEqual(len(self.sale_order.order_line), 4) + # The products of those four lines are the main product pack and its + # product components + self.assertEqual( + self.sale_order.order_line.mapped("product_id"), + product_tp | product_tp.get_pack_lines().mapped("product_id"), + ) + # All component lines have zero as subtotal + self.assertAlmostEqual( + (self.sale_order.order_line - line).mapped("price_subtotal"), [0, 0, 0] + ) + # Pack price is equal to the sum of component prices + self.assertAlmostEqual(line.price_subtotal, 2662.5) + self.assertAlmostEqual(self._get_component_prices_sum(product_tp), 2662.5) + + # Update pricelist with a discount + self.sale_order.pricelist_id = self.discount_pricelist + self.sale_order.action_update_prices() + self.assertAlmostEqual(line.price_subtotal, 2396.25) + self.assertEqual( + (self.sale_order.order_line - line).mapped("price_subtotal"), [0, 0, 0] + ) + + def test_create_non_detailed_price_order_line(self): + product_ndtp = self.env.ref("product_pack.product_pack_cpu_non_detailed") + line = self.env["sale.order.line"].create( + { + "order_id": self.sale_order.id, + "name": product_ndtp.name, + "product_id": product_ndtp.id, + "product_uom_qty": 1, + } + ) + # After create, there will be only one line, because product_type is + # not a detailed one + self.assertEqual(self.sale_order.order_line, line) + # Pack price is equal to the sum of component prices + self.assertAlmostEqual(line.price_subtotal, 2662.5) + self.assertAlmostEqual(self._get_component_prices_sum(product_ndtp), 2662.5) + + # Update pricelist with a discount + self.sale_order.pricelist_id = self.discount_pricelist + self.sale_order.action_update_prices() + self.assertAlmostEqual(line.price_subtotal, 2396.25) + + def test_update_qty(self): + # Ensure the quantities are always updated + + def qty_in_order(): + return sum(self.sale_order.order_line.mapped("product_uom_qty")) + + product_cp = self.env.ref("product_pack.product_pack_cpu_detailed_components") + main_sol = self.env["sale.order.line"].create( + { + "order_id": self.sale_order.id, + "name": product_cp.name, + "product_id": product_cp.id, + "product_uom_qty": 1, + } + ) + total_qty_init = qty_in_order() + # change qty of main sol + main_sol.product_uom_qty = 2 * main_sol.product_uom_qty + total_qty_updated = qty_in_order() + # Ensure all quantities have doubled + self.assertAlmostEqual(total_qty_init * 2, total_qty_updated) + + # Confirm the sale + self.sale_order.action_confirm() + + # Ensure we can still update the quantity + main_sol.product_uom_qty = 2 * main_sol.product_uom_qty + total_qty_confirmed = qty_in_order() + self.assertAlmostEqual(total_qty_updated * 2, total_qty_confirmed) + + def test_do_not_expand(self): + product_cp = self.env.ref("product_pack.product_pack_cpu_detailed_components") + pack_line = self.env["sale.order.line"].create( + { + "order_id": self.sale_order.id, + "name": product_cp.name, + "product_id": product_cp.id, + "product_uom_qty": 1, + } + ) + # After create, there will be four lines + self.assertEqual(len(self.sale_order.order_line), 4) + pack_line_update = pack_line.with_context(update_prices=True) + self.assertTrue(pack_line_update.do_no_expand_pack_lines) + pack_line_update = pack_line.with_context(update_pricelist=True) + self.assertTrue(pack_line_update.do_no_expand_pack_lines) + + def test_create_several_lines(self): + # Create two sale order lines with two pack products + # Check 8 lines are created + # Check lines sequences and order are respected + product_cp = self.env.ref("product_pack.product_pack_cpu_detailed_components") + product_tp = self.env.ref("product_pack.product_pack_cpu_detailed_ignored") + vals = [ + { + "order_id": self.sale_order.id, + "name": product_cp.name, + "product_id": product_cp.id, + "product_uom_qty": 1, + }, + { + "order_id": self.sale_order.id, + "name": product_tp.name, + "product_id": product_tp.id, + "product_uom_qty": 1, + }, + ] + self.env["sale.order.line"].create(vals) + # After create, there will be eight lines (4 + 4) + self.assertEqual(len(self.sale_order.order_line), 8) + # Check if lines are well ordered + self.assertEqual(self.sale_order.order_line[0].product_id, product_cp) + sequence_cp = self.sale_order.order_line[0].sequence + self.assertEqual(sequence_cp, self.sale_order.order_line[1].sequence) + self.assertEqual(sequence_cp, self.sale_order.order_line[2].sequence) + self.assertEqual(sequence_cp, self.sale_order.order_line[3].sequence) + + self.assertEqual(self.sale_order.order_line[4].product_id, product_tp) + sequence_tp = self.sale_order.order_line[4].sequence + self.assertEqual(sequence_tp, self.sale_order.order_line[5].sequence) + self.assertEqual(sequence_tp, self.sale_order.order_line[6].sequence) + self.assertEqual(sequence_tp, self.sale_order.order_line[7].sequence) diff --git a/sale_product_pack/views/product_pack_line_views.xml b/sale_product_pack/views/product_pack_line_views.xml new file mode 100644 index 000000000..c74f6fd47 --- /dev/null +++ b/sale_product_pack/views/product_pack_line_views.xml @@ -0,0 +1,51 @@ + + + + + product.pack.line.sale.form + product.pack.line + + + + + + + + + product.pack.line.sale.tree + product.pack.line + + + + + + + + + sale.order + + + + + +