← Back to team overview

openobject-italia-core-devs team mailing list archive

lp:~icsergio/openobject-italia/adding_l10n_it_partially_deductible_vat into lp:openobject-italia/7.0

 

Sergio Corato has proposed merging lp:~icsergio/openobject-italia/adding_l10n_it_partially_deductible_vat into lp:openobject-italia/7.0.

Requested reviews:
  OpenERP Italia core devs (openobject-italia-core-devs)

For more details, see:
https://code.launchpad.net/~icsergio/openobject-italia/adding_l10n_it_partially_deductible_vat/+merge/142416
-- 
https://code.launchpad.net/~icsergio/openobject-italia/adding_l10n_it_partially_deductible_vat/+merge/142416
Your team OpenERP Italia core devs is requested to review the proposed merge of lp:~icsergio/openobject-italia/adding_l10n_it_partially_deductible_vat into lp:openobject-italia/7.0.
=== added directory 'l10n_it_partially_deductible_vat'
=== added file 'l10n_it_partially_deductible_vat/AUTHORS.txt'
--- l10n_it_partially_deductible_vat/AUTHORS.txt	1970-01-01 00:00:00 +0000
+++ l10n_it_partially_deductible_vat/AUTHORS.txt	2013-01-08 23:03:21 +0000
@@ -0,0 +1,2 @@
+Lorenzo Battistini <lorenzo.battistini@xxxxxxxxxxx>
+Franco Tampieri <franco.tampieri@xxxxxxxxxxx>

=== added file 'l10n_it_partially_deductible_vat/__init__.py'
--- l10n_it_partially_deductible_vat/__init__.py	1970-01-01 00:00:00 +0000
+++ l10n_it_partially_deductible_vat/__init__.py	2013-01-08 23:03:21 +0000
@@ -0,0 +1,22 @@
+##############################################################################
+#
+#    OpenERP, Open Source Management Solution
+#    Copyright (C) 2011
+#    Associazione OpenERP Italia (<http://www.openerp-italia.org>)
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU Affero General Public License as
+#    published by the Free Software Foundation, either version 3 of the
+#    License, or (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU Affero General Public License for more details.
+#
+#    You should have received a copy of the GNU Affero General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+import account

=== added file 'l10n_it_partially_deductible_vat/__openerp__.py'
--- l10n_it_partially_deductible_vat/__openerp__.py	1970-01-01 00:00:00 +0000
+++ l10n_it_partially_deductible_vat/__openerp__.py	2013-01-08 23:03:21 +0000
@@ -0,0 +1,50 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+#    OpenERP, Open Source Management Solution
+#    Copyright (C) 2011
+#    Associazione OpenERP Italia (<http://www.openerp-italia.org>)
+#    Copyright (C) 2012 Agile Business Group sagl (<http://www.agilebg.com>)
+#    Copyright (C) 2012 Domsense srl (<http://www.domsense.com>)
+#    All Rights Reserved
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU Affero General Public License as
+#    published by the Free Software Foundation, either version 3 of the
+#    License, or (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU Affero General Public License for more details.
+#
+#    You should have received a copy of the GNU Affero General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+{
+    "name" : "Italy - Partially Deductible VAT",
+    "version" : "0.1",
+    "depends" : ['account'],
+    "author" : "OpenERP Italian Community",
+    "description": """
+    Calcoli aggiuntivi per la gestione dell'IVA parzialmente detraibile. Senza questo modulo non è possibile calcolare correttamente imponibili, imposte e conti imposte relativi all'IVA parzialmente detraibile.
+    La configurazione dell'IVA parzialmente detraibile deve essere quella utilizzata dal modulo 'l10n_it', anche se non viene usato tale modulo.
+    """,
+    "license": "AGPL-3",
+    "category" : "Localisation/Italy",
+    'website': 'http://www.openerp-italia.org/',
+    'init_xml': [
+        ],
+    'update_xml': [
+        ],
+    'demo_xml': [
+        ],
+    'test': [
+        'test/account_tax.xml',
+        'test/tax_computation.yml',
+        ],
+    'installable': True,
+    'active': False,
+}

