Submit and modify Recieved invoices to SII
This commit is contained in:
parent
3cdda9406a
commit
6436cacacd
61
aeat.py
61
aeat.py
|
@ -362,6 +362,11 @@ class SIIReport(Workflow, ModelSQL, ModelView):
|
|||
report.delete_issued_invoices()
|
||||
else:
|
||||
raise NotImplementedError
|
||||
elif report.book == 'R':
|
||||
if report.operation_type in {'A0', 'A1'}:
|
||||
report.submit_recieved_invoices()
|
||||
else:
|
||||
raise NotImplementedError
|
||||
else:
|
||||
raise NotImplementedError
|
||||
_logger.debug('Done sending reports to AEAT SII')
|
||||
|
@ -411,7 +416,7 @@ class SIIReport(Workflow, ModelSQL, ModelView):
|
|||
(line.invoice for line in self.lines))
|
||||
res = None
|
||||
with self.company.tmp_ssl_credentials() as (crt, key):
|
||||
srv = service.bind_SuministroFactEmitidas(crt, key, test=True)
|
||||
srv = service.bind_issued_invoices_service(crt, key, test=True)
|
||||
res = srv.SuministroLRFacturasEmitidas(headers, invoices)
|
||||
# TODO: assert response order matches report order
|
||||
for (report_line, response_line) in zip(
|
||||
|
@ -436,7 +441,7 @@ class SIIReport(Workflow, ModelSQL, ModelView):
|
|||
(line.invoice for line in self.lines))
|
||||
res = None
|
||||
with self.company.tmp_ssl_credentials() as (crt, key):
|
||||
srv = service.bind_SuministroFactEmitidas(crt, key, test=True)
|
||||
srv = service.bind_issued_invoices_service(crt, key, test=True)
|
||||
res = srv.AnulacionLRFacturasEmitidas(headers, invoices)
|
||||
# TODO: assert response order matches report order
|
||||
for (report_line, response_line) in zip(
|
||||
|
@ -470,7 +475,7 @@ class SIIReport(Workflow, ModelSQL, ModelView):
|
|||
# EstadoCuadre, ClavePaginacion
|
||||
}
|
||||
with self.company.tmp_ssl_credentials() as (crt, key):
|
||||
srv = service.bind_SuministroFactEmitidas(
|
||||
srv = service.bind_issued_invoices_service(
|
||||
crt, key, test=True)
|
||||
res = srv.ConsultaLRFacturasEmitidas(
|
||||
headers, filter_)
|
||||
|
@ -506,6 +511,34 @@ class SIIReport(Workflow, ModelSQL, ModelView):
|
|||
'lines': [('create', lines_to_create)]
|
||||
})
|
||||
|
||||
def submit_recieved_invoices(self):
|
||||
_logger.info('Sending report %s to AEAT SII', self.id)
|
||||
headers = mapping.get_headers(
|
||||
name=self.company.party.name,
|
||||
vat=self.company.party.vat_number,
|
||||
comm_kind=self.operation_type)
|
||||
invoices = map(
|
||||
RecievedTrytonInvoiceMapper.build_submit_request,
|
||||
(line.invoice for line in self.lines))
|
||||
res = None
|
||||
_logger.debug(invoices)
|
||||
with self.company.tmp_ssl_credentials() as (crt, key):
|
||||
srv = service.bind_recieved_invoices_service(crt, key, test=True)
|
||||
res = srv.SuministroLRFacturasRecibidas(headers, invoices)
|
||||
_logger.debug(res)
|
||||
# TODO: assert response order matches report order
|
||||
for (report_line, response_line) in zip(
|
||||
self.lines, res.RespuestaLinea):
|
||||
report_line.write([report_line], {
|
||||
'state': response_line.EstadoRegistro,
|
||||
'communication_code': response_line.CodigoErrorRegistro,
|
||||
'communication_msg': response_line.DescripcionErrorRegistro,
|
||||
})
|
||||
self.write([self], {
|
||||
'communication_state': res.EstadoEnvio,
|
||||
'csv': res.CSV,
|
||||
})
|
||||
|
||||
|
||||
class IssuedTrytonInvoiceMapper(mapping.OutInvoiceMapper):
|
||||
year = attrgetter('move.period.fiscalyear.name')
|
||||
|
@ -527,6 +560,28 @@ class IssuedTrytonInvoiceMapper(mapping.OutInvoiceMapper):
|
|||
tax_amount = attrgetter('amount')
|
||||
|
||||
|
||||
class RecievedTrytonInvoiceMapper(mapping.RecievedInvoiceMapper):
|
||||
year = attrgetter('move.period.fiscalyear.name')
|
||||
period = attrgetter('move.period.start_date.month')
|
||||
nif = attrgetter('company.party.vat_number')
|
||||
serial_number = attrgetter('reference')
|
||||
issue_date = attrgetter('invoice_date')
|
||||
invoice_kind = attrgetter('sii_operation_key')
|
||||
specialkey_or_trascendence = attrgetter('sii_received_key')
|
||||
description = attrgetter('description')
|
||||
not_exempt_kind = attrgetter('sii_subjected')
|
||||
counterpart_name = attrgetter('party.name')
|
||||
counterpart_nif = attrgetter('party.vat_number')
|
||||
counterpart_id_type = attrgetter('party.identifier_type')
|
||||
counterpart_country = attrgetter('party.vat_country')
|
||||
move_date = attrgetter('move.date')
|
||||
deductible_amount = attrgetter('tax_amount') # most of the times
|
||||
taxes = attrgetter('taxes')
|
||||
tax_rate = attrgetter('tax.rate')
|
||||
tax_base = attrgetter('base')
|
||||
tax_amount = attrgetter('amount')
|
||||
|
||||
|
||||
class SIIReportLine(ModelSQL, ModelView):
|
||||
'''
|
||||
AEAT SII Issued
|
||||
|
|
|
@ -2,8 +2,11 @@
|
|||
__all__ = [
|
||||
'get_headers',
|
||||
'OutInvoiceMapper',
|
||||
'RecievedInvoiceMapper',
|
||||
]
|
||||
|
||||
_DATE_FMT = '%d-%m-%Y'
|
||||
|
||||
|
||||
def get_headers(name=None, vat=None, comm_kind=None, version='0.7'):
|
||||
return {
|
||||
|
@ -46,7 +49,7 @@ class OutInvoiceMapper(object):
|
|||
},
|
||||
'NumSerieFacturaEmisor': cls.serial_number(invoice),
|
||||
'FechaExpedicionFacturaEmisor':
|
||||
cls.issue_date(invoice).strftime('%d/%m/%Y'),
|
||||
cls.issue_date(invoice).strftime(_DATE_FMT),
|
||||
}
|
||||
|
||||
@classmethod
|
||||
|
@ -108,3 +111,83 @@ class OutInvoiceMapper(object):
|
|||
'CuotaRepercutida': cls.tax_amount(tax),
|
||||
# TODO: TipoRecargoEquivalencia, CuotaRecargoEquivalencia
|
||||
}
|
||||
|
||||
|
||||
class RecievedInvoiceMapper(object):
|
||||
|
||||
@classmethod
|
||||
def build_delete_request(cls, invoice):
|
||||
return {
|
||||
'PeriodoImpositivo': cls.build_period(invoice),
|
||||
'IDFactura': cls.build_invoice_id(invoice),
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def build_submit_request(cls, invoice):
|
||||
request = cls.build_delete_request(invoice)
|
||||
request['FacturaRecibida'] = cls.build_invoice(invoice)
|
||||
return request
|
||||
|
||||
@classmethod
|
||||
def build_period(cls, invoice):
|
||||
return {
|
||||
'Ejercicio': cls.year(invoice),
|
||||
'Periodo': str(cls.period(invoice)).zfill(2),
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def build_invoice_id(cls, invoice):
|
||||
return {
|
||||
'IDEmisorFactura': {
|
||||
'NIF': cls.counterpart_nif(invoice),
|
||||
},
|
||||
'NumSerieFacturaEmisor': cls.serial_number(invoice),
|
||||
'FechaExpedicionFacturaEmisor':
|
||||
cls.issue_date(invoice).strftime(_DATE_FMT),
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def build_invoice(cls, invoice):
|
||||
ret = {
|
||||
'TipoFactura': cls.invoice_kind(invoice),
|
||||
'ClaveRegimenEspecialOTrascendencia':
|
||||
cls.specialkey_or_trascendence(invoice),
|
||||
'DescripcionOperacion': cls.description(invoice),
|
||||
'DesgloseFactura': {
|
||||
# 'InversionSujetoPasivo': {
|
||||
# 'DetalleIVA':
|
||||
# map(cls.build_taxes, cls.taxes(invoice)),
|
||||
# },
|
||||
'DesgloseIVA': {
|
||||
'DetalleIVA':
|
||||
map(cls.build_taxes, cls.taxes(invoice)),
|
||||
}
|
||||
},
|
||||
'FechaRegContable': cls.move_date(invoice).strftime(_DATE_FMT),
|
||||
'CuotaDeducible': cls.deductible_amount(invoice),
|
||||
}
|
||||
if ret['TipoFactura'] not in {'F2', 'F4', 'R5'}:
|
||||
ret['Contraparte'] = cls.build_counterpart(invoice)
|
||||
return ret
|
||||
|
||||
@classmethod
|
||||
def build_counterpart(cls, invoice):
|
||||
return {
|
||||
'NombreRazon': cls.counterpart_name(invoice),
|
||||
'NIF': cls.counterpart_nif(invoice),
|
||||
# 'IDOtro': {
|
||||
# 'IDType': cls.counterpart_id_type(invoice),
|
||||
# 'CodigoPais': cls.counterpart_country(invoice),
|
||||
# # 'ID': cls.counterpart_nif(invoice),
|
||||
# },
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def build_taxes(cls, tax):
|
||||
return {
|
||||
'TipoImpositivo': int(100 * cls.tax_rate(tax)),
|
||||
'BaseImponible': cls.tax_base(tax),
|
||||
'CuotaSoportada': cls.tax_amount(tax),
|
||||
# TODO: TipoRecargoEquivalencia, CuotaRecargoEquivalencia
|
||||
# TODO: PorcentCompensacionREAGYP, ImporteCompensacionREAGYP
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
|
||||
__all__ = [
|
||||
'bind_SuministroFactEmitidas',
|
||||
'bind_issued_invoices_service',
|
||||
'bind_recieved_invoices_service',
|
||||
]
|
||||
|
||||
from requests import Session
|
||||
|
@ -25,7 +26,7 @@ def _get_client(wsdl, public_crt, private_key, test=False):
|
|||
return client
|
||||
|
||||
|
||||
def bind_SuministroFactEmitidas(crt, pkey, test=False):
|
||||
def bind_issued_invoices_service(crt, pkey, test=False):
|
||||
wsdl = (
|
||||
'http://www.agenciatributaria.es/static_files/AEAT/'
|
||||
'Contenidos_Comunes/La_Agencia_Tributaria/Modelos_y_formularios/'
|
||||
|
@ -39,9 +40,17 @@ def bind_SuministroFactEmitidas(crt, pkey, test=False):
|
|||
service = cli.bind('siiService', port_name)
|
||||
return service
|
||||
|
||||
# wsdl_in = fields.Char(
|
||||
# string='WSDL Invoice In', required=True,
|
||||
# default='http://www.agenciatributaria.es/static_files/AEAT/'
|
||||
# 'Contenidos_Comunes/La_Agencia_Tributaria/Modelos_y_formularios/'
|
||||
# 'Suministro_inmediato_informacion/FicherosSuministros/V_06/'
|
||||
# 'SuministroFactRecibidas.wsdl')
|
||||
|
||||
def bind_recieved_invoices_service(crt, pkey, test=False):
|
||||
wsdl = (
|
||||
'http://www.agenciatributaria.es/static_files/AEAT/'
|
||||
'Contenidos_Comunes/La_Agencia_Tributaria/Modelos_y_formularios/'
|
||||
'Suministro_inmediato_informacion/FicherosSuministros/V_07/'
|
||||
'SuministroFactRecibidas.wsdl'
|
||||
)
|
||||
port_name = 'SuministroFactRecibidas'
|
||||
if test:
|
||||
port_name += 'Pruebas'
|
||||
cli = _get_client(wsdl, crt, pkey, test)
|
||||
service = cli.bind('siiService', port_name)
|
||||
return service
|
||||
|
|
Loading…
Reference in New Issue