diff --git a/product_multi_price/README.rst b/product_multi_price/README.rst new file mode 100644 index 00000000000..65a3670e3ff --- /dev/null +++ b/product_multi_price/README.rst @@ -0,0 +1,122 @@ +=================== +Product Multi Price +=================== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:6fcd6b64546a1765154233271fd0d6c6dab2f26e5dd3548f51d94b363acd2d25 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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--attribute-lightgray.png?logo=github + :target: https://github.com/OCA/product-attribute/tree/16.0/product_multi_price + :alt: OCA/product-attribute +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/product-attribute-16-0/product-attribute-16-0-product_multi_price + :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-attribute&target_branch=16.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module allows to set multiple prices to products and base pricelist +rules on them. + +**Table of contents** + +.. contents:: + :local: + +Configuration +============= + +To configure multiple prices you need to set multi prices field names first. +To do so, you need admin permissions. Then go to: + +#. *Settings > Technical > Database Structure > Price Field Names* +#. Create the multi price fields you need. + +If you have multiple companies, you can assign independent field sets for each +one. + +Note: 'Show multi prices' access group must be checked to be able to +add multiple prices in the product form view. + +Usage +===== + +To use this module, you need to: + +#. Go to the product page. +#. In the general tab, there's a list called *Other Prices*. +#. You can add one for every price name available. + +To base pricelist rules on that fields, in the pricelist: + +#. Add a rule and choose *formula* as the computing method. +#. In the *Based on* dropdown list, select *Other Price*. +#. A new list appear: *Other Price Name*. Pick the one you need. +#. Configure the formula. +#. Now the rule is based on that price for the products that have it + configured. Otherwise, it will return 0. + +Known issues / Roadmap +====================== + +* Add mechanisms that allow to set multiprices values from external flows. For + example: having AVCO, FIFO and Standard prices computed simultaneously in + this table. + +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 +* Heliconia Solutions + +Contributors +~~~~~~~~~~~~ + +* `Tecnativa `_ + + * David Vidal + * Pedro M. Baeza + * Ernesto Tejeda + +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/product-attribute `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/product_multi_price/__init__.py b/product_multi_price/__init__.py new file mode 100644 index 00000000000..cc6b6354ad8 --- /dev/null +++ b/product_multi_price/__init__.py @@ -0,0 +1,2 @@ +from . import models +from .hooks import post_init_hook diff --git a/product_multi_price/__manifest__.py b/product_multi_price/__manifest__.py new file mode 100644 index 00000000000..1254354603c --- /dev/null +++ b/product_multi_price/__manifest__.py @@ -0,0 +1,23 @@ +# Copyright 2020 Tecnativa - David Vidal +# Copyright 2020 Tecnativa - Pedro M. Baeza +# Copyright 2024 Heliconia Solutions +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +{ + "name": "Product Multi Price", + "version": "16.0.1.0.0", + "author": "Tecnativa," "Heliconia Solutions, " "Odoo Community Association (OCA)", + "website": "https://github.com/OCA/product-attribute", + "category": "Product Management", + "license": "AGPL-3", + "depends": ["product"], + "data": [ + "security/ir.model.access.csv", + "security/multi_price_security.xml", + "views/multi_price_views.xml", + "views/product_pricelist_views.xml", + "views/product_views.xml", + ], + "demo": ["demo/multi_price_demo_data.xml"], + "post_init_hook": "post_init_hook", + "installable": True, +} diff --git a/product_multi_price/demo/multi_price_demo_data.xml b/product_multi_price/demo/multi_price_demo_data.xml new file mode 100644 index 00000000000..9d9efab5fde --- /dev/null +++ b/product_multi_price/demo/multi_price_demo_data.xml @@ -0,0 +1,7 @@ + + + + price_1 + + + diff --git a/product_multi_price/hooks.py b/product_multi_price/hooks.py new file mode 100644 index 00000000000..c65f8560c4e --- /dev/null +++ b/product_multi_price/hooks.py @@ -0,0 +1,15 @@ +# Copyright 2020 Tecnativa - Ernesto Tejeda +# Copyright 2024 Heliconia Solutions +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import SUPERUSER_ID, Command, api + + +def post_init_hook(cr, registry): + env = api.Environment(cr, SUPERUSER_ID, {}) + group_id = env.ref("product_multi_price.group_show_multi_prices").id + default_user = env.ref("base.default_user") + user = ( + env["res.users"].with_context(active_test=False).search([("share", "=", False)]) + ) + (user - default_user).write({"groups_id": [Command.link(group_id)]}) diff --git a/product_multi_price/i18n/ca.po b/product_multi_price/i18n/ca.po new file mode 100644 index 00000000000..74a25dafc3f --- /dev/null +++ b/product_multi_price/i18n/ca.po @@ -0,0 +1,181 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * product_multi_price +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 13.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2021-02-23 18:45+0000\n" +"Last-Translator: claudiagn \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: product_multi_price +#: model:ir.model.constraint,message:product_multi_price.constraint_product_multi_price_multi_price_uniq +msgid "" +"A field name cannot be assigned to a product twice for the same company" +msgstr "" +"No es pot assignar un nom de camp a un producte dues vegades per a la " +"mateixa empresa" + +#. module: product_multi_price +#: model:ir.model.fields,help:product_multi_price.field_product_pricelist_item__base +msgid "" +"Base price for computation.\n" +"Sales Price: The base price will be the Sales Price.\n" +"Cost Price : The base price will be the cost price.\n" +"Other Pricelist : Computation of the base price based on another Pricelist." +msgstr "" +"Preu base de càlcul.\n" +"Preu de venda: el preu base serà el preu de venda.\n" +"Preu de cost: el preu base serà el preu de cost.\n" +"Una altra llista de preus: càlcul del preu base basat en una altra llista de " +"preus." + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_pricelist_item__base +msgid "Based on" +msgstr "Basat en" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__company_id +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price_name__company_id +msgid "Company" +msgstr "Companyia" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__create_uid +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price_name__create_uid +msgid "Created by" +msgstr "Creat per" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__create_date +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price_name__create_date +msgid "Created on" +msgstr "Creat el" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__display_name +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price_name__display_name +msgid "Display Name" +msgstr "Nom visible" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__id +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price_name__id +msgid "ID" +msgstr "ID" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price____last_update +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price_name____last_update +msgid "Last Modified on" +msgstr "Darrera modificació el" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__write_uid +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price_name__write_uid +msgid "Last Updated by" +msgstr "Darrera actualització per" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__write_date +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price_name__write_date +msgid "Last Updated on" +msgstr "Darrera actualització el" + +#. module: product_multi_price +#: model:ir.model,name:product_multi_price.model_product_multi_price_name +msgid "Multi Price Record Options" +msgstr "Opcions de registre de preus múltiples" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__name +msgid "Name" +msgstr "Nom" + +#. module: product_multi_price +#: model:ir.model.fields.selection,name:product_multi_price.selection__product_pricelist_item__base__multi_price +msgid "Other Price" +msgstr "Altre preu" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_pricelist_item__multi_price_name +msgid "Other Price Name" +msgstr "Nom de l'altre preu" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_product__price_ids +#: model:ir.model.fields,field_description:product_multi_price.field_product_template__price_ids +msgid "Other Prices" +msgstr "Altres preus" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__price +msgid "Price" +msgstr "Preu" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price_name__name +msgid "Price Field Name" +msgstr "Nom del camp del preu" + +#. module: product_multi_price +#: model:ir.actions.act_window,name:product_multi_price.action_multi_price_name_config +#: model:ir.ui.menu,name:product_multi_price.multi_price_name_menu +msgid "Price Field Names" +msgstr "Noms de camps de preus" + +#. module: product_multi_price +#: model:ir.model,name:product_multi_price.model_product_pricelist +msgid "Pricelist" +msgstr "Tarifa" + +#. module: product_multi_price +#: model:ir.model,name:product_multi_price.model_product_pricelist_item +msgid "Pricelist Rule" +msgstr "Regla de tarifa" + +#. module: product_multi_price +#: model:ir.model.constraint,message:product_multi_price.constraint_product_multi_price_name_multi_price_name_uniq +msgid "Prices Names must be unique per company" +msgstr "Els noms dels preus han de ser únics per empresa" + +#. module: product_multi_price +#: model:ir.model,name:product_multi_price.model_product_product +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__product_id +msgid "Product" +msgstr "Producte" + +#. module: product_multi_price +#: model_terms:ir.ui.view,arch_db:product_multi_price.product_multi_price_form_view +#: model_terms:ir.ui.view,arch_db:product_multi_price.product_multi_price_tree_view +msgid "Product Multi Price" +msgstr "Preu múltiple de producte" + +#. module: product_multi_price +#: model_terms:ir.ui.view,arch_db:product_multi_price.product_multi_price_name_tree_view +msgid "Product Multi Price Field Name" +msgstr "Nom del camp del preu múltiple del producte" + +#. module: product_multi_price +#: model:ir.model,name:product_multi_price.model_product_multi_price +msgid "Product Multiple Prices" +msgstr "Preus múltiples de productes" + +#. module: product_multi_price +#: model:ir.model,name:product_multi_price.model_product_template +msgid "Product Template" +msgstr "Plantilla de producte" + +#. module: product_multi_price +#: model:res.groups,name:product_multi_price.group_show_multi_prices +msgid "Show multi prices" +msgstr "Mostra preus múltiples" diff --git a/product_multi_price/i18n/de.po b/product_multi_price/i18n/de.po new file mode 100644 index 00000000000..db6b551400c --- /dev/null +++ b/product_multi_price/i18n/de.po @@ -0,0 +1,69 @@ +msgid "" +msgstr "" +"Project-Id-Version: ametras-xsolutions\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: \n" +"Language-Team: German\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-Crowdin-Project: ametras-xsolutions\n" +"X-Crowdin-Project-ID: 530964\n" +"X-Crowdin-Language: de\n" +"X-Crowdin-File: /[AmetrasIntelligence.oca-migrated] 16.0/product_multi_price/i18n/product_multi_price.pot\n" +"X-Crowdin-File-ID: 21390\n" +"Language: de_DE\n" +"PO-Revision-Date: 2024-09-25 12:08\n" + +#. module: product_multi_price +#: model:ir.model.constraint,message:product_multi_price.constraint_product_multi_price_multi_price_uniq +msgid "A field name cannot be assigned to a product twice for the same company" +msgstr "" + +#. module: product_multi_price +#: model:ir.model,name:product_multi_price.model_product_multi_price_name +msgid "Multi Price Record Options" +msgstr "" + +#. module: product_multi_price +#: model:ir.actions.act_window,name:product_multi_price.action_multi_price_name_config +#: model:ir.ui.menu,name:product_multi_price.multi_price_name_menu +msgid "Price Field Names" +msgstr "" + +#. module: product_multi_price +#: model:ir.model,name:product_multi_price.model_product_pricelist_item +msgid "Pricelist Rule" +msgstr "" + +#. module: product_multi_price +#: model:ir.model.constraint,message:product_multi_price.constraint_product_multi_price_name_multi_price_name_uniq +msgid "Prices Names must be unique per company" +msgstr "" + +#. module: product_multi_price +#: model:ir.model,name:product_multi_price.model_product_template +msgid "Product" +msgstr "" + +#. module: product_multi_price +#: model_terms:ir.ui.view,arch_db:product_multi_price.product_multi_price_form_view +msgid "Product Multi Price" +msgstr "" + +#. module: product_multi_price +#: model:ir.model,name:product_multi_price.model_product_multi_price +msgid "Product Multiple Prices" +msgstr "" + +#. module: product_multi_price +#: model:ir.model,name:product_multi_price.model_product_product +msgid "Product Variant" +msgstr "" + +#. module: product_multi_price +#: model:res.groups,name:product_multi_price.group_show_multi_prices +msgid "Show multi prices" +msgstr "" + diff --git a/product_multi_price/i18n/es.po b/product_multi_price/i18n/es.po new file mode 100644 index 00000000000..94e82d2b45e --- /dev/null +++ b/product_multi_price/i18n/es.po @@ -0,0 +1,200 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * product_multi_price +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 13.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2020-04-09 08:52+0000\n" +"PO-Revision-Date: 2021-02-23 18:45+0000\n" +"Last-Translator: claudiagn \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.3.2\n" + +#. module: product_multi_price +#: model:ir.model.constraint,message:product_multi_price.constraint_product_multi_price_multi_price_uniq +msgid "A field name cannot be assigned to a product twice for the same company" +msgstr "No puede haber un nombre de campo repetido en la misma compañía" + +#. module: product_multi_price +#: model:ir.model.fields,help:product_multi_price.field_product_pricelist_item__base +msgid "" +"Base price for computation.\n" +"Sales Price: The base price will be the Sales Price.\n" +"Cost Price : The base price will be the cost price.\n" +"Other Pricelist : Computation of the base price based on another Pricelist." +msgstr "" +"Precio base de cálculo.\n" +"Precio de venta: el precio base será el precio de venta.\n" +"Precio de costo: el precio base será el precio de costo.\n" +"Otra lista de precios: cálculo del precio base basado en otra lista de " +"precios." + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_pricelist_item__base +msgid "Based on" +msgstr "Basado en" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__company_id +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price_name__company_id +msgid "Company" +msgstr "Compañía" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__create_uid +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price_name__create_uid +msgid "Created by" +msgstr "Creado por" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__create_date +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price_name__create_date +msgid "Created on" +msgstr "Creado en" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__display_name +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price_name__display_name +msgid "Display Name" +msgstr "Nombre mostrado" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__id +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price_name__id +msgid "ID" +msgstr "ID" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price____last_update +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price_name____last_update +msgid "Last Modified on" +msgstr "Última modificación en" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__write_uid +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price_name__write_uid +msgid "Last Updated by" +msgstr "Última actualización de" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__write_date +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price_name__write_date +msgid "Last Updated on" +msgstr "Última actualización en" + +#. module: product_multi_price +#: model:ir.model,name:product_multi_price.model_product_multi_price_name +msgid "Multi Price Record Options" +msgstr "Opciones de registro de precios múltiples" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__name +msgid "Name" +msgstr "Nombre" + +#. module: product_multi_price +#: model:ir.model.fields.selection,name:product_multi_price.selection__product_pricelist_item__base__multi_price +msgid "Other Price" +msgstr "Otro precio" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_pricelist_item__multi_price_name +msgid "Other Price Name" +msgstr "Nombre del otro precio" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_product__price_ids +#: model:ir.model.fields,field_description:product_multi_price.field_product_template__price_ids +msgid "Other Prices" +msgstr "Otros precios" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__price +msgid "Price" +msgstr "Precio" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price_name__name +msgid "Price Field Name" +msgstr "Nombre de Campo de Precio" + +#. module: product_multi_price +#: model:ir.actions.act_window,name:product_multi_price.action_multi_price_name_config +#: model:ir.ui.menu,name:product_multi_price.multi_price_name_menu +msgid "Price Field Names" +msgstr "Nombres de Campo de Precio" + +#. module: product_multi_price +#: model:ir.model,name:product_multi_price.model_product_pricelist +msgid "Pricelist" +msgstr "Tarifa" + +#. module: product_multi_price +#: model:ir.model,name:product_multi_price.model_product_pricelist_item +msgid "Pricelist Rule" +msgstr "Regla de tarifa" + +#. module: product_multi_price +#: model:ir.model.constraint,message:product_multi_price.constraint_product_multi_price_name_multi_price_name_uniq +msgid "Prices Names must be unique per company" +msgstr "Los Nombres de Precio deben ser únicos para cada compañía" + +#. module: product_multi_price +#: model:ir.model,name:product_multi_price.model_product_product +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__product_id +msgid "Product" +msgstr "Producto" + +#. module: product_multi_price +#: model_terms:ir.ui.view,arch_db:product_multi_price.product_multi_price_form_view +#: model_terms:ir.ui.view,arch_db:product_multi_price.product_multi_price_tree_view +msgid "Product Multi Price" +msgstr "Multi Precio de Producto" + +#. module: product_multi_price +#: model_terms:ir.ui.view,arch_db:product_multi_price.product_multi_price_name_tree_view +msgid "Product Multi Price Field Name" +msgstr "Nombre de Campo de Multi Precio de Producto" + +#. module: product_multi_price +#: model:ir.model,name:product_multi_price.model_product_multi_price +msgid "Product Multiple Prices" +msgstr "Múltiples Precios de Producto" + +#. module: product_multi_price +#: model:ir.model,name:product_multi_price.model_product_template +msgid "Product Template" +msgstr "Plantilla de producto" + +#. module: product_multi_price +#: model:res.groups,name:product_multi_price.group_show_multi_prices +msgid "Show multi prices" +msgstr "Muestra precios múltiples" + +#~ msgid "Cost" +#~ msgstr "Coste" + +#~ msgid "Cost Price Tax Included" +#~ msgstr "Precio de coste con impuesto incluido" + +#~ msgid "Other Pricelist" +#~ msgstr "Otra tarifa" + +#~ msgid "Partner Prices on the product form" +#~ msgstr "Precios de socios en el formulario de producto" + +#~ msgid "Prices based on supplier info" +#~ msgstr "Precios basados en la información del proveedor" + +#~ msgid "Public Price" +#~ msgstr "Precio público" + +#~ msgid "product.multi.price.name" +#~ msgstr "product.multi.price.name" diff --git a/product_multi_price/i18n/fr.po b/product_multi_price/i18n/fr.po new file mode 100644 index 00000000000..d856b87910d --- /dev/null +++ b/product_multi_price/i18n/fr.po @@ -0,0 +1,69 @@ +msgid "" +msgstr "" +"Project-Id-Version: ametras-xsolutions\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: \n" +"Language-Team: French\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-Crowdin-Project: ametras-xsolutions\n" +"X-Crowdin-Project-ID: 530964\n" +"X-Crowdin-Language: fr\n" +"X-Crowdin-File: /[AmetrasIntelligence.oca-migrated] 16.0/product_multi_price/i18n/product_multi_price.pot\n" +"X-Crowdin-File-ID: 21390\n" +"Language: fr_FR\n" +"PO-Revision-Date: 2024-09-25 12:08\n" + +#. module: product_multi_price +#: model:ir.model.constraint,message:product_multi_price.constraint_product_multi_price_multi_price_uniq +msgid "A field name cannot be assigned to a product twice for the same company" +msgstr "" + +#. module: product_multi_price +#: model:ir.model,name:product_multi_price.model_product_multi_price_name +msgid "Multi Price Record Options" +msgstr "" + +#. module: product_multi_price +#: model:ir.actions.act_window,name:product_multi_price.action_multi_price_name_config +#: model:ir.ui.menu,name:product_multi_price.multi_price_name_menu +msgid "Price Field Names" +msgstr "" + +#. module: product_multi_price +#: model:ir.model,name:product_multi_price.model_product_pricelist_item +msgid "Pricelist Rule" +msgstr "" + +#. module: product_multi_price +#: model:ir.model.constraint,message:product_multi_price.constraint_product_multi_price_name_multi_price_name_uniq +msgid "Prices Names must be unique per company" +msgstr "" + +#. module: product_multi_price +#: model:ir.model,name:product_multi_price.model_product_template +msgid "Product" +msgstr "" + +#. module: product_multi_price +#: model_terms:ir.ui.view,arch_db:product_multi_price.product_multi_price_form_view +msgid "Product Multi Price" +msgstr "" + +#. module: product_multi_price +#: model:ir.model,name:product_multi_price.model_product_multi_price +msgid "Product Multiple Prices" +msgstr "" + +#. module: product_multi_price +#: model:ir.model,name:product_multi_price.model_product_product +msgid "Product Variant" +msgstr "" + +#. module: product_multi_price +#: model:res.groups,name:product_multi_price.group_show_multi_prices +msgid "Show multi prices" +msgstr "" + diff --git a/product_multi_price/i18n/it.po b/product_multi_price/i18n/it.po new file mode 100644 index 00000000000..f9fad1e8609 --- /dev/null +++ b/product_multi_price/i18n/it.po @@ -0,0 +1,198 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * product_multi_price +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 13.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2020-09-22 16:00+0000\n" +"Last-Translator: Lorenzo Battistini \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 3.10\n" + +#. module: product_multi_price +#: model:ir.model.constraint,message:product_multi_price.constraint_product_multi_price_multi_price_uniq +msgid "A field name cannot be assigned to a product twice for the same company" +msgstr "" +"Un nome di campo non può essere assegnato a un prodotto due volte per la " +"stessa azienda" + +#. module: product_multi_price +#: model:ir.model.fields,help:product_multi_price.field_product_pricelist_item__base +#, fuzzy +msgid "" +"Base price for computation.\n" +"Sales Price: The base price will be the Sales Price.\n" +"Cost Price : The base price will be the cost price.\n" +"Other Pricelist : Computation of the base price based on another Pricelist." +msgstr "" +"Prezzo di base per il calcolo.\n" +"Prezzo pubblico: il prezzo di base sarà il prezzo di vendita/prezzo " +"pubblico.\n" +"Prezzo di costo : il prezzo di base sarà il prezzo di costo.\n" +"Altro listino prezzi : calcolo del prezzo di base sulla base di un altro " +"listino prezzi." + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_pricelist_item__base +msgid "Based on" +msgstr "Basato su" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__company_id +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price_name__company_id +msgid "Company" +msgstr "Azienda" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__create_uid +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price_name__create_uid +msgid "Created by" +msgstr "" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__create_date +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price_name__create_date +msgid "Created on" +msgstr "" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__display_name +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price_name__display_name +msgid "Display Name" +msgstr "Nome visualizzato" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__id +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price_name__id +msgid "ID" +msgstr "" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price____last_update +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price_name____last_update +msgid "Last Modified on" +msgstr "" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__write_uid +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price_name__write_uid +msgid "Last Updated by" +msgstr "" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__write_date +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price_name__write_date +msgid "Last Updated on" +msgstr "" + +#. module: product_multi_price +#: model:ir.model,name:product_multi_price.model_product_multi_price_name +msgid "Multi Price Record Options" +msgstr "" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__name +msgid "Name" +msgstr "Nome" + +#. module: product_multi_price +#: model:ir.model.fields.selection,name:product_multi_price.selection__product_pricelist_item__base__multi_price +msgid "Other Price" +msgstr "Altro prezzo" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_pricelist_item__multi_price_name +msgid "Other Price Name" +msgstr "Nome altro prezzo" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_product__price_ids +#: model:ir.model.fields,field_description:product_multi_price.field_product_template__price_ids +msgid "Other Prices" +msgstr "Altri prezzi" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__price +msgid "Price" +msgstr "Prezzo" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price_name__name +msgid "Price Field Name" +msgstr "Nome campo prezzo" + +#. module: product_multi_price +#: model:ir.actions.act_window,name:product_multi_price.action_multi_price_name_config +#: model:ir.ui.menu,name:product_multi_price.multi_price_name_menu +msgid "Price Field Names" +msgstr "Nomi campi prezzo" + +#. module: product_multi_price +#: model:ir.model,name:product_multi_price.model_product_pricelist +msgid "Pricelist" +msgstr "Listino" + +#. module: product_multi_price +#: model:ir.model,name:product_multi_price.model_product_pricelist_item +#, fuzzy +msgid "Pricelist Rule" +msgstr "Articolo di listino" + +#. module: product_multi_price +#: model:ir.model.constraint,message:product_multi_price.constraint_product_multi_price_name_multi_price_name_uniq +msgid "Prices Names must be unique per company" +msgstr "I nomi dei prezzi devono essere unici per azienda" + +#. module: product_multi_price +#: model:ir.model,name:product_multi_price.model_product_product +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__product_id +msgid "Product" +msgstr "Prodotto" + +#. module: product_multi_price +#: model_terms:ir.ui.view,arch_db:product_multi_price.product_multi_price_form_view +#: model_terms:ir.ui.view,arch_db:product_multi_price.product_multi_price_tree_view +msgid "Product Multi Price" +msgstr "Prezzi multipli prodotto" + +#. module: product_multi_price +#: model_terms:ir.ui.view,arch_db:product_multi_price.product_multi_price_name_tree_view +msgid "Product Multi Price Field Name" +msgstr "" + +#. module: product_multi_price +#: model:ir.model,name:product_multi_price.model_product_multi_price +msgid "Product Multiple Prices" +msgstr "Prezzi multipli prodotto" + +#. module: product_multi_price +#: model:ir.model,name:product_multi_price.model_product_template +msgid "Product Template" +msgstr "Modello prodotto" + +#. module: product_multi_price +#: model:res.groups,name:product_multi_price.group_show_multi_prices +msgid "Show multi prices" +msgstr "Mostrare prezzi multipli" + +#~ msgid "Cost" +#~ msgstr "Costo" + +#~ msgid "Cost Price Tax Included" +#~ msgstr "Prezzo di costo imposte incluse" + +#~ msgid "Other Pricelist" +#~ msgstr "Altro listino" + +#~ msgid "Prices based on supplier info" +#~ msgstr "Prezzi basati sulle informazioni del fornitore" + +#~ msgid "Public Price" +#~ msgstr "Prezzo al pubblico" diff --git a/product_multi_price/i18n/product_multi_price.pot b/product_multi_price/i18n/product_multi_price.pot new file mode 100644 index 00000000000..7ce227585ae --- /dev/null +++ b/product_multi_price/i18n/product_multi_price.pot @@ -0,0 +1,66 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * product_multi_price +# +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: product_multi_price +#: model:ir.model.constraint,message:product_multi_price.constraint_product_multi_price_multi_price_uniq +msgid "" +"A field name cannot be assigned to a product twice for the same company" +msgstr "" + +#. module: product_multi_price +#: model:ir.model,name:product_multi_price.model_product_multi_price_name +msgid "Multi Price Record Options" +msgstr "" + +#. module: product_multi_price +#: model:ir.actions.act_window,name:product_multi_price.action_multi_price_name_config +#: model:ir.ui.menu,name:product_multi_price.multi_price_name_menu +msgid "Price Field Names" +msgstr "" + +#. module: product_multi_price +#: model:ir.model,name:product_multi_price.model_product_pricelist_item +msgid "Pricelist Rule" +msgstr "" + +#. module: product_multi_price +#: model:ir.model.constraint,message:product_multi_price.constraint_product_multi_price_name_multi_price_name_uniq +msgid "Prices Names must be unique per company" +msgstr "" + +#. module: product_multi_price +#: model:ir.model,name:product_multi_price.model_product_template +msgid "Product" +msgstr "" + +#. module: product_multi_price +#: model_terms:ir.ui.view,arch_db:product_multi_price.product_multi_price_form_view +msgid "Product Multi Price" +msgstr "" + +#. module: product_multi_price +#: model:ir.model,name:product_multi_price.model_product_multi_price +msgid "Product Multiple Prices" +msgstr "" + +#. module: product_multi_price +#: model:ir.model,name:product_multi_price.model_product_product +msgid "Product Variant" +msgstr "" + +#. module: product_multi_price +#: model:res.groups,name:product_multi_price.group_show_multi_prices +msgid "Show multi prices" +msgstr "" diff --git a/product_multi_price/models/__init__.py b/product_multi_price/models/__init__.py new file mode 100644 index 00000000000..b0fa0aa6da9 --- /dev/null +++ b/product_multi_price/models/__init__.py @@ -0,0 +1,4 @@ +from . import product_multi_price +from . import product_pricelist +from . import product_product +from . import product_template diff --git a/product_multi_price/models/product_multi_price.py b/product_multi_price/models/product_multi_price.py new file mode 100644 index 00000000000..d6e9eeae6a9 --- /dev/null +++ b/product_multi_price/models/product_multi_price.py @@ -0,0 +1,62 @@ +# Copyright 2020 Tecnativa - David Vidal +# Copyright 2024 Heliconia Solutions +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from odoo import api, fields, models + + +class ProductMultiPrice(models.Model): + _name = "product.multi.price" + _description = "Product Multiple Prices" + + name = fields.Many2one( + comodel_name="product.multi.price.name", + required=True, + index=True, + ) + product_id = fields.Many2one( + comodel_name="product.product", required=True, ondelete="cascade", index=True + ) + price = fields.Float( + digits="Product Price", + ) + company_id = fields.Many2one( + comodel_name="res.company", + related="name.company_id", + store=True, + readonly=True, + index=True, + ) + + _sql_constraints = [ + ( + "multi_price_uniq", + "unique(name, product_id, company_id)", + "A field name cannot be assigned to a product twice for the same " + "company", + ), + ] + + +class ProductMultiPriceName(models.Model): + _name = "product.multi.price.name" + _description = "Multi Price Record Options" + + @api.model + def _get_company(self): + return self._context.get("company_id", self.env.company) + + name = fields.Char(required=True, string="Price Field Name") + company_id = fields.Many2one( + comodel_name="res.company", + required=True, + default=lambda self: self._get_company(), + index=True, + ) + + _sql_constraints = [ + ( + "multi_price_name_uniq", + "unique(name, company_id)", + "Prices Names must be unique per company", + ), + ] diff --git a/product_multi_price/models/product_pricelist.py b/product_multi_price/models/product_pricelist.py new file mode 100644 index 00000000000..51bb48beebb --- /dev/null +++ b/product_multi_price/models/product_pricelist.py @@ -0,0 +1,28 @@ +# Copyright 2020 Tecnativa - David Vidal +# Copyright 2024 Heliconia Solutions +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from odoo import fields, models + + +class ProductPricelistItem(models.Model): + _inherit = "product.pricelist.item" + + base = fields.Selection( + selection_add=[("multi_price", "Other Price")], + ondelete={"multi_price": "set default"}, + ) + multi_price_name = fields.Many2one( + comodel_name="product.multi.price.name", + string="Other Price Name", + ) + + def _compute_price(self, product, quantity, uom, date, currency=None): + result = super()._compute_price(product, quantity, uom, date, currency) + is_reprice = self.env.context.get("is_reprice", False) + if ( + self.compute_price == "formula" + and self.base == "multi_price" + and not is_reprice + ): + result = product.sudo()._get_multiprice_pricelist_price(self) + return result diff --git a/product_multi_price/models/product_product.py b/product_multi_price/models/product_product.py new file mode 100644 index 00000000000..8b993310f4f --- /dev/null +++ b/product_multi_price/models/product_product.py @@ -0,0 +1,74 @@ +# Copyright 2024 Heliconia Solutions +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from odoo import api, fields, models, tools + + +class ProductProduct(models.Model): + _inherit = "product.product" + + price_ids = fields.One2many( + comodel_name="product.multi.price", + inverse_name="product_id", + string="Other Prices", + index=True, + ) + + def _convert_to_price_uom(self, price): + qty_uom_id = self._context.get("uom") or self.uom_id.id + price_uom = self.env["uom.uom"].browse([qty_uom_id]) + return self.uom_id._compute_price(price, price_uom) + + def _get_multiprice_pricelist_price(self, rule): + """Method for getting the price from multi price.""" + self.ensure_one() + company = rule.company_id or self.env.user.company_id + price = ( + self.env["product.multi.price"] + .sudo() + .search( + [ + ("company_id", "=", company.id), + ("name", "=", rule.multi_price_name.id), + ("product_id", "=", self.id), + ] + ) + .price + or 0 + ) + if price: + # We have to replicate this logic in this method as pricelist + # method are atomic and we can't hack inside. + # Verbatim copy of part of product.pricelist._compute_price_rule. + price_limit = price + price = (price - (price * (rule.price_discount / 100))) or 0.0 + if rule.price_round: + price = tools.float_round(price, precision_rounding=rule.price_round) + if rule.price_surcharge: + price_surcharge = self._convert_to_price_uom(rule.price_surcharge) + price += price_surcharge + if rule.price_min_margin: + price_min_margin = self._convert_to_price_uom(rule.price_min_margin) + price = max(price, price_limit + price_min_margin) + if rule.price_max_margin: + price_max_margin = self._convert_to_price_uom(rule.price_max_margin) + price = min(price, price_limit + price_max_margin) + return price + + def price_compute( + self, price_type, uom=None, currency=None, company=None, date=False + ): + """Return temporary prices when computation is done for multi price for + avoiding error on super method. We will later fill these with the + correct values. + """ + if price_type == "multi_price": + return dict.fromkeys(self.ids, 1.0) + return super().price_compute( + price_type, uom=uom, currency=currency, company=company, date=date + ) + + @api.model + def get_views(self, views, options=None): + if self.user_has_groups("product_multi_price.group_show_multi_prices"): + self = self.with_context(group_show_multi_prices=True) + return super(ProductProduct, self).get_views(views, options) diff --git a/product_multi_price/models/product_template.py b/product_multi_price/models/product_template.py new file mode 100644 index 00000000000..c4377146a55 --- /dev/null +++ b/product_multi_price/models/product_template.py @@ -0,0 +1,62 @@ +# Copyright 2020 Tecnativa - David Vidal +# Copyright 2024 Heliconia Solutions +# 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" + + price_ids = fields.One2many( + comodel_name="product.multi.price", + compute="_compute_price_ids", + inverse="_inverse_price_ids", + string="Other Prices", + ) + + @api.depends("product_variant_ids", "product_variant_ids.price_ids") + def _compute_price_ids(self): + for p in self: + if len(p.product_variant_ids) == 1: + p.price_ids = p.product_variant_ids.price_ids + else: + p.price_ids = False + + def _inverse_price_ids(self): + for p in self: + if len(p.product_variant_ids) == 1: + p.product_variant_ids.price_ids = p.price_ids + + def _get_multiprice_pricelist_price(self, rule): + if len(self.product_variant_ids) == 1: + return self.product_variant_ids._get_multiprice_pricelist_price(rule) + return 0 + + @api.model + def create(self, vals): + """Overwrite creation for rewriting the prices (if set and having only + one variant), after the variant creation, that is performed in super. + """ + template = super().create(vals) + if vals.get("price_ids"): + template.write({"price_ids": vals.get("price_ids")}) + return template + + def price_compute( + self, price_type, uom=None, currency=None, company=None, date=False + ): + """Return temporary prices when computation is done for multi price for + avoiding error on super method. We will later fill these with the + correct values. + """ + if price_type == "multi_price": + return dict.fromkeys(self.ids, 1.0) + return super().price_compute( + price_type, uom=uom, currency=currency, company=company, date=date + ) + + @api.model + def get_views(self, views, options=None): + if self.user_has_groups("product_multi_price.group_show_multi_prices"): + self = self.with_context(group_show_multi_prices=True) + return super(ProductTemplate, self).get_views(views, options) diff --git a/product_multi_price/readme/CONFIGURE.rst b/product_multi_price/readme/CONFIGURE.rst new file mode 100644 index 00000000000..b61299a3901 --- /dev/null +++ b/product_multi_price/readme/CONFIGURE.rst @@ -0,0 +1,11 @@ +To configure multiple prices you need to set multi prices field names first. +To do so, you need admin permissions. Then go to: + +#. *Settings > Technical > Database Structure > Price Field Names* +#. Create the multi price fields you need. + +If you have multiple companies, you can assign independent field sets for each +one. + +Note: 'Show multi prices' access group must be checked to be able to +add multiple prices in the product form view. diff --git a/product_multi_price/readme/CONTRIBUTORS.rst b/product_multi_price/readme/CONTRIBUTORS.rst new file mode 100644 index 00000000000..9eb6d6c6984 --- /dev/null +++ b/product_multi_price/readme/CONTRIBUTORS.rst @@ -0,0 +1,5 @@ +* `Tecnativa `_ + + * David Vidal + * Pedro M. Baeza + * Ernesto Tejeda diff --git a/product_multi_price/readme/DESCRIPTION.rst b/product_multi_price/readme/DESCRIPTION.rst new file mode 100644 index 00000000000..c76055a6eb9 --- /dev/null +++ b/product_multi_price/readme/DESCRIPTION.rst @@ -0,0 +1,2 @@ +This module allows to set multiple prices to products and base pricelist +rules on them. diff --git a/product_multi_price/readme/ROADMAP.rst b/product_multi_price/readme/ROADMAP.rst new file mode 100644 index 00000000000..620354d64ab --- /dev/null +++ b/product_multi_price/readme/ROADMAP.rst @@ -0,0 +1,3 @@ +* Add mechanisms that allow to set multiprices values from external flows. For + example: having AVCO, FIFO and Standard prices computed simultaneously in + this table. diff --git a/product_multi_price/readme/USAGE.rst b/product_multi_price/readme/USAGE.rst new file mode 100644 index 00000000000..409ae850807 --- /dev/null +++ b/product_multi_price/readme/USAGE.rst @@ -0,0 +1,14 @@ +To use this module, you need to: + +#. Go to the product page. +#. In the general tab, there's a list called *Other Prices*. +#. You can add one for every price name available. + +To base pricelist rules on that fields, in the pricelist: + +#. Add a rule and choose *formula* as the computing method. +#. In the *Based on* dropdown list, select *Other Price*. +#. A new list appear: *Other Price Name*. Pick the one you need. +#. Configure the formula. +#. Now the rule is based on that price for the products that have it + configured. Otherwise, it will return 0. diff --git a/product_multi_price/security/ir.model.access.csv b/product_multi_price/security/ir.model.access.csv new file mode 100644 index 00000000000..603077c94d3 --- /dev/null +++ b/product_multi_price/security/ir.model.access.csv @@ -0,0 +1,4 @@ +"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink" +multi_price,product.multi.price,model_product_multi_price,base.group_user,1,1,1,1 +multi_price_name_read,product.multi.price.name,model_product_multi_price_name,base.group_user,1,0,0,0 +multi_price_name_admin,product.multi.price.name,model_product_multi_price_name,base.group_system,1,1,1,1 diff --git a/product_multi_price/security/multi_price_security.xml b/product_multi_price/security/multi_price_security.xml new file mode 100644 index 00000000000..298cf39d735 --- /dev/null +++ b/product_multi_price/security/multi_price_security.xml @@ -0,0 +1,24 @@ + + + + Show multi prices + + + + + Multiple Price multi-company + + + ['|',('company_id','=',False),('company_id','in',company_ids)] + + + Multiple Price Field Name multi-company + + + ['|',('company_id','=',False),('company_id','in',company_ids)] + + diff --git a/product_multi_price/static/description/icon.png b/product_multi_price/static/description/icon.png new file mode 100644 index 00000000000..3a0328b516c Binary files /dev/null and b/product_multi_price/static/description/icon.png differ diff --git a/product_multi_price/static/description/index.html b/product_multi_price/static/description/index.html new file mode 100644 index 00000000000..be7b75a9d56 --- /dev/null +++ b/product_multi_price/static/description/index.html @@ -0,0 +1,469 @@ + + + + + +Product Multi Price + + + +
+

