diff --git a/fermente_purchase_quick/i18n/fr.po b/fermente_purchase_quick/i18n/fr.po index 3e850e7a4..d3750f3e3 100644 --- a/fermente_purchase_quick/i18n/fr.po +++ b/fermente_purchase_quick/i18n/fr.po @@ -1,87 +1,99 @@ # Translation of Odoo Server. # This file contains the translation of the following modules: -# * grap_change_base_product_mass_addition +# * fermente_purchase_quick # msgid "" msgstr "" -"Project-Id-Version: Odoo Server 12.0\n" +"Project-Id-Version: Odoo Server 16.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-11-16 00:21+0000\n" -"PO-Revision-Date: 2020-11-16 00:21+0000\n" -"Last-Translator: <>\n" +"POT-Creation-Date: 2026-03-11 19:02+0000\n" +"PO-Revision-Date: 2026-03-11 19:02+0000\n" +"Last-Translator: \n" "Language-Team: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: \n" "Plural-Forms: \n" -#. module: grap_change_base_product_mass_addition -#: model_terms:ir.ui.view,arch_db:grap_change_base_product_mass_addition.view_product_product_tree +#. module: fermente_purchase_quick +#: model_terms:ir.ui.view,arch_db:fermente_purchase_quick.view_product_product_tree msgid "Disc 1" msgstr "Rem. 1" -#. module: grap_change_base_product_mass_addition -#: model_terms:ir.ui.view,arch_db:grap_change_base_product_mass_addition.view_product_product_tree +#. module: fermente_purchase_quick +#: model_terms:ir.ui.view,arch_db:fermente_purchase_quick.view_product_product_tree msgid "Disc 2" msgstr "Rem. 2" -#. module: grap_change_base_product_mass_addition -#: model:ir.model.fields,field_description:grap_change_base_product_mass_addition.field_product_product__mass_addition_purchase_discount -msgid "Mass Addition Purchase Discount" +#. module: fermente_purchase_quick +#: model:ir.model.fields,field_description:fermente_purchase_quick.field_product_product__mass_addition_purchase_discount1 +msgid "Mass Addition Purchase Discount1" msgstr "" -#. module: grap_change_base_product_mass_addition -#: model:ir.model.fields,field_description:grap_change_base_product_mass_addition.field_product_product__mass_addition_purchase_discount2 +#. module: fermente_purchase_quick +#: model:ir.model.fields,field_description:fermente_purchase_quick.field_product_product__mass_addition_purchase_discount2 msgid "Mass Addition Purchase Discount2" msgstr "" -#. module: grap_change_base_product_mass_addition -#: model:ir.model.fields,field_description:grap_change_base_product_mass_addition.field_product_product__mass_addition_purchase_min_qty +#. module: fermente_purchase_quick +#: model:ir.model.fields,field_description:fermente_purchase_quick.field_product_product__mass_addition_purchase_min_qty msgid "Mass Addition Purchase Min Qty" msgstr "" -#. module: grap_change_base_product_mass_addition -#: model:ir.model.fields,field_description:grap_change_base_product_mass_addition.field_product_product__mass_addition_purchase_min_qty_bad +#. module: fermente_purchase_quick +#: model:ir.model.fields,field_description:fermente_purchase_quick.field_product_product__mass_addition_purchase_min_qty_bad msgid "Mass Addition Purchase Min Qty Bad" msgstr "" -#. module: grap_change_base_product_mass_addition -#: model:ir.model.fields,field_description:grap_change_base_product_mass_addition.field_product_product__mass_addition_purchase_multiplier_qty +#. module: fermente_purchase_quick +#: model:ir.model.fields,field_description:fermente_purchase_quick.field_product_product__mass_addition_purchase_multiplier_qty msgid "Mass Addition Purchase Multiplier Qty" msgstr "" -#. module: grap_change_base_product_mass_addition -#: model:ir.model.fields,field_description:grap_change_base_product_mass_addition.field_product_product__mass_addition_purchase_multiplier_qty_bad +#. module: fermente_purchase_quick +#: model:ir.model.fields,field_description:fermente_purchase_quick.field_product_product__mass_addition_purchase_multiplier_qty_bad msgid "Mass Addition Purchase Multiplier Qty Bad" msgstr "" -#. module: grap_change_base_product_mass_addition -#: model:ir.model.fields,field_description:grap_change_base_product_mass_addition.field_product_product__mass_addition_purchase_price -msgid "Mass Addition Purchase Price" -msgstr "" - -#. module: grap_change_base_product_mass_addition -#: model_terms:ir.ui.view,arch_db:grap_change_base_product_mass_addition.view_product_product_tree +#. module: fermente_purchase_quick +#: model_terms:ir.ui.view,arch_db:fermente_purchase_quick.view_product_product_tree msgid "Min Qty" msgstr "Qté Min." -#. module: grap_change_base_product_mass_addition -#: model_terms:ir.ui.view,arch_db:grap_change_base_product_mass_addition.view_product_product_tree +#. module: fermente_purchase_quick +#: model_terms:ir.ui.view,arch_db:fermente_purchase_quick.view_product_product_tree msgid "Multiplier Qty" msgstr "Qté Cond." -#. module: grap_change_base_product_mass_addition -#: model_terms:ir.ui.view,arch_db:grap_change_base_product_mass_addition.view_product_product_tree -msgid "Price" -msgstr "Prix" - -#. module: grap_change_base_product_mass_addition -#: model:ir.model,name:grap_change_base_product_mass_addition.model_product_product -msgid "Product" -msgstr "Article" +#. module: fermente_purchase_quick +#: model:ir.model,name:fermente_purchase_quick.model_product_product +msgid "Product Variant" +msgstr "Variante de produit" +#. module: fermente_purchase_quick +#. odoo-python +#: code:addons/fermente_purchase_quick/models/product_product.py:0 +#, python-format +msgid "" +"Quantity was too small.\n" +"The quantity has been automatically changed to %(qty)s %(uom)s." +msgstr "" +"La quantité était trop petite.\n" +"Elle a été changé automatiquement en %(qty)s %(uom)s." -#. module: grap_change_base_product_mass_addition -#: model_terms:ir.ui.view,arch_db:grap_change_base_product_mass_addition.view_product_product_tree -msgid "Purchase UoM" -msgstr "UdM d'Achat" +#. module: fermente_purchase_quick +#. odoo-python +#: code:addons/fermente_purchase_quick/models/product_product.py:0 +#, python-format +msgid "" +"The supplier only sells this product by %(mult)s %(uom)s.\n" +"The quantity has been automatically changed to %(qty)s %(uom)s." +msgstr "" +"Læ fournisseurse vend se produit seulement par %(mult)s %(uom)s. \n" +"Elle a été changé automatiquement en %(qty)s %(uom)s." +#. module: fermente_purchase_quick +#. odoo-python +#: code:addons/fermente_purchase_quick/models/product_product.py:0 +#, python-format +msgid "Warning" +msgstr "Attention" \ No newline at end of file diff --git a/fermente_purchase_quick/models/product_product.py b/fermente_purchase_quick/models/product_product.py index a00e0c2f4..cbee506b3 100644 --- a/fermente_purchase_quick/models/product_product.py +++ b/fermente_purchase_quick/models/product_product.py @@ -2,7 +2,9 @@ # @author: Sylvain LE GAL (https://twitter.com/legalsylvain) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -from odoo import api, fields, models +import math + +from odoo import _, api, fields, models class ProductProduct(models.Model): @@ -65,3 +67,54 @@ def _compute_mass_addition_purchase(self): product.mass_addition_purchase_multiplier_qty = seller.multiplier_qty product.mass_addition_purchase_discount1 = seller.discount1 product.mass_addition_purchase_discount2 = seller.discount2 + + def _inverse_set_process_qty(self): + if self.env.context.get("parent_model") != "purchase.order": + return super()._inverse_set_process_qty() + + for product in self: + user_qty = product.qty_to_process or 0.0 + min_qty = product.mass_addition_purchase_min_qty or 0.0 + mult = product.mass_addition_purchase_multiplier_qty or 0.0 + + # Respect minimum quantity + target_qty = max(user_qty, min_qty) + changeby = "min_qty" if target_qty != user_qty else False + + # Respect multiplier + new_qty = target_qty + if mult: + new_qty = math.ceil(target_qty / mult) * mult + if new_qty != target_qty: + changeby = "mult" + + if changeby == "min_qty": + message = _( + "Quantity was too small.\n" + "The quantity has been automatically changed to %(qty)s %(uom)s." + ) % { + "qty": target_qty, + "uom": product.uom_name, + } + + elif changeby == "mult": + message = _( + "The supplier only sells this product by %(mult)s %(uom)s.\n" + "The quantity has been automatically changed to %(qty)s %(uom)s." + ) % { + "mult": mult, + "qty": new_qty, + "uom": product.uom_name, + } + + else: + continue + + self.env.user.notify_warning( + title=_("Warning"), + message=message, + ) + + product.qty_to_process = new_qty + + return super()._inverse_set_process_qty() diff --git a/fermente_purchase_quick/tests/__init__.py b/fermente_purchase_quick/tests/__init__.py new file mode 100644 index 000000000..782ea99bb --- /dev/null +++ b/fermente_purchase_quick/tests/__init__.py @@ -0,0 +1 @@ +from . import test_fermente_purchase_quick diff --git a/fermente_purchase_quick/tests/test_fermente_purchase_quick.py b/fermente_purchase_quick/tests/test_fermente_purchase_quick.py new file mode 100644 index 000000000..19c673ec0 --- /dev/null +++ b/fermente_purchase_quick/tests/test_fermente_purchase_quick.py @@ -0,0 +1,89 @@ +# @author Quentin DUPONT +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo.tests import tagged +from odoo.tests.common import Form, TransactionCase + + +# Inspired by OCA/purchase_workflow/purchase_quick tests +@tagged("post_install", "-at_install") +class TestFermentePurchaseQuick(TransactionCase): + @classmethod + def _add_seller(cls, product, sellers): + product.seller_ids.filtered(lambda s: s.partner_id == cls.partner).unlink() + + for seller in sellers: + cls.env["product.supplierinfo"].create( + { + "product_tmpl_id": product.product_tmpl_id.id, + "partner_id": cls.partner.id, + "min_qty": seller.get("min_qty", 0), + "price": seller.get("price", 0), + "multiplier_qty": seller.get("multiplier_qty", 0), + "discount": seller.get("discount", 0), + "discount2": seller.get("discount2", 0), + } + ) + + @classmethod + def _setUpBasicPurchaseOrder(cls): + vals = {"partner_id": cls.partner.id} + if hasattr(cls.env["purchase.order"], "order_type"): + vals["order_type"] = cls.env.ref("purchase_order_type.po_type_blanket").id + cls.po = cls.env["purchase.order"].create(vals) + with Form(cls.po, "purchase.purchase_order_form") as po_form: + po_form.partner_id = cls.partner + ctx = {"parent_id": cls.po.id, "parent_model": "purchase.order"} + cls.product_1 = cls.product_1.with_context(**ctx) + cls.product_2 = cls.product_2.with_context(**ctx) + + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.partner = cls.env.ref("base.res_partner_1") + cls.product_1 = cls.env.ref("product.product_product_8") + cls.product_2 = cls.env.ref("product.product_product_11") + + cls._add_seller( + cls.product_1, + [ + {"min_qty": 0, "price": 117, "multiplier_qty": 2}, + {"min_qty": 40, "price": 217, "multiplier_qty": 20}, + ], + ) + + cls._add_seller( + cls.product_2, + [ + {"min_qty": 3, "price": 1789, "multiplier_qty": 5}, + ], + ) + + cls._setUpBasicPurchaseOrder() + + # With Product 01, get the right supplier price → + # for the moment the price link to the lowest min_qty + def test_01_supplier_price_selection(self): + self.product_1.qty_to_process = 12 # whatever + self.assertEqual(self.product_1.seller_price, 117) + + # With Product 02, multiplier quantity 5 should be bad + # but inverse function change it + def test_02_multiplier_bad(self): + self.product_2.qty_to_process = 4 + self.assertAlmostEqual(self.product_2.qty_to_process, 5) + + # With Product 02 multiplier quantity 6 is ok and qty not changed + def test_03_multiplier_ok(self): + self.product_2.qty_to_process = 10 + self.assertAlmostEqual(self.product_2.qty_to_process, 10) + + # With Product 03, minimum quantity 2 will be bad + def test_04_min_qty_bad(self): + self.product_2.qty_to_process = 2 + self.assertAlmostEqual(self.product_2.qty_to_process, 5) + + # With Product 03, minimum quantity bad + multiplier + def test_05_min_qty_ok(self): + self.product_2.qty_to_process = 11 + self.assertAlmostEqual(self.product_2.qty_to_process, 15)