diff --git a/sale_order_secondary_unit/README.rst b/sale_order_secondary_unit/README.rst new file mode 100644 index 00000000000..9513abca5df --- /dev/null +++ b/sale_order_secondary_unit/README.rst @@ -0,0 +1,110 @@ +.. image:: https://odoo-community.org/readme-banner-image + :target: https://odoo-community.org/get-involved?utm_source=readme + :alt: Odoo Community Association + +========================= +Sale Order Secondary Unit +========================= + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:7ffc87bcee58eacbd472a2b17123ee8e80c5ee9abd4aaf9b98d76a481f8f7f2c + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Production%2FStable-green.png + :target: https://odoo-community.org/page/development-status + :alt: Production/Stable +.. |badge2| image:: https://img.shields.io/badge/license-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%2Fsale--workflow-lightgray.png?logo=github + :target: https://github.com/OCA/sale-workflow/tree/19.0/sale_order_secondary_unit + :alt: OCA/sale-workflow +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/sale-workflow-19-0/sale-workflow-19-0-sale_order_secondary_unit + :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/sale-workflow&target_branch=19.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module extends the functionality of sale orders to allow sale +products in secondary unit of distinct category. + +**Table of contents** + +.. contents:: + :local: + +Configuration +============= + +To configure this module, you need to: + +1. Go to *Sales > Configuration > Products > Secondary Units of Measure* + to manage all the 'Secondary Units of Measure' in the system. + +Usage +===== + +To use this module you need to: + +1. Go to a *Product > General Information tab*. +2. Create any record in "Secondary unit of measure". +3. Set the conversion factor. +4. Go to *Sales > Quotation > Create*. +5. Change quantities in line and secondary unit (produc_qty will be + change). + +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 +------- + +* Tecnativa + +Contributors +------------ + +- Tony Gu +- Alexei Rivera +- Kevin Roche +- `Tecnativa `__: + + - Carlos Dauden + - Sergio Teruel + - Ernesto Tejeda + - Pedro M. Baeza + - Pilar Vargas + +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. + +This module is part of the `OCA/sale-workflow `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/sale_order_secondary_unit/__init__.py b/sale_order_secondary_unit/__init__.py new file mode 100644 index 00000000000..3275ac2adf3 --- /dev/null +++ b/sale_order_secondary_unit/__init__.py @@ -0,0 +1,2 @@ +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from . import models diff --git a/sale_order_secondary_unit/__manifest__.py b/sale_order_secondary_unit/__manifest__.py new file mode 100644 index 00000000000..ffb82d9e2c6 --- /dev/null +++ b/sale_order_secondary_unit/__manifest__.py @@ -0,0 +1,22 @@ +# Copyright 2018-2020 Tecnativa - Carlos Dauden +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +{ + "name": "Sale Order Secondary Unit", + "summary": "Sale product in a secondary unit", + "version": "19.0.1.0.0", + "development_status": "Production/Stable", + "category": "Sale", + "website": "https://github.com/OCA/sale-workflow", + "author": "Tecnativa, Odoo Community Association (OCA)", + "license": "AGPL-3", + "application": False, + "installable": True, + "auto_install": True, + "depends": ["sale", "product_secondary_unit"], + "data": [ + "views/product_secondary_unit_views.xml", + "views/product_views.xml", + "views/sale_order_views.xml", + "report/sale_report_templates.xml", + ], +} diff --git a/sale_order_secondary_unit/i18n/de.po b/sale_order_secondary_unit/i18n/de.po new file mode 100644 index 00000000000..d463b290bbc --- /dev/null +++ b/sale_order_secondary_unit/i18n/de.po @@ -0,0 +1,118 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * sale_order_secondary_unit +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 11.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2020-01-15 13:25+0000\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: de\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_order_secondary_unit +#: model_terms:ir.ui.view,arch_db:sale_order_secondary_unit.view_order_form +msgid "->" +msgstr "" + +#. module: sale_order_secondary_unit +#: model:ir.model.fields,field_description:sale_order_secondary_unit.field_sale_order_line__secondary_uom_unit_price +msgid "2nd unit price" +msgstr "" + +#. module: sale_order_secondary_unit +#: model_terms:ir.ui.view,arch_db:sale_order_secondary_unit.report_saleorder_document +msgid "Second. Qty" +msgstr "" + +#. module: sale_order_secondary_unit +#: model:ir.model.fields,field_description:sale_order_secondary_unit.field_product_product__sale_secondary_uom_id +#: model:ir.model.fields,field_description:sale_order_secondary_unit.field_product_template__sale_secondary_uom_id +msgid "Default secondary unit for sales" +msgstr "" + +#. module: sale_order_secondary_unit +#: model_terms:ir.ui.view,arch_db:sale_order_secondary_unit.product_secondary_unit_view_search +msgid "Group By" +msgstr "" + +#. module: sale_order_secondary_unit +#: model:ir.model.fields,help:sale_order_secondary_unit.field_product_product__sale_secondary_uom_id +#: model:ir.model.fields,help:sale_order_secondary_unit.field_product_template__sale_secondary_uom_id +msgid "" +"In order to set a value, please first add at least one record in 'Secondary " +"Unit of Measure'" +msgstr "" + +#. module: sale_order_secondary_unit +#: model:ir.model,name:sale_order_secondary_unit.model_product_template +msgid "Product" +msgstr "" + +#. module: sale_order_secondary_unit +#: model_terms:ir.ui.view,arch_db:sale_order_secondary_unit.product_secondary_unit_view_search +msgid "Product Template" +msgstr "" + +#. module: sale_order_secondary_unit +#: model:ir.model,name:sale_order_secondary_unit.model_product_product +#: model_terms:ir.ui.view,arch_db:sale_order_secondary_unit.product_secondary_unit_view_search +msgid "Product Variant" +msgstr "" + +#. module: sale_order_secondary_unit +#. odoo-python +#: code:addons/sale_order_secondary_unit/models/product_template.py:0 +#, python-format +msgid "" +"Product variants have distinct sale secondary uom:\n" +"%(secondary_uom)s\n" +"All variants will be written with new secondary uom" +msgstr "" + +#. module: sale_order_secondary_unit +#: model:ir.model.fields,field_description:sale_order_secondary_unit.field_sale_order_line__product_uom_qty +msgid "Quantity" +msgstr "" + +#. module: sale_order_secondary_unit +#: model:ir.model,name:sale_order_secondary_unit.model_sale_order_line +msgid "Sales Order Line" +msgstr "" + +#. module: sale_order_secondary_unit +#: model:ir.model.fields,field_description:sale_order_secondary_unit.field_sale_order_line__secondary_uom_id +msgid "Second unit" +msgstr "" + +#. module: sale_order_secondary_unit +#: model:ir.model.fields,field_description:sale_order_secondary_unit.field_sale_order_line__secondary_uom_qty +msgid "Secondary Qty" +msgstr "" + +#. module: sale_order_secondary_unit +#: model:ir.actions.act_window,name:sale_order_secondary_unit.product_secondary_unit_action +msgid "Secondary Unit" +msgstr "" + +#. module: sale_order_secondary_unit +#: model:ir.ui.menu,name:sale_order_secondary_unit.product_secondary_unit_menu +msgid "Secondary Units of Measure" +msgstr "" + +#. module: sale_order_secondary_unit +#: model_terms:ir.ui.view,arch_db:sale_order_secondary_unit.product_secondary_unit_view_search +msgid "UoM" +msgstr "" + +#. module: sale_order_secondary_unit +#. odoo-python +#: code:addons/sale_order_secondary_unit/models/product_template.py:0 +#, python-format +msgid "Warning" +msgstr "" diff --git a/sale_order_secondary_unit/i18n/es.po b/sale_order_secondary_unit/i18n/es.po new file mode 100644 index 00000000000..ddad5fb285c --- /dev/null +++ b/sale_order_secondary_unit/i18n/es.po @@ -0,0 +1,141 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * sale_order_secondary_unit +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 14.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-01-22 15:23+0000\n" +"PO-Revision-Date: 2023-07-24 18:09+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: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.17\n" + +#. module: sale_order_secondary_unit +#: model_terms:ir.ui.view,arch_db:sale_order_secondary_unit.view_order_form +msgid "->" +msgstr "->" + +#. module: sale_order_secondary_unit +#: model:ir.model.fields,field_description:sale_order_secondary_unit.field_sale_order_line__secondary_uom_unit_price +msgid "2nd unit price" +msgstr "Precio de la 2ª unidad" + +#. module: sale_order_secondary_unit +#: model_terms:ir.ui.view,arch_db:sale_order_secondary_unit.report_saleorder_document +msgid "Second. Qty" +msgstr "Cantidad secundaria" + +#. module: sale_order_secondary_unit +#: model:ir.model.fields,field_description:sale_order_secondary_unit.field_product_product__sale_secondary_uom_id +#: model:ir.model.fields,field_description:sale_order_secondary_unit.field_product_template__sale_secondary_uom_id +msgid "Default secondary unit for sales" +msgstr "Ud de venta secundaria por defecto" + +#. module: sale_order_secondary_unit +#: model_terms:ir.ui.view,arch_db:sale_order_secondary_unit.product_secondary_unit_view_search +msgid "Group By" +msgstr "Agrupado por" + +#. module: sale_order_secondary_unit +#: model:ir.model.fields,help:sale_order_secondary_unit.field_product_product__sale_secondary_uom_id +#: model:ir.model.fields,help:sale_order_secondary_unit.field_product_template__sale_secondary_uom_id +msgid "" +"In order to set a value, please first add at least one record in 'Secondary " +"Unit of Measure'" +msgstr "" +"Para establecer un valor, primero agregue al menos un registro en 'Segunda " +"unidad de medida'" + +#. module: sale_order_secondary_unit +#: model:ir.model,name:sale_order_secondary_unit.model_product_template +msgid "Product" +msgstr "Producto" + +#. module: sale_order_secondary_unit +#: model_terms:ir.ui.view,arch_db:sale_order_secondary_unit.product_secondary_unit_view_search +msgid "Product Template" +msgstr "Plantilla de producto" + +#. module: sale_order_secondary_unit +#: model:ir.model,name:sale_order_secondary_unit.model_product_product +#: model_terms:ir.ui.view,arch_db:sale_order_secondary_unit.product_secondary_unit_view_search +msgid "Product Variant" +msgstr "Variante de Producto" + +#. module: sale_order_secondary_unit +#. odoo-python +#: code:addons/sale_order_secondary_unit/models/product_template.py:0 +#, python-format +msgid "" +"Product variants have distinct sale secondary uom:\n" +"%(secondary_uom)s\n" +"All variants will be written with new secondary uom" +msgstr "" +"Las variantes de producto tienen unidades de medida secundarias de venta " +"distinto:\n" +"%(secondary_uom)s\n" +"Todas las variantes se escribirán con la nueva unidad de medida secundaria" + +#. module: sale_order_secondary_unit +#: model:ir.model.fields,field_description:sale_order_secondary_unit.field_sale_order_line__product_uom_qty +msgid "Quantity" +msgstr "Cantidad" + +#. module: sale_order_secondary_unit +#: model:ir.model,name:sale_order_secondary_unit.model_sale_order_line +msgid "Sales Order Line" +msgstr "Línea de pedido" + +#. module: sale_order_secondary_unit +#: model:ir.model.fields,field_description:sale_order_secondary_unit.field_sale_order_line__secondary_uom_id +msgid "Second unit" +msgstr "Unidad secundaria" + +#. module: sale_order_secondary_unit +#: model:ir.model.fields,field_description:sale_order_secondary_unit.field_sale_order_line__secondary_uom_qty +msgid "Secondary Qty" +msgstr "Cta. Ud. secundaria" + +#. module: sale_order_secondary_unit +#: model:ir.actions.act_window,name:sale_order_secondary_unit.product_secondary_unit_action +msgid "Secondary Unit" +msgstr "Unidad Secundaria" + +#. module: sale_order_secondary_unit +#: model:ir.ui.menu,name:sale_order_secondary_unit.product_secondary_unit_menu +msgid "Secondary Units of Measure" +msgstr "Unidades de medida secundarias" + +#. module: sale_order_secondary_unit +#: model_terms:ir.ui.view,arch_db:sale_order_secondary_unit.product_secondary_unit_view_search +msgid "UoM" +msgstr "UDM (Unidad De Medida)" + +#. module: sale_order_secondary_unit +#. odoo-python +#: code:addons/sale_order_secondary_unit/models/product_template.py:0 +#, python-format +msgid "Warning" +msgstr "Aviso" + +#~ msgid "Display Name" +#~ msgstr "Mostrar nombre" + +#~ msgid "ID" +#~ msgstr "ID (Identificador)" + +#~ msgid "Last Modified on" +#~ msgstr "Última modificación en" + +#~ msgid "Second. Qty" +#~ msgstr "Ud. Secundaria" + +#~ msgid "Secondary uom" +#~ msgstr "Unidad Secundaria" diff --git a/sale_order_secondary_unit/i18n/fi.po b/sale_order_secondary_unit/i18n/fi.po new file mode 100644 index 00000000000..0ef320de00d --- /dev/null +++ b/sale_order_secondary_unit/i18n/fi.po @@ -0,0 +1,120 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * sale_order_secondary_unit +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 15.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2023-08-11 12:10+0000\n" +"Last-Translator: Oskars Zālītis \n" +"Language-Team: none\n" +"Language: fi\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_order_secondary_unit +#: model_terms:ir.ui.view,arch_db:sale_order_secondary_unit.view_order_form +msgid "->" +msgstr "" + +#. module: sale_order_secondary_unit +#: model:ir.model.fields,field_description:sale_order_secondary_unit.field_sale_order_line__secondary_uom_unit_price +msgid "2nd unit price" +msgstr "2. Yksikköhinta" + +#. module: sale_order_secondary_unit +#: model_terms:ir.ui.view,arch_db:sale_order_secondary_unit.report_saleorder_document +msgid "Second. Qty" +msgstr "2. Määrä" + +#. module: sale_order_secondary_unit +#: model:ir.model.fields,field_description:sale_order_secondary_unit.field_product_product__sale_secondary_uom_id +#: model:ir.model.fields,field_description:sale_order_secondary_unit.field_product_template__sale_secondary_uom_id +msgid "Default secondary unit for sales" +msgstr "2. myynnin oletusyksikkö" + +#. module: sale_order_secondary_unit +#: model_terms:ir.ui.view,arch_db:sale_order_secondary_unit.product_secondary_unit_view_search +msgid "Group By" +msgstr "" + +#. module: sale_order_secondary_unit +#: model:ir.model.fields,help:sale_order_secondary_unit.field_product_product__sale_secondary_uom_id +#: model:ir.model.fields,help:sale_order_secondary_unit.field_product_template__sale_secondary_uom_id +msgid "" +"In order to set a value, please first add at least one record in 'Secondary " +"Unit of Measure'" +msgstr "" +"Asettaaksesi arvon, lisää vähintään yksi tietue \"Toissijaiseksi yksiköksi\"" + +#. module: sale_order_secondary_unit +#: model:ir.model,name:sale_order_secondary_unit.model_product_template +msgid "Product" +msgstr "" + +#. module: sale_order_secondary_unit +#: model_terms:ir.ui.view,arch_db:sale_order_secondary_unit.product_secondary_unit_view_search +msgid "Product Template" +msgstr "Tuotemalli" + +#. module: sale_order_secondary_unit +#: model:ir.model,name:sale_order_secondary_unit.model_product_product +#: model_terms:ir.ui.view,arch_db:sale_order_secondary_unit.product_secondary_unit_view_search +msgid "Product Variant" +msgstr "" + +#. module: sale_order_secondary_unit +#. odoo-python +#: code:addons/sale_order_secondary_unit/models/product_template.py:0 +#, python-format +msgid "" +"Product variants have distinct sale secondary uom:\n" +"%(secondary_uom)s\n" +"All variants will be written with new secondary uom" +msgstr "" + +#. module: sale_order_secondary_unit +#: model:ir.model.fields,field_description:sale_order_secondary_unit.field_sale_order_line__product_uom_qty +msgid "Quantity" +msgstr "Määrä" + +#. module: sale_order_secondary_unit +#: model:ir.model,name:sale_order_secondary_unit.model_sale_order_line +msgid "Sales Order Line" +msgstr "Myyntitilausrivi" + +#. module: sale_order_secondary_unit +#: model:ir.model.fields,field_description:sale_order_secondary_unit.field_sale_order_line__secondary_uom_id +msgid "Second unit" +msgstr "" + +#. module: sale_order_secondary_unit +#: model:ir.model.fields,field_description:sale_order_secondary_unit.field_sale_order_line__secondary_uom_qty +msgid "Secondary Qty" +msgstr "" + +#. module: sale_order_secondary_unit +#: model:ir.actions.act_window,name:sale_order_secondary_unit.product_secondary_unit_action +msgid "Secondary Unit" +msgstr "" + +#. module: sale_order_secondary_unit +#: model:ir.ui.menu,name:sale_order_secondary_unit.product_secondary_unit_menu +msgid "Secondary Units of Measure" +msgstr "" + +#. module: sale_order_secondary_unit +#: model_terms:ir.ui.view,arch_db:sale_order_secondary_unit.product_secondary_unit_view_search +msgid "UoM" +msgstr "" + +#. module: sale_order_secondary_unit +#. odoo-python +#: code:addons/sale_order_secondary_unit/models/product_template.py:0 +#, python-format +msgid "Warning" +msgstr "" diff --git a/sale_order_secondary_unit/i18n/it.po b/sale_order_secondary_unit/i18n/it.po new file mode 100644 index 00000000000..931359adb8e --- /dev/null +++ b/sale_order_secondary_unit/i18n/it.po @@ -0,0 +1,124 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * sale_order_secondary_unit +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 17.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2025-01-04 15:06+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 5.6.2\n" + +#. module: sale_order_secondary_unit +#: model_terms:ir.ui.view,arch_db:sale_order_secondary_unit.view_order_form +msgid "->" +msgstr "->" + +#. module: sale_order_secondary_unit +#: model:ir.model.fields,field_description:sale_order_secondary_unit.field_sale_order_line__secondary_uom_unit_price +msgid "2nd unit price" +msgstr "2° prezzo unitario" + +#. module: sale_order_secondary_unit +#: model_terms:ir.ui.view,arch_db:sale_order_secondary_unit.report_saleorder_document +msgid "Second. Qty" +msgstr " Q.tà secondaria" + +#. module: sale_order_secondary_unit +#: model:ir.model.fields,field_description:sale_order_secondary_unit.field_product_product__sale_secondary_uom_id +#: model:ir.model.fields,field_description:sale_order_secondary_unit.field_product_template__sale_secondary_uom_id +msgid "Default secondary unit for sales" +msgstr "Unità di misura secondaria predefinita per la vendita" + +#. module: sale_order_secondary_unit +#: model_terms:ir.ui.view,arch_db:sale_order_secondary_unit.product_secondary_unit_view_search +msgid "Group By" +msgstr "Raggruppa per" + +#. module: sale_order_secondary_unit +#: model:ir.model.fields,help:sale_order_secondary_unit.field_product_product__sale_secondary_uom_id +#: model:ir.model.fields,help:sale_order_secondary_unit.field_product_template__sale_secondary_uom_id +msgid "" +"In order to set a value, please first add at least one record in 'Secondary " +"Unit of Measure'" +msgstr "" +"Per impostare un valore, aggiungere almeno un record in 'Unità di misura " +"secondaria'" + +#. module: sale_order_secondary_unit +#: model:ir.model,name:sale_order_secondary_unit.model_product_template +msgid "Product" +msgstr "Prodotto" + +#. module: sale_order_secondary_unit +#: model_terms:ir.ui.view,arch_db:sale_order_secondary_unit.product_secondary_unit_view_search +msgid "Product Template" +msgstr "Modello prodotto" + +#. module: sale_order_secondary_unit +#: model:ir.model,name:sale_order_secondary_unit.model_product_product +#: model_terms:ir.ui.view,arch_db:sale_order_secondary_unit.product_secondary_unit_view_search +msgid "Product Variant" +msgstr "Variante prodotto" + +#. module: sale_order_secondary_unit +#. odoo-python +#: code:addons/sale_order_secondary_unit/models/product_template.py:0 +#, python-format +msgid "" +"Product variants have distinct sale secondary uom:\n" +"%(secondary_uom)s\n" +"All variants will be written with new secondary uom" +msgstr "" +"Le varianti prodotto hanno udm secondarie distinte per le vendite:\n" +"%(secondary_uom)s\n" +"Tutte le varianti verranno scritte con la nuova udm secondaria" + +#. module: sale_order_secondary_unit +#: model:ir.model.fields,field_description:sale_order_secondary_unit.field_sale_order_line__product_uom_qty +msgid "Quantity" +msgstr "Quantità" + +#. module: sale_order_secondary_unit +#: model:ir.model,name:sale_order_secondary_unit.model_sale_order_line +msgid "Sales Order Line" +msgstr "Riga ordine di vendita" + +#. module: sale_order_secondary_unit +#: model:ir.model.fields,field_description:sale_order_secondary_unit.field_sale_order_line__secondary_uom_id +msgid "Second unit" +msgstr "Unità secondaria" + +#. module: sale_order_secondary_unit +#: model:ir.model.fields,field_description:sale_order_secondary_unit.field_sale_order_line__secondary_uom_qty +msgid "Secondary Qty" +msgstr "Q.tà secondaria" + +#. module: sale_order_secondary_unit +#: model:ir.actions.act_window,name:sale_order_secondary_unit.product_secondary_unit_action +msgid "Secondary Unit" +msgstr "Unità secondaria" + +#. module: sale_order_secondary_unit +#: model:ir.ui.menu,name:sale_order_secondary_unit.product_secondary_unit_menu +msgid "Secondary Units of Measure" +msgstr "Unità di misura secondaria" + +#. module: sale_order_secondary_unit +#: model_terms:ir.ui.view,arch_db:sale_order_secondary_unit.product_secondary_unit_view_search +msgid "UoM" +msgstr "UdM" + +#. module: sale_order_secondary_unit +#. odoo-python +#: code:addons/sale_order_secondary_unit/models/product_template.py:0 +#, python-format +msgid "Warning" +msgstr "Attenzione" diff --git a/sale_order_secondary_unit/i18n/sale_order_secondary_unit.pot b/sale_order_secondary_unit/i18n/sale_order_secondary_unit.pot new file mode 100644 index 00000000000..bb4e7dd4a90 --- /dev/null +++ b/sale_order_secondary_unit/i18n/sale_order_secondary_unit.pot @@ -0,0 +1,109 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * sale_order_secondary_unit +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.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_order_secondary_unit +#: model:ir.model.fields,field_description:sale_order_secondary_unit.field_sale_order_line__secondary_uom_unit_price +msgid "2nd unit price" +msgstr "" + +#. module: sale_order_secondary_unit +#: model_terms:ir.ui.view,arch_db:sale_order_secondary_unit.report_saleorder_document +msgid "Second. Qty" +msgstr "" + +#. module: sale_order_secondary_unit +#: model:ir.model.fields,field_description:sale_order_secondary_unit.field_product_product__sale_secondary_uom_id +#: model:ir.model.fields,field_description:sale_order_secondary_unit.field_product_template__sale_secondary_uom_id +msgid "Default secondary unit for sales" +msgstr "" + +#. module: sale_order_secondary_unit +#: model_terms:ir.ui.view,arch_db:sale_order_secondary_unit.product_secondary_unit_view_search +msgid "Group By" +msgstr "" + +#. module: sale_order_secondary_unit +#: model:ir.model.fields,help:sale_order_secondary_unit.field_product_product__sale_secondary_uom_id +#: model:ir.model.fields,help:sale_order_secondary_unit.field_product_template__sale_secondary_uom_id +msgid "" +"In order to set a value, please first add at least one record in 'Secondary " +"Unit of Measure'" +msgstr "" + +#. module: sale_order_secondary_unit +#: model:ir.model,name:sale_order_secondary_unit.model_product_template +msgid "Product" +msgstr "" + +#. module: sale_order_secondary_unit +#: model_terms:ir.ui.view,arch_db:sale_order_secondary_unit.product_secondary_unit_view_search +msgid "Product Template" +msgstr "" + +#. module: sale_order_secondary_unit +#: model:ir.model,name:sale_order_secondary_unit.model_product_product +#: model_terms:ir.ui.view,arch_db:sale_order_secondary_unit.product_secondary_unit_view_search +msgid "Product Variant" +msgstr "" + +#. module: sale_order_secondary_unit +#. odoo-python +#: code:addons/sale_order_secondary_unit/models/product_template.py:0 +msgid "" +"Product variants have distinct sale secondary uom:\n" +"%(secondary_uom)s\n" +"All variants will be written with new secondary uom" +msgstr "" + +#. module: sale_order_secondary_unit +#: model:ir.model.fields,field_description:sale_order_secondary_unit.field_sale_order_line__product_uom_qty +msgid "Quantity" +msgstr "" + +#. module: sale_order_secondary_unit +#: model:ir.model,name:sale_order_secondary_unit.model_sale_order_line +msgid "Sales Order Line" +msgstr "" + +#. module: sale_order_secondary_unit +#: model:ir.model.fields,field_description:sale_order_secondary_unit.field_sale_order_line__secondary_uom_id +msgid "Second unit" +msgstr "" + +#. module: sale_order_secondary_unit +#: model:ir.model.fields,field_description:sale_order_secondary_unit.field_sale_order_line__secondary_uom_qty +msgid "Secondary Qty" +msgstr "" + +#. module: sale_order_secondary_unit +#: model:ir.actions.act_window,name:sale_order_secondary_unit.product_secondary_unit_action +msgid "Secondary Unit" +msgstr "" + +#. module: sale_order_secondary_unit +#: model:ir.ui.menu,name:sale_order_secondary_unit.product_secondary_unit_menu +msgid "Secondary Units of Measure" +msgstr "" + +#. module: sale_order_secondary_unit +#: model_terms:ir.ui.view,arch_db:sale_order_secondary_unit.product_secondary_unit_view_search +msgid "UoM" +msgstr "" + +#. module: sale_order_secondary_unit +#. odoo-python +#: code:addons/sale_order_secondary_unit/models/product_template.py:0 +msgid "Warning" +msgstr "" diff --git a/sale_order_secondary_unit/i18n/zh_CN.po b/sale_order_secondary_unit/i18n/zh_CN.po new file mode 100644 index 00000000000..3ade6f81510 --- /dev/null +++ b/sale_order_secondary_unit/i18n/zh_CN.po @@ -0,0 +1,124 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * sale_order_secondary_unit +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 11.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2020-01-15 13:25+0000\n" +"Last-Translator: Tony Gu \n" +"Language-Team: \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: sale_order_secondary_unit +#: model_terms:ir.ui.view,arch_db:sale_order_secondary_unit.view_order_form +msgid "->" +msgstr "" + +#. module: sale_order_secondary_unit +#: model:ir.model.fields,field_description:sale_order_secondary_unit.field_sale_order_line__secondary_uom_unit_price +msgid "2nd unit price" +msgstr "" + +#. module: sale_order_secondary_unit +#: model_terms:ir.ui.view,arch_db:sale_order_secondary_unit.report_saleorder_document +msgid "Second. Qty" +msgstr "" + +#. module: sale_order_secondary_unit +#: model:ir.model.fields,field_description:sale_order_secondary_unit.field_product_product__sale_secondary_uom_id +#: model:ir.model.fields,field_description:sale_order_secondary_unit.field_product_template__sale_secondary_uom_id +msgid "Default secondary unit for sales" +msgstr "默认销售辅助计量单位" + +#. module: sale_order_secondary_unit +#: model_terms:ir.ui.view,arch_db:sale_order_secondary_unit.product_secondary_unit_view_search +msgid "Group By" +msgstr "" + +#. module: sale_order_secondary_unit +#: model:ir.model.fields,help:sale_order_secondary_unit.field_product_product__sale_secondary_uom_id +#: model:ir.model.fields,help:sale_order_secondary_unit.field_product_template__sale_secondary_uom_id +msgid "" +"In order to set a value, please first add at least one record in 'Secondary " +"Unit of Measure'" +msgstr "" + +#. module: sale_order_secondary_unit +#: model:ir.model,name:sale_order_secondary_unit.model_product_template +msgid "Product" +msgstr "" + +#. module: sale_order_secondary_unit +#: model_terms:ir.ui.view,arch_db:sale_order_secondary_unit.product_secondary_unit_view_search +msgid "Product Template" +msgstr "产品模版" + +#. module: sale_order_secondary_unit +#: model:ir.model,name:sale_order_secondary_unit.model_product_product +#: model_terms:ir.ui.view,arch_db:sale_order_secondary_unit.product_secondary_unit_view_search +msgid "Product Variant" +msgstr "" + +#. module: sale_order_secondary_unit +#. odoo-python +#: code:addons/sale_order_secondary_unit/models/product_template.py:0 +#, python-format +msgid "" +"Product variants have distinct sale secondary uom:\n" +"%(secondary_uom)s\n" +"All variants will be written with new secondary uom" +msgstr "" + +#. module: sale_order_secondary_unit +#: model:ir.model.fields,field_description:sale_order_secondary_unit.field_sale_order_line__product_uom_qty +msgid "Quantity" +msgstr "" + +#. module: sale_order_secondary_unit +#: model:ir.model,name:sale_order_secondary_unit.model_sale_order_line +msgid "Sales Order Line" +msgstr "销售订单明细" + +#. module: sale_order_secondary_unit +#: model:ir.model.fields,field_description:sale_order_secondary_unit.field_sale_order_line__secondary_uom_id +msgid "Second unit" +msgstr "" + +#. module: sale_order_secondary_unit +#: model:ir.model.fields,field_description:sale_order_secondary_unit.field_sale_order_line__secondary_uom_qty +msgid "Secondary Qty" +msgstr "辅助单位数量" + +#. module: sale_order_secondary_unit +#: model:ir.actions.act_window,name:sale_order_secondary_unit.product_secondary_unit_action +msgid "Secondary Unit" +msgstr "" + +#. module: sale_order_secondary_unit +#: model:ir.ui.menu,name:sale_order_secondary_unit.product_secondary_unit_menu +msgid "Secondary Units of Measure" +msgstr "" + +#. module: sale_order_secondary_unit +#: model_terms:ir.ui.view,arch_db:sale_order_secondary_unit.product_secondary_unit_view_search +msgid "UoM" +msgstr "" + +#. module: sale_order_secondary_unit +#. odoo-python +#: code:addons/sale_order_secondary_unit/models/product_template.py:0 +#, python-format +msgid "Warning" +msgstr "" + +#~ msgid "Second. Qty" +#~ msgstr "辅助单位数量" + +#~ msgid "Secondary uom" +#~ msgstr "辅助计量单位" diff --git a/sale_order_secondary_unit/models/__init__.py b/sale_order_secondary_unit/models/__init__.py new file mode 100644 index 00000000000..645eca29a9e --- /dev/null +++ b/sale_order_secondary_unit/models/__init__.py @@ -0,0 +1,4 @@ +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from . import product +from . import product_template +from . import sale_order diff --git a/sale_order_secondary_unit/models/product.py b/sale_order_secondary_unit/models/product.py new file mode 100644 index 00000000000..c76d013eb95 --- /dev/null +++ b/sale_order_secondary_unit/models/product.py @@ -0,0 +1,17 @@ +# Copyright 2022 Tecnativa - Sergio Teruel +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from odoo import fields, models + + +class ProductProduct(models.Model): + _inherit = "product.product" + + sale_secondary_uom_id = fields.Many2one( + comodel_name="product.secondary.unit", + string="Default secondary unit for sales", + help="In order to set a value, please first add at least one record" + " in 'Secondary Unit of Measure'", + domain="['|', ('product_id', '=', id)," + "'&', ('product_tmpl_id', '=', product_tmpl_id)," + " ('product_id', '=', False)]", + ) diff --git a/sale_order_secondary_unit/models/product_template.py b/sale_order_secondary_unit/models/product_template.py new file mode 100644 index 00000000000..67263e0f432 --- /dev/null +++ b/sale_order_secondary_unit/models/product_template.py @@ -0,0 +1,71 @@ +# Copyright 2018-2020 Tecnativa - Sergio Teruel +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from odoo import api, fields, models + + +class ProductTemplate(models.Model): + _inherit = "product.template" + + sale_secondary_uom_id = fields.Many2one( + comodel_name="product.secondary.unit", + string="Default secondary unit for sales", + compute="_compute_sale_secondary_uom_id", + inverse="_inverse_sale_secondary_uom_id", + help="In order to set a value, please first add at least one record" + " in 'Secondary Unit of Measure'", + domain="[('product_tmpl_id', '=', id), ('product_id', '=', False)]", + store=True, + ) + + @api.depends("product_variant_ids", "product_variant_ids.sale_secondary_uom_id") + def _compute_sale_secondary_uom_id(self): + unique_variants = self.filtered(lambda tmpl: tmpl.product_variant_count == 1) + for template in unique_variants: + template.sale_secondary_uom_id = ( + template.product_variant_ids.sale_secondary_uom_id + ) + for template in self - unique_variants: + if len(template.product_variant_ids.sale_secondary_uom_id) == 1: + template.sale_secondary_uom_id = ( + template.product_variant_ids.sale_secondary_uom_id + ) + else: + template.sale_secondary_uom_id = False + + def _inverse_sale_secondary_uom_id(self): + for template in self: + # if template.product_variant_count == 1: + template.product_variant_ids.sale_secondary_uom_id = ( + template.sale_secondary_uom_id + ) + + @api.onchange("sale_secondary_uom_id") + def onchange_sale_secondary_uom_id(self): + if len(self.product_variant_ids.sale_secondary_uom_id) > 1: + return { + "warning": { + "title": self.env._("Warning"), + "message": self.env._( + "Product variants have distinct sale secondary uom:" + "\n%(secondary_uom)s\n" + "All variants will be written with new secondary uom", + secondary_uom="\n".join( + self.product_variant_ids.mapped( + "sale_secondary_uom_id.name" + ) + ), + ), + } + } + + @api.model_create_multi + def create(self, vals_list): + templates = super().create(vals_list) + # This is needed to set given values to first variant after creation + for template, vals in zip(templates, vals_list, strict=True): + related_vals = {} + if vals.get("sale_secondary_uom_id"): + related_vals["sale_secondary_uom_id"] = vals["sale_secondary_uom_id"] + if related_vals: + template.write(related_vals) + return templates diff --git a/sale_order_secondary_unit/models/sale_order.py b/sale_order_secondary_unit/models/sale_order.py new file mode 100644 index 00000000000..7d0c0ca0a4a --- /dev/null +++ b/sale_order_secondary_unit/models/sale_order.py @@ -0,0 +1,61 @@ +# Copyright 2018-2020 Tecnativa - Carlos Dauden +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from odoo import api, fields, models + + +class SaleOrderLine(models.Model): + _inherit = ["sale.order.line", "product.secondary.unit.mixin"] + _name = "sale.order.line" + _secondary_unit_fields = { + "qty_field": "product_uom_qty", + "uom_field": "product_uom_id", + } + + secondary_uom_unit_price = fields.Float( + string="2nd unit price", + digits="Product Price", + compute="_compute_secondary_uom_unit_price", + ) + + product_uom_qty = fields.Float(copy=True) + + @api.depends( + "display_type", + "product_id", + "secondary_uom_qty", + "secondary_uom_id", + "product_uom_qty", + ) + def _compute_product_uom_qty(self): + res = super()._compute_product_uom_qty() + for line in self: + line._compute_helper_target_field_qty() + return res + + @api.depends("product_id") + def _compute_product_uom_id(self): + res = super()._compute_product_uom_id() + for line in self: + line._onchange_helper_product_uom_for_secondary() + return res + + @api.onchange("product_id") + def _onchange_product_id_secondary_uom(self): + if self.product_id and not self.env.context.get("skip_secondary_uom_default"): + self.secondary_uom_id = self.product_id.sale_secondary_uom_id + if self.product_uom_qty == 1.0: + self.secondary_uom_qty = 1.0 + self._onchange_helper_product_uom_for_secondary() + + @api.depends("secondary_uom_qty", "product_uom_qty", "price_unit") + def _compute_secondary_uom_unit_price(self): + for line in self: + if line.secondary_uom_id: + try: + line.secondary_uom_unit_price = ( + line.price_subtotal / line.secondary_uom_qty + ) + except ZeroDivisionError: + line.secondary_uom_unit_price = 0 + else: + line.secondary_uom_unit_price = 0 diff --git a/sale_order_secondary_unit/pyproject.toml b/sale_order_secondary_unit/pyproject.toml new file mode 100644 index 00000000000..4231d0cccb3 --- /dev/null +++ b/sale_order_secondary_unit/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/sale_order_secondary_unit/readme/CONFIGURE.md b/sale_order_secondary_unit/readme/CONFIGURE.md new file mode 100644 index 00000000000..4a98897fec3 --- /dev/null +++ b/sale_order_secondary_unit/readme/CONFIGURE.md @@ -0,0 +1,5 @@ +To configure this module, you need to: + +1. Go to *Sales \> Configuration \> Products \> Secondary Units of + Measure* to manage all the 'Secondary Units of Measure' in the + system. diff --git a/sale_order_secondary_unit/readme/CONTRIBUTORS.md b/sale_order_secondary_unit/readme/CONTRIBUTORS.md new file mode 100644 index 00000000000..2d01a4ee23d --- /dev/null +++ b/sale_order_secondary_unit/readme/CONTRIBUTORS.md @@ -0,0 +1,9 @@ +- Tony Gu \<\> +- Alexei Rivera \<\> +- Kevin Roche \<\> +- [Tecnativa](https://www.tecnativa.com): + - Carlos Dauden + - Sergio Teruel + - Ernesto Tejeda + - Pedro M. Baeza + - Pilar Vargas diff --git a/sale_order_secondary_unit/readme/DESCRIPTION.md b/sale_order_secondary_unit/readme/DESCRIPTION.md new file mode 100644 index 00000000000..a83fc08e94b --- /dev/null +++ b/sale_order_secondary_unit/readme/DESCRIPTION.md @@ -0,0 +1,2 @@ +This module extends the functionality of sale orders to allow sale +products in secondary unit of distinct category. diff --git a/sale_order_secondary_unit/readme/USAGE.md b/sale_order_secondary_unit/readme/USAGE.md new file mode 100644 index 00000000000..086ac4843a9 --- /dev/null +++ b/sale_order_secondary_unit/readme/USAGE.md @@ -0,0 +1,8 @@ +To use this module you need to: + +1. Go to a *Product \> General Information tab*. +2. Create any record in "Secondary unit of measure". +3. Set the conversion factor. +4. Go to *Sales \> Quotation \> Create*. +5. Change quantities in line and secondary unit (produc_qty will be + change). diff --git a/sale_order_secondary_unit/report/sale_report_templates.xml b/sale_order_secondary_unit/report/sale_report_templates.xml new file mode 100644 index 00000000000..d8b87bdfd72 --- /dev/null +++ b/sale_order_secondary_unit/report/sale_report_templates.xml @@ -0,0 +1,26 @@ + + + + diff --git a/sale_order_secondary_unit/static/description/icon.png b/sale_order_secondary_unit/static/description/icon.png new file mode 100644 index 00000000000..3a0328b516c Binary files /dev/null and b/sale_order_secondary_unit/static/description/icon.png differ diff --git a/sale_order_secondary_unit/static/description/index.html b/sale_order_secondary_unit/static/description/index.html new file mode 100644 index 00000000000..6137b93ae15 --- /dev/null +++ b/sale_order_secondary_unit/static/description/index.html @@ -0,0 +1,462 @@ + + + + + +README.rst + + + +
+ + + +Odoo Community Association + +
+

