578 lines
22 KiB
Python
578 lines
22 KiB
Python
# -*- coding: utf-8 -*-
|
|
# The COPYRIGHT file at the top level of this repository contains the full
|
|
# copyright notices and license terms.
|
|
from decimal import Decimal
|
|
from logging import getLogger
|
|
from operator import attrgetter
|
|
from datetime import date
|
|
|
|
from trytond.i18n import gettext
|
|
from trytond.model import Model
|
|
from trytond.exceptions import UserError
|
|
from . import tools
|
|
|
|
|
|
_logger = getLogger(__name__)
|
|
|
|
_DATE_FMT = '%d-%m-%Y'
|
|
_FIRST_SEMESTER_RECORD_DESCRIPTION = "Registro del Primer semestre"
|
|
|
|
RECTIFIED_KINDS = frozenset({'R1', 'R2', 'R3', 'R4', 'R5'})
|
|
OTHER_ID_TYPES = frozenset({'02', '03', '04', '05', '06', '07'})
|
|
|
|
SEMESTER1_ISSUED_SPECIALKEY = '16'
|
|
SEMESTER1_RECIEVED_SPECIALKEY = '14'
|
|
|
|
|
|
class BaseInvoiceMapper(Model):
|
|
year = attrgetter('move.period.start_date.year')
|
|
period = attrgetter('move.period.start_date.month')
|
|
nif = attrgetter('company.party.sii_vat_code')
|
|
issue_date = attrgetter('invoice_date')
|
|
invoice_kind = attrgetter('sii_operation_key')
|
|
rectified_invoice_kind = tools.fixed_value('I')
|
|
|
|
def not_exempt_kind(self, tax):
|
|
return attrgetter('sii_subjected_key')(tax)
|
|
|
|
def exempt_kind(self, tax):
|
|
return attrgetter('sii_exemption_cause')(tax)
|
|
|
|
def not_subject(self, invoice):
|
|
base = 0
|
|
for line in invoice.lines:
|
|
for tax in line.taxes:
|
|
if (tax.sii_exemption_cause == 'NotSubject' and
|
|
not tax.service):
|
|
base += attrgetter('amount')(line)
|
|
return base
|
|
|
|
def counterpart_nif(self, invoice):
|
|
nif = ''
|
|
if invoice.sii_operation_key == 'F5':
|
|
# Assume that the company party is configured correctly.
|
|
nif = invoice.company.party.tax_identifier.code
|
|
else:
|
|
if invoice.party.tax_identifier:
|
|
nif = invoice.party.tax_identifier.code
|
|
elif invoice.party.identifiers:
|
|
nif = invoice.party.identifiers[0].code
|
|
if nif.startswith('ES'):
|
|
nif = nif[2:]
|
|
return nif
|
|
|
|
def get_tax_amount(self, tax):
|
|
val = attrgetter('company_amount')(tax)
|
|
return val
|
|
|
|
def get_tax_base(self, tax):
|
|
val = attrgetter('company_base')(tax)
|
|
return val
|
|
|
|
def get_invoice_total(self, invoice):
|
|
taxes = self.total_invoice_taxes(invoice)
|
|
taxes_base = 0
|
|
taxes_amount = 0
|
|
taxes_surcharge = 0
|
|
taxes_used = {}
|
|
for tax in taxes:
|
|
base = self.get_tax_base(tax)
|
|
taxes_amount += self.get_tax_amount(tax)
|
|
taxes_surcharge += self.tax_equivalence_surcharge_amount(tax) or 0
|
|
parent = tax.tax.parent if tax.tax.parent else tax.tax
|
|
if (parent.id in list(taxes_used.keys()) and
|
|
base == taxes_used[parent.id]):
|
|
continue
|
|
taxes_base += base
|
|
taxes_used[parent.id] = base
|
|
return (taxes_amount + taxes_base + taxes_surcharge)
|
|
|
|
def counterpart_id_type(self, invoice):
|
|
if invoice.sii_operation_key == 'F5':
|
|
return invoice.company.party.sii_identifier_type
|
|
else:
|
|
if (invoice.sii_received_key == '09' and
|
|
invoice.party.sii_identifier_type != '02'):
|
|
raise UserError(gettext('aeat_sii.msg_wrong_identifier_type',
|
|
invoice=invoice.number, party=invoice.party.rec_name))
|
|
for tax in invoice.taxes:
|
|
if (self.exempt_kind(tax.tax) == 'E5' and
|
|
invoice.party.sii_identifier_type != '02'):
|
|
raise UserError(gettext(
|
|
'aeat_sii.msg_wrong_identifier_type',
|
|
invoice=invoice.number,
|
|
party=invoice.party.rec_name))
|
|
return invoice.party.sii_identifier_type
|
|
|
|
counterpart_id = counterpart_nif
|
|
total_amount = get_invoice_total
|
|
tax_rate = attrgetter('tax.rate')
|
|
tax_base = get_tax_base
|
|
tax_amount = get_tax_amount
|
|
|
|
def counterpart_name(self, invoice):
|
|
if invoice.sii_operation_key == 'F5':
|
|
return tools.unaccent(invoice.company.party.name)
|
|
else:
|
|
return tools.unaccent(invoice.party.name)
|
|
|
|
def counterpart_country(self, invoice):
|
|
return (invoice.invoice_address.country.code
|
|
if invoice.invoice_address.country else '')
|
|
|
|
def serial_number(self, invoice):
|
|
return invoice.number if invoice.type == 'out' else (invoice.reference or '')
|
|
|
|
def taxes(self, invoice):
|
|
return [invoice_tax for invoice_tax in invoice.taxes if (
|
|
invoice_tax.tax.tax_used and
|
|
not invoice_tax.tax.recargo_equivalencia)]
|
|
|
|
def total_invoice_taxes(self, invoice):
|
|
return [invoice_tax for invoice_tax in invoice.taxes if (
|
|
invoice_tax.tax.invoice_used and
|
|
not invoice_tax.tax.recargo_equivalencia)]
|
|
|
|
def _tax_equivalence_surcharge(self, invoice_tax):
|
|
surcharge_tax = None
|
|
for invoicetax in invoice_tax.invoice.taxes:
|
|
if (invoicetax.tax.recargo_equivalencia and
|
|
invoice_tax.tax.recargo_equivalencia_related_tax ==
|
|
invoicetax.tax and invoicetax.base ==
|
|
invoicetax.base.copy_sign(invoice_tax.base)):
|
|
surcharge_tax = invoicetax
|
|
break
|
|
return surcharge_tax
|
|
|
|
def tax_equivalence_surcharge_rate(self, invoice_tax):
|
|
surcharge_tax = self._tax_equivalence_surcharge(invoice_tax)
|
|
if surcharge_tax:
|
|
return self.tax_rate(surcharge_tax)
|
|
|
|
def tax_equivalence_surcharge_amount(self, invoice_tax):
|
|
surcharge_tax = self._tax_equivalence_surcharge(invoice_tax)
|
|
if surcharge_tax:
|
|
return self.tax_amount(surcharge_tax)
|
|
|
|
def _build_period(self, invoice):
|
|
return {
|
|
'Ejercicio': self.year(invoice),
|
|
'Periodo': tools._format_period(self.period(invoice)),
|
|
}
|
|
|
|
def _build_invoice_id(self, invoice):
|
|
number = self.serial_number(invoice)
|
|
ret = {
|
|
'IDEmisorFactura': self._build_issuer_id(invoice),
|
|
'NumSerieFacturaEmisor': number,
|
|
'FechaExpedicionFacturaEmisor':
|
|
self.issue_date(invoice).strftime(_DATE_FMT),
|
|
}
|
|
if self.invoice_kind(invoice) == 'F4':
|
|
first_invoice = invoice.simplified_serial_number('first')
|
|
last_invoice = invoice.simplified_serial_number('last')
|
|
ret['NumSerieFacturaEmisor'] = number + first_invoice
|
|
ret['NumSerieFacturaEmisorResumenFin'] = number + last_invoice
|
|
return ret
|
|
|
|
def _build_counterpart(self, invoice):
|
|
ret = {
|
|
'NombreRazon': self.counterpart_name(invoice),
|
|
}
|
|
id_type = self.counterpart_id_type(invoice)
|
|
if id_type and id_type in OTHER_ID_TYPES:
|
|
ret['IDOtro'] = {
|
|
'IDType': id_type,
|
|
'CodigoPais': self.counterpart_country(invoice),
|
|
'ID': self.counterpart_id(invoice),
|
|
}
|
|
else:
|
|
ret['NIF'] = self.counterpart_nif(invoice)
|
|
return ret
|
|
|
|
def _description(self, invoice):
|
|
description = ''
|
|
if invoice.description:
|
|
description = tools.unaccent(invoice.description)
|
|
if invoice.lines and invoice.lines[0].description:
|
|
description = tools.unaccent(invoice.lines[0].description)
|
|
description = self.serial_number(invoice)
|
|
|
|
return (description if not self._is_first_semester(invoice)
|
|
else _FIRST_SEMESTER_RECORD_DESCRIPTION
|
|
)
|
|
|
|
def build_query_filter(self, year=None, period=None, last_invoice=None):
|
|
# TODO: IDFactura, Contraparte,
|
|
# FechaPresentacion, FechaCuadre, FacturaModificada,
|
|
# EstadoCuadre
|
|
result = {
|
|
'PeriodoLiquidacion': {
|
|
'Ejercicio': year,
|
|
'Periodo': tools._format_period(period),
|
|
}
|
|
}
|
|
if last_invoice:
|
|
result['ClavePaginacion'] = last_invoice
|
|
return result
|
|
|
|
|
|
class IssuedInvoiceMapper(BaseInvoiceMapper):
|
|
"""
|
|
Tryton Issued Invoice to AEAT mapper
|
|
"""
|
|
__name__ = 'aeat.sii.issued.invoice.mapper'
|
|
specialkey_or_trascendence = attrgetter('sii_issued_key')
|
|
|
|
def _is_first_semester(self, invoice):
|
|
return self.specialkey_or_trascendence(invoice) == \
|
|
SEMESTER1_ISSUED_SPECIALKEY
|
|
|
|
def build_delete_request(self, invoice):
|
|
return {
|
|
'PeriodoLiquidacion': self._build_period(invoice),
|
|
'IDFactura': self._build_invoice_id(invoice),
|
|
}
|
|
|
|
def build_submit_request(self, invoice):
|
|
request = self.build_delete_request(invoice)
|
|
request['FacturaExpedida'] = self.build_issued_invoice(invoice)
|
|
return request
|
|
|
|
def _build_issuer_id(self, invoice):
|
|
return {
|
|
'NIF': self.nif(invoice),
|
|
}
|
|
|
|
def build_taxes(self, tax):
|
|
if not tax:
|
|
return {}
|
|
|
|
res = {
|
|
'TipoImpositivo': tools._rate_to_percent(self.tax_rate(tax)),
|
|
'BaseImponible': self.tax_base(tax),
|
|
'CuotaRepercutida': self.tax_amount(tax)
|
|
}
|
|
|
|
# In case base is 0, return only the tax, not the possible IRPF.
|
|
if self.tax_base(tax) == Decimal(0):
|
|
return res
|
|
|
|
if self.tax_equivalence_surcharge_rate(tax):
|
|
res['TipoRecargoEquivalencia'] = (
|
|
tools._rate_to_percent(self.tax_equivalence_surcharge_rate(
|
|
tax)))
|
|
|
|
if self.tax_equivalence_surcharge_amount(tax):
|
|
res['CuotaRecargoEquivalencia'] = (
|
|
self.tax_equivalence_surcharge_amount(tax))
|
|
return res
|
|
|
|
def location_rules(self, invoice):
|
|
base = 0
|
|
for line in invoice.lines:
|
|
for tax in line.taxes:
|
|
if (tax.sii_issued_key == '08' or
|
|
(tax.sii_exemption_cause == 'NotSubject' and
|
|
tax.service)):
|
|
base += attrgetter('amount')(line)
|
|
return base
|
|
|
|
def build_issued_invoice(self, invoice):
|
|
ret = {
|
|
'TipoFactura': self.invoice_kind(invoice),
|
|
# TODO: FacturasAgrupadas
|
|
# TODO: FacturasRectificadas
|
|
# TODO: FechaOperacion
|
|
'ClaveRegimenEspecialOTrascendencia':
|
|
self.specialkey_or_trascendence(invoice),
|
|
# TODO: ClaveRegimenEspecialOTrascendenciaAdicional1
|
|
# TODO: ClaveRegimenEspecialOTrascendenciaAdicional2
|
|
# TODO: NumRegistroAcuerdoFacturacion
|
|
'ImporteTotal': self.total_amount(invoice),
|
|
# TODO: BaseImponibleACoste
|
|
'DescripcionOperacion': self._description(invoice),
|
|
# TODO: RefExterna
|
|
# TODO: FacturaSimplificadaArticulos7.2_7.3
|
|
# TODO: EntidadSucedida
|
|
# TODO: RegPrevioGGEEoREDEMEoCompetencia
|
|
# TODO: Macrodato
|
|
# TODO: DatosInmueble
|
|
# TODO: ImporteTransmisionInmueblesSujetoAIVA
|
|
# TODO: EmitidaPorTercerosODestinatario
|
|
# TODO: FacturacionDispAdicinalTerceraYsextayDelMercadoOrganizadoDelGas
|
|
# TODO: VariosDestinatarios
|
|
# TODO: Cupon
|
|
# TODO: FacturaSinIdentifDestinatarioArticulo6.1.d
|
|
'TipoDesglose': {},
|
|
}
|
|
self._update_counterpart(ret, invoice)
|
|
|
|
must_detail_op = (ret.get('Contraparte', {}) and (
|
|
'IDOtro' in ret['Contraparte'] or ('NIF' in ret['Contraparte'] and
|
|
ret['Contraparte']['NIF'].startswith('N')))
|
|
)
|
|
detail = {
|
|
'Sujeta': {},
|
|
'NoSujeta': {}
|
|
}
|
|
if must_detail_op:
|
|
ret['TipoDesglose'].update({
|
|
'DesgloseTipoOperacion': {
|
|
'Entrega': detail,
|
|
'PrestacionServicios': detail,
|
|
}
|
|
})
|
|
else:
|
|
ret['TipoDesglose'].update({
|
|
'DesgloseFactura': detail
|
|
})
|
|
|
|
taxes = self.taxes(invoice)
|
|
for tax in taxes:
|
|
exempt_kind = self.exempt_kind(tax.tax)
|
|
not_exempt_kind = self.not_exempt_kind(tax.tax)
|
|
if (not_exempt_kind in ('S2', 'S3') and
|
|
'NIF' not in ret.get('Contraparte', {})):
|
|
raise UserError(gettext('aeat_sii.msg_missing_nif',
|
|
invoice=invoice))
|
|
|
|
if not_exempt_kind:
|
|
if not_exempt_kind == 'S2':
|
|
# inv. subj. pass.
|
|
tax_detail = {
|
|
'TipoImpositivo': 0,
|
|
'BaseImponible': self.get_tax_base(tax),
|
|
'CuotaRepercutida': 0
|
|
}
|
|
else:
|
|
tax_detail = self.build_taxes(tax)
|
|
if tax_detail:
|
|
if (not detail['Sujeta'] or
|
|
not detail['Sujeta'].get('NoExenta')):
|
|
detail['Sujeta'].update({
|
|
'NoExenta': {
|
|
'TipoNoExenta': not_exempt_kind,
|
|
'DesgloseIVA': {
|
|
'DetalleIVA': [tax_detail]
|
|
}
|
|
}
|
|
})
|
|
else:
|
|
detail['Sujeta']['NoExenta']['DesgloseIVA'][
|
|
'DetalleIVA'].append(tax_detail)
|
|
elif exempt_kind:
|
|
if exempt_kind != 'NotSubject':
|
|
baseimponible = self.get_tax_base(tax)
|
|
if detail['Sujeta'].get('Exenta', {}).get(
|
|
'DetalleExenta', {}).get(
|
|
'CausaExencion', None) == exempt_kind:
|
|
baseimponible += detail['Sujeta'].get('Exenta').get(
|
|
'DetalleExenta').get('BaseImponible', 0)
|
|
detail['Sujeta'].update({
|
|
'Exenta': {
|
|
'DetalleExenta': {
|
|
'CausaExencion': exempt_kind,
|
|
'BaseImponible': baseimponible,
|
|
}
|
|
}
|
|
})
|
|
if self.location_rules(invoice):
|
|
detail['NoSujeta'].update({
|
|
'ImporteTAIReglasLocalizacion': self.location_rules(
|
|
invoice)
|
|
})
|
|
elif self.not_subject(invoice):
|
|
detail['NoSujeta'].update({
|
|
'ImportePorArticulos7_14_Otros': self.not_subject(
|
|
invoice),
|
|
})
|
|
|
|
# remove unused key
|
|
for key in ('Sujeta', 'NoSujeta'):
|
|
if not detail[key]:
|
|
detail.pop(key)
|
|
|
|
if must_detail_op:
|
|
if not taxes:
|
|
if self.not_subject(invoice):
|
|
ret['TipoDesglose']['DesgloseTipoOperacion'].pop(
|
|
'PrestacionServicios')
|
|
elif self.location_rules(invoice):
|
|
ret['TipoDesglose']['DesgloseTipoOperacion'].pop('Entrega')
|
|
else:
|
|
if tax.tax.service:
|
|
ret['TipoDesglose']['DesgloseTipoOperacion'].pop('Entrega')
|
|
else:
|
|
ret['TipoDesglose']['DesgloseTipoOperacion'].pop(
|
|
'PrestacionServicios')
|
|
|
|
self._update_total_amount(ret, invoice)
|
|
self._update_rectified_invoice(ret, invoice)
|
|
return ret
|
|
|
|
def _update_total_amount(self, ret, invoice):
|
|
if (
|
|
ret['TipoFactura'] == 'R5' and
|
|
ret['TipoDesglose']['DesgloseFactura']['Sujeta'].get('NoExenta',
|
|
None) and
|
|
len(
|
|
ret['TipoDesglose']['DesgloseFactura']['Sujeta']['NoExenta']
|
|
['DesgloseIVA']['DetalleIVA']
|
|
) == 1 and
|
|
(
|
|
ret['TipoDesglose']['DesgloseFactura']['Sujeta']['NoExenta']
|
|
['DesgloseIVA']['DetalleIVA'][0]['BaseImponible'] == 0
|
|
)
|
|
):
|
|
ret['ImporteTotal'] = self.total_amount(invoice)
|
|
|
|
def _update_counterpart(self, ret, invoice):
|
|
if ret['TipoFactura'] not in {'F2', 'F4', 'R5'}:
|
|
ret['Contraparte'] = self._build_counterpart(invoice)
|
|
|
|
def _update_rectified_invoice(self, ret, invoice):
|
|
if ret['TipoFactura'] in RECTIFIED_KINDS:
|
|
ret['TipoRectificativa'] = self.rectified_invoice_kind(invoice)
|
|
if ret['TipoRectificativa'] == 'S':
|
|
ret['ImporteRectificacion'] = {
|
|
'BaseRectificada': self.rectified_base(invoice),
|
|
'CuotaRectificada': self.rectified_amount(invoice),
|
|
# TODO: CuotaRecargoRectificado
|
|
}
|
|
|
|
|
|
class RecievedInvoiceMapper(BaseInvoiceMapper):
|
|
"""
|
|
Tryton Recieved Invoice to AEAT mapper
|
|
"""
|
|
__name__ = 'aeat.sii.recieved.invoice.mapper'
|
|
specialkey_or_trascendence = attrgetter('sii_received_key')
|
|
move_date = attrgetter('move.date')
|
|
|
|
def _is_first_semester(self, invoice):
|
|
return self.specialkey_or_trascendence(invoice) == \
|
|
SEMESTER1_RECIEVED_SPECIALKEY
|
|
|
|
def _deductible_amount(self, invoice):
|
|
val = Decimal(0)
|
|
for tax in self.taxes(invoice):
|
|
if tax.tax.deducible:
|
|
val += tax.company_amount
|
|
|
|
return val if not self._is_first_semester(invoice) else 0
|
|
|
|
def _move_date(self, invoice):
|
|
return (
|
|
self.move_date(invoice)
|
|
if not self._is_first_semester(invoice)
|
|
else self.sent_date(invoice)
|
|
)
|
|
|
|
def sent_date(self, invoice):
|
|
# Unless overriden, the date an invoice is sent to the SII system
|
|
# is assumed to be the date it is being mapped
|
|
return date.today()
|
|
|
|
def build_delete_request(self, invoice):
|
|
return {
|
|
'PeriodoLiquidacion': self._build_period(invoice),
|
|
'IDFactura': self._build_invoice_id(invoice),
|
|
}
|
|
|
|
def build_submit_request(self, invoice):
|
|
request = self.build_delete_request(invoice)
|
|
request['FacturaRecibida'] = self.build_received_invoice(invoice)
|
|
return request
|
|
|
|
_build_issuer_id = BaseInvoiceMapper._build_counterpart
|
|
|
|
def build_received_invoice(self, invoice):
|
|
ret = {
|
|
'TipoFactura': self.invoice_kind(invoice),
|
|
# TODO: FacturasAgrupadas: {IDFacturaAgrupada: [{Num, Fecha}]}
|
|
# TODO: FechaOperacion
|
|
'ClaveRegimenEspecialOTrascendencia':
|
|
self.specialkey_or_trascendence(invoice),
|
|
# TODO: ClaveRegimenEspecialOTrascendenciaAdicional1
|
|
# TODO: ClaveRegimenEspecialOTrascendenciaAdicional2
|
|
# TODO: NumRegistroAcuerdoFacturacion
|
|
'ImporteTotal': self.total_amount(invoice),
|
|
# TODO: BaseImponibleACoste
|
|
'DescripcionOperacion': self._description(invoice),
|
|
'DesgloseFactura': {},
|
|
'Contraparte': self._build_counterpart(invoice),
|
|
'FechaRegContable': self._move_date(invoice).strftime(_DATE_FMT),
|
|
'CuotaDeducible': self._deductible_amount(invoice),
|
|
# TODO: ADeducirEnPeriodoPosterior
|
|
# TODO: EjercicioDeduccion
|
|
# TODO: PeriodoDeduccion
|
|
}
|
|
_taxes = self.taxes(invoice)
|
|
isp_taxes = self.isp_taxes(_taxes)
|
|
_taxes = list(set(_taxes) - set(isp_taxes))
|
|
if _taxes:
|
|
ret['DesgloseFactura']['DesgloseIVA'] = {
|
|
'DetalleIVA': [],
|
|
}
|
|
for tax in _taxes:
|
|
validate_tax = self.build_taxes(invoice, tax)
|
|
if validate_tax:
|
|
ret['DesgloseFactura']['DesgloseIVA']['DetalleIVA'].append(
|
|
validate_tax)
|
|
if isp_taxes:
|
|
ret['DesgloseFactura']['InversionSujetoPasivo'] = {
|
|
'DetalleIVA': []
|
|
}
|
|
for tax in isp_taxes:
|
|
validate_tax = self.build_taxes(invoice, tax)
|
|
if validate_tax:
|
|
ret['DesgloseFactura']['InversionSujetoPasivo'][
|
|
'DetalleIVA'].append(validate_tax)
|
|
self._update_rectified_invoice(ret, invoice)
|
|
return ret
|
|
|
|
def _update_rectified_invoice(self, ret, invoice):
|
|
if ret['TipoFactura'] in RECTIFIED_KINDS:
|
|
ret['TipoRectificativa'] = self.rectified_invoice_kind(invoice)
|
|
# TODO: FacturasRectificadas:{IDFacturaRectificada:[{Num, Fecha}]}
|
|
# TODO: ImporteRectificacion: {
|
|
# BaseRectificada, CuotaRectificada, CuotaRecargoRectificado }
|
|
|
|
def build_taxes(self, invoice, tax):
|
|
if not tax:
|
|
return {}
|
|
# In case base is 0, return only the tax, not the possible IRPF.
|
|
if self.tax_base(tax) == Decimal(0):
|
|
ret = {
|
|
'TipoImpositivo': tools._rate_to_percent(self.tax_rate(tax)),
|
|
'BaseImponible': Decimal(0),
|
|
'CuotaSoportada': Decimal(0),
|
|
}
|
|
else:
|
|
ret = {
|
|
'BaseImponible': self.tax_base(tax),
|
|
}
|
|
if self.specialkey_or_trascendence(invoice) != '02':
|
|
ret['TipoImpositivo'] = tools._rate_to_percent(self.tax_rate(tax))
|
|
ret['CuotaSoportada'] = self.tax_amount(tax)
|
|
if self.tax_equivalence_surcharge_rate(tax):
|
|
ret['TipoRecargoEquivalencia'] = \
|
|
tools._rate_to_percent(self.tax_equivalence_surcharge_rate(
|
|
tax))
|
|
if self.tax_equivalence_surcharge_amount(tax):
|
|
ret['CuotaRecargoEquivalencia'] = \
|
|
self.tax_equivalence_surcharge_amount(tax)
|
|
bieninversion = all(map(lambda w: w in tax.tax.name, (
|
|
'bien', 'inversión')))
|
|
ret['BienInversion'] = 'S' if bieninversion else 'N'
|
|
else:
|
|
ret['PorcentCompensacionREAGYP'] = \
|
|
tools._rate_to_percent(self.tax_rate(tax))
|
|
ret['ImporteCompensacionREAGYP'] = \
|
|
(self.tax_amount(tax))
|
|
return ret
|
|
|
|
def isp_taxes(self, taxes):
|
|
return [tax for tax in taxes if tax.tax.isp]
|