trytond-account_invoice_fac.../template_facturae_3.2.2.xml

397 lines
26 KiB
XML

{% from "template_facturae_macros.xml" import administrative_center, address, contact, registration_data %}
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<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#">
<FileHeader>
<SchemaVersion>3.2.2</SchemaVersion>
<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>
<BatchIdentifier>{{ ('%s%s' % (invoice.company.party.tax_identifier.code, invoice.number))[:70] }}</BatchIdentifier>
<InvoicesCount>1</InvoicesCount>
<TotalInvoicesAmount>
<TotalAmount>{{ Currency.compute(invoice.currency, invoice.total_amount, euro) }}</TotalAmount>
{% 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? #}
<TotalAmount>{{ Currency.compute(invoice.currency, invoice.total_amount, euro) }}</TotalAmount>
{% 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? #}
<TotalAmount>{{ Currency.compute(invoice.currency, invoice.total_amount, euro) }}</TotalAmount>
{% if invoice.currency != euro %}
<EquivalentInEuros>{{ Currency.compute(invoice.currency, invoice.total_amount, euro) }}</EquivalentInEuros>
{% endif %}
</TotalExecutableAmount>
<InvoiceCurrencyCode>{{ invoice.currency.code.upper() }}</InvoiceCurrencyCode>
</Batch>
{# FactoryAssignmentData optional: not supported (factoring not supported) #}
</FileHeader>
<Parties>
<SellerParty>
<TaxIdentification>
<PersonTypeCode>{{ invoice.company.facturae_person_type }}</PersonTypeCode>
<ResidenceTypeCode>{{ invoice.company.facturae_residence_type }}</ResidenceTypeCode>
<TaxIdentificationNumber>{{ invoice.company.party.tax_identifier.code[:30] }}</TaxIdentificationNumber>
</TaxIdentification>
{# Optional. It could be the ID or the code #}
{% if invoice.company.party.code and invoice.company.party.code | length < 10 %}
<PartyIdentification>{{ invoice.company.party.code|int or invoice.company.party.id }}</PartyIdentification>
{% endif %}
{% if invoice.company.oficina_contable or invoice.company.organo_gestor or invoice.company.unidad_tramitadora or invoice.company.organo_proponente %}
<AdministrativeCentres>
{% 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 %}
</AdministrativeCentres>
{% endif %}
<LegalEntity>
<CorporateName>{{ invoice.company.party.name[:80] }}</CorporateName>
{% 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 %}
{{ address(invoice.company.party.addresses[0]) }}
{% endif %}
{% if invoice.company.party.contact_mechanisms %}
{{ contact(invoice.company.party) }}
{% endif %}
</LegalEntity>
</SellerParty>
<BuyerParty>
<TaxIdentification>
<PersonTypeCode>{{ invoice.invoice_address.facturae_person_type }}</PersonTypeCode>
<ResidenceTypeCode>{{ invoice.invoice_address.facturae_residence_type }}</ResidenceTypeCode>
<TaxIdentificationNumber>{{ invoice.party.tax_identifier.code[:30] }}</TaxIdentificationNumber>
</TaxIdentification>
{# Optional. It could be the ID or the code #}
{% 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 %}
<AdministrativeCentres>
{% 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.invoice_address.organo_proponente %}{{ administrative_center(invoice.invoice_address.organo_proponente, '04', invoice.invoice_address.facturae_person_type, invoice.invoice_address) }}{% endif %}
</AdministrativeCentres>
{% endif %}
{% if invoice.invoice_address.facturae_person_type == 'J' %}
<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>
{% 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 %}
</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>
<TaxPeriod>
{# TODO: it is the period or the term (VAT report period?) #}
<StartDate>{{ invoice.credited_invoices[0].move.period.start_date.isoformat() }}</StartDate>
<EndDate>{{ invoice.credited_invoices[0].move.period.end_date.isoformat() }}</EndDate>
</TaxPeriod>
{# 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 #}
{# TODO: InvoiceIssueDate: Nuevo campo para definir la fecha de expedición de la factura rectificada. Valor obligatorio en el supuesto de que la etiqueta CorrectionMethod tome los valores “01” o “02” #}
</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>{{ invoice.currency.code.upper() }}</InvoiceCurrencyCode>
{% if invoice.currency != euro %}
<ExchangeRateDetails>
<ExchangeRate>{{ Invoice.double_up_to_eight(exchange_rate) }}</ExchangeRate>
<ExchangeRateDate>{% if exchange_rate_date %}{{ exchange_rate_date.isoformat() }}{% endif %}</ExchangeRateDate>
</ExchangeRateDetails>
{% endif %}
<TaxCurrencyCode>EUR</TaxCurrencyCode>
<LanguageName>{{ invoice.party_lang[:2] if invoice.party_lang else 'es' }}</LanguageName>
<ReceiverTransactionReference>{{ invoice.reference and invoice.reference[:20] or '' }}</ReceiverTransactionReference>
</InvoiceIssueData>
<TaxesOutputs>
{% for invoice_tax in invoice.taxes_outputs %}
<Tax>
<TaxTypeCode>{{ invoice_tax.tax.report_type }}</TaxTypeCode>
<TaxRate>{{ Invoice.double_up_to_eight(invoice_tax.tax.rate * 100) }}</TaxRate>
<TaxableBase>
<TotalAmount>{{ Invoice.double_up_to_eight(invoice_tax.base) }}</TotalAmount>
{% if invoice.currency != euro %}
<EquivalentInEuros>{{ Invoice.double_up_to_eight(invoice_tax.base) }}</EquivalentInEuros>
{% endif %}
</TaxableBase>
<TaxAmount>
<TotalAmount>{{ Invoice.double_up_to_eight(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? #}
<EquivalenceSurcharge>{{ (invoice_tax.tax.rate * 100).quantize(Decimal('0.01')) }}</EquivalenceSurcharge>
<EquivalenceSurchargeAmount>
<TotalAmount>{{ Currency.compute(invoice.currency, invoice_tax.amount, euro) }}</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>
<TaxRate>{{ Invoice.double_up_to_eight(invoice_tax.tax.rate * 100) }}</TaxRate>
<TaxableBase>
<TotalAmount>{{ Currency.compute(invoice.currency, invoice_tax.base, euro) }}</TotalAmount>
{% if invoice.currency != euro %}
<EquivalentInEuros>{{ Currency.compute(invoice.currency, invoice_tax.base, euro) }}</EquivalentInEuros>
{% endif %}
</TaxableBase>
<TaxAmount>
<TotalAmount>{{ Currency.compute(invoice.currency, invoice_tax.amount, euro) }}</TotalAmount>
{% if invoice.currency != euro %}
<EquivalentInEuros>{{ Currency.compute(invoice.currency, invoice_tax.amount, euro) }}</EquivalentInEuros>
{% endif %}
</TaxAmount>
</Tax>
{% endfor %}
</TaxesWithheld>
{% endif %}
<InvoiceTotals>
<TotalGrossAmount>{{ Invoice.double_up_to_eight(invoice.untaxed_amount) }}</TotalGrossAmount>
{# TODO: GeneralDiscounts and TotalGeneralDiscounts (account_invoice_discount_global) not supported #}
{# TODO: GeneralSurcharges and TotalGeneralSurcharges not supported #}
<TotalGrossAmountBeforeTaxes>{{ Invoice.double_up_to_eight(invoice.untaxed_amount) }}</TotalGrossAmountBeforeTaxes>
<TotalTaxOutputs>{{ Invoice.double_up_to_eight(invoice.taxes_outputs | sum(attribute='amount', start=Decimal(0))) }}</TotalTaxOutputs>
<TotalTaxesWithheld>{{ Invoice.double_up_to_eight(invoice.taxes_withheld | sum(attribute='amount', start=Decimal(0))) }}</TotalTaxesWithheld>
<InvoiceTotal>{{ Invoice.double_up_to_eight(invoice.total_amount) }}</InvoiceTotal>
{# TODO: optional, not supported
- Subsidies
- PaymentsOnAccount, TotalPaymentsOnAccount
- ReimbursableExpenses, TotalReimbursableExpenses (suplidos?)
- TotalFinancialExpenses (account_payment_type_cost?)
- AmountsWithheld
#}
<TotalOutstandingAmount>{{ Invoice.double_up_to_eight(invoice.total_amount) }}</TotalOutstandingAmount>
<TotalExecutableAmount>{{ Invoice.double_up_to_eight(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)
- FileReference, FileDate
- SequenceNumber
- DeliveryNotesReferences (account_invoice_stock)
- TransactionDate
- Extensions
#}
<ReceiverTransactionReference>{{ line.facturae_receiver_transaction_reference }}</ReceiverTransactionReference>
<ItemDescription>{{ line.facturae_item_description[:2500] }}</ItemDescription>
<Quantity>{{ line.quantity }}</Quantity>
<UnitOfMeasure>{{ UOM_CODE2TYPE.get(line.unit.symbol, '05') if line.unit else '05' }}</UnitOfMeasure>
<UnitPriceWithoutTax>{{ Invoice.double_up_to_eight(line.unit_price) }}</UnitPriceWithoutTax>
<TotalCost>{{ Invoice.double_up_to_eight(line.amount) }}</TotalCost>
{# TODO: optional, not supported
- DiscountsAndRebates (account_invoice_discount)
- Charges
#}
<GrossAmount>{{ Invoice.double_up_to_eight(line.amount) }}</GrossAmount>
{% if line.taxes_withheld %}
<TaxesWithheld>
{% for line_tax in invoice.taxes_withheld %}
<Tax>
<TaxTypeCode>{{ line_tax.tax.report_type }}</TaxTypeCode>
<TaxRate>{{ Invoice.double_up_to_eight(line_tax.tax.rate * 100) }}</TaxRate>
<TaxableBase>
<TotalAmount>{{ Currency.compute(invoice.currency, line.amount, euro) }}</TotalAmount>
{% if invoice.currency != euro %}
<EquivalentInEuros>{{ Currency.compute(invoice.currency, line.amount, euro) }}</EquivalentInEuros>
{% endif %}
</TaxableBase>
<TaxAmount>
<TotalAmount>{{ Currency.compute(invoice.currency, line.amount * line_tax.tax.rate, euro) }}</TotalAmount>
{% 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>
<TaxRate>{{ Currency.compute(invoice.currency, line_tax.tax.rate * 100, euro) }}</TaxRate>
<TaxableBase>
<TotalAmount>{{ Currency.compute(invoice.currency, line.amount, euro) }}</TotalAmount>
{% if invoice.currency != euro %}
<EquivalentInEuros>{{ Currency.compute(invoice.currency, line.amount, euro) }}</EquivalentInEuros>
{% endif %}
</TaxableBase>
<TaxAmount>
<TotalAmount>{{ Currency.compute(invoice.currency, line.amount * line_tax.tax.rate, euro) }}</TotalAmount>
{% 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? #}
<EquivalenceSurcharge>{{ (line_tax.tax.rate * 100).quantize(Decimal('0.01')) }}</EquivalenceSurcharge>
<EquivalenceSurchargeAmount>
<TotalAmount>{{ Currency.compute(invoice.currency, line.amount * line_tax.tax.rate, euro) }}</TotalAmount>
{% 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.facturae_start_date %}
<LineItemPeriod>
<StartDate>{{ line.facturae_start_date.isoformat() }}</StartDate>
<EndDate>{{ line.facturae_end_date.isoformat() }}</EndDate>
</LineItemPeriod>
{% endif %}
{% if line.taxes_additional_line_item_information or line.note %}
<AdditionalLineItemInformation>
{% if line.taxes_additional_line_item_information %}
{% for key, description in line.taxes_additional_line_item_information.items() %}
{{ key }} = {{ description }}
{% endfor %}
{% elif line.note %}
{{ line.note }}
{% endif %}
</AdditionalLineItemInformation>
{% endif %}
{# TODO: SpecialTaxableEvent not supported #}
{% if line.product and line.product.code %}
<ArticleCode>{{ line.facturae_article_code[:20] }}</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>
<InstallmentAmount>{{ Currency.compute(invoice.currency, ((move_line.debit - move_line.credit) | abs).quantize(Decimal('0.01')), euro) }}</InstallmentAmount>
<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[:60]
- CollectionAdditionalInformation[:2500]
- RegulatoryReportingData (for international operations)
- DebitReconciliationReference[:60]
#}
{% 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>
<AdditionalData>
{# optional, not supported:
- RelatedInvoice[:40]
- RelatedDocuments
- Extensions
#}
<InvoiceAdditionalInformation> # [:2500]
Factura generada con Tryton (https://www.tryton.org)
</InvoiceAdditionalInformation>
</AdditionalData>
</Invoice>
</Invoices>
{# Extensions optional, not supported #}
</namespace:Facturae>