diff --git a/sii/models/basic_models.py b/sii/models/basic_models.py index ce27282..b6dfbc9 100644 --- a/sii/models/basic_models.py +++ b/sii/models/basic_models.py @@ -36,14 +36,17 @@ def __init__(self, state, ref_catastral=False): class Partner: - def __init__(self, name, nif, country, aeat_registered=True): + def __init__(self, name, nif, country, aeat_registered=True, auto_vat_type='00'): self.name = name self.vat = nif self.country_id = country self.aeat_registered = aeat_registered + self.auto_vat_type = auto_vat_type def sii_get_vat_type(self): - return VAT.sii_get_vat_type(self.vat) + return VAT.sii_get_vat_type( + self.vat, self.aeat_registered, self.auto_vat_type + ) class Journal: diff --git a/sii/resource.py b/sii/resource.py index fe42f24..079958b 100644 --- a/sii/resource.py +++ b/sii/resource.py @@ -148,25 +148,19 @@ def get_iva_values(invoice, in_invoice, is_export=False, is_import=False): def get_partner_info(fiscal_partner, in_invoice, nombre_razon=False): - vat_type = fiscal_partner.sii_get_vat_type() + vat_type, auto_vat = fiscal_partner.sii_get_vat_type() contraparte = {} partner_country = fiscal_partner.partner_country if nombre_razon: contraparte['NombreRazon'] = unidecode_str(fiscal_partner.name) + if auto_vat and vat_type == '07' and in_invoice: + vat_type = '02' + if vat_type == '02': - if not fiscal_partner.aeat_registered and not in_invoice: - contraparte['IDOtro'] = { - 'CodigoPais': partner_country.code, - 'IDType': '07', - 'ID': VAT.clean_vat(fiscal_partner.vat) - } - else: - contraparte['NIF'] = VAT.clean_vat(fiscal_partner.vat) + contraparte['NIF'] = VAT.clean_vat(fiscal_partner.vat) else: - if vat_type == '04' and partner_country.is_eu_member: - vat_type = '02' contraparte['IDOtro'] = { 'CodigoPais': partner_country.code, 'IDType': vat_type, @@ -269,7 +263,8 @@ def get_factura_emitida_tipo_desglose(invoice): partner_vat_starts_with_n = ( partner_vat and partner_vat.upper().startswith('N') ) - has_id_otro = invoice.partner_id.sii_get_vat_type() != '02' + id_type, auto_vat = invoice.partner_id.sii_get_vat_type() + has_id_otro = id_type != '02' if has_id_otro or partner_vat_starts_with_n: tipo_desglose = { 'DesgloseTipoOperacion': { diff --git a/sii/utils.py b/sii/utils.py index c705f81..0eab74e 100644 --- a/sii/utils.py +++ b/sii/utils.py @@ -11,7 +11,8 @@ def unidecode_str(s): class FiscalPartner(object): def __init__(self, invoice=None, name=None, vat=None, - aeat_registered=None, partner_country=None + aeat_registered=None, partner_country=None, + auto_vat_type=None ): """ :param invoice: Invoce from take info @@ -33,14 +34,18 @@ def __init__(self, invoice=None, name=None, vat=None, self.vat = invoice.partner_id.vat self.aeat_registered = invoice.partner_id.aeat_registered self.partner_country = invoice.partner_id.country_id or invoice.partner_id.country + self.auto_vat_type = invoice.partner_id.auto_vat_type else: self.name = name self.vat = vat self.aeat_registered = aeat_registered self.partner_country = partner_country + self.auto_vat_type = auto_vat_type def sii_get_vat_type(self): - return VAT.sii_get_vat_type(self.vat) + return VAT.sii_get_vat_type( + self.vat, self.aeat_registered, self.auto_vat_type + ) class VAT: @@ -116,19 +121,27 @@ def is_passport(vat): return False @staticmethod - def sii_get_vat_type(vat): + def sii_get_vat_type(vat, aeat_registered, auto_vat_type): partner_vat = vat + auto_vat = auto_vat_type == '00' + is_nif = VAT.is_dni_vat(partner_vat) is_nie = VAT.is_nie_vat(partner_vat) is_enterprise = VAT.is_enterprise_vat(partner_vat) - if is_nif or is_nie or is_enterprise: - return '02' + + if not auto_vat: + return auto_vat_type, auto_vat + elif is_nif or is_nie or is_enterprise: + if aeat_registered: + return '02', auto_vat + else: + return '07', auto_vat elif VAT.is_passport(partner_vat): - return '03' + return '03', auto_vat elif VAT.is_official_identification_document(partner_vat): - return '04' + return '04', auto_vat else: - return '02' + return '02', auto_vat COUNTRY_CODES = { diff --git a/spec/serialization_spec.py b/spec/serialization_spec.py index 44c1d53..d56645d 100644 --- a/spec/serialization_spec.py +++ b/spec/serialization_spec.py @@ -94,8 +94,8 @@ def group_by_tax_rate(iva_values, in_invoice): with context('en los NIFs involucrados sin fiscal info'): with before.all: os.environ['NIF_TITULAR'] = 'ES12345678T' - os.environ['NIF_CONTRAPARTE'] = 'esES654321P' - os.environ['FISCAL_VAT_CONTRAPARTE'] = 'esES654321P' + os.environ['NIF_CONTRAPARTE'] = 'ES18745529T' + os.environ['FISCAL_VAT_CONTRAPARTE'] = 'ES18745529T' new_data_gen = DataGenerator() nifs_test_invoice = new_data_gen.get_out_invoice(with_fiscal_info=False) @@ -136,8 +136,8 @@ def group_by_tax_rate(iva_values, in_invoice): with context('en los NIFs involucrados con fiscal info'): with before.all: os.environ['NIF_TITULAR'] = 'ES12345678T' - os.environ['NIF_CONTRAPARTE'] = 'esES654321P' - os.environ['FISCAL_VAT_CONTRAPARTE'] = 'esES654321P' + os.environ['NIF_CONTRAPARTE'] = 'ES18745529T' + os.environ['FISCAL_VAT_CONTRAPARTE'] = 'ES18745529T' new_data_gen = DataGenerator() nifs_test_invoice = new_data_gen.get_out_invoice() @@ -524,10 +524,10 @@ def group_by_tax_rate(iva_values, in_invoice): self.emisor_factura['IDOtro']['ID'] ).to(equal(nif_emisor)) - with it('el IDType debe ser "02"'): + with it('el IDType debe ser "04"'): expect( self.emisor_factura['IDOtro']['IDType'] - ).to(equal('02')) + ).to(equal('04')) with it('el CodigoPais debe ser "FR"'): expect( @@ -789,10 +789,10 @@ def group_by_tax_rate(iva_values, in_invoice): self.emisor_factura['IDOtro']['ID'] ).to(equal(nif_emisor)) - with it('el IDType debe ser "02"'): + with it('el IDType debe ser "04"'): expect( self.emisor_factura['IDOtro']['IDType'] - ).to(equal('02')) + ).to(equal('04')) with it('el CodigoPais debe ser "FR"'): expect( @@ -1400,3 +1400,36 @@ def group_by_tax_rate(iva_values, in_invoice): ).to(equal( self.out_refund.tax_line[0].tax_id.amount * 100 )) + + with description('en los datos de una factura emitida'): + with before.all: + self.out_invoice = self.data_gen.get_out_invoice() + self.out_invoice_obj = SII(self.out_invoice).generate_object() + self.factura_emitida = ( + self.out_invoice_obj['SuministroLRFacturasEmitidas'] + ['RegistroLRFacturasEmitidas'] + ) + + with context('en una contraparte con IDType 05'): + with before.all: + new_data_gen = DataGenerator(contraparte_registered=False) + self.out_invoice = new_data_gen.get_out_invoice_partner_id_type_05() + self.nif_contraparte = self.out_invoice.partner_id.vat[2:] + + out_invoice_obj = SII(self.out_invoice).generate_object() + self.contraparte = ( + out_invoice_obj['SuministroLRFacturasEmitidas'] + ['RegistroLRFacturasEmitidas']['FacturaExpedida'] + ['Contraparte'] + ) + + with it('el ID debe ser el NIF de la contraparte'): + expect( + self.contraparte['IDOtro']['ID'] + ).to(equal(self.nif_contraparte)) + + with it('el IDType debe ser "05"'): + expect(self.contraparte['IDOtro']['IDType']).to(equal('05')) + + with it('el CodigoPais debe ser "ES"'): + expect(self.contraparte['IDOtro']['CodigoPais']).to(equal('ES')) diff --git a/spec/testing_data.py b/spec/testing_data.py index 1793577..71002ba 100644 --- a/spec/testing_data.py +++ b/spec/testing_data.py @@ -568,3 +568,61 @@ def get_out_invoice_rescision(self): sii_out_clave_regimen_especial=self.sii_out_clave_regimen_especial, ) return invoice + + def get_out_invoice_partner_id_type_05(self, with_fiscal_info=True): + journal = Journal( + name=u'Factura de Energía Emitida' + ) + spain = Country(code='ES', is_eu_member=False) + partner = Partner( + name=os.environ.get('NOMBRE_CONTRAPARTE', u'Francisco García'), + nif=os.environ.get('NIF_CONTRAPARTE', u'ES12345678Z'), + country=spain, aeat_registered=True, auto_vat_type='05' + ) + if with_fiscal_info: + invoice = Invoice( + invoice_type='out_invoice', + journal_id=journal, + rectificative_type='N', + rectifying_id=False, + number='FEmit{}'.format(self.invoice_number), + partner_id=partner, + fiscal_name=self.fiscal_name, + fiscal_vat=self.fiscal_vat, + address_contact_id=self.address_contact_id, + company_id=self.company, + amount_total=self.amount_total, + amount_untaxed=self.amount_untaxed, + amount_tax=self.amount_tax, + period_id=self.period, + date_invoice=self.date_invoice, + tax_line=self.tax_line, + invoice_line=self.invoice_line, + sii_registered=self.sii_registered, + fiscal_position=self.fiscal_position, + sii_description=self.sii_description, + sii_out_clave_regimen_especial=self.sii_out_clave_regimen_especial, + ) + else: + invoice = Invoice( + invoice_type='out_invoice', + journal_id=journal, + rectificative_type='N', + rectifying_id=False, + number='FEmit{}'.format(self.invoice_number), + partner_id=partner, + address_contact_id=self.address_contact_id, + company_id=self.company, + amount_total=self.amount_total, + amount_untaxed=self.amount_untaxed, + amount_tax=self.amount_tax, + period_id=self.period, + date_invoice=self.date_invoice, + tax_line=self.tax_line, + invoice_line=self.invoice_line, + sii_registered=self.sii_registered, + fiscal_position=self.fiscal_position, + sii_description=self.sii_description, + sii_out_clave_regimen_especial=self.sii_out_clave_regimen_especial, + ) + return invoice