OCA/l10n-italy

View on GitHub
l10n_it_invoices_data_communication/models/account_invoice.py

Summary

Maintainability
A
2 hrs
Test Coverage
# -*- coding: utf-8 -*-


from openerp import api, fields, models, _
from openerp.exceptions import ValidationError


class AccountInvoice(models.Model):
    _inherit = "account.invoice"

    comunicazione_dati_iva_escludi = fields.Boolean(
        string='Exclude from invoices communication')

    @api.multi
    def _compute_taxes_in_company_currency(self, vals):
        self.ensure_one()
        sign = 1 if self.type in ('out_invoice', 'in_refund') else -1
        amount_total_signed = sign * self.amount_total
        currency_id = self.currency_id.with_context(date=self.date_invoice)
        amount_total_company = currency_id.compute(
            self.amount_total, self.company_id.currency_id)
        amount_total_company_signed = sign * amount_total_company
        try:
            exchange_rate = (
                amount_total_signed /
                amount_total_company_signed)
        except ZeroDivisionError:
            exchange_rate = 1
        vals['ImponibileImporto'] = vals['ImponibileImporto'] / exchange_rate
        vals['Imposta'] = vals['Imposta'] / exchange_rate

    @api.multi
    def _get_tax_comunicazione_dati_iva(self):
        self.ensure_one()
        tax_grouped = {}
        tot_imponibile = 0
        tot_imposta = 0
        for tax_line in self.tax_line:
            tax, val = self.get_tax_line_vals(tax_line)

            tot_imponibile += val['ImponibileImporto']
            tot_imposta += val['Imposta']

            if tax.id not in tax_grouped:
                tax_grouped[tax.id] = val
            else:
                tax_grouped[tax.id]['ImponibileImporto'] += \
                    val['ImponibileImporto']
                tax_grouped[tax.id]['Imposta'] += val['Imposta']

        tax_lines = []
        if tax_grouped:
            for key in tax_grouped:
                val = tax_grouped[key]
                val = self._check_tax_comunicazione_dati_iva(key, val)
                tax_lines.append((0, 0, val))
        tot_vals = {
            'tot_imponibile': tot_imponibile,
            'tot_imposta': tot_imposta
        }
        self._check_tax_comunicazione_dati_iva_fattura(tot_vals)
        return tax_lines

    @api.multi
    def get_tax_line_vals(self, tax_line):
        self.ensure_one()
        # aliquota, natura, esigibilità
        aliquota = 0
        kind_id = False
        payability = False
        domain = [('tax_code_id', '=', tax_line.tax_code_id.id)]
        tax = self.env['account.tax'].search(domain, order='id', limit=1)
        tax_origin = tax
        if tax.parent_id:
            tax = tax.parent_id

        if tax:
            aliquota = tax.amount * 100
            kind_id = tax.kind_id.id
            payability = tax.payability
        vals_tax_line = \
            self._get_tax_comunicazione_dati_iva_tax_line_amount(tax_line)
        val = {
            'ImponibileImporto': vals_tax_line['base'],
            'Imposta': vals_tax_line['amount'],
            'Aliquota': aliquota,
            'Natura_id': kind_id,
            'EsigibilitaIVA': payability
        }
        # Detraibilità
        detraibilita = False
        if tax_origin.parent_id and tax_origin.type in ['percent']:
            if tax_origin.account_collected_id:
                detraibilita = tax_origin.amount * 100
            else:
                detraibilita = 100 - (tax_origin.amount * 100)
        if detraibilita:
            val['Detraibile'] = detraibilita
        if self.type in ('in_invoice', 'in_refund'):
            val['Detraibile'] = 100.0
        # Solo imponibile legato alla parte indetraibile
        if tax_origin.parent_id:
            if not tax_line.base_code_id:
                val['ImponibileImporto'] = 0
        return tax, val

    @api.multi
    def _get_tax_comunicazione_dati_iva_tax_line_amount(self, tax_line):
        self.ensure_one()
        vals = {
            'base': abs(tax_line.base_amount),
            'amount': abs(tax_line.tax_amount)
        }
        # Gestione righe negative
        if tax_line.base < 0 or 'refund' in self.type:
            vals['base'] = vals['base'] * -1
            vals['amount'] = vals['amount'] * -1
        return vals

    @api.multi
    def _check_tax_comunicazione_dati_iva_fattura(self, args=None):
        self.ensure_one()
        if (
            self.currency_id and
            self.currency_id.id != self.company_id.currency_id.id
        ):
            # in caso di fatture in valuta estera, non controllo amount_untaxed
            # perchè sarebbe comunque diverso dall'importo in valuta base
            return
        if not args:
            args = {}

        if 'tot_imponibile' in args:
            if not abs(round(self.amount_untaxed, 2)) ==\
                    abs(round(args['tot_imponibile'], 2)):
                raise ValidationError(
                    _("Imponibile ft {} del partner {} non congruente. \
                    Verificare dettaglio sezione imposte della fattura (\
                    imponible doc:{} - imponibile dati iva:{})"
                      ).format(self.number, self.partner_id.name,
                               str(self.amount_untaxed),
                               str(args['tot_imponibile'])))

    @api.multi
    def _check_tax_comunicazione_dati_iva(self, tax, val=None):
        self.ensure_one()
        if not val:
            val = {}
        if val['Aliquota'] == 0 and not val['Natura_id']:
            raise ValidationError(
                _(
                    "Please specify exemption kind for tax: {} - Invoice {}"
                ).format(tax.name, self.number or False))
        if not val['EsigibilitaIVA']:
            raise ValidationError(
                _(
                    "Please specify VAT payability for tax: {} - Invoice {}"
                ).format(tax.name, self.number or False))
        return val