diff --git a/aeat.py b/aeat.py index 5ad38e6..eaa7f1b 100644 --- a/aeat.py +++ b/aeat.py @@ -247,7 +247,7 @@ class SIIReport(Workflow, ModelSQL, ModelView): 'readonly': Eval('state') != 'draft', }, depends=['state']) currency = fields.Function(fields.Many2One('currency.currency', - 'Currency'), 'get_currency') + 'Currency'), 'on_change_with_currency') fiscalyear = fields.Many2One('account.fiscalyear', 'Fiscal Year', required=True, states={ 'readonly': Eval('state') != 'draft', @@ -261,7 +261,7 @@ class SIIReport(Workflow, ModelSQL, ModelView): domain=[('fiscalyear', '=', Eval('fiscalyear'))], states={ 'readonly': Eval('state') != 'draft', - }, depends=['state']) + }, depends=['state', 'fiscalyear']) operation_type = fields.Selection(COMMUNICATION_TYPE, 'Operation Type', required=True, @@ -335,14 +335,14 @@ class SIIReport(Workflow, ModelSQL, ModelView): ('cancelled', 'draft'), )) - @staticmethod def default_company(): - return Transaction().context.get('company') - def get_currency(self, name): - return self.company.currency.id + @fields.depends('company') + def on_change_with_currency(self, name): + if self.company: + return self.company.currency.id @staticmethod def default_fiscalyear(): @@ -356,12 +356,21 @@ class SIIReport(Workflow, ModelSQL, ModelView): @staticmethod def default_version(): - return '0.6' + return '0.7' @fields.depends('company') def on_change_with_company_vat(self): if self.company: - return self.company.party.vat_code + return self.company.party.sii_vat_code + + @classmethod + def copy(cls, records, default=None): + if default is None: + default = {} + else: + default = default.copy() + default['communication_state'] = None + return super(SIIReport, cls).copy(records, default=default) @classmethod @ModelView.button @@ -440,10 +449,10 @@ class SIIReport(Workflow, ModelSQL, ModelView): _logger.info('Sending report %s to AEAT SII', self.id) headers = mapping.get_headers( name=self.company.party.name, - vat=self.company.party.vat_code, + vat=self.company_vat, comm_kind=self.operation_type) pool = Pool() - mapper = pool.get('aeat.sii.issued.invoice.mapper')(pool=pool) + mapper = IssuedTrytonInvoiceMapper(pool=pool) res = None with self.company.tmp_ssl_credentials() as (crt, key): srv = service.bind_issued_invoices_service(crt, key, test=True) @@ -467,10 +476,10 @@ class SIIReport(Workflow, ModelSQL, ModelView): def delete_issued_invoices(self): headers = mapping.get_headers( name=self.company.party.name, - vat=self.company.party.vat_code, + vat=self.company_vat, comm_kind=self.operation_type) pool = Pool() - mapper = pool.get('aeat.sii.issued.invoice.mapper')(pool=pool) + mapper = IssuedTrytonInvoiceMapper(pool=pool) res = None with self.company.tmp_ssl_credentials() as (crt, key): srv = service.bind_issued_invoices_service(crt, key, test=True) @@ -497,7 +506,7 @@ class SIIReport(Workflow, ModelSQL, ModelView): Invoice = pool.get('account.invoice') headers = mapping.get_headers( name=self.company.party.name, - vat=self.company.party.vat_code, + vat=self.company_vat, comm_kind=self.operation_type) with self.company.tmp_ssl_credentials() as (crt, key): @@ -544,10 +553,10 @@ class SIIReport(Workflow, ModelSQL, ModelView): _logger.info('Sending report %s to AEAT SII', self.id) headers = mapping.get_headers( name=self.company.party.name, - vat=self.company.party.vat_code, + vat=self.company_vat, comm_kind=self.operation_type) pool = Pool() - mapper = pool.get('aeat.sii.recieved.invoice.mapper')(pool=pool) + mapper = RecievedTrytonInvoiceMapper(pool=pool) res = None with self.company.tmp_ssl_credentials() as (crt, key): srv = service.bind_recieved_invoices_service(crt, key, test=True) @@ -571,10 +580,10 @@ class SIIReport(Workflow, ModelSQL, ModelView): def delete_recieved_invoices(self): headers = mapping.get_headers( name=self.company.party.name, - vat=self.company.party.vat_code, + vat=self.company_vat, comm_kind=self.operation_type) pool = Pool() - mapper = pool.get('aeat.sii.recieved.invoice.mapper')(pool=pool) + mapper = RecievedTrytonInvoiceMapper(pool=pool) res = None with self.company.tmp_ssl_credentials() as (crt, key): srv = service.bind_recieved_invoices_service(crt, key, test=True) @@ -601,7 +610,7 @@ class SIIReport(Workflow, ModelSQL, ModelView): Invoice = pool.get('account.invoice') headers = mapping.get_headers( name=self.company.party.name, - vat=self.company.party.vat_code, + vat=self.company_vat, comm_kind=self.operation_type) with self.company.tmp_ssl_credentials() as (crt, key): @@ -646,23 +655,23 @@ class SIIReport(Workflow, ModelSQL, ModelView): }) -class BaseTrytonInvoiceMapper(Model): +class BaseTrytonInvoiceMapper(object): def __init__(self, *args, **kwargs): - super(BaseTrytonInvoiceMapper, self).__init__(*args, **kwargs) + super(BaseTrytonInvoiceMapper, self).__init__() self.pool = Pool() year = attrgetter('move.period.fiscalyear.name') period = attrgetter('move.period.start_date.month') - nif = attrgetter('company.party.vat_code') + nif = attrgetter('company.party.sii_vat_code') issue_date = attrgetter('invoice_date') invoice_kind = attrgetter('sii_operation_key') rectified_invoice_kind = callback_utils.fixed_value('I') not_exempt_kind = attrgetter('sii_subjected') counterpart_name = attrgetter('party.name') - counterpart_nif = attrgetter('party.vat_code') + counterpart_nif = attrgetter('party.sii_vat_code') counterpart_id_type = attrgetter('party.identifier_type') - counterpart_country = attrgetter('party.vat_country') + counterpart_country = attrgetter('party.sii_vat_country') counterpart_id = counterpart_nif taxes = attrgetter('taxes') tax_rate = attrgetter('tax.rate') @@ -697,7 +706,6 @@ class IssuedTrytonInvoiceMapper( """ Tryton Issued Invoice to AEAT mapper """ - __name__ = 'aeat.sii.issued.invoice.mapper' serial_number = attrgetter('number') specialkey_or_trascendence = attrgetter('sii_issued_key') @@ -708,7 +716,6 @@ class RecievedTrytonInvoiceMapper( """ Tryton Recieved Invoice to AEAT mapper """ - __name__ = 'aeat.sii.recieved.invoice.mapper' serial_number = attrgetter('reference') specialkey_or_trascendence = attrgetter('sii_received_key') move_date = attrgetter('move.date') @@ -735,3 +742,14 @@ class SIIReportLine(ModelSQL, ModelView): @staticmethod def default_company(): return Transaction().context.get('company') + + @classmethod + def copy(cls, records, default=None): + if default is None: + default = {} + else: + default = default.copy() + default['state'] = None + default['communication_code'] = None + default['communication_msg'] = None + return super(SIIReportLine, cls).copy(records, default=default) diff --git a/aeat.xml b/aeat.xml index 95affc4..287dd87 100644 --- a/aeat.xml +++ b/aeat.xml @@ -1,4 +1,6 @@ + diff --git a/company.py b/company.py index 7686c8d..4f6753f 100644 --- a/company.py +++ b/company.py @@ -1,6 +1,5 @@ -#This file is part party_comment module for Tryton. -#The COPYRIGHT file at the top level of this repository contains -#the full copyright notices and license terms. +# The COPYRIGHT file at the top level of this repository contains +# the full copyright notices and license terms. from logging import getLogger from contextlib import contextmanager @@ -27,6 +26,7 @@ class Company: cls._error_messages.update({ 'missing_fernet_key': "Missing Fernet key configuration", + 'missing_pem_cert': "Missing PEM certificate" }) pem_certificate = fields.Binary( @@ -90,6 +90,8 @@ class Company: @contextmanager def tmp_ssl_credentials(self): + if not self.pem_certificate: + self.raise_user_error('missing_pem_cert') with NamedTemporaryFile(suffix='.crt') as crt: with NamedTemporaryFile(suffix='.pem') as key: crt.write(self.pem_certificate) diff --git a/company.xml b/company.xml index 634c2e4..39b33d1 100644 --- a/company.xml +++ b/company.xml @@ -1,4 +1,6 @@ - + + diff --git a/invoice.py b/invoice.py index e352ae2..4634409 100644 --- a/invoice.py +++ b/invoice.py @@ -61,7 +61,7 @@ class Invoice: table = SIILines.__table__() - cursor = Transaction().connection.cursor() + cursor = Transaction().cursor cursor.execute(*table.select(Max(table.id), table.invoice, group_by=table.invoice)) @@ -86,10 +86,10 @@ class Invoice: SIILines = pool.get('aeat.sii.report.lines') result = {} for name in names: - result[name] = dict((i.id, '') for i in invoices) + result[name] = dict((i.id, None) for i in invoices) table = SIILines.__table__() - cursor = Transaction().connection.cursor() + cursor = Transaction().cursor cursor.execute(*table.select(Max(table.id), table.invoice, where=table.invoice.in_([x.id for x in invoices]), group_by=table.invoice)) @@ -102,7 +102,6 @@ class Invoice: for state, inv in cursor.fetchall(): result['sii_state'][inv] = state - return result def _credit(self): diff --git a/invoice.xml b/invoice.xml index 48c8f4b..91d95fc 100644 --- a/invoice.xml +++ b/invoice.xml @@ -1,4 +1,6 @@ + diff --git a/load_pkcs12.xml b/load_pkcs12.xml index d98fec5..372f6b9 100644 --- a/load_pkcs12.xml +++ b/load_pkcs12.xml @@ -1,21 +1,23 @@ + - + - - aeat.sii.load_pkcs12.start - form - load_pkcs12_start - - - Load PKCS12 - aeat.sii.load_pkcs12 - - - - form_action - company.company,-1 - + + aeat.sii.load_pkcs12.start + form + load_pkcs12_start + + + Load PKCS12 + aeat.sii.load_pkcs12 + + + + form_action + company.company,-1 + - + diff --git a/locale/es_ES.po b/locale/es_ES.po index dc5c7a5..afbe095 100644 --- a/locale/es_ES.po +++ b/locale/es_ES.po @@ -8,7 +8,11 @@ msgstr "No se ha podido cargar PKCS12: %s" msgctxt "error:company.company:" msgid "Missing Fernet key configuration" -msgstr "Falta clave Fernet a la configuración" +msgstr "Falta clave Fernet en la configuración" + +msgctxt "error:company.company:" +msgid "Missing PEM certificate" +msgstr "Falta certificado PEM" msgctxt "field:account.invoice,sii_book_key:" msgid "SII Book Key" @@ -122,7 +126,6 @@ msgctxt "field:aeat.sii.report,rec_name:" msgid "Name" msgstr "Nombre" -#, fuzzy msgctxt "field:aeat.sii.report,state:" msgid "State" msgstr "Estado" @@ -131,7 +134,6 @@ msgctxt "field:aeat.sii.report,version:" msgid "Version" msgstr "Versión" -#, fuzzy msgctxt "field:aeat.sii.report,write_date:" msgid "Write Date" msgstr "Fecha de modificación" @@ -184,7 +186,6 @@ msgctxt "field:aeat.sii.report.lines,write_date:" msgid "Write Date" msgstr "Fecha de modificación" -#, fuzzy msgctxt "field:aeat.sii.report.lines,write_uid:" msgid "Write User" msgstr "Usuario modificación" @@ -251,7 +252,7 @@ msgstr "Informe SII" msgctxt "model:ir.action,name:act_aeat_sii_report_line" msgid "AEAT SII Report Lines" -msgstr "Línias informe SII" +msgstr "Líneas informe SII" msgctxt "model:ir.action,name:act_aeat_sii_report_lines" msgid "SII Report Lines" @@ -802,14 +803,13 @@ msgctxt "view:aeat.sii.report:" msgid "Load Invoices" msgstr "Cargar facturas" -#, fuzzy msgctxt "view:aeat.sii.report:" msgid "Send" msgstr "Enviar" msgctxt "view:company.company:" msgid "Certificate" -msgstr "" +msgstr "Certificado" msgctxt "wizard_button:aeat.sii.load_pkcs12,start,end:" msgid "Cancel" diff --git a/party.py b/party.py index 713983c..f279f39 100644 --- a/party.py +++ b/party.py @@ -1,16 +1,27 @@ -#This file is part party_comment module for Tryton. -#The COPYRIGHT file at the top level of this repository contains -#the full copyright notices and license terms. +# 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 . import aeat __all__ = ['Party'] + class Party: __name__ = 'party.party' __metaclass__ = PoolMeta # TODO: v4 change to party.identifier module - identifier_type = fields.Selection([('', '')] + aeat.PARTY_IDENTIFIER_TYPE, - 'Identifier Type', ) + identifier_type = fields.Selection(aeat.PARTY_IDENTIFIER_TYPE, + 'Identifier Type') + sii_vat_code = fields.Function(fields.Char('VAT', size=9), + 'get_sii_vat_data') + sii_vat_country = fields.Function(fields.Char('VAT', size=2), + 'get_sii_vat_data') + + def get_sii_vat_data(self, name=None): + if self.vat_code: + if name == 'sii_vat_code': + return self.vat_code[-9:] + elif name == 'sii_vat_country': + return self.vat_code[:2] diff --git a/party.xml b/party.xml index d38f4b3..d5922b5 100644 --- a/party.xml +++ b/party.xml @@ -1,6 +1,5 @@ - + diff --git a/tests/test_aeat_sii.py b/tests/test_aeat_sii.py index 0ca3ea5..211c3da 100644 --- a/tests/test_aeat_sii.py +++ b/tests/test_aeat_sii.py @@ -3,29 +3,20 @@ import unittest # import doctest import trytond.tests.test_tryton -from trytond.tests.test_tryton import test_view, test_depends +from trytond.tests.test_tryton import ModuleTestCase # TODO: Remove if no sceneario needed. # from trytond.tests.test_tryton import doctest_setup, doctest_teardown -class TestCase(unittest.TestCase): - 'Test module' - - def setUp(self): - trytond.tests.test_tryton.install_module('aeat_sii') - - def test0005views(self): - 'Test views' - test_view('aeat_sii') - - def test0006depends(self): - 'Test depends' - test_depends() +class AeatSIITestCase(ModuleTestCase): + 'Test AEAT SII module' + module = 'aeat_sii' def suite(): suite = trytond.tests.test_tryton.suite() - suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestCase)) + suite.addTests(unittest.TestLoader().loadTestsFromTestCase( + AeatSIITestCase)) # TODO: remove if no scenario needed. #suite.addTests(doctest.DocFileSuite('scenario_aeat_sii.rst', # setUp=doctest_setup, tearDown=doctest_teardown, encoding='utf-8', diff --git a/view/company_form.xml b/view/company_form.xml index bb15fbc..c2b3476 100644 --- a/view/company_form.xml +++ b/view/company_form.xml @@ -1,8 +1,6 @@ - - diff --git a/view/load_pkcs12_start.xml b/view/load_pkcs12_start.xml index cfaa5e6..885c7da 100644 --- a/view/load_pkcs12_start.xml +++ b/view/load_pkcs12_start.xml @@ -1,8 +1,6 @@ - -