diff --git a/modules/account_eu/CHANGELOG b/modules/account_eu/CHANGELOG index 106404c5a3..e57edfe52c 100644 --- a/modules/account_eu/CHANGELOG +++ b/modules/account_eu/CHANGELOG @@ -1,3 +1,4 @@ +* Add VAT exemption code on tax * Add support for Python 3.14 * Remove support for Python 3.9 diff --git a/modules/account_eu/account.py b/modules/account_eu/account.py index 3702485894..40a0623d24 100644 --- a/modules/account_eu/account.py +++ b/modules/account_eu/account.py @@ -10,18 +10,190 @@ from trytond.pool import Pool, PoolMeta from trytond.pyson import Bool, Eval from trytond.transaction import Transaction +VATEX_CODES = [ + ('VATEX-EU-79-C', + "Exempt based on article 79, point c of Council Directive " + "2006/112/EC"), + ('VATEX-EU-132', + "Exempt based on article 132 of Council Directive 2006/112/EC"), + ('VATEX-EU-132-1A', + "Exempt based on article 132, section 1 (a) of Council Directive " + "2006/112/EC"), + ('VATEX-EU-132-1B', + "Exempt based on article 132, section 1 (b) of Council Directive " + "2006/112/EC"), + ('VATEX-EU-132-1C', + "Exempt based on article 132, section 1 (c) of Council Directive " + "2006/112/EC"), + ('VATEX-EU-132-1D', + "Exempt based on article 132, section 1 (d) of Council Directive " + "2006/112/EC"), + ('VATEX-EU-132-1E', + "Exempt based on article 132, section 1 (e) of Council Directive " + "2006/112/EC"), + ('VATEX-EU-132-1F', + "Exempt based on article 132, section 1 (f) of Council Directive " + "2006/112/EC"), + ('VATEX-EU-132-1G', + "Exempt based on article 132, section 1 (g) of Council Directive " + "2006/112/EC"), + ('VATEX-EU-132-1H', + "Exempt based on article 132, section 1 (h) of Council Directive " + "2006/112/EC"), + ('VATEX-EU-132-1I', + "Exempt based on article 132, section 1 (i) of Council Directive " + "2006/112/EC"), + ('VATEX-EU-132-1J', + "Exempt based on article 132, section 1 (j) of Council Directive " + "2006/112/EC"), + ('VATEX-EU-132-1K', + "Exempt based on article 132, section 1 (k) of Council Directive " + "2006/112/EC"), + ('VATEX-EU-132-1L', + "Exempt based on article 132, section 1 (l) of Council Directive " + "2006/112/EC"), + ('VATEX-EU-132-1M', + "Exempt based on article 132, section 1 (m) of Council Directive " + "2006/112/EC"), + ('VATEX-EU-132-1N', + "Exempt based on article 132, section 1 (n) of Council Directive " + "2006/112/EC"), + ('VATEX-EU-132-1O', + "Exempt based on article 132, section 1 (o) of Council Directive " + "2006/112/EC"), + ('VATEX-EU-132-1P', + "Exempt based on article 132, section 1 (p) of Council Directive " + "2006/112/EC"), + ('VATEX-EU-132-1Q', + "Exempt based on article 132, section 1 (q) of Council Directive " + "2006/112/EC"), + ('VATEX-EU-143', + "Exempt based on article 143 of Council Directive 2006/112/EC"), + ('VATEX-EU-143-1A', + "Exempt based on article 143, section 1 (a) of Council Directive " + "2006/112/EC"), + ('VATEX-EU-143-1B', + "Exempt based on article 143, section 1 (b) of Council Directive " + "2006/112/EC"), + ('VATEX-EU-143-1C', + "Exempt based on article 143, section 1 (c) of Council Directive " + "2006/112/EC"), + ('VATEX-EU-143-1D', + "Exempt based on article 143, section 1 (d) of Council Directive " + "2006/112/EC"), + ('VATEX-EU-143-1E', + "Exempt based on article 143, section 1 (e) of Council Directive " + "2006/112/EC"), + ('VATEX-EU-143-1F', + "Exempt based on article 143, section 1 (f) of Council Directive " + "2006/112/EC"), + ('VATEX-EU-143-1FA', + "Exempt based on article 143, section 1 (fa) of Council Directive " + "2006/112/EC"), + ('VATEX-EU-143-1G', + "Exempt based on article 143, section 1 (g) of Council Directive " + "2006/112/EC"), + ('VATEX-EU-143-1H', + "Exempt based on article 143, section 1 (h) of Council Directive " + "2006/112/EC"), + ('VATEX-EU-143-1I', + "Exempt based on article 143, section 1 (i) of Council Directive " + "2006/112/EC"), + ('VATEX-EU-143-1J', + "Exempt based on article 143, section 1 (j) of Council Directive " + "2006/112/EC"), + ('VATEX-EU-143-1K', + "Exempt based on article 143, section 1 (k) of Council Directive " + "2006/112/EC"), + ('VATEX-EU-143-1L', + "Exempt based on article 143, section 1 (l) of Council Directive " + "2006/112/EC"), + ('VATEX-EU-144', + "Exempt based on article 144 of Council Directive 2006/112/EC"), + ('VATEX-EU-146-1E', + "Exempt based on article 146 section 1 (e) of Council Directive " + "2006/112/EC"), + ('VATEX-EU-148', + "Exempt based on article 148 of Council Directive 2006/112/EC"), + ('VATEX-EU-148-A', + "Exempt based on article 148, section (a) of Council Directive " + "2006/112/EC"), + ('VATEX-EU-148-B', + "Exempt based on article 148, section (b) of Council Directive " + "2006/112/EC"), + ('VATEX-EU-148-C', + "Exempt based on article 148, section (c) of Council Directive " + "2006/112/EC"), + ('VATEX-EU-148-D', + "Exempt based on article 148, section (d) of Council Directive " + "2006/112/EC"), + ('VATEX-EU-148-E', + "Exempt based on article 148, section (e) of Council Directive " + "2006/112/EC"), + ('VATEX-EU-148-F', + "Exempt based on article 148, section (f) of Council Directive " + "2006/112/EC"), + ('VATEX-EU-148-G', + "Exempt based on article 148, section (g) of Council Directive " + "2006/112/EC"), + ('VATEX-EU-151', + "Exempt based on article 151 of Council Directive 2006/112/EC"), + ('VATEX-EU-151-1A', + "Exempt based on article 151, section 1 (a) of Council Directive " + "2006/112/EC"), + ('VATEX-EU-151-1AA', + "Exempt based on article 151, section 1 (aa) of Council Directive " + "2006/112/EC"), + ('VATEX-EU-151-1B', + "Exempt based on article 151, section 1 (b) of Council Directive " + "2006/112/EC"), + ('VATEX-EU-151-1C', + "Exempt based on article 151, section 1 (c) of Council Directive " + "2006/112/EC"), + ('VATEX-EU-151-1D', + "Exempt based on article 151, section 1 (d) of Council Directive " + "2006/112/EC"), + ('VATEX-EU-151-1E', + "Exempt based on article 151, section 1 (e) of Council Directive " + "2006/112/EC"), + ('VATEX-EU-159', + "Exempt based on article 159 of Council Directive 2006/112/EC"), + ('VATEX-EU-309', + "Exempt based on article 309 of Council Directive 2006/112/EC"), + ('VATEX-EU-AE', "Reverse charge"), + ('VATEX-EU-D', + "Intra-Community acquisition from second hand means of transport"), + ('VATEX-EU-F', "Intra-Community acquisition of second hand goods"), + ('VATEX-EU-G', "Export outside the EU"), + ('VATEX-EU-I', "Intra-Community acquisition of works of art"), + ('VATEX-EU-IC', "Intra-Community supply"), + ('VATEX-EU-O', "Not subject to VAT"), + ('VATEX-EU-J', + "Intra-Community acquisition of collectors items and antiques"), + ] + class TaxTemplate(metaclass=PoolMeta): __name__ = 'account.tax.template' ec_sales_list_code = fields.Char("EC Sales List Code") + vatex_code = fields.Selection( + 'get_vatex_codes', "Tax Exemption Code") def _get_tax_value(self, tax=None): value = super()._get_tax_value(tax=tax) if not tax or tax.ec_sales_list_code != self.ec_sales_list_code: value['ec_sales_list_code'] = self.ec_sales_list_code + if not tax or tax.vatex_code != self.vatex_code: + value['vatex_code'] = self.vatex_code return value + @classmethod + def get_vatex_codes(cls): + pool = Pool() + Tax = pool.get('account.tax') + return Tax.fields_get(['vatex_code'])['vatex_code']['selection'] + class Tax(metaclass=PoolMeta): __name__ = 'account.tax' @@ -31,6 +203,13 @@ class Tax(metaclass=PoolMeta): 'readonly': (Bool(Eval('template', -1)) & ~Eval('template_override', False)), }) + vatex_code = fields.Selection( + [(None, "")] + VATEX_CODES, "Tax Exemption Code", sort=False, + states={ + 'readonly': (Bool(Eval('template', -1)) + & ~Eval('template_override', False)), + }, + help="The reason why the amount is exempted from VAT.") class ECSalesList(ModelSQL, ModelView): diff --git a/modules/account_eu/view/tax_form.xml b/modules/account_eu/view/tax_form.xml index 00447ad9dc..91de4c44b6 100644 --- a/modules/account_eu/view/tax_form.xml +++ b/modules/account_eu/view/tax_form.xml @@ -3,9 +3,13 @@ this repository contains the full copyright notices and license terms. --> - + diff --git a/modules/account_eu/view/tax_template_form.xml b/modules/account_eu/view/tax_template_form.xml index 00447ad9dc..91de4c44b6 100644 --- a/modules/account_eu/view/tax_template_form.xml +++ b/modules/account_eu/view/tax_template_form.xml @@ -3,9 +3,13 @@ this repository contains the full copyright notices and license terms. --> - + diff --git a/modules/account_fr/account.py b/modules/account_fr/account.py index 4418ceb6f4..ca2cfaed41 100644 --- a/modules/account_fr/account.py +++ b/modules/account_fr/account.py @@ -14,6 +14,88 @@ from trytond.pyson import Eval from trytond.transaction import Transaction from trytond.wizard import Button, StateTransition, StateView, Wizard +VATEX_CODES = [ + ('VATEX-FR-FRANCHISE', "France domestic VAT franchise in base"), + ('VATEX-FR-CNWVAT', + "France domestic Credit Notes without VAT, due to supplier forfeit of " + "VAT for discount"), + ('VATEX-EU-153', + "Exempt based on article 153 of Council Directive 2006/112/EC"), + ('VATEX-FR-CGI261-1', + "Exempt based on 1 of article 261 of the Code Général des Impôts " + "(CGI; General tax code)"), + ('VATEX-FR-CGI261-2', + "Exempt based on 2 of article 261 of the Code Général des Impôts " + "(CGI ; General tax code)"), + ('VATEX-FR-CGI261-3', + "Exempt based on 3 of article 261 of the Code Général des Impôts " + "(CGI ; General tax code"), + ('VATEX-FR-CGI261-4', + "Exempt based on 4 of article 261 of the Code Général des Impôts " + "(CGI ; General tax code)"), + ('VATEX-FR-CGI261-5', + "Exempt based on 5 of article 261 of the Code Général des Impôts " + "(CGI ; General tax code)"), + ('VATEX-FR-CGI261-7', + "Exempt based on 7 of article 261 of the Code Général des Impôts " + "(CGI ; General tax code)"), + ('VATEX-FR-CGI261-8', + "Exempt based on 8 of article 261 of the Code Général des Impôts " + "(CGI ; General tax code)"), + ('VATEX-FR-CGI261A', + "Exempt based on article 261 A of the Code Général des Impôts " + "(CGI ; General tax code)"), + ('VATEX-FR-CGI261B', + "Exempt based on article 261 B of the Code Général des Impôts " + "(CGI ; General tax code)"), + ('VATEX-FR-CGI261C-1', + "Exempt based on 1° of article 261 C of the Code Général des Impôts " + "(CGI ; General tax code)"), + ('VATEX-FR-CGI261C-2', + "Exempt based on 2° of article 261 C of the Code Général des Impôts " + "(CGI ; General tax code)"), + ('VATEX-FR-CGI261C-3', + "Exempt based on 3° of article 261 C of the Code Général des Impôts " + "(CGI ; General tax code)"), + ('VATEX-FR-CGI261D-1', + "Exempt based on 1° of article 261 D of the Code Général des Impôts " + "(CGI ; General tax code)"), + ('VATEX-FR-CGI261D-1BIS', + "Exempt based on 1°bis of article 261 D of the Code Général des " + "Impôts (CGI ; General tax code)"), + ('VATEX-FR-CGI261D-2', + "Exempt based on 2° of article 261 D of the Code Général des Impôts " + "(CGI ; General tax code)"), + ('VATEX-FR-CGI261D-3', + "Exempt based on 3° of article 261 D of the Code Général des Impôts " + "(CGI ; General tax code) " + "Exonération de TVA - Article 261 D-3° du Code Général des Impôts"), + ('VATEX-FR-CGI261D-4', + "Exempt based on 4° of article 261 D of the Code Général des Impôts " + "(CGI ; General tax code)"), + ('VATEX-FR-CGI261E-1', + "Exempt based on 1° of article 261 E of the Code Général des Impôts " + "(CGI ; General tax code)"), + ('VATEX-FR-CGI261E-2', + "Exempt based on 2° of article 261 E of the Code Général des Impôts " + "(CGI ; General tax code)"), + ('VATEX-FR-CGI277A', + "Exempt based on article 277 A of the Code Général des Impôts " + "(CGI ; General tax code)"), + ('VATEX-FR-CGI275', + " Exempt based on article 275 of the Code Général des Impôts " + "(CGI ; General tax code)"), + ('VATEX-FR-298SEXDECIESA', + " Exempt based on article 298 sexdecies A of the Code Général des " + "Impôts (CGI ; General tax code)"), + ('VATEX-FR-CGI295', + "Exempt based on article 295 of the Code Général des Impôts " + "(CGI ; General tax code)"), + ('VATEX-FR-AE', + " Exempt based on 2 of article 283 of the Code Général des Impôts " + "(CGI ; General tax code)"), + ] + class AccountTemplate(metaclass=PoolMeta): __name__ = 'account.account.template' @@ -45,6 +127,16 @@ class AccountTemplate(metaclass=PoolMeta): super().__register__(module_name) +class Tax(metaclass=PoolMeta): + __name__ = 'account.tax' + + @classmethod + def __setup__(cls): + super().__setup__() + if hasattr(cls, 'vatex_code'): + cls.vatex_code.selection.extend(VATEX_CODES) + + class CreateChart(metaclass=PoolMeta): __name__ = 'account.create_chart' diff --git a/modules/account_fr/tests/test_module.py b/modules/account_fr/tests/test_module.py index 227a1fc155..f4264d33b1 100644 --- a/modules/account_fr/tests/test_module.py +++ b/modules/account_fr/tests/test_module.py @@ -9,6 +9,7 @@ from trytond.tests.test_tryton import ModuleTestCase, with_transaction class AccountFRTestCase(ModuleTestCase): 'Test Account FR module' module = 'account_fr' + extras = ['account_eu'] @with_transaction() def test_create_chart(self): diff --git a/modules/account_fr/tryton.cfg b/modules/account_fr/tryton.cfg index 89f3694878..fd3d8e1159 100644 --- a/modules/account_fr/tryton.cfg +++ b/modules/account_fr/tryton.cfg @@ -6,6 +6,7 @@ depends: extras_depend: account_asset account_deposit + account_eu account_invoice sale_advance_payment xml: @@ -16,6 +17,7 @@ xml: [register] model: account.AccountTemplate + account.Tax account.FrFECStart account.FrFECResult wizard: diff --git a/modules/edocument_ubl/CHANGELOG b/modules/edocument_ubl/CHANGELOG index 94f87f4f5c..eafa21c685 100644 --- a/modules/edocument_ubl/CHANGELOG +++ b/modules/edocument_ubl/CHANGELOG @@ -1,3 +1,4 @@ +* Use VATEX as tax exemption reason code * Add support for Python 3.14 * Remove support for Python 3.9 * Fill payment means diff --git a/modules/edocument_ubl/edocument.py b/modules/edocument_ubl/edocument.py index dfb11ccef6..221ac19d28 100644 --- a/modules/edocument_ubl/edocument.py +++ b/modules/edocument_ubl/edocument.py @@ -194,7 +194,7 @@ class Invoice(Model): class Tax(namedtuple( 'Tax', ('type', 'rate', 'unece_category_code', 'unece_code', - 'legal_notice'))): + 'vatex_code', 'legal_notice'))): @classmethod def from_line(cls, line): return Tax( @@ -202,6 +202,7 @@ class Invoice(Model): rate=line.tax.rate, unece_category_code=line.tax.unece_category_code, unece_code=line.tax.unece_code, + vatex_code=getattr(line.tax, 'vatex_code', ''), legal_notice=line.legal_notice or '') TaxLine = namedtuple('TaxLine', ('base', 'amount', 'tax')) for group, lines in groupby(sorted( @@ -570,8 +571,11 @@ class Invoice(Model): ], ('company', '=', company.id), ]) + order = [] + if hasattr(Tax, 'vatex_code'): + order.append(('vatex_code', 'ASC NULLS LAST')) try: - tax, = Tax.search(domain, limit=1) + tax, = Tax.search(domain, limit=1, order=order) except ValueError: raise InvoiceError(gettext( 'edocument_ubl.msg_tax_not_found', @@ -1135,6 +1139,8 @@ class Invoice(Model): @classmethod def _parse_2_tax_category(cls, tax_category): + pool = Pool() + Tax = pool.get('account.tax') domain = [ ('parent', '=', None), ] @@ -1148,6 +1154,13 @@ class Invoice(Model): if percent: domain.append(('type', '=', 'percentage')) domain.append(('rate', '=', Decimal(percent) / 100)) + if (hasattr(Tax, 'vatex_code') + and (tax_exemption_reason_code := tax_category.findtext( + './{*}TaxExemptionReasonCode'))): + domain.append(['OR', + ('vatex_code', '=', tax_exemption_reason_code), + ('vatex_code', '=', None), + ]) return domain @classmethod diff --git a/modules/edocument_ubl/template/2/base.xml b/modules/edocument_ubl/template/2/base.xml index f9e59bd646..8363fb6768 100644 --- a/modules/edocument_ubl/template/2/base.xml +++ b/modules/edocument_ubl/template/2/base.xml @@ -84,6 +84,7 @@ this repository contains the full copyright notices and license terms. --> ${tax.unece_category_code} ${format((tax.rate * 100).normalize(), 'f')} + ${tax.vatex_code} ${tax.legal_notice} ${tax.unece_code} diff --git a/modules/edocument_uncefact/CHANGELOG b/modules/edocument_uncefact/CHANGELOG index 370fa6bc42..1b806603e9 100644 --- a/modules/edocument_uncefact/CHANGELOG +++ b/modules/edocument_uncefact/CHANGELOG @@ -1,3 +1,4 @@ +* Use VATEX as tax exemption reason code * Add support for Python 3.14 * Remove support for Python 3.9 * Render payment means diff --git a/modules/edocument_uncefact/template/16B-CII/CrossIndustryInvoice.xml b/modules/edocument_uncefact/template/16B-CII/CrossIndustryInvoice.xml index dfcd84996f..0f84f4df05 100644 --- a/modules/edocument_uncefact/template/16B-CII/CrossIndustryInvoice.xml +++ b/modules/edocument_uncefact/template/16B-CII/CrossIndustryInvoice.xml @@ -45,6 +45,7 @@ this repository contains the full copyright notices and license terms. --> ${amount * this.type_sign} ${tax.unece_code} + ${tax.vatex_code} ${tax.legal_notice} ${base * this.type_sign} ${tax.unece_category_code}