Sale Order Secondary Unit

+ +

Production/Stable License: AGPL-3 OCA/sale-workflow Translate me on Weblate Try me on Runboat

+

This module extends the functionality of sale orders to allow sale +products in secondary unit of distinct category.

+

Table of contents

+ +
+

Configuration

+

To configure this module, you need to:

+
    +
  1. Go to Sales > Configuration > Products > Secondary Units of Measure +to manage all the ‘Secondary Units of Measure’ in the system.
  2. +
+
+
+

Usage

+

To use this module you need to:

+
    +
  1. Go to a Product > General Information tab.
  2. +
  3. Create any record in “Secondary unit of measure”.
  4. +
  5. Set the conversion factor.
  6. +
  7. Go to Sales > Quotation > Create.
  8. +
  9. Change quantities in line and secondary unit (produc_qty will be +change).
  10. +
+
+
+

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

+
    +
  • 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.

+

This module is part of the OCA/sale-workflow project on GitHub.

+

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

+
+
+
+
+ + diff --git a/sale_order_secondary_unit/tests/__init__.py b/sale_order_secondary_unit/tests/__init__.py new file mode 100644 index 00000000000..07877c48f05 --- /dev/null +++ b/sale_order_secondary_unit/tests/__init__.py @@ -0,0 +1,3 @@ +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from . import test_product_template +from . import test_sale_order diff --git a/sale_order_secondary_unit/tests/test_product_template.py b/sale_order_secondary_unit/tests/test_product_template.py new file mode 100644 index 00000000000..45346547fb3 --- /dev/null +++ b/sale_order_secondary_unit/tests/test_product_template.py @@ -0,0 +1,135 @@ +# Copyright 2018-2020 Tecnativa - Carlos Dauden +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from odoo import Command +from odoo.tests import tagged + +from odoo.addons.base.tests.common import BaseCommon + + +@tagged("post_install", "-at_install") +class TestProductTemplate(BaseCommon): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.product_uom_unit = cls.env.ref("uom.product_uom_unit") + cls.product_attribute_model = cls.env["product.attribute"] + cls.product_attribute_value_model = cls.env["product.attribute.value"] + # Create product attributes + cls.color_attribute = cls.product_attribute_model.create( + { + "name": "Test Color (sale_order_secondary_unit)", + "create_variant": "always", + } + ) + cls.color_values = cls.product_attribute_value_model.create( + [ + {"name": "Red", "attribute_id": cls.color_attribute.id}, + {"name": "Blue", "attribute_id": cls.color_attribute.id}, + {"name": "Green", "attribute_id": cls.color_attribute.id}, + ] + ) + cls.size_attribute = cls.product_attribute_model.create( + { + "name": "Test Size (sale_order_secondary_unit)", + "create_variant": "always", + } + ) + cls.size_values = cls.product_attribute_value_model.create( + [ + {"name": "S", "attribute_id": cls.size_attribute.id}, + {"name": "M", "attribute_id": cls.size_attribute.id}, + {"name": "L", "attribute_id": cls.size_attribute.id}, + ] + ) + + # Create product template + cls.product_template_1 = cls.env["product.template"].create( + { + "name": "Test Product 1", + } + ) + # Create product variants + cls.product_template_2 = cls.env["product.template"].create( + { + "name": "Test Product 2", + "attribute_line_ids": [ + Command.create( + { + "attribute_id": cls.color_attribute.id, + "value_ids": [(6, 0, cls.color_values.ids)], + }, + ), + Command.create( + { + "attribute_id": cls.size_attribute.id, + "value_ids": [(6, 0, cls.size_values.ids)], + }, + ), + ], + } + ) + # Create secondary units + cls.secondary_uom_1 = cls.env["product.secondary.unit"].create( + { + "name": "Unit 1", + "uom_id": cls.product_uom_unit.id, + "factor": 1, + "product_tmpl_id": cls.product_template_1.id, + } + ) + cls.secondary_uom_2 = cls.env["product.secondary.unit"].create( + { + "name": "Unit 2", + "uom_id": cls.product_uom_unit.id, + "factor": 1, + "product_tmpl_id": cls.product_template_1.id, + } + ) + cls.secondary_uom_3 = cls.env["product.secondary.unit"].create( + { + "name": "Unit 3", + "uom_id": cls.product_uom_unit.id, + "factor": 1, + "product_tmpl_id": cls.product_template_2.id, + } + ) + cls.secondary_uom_4 = cls.env["product.secondary.unit"].create( + { + "name": "Unit 4", + "uom_id": cls.product_uom_unit.id, + "factor": 1, + "product_tmpl_id": cls.product_template_2.id, + } + ) + + def test_create_sets_sale_secondary_uom_id_for_single_variant(self): + product_variant_ids = self.product_template_1.product_variant_ids + product_variant_ids.sale_secondary_uom_id = self.secondary_uom_1 + self.assertEqual(self.product_template_1.sale_secondary_uom_id.name, "Unit 1") + + def test_create_not_sale_secondary_uom_id_for_variants_and_warns(self): + product_variant_ids = self.product_template_2.product_variant_ids + product_variant_ids[0].sale_secondary_uom_id = self.secondary_uom_3 + product_variant_ids[1].sale_secondary_uom_id = self.secondary_uom_4 + self.assertFalse(self.product_template_2.sale_secondary_uom_id) + + warning = self.product_template_2.onchange_sale_secondary_uom_id() + self.assertIn("warning", warning) + self.assertIn( + "Product variants have distinct sale secondary uom", + warning["warning"]["message"], + ) + + def test_create_sale_secondary_uom_id_multiple_variants_same_uom(self): + product_variant_ids = self.product_template_2.product_variant_ids + product_variant_ids[0].sale_secondary_uom_id = self.secondary_uom_3 + product_variant_ids[1].sale_secondary_uom_id = self.secondary_uom_3 + self.assertEqual(self.product_template_2.sale_secondary_uom_id.name, "Unit 3") + + def test_inverse_sale_secondary_uom_id_updates_variants_correctly(self): + self.product_template_1.sale_secondary_uom_id = self.secondary_uom_2 + self.product_template_1._inverse_sale_secondary_uom_id() + self.assertEqual( + self.product_template_1.product_variant_ids.sale_secondary_uom_id, + self.product_template_1.sale_secondary_uom_id, + ) diff --git a/sale_order_secondary_unit/tests/test_sale_order.py b/sale_order_secondary_unit/tests/test_sale_order.py new file mode 100644 index 00000000000..d990bd8a8db --- /dev/null +++ b/sale_order_secondary_unit/tests/test_sale_order.py @@ -0,0 +1,108 @@ +# Copyright 2018-2020 Tecnativa - Carlos Dauden +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from odoo import Command +from odoo.tests import Form, tagged + +from odoo.addons.base.tests.common import BaseCommon + + +@tagged("post_install", "-at_install") +class TestSaleOrder(BaseCommon): + @classmethod + def setUpClass(cls): + super().setUpClass() + # Remove this variable in v16 and put instead: + # from odoo.addons.base.tests.common import DISABLED_MAIL_CONTEXT + cls.product_uom_kg = cls.env.ref("uom.product_uom_kgm") + cls.product_uom_gram = cls.env.ref("uom.product_uom_gram") + cls.product_uom_unit = cls.env.ref("uom.product_uom_unit") + cls.product = cls.env["product.product"].create( + { + "name": "test", + "uom_id": cls.product_uom_kg.id, + "list_price": 1000, + } + ) + # Set secondary uom on product template + cls.product.product_tmpl_id.write( + { + "secondary_uom_ids": [ + Command.create( + { + "name": "unit-500", + "uom_id": cls.product_uom_unit.id, + "factor": 0.5, + }, + ) + ], + } + ) + cls.secondary_unit = cls.env["product.secondary.unit"].search( + [("product_tmpl_id", "=", cls.product.product_tmpl_id.id)] + ) + cls.product.sale_secondary_uom_id = cls.secondary_unit.id + cls.partner = cls.env["res.partner"].create({"name": "test - partner"}) + with Form(cls.env["sale.order"]) as order_form: + order_form.partner_id = cls.partner + with order_form.order_line.new() as line_form: + line_form.product_id = cls.product + line_form.product_uom_qty = 1 + cls.order = order_form.save() + + def test_onchange_secondary_uom(self): + self.order.order_line.write( + {"secondary_uom_id": self.secondary_unit.id, "secondary_uom_qty": 5} + ) + self.order.order_line._compute_product_uom_qty() + self.assertEqual(self.order.order_line.product_uom_qty, 2.5) + + def test_onchange_secondary_unit_product_uom_qty(self): + self.order.order_line.update( + {"secondary_uom_id": self.secondary_unit.id, "product_uom_qty": 3.5} + ) + self.assertEqual(self.order.order_line.secondary_uom_qty, 7.0) + + def test_default_secondary_unit(self): + self.order.order_line._onchange_product_id_secondary_uom() + self.assertEqual(self.order.order_line.secondary_uom_id, self.secondary_unit) + + def test_onchange_order_product_uom(self): + self.order.order_line.update( + { + "secondary_uom_id": self.secondary_unit.id, + "product_uom_id": self.product_uom_gram.id, + "product_uom_qty": 3500.00, + } + ) + self.assertEqual(self.order.order_line.secondary_uom_qty, 7.0) + + def test_independent_type(self): + # dependent type is already tested as dependency_type by default + self.order.order_line.secondary_uom_id = self.secondary_unit.id + self.order.order_line.secondary_uom_id.write({"dependency_type": "independent"}) + + # Remember previous UoM quantity for avoiding interactions with other modules + previous_uom_qty = self.order.order_line.product_uom_qty + self.order.order_line.write({"secondary_uom_qty": 2}) + self.assertEqual(self.order.order_line.product_uom_qty, previous_uom_qty) + self.assertEqual(self.order.order_line.secondary_uom_qty, 2) + + self.order.order_line.write({"product_uom_qty": 17}) + self.assertEqual(self.order.order_line.secondary_uom_qty, 2) + self.assertEqual(self.order.order_line.product_uom_qty, 17) + + def test_secondary_uom_unit_price(self): + # Remove secondary uom in sale line to do a complete test of secondary price + self.order.order_line.secondary_uom_id = False + self.assertEqual(self.order.order_line.secondary_uom_unit_price, 0) + self.order.order_line.update( + {"secondary_uom_id": self.secondary_unit.id, "product_uom_qty": 2} + ) + + self.assertEqual(self.order.order_line.secondary_uom_qty, 4) + self.assertEqual(self.order.order_line.secondary_uom_unit_price, 500) + + self.order.order_line.write({"product_uom_qty": 8}) + self.assertEqual(self.order.order_line.secondary_uom_qty, 16) + self.assertEqual(self.order.order_line.secondary_uom_unit_price, 500) + self.assertEqual(self.order.order_line.price_subtotal, 8000) diff --git a/sale_order_secondary_unit/views/product_secondary_unit_views.xml b/sale_order_secondary_unit/views/product_secondary_unit_views.xml new file mode 100644 index 00000000000..3294dbdcb0f --- /dev/null +++ b/sale_order_secondary_unit/views/product_secondary_unit_views.xml @@ -0,0 +1,63 @@ + + + + product.secondary.unit.view.search + product.secondary.unit + + + + + + + + + + + + + + + + product.secondary.unit.sale.view.list + product.secondary.unit + + + + + + + + + + + + + Secondary Unit + product.secondary.unit + list,form + + + diff --git a/sale_order_secondary_unit/views/product_views.xml b/sale_order_secondary_unit/views/product_views.xml new file mode 100644 index 00000000000..e188d3f00ef --- /dev/null +++ b/sale_order_secondary_unit/views/product_views.xml @@ -0,0 +1,19 @@ + + + + + Product template Secondary Unit + product.template + + +
+ +
+
+
+
diff --git a/sale_order_secondary_unit/views/sale_order_views.xml b/sale_order_secondary_unit/views/sale_order_views.xml new file mode 100644 index 00000000000..033d89c1477 --- /dev/null +++ b/sale_order_secondary_unit/views/sale_order_views.xml @@ -0,0 +1,75 @@ + + + + + Sale Order Secondary Unit + sale.order + + + + + + + + + + + + + + + + + + + + + + diff --git a/test-requirements.txt b/test-requirements.txt new file mode 100644 index 00000000000..266b739de11 --- /dev/null +++ b/test-requirements.txt @@ -0,0 +1 @@ +odoo-addon-product_secondary_unit @ git+https://github.com/OCA/product-attribute.git@refs/pull/2222/head#subdirectory=product_secondary_unit