From eccab77238ae02586b70fc935dc956999b5cd88d Mon Sep 17 00:00:00 2001 From: Sergi Almacellas Abellana Date: Sat, 1 Sep 2018 14:55:15 +0200 Subject: [PATCH] Allow to export tax reports as file issue7484 review45241002 --- CHANGELOG | 1 + __init__.py | 19 ++ account.py | 39 ++++ aeat111.txt | 1 + aeat115.txt | 1 + aeat303.txt | 1 + doc/index.rst | 6 + reporting_tax.py | 317 ++++++++++++++++++++++++++++++++ reporting_tax.xml | 84 +++++++++ setup.py | 3 +- tax.xml | 46 +++++ tax_normal.xml | 46 +++++ tax_pyme.xml | 46 +++++ tests/111.txt | 1 + tests/115.txt | 1 + tests/303.txt | 1 + tests/scenario_reporting.rst | 181 ++++++++++++++++++ tests/test_account_es.py | 8 + tryton.cfg | 2 + view.xml | 18 ++ view/print_aeat_start_form.xml | 8 + view/tax_code_form.xml | 9 + view/tax_code_template_form.xml | 9 + 23 files changed, 847 insertions(+), 1 deletion(-) create mode 100644 account.py create mode 100644 aeat111.txt create mode 100644 aeat115.txt create mode 100644 aeat303.txt create mode 100644 reporting_tax.py create mode 100644 reporting_tax.xml create mode 100644 tests/111.txt create mode 100644 tests/115.txt create mode 100644 tests/303.txt create mode 100644 tests/scenario_reporting.rst create mode 100644 view.xml create mode 100644 view/print_aeat_start_form.xml create mode 100644 view/tax_code_form.xml create mode 100644 view/tax_code_template_form.xml diff --git a/CHANGELOG b/CHANGELOG index a26e8fb14e..b543ba1dec 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,4 @@ +* Allow to export tax reports as file * Remove support for Python 2.7 Version 4.8.0 - 2018-05-21 diff --git a/__init__.py b/__init__.py index 4effdfa4a2..61a7b99e32 100644 --- a/__init__.py +++ b/__init__.py @@ -1,2 +1,21 @@ # This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. +from trytond.pool import Pool +from . import account +from . import reporting_tax + + +def register(): + Pool.register( + reporting_tax.PrintAEATStart, + account.TaxCodeTemplate, + account.TaxCode, + module='account_es', type_='model') + Pool.register( + reporting_tax.AEAT111, + reporting_tax.AEAT115, + reporting_tax.AEAT303, + module='account_es', type_='report') + Pool.register( + reporting_tax.PrintAEAT, + module='account_es', type_='wizard') diff --git a/account.py b/account.py new file mode 100644 index 0000000000..c217d76ba3 --- /dev/null +++ b/account.py @@ -0,0 +1,39 @@ +# This file is part of Tryton. The COPYRIGHT file at the top level of +# this repository contains the full copyright notices and license terms. +from trytond.model import fields +from trytond.pool import PoolMeta +from trytond.pyson import Bool, Eval + +__all__ = ['TaxCodeTemplate', 'TaxCode'] + + +class TaxCodeTemplate(metaclass=PoolMeta): + __name__ = 'account.tax.code.template' + + aeat_report = fields.Selection([ + (None, ''), + ('111', "Model 111"), + ('115', "Model 115"), + ('303', "Model 303"), + ], "AEAT Report") + + def _get_tax_code_value(self, code=None): + value = super(TaxCodeTemplate, self)._get_tax_code_value(code=code) + value['aeat_report'] = self.aeat_report + return value + + +class TaxCode(metaclass=PoolMeta): + __name__ = 'account.tax.code' + + aeat_report = fields.Selection([ + (None, ''), + ('111', "Model 111"), + ('115', "Model 115"), + ('303', "Model 303"), + ], "AEAT Report", + states={ + 'readonly': (Bool(Eval('template', -1)) + & ~Eval('template_override', False)), + }, + depends=['template', 'template_override']) diff --git a/aeat111.txt b/aeat111.txt new file mode 100644 index 0000000000..7829ceab21 --- /dev/null +++ b/aeat111.txt @@ -0,0 +1 @@ +${justify('', 300)} I${company.party.tax_identifier.code[2:]}${justify(company.rec_name.upper(), 80)}${year}${period}${format_integer(parties['02'])}${format_decimal(amounts['02'])}${format_decimal(amounts['03'])}${format_integer(parties['05'])}${format_decimal(amounts['05'])}${format_decimal(amounts['06'])}${format_integer(parties['08'])}${format_decimal(amounts['08'])}${format_decimal(amounts['09'])}${format_integer(parties['11'])}${format_decimal(amounts['11'])}${format_decimal(amounts['12'])}${format_integer(parties['14'])}${format_decimal(amounts['14'])}${format_decimal(amounts['15'])}${format_integer(parties['17'])}${format_decimal(amounts['17'])}${format_decimal(amounts['18'])}${format_integer(parties['20'])}${format_decimal(amounts['20'])}${format_decimal(amounts['21'])}${format_integer(parties['23'])}${format_decimal(amounts['23'])}${format_decimal(amounts['24'])}${format_integer(parties['26'])}${format_decimal(amounts['26'])}${format_decimal(amounts['27'])}${format_decimal(amounts['28'])}${format_decimal(amounts['29'])}${format_decimal(amounts['30'])}${justify('', 451)} diff --git a/aeat115.txt b/aeat115.txt new file mode 100644 index 0000000000..4c0be980b2 --- /dev/null +++ b/aeat115.txt @@ -0,0 +1 @@ +${justify('', 300)} I${company.party.tax_identifier.code[2:]}${justify(company.rec_name.upper(), 80)}${year}${period}${format_integer(parties['03'], 15)}${format_decimal(amounts['02'])}${format_decimal(amounts['03'])}${format_decimal(amounts['04'])}${format_decimal(amounts['05'])}${justify('', 297)} diff --git a/aeat303.txt b/aeat303.txt new file mode 100644 index 0000000000..42dcd3824d --- /dev/null +++ b/aeat303.txt @@ -0,0 +1 @@ +${justify('', 300)} ${declaration_type}${company.party.tax_identifier.code[2:]}${justify(company.rec_name.upper(), 80)}${year}${period}2322 2222${format_decimal(amounts['01'])}${format_percentage(amounts['02'])}${format_decimal(amounts['03'])}${format_decimal(amounts['04'])}${format_percentage(amounts['05'])}${format_decimal(amounts['06'])}${format_decimal(amounts['07'])}${format_percentage(amounts['08'])}${format_decimal(amounts['09'])}${format_decimal(amounts['10'])}${format_decimal(amounts['11'])}${format_decimal(amounts['12'])}${format_decimal(amounts['13'])}${format_decimal(amounts['14'])}${format_decimal(amounts['15'])}${format_decimal(amounts['16'])}${format_percentage(amounts['017'])}${format_decimal(amounts['18'])}${format_decimal(amounts['19'])}${format_percentage(amounts['20'])}${format_decimal(amounts['21'])}${format_decimal(amounts['22'])}${format_percentage(amounts['23'])}${format_decimal(amounts['24'])}${format_decimal(amounts['25'], True)}${format_decimal(amounts['26'], True)}${format_decimal(amounts['27'], True)}${format_decimal(amounts['28'])}${format_decimal(amounts['29'])}${format_decimal(amounts['30'])}${format_decimal(amounts['31'])}${format_decimal(amounts['32'])}${format_decimal(amounts['33'])}${format_decimal(amounts['34'])}${format_decimal(amounts['35'])}${format_decimal(amounts['36'])}${format_decimal(amounts['37'])}${format_decimal(amounts['38'])}${format_decimal(amounts['39'])}${format_decimal(amounts['40'], True)}${format_decimal(amounts['41'], True)}${format_decimal(amounts['42'], True)}${format_decimal(amounts['43'], True)}${format_decimal(amounts['44'], True)}${format_decimal(amounts['45'], True)}${format_decimal(amounts['46'], True)}022${justify('', 592)}${format_decimal(amounts['59'])}${format_decimal(amounts['60'])}${format_decimal(amounts['61'])}${format_decimal(amounts['62'])}${format_decimal(amounts['63'])}${format_decimal(amounts['74'])}${format_decimal(amounts['75'])}${format_decimal(amounts['76'])}${format_decimal(amounts['64'], True)}${format_percentage(amounts['65'])}0000${format_decimal(amounts['66'], True)}${format_decimal(amounts['77'])}${format_decimal(amounts['67'])}${format_decimal(amounts['68'], True)}${format_decimal(amounts['69'], True)}${format_decimal(amounts['70'], True)}${format_decimal(amounts['71'], True)}${justify('', 60)}0 0 0 0 0 0 ${format_decimal(amounts['80'])}${format_decimal(amounts['81'])}${format_decimal(amounts['93'])}${format_decimal(amounts['83'])}${format_decimal(amounts['84'])}${format_decimal(amounts['85'])}${format_decimal(amounts['86'])}${format_decimal(amounts['79'])}${format_decimal(amounts['88'])}0${format_percentage(amounts['89'])}${format_percentage(amounts['90'])}${format_percentage(amounts['91'])}${format_percentage(amounts['92'])}${format_decimal(amounts['94'])}${format_decimal(amounts['95'])}${format_decimal(amounts['96'])}${format_decimal(amounts['97'])}${format_decimal(amounts['98'])}${format_decimal(amounts['99'])}${justify('', 468)} diff --git a/doc/index.rst b/doc/index.rst index eb980f3c5a..a86104816b 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -9,3 +9,9 @@ The Spanish account module defines the following charts of account: The chart was published as `REAL DECRETO 1514/2007 https://www.boe.es/boe/dias/2007/11/20/pdfs/C00001-00152.pdf`_ on 20th November 2007. + +A wizard allows to generate the following AEAT files: + +* Modelo 111 +* Modelo 115 +* Modelo 303 diff --git a/reporting_tax.py b/reporting_tax.py new file mode 100644 index 0000000000..93f72e753c --- /dev/null +++ b/reporting_tax.py @@ -0,0 +1,317 @@ +# This file is part of Tryton. The COPYRIGHT file at the top level of +# this repository contains the full copyright notices and license terms. +from collections import defaultdict +from decimal import Decimal +from operator import attrgetter + +from sql import Cast, Null, Literal +from sql.aggregate import Count +from sql.conditionals import Case +from sql.functions import Substring, Position + +from trytond.model import ModelView, fields +from trytond.model.modelsql import convert_from +from trytond.pool import Pool +from trytond.report import Report +from trytond.transaction import Transaction +from trytond.wizard import Wizard, StateView, StateTransition, StateReport, \ + Button + +__all__ = ['AEAT111', 'AEAT115', 'AEAT303', 'PrintAEATStart', 'PrintAEAT'] + + +def justify(string, size): + return string[:size].ljust(size) + + +def format_decimal(n, include_sign=False): + if not isinstance(n, Decimal): + n = Decimal(n) + sign = '' + if include_sign: + sign = 'N' if n < 0 else '' + return sign + ('{0:.2f}'.format(abs(n))).replace('.', '').rjust( + 17 - len(sign), '0') + + +def format_integer(n, size=8): + return ('%d' % n).rjust(size, '0') + + +def format_percentage(n, size=5): + return ('{0:.2f}'.format(n)).replace('.', '').rjust(size, '0') + + +class AEATReport(Report): + + @classmethod + def get_context(cls, records, data): + pool = Pool() + Period = pool.get('account.period') + context = super().get_context(records, data) + + periods = sorted( + Period.browse(data['periods']), key=attrgetter('start_date')) + + context['year'] = str(periods[0].start_date.year) + context['company'] = periods[0].fiscalyear.company + + start_month = periods[0].start_date.month + end_month = periods[-1].end_date.month + if end_month - start_month > 0: + context['period'] = str(end_month // 3) + 'T' + else: + context['period'] = str(start_month).rjust(2, '0') + + context['justify'] = justify + context['format_decimal'] = format_decimal + context['format_integer'] = format_integer + context['format_percentage'] = format_percentage + + with Transaction().set_context(periods=data['periods']): + context['amounts'] = cls.compute_amounts() + + return context + + @classmethod + def compute_amounts(cls): + amounts = defaultdict(lambda: Decimal(0)) + for tax_code in cls.tax_codes(): + amounts[tax_code.code] += tax_code.amount + return amounts + + @classmethod + def tax_codes(cls): + pool = Pool() + TaxCode = pool.get('account.tax.code') + return TaxCode.search([('aeat_report', '=', cls._aeat_report)]) + + +class AEATPartyReport(AEATReport): + + @classmethod + def aeat_party_expression(cls, tables): + ''' + Returns a couple of sql expression and tables used by sql query to + compute the aeat party. + ''' + pool = Pool() + Invoice = pool.get('account.invoice') + + table, _ = tables[None] + is_invoice = table.origin.like(Invoice.__name__ + ',%') + + if 'invoice' in tables: + invoice, _ = tables['invoice'] + else: + invoice = Invoice.__table__() + tables['invoice'] = { + None: (invoice, (is_invoice + & (invoice.id == Cast( + Substring(table.origin, + Position(',', table.origin) + Literal(1)), + Invoice.id.sql_type().base)))), + } + + return Case((is_invoice, invoice.party), else_=Null), tables + + @classmethod + def get_context(cls, records, data): + pool = Pool() + Move = pool.get('account.move') + Line = pool.get('account.move.line') + TaxLine = pool.get('account.tax.line') + Tax = pool.get('account.tax') + + context = super().get_context(records, data) + cursor = Transaction().connection.cursor() + + move = Move.__table__() + move_line = Line.__table__() + tax_line = TaxLine.__table__() + + tables = { + None: (move, None), + 'lines': { + None: (move_line, move_line.move == move.id), + 'tax_lines': { + None: (tax_line, tax_line.move_line == move_line.id), + }, + }, + } + + expression, tables = cls.aeat_party_expression(tables) + + parties = defaultdict(int) + for tax_code in cls.tax_codes(): + domain = ['OR'] + for line in tax_code.lines: + domain.append(line._line_domain) + + with Transaction().set_context(periods=data['periods']): + tax_line_domain = [Tax._amount_domain(), domain] + _, where = Move.search_domain([ + ('lines', 'where', [ + ('tax_lines', 'where', tax_line_domain), + ]), + ], tables=tables) + + from_ = convert_from(None, tables) + cursor.execute(*from_.select( + expression, where=where, group_by=(expression,)).select( + Count(Literal('*')))) + row = cursor.fetchone() + if row: + parties[tax_code.code] += row[0] + context['parties'] = parties + return context + + +class AEAT111(AEATPartyReport): + __name__ = 'account.reporting.aeat111' + _aeat_report = '111' + + @classmethod + def get_context(cls, records, data): + context = super().get_context(records, data) + amounts = context['amounts'] + for code in ['28', '30']: + assert code not in amounts, ( + "computed code %s already defined" % code) + amounts['28'] = (amounts['03'] + amounts['06'] + amounts['09'] + + amounts['12'] + amounts['15'] + amounts['18'] + amounts['21'] + + amounts['24'] + amounts['27']) + amounts['30'] = amounts['28'] - amounts['29'] + return context + + +class AEAT115(AEATPartyReport): + __name__ = 'account.reporting.aeat115' + _aeat_report = '115' + + @classmethod + def get_context(cls, records, data): + context = super().get_context(records, data) + amounts = context['amounts'] + assert '05' not in amounts, ( + "computed code 05 already defined") + amounts['05'] = amounts['03'] - amounts['04'] + return context + + +class AEAT303(AEATReport): + __name__ = 'account.reporting.aeat303' + _aeat_report = '303' + + @classmethod + def compute_amounts(cls): + amounts = super().compute_amounts() + amounts['65'] = 100.0 + return amounts + + @classmethod + def get_context(cls, records, data): + pool = Pool() + Period = pool.get('account.period') + TaxCodeLine = pool.get('account.tax.code.line') + context = super().get_context(records, data) + amounts = context['amounts'] + + periods = Period.browse(data['periods']) + start_date = periods[0].start_date + end_date = periods[-1].end_date + + lines = TaxCodeLine.search([ + ('code', 'in', cls.tax_codes()), + ('code.code', 'in', ['03', '06', '09', '18', '21', '24']), + ('tax', 'where', [ + ('type', '=', 'percentage'), + ['OR', + ('start_date', '=', None), + ('start_date', '<=', end_date), + ], + ['OR', + ('end_date', '=', None), + ('end_date', '>=', start_date), + ], + ]), + ]) + for line in lines: + code = str(int(line.code.code) - 1).rjust(2, '0') + amounts[code] = float(line.tax.rate * Decimal(100)) + + for code in ['46', '64', '66', '69', '71', '88']: + assert code not in amounts, ( + "computed code %s already defined" % code) + amounts['46'] = amounts['27'] - amounts['45'] + amounts['64'] = amounts['46'] + amounts['58'] + amounts['76'] + amounts['66'] = amounts['64'] * Decimal(amounts['65']) / Decimal(100.0) + amounts['69'] = (amounts['66'] + amounts['77'] - amounts['67'] + + amounts['68']) + amounts['71'] = (amounts['69'] - amounts['70']) + amounts['88'] = (amounts['80'] + amounts['81'] - amounts['93'] + + amounts['94'] + amounts['83'] + amounts['84'] + amounts['85'] + + amounts['86'] + amounts['95'] + amounts['96'] + amounts['97'] + + amounts['98'] - amounts['79'] - amounts['99']) + + last_period = [p for p in periods[0].fiscalyear.periods + if p.type == 'standard'][-1] + declaration_type = 'N' + if amounts['69'] > 0: + declaration_type = 'I' + elif amounts['69'] < 0: + declaration_type = 'D' if last_period in periods else 'C' + context['declaration_type'] = declaration_type + return context + + +class PrintAEATStart(ModelView): + 'Print AEAT Start' + __name__ = 'account.reporting.aeat.start' + + report = fields.Selection([ + ('111', "Model 111"), + ('115', "Model 115"), + ('303', "Model 303"), + ], "Report", required=True) + periods = fields.Many2Many('account.period', None, None, 'Periods', + required=True) + + +class PrintAEAT(Wizard): + 'Print AEAT' + __name__ = 'account.reporting.aeat' + start = StateView('account.reporting.aeat.start', + 'account_es.print_aeat_start_view_form', [ + Button('Cancel', 'end', 'tryton-cancel'), + Button('Print', 'choice', 'tryton-ok', default=True), + ]) + choice = StateTransition() + model_111 = StateReport('account.reporting.aeat111') + model_115 = StateReport('account.reporting.aeat115') + model_303 = StateReport('account.reporting.aeat303') + + @classmethod + def __setup__(cls): + super().__setup__() + cls._error_messages.update({ + 'same_fiscalyear': ("Periods should be of the same fiscalyear " + "to generate the report."), + }) + + def transition_choice(self): + validate = getattr(self, 'validate_%s' % self.start.report, None) + if validate: + validate() + return 'model_%s' % self.start.report + + def open_report(self, action): + return action, {'periods': [p.id for p in self.start.periods]} + + do_model_111 = open_report + do_model_115 = open_report + do_model_303 = open_report + + def validate_303(self): + if len(set(p.fiscalyear for p in self.start.periods)) > 1: + self.raise_user_error('same_fiscalyear') diff --git a/reporting_tax.xml b/reporting_tax.xml new file mode 100644 index 0000000000..125f2e0706 --- /dev/null +++ b/reporting_tax.xml @@ -0,0 +1,84 @@ + + + + + + + AEAT Model 111 + account.reporting.aeat111 + account_es/aeat111.txt + txt + + + + + + + + + + + + AEAT Model 115 + account.reporting.aeat115 + account_es/aeat115.txt + txt + + + + + + + + + + + + AEAT Model 303 + account.reporting.aeat303 + account_es/aeat303.txt + txt + + + + + + + + + + + + account.reporting.aeat.start + form + print_aeat_start_form + + + Print AEAT + account.reporting.aeat + + + + + + + + + + + + + + + + + + + + + + diff --git a/setup.py b/setup.py index a54c6c2190..f59eb6dad1 100644 --- a/setup.py +++ b/setup.py @@ -72,7 +72,8 @@ setup(name=name, ], package_data={ 'trytond.modules.account_es': (info.get('xml', []) - + ['tryton.cfg']), + + ['tryton.cfg', 'view/*.xml', 'locale/*.po', '*.text', + 'icons/*.svg', 'tests/*.rst', 'tests/*.txt']), }, classifiers=[ 'Development Status :: 5 - Production/Stable', diff --git a/tax.xml b/tax.xml index 388c635281..cfd43bd87a 100644 --- a/tax.xml +++ b/tax.xml @@ -375,6 +375,7 @@ this repository contains the full copyright notices and license terms. --> IVA superreducido 01 + 303 @@ -395,6 +396,7 @@ this repository contains the full copyright notices and license terms. --> IVA reducido 04 + 303 @@ -415,6 +417,7 @@ this repository contains the full copyright notices and license terms. --> IVA normal 07 + 303 @@ -435,6 +438,7 @@ this repository contains the full copyright notices and license terms. --> Adquisiciones intracomunitarias de bienes y servicios 10 + 303 @@ -469,18 +473,21 @@ this repository contains the full copyright notices and license terms. --> Otras operaciones con inversión del sujeto pasivo 12 + 303 Modificación bases 14 + 303 Recargo equivalencia normal 16 + 303 @@ -501,6 +508,7 @@ this repository contains the full copyright notices and license terms. --> Recargo equivalencia reducido 19 + 303 @@ -521,6 +529,7 @@ this repository contains the full copyright notices and license terms. --> Recargo equivalencia superreducido 22 + 303 @@ -542,6 +551,7 @@ this repository contains the full copyright notices and license terms. --> Modificación bases del recargo de equivalencia 25 + 303 @@ -549,12 +559,14 @@ this repository contains the full copyright notices and license terms. --> Total cuota devengada 27 + 303 IVA superreducido 03 + 303 @@ -575,6 +587,7 @@ this repository contains the full copyright notices and license terms. --> IVA reducido 06 + 303 @@ -595,6 +608,7 @@ this repository contains the full copyright notices and license terms. --> IVA normal 09 + 303 @@ -615,6 +629,7 @@ this repository contains the full copyright notices and license terms. --> Adquisiciones intracomunitarias de bienes y servicios 11 + 303 @@ -649,18 +664,21 @@ this repository contains the full copyright notices and license terms. --> Otras operaciones con inversión del sujeto pasivo 13 + 303 Modificación cuotas 15 + 303 Recargo equivalencia normal 18 + 303 @@ -681,6 +699,7 @@ this repository contains the full copyright notices and license terms. --> Recargo equivalencia reducido 21 + 303 @@ -701,6 +720,7 @@ this repository contains the full copyright notices and license terms. --> Recargo equivalencia superreducido 24 + 303 @@ -722,6 +742,7 @@ this repository contains the full copyright notices and license terms. --> Modificación cuotas del recargo equivalencia 26 + 303 @@ -741,6 +762,7 @@ this repository contains the full copyright notices and license terms. --> Operaciones interiores corrientes 28 + 303 @@ -804,6 +826,7 @@ this repository contains the full copyright notices and license terms. --> Operaciones interiores con bienes inversión 30 + 303 @@ -853,6 +876,7 @@ this repository contains the full copyright notices and license terms. --> Importaciones de bienes corrientes 32 + 303 @@ -873,6 +897,7 @@ this repository contains the full copyright notices and license terms. --> Importaciones de bienes de inversión 34 + 303 @@ -893,6 +918,7 @@ this repository contains the full copyright notices and license terms. --> Adquisiciones intracomunitarios de bienes y servicios corrientes 36 + 303 @@ -913,6 +939,7 @@ this repository contains the full copyright notices and license terms. --> Adquisiciones intracomunitario de bienes de inversión 38 + 303 @@ -933,6 +960,7 @@ this repository contains the full copyright notices and license terms. --> Rectificación de deducciones 40 + 303 @@ -940,12 +968,14 @@ this repository contains the full copyright notices and license terms. --> Total a deducir 45 + 303 Por cuotas soportadas en operaciones interiores corrientes 29 + 303 @@ -995,6 +1025,7 @@ this repository contains the full copyright notices and license terms. --> Por cuotas soportadas en operaciones interiores con bienes inversión 31 + 303 @@ -1057,6 +1088,7 @@ this repository contains the full copyright notices and license terms. --> Por cuotas soportadas en las importaciones de bienes corrientes 33 + 303 @@ -1077,6 +1109,7 @@ this repository contains the full copyright notices and license terms. --> Por cuotas soportadas en las importaciones de bienes de inversión 35 + 303 @@ -1097,6 +1130,7 @@ this repository contains the full copyright notices and license terms. --> En adquisiciones intracomunitarios de bienes y servicios corrientes 37 + 303 @@ -1117,6 +1151,7 @@ this repository contains the full copyright notices and license terms. --> En adquisiciones intracomunitario de bienes de inversión 39 + 303 @@ -1137,24 +1172,28 @@ this repository contains the full copyright notices and license terms. --> Rectificación de deducciones 41 + 303 Compensaciones Reǵimen Especial A.G y P. 42 + 303 Regularización bienes de inversión 43 + 303 Regularización por aplicación del porcentaje definitio de prorrata 44 + 303 @@ -1162,6 +1201,7 @@ this repository contains the full copyright notices and license terms. --> Entregas intracomunitarias de bienes y servicios 59 + 303 @@ -1198,6 +1238,7 @@ this repository contains the full copyright notices and license terms. --> Exportaciones y operaciones asimiladas 60 + 303 @@ -1218,6 +1259,7 @@ this repository contains the full copyright notices and license terms. --> Operaciones no sujetas o con inversión del sujeto pasivo que originn derecho a deducción 61 + 303 @@ -1231,6 +1273,7 @@ this repository contains the full copyright notices and license terms. --> Importe percepeciones actividades economicas 08 + 111 @@ -1293,6 +1336,7 @@ this repository contains the full copyright notices and license terms. --> Importe retenciones actividades economicas 09 + 111 @@ -1362,6 +1406,7 @@ this repository contains the full copyright notices and license terms. --> Base de las retenciones e ingresos a cuenta 02 + 115 @@ -1382,6 +1427,7 @@ this repository contains the full copyright notices and license terms. --> Retenciones e ingresos a cuenta 03 + 115 diff --git a/tax_normal.xml b/tax_normal.xml index 59ff67879a..a90ad181bc 100644 --- a/tax_normal.xml +++ b/tax_normal.xml @@ -375,6 +375,7 @@ this repository contains the full copyright notices and license terms. --> IVA superreducido 01 + 303 @@ -395,6 +396,7 @@ this repository contains the full copyright notices and license terms. --> IVA reducido 04 + 303 @@ -415,6 +417,7 @@ this repository contains the full copyright notices and license terms. --> IVA normal 07 + 303 @@ -435,6 +438,7 @@ this repository contains the full copyright notices and license terms. --> Adquisiciones intracomunitarias de bienes y servicios 10 + 303 @@ -469,18 +473,21 @@ this repository contains the full copyright notices and license terms. --> Otras operaciones con inversión del sujeto pasivo 12 + 303 Modificación bases 14 + 303 Recargo equivalencia normal 16 + 303 @@ -501,6 +508,7 @@ this repository contains the full copyright notices and license terms. --> Recargo equivalencia reducido 19 + 303 @@ -521,6 +529,7 @@ this repository contains the full copyright notices and license terms. --> Recargo equivalencia superreducido 22 + 303 @@ -542,6 +551,7 @@ this repository contains the full copyright notices and license terms. --> Modificación bases del recargo de equivalencia 25 + 303 @@ -549,12 +559,14 @@ this repository contains the full copyright notices and license terms. --> Total cuota devengada 27 + 303 IVA superreducido 03 + 303 @@ -575,6 +587,7 @@ this repository contains the full copyright notices and license terms. --> IVA reducido 06 + 303 @@ -595,6 +608,7 @@ this repository contains the full copyright notices and license terms. --> IVA normal 09 + 303 @@ -615,6 +629,7 @@ this repository contains the full copyright notices and license terms. --> Adquisiciones intracomunitarias de bienes y servicios 11 + 303 @@ -649,18 +664,21 @@ this repository contains the full copyright notices and license terms. --> Otras operaciones con inversión del sujeto pasivo 13 + 303 Modificación cuotas 15 + 303 Recargo equivalencia normal 18 + 303 @@ -681,6 +699,7 @@ this repository contains the full copyright notices and license terms. --> Recargo equivalencia reducido 21 + 303 @@ -701,6 +720,7 @@ this repository contains the full copyright notices and license terms. --> Recargo equivalencia superreducido 24 + 303 @@ -722,6 +742,7 @@ this repository contains the full copyright notices and license terms. --> Modificación cuotas del recargo equivalencia 26 + 303 @@ -741,6 +762,7 @@ this repository contains the full copyright notices and license terms. --> Operaciones interiores corrientes 28 + 303 @@ -804,6 +826,7 @@ this repository contains the full copyright notices and license terms. --> Operaciones interiores con bienes inversión 30 + 303 @@ -853,6 +876,7 @@ this repository contains the full copyright notices and license terms. --> Importaciones de bienes corrientes 32 + 303 @@ -873,6 +897,7 @@ this repository contains the full copyright notices and license terms. --> Importaciones de bienes de inversión 34 + 303 @@ -893,6 +918,7 @@ this repository contains the full copyright notices and license terms. --> Adquisiciones intracomunitarios de bienes y servicios corrientes 36 + 303 @@ -913,6 +939,7 @@ this repository contains the full copyright notices and license terms. --> Adquisiciones intracomunitario de bienes de inversión 38 + 303 @@ -933,6 +960,7 @@ this repository contains the full copyright notices and license terms. --> Rectificación de deducciones 40 + 303 @@ -940,12 +968,14 @@ this repository contains the full copyright notices and license terms. --> Total a deducir 45 + 303 Por cuotas soportadas en operaciones interiores corrientes 29 + 303 @@ -995,6 +1025,7 @@ this repository contains the full copyright notices and license terms. --> Por cuotas soportadas en operaciones interiores con bienes inversión 31 + 303 @@ -1057,6 +1088,7 @@ this repository contains the full copyright notices and license terms. --> Por cuotas soportadas en las importaciones de bienes corrientes 33 + 303 @@ -1077,6 +1109,7 @@ this repository contains the full copyright notices and license terms. --> Por cuotas soportadas en las importaciones de bienes de inversión 35 + 303 @@ -1097,6 +1130,7 @@ this repository contains the full copyright notices and license terms. --> En adquisiciones intracomunitarios de bienes y servicios corrientes 37 + 303 @@ -1117,6 +1151,7 @@ this repository contains the full copyright notices and license terms. --> En adquisiciones intracomunitario de bienes de inversión 39 + 303 @@ -1137,24 +1172,28 @@ this repository contains the full copyright notices and license terms. --> Rectificación de deducciones 41 + 303 Compensaciones Reǵimen Especial A.G y P. 42 + 303 Regularización bienes de inversión 43 + 303 Regularización por aplicación del porcentaje definitio de prorrata 44 + 303 @@ -1162,6 +1201,7 @@ this repository contains the full copyright notices and license terms. --> Entregas intracomunitarias de bienes y servicios 59 + 303 @@ -1198,6 +1238,7 @@ this repository contains the full copyright notices and license terms. --> Exportaciones y operaciones asimiladas 60 + 303 @@ -1218,6 +1259,7 @@ this repository contains the full copyright notices and license terms. --> Operaciones no sujetas o con inversión del sujeto pasivo que originn derecho a deducción 61 + 303 @@ -1231,6 +1273,7 @@ this repository contains the full copyright notices and license terms. --> Importe percepeciones actividades economicas 08 + 111 @@ -1293,6 +1336,7 @@ this repository contains the full copyright notices and license terms. --> Importe retenciones actividades economicas 09 + 111 @@ -1362,6 +1406,7 @@ this repository contains the full copyright notices and license terms. --> Base de las retenciones e ingresos a cuenta 02 + 115 @@ -1382,6 +1427,7 @@ this repository contains the full copyright notices and license terms. --> Retenciones e ingresos a cuenta 03 + 115 diff --git a/tax_pyme.xml b/tax_pyme.xml index a477ba0a5b..3948cf060c 100644 --- a/tax_pyme.xml +++ b/tax_pyme.xml @@ -375,6 +375,7 @@ this repository contains the full copyright notices and license terms. --> IVA superreducido 01 + 303 @@ -395,6 +396,7 @@ this repository contains the full copyright notices and license terms. --> IVA reducido 04 + 303 @@ -415,6 +417,7 @@ this repository contains the full copyright notices and license terms. --> IVA normal 07 + 303 @@ -435,6 +438,7 @@ this repository contains the full copyright notices and license terms. --> Adquisiciones intracomunitarias de bienes y servicios 10 + 303 @@ -469,18 +473,21 @@ this repository contains the full copyright notices and license terms. --> Otras operaciones con inversión del sujeto pasivo 12 + 303 Modificación bases 14 + 303 Recargo equivalencia normal 16 + 303 @@ -501,6 +508,7 @@ this repository contains the full copyright notices and license terms. --> Recargo equivalencia reducido 19 + 303 @@ -521,6 +529,7 @@ this repository contains the full copyright notices and license terms. --> Recargo equivalencia superreducido 22 + 303 @@ -542,6 +551,7 @@ this repository contains the full copyright notices and license terms. --> Modificación bases del recargo de equivalencia 25 + 303 @@ -549,12 +559,14 @@ this repository contains the full copyright notices and license terms. --> Total cuota devengada 27 + 303 IVA superreducido 03 + 303 @@ -575,6 +587,7 @@ this repository contains the full copyright notices and license terms. --> IVA reducido 06 + 303 @@ -595,6 +608,7 @@ this repository contains the full copyright notices and license terms. --> IVA normal 09 + 303 @@ -615,6 +629,7 @@ this repository contains the full copyright notices and license terms. --> Adquisiciones intracomunitarias de bienes y servicios 11 + 303 @@ -649,18 +664,21 @@ this repository contains the full copyright notices and license terms. --> Otras operaciones con inversión del sujeto pasivo 13 + 303 Modificación cuotas 15 + 303 Recargo equivalencia normal 18 + 303 @@ -681,6 +699,7 @@ this repository contains the full copyright notices and license terms. --> Recargo equivalencia reducido 21 + 303 @@ -701,6 +720,7 @@ this repository contains the full copyright notices and license terms. --> Recargo equivalencia superreducido 24 + 303 @@ -722,6 +742,7 @@ this repository contains the full copyright notices and license terms. --> Modificación cuotas del recargo equivalencia 26 + 303 @@ -741,6 +762,7 @@ this repository contains the full copyright notices and license terms. --> Operaciones interiores corrientes 28 + 303 @@ -804,6 +826,7 @@ this repository contains the full copyright notices and license terms. --> Operaciones interiores con bienes inversión 30 + 303 @@ -853,6 +876,7 @@ this repository contains the full copyright notices and license terms. --> Importaciones de bienes corrientes 32 + 303 @@ -873,6 +897,7 @@ this repository contains the full copyright notices and license terms. --> Importaciones de bienes de inversión 34 + 303 @@ -893,6 +918,7 @@ this repository contains the full copyright notices and license terms. --> Adquisiciones intracomunitarios de bienes y servicios corrientes 36 + 303 @@ -913,6 +939,7 @@ this repository contains the full copyright notices and license terms. --> Adquisiciones intracomunitario de bienes de inversión 38 + 303 @@ -933,6 +960,7 @@ this repository contains the full copyright notices and license terms. --> Rectificación de deducciones 40 + 303 @@ -940,12 +968,14 @@ this repository contains the full copyright notices and license terms. --> Total a deducir 45 + 303 Por cuotas soportadas en operaciones interiores corrientes 29 + 303 @@ -995,6 +1025,7 @@ this repository contains the full copyright notices and license terms. --> Por cuotas soportadas en operaciones interiores con bienes inversión 31 + 303 @@ -1057,6 +1088,7 @@ this repository contains the full copyright notices and license terms. --> Por cuotas soportadas en las importaciones de bienes corrientes 33 + 303 @@ -1077,6 +1109,7 @@ this repository contains the full copyright notices and license terms. --> Por cuotas soportadas en las importaciones de bienes de inversión 35 + 303 @@ -1097,6 +1130,7 @@ this repository contains the full copyright notices and license terms. --> En adquisiciones intracomunitarios de bienes y servicios corrientes 37 + 303 @@ -1117,6 +1151,7 @@ this repository contains the full copyright notices and license terms. --> En adquisiciones intracomunitario de bienes de inversión 39 + 303 @@ -1137,24 +1172,28 @@ this repository contains the full copyright notices and license terms. --> Rectificación de deducciones 41 + 303 Compensaciones Reǵimen Especial A.G y P. 42 + 303 Regularización bienes de inversión 43 + 303 Regularización por aplicación del porcentaje definitio de prorrata 44 + 303 @@ -1162,6 +1201,7 @@ this repository contains the full copyright notices and license terms. --> Entregas intracomunitarias de bienes y servicios 59 + 303 @@ -1198,6 +1238,7 @@ this repository contains the full copyright notices and license terms. --> Exportaciones y operaciones asimiladas 60 + 303 @@ -1218,6 +1259,7 @@ this repository contains the full copyright notices and license terms. --> Operaciones no sujetas o con inversión del sujeto pasivo que originn derecho a deducción 61 + 303 @@ -1231,6 +1273,7 @@ this repository contains the full copyright notices and license terms. --> Importe percepeciones actividades economicas 08 + 111 @@ -1293,6 +1336,7 @@ this repository contains the full copyright notices and license terms. --> Importe retenciones actividades economicas 09 + 111 @@ -1362,6 +1406,7 @@ this repository contains the full copyright notices and license terms. --> Base de las retenciones e ingresos a cuenta 02 + 115 @@ -1382,6 +1427,7 @@ this repository contains the full copyright notices and license terms. --> Retenciones e ingresos a cuenta 03 + 115 diff --git a/tests/111.txt b/tests/111.txt new file mode 100644 index 0000000000..7c4f50a7b6 --- /dev/null +++ b/tests/111.txt @@ -0,0 +1 @@ + IB01000009DUNDER MIFFLIN 201801000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000001000000000000000001500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000015000000000000000000000000000000001500 diff --git a/tests/115.txt b/tests/115.txt new file mode 100644 index 0000000000..71ac67adb2 --- /dev/null +++ b/tests/115.txt @@ -0,0 +1 @@ + IB01000009DUNDER MIFFLIN 20180100000000000000000000000000000000000000000000000000000000000000000000000000000000000 diff --git a/tests/303.txt b/tests/303.txt new file mode 100644 index 0000000000..03ba10e37f --- /dev/null +++ b/tests/303.txt @@ -0,0 +1 @@ + IB01000009DUNDER MIFFLIN 2018012322 222200000000000000000004000000000000000000000000000000000000010000000000000000000000000000000020000021000000000000000420000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000000420000000000000010000000000000000021000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000210000000000000002100022 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000210010000000000000000000002100000000000000000000000000000000000000000000000000000000000000000021000000000000000000000000000000002100 0 0 0 0 0 0 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 diff --git a/tests/scenario_reporting.rst b/tests/scenario_reporting.rst new file mode 100644 index 0000000000..1f0c4ce5a5 --- /dev/null +++ b/tests/scenario_reporting.rst @@ -0,0 +1,181 @@ +============================= +Account ES Reporting Scenario +============================= + +Imports:: + + >>> import datetime + >>> from decimal import Decimal + >>> from proteus import Model, Wizard + >>> from trytond.tests.tools import activate_modules + >>> from trytond.tools import file_open + >>> from trytond.modules.company.tests.tools import create_company, \ + ... get_company + >>> from trytond.modules.account.tests.tools import create_fiscalyear + >>> from trytond.modules.account_invoice.tests.tools import \ + ... set_fiscalyear_invoice_sequences + >>> today = datetime.date.today() + +Install account_es:: + + >>> config = activate_modules('account_es') + +Create company:: + + >>> _ = create_company() + >>> company = get_company() + >>> tax_identifier = company.party.identifiers.new() + >>> tax_identifier.type = 'eu_vat' + >>> tax_identifier.code = 'ESB01000009' + >>> company.party.save() + +Create fiscal year:: + + >>> fiscalyear = set_fiscalyear_invoice_sequences( + ... create_fiscalyear(company, datetime.date(2018, 1, 1))) + >>> fiscalyear.click('create_period') + >>> period = fiscalyear.periods[0] + +Create chart of accounts:: + + >>> AccountTemplate = Model.get('account.account.template') + >>> Account = Model.get('account.account') + >>> ModelData = Model.get('ir.model.data') + >>> data, = ModelData.find([ + ... ('module', '=', 'account_es'), + ... ('fs_id', '=', 'pgc_0_pyme'), + ... ], limit=1) + >>> account_template = AccountTemplate(data.db_id) + >>> create_chart = Wizard('account.create_chart') + >>> create_chart.execute('account') + >>> create_chart.form.account_template = account_template + >>> create_chart.form.company = company + >>> create_chart.execute('create_account') + >>> accounts = {} + >>> for kind in ['receivable', 'payable', 'revenue', 'expense']: + ... accounts[kind], = Account.find([ + ... ('kind', '=', kind), + ... ('company', '=', company.id), + ... ], limit=1) + >>> expense = accounts['expense'] + >>> revenue = accounts['revenue'] + >>> create_chart.form.account_receivable = accounts['receivable'] + >>> create_chart.form.account_payable = accounts['payable'] + >>> create_chart.execute('create_properties') + +Create parties:: + + >>> Party = Model.get('party.party') + >>> TaxRule = Model.get('account.tax.rule') + >>> party = Party(name='Party') + >>> party.save() + >>> tax_rule, = TaxRule.find([ + ... ('company', '=', company.id), + ... ('kind', '=', 'purchase'), + ... ('name', '=', 'Retención IRPF 15%'), + ... ]) + >>> supplier = Party(name='Supplier') + >>> supplier.supplier_tax_rule = tax_rule + >>> supplier.save() + +Create account category:: + + >>> Tax = Model.get('account.tax') + >>> customer_tax, = Tax.find([ + ... ('company', '=', company.id), + ... ('name', '=', 'IVA 21%'), + ... ]) + >>> supplier_tax, = Tax.find([ + ... ('company', '=', company.id), + ... ('name', '=', 'IVA 21% (operaciones corrientes)'), + ... ]) + >>> ProductCategory = Model.get('product.category') + >>> account_category = ProductCategory(name="Account Category") + >>> account_category.accounting = True + >>> account_category.account_expense = expense + >>> account_category.account_revenue = revenue + >>> account_category.customer_taxes.append(customer_tax) + >>> account_category.supplier_taxes.append(supplier_tax) + >>> account_category.save() + +Create product:: + + >>> ProductUom = Model.get('product.uom') + >>> unit, = ProductUom.find([('name', '=', 'Unit')]) + >>> ProductTemplate = Model.get('product.template') + >>> template = ProductTemplate() + >>> template.name = 'product' + >>> template.default_uom = unit + >>> template.type = 'service' + >>> template.list_price = Decimal('40') + >>> template.account_category = account_category + >>> template.save() + >>> product, = template.products + +Create invoices:: + + >>> Invoice = Model.get('account.invoice') + >>> invoice = Invoice() + >>> invoice.party = party + >>> invoice.invoice_date = period.start_date + >>> line = invoice.lines.new() + >>> line.product = product + >>> line.quantity = 5 + >>> line.unit_price = Decimal('40') + >>> invoice.click('post') + >>> invoice.total_amount + Decimal('242.00') + >>> invoice = Invoice() + >>> invoice.type = 'in' + >>> invoice.party = supplier + >>> invoice.invoice_date = period.start_date + >>> line = invoice.lines.new() + >>> line.product = product + >>> line.quantity = 5 + >>> line.unit_price = Decimal('20') + >>> invoice.click('post') + >>> invoice.total_amount + Decimal('106.00') + +Generate aeat reports:: + + >>> Period = Model.get('account.period') + >>> aeat = Wizard('account.reporting.aeat') + >>> aeat.form.report = '111' + >>> aeat.form.periods.append(Period(period.id)) + >>> aeat.execute('choice') + >>> extension, content, _, name = aeat.actions[0] + >>> extension + 'txt' + >>> with file_open('account_es/tests/111.txt') as f: + ... content == f.read() + True + >>> name + 'AEAT Model 111' + + >>> aeat = Wizard('account.reporting.aeat') + >>> aeat.form.report = '115' + >>> period = Period(period.id) + >>> aeat.form.periods.append(Period(period.id)) + >>> aeat.execute('choice') + >>> extension, content, _, name = aeat.actions[0] + >>> extension + 'txt' + >>> with file_open('account_es/tests/115.txt') as f: + ... content == f.read() + True + >>> name + 'AEAT Model 115' + + >>> aeat = Wizard('account.reporting.aeat') + >>> aeat.form.report = '303' + >>> aeat.form.periods.append(Period(period.id)) + >>> aeat.execute('choice') + >>> extension, content, _, name = aeat.actions[0] + >>> extension + 'txt' + >>> with file_open('account_es/tests/303.txt') as f: + ... content == f.read() + True + >>> name + 'AEAT Model 303' diff --git a/tests/test_account_es.py b/tests/test_account_es.py index cadbdb6637..9103632753 100644 --- a/tests/test_account_es.py +++ b/tests/test_account_es.py @@ -1,8 +1,12 @@ # This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import unittest +import doctest + import trytond.tests.test_tryton from trytond.tests.test_tryton import ModuleTestCase +from trytond.tests.test_tryton import doctest_teardown +from trytond.tests.test_tryton import doctest_checker class AccountTestCase(ModuleTestCase): @@ -14,4 +18,8 @@ def suite(): suite = trytond.tests.test_tryton.suite() suite.addTests(unittest.TestLoader().loadTestsFromTestCase( AccountTestCase)) + suite.addTests(doctest.DocFileSuite('scenario_reporting.rst', + tearDown=doctest_teardown, encoding='utf-8', + checker=doctest_checker, + optionflags=doctest.REPORT_ONLY_FIRST_FAILURE)) return suite diff --git a/tryton.cfg b/tryton.cfg index 59db24c7bd..24e14c56c5 100644 --- a/tryton.cfg +++ b/tryton.cfg @@ -10,3 +10,5 @@ xml: tax_normal.xml account_pyme.xml tax_pyme.xml + view.xml + reporting_tax.xml diff --git a/view.xml b/view.xml new file mode 100644 index 0000000000..9ec9fb4736 --- /dev/null +++ b/view.xml @@ -0,0 +1,18 @@ + + + + + + account.tax.code.template + + tax_code_template_form + + + + account.tax.code + + tax_code_form + + + diff --git a/view/print_aeat_start_form.xml b/view/print_aeat_start_form.xml new file mode 100644 index 0000000000..a46dc6a7ca --- /dev/null +++ b/view/print_aeat_start_form.xml @@ -0,0 +1,8 @@ + + +
+