Product Multi Price

+ + +

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

+

This module allows to set multiple prices to products and base pricelist +rules on them.

+

Table of contents

+ +
+

Configuration

+

To configure multiple prices you need to set multi prices field names first. +To do so, you need admin permissions. Then go to:

+
    +
  1. Settings > Technical > Database Structure > Price Field Names
  2. +
  3. Create the multi price fields you need.
  4. +
+

If you have multiple companies, you can assign independent field sets for each +one.

+

Note: ‘Show multi prices’ access group must be checked to be able to +add multiple prices in the product form view.

+
+
+

Usage

+

To use this module, you need to:

+
    +
  1. Go to the product page.
  2. +
  3. In the general tab, there’s a list called Other Prices.
  4. +
  5. You can add one for every price name available.
  6. +
+

To base pricelist rules on that fields, in the pricelist:

+
    +
  1. Add a rule and choose formula as the computing method.
  2. +
  3. In the Based on dropdown list, select Other Price.
  4. +
  5. A new list appear: Other Price Name. Pick the one you need.
  6. +
  7. Configure the formula.
  8. +
  9. Now the rule is based on that price for the products that have it +configured. Otherwise, it will return 0.
  10. +
+
+
+

Known issues / Roadmap

+
    +
  • Add mechanisms that allow to set multiprices values from external flows. For +example: having AVCO, FIFO and Standard prices computed simultaneously in +this table.
  • +
