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

from odoo.addons.stock_account.tests.test_anglo_saxon_valuation_reconciliation_common import ValuationReconciliationTestCommon
from odoo import Command
from odoo.tests import tagged, Form


@tagged('post_install', '-at_install')
class TestSubcontractingDropshippingValuation(ValuationReconciliationTestCommon):

    @classmethod
    def setUpClass(cls, chart_template_ref=None):
        super().setUpClass(chart_template_ref=chart_template_ref)

        categ_form = Form(cls.env['product.category'])
        categ_form.name = 'fifo auto'
        categ_form.parent_id = cls.env.ref('product.product_category_all')
        categ_form.property_cost_method = 'fifo'
        categ_form.property_valuation = 'real_time'
        cls.categ_fifo_auto = categ_form.save()

        categ_form = Form(cls.env['product.category'])
        categ_form.name = 'avco auto'
        categ_form.parent_id = cls.env.ref('product.product_category_all')
        categ_form.property_cost_method = 'average'
        categ_form.property_valuation = 'real_time'
        cls.categ_avco_auto = categ_form.save()

        cls.dropship_route = cls.env.ref('stock_dropshipping.route_drop_shipping')
        cls.dropship_subcontractor_route = cls.env.ref('mrp_subcontracting_dropshipping.route_subcontracting_dropshipping')

        (cls.product_a | cls.product_b).type = 'product'

        cls.bom_a = cls.env['mrp.bom'].create({
            'product_tmpl_id': cls.product_a.product_tmpl_id.id,
            'type': 'subcontract',
            'subcontractor_ids': [(6, 0, cls.partner_a.ids)],
            'bom_line_ids': [
                (0, 0, {'product_id': cls.product_b.id, 'product_qty': 1.0}),
            ],
        })

    def test_valuation_subcontracted_and_dropshipped(self):
        """
        Product:
            - FIFO + Auto
            - Subcontracted
        Purchase 2 from Subcontractor to a customer (dropship).
        Then return 1 to subcontractor and one to stock
        It should generate the correct valuations AMLs
        """
        # pylint: disable=bad-whitespace
        all_amls_ids = self.env['account.move.line'].search_read([], ['id'])

        grp_multi_loc = self.env.ref('stock.group_stock_multi_locations')
        self.env.user.write({'groups_id': [(4, grp_multi_loc.id)]})

        (self.product_a | self.product_b).categ_id = self.categ_fifo_auto
        self.product_b.standard_price = 10

        dropship_picking_type = self.env['stock.picking.type'].search([
            ('company_id', '=', self.env.company.id),
            ('default_location_src_id.usage', '=', 'supplier'),
            ('default_location_dest_id.usage', '=', 'customer'),
        ], limit=1, order='sequence')

        po = self.env['purchase.order'].create({
            "partner_id": self.partner_a.id,
            "picking_type_id": dropship_picking_type.id,
            "dest_address_id": self.partner_b.id,
            "order_line": [(0, 0, {
                'product_id': self.product_a.id,
                'name': self.product_a.name,
                'product_qty': 2.0,
                'price_unit': 100,
                'taxes_id': False,
            })],
        })
        po.button_confirm()

        delivery = po.picking_ids
        res = delivery.button_validate()
        Form(self.env['stock.immediate.transfer'].with_context(res['context'])).save().process()

        stock_in_acc_id = self.categ_fifo_auto.property_stock_account_input_categ_id.id
        stock_out_acc_id = self.categ_fifo_auto.property_stock_account_output_categ_id.id
        stock_valu_acc_id = self.categ_fifo_auto.property_stock_valuation_account_id.id

        amls = self.env['account.move.line'].search([('id', 'not in', all_amls_ids)])
        all_amls_ids += amls.ids
        self.assertRecordValues(amls, [
            # Compensation of dropshipping value
            {'account_id': stock_valu_acc_id,   'product_id': self.product_a.id,    'debit': 0.0,   'credit': 20.0},
            {'account_id': stock_out_acc_id,    'product_id': self.product_a.id,    'debit': 20.0,  'credit': 0.0},
            # Receipt from subcontractor
            {'account_id': stock_in_acc_id,     'product_id': self.product_a.id,    'debit': 0.0,   'credit': 220.0},
            {'account_id': stock_valu_acc_id,   'product_id': self.product_a.id,    'debit': 220.0, 'credit': 0.0},
            # Delivery to subcontractor
            {'account_id': stock_valu_acc_id,   'product_id': self.product_b.id,    'debit': 0.0,   'credit': 20.0},
            {'account_id': stock_out_acc_id,    'product_id': self.product_b.id,    'debit': 20.0,  'credit': 0.0},
            # Initial dropshipped value
            {'account_id': stock_valu_acc_id,   'product_id': self.product_a.id,    'debit': 0.0,   'credit': 200.0},
            {'account_id': stock_out_acc_id,    'product_id': self.product_a.id,    'debit': 200.0, 'credit': 0.0},
        ])

        # return to subcontracting location
        sbc_location = self.env.company.subcontracting_location_id
        return_form = Form(self.env['stock.return.picking'].with_context(active_id=delivery.id, active_model='stock.picking'))
        return_form.location_id = sbc_location
        with return_form.product_return_moves.edit(0) as line:
            line.quantity = 1
        return_wizard = return_form.save()
        return_id, _ = return_wizard._create_returns()
        return_picking = self.env['stock.picking'].browse(return_id)
        return_picking.move_ids.quantity_done = 1
        return_picking.button_validate()

        amls = self.env['account.move.line'].search([('id', 'not in', all_amls_ids)])
        all_amls_ids += amls.ids
        self.assertRecordValues(amls, [
            {'account_id': stock_valu_acc_id,   'product_id': self.product_a.id,    'debit': 0.0,   'credit': 110.0},
            {'account_id': stock_in_acc_id,     'product_id': self.product_a.id,    'debit': 110.0, 'credit': 0.0},
        ])

        # return to stock location
        warehouse = self.env['stock.warehouse'].search([('company_id', '=', self.env.company.id)], limit=1)
        stock_location = warehouse.lot_stock_id
        stock_location.return_location = True
        return_form = Form(self.env['stock.return.picking'].with_context(active_id=delivery.id, active_model='stock.picking'))
        return_form.location_id = stock_location
        with return_form.product_return_moves.edit(0) as line:
            line.quantity = 1
        return_wizard = return_form.save()
        return_id, _ = return_wizard._create_returns()
        return_picking = self.env['stock.picking'].browse(return_id)
        return_picking.move_ids.quantity_done = 1
        return_picking.button_validate()

        amls = self.env['account.move.line'].search([('id', 'not in', all_amls_ids)])
        all_amls_ids += amls.ids
        self.assertRecordValues(amls, [
            {'account_id': stock_out_acc_id,    'product_id': self.product_a.id,    'debit': 0.0,   'credit': 110.0},
            {'account_id': stock_valu_acc_id,   'product_id': self.product_a.id,    'debit': 110.0, 'credit': 0.0},
        ])

    def test_avco_valuation_subcontract_and_dropshipped_and_backorder(self):
        """ Splitting a dropship transfer via backorder and invoicing for delivered quantities
        should result in SVL records which have accurate values based on the portion of the total
        order-picking sequence for which they were generated.
        """
        final_product = self.product_a
        final_product.write({
            'categ_id': self.categ_avco_auto.id,
            'invoice_policy': 'delivery',
        })
        comp_product = self.product_b
        comp_product.write({
            'categ_id': self.categ_avco_auto.id,
            'route_ids': [(4, self.dropship_subcontractor_route.id)],
        })

        self.env['product.supplierinfo'].create({
            'product_tmpl_id': final_product.product_tmpl_id.id,
            'partner_id': self.partner_a.id,
            'price': 10,
        })
        self.env['product.supplierinfo'].create({
            'product_tmpl_id': comp_product.product_tmpl_id.id,
            'partner_id': self.partner_a.id,
            'price': 1,
        })

        sale_order = self.env['sale.order'].create({
            'partner_id': self.partner_a.id,
            'order_line': [(0, 0, {
                'product_id': final_product.id,
                'route_id': self.dropship_route.id,
                'product_uom_qty': 100,
            })],
        })
        sale_order.action_confirm()
        purchase_order = sale_order._get_purchase_orders()[0]
        purchase_order.button_confirm()
        dropship_transfer = purchase_order.picking_ids[0]
        dropship_transfer.move_ids[0].quantity_done = 50
        dropship_transfer.with_context(cancel_backorder=False)._action_done()
        account_move_1 = sale_order._create_invoices()
        account_move_1.action_post()
        dropship_backorder = dropship_transfer.backorder_ids[0]
        dropship_backorder.action_set_quantities_to_reservation()
        dropship_backorder._action_done()
        account_move_2 = sale_order._create_invoices()
        account_move_2.action_post()

        self.assertRecordValues(
            self.env['stock.valuation.layer'].search([('product_id', '=', final_product.id)]),
            [
                # DS/01
                {'reference': dropship_transfer.name, 'quantity': -50, 'value': -500},
                {'reference': dropship_transfer.move_ids.move_orig_ids[0].name, 'quantity': 50, 'value': 8500},
                {'reference': dropship_transfer.name, 'quantity': 0, 'value': -8000},
                # DS/02 - backorder
                {'reference': dropship_backorder.name, 'quantity': -50, 'value': -500},
                {'reference': dropship_backorder.move_ids.move_orig_ids[1].name, 'quantity': 50, 'value': 8500},
                {'reference': dropship_backorder.name, 'quantity': 0, 'value': -8000},
            ]
        )

    def test_account_line_entry_kit_bom_dropship(self):
        """ An order delivered via dropship for some kit bom product variant should result in
        accurate journal entries in the expense and stock output accounts if the cost on the
        purchase order line has been manually edited.
        """
        kit_final_prod = self.product_a
        product_c = self.env['product.product'].create({
            'name': 'product_c',
            'uom_id': self.env.ref('uom.product_uom_dozen').id,
            'uom_po_id': self.env.ref('uom.product_uom_dozen').id,
            'lst_price': 120.0,
            'standard_price': 100.0,
            'property_account_income_id': self.copy_account(self.company_data['default_account_revenue']).id,
            'property_account_expense_id': self.copy_account(self.company_data['default_account_expense']).id,
            'taxes_id': [Command.set((self.tax_sale_a + self.tax_sale_b).ids)],
            'supplier_taxes_id': [Command.set((self.tax_purchase_a + self.tax_purchase_b).ids)],
        })
        kit_bom = self.env['mrp.bom'].create({
            'product_tmpl_id': kit_final_prod.product_tmpl_id.id,
            'product_uom_id': kit_final_prod.uom_id.id,
            'product_qty': 1.0,
            'type': 'phantom',
        })
        kit_bom.bom_line_ids = [(0, 0, {
            'product_id': self.product_b.id,
            'product_qty': 4,
        }), (0, 0, {
            'product_id': product_c.id,
            'product_qty': 2,
        })]

        self.env['product.supplierinfo'].create({
            'product_id': self.product_b.id,
            'partner_id': self.partner_a.id,
            'price': 160,
        })
        self.env['product.supplierinfo'].create({
            'product_id': product_c.id,
            'partner_id': self.partner_a.id,
            'price': 100,
        })

        (kit_final_prod + self.product_b).categ_id.write({
            'property_cost_method': 'fifo',
            'property_valuation': 'real_time',
        })

        sale_order = self.env['sale.order'].create({
            'partner_id': self.partner_b.id,
            'order_line': [(0, 0, {
                'price_unit': 900,
                'product_id': kit_final_prod.id,
                'route_id': self.dropship_route.id,
                'product_uom_qty': 2.0,
            })],
        })
        sale_order.action_confirm()
        purchase_order = sale_order._get_purchase_orders()[0]
        purchase_order.button_confirm()
        dropship_transfer = purchase_order.picking_ids[0]
        dropship_transfer.move_ids[0].quantity_done = 2.0
        dropship_transfer.button_validate()

        account_move = sale_order._create_invoices()
        account_move.action_post()

        # Each product_a should cost:
        # 4x product_b = 160 * 4 = 640 +
        # 2x product_c = 100 * 2 = 200
        #                        = 840
        self.assertRecordValues(
            account_move.line_ids,
            [
                {'name': 'product_a',           'debit': 0.0,       'credit': 1800.0},
                {'name': 'Tax 15% (Copy)',      'debit': 0.0,       'credit': 270.0},
                {'name': account_move.name,     'debit': 621.0,     'credit': 0.0},
                {'name': account_move.name,     'debit': 1449.0,    'credit': 0.0},
                {'name': 'product_a',           'debit': 0.0,       'credit': 840 * 2},
                {'name': 'product_a',           'debit': 840 * 2,   'credit': 0.0},
            ]
        )
