# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.

from odoo.tests import Form
from odoo.addons.mail.tests.common import mail_new_test_user
from odoo.addons.stock.tests.test_report import TestReportsCommon


class TestPurchaseStockReports(TestReportsCommon):
    def test_report_forecast_1_purchase_order_multi_receipt(self):
        """ Create a PO for 5 product, receive them then increase the quantity to 10.
        """
        po_form = Form(self.env['purchase.order'])
        po_form.partner_id = self.partner
        with po_form.order_line.new() as line:
            line.product_id = self.product
            line.product_qty = 5
        po = po_form.save()

        # Checks the report.
        report_values, docs, lines = self.get_report_forecast(product_template_ids=self.product_template.ids)
        draft_picking_qty_in = docs['draft_picking_qty']['in']
        draft_purchase_qty = docs['draft_purchase_qty']
        pending_qty_in = docs['qty']['in']
        self.assertEqual(len(lines), 0, "Must have 0 line for now.")
        self.assertEqual(draft_picking_qty_in, 0)
        self.assertEqual(draft_purchase_qty, 5)
        self.assertEqual(pending_qty_in, 5)

        # Confirms the PO and checks the report again.
        po.button_confirm()
        report_values, docs, lines = self.get_report_forecast(product_template_ids=self.product_template.ids)
        draft_picking_qty_in = docs['draft_picking_qty']['in']
        draft_purchase_qty = docs['draft_purchase_qty']
        pending_qty_in = docs['qty']['in']
        self.assertEqual(len(lines), 1)
        self.assertEqual(lines[0]['document_in']['id'], po.id)
        self.assertEqual(lines[0]['quantity'], 5)
        self.assertEqual(lines[0]['document_out'], False)
        self.assertEqual(draft_picking_qty_in, 0)
        self.assertEqual(draft_purchase_qty, 0)
        self.assertEqual(pending_qty_in, 0)

        # Receives 5 products.
        receipt = po.picking_ids
        receipt.button_validate()
        report_values, docs, lines = self.get_report_forecast(product_template_ids=self.product_template.ids)
        draft_picking_qty_in = docs['draft_picking_qty']['in']
        draft_purchase_qty = docs['draft_purchase_qty']
        pending_qty_in = docs['qty']['in']
        self.assertEqual(len(lines), 0)
        self.assertEqual(draft_picking_qty_in, 0)
        self.assertEqual(draft_purchase_qty, 0)
        self.assertEqual(pending_qty_in, 0)

        # Increase the PO quantity to 10, so must create a second receipt.
        po_form = Form(po)
        with po_form.order_line.edit(0) as line:
            line.product_qty = 10
        po = po_form.save()
        # Checks the report.
        report_values, docs, lines = self.get_report_forecast(product_template_ids=self.product_template.ids)
        draft_picking_qty_in = docs['draft_picking_qty']['in']
        draft_purchase_qty = docs['draft_purchase_qty']
        pending_qty_in = docs['qty']['in']
        self.assertEqual(len(lines), 1, "Must have 1 line for now.")
        self.assertEqual(lines[0]['document_in']['id'], po.id)
        self.assertEqual(lines[0]['quantity'], 5)
        self.assertEqual(draft_picking_qty_in, 0)
        self.assertEqual(draft_purchase_qty, 0)
        self.assertEqual(pending_qty_in, 0)

    def test_report_forecast_2_purchase_order_three_step_receipt(self):
        """ Create a PO for 4 product, receive them then increase the quantity
        to 10, but use three steps receipt.
        """
        grp_multi_loc = self.env.ref('stock.group_stock_multi_locations')
        grp_multi_routes = self.env.ref('stock.group_adv_location')
        self.env.user.write({'groups_id': [(4, grp_multi_loc.id)]})
        self.env.user.write({'groups_id': [(4, grp_multi_routes.id)]})
        # Configure warehouse.
        warehouse = self.env.ref('stock.warehouse0')
        warehouse.reception_steps = 'three_steps'

        po_form = Form(self.env['purchase.order'])
        po_form.partner_id = self.partner
        with po_form.order_line.new() as line:
            line.product_id = self.product
            line.product_qty = 4
        po = po_form.save()

        # Checks the report -> Must be empty for now, just display some pending qty.
        report_values, docs, lines = self.get_report_forecast(product_template_ids=self.product_template.ids)
        draft_picking_qty_in = docs['draft_picking_qty']['in']
        draft_purchase_qty = docs['draft_purchase_qty']
        pending_qty_in = docs['qty']['in']
        self.assertEqual(len(lines), 0, "Must have 0 line for now.")
        self.assertEqual(draft_picking_qty_in, 0)
        self.assertEqual(draft_purchase_qty, 4)
        self.assertEqual(pending_qty_in, 4)

        # Confirms the PO and checks the report again.
        po.button_confirm()
        report_values, docs, lines = self.get_report_forecast(product_template_ids=self.product_template.ids)
        draft_picking_qty_in = docs['draft_picking_qty']['in']
        draft_purchase_qty = docs['draft_purchase_qty']
        pending_qty_in = docs['qty']['in']
        self.assertEqual(len(lines), 1)
        self.assertEqual(lines[0]['document_in']['id'], po.id)
        self.assertEqual(lines[0]['quantity'], 4)
        self.assertEqual(lines[0]['document_out'], False)
        self.assertEqual(draft_picking_qty_in, 0)
        self.assertEqual(draft_purchase_qty, 0)
        self.assertEqual(pending_qty_in, 0)
        # Get back the different transfers.
        receipt = po.picking_ids

        # Receives 4 products.
        receipt.button_validate()
        report_values, docs, lines = self.get_report_forecast(product_template_ids=self.product_template.ids)
        draft_picking_qty_in = docs['draft_picking_qty']['in']
        draft_purchase_qty = docs['draft_purchase_qty']
        pending_qty_in = docs['qty']['in']
        self.assertEqual(len(lines), 0)
        self.assertEqual(draft_picking_qty_in, 0)
        self.assertEqual(draft_purchase_qty, 0)
        self.assertEqual(pending_qty_in, 0)

        # Increase the PO quantity to 10, so must create a second receipt.
        po_form = Form(po)
        with po_form.order_line.edit(0) as line:
            line.product_qty = 10
        po = po_form.save()
        # Checks the report.
        report_values, docs, lines = self.get_report_forecast(product_template_ids=self.product_template.ids)
        draft_picking_qty_in = docs['draft_picking_qty']['in']
        draft_purchase_qty = docs['draft_purchase_qty']
        pending_qty_in = docs['qty']['in']
        self.assertEqual(len(lines), 1)
        self.assertEqual(lines[0]['document_in']['id'], po.id)
        self.assertEqual(lines[0]['quantity'], 6)
        self.assertEqual(draft_picking_qty_in, 0)
        self.assertEqual(draft_purchase_qty, 0)
        self.assertEqual(pending_qty_in, 0)

    def test_report_forecast_3_report_line_corresponding_to_po_line_highlighted(self):
        """ When accessing the report from a PO line, checks if the correct PO line is highlighted in the report
        """
        # We create 2 identical PO
        po_form = Form(self.env['purchase.order'])
        po_form.partner_id = self.partner
        with po_form.order_line.new() as line:
            line.product_id = self.product
            line.product_qty = 5
        po1 = po_form.save()
        po1.button_confirm()
        po2 = po1.copy()
        po2.button_confirm()

        # Check for both PO if the highlight (is_matched) corresponds to the correct PO
        for po in [po1, po2]:
            context = po.order_line[0].action_product_forecast_report()['context']
            _, _, lines = self.get_report_forecast(product_template_ids=self.product_template.ids, context=context)
            for line in lines:
                if line['document_in']['id'] == po.id:
                    self.assertTrue(line['is_matched'], "The corresponding PO line should be matched in the forecast report.")
                else:
                    self.assertFalse(line['is_matched'], "A line of the forecast report not linked to the PO shoud not be matched.")

    def test_approval_and_forecasted_qty(self):
        """
        When a PO is waiting for an approval, its quantities should be included
        in the draft quantity count
        """
        self.env.company.po_double_validation = 'two_step'
        self.env.company.po_double_validation_amount = 0

        basic_purchase_user = mail_new_test_user(
            self.env,
            login='basic_purchase_user',
            groups='base.group_user,purchase.group_purchase_user',
        )

        po_form = Form(self.env['purchase.order'])
        po_form.partner_id = self.partner
        with po_form.order_line.new() as line:
            line.product_id = self.product
            line.product_qty = 50
        po_form.save()

        po_form = Form(self.env['purchase.order'])
        po_form.partner_id = self.partner
        with po_form.order_line.new() as line:
            line.product_id = self.product
            line.product_qty = 100
        po = po_form.save()
        po.with_user(basic_purchase_user).button_confirm()

        docs = self.get_report_forecast(product_template_ids=self.product_template.ids)[1]
        self.assertEqual(docs['draft_purchase_qty'], 150)

    def test_vendor_delay_report_with_uom(self):
        """
        PO 12 units x P
        Receive 1 dozen x P
        -> 100% received
        """
        uom_12 = self.env.ref('uom.product_uom_dozen')

        po_form = Form(self.env['purchase.order'])
        po_form.partner_id = self.partner
        with po_form.order_line.new() as line:
            line.product_id = self.product
            line.product_qty = 12
        po = po_form.save()
        po.button_confirm()

        receipt = po.picking_ids
        receipt_move = receipt.move_ids
        receipt_move.move_line_ids.unlink()
        receipt_move.move_line_ids = [(0, 0, {
            'location_id': receipt_move.location_id.id,
            'location_dest_id': receipt_move.location_dest_id.id,
            'product_id': self.product.id,
            'product_uom_id': uom_12.id,
            'quantity': 1,
            'picking_id': receipt.id,
        })]
        receipt.move_ids.picked = True
        receipt.button_validate()

        data = self.env['vendor.delay.report'].read_group(
            [('partner_id', '=', self.partner.id)],
            ['product_id', 'on_time_rate', 'qty_on_time', 'qty_total'],
            ['product_id'],
        )[0]
        self.assertEqual(data['qty_on_time'], 12)
        self.assertEqual(data['qty_total'], 12)
        self.assertEqual(data['on_time_rate'], 100)

    def test_vendor_delay_report_with_multi_location(self):
        """
        PO 10 units x P
        Receive
            - 6 x P in Child Location 01
            - 4 x P in Child Location 02
        -> 100% received
        """
        if not self.stock_location.child_ids:
            self.env['stock.location'].create([{
                'name': 'Shelf 1',
                'location_id': self.stock_location.id,
            }, {
                'name': 'Shelf 2',
                'location_id': self.stock_location.id,
            }])

        child_loc_01, child_loc_02 = self.stock_location.child_ids

        po_form = Form(self.env['purchase.order'])
        po_form.partner_id = self.partner
        with po_form.order_line.new() as line:
            line.product_id = self.product
            line.product_qty = 10
        po = po_form.save()
        po.button_confirm()

        receipt = po.picking_ids
        receipt_move = receipt.move_ids
        receipt_move.move_line_ids.unlink()
        receipt_move.move_line_ids = [(0, 0, {
            'location_id': receipt_move.location_id.id,
            'location_dest_id': child_loc_01.id,
            'product_id': self.product.id,
            'product_uom_id': self.product.uom_id.id,
            'quantity': 6,
            'picking_id': receipt.id,
        }), (0, 0, {
            'location_id': receipt_move.location_id.id,
            'location_dest_id': child_loc_02.id,
            'product_id': self.product.id,
            'product_uom_id': self.product.uom_id.id,
            'quantity': 4,
            'picking_id': receipt.id,
        })]
        receipt.move_ids.picked = True
        receipt.button_validate()

        data = self.env['vendor.delay.report'].read_group(
            [('partner_id', '=', self.partner.id)],
            ['product_id', 'on_time_rate', 'qty_on_time', 'qty_total'],
            ['product_id'],
        )[0]
        self.assertEqual(data['qty_on_time'], 10)
        self.assertEqual(data['qty_total'], 10)
        self.assertEqual(data['on_time_rate'], 100)

    def test_vendor_delay_report_with_backorder(self):
        """
        PO 10 units x P
        Receive 6 x P with backorder
        -> 60% received
        Process the backorder
        -> 100% received
        """
        po_form = Form(self.env['purchase.order'])
        po_form.partner_id = self.partner
        with po_form.order_line.new() as line:
            line.product_id = self.product
            line.product_qty = 10
        po = po_form.save()
        po.button_confirm()

        receipt01 = po.picking_ids
        receipt01_move = receipt01.move_ids
        receipt01_move.quantity = 6
        Form.from_action(self.env, receipt01.button_validate()).save().process()

        data = self.env['vendor.delay.report'].read_group(
            [('partner_id', '=', self.partner.id)],
            ['product_id', 'on_time_rate', 'qty_on_time', 'qty_total'],
            ['product_id'],
        )[0]
        self.assertEqual(data['qty_on_time'], 6)
        self.assertEqual(data['qty_total'], 10)
        self.assertEqual(data['on_time_rate'], 60)

        receipt02 = receipt01.backorder_ids
        receipt02.move_ids.quantity = 4
        receipt02.move_ids.picked = True
        receipt02.button_validate()

        (receipt01 | receipt02).move_ids.invalidate_recordset()
        data = self.env['vendor.delay.report'].read_group(
            [('partner_id', '=', self.partner.id)],
            ['product_id', 'on_time_rate', 'qty_on_time', 'qty_total'],
            ['product_id'],
        )[0]
        self.assertEqual(data['qty_on_time'], 10)
        self.assertEqual(data['qty_total'], 10)
        self.assertEqual(data['on_time_rate'], 100)

    def test_vendor_delay_report_without_backorder(self):
        """
        PO 10 units x P
        Receive 6 x P without backorder
        -> 60% received
        """
        po_form = Form(self.env['purchase.order'])
        po_form.partner_id = self.partner
        with po_form.order_line.new() as line:
            line.product_id = self.product
            line.product_qty = 10
        po = po_form.save()
        po.button_confirm()

        receipt01 = po.picking_ids
        receipt01_move = receipt01.move_ids
        receipt01_move.quantity = 6
        receipt01_move.picked = True
        Form.from_action(self.env, receipt01.button_validate()).save().process_cancel_backorder()

        data = self.env['vendor.delay.report'].read_group(
            [('partner_id', '=', self.partner.id)],
            ['product_id', 'on_time_rate', 'qty_on_time', 'qty_total'],
            ['product_id'],
        )[0]
        self.assertEqual(data['qty_on_time'], 6)
        self.assertEqual(data['qty_total'], 10)
        self.assertEqual(data['on_time_rate'], 60)