+
+
+

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
  • +
  • Heliconia Solutions
  • +
+
+
+

Contributors

+
    +
  • Tecnativa
      +
    • David Vidal
    • +
    • Pedro M. Baeza
    • +
    • Ernesto Tejeda
    • +
    +
  • +
+
+
+

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/product-attribute project on GitHub.

+

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

+
+
+
+ + diff --git a/product_multi_price/tests/__init__.py b/product_multi_price/tests/__init__.py new file mode 100644 index 00000000000..03b7c618dfc --- /dev/null +++ b/product_multi_price/tests/__init__.py @@ -0,0 +1 @@ +from . import test_product_multi_price diff --git a/product_multi_price/tests/test_product_multi_price.py b/product_multi_price/tests/test_product_multi_price.py new file mode 100644 index 00000000000..4e97f9dcf2a --- /dev/null +++ b/product_multi_price/tests/test_product_multi_price.py @@ -0,0 +1,98 @@ +# Copyright 2020 Tecnativa - David Vidal +# Copyright 2024 Heliconia Solutions +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from odoo.tests.common import TransactionCase + + +class TestProductMultiPrice(TransactionCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.price_name_obj = cls.env["product.multi.price.name"] + cls.price_field_1 = cls.price_name_obj.create({"name": "test_field_1"}) + cls.price_field_2 = cls.price_name_obj.create({"name": "test_field_2"}) + prod_tmpl_obj = cls.env["product.template"] + cls.prod_1 = prod_tmpl_obj.create( + { + "name": "Test Product Template", + "price_ids": [ + (0, 0, {"name": cls.price_field_1.id, "price": 5.5}), + (0, 0, {"name": cls.price_field_2.id, "price": 20.0}), + ], + } + ) + cls.prod_att_1 = cls.env["product.attribute"].create({"name": "Color"}) + cls.prod_attr1_v1 = cls.env["product.attribute.value"].create( + {"name": "red", "attribute_id": cls.prod_att_1.id} + ) + cls.prod_attr1_v2 = cls.env["product.attribute.value"].create( + {"name": "blue", "attribute_id": cls.prod_att_1.id} + ) + cls.prod_2 = prod_tmpl_obj.create( + { + "name": "Test Product 2 With Variants", + "attribute_line_ids": [ + ( + 0, + 0, + { + "attribute_id": cls.prod_att_1.id, + "value_ids": [ + (6, 0, [cls.prod_attr1_v1.id, cls.prod_attr1_v2.id]) + ], + }, + ) + ], + } + ) + cls.prod_prod_2_1 = cls.prod_2.product_variant_ids[0] + cls.prod_prod_2_2 = cls.prod_2.product_variant_ids[1] + cls.prod_prod_2_1.write( + { + "price_ids": [ + (0, 0, {"name": cls.price_field_1.id, "price": 6.6}), + (0, 0, {"name": cls.price_field_2.id, "price": 7.7}), + ], + } + ) + cls.prod_prod_2_2.write( + { + "price_ids": [ + (0, 0, {"name": cls.price_field_1.id, "price": 8.8}), + (0, 0, {"name": cls.price_field_2.id, "price": 9.9}), + ], + } + ) + cls.pricelist = cls.env["product.pricelist"].create( + { + "name": "Test pricelist", + "item_ids": [ + ( + 0, + 0, + { + "compute_price": "formula", + "base": "multi_price", + "multi_price_name": cls.price_field_1.id, + "price_discount": 10, + "applied_on": "3_global", + }, + ) + ], + } + ) + + def test_product_multi_price_pricelist(self): + """Pricelists based on multi prices for templates or variants""" + price = self.pricelist.with_context( + pricelist=self.pricelist.id + )._get_products_price(self.prod_1, 1) + self.assertAlmostEqual(price.get(self.prod_1.id), 4.95) + price = self.pricelist.with_context( + pricelist=self.pricelist.id + )._get_products_price(self.prod_prod_2_1, 1) + self.assertAlmostEqual(price.get(self.prod_prod_2_1.id), 5.94) + price = self.pricelist.with_context( + pricelist=self.pricelist.id + )._get_products_price(self.prod_prod_2_2, 1) + self.assertAlmostEqual(price.get(self.prod_prod_2_2.id), 7.92) diff --git a/product_multi_price/views/multi_price_views.xml b/product_multi_price/views/multi_price_views.xml new file mode 100644 index 00000000000..7d68a76b684 --- /dev/null +++ b/product_multi_price/views/multi_price_views.xml @@ -0,0 +1,74 @@ + + + + product.multi.price + + + + + + + + + + + product.multi.price + +
+ + + + + + + + +
+
+
+ + product.multi.price + primary + + + + + 1 + + + bottom + + + + + product.multi.price.name + + + + + + + + + Price Field Names + product.multi.price.name + {} + + + +
diff --git a/product_multi_price/views/product_pricelist_views.xml b/product_multi_price/views/product_pricelist_views.xml new file mode 100644 index 00000000000..5f23f517bfa --- /dev/null +++ b/product_multi_price/views/product_pricelist_views.xml @@ -0,0 +1,16 @@ + + + + product.pricelist.item + + + + + + + + diff --git a/product_multi_price/views/product_views.xml b/product_multi_price/views/product_views.xml new file mode 100644 index 00000000000..3e40a92c5fc --- /dev/null +++ b/product_multi_price/views/product_views.xml @@ -0,0 +1,32 @@ + + + + product.template + + + + + + + + + product.product + + + + + + + + diff --git a/setup/product_multi_price/odoo/addons/product_multi_price b/setup/product_multi_price/odoo/addons/product_multi_price new file mode 120000 index 00000000000..95451253888 --- /dev/null +++ b/setup/product_multi_price/odoo/addons/product_multi_price @@ -0,0 +1 @@ +../../../../product_multi_price \ No newline at end of file diff --git a/setup/product_multi_price/setup.py b/setup/product_multi_price/setup.py new file mode 100644 index 00000000000..28c57bb6403 --- /dev/null +++ b/setup/product_multi_price/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +)