2023-10-04 11:24:12 +02:00
{% from "template_facturae_macros.xml" import administrative_center, address, contact, registration_data %}
2018-11-07 16:47:03 +01:00
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
2023-10-04 11:24:12 +02:00
<namespace:Facturae xmlns:namespace= "http://www.facturae.gob.es/formato/Versiones/Facturaev3_2_2.xml" xmlns:namespace2= "http://uri.etsi.org/01903/v1.2.2#" xmlns:namespace3= "http://www.w3.org/2000/09/xmldsig#" >
2018-09-13 13:28:44 +02:00
<FileHeader >
2023-10-04 11:24:12 +02:00
<SchemaVersion > 3.2.2</SchemaVersion>
2018-09-13 13:28:44 +02:00
<Modality > I</Modality>
{# The invoice is signed by Issuer (the company, only supported out invoices) #}
<InvoiceIssuerType > EM</InvoiceIssuerType>
{# As InvoiceIssuerType != TE, ThirdParty element is not generated #}
<Batch >
2018-09-13 18:38:06 +02:00
<BatchIdentifier > {{ ('%s%s' % (invoice.company.party.tax_identifier.code, invoice.number))[:70] }}</BatchIdentifier>
2018-09-13 13:28:44 +02:00
<InvoicesCount > 1</InvoicesCount>
<TotalInvoicesAmount >
2023-10-04 11:24:12 +02:00
<TotalAmount > {{ Currency.compute(invoice.currency, invoice.total_amount, euro) }}</TotalAmount>
2018-09-13 13:28:44 +02:00
{% if invoice.currency != euro %}
<EquivalentInEuros > {{ Currency.compute(invoice.currency, invoice.total_amount, euro) }}</EquivalentInEuros>
{% endif %}
</TotalInvoicesAmount>
<TotalOutstandingAmount >
{# TODO: it must to get amount_to_pay? #}
2023-10-04 11:24:12 +02:00
<TotalAmount > {{ Currency.compute(invoice.currency, invoice.total_amount, euro) }}</TotalAmount>
2018-09-13 13:28:44 +02:00
{% if invoice.currency != euro %}
<EquivalentInEuros > {{ Currency.compute(invoice.currency, invoice.total_amount, euro) }}</EquivalentInEuros>
{% endif %}
</TotalOutstandingAmount>
<TotalExecutableAmount >
{# TODO: it must to get amount_to_pay? #}
2023-10-04 11:24:12 +02:00
<TotalAmount > {{ Currency.compute(invoice.currency, invoice.total_amount, euro) }}</TotalAmount>
2018-09-13 13:28:44 +02:00
{% if invoice.currency != euro %}
<EquivalentInEuros > {{ Currency.compute(invoice.currency, invoice.total_amount, euro) }}</EquivalentInEuros>
{% endif %}
</TotalExecutableAmount>
2023-10-04 11:24:12 +02:00
<InvoiceCurrencyCode > {{ invoice.currency.code.upper() }}</InvoiceCurrencyCode>
2018-09-13 13:28:44 +02:00
</Batch>
{# FactoryAssignmentData optional: not supported (factoring not supported) #}
</FileHeader>
<Parties >
<SellerParty >
<TaxIdentification >
2023-10-04 11:24:12 +02:00
<PersonTypeCode > {{ invoice.company.facturae_person_type }}</PersonTypeCode>
<ResidenceTypeCode > {{ invoice.company.facturae_residence_type }}</ResidenceTypeCode>
2018-09-13 18:38:06 +02:00
<TaxIdentificationNumber > {{ invoice.company.party.tax_identifier.code[:30] }}</TaxIdentificationNumber>
2018-09-13 13:28:44 +02:00
</TaxIdentification>
{# Optional. It could be the ID or the code #}
2023-12-13 13:13:58 +01:00
<PartyIdentification > {{ invoice.company.party.id_electronet }}</PartyIdentification>
2023-10-04 11:24:12 +02:00
{% if invoice.company.oficina_contable or invoice.company.organo_gestor or invoice.company.unidad_tramitadora or invoice.company.organo_proponente %}
2018-09-13 13:28:44 +02:00
<AdministrativeCentres >
2023-10-04 11:24:12 +02:00
{% if invoice.company.oficina_contable %}{{ administrative_center(invoice.company.oficina_contable, '01', invoice.company.facturae_person_type, invoice.company.party.address_get('invoice')) }}{% endif %}
{% if invoice.company.organo_gestor %}{{ administrative_center(invoice.company.organo_gestor, '02', invoice.company.facturae_person_type, invoice.company.party.address_get('invoice')) }}{% endif %}
{% if invoice.company.unidad_tramitadora %}{{ administrative_center(invoice.company.unidad_tramitadora, '03', invoice.company.facturae_person_type, invoice.company.party.address_get('invoice')) }}{% endif %}
{% if invoice.company.organo_proponente %}{{ administrative_center(invoice.company.organo_proponente, '04', invoice.company.facturae_person_type, invoice.company.party.address_get('invoice')) }}{% endif %}
2018-09-13 13:28:44 +02:00
</AdministrativeCentres>
2023-10-04 11:24:12 +02:00
{% endif %}
2018-09-13 13:28:44 +02:00
<LegalEntity >
<CorporateName > {{ invoice.company.party.name[:80] }}</CorporateName>
2023-10-04 11:24:12 +02:00
{% if invoice.company.party.trade_name %}
<TradeName > {{ invoice.company.party.trade_name[:40] }}</TradeName>
{% endif %}
{% if invoice.company %}
{{ registration_data(invoice.company) }}
{% endif %}
{% if invoice.company.party.addresses %}
2018-09-13 13:28:44 +02:00
{{ address(invoice.company.party.addresses[0]) }}
2023-10-04 11:24:12 +02:00
{% endif %}
2018-09-13 13:28:44 +02:00
{% if invoice.company.party.contact_mechanisms %}
{{ contact(invoice.company.party) }}
{% endif %}
</LegalEntity>
</SellerParty>
<BuyerParty >
<TaxIdentification >
2023-10-04 11:24:12 +02:00
<PersonTypeCode > {{ invoice.invoice_address.facturae_person_type }}</PersonTypeCode>
<ResidenceTypeCode > {{ invoice.invoice_address.facturae_residence_type }}</ResidenceTypeCode>
2018-09-13 18:38:06 +02:00
<TaxIdentificationNumber > {{ invoice.party.tax_identifier.code[:30] }}</TaxIdentificationNumber>
2018-09-13 13:28:44 +02:00
</TaxIdentification>
{# Optional. It could be the ID or the code #}
2023-10-04 11:24:12 +02:00
{% if invoice.party.code and invoice.party.code | length < 10 % }
<PartyIdentification > {{ invoice.party.code|int or invoice.party.id }}</PartyIdentification>
{% endif %}
{% if invoice.invoice_address.oficina_contable or invoice.invoice_address.organo_gestor or invoice.invoice_address.unidad_tramitadora or invoice.invoice_address.organo_proponente %}
2018-09-13 13:28:44 +02:00
<AdministrativeCentres >
2023-10-04 11:24:12 +02:00
{% if invoice.invoice_address.oficina_contable %}{{ administrative_center(invoice.invoice_address.oficina_contable, '01', invoice.invoice_address.facturae_person_type, invoice.invoice_address) }}{% endif %}
{% if invoice.invoice_address.organo_gestor %}{{ administrative_center(invoice.invoice_address.organo_gestor, '02', invoice.invoice_address.facturae_person_type, invoice.invoice_address) }}{% endif %}
{% if invoice.invoice_address.unidad_tramitadora %}{{ administrative_center(invoice.invoice_address.unidad_tramitadora, '03', invoice.invoice_address.facturae_person_type, invoice.invoice_address) }}{% endif %}
{% if invoice.sale_point_code %}{{ administrative_center(invoice.sale_point_code, '04', invoice.invoice_address.facturae_person_type, invoice.invoice_address) }}{% endif %}
2018-09-13 13:28:44 +02:00
</AdministrativeCentres>
2023-10-04 11:24:12 +02:00
{% endif %}
{% if invoice.invoice_address.facturae_person_type == 'J' %}
2018-09-13 13:28:44 +02:00
<LegalEntity >
<CorporateName > {{ invoice.party.name and invoice.party.name[:80] or invoice.party.code[:80] }}</CorporateName>
{% if invoice.party.trade_name %}
<TradeName > {{ invoice.party.trade_name[:40] }}</TradeName>
{% endif %}
{{ address(invoice.invoice_address) }}
{% if invoice.party.contact_mechanisms %}
{{ contact(invoice.party) }}
{% endif %}
</LegalEntity>
2023-10-04 11:24:12 +02:00
{% else %}
<Individual >
<Name > {{ invoice.party.name and invoice.party.name.split(' ', 2)[0][:40] or invoice.party.code[:40] }}</Name>
<FirstSurname > {{ invoice.party.name and invoice.party.name.split(' ', 2)[1][:40] }}</FirstSurname>
{% if invoice.party.name.split(' ') | length > 2 %}
<SecondSurname > {{ invoice.party.name and invoice.party.name.split(' ', 2)[2][:40] }}</SecondSurname>
{% endif %}
{{ address(invoice.invoice_address) }}
{% if invoice.party.contact_mechanisms %}
{{ contact(invoice.party) }}
{% endif %}
</Individual>
{% endif %}
2018-09-13 13:28:44 +02:00
</BuyerParty>
</Parties>
<Invoices >
<Invoice >
<InvoiceHeader >
<InvoiceNumber > {{ invoice.number[:20] }}</InvoiceNumber>
{# InvoiceSeriesCode optional: not supported #}
{# TODO: FA (Factura Simplificada) not supported #}
<InvoiceDocumentType > FC</InvoiceDocumentType>
{# TODO: Types not supported:
- OC (O. Recapitulativa)
- CO (Duplicado Original)
- CR, (D. Rectificativa)
- CC (D. Recapitulativa)
#}
<InvoiceClass > {{ 'OO' if not invoice.credited_invoices else 'OR' }}</InvoiceClass>
{% if invoice.credited_invoices %}
<Corrective >
<InvoiceNumber > {{ invoice.credited_invoices and invoice.credited_invoices[0].number[:20] }}</InvoiceNumber>
{# InvoiceSeriesCode Optional: not supported #}
<ReasonCode > {{ invoice.rectificative_reason_code }}</ReasonCode>
<ReasonDescription > {{ invoice.rectificative_reason_spanish_description }}</ReasonDescription>
{# TODO: Methods not supported:
- 02 (solo se
anotan los detalles ya rectificados)
- 03 (Rectificación por
descuento por volumen de operaciones durante un periodo)
- 04 (Autorizadas por la Agencia Tributaria)
#}
<CorrectionMethod > 01</CorrectionMethod>
<CorrectionMethodDescription > Rectificación Íntegra</CorrectionMethodDescription>
{# AdditionalReasonDescription optional: not supported #}
</Corrective>
{% endif %}
</InvoiceHeader>
<InvoiceIssueData >
<IssueDate > {{ invoice.invoice_date.isoformat() }}</IssueDate>
{# OperationDate required only if is different to IssueDate, but we consider OperatinDate==invoice_date: not supported #}
{# PlaceOfIssue optional: not supported #}
{# InvoicingPeriod required only for Recapitulativas or temporary service: not supported #}
<InvoiceCurrencyCode > EUR</InvoiceCurrencyCode>
<TaxCurrencyCode > EUR</TaxCurrencyCode>
<LanguageName > es</LanguageName>
</InvoiceIssueData>
<TaxesOutputs >
{% for invoice_tax in invoice.taxes_outputs %}
<Tax >
<TaxTypeCode > {{ invoice_tax.tax.report_type }}</TaxTypeCode>
2019-02-14 11:19:22 +01:00
<TaxRate > {{ Decimal(invoice_tax.tax.rate * 100).quantize(Decimal('0.01')) }}</TaxRate>
2018-09-13 13:28:44 +02:00
<TaxableBase >
<TotalAmount > {{ invoice_tax.base }}</TotalAmount>
{% if invoice.currency != euro %}
<EquivalentInEuros > {{ Currency.compute(invoice.currency, invoice_tax.base, euro) }}</EquivalentInEuros>
{% endif %}
</TaxableBase>
<TaxAmount >
<TotalAmount > {{ invoice_tax.amount }}</TotalAmount>
{% if invoice.currency != euro %}
<EquivalentInEuros > {{ Currency.compute(invoice.currency, invoice_tax.amount, euro) }}</EquivalentInEuros>
{% endif %}
</TaxAmount>
{# TODO: special taxes not supported
- SpecialTaxableBase
- SpecialTaxAmount
#}
{% if invoice_tax.tax.recargo_equivalencia %}
{# TODO: EquivalenceSurchace must to have its own Tax entry or it must to go to the IVA line? TaxRate == EquivalenceSurcharge and TaxAmount == EquivalenceSurchargeAmount? #}
2019-02-14 11:19:22 +01:00
<EquivalenceSurcharge > {{ Decimal(invoice_tax.tax.rate * 100).quantize(Decimal('0.01')) }}</EquivalenceSurcharge>
2018-09-13 13:28:44 +02:00
<EquivalenceSurchargeAmount >
<TotalAmount > {{ invoice_tax.amount }}</TotalAmount>
{% if invoice.currency != euro %}
<EquivalentInEuros > {{ Currency.compute(invoice.currency, invoice_tax.amount, euro) }}</EquivalentInEuros>
{% endif %}
</EquivalenceSurchargeAmount>
{% endif %}
</Tax>
{% endfor %}
</TaxesOutputs>
{% if invoice.taxes_withheld %}
<TaxesWithheld >
{% for invoice_tax in invoice.taxes_withheld %}
<Tax >
<TaxTypeCode > {{ invoice_tax.tax.report_type }}</TaxTypeCode>
2019-02-14 11:19:22 +01:00
<TaxRate > {{ Decimal(invoice_tax.tax.rate * 100).quantize(Decimal('0.01')) }}</TaxRate>
2018-09-13 13:28:44 +02:00
<TaxableBase >
<TotalAmount > {{ invoice_tax.base }}</TotalAmount>
{% if invoice.currency != euro %}
<EquivalentInEuros > {{ Currency.compute(invoice.currency, invoice_tax.base, euro) }}</EquivalentInEuros>
{% endif %}
</TaxableBase>
<TaxAmount >
<TotalAmount > {{ invoice_tax.amount }}</TotalAmount>
{% if invoice.currency != euro %}
<EquivalentInEuros > {{ Currency.compute(invoice.currency, invoice_tax.amount, euro) }}</EquivalentInEuros>
{% endif %}
</TaxAmount>
</Tax>
{% endfor %}
</TaxesWithheld>
{% endif %}
<InvoiceTotals >
<TotalGrossAmount > {{ invoice.untaxed_amount }}</TotalGrossAmount>
{# TODO: GeneralDiscounts and TotalGeneralDiscounts (account_invoice_discount_global) not supported #}
{# TODO: GeneralSurcharges and TotalGeneralSurcharges not supported #}
<TotalGrossAmountBeforeTaxes > {{ invoice.untaxed_amount }}</TotalGrossAmountBeforeTaxes>
<TotalTaxOutputs > {{ invoice.taxes_outputs | sum(attribute='amount', start=Decimal('0.00')) }}</TotalTaxOutputs>
<TotalTaxesWithheld > {{ invoice.taxes_withheld | sum(attribute='amount', start=Decimal('0.00')) }}</TotalTaxesWithheld>
<InvoiceTotal > {{ invoice.total_amount }}</InvoiceTotal>
{# TODO: optional, not supported
- Subsidies
- PaymentsOnAccount, TotalPaymentsOnAccount
- ReimbursableExpenses, TotalReimbursableExpenses (suplidos?)
- TotalFinancialExpenses (account_payment_type_cost?)
- AmountsWithheld
#}
<TotalOutstandingAmount > {{ invoice.total_amount }}</TotalOutstandingAmount>
<TotalExecutableAmount > {{ invoice.total_amount }}</TotalExecutableAmount>
</InvoiceTotals>
<Items >
{% for line in invoice.lines if line.type == 'line' %}
<InvoiceLine >
{# TODO: optional, not supported
- Issuer/ReceiverContractReference, Issuer/ReceiverContractDate (contract)
- Issuer/ReceiverTransactionReference, Issuer/ReceiverTransactionDate (sale, contract...)
- FileReference, FileDate
- SequenceNumber
- DeliveryNotesReferences (account_invoice_stock)
- LineItemPeriod
- TransactionDate
- Extensions
#}
2018-11-07 16:47:03 +01:00
{% if line.shipments %}
{% for shipment in line.shipments %}
2019-01-07 10:47:12 +01:00
<ReceiverTransactionReference > {{ shipment.origin_reference or '' }}</ReceiverTransactionReference>
2018-11-07 16:47:03 +01:00
{% endfor %}
<DeliveryNotesReferences >
{% for shipment in line.shipments %}
<DeliveryNote >
2019-01-07 10:47:12 +01:00
<DeliveryNoteNumber > {{ shipment.number or '' }}</DeliveryNoteNumber>
2018-11-07 16:47:03 +01:00
</DeliveryNote>
{% endfor %}
</DeliveryNotesReferences>
{% endif %}
2018-09-13 13:28:44 +02:00
<ItemDescription > {{ line.description and line.description[:2500] or '' }}</ItemDescription>
<Quantity > {{ line.quantity }}</Quantity>
<UnitOfMeasure > {{ UOM_CODE2TYPE.get(line.unit.symbol, '05') if line.unit else '05' }}</UnitOfMeasure>
2019-02-14 11:19:22 +01:00
<UnitPriceWithoutTax > {{ Decimal(line.unit_price).quantize(Decimal('0.000001')) }}</UnitPriceWithoutTax>
<TotalCost > {{ Decimal(line.amount).quantize(Decimal('0.000001')) }}</TotalCost>
2018-09-13 13:28:44 +02:00
{# TODO: optional, not supported
- DiscountsAndRebates (account_invoice_discount)
- Charges
#}
2019-02-14 11:19:22 +01:00
<GrossAmount > {{ Decimal(line.amount).quantize(Decimal('0.000001')) }}</GrossAmount>
2018-09-13 13:28:44 +02:00
{% if line.taxes_withheld %}
<TaxesWithheld >
{% for line_tax in invoice.taxes_withheld %}
<Tax >
<TaxTypeCode > {{ line_tax.tax.report_type }}</TaxTypeCode>
2019-02-14 11:19:22 +01:00
<TaxRate > {{ Decimal(line_tax.tax.rate * 100).quantize(Decimal('0.01')) }}</TaxRate>
2018-09-13 13:28:44 +02:00
<TaxableBase >
2019-02-14 11:19:22 +01:00
<TotalAmount > {{ Decimal(line.amount).quantize(Decimal('0.01')) }}</TotalAmount>
2018-09-13 13:28:44 +02:00
{% if invoice.currency != euro %}
<EquivalentInEuros > {{ Currency.compute(invoice.currency, line.amount, euro) }}</EquivalentInEuros>
{% endif %}
</TaxableBase>
<TaxAmount >
2019-02-14 11:19:22 +01:00
<TotalAmount > {{ Decimal(line.amount * line_tax.tax.rate).quantize(Decimal('0.01')) }}</TotalAmount>
2018-09-13 13:28:44 +02:00
{% if invoice.currency != euro %}
<EquivalentInEuros > {{ Currency.compute(invoice.currency, line.amount * line_tax.tax.rate, euro) }}</EquivalentInEuros>
{% endif %}
</TaxAmount>
</Tax>
{% endfor %}
</TaxesWithheld>
{% endif %}
<TaxesOutputs >
{% for line_tax in line.taxes_outputs %}
<Tax >
<TaxTypeCode > {{ line_tax.tax.report_type }}</TaxTypeCode>
2019-02-14 11:19:22 +01:00
<TaxRate > {{ Decimal(line_tax.tax.rate * 100).quantize(Decimal('0.01')) }}</TaxRate>
2018-09-13 13:28:44 +02:00
<TaxableBase >
2019-02-14 11:19:22 +01:00
<TotalAmount > {{ Decimal(line.amount).quantize(Decimal('0.01')) }}</TotalAmount>
2018-09-13 13:28:44 +02:00
{% if invoice.currency != euro %}
<EquivalentInEuros > {{ Currency.compute(invoice.currency, line.amount, euro) }}</EquivalentInEuros>
{% endif %}
</TaxableBase>
<TaxAmount >
2019-02-14 11:19:22 +01:00
<TotalAmount > {{ Decimal(line.amount * line_tax.tax.rate).quantize(Decimal('0.01')) }}</TotalAmount>
2018-09-13 13:28:44 +02:00
{% if invoice.currency != euro %}
<EquivalentInEuros > {{ Currency.compute(invoice.currency, line.amount * line_tax.tax.rate, euro) }}</EquivalentInEuros>
{% endif %}
</TaxAmount>
{# TODO: special taxes not supported
- SpecialTaxableBase
- SpecialTaxAmount
#}
{% if line_tax.tax.recargo_equivalencia %}
{# TODO: EquivalenceSurchace must to have its own Tax entry or it must to go to the IVA line? TaxRate == EquivalenceSurcharge and TaxAmount == EquivalenceSurchargeAmount? #}
2019-02-14 11:19:22 +01:00
<EquivalenceSurcharge > {{ Decimal(line_tax.tax.rate * 100).quantize(Decimal('0.01')) }}</EquivalenceSurcharge>
2018-09-13 13:28:44 +02:00
<EquivalenceSurchargeAmount >
2019-02-14 11:19:22 +01:00
<TotalAmount > {{ Decimal(line.amount * line_tax.tax.rate).quantize(Decimal('0.01')) }}</TotalAmount>
2018-09-13 13:28:44 +02:00
{% if invoice.currency != euro %}
<EquivalentInEuros > {{ Currency.compute(invoice.currency, line.amount * line_tax.tax.rate, euro) }}</EquivalentInEuros>
{% endif %}
</EquivalenceSurchargeAmount>
{% endif %}
</Tax>
{% endfor %}
</TaxesOutputs>
{% if line.taxes_additional_line_item_information %}
<AdditionalLineItemInformation >
{% for key, description in line.taxes_additional_line_item_information.items() %}
{{ key }} = {{ description }}
{% endfor %}
</AdditionalLineItemInformation>
{% endif %}
{# TODO: SpecialTaxableEvent not supported #}
{% if line.product and line.product.code %}
<ArticleCode > {{ line.product.code }}</ArticleCode>
{% endif %}
</InvoiceLine>
{% endfor %}
</Items>
{% if invoice.payment_details %}
<PaymentDetails >
{% for move_line in invoice.payment_details %}
<Installment >
<InstallmentDueDate > {{ move_line.maturity_date.isoformat() }}</InstallmentDueDate>
2019-02-14 11:19:22 +01:00
<InstallmentAmount > {{ Decimal((move_line.debit - move_line.credit) | abs).quantize(Decimal('0.01')) }}</InstallmentAmount>
2018-09-13 13:28:44 +02:00
<PaymentMeans > {{ move_line.payment_type.facturae_type }}</PaymentMeans>
{% if move_line.payment_type.facturae_type == '04' %}
<AccountToBeCredited >
<IBAN > {% for number in (move_line.bank_account.numbers|selectattr('type', 'equalto', 'iban')) %}{% if loop.first %}{{ number.number_compact }}{% endif %}{% endfor %}</IBAN>
{# Unnecessary if IBAN is supplied: AccountNumber, BankCode, BranchCode, BranchInSpainAddress, OverseasBranchAddress, BIC #}
</AccountToBeCredited>
{% elif move_line.payment_type.facturae_type == '02' %}
<AccountToBeDebited >
<IBAN > {% for number in (move_line.bank_account.numbers|selectattr('type', 'equalto', 'iban')) %}{% if loop.first %}{{ number.number_compact }}{% endif %}{% endfor %}</IBAN>
{# Unnecessary if IBAN is supplied: AccountNumber, BankCode, BranchCode, BranchInSpainAddress, OverseasBranchAddress, BIC #}
</AccountToBeDebited>
{# optional, not supported:
- PaymentReconciliationReference
- CollectionAdditionalInformation
- RegulatoryReportingData (for international operations)
- DebitReconciliationReference
#}
{% endif %}
</Installment>
{% endfor %}
</PaymentDetails>
{% endif %}
<LegalLiterals >
{% for inv_tax in invoice.taxes %}
{% if inv_tax.tax and inv_tax.tax.report_description %}
<LegalReference > {{ inv_tax.tax.report_description[:250] }}</LegalReference>
{% endif %}
{% endfor %}
</LegalLiterals>
</Invoice>
</Invoices>
{# Extensions optional, not supported #}
</namespace:Facturae>