Add core taxes.

Add reagyp functionality.
This commit is contained in:
Sergio Morillo 2022-07-11 16:55:12 +02:00
parent 8e31f4eff0
commit 61689ee285
10 changed files with 540 additions and 10 deletions

View File

@ -33,6 +33,8 @@ class Configuration(metaclass=PoolMeta):
domain=['OR',
[('max_sii_lines', '=', None)],
[('max_sii_lines', '>', 0)]])
sii_reagyp_invoice_paid = fields.Boolean('Load SII REAGYP when paid',
help='Load REAGYP invoices on SII book only when they are paid')
@staticmethod
def default_aeat_pending_sii():

37
aeat.py
View File

@ -16,7 +16,7 @@ from trytond.pool import Pool
from trytond.transaction import Transaction
from trytond.config import config
from trytond.i18n import gettext
from trytond.exceptions import UserError
from trytond.exceptions import UserError, UserWarning
from trytond.tools import grouped_slice, reduce_ids
from . import tools
from . import service
@ -423,6 +423,7 @@ class SIIReport(Workflow, ModelSQL, ModelView):
for report in reports:
report.check_invoice_state()
report.check_duplicate_invoices()
report.check_reagyp_invoices()
@classmethod
@ModelView.button
@ -481,12 +482,38 @@ class SIIReport(Workflow, ModelSQL, ModelView):
'aeat_sii.msg_report_wrong_invoice_state',
invoice=line.invoice.rec_name))
def check_reagyp_invoices(self):
pool = Pool()
Invoice = pool.get('account.invoice')
Warning = pool.get('res.user.warning')
to_warn = []
invoices = [
l.invoice for l in self.lines if l.invoice]
invoices = [invoice_id for invoice_id, value
in Invoice.get_is_reagyp(invoices).items() if value]
invoices = Invoice.browse(invoices)
for invoice in invoices:
if invoice.state != 'paid':
to_warn.append(invoice)
if to_warn:
key = 'aeat_sii.msg_report_unpaid_reagyp_invoice_%s' % '_'.join([
str(invoice.id) for invoice in to_warn])
if Warning.check(key):
raise UserWarning(key, gettext(
'aeat_sii.msg_report_unpaid_reagyp_invoice',
invoices=', '.join([
invoice.rec_name for invoice in to_warn])))
@classmethod
@ModelView.button
def load_invoices(cls, reports):
pool = Pool()
Invoice = pool.get('account.invoice')
ReportLine = pool.get('aeat.sii.report.lines')
Conf = pool.get('account.configuration')
conf = Conf(1)
to_create = []
for report in reports:
@ -513,9 +540,15 @@ class SIIReport(Workflow, ModelSQL, ModelView):
_logger.debug('Searching invoices for SII report: %s', domain)
for invoice in Invoice.search(domain):
invoices = Invoice.search(domain)
reagyp = Invoice.get_is_reagyp(invoices)
for invoice in invoices:
if not all(x.report != report for x in invoice.sii_records):
continue
if (conf.sii_reagyp_invoice_paid and reagyp[invoice.id]
and invoice.state != 'paid'):
continue
to_create.append({
'report': report,
'invoice': invoice,

View File

@ -47,6 +47,7 @@ class Invoice(metaclass=PoolMeta):
sii_pending_sending = fields.Boolean('SII Pending Sending Pending',
readonly=True)
sii_header = fields.Text('Header')
is_reagyp = fields.Function(fields.Boolean('Is REAGYP'), 'get_is_reagyp')
@classmethod
def __setup__(cls):
@ -256,6 +257,41 @@ class Invoice(metaclass=PoolMeta):
header = mapper.build_delete_request(invoice)
return header
@classmethod
def set_number(cls, invoices):
super().set_number(invoices)
is_reagyp = cls.get_is_reagyp(invoices)
for invoice in invoices:
if not invoice.reference and is_reagyp[invoice.id]:
invoice.reference = invoice.number
cls.save(invoices)
@classmethod
def get_is_reagyp(cls, invoices, name=None):
pool = Pool()
Modeldata = pool.get('ir.model.data')
res = {}
try:
reagyp_ids = [
Modeldata.get_id('account_es', 'iva_reagp_12_normal'),
Modeldata.get_id('account_es', 'iva_reagp_12_pyme'),
]
except AttributeError:
reagyp_ids = [
Modeldata.get_id('account_es', 'iva_reagp_compras_12_1')
]
for invoice in invoices:
res[invoice.id] = False
if not invoice.taxes or invoice.type != 'in':
continue
for tax in invoice.taxes:
if tax.tax.template and tax.tax.template.id in reagyp_ids:
res[invoice.id] = True
break
return res
class ResetSIIKeysStart(ModelView):
"""

View File

@ -1874,4 +1874,18 @@ msgstr "Máximo líneas SII"
msgctxt "help:account.configuration,max_sii_lines:"
msgid "Indicates the maximum number of invoices to be included in each SII book."
msgstr "Indica el número máximo de facturas a incluir por libro del SII."
msgstr "Indica el número máximo de facturas a incluir por libro del SII."
msgctxt "model:ir.message,text:msg_report_unpaid_reagyp_invoice"
msgid ""
"There are unpaid invoices with REAGYP taxes in SII Book to confirm:\n%(invoices)s."
msgstr ""
"Existen facturas sin pagar con impuestos REAGYP en el libro SII a confirmar:\n%(invoices)s."
msgctxt "field:account.configuration,sii_reagyp_invoice_paid:"
msgid "Load SII REAGYP when paid"
msgstr "Cargar REAGYP en SII cuando pagadas"
msgctxt "help:account.configuration,sii_reagyp_invoice_paid:"
msgid "Load REAGYP invoices on SII book only when they are paid"
msgstr "Carga facturas REAGYP en libro SII solo cuando estan pagadas."

View File

@ -23,12 +23,12 @@ If you edit them take care if you need to update again to SII</field>
<record model="ir.message" id="msg_error_loading_pkcs12">
<field name="text">Unable to load PKCS12: %(message)s</field>
</record>
<record model="ir.message" id="reports_exist">
<field name="text">There are some reports in draft and/or confirmed. Any report won't be created until this reports will be processed.</field>
</record>
<record model="ir.message" id="msg_service_message">
<field name="text">%(message)s</field>
</record>
<record model="ir.message" id="reports_exist">
<field name="text">There are some reports in draft and/or confirmed. Any report won't be created until this reports will be processed.</field>
</record>
<record model="ir.message" id="msg_service_message">
<field name="text">%(message)s</field>
</record>
<record model="ir.message" id="msg_missing_nif">
<field name="text">The party of the invoice %(invoice)s must has a valid Tax Identifier.</field>
</record>
@ -53,5 +53,9 @@ If you edit them take care if you need to update again to SII</field>
<record model="ir.message" id="msg_report_duplicated_invoice">
<field name="text">Invoice "%(invoice)s" is duplicated on SII Report "%(report)s".</field>
</record>
<record model="ir.message" id="msg_report_unpaid_reagyp_invoice">
<field name="text">There are unpaid invoices with REAGYP taxes in SII Book to confirm:
%(invoices)s.</field>
</record>
</data>
</tryton>

222
sii_core.xml Normal file
View File

@ -0,0 +1,222 @@
<?xml version='1.0'?>
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
this repository contains the full copyright notices and license terms. -->
<tryton>
<data depends="account_es">
<record model="account.tax.template" id="account_es.iva_sop_21_normal">
<field name="sii_book_key">R</field>
<field name="sii_received_key">01</field>
<field name="sii_subjected_key">S1</field>
<field name="tax_used" eval="True"/>
<field name="invoice_used" eval="True"/>
</record>
<record model="account.tax.template" id="account_es.iva_sop_21_servicios_normal">
<field name="sii_book_key">R</field>
<field name="sii_received_key">01</field>
<field name="sii_subjected_key">S1</field>
<field name="tax_used" eval="True"/>
<field name="invoice_used" eval="True"/>
</record>
<record model="account.tax.template" id="account_es.iva_sop_10_normal">
<field name="sii_book_key">R</field>
<field name="sii_received_key">01</field>
<field name="sii_subjected_key">S1</field>
<field name="tax_used" eval="True"/>
<field name="invoice_used" eval="True"/>
</record>
<record model="account.tax.template" id="account_es.iva_sop_10_servicios_normal">
<field name="sii_book_key">R</field>
<field name="sii_received_key">01</field>
<field name="sii_subjected_key">S1</field>
<field name="tax_used" eval="True"/>
<field name="invoice_used" eval="True"/>
</record>
<record model="account.tax.template" id="account_es.iva_sop_4_normal">
<field name="sii_book_key">R</field>
<field name="sii_received_key">01</field>
<field name="sii_subjected_key">S1</field>
<field name="tax_used" eval="True"/>
<field name="invoice_used" eval="True"/>
</record>
<record model="account.tax.template" id="account_es.iva_sop_importacion_normal">
<field name="sii_book_key">R</field>
<field name="sii_received_key">13</field>
<field name="sii_exemption_cause">E6</field>
<field name="tax_used" eval="True"/>
<field name="invoice_used" eval="True"/>
</record>
<record model="account.tax.template" id="account_es.iva_sop_importacion_servicios_normal">
<field name="sii_book_key">R</field>
<field name="sii_received_key">13</field>
<field name="sii_exemption_cause">E6</field>
<field name="tax_used" eval="True"/>
<field name="invoice_used" eval="True"/>
</record>
<record model="account.tax.template" id="account_es.iva_sop_importacion_inv_normal">
<field name="sii_book_key">R</field>
<field name="sii_received_key">13</field>
<field name="sii_exemption_cause">E6</field>
<field name="tax_used" eval="True"/>
<field name="invoice_used" eval="True"/>
</record>
<record model="account.tax.template" id="account_es.iva_rep_exportaciones_normal">
<field name="sii_book_key">E</field>
<field name="sii_issued_key">02</field>
<field name="sii_exemption_cause">E2</field>
<field name="tax_used" eval="True"/>
<field name="invoice_used" eval="True"/>
</record>
<record model="account.tax.template" id="account_es.iva_rep_exportaciones_servicios_normal">
<field name="sii_book_key">E</field>
<field name="sii_issued_key">02</field>
<field name="sii_exemption_cause">E2</field>
<field name="tax_used" eval="True"/>
<field name="invoice_used" eval="True"/>
</record>
<record model="account.tax.template" id="account_es.iva_rep_ex_normal">
<field name="sii_book_key">E</field>
<field name="sii_issued_key">01</field>
<field name="sii_exemption_cause">E1</field>
<field name="tax_used" eval="True"/>
<field name="invoice_used" eval="True"/>
</record>
<record model="account.tax.template" id="account_es.iva_rep_ex_servicios_normal">
<field name="sii_book_key">E</field>
<field name="sii_issued_key">01</field>
<field name="sii_exemption_cause">E1</field>
<field name="tax_used" eval="True"/>
<field name="invoice_used" eval="True"/>
</record>
<record model="account.tax.template" id="account_es.iva_rep_intracomunitario_bienes_normal">
<field name="sii_book_key">E</field>
<field name="sii_issued_key">01</field>
<field name="sii_exemption_cause">E5</field>
<field name="tax_used" eval="True"/>
<field name="invoice_used" eval="True"/>
</record>
<record model="account.tax.template" id="account_es.iva_rep_intracomunitario_servicios_normal">
<field name="sii_book_key">E</field>
<field name="sii_issued_key">01</field>
<field name="sii_exemption_cause">E5</field>
<field name="tax_used" eval="True"/>
<field name="invoice_used" eval="True"/>
</record>
<record model="account.tax.template" id="account_es.iva_sop_intracomunitario_1_normal">
<field name="sii_book_key">R</field>
<field name="sii_received_key">09</field>
<field name="sii_subjected_key">S1</field>
<field name="tax_used" eval="True"/>
<field name="invoice_used" eval="True"/>
</record>
<record model="account.tax.template" id="account_es.iva_sop_intracomunitario_2_normal">
<field name="sii_book_key">R</field>
<field name="sii_received_key">09</field>
<field name="sii_subjected_key">S1</field>
<field name="tax_used" eval="False"/>
<field name="invoice_used" eval="True"/>
</record>
<record model="account.tax.template" id="account_es.iva_sop_intracomunitario_servicios_1_normal">
<field name="sii_book_key">R</field>
<field name="sii_received_key">09</field>
<field name="sii_exemption_cause">E6</field>
<field name="tax_used" eval="False"/>
<field name="invoice_used" eval="True"/>
</record>
<record model="account.tax.template" id="account_es.iva_sop_intracomunitario_servicios_2_normal">
<field name="sii_book_key">R</field>
<field name="sii_received_key">09</field>
<field name="sii_subjected_key">S1</field>
<field name="tax_used" eval="True"/>
<field name="invoice_used" eval="True"/>
</record>
<record model="account.tax.template" id="account_es.iva_sop_intracomunitario_inv_1_normal">
<field name="sii_book_key">R</field>
<field name="sii_received_key">09</field>
<field name="sii_subjected_key">S1</field>
<field name="tax_used" eval="True"/>
<field name="invoice_used" eval="True"/>
</record>
<record model="account.tax.template" id="account_es.iva_sop_intracomunitario_inv_2_normal">
<field name="sii_book_key">R</field>
<field name="sii_received_key">09</field>
<field name="sii_subjected_key">S1</field>
<field name="tax_used" eval="False"/>
<field name="invoice_used" eval="True"/>
</record>
<record model="account.tax.template" id="account_es.iva_sop_ex_normal">
<field name="sii_book_key">R</field>
<field name="sii_received_key">01</field>
<field name="sii_exemption_cause">E1</field>
<field name="tax_used" eval="False"/>
<field name="invoice_used" eval="True"/>
</record>
<record model="account.tax.template" id="account_es.iva_sop_ex_servicios_normal">
<field name="sii_book_key">R</field>
<field name="sii_received_key">01</field>
<field name="sii_exemption_cause">E1</field>
<field name="tax_used" eval="False"/>
<field name="invoice_used" eval="True"/>
</record>
<record model="account.tax.template" id="account_es.iva_sop_ex_inv_normal">
<field name="sii_book_key">R</field>
<field name="sii_received_key">01</field>
<field name="sii_exemption_cause">E6</field>
<field name="tax_used" eval="False"/>
<field name="invoice_used" eval="True"/>
</record>
<record model="account.tax.template" id="account_es.iva_rep_4_normal">
<field name="sii_book_key">E</field>
<field name="sii_issued_key">01</field>
<field name="sii_subjected_key">S1</field>
<field name="tax_used" eval="True"/>
<field name="invoice_used" eval="True"/>
</record>
<record model="account.tax.template" id="account_es.iva_rep_10_normal">
<field name="sii_book_key">E</field>
<field name="sii_issued_key">01</field>
<field name="sii_subjected_key">S1</field>
<field name="tax_used" eval="True"/>
<field name="invoice_used" eval="True"/>
</record>
<record model="account.tax.template" id="account_es.iva_rep_10_servicios_normal">
<field name="sii_book_key">E</field>
<field name="sii_issued_key">01</field>
<field name="sii_subjected_key">S1</field>
<field name="tax_used" eval="True"/>
<field name="invoice_used" eval="True"/>
</record>
<record model="account.tax.template" id="account_es.iva_rep_21_normal">
<field name="sii_book_key">E</field>
<field name="sii_issued_key">01</field>
<field name="sii_subjected_key">S1</field>
<field name="tax_used" eval="True"/>
<field name="invoice_used" eval="True"/>
</record>
<record model="account.tax.template" id="account_es.iva_rep_21_servicios_normal">
<field name="sii_book_key">E</field>
<field name="sii_issued_key">01</field>
<field name="sii_subjected_key">S1</field>
<field name="tax_used" eval="True"/>
<field name="invoice_used" eval="True"/>
</record>
<record model="account.tax.template" id="account_es.iva_reagp_12_normal">
<field name="sii_book_key">R</field>
<field name="sii_received_key">02</field>
<field name="sii_subjected_key">S1</field>
<field name="tax_used" eval="False"/>
<field name="invoice_used" eval="True"/>
</record>
<record model="account.tax.template" id="account_es.iva_reagp_105_normal">
<field name="sii_book_key">R</field>
<field name="sii_received_key">02</field>
<field name="sii_subjected_key">S1</field>
<field name="tax_used" eval="False"/>
<field name="invoice_used" eval="True"/>
</record>
</data>
</tryton>

View File

@ -0,0 +1,209 @@
===================================
Account Es Reagyp AEAT SII Scenario
===================================
Imports::
>>> import datetime
>>> from dateutil.relativedelta import relativedelta
>>> from decimal import Decimal
>>> from operator import attrgetter
>>> from proteus import config, Model, Wizard
>>> from trytond.tests.tools import activate_modules
>>> from trytond.modules.company.tests.tools import create_company, \
... get_company
>>> from trytond.modules.account.tests.tools import create_fiscalyear, \
... create_chart, get_accounts, create_tax, create_tax_code
>>> from trytond.modules.account_invoice.tests.tools import \
... set_fiscalyear_invoice_sequences
>>> today = datetime.date.today()
Install modules::
>>> config = activate_modules(['aeat_sii'])
Create company::
>>> _ = create_company()
>>> company = get_company()
Create fiscal year::
>>> fiscalyear = set_fiscalyear_invoice_sequences(
... create_fiscalyear(company))
>>> fiscalyear.click('create_period')
>>> Period = Model.get('account.period')
>>> period, = Period.find([
... ('start_date', '>=', today.replace(day=1)),
... ('end_date', '<=', today.replace(day=1) + relativedelta(months=+1)),
... ], limit=1)
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_normal'),
... ], 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([
... ('type.%s' % kind, '=', True),
... ('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 party::
>>> Party = Model.get('party.party')
>>> party = Party(name='Party')
>>> party.save()
>>> TaxRule = Model.get('account.tax.rule')
>>> tax_rule, = TaxRule.find([
... ('company', '=', company.id),
... ('kind', '=', 'purchase'),
... ('name', 'ilike', '%especial agr%'),
... ])
>>> party_reagyp = Party(name='Party REAGYP')
>>> party_reagyp.supplier_tax_rule = tax_rule
>>> party_reagyp.save()
Create account category::
>>> Tax = Model.get('account.tax')
>>> customer_tax, = Tax.find([
... ('company', '=', company.id),
... ('description', 'like', '%IVA 21%'),
... ('group.kind', '=', 'sale'),
... ], limit=1)
>>> supplier_tax, = Tax.find([
... ('company', '=', company.id),
... ('description', 'like', '%IVA 21%'),
... ('group.kind', '=', 'purchase'),
... ], limit=1)
>>> 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')
>>> Product = Model.get('product.product')
>>> product = Product()
>>> template = ProductTemplate()
>>> template.name = 'product'
>>> template.default_uom = unit
>>> template.type = 'service'
>>> template.list_price = Decimal('40')
>>> template.cost_price = Decimal('25')
>>> template.account_category = account_category
>>> template.save()
>>> product, = template.products
Create invoices::
>>> Invoice = Model.get('account.invoice')
>>> invoice = Invoice(type='in')
>>> invoice.party = party
>>> invoice.invoice_date = period.start_date
>>> invoice.accounting_date = period.start_date
>>> line = invoice.lines.new()
>>> line.product = product
>>> line.quantity = 5
>>> line.unit_price = Decimal('40')
>>> invoice.sii_book_key = 'R'
>>> invoice.save()
>>> invoice.click('post')
>>> invoice.state
'posted'
>>> bool(invoice.is_reagyp)
False
>>> invoice2 = Invoice(type='in')
>>> invoice2.party = party_reagyp
>>> invoice2.invoice_date = period.start_date
>>> invoice2.accounting_date = period.start_date
>>> line = invoice2.lines.new()
>>> line.product = product
>>> line.quantity = 5
>>> line.unit_price = Decimal('40')
>>> invoice2.sii_book_key = 'R'
>>> invoice2.save()
>>> invoice2.click('post')
>>> invoice2.state
'posted'
>>> bool(invoice2.is_reagyp)
True
Check invoices references::
>>> invoice.click('post')
>>> invoice.reference == invoice.number
False
>>> invoice2.click('post')
>>> invoice2.reference == invoice2.number
True
Create AEAT Report::
>>> AEATReport = Model.get('aeat.sii.report')
>>> Conf = Model.get('account.configuration')
>>> conf = Conf(1)
>>> report = AEATReport()
>>> report.fiscalyear = fiscalyear
>>> report.period = period
>>> report.operation_type = 'A0'
>>> report.book = 'R'
>>> report.company_vat = '123456789'
>>> report.save()
>>> report.state
'draft'
>>> report.click('load_invoices')
>>> len(report.lines)
2
>>> line1, line2 = report.lines
>>> report.lines.remove(line1)
>>> report.lines.remove(line2)
>>> report.save()
>>> conf.sii_reagyp_invoice_paid = True
>>> conf.save()
>>> report.click('load_invoices')
>>> len(report.lines)
1
>>> line = report.lines.new()
>>> line.invoice = invoice2
>>> report.save()
>>> report.reload()
>>> len(report.lines)
2
>>> report.click('confirm')
Traceback (most recent call last):
...
trytond.exceptions.UserWarning: There are unpaid invoices with REAGYP taxes in SII Book to confirm:
2 [2]. -

View File

@ -32,4 +32,9 @@ def suite():
tearDown=doctest_teardown, encoding='utf-8',
checker=doctest_checker,
optionflags=doctest.REPORT_ONLY_FIRST_FAILURE))
suite.addTests(doctest.DocFileSuite(
'scenario_aeat_sii_reagyp.rst',
tearDown=doctest_teardown, encoding='utf-8',
checker=doctest_checker,
optionflags=doctest.REPORT_ONLY_FIRST_FAILURE))
return suite

View File

@ -19,5 +19,8 @@ xml:
party.xml
company.xml
load_pkcs12.xml
sii.xml
message.xml
# uncomment to use 'account_es' from trytonspain
sii.xml
# uncomment to use 'account_es' from foundation
#sii_core.xml

View File

@ -15,5 +15,7 @@ copyright notices and license types. -->
<label name="max_sii_lines"/>
<field name="max_sii_lines"/>
<newline/>
<label name="sii_reagyp_invoice_paid"/>
<field name="sii_reagyp_invoice_paid"/>
</xpath>
</data>