# Part of Odoo. See LICENSE file for full copyright and licensing details.

from odoo.fields import Command
from odoo.tests import Form, tagged
from odoo.tools import html2plaintext


from odoo.addons.sale.tests.common import TestSaleCommon
from odoo.addons.stock.tests.test_report import TestReportsCommon


@tagged('post_install', '-at_install')
class TestSaleMrpInvoices(TestSaleCommon):

    @classmethod
    def setUpClass(cls):
        super().setUpClass()

        cls.product_by_lot = cls.env['product.product'].create({
            'name': 'Product By Lot',
            'is_storable': True,
            'tracking': 'lot',
        })
        cls.warehouse = cls.env['stock.warehouse'].search([('company_id', '=', cls.env.company.id)], limit=1)
        cls.stock_location = cls.warehouse.lot_stock_id
        cls.lot = cls.env['stock.lot'].create({
            'name': 'LOT0001',
            'product_id': cls.product_by_lot.id,
        })
        cls.env['stock.quant']._update_available_quantity(cls.product_by_lot, cls.stock_location, 10, lot_id=cls.lot)

        cls.tracked_kit = cls.env['product.product'].create({
            'name': 'Simple Kit',
            'type': 'consu',
        })
        cls.env['mrp.bom'].create({
            'product_tmpl_id': cls.tracked_kit.product_tmpl_id.id,
            'type': 'phantom',
            'bom_line_ids': [(0, 0, {
                'product_id': cls.product_by_lot.id,
                'product_qty': 1,
            })]
        })

    def test_deliver_and_invoice_tracked_components(self):
        """
        Suppose the lots are printed on the invoices.
        The user sells a kit that has one tracked component.
        The lot of the delivered component should be on the invoice.
        """
        display_lots = self.env.ref('stock_account.group_lot_on_invoice')
        display_uom = self.env.ref('uom.group_uom')
        self.env.user.write({'group_ids': [(4, display_lots.id), (4, display_uom.id)]})

        so = self.env['sale.order'].create({
            'partner_id': self.partner.id,
            'order_line': [
                (0, 0, {'name': self.tracked_kit.name, 'product_id': self.tracked_kit.id, 'product_uom_qty': 1}),
            ],
        })
        so.action_confirm()

        so.picking_ids.button_validate()

        invoice = so._create_invoices()
        invoice.action_post()

        html = self.env['ir.actions.report']._render_qweb_html(
            'account.report_invoice_with_payments', invoice.ids)[0]
        text = html2plaintext(html.decode())
        self.assertRegex(text, r'Product By Lot\n1.00Units\nLOT0001', "There should be a line that specifies 1 x LOT0001")

    def test_report_forecast_for_mto_procure_method(self):
        """
        Check that mto moves are not reported as taking from stock in the forecast report
        """
        mto_route = self.env.ref('stock.route_warehouse0_mto')
        mto_route.active = True
        manufacturing_route = self.env.ref('mrp.route_warehouse0_manufacture')
        product = self.env['product.product'].create({
            'name': 'SuperProduct',
            'is_storable': True,
            'route_ids': [Command.set((mto_route + manufacturing_route).ids)]
        })

        product.bom_ids = [Command.create({
            'product_id': product.id,
            'product_tmpl_id': product.product_tmpl_id.id,
            'product_uom_id': product.uom_id.id,
            'bom_line_ids': [Command.create({
                'product_id': self.product_by_lot.id,
                'product_qty': 1,
            })]
        })]
        warehouse = self.warehouse
        # make 2 so: so_1 can be fulfilled and so_2 requires a replenishment
        self.env['stock.quant']._update_available_quantity(product, warehouse.lot_stock_id, 10.0)
        so_1, so_2 = self.env['sale.order'].create([
            {
                'partner_id': self.partner_a.id,
                'order_line': [Command.create({
                    'name': product.name,
                    'product_id': product.id,
                    'product_uom_qty': 8.0,
                    'price_unit': product.list_price,
                })]
            },
            {
                'partner_id': self.partner_a.id,
                'order_line': [Command.create({
                    'name': product.name,
                    'product_id': product.id,
                    'product_uom_qty': 7.0,
                    'price_unit': product.list_price,
                })]
            },

        ])
        (so_1 | so_2).action_confirm()
        report_lines = self.env['stock.forecasted_product_product'].with_context(warehouse=warehouse.id).get_report_values(docids=product.ids)['docs']['lines']
        self.assertEqual(len(report_lines), 3)
        so_1_line = report_lines[0]
        self.assertEqual(
            [so_1_line['quantity'], so_1_line['move_out']['id'], so_1_line['replenishment_filled']],
            [8.0, so_1.picking_ids.move_ids.id, True]
        )
        so_2_line = report_lines[1]
        self.assertEqual(
            [so_2_line['quantity'], so_2_line['move_out']['id'], so_2_line['replenishment_filled']],
            [7.0, so_2.picking_ids.move_ids.id, True]
        )
        replenisment_line = report_lines[2]
        self.assertEqual(
            [replenisment_line['document_in'], replenisment_line['document_out'], replenisment_line['quantity'], replenisment_line['move_out'], replenisment_line['replenishment_filled']],
            [False, False, 10.0, None, True]
        )


class TestSaleMrpReports(TestReportsCommon):

    def test_forecast_report_shows_mo_for_mto_manufacture(self):
        """Ensure forecast report shows Manufacturing Order as source
        for MTO manufactured products."""
        # Enable MTO route
        warehouse = self.env['stock.warehouse'].search([('company_id', '=', self.env.company.id)], limit=1)
        mto_route = warehouse.mto_pull_id.route_id
        mto_route.active = True
        self.product.route_ids = [Command.link(mto_route.id)]
        # Create component and BOM
        component = self.env['product.product'].create({'name': 'Component'})
        self.env['mrp.bom'].create({
            'product_tmpl_id': self.product_template.id,
            'bom_line_ids': [Command.create({'product_id': component.id})],
        })
        # Create and confirm SO
        so_form = Form(self.env['sale.order'])
        so_form.partner_id = self.partner
        with so_form.order_line.new() as line:
            line.product_id = self.product
        so = so_form.save()
        so.action_confirm()
        # Get forecast report
        _, _, lines = self.get_report_forecast(product_template_ids=self.product_template.ids)
        self.assertEqual(len(lines), 1)
        self.assertEqual(lines[0]['document_in']['id'], so.mrp_production_ids.id)
        self.assertEqual(lines[0]['document_out']['id'], so.id)
