from unittest import skip

import odoo

from odoo.addons.pos_mrp.tests.common import CommonPosMrpTest
from odoo import Command, fields


@odoo.tests.tagged('post_install', '-at_install')
class TestPosMrp(CommonPosMrpTest):
    def test_bom_kit_order_total_cost(self):
        order, _ = self.create_backend_pos_order({
            'line_data': [
                {'product_id': self.product_product_kit_two.id}
            ],
            'payment_data': [
                {'payment_method_id': self.cash_payment_method.id}
            ]
        })

        self.pos_config_usd.current_session_id.action_pos_session_closing_control()
        self.assertEqual(order.lines[0].total_cost, 20.0)

    @skip('Temporary to fast merge new valuation')
    def test_bom_kit_with_kit_invoice_valuation(self):
        self.product_product_kit_one.categ_id = self.category_fifo_realtime
        self.product_product_kit_two.categ_id = self.category_fifo_realtime
        self.product_product_kit_three.categ_id = self.category_fifo_realtime
        self.product_product_kit_four.categ_id = self.category_fifo_realtime

        order, _ = self.create_backend_pos_order({
            'order_data': {
                'to_invoice': True,
                'partner_id': self.partner_moda.id,
            },
            'line_data': [
                {'product_id': self.product_product_kit_three.id},
                {'product_id': self.product_product_kit_four.id}
            ],
            'payment_data': [
                {'payment_method_id': self.cash_payment_method.id}
            ]
        })

        self.assertEqual(order.lines.filtered(
            lambda l: l.product_id == self.product_product_kit_three).total_cost, 30.0)
        accounts = self.product_product_kit_three.product_tmpl_id.get_product_accounts()
        debit_interim_account = accounts['stock_output']
        credit_expense_account = accounts['expense']
        invoice_accounts = order.account_move.line_ids.mapped('account_id.id')
        self.assertTrue(debit_interim_account.id in invoice_accounts)
        self.assertTrue(credit_expense_account.id in invoice_accounts)
        expense_line = order.account_move.line_ids.filtered(lambda l: l.account_id.id == credit_expense_account.id)
        self.assertEqual(expense_line.filtered(
            lambda l: l.product_id == self.product_product_kit_three).credit, 0.0)
        self.assertEqual(expense_line.filtered(
            lambda l: l.product_id == self.product_product_kit_three).debit, 30.0)
        interim_line = order.account_move.line_ids.filtered(lambda l: l.account_id.id == debit_interim_account.id)
        self.assertEqual(interim_line.filtered(
            lambda l: l.product_id == self.product_product_kit_three).credit, 30.0)
        self.assertEqual(interim_line.filtered(
            lambda l: l.product_id == self.product_product_kit_three).debit, 0.0)
        self.pos_config_usd.current_session_id.action_pos_session_closing_control()

    @skip('Temporary to fast merge new valuation')
    def test_bom_kit_different_uom_invoice_valuation(self):
        """This test make sure that when a kit is made of product using UoM A but the bom line uses UoM B
           the price unit is correctly computed on the invoice lines.
        """
        self.env.user.group_ids += self.env.ref('uom.group_uom')

        # Edit kit product and component product
        self.product_product_kit_one.categ_id = self.category_fifo_realtime
        self.product_product_comp_one.standard_price = 12000
        self.product_product_comp_one.uom_id = self.env.ref('uom.product_uom_dozen').id

        # Edit kit product quantity
        self.bom_one_line.bom_line_ids[0].product_qty = 6.0
        self.bom_one_line.bom_line_ids[0].product_uom_id = self.env.ref('uom.product_uom_unit').id
        self.bom_one_line.product_qty = 2.0

        order, _ = self.create_backend_pos_order({
            'order_data': {
                'to_invoice': True,
                'partner_id': self.partner_moda.id,
            },
            'line_data': [
                {'product_id': self.product_product_kit_one.id, 'qty': 2},
            ],
            'payment_data': [
                {'payment_method_id': self.cash_payment_method.id}
            ]
        })

        accounts = self.product_product_kit_one.product_tmpl_id.get_product_accounts()
        expense_line = order.account_move.line_ids.filtered(
            lambda l: l.account_id.id == accounts['expense'].id)
        interim_line = order.account_move.line_ids.filtered(
            lambda l: l.account_id.id == accounts['stock_output'].id)
        expense_line = expense_line.filtered(lambda l: l.product_id == self.product_product_kit_one)
        interim_line = interim_line.filtered(lambda l: l.product_id == self.product_product_kit_one)

        self.assertEqual(expense_line.debit, 6000.0)
        self.assertEqual(interim_line.credit, 6000.0)

    def test_bom_kit_order_total_cost_with_shared_component(self):
        self.bom_one_line.product_tmpl_id.categ_id = self.category_average
        self.bom_two_lines.product_tmpl_id.categ_id = self.category_average
        kit_1 = self.bom_one_line.product_tmpl_id.product_variant_id
        kit_2 = self.bom_two_lines.product_tmpl_id.product_variant_id

        order, _ = self.create_backend_pos_order({
            'line_data': [
                {'product_id': kit_1.id},
                {'product_id': kit_2.id}
            ],
            'payment_data': [
                {'payment_method_id': self.cash_payment_method.id}
            ]
        })

        self.pos_config_usd.current_session_id.action_pos_session_closing_control()
        self.assertRecordValues(order.lines, [
            {'product_id': kit_1.id, 'total_cost': 10.0},
            {'product_id': kit_2.id, 'total_cost': 20.0},
        ])

    def test_bom_nested_kit_order_total_cost_with_shared_component(self):
        self.bom_one_line.product_tmpl_id.categ_id = self.category_average
        self.bom_two_lines.product_tmpl_id.categ_id = self.category_average
        self.ten_dollars_with_5_incl.standard_price = 30.0
        self.twenty_dollars_with_5_incl.standard_price = 50.0
        kit_1 = self.bom_one_line.copy()
        kit_2 = self.bom_one_line.copy()
        kit_2.product_tmpl_id = self.ten_dollars_with_5_incl
        kit_3 = self.bom_one_line.copy()
        kit_3.product_tmpl_id = self.twenty_dollars_with_5_incl
        kit_3.bom_line_ids[0].product_id = kit_1.product_tmpl_id.product_variant_id

        order, _ = self.create_backend_pos_order({
            'line_data': [
                {'product_id': kit_3.product_tmpl_id.product_variant_id.id},
                {'product_id': kit_2.product_tmpl_id.product_variant_id.id}
            ],
            'payment_data': [
                {'payment_method_id': self.cash_payment_method.id}
            ]
        })

        self.assertRecordValues(order.lines, [
            {'product_id': kit_3.product_tmpl_id.product_variant_id.id, 'total_cost': 50.0},
            {'product_id': kit_2.product_tmpl_id.product_variant_id.id, 'total_cost': 30.0},
        ])

    def test_never_variant_bom_product_picking(self):
        self.attribute_1 = self.env['product.attribute'].create({
            'name': 'Color',
            'create_variant': 'no_variant',
            'sequence': 1,
        })

        # Create attribute values
        self.value_1_1 = self.env['product.attribute.value'].create({
            'name': 'Red',
            'attribute_id': self.attribute_1.id,
            'sequence': 1,
        })
        self.value_1_2 = self.env['product.attribute.value'].create({
            'name': 'Blue',
            'attribute_id': self.attribute_1.id,
            'sequence': 2,
        })

        # Create the configurable product with attributes
        self.configurable_product = self.env['product.product'].create({
            'name': 'Configurable Chair',
            'is_storable': True,
            'available_in_pos': True,
            'list_price': 100,
        })

        ptal = self.env['product.template.attribute.line'].create([{
            'product_tmpl_id': self.configurable_product.product_tmpl_id.id,
            'attribute_id': self.attribute_1.id,
            'value_ids': [Command.set([self.value_1_1.id, self.value_1_2.id])],
        }])

        # Create the component products
        self.component_common = self.env['product.product'].create({
            'name': 'Common Frame',
            'is_storable': True,
            'list_price': 50,
        })

        self.component_red = self.env['product.product'].create({
            'name': 'Red Cushion',
            'is_storable': True,
            'list_price': 20,
        })

        self.component_blue = self.env['product.product'].create({
            'name': 'Blue Cushion',
            'is_storable': True,
            'list_price': 20,
        })

        # Create BOM for the configurable product
        self.bom = self.env['mrp.bom'].create({
            'product_tmpl_id': self.configurable_product.product_tmpl_id.id,
            'product_qty': 1.0,
            'type': 'phantom',  # Kit type
            'bom_line_ids': [
                Command.create({
                    'product_id': self.component_common.id,
                    'product_qty': 1.0,
                }),
                Command.create({
                    'product_id': self.component_red.id,
                    'product_qty': 1.0,
                    'bom_product_template_attribute_value_ids': [
                        Command.link(self.configurable_product.product_tmpl_id.attribute_line_ids[0].product_template_value_ids[0].id)
                    ],
                }),
                Command.create({
                    'product_id': self.component_blue.id,
                    'product_qty': 1.0,
                    'bom_product_template_attribute_value_ids': [
                        Command.link(self.configurable_product.product_tmpl_id.attribute_line_ids[0].product_template_value_ids[1].id)
                    ],
                }),
            ],
        })
        self.pos_config_usd.open_ui()
        current_session = self.pos_config_usd.current_session_id
        pos_order_data = {
                'amount_paid': 100,
                'amount_return': 0,
                'amount_tax': 0,
                'amount_total': 100,
                'date_order': fields.Datetime.to_string(fields.Datetime.now()),
                'fiscal_position_id': False,
                'lines': [
                    Command.create({
                        'attribute_value_ids': [ptal.product_template_value_ids[0].id],
                        'discount': 0,
                        'pack_lot_ids': [],
                        'price_unit': 100.0,
                        'product_id': self.configurable_product.id,
                        'price_subtotal': 100.0,
                        'price_subtotal_incl': 100.0,
                        'qty': 1,
                        'tax_ids': [],
                    }),
                    Command.create({
                        'attribute_value_ids': [ptal.product_template_value_ids[1].id],
                        'discount': 0,
                        'pack_lot_ids': [],
                        'price_unit': 100.0,
                        'product_id': self.configurable_product.id,
                        'price_subtotal': 100.0,
                        'price_subtotal_incl': 100.0,
                        'qty': 1,
                        'tax_ids': [],
                        }),
                ],
                'name': 'Order 12345-123-1234',
                'partner_id': False,
                'session_id': current_session.id,
                'sequence_number': 2,
                'payment_ids': [
                    Command.create({
                        'amount': 100,
                        'name': fields.Datetime.now(),
                        'payment_method_id': self.cash_payment_method.id
                    })
                ],
                'uuid': '12345-123-1234',
                'last_order_preparation_change': '{}',
                'user_id': self.env.uid
            }
        self.env['pos.order'].sync_from_ui([pos_order_data])['pos.order'][0]['id']
        self.assertEqual(len(current_session.picking_ids.move_line_ids), 4)

    def test_bom_variant_exclusive_bom_lines(self):
        """This test make sure that the cost is correctly computed when a product has a BoM with lines linked
              to specific variant."""
        category = self.env['product.category'].create({
            'name': 'Category for kit',
            'property_cost_method': 'fifo',
            'property_valuation': 'real_time',
        })
        attribute_size = self.env['product.attribute'].create({
            'name': 'Size',
            'create_variant': 'always',
            'value_ids': [Command.create({'name': 'S'}), Command.create({'name': 'L'})],
        })
        product_test = self.env['product.template'].create({
            'name': 'Test product',
            'categ_id': category.id,
            'is_storable': True,
            'available_in_pos': True,
            'attribute_line_ids': [Command.create({
                'attribute_id': attribute_size.id,
                'value_ids': [Command.set(attribute_size.value_ids.ids)],
            })],
        })

        component_size = self.env['product.product'].create({
            'name': 'Test Product - Small',
            'standard_price': 10.0,
        })

        self.env['mrp.bom'].create({
            'product_tmpl_id': product_test.id,
            'product_uom_id': product_test.uom_id.id,
            'product_qty': 1.0,
            'type': 'phantom',
            'bom_line_ids': [
                Command.create({
                    'product_id': component_size.id,
                    'product_qty': 1,
                    'bom_product_template_attribute_value_ids': product_test.product_variant_ids[0].product_template_variant_value_ids.ids
                    }),
                Command.create({
                    'product_id': component_size.id,
                    'product_qty': 2,
                    'bom_product_template_attribute_value_ids': product_test.product_variant_ids[1].product_template_variant_value_ids.ids
                    }),
            ]
        })
        product_1 = product_test.product_variant_ids[0]
        product_2 = product_test.product_variant_ids[1]
        self.pos_config_usd.open_ui()
        order = self.env['pos.order'].create({
            'session_id': self.pos_config_usd.current_session_id.id,
            'lines': [(0, 0, {
                'name': product_2.name,
                'product_id': product_2.id,
                'price_unit': product_2.lst_price,
                'qty': 1,
                'tax_ids': [],
                'price_subtotal': product_2.lst_price,
                'price_subtotal_incl': product_2.lst_price,
            }),
            (0, 0, {
                'name': product_1.name,
                'product_id': product_1.id,
                'price_unit': product_1.lst_price,
                'qty': 1,
                'tax_ids': [],
                'price_subtotal': product_1.lst_price,
                'price_subtotal_incl': product_1.lst_price,
            })],
            'pricelist_id': self.pos_config_usd.pricelist_id.id,
            'amount_paid': product_2.lst_price + product_1.lst_price,
            'amount_total': product_2.lst_price + product_1.lst_price,
            'amount_tax': 0.0,
            'amount_return': 0.0,
            'to_invoice': False,
        })
        payment_context = {"active_ids": order.ids, "active_id": order.id}
        order_payment = self.env['pos.make.payment'].with_context(**payment_context).create({
            'amount': order.amount_total,
            'payment_method_id': self.cash_payment_method.id
        })
        order_payment.with_context(**payment_context).check()
        self.pos_config_usd.current_session_id.action_pos_session_closing_control()
        self.assertRecordValues(order.lines, [
            {'product_id': product_2.id, 'total_cost': 20},
            {'product_id': product_1.id, 'total_cost': 10},
        ])

    def test_bom_kit_different_uom_invoice_valuation_2(self):
        """This test make sure that when a kit is made of product using UoM A but the bom line uses UoM B
           the price unit is correctly computed on the invoice lines.
        """
        self.env.user.group_ids += self.env.ref('uom.group_uom')

        # Edit kit product and component product
        self.product_product_kit_one.categ_id = self.category_fifo_realtime
        self.product_product_comp_one.standard_price = 12000
        self.product_product_comp_one.uom_id = self.env.ref('uom.product_uom_dozen').id

        # Edit kit product quantity
        self.bom_one_line.bom_line_ids[0].product_qty = 1
        self.bom_one_line.bom_line_ids[0].product_uom_id = self.env.ref('uom.product_uom_unit').id
        self.bom_one_line.product_qty = 1

        order, _ = self.create_backend_pos_order({
            'order_data': {
                'to_invoice': True,
                'partner_id': self.partner_moda.id,
            },
            'line_data': [
                {'product_id': self.product_product_kit_one.id, 'qty': 1},
            ],
            'payment_data': [
                {'payment_method_id': self.cash_payment_method.id}
            ]
        })
        self.assertEqual(order.lines[0].total_cost, 1000.0)


# TODO : Merge this test with the other class when it is not skipped anymore
@odoo.tests.tagged('post_install', '-at_install')
class TestPosMrpTemp(CommonPosMrpTest):
    def test_bom_kit_different_uom_invoice_valuation_no_invoice(self):
        """This test make sure that when a kit is made of product using UoM A but the bom line uses UoM B
           the price unit is correctly computed on the invoice lines.
        """
        self.env.user.group_ids += self.env.ref('uom.group_uom')
        self.env.company.inventory_valuation = 'real_time'
        # Edit kit product and component product
        self.product_product_kit_one.categ_id = self.category_fifo_realtime
        self.product_product_comp_one.standard_price = 12000
        self.product_product_comp_one.uom_id = self.env.ref('uom.product_uom_dozen').id
        self.product_product_comp_one.categ_id = self.category_fifo_realtime
        self.product_product_comp_one.is_storable = True

        # Edit kit product UoM
        self.bom_one_line.bom_line_ids[0].product_uom_id = self.env.ref('uom.product_uom_unit').id

        self.create_backend_pos_order({
            'order_data': {
                'partner_id': self.partner_moda.id,
            },
            'line_data': [
                {'product_id': self.product_product_kit_one.id, 'qty': 1},
            ],
            'payment_data': [
                {'payment_method_id': self.cash_payment_method.id}
            ]
        })

        current_session = self.pos_config_usd.current_session_id
        current_session.action_pos_session_closing_control()

        accounts = self.product_product_kit_one.product_tmpl_id.get_product_accounts()
        expense_line = current_session.move_id.line_ids.filtered(
            lambda l: l.account_id.id == accounts['expense'].id)
        interim_line = current_session.move_id.line_ids.filtered(
            lambda l: l.account_id.id == accounts['stock_valuation'].id)

        self.assertEqual(expense_line.debit, 1000.0)
        self.assertEqual(interim_line.credit, 1000.0)
