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

from odoo import Command
from odoo.addons.account.tests.common import AccountTestInvoicingCommon

import datetime


class L10nHuEdiTestCommon(AccountTestInvoicingCommon):
    @classmethod
    @AccountTestInvoicingCommon.setup_country('hu')
    def setUpClass(cls):
        super().setUpClass()

        cls.today = datetime.date.today()
        cls.yesterday = cls.today - datetime.timedelta(days=1)

        # Company
        company = cls.company_data['company']
        company.write({
            'city': 'Budapest',
            'zip': '1073',
            'street': 'Akácfa utca 74.',
            'country_id': cls.env.ref('base.hu').id,
            'vat': '27725414-2-13',
        })

        cls.write_edi_credentials()

        # Products
        cls.product_service = cls.env['product.product'].create({
            'name': 'Consultancy Service',
            'type': 'service',
            'uom_id': cls.env.ref('uom.product_uom_hour').id,
            'property_account_income_id': cls.company_data['default_account_revenue'].id,
            'property_account_expense_id': cls.company_data['default_account_expense'].id,
        })
        cls.product_no_uom = cls.env['product.product'].create({
            'name': 'Item without UoM',
            'type': 'service',
            'property_account_income_id': cls.company_data['default_account_revenue'].id,
            'property_account_expense_id': cls.company_data['default_account_expense'].id,
        })

        # Partners
        cls.partner_company = cls.env['res.partner'].create({
            'name': 'Magyar Vevő Kft.',
            'is_company': True,
            'street': 'Alkotmány utca 11.',
            'city': 'Debrecen',
            'zip': '4000',
            'country_id': cls.env.ref('base.hu').id,
            'vat': '14933477-2-13',
            'invoice_edi_format': False,
        })
        cls.partner_group_company_1 = cls.env['res.partner'].create({
            'name': 'MOL Nyrt.',
            'is_company': True,
            'street': 'Dombóvári út 28.',
            'city': 'Budapest',
            'zip': '1117',
            'country_id': cls.env.ref('base.hu').id,
            'vat': '10625790-4-44',
            'l10n_hu_group_vat': '17781774-5-44',
        })
        cls.partner_group_company_2 = cls.env['res.partner'].create({
            'name': 'MOL Petrolkémia Zrt.',
            'is_company': True,
            'street': 'TVK-Ipartelep, TVK Központi Irodaház 2119/3hrsz. 136. ép.',
            'city': 'Tiszaújváros',
            'zip': '3581',
            'country_id': cls.env.ref('base.hu').id,
            'vat': '10725759-4-05',
            'l10n_hu_group_vat': '17781774-5-44',
        })

        # Currency rates
        currency_eur = cls.env.ref('base.EUR')
        currency_eur.active = True
        cls.env['res.currency.rate'].create(
            {
                'name': cls.today,
                'currency_id': currency_eur.id,
                'company_id': company.id,
                'inverse_company_rate': '380.77',
            }
        )
        cls.env['res.currency.rate'].create(
            {
                'name': cls.yesterday,
                'currency_id': currency_eur.id,
                'company_id': company.id,
                'inverse_company_rate': '377.66',
            }
        )

        # Taxes
        cls.tax_vat = cls.env['account.chart.template'].ref('F27')
        cls.tax_vat_18 = cls.env['account.chart.template'].ref('F18')
        cls.tax_aam = cls.env['account.chart.template'].ref('VA')
        cls.tax_price_include = cls.env['account.tax'].create({
            'name': 'Excise tax',
            'amount_type': 'percent',
            'amount': 30.0,
            'country_id': company.account_fiscal_country_id.id,
            'tax_exigibility': 'on_invoice',
            'price_include_override': 'tax_included',
            'include_base_amount': True,
            'l10n_hu_tax_type': 'VAT',
            'invoice_repartition_line_ids': [
                Command.create({'repartition_type': 'base'}),
                Command.create({
                    'repartition_type': 'tax',
                    'account_id': cls.company_data['default_account_tax_sale'].id,
                }),
            ],
            'refund_repartition_line_ids': [
                Command.create({'repartition_type': 'base'}),
                Command.create({
                    'repartition_type': 'tax',
                    'account_id': cls.company_data['default_account_tax_sale'].id,
                }),
            ],
        })

    @classmethod
    def write_edi_credentials(cls):
        # Set up test EDI user
        return cls.company_data['company'].write({
            'l10n_hu_edi_server_mode': 'test',
            'l10n_hu_edi_username': 'this',
            'l10n_hu_edi_password': 'that',
            'l10n_hu_edi_signature_key': 'some_key',
            'l10n_hu_edi_replacement_key': 'abcdefghijklmnop',
        })
    
    def _create_simple_move(self, move_type='out_invoice', currency=None, amount=None):
        journal = self.company_data['default_journal_sale'] if move_type in self.env['account.move'].get_sale_types() else self.company_data['default_journal_purchase']

        return self.env['account.move'].create({
            'move_type': move_type,
            'journal_id': journal.id,
            'currency_id': (currency or self.env.ref('base.HUF')).id,
            'partner_id': self.partner_company.id,
            'invoice_date': self.today,
            'delivery_date': self.today,
            'invoice_line_ids': [
                Command.create({
                    'product_id': self.product_a.id,
                    'price_unit': amount or 10000.0,
                    'quantity': 1,
                    'tax_ids': [Command.set(self.tax_vat.ids)],
                })
            ]
        })

    def create_invoice_simple(self, currency=None, amount=None):
        """ Create a really basic invoice - just one line. """
        return self._create_simple_move(move_type='out_invoice', currency=currency, amount=amount)
    
    def create_bill_simple(self, currency=None):
        """ Create a really basic bill - just one line. """
        return self._create_simple_move(move_type='in_invoice', currency=currency)
    
    def create_credit_note_simple(self, currency=None):
        """ Create a really basic credit note - just one line. """
        return self._create_simple_move(move_type='out_refund', currency=currency)
    
    def create_refund_simple(self, currency=None):
        """ Create a really basic bill refund - just one line. """
        return self._create_simple_move(move_type='in_refund', currency=currency)

    def create_invoice_simple_discount(self):
        """ Create a really basic invoice with a discount - just one line. """
        return self.env['account.move'].create({
            'move_type': 'out_invoice',
            'journal_id': self.company_data['default_journal_sale'].id,
            'currency_id': self.env.ref('base.HUF').id,
            'partner_id': self.partner_company.id,
            'invoice_date': self.today,
            'delivery_date': self.today,
            'invoice_line_ids': [
                Command.create({
                    'product_id': self.product_a.id,
                    'price_unit': 10000.0,
                    'quantity': 1,
                    'discount': 20,
                    'tax_ids': [Command.set(self.tax_vat.ids)],
                })
            ]
        })

    def create_invoice_tax_price_include(self):
        """ Create an invoice with :
            * one line using a tax with price included
            * one line using a tax with price included and a discount
        """
        return self.env['account.move'].create({
            'move_type': 'out_invoice',
            'journal_id': self.company_data['default_journal_sale'].id,
            'currency_id': self.env.ref('base.HUF').id,
            'partner_id': self.partner_company.id,
            'invoice_date': self.today,
            'delivery_date': self.today,
            'invoice_line_ids': [
                Command.create({
                    'product_id': self.product_a.id,
                    'price_unit': 1000.00,
                    'quantity': 1,
                    'tax_ids': [Command.set(self.tax_price_include.ids)],
                }),
                Command.create({
                    'product_id': self.product_a.id,
                    'price_unit': 1000.00,
                    'quantity': 1,
                    'discount': 20,
                    'tax_ids': [Command.set(self.tax_price_include.ids)],
                }),
            ]
        })

    def create_advance_invoice(self):
        """ Create a sale order and an advance invoice. """
        self.product_a.invoice_policy = 'order'
        pricelist_huf = self.env['product.pricelist'].create({
            'name': 'HUF pricelist',
            'currency_id': self.company_data['company'].currency_id.id,
            'company_id': False,
        })
        sale_order = self.env['sale.order'].with_context(tracking_disable=True).create({
            'partner_id': self.partner_company.id,
            'pricelist_id': pricelist_huf.id,
            'order_line': [
                Command.create({
                    'product_id': self.product_a.id,
                    'product_uom_qty': 1,
                    'price_unit': 10000.0,
                    'tax_ids': [Command.set(self.tax_vat.ids)],
                })
            ]
        })
        sale_order.action_confirm()

        downpayment = self.env['sale.advance.payment.inv'].with_context({
            'active_model': 'sale.order',
            'active_ids': [sale_order.id],
            'active_id': sale_order.id,
            'default_journal_id': self.company_data['default_journal_sale'].id,
        }).create({
            'advance_payment_method': 'fixed',
            'fixed_amount': 6350.0,
        })
        downpayment.create_invoices()
        return sale_order, sale_order.invoice_ids

    def create_final_invoice(self, sale_order):
        """ Create a final invoice for a sale order """
        advance_invoice = sale_order.invoice_ids
        final_payment = self.env['sale.advance.payment.inv'].with_context({
            'active_model': 'sale.order',
            'active_ids': [sale_order.id],
            'active_id': sale_order.id,
            'default_journal_id': self.company_data['default_journal_sale'].id,
        }).create({
            'advance_payment_method': 'delivered',
        })
        final_payment.create_invoices()
        final_invoice = sale_order.invoice_ids - advance_invoice

        return final_invoice

    def create_invoice_complex_huf(self):
        """ Create a complex invoice in HUF, with cash rounding. """
        return self.env['account.move'].create({
            'move_type': 'out_invoice',
            'journal_id': self.company_data['default_journal_sale'].id,
            'currency_id': self.env.ref('base.HUF').id,
            'partner_id': self.partner_company.id,
            'invoice_date': self.today,
            'delivery_date': self.today,
            'l10n_hu_payment_mode': 'TRANSFER',
            'invoice_cash_rounding_id': self.env.ref('l10n_hu_edi.cash_rounding_1_huf').id,
            'invoice_line_ids': [
                Command.create({
                    'product_id': self.product_a.id,
                    'price_unit': 10.00,
                    'quantity': 3,
                    'discount': 20,
                    'tax_ids': [Command.set(self.tax_vat.ids)],
                }),
                Command.create({
                    'product_id': self.product_b.id,
                    'price_unit': 19.99,
                    'quantity': 1,
                    'tax_ids': [Command.set(self.tax_vat.ids)],
                }),
                Command.create({
                    'product_id': self.product_service.id,
                    'price_unit': 50.00,
                    'quantity': 2,
                    'tax_ids': [Command.set(self.tax_vat_18.ids)],
                }),
                Command.create({
                    'product_id': self.product_no_uom.id,
                    'price_unit': 200.00,
                    'quantity': 1,
                    'tax_ids': [Command.set(self.tax_aam.ids)],
                })
            ]
        })

    def create_invoice_complex_eur(self):
        """ Create a complex invoice in EUR with several lines, different taxes, and discounts. """
        return self.env['account.move'].create({
            'move_type': 'out_invoice',
            'journal_id': self.company_data['default_journal_sale'].id,
            'currency_id': self.env.ref('base.EUR').id,
            'partner_id': self.partner_company.id,
            'invoice_date': self.yesterday,
            'delivery_date': self.today,
            'l10n_hu_payment_mode': 'TRANSFER',
            'invoice_line_ids': [
                Command.create({
                    'product_id': self.product_a.id,
                    'price_unit': 10.00,
                    'quantity': 3,
                    'discount': 20,
                    'tax_ids': [Command.set(self.tax_vat.ids)],
                }),
                Command.create({
                    'product_id': self.product_b.id,
                    'price_unit': 19.99,
                    'quantity': 1,
                    'tax_ids': [Command.set(self.tax_vat.ids)],
                }),
                Command.create({
                    'product_id': self.product_service.id,
                    'price_unit': 50.00,
                    'quantity': 2,
                    'tax_ids': [Command.set(self.tax_vat_18.ids)],
                }),
                Command.create({
                    'product_id': self.product_no_uom.id,
                    'price_unit': 200.00,
                    'quantity': 1,
                    'tax_ids': [Command.set(self.tax_aam.ids)],
                })
            ]
        })

    def create_reversal(self, invoice, is_modify=False, amount=None):
        """ Create a credit note that reverses an invoice. """
        wizard_vals = {'journal_id': invoice.journal_id.id}
        wizard_reverse = self.env['account.move.reversal'].with_context(active_ids=invoice.ids, active_model='account.move').create(wizard_vals)
        wizard_reverse.reverse_moves(is_modify=is_modify)
        reversal_moves = wizard_reverse.new_move_ids
        if amount:
            reversal_moves.invoice_line_ids.write({
                'price_unit': amount
            })
        return reversal_moves

    def create_debit_note(self, invoice, amount=None):
        """ Create Debit Note """
        wizard_vals = {
            'journal_id': invoice.journal_id.id,
            'copy_lines': True,
        }
        move_debit_note_wiz = self.env['account.debit.note'].with_context(active_model="account.move", active_ids=invoice.ids).create(wizard_vals)
        move_debit_note_wiz.create_debit()
        debit_note = self.env['account.move'].search([('debit_origin_id', '=', invoice.id)])
        if amount:
            debit_note.invoice_line_ids.write({
                'price_unit': amount
            })
        return debit_note

    def register_payment(self, invoice, amount):
        payment_register = self.env['account.payment.register'].with_context(active_model='account.move', active_ids=invoice.ids).create({
            'payment_date': self.today,
            'journal_id': self.company_data['default_journal_bank'].id,
            'amount': amount,
        })
        payment_register.action_create_payments()

    def create_cancel_wizard(self):
        """ Create an invoice, send it, and create a cancellation wizard for it. """
        invoice = self.create_invoice_simple()
        invoice.action_post()
        send_and_print = self.create_send_and_print(invoice, sending_methods=[])
        self.assertTrue(send_and_print.extra_edi_checkboxes and send_and_print.extra_edi_checkboxes.get('hu_nav_30', {}).get('checked'))
        self.assertFalse(invoice._l10n_hu_edi_check_invoices())
        send_and_print.action_send_and_print()
        cancel_wizard = self.env['l10n_hu_edi.cancellation'].with_context({"default_invoice_id": invoice.id}).create({
            'code': 'ERRATIC_DATA',
            'reason': 'Some reason...',
        })
        return invoice, cancel_wizard
