diff --git a/product_pricelist_supplierinfo/README.rst b/product_pricelist_supplierinfo/README.rst new file mode 100644 index 00000000000..556ebd5dbe9 --- /dev/null +++ b/product_pricelist_supplierinfo/README.rst @@ -0,0 +1,157 @@ +======================================== +Supplier info prices in sales pricelists +======================================== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:e6539df59b27f0932ee4afb66ee75503be8c81c9ec41fd11623a5abcfca59e9c + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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/17.0/product_pricelist_supplierinfo + :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-17-0/product-attribute-17-0-product_pricelist_supplierinfo + :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=17.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module allows you to create a sales pricelist based on product +supplierinfo prices. If you want, you can bypass minimum quantity in +pricelist item. + +We can also define sale marging applied on purchase price directly on +supplier info. For this, you must add users to "Show sale margin on +Product Supplierinfo" group. + +**Table of contents** + +.. contents:: + :local: + +Installation +============ + +Although this module doesn't depend technically on **Sales Management**, +you must install it for configuring and seeing the effects of it. + +Configuration +============= + +To configure pricelists with the new feature of this module, you need +to: + +1. Go to *Sales > Configuration > Settings* and check "Pricelists" + option and "Advanced price rules (discounts, formulas)" after that. + You must have correct permissions and you must install **Sales + Management** app (sale) and **Purchase** app to see these settings. +2. Create or edit a Sales Pricelist at *Sales > Products > Pricelists*. +3. Add or edit a pricelist item and check "Formula" option in "Price + Computation" section. +4. You will see the new option "Prices based on supplier info". +5. If you want to bypass the "Min.Quantity" field of the supplier info + and always select the lowest quantity price, check the option "Ignore + Supplier Info Min. Quantity". + +Usage +===== + +For adding supplier info: + +1. Go to *Sales > Products > Products* +2. Open or create a product. +3. Go to "Purchase" page. +4. On "Vendors" section, add the supplier and prices. +5. You can drag and drop for reordering these lines. + +Check the remark in known issues about the supplier info line selection. + +For checking pricelists in action, you can (with sale module installed): + +1. Go to *Sales > Orders > Quotations* +2. Create or edit a quotation. +3. Add a line. +4. Select a product with the criteria to match the pricelist from + supplier info. +5. See the proper price appears in the line. + +Known issues / Roadmap +====================== + +- First line that matches by minimum quantity criteria, independently + from the supplier, will be the one that provides the price for the + pricelist. +- There's no mechanism for selecting the supplier from possible sources + like sales orders. + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues <https://github.com/OCA/product-attribute/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 <https://github.com/OCA/product-attribute/issues/new?body=module:%20product_pricelist_supplierinfo%0Aversion:%2017.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +------- + +* Tecnativa +* Vauxoo + +Contributors +------------ + +- `Tecnativa <https://www.tecnativa.com/>`__: + + - Vicent Cubells + - Pedro M. Baeza + - Carlos Roca + +- Nikul Chaudhary <nikulchaudhary2112@gmail.com> +- `TAKOBI <https://takobi.online/>`__: + + - Lorenzo Battistini + +- Andrea Gidalti <andreag@vauxoo.com> + +Maintainers +----------- + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +.. |maintainer-luisg123v| image:: https://github.com/luisg123v.png?size=40px + :target: https://github.com/luisg123v + :alt: luisg123v + +Current `maintainer <https://odoo-community.org/page/maintainer-role>`__: + +|maintainer-luisg123v| + +This module is part of the `OCA/product-attribute <https://github.com/OCA/product-attribute/tree/17.0/product_pricelist_supplierinfo>`_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/product_pricelist_supplierinfo/__init__.py b/product_pricelist_supplierinfo/__init__.py new file mode 100644 index 00000000000..0650744f6bc --- /dev/null +++ b/product_pricelist_supplierinfo/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/product_pricelist_supplierinfo/__manifest__.py b/product_pricelist_supplierinfo/__manifest__.py new file mode 100644 index 00000000000..cf43b8bb15c --- /dev/null +++ b/product_pricelist_supplierinfo/__manifest__.py @@ -0,0 +1,20 @@ +# Copyright 2018 Tecnativa - Vicent Cubells +# Copyright 2018 Tecnativa - Pedro M. Baeza +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +{ + "name": "Supplier info prices in sales pricelists", + "summary": "Allows to create priceslists based on supplier info", + "version": "17.0.1.0.0", + "category": "Sales/Sales", + "website": "https://github.com/OCA/product-attribute", + "author": "Tecnativa, Odoo Community Association (OCA), Vauxoo", + "maintainers": ["luisg123v"], + "license": "AGPL-3", + "depends": ["product"], + "data": [ + "security/res_groups.xml", + "views/product_pricelist_item_views.xml", + "views/product_supplierinfo_view.xml", + ], + "installable": True, +} diff --git a/product_pricelist_supplierinfo/i18n/ca.po b/product_pricelist_supplierinfo/i18n/ca.po new file mode 100644 index 00000000000..d91135d1d7b --- /dev/null +++ b/product_pricelist_supplierinfo/i18n/ca.po @@ -0,0 +1,138 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * product_pricelist_supplierinfo +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2021-02-15 17:45+0000\n" +"Last-Translator: claudiagn <claudia.gargallo@qubiq.es>\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_pricelist_supplierinfo +#: model:ir.model.fields,help:product_pricelist_supplierinfo.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 "" + +#. module: product_pricelist_supplierinfo +#: model:ir.model.fields,field_description:product_pricelist_supplierinfo.field_product_pricelist_item__base +msgid "Based on" +msgstr "Basat en" + +#. module: product_pricelist_supplierinfo +#: model:ir.model.fields,field_description:product_pricelist_supplierinfo.field_product_pricelist_item__no_supplierinfo_min_quantity +msgid "Ignore Supplier Info Min. Quantity" +msgstr "Ignora la informació del proveïdor Min. Quantitat" + +#. module: product_pricelist_supplierinfo +#: model:ir.model.fields,help:product_pricelist_supplierinfo.field_product_supplierinfo__sale_margin +msgid "Margin to apply on price to obtain sale price" +msgstr "Marge a aplicar sobre el preu per obtenir el preu de venda" + +#. module: product_pricelist_supplierinfo +#: model:ir.model.fields,help:product_pricelist_supplierinfo.field_product_pricelist_item__filter_supplier_id +msgid "Only match prices from the selected supplier" +msgstr "Coincideix només amb els preus del proveïdor seleccionat" + +#. module: product_pricelist_supplierinfo +#: model:ir.model,name:product_pricelist_supplierinfo.model_product_pricelist_item +msgid "Pricelist Rule" +msgstr "" + +#. module: product_pricelist_supplierinfo +#: model:ir.model.fields.selection,name:product_pricelist_supplierinfo.selection__product_pricelist_item__base__supplierinfo +msgid "Prices based on supplier info" +msgstr "Preu basat en la informació del proveedor" + +#. module: product_pricelist_supplierinfo +#: model:ir.model,name:product_pricelist_supplierinfo.model_product_template +msgid "Product" +msgstr "Producte" + +#. module: product_pricelist_supplierinfo +#: model:ir.model,name:product_pricelist_supplierinfo.model_product_product +msgid "Product Variant" +msgstr "" + +#. module: product_pricelist_supplierinfo +#: model:ir.model.fields,field_description:product_pricelist_supplierinfo.field_product_supplierinfo__sale_margin +msgid "Sale Margin" +msgstr "Marge de vendes" + +#. module: product_pricelist_supplierinfo +#: model_terms:ir.ui.view,arch_db:product_pricelist_supplierinfo.product_supplierinfo_tree_view +msgid "Sale margin" +msgstr "Marge de venda" + +#. module: product_pricelist_supplierinfo +#: model:res.groups,name:product_pricelist_supplierinfo.group_supplierinfo_pricelist_sale_margin +msgid "Show sale margin on Product Supplierinfo" +msgstr "Mostra el marge de venda a la informació del proveïdor de productes" + +#. module: product_pricelist_supplierinfo +#: model:ir.model,name:product_pricelist_supplierinfo.model_product_supplierinfo +msgid "Supplier Pricelist" +msgstr "Tarifa de proveedor" + +#. module: product_pricelist_supplierinfo +#: model:ir.model.fields,field_description:product_pricelist_supplierinfo.field_product_pricelist_item__filter_supplier_id +msgid "Supplier filter" +msgstr "Filtre de proveïdor" + +#~ msgid "Pricelist" +#~ msgstr "Tarifa" + +#~ msgid "" +#~ "<span attrs=\"{'invisible':[('base', '!=', 'supplierinfo')]}\">Supplier " +#~ "price - </span>" +#~ msgstr "" +#~ "<span attrs=\"{'invisible':[('base', '!=', 'supplierinfo')]}\">Preu de " +#~ "proveïdor - </span>" + +#~ msgid "" +#~ "Base price for computation.\n" +#~ "Public Price: The base price will be the Sale/public 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 públic: el preu base serà el preu de venda / públic.\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." + +#~ msgid "Cost" +#~ msgstr "Cost" + +#~ msgid "Cost Price Tax Included" +#~ msgstr "Preu de cost impost inclòs" + +#~ msgid "Other Price" +#~ msgstr "Altre preu" + +#~ msgid "Other Pricelist" +#~ msgstr "Altra tarifa" + +#~ msgid "Partner Prices on the product form" +#~ msgstr "Preus de soci al formulari de producte" + +#~ msgid "Pricelist Item" +#~ msgstr "Element de tarifa" + +#~ msgid "Product Template" +#~ msgstr "Plantilla de producte" + +#~ msgid "Public Price" +#~ msgstr "Preu públic" diff --git a/product_pricelist_supplierinfo/i18n/es.po b/product_pricelist_supplierinfo/i18n/es.po new file mode 100644 index 00000000000..555d40852a4 --- /dev/null +++ b/product_pricelist_supplierinfo/i18n/es.po @@ -0,0 +1,145 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * product_pricelist_supplierinfo +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 11.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-10-31 17:35+0000\n" +"PO-Revision-Date: 2023-08-29 08:30+0000\n" +"Last-Translator: Ivorra78 <informatica@totmaterial.es>\n" +"Language-Team: \n" +"Language: es\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.17\n" + +#. module: product_pricelist_supplierinfo +#: model:ir.model.fields,help:product_pricelist_supplierinfo.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 para el cómputo.\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 en base a otra Lista de " +"Precios." + +#. module: product_pricelist_supplierinfo +#: model:ir.model.fields,field_description:product_pricelist_supplierinfo.field_product_pricelist_item__base +msgid "Based on" +msgstr "Basado en" + +#. module: product_pricelist_supplierinfo +#: model:ir.model.fields,field_description:product_pricelist_supplierinfo.field_product_pricelist_item__no_supplierinfo_min_quantity +msgid "Ignore Supplier Info Min. Quantity" +msgstr "Ignorar cantidad mínima de la info de proveedor" + +#. module: product_pricelist_supplierinfo +#: model:ir.model.fields,help:product_pricelist_supplierinfo.field_product_supplierinfo__sale_margin +msgid "Margin to apply on price to obtain sale price" +msgstr "Margen a aplicar sobre el precio para obtener precio de venta" + +#. module: product_pricelist_supplierinfo +#: model:ir.model.fields,help:product_pricelist_supplierinfo.field_product_pricelist_item__filter_supplier_id +msgid "Only match prices from the selected supplier" +msgstr "Igualar sólo los precios del proveedor seleccionado" + +#. module: product_pricelist_supplierinfo +#: model:ir.model,name:product_pricelist_supplierinfo.model_product_pricelist_item +msgid "Pricelist Rule" +msgstr "Regla de la lista de precios" + +#. module: product_pricelist_supplierinfo +#: model:ir.model.fields.selection,name:product_pricelist_supplierinfo.selection__product_pricelist_item__base__supplierinfo +msgid "Prices based on supplier info" +msgstr "Precios basados en la información del proveedor" + +#. module: product_pricelist_supplierinfo +#: model:ir.model,name:product_pricelist_supplierinfo.model_product_template +msgid "Product" +msgstr "Producto" + +#. module: product_pricelist_supplierinfo +#: model:ir.model,name:product_pricelist_supplierinfo.model_product_product +msgid "Product Variant" +msgstr "Variante del producto" + +#. module: product_pricelist_supplierinfo +#: model:ir.model.fields,field_description:product_pricelist_supplierinfo.field_product_supplierinfo__sale_margin +msgid "Sale Margin" +msgstr "Margen de venta" + +#. module: product_pricelist_supplierinfo +#: model_terms:ir.ui.view,arch_db:product_pricelist_supplierinfo.product_supplierinfo_tree_view +msgid "Sale margin" +msgstr "Margen de venta" + +#. module: product_pricelist_supplierinfo +#: model:res.groups,name:product_pricelist_supplierinfo.group_supplierinfo_pricelist_sale_margin +msgid "Show sale margin on Product Supplierinfo" +msgstr "Mostrar margen de venta en Producto Proveedorinfo" + +#. module: product_pricelist_supplierinfo +#: model:ir.model,name:product_pricelist_supplierinfo.model_product_supplierinfo +msgid "Supplier Pricelist" +msgstr "Lista de precios de proveedor" + +#. module: product_pricelist_supplierinfo +#: model:ir.model.fields,field_description:product_pricelist_supplierinfo.field_product_pricelist_item__filter_supplier_id +msgid "Supplier filter" +msgstr "Filtro de Proveedor" + +#~ msgid "Pricelist" +#~ msgstr "Tarifa" + +#~ msgid "" +#~ "<span attrs=\"{'invisible':[('base', '!=', 'supplierinfo')]}\">Supplier " +#~ "price - </span>" +#~ msgstr "" +#~ "<span attrs=\"{'invisible':[('base', '!=', 'supplierinfo')]}\">Precio de " +#~ "proveedor - </span>" + +#~ msgid "" +#~ "Base price for computation.\n" +#~ "Public Price: The base price will be the Sale/public 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 Público: El precio base será el Precio Público / 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." + +#~ msgid "Cost" +#~ msgstr "Coste" + +#~ msgid "Cost Price Tax Included" +#~ msgstr "Precio de coste con impuesto incluido" + +#~ msgid "Other Price" +#~ msgstr "Otro precio" + +#~ msgid "Other Pricelist" +#~ msgstr "Otras tarifas" + +#~ msgid "Partner Prices on the product form" +#~ msgstr "Precios de socios en el formulario de producto" + +#, fuzzy +#~ msgid "Pricelist Item" +#~ msgstr "Item de Lista de precios" + +#~ msgid "Product Template" +#~ msgstr "Plantilla de producto" + +#~ msgid "Public Price" +#~ msgstr "Precio público" diff --git a/product_pricelist_supplierinfo/i18n/fr.po b/product_pricelist_supplierinfo/i18n/fr.po new file mode 100644 index 00000000000..5a9b7b182fb --- /dev/null +++ b/product_pricelist_supplierinfo/i18n/fr.po @@ -0,0 +1,140 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * product_pricelist_supplierinfo +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2020-10-08 15:16+0000\n" +"Last-Translator: Yann Papouin <y.papouin@dec-industrie.com>\n" +"Language-Team: none\n" +"Language: fr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n > 1;\n" +"X-Generator: Weblate 3.10\n" + +#. module: product_pricelist_supplierinfo +#: model:ir.model.fields,help:product_pricelist_supplierinfo.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 "" + +#. module: product_pricelist_supplierinfo +#: model:ir.model.fields,field_description:product_pricelist_supplierinfo.field_product_pricelist_item__base +msgid "Based on" +msgstr "Basée sur" + +#. module: product_pricelist_supplierinfo +#: model:ir.model.fields,field_description:product_pricelist_supplierinfo.field_product_pricelist_item__no_supplierinfo_min_quantity +msgid "Ignore Supplier Info Min. Quantity" +msgstr "Ignorer le champ Quantité minimale" + +#. module: product_pricelist_supplierinfo +#: model:ir.model.fields,help:product_pricelist_supplierinfo.field_product_supplierinfo__sale_margin +msgid "Margin to apply on price to obtain sale price" +msgstr "Marge à appliquer pour obtenir le prix de vente" + +#. module: product_pricelist_supplierinfo +#: model:ir.model.fields,help:product_pricelist_supplierinfo.field_product_pricelist_item__filter_supplier_id +msgid "Only match prices from the selected supplier" +msgstr "" + +#. module: product_pricelist_supplierinfo +#: model:ir.model,name:product_pricelist_supplierinfo.model_product_pricelist_item +msgid "Pricelist Rule" +msgstr "" + +#. module: product_pricelist_supplierinfo +#: model:ir.model.fields.selection,name:product_pricelist_supplierinfo.selection__product_pricelist_item__base__supplierinfo +msgid "Prices based on supplier info" +msgstr "Section Achats/Fournisseurs de la fiche produit" + +#. module: product_pricelist_supplierinfo +#: model:ir.model,name:product_pricelist_supplierinfo.model_product_template +msgid "Product" +msgstr "Article" + +#. module: product_pricelist_supplierinfo +#: model:ir.model,name:product_pricelist_supplierinfo.model_product_product +msgid "Product Variant" +msgstr "" + +#. module: product_pricelist_supplierinfo +#: model:ir.model.fields,field_description:product_pricelist_supplierinfo.field_product_supplierinfo__sale_margin +msgid "Sale Margin" +msgstr "Marge à la revente" + +#. module: product_pricelist_supplierinfo +#: model_terms:ir.ui.view,arch_db:product_pricelist_supplierinfo.product_supplierinfo_tree_view +msgid "Sale margin" +msgstr "Marge à la revente" + +#. module: product_pricelist_supplierinfo +#: model:res.groups,name:product_pricelist_supplierinfo.group_supplierinfo_pricelist_sale_margin +msgid "Show sale margin on Product Supplierinfo" +msgstr "" +"Afficher la marge commerciale dans la section Achats/Fournisseurs de la " +"fiche produit" + +#. module: product_pricelist_supplierinfo +#: model:ir.model,name:product_pricelist_supplierinfo.model_product_supplierinfo +msgid "Supplier Pricelist" +msgstr "Liste de prix du fournisseur" + +#. module: product_pricelist_supplierinfo +#: model:ir.model.fields,field_description:product_pricelist_supplierinfo.field_product_pricelist_item__filter_supplier_id +msgid "Supplier filter" +msgstr "" + +#~ msgid "Pricelist" +#~ msgstr "Liste de prix" + +#~ msgid "" +#~ "<span attrs=\"{'invisible':[('base', '!=', 'supplierinfo')]}\">Supplier " +#~ "price - </span>" +#~ msgstr "" +#~ "<span attrs=\"{'invisible':[('base', '!=', 'supplierinfo')]}\">Prix " +#~ "fournisseur - </span>" + +#~ msgid "" +#~ "Base price for computation.\n" +#~ "Public Price: The base price will be the Sale/public 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 "" +#~ "Prix de base pour le calcul.\n" +#~ "Prix public : le prix de base sera le prix de vente/prix public.\n" +#~ "Prix de revient : le prix de base sera le prix de revient.\n" +#~ "Autre liste de prix : calcul du prix de base, basé sur une autre liste de " +#~ "prix." + +#~ msgid "Cost" +#~ msgstr "Coût" + +#~ msgid "Cost Price Tax Included" +#~ msgstr "Coût de revient taxes comprises" + +#~ msgid "Other Price" +#~ msgstr "Autre prix" + +#~ msgid "Other Pricelist" +#~ msgstr "Autre liste de prix" + +#~ msgid "Partner Prices on the product form" +#~ msgstr "Prix fournisseurs sur la fiche produit" + +#~ msgid "Pricelist Item" +#~ msgstr "Élément de la liste de prix" + +#~ msgid "Product Template" +#~ msgstr "Modèle de produit" + +#~ msgid "Public Price" +#~ msgstr "Prix public" diff --git a/product_pricelist_supplierinfo/i18n/it.po b/product_pricelist_supplierinfo/i18n/it.po new file mode 100644 index 00000000000..4639e7d76f6 --- /dev/null +++ b/product_pricelist_supplierinfo/i18n/it.po @@ -0,0 +1,140 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * product_pricelist_supplierinfo +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2023-10-29 13:26+0000\n" +"Last-Translator: mymage <stefano.consolaro@mymage.it>\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.17\n" + +#. module: product_pricelist_supplierinfo +#: model:ir.model.fields,help:product_pricelist_supplierinfo.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 "" +"Prezzo base per il calcolo.\n" +"Prezzo di vendita: il prezzo base sarà il prezzo di vendita.\n" +"Prezzo di costo: il prezzo base sarà il prezzo di costo.\n" +"Altri listini prezzi: il calcolo del prezzo base sarà basato su un altro " +"listino prezzi." + +#. module: product_pricelist_supplierinfo +#: model:ir.model.fields,field_description:product_pricelist_supplierinfo.field_product_pricelist_item__base +msgid "Based on" +msgstr "Basato su" + +#. module: product_pricelist_supplierinfo +#: model:ir.model.fields,field_description:product_pricelist_supplierinfo.field_product_pricelist_item__no_supplierinfo_min_quantity +msgid "Ignore Supplier Info Min. Quantity" +msgstr "Ignorare la quantità min del listino fornitore" + +#. module: product_pricelist_supplierinfo +#: model:ir.model.fields,help:product_pricelist_supplierinfo.field_product_supplierinfo__sale_margin +msgid "Margin to apply on price to obtain sale price" +msgstr "Margine da applicare per ottenere il prezzo di vendita" + +#. module: product_pricelist_supplierinfo +#: model:ir.model.fields,help:product_pricelist_supplierinfo.field_product_pricelist_item__filter_supplier_id +msgid "Only match prices from the selected supplier" +msgstr "Solo prezzi corrispondenti dal fornitore selezionato" + +#. module: product_pricelist_supplierinfo +#: model:ir.model,name:product_pricelist_supplierinfo.model_product_pricelist_item +msgid "Pricelist Rule" +msgstr "Regola listino prezzi" + +#. module: product_pricelist_supplierinfo +#: model:ir.model.fields.selection,name:product_pricelist_supplierinfo.selection__product_pricelist_item__base__supplierinfo +msgid "Prices based on supplier info" +msgstr "Prezzi basati su listino fornitore" + +#. module: product_pricelist_supplierinfo +#: model:ir.model,name:product_pricelist_supplierinfo.model_product_template +msgid "Product" +msgstr "Prodotto" + +#. module: product_pricelist_supplierinfo +#: model:ir.model,name:product_pricelist_supplierinfo.model_product_product +msgid "Product Variant" +msgstr "Variante prodotto" + +#. module: product_pricelist_supplierinfo +#: model:ir.model.fields,field_description:product_pricelist_supplierinfo.field_product_supplierinfo__sale_margin +msgid "Sale Margin" +msgstr "Margine di vendita" + +#. module: product_pricelist_supplierinfo +#: model_terms:ir.ui.view,arch_db:product_pricelist_supplierinfo.product_supplierinfo_tree_view +msgid "Sale margin" +msgstr "Margine di vendita" + +#. module: product_pricelist_supplierinfo +#: model:res.groups,name:product_pricelist_supplierinfo.group_supplierinfo_pricelist_sale_margin +msgid "Show sale margin on Product Supplierinfo" +msgstr "Visualizza margine di vendita sulle informazioni fornitore prodotto" + +#. module: product_pricelist_supplierinfo +#: model:ir.model,name:product_pricelist_supplierinfo.model_product_supplierinfo +msgid "Supplier Pricelist" +msgstr "Listino prezzi fornitore" + +#. module: product_pricelist_supplierinfo +#: model:ir.model.fields,field_description:product_pricelist_supplierinfo.field_product_pricelist_item__filter_supplier_id +msgid "Supplier filter" +msgstr "Filtro fornitore" + +#~ msgid "Pricelist" +#~ msgstr "Listino prezzi" + +#~ msgid "" +#~ "<span attrs=\"{'invisible':[('base', '!=', 'supplierinfo')]}\">Supplier " +#~ "price - </span>" +#~ msgstr "" +#~ "<span attrs=\"{'invisible':[('base', '!=', 'supplierinfo')]}\">Prezzo " +#~ "fornitore - </span>" + +#~ msgid "" +#~ "Base price for computation.\n" +#~ "Public Price: The base price will be the Sale/public 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 base per il calcolo.\n" +#~ "Prezzo pubblico: il prezzo base sarà il prezzo di vendita / pubblico.\n" +#~ "Prezzo di costo: il prezzo base sarà il prezzo di costo.\n" +#~ "Altro listino: calcolo del prezzo base basato su un altro listino." + +#~ msgid "Cost" +#~ msgstr "Costo" + +#, fuzzy +#~ msgid "Other Price" +#~ msgstr "Altro listino" + +#~ msgid "Other Pricelist" +#~ msgstr "Altro listino" + +#~ msgid "Partner Prices on the product form" +#~ msgstr "Prezzi partner nella scheda prodotto" + +#~ msgid "Pricelist Item" +#~ msgstr "Articolo listino prezzi" + +#~ msgid "Product Template" +#~ msgstr "Modello prodotto" + +#~ msgid "Public Price" +#~ msgstr "Prezzo pubblico" diff --git a/product_pricelist_supplierinfo/i18n/nl.po b/product_pricelist_supplierinfo/i18n/nl.po new file mode 100644 index 00000000000..1fe7d46c31a --- /dev/null +++ b/product_pricelist_supplierinfo/i18n/nl.po @@ -0,0 +1,142 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * product_pricelist_supplierinfo +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2021-01-24 18:44+0000\n" +"Last-Translator: Bosd <c5e2fd43-d292-4c90-9d1f-74ff3436329a@anonaddy.me>\n" +"Language-Team: none\n" +"Language: nl\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.3.2\n" + +#. module: product_pricelist_supplierinfo +#: model:ir.model.fields,help:product_pricelist_supplierinfo.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 "" + +#. module: product_pricelist_supplierinfo +#: model:ir.model.fields,field_description:product_pricelist_supplierinfo.field_product_pricelist_item__base +msgid "Based on" +msgstr "Gebaseerd op" + +#. module: product_pricelist_supplierinfo +#: model:ir.model.fields,field_description:product_pricelist_supplierinfo.field_product_pricelist_item__no_supplierinfo_min_quantity +msgid "Ignore Supplier Info Min. Quantity" +msgstr "Negeer leveranciers info Minimum aantal" + +#. module: product_pricelist_supplierinfo +#: model:ir.model.fields,help:product_pricelist_supplierinfo.field_product_supplierinfo__sale_margin +msgid "Margin to apply on price to obtain sale price" +msgstr "" +"Marge om toe te passen op de prijs voor de berekening van de verkoopsprijs" + +#. module: product_pricelist_supplierinfo +#: model:ir.model.fields,help:product_pricelist_supplierinfo.field_product_pricelist_item__filter_supplier_id +#, fuzzy +msgid "Only match prices from the selected supplier" +msgstr "Alleen prijzen vergelijken van de geselecteerde leverancier" + +#. module: product_pricelist_supplierinfo +#: model:ir.model,name:product_pricelist_supplierinfo.model_product_pricelist_item +msgid "Pricelist Rule" +msgstr "" + +#. module: product_pricelist_supplierinfo +#: model:ir.model.fields.selection,name:product_pricelist_supplierinfo.selection__product_pricelist_item__base__supplierinfo +msgid "Prices based on supplier info" +msgstr "Prijzen gebaseerd op leveranciers info" + +#. module: product_pricelist_supplierinfo +#: model:ir.model,name:product_pricelist_supplierinfo.model_product_template +msgid "Product" +msgstr "Product" + +#. module: product_pricelist_supplierinfo +#: model:ir.model,name:product_pricelist_supplierinfo.model_product_product +msgid "Product Variant" +msgstr "" + +#. module: product_pricelist_supplierinfo +#: model:ir.model.fields,field_description:product_pricelist_supplierinfo.field_product_supplierinfo__sale_margin +msgid "Sale Margin" +msgstr "Verkoopsmarge" + +#. module: product_pricelist_supplierinfo +#: model_terms:ir.ui.view,arch_db:product_pricelist_supplierinfo.product_supplierinfo_tree_view +msgid "Sale margin" +msgstr "Verkoopsmarge" + +#. module: product_pricelist_supplierinfo +#: model:res.groups,name:product_pricelist_supplierinfo.group_supplierinfo_pricelist_sale_margin +#, fuzzy +msgid "Show sale margin on Product Supplierinfo" +msgstr "Weergave van verkoop marge op products leveranciersinfo" + +#. module: product_pricelist_supplierinfo +#: model:ir.model,name:product_pricelist_supplierinfo.model_product_supplierinfo +msgid "Supplier Pricelist" +msgstr "Leveranciers Prijslijst" + +#. module: product_pricelist_supplierinfo +#: model:ir.model.fields,field_description:product_pricelist_supplierinfo.field_product_pricelist_item__filter_supplier_id +msgid "Supplier filter" +msgstr "Leveranciersfilter" + +#~ msgid "" +#~ "<span attrs=\"{'invisible':[('base', '!=', 'supplierinfo')]}\">Supplier " +#~ "price - </span>" +#~ msgstr "" +#~ "<span attrs=\"{'invisible':[('base', '!=', " +#~ "'supplierinfo')]}\">Leveranciers prijs - </span>" + +#~ msgid "" +#~ "Base price for computation.\n" +#~ "Public Price: The base price will be the Sale/public 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 "" +#~ "Basis prijs voor de berekening.\n" +#~ "Publieke Prijs: Als basisprijs zal de verkoop/publieke prijs gebruikt " +#~ "worden.\n" +#~ "Kostprijs : Als basisprijs zal de kostprijs gebruikt worden.\n" +#~ "Andere Prijslijst : Berekening van de basisprijs gebaseerd op een andere " +#~ "prijslijst." + +#~ msgid "Cost" +#~ msgstr "Kost" + +#~ msgid "Cost Price Tax Included" +#~ msgstr "Kostprijs inclusief belasting" + +#~ msgid "Other Price" +#~ msgstr "Andere prijs" + +#~ msgid "Other Pricelist" +#~ msgstr "Andere Prijslijst" + +#~ msgid "Partner Prices on the product form" +#~ msgstr "Partner's prijs van het product formulier" + +#~ msgid "Pricelist" +#~ msgstr "Prijslijst" + +#~ msgid "Pricelist Item" +#~ msgstr "Prijslijst item" + +#~ msgid "Product Template" +#~ msgstr "Product sjabloon" + +#~ msgid "Public Price" +#~ msgstr "Publieke prijs" diff --git a/product_pricelist_supplierinfo/i18n/product_pricelist_supplierinfo.pot b/product_pricelist_supplierinfo/i18n/product_pricelist_supplierinfo.pot new file mode 100644 index 00000000000..85508b21e52 --- /dev/null +++ b/product_pricelist_supplierinfo/i18n/product_pricelist_supplierinfo.pot @@ -0,0 +1,88 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * product_pricelist_supplierinfo +# +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_pricelist_supplierinfo +#: model:ir.model.fields,help:product_pricelist_supplierinfo.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 "" + +#. module: product_pricelist_supplierinfo +#: model:ir.model.fields,field_description:product_pricelist_supplierinfo.field_product_pricelist_item__base +msgid "Based on" +msgstr "" + +#. module: product_pricelist_supplierinfo +#: model:ir.model.fields,field_description:product_pricelist_supplierinfo.field_product_pricelist_item__no_supplierinfo_min_quantity +msgid "Ignore Supplier Info Min. Quantity" +msgstr "" + +#. module: product_pricelist_supplierinfo +#: model:ir.model.fields,help:product_pricelist_supplierinfo.field_product_supplierinfo__sale_margin +msgid "Margin to apply on price to obtain sale price" +msgstr "" + +#. module: product_pricelist_supplierinfo +#: model:ir.model.fields,help:product_pricelist_supplierinfo.field_product_pricelist_item__filter_supplier_id +msgid "Only match prices from the selected supplier" +msgstr "" + +#. module: product_pricelist_supplierinfo +#: model:ir.model,name:product_pricelist_supplierinfo.model_product_pricelist_item +msgid "Pricelist Rule" +msgstr "" + +#. module: product_pricelist_supplierinfo +#: model:ir.model.fields.selection,name:product_pricelist_supplierinfo.selection__product_pricelist_item__base__supplierinfo +msgid "Prices based on supplier info" +msgstr "" + +#. module: product_pricelist_supplierinfo +#: model:ir.model,name:product_pricelist_supplierinfo.model_product_template +msgid "Product" +msgstr "" + +#. module: product_pricelist_supplierinfo +#: model:ir.model,name:product_pricelist_supplierinfo.model_product_product +msgid "Product Variant" +msgstr "" + +#. module: product_pricelist_supplierinfo +#: model:ir.model.fields,field_description:product_pricelist_supplierinfo.field_product_supplierinfo__sale_margin +msgid "Sale Margin" +msgstr "" + +#. module: product_pricelist_supplierinfo +#: model_terms:ir.ui.view,arch_db:product_pricelist_supplierinfo.product_supplierinfo_tree_view +msgid "Sale margin" +msgstr "" + +#. module: product_pricelist_supplierinfo +#: model:res.groups,name:product_pricelist_supplierinfo.group_supplierinfo_pricelist_sale_margin +msgid "Show sale margin on Product Supplierinfo" +msgstr "" + +#. module: product_pricelist_supplierinfo +#: model:ir.model,name:product_pricelist_supplierinfo.model_product_supplierinfo +msgid "Supplier Pricelist" +msgstr "" + +#. module: product_pricelist_supplierinfo +#: model:ir.model.fields,field_description:product_pricelist_supplierinfo.field_product_pricelist_item__filter_supplier_id +msgid "Supplier filter" +msgstr "" diff --git a/product_pricelist_supplierinfo/i18n/pt_BR.po b/product_pricelist_supplierinfo/i18n/pt_BR.po new file mode 100644 index 00000000000..2b47e686644 --- /dev/null +++ b/product_pricelist_supplierinfo/i18n/pt_BR.po @@ -0,0 +1,96 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * product_pricelist_supplierinfo +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2023-10-28 21:26+0000\n" +"Last-Translator: Adriano Prado <adrianojprado@gmail.com>\n" +"Language-Team: none\n" +"Language: pt_BR\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: product_pricelist_supplierinfo +#: model:ir.model.fields,help:product_pricelist_supplierinfo.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 "" +"Preço base para cálculo.\n" +"Preço de Venda: O preço base será o Preço de Venda.\n" +"Preço de custo: O preço base será o preço de custo.\n" +"Outra Lista de Preços: Cálculo do preço base com base em outra Lista de " +"Preços." + +#. module: product_pricelist_supplierinfo +#: model:ir.model.fields,field_description:product_pricelist_supplierinfo.field_product_pricelist_item__base +msgid "Based on" +msgstr "Baseado Em" + +#. module: product_pricelist_supplierinfo +#: model:ir.model.fields,field_description:product_pricelist_supplierinfo.field_product_pricelist_item__no_supplierinfo_min_quantity +msgid "Ignore Supplier Info Min. Quantity" +msgstr "Ignorar informações mínimas do fornecedor. Quantidade" + +#. module: product_pricelist_supplierinfo +#: model:ir.model.fields,help:product_pricelist_supplierinfo.field_product_supplierinfo__sale_margin +msgid "Margin to apply on price to obtain sale price" +msgstr "Margem a aplicar sobre o preço para obter o preço de venda" + +#. module: product_pricelist_supplierinfo +#: model:ir.model.fields,help:product_pricelist_supplierinfo.field_product_pricelist_item__filter_supplier_id +msgid "Only match prices from the selected supplier" +msgstr "Combine apenas os preços do fornecedor selecionado" + +#. module: product_pricelist_supplierinfo +#: model:ir.model,name:product_pricelist_supplierinfo.model_product_pricelist_item +msgid "Pricelist Rule" +msgstr "Regra Lista de Preço" + +#. module: product_pricelist_supplierinfo +#: model:ir.model.fields.selection,name:product_pricelist_supplierinfo.selection__product_pricelist_item__base__supplierinfo +msgid "Prices based on supplier info" +msgstr "Preços baseados em informações do fornecedor" + +#. module: product_pricelist_supplierinfo +#: model:ir.model,name:product_pricelist_supplierinfo.model_product_template +msgid "Product" +msgstr "Produto" + +#. module: product_pricelist_supplierinfo +#: model:ir.model,name:product_pricelist_supplierinfo.model_product_product +msgid "Product Variant" +msgstr "Variante do produto" + +#. module: product_pricelist_supplierinfo +#: model:ir.model.fields,field_description:product_pricelist_supplierinfo.field_product_supplierinfo__sale_margin +msgid "Sale Margin" +msgstr "Margem de Venda" + +#. module: product_pricelist_supplierinfo +#: model_terms:ir.ui.view,arch_db:product_pricelist_supplierinfo.product_supplierinfo_tree_view +msgid "Sale margin" +msgstr "Margem de venda" + +#. module: product_pricelist_supplierinfo +#: model:res.groups,name:product_pricelist_supplierinfo.group_supplierinfo_pricelist_sale_margin +msgid "Show sale margin on Product Supplierinfo" +msgstr "Mostrar margem de venda nas informações do fornecedor do produto" + +#. module: product_pricelist_supplierinfo +#: model:ir.model,name:product_pricelist_supplierinfo.model_product_supplierinfo +msgid "Supplier Pricelist" +msgstr "Lista de Preço Fornecedor" + +#. module: product_pricelist_supplierinfo +#: model:ir.model.fields,field_description:product_pricelist_supplierinfo.field_product_pricelist_item__filter_supplier_id +msgid "Supplier filter" +msgstr "Filtro Fornecedor" diff --git a/product_pricelist_supplierinfo/models/__init__.py b/product_pricelist_supplierinfo/models/__init__.py new file mode 100644 index 00000000000..c4e59fd136d --- /dev/null +++ b/product_pricelist_supplierinfo/models/__init__.py @@ -0,0 +1,6 @@ +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from . import product_supplierinfo +from . import product_pricelist_item +from . import product_product +from . import product_template diff --git a/product_pricelist_supplierinfo/models/product_pricelist_item.py b/product_pricelist_supplierinfo/models/product_pricelist_item.py new file mode 100644 index 00000000000..c490d920df0 --- /dev/null +++ b/product_pricelist_supplierinfo/models/product_pricelist_item.py @@ -0,0 +1,33 @@ +# Copyright 2018 Tecnativa - Vicent Cubells +# Copyright 2018 Tecnativa - Pedro M. Baeza +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo import fields, models + + +class ProductPricelistItem(models.Model): + _inherit = "product.pricelist.item" + + base = fields.Selection( + selection_add=[("supplierinfo", "Prices based on supplier info")], + ondelete={"supplierinfo": "set default"}, + ) + no_supplierinfo_min_quantity = fields.Boolean( + string="Ignore Supplier Info Min. Quantity", + ) + filter_supplier_id = fields.Many2one( + comodel_name="res.partner", + string="Supplier filter", + help="Only match prices from the selected supplier", + ) + + def _compute_price(self, product, quantity, uom, date, currency=None): + result = super()._compute_price(product, quantity, uom, date, currency) + context = self.env.context + if self.compute_price == "formula" and self.base == "supplierinfo": + result = product.sudo()._get_supplierinfo_pricelist_price( + self, + date=date or context.get("date", fields.Date.today()), + quantity=quantity, + ) + return result diff --git a/product_pricelist_supplierinfo/models/product_product.py b/product_pricelist_supplierinfo/models/product_product.py new file mode 100644 index 00000000000..fcac5c2fbc6 --- /dev/null +++ b/product_pricelist_supplierinfo/models/product_product.py @@ -0,0 +1,43 @@ +# Copyright 2018 Tecnativa - Vicent Cubells +# Copyright 2018 Tecnativa - Pedro M. Baeza +# Copyright 2019 Tecnativa - Carlos Dauden +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo import models + + +class ProductProduct(models.Model): + _inherit = "product.product" + + def _prepare_sellers(self, params=False): + """When we override min qty we want that _select_sellers gives us the + first possible seller for every other criteria ignoring the quantity. As + supplierinfos are sorted by min_qty descending, we want to revert such + order so we get the very first one, which is probably the one to go. + """ + sellers = super()._prepare_sellers(params) + if self.env.context.get("override_min_qty"): + sellers = sellers.sorted("min_qty") + return sellers + + def _get_supplierinfo_pricelist_price(self, rule, date=None, quantity=None): + return self.product_tmpl_id._get_supplierinfo_pricelist_price( + rule, date=date, quantity=quantity, product_id=self.id + ) + + def _price_compute( + self, price_type, uom=None, currency=None, company=None, date=False + ): + """Return dummy not falsy prices when computation is done from supplier + info for avoiding error on super method. We will later fill these with + correct values. + """ + if price_type == "supplierinfo": + return dict.fromkeys(self.ids, 1.0) + return super()._price_compute( + price_type, + uom=uom, + currency=currency, + company=company, + date=date, + ) diff --git a/product_pricelist_supplierinfo/models/product_supplierinfo.py b/product_pricelist_supplierinfo/models/product_supplierinfo.py new file mode 100644 index 00000000000..1a8e637cbba --- /dev/null +++ b/product_pricelist_supplierinfo/models/product_supplierinfo.py @@ -0,0 +1,21 @@ +# Copyright 2020 Akretion - Mourad EL HADJ MIMOUNE +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo import fields, models + + +class ProductSupplierinfo(models.Model): + _inherit = "product.supplierinfo" + + sale_margin = fields.Float( + default=0, + digits=(16, 2), + help="Margin to apply on price to obtain sale price", + ) + + def _get_supplierinfo_pricelist_price(self): + self.ensure_one() + sale_price = self.price + if self.sale_margin: + sale_price = (self.price + (self.price * (self.sale_margin / 100))) or 0.0 + return sale_price diff --git a/product_pricelist_supplierinfo/models/product_template.py b/product_pricelist_supplierinfo/models/product_template.py new file mode 100644 index 00000000000..589855500b9 --- /dev/null +++ b/product_pricelist_supplierinfo/models/product_template.py @@ -0,0 +1,96 @@ +# Copyright 2018 Tecnativa - Vicent Cubells +# Copyright 2018 Tecnativa - Pedro M. Baeza +# Copyright 2019 Tecnativa - Carlos Dauden +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from datetime import datetime + +from odoo import fields, models, tools + + +class ProductTemplate(models.Model): + _inherit = "product.template" + + def _get_supplierinfo_pricelist_price( + self, rule, date=None, quantity=None, product_id=None + ): + """Method for getting the price from supplier info.""" + self.ensure_one() + price = 0.0 + product = self.product_variant_id + if product_id: + product = product.browse(product_id) + if rule.no_supplierinfo_min_quantity: + # No matter which minimum qty, we'll get every seller. We set a + # number absurdidly high + quantity = 1e9 + # The product_variant_id returns empty recordset if template is not + # active, so we must ensure variant exists or _select_seller fails. + if product: + if type(date) == datetime: + date = date.date() + seller = product.with_context( + override_min_qty=rule.no_supplierinfo_min_quantity + )._select_seller( + # For a public user this record could be not accessible, but we + # need to get the price anyway + partner_id=self.env.context.get( + "force_filter_supplier_id", rule.sudo().filter_supplier_id + ), + quantity=quantity, + date=date, + ) + if seller: + price = seller._get_supplierinfo_pricelist_price() + if price: + # We need to convert the price if the pricelist and seller have + # different currencies so the price have the pricelist currency + if rule.currency_id != seller.currency_id: + convert_date = date or self.env.context.get("date", fields.Date.today()) + price = seller.currency_id._convert( + price, rule.currency_id, seller.company_id, convert_date + ) + + # 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. + qty_uom_id = self._context.get("uom") or self.uom_id.id + price_uom = self.env["uom.uom"].browse([qty_uom_id]) + + # We need to convert the price to the uom used on the sale, if the + # uom on the seller is a different one that the one used there. + if seller and seller.product_uom != price_uom: + price = seller.product_uom._compute_price(price, price_uom) + 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.uom_id._compute_price( + rule.price_surcharge, price_uom + ) + price += price_surcharge + if rule.price_min_margin: + price_min_margin = self.uom_id._compute_price( + rule.price_min_margin, price_uom + ) + price = max(price, price_limit + price_min_margin) + if rule.price_max_margin: + price_max_margin = self.uom_id._compute_price( + rule.price_max_margin, price_uom + ) + price = min(price, price_limit + price_max_margin) + return price + + def _price_compute( + self, price_type, uom=None, currency=None, company=False, date=False + ): + """Return dummy not falsy prices when computation is done from supplier + info for avoiding error on super method. We will later fill these with + correct values. + """ + if price_type == "supplierinfo": + return dict.fromkeys(self.ids, 1.0) + return super()._price_compute( + price_type, uom=uom, currency=currency, company=company, date=date + ) diff --git a/product_pricelist_supplierinfo/pyproject.toml b/product_pricelist_supplierinfo/pyproject.toml new file mode 100644 index 00000000000..4231d0cccb3 --- /dev/null +++ b/product_pricelist_supplierinfo/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/product_pricelist_supplierinfo/readme/CONFIGURE.md b/product_pricelist_supplierinfo/readme/CONFIGURE.md new file mode 100644 index 00000000000..48997a2db75 --- /dev/null +++ b/product_pricelist_supplierinfo/readme/CONFIGURE.md @@ -0,0 +1,15 @@ +To configure pricelists with the new feature of this module, you need +to: + +1. Go to *Sales \> Configuration \> Settings* and check "Pricelists" + option and "Advanced price rules (discounts, formulas)" after that. + You must have correct permissions and you must install **Sales + Management** app (sale) and **Purchase** app to see these settings. +2. Create or edit a Sales Pricelist at *Sales \> Products \> + Pricelists*. +3. Add or edit a pricelist item and check "Formula" option in "Price + Computation" section. +4. You will see the new option "Prices based on supplier info". +5. If you want to bypass the "Min.Quantity" field of the supplier info + and always select the lowest quantity price, check the option + "Ignore Supplier Info Min. Quantity". diff --git a/product_pricelist_supplierinfo/readme/CONTRIBUTORS.md b/product_pricelist_supplierinfo/readme/CONTRIBUTORS.md new file mode 100644 index 00000000000..8eccff75049 --- /dev/null +++ b/product_pricelist_supplierinfo/readme/CONTRIBUTORS.md @@ -0,0 +1,8 @@ +- [Tecnativa](https://www.tecnativa.com/): + - Vicent Cubells + - Pedro M. Baeza + - Carlos Roca +- Nikul Chaudhary \<<nikulchaudhary2112@gmail.com>\> +- [TAKOBI](https://takobi.online/): + - Lorenzo Battistini +- Andrea Gidalti \<<andreag@vauxoo.com>\> diff --git a/product_pricelist_supplierinfo/readme/DESCRIPTION.md b/product_pricelist_supplierinfo/readme/DESCRIPTION.md new file mode 100644 index 00000000000..1e0b4069391 --- /dev/null +++ b/product_pricelist_supplierinfo/readme/DESCRIPTION.md @@ -0,0 +1,7 @@ +This module allows you to create a sales pricelist based on product +supplierinfo prices. If you want, you can bypass minimum quantity in +pricelist item. + +We can also define sale marging applied on purchase price directly on +supplier info. For this, you must add users to "Show sale margin on +Product Supplierinfo" group. diff --git a/product_pricelist_supplierinfo/readme/INSTALL.md b/product_pricelist_supplierinfo/readme/INSTALL.md new file mode 100644 index 00000000000..b0254a4a46a --- /dev/null +++ b/product_pricelist_supplierinfo/readme/INSTALL.md @@ -0,0 +1,2 @@ +Although this module doesn't depend technically on **Sales Management**, +you must install it for configuring and seeing the effects of it. diff --git a/product_pricelist_supplierinfo/readme/ROADMAP.md b/product_pricelist_supplierinfo/readme/ROADMAP.md new file mode 100644 index 00000000000..98de803c832 --- /dev/null +++ b/product_pricelist_supplierinfo/readme/ROADMAP.md @@ -0,0 +1,5 @@ +- First line that matches by minimum quantity criteria, independently + from the supplier, will be the one that provides the price for the + pricelist. +- There's no mechanism for selecting the supplier from possible sources + like sales orders. diff --git a/product_pricelist_supplierinfo/readme/USAGE.md b/product_pricelist_supplierinfo/readme/USAGE.md new file mode 100644 index 00000000000..b7fb448c863 --- /dev/null +++ b/product_pricelist_supplierinfo/readme/USAGE.md @@ -0,0 +1,18 @@ +For adding supplier info: + +1. Go to *Sales \> Products \> Products* +2. Open or create a product. +3. Go to "Purchase" page. +4. On "Vendors" section, add the supplier and prices. +5. You can drag and drop for reordering these lines. + +Check the remark in known issues about the supplier info line selection. + +For checking pricelists in action, you can (with sale module installed): + +1. Go to *Sales \> Orders \> Quotations* +2. Create or edit a quotation. +3. Add a line. +4. Select a product with the criteria to match the pricelist from + supplier info. +5. See the proper price appears in the line. diff --git a/product_pricelist_supplierinfo/security/res_groups.xml b/product_pricelist_supplierinfo/security/res_groups.xml new file mode 100644 index 00000000000..15c907f0042 --- /dev/null +++ b/product_pricelist_supplierinfo/security/res_groups.xml @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<odoo> + + <record id="group_supplierinfo_pricelist_sale_margin" model="res.groups"> + <field name="name">Show sale margin on Product Supplierinfo</field> + <field name="category_id" ref="base.module_category_hidden" /> + </record> + +</odoo> diff --git a/product_pricelist_supplierinfo/static/description/icon.png b/product_pricelist_supplierinfo/static/description/icon.png new file mode 100644 index 00000000000..3a0328b516c Binary files /dev/null and b/product_pricelist_supplierinfo/static/description/icon.png differ diff --git a/product_pricelist_supplierinfo/static/description/index.html b/product_pricelist_supplierinfo/static/description/index.html new file mode 100644 index 00000000000..ff080e30eaf --- /dev/null +++ b/product_pricelist_supplierinfo/static/description/index.html @@ -0,0 +1,498 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> +<meta name="generator" content="Docutils: https://docutils.sourceforge.io/" /> +<title>Supplier info prices in sales pricelists</title> +<style type="text/css"> + +/* +:Author: David Goodger (goodger@python.org) +:Id: $Id: html4css1.css 8954 2022-01-20 10:10:25Z milde $ +:Copyright: This stylesheet has been placed in the public domain. + +Default cascading style sheet for the HTML output of Docutils. + +See https://docutils.sourceforge.io/docs/howto/html-stylesheets.html for how to +customize this style sheet. +*/ + +/* used to remove borders from tables and images */ +.borderless, table.borderless td, table.borderless th { + border: 0 } + +table.borderless td, table.borderless th { + /* Override padding for "table.docutils td" with "! important". + The right padding separates the table cells. */ + padding: 0 0.5em 0 0 ! important } + +.first { + /* Override more specific margin styles with "! important". */ + margin-top: 0 ! important } + +.last, .with-subtitle { + margin-bottom: 0 ! important } + +.hidden { + display: none } + +.subscript { + vertical-align: sub; + font-size: smaller } + +.superscript { + vertical-align: super; + font-size: smaller } + +a.toc-backref { + text-decoration: none ; + color: black } + +blockquote.epigraph { + margin: 2em 5em ; } + +dl.docutils dd { + margin-bottom: 0.5em } + +object[type="image/svg+xml"], object[type="application/x-shockwave-flash"] { + overflow: hidden; +} + +/* Uncomment (and remove this text!) to get bold-faced definition list terms +dl.docutils dt { + font-weight: bold } +*/ + +div.abstract { + margin: 2em 5em } + +div.abstract p.topic-title { + font-weight: bold ; + text-align: center } + +div.admonition, div.attention, div.caution, div.danger, div.error, +div.hint, div.important, div.note, div.tip, div.warning { + margin: 2em ; + border: medium outset ; + padding: 1em } + +div.admonition p.admonition-title, div.hint p.admonition-title, +div.important p.admonition-title, div.note p.admonition-title, +div.tip p.admonition-title { + font-weight: bold ; + font-family: sans-serif } + +div.attention p.admonition-title, div.caution p.admonition-title, +div.danger p.admonition-title, div.error p.admonition-title, +div.warning p.admonition-title, .code .error { + color: red ; + font-weight: bold ; + font-family: sans-serif } + +/* Uncomment (and remove this text!) to get reduced vertical space in + compound paragraphs. +div.compound .compound-first, div.compound .compound-middle { + margin-bottom: 0.5em } + +div.compound .compound-last, div.compound .compound-middle { + margin-top: 0.5em } +*/ + +div.dedication { + margin: 2em 5em ; + text-align: center ; + font-style: italic } + +div.dedication p.topic-title { + font-weight: bold ; + font-style: normal } + +div.figure { + margin-left: 2em ; + margin-right: 2em } + +div.footer, div.header { + clear: both; + font-size: smaller } + +div.line-block { + display: block ; + margin-top: 1em ; + margin-bottom: 1em } + +div.line-block div.line-block { + margin-top: 0 ; + margin-bottom: 0 ; + margin-left: 1.5em } + +div.sidebar { + margin: 0 0 0.5em 1em ; + border: medium outset ; + padding: 1em ; + background-color: #ffffee ; + width: 40% ; + float: right ; + clear: right } + +div.sidebar p.rubric { + font-family: sans-serif ; + font-size: medium } + +div.system-messages { + margin: 5em } + +div.system-messages h1 { + color: red } + +div.system-message { + border: medium outset ; + padding: 1em } + +div.system-message p.system-message-title { + color: red ; + font-weight: bold } + +div.topic { + margin: 2em } + +h1.section-subtitle, h2.section-subtitle, h3.section-subtitle, +h4.section-subtitle, h5.section-subtitle, h6.section-subtitle { + margin-top: 0.4em } + +h1.title { + text-align: center } + +h2.subtitle { + text-align: center } + +hr.docutils { + width: 75% } + +img.align-left, .figure.align-left, object.align-left, table.align-left { + clear: left ; + float: left ; + margin-right: 1em } + +img.align-right, .figure.align-right, object.align-right, table.align-right { + clear: right ; + float: right ; + margin-left: 1em } + +img.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +table.align-center { + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left } + +.align-center { + clear: both ; + text-align: center } + +.align-right { + text-align: right } + +/* reset inner alignment in figures */ +div.align-right { + text-align: inherit } + +/* div.align-center * { */ +/* text-align: left } */ + +.align-top { + vertical-align: top } + +.align-middle { + vertical-align: middle } + +.align-bottom { + vertical-align: bottom } + +ol.simple, ul.simple { + margin-bottom: 1em } + +ol.arabic { + list-style: decimal } + +ol.loweralpha { + list-style: lower-alpha } + +ol.upperalpha { + list-style: upper-alpha } + +ol.lowerroman { + list-style: lower-roman } + +ol.upperroman { + list-style: upper-roman } + +p.attribution { + text-align: right ; + margin-left: 50% } + +p.caption { + font-style: italic } + +p.credits { + font-style: italic ; + font-size: smaller } + +p.label { + white-space: nowrap } + +p.rubric { + font-weight: bold ; + font-size: larger ; + color: maroon ; + text-align: center } + +p.sidebar-title { + font-family: sans-serif ; + font-weight: bold ; + font-size: larger } + +p.sidebar-subtitle { + font-family: sans-serif ; + font-weight: bold } + +p.topic-title { + font-weight: bold } + +pre.address { + margin-bottom: 0 ; + margin-top: 0 ; + font: inherit } + +pre.literal-block, pre.doctest-block, pre.math, pre.code { + margin-left: 2em ; + margin-right: 2em } + +pre.code .ln { color: grey; } /* line numbers */ +pre.code, code { background-color: #eeeeee } +pre.code .comment, code .comment { color: #5C6576 } +pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold } +pre.code .literal.string, code .literal.string { color: #0C5404 } +pre.code .name.builtin, code .name.builtin { color: #352B84 } +pre.code .deleted, code .deleted { background-color: #DEB0A1} +pre.code .inserted, code .inserted { background-color: #A3D289} + +span.classifier { + font-family: sans-serif ; + font-style: oblique } + +span.classifier-delimiter { + font-family: sans-serif ; + font-weight: bold } + +span.interpreted { + font-family: sans-serif } + +span.option { + white-space: nowrap } + +span.pre { + white-space: pre } + +span.problematic { + color: red } + +span.section-subtitle { + /* font-size relative to parent (h1..h6 element) */ + font-size: 80% } + +table.citation { + border-left: solid 1px gray; + margin-left: 1px } + +table.docinfo { + margin: 2em 4em } + +table.docutils { + margin-top: 0.5em ; + margin-bottom: 0.5em } + +table.footnote { + border-left: solid 1px black; + margin-left: 1px } + +table.docutils td, table.docutils th, +table.docinfo td, table.docinfo th { + padding-left: 0.5em ; + padding-right: 0.5em ; + vertical-align: top } + +table.docutils th.field-name, table.docinfo th.docinfo-name { + font-weight: bold ; + text-align: left ; + white-space: nowrap ; + padding-left: 0 } + +/* "booktabs" style (no vertical lines) */ +table.docutils.booktabs { + border: 0px; + border-top: 2px solid; + border-bottom: 2px solid; + border-collapse: collapse; +} +table.docutils.booktabs * { + border: 0px; +} +table.docutils.booktabs th { + border-bottom: thin solid; + text-align: left; +} + +h1 tt.docutils, h2 tt.docutils, h3 tt.docutils, +h4 tt.docutils, h5 tt.docutils, h6 tt.docutils { + font-size: 100% } + +ul.auto-toc { + list-style-type: none } + +</style> +</head> +<body> +<div class="document" id="supplier-info-prices-in-sales-pricelists"> +<h1 class="title">Supplier info prices in sales pricelists</h1> + +<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +!! This file is generated by oca-gen-addon-readme !! +!! changes will be overwritten. !! +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +!! source digest: sha256:e6539df59b27f0932ee4afb66ee75503be8c81c9ec41fd11623a5abcfca59e9c +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! --> +<p><a class="reference external image-reference" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external image-reference" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external image-reference" href="https://github.com/OCA/product-attribute/tree/17.0/product_pricelist_supplierinfo"><img alt="OCA/product-attribute" src="https://img.shields.io/badge/github-OCA%2Fproduct--attribute-lightgray.png?logo=github" /></a> <a class="reference external image-reference" href="https://translation.odoo-community.org/projects/product-attribute-17-0/product-attribute-17-0-product_pricelist_supplierinfo"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external image-reference" href="https://runboat.odoo-community.org/builds?repo=OCA/product-attribute&target_branch=17.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-Try%20me-875A7B.png" /></a></p> +<p>This module allows you to create a sales pricelist based on product +supplierinfo prices. If you want, you can bypass minimum quantity in +pricelist item.</p> +<p>We can also define sale marging applied on purchase price directly on +supplier info. For this, you must add users to “Show sale margin on +Product Supplierinfo” group.</p> +<p><strong>Table of contents</strong></p> +<div class="contents local topic" id="contents"> +<ul class="simple"> +<li><a class="reference internal" href="#installation" id="toc-entry-1">Installation</a></li> +<li><a class="reference internal" href="#configuration" id="toc-entry-2">Configuration</a></li> +<li><a class="reference internal" href="#usage" id="toc-entry-3">Usage</a></li> +<li><a class="reference internal" href="#known-issues-roadmap" id="toc-entry-4">Known issues / Roadmap</a></li> +<li><a class="reference internal" href="#bug-tracker" id="toc-entry-5">Bug Tracker</a></li> +<li><a class="reference internal" href="#credits" id="toc-entry-6">Credits</a><ul> +<li><a class="reference internal" href="#authors" id="toc-entry-7">Authors</a></li> +<li><a class="reference internal" href="#contributors" id="toc-entry-8">Contributors</a></li> +<li><a class="reference internal" href="#maintainers" id="toc-entry-9">Maintainers</a></li> +</ul> +</li> +</ul> +</div> +<div class="section" id="installation"> +<h1><a class="toc-backref" href="#toc-entry-1">Installation</a></h1> +<p>Although this module doesn’t depend technically on <strong>Sales Management</strong>, +you must install it for configuring and seeing the effects of it.</p> +</div> +<div class="section" id="configuration"> +<h1><a class="toc-backref" href="#toc-entry-2">Configuration</a></h1> +<p>To configure pricelists with the new feature of this module, you need +to:</p> +<ol class="arabic simple"> +<li>Go to <em>Sales > Configuration > Settings</em> and check “Pricelists” +option and “Advanced price rules (discounts, formulas)” after that. +You must have correct permissions and you must install <strong>Sales +Management</strong> app (sale) and <strong>Purchase</strong> app to see these settings.</li> +<li>Create or edit a Sales Pricelist at <em>Sales > Products > Pricelists</em>.</li> +<li>Add or edit a pricelist item and check “Formula” option in “Price +Computation” section.</li> +<li>You will see the new option “Prices based on supplier info”.</li> +<li>If you want to bypass the “Min.Quantity” field of the supplier info +and always select the lowest quantity price, check the option “Ignore +Supplier Info Min. Quantity”.</li> +</ol> +</div> +<div class="section" id="usage"> +<h1><a class="toc-backref" href="#toc-entry-3">Usage</a></h1> +<p>For adding supplier info:</p> +<ol class="arabic simple"> +<li>Go to <em>Sales > Products > Products</em></li> +<li>Open or create a product.</li> +<li>Go to “Purchase” page.</li> +<li>On “Vendors” section, add the supplier and prices.</li> +<li>You can drag and drop for reordering these lines.</li> +</ol> +<p>Check the remark in known issues about the supplier info line selection.</p> +<p>For checking pricelists in action, you can (with sale module installed):</p> +<ol class="arabic simple"> +<li>Go to <em>Sales > Orders > Quotations</em></li> +<li>Create or edit a quotation.</li> +<li>Add a line.</li> +<li>Select a product with the criteria to match the pricelist from +supplier info.</li> +<li>See the proper price appears in the line.</li> +</ol> +</div> +<div class="section" id="known-issues-roadmap"> +<h1><a class="toc-backref" href="#toc-entry-4">Known issues / Roadmap</a></h1> +<ul class="simple"> +<li>First line that matches by minimum quantity criteria, independently +from the supplier, will be the one that provides the price for the +pricelist.</li> +<li>There’s no mechanism for selecting the supplier from possible sources +like sales orders.</li> +</ul> +</div> +<div class="section" id="bug-tracker"> +<h1><a class="toc-backref" href="#toc-entry-5">Bug Tracker</a></h1> +<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/product-attribute/issues">GitHub Issues</a>. +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 +<a class="reference external" href="https://github.com/OCA/product-attribute/issues/new?body=module:%20product_pricelist_supplierinfo%0Aversion:%2017.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p> +<p>Do not contact contributors directly about support or help with technical issues.</p> +</div> +<div class="section" id="credits"> +<h1><a class="toc-backref" href="#toc-entry-6">Credits</a></h1> +<div class="section" id="authors"> +<h2><a class="toc-backref" href="#toc-entry-7">Authors</a></h2> +<ul class="simple"> +<li>Tecnativa</li> +<li>Vauxoo</li> +</ul> +</div> +<div class="section" id="contributors"> +<h2><a class="toc-backref" href="#toc-entry-8">Contributors</a></h2> +<ul class="simple"> +<li><a class="reference external" href="https://www.tecnativa.com/">Tecnativa</a>:<ul> +<li>Vicent Cubells</li> +<li>Pedro M. Baeza</li> +<li>Carlos Roca</li> +</ul> +</li> +<li>Nikul Chaudhary <<a class="reference external" href="mailto:nikulchaudhary2112@gmail.com">nikulchaudhary2112@gmail.com</a>></li> +<li><a class="reference external" href="https://takobi.online/">TAKOBI</a>:<ul> +<li>Lorenzo Battistini</li> +</ul> +</li> +<li>Andrea Gidalti <<a class="reference external" href="mailto:andreag@vauxoo.com">andreag@vauxoo.com</a>></li> +</ul> +</div> +<div class="section" id="maintainers"> +<h2><a class="toc-backref" href="#toc-entry-9">Maintainers</a></h2> +<p>This module is maintained by the OCA.</p> +<a class="reference external image-reference" href="https://odoo-community.org"><img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" /></a> +<p>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.</p> +<p>Current <a class="reference external" href="https://odoo-community.org/page/maintainer-role">maintainer</a>:</p> +<p><a class="reference external image-reference" href="https://github.com/luisg123v"><img alt="luisg123v" src="https://github.com/luisg123v.png?size=40px" /></a></p> +<p>This module is part of the <a class="reference external" href="https://github.com/OCA/product-attribute/tree/17.0/product_pricelist_supplierinfo">OCA/product-attribute</a> project on GitHub.</p> +<p>You are welcome to contribute. To learn how please visit <a class="reference external" href="https://odoo-community.org/page/Contribute">https://odoo-community.org/page/Contribute</a>.</p> +</div> +</div> +</div> +</body> +</html> diff --git a/product_pricelist_supplierinfo/tests/__init__.py b/product_pricelist_supplierinfo/tests/__init__.py new file mode 100644 index 00000000000..0ff6e5eba5e --- /dev/null +++ b/product_pricelist_supplierinfo/tests/__init__.py @@ -0,0 +1 @@ +from . import test_product_supplierinfo diff --git a/product_pricelist_supplierinfo/tests/test_product_supplierinfo.py b/product_pricelist_supplierinfo/tests/test_product_supplierinfo.py new file mode 100644 index 00000000000..31521cfa97e --- /dev/null +++ b/product_pricelist_supplierinfo/tests/test_product_supplierinfo.py @@ -0,0 +1,313 @@ +# Copyright 2018 Tecnativa - Vicent Cubells +# Copyright 2018 Tecnativa - Pedro M. Baeza +# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html + +from datetime import date + +from odoo import Command +from odoo.tests import TransactionCase, tagged + + +@tagged("product_supplier_info") +class TestProductSupplierinfo(TransactionCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.partner_obj = cls.env["res.partner"] + cls.currency_rate_obj = cls.env["res.currency.rate"] + cls.partner = cls.partner_obj.create({"name": "Partner Test"}) + cls.supplier1 = cls.partner_obj.create({"name": "Supplier #1"}) + cls.supplier2 = cls.partner_obj.create({"name": "Supplier #2"}) + cls.product = cls.env["product.product"].create( + { + "name": "Product Test", + "seller_ids": [ + Command.create( + {"partner_id": cls.supplier1.id, "min_qty": 5, "price": 50}, + ), + Command.create( + {"partner_id": cls.supplier2.id, "min_qty": 1, "price": 10}, + ), + ], + } + ) + cls.product_with_diff_uom = cls.env["product.product"].create( + { + "name": "Product UOM Test", + "uom_id": cls.env.ref("uom.product_uom_unit").id, + "uom_po_id": cls.env.ref("uom.product_uom_dozen").id, + "seller_ids": [ + Command.create( + {"partner_id": cls.supplier1.id, "min_qty": 1, "price": 1200}, + ) + ], + } + ) + cls.pricelist = cls.env["product.pricelist"].create( + { + "name": "Supplierinfo Pricelist", + "item_ids": [ + Command.create( + { + "compute_price": "formula", + "base": "supplierinfo", + "price_discount": 0, + "min_quantity": 1.0, + }, + ) + ], + } + ) + + @classmethod + def _update_rate(cls, currency_id, rate): + currency_rate = cls.currency_rate_obj.search( + [("name", "=", date.today()), ("currency_id", "=", currency_id.id)], limit=1 + ) + if not currency_rate: + cls.currency_rate_obj.create( + { + "currency_id": currency_id.id, + "rate": rate, + "name": date.today(), + } + ) + else: + currency_rate.write({"rate": rate}) + + def test_pricelist_based_on_product_category(self): + self.pricelist.item_ids[0].write( + { + "price_discount": 50, + "applied_on": "2_product_category", + "categ_id": self.env.ref("product.product_category_all").id, + } + ) + self.assertAlmostEqual( + self.pricelist._get_product_price(self.product, 1), + 5.0, + ) + + def test_pricelist_based_on_product(self): + self.pricelist.item_ids[0].write( + { + "applied_on": "1_product", + "product_tmpl_id": self.product.product_tmpl_id.id, + } + ) + self.assertAlmostEqual( + self.pricelist._get_product_price(self.product, 1), + 10.0, + ) + + def test_pricelist_based_on_product_variant(self): + self.pricelist.item_ids[0].write( + { + "price_discount": -25, + "applied_on": "0_product_variant", + "product_id": self.product.id, + } + ) + self.assertAlmostEqual( + self.pricelist._get_product_price(self.product, 1), + 12.5, + ) + + def test_pricelist_min_quantity(self): + self.assertAlmostEqual( + self.pricelist._get_product_price(self.product, 1), + 10, + ) + self.assertAlmostEqual( + self.pricelist._get_product_price(self.product, 5), + 50, + ) + self.assertAlmostEqual( + self.pricelist._get_product_price(self.product, 10), + 50, + ) + self.pricelist.item_ids[0].no_supplierinfo_min_quantity = True + self.assertAlmostEqual( + self.pricelist._get_product_price(self.product, 5), + 10, + ) + + def test_pricelist_supplier_filter(self): + self.assertAlmostEqual( + self.pricelist._get_product_price(self.product, 5), + 50, + ) + self.pricelist.item_ids[0].filter_supplier_id = self.supplier2.id + self.assertAlmostEqual( + self.pricelist._get_product_price(self.product, 5), + 10, + ) + + def test_pricelist_dates(self): + """Test pricelist and supplierinfo dates""" + self.product.seller_ids.filtered(lambda x: x.min_qty == 5)[ + 0 + ].date_start = "2018-12-31" + self.assertAlmostEqual( + self.pricelist._get_product_price( + self.product, + 5, + date=date(2019, 1, 1), + ), + 50, + ) + + def test_pricelist_based_price_round(self): + self.pricelist.item_ids[0].write( + { + "price_discount": 50, + "applied_on": "2_product_category", + "categ_id": self.product.categ_id.id, + "price_round": 1, + "price_surcharge": 5, + "price_min_margin": 10, + "price_max_margin": 100, + } + ) + self.assertAlmostEqual( + self.pricelist._get_product_price(self.product, 1), + 20.0, + ) + + def test_pricelist_based_on_sale_margin(self): + self.pricelist.item_ids[0].write( + { + "applied_on": "1_product", + "product_tmpl_id": self.product.product_tmpl_id.id, + } + ) + seller = self.product.seller_ids[0] + seller.sale_margin = 50 + self.assertAlmostEqual( + seller._get_supplierinfo_pricelist_price(), + 75.0, + ) + self.assertAlmostEqual( + self.pricelist._get_product_price(self.product, 6), + 75.0, + ) + + def test_supplierinfo_per_variant(self): + tmpl = self.env["product.template"].create( + { + "name": "Test Product", + "attribute_line_ids": [ + Command.create( + { + "attribute_id": self.env.ref( + "product.product_attribute_1" + ).id, + "value_ids": [ + Command.link( + self.env.ref( + "product.product_attribute_value_1" + ).id, + ), + Command.link( + self.env.ref( + "product.product_attribute_value_2" + ).id, + ), + ], + }, + ) + ], + } + ) + variant1 = tmpl.product_variant_ids[0] + variant2 = tmpl.product_variant_ids[1] + tmpl.write( + { + "seller_ids": [ + Command.create( + { + "partner_id": self.supplier1.id, + "product_id": variant1.id, + "price": 15, + } + ), + Command.create( + { + "partner_id": self.supplier1.id, + "product_id": variant2.id, + "price": 25, + }, + ), + ] + } + ) + self.assertAlmostEqual( + self.pricelist._get_product_price(variant1, 1), + 15.0, + ) + self.assertAlmostEqual( + self.pricelist._get_product_price(variant2, 1), + 25.0, + ) + + def test_pricelist_and_supplierinfo_currencies(self): + """Test when we have 2 records of supplierinfo in two currencies, on a same + pricelist as pricelist items, the currency on the supplier that have a + different currency will be converted to the pricelist's currency. + """ + # Setting the currencies and rates for the test, so we can have a supplierinfo + # and pricelist with different currencies + currency_usd = self.env.ref("base.USD") + currency_mxn = self.env.ref("base.MXN") + self._update_rate(currency_usd, 1) + self._update_rate(currency_mxn, 20) + + # Setting the item with the product + self.pricelist.item_ids[0].write( + { + "applied_on": "0_product_variant", + "product_id": self.product.id, + } + ) + self.product.seller_ids[0].currency_id = currency_mxn + self.pricelist.currency_id = currency_usd + + product_seller_price = self.product.seller_ids[0].price + product_pricelist_price = self.pricelist._get_product_price(self.product, 5) + # The price with MXN Currency will be 50 as is set in the setup + self.assertEqual(product_seller_price, 50) + # And the price with the pricelist (USD Currency) will be 2.5 + self.assertEqual(product_pricelist_price, 2.5) + + def test_line_uom_and_supplierinfo_uom(self): + """Test when we have a product is sold in a different uom from the one on set + for purchase. + """ + # Setting the item with the product + self.pricelist.item_ids[0].write( + { + "applied_on": "0_product_variant", + "product_id": self.product_with_diff_uom.id, + "price_discount": -20, + } + ) + + product_seller_price = self.product_with_diff_uom.seller_ids[0].price + uom_dozen = self.env.ref("uom.product_uom_dozen") + product_pricelist_price_dozen = self.pricelist._get_product_price( + self.product_with_diff_uom.with_context(uom=uom_dozen.id), 1 + ) + uom_unit = self.env.ref("uom.product_uom_unit") + product_pricelist_price_unit = self.pricelist._get_product_price( + self.product_with_diff_uom.with_context(uom=uom_unit.id), 1 + ) + # The price with the will be 1200 on the seller (1 Dozen) + self.assertEqual(product_seller_price, 1200) + + # The price with the will be 1200 plus the increment of the 20% which will + # give us a total of 1440 (1 Dozen) + self.assertEqual(product_pricelist_price_dozen, 1440) + + # And the price with the pricelist and the uom of Units (Instead of Dozen) + # will be 100, plus the 20% the total will be 120 per Unit + self.assertEqual(product_pricelist_price_unit, 120) diff --git a/product_pricelist_supplierinfo/views/product_pricelist_item_views.xml b/product_pricelist_supplierinfo/views/product_pricelist_item_views.xml new file mode 100644 index 00000000000..c0e870c6cb6 --- /dev/null +++ b/product_pricelist_supplierinfo/views/product_pricelist_item_views.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="utf-8" ?> +<odoo> + <record id="product_pricelist_supplier_item_form_view" model="ir.ui.view"> + <field name="name">product.pricelist.item.form</field> + <field name="model">product.pricelist.item</field> + <field name="inherit_id" ref="product.product_pricelist_item_form_view" /> + <field name="arch" type="xml"> + <xpath expr="//field[@name='price_max_margin']/.." position="after"> + <field + invisible="base != 'supplierinfo'" + name="no_supplierinfo_min_quantity" + /> + <field invisible="base != 'supplierinfo'" name="filter_supplier_id" /> + </xpath></field> + </record> +</odoo> diff --git a/product_pricelist_supplierinfo/views/product_supplierinfo_view.xml b/product_pricelist_supplierinfo/views/product_supplierinfo_view.xml new file mode 100644 index 00000000000..fcf823e23c4 --- /dev/null +++ b/product_pricelist_supplierinfo/views/product_supplierinfo_view.xml @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="utf-8" ?> +<odoo> + + <record id="product_supplierinfo_tree_view" model="ir.ui.view"> + <field name="name">product.supplierinfo.tree.view.pricelist</field> + <field name="model">product.supplierinfo</field> + <field name="inherit_id" ref="product.product_supplierinfo_tree_view" /> + <field name="arch" type="xml"> + <field name="price" position="after"> + <field + name="sale_margin" + string="Sale margin" + groups="product_pricelist_supplierinfo.group_supplierinfo_pricelist_sale_margin" + /> + </field> + </field> + </record> + + <record id="product_supplierinfo_form_view" model="ir.ui.view"> + <field name="name">product.supplierinfo.form.view.pricelist</field> + <field name="model">product.supplierinfo</field> + <field name="inherit_id" ref="product.product_supplierinfo_form_view" /> + <field name="arch" type="xml"> + <xpath expr="//label[@for='date_start']" position="before"> + <label + for="sale_margin" + groups="product_pricelist_supplierinfo.group_supplierinfo_pricelist_sale_margin" + /> + <div + groups="product_pricelist_supplierinfo.group_supplierinfo_pricelist_sale_margin" + > + <field name="sale_margin" class="oe_inline" /> + </div> + </xpath> + </field> + </record> + +</odoo>