=== added file 'l10n_it_partially_deductible_vat/account.py'
--- l10n_it_partially_deductible_vat/account.py	1970-01-01 00:00:00 +0000
+++ l10n_it_partially_deductible_vat/account.py	2013-01-08 23:03:21 +0000
@@ -0,0 +1,229 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+#    OpenERP, Open Source Management Solution
+#    Copyright (C) 2011
+#    Associazione OpenERP Italia (<http://www.openerp-italia.org>)
+#    Copyright (C) 2012 Agile Business Group sagl (<http://www.agilebg.com>)
+#    Copyright (C) 2012 Domsense srl (<http://www.domsense.com>)
+#    All Rights Reserved
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU Affero General Public License as
+#    published by the Free Software Foundation, either version 3 of the
+#    License, or (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU Affero General Public License for more details.
+#
+#    You should have received a copy of the GNU Affero General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+from osv import fields, osv
+import decimal_precision as dp
+from decimal import *
+import time
+
+class account_tax(osv.osv):
+
+    _inherit = 'account.tax'
+
+    def _have_same_rate(self, account_taxes):
+        rate = None
+        for account_tax in account_taxes:
+            if rate is None:
+                rate = account_tax.amount
+            elif rate != account_tax.amount:
+                return False
+        return True
+
+    def get_main_tax(self, tax):
+        if not tax.parent_id:
+            return tax
+        else:
+            return self.get_main_tax(tax.parent_id)
+
+    def get_account_tax_by_tax_code(self, tax_code):
+        if tax_code.tax_ids:
+            if not self._have_same_rate(tax_code.tax_ids):
+                raise osv.except_osv(_('Error'),
+                    _('The taxes %s have different rates') % str(tax_code.tax_ids))
+            return tax_code.tax_ids[0]
+        if tax_code.ref_tax_ids:
+            if not self._have_same_rate(tax_code.ref_tax_ids):
+                raise osv.except_osv(_('Error'),
+                    _('The taxes %s have different rates') % str(tax_code.ref_tax_ids))
+            return tax_code.ref_tax_ids[0]
+        raise osv.except_osv(_('Error'),
+            _('No taxes associated to tax code %s') % str(tax_code.name))
+
+    def get_account_tax_by_base_code(self, tax_code):
+        if tax_code.base_tax_ids:
+            if not self._have_same_rate(tax_code.base_tax_ids):
+                raise osv.except_osv(_('Error'),
+                    _('The taxes %s have different rates') % str(tax_code.base_tax_ids))
+            return tax_code.base_tax_ids[0]
+        if tax_code.ref_base_tax_ids:
+            if not self._have_same_rate(tax_code.ref_base_tax_ids):
+                raise osv.except_osv(_('Error'),
+                    _('The taxes %s have different rates') % str(tax_code.ref_base_tax_ids))
+            return tax_code.ref_base_tax_ids[0]
+        raise osv.except_osv(_('Error'),
+            _('No taxes associated to tax code %s') % str(tax_code.name))
+
+    def compute_all(self, cr, uid, taxes, price_unit, quantity, product=None, partner=None, force_excluded=False):
+        res = super(account_tax, self).compute_all(cr, uid, taxes, price_unit, quantity, product, partner, force_excluded)
+
+        precision = self.pool.get('decimal.precision').precision_get(cr, uid, 'Account')
+        tax_list = res['taxes']
+        totalex = res['total']
+        if len(tax_list) == 2:
+            for tax in tax_list:
+                if tax.get('balance',False): # Calcolo di imponibili per l'IVA parzialmente detraibile
+                    deductible_base = totalex
+                    ind_tax = tax_list[abs(tax_list.index(tax)-1)]
+                    ind_tax_obj = self.browse(cr, uid, ind_tax['id'])
+                    ded_tax_obj = self.browse(cr, uid, tax['id'])
+                    base_ind = float(Decimal(str(totalex * ind_tax_obj.amount)).quantize(Decimal('1.'+precision*'0'), rounding=ROUND_HALF_UP))
+                    base_ded = float(Decimal(str(totalex - base_ind)).quantize(Decimal('1.'+precision*'0'), rounding=ROUND_HALF_UP))
+                    tax_total = float(Decimal(str(tax['balance'])).quantize(Decimal('1.'+precision*'0'), rounding=ROUND_HALF_UP))
+                    ind_tax['price_unit']  = base_ind
+                    tax['price_unit'] = base_ded
+
+        return res
+
+account_tax()
+
+class account_invoice_tax(osv.osv):
+
+    _inherit = "account.invoice.tax"
+
+    '''
+    tax_grouped:
+
+    {(False, 21, 132): {'account_id': 132,
+                    'amount': 12.36,
+                    'base': 61.79,
+                    'base_amount': 61.79,
+                    'base_code_id': 21,
+                    'invoice_id': 1L,
+                    'manual': False,
+                    'name': u'20I5b - IVA al 20% detraibile al 50% (I)',
+                    'sequence': 1,
+                    'tax_amount': 12.36,
+                    'tax_code_id': False},
+    (20, False, 46): {'account_id': 46,
+                   'amount': 12.35,
+                   'base': 61.78,
+                   'base_amount': 61.78,
+                   'base_code_id': False,
+                   'invoice_id': 1L,
+                   'manual': False,
+                   'name': u'20I5a - IVA al 20% detraibile al 50% (D)',
+                   'sequence': 2,
+                   'tax_amount': 12.35,
+                   'tax_code_id': 20},
+    (26, 27, 46): {'account_id': 46,
+                'amount': 24.71,
+                'base': 123.57000000000001,
+                'base_amount': 123.57000000000001,
+                'base_code_id': 27,
+                'invoice_id': 1L,
+                'manual': False,
+                'name': u'20b - Iva al 20% (credito)',
+                'sequence': 1,
+                'tax_amount': 24.71,
+                'tax_code_id': 26}}
+    '''
+
+    def tax_difference(self, cr, uid, cur, tax_grouped):
+        real_total = 0
+        invoice_total = 0
+        cur_obj = self.pool.get('res.currency')
+        tax_obj = self.pool.get('account.tax')
+        tax_code_obj = self.pool.get('account.tax.code')
+        grouped_base = {}
+        for inv_tax in tax_grouped.values():
+            if inv_tax['tax_code_id']:
+                main_tax = tax_obj.get_main_tax(tax_obj.get_account_tax_by_tax_code(
+                    tax_code_obj.browse(cr, uid, inv_tax['tax_code_id'])))
+            elif inv_tax['base_code_id']:
+                main_tax = tax_obj.get_main_tax(tax_obj.get_account_tax_by_base_code(
+                    tax_code_obj.browse(cr, uid, inv_tax['base_code_id'])))
+            else:
+                raise osv.except_osv(_('Error'),
+                    _('No tax codes for invoice tax %s') % inv_tax['name'])
+            if not grouped_base.get(main_tax.amount, False):
+                grouped_base[main_tax.amount] = 0
+            grouped_base[main_tax.amount] +=  inv_tax['base']
+        for tax_rate in grouped_base:
+            real_total += grouped_base[tax_rate] * tax_rate
+        real_total = cur_obj.round(cr, uid, cur, real_total)
+        for inv_tax in tax_grouped.values():
+            invoice_total += inv_tax['amount']
+        return real_total - invoice_total
+
+    def compute(self, cr, uid, invoice_id, context=None):
+        tax_grouped = super(account_invoice_tax, self).compute(cr, uid, invoice_id, context)
+        inv_obj = self.pool.get('account.invoice')
+        tax_obj = self.pool.get('account.tax')
+        tax_code_obj = self.pool.get('account.tax.code')
+        invoice = inv_obj.browse(cr, uid, invoice_id, context=context)
+        cur = invoice.currency_id
+        tax_difference = self.tax_difference(cr, uid, cur, tax_grouped)
+        cur_obj = self.pool.get('res.currency')
+        if cur_obj.is_zero(cr, uid, cur, tax_difference):
+            return tax_grouped
+        company_currency = invoice.company_id.currency_id.id
+        for inv_tax in tax_grouped.values():
+            # parte detraibile
+            if not inv_tax['base_code_id'] and inv_tax['tax_code_id']:
+                ded_tax = tax_obj.get_account_tax_by_tax_code(
+                    tax_code_obj.browse(cr, uid, inv_tax['tax_code_id']))
+                tax = tax_obj.get_main_tax(ded_tax)
+                for inv_tax_2 in tax_grouped.values():
+                    # parte indetraibile
+                    if inv_tax_2['base_code_id'] and not inv_tax_2['tax_code_id']:
+                        main_tax = tax_obj.get_main_tax(tax_obj.get_account_tax_by_base_code(
+                            tax_code_obj.browse(cr, uid, inv_tax_2['base_code_id'])))
+                        # Se hanno la stessa tassa
+                        # (Il get_account_tax_by* potrebbe in generale ritornare una qualunque
+                        # delle N imposte associate al tax_code. Per la parte indetraibile, il
+                        # tax code dovrà sempre avere una sola imposta)
+                        if main_tax.id == tax.id:
+                            # se risulta un'eccedenza, la tolgo dalla parte detraibile
+                            if tax_difference < 0:
+                                inv_tax['amount'] = inv_tax['amount'] + tax_difference
+                            # se risulta una mancanza, la aggiungo alla parte indetraibile
+                            elif tax_difference > 0:
+                                inv_tax_2['amount'] = inv_tax_2['amount'] + tax_difference
+                            # calcolo l'importo del tax.code relativo all'imposta (la parte indetraibile non lo muove)
+                            if invoice.type in ('out_invoice','in_invoice'):
+                                inv_tax['tax_amount'] = cur_obj.compute(cr, uid, invoice.currency_id.id, company_currency,
+                                    inv_tax['amount'] * main_tax['tax_sign'],
+                                    context={'date': invoice.date_invoice or time.strftime('%Y-%m-%d')}, round=False)
+                            else:
+                                inv_tax['tax_amount'] = cur_obj.compute(cr, uid, invoice.currency_id.id, company_currency,
+                                    inv_tax['amount'] * main_tax['ref_tax_sign'],
+                                    context={'date': invoice.date_invoice or time.strftime('%Y-%m-%d')}, round=False)
+
+                            inv_tax['amount'] = cur_obj.round(cr, uid, cur, inv_tax['amount'])
+                            inv_tax['tax_amount'] = cur_obj.round(cr, uid, cur, inv_tax['tax_amount'])
+                            inv_tax_2['amount'] = cur_obj.round(cr, uid, cur, inv_tax_2['amount'])
+        return tax_grouped
+
+
+class account_tax_code(osv.osv):
+
+    _inherit = 'account.tax.code'
+
+    _columns = {
+        'base_tax_ids': fields.one2many('account.tax', 'base_code_id', 'Base Taxes'),
+        'tax_ids': fields.one2many('account.tax', 'tax_code_id', 'Taxes'),
+        'ref_base_tax_ids': fields.one2many('account.tax', 'ref_base_code_id', 'Ref Base Taxes'),
+        'ref_tax_ids': fields.one2many('account.tax', 'ref_tax_code_id', 'Ref Taxes'),
+        }

=== added directory 'l10n_it_partially_deductible_vat/i18n'
=== added file 'l10n_it_partially_deductible_vat/i18n/it.po'
--- l10n_it_partially_deductible_vat/i18n/it.po	1970-01-01 00:00:00 +0000
+++ l10n_it_partially_deductible_vat/i18n/it.po	2013-01-08 23:03:21 +0000
@@ -0,0 +1,62 @@
+# Translation of OpenERP Server.
+# This file contains the translation of the following modules:
+#	* l10n_it_partially_deductible_vat
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: OpenERP Server 6.0.3\n"
+"Report-Msgid-Bugs-To: support@xxxxxxxxxxx\n"
+"POT-Creation-Date: 2011-11-30 16:27+0000\n"
+"PO-Revision-Date: 2011-11-30 17:31+0100\n"
+"Last-Translator: Lorenzo Battistini <lorenzo.battistini@xxxxxxxxxxx>\n"
+"Language-Team: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: \n"
+
+#. module: l10n_it_partially_deductible_vat
+#: model:ir.module.module,description:l10n_it_partially_deductible_vat.module_meta_information
+msgid ""
+"\n"
+"    Calcoli aggiuntivi per la gestione dell'IVA parzialmente detraibile. Senza questo modulo non è possibile calcolare correttamente imponibili, imposte e conti imposte relativi all'IVA parzialmente detraibile.\n"
+"    La configurazione dell'IVA parzialmente detraibile deve essere quella utilizzata dal modulo 'l10n_it', anche se non viene usato tale modulo.\n"
+"    "
+msgstr ""
+"\n"
+"    Calcoli aggiuntivi per la gestione dell'IVA parzialmente detraibile. Senza questo modulo non è possibile calcolare correttamente imponibili, imposte e conti imposte relativi all'IVA parzialmente detraibile.\n"
+"    La configurazione dell'IVA parzialmente detraibile deve essere quella utilizzata dal modulo 'l10n_it', anche se non viene usato tale modulo.\n"
+"    "
+
+#. module: l10n_it_partially_deductible_vat
+#: model:ir.module.module,shortdesc:l10n_it_partially_deductible_vat.module_meta_information
+msgid "Italy - Partially Deductible VAT"
+msgstr "IVA parzialmente detraibile"
+
+#. module: l10n_it_partially_deductible_vat
+#: model:ir.model,name:l10n_it_partially_deductible_vat.model_account_invoice_tax
+msgid "Invoice Tax"
+msgstr "Imposta della fattura"
+
+#. module: l10n_it_partially_deductible_vat
+#: code:addons/l10n_it_partially_deductible_vat/account.py:113
+#, python-format
+msgid "No tax codes for invoice tax %s"
+msgstr "Nessun conto imposta per l'imposta %s"
+
+#. module: l10n_it_partially_deductible_vat
+#: code:addons/l10n_it_partially_deductible_vat/account.py:112
+#, python-format
+msgid "Error"
+msgstr "Error"
+
+#. module: l10n_it_partially_deductible_vat
+#: model:ir.model,name:l10n_it_partially_deductible_vat.model_account_tax
+msgid "account.tax"
+msgstr "account.tax"
+
+#. module: l10n_it_partially_deductible_vat
+#: sql_constraint:account.tax:0
+msgid "The tax name must be unique!"
+msgstr "Il nome dell'imposta deve essere unico"
+

=== added directory 'l10n_it_partially_deductible_vat/test'
=== added file 'l10n_it_partially_deductible_vat/test/account_tax.xml'
--- l10n_it_partially_deductible_vat/test/account_tax.xml	1970-01-01 00:00:00 +0000
+++ l10n_it_partially_deductible_vat/test/account_tax.xml	2013-01-08 23:03:21 +0000
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8"?>
+<openerp>
+    <data noupdate="1">
+
+        <record id="tax_20" model="account.tax">
+            <field name="name">20 %</field>
+            <field name="amount">0.2</field>
+        </record>
+
+        <record id="tax_20I5" model="account.tax">
+            <field name="name">IVA al 20% detraibile al 50%</field>
+            <field name="amount">0.2</field>
+            <field name="child_depend">1</field>
+        </record>
+
+        <record id="tax_20I5b" model="account.tax">
+            <field name="name">IVA al 20% detraibile al 50% (I)</field>
+            <field name="amount">0.5</field>
+            <field name="parent_id" ref="tax_20I5"></field>
+        </record>
+
+        <record id="tax_20I5a" model="account.tax">
+            <field name="name">IVA al 20% detraibile al 50% (D)</field>
+            <field name="amount">0</field>
+            <field name="type">balance</field>
+            <field name="parent_id" ref="tax_20I5"></field>
+        </record>
+
+        <record id="tax_2010" model="account.tax">
+            <field name="name">IVA al 20% detraibile al 10%</field>
+            <field name="amount">0.2</field>
+            <field name="child_depend">1</field>
+        </record>
+
+        <record id="tax_2010b" model="account.tax">
+            <field name="name">IVA al 20% detraibile al 10% (I)</field>
+            <field name="amount">0.9</field>
+            <field name="parent_id" ref="tax_2010"></field>
+        </record>
+
+        <record id="tax_2010a" model="account.tax">
+            <field name="name">IVA al 20% detraibile al 10% (D)</field>
+            <field name="amount">0</field>
+            <field name="type">balance</field>
+            <field name="parent_id" ref="tax_2010"></field>
+        </record>
+        
+    </data>
+</openerp>

=== added file 'l10n_it_partially_deductible_vat/test/tax_computation.yml'
--- l10n_it_partially_deductible_vat/test/tax_computation.yml	1970-01-01 00:00:00 +0000
+++ l10n_it_partially_deductible_vat/test/tax_computation.yml	2013-01-08 23:03:21 +0000
@@ -0,0 +1,142 @@
+-
+  In order to test tax computation I create a new customer invoice
+-
+  !record {model: account.invoice, id: account_invoice_customer0}:
+    account_id: account.a_recv
+    address_contact_id: base.res_partner_address_zen
+    address_invoice_id: base.res_partner_address_zen
+    company_id: base.main_company
+    currency_id: base.EUR
+    date_invoice: !eval time.strftime('%Y-%m-%d')
+    vertical_comp: 1
+    invoice_line:
+      - account_id: account.a_sale
+        name: '123.57'
+        price_unit: 123.57
+        quantity: 1.0
+        invoice_line_tax_id:
+            - tax_20I5
+    journal_id: account.sales_journal
+    partner_id: base.res_partner_3
+    
+-  
+    Compute the total tax.
+-  
+    !python {model: account.invoice}: |
+        self.button_compute(cr, uid, [ref("account_invoice_customer0")])  
+-  
+    Then I verify the amount.
+    123.57 * 0.2 = 24.714 = 24.71
+-  
+    !assert {model: account.invoice, id: account_invoice_customer0}:
+        - amount_tax == 24.71
+-
+  In order to test tax computation I create a new customer invoice
+-
+  !record {model: account.invoice, id: account_invoice_customer1}:
+    account_id: account.a_recv
+    address_contact_id: base.res_partner_address_zen
+    address_invoice_id: base.res_partner_address_zen
+    company_id: base.main_company
+    currency_id: base.EUR
+    date_invoice: !eval time.strftime('%Y-%m-%d')
+    vertical_comp: 1
+    invoice_line:
+      - account_id: account.a_sale
+        name: '123.57'
+        price_unit: 123.57
+        quantity: 1.0
+        invoice_line_tax_id:
+            - tax_20I5
+      - account_id: account.a_sale
+        name: '123.57'
+        price_unit: 123.57
+        quantity: 1.0
+        invoice_line_tax_id:
+            - tax_20
+    journal_id: account.sales_journal
+    partner_id: base.res_partner_3
+    
+-  
+    Compute the total tax.
+-  
+    !python {model: account.invoice}: |
+        self.button_compute(cr, uid, [ref("account_invoice_customer1")])  
+-  
+    Then I verify the amount.
+    123.57 + 123.57 = 247.14
+    247.14 × 0.2 = 49.428 = 49.43
+-  
+    !assert {model: account.invoice, id: account_invoice_customer1}:
+        - amount_tax == 49.43
+-
+  In order to test tax computation I create a new customer invoice
+-
+  !record {model: account.invoice, id: account_invoice_customer3}:
+    account_id: account.a_recv
+    address_contact_id: base.res_partner_address_zen
+    address_invoice_id: base.res_partner_address_zen
+    company_id: base.main_company
+    currency_id: base.EUR
+    date_invoice: !eval time.strftime('%Y-%m-%d')
+    vertical_comp: 1
+    invoice_line:
+      - account_id: account.a_sale
+        name: '123.57'
+        price_unit: 123.57
+        quantity: 1.0
+        invoice_line_tax_id:
+            - tax_2010
+      - account_id: account.a_sale
+        name: '123.57'
+        price_unit: 123.57
+        quantity: 1.0
+        invoice_line_tax_id:
+            - tax_20
+    journal_id: account.sales_journal
+    partner_id: base.res_partner_3
+    
+-  
+    Compute the total tax.
+-  
+    !python {model: account.invoice}: |
+        self.button_compute(cr, uid, [ref("account_invoice_customer3")])  
+-  
+    Then I verify the amount.
+    123.57 + 123.57 = 247.14
+    247.14 × 0.2 = 49.428 = 49.43
+-  
+    !assert {model: account.invoice, id: account_invoice_customer3}:
+        - amount_tax == 49.43
+-
+  In order to test tax computation I create a new customer invoice
+-
+  !record {model: account.invoice, id: account_invoice_customer2}:
+    account_id: account.a_recv
+    address_contact_id: base.res_partner_address_zen
+    address_invoice_id: base.res_partner_address_zen
+    company_id: base.main_company
+    currency_id: base.EUR
+    date_invoice: !eval time.strftime('%Y-%m-%d')
+    vertical_comp: 1
+    invoice_line:
+      - account_id: account.a_sale
+        name: '100.03'
+        price_unit: 100.03
+        quantity: 1.0
+        invoice_line_tax_id:
+            - tax_20I5
+    journal_id: account.sales_journal
+    partner_id: base.res_partner_3
+    
+-  
+    Compute the total tax.
+-  
+    !python {model: account.invoice}: |
+        self.button_compute(cr, uid, [ref("account_invoice_customer2")])  
+-  
+    Then I verify the amount.
+    100.03 × 0.2 = 20.006 = 20.01
+-  
+    !assert {model: account.invoice, id: account_invoice_customer2}:
+        - amount_tax == 20.01


Follow ups