# Copyright 2023 Moduon Team S.L.
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl-3.0)
from odoo import fields
from odoo.tests import Form

from odoo.addons.product.tests.common import ProductCommon


class SalePackagingDefaultCase(ProductCommon):
    @classmethod
    def setUpClass(cls):
        super().setUpClass()
        cls.env.user.groups_id |= cls.env.ref("product.group_stock_packaging")
        with Form(cls.product) as product_f:
            with product_f.packaging_ids.new() as packaging_f:
                packaging_f.name = "Dozen"
                packaging_f.qty = 12
                packaging_f.sales = True
                packaging_f.sequence = 20
            with product_f.packaging_ids.new() as packaging_f:
                packaging_f.name = "Big box"
                packaging_f.qty = 100
                packaging_f.sales = True
                packaging_f.sequence = 10  # This is the default one
        cls.big_box, cls.dozen = cls.product.packaging_ids
        assert cls.dozen.name == "Dozen"
        assert cls.big_box.name == "Big box"
        cls.product2 = cls.env["product.product"].create(
            {
                "name": "Product 2",
                "type": "consu",
                "packaging_ids": [
                    fields.Command.create(
                        {
                            "name": "3-pack",
                            "qty": 3,
                            "sales": True,
                            "sequence": 10,
                        }
                    ),
                ],
            }
        )
        cls.p2_three_pack = cls.product2.packaging_ids[0]
        assert cls.p2_three_pack.name == "3-pack"
        cls.product_packaging_qty_no_integer = cls.env["product.product"].create(
            {
                "name": "Product packaging with qty not integer",
                "type": "consu",
                "packaging_ids": [
                    fields.Command.create(
                        {
                            "name": "1 Piece",
                            "qty": 1.6,
                            "sales": True,
                            "sequence": 10,
                        }
                    ),
                ],
            }
        )
        cls.packaging = cls.product_packaging_qty_no_integer.packaging_ids

    def test_default_packaging_sale_order(self):
        """Check is packaging usage in sale order."""
        # Create a sale order with the product
        so_f = Form(self.env["sale.order"])
        so_f.partner_id = self.partner
        with so_f.order_line.new() as line_f:
            line_f.product_id = self.product
            # Automatically set the default packaging and the quantity
            self.assertEqual(line_f.product_packaging_id, self.big_box)
            self.assertEqual(line_f.product_packaging_qty, 1)
            self.assertEqual(line_f.product_uom_qty, 100)
            # Change the packaging, and qtys are recalculated
            line_f.product_packaging_id = self.dozen
            self.assertEqual(line_f.product_packaging_qty, 1)
            self.assertEqual(line_f.product_uom_qty, 12)
            # Change product qty, and packaging is recalculated
            line_f.product_uom_qty = 1200
            self.assertEqual(line_f.product_packaging_qty, 12)
            self.assertEqual(line_f.product_packaging_id, self.big_box)
            self.assertEqual(line_f.product_uom_qty, 1200)
            # I want it in dozens, so I change the packaging
            line_f.product_packaging_id = self.dozen
            self.assertEqual(line_f.product_packaging_id, self.dozen)
            self.assertEqual(line_f.product_uom_qty, 1200)
            self.assertEqual(line_f.product_packaging_qty, 100)
            # I want less dozens, so I change the packaging qty
            line_f.product_packaging_qty = 90
            self.assertEqual(line_f.product_packaging_id, self.dozen)
            self.assertEqual(line_f.product_uom_qty, 1080)
            # Change the packaging again, and qtys are recalculated
            line_f.product_packaging_id = self.big_box
            self.assertEqual(line_f.product_packaging_qty, 1)
            self.assertEqual(line_f.product_uom_qty, 100)
            # I want more units, so I change the uom qty
            line_f.product_uom_qty = 120
            self.assertEqual(line_f.product_packaging_qty, 10)
            self.assertEqual(line_f.product_packaging_id, self.dozen)
            # If I set a uom qty without packaging, it is emptied
            line_f.product_uom_qty = 7
            self.assertFalse(line_f.product_packaging_id)
            self.assertEqual(line_f.product_packaging_qty, 0)
            self.assertEqual(line_f.product_uom_qty, 7)
            # Setting zero uom qty resets to the default packaging
            line_f.product_uom_qty = 0
            self.assertEqual(line_f.product_packaging_id, self.big_box)
            self.assertEqual(line_f.product_packaging_qty, 0)
            self.assertEqual(line_f.product_uom_qty, 0)

    def test_sale_order_product_picker_compatibility(self):
        """Emulate a call done by the product picker module and see it works.

        This test asserts support for cross-compatibility with
        `sale_order_product_picker`.
        """
        so_f = Form(
            self.env["sale.order"].with_context(
                default_product_id=self.product.id, default_price_unit=20
            )
        )
        so_f.partner_id = self.partner
        # User clicks on +1 button
        with so_f.order_line.new() as line_f:
            self.assertEqual(line_f.product_uom_qty, 1)
            self.assertFalse(line_f.product_packaging_id)

    def test_product_change(self):
        """Set one product, alter qtys, change product, qtys are reset."""
        so_f = Form(self.env["sale.order"])
        so_f.partner_id = self.partner
        with so_f.order_line.new() as line_f:
            line_f.product_id = self.product
            self.assertEqual(line_f.product_packaging_id, self.big_box)
            self.assertEqual(line_f.product_packaging_qty, 1)
            self.assertEqual(line_f.product_uom_qty, 100)
            line_f.product_uom_qty = 120
            self.assertEqual(line_f.product_packaging_id, self.dozen)
            self.assertEqual(line_f.product_packaging_qty, 10)
            self.assertEqual(line_f.product_uom_qty, 120)
            line_f.product_id = self.product2
            self.assertEqual(line_f.product_packaging_id, self.p2_three_pack)
            self.assertEqual(line_f.product_packaging_qty, 10)
            self.assertEqual(line_f.product_uom_qty, 30)

    def test_product_packaging_qty_no_integer(self):
        """Check behavior with float qty in packaging without using modulo operator.

        If product_packaging_qty is multiple of qty pacakging, with modulo operator the
        quantity per package might be a float. Example # 8 % 1.6 = 1.5999999999999996
        """
        so_f = Form(self.env["sale.order"])
        so_f.partner_id = self.partner
        with so_f.order_line.new() as line_f:
            line_f.product_id = self.product_packaging_qty_no_integer
            # Automatically set the default packaging and the quantity
            self.assertEqual(line_f.product_packaging_id, self.packaging)
            self.assertEqual(line_f.product_packaging_qty, 1)
            self.assertEqual(line_f.product_uom_qty, 1.6)
            # Change qty to 8 to force calculate with modulo operator
            # (8 % 1.6 = 1.5999999999999996)
            line_f.product_packaging_qty = 5
            self.assertEqual(line_f.product_packaging_id, self.packaging)
            self.assertEqual(line_f.product_uom_qty, 8)
