[ADD] l10n_es_edi_facturae: Add Facturae governmental EDI
Add an implementation to allow companies to use the Facturae governmental EDI, by generating and signing the XML closes odoo/odoo#108350 Task: task-2793440 Signed-off-by: Laurent Smet <las@odoo.com>
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
import csv
|
||||
|
||||
from odoo.tools import file_open
|
||||
from . import models
|
||||
from . import wizard
|
||||
|
||||
def _edit_tax_types(env, template_data):
|
||||
"""
|
||||
Applies all existing tax l10n_es_edi_facturae_tax_type field to their proper value if any link between tax and their template is found
|
||||
"""
|
||||
concerned_company_ids = [
|
||||
company.id
|
||||
for company in env.companies
|
||||
if company.chart_template and company.chart_template.startswith('es_')
|
||||
]
|
||||
if not concerned_company_ids:
|
||||
return
|
||||
current_taxes = env['account.tax'].search([('company_id', 'in', concerned_company_ids)])
|
||||
if not current_taxes:
|
||||
return
|
||||
xmlid2tax = {
|
||||
xml_id.split('.')[1].split('_', maxsplit=1)[1]: env['account.tax'].browse(record)
|
||||
for record, xml_id in current_taxes.get_external_id().items() if xml_id
|
||||
}
|
||||
for xmlid, values in template_data.items():
|
||||
# Only update the tax_type fields
|
||||
oldtax = xmlid2tax.get(xmlid)
|
||||
if oldtax and oldtax.l10n_es_edi_facturae_tax_type != values.get('l10n_es_edi_facturae_tax_type'):
|
||||
oldtax.l10n_es_edi_facturae_tax_type = values.get('l10n_es_edi_facturae_tax_type')
|
||||
|
||||
def _l10n_es_edi_facturae_post_init_hook(env):
|
||||
"""
|
||||
We need to replace the existing spanish taxes following the template so the new fields are set properly
|
||||
"""
|
||||
if env['account.tax'].search_count([('country_id', '=', env.ref('base.es').id)], limit=1):
|
||||
with file_open('l10n_es_edi_facturae/data/template/account.tax-es_common.csv') as template_file:
|
||||
template_data = {record['id']: record['l10n_es_edi_facturae_tax_type'] for record in csv.DictReader(template_file)}
|
||||
_edit_tax_types(env, template_data)
|
||||
@@ -0,0 +1,42 @@
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
{
|
||||
'name': 'Spain - Facturae EDI',
|
||||
'version': '1.0',
|
||||
'category': 'Accounting/Localizations/EDI',
|
||||
'website': 'https://www.facturae.gob.es/face/Paginas/FACE.aspx',
|
||||
'description': """
|
||||
This module create the Facturae file required to send the invoices information to the General State Administrations.
|
||||
It allows the export and signature of the signing of Facturae files.
|
||||
The current version of Facturae supported is the 3.2.1
|
||||
|
||||
for more informations, see https://www.facturae.gob.es/face/Paginas/FACE.aspx
|
||||
""",
|
||||
'depends': [
|
||||
'l10n_es',
|
||||
],
|
||||
'data': [
|
||||
'data/uom.uom.csv',
|
||||
'data/facturae_templates.xml',
|
||||
'data/signature_templates.xml',
|
||||
|
||||
'security/ir.model.access.csv',
|
||||
'security/l10n_es_edi_certificate.xml',
|
||||
|
||||
'views/l10n_es_edi_facturae_views.xml',
|
||||
'views/res_company_views.xml',
|
||||
'views/account_tax_views.xml',
|
||||
'views/uom_uom_views.xml',
|
||||
'views/account_menuitem.xml',
|
||||
'views/account_move_send_views.xml',
|
||||
|
||||
'wizard/account_move_reversal_view.xml',
|
||||
],
|
||||
'demo': [
|
||||
'demo/l10n_es_edi_facturae_demo.xml',
|
||||
],
|
||||
'post_init_hook': '_l10n_es_edi_facturae_post_init_hook',
|
||||
'installable': True,
|
||||
'auto_install': True,
|
||||
'license': 'LGPL-3',
|
||||
}
|
||||
@@ -0,0 +1,295 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data>
|
||||
<!-- Sub-template used for every instance of AddressType -->
|
||||
<template id="address_type">
|
||||
<t t-if="partner_country_code == 'ESP'">
|
||||
<AddressInSpain>
|
||||
<Address t-out="', '.join(val for val in (partner.street, partner.street2) if val)"/>
|
||||
<PostCode t-out="str(partner.zip)"/>
|
||||
<Town t-out="partner.city"/>
|
||||
<Province t-out="partner.state_id.name if partner.state_id else partner.country_id.name"/>
|
||||
<CountryCode t-out="partner_country_code"/>
|
||||
</AddressInSpain>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<OverseasAddress>
|
||||
<Address t-out="', '.join(val for val in (partner.street, partner.street2) if val)"/>
|
||||
<PostCodeAndTown t-out="' '.join(var for var in (str(partner.zip), partner.city) if var)"/>
|
||||
<Province t-out="partner.state_id.name if partner.state_id else partner.country_id.name"/>
|
||||
<CountryCode t-out="partner_country_code"/>
|
||||
</OverseasAddress>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
<!-- Sub-template used for every instance of ContactDetails -->
|
||||
<template id="contact_details_type">
|
||||
<ContactDetails>
|
||||
<Telephone t-out="partner_phone"/>
|
||||
<WebAddress t-out="partner.website"/>
|
||||
<ElectronicMail t-out="partner.email"/>
|
||||
</ContactDetails>
|
||||
</template>
|
||||
|
||||
<!-- Sub-template used for every instance of LegalEntityType -->
|
||||
<template id="legal_entity_type">
|
||||
<LegalEntity>
|
||||
<CorporateName t-out="partner.name"/>
|
||||
<TradeName t-out="partner.display_name"/>
|
||||
<t t-call="l10n_es_edi_facturae.address_type"/>
|
||||
<t t-call="l10n_es_edi_facturae.contact_details_type"/>
|
||||
</LegalEntity>
|
||||
</template>
|
||||
|
||||
<!-- Sub-template used for every instance of IndividualType -->
|
||||
<template id="individual_type">
|
||||
<Individual>
|
||||
<Name t-out="partner_name.get('firstname')"/>
|
||||
<FirstSurname t-out="partner_name.get('surname')"/>
|
||||
<SecondSurname t-out="partner_name.get('surname2')"/>
|
||||
<t t-call="l10n_es_edi_facturae.address_type"/>
|
||||
<t t-call="l10n_es_edi_facturae.contact_details_type"/>
|
||||
</Individual>
|
||||
</template>
|
||||
|
||||
<!-- Sub-template used for every instance of TaxIdentificationType -->
|
||||
<template id="tax_identification_type">
|
||||
<TaxIdentification>
|
||||
<PersonTypeCode t-out="'J' if partner.is_company else 'F'"/>
|
||||
<ResidenceTypeCode t-out="partner.l10n_es_edi_facturae_residence_type"/>
|
||||
<TaxIdentificationNumber t-out="partner.vat"/>
|
||||
</TaxIdentification>
|
||||
</template>
|
||||
|
||||
<!-- Sub-template used for every instance of BusinessType -->
|
||||
<template id="business_type">
|
||||
<t t-call="l10n_es_edi_facturae.tax_identification_type"/>
|
||||
<t t-if="partner.is_company">
|
||||
<t t-call="l10n_es_edi_facturae.legal_entity_type"/>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<t t-call="l10n_es_edi_facturae.individual_type"/>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
<!-- Sub-template used for every instance of TaxType -->
|
||||
<template id="tax_type">
|
||||
<Tax>
|
||||
<TaxTypeCode t-out="tax['tax_record'].l10n_es_edi_facturae_tax_type"/>
|
||||
<TaxRate t-out="tax['TaxRate']"/>
|
||||
<TaxableBase>
|
||||
<TotalAmount t-out="float_repr(refund_multiplier*tax['TaxableBase']['TotalAmount'], file_currency.decimal_places)"/>
|
||||
<EquivalentInEuros t-if="need_conversion" t-out="float_repr(refund_multiplier*tax['TaxableBase']['EquivalentInEuros'], eur.decimal_places)"/>
|
||||
</TaxableBase>
|
||||
<TaxAmount t-if="tax.get('TaxAmount')">
|
||||
<TotalAmount t-out="float_repr(refund_multiplier*tax['TaxAmount']['TotalAmount'], file_currency.decimal_places)"/>
|
||||
<EquivalentInEuros t-if="need_conversion" t-out="float_repr(refund_multiplier*tax['TaxAmount']['EquivalentInEuros'], eur.decimal_places)"/>
|
||||
</TaxAmount>
|
||||
<SpecialTaxableBase t-if="tax.get('SpecialTaxableBase')">
|
||||
<TotalAmount t-out="float_repr(refund_multiplier*tax['SpecialTaxableBase']['TotalAmount'], file_currency.decimal_places)"/>
|
||||
<EquivalentInEuros t-if="need_conversion" t-out="float_repr(refund_multiplier*tax['SpecialTaxableBase']['EquivalentInEuros'], eur.decimal_places)"/>
|
||||
</SpecialTaxableBase>
|
||||
<SpecialTaxAmount t-if="tax.get('SpecialTaxAmount')">
|
||||
<TotalAmount t-out="float_repr(refund_multiplier*tax['SpecialTaxAmount']['TotalAmount'], file_currency.decimal_places)"/>
|
||||
<EquivalentInEuros t-if="need_conversion" t-out="float_repr(refund_multiplier*tax['SpecialTaxAmount']['EquivalentInEuros'], eur.decimal_places)"/>
|
||||
</SpecialTaxAmount>
|
||||
<EquivalenceSurcharge t-out="tax.get('EquivalenceSurcharge')"/>
|
||||
<EquivalenceSurchargeAmount t-if="tax.get('EquivalenceSurchargeAmount')">
|
||||
<TotalAmount t-out="float_repr(refund_multiplier*tax['EquivalenceSurchargeAmount']['TotalAmount'], file_currency.decimal_places)"/>
|
||||
<EquivalentInEuros t-if="need_conversion" t-out="float_repr(refund_multiplier*tax['EquivalenceSurchargeAmount']['EquivalentInEuros'], eur.decimal_places)"/>
|
||||
</EquivalenceSurchargeAmount>
|
||||
</Tax>
|
||||
</template>
|
||||
|
||||
<!-- Sub-template used for every instance of InvoiceLineType -->
|
||||
<template id="invoice_line_type">
|
||||
<InvoiceLine>
|
||||
<FileReference t-out="line.get('FileReference')"/>
|
||||
<FileDate t-out="line.get('FileDate')"/>
|
||||
<SequenceNumber t-out="line.get('SequenceNumber')"/>
|
||||
<ItemDescription t-out="line['ItemDescription']"/>
|
||||
<Quantity t-out="line['Quantity']"/>
|
||||
<UnitOfMeasure t-out="line.get('UnitOfMeasure')"/>
|
||||
<UnitPriceWithoutTax t-out="float_repr(refund_multiplier*line['UnitPriceWithoutTax'], file_currency.decimal_places)"/>
|
||||
<TotalCost t-out="float_repr(refund_multiplier*line['TotalCost'], file_currency.decimal_places)"/>
|
||||
<DiscountsAndRebates t-if="line.get('DiscountsAndRebates')">
|
||||
<t t-foreach="line['DiscountsAndRebates']" t-as="discount">
|
||||
<Discount>
|
||||
<DiscountReason t-out="discount['DiscountReason']"/>
|
||||
<DiscountRate t-out="discount.get('DiscountRate')"/>
|
||||
<DiscountAmount t-out="float_repr(refund_multiplier*discount['DiscountAmount'], file_currency.decimal_places)"/>
|
||||
</Discount>
|
||||
</t>
|
||||
</DiscountsAndRebates>
|
||||
<Charges t-if="line.get('Charges')">
|
||||
<t t-foreach="line['Charges']" t-as="charge">
|
||||
<Charge>
|
||||
<ChargeReason t-out="charge['ChargeReason']"/>
|
||||
<ChargeRate t-out="charge.get('ChargeRate')"/>
|
||||
<ChargeAmount t-out="float_repr(refund_multiplier*charge['ChargeAmount'], file_currency.decimal_places)"/>
|
||||
</Charge>
|
||||
</t>
|
||||
</Charges>
|
||||
<GrossAmount t-out="float_repr(refund_multiplier*line['GrossAmount'], file_currency.decimal_places)"/>
|
||||
<TaxesOutputs>
|
||||
<t t-foreach="line['TaxesOutputs']" t-as="tax"><t t-call="l10n_es_edi_facturae.tax_type"/></t>
|
||||
</TaxesOutputs>
|
||||
<TaxesWithheld t-if="line.get('TaxesWithheld')">
|
||||
<t t-foreach="line['TaxesWithheld']" t-as="tax"><t t-call="l10n_es_edi_facturae.tax_type"/></t>
|
||||
</TaxesWithheld>
|
||||
<LineItemPeriod t-if="line.get('LineItemPeriod')">
|
||||
<StartDate t-out="line['LineItemPeriod']['StartDate']"/>
|
||||
<EndDate t-out="line['LineItemPeriod']['EndDate']"/>
|
||||
</LineItemPeriod>
|
||||
<TransactionDate t-out="line.get('TransactionDate')"/>
|
||||
</InvoiceLine>
|
||||
</template>
|
||||
|
||||
<template id="corrective_type">
|
||||
<Corrective>
|
||||
<InvoiceNumber t-out="invoice['Corrective']['refunded_invoice_record'].name"/>
|
||||
<ReasonCode t-out="invoice['Corrective']['ReasonCode']"/>
|
||||
<ReasonDescription t-out="invoice['Corrective']['Reason']"/>
|
||||
<TaxPeriod>
|
||||
<StartDate t-out="invoice['Corrective']['TaxPeriod']['StartDate']"/>
|
||||
<EndDate t-out="invoice['Corrective']['TaxPeriod']['EndDate']"/>
|
||||
</TaxPeriod>
|
||||
<CorrectionMethod>01</CorrectionMethod>
|
||||
<CorrectionMethodDescription>Rectificación modelo íntegro.</CorrectionMethodDescription>
|
||||
</Corrective>
|
||||
</template>
|
||||
|
||||
<!-- Sub-template used for every instance of InvoiceType -->
|
||||
<template id="invoice_type">
|
||||
<Invoice>
|
||||
<InvoiceHeader>
|
||||
<InvoiceNumber t-out="invoice['invoice_record'].name"/>
|
||||
<InvoiceDocumentType t-out="invoice['InvoiceDocumentType']"/>
|
||||
<InvoiceClass t-out="invoice['InvoiceClass']"/>
|
||||
<t t-if="refund_multiplier == -1" t-call="l10n_es_edi_facturae.corrective_type"/>
|
||||
</InvoiceHeader>
|
||||
<InvoiceIssueData>
|
||||
<IssueDate t-out="invoice['invoice_record'].invoice_date.isoformat()"/>
|
||||
<OperationDate t-out="invoice['InvoiceIssueData'].get('OperationDate')"/>
|
||||
<InvoicingPeriod t-if="invoice['InvoiceIssueData'].get('InvoicingPeriod')">
|
||||
<StartDate t-out="invoice['InvoiceIssueData']['InvoicingPeriod']['StartDate']"/>
|
||||
<EndDate t-out="invoice['InvoiceIssueData']['InvoicingPeriod']['EndDate']"/>
|
||||
</InvoicingPeriod>
|
||||
<InvoiceCurrencyCode t-out="invoice['invoice_currency'].name"/>
|
||||
<ExchangeRateDetails t-if="invoice['InvoiceIssueData'].get('ExchangeRateDetails')">
|
||||
<ExchangeRate t-out="invoice['InvoiceIssueData']['ExchangeRate']"/>
|
||||
<ExchangeRateDate t-out="(invoice['invoice_record'].invoice_date or invoice['invoice_record'].date).isoformat()"/>
|
||||
</ExchangeRateDetails>
|
||||
<TaxCurrencyCode t-out="invoice['invoice_currency'].name"/>
|
||||
<LanguageName t-out="invoice['InvoiceIssueData']['LanguageName']"/>
|
||||
</InvoiceIssueData>
|
||||
<TaxesOutputs>
|
||||
<t t-foreach="invoice['TaxOutputs']" t-as="tax"><t t-call="l10n_es_edi_facturae.tax_type"/></t>
|
||||
</TaxesOutputs>
|
||||
<TaxesWithheld t-if="invoice.get('TaxesWithheld')">
|
||||
<t t-foreach="invoice['TaxesWithheld']" t-as="tax"><t t-call="l10n_es_edi_facturae.tax_type"/></t>
|
||||
</TaxesWithheld>
|
||||
<InvoiceTotals>
|
||||
<TotalGrossAmount t-out="float_repr(refund_multiplier*invoice['TotalGrossAmount'], file_currency.decimal_places)"/>
|
||||
<GeneralDiscounts t-if="invoice.get('GeneralDiscounts')">
|
||||
<t t-foreach="invoice['GeneralDiscounts']" t-as="discount">
|
||||
<Discount>
|
||||
<DiscountReason t-out="discount['DiscountReason']"/>
|
||||
<DiscountRate t-out="discount.get('DiscountRate')"/>
|
||||
<DiscountAmount t-out="float_repr(refund_multiplier*discount['DiscountAmount'], file_currency.decimal_places)"/>
|
||||
</Discount>
|
||||
</t>
|
||||
</GeneralDiscounts>
|
||||
<GeneralSurcharges t-if="invoice.get('GeneralSurcharges')">
|
||||
<t t-foreach="invoice['GeneralSurcharges']" t-as="charge">
|
||||
<Charge>
|
||||
<ChargeReason t-out="charge['ChargeReason']"/>
|
||||
<ChargeRate t-out="charge.get('ChargeRate')"/>
|
||||
<ChargeAmount t-out="float_repr(refund_multiplier*charge['ChargeAmount'], file_currency.decimal_places)"/>
|
||||
</Charge>
|
||||
</t>
|
||||
</GeneralSurcharges>
|
||||
<TotalGeneralDiscounts t-if="invoice.get('TotalGeneralDiscounts')" t-out="float_repr(refund_multiplier*invoice['TotalGeneralDiscounts'], file_currency.decimal_places)"/>
|
||||
<TotalGeneralSurcharges t-if="invoice.get('TotalGeneralSurcharges')" t-out="float_repr(refund_multiplier*invoice['TotalGeneralSurcharges'], file_currency.decimal_places)"/>
|
||||
<TotalGrossAmountBeforeTaxes t-out="float_repr(refund_multiplier*invoice['TotalGrossAmountBeforeTaxes'], file_currency.decimal_places)"/>
|
||||
<TotalTaxOutputs t-out="float_repr(refund_multiplier*invoice['TotalTaxOutputs'], file_currency.decimal_places)"/>
|
||||
<TotalTaxesWithheld t-out="float_repr(refund_multiplier*invoice['TotalTaxesWithheld'], file_currency.decimal_places)"/>
|
||||
<InvoiceTotal t-out="float_repr(refund_multiplier*invoice['InvoiceTotal'], file_currency.decimal_places)"/>
|
||||
<PaymentsOnAccount t-if="invoice.get('PaymentsOnAccount')">
|
||||
<t t-foreach="invoice['PaymentsOnAccount']" t-as="payment">
|
||||
<PaymentOnAccount>
|
||||
<PaymentOnAccountDate t-out="payment['PaymentOnAccountDate']"/>
|
||||
<PaymentOnAccountAmount t-out="float_repr(refund_multiplier*payment['PaymentOnAccountAmount'], file_currency.decimal_places)"/>
|
||||
</PaymentOnAccount>
|
||||
</t>
|
||||
</PaymentsOnAccount>
|
||||
<TotalFinancialExpenses t-if="invoice.get('ReimbursableExpensesAmount')" t-out="float_repr(refund_multiplier*invoice['ReimbursableExpensesAmount'], file_currency.decimal_places)"/>
|
||||
<TotalOutstandingAmount t-out="float_repr(refund_multiplier*invoice['TotalOutstandingAmount'], file_currency.decimal_places)"/>
|
||||
<TotalPaymentsOnAccount t-if="invoice.get('TotalPaymentsOnAccount')" t-out="float_repr(refund_multiplier*invoice['TotalPaymentsOnAccount'], file_currency.decimal_places)"/>
|
||||
<AmountsWithheld t-if="invoice.get('AmountsWithheld')">
|
||||
<WithholdingReason t-out="invoice['AmountsWithheld']['WithholdingReason']"/>
|
||||
<WithholdingRate t-out="invoice['AmountsWithheld'].get('WithholdingRate')"/>
|
||||
<WithholdingAmount t-out="float_repr(refund_multiplier*invoice['AmountsWithheld']['WithholdingAmount'], file_currency.decimal_places)"/>
|
||||
</AmountsWithheld>
|
||||
<TotalExecutableAmount t-out="float_repr(refund_multiplier*invoice['TotalExecutableAmount'], file_currency.decimal_places)"/>
|
||||
<TotalReimbursableExpenses t-if="invoice.get('TotalReimbursableExpenses')" t-out="float_repr(refund_multiplier*invoice['TotalReimbursableExpenses'], file_currency.decimal_places)"/>
|
||||
</InvoiceTotals>
|
||||
<Items>
|
||||
<t t-foreach="invoice['Items']" t-as="line"><t t-call="l10n_es_edi_facturae.invoice_line_type"/></t>
|
||||
</Items>
|
||||
<LegalLiterals t-if="invoice.get('LegalLiterals')">
|
||||
<t t-foreach="invoice['LegalLiterals']" t-as="reference"><LegalReference t-out="reference"/></t>
|
||||
</LegalLiterals>
|
||||
</Invoice>
|
||||
</template>
|
||||
|
||||
<!-- Main template used for the EDI -->
|
||||
<template id="account_invoice_facturae_export">
|
||||
<fac:Facturae xmlns:fac="http://www.facturae.es/Facturae/2014/v3.2.1/Facturae">
|
||||
<FileHeader>
|
||||
<SchemaVersion>3.2.1</SchemaVersion>
|
||||
<Modality t-out="Modality"/>
|
||||
<InvoiceIssuerType t-out="'EM' if is_outstanding else 'RE'"/>
|
||||
<Batch>
|
||||
<BatchIdentifier t-out="BatchIdentifier"/>
|
||||
<InvoicesCount t-out="InvoicesCount"/>
|
||||
<TotalInvoicesAmount>
|
||||
<TotalAmount t-out="float_repr(refund_multiplier*TotalInvoicesAmount['TotalAmount'], file_currency.decimal_places)"/>
|
||||
<EquivalentInEuros t-if="conversion_needed" t-out="float_repr(refund_multiplier*TotalInvoicesAmount['EquivalentInEuros'], eur.decimal_places)"/>
|
||||
</TotalInvoicesAmount>
|
||||
<TotalOutstandingAmount>
|
||||
<TotalAmount t-out="float_repr(refund_multiplier*TotalOutstandingAmount['TotalAmount'], file_currency.decimal_places)"/>
|
||||
<EquivalentInEuros t-if="conversion_needed" t-out="float_repr(refund_multiplier*TotalOutstandingAmount['EquivalentInEuros'], eur.decimal_places)"/>
|
||||
</TotalOutstandingAmount>
|
||||
<TotalExecutableAmount>
|
||||
<TotalAmount t-out="float_repr(refund_multiplier*TotalExecutableAmount['TotalAmount'], file_currency.decimal_places)"/>
|
||||
<EquivalentInEuros t-if="conversion_needed" t-out="float_repr(refund_multiplier*TotalExecutableAmount['EquivalentInEuros'], eur.decimal_places)"/>
|
||||
</TotalExecutableAmount>
|
||||
<InvoiceCurrencyCode t-out="InvoiceCurrencyCode"/>
|
||||
</Batch>
|
||||
</FileHeader>
|
||||
<Parties>
|
||||
<SellerParty>
|
||||
<t t-call="l10n_es_edi_facturae.business_type">
|
||||
<t t-set="partner" t-value="self_party if is_outstanding else other_party"/>
|
||||
<t t-set="partner_country_code" t-value="self_party_country_code if is_outstanding else other_party_country_code"/>
|
||||
<t t-set="partner_phone" t-value="False if is_outstanding else other_party_phone"/>
|
||||
<t t-set="partner_name" t-value="{} if is_outstanding else other_party_name"/>
|
||||
</t>
|
||||
</SellerParty>
|
||||
<BuyerParty>
|
||||
<t t-call="l10n_es_edi_facturae.business_type">
|
||||
<t t-set="partner" t-value="other_party if is_outstanding else self_party"/>
|
||||
<t t-set="partner_country_code" t-value="other_party_country_code if is_outstanding else self_party_country_code"/>
|
||||
<t t-set="partner_phone" t-value="other_party_phone if is_outstanding else False"/>
|
||||
<t t-set="partner_name" t-value="other_party_name if is_outstanding else {}"/>
|
||||
</t>
|
||||
</BuyerParty>
|
||||
</Parties>
|
||||
<Invoices>
|
||||
<t t-foreach="Invoices" t-as="invoice"><t t-call="l10n_es_edi_facturae.invoice_type"/></t>
|
||||
</Invoices>
|
||||
</fac:Facturae>
|
||||
</template>
|
||||
</data>
|
||||
</odoo>
|
||||
@@ -0,0 +1,95 @@
|
||||
<odoo>
|
||||
<data>
|
||||
<template id="template_xades_signature">
|
||||
<ds:Signature t-att-Id="signature_id" xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
|
||||
<ds:SignedInfo>
|
||||
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
|
||||
<ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
|
||||
<ds:Reference t-att-Id="reference_uri" Type="http://www.w3.org/2000/09/xmldsig#Object" URI="">
|
||||
<ds:Transforms>
|
||||
<ds:Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
|
||||
<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
|
||||
<ds:Transform Algorithm="http://www.w3.org/TR/1999/REC-xpath-19991116">
|
||||
<ds:XPath>not(ancestor-or-self::ds:Signature)</ds:XPath>
|
||||
</ds:Transform>
|
||||
</ds:Transforms>
|
||||
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
|
||||
<ds:DigestValue></ds:DigestValue>
|
||||
</ds:Reference>
|
||||
<ds:Reference Type="http://uri.etsi.org/01903#SignedProperties" t-attf-URI="##{sigproperties_id}">
|
||||
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
|
||||
<ds:DigestValue></ds:DigestValue>
|
||||
</ds:Reference>
|
||||
<ds:Reference t-attf-URI="##{keyinfo_id}">
|
||||
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
|
||||
<ds:DigestValue></ds:DigestValue>
|
||||
</ds:Reference>
|
||||
</ds:SignedInfo>
|
||||
<ds:SignatureValue></ds:SignatureValue>
|
||||
<ds:KeyInfo t-att-Id="keyinfo_id">
|
||||
<ds:X509Data>
|
||||
<ds:X509Certificate t-out="x509_certificate"/>
|
||||
</ds:X509Data>
|
||||
<ds:KeyValue>
|
||||
<ds:RSAKeyValue>
|
||||
<ds:Modulus t-out="public_modulus"/>
|
||||
<ds:Exponent t-out="public_exponent"/>
|
||||
</ds:RSAKeyValue>
|
||||
</ds:KeyValue>
|
||||
</ds:KeyInfo>
|
||||
<ds:Object>
|
||||
<xades:QualifyingProperties xmlns:xades="http://uri.etsi.org/01903/v1.3.2#" t-attf-Target="##{signature_id}">
|
||||
<xades:SignedProperties t-att-Id="sigproperties_id">
|
||||
<xades:SignedSignatureProperties>
|
||||
<xades:SigningTime t-out="iso_now"/>
|
||||
<xades:SigningCertificateV2>
|
||||
<xades:Cert>
|
||||
<xades:CertDigest>
|
||||
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
|
||||
<ds:DigestValue t-out="sigcertif_digest"/>
|
||||
</xades:CertDigest>
|
||||
<xades:IssuerSerial>
|
||||
<ds:X509IssuerName t-out="x509_issuer_description"/>
|
||||
<ds:X509SerialNumber t-out="x509_serial_number"/>
|
||||
</xades:IssuerSerial>
|
||||
</xades:Cert>
|
||||
</xades:SigningCertificateV2>
|
||||
<xades:SignaturePolicyIdentifier>
|
||||
<xades:SignaturePolicyId>
|
||||
<xades:SigPolicyId>
|
||||
<xades:Identifier t-out="sigpolicy_url"/>
|
||||
<xades:Description t-out="sigpolicy_description"/>
|
||||
</xades:SigPolicyId>
|
||||
<xades:SigPolicyHash>
|
||||
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
|
||||
<ds:DigestValue>a/vDoueJq9zxWGCFwdsXdlXtkFSEek4XVtmlQCEDaE8=</ds:DigestValue>
|
||||
</xades:SigPolicyHash>
|
||||
<xades:SigPolicyQualifiers>
|
||||
<xades:SigPolicyQualifier>
|
||||
<xades:SPURI t-out="sigpolicy_url"/>
|
||||
</xades:SigPolicyQualifier>
|
||||
</xades:SigPolicyQualifiers>
|
||||
</xades:SignaturePolicyId>
|
||||
</xades:SignaturePolicyIdentifier>
|
||||
</xades:SignedSignatureProperties>
|
||||
<xades:SignedDataObjectProperties>
|
||||
<xades:DataObjectFormat t-attf-ObjectReference="##{reference_uri}">
|
||||
<xades:Description/>
|
||||
<xades:ObjectIdentifier>
|
||||
<!-- Identifier below is Uniform Resource Number for MimeType "text/xml" (no specific version) -->
|
||||
<!-- 1.2.840.10003.5: see http://www.oid-info.com/cgi-bin/display?oid=1.2.840.10003.5&a=display -->
|
||||
<!-- 109.10: see https://www.loc.gov/z3950/agency/defns/oids.html#5 -->
|
||||
<xades:Identifier Qualifier="OIDAsURN">urn:oid:1.2.840.10003.5.109.10</xades:Identifier>
|
||||
<xades:Description/>
|
||||
</xades:ObjectIdentifier>
|
||||
<xades:MimeType>text/xml</xades:MimeType>
|
||||
<xades:Encoding/>
|
||||
</xades:DataObjectFormat>
|
||||
</xades:SignedDataObjectProperties>
|
||||
</xades:SignedProperties>
|
||||
</xades:QualifyingProperties>
|
||||
</ds:Object>
|
||||
</ds:Signature>
|
||||
</template>
|
||||
</data>
|
||||
</odoo>
|
||||
@@ -0,0 +1,89 @@
|
||||
"id","l10n_es_edi_facturae_tax_type"
|
||||
"l10n_es.account_tax_template_s_iva21b","01"
|
||||
"l10n_es.account_tax_template_p_iva4_bc","01"
|
||||
"l10n_es.account_tax_template_p_iva4_ibc","01"
|
||||
"l10n_es.account_tax_template_p_iva4_sc","01"
|
||||
"l10n_es.account_tax_template_p_iva4_sp_ex","01"
|
||||
"l10n_es.account_tax_template_p_iva4_bi","01"
|
||||
"l10n_es.account_tax_template_p_iva4_ibi","01"
|
||||
"l10n_es.account_tax_template_p_iva10_bc","01"
|
||||
"l10n_es.account_tax_template_p_iva10_ibc","01"
|
||||
"l10n_es.account_tax_template_p_iva10_sc","01"
|
||||
"l10n_es.account_tax_template_p_iva10_sp_ex","01"
|
||||
"l10n_es.account_tax_template_p_iva10_bi","01"
|
||||
"l10n_es.account_tax_template_p_iva10_ibi","01"
|
||||
"l10n_es.account_tax_template_p_iva21_bc","01"
|
||||
"l10n_es.account_tax_template_p_iva21_ibc","01"
|
||||
"l10n_es.account_tax_template_p_iva21_sc","01"
|
||||
"l10n_es.account_tax_template_p_iva21_sp_ex","01"
|
||||
"l10n_es.account_tax_template_p_iva21_bi","01"
|
||||
"l10n_es.account_tax_template_p_iva21_ibi","01"
|
||||
"l10n_es.account_tax_template_s_iva4b","01"
|
||||
"l10n_es.account_tax_template_s_iva0_e","01"
|
||||
"l10n_es.account_tax_template_s_iva4s","01"
|
||||
"l10n_es.account_tax_template_s_iva_e","01"
|
||||
"l10n_es.account_tax_template_s_iva10b","01"
|
||||
"l10n_es.account_tax_template_s_iva10s","01"
|
||||
"l10n_es.account_tax_template_s_iva21s","01"
|
||||
"l10n_es.account_tax_template_s_iva21isp","01"
|
||||
"l10n_es.account_tax_template_p_iva4_ic_bc","01"
|
||||
"l10n_es.account_tax_template_p_iva4_sp_in","01"
|
||||
"l10n_es.account_tax_template_p_iva4_ic_bi","01"
|
||||
"l10n_es.account_tax_template_p_iva10_ic_bc","01"
|
||||
"l10n_es.account_tax_template_p_iva10_sp_in","01"
|
||||
"l10n_es.account_tax_template_p_iva10_ic_bi","01"
|
||||
"l10n_es.account_tax_template_p_iva21_ic_bc","01"
|
||||
"l10n_es.account_tax_template_p_iva21_sp_in","01"
|
||||
"l10n_es.account_tax_template_p_iva21_ic_bi","01"
|
||||
"l10n_es.account_tax_template_s_iva0_ic","01"
|
||||
"l10n_es.account_tax_template_s_iva0_sp_i","01"
|
||||
"l10n_es.account_tax_template_p_iva0_ns_b","01"
|
||||
"l10n_es.account_tax_template_p_iva0_ns","01"
|
||||
"l10n_es.account_tax_template_s_iva_ns_b","01"
|
||||
"l10n_es.account_tax_template_s_iva_ns","01"
|
||||
"l10n_es.account_tax_template_s_req05","05"
|
||||
"l10n_es.account_tax_template_s_req014","05"
|
||||
"l10n_es.account_tax_template_s_req52","05"
|
||||
"l10n_es.account_tax_template_p_req05","05"
|
||||
"l10n_es.account_tax_template_p_req014","05"
|
||||
"l10n_es.account_tax_template_p_req52","05"
|
||||
"l10n_es.account_tax_template_s_iva0_isp","01"
|
||||
"l10n_es.account_tax_template_s_irpf19a","04"
|
||||
"l10n_es.account_tax_template_p_irpf19a","04"
|
||||
"l10n_es.account_tax_template_s_iva0","01"
|
||||
"l10n_es.account_tax_template_p_iva0_bc","01"
|
||||
"l10n_es.account_tax_template_s_irpf195a","04"
|
||||
"l10n_es.account_tax_template_p_irpf195a","04"
|
||||
"l10n_es.account_tax_template_s_irpf20a","04"
|
||||
"l10n_es.account_tax_template_p_irpf20a","04"
|
||||
"l10n_es.account_tax_template_s_irpf21a","04"
|
||||
"l10n_es.account_tax_template_p_irpf21a","04"
|
||||
"l10n_es.account_tax_template_s_irpf21","04"
|
||||
"l10n_es.account_tax_template_s_iva0_ns","01"
|
||||
"l10n_es.account_tax_template_p_irpf21p","04"
|
||||
"l10n_es.account_tax_template_s_irpf20","04"
|
||||
"l10n_es.account_tax_template_p_irpf20","04"
|
||||
"l10n_es.account_tax_template_s_irpf24","04"
|
||||
"l10n_es.account_tax_template_p_irpf24","04"
|
||||
"l10n_es.account_tax_template_s_irpf15","04"
|
||||
"l10n_es.account_tax_template_p_irpf15","04"
|
||||
"l10n_es.account_tax_template_s_irpf18","04"
|
||||
"l10n_es.account_tax_template_p_irpf18","04"
|
||||
"l10n_es.account_tax_template_s_irpf19","04"
|
||||
"l10n_es.account_tax_template_p_irpf19","04"
|
||||
"l10n_es.account_tax_template_s_irpf9","04"
|
||||
"l10n_es.account_tax_template_p_irpf9","04"
|
||||
"l10n_es.account_tax_template_s_irpf7","04"
|
||||
"l10n_es.account_tax_template_p_irpf7","04"
|
||||
"l10n_es.account_tax_template_s_irpf2","04"
|
||||
"l10n_es.account_tax_template_p_irpf2","04"
|
||||
"l10n_es.account_tax_template_s_irpf1","04"
|
||||
"l10n_es.account_tax_template_p_irpf1","04"
|
||||
"l10n_es.account_tax_template_p_iva4_isp","01"
|
||||
"l10n_es.account_tax_template_p_iva4_isp_bi","01"
|
||||
"l10n_es.account_tax_template_p_iva10_isp","01"
|
||||
"l10n_es.account_tax_template_p_iva10_isp_bi","01"
|
||||
"l10n_es.account_tax_template_p_iva21_isp","01"
|
||||
"l10n_es.account_tax_template_p_iva21_isp_bi","01"
|
||||
"l10n_es.account_tax_template_p_iva12_agr","01"
|
||||
"l10n_es.account_tax_template_p_iva105_gan","01"
|
||||
|
@@ -0,0 +1,14 @@
|
||||
"id","l10n_es_edi_facturae_uom_code"
|
||||
uom.product_uom_unit,01
|
||||
uom.product_uom_dozen,18
|
||||
uom.product_uom_hour,02
|
||||
uom.product_uom_meter,25
|
||||
uom.product_uom_millimeter,26
|
||||
uom.product_uom_km,22
|
||||
uom.product_uom_cm,16
|
||||
uom.uom_square_meter,05
|
||||
uom.product_uom_litre,04
|
||||
uom.product_uom_cubic_meter,33
|
||||
uom.product_uom_kgm,03
|
||||
uom.product_uom_gram,21
|
||||
uom.product_uom_ton,05
|
||||
|
Binary file not shown.
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo>
|
||||
<data>
|
||||
<record id="face_certificate_demo" model="l10n_es_edi_facturae.certificate">
|
||||
<field name="password">test</field>
|
||||
<field name="content" type="base64" file="l10n_es_edi_facturae/demo/certificate_demo.pfx"/>
|
||||
<field name="company_id" eval="ref('l10n_es.demo_company_es')"/>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
@@ -0,0 +1,620 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * l10n_es_edi_facturae
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server 16.3alpha1+e\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2023-05-12 10:00+0000\n"
|
||||
"PO-Revision-Date: 2023-05-12 10:00+0000\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Plural-Forms: \n"
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model_terms:ir.ui.view,arch_db:l10n_es_edi_facturae.corrective_type
|
||||
msgid "01"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model_terms:ir.ui.view,arch_db:l10n_es_edi_facturae.account_invoice_facturae_export
|
||||
msgid "3.2.1"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__uom_uom__l10n_es_edi_facturae_uom_code__27
|
||||
msgid "6-Packs"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model,name:l10n_es_edi_facturae.model_account_move_reversal
|
||||
msgid "Account Move Reversal"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model,name:l10n_es_edi_facturae.model_account_move_send
|
||||
msgid "Account Move Send"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__uom_uom__l10n_es_edi_facturae_uom_code__10
|
||||
msgid "Bags"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__uom_uom__l10n_es_edi_facturae_uom_code__08
|
||||
msgid "Barrels"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__uom_uom__l10n_es_edi_facturae_uom_code__17
|
||||
msgid "Bins"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__uom_uom__l10n_es_edi_facturae_uom_code__12
|
||||
msgid "Bottles, non-protected, cylindrical"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__uom_uom__l10n_es_edi_facturae_uom_code__06
|
||||
msgid "Boxes"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__uom_uom__l10n_es_edi_facturae_uom_code__24
|
||||
msgid "Bunches"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__account_move__l10n_es_edi_facturae_reason_code__80
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__account_move_reversal__l10n_es_edi_facturae_reason_code__80
|
||||
msgid "Calculation of output quotas"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__account_move__l10n_es_edi_facturae_reason_code__81
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__account_move_reversal__l10n_es_edi_facturae_reason_code__81
|
||||
msgid "Calculation of withholding taxes"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__uom_uom__l10n_es_edi_facturae_uom_code__13
|
||||
msgid "Canisters"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__uom_uom__l10n_es_edi_facturae_uom_code__23
|
||||
msgid "Cans, rectangular"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__uom_uom__l10n_es_edi_facturae_uom_code__11
|
||||
msgid "Carboys, non-protected"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__uom_uom__l10n_es_edi_facturae_uom_code__19
|
||||
msgid "Cases"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__uom_uom__l10n_es_edi_facturae_uom_code__15
|
||||
msgid "Centiliters"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__uom_uom__l10n_es_edi_facturae_uom_code__16
|
||||
msgid "Centimeters"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.ui.menu,name:l10n_es_edi_facturae.menu_l10n_es_edi_facturae_root_certificates
|
||||
msgid "Certificates"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.actions.act_window,name:l10n_es_edi_facturae.l10n_es_edi_facturae_certificate_action
|
||||
msgid "Certificates for Facturae EDI invoices on Spain"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model,name:l10n_es_edi_facturae.model_res_company
|
||||
msgid "Companies"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields,field_description:l10n_es_edi_facturae.field_l10n_es_edi_facturae_certificate__company_id
|
||||
msgid "Company"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model,name:l10n_es_edi_facturae.model_res_partner
|
||||
msgid "Contact"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model_terms:ir.actions.act_window,help:l10n_es_edi_facturae.l10n_es_edi_facturae_certificate_action
|
||||
msgid "Create the first certificate"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields,field_description:l10n_es_edi_facturae.field_l10n_es_edi_facturae_certificate__create_uid
|
||||
msgid "Created by"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields,field_description:l10n_es_edi_facturae.field_l10n_es_edi_facturae_certificate__create_date
|
||||
msgid "Created on"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__uom_uom__l10n_es_edi_facturae_uom_code__33
|
||||
msgid "Cubic meter"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields,field_description:l10n_es_edi_facturae.field_l10n_es_edi_facturae_certificate__date_end
|
||||
msgid "Date End"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields,field_description:l10n_es_edi_facturae.field_l10n_es_edi_facturae_certificate__date_start
|
||||
msgid "Date Start"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__account_move__l10n_es_edi_facturae_reason_code__03
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__account_move_reversal__l10n_es_edi_facturae_reason_code__03
|
||||
msgid "Date of issue"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__account_move__l10n_es_edi_facturae_reason_code__13
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__account_move_reversal__l10n_es_edi_facturae_reason_code__13
|
||||
msgid "Date/Period to apply"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__uom_uom__l10n_es_edi_facturae_uom_code__20
|
||||
msgid "Demijohns, non-protected"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields,field_description:l10n_es_edi_facturae.field_l10n_es_edi_facturae_certificate__display_name
|
||||
msgid "Display Name"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__uom_uom__l10n_es_edi_facturae_uom_code__18
|
||||
msgid "Dozens"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__uom_uom__l10n_es_edi_facturae_uom_code__31
|
||||
msgid "Envelopes"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#. odoo-python
|
||||
#: code:addons/l10n_es_edi_facturae/models/account_move_send.py:0
|
||||
#, python-format
|
||||
msgid "Errors occured while creating the EDI document (format: %s):"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields,field_description:l10n_es_edi_facturae.field_account_bank_statement_line__l10n_es_edi_facturae_xml_id
|
||||
#: model:ir.model.fields,field_description:l10n_es_edi_facturae.field_account_move__l10n_es_edi_facturae_xml_id
|
||||
#: model:ir.model.fields,field_description:l10n_es_edi_facturae.field_account_payment__l10n_es_edi_facturae_xml_id
|
||||
msgid "Facturae Attachment"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model,name:l10n_es_edi_facturae.model_l10n_es_edi_facturae_certificate
|
||||
msgid "Facturae Digital Certificate"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields,field_description:l10n_es_edi_facturae.field_res_company__l10n_es_edi_facturae_residence_type
|
||||
#: model:ir.model.fields,field_description:l10n_es_edi_facturae.field_res_partner__l10n_es_edi_facturae_residence_type
|
||||
#: model:ir.model.fields,field_description:l10n_es_edi_facturae.field_res_users__l10n_es_edi_facturae_residence_type
|
||||
msgid "Facturae EDI Residency Type Code"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields,field_description:l10n_es_edi_facturae.field_res_company__l10n_es_edi_facturae_certificate_id
|
||||
msgid "Facturae EDI signing certificate"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields,field_description:l10n_es_edi_facturae.field_account_bank_statement_line__l10n_es_edi_facturae_xml_file
|
||||
#: model:ir.model.fields,field_description:l10n_es_edi_facturae.field_account_move__l10n_es_edi_facturae_xml_file
|
||||
#: model:ir.model.fields,field_description:l10n_es_edi_facturae.field_account_payment__l10n_es_edi_facturae_xml_file
|
||||
msgid "Facturae File"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model_terms:ir.ui.view,arch_db:l10n_es_edi_facturae.view_company_form_inherit_l10n_es_edi_facturae
|
||||
msgid "Facturae signature certificate"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields,field_description:l10n_es_edi_facturae.field_account_move_send__l10n_es_edi_facturae_checkbox_xml
|
||||
msgid "Generate Facturae edi file"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__uom_uom__l10n_es_edi_facturae_uom_code__21
|
||||
msgid "Grams"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__uom_uom__l10n_es_edi_facturae_uom_code__02
|
||||
msgid "Hours"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields,field_description:l10n_es_edi_facturae.field_l10n_es_edi_facturae_certificate__id
|
||||
msgid "ID"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__account_move__l10n_es_edi_facturae_reason_code__01
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__account_move_reversal__l10n_es_edi_facturae_reason_code__01
|
||||
msgid "Invoice number"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__account_move__l10n_es_edi_facturae_reason_code__02
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__account_move_reversal__l10n_es_edi_facturae_reason_code__02
|
||||
msgid "Invoice series"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__account_move__l10n_es_edi_facturae_reason_code__14
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__account_move_reversal__l10n_es_edi_facturae_reason_code__14
|
||||
msgid "Invoice type"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__account_move__l10n_es_edi_facturae_reason_code__08
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__account_move_reversal__l10n_es_edi_facturae_reason_code__08
|
||||
msgid "Issuer/Oblige Address"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__uom_uom__l10n_es_edi_facturae_uom_code__09
|
||||
msgid "Jerricans, cylindrical"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model,name:l10n_es_edi_facturae.model_account_move
|
||||
msgid "Journal Entry"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__uom_uom__l10n_es_edi_facturae_uom_code__03
|
||||
msgid "Kilograms"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__uom_uom__l10n_es_edi_facturae_uom_code__22
|
||||
msgid "Kilometers"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields,field_description:l10n_es_edi_facturae.field_account_move_send__l10n_es_edi_facturae_enable_xml
|
||||
msgid "L10N Es Edi Facturae Enable Xml"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields,field_description:l10n_es_edi_facturae.field_l10n_es_edi_facturae_certificate__write_uid
|
||||
msgid "Last Updated by"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields,field_description:l10n_es_edi_facturae.field_l10n_es_edi_facturae_certificate__write_date
|
||||
msgid "Last Updated on"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__uom_uom__l10n_es_edi_facturae_uom_code__04
|
||||
msgid "Liters"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__uom_uom__l10n_es_edi_facturae_uom_code__25
|
||||
msgid "Meters"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__uom_uom__l10n_es_edi_facturae_uom_code__26
|
||||
msgid "Millimeters"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__account_move__l10n_es_edi_facturae_reason_code__04
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__account_move_reversal__l10n_es_edi_facturae_reason_code__04
|
||||
msgid "Name and surname/company name - Issuer"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__account_move__l10n_es_edi_facturae_reason_code__05
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__account_move_reversal__l10n_es_edi_facturae_reason_code__05
|
||||
msgid "Name and surname/company name - Recipient"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#. odoo-python
|
||||
#: code:addons/l10n_es_edi_facturae/models/account_move.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"No valid certificate found for this company, Facturae EDI file will not be "
|
||||
"signed.\n"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__uom_uom__l10n_es_edi_facturae_uom_code__05
|
||||
msgid "Other"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields,field_description:l10n_es_edi_facturae.field_l10n_es_edi_facturae_certificate__content
|
||||
#: model:ir.model.fields,help:l10n_es_edi_facturae.field_l10n_es_edi_facturae_certificate__content
|
||||
msgid "PFX Certificate"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__uom_uom__l10n_es_edi_facturae_uom_code__28
|
||||
msgid "Packages"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields,help:l10n_es_edi_facturae.field_l10n_es_edi_facturae_certificate__password
|
||||
msgid "Passphrase for the PFX certificate"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields,field_description:l10n_es_edi_facturae.field_l10n_es_edi_facturae_certificate__password
|
||||
msgid "Password"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__uom_uom__l10n_es_edi_facturae_uom_code__29
|
||||
msgid "Portions"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model,name:l10n_es_edi_facturae.model_uom_uom
|
||||
msgid "Product Unit of Measure"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model_terms:ir.ui.view,arch_db:l10n_es_edi_facturae.view_account_move_reversal_inherit_l10n_es_edi_facturae
|
||||
msgid "Reason"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__account_move__l10n_es_edi_facturae_reason_code__09
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__account_move_reversal__l10n_es_edi_facturae_reason_code__09
|
||||
msgid "Receiving Address"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model_terms:ir.ui.view,arch_db:l10n_es_edi_facturae.corrective_type
|
||||
msgid "Rectificación modelo íntegro."
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__uom_uom__l10n_es_edi_facturae_uom_code__30
|
||||
msgid "Rolls"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__uom_uom__l10n_es_edi_facturae_uom_code__34
|
||||
msgid "Second"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields,field_description:l10n_es_edi_facturae.field_l10n_es_edi_facturae_certificate__serial_number
|
||||
msgid "Serial Number"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.ui.menu,name:l10n_es_edi_facturae.menu_l10n_es_edi_facturae_root
|
||||
msgid "Spain Facturae EDI"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields,field_description:l10n_es_edi_facturae.field_uom_uom__l10n_es_edi_facturae_uom_code
|
||||
msgid "Spanish EDI Units"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields,field_description:l10n_es_edi_facturae.field_account_bank_statement_line__l10n_es_edi_facturae_reason_code
|
||||
#: model:ir.model.fields,field_description:l10n_es_edi_facturae.field_account_move__l10n_es_edi_facturae_reason_code
|
||||
#: model:ir.model.fields,field_description:l10n_es_edi_facturae.field_account_move_reversal__l10n_es_edi_facturae_reason_code
|
||||
#: model:ir.model.fields,field_description:l10n_es_edi_facturae.field_account_payment__l10n_es_edi_facturae_reason_code
|
||||
msgid "Spanish Facturae EDI Reason Code"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields,field_description:l10n_es_edi_facturae.field_account_tax__l10n_es_edi_facturae_tax_type
|
||||
msgid "Spanish Facturae EDI Tax Type"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model_terms:ir.ui.view,arch_db:l10n_es_edi_facturae.product_uom_categ_form_view_inherit_l10n_es_edi_facturae
|
||||
#: model_terms:ir.ui.view,arch_db:l10n_es_edi_facturae.product_uom_form_view_inherit_l10n_es_edi_facturae
|
||||
#: model_terms:ir.ui.view,arch_db:l10n_es_edi_facturae.product_uom_tree_view_inherit_l10n_es_edi_facturae
|
||||
msgid "Spanish Facturae EDI type"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model_terms:ir.ui.view,arch_db:l10n_es_edi_facturae.view_tax_tree_inherit_l10n_es_edi_facturae
|
||||
msgid "Spanish Tax Type"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__account_move__l10n_es_edi_facturae_reason_code__15
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__account_move_reversal__l10n_es_edi_facturae_reason_code__15
|
||||
msgid "Statutory letters"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model,name:l10n_es_edi_facturae.model_account_tax
|
||||
msgid "Tax"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__account_move__l10n_es_edi_facturae_reason_code__06
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__account_move_reversal__l10n_es_edi_facturae_reason_code__06
|
||||
msgid "Tax identification Issuer/Oblige"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__account_move__l10n_es_edi_facturae_reason_code__07
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__account_move_reversal__l10n_es_edi_facturae_reason_code__07
|
||||
msgid "Tax identification Receiver"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__account_move__l10n_es_edi_facturae_reason_code__11
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__account_move__l10n_es_edi_facturae_reason_code__12
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__account_move_reversal__l10n_es_edi_facturae_reason_code__11
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__account_move_reversal__l10n_es_edi_facturae_reason_code__12
|
||||
msgid "Tax rate to be applied"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__account_move__l10n_es_edi_facturae_reason_code__16
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__account_move_reversal__l10n_es_edi_facturae_reason_code__16
|
||||
msgid "Taxable amount"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__account_move__l10n_es_edi_facturae_reason_code__82
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__account_move_reversal__l10n_es_edi_facturae_reason_code__82
|
||||
msgid "Taxable amount modified by return of containers/packaging"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__account_move__l10n_es_edi_facturae_reason_code__83
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__account_move_reversal__l10n_es_edi_facturae_reason_code__83
|
||||
msgid "Taxable income modified by discounts and allowances"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__account_move__l10n_es_edi_facturae_reason_code__84
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__account_move_reversal__l10n_es_edi_facturae_reason_code__84
|
||||
msgid "Taxable income modified by final, judicial or administrative ruling"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__account_move__l10n_es_edi_facturae_reason_code__85
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__account_move_reversal__l10n_es_edi_facturae_reason_code__85
|
||||
msgid ""
|
||||
"Taxable income modified by unpaid tax assessments. Order of declaration of "
|
||||
"bankruptcy"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__uom_uom__l10n_es_edi_facturae_uom_code__14
|
||||
msgid "Tetra Briks"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#. odoo-python
|
||||
#: code:addons/l10n_es_edi_facturae/models/l10n_es_edi_facturae_certificate.py:0
|
||||
#, python-format
|
||||
msgid "The certificate is expired since %s"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#. odoo-python
|
||||
#: code:addons/l10n_es_edi_facturae/models/account_move.py:0
|
||||
#, python-format
|
||||
msgid "The company needs a set tax identification number or VAT number"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields,help:l10n_es_edi_facturae.field_l10n_es_edi_facturae_certificate__date_end
|
||||
msgid "The date on which the certificate expires"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields,help:l10n_es_edi_facturae.field_l10n_es_edi_facturae_certificate__date_start
|
||||
msgid "The date on which the certificate starts to be valid"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#. odoo-python
|
||||
#: code:addons/l10n_es_edi_facturae/models/account_move.py:0
|
||||
#, python-format
|
||||
msgid "The partner needs a set tax identification number or VAT number"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields,help:l10n_es_edi_facturae.field_l10n_es_edi_facturae_certificate__serial_number
|
||||
msgid "The serial number to add to electronic documents"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#. odoo-python
|
||||
#: code:addons/l10n_es_edi_facturae/models/l10n_es_edi_facturae_certificate.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"There has been a problem with the certificate, some usual problems can be:\n"
|
||||
"\t- The password given or the certificate are not valid.\n"
|
||||
"\t- The certificate content is invalid."
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__account_move__l10n_es_edi_facturae_reason_code__10
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__account_move_reversal__l10n_es_edi_facturae_reason_code__10
|
||||
msgid "Transaction Details"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__uom_uom__l10n_es_edi_facturae_uom_code__07
|
||||
msgid "Trays, one layer no cover, plastic"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__uom_uom__l10n_es_edi_facturae_uom_code__32
|
||||
msgid "Tubs"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__uom_uom__l10n_es_edi_facturae_uom_code__01
|
||||
msgid "Units"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model_terms:ir.ui.view,arch_db:l10n_es_edi_facturae.l10n_es_edi_facturae_certificate_form
|
||||
msgid "Validity"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model:ir.model.fields.selection,name:l10n_es_edi_facturae.selection__uom_uom__l10n_es_edi_facturae_uom_code__35
|
||||
msgid "Watt"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model_terms:ir.ui.view,arch_db:l10n_es_edi_facturae.template_xades_signature
|
||||
msgid "not(ancestor-or-self::ds:Signature)"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model_terms:ir.ui.view,arch_db:l10n_es_edi_facturae.template_xades_signature
|
||||
msgid "text/xml"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_es_edi_facturae
|
||||
#: model_terms:ir.ui.view,arch_db:l10n_es_edi_facturae.template_xades_signature
|
||||
msgid "urn:oid:1.2.840.10003.5.109.10"
|
||||
msgstr ""
|
||||
@@ -0,0 +1,7 @@
|
||||
from . import account_tax
|
||||
from . import l10n_es_edi_facturae_certificate
|
||||
from . import res_company
|
||||
from . import res_partner
|
||||
from . import uom_uom
|
||||
from . import account_move
|
||||
from . import account_move_send
|
||||
@@ -0,0 +1,362 @@
|
||||
from collections import defaultdict
|
||||
|
||||
from odoo import fields, models, api, _
|
||||
from odoo.exceptions import UserError
|
||||
from odoo.tools import float_repr, date_utils
|
||||
from odoo.tools.xml_utils import cleanup_xml_node
|
||||
|
||||
PHONE_CLEAN_TABLE = str.maketrans({" ": None, "-": None, "(": None, ")": None, "+": None})
|
||||
COUNTRY_CODE_MAP = {
|
||||
"BD": "BGD", "BE": "BEL", "BF": "BFA", "BG": "BGR", "BA": "BIH", "BB": "BRB", "WF": "WLF", "BL": "BLM", "BM": "BMU",
|
||||
"BN": "BRN", "BO": "BOL", "BH": "BHR", "BI": "BDI", "BJ": "BEN", "BT": "BTN", "JM": "JAM", "BV": "BVT", "BW": "BWA",
|
||||
"WS": "WSM", "BQ": "BES", "BR": "BRA", "BS": "BHS", "JE": "JEY", "BY": "BLR", "BZ": "BLZ", "RU": "RUS", "RW": "RWA",
|
||||
"RS": "SRB", "TL": "TLS", "RE": "REU", "TM": "TKM", "TJ": "TJK", "RO": "ROU", "TK": "TKL", "GW": "GNB", "GU": "GUM",
|
||||
"GT": "GTM", "GS": "SGS", "GR": "GRC", "GQ": "GNQ", "GP": "GLP", "JP": "JPN", "GY": "GUY", "GG": "GGY", "GF": "GUF",
|
||||
"GE": "GEO", "GD": "GRD", "GB": "GBR", "GA": "GAB", "SV": "SLV", "GN": "GIN", "GM": "GMB", "GL": "GRL", "GI": "GIB",
|
||||
"GH": "GHA", "OM": "OMN", "TN": "TUN", "JO": "JOR", "HR": "HRV", "HT": "HTI", "HU": "HUN", "HK": "HKG", "HN": "HND",
|
||||
"HM": "HMD", "VE": "VEN", "PR": "PRI", "PS": "PSE", "PW": "PLW", "PT": "PRT", "SJ": "SJM", "PY": "PRY", "IQ": "IRQ",
|
||||
"PA": "PAN", "PF": "PYF", "PG": "PNG", "PE": "PER", "PK": "PAK", "PH": "PHL", "PN": "PCN", "PL": "POL", "PM": "SPM",
|
||||
"ZM": "ZMB", "EH": "ESH", "EE": "EST", "EG": "EGY", "ZA": "ZAF", "EC": "ECU", "IT": "ITA", "VN": "VNM", "SB": "SLB",
|
||||
"ET": "ETH", "SO": "SOM", "ZW": "ZWE", "SA": "SAU", "ES": "ESP", "ER": "ERI", "ME": "MNE", "MD": "MDA", "MG": "MDG",
|
||||
"MF": "MAF", "MA": "MAR", "MC": "MCO", "UZ": "UZB", "MM": "MMR", "ML": "MLI", "MO": "MAC", "MN": "MNG", "MH": "MHL",
|
||||
"MK": "MKD", "MU": "MUS", "MT": "MLT", "MW": "MWI", "MV": "MDV", "MQ": "MTQ", "MP": "MNP", "MS": "MSR", "MR": "MRT",
|
||||
"IM": "IMN", "UG": "UGA", "TZ": "TZA", "MY": "MYS", "MX": "MEX", "IL": "ISR", "FR": "FRA", "IO": "IOT", "SH": "SHN",
|
||||
"FI": "FIN", "FJ": "FJI", "FK": "FLK", "FM": "FSM", "FO": "FRO", "NI": "NIC", "NL": "NLD", "NO": "NOR", "NA": "NAM",
|
||||
"VU": "VUT", "NC": "NCL", "NE": "NER", "NF": "NFK", "NG": "NGA", "NZ": "NZL", "NP": "NPL", "NR": "NRU", "NU": "NIU",
|
||||
"CK": "COK", "XK": "XKX", "CI": "CIV", "CH": "CHE", "CO": "COL", "CN": "CHN", "CM": "CMR", "CL": "CHL", "CC": "CCK",
|
||||
"CA": "CAN", "CG": "COG", "CF": "CAF", "CD": "COD", "CZ": "CZE", "CY": "CYP", "CX": "CXR", "CR": "CRI", "CW": "CUW",
|
||||
"CV": "CPV", "CU": "CUB", "SZ": "SWZ", "SY": "SYR", "SX": "SXM", "KG": "KGZ", "KE": "KEN", "SS": "SSD", "SR": "SUR",
|
||||
"KI": "KIR", "KH": "KHM", "KN": "KNA", "KM": "COM", "ST": "STP", "SK": "SVK", "KR": "KOR", "SI": "SVN", "KP": "PRK",
|
||||
"KW": "KWT", "SN": "SEN", "SM": "SMR", "SL": "SLE", "SC": "SYC", "KZ": "KAZ", "KY": "CYM", "SG": "SGP", "SE": "SWE",
|
||||
"SD": "SDN", "DO": "DOM", "DM": "DMA", "DJ": "DJI", "DK": "DNK", "VG": "VGB", "DE": "DEU", "YE": "YEM", "DZ": "DZA",
|
||||
"US": "USA", "UY": "URY", "YT": "MYT", "UM": "UMI", "LB": "LBN", "LC": "LCA", "LA": "LAO", "TV": "TUV", "TW": "TWN",
|
||||
"TT": "TTO", "TR": "TUR", "LK": "LKA", "LI": "LIE", "LV": "LVA", "TO": "TON", "LT": "LTU", "LU": "LUX", "LR": "LBR",
|
||||
"LS": "LSO", "TH": "THA", "TF": "ATF", "TG": "TGO", "TD": "TCD", "TC": "TCA", "LY": "LBY", "VA": "VAT", "VC": "VCT",
|
||||
"AE": "ARE", "AD": "AND", "AG": "ATG", "AF": "AFG", "AI": "AIA", "VI": "VIR", "IS": "ISL", "IR": "IRN", "AM": "ARM",
|
||||
"AL": "ALB", "AO": "AGO", "AQ": "ATA", "AS": "ASM", "AR": "ARG", "AU": "AUS", "AT": "AUT", "AW": "ABW", "IN": "IND",
|
||||
"AX": "ALA", "AZ": "AZE", "IE": "IRL", "ID": "IDN", "UA": "UKR", "QA": "QAT", "MZ": "MOZ"
|
||||
}
|
||||
REVERSED_COUNTRY_CODE = {v: k for k, v in COUNTRY_CODE_MAP.items()}
|
||||
|
||||
class AccountMove(models.Model):
|
||||
_inherit = 'account.move'
|
||||
|
||||
l10n_es_edi_facturae_xml_id = fields.Many2one(
|
||||
comodel_name='ir.attachment',
|
||||
string="Facturae Attachment",
|
||||
compute=lambda self: self._compute_linked_attachment_id('l10n_es_edi_facturae_xml_id', 'l10n_es_edi_facturae_xml_file'),
|
||||
depends=['l10n_es_edi_facturae_xml_file']
|
||||
)
|
||||
l10n_es_edi_facturae_xml_file = fields.Binary(
|
||||
attachment=True,
|
||||
string="Facturae File",
|
||||
copy=False,
|
||||
)
|
||||
l10n_es_edi_facturae_reason_code = fields.Selection(
|
||||
selection=[
|
||||
('01', 'Invoice number'),
|
||||
('02', 'Invoice series'),
|
||||
('03', 'Date of issue'),
|
||||
('04', 'Name and surname/company name - Issuer'),
|
||||
('05', 'Name and surname/company name - Recipient'),
|
||||
('06', 'Tax identification Issuer/Oblige'),
|
||||
('07', 'Tax identification Receiver'),
|
||||
('08', 'Issuer/Oblige Address'),
|
||||
('09', 'Receiving Address'),
|
||||
('10', 'Transaction Details'),
|
||||
('11', 'Tax rate to be applied'),
|
||||
('12', 'Tax rate to be applied'),
|
||||
('13', 'Date/Period to apply'),
|
||||
('14', 'Invoice type'),
|
||||
('15', 'Statutory letters'),
|
||||
('16', 'Taxable amount'),
|
||||
('80', 'Calculation of output quotas'),
|
||||
('81', 'Calculation of withholding taxes'),
|
||||
('82', 'Taxable amount modified by return of containers/packaging'),
|
||||
('83', 'Taxable income modified by discounts and allowances'),
|
||||
('84', 'Taxable income modified by final, judicial or administrative ruling'),
|
||||
('85', 'Taxable income modified by unpaid tax assessments. Order of declaration of bankruptcy'),
|
||||
], string='Spanish Facturae EDI Reason Code', default='10')
|
||||
|
||||
def _l10n_es_edi_facturae_get_default_enable(self):
|
||||
self.ensure_one()
|
||||
return self.company_id.country_code == 'ES' and self.company_id.currency_id.name == 'EUR'
|
||||
|
||||
def _l10n_es_edi_facturae_get_filename(self):
|
||||
self.ensure_one()
|
||||
return f'{self.name.replace("/", "_")}_facturae_signed.xml'
|
||||
|
||||
def _l10n_es_edi_facturae_get_tax_period(self):
|
||||
self.ensure_one()
|
||||
if self.env['res.company'].fields_get(['account_tax_periodicity']):
|
||||
period_start, period_end = self.company_id._get_tax_closing_period_boundaries(self.date)
|
||||
else:
|
||||
period_start = date_utils.start_of(self.date, 'month')
|
||||
period_end = date_utils.end_of(self.date, 'month')
|
||||
|
||||
return {'start':period_start, 'end':period_end}
|
||||
|
||||
def _l10n_es_edi_facturae_get_refunded_invoices(self):
|
||||
self.env['account.partial.reconcile'].flush_model()
|
||||
invoices_refunded_mapping = {invoice.id: invoice.reversed_entry_id for invoice in self}
|
||||
|
||||
queries = []
|
||||
for source_field, counterpart_field in (('debit', 'credit'), ('credit', 'debit')):
|
||||
queries.append(f'''
|
||||
SELECT
|
||||
source_line.move_id AS source_move_id,
|
||||
counterpart_line.move_id AS counterpart_move_id
|
||||
FROM account_partial_reconcile part
|
||||
JOIN account_move_line source_line ON source_line.id = part.{source_field}_move_id
|
||||
JOIN account_move_line counterpart_line ON counterpart_line.id = part.{counterpart_field}_move_id
|
||||
WHERE source_line.move_id IN %s AND counterpart_line.move_id != source_line.move_id
|
||||
GROUP BY source_move_id, counterpart_move_id
|
||||
''')
|
||||
self._cr.execute(' UNION ALL '.join(queries), [tuple(self.ids)] * 2)
|
||||
payment_data = defaultdict(lambda: [])
|
||||
for row in self._cr.dictfetchall():
|
||||
payment_data[row['source_move_id']].append(row)
|
||||
|
||||
for invoice in self:
|
||||
if not invoice.move_type.endswith('refund'):
|
||||
# We only want to map refunds
|
||||
continue
|
||||
|
||||
for move_id in (record_dict['counterpart_move_id'] for record_dict in payment_data.get(invoice.id, [])):
|
||||
invoices_refunded_mapping[invoice.id] = move_id
|
||||
return invoices_refunded_mapping
|
||||
|
||||
def _l10n_es_edi_facturae_get_corrective_data(self):
|
||||
self.ensure_one()
|
||||
if self.move_type.endswith('refund'):
|
||||
refunded_invoice = self.env['account.move'].browse(self._l10n_es_edi_facturae_get_refunded_invoices()[self.id])
|
||||
tax_period = refunded_invoice._l10n_es_edi_facturae_get_tax_period()
|
||||
|
||||
reason_code = self.l10n_es_edi_facturae_reason_code or '10'
|
||||
reason_description = [label for code, label in self._fields['l10n_es_edi_facturae_reason_code'].selection
|
||||
if code == reason_code][0]
|
||||
return {
|
||||
'refunded_invoice_record': refunded_invoice,
|
||||
'ReasonCode': reason_code,
|
||||
'Reason': reason_description,
|
||||
'TaxPeriod': {
|
||||
'StartDate': tax_period.get('start'),
|
||||
'EndDate': tax_period.get('end'),
|
||||
}
|
||||
}
|
||||
return {}
|
||||
|
||||
@api.model
|
||||
def _l10n_es_edi_facturae_convert_computed_tax_to_template(self, computed_tax_dict):
|
||||
""" Helper to convert the tax dict from a _compute_taxes() into a dict usable in the template """
|
||||
tax = self.env["account.tax"].browse(computed_tax_dict["tax_id"])
|
||||
return {
|
||||
"tax_record": tax,
|
||||
"TaxRate": f'{abs(tax.amount):.3f}',
|
||||
"TaxableBase": {
|
||||
'TotalAmount': computed_tax_dict["base_amount_currency"],
|
||||
'EquivalentInEuros': computed_tax_dict["base_amount"],
|
||||
},
|
||||
"TaxAmount": {
|
||||
"TotalAmount": abs(computed_tax_dict["tax_amount_currency"]),
|
||||
"EquivalentInEuros": abs(computed_tax_dict["tax_amount"]),
|
||||
},
|
||||
}
|
||||
|
||||
def _l10n_es_edi_facturae_inv_lines_to_items(self, conversion_rate=None):
|
||||
"""
|
||||
Convert the invoice lines to a list of items required for the Facturae xml generation
|
||||
|
||||
:param float conversion_rate: Conversion rate of the invoice, if needed
|
||||
:return: A tuple containing the Face items, the taxes and the invoice totals data.
|
||||
"""
|
||||
self.ensure_one()
|
||||
items = []
|
||||
totals = {
|
||||
'total_gross_amount': 0.,
|
||||
'total_general_discounts': 0.,
|
||||
'total_general_surcharges': 0.,
|
||||
'total_taxes_withheld': 0.,
|
||||
'total_tax_outputs': 0.,
|
||||
'total_payments_on_account': 0.,
|
||||
'amounts_withheld': 0.,
|
||||
}
|
||||
taxes = []
|
||||
taxes_withheld = []
|
||||
for line in self.invoice_line_ids:
|
||||
if line.display_type in {'line_section', 'line_note'}:
|
||||
continue
|
||||
invoice_line_values = {}
|
||||
|
||||
price_before_discount = line.currency_id.round(line.price_subtotal / (1 - line.discount / 100.0))
|
||||
discount = max(0., (price_before_discount - line.price_subtotal))
|
||||
surcharge = abs(min(0., (price_before_discount - line.price_subtotal)))
|
||||
totals['total_gross_amount'] += line.price_subtotal
|
||||
totals['total_general_discounts'] += discount
|
||||
totals['total_general_surcharges'] += surcharge
|
||||
base_line = self.env['account.tax']._convert_to_tax_base_line_dict(
|
||||
line, partner=line.partner_id, currency=line.currency_id, product=line.product_id, taxes=line.tax_ids,
|
||||
price_unit=line.price_unit, quantity=line.quantity, discount=line.discount, account=line.account_id,
|
||||
price_subtotal=line.price_subtotal, is_refund=line.is_refund, rate=conversion_rate
|
||||
)
|
||||
|
||||
taxes_computed = self.env['account.tax']._compute_taxes([base_line])
|
||||
taxes_withheld_computed = [tax for tax in taxes_computed["tax_lines_to_add"] if tax["tax_amount"] < 0]
|
||||
taxes_normal_computed = [tax for tax in taxes_computed["tax_lines_to_add"] if tax["tax_amount"] >= 0]
|
||||
|
||||
taxes_output = [self._l10n_es_edi_facturae_convert_computed_tax_to_template(tax) for tax in taxes_normal_computed]
|
||||
totals['total_tax_outputs'] += sum((abs(tax["tax_amount"]) for tax in taxes_normal_computed))
|
||||
|
||||
tax_withheld_output = [self._l10n_es_edi_facturae_convert_computed_tax_to_template(tax) for tax in taxes_withheld_computed]
|
||||
totals['total_taxes_withheld'] += sum((abs(tax["tax_amount"]) for tax in taxes_withheld_computed))
|
||||
|
||||
invoice_line_values.update({
|
||||
'ItemDescription': line.name,
|
||||
'Quantity': line.quantity,
|
||||
'UnitOfMeasure': line.product_uom_id.l10n_es_edi_facturae_uom_code,
|
||||
'UnitPriceWithoutTax': line.currency_id.round(price_before_discount / line.quantity if line.quantity else 0.),
|
||||
'TotalCost': price_before_discount,
|
||||
'DiscountsAndRebates': [{
|
||||
'DiscountReason': '',
|
||||
'DiscountRate': f'{line.discount:.2f}',
|
||||
'DiscountAmount': discount
|
||||
}, ] if discount != 0. else [],
|
||||
'Charges': [{
|
||||
'ChargeReason': '',
|
||||
'ChargeRate': f'{max(0, -line.discount):.2f}',
|
||||
'ChargeAmount': surcharge,
|
||||
}, ] if surcharge != 0. else [],
|
||||
'GrossAmount': line.price_subtotal,
|
||||
'TaxesOutputs': taxes_output,
|
||||
'TaxesWithheld': tax_withheld_output,
|
||||
})
|
||||
items.append(invoice_line_values)
|
||||
taxes += taxes_output
|
||||
taxes_withheld += tax_withheld_output
|
||||
return items, taxes, taxes_withheld, totals
|
||||
|
||||
def _l10n_es_edi_facturae_export_facturae(self):
|
||||
"""
|
||||
Produce the Facturae XML data for the invoice.
|
||||
|
||||
:return: (data needed to render the full template, data needed to render the signature template)
|
||||
"""
|
||||
self.ensure_one()
|
||||
company = self.company_id
|
||||
partner = self.commercial_partner_id
|
||||
|
||||
if not company.vat:
|
||||
raise UserError(_('The company needs a set tax identification number or VAT number'))
|
||||
if not partner.vat:
|
||||
raise UserError(_('The partner needs a set tax identification number or VAT number'))
|
||||
if self.move_type == "entry":
|
||||
return False
|
||||
|
||||
eur_curr = self.env['res.currency'].search([('name', '=', 'EUR')])
|
||||
inv_curr = self.currency_id
|
||||
legal_literals = self.narration.striptags() if self.narration else False
|
||||
legal_literals = legal_literals.split(";") if legal_literals else False
|
||||
|
||||
partner_name = {'firstname': 'UNKNOWN', 'surname': 'UNKNOWN', 'surname2': ''}
|
||||
if not partner.is_company:
|
||||
name_split = [part for part in partner.name.replace(', ', ' ').split(' ') if part]
|
||||
if len(name_split) > 2:
|
||||
partner_name['firstname'] = ' '.join(name_split[:-2])
|
||||
partner_name['surname'], partner_name['surname2'] = name_split[-2:]
|
||||
elif len(name_split) == 2:
|
||||
partner_name['firstname'] = ' '.join(name_split[:-1])
|
||||
partner_name['surname'] = name_split[-1]
|
||||
|
||||
invoice_issuer_signature_type = 'supplier' if self.move_type == 'out_invoice' else 'customer'
|
||||
need_conv = bool(inv_curr != eur_curr)
|
||||
conversion_rate = abs(self.amount_total_in_currency_signed / self.amount_total_signed) if self.amount_total_signed else 0.
|
||||
total_outst_am_in_currency = abs(self.amount_total_in_currency_signed)
|
||||
total_outst_am = abs(self.amount_total_signed)
|
||||
total_exec_am_in_currency = abs(self.amount_total_in_currency_signed)
|
||||
total_exec_am = abs(self.amount_total_signed)
|
||||
items, taxes, taxes_withheld, totals = self._l10n_es_edi_facturae_inv_lines_to_items(conversion_rate)
|
||||
template_values = {
|
||||
'self_party': company.partner_id,
|
||||
'self_party_country_code': COUNTRY_CODE_MAP[company.country_id.code],
|
||||
'other_party': partner,
|
||||
'other_party_country_code': COUNTRY_CODE_MAP[partner.country_id.code],
|
||||
'other_party_phone': partner.phone.translate(PHONE_CLEAN_TABLE) if partner.phone else False,
|
||||
'other_party_name': partner_name,
|
||||
'is_outstanding': self.move_type.startswith('out_'),
|
||||
'float_repr': float_repr,
|
||||
'file_currency': inv_curr,
|
||||
'eur': eur_curr,
|
||||
'conversion_needed': need_conv,
|
||||
'refund_multiplier': -1 if self.move_type.endswith('refund') else 1,
|
||||
|
||||
'Modality': 'I',
|
||||
'BatchIdentifier': self.name,
|
||||
'InvoicesCount': 1,
|
||||
'TotalInvoicesAmount': {
|
||||
'TotalAmount': abs(self.amount_total_in_currency_signed),
|
||||
'EquivalentInEuros': abs(self.amount_total_signed),
|
||||
},
|
||||
'TotalOutstandingAmount': {
|
||||
'TotalAmount': abs(total_outst_am_in_currency),
|
||||
'EquivalentInEuros': abs(total_outst_am),
|
||||
},
|
||||
'TotalExecutableAmount': {
|
||||
'TotalAmount': total_exec_am_in_currency,
|
||||
'EquivalentInEuros': total_exec_am,
|
||||
},
|
||||
'InvoiceCurrencyCode': inv_curr.name,
|
||||
'Invoices': [{
|
||||
'invoice_record': self,
|
||||
'invoice_currency': inv_curr,
|
||||
'InvoiceDocumentType': 'FC',
|
||||
'InvoiceClass': 'OO',
|
||||
'Corrective': self._l10n_es_edi_facturae_get_corrective_data(),
|
||||
'InvoiceIssueData': {
|
||||
'ExchangeRateDetails': need_conv,
|
||||
'ExchangeRate': f"{round(conversion_rate, 4):.4f}",
|
||||
'LanguageName': self._context.get('lang', 'en_US').split('_')[0],
|
||||
},
|
||||
'TaxOutputs': taxes,
|
||||
'TaxesWithheld': taxes_withheld,
|
||||
'TotalGrossAmount': totals['total_gross_amount'],
|
||||
'TotalGeneralDiscounts': totals['total_general_discounts'],
|
||||
'TotalGeneralSurcharges': totals['total_general_surcharges'],
|
||||
'TotalGrossAmountBeforeTaxes': totals['total_gross_amount'] - totals['total_general_discounts'] + totals['total_general_surcharges'],
|
||||
'TotalTaxOutputs': totals['total_tax_outputs'],
|
||||
'TotalTaxesWithheld': totals['total_taxes_withheld'],
|
||||
'PaymentsOnAccount': [],
|
||||
'TotalOutstandingAmount': total_outst_am_in_currency,
|
||||
'InvoiceTotal': abs(self.amount_total_in_currency_signed),
|
||||
'TotalPaymentsOnAccount': totals['total_payments_on_account'],
|
||||
'AmountsWithheld': {
|
||||
'WithholdingReason': '',
|
||||
'WithholdingRate': False,
|
||||
'WithholdingAmount': totals['amounts_withheld'],
|
||||
} if totals['amounts_withheld'] else False,
|
||||
'TotalExecutableAmount': total_exec_am_in_currency,
|
||||
'Items': items,
|
||||
'PaymentDetails': [],
|
||||
'LegalLiterals': legal_literals,
|
||||
}],
|
||||
}
|
||||
signature_values = {'SigningTime': '', 'SignerRole': invoice_issuer_signature_type, }
|
||||
return template_values, signature_values
|
||||
|
||||
def _l10n_es_edi_facturae_render_facturae(self):
|
||||
"""
|
||||
Produce the Facturae XML file for the invoice.
|
||||
|
||||
:return: rendered xml file string.
|
||||
:rtype: str
|
||||
"""
|
||||
self.ensure_one()
|
||||
company = self.company_id
|
||||
template_values, signature_values = self._l10n_es_edi_facturae_export_facturae()
|
||||
xml_content = cleanup_xml_node(self.env['ir.qweb']._render('l10n_es_edi_facturae.account_invoice_facturae_export', template_values))
|
||||
certificate = self.env['l10n_es_edi_facturae.certificate'].search([("company_id", '=', company.id)], limit=1)
|
||||
|
||||
try:
|
||||
xml_content = certificate._sign_xml(xml_content, signature_values)
|
||||
except ValueError:
|
||||
raise UserError(_('No valid certificate found for this company, Facturae EDI file will not be signed.\n'))
|
||||
return xml_content
|
||||
@@ -0,0 +1,86 @@
|
||||
from odoo import _, api, fields, models
|
||||
|
||||
class AccountMoveSend(models.Model):
|
||||
_inherit = 'account.move.send'
|
||||
|
||||
l10n_es_edi_facturae_enable_xml = fields.Boolean(compute='_compute_send_mail_extra_fields')
|
||||
l10n_es_edi_facturae_checkbox_xml = fields.Boolean(
|
||||
string="Generate Facturae edi file",
|
||||
default=True,
|
||||
)
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# COMPUTE METHODS
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
def _compute_send_mail_extra_fields(self):
|
||||
# EXTENDS 'account'
|
||||
super()._compute_send_mail_extra_fields()
|
||||
for wizard in self:
|
||||
wizard.l10n_es_edi_facturae_enable_xml = any(move._l10n_es_edi_facturae_get_default_enable() for move in wizard.move_ids)
|
||||
|
||||
@api.depends('l10n_es_edi_facturae_checkbox_xml')
|
||||
def _compute_mail_attachments_widget(self):
|
||||
# EXTENDS 'account' - add depends
|
||||
super()._compute_mail_attachments_widget()
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# ATTACHMENTS
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
@api.model
|
||||
def _get_linked_attachments(self, move):
|
||||
# EXTENDS 'account'
|
||||
return super()._get_linked_attachments(move) + move.l10n_es_edi_facturae_xml_id
|
||||
|
||||
def _get_placeholder_mail_attachments_data(self, move):
|
||||
# EXTENDS 'account'
|
||||
results = super()._get_placeholder_mail_attachments_data(move)
|
||||
|
||||
if self.l10n_es_edi_facturae_enable_xml and self.l10n_es_edi_facturae_checkbox_xml:
|
||||
filename = f'{move.name.replace("/", "_")}_facturae_signed.xml'
|
||||
results.append({
|
||||
'id': f'placeholder_{filename}',
|
||||
'name': filename,
|
||||
'mimetype': 'application/xml',
|
||||
'placeholder': True,
|
||||
})
|
||||
|
||||
return results
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# BUSINESS ACTIONS
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
def _prepare_document(self, invoice):
|
||||
# EXTENDS 'account'
|
||||
results = super()._prepare_document(invoice)
|
||||
|
||||
if self.l10n_es_edi_facturae_checkbox_xml and invoice._l10n_es_edi_facturae_get_default_enable():
|
||||
try:
|
||||
xml_content = invoice._l10n_es_edi_facturae_render_facturae(invoice)
|
||||
except Exception as error:
|
||||
return {
|
||||
'error': "".join((_("Errors occured while creating the EDI document (format: %s):", "Facturae"),
|
||||
"\n", str(error))),
|
||||
}
|
||||
|
||||
results['l10n_es_edi_facturae_attachment_values'] = {
|
||||
'name': invoice._l10n_es_edi_facturae_get_filename(),
|
||||
'raw': xml_content,
|
||||
'mimetype': 'application/xml',
|
||||
'res_model': invoice._name,
|
||||
'res_id': invoice.id,
|
||||
'res_field': 'l10n_es_edi_facturae_xml_file', # Binary field
|
||||
}
|
||||
|
||||
return results
|
||||
|
||||
def _link_document(self, invoice, prepared_data):
|
||||
# EXTENDS 'account'
|
||||
super()._link_document(invoice, prepared_data)
|
||||
|
||||
attachment_vals = prepared_data.get('l10n_es_edi_facturae_attachment_values')
|
||||
if attachment_vals:
|
||||
self.env['ir.attachment'].create(attachment_vals)
|
||||
invoice.invalidate_model(fnames=['l10n_es_edi_facturae_xml_id', 'l10n_es_edi_facturae_xml_file'])
|
||||
@@ -0,0 +1,37 @@
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class AccountTax(models.Model):
|
||||
_inherit = 'account.tax'
|
||||
|
||||
l10n_es_edi_facturae_tax_type = fields.Selection((
|
||||
('01', 'Value-Added Tax'),
|
||||
('02', 'Taxes on production, services and imports in Ceuta and Melilla'),
|
||||
('03', 'IGIC: Canaries General Indirect Tax'),
|
||||
('04', 'IRPF: Personal Income Tax'),
|
||||
('05', 'Other'),
|
||||
('06', 'ITPAJD: Tax on wealth transfers and stamp duty'),
|
||||
('07', 'IE: Excise duties and consumption taxes'),
|
||||
('08', 'RA: Customs duties'),
|
||||
('09', 'IGTECM: Sales tax in Ceuta and Melilla'),
|
||||
('10', 'IECDPCAC: Excise duties on oil derivates in Canaries'),
|
||||
('11', 'IIIMAB: Tax on premises that affect the environment in the Balearic Islands'),
|
||||
('12', 'ICIO: Tax on construction, installation and works'),
|
||||
('13', 'IMVDN: Local tax on unoccupied homes in Navarre'),
|
||||
('14', 'IMSN: Local tax on building plots in Navarre'),
|
||||
('15', 'IMGSN: Local sumptuary tax in Navarre'),
|
||||
('16', 'IMPN: Local tax on advertising in Navarre'),
|
||||
('17', 'REIVA: Special VAT for travel agencies'),
|
||||
('18', 'REIGIC: Special IGIC: for travel agencies'),
|
||||
('19', 'REIPSI: Special IPSI for travel agencies'),
|
||||
('20', 'IPS: Insurance premiums Tax'),
|
||||
('21', 'SWUA: Surcharge for Winding Up Activity'),
|
||||
('22', 'IVPEE: Tax on the value of electricity generation'),
|
||||
('23', 'Tax on the production of spent nuclear fuel and radioactive waste from the generation of nuclear electric power'),
|
||||
('24', 'Tax on the storage of spent nuclear energy and radioactive waste in centralised facilities'),
|
||||
('25', 'IDEC: Tax on bank deposits'),
|
||||
('26', 'Excise duty applied to manufactured tobacco in Canaries'),
|
||||
('27', 'IGFEI: Tax on Fluorinated Greenhouse Gases'),
|
||||
('28', 'IRNR: Non-resident Income Tax'),
|
||||
('29', 'Corporation Tax'),
|
||||
), string='Spanish Facturae EDI Tax Type', default='01')
|
||||
@@ -0,0 +1,109 @@
|
||||
import re
|
||||
from base64 import b64decode, b64encode, encodebytes
|
||||
from copy import deepcopy
|
||||
from hashlib import sha1
|
||||
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
from cryptography.hazmat.primitives import hashes, serialization
|
||||
from cryptography.hazmat.primitives.serialization import pkcs12
|
||||
from lxml import etree
|
||||
|
||||
from odoo import _, api, fields, models
|
||||
from odoo.addons.l10n_es_edi_facturae import xml_utils
|
||||
from odoo.exceptions import UserError
|
||||
from odoo.tools import cleanup_xml_node
|
||||
|
||||
class Certificate(models.Model):
|
||||
_name = 'l10n_es_edi_facturae.certificate'
|
||||
_description = 'Facturae Digital Certificate'
|
||||
_order = 'date_start desc, id desc'
|
||||
_rec_name = 'serial_number'
|
||||
|
||||
content = fields.Binary(string="PFX Certificate", required=True, help="PFX Certificate")
|
||||
password = fields.Char(help="Passphrase for the PFX certificate")
|
||||
serial_number = fields.Char(readonly=True, index=True, help="The serial number to add to electronic documents")
|
||||
date_start = fields.Datetime(readonly=True, help="The date on which the certificate starts to be valid")
|
||||
date_end = fields.Datetime(readonly=True, help="The date on which the certificate expires")
|
||||
company_id = fields.Many2one(comodel_name='res.company', default=lambda self: self.env.company, required=True, readonly=True)
|
||||
|
||||
def _decode_certificate(self):
|
||||
"""
|
||||
Return certificate data
|
||||
|
||||
:return tuple: private_key, certificate
|
||||
"""
|
||||
self.ensure_one()
|
||||
content, password = b64decode(self.with_context(bin_size=False).content), self.password.encode()
|
||||
private_key, certificate, *_dummy = pkcs12.load_key_and_certificates(content, password, backend=default_backend())
|
||||
return private_key, certificate
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# LOW-LEVEL METHODS
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
certificates = super().create(vals_list)
|
||||
for certificate in certificates:
|
||||
try:
|
||||
_key, certif = certificate._decode_certificate()
|
||||
except ValueError:
|
||||
raise UserError(_('There has been a problem with the certificate, some usual problems can be:\n'
|
||||
'\t- The password given or the certificate are not valid.\n'
|
||||
'\t- The certificate content is invalid.'))
|
||||
if fields.datetime.now() > certif.not_valid_after:
|
||||
raise UserError(_('The certificate is expired since %s', certif.not_valid_after))
|
||||
# Assign extracted values from the certificate
|
||||
certificate.write({'serial_number': certif.serial_number, 'date_start': certif.not_valid_before, 'date_end': certif.not_valid_after})
|
||||
return certificates
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# BUSINESS METHODS #
|
||||
# -------------------------------------------------------------------------
|
||||
def _sign_xml(self, edi_data, signature_data):
|
||||
"""
|
||||
Signs the given XML data with the certificate and private key.
|
||||
|
||||
:param etree._Element edi_data: The XML data to sign.
|
||||
:param dict signature_data: The signature data to use.
|
||||
:return: The signed XML data string.
|
||||
:rtype: str
|
||||
"""
|
||||
self.ensure_one()
|
||||
if not (self.date_start < fields.Datetime.now() < self.date_end):
|
||||
raise UserError('Facturae certificate date is not valid, its validity has probably expired')
|
||||
root = deepcopy(edi_data)
|
||||
cert_private, cert_public = self._decode_certificate()
|
||||
public_key_numbers = cert_public.public_key().public_numbers()
|
||||
rdns_pattern = re.compile(r'(?<=\()([A-Z]{1,2}=.*)(?=\))')
|
||||
issuer = ', '.join(sorted(match.group() for match in (rdns_pattern.search(str(element)) for element in cert_public.issuer.rdns) if match))
|
||||
|
||||
# Identifiers
|
||||
document_id = f"Document-{sha1(etree.tostring(edi_data)).hexdigest()}"
|
||||
signature_id = f"Signature-{document_id}"
|
||||
keyinfo_id = f"KeyInfo-{document_id}"
|
||||
sigproperties_id = f"SignatureProperties-{document_id}"
|
||||
|
||||
signature_data.update({
|
||||
'document_id': document_id,
|
||||
'x509_certificate': encodebytes(cert_public.public_bytes(encoding=serialization.Encoding.DER)).decode(),
|
||||
'public_modulus': encodebytes(xml_utils._int_to_bytes(public_key_numbers.n)).decode(),
|
||||
'public_exponent': encodebytes(xml_utils._int_to_bytes(public_key_numbers.e)).decode(),
|
||||
'iso_now': fields.datetime.now().isoformat(),
|
||||
'keyinfo_id': keyinfo_id,
|
||||
'signature_id': signature_id,
|
||||
'sigproperties_id': sigproperties_id,
|
||||
'reference_uri': "Reference-" + document_id,
|
||||
'sigpolicy_url': "http://www.facturae.es/politica_de_firma_formato_facturae/politica_de_firma_formato_facturae_v3_1.pdf",
|
||||
'sigpolicy_description': "Política de firma electrónica para facturación electrónica con formato Facturae",
|
||||
'sigcertif_digest': b64encode(cert_public.fingerprint(hashes.SHA256())).decode(),
|
||||
'x509_issuer_description': issuer,
|
||||
'x509_serial_number': cert_public.serial_number,
|
||||
})
|
||||
signature = self.env['ir.qweb']._render('l10n_es_edi_facturae.template_xades_signature', signature_data)
|
||||
signature = cleanup_xml_node(signature, remove_blank_nodes=False)
|
||||
root.append(signature)
|
||||
xml_utils._reference_digests(signature.find("ds:SignedInfo", namespaces=xml_utils.NS_MAP))
|
||||
xml_utils._fill_signature(signature, cert_private)
|
||||
|
||||
return etree.tostring(root, xml_declaration=True, encoding='UTF-8', standalone=True)
|
||||
@@ -0,0 +1,9 @@
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class Company(models.Model):
|
||||
_inherit = 'res.company'
|
||||
|
||||
l10n_es_edi_facturae_residence_type = fields.Char(string='Facturae EDI Residency Type Code', related='partner_id.l10n_es_edi_facturae_residence_type')
|
||||
l10n_es_edi_facturae_certificate_id = fields.One2many(string='Facturae EDI signing certificate',
|
||||
comodel_name='l10n_es_edi_facturae.certificate', inverse_name='company_id')
|
||||
@@ -0,0 +1,20 @@
|
||||
from odoo import api, fields, models
|
||||
|
||||
|
||||
class Partner(models.Model):
|
||||
_inherit = 'res.partner'
|
||||
|
||||
l10n_es_edi_facturae_residence_type = fields.Char(string='Facturae EDI Residency Type Code',
|
||||
compute='_compute_l10n_es_edi_facturae_residence_type', store=False, readonly=True,)
|
||||
|
||||
@api.depends('country_id')
|
||||
def _compute_l10n_es_edi_facturae_residence_type(self):
|
||||
eu_country_ids = self.env.ref('base.europe').country_ids.ids
|
||||
for partner in self:
|
||||
country = partner.country_id
|
||||
if country.code == 'ES':
|
||||
partner.l10n_es_edi_facturae_residence_type = 'R'
|
||||
elif country.id in eu_country_ids:
|
||||
partner.l10n_es_edi_facturae_residence_type = 'U'
|
||||
else:
|
||||
partner.l10n_es_edi_facturae_residence_type = 'E'
|
||||
@@ -0,0 +1,44 @@
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class UoM(models.Model):
|
||||
_inherit = 'uom.uom'
|
||||
|
||||
l10n_es_edi_facturae_uom_code = fields.Selection(
|
||||
selection=[
|
||||
('01', 'Units'),
|
||||
('02', 'Hours'),
|
||||
('03', 'Kilograms'),
|
||||
('04', 'Liters'),
|
||||
('05', 'Other'),
|
||||
('06', 'Boxes'),
|
||||
('07', 'Trays, one layer no cover, plastic'),
|
||||
('08', 'Barrels'),
|
||||
('09', 'Jerricans, cylindrical'),
|
||||
('10', 'Bags'),
|
||||
('11', 'Carboys, non-protected'),
|
||||
('12', 'Bottles, non-protected, cylindrical'),
|
||||
('13', 'Canisters'),
|
||||
('14', 'Tetra Briks'),
|
||||
('15', 'Centiliters'),
|
||||
('16', 'Centimeters'),
|
||||
('17', 'Bins'),
|
||||
('18', 'Dozens'),
|
||||
('19', 'Cases'),
|
||||
('20', 'Demijohns, non-protected'),
|
||||
('21', 'Grams'),
|
||||
('22', 'Kilometers'),
|
||||
('23', 'Cans, rectangular'),
|
||||
('24', 'Bunches'),
|
||||
('25', 'Meters'),
|
||||
('26', 'Millimeters'),
|
||||
('27', '6-Packs'),
|
||||
('28', 'Packages'),
|
||||
('29', 'Portions'),
|
||||
('30', 'Rolls'),
|
||||
('31', 'Envelopes'),
|
||||
('32', 'Tubs'),
|
||||
('33', 'Cubic meter'),
|
||||
('34', 'Second'),
|
||||
('35', 'Watt'),
|
||||
], string='Spanish EDI Units', default="05", required=True)
|
||||
@@ -0,0 +1,3 @@
|
||||
id,name,model_id/id,group_id/id,perm_read,perm_write,perm_create,perm_unlink
|
||||
l10n_es_edi_facturae.access_l10n_es_edi_facturae_certificate_manager,access_l10n_es_edi_facturae_certificate,l10n_es_edi_facturae.model_l10n_es_edi_facturae_certificate,account.group_account_manager,1,0,0,0
|
||||
l10n_es_edi_facturae.access_l10n_es_edi_facturae_certificate_system,access_l10n_es_edi_facturae_certificate,l10n_es_edi_facturae.model_l10n_es_edi_facturae_certificate,base.group_system,1,1,1,1
|
||||
|
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo noupdate="1">
|
||||
<!-- Allow read certificates of my company-->
|
||||
<record id="facturae_digital_certificate" model="ir.rule">
|
||||
<field name="name">Facturae Digital Certificate</field>
|
||||
<field name="model_id" ref="l10n_es_edi_facturae.model_l10n_es_edi_facturae_certificate"/>
|
||||
<field name="groups" eval="[Command.link(ref('account.group_account_user')), Command.link(ref('account.group_account_manager'))]"/>
|
||||
<field name="domain_force">[('company_id', 'in', user.company_ids.ids)]</field>
|
||||
</record>
|
||||
</odoo>
|
||||
@@ -0,0 +1 @@
|
||||
from . import test_edi_xml
|
||||
Binary file not shown.
@@ -0,0 +1,358 @@
|
||||
<?xml version='1.0' encoding='UTF-8' standalone='yes'?>
|
||||
<fac:Facturae xmlns:fac="http://www.facturae.es/Facturae/2014/v3.2.1/Facturae">
|
||||
<FileHeader>
|
||||
<SchemaVersion>3.2.1</SchemaVersion>
|
||||
<Modality>I</Modality>
|
||||
<InvoiceIssuerType>RE</InvoiceIssuerType>
|
||||
<Batch>
|
||||
<BatchIdentifier>BILL/2023/01/0001</BatchIdentifier>
|
||||
<InvoicesCount>1</InvoicesCount>
|
||||
<TotalInvoicesAmount>
|
||||
<TotalAmount>2904.00</TotalAmount>
|
||||
</TotalInvoicesAmount>
|
||||
<TotalOutstandingAmount>
|
||||
<TotalAmount>2904.00</TotalAmount>
|
||||
</TotalOutstandingAmount>
|
||||
<TotalExecutableAmount>
|
||||
<TotalAmount>2904.00</TotalAmount>
|
||||
</TotalExecutableAmount>
|
||||
<InvoiceCurrencyCode>EUR</InvoiceCurrencyCode>
|
||||
</Batch>
|
||||
</FileHeader>
|
||||
<Parties>
|
||||
<SellerParty>
|
||||
<TaxIdentification>
|
||||
<PersonTypeCode>F</PersonTypeCode>
|
||||
<ResidenceTypeCode>U</ResidenceTypeCode>
|
||||
<TaxIdentificationNumber>BE0477472701</TaxIdentificationNumber>
|
||||
</TaxIdentification>
|
||||
<Individual>
|
||||
<Name>UNKNOWN</Name>
|
||||
<FirstSurname>UNKNOWN</FirstSurname>
|
||||
<OverseasAddress>
|
||||
<Address>Rue de Bruxelles, 15000</Address>
|
||||
<PostCodeAndTown>5000 Namur</PostCodeAndTown>
|
||||
<Province>Belgium</Province>
|
||||
<CountryCode>BEL</CountryCode>
|
||||
</OverseasAddress>
|
||||
</Individual>
|
||||
</SellerParty>
|
||||
<BuyerParty>
|
||||
<TaxIdentification>
|
||||
<PersonTypeCode>J</PersonTypeCode>
|
||||
<ResidenceTypeCode>R</ResidenceTypeCode>
|
||||
<TaxIdentificationNumber>ES59962470K</TaxIdentificationNumber>
|
||||
</TaxIdentification>
|
||||
<LegalEntity>
|
||||
<CorporateName>company_1_data</CorporateName>
|
||||
<TradeName>company_1_data</TradeName>
|
||||
<AddressInSpain>
|
||||
<Address>C. de Embajadores, 68-116</Address>
|
||||
<PostCode>12345</PostCode>
|
||||
<Town>Madrid</Town>
|
||||
<Province>Madrid</Province>
|
||||
<CountryCode>ESP</CountryCode>
|
||||
</AddressInSpain>
|
||||
</LegalEntity>
|
||||
</BuyerParty>
|
||||
</Parties>
|
||||
<Invoices>
|
||||
<Invoice>
|
||||
<InvoiceHeader>
|
||||
<InvoiceNumber>BILL/2023/01/0001</InvoiceNumber>
|
||||
<InvoiceDocumentType>FC</InvoiceDocumentType>
|
||||
<InvoiceClass>OO</InvoiceClass>
|
||||
</InvoiceHeader>
|
||||
<InvoiceIssueData>
|
||||
<IssueDate>2023-01-01</IssueDate>
|
||||
<InvoiceCurrencyCode>EUR</InvoiceCurrencyCode>
|
||||
<TaxCurrencyCode>EUR</TaxCurrencyCode>
|
||||
<LanguageName>en</LanguageName>
|
||||
</InvoiceIssueData>
|
||||
<TaxesOutputs>
|
||||
<Tax>
|
||||
<TaxTypeCode>01</TaxTypeCode>
|
||||
<TaxRate>21.000</TaxRate>
|
||||
<TaxableBase>
|
||||
<TotalAmount>100.00</TotalAmount>
|
||||
</TaxableBase>
|
||||
<TaxAmount>
|
||||
<TotalAmount>21.00</TotalAmount>
|
||||
</TaxAmount>
|
||||
</Tax>
|
||||
<Tax>
|
||||
<TaxTypeCode>01</TaxTypeCode>
|
||||
<TaxRate>21.000</TaxRate>
|
||||
<TaxableBase>
|
||||
<TotalAmount>100.00</TotalAmount>
|
||||
</TaxableBase>
|
||||
<TaxAmount>
|
||||
<TotalAmount>21.00</TotalAmount>
|
||||
</TaxAmount>
|
||||
</Tax>
|
||||
<Tax>
|
||||
<TaxTypeCode>01</TaxTypeCode>
|
||||
<TaxRate>21.000</TaxRate>
|
||||
<TaxableBase>
|
||||
<TotalAmount>200.00</TotalAmount>
|
||||
</TaxableBase>
|
||||
<TaxAmount>
|
||||
<TotalAmount>42.00</TotalAmount>
|
||||
</TaxAmount>
|
||||
</Tax>
|
||||
<Tax>
|
||||
<TaxTypeCode>01</TaxTypeCode>
|
||||
<TaxRate>21.000</TaxRate>
|
||||
<TaxableBase>
|
||||
<TotalAmount>900.00</TotalAmount>
|
||||
</TaxableBase>
|
||||
<TaxAmount>
|
||||
<TotalAmount>189.00</TotalAmount>
|
||||
</TaxAmount>
|
||||
</Tax>
|
||||
<Tax>
|
||||
<TaxTypeCode>01</TaxTypeCode>
|
||||
<TaxRate>21.000</TaxRate>
|
||||
<TaxableBase>
|
||||
<TotalAmount>1100.00</TotalAmount>
|
||||
</TaxableBase>
|
||||
<TaxAmount>
|
||||
<TotalAmount>231.00</TotalAmount>
|
||||
</TaxAmount>
|
||||
</Tax>
|
||||
</TaxesOutputs>
|
||||
<InvoiceTotals>
|
||||
<TotalGrossAmount>2400.00</TotalGrossAmount>
|
||||
<TotalGeneralDiscounts>100.00</TotalGeneralDiscounts>
|
||||
<TotalGeneralSurcharges>100.00</TotalGeneralSurcharges>
|
||||
<TotalGrossAmountBeforeTaxes>2400.00</TotalGrossAmountBeforeTaxes>
|
||||
<TotalTaxOutputs>504.00</TotalTaxOutputs>
|
||||
<TotalTaxesWithheld>0.00</TotalTaxesWithheld>
|
||||
<InvoiceTotal>2904.00</InvoiceTotal>
|
||||
<TotalOutstandingAmount>2904.00</TotalOutstandingAmount>
|
||||
<TotalExecutableAmount>2904.00</TotalExecutableAmount>
|
||||
</InvoiceTotals>
|
||||
<Items>
|
||||
<InvoiceLine>
|
||||
<ItemDescription>product_a</ItemDescription>
|
||||
<Quantity>1.0</Quantity>
|
||||
<UnitOfMeasure>01</UnitOfMeasure>
|
||||
<UnitPriceWithoutTax>100.00</UnitPriceWithoutTax>
|
||||
<TotalCost>100.00</TotalCost>
|
||||
<GrossAmount>100.00</GrossAmount>
|
||||
<TaxesOutputs>
|
||||
<Tax>
|
||||
<TaxTypeCode>01</TaxTypeCode>
|
||||
<TaxRate>21.000</TaxRate>
|
||||
<TaxableBase>
|
||||
<TotalAmount>100.00</TotalAmount>
|
||||
</TaxableBase>
|
||||
<TaxAmount>
|
||||
<TotalAmount>21.00</TotalAmount>
|
||||
</TaxAmount>
|
||||
</Tax>
|
||||
</TaxesOutputs>
|
||||
</InvoiceLine>
|
||||
<InvoiceLine>
|
||||
<ItemDescription>product_a</ItemDescription>
|
||||
<Quantity>1.0</Quantity>
|
||||
<UnitOfMeasure>01</UnitOfMeasure>
|
||||
<UnitPriceWithoutTax>100.00</UnitPriceWithoutTax>
|
||||
<TotalCost>100.00</TotalCost>
|
||||
<GrossAmount>100.00</GrossAmount>
|
||||
<TaxesOutputs>
|
||||
<Tax>
|
||||
<TaxTypeCode>01</TaxTypeCode>
|
||||
<TaxRate>21.000</TaxRate>
|
||||
<TaxableBase>
|
||||
<TotalAmount>100.00</TotalAmount>
|
||||
</TaxableBase>
|
||||
<TaxAmount>
|
||||
<TotalAmount>21.00</TotalAmount>
|
||||
</TaxAmount>
|
||||
</Tax>
|
||||
</TaxesOutputs>
|
||||
</InvoiceLine>
|
||||
<InvoiceLine>
|
||||
<ItemDescription>product_a</ItemDescription>
|
||||
<Quantity>1.0</Quantity>
|
||||
<UnitOfMeasure>01</UnitOfMeasure>
|
||||
<UnitPriceWithoutTax>200.00</UnitPriceWithoutTax>
|
||||
<TotalCost>200.00</TotalCost>
|
||||
<GrossAmount>200.00</GrossAmount>
|
||||
<TaxesOutputs>
|
||||
<Tax>
|
||||
<TaxTypeCode>01</TaxTypeCode>
|
||||
<TaxRate>21.000</TaxRate>
|
||||
<TaxableBase>
|
||||
<TotalAmount>200.00</TotalAmount>
|
||||
</TaxableBase>
|
||||
<TaxAmount>
|
||||
<TotalAmount>42.00</TotalAmount>
|
||||
</TaxAmount>
|
||||
</Tax>
|
||||
</TaxesOutputs>
|
||||
</InvoiceLine>
|
||||
<InvoiceLine>
|
||||
<ItemDescription>product_a</ItemDescription>
|
||||
<Quantity>1.0</Quantity>
|
||||
<UnitOfMeasure>01</UnitOfMeasure>
|
||||
<UnitPriceWithoutTax>1000.00</UnitPriceWithoutTax>
|
||||
<TotalCost>1000.00</TotalCost>
|
||||
<DiscountsAndRebates>
|
||||
<Discount>
|
||||
<DiscountRate>10.00</DiscountRate>
|
||||
<DiscountAmount>100.00</DiscountAmount>
|
||||
</Discount>
|
||||
</DiscountsAndRebates>
|
||||
<GrossAmount>900.00</GrossAmount>
|
||||
<TaxesOutputs>
|
||||
<Tax>
|
||||
<TaxTypeCode>01</TaxTypeCode>
|
||||
<TaxRate>21.000</TaxRate>
|
||||
<TaxableBase>
|
||||
<TotalAmount>900.00</TotalAmount>
|
||||
</TaxableBase>
|
||||
<TaxAmount>
|
||||
<TotalAmount>189.00</TotalAmount>
|
||||
</TaxAmount>
|
||||
</Tax>
|
||||
</TaxesOutputs>
|
||||
</InvoiceLine>
|
||||
<InvoiceLine>
|
||||
<ItemDescription>product_a</ItemDescription>
|
||||
<Quantity>1.0</Quantity>
|
||||
<UnitOfMeasure>01</UnitOfMeasure>
|
||||
<UnitPriceWithoutTax>1000.00</UnitPriceWithoutTax>
|
||||
<TotalCost>1000.00</TotalCost>
|
||||
<Charges>
|
||||
<Charge>
|
||||
<ChargeRate>10.00</ChargeRate>
|
||||
<ChargeAmount>100.00</ChargeAmount>
|
||||
</Charge>
|
||||
</Charges>
|
||||
<GrossAmount>1100.00</GrossAmount>
|
||||
<TaxesOutputs>
|
||||
<Tax>
|
||||
<TaxTypeCode>01</TaxTypeCode>
|
||||
<TaxRate>21.000</TaxRate>
|
||||
<TaxableBase>
|
||||
<TotalAmount>1100.00</TotalAmount>
|
||||
</TaxableBase>
|
||||
<TaxAmount>
|
||||
<TotalAmount>231.00</TotalAmount>
|
||||
</TaxAmount>
|
||||
</Tax>
|
||||
</TaxesOutputs>
|
||||
</InvoiceLine>
|
||||
</Items>
|
||||
</Invoice>
|
||||
</Invoices>
|
||||
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#" Id="Signature-Document-da39a3ee5e6b4b0d3255bfef95601890afd80709">
|
||||
<ds:SignedInfo>
|
||||
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
|
||||
<ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
|
||||
<ds:Reference Type="http://www.w3.org/2000/09/xmldsig#Object" URI="" Id="Reference-Document-da39a3ee5e6b4b0d3255bfef95601890afd80709">
|
||||
<ds:Transforms>
|
||||
<ds:Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
|
||||
<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
|
||||
<ds:Transform Algorithm="http://www.w3.org/TR/1999/REC-xpath-19991116">
|
||||
<ds:XPath>not(ancestor-or-self::ds:Signature)</ds:XPath>
|
||||
</ds:Transform>
|
||||
</ds:Transforms>
|
||||
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
|
||||
<ds:DigestValue>___ignore___</ds:DigestValue>
|
||||
</ds:Reference>
|
||||
<ds:Reference Type="http://uri.etsi.org/01903#SignedProperties" URI="#SignatureProperties-Document-da39a3ee5e6b4b0d3255bfef95601890afd80709">
|
||||
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
|
||||
<ds:DigestValue>UQH7ea0mtLoqLN/aM5mWssQ38fOK1bxnWT4fKQBYiSI=</ds:DigestValue>
|
||||
</ds:Reference>
|
||||
<ds:Reference URI="#KeyInfo-Document-da39a3ee5e6b4b0d3255bfef95601890afd80709">
|
||||
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
|
||||
<ds:DigestValue>wwDtGZ3EpRH8tRKQ8lKgbpfDkE1Zmza9QHkjJDN1Nmw=</ds:DigestValue>
|
||||
</ds:Reference>
|
||||
</ds:SignedInfo>
|
||||
<ds:SignatureValue>___ignore___</ds:SignatureValue>
|
||||
<ds:KeyInfo Id="KeyInfo-Document-da39a3ee5e6b4b0d3255bfef95601890afd80709">
|
||||
<ds:X509Data>
|
||||
<ds:X509Certificate>MIID8jCCAtqgAwIBAgIUYBl+61DsTkNyyUFGveskbaGP/SkwDQYJKoZIhvcNAQELBQAwgYoxCzAJ
|
||||
BgNVBAYTAkJFMRIwEAYDVQQIDAlXYWxsb25uaWExEjAQBgNVBAcMCVJhbWlsbGllczENMAsGA1UE
|
||||
CgwET2RvbzEMMAoGA1UECwwDUiZEMRgwFgYDVQQDDA9ydW5ib3Qub2Rvby5jb20xHDAaBgkqhkiG
|
||||
9w0BCQEWDWluZm9Ab2Rvby5jb20wHhcNMjIwNDI2MDczMTUwWhcNMjMwNDI2MDczMTUwWjCBlTEL
|
||||
MAkGA1UEBhMCQkUxEjAQBgNVBAgMCVdhbGxvbm5pYTESMBAGA1UEBwwJUmFtaWxsaWVzMRIwEAYD
|
||||
VQQKDAlPZG9vIFMuQS4xGTAXBgNVBAsMEFImRCAtIEFjY291bnRpbmcxETAPBgNVBAMMCG9kb28u
|
||||
Y29tMRwwGgYJKoZIhvcNAQkBFg1pbmZvQG9kb28uY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
|
||||
MIIBCgKCAQEAtGUbyNJrA3yyOC01gIMR1A1rWIHCHD+afLCLCddBDZwC4Q034yFBuMqQFNWaxxLc
|
||||
9s+wFbNZqu5D7rynN3qXvWJj40VZxygoV/09y71IhaspuAZ0rdzYsqjDmTJiPSrEl6iydF2eq6sJ
|
||||
4J0ItCUFc2e88B25wz7esslAN249C20oQj5ZiGifR4P0CRQSmDy0SPYZGxTurVwtq6IsYbOqEw8/
|
||||
Wqx6ApOltperFX88DZCdbY59ZedqQrGQh2Z5Au7h/8nhmdbpz7Ixw2zocxVigR0ClNDpKKxvolX1
|
||||
virQpICkfWcAaWAYAMCL4KhvISclysD+5juDLpGCLHPtKxBXTQIDAQABo0MwQTAfBgNVHSMEGDAW
|
||||
gBTmxEG4Ub7b5wRXqWea94Vs1hB13zAJBgNVHRMEAjAAMBMGA1UdEQQMMAqCCG9kb28uY29tMA0G
|
||||
CSqGSIb3DQEBCwUAA4IBAQAFLvTlSELTVWRfIlGthoFOmkv8MrwJuo8y7qTmvsFXeA2hZtsPdNxx
|
||||
iwAGPobiUO0GCEPUFKZ7NksQa7DAKGXfb5RSwfujDfEMAhgi00+wF1VIKeKqnGt4idzCr+2NtiQY
|
||||
e9oK+Ee7o82llnNFwbWvRKx55lhHW3bwN6Tl31qUYbxacJyA9z5sQpe2zImWMVsm4g7OAjzg3Cn2
|
||||
0TFu+0XekB892n7DYh4gHiMWaMOVYmi/aEWLSqxMlbiHQr75FmPftozFvTxW26jU3ALhq+yXPVa4
|
||||
lg4r/h6HH5TbtSjYzTSJ4MvMyrECgIQYf0zsS4D6K/GvCZbu7LKHRwuC0fis</ds:X509Certificate>
|
||||
</ds:X509Data>
|
||||
<ds:KeyValue>
|
||||
<ds:RSAKeyValue>
|
||||
<ds:Modulus>tGUbyNJrA3yyOC01gIMR1A1rWIHCHD+afLCLCddBDZwC4Q034yFBuMqQFNWaxxLc9s+wFbNZqu5D
|
||||
7rynN3qXvWJj40VZxygoV/09y71IhaspuAZ0rdzYsqjDmTJiPSrEl6iydF2eq6sJ4J0ItCUFc2e8
|
||||
8B25wz7esslAN249C20oQj5ZiGifR4P0CRQSmDy0SPYZGxTurVwtq6IsYbOqEw8/Wqx6ApOltper
|
||||
FX88DZCdbY59ZedqQrGQh2Z5Au7h/8nhmdbpz7Ixw2zocxVigR0ClNDpKKxvolX1virQpICkfWcA
|
||||
aWAYAMCL4KhvISclysD+5juDLpGCLHPtKxBXTQ==</ds:Modulus>
|
||||
<ds:Exponent>AQAB</ds:Exponent>
|
||||
</ds:RSAKeyValue>
|
||||
</ds:KeyValue>
|
||||
</ds:KeyInfo>
|
||||
<ds:Object>
|
||||
<xades:QualifyingProperties xmlns:xades="http://uri.etsi.org/01903/v1.3.2#" Target="#Signature-Document-da39a3ee5e6b4b0d3255bfef95601890afd80709">
|
||||
<xades:SignedProperties Id="SignatureProperties-Document-da39a3ee5e6b4b0d3255bfef95601890afd80709">
|
||||
<xades:SignedSignatureProperties>
|
||||
<xades:SigningTime>2023-01-01T00:00:00</xades:SigningTime>
|
||||
<xades:SigningCertificateV2>
|
||||
<xades:Cert>
|
||||
<xades:CertDigest>
|
||||
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
|
||||
<ds:DigestValue>FHf2lN+5FALNa7JXV2+pByL92/dr8LeCVhpItYic5oA=</ds:DigestValue>
|
||||
</xades:CertDigest>
|
||||
<xades:IssuerSerial>
|
||||
<ds:X509IssuerName>C=BE, CN=runbot.odoo.com, L=Ramillies, O=Odoo, OU=R&D, ST=Wallonnia</ds:X509IssuerName>
|
||||
<ds:X509SerialNumber>548631688851000697209704649636588277530075594025</ds:X509SerialNumber>
|
||||
</xades:IssuerSerial>
|
||||
</xades:Cert>
|
||||
</xades:SigningCertificateV2>
|
||||
<xades:SignaturePolicyIdentifier>
|
||||
<xades:SignaturePolicyId>
|
||||
<xades:SigPolicyId>
|
||||
<xades:Identifier>http://www.facturae.es/politica_de_firma_formato_facturae/politica_de_firma_formato_facturae_v3_1.pdf</xades:Identifier>
|
||||
<xades:Description>Política de firma electrónica para facturación electrónica con formato Facturae</xades:Description>
|
||||
</xades:SigPolicyId>
|
||||
<xades:SigPolicyHash>
|
||||
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
|
||||
<ds:DigestValue>a/vDoueJq9zxWGCFwdsXdlXtkFSEek4XVtmlQCEDaE8=</ds:DigestValue>
|
||||
</xades:SigPolicyHash>
|
||||
<xades:SigPolicyQualifiers>
|
||||
<xades:SigPolicyQualifier>
|
||||
<xades:SPURI>http://www.facturae.es/politica_de_firma_formato_facturae/politica_de_firma_formato_facturae_v3_1.pdf</xades:SPURI>
|
||||
</xades:SigPolicyQualifier>
|
||||
</xades:SigPolicyQualifiers>
|
||||
</xades:SignaturePolicyId>
|
||||
</xades:SignaturePolicyIdentifier>
|
||||
</xades:SignedSignatureProperties>
|
||||
<xades:SignedDataObjectProperties>
|
||||
<xades:DataObjectFormat ObjectReference="#Reference-Document-da39a3ee5e6b4b0d3255bfef95601890afd80709">
|
||||
<xades:Description/>
|
||||
<xades:ObjectIdentifier>
|
||||
<xades:Identifier Qualifier="OIDAsURN">urn:oid:1.2.840.10003.5.109.10</xades:Identifier>
|
||||
<xades:Description/>
|
||||
</xades:ObjectIdentifier>
|
||||
<xades:MimeType>text/xml</xades:MimeType>
|
||||
<xades:Encoding/>
|
||||
</xades:DataObjectFormat>
|
||||
</xades:SignedDataObjectProperties>
|
||||
</xades:SignedProperties>
|
||||
</xades:QualifyingProperties>
|
||||
</ds:Object>
|
||||
</ds:Signature>
|
||||
</fac:Facturae>
|
||||
@@ -0,0 +1,265 @@
|
||||
<?xml version='1.0' encoding='UTF-8' standalone='yes'?>
|
||||
<fac:Facturae xmlns:fac="http://www.facturae.es/Facturae/2014/v3.2.1/Facturae">
|
||||
<FileHeader>
|
||||
<SchemaVersion>3.2.1</SchemaVersion>
|
||||
<Modality>I</Modality>
|
||||
<InvoiceIssuerType>EM</InvoiceIssuerType>
|
||||
<Batch>
|
||||
<BatchIdentifier>RINV/2023/00001</BatchIdentifier>
|
||||
<InvoicesCount>1</InvoicesCount>
|
||||
<TotalInvoicesAmount>
|
||||
<TotalAmount>-242.00</TotalAmount>
|
||||
</TotalInvoicesAmount>
|
||||
<TotalOutstandingAmount>
|
||||
<TotalAmount>-242.00</TotalAmount>
|
||||
</TotalOutstandingAmount>
|
||||
<TotalExecutableAmount>
|
||||
<TotalAmount>-242.00</TotalAmount>
|
||||
</TotalExecutableAmount>
|
||||
<InvoiceCurrencyCode>EUR</InvoiceCurrencyCode>
|
||||
</Batch>
|
||||
</FileHeader>
|
||||
<Parties>
|
||||
<SellerParty>
|
||||
<TaxIdentification>
|
||||
<PersonTypeCode>J</PersonTypeCode>
|
||||
<ResidenceTypeCode>R</ResidenceTypeCode>
|
||||
<TaxIdentificationNumber>ES59962470K</TaxIdentificationNumber>
|
||||
</TaxIdentification>
|
||||
<LegalEntity>
|
||||
<CorporateName>company_1_data</CorporateName>
|
||||
<TradeName>company_1_data</TradeName>
|
||||
<AddressInSpain>
|
||||
<Address>C. de Embajadores, 68-116</Address>
|
||||
<PostCode>12345</PostCode>
|
||||
<Town>Madrid</Town>
|
||||
<Province>Madrid</Province>
|
||||
<CountryCode>ESP</CountryCode>
|
||||
</AddressInSpain>
|
||||
</LegalEntity>
|
||||
</SellerParty>
|
||||
<BuyerParty>
|
||||
<TaxIdentification>
|
||||
<PersonTypeCode>F</PersonTypeCode>
|
||||
<ResidenceTypeCode>U</ResidenceTypeCode>
|
||||
<TaxIdentificationNumber>BE0477472701</TaxIdentificationNumber>
|
||||
</TaxIdentification>
|
||||
<Individual>
|
||||
<Name>UNKNOWN</Name>
|
||||
<FirstSurname>UNKNOWN</FirstSurname>
|
||||
<OverseasAddress>
|
||||
<Address>Rue de Bruxelles, 15000</Address>
|
||||
<PostCodeAndTown>5000 Namur</PostCodeAndTown>
|
||||
<Province>Belgium</Province>
|
||||
<CountryCode>BEL</CountryCode>
|
||||
</OverseasAddress>
|
||||
</Individual>
|
||||
</BuyerParty>
|
||||
</Parties>
|
||||
<Invoices>
|
||||
<Invoice>
|
||||
<InvoiceHeader>
|
||||
<InvoiceNumber>RINV/2023/00001</InvoiceNumber>
|
||||
<InvoiceDocumentType>FC</InvoiceDocumentType>
|
||||
<InvoiceClass>OO</InvoiceClass>
|
||||
<Corrective>
|
||||
<InvoiceNumber>INV/2023/00001</InvoiceNumber>
|
||||
<ReasonCode>01</ReasonCode>
|
||||
<ReasonDescription>Invoice number</ReasonDescription>
|
||||
<TaxPeriod>
|
||||
<StartDate>2023-01-01</StartDate>
|
||||
<EndDate>2023-01-31</EndDate>
|
||||
</TaxPeriod>
|
||||
<CorrectionMethod>01</CorrectionMethod>
|
||||
<CorrectionMethodDescription>Rectificación modelo íntegro.</CorrectionMethodDescription>
|
||||
</Corrective>
|
||||
</InvoiceHeader>
|
||||
<InvoiceIssueData>
|
||||
<IssueDate>2023-01-01</IssueDate>
|
||||
<InvoiceCurrencyCode>EUR</InvoiceCurrencyCode>
|
||||
<TaxCurrencyCode>EUR</TaxCurrencyCode>
|
||||
<LanguageName>en</LanguageName>
|
||||
</InvoiceIssueData>
|
||||
<TaxesOutputs>
|
||||
<Tax>
|
||||
<TaxTypeCode>01</TaxTypeCode>
|
||||
<TaxRate>21.000</TaxRate>
|
||||
<TaxableBase>
|
||||
<TotalAmount>-100.00</TotalAmount>
|
||||
</TaxableBase>
|
||||
<TaxAmount>
|
||||
<TotalAmount>-21.00</TotalAmount>
|
||||
</TaxAmount>
|
||||
</Tax>
|
||||
<Tax>
|
||||
<TaxTypeCode>01</TaxTypeCode>
|
||||
<TaxRate>21.000</TaxRate>
|
||||
<TaxableBase>
|
||||
<TotalAmount>-100.00</TotalAmount>
|
||||
</TaxableBase>
|
||||
<TaxAmount>
|
||||
<TotalAmount>-21.00</TotalAmount>
|
||||
</TaxAmount>
|
||||
</Tax>
|
||||
</TaxesOutputs>
|
||||
<InvoiceTotals>
|
||||
<TotalGrossAmount>-200.00</TotalGrossAmount>
|
||||
<TotalGrossAmountBeforeTaxes>-200.00</TotalGrossAmountBeforeTaxes>
|
||||
<TotalTaxOutputs>-42.00</TotalTaxOutputs>
|
||||
<TotalTaxesWithheld>-0.00</TotalTaxesWithheld>
|
||||
<InvoiceTotal>-242.00</InvoiceTotal>
|
||||
<TotalOutstandingAmount>-242.00</TotalOutstandingAmount>
|
||||
<TotalExecutableAmount>-242.00</TotalExecutableAmount>
|
||||
</InvoiceTotals>
|
||||
<Items>
|
||||
<InvoiceLine>
|
||||
<ItemDescription>product_a</ItemDescription>
|
||||
<Quantity>1.0</Quantity>
|
||||
<UnitOfMeasure>01</UnitOfMeasure>
|
||||
<UnitPriceWithoutTax>-100.00</UnitPriceWithoutTax>
|
||||
<TotalCost>-100.00</TotalCost>
|
||||
<GrossAmount>-100.00</GrossAmount>
|
||||
<TaxesOutputs>
|
||||
<Tax>
|
||||
<TaxTypeCode>01</TaxTypeCode>
|
||||
<TaxRate>21.000</TaxRate>
|
||||
<TaxableBase>
|
||||
<TotalAmount>-100.00</TotalAmount>
|
||||
</TaxableBase>
|
||||
<TaxAmount>
|
||||
<TotalAmount>-21.00</TotalAmount>
|
||||
</TaxAmount>
|
||||
</Tax>
|
||||
</TaxesOutputs>
|
||||
</InvoiceLine>
|
||||
<InvoiceLine>
|
||||
<ItemDescription>product_a</ItemDescription>
|
||||
<Quantity>1.0</Quantity>
|
||||
<UnitOfMeasure>01</UnitOfMeasure>
|
||||
<UnitPriceWithoutTax>-100.00</UnitPriceWithoutTax>
|
||||
<TotalCost>-100.00</TotalCost>
|
||||
<GrossAmount>-100.00</GrossAmount>
|
||||
<TaxesOutputs>
|
||||
<Tax>
|
||||
<TaxTypeCode>01</TaxTypeCode>
|
||||
<TaxRate>21.000</TaxRate>
|
||||
<TaxableBase>
|
||||
<TotalAmount>-100.00</TotalAmount>
|
||||
</TaxableBase>
|
||||
<TaxAmount>
|
||||
<TotalAmount>-21.00</TotalAmount>
|
||||
</TaxAmount>
|
||||
</Tax>
|
||||
</TaxesOutputs>
|
||||
</InvoiceLine>
|
||||
</Items>
|
||||
</Invoice>
|
||||
</Invoices>
|
||||
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#" Id="Signature-Document-da39a3ee5e6b4b0d3255bfef95601890afd80709">
|
||||
<ds:SignedInfo>
|
||||
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
|
||||
<ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
|
||||
<ds:Reference Type="http://www.w3.org/2000/09/xmldsig#Object" URI="" Id="Reference-Document-da39a3ee5e6b4b0d3255bfef95601890afd80709">
|
||||
<ds:Transforms>
|
||||
<ds:Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
|
||||
<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
|
||||
<ds:Transform Algorithm="http://www.w3.org/TR/1999/REC-xpath-19991116">
|
||||
<ds:XPath>not(ancestor-or-self::ds:Signature)</ds:XPath>
|
||||
</ds:Transform>
|
||||
</ds:Transforms>
|
||||
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
|
||||
<ds:DigestValue>___ignore___</ds:DigestValue>
|
||||
</ds:Reference>
|
||||
<ds:Reference Type="http://uri.etsi.org/01903#SignedProperties" URI="#SignatureProperties-Document-da39a3ee5e6b4b0d3255bfef95601890afd80709">
|
||||
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
|
||||
<ds:DigestValue>UQH7ea0mtLoqLN/aM5mWssQ38fOK1bxnWT4fKQBYiSI=</ds:DigestValue>
|
||||
</ds:Reference>
|
||||
<ds:Reference URI="#KeyInfo-Document-da39a3ee5e6b4b0d3255bfef95601890afd80709">
|
||||
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
|
||||
<ds:DigestValue>wwDtGZ3EpRH8tRKQ8lKgbpfDkE1Zmza9QHkjJDN1Nmw=</ds:DigestValue>
|
||||
</ds:Reference>
|
||||
</ds:SignedInfo>
|
||||
<ds:SignatureValue>___ignore___</ds:SignatureValue>
|
||||
<ds:KeyInfo Id="KeyInfo-Document-da39a3ee5e6b4b0d3255bfef95601890afd80709">
|
||||
<ds:X509Data>
|
||||
<ds:X509Certificate>MIID8jCCAtqgAwIBAgIUYBl+61DsTkNyyUFGveskbaGP/SkwDQYJKoZIhvcNAQELBQAwgYoxCzAJ
|
||||
BgNVBAYTAkJFMRIwEAYDVQQIDAlXYWxsb25uaWExEjAQBgNVBAcMCVJhbWlsbGllczENMAsGA1UE
|
||||
CgwET2RvbzEMMAoGA1UECwwDUiZEMRgwFgYDVQQDDA9ydW5ib3Qub2Rvby5jb20xHDAaBgkqhkiG
|
||||
9w0BCQEWDWluZm9Ab2Rvby5jb20wHhcNMjIwNDI2MDczMTUwWhcNMjMwNDI2MDczMTUwWjCBlTEL
|
||||
MAkGA1UEBhMCQkUxEjAQBgNVBAgMCVdhbGxvbm5pYTESMBAGA1UEBwwJUmFtaWxsaWVzMRIwEAYD
|
||||
VQQKDAlPZG9vIFMuQS4xGTAXBgNVBAsMEFImRCAtIEFjY291bnRpbmcxETAPBgNVBAMMCG9kb28u
|
||||
Y29tMRwwGgYJKoZIhvcNAQkBFg1pbmZvQG9kb28uY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
|
||||
MIIBCgKCAQEAtGUbyNJrA3yyOC01gIMR1A1rWIHCHD+afLCLCddBDZwC4Q034yFBuMqQFNWaxxLc
|
||||
9s+wFbNZqu5D7rynN3qXvWJj40VZxygoV/09y71IhaspuAZ0rdzYsqjDmTJiPSrEl6iydF2eq6sJ
|
||||
4J0ItCUFc2e88B25wz7esslAN249C20oQj5ZiGifR4P0CRQSmDy0SPYZGxTurVwtq6IsYbOqEw8/
|
||||
Wqx6ApOltperFX88DZCdbY59ZedqQrGQh2Z5Au7h/8nhmdbpz7Ixw2zocxVigR0ClNDpKKxvolX1
|
||||
virQpICkfWcAaWAYAMCL4KhvISclysD+5juDLpGCLHPtKxBXTQIDAQABo0MwQTAfBgNVHSMEGDAW
|
||||
gBTmxEG4Ub7b5wRXqWea94Vs1hB13zAJBgNVHRMEAjAAMBMGA1UdEQQMMAqCCG9kb28uY29tMA0G
|
||||
CSqGSIb3DQEBCwUAA4IBAQAFLvTlSELTVWRfIlGthoFOmkv8MrwJuo8y7qTmvsFXeA2hZtsPdNxx
|
||||
iwAGPobiUO0GCEPUFKZ7NksQa7DAKGXfb5RSwfujDfEMAhgi00+wF1VIKeKqnGt4idzCr+2NtiQY
|
||||
e9oK+Ee7o82llnNFwbWvRKx55lhHW3bwN6Tl31qUYbxacJyA9z5sQpe2zImWMVsm4g7OAjzg3Cn2
|
||||
0TFu+0XekB892n7DYh4gHiMWaMOVYmi/aEWLSqxMlbiHQr75FmPftozFvTxW26jU3ALhq+yXPVa4
|
||||
lg4r/h6HH5TbtSjYzTSJ4MvMyrECgIQYf0zsS4D6K/GvCZbu7LKHRwuC0fis</ds:X509Certificate>
|
||||
</ds:X509Data>
|
||||
<ds:KeyValue>
|
||||
<ds:RSAKeyValue>
|
||||
<ds:Modulus>tGUbyNJrA3yyOC01gIMR1A1rWIHCHD+afLCLCddBDZwC4Q034yFBuMqQFNWaxxLc9s+wFbNZqu5D
|
||||
7rynN3qXvWJj40VZxygoV/09y71IhaspuAZ0rdzYsqjDmTJiPSrEl6iydF2eq6sJ4J0ItCUFc2e8
|
||||
8B25wz7esslAN249C20oQj5ZiGifR4P0CRQSmDy0SPYZGxTurVwtq6IsYbOqEw8/Wqx6ApOltper
|
||||
FX88DZCdbY59ZedqQrGQh2Z5Au7h/8nhmdbpz7Ixw2zocxVigR0ClNDpKKxvolX1virQpICkfWcA
|
||||
aWAYAMCL4KhvISclysD+5juDLpGCLHPtKxBXTQ==</ds:Modulus>
|
||||
<ds:Exponent>AQAB</ds:Exponent>
|
||||
</ds:RSAKeyValue>
|
||||
</ds:KeyValue>
|
||||
</ds:KeyInfo>
|
||||
<ds:Object>
|
||||
<xades:QualifyingProperties xmlns:xades="http://uri.etsi.org/01903/v1.3.2#" Target="#Signature-Document-da39a3ee5e6b4b0d3255bfef95601890afd80709">
|
||||
<xades:SignedProperties Id="SignatureProperties-Document-da39a3ee5e6b4b0d3255bfef95601890afd80709">
|
||||
<xades:SignedSignatureProperties>
|
||||
<xades:SigningTime>2023-01-01T00:00:00</xades:SigningTime>
|
||||
<xades:SigningCertificateV2>
|
||||
<xades:Cert>
|
||||
<xades:CertDigest>
|
||||
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
|
||||
<ds:DigestValue>FHf2lN+5FALNa7JXV2+pByL92/dr8LeCVhpItYic5oA=</ds:DigestValue>
|
||||
</xades:CertDigest>
|
||||
<xades:IssuerSerial>
|
||||
<ds:X509IssuerName>C=BE, CN=runbot.odoo.com, L=Ramillies, O=Odoo, OU=R&D, ST=Wallonnia</ds:X509IssuerName>
|
||||
<ds:X509SerialNumber>548631688851000697209704649636588277530075594025</ds:X509SerialNumber>
|
||||
</xades:IssuerSerial>
|
||||
</xades:Cert>
|
||||
</xades:SigningCertificateV2>
|
||||
<xades:SignaturePolicyIdentifier>
|
||||
<xades:SignaturePolicyId>
|
||||
<xades:SigPolicyId>
|
||||
<xades:Identifier>http://www.facturae.es/politica_de_firma_formato_facturae/politica_de_firma_formato_facturae_v3_1.pdf</xades:Identifier>
|
||||
<xades:Description>Política de firma electrónica para facturación electrónica con formato Facturae</xades:Description>
|
||||
</xades:SigPolicyId>
|
||||
<xades:SigPolicyHash>
|
||||
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
|
||||
<ds:DigestValue>a/vDoueJq9zxWGCFwdsXdlXtkFSEek4XVtmlQCEDaE8=</ds:DigestValue>
|
||||
</xades:SigPolicyHash>
|
||||
<xades:SigPolicyQualifiers>
|
||||
<xades:SigPolicyQualifier>
|
||||
<xades:SPURI>http://www.facturae.es/politica_de_firma_formato_facturae/politica_de_firma_formato_facturae_v3_1.pdf</xades:SPURI>
|
||||
</xades:SigPolicyQualifier>
|
||||
</xades:SigPolicyQualifiers>
|
||||
</xades:SignaturePolicyId>
|
||||
</xades:SignaturePolicyIdentifier>
|
||||
</xades:SignedSignatureProperties>
|
||||
<xades:SignedDataObjectProperties>
|
||||
<xades:DataObjectFormat ObjectReference="#Reference-Document-da39a3ee5e6b4b0d3255bfef95601890afd80709">
|
||||
<xades:Description/>
|
||||
<xades:ObjectIdentifier>
|
||||
<xades:Identifier Qualifier="OIDAsURN">urn:oid:1.2.840.10003.5.109.10</xades:Identifier>
|
||||
<xades:Description/>
|
||||
</xades:ObjectIdentifier>
|
||||
<xades:MimeType>text/xml</xades:MimeType>
|
||||
<xades:Encoding/>
|
||||
</xades:DataObjectFormat>
|
||||
</xades:SignedDataObjectProperties>
|
||||
</xades:SignedProperties>
|
||||
</xades:QualifyingProperties>
|
||||
</ds:Object>
|
||||
</ds:Signature>
|
||||
</fac:Facturae>
|
||||
@@ -0,0 +1,358 @@
|
||||
<?xml version='1.0' encoding='UTF-8' standalone='yes'?>
|
||||
<fac:Facturae xmlns:fac="http://www.facturae.es/Facturae/2014/v3.2.1/Facturae">
|
||||
<FileHeader>
|
||||
<SchemaVersion>3.2.1</SchemaVersion>
|
||||
<Modality>I</Modality>
|
||||
<InvoiceIssuerType>EM</InvoiceIssuerType>
|
||||
<Batch>
|
||||
<BatchIdentifier>INV/2023/00001</BatchIdentifier>
|
||||
<InvoicesCount>1</InvoicesCount>
|
||||
<TotalInvoicesAmount>
|
||||
<TotalAmount>2904.00</TotalAmount>
|
||||
</TotalInvoicesAmount>
|
||||
<TotalOutstandingAmount>
|
||||
<TotalAmount>2904.00</TotalAmount>
|
||||
</TotalOutstandingAmount>
|
||||
<TotalExecutableAmount>
|
||||
<TotalAmount>2904.00</TotalAmount>
|
||||
</TotalExecutableAmount>
|
||||
<InvoiceCurrencyCode>EUR</InvoiceCurrencyCode>
|
||||
</Batch>
|
||||
</FileHeader>
|
||||
<Parties>
|
||||
<SellerParty>
|
||||
<TaxIdentification>
|
||||
<PersonTypeCode>J</PersonTypeCode>
|
||||
<ResidenceTypeCode>R</ResidenceTypeCode>
|
||||
<TaxIdentificationNumber>ES59962470K</TaxIdentificationNumber>
|
||||
</TaxIdentification>
|
||||
<LegalEntity>
|
||||
<CorporateName>company_1_data</CorporateName>
|
||||
<TradeName>company_1_data</TradeName>
|
||||
<AddressInSpain>
|
||||
<Address>C. de Embajadores, 68-116</Address>
|
||||
<PostCode>12345</PostCode>
|
||||
<Town>Madrid</Town>
|
||||
<Province>Madrid</Province>
|
||||
<CountryCode>ESP</CountryCode>
|
||||
</AddressInSpain>
|
||||
</LegalEntity>
|
||||
</SellerParty>
|
||||
<BuyerParty>
|
||||
<TaxIdentification>
|
||||
<PersonTypeCode>F</PersonTypeCode>
|
||||
<ResidenceTypeCode>U</ResidenceTypeCode>
|
||||
<TaxIdentificationNumber>BE0477472701</TaxIdentificationNumber>
|
||||
</TaxIdentification>
|
||||
<Individual>
|
||||
<Name>UNKNOWN</Name>
|
||||
<FirstSurname>UNKNOWN</FirstSurname>
|
||||
<OverseasAddress>
|
||||
<Address>Rue de Bruxelles, 15000</Address>
|
||||
<PostCodeAndTown>5000 Namur</PostCodeAndTown>
|
||||
<Province>Belgium</Province>
|
||||
<CountryCode>BEL</CountryCode>
|
||||
</OverseasAddress>
|
||||
</Individual>
|
||||
</BuyerParty>
|
||||
</Parties>
|
||||
<Invoices>
|
||||
<Invoice>
|
||||
<InvoiceHeader>
|
||||
<InvoiceNumber>INV/2023/00001</InvoiceNumber>
|
||||
<InvoiceDocumentType>FC</InvoiceDocumentType>
|
||||
<InvoiceClass>OO</InvoiceClass>
|
||||
</InvoiceHeader>
|
||||
<InvoiceIssueData>
|
||||
<IssueDate>2023-01-01</IssueDate>
|
||||
<InvoiceCurrencyCode>EUR</InvoiceCurrencyCode>
|
||||
<TaxCurrencyCode>EUR</TaxCurrencyCode>
|
||||
<LanguageName>en</LanguageName>
|
||||
</InvoiceIssueData>
|
||||
<TaxesOutputs>
|
||||
<Tax>
|
||||
<TaxTypeCode>01</TaxTypeCode>
|
||||
<TaxRate>21.000</TaxRate>
|
||||
<TaxableBase>
|
||||
<TotalAmount>100.00</TotalAmount>
|
||||
</TaxableBase>
|
||||
<TaxAmount>
|
||||
<TotalAmount>21.00</TotalAmount>
|
||||
</TaxAmount>
|
||||
</Tax>
|
||||
<Tax>
|
||||
<TaxTypeCode>01</TaxTypeCode>
|
||||
<TaxRate>21.000</TaxRate>
|
||||
<TaxableBase>
|
||||
<TotalAmount>100.00</TotalAmount>
|
||||
</TaxableBase>
|
||||
<TaxAmount>
|
||||
<TotalAmount>21.00</TotalAmount>
|
||||
</TaxAmount>
|
||||
</Tax>
|
||||
<Tax>
|
||||
<TaxTypeCode>01</TaxTypeCode>
|
||||
<TaxRate>21.000</TaxRate>
|
||||
<TaxableBase>
|
||||
<TotalAmount>200.00</TotalAmount>
|
||||
</TaxableBase>
|
||||
<TaxAmount>
|
||||
<TotalAmount>42.00</TotalAmount>
|
||||
</TaxAmount>
|
||||
</Tax>
|
||||
<Tax>
|
||||
<TaxTypeCode>01</TaxTypeCode>
|
||||
<TaxRate>21.000</TaxRate>
|
||||
<TaxableBase>
|
||||
<TotalAmount>900.00</TotalAmount>
|
||||
</TaxableBase>
|
||||
<TaxAmount>
|
||||
<TotalAmount>189.00</TotalAmount>
|
||||
</TaxAmount>
|
||||
</Tax>
|
||||
<Tax>
|
||||
<TaxTypeCode>01</TaxTypeCode>
|
||||
<TaxRate>21.000</TaxRate>
|
||||
<TaxableBase>
|
||||
<TotalAmount>1100.00</TotalAmount>
|
||||
</TaxableBase>
|
||||
<TaxAmount>
|
||||
<TotalAmount>231.00</TotalAmount>
|
||||
</TaxAmount>
|
||||
</Tax>
|
||||
</TaxesOutputs>
|
||||
<InvoiceTotals>
|
||||
<TotalGrossAmount>2400.00</TotalGrossAmount>
|
||||
<TotalGeneralDiscounts>100.00</TotalGeneralDiscounts>
|
||||
<TotalGeneralSurcharges>100.00</TotalGeneralSurcharges>
|
||||
<TotalGrossAmountBeforeTaxes>2400.00</TotalGrossAmountBeforeTaxes>
|
||||
<TotalTaxOutputs>504.00</TotalTaxOutputs>
|
||||
<TotalTaxesWithheld>0.00</TotalTaxesWithheld>
|
||||
<InvoiceTotal>2904.00</InvoiceTotal>
|
||||
<TotalOutstandingAmount>2904.00</TotalOutstandingAmount>
|
||||
<TotalExecutableAmount>2904.00</TotalExecutableAmount>
|
||||
</InvoiceTotals>
|
||||
<Items>
|
||||
<InvoiceLine>
|
||||
<ItemDescription>product_a</ItemDescription>
|
||||
<Quantity>1.0</Quantity>
|
||||
<UnitOfMeasure>01</UnitOfMeasure>
|
||||
<UnitPriceWithoutTax>100.00</UnitPriceWithoutTax>
|
||||
<TotalCost>100.00</TotalCost>
|
||||
<GrossAmount>100.00</GrossAmount>
|
||||
<TaxesOutputs>
|
||||
<Tax>
|
||||
<TaxTypeCode>01</TaxTypeCode>
|
||||
<TaxRate>21.000</TaxRate>
|
||||
<TaxableBase>
|
||||
<TotalAmount>100.00</TotalAmount>
|
||||
</TaxableBase>
|
||||
<TaxAmount>
|
||||
<TotalAmount>21.00</TotalAmount>
|
||||
</TaxAmount>
|
||||
</Tax>
|
||||
</TaxesOutputs>
|
||||
</InvoiceLine>
|
||||
<InvoiceLine>
|
||||
<ItemDescription>product_a</ItemDescription>
|
||||
<Quantity>1.0</Quantity>
|
||||
<UnitOfMeasure>01</UnitOfMeasure>
|
||||
<UnitPriceWithoutTax>100.00</UnitPriceWithoutTax>
|
||||
<TotalCost>100.00</TotalCost>
|
||||
<GrossAmount>100.00</GrossAmount>
|
||||
<TaxesOutputs>
|
||||
<Tax>
|
||||
<TaxTypeCode>01</TaxTypeCode>
|
||||
<TaxRate>21.000</TaxRate>
|
||||
<TaxableBase>
|
||||
<TotalAmount>100.00</TotalAmount>
|
||||
</TaxableBase>
|
||||
<TaxAmount>
|
||||
<TotalAmount>21.00</TotalAmount>
|
||||
</TaxAmount>
|
||||
</Tax>
|
||||
</TaxesOutputs>
|
||||
</InvoiceLine>
|
||||
<InvoiceLine>
|
||||
<ItemDescription>product_a</ItemDescription>
|
||||
<Quantity>1.0</Quantity>
|
||||
<UnitOfMeasure>01</UnitOfMeasure>
|
||||
<UnitPriceWithoutTax>200.00</UnitPriceWithoutTax>
|
||||
<TotalCost>200.00</TotalCost>
|
||||
<GrossAmount>200.00</GrossAmount>
|
||||
<TaxesOutputs>
|
||||
<Tax>
|
||||
<TaxTypeCode>01</TaxTypeCode>
|
||||
<TaxRate>21.000</TaxRate>
|
||||
<TaxableBase>
|
||||
<TotalAmount>200.00</TotalAmount>
|
||||
</TaxableBase>
|
||||
<TaxAmount>
|
||||
<TotalAmount>42.00</TotalAmount>
|
||||
</TaxAmount>
|
||||
</Tax>
|
||||
</TaxesOutputs>
|
||||
</InvoiceLine>
|
||||
<InvoiceLine>
|
||||
<ItemDescription>product_a</ItemDescription>
|
||||
<Quantity>1.0</Quantity>
|
||||
<UnitOfMeasure>01</UnitOfMeasure>
|
||||
<UnitPriceWithoutTax>1000.00</UnitPriceWithoutTax>
|
||||
<TotalCost>1000.00</TotalCost>
|
||||
<DiscountsAndRebates>
|
||||
<Discount>
|
||||
<DiscountRate>10.00</DiscountRate>
|
||||
<DiscountAmount>100.00</DiscountAmount>
|
||||
</Discount>
|
||||
</DiscountsAndRebates>
|
||||
<GrossAmount>900.00</GrossAmount>
|
||||
<TaxesOutputs>
|
||||
<Tax>
|
||||
<TaxTypeCode>01</TaxTypeCode>
|
||||
<TaxRate>21.000</TaxRate>
|
||||
<TaxableBase>
|
||||
<TotalAmount>900.00</TotalAmount>
|
||||
</TaxableBase>
|
||||
<TaxAmount>
|
||||
<TotalAmount>189.00</TotalAmount>
|
||||
</TaxAmount>
|
||||
</Tax>
|
||||
</TaxesOutputs>
|
||||
</InvoiceLine>
|
||||
<InvoiceLine>
|
||||
<ItemDescription>product_a</ItemDescription>
|
||||
<Quantity>1.0</Quantity>
|
||||
<UnitOfMeasure>01</UnitOfMeasure>
|
||||
<UnitPriceWithoutTax>1000.00</UnitPriceWithoutTax>
|
||||
<TotalCost>1000.00</TotalCost>
|
||||
<Charges>
|
||||
<Charge>
|
||||
<ChargeRate>10.00</ChargeRate>
|
||||
<ChargeAmount>100.00</ChargeAmount>
|
||||
</Charge>
|
||||
</Charges>
|
||||
<GrossAmount>1100.00</GrossAmount>
|
||||
<TaxesOutputs>
|
||||
<Tax>
|
||||
<TaxTypeCode>01</TaxTypeCode>
|
||||
<TaxRate>21.000</TaxRate>
|
||||
<TaxableBase>
|
||||
<TotalAmount>1100.00</TotalAmount>
|
||||
</TaxableBase>
|
||||
<TaxAmount>
|
||||
<TotalAmount>231.00</TotalAmount>
|
||||
</TaxAmount>
|
||||
</Tax>
|
||||
</TaxesOutputs>
|
||||
</InvoiceLine>
|
||||
</Items>
|
||||
</Invoice>
|
||||
</Invoices>
|
||||
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#" Id="Signature-Document-da39a3ee5e6b4b0d3255bfef95601890afd80709">
|
||||
<ds:SignedInfo>
|
||||
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
|
||||
<ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
|
||||
<ds:Reference Type="http://www.w3.org/2000/09/xmldsig#Object" URI="" Id="Reference-Document-da39a3ee5e6b4b0d3255bfef95601890afd80709">
|
||||
<ds:Transforms>
|
||||
<ds:Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
|
||||
<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
|
||||
<ds:Transform Algorithm="http://www.w3.org/TR/1999/REC-xpath-19991116">
|
||||
<ds:XPath>not(ancestor-or-self::ds:Signature)</ds:XPath>
|
||||
</ds:Transform>
|
||||
</ds:Transforms>
|
||||
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
|
||||
<ds:DigestValue>___ignore___</ds:DigestValue>
|
||||
</ds:Reference>
|
||||
<ds:Reference Type="http://uri.etsi.org/01903#SignedProperties" URI="#SignatureProperties-Document-da39a3ee5e6b4b0d3255bfef95601890afd80709">
|
||||
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
|
||||
<ds:DigestValue>UQH7ea0mtLoqLN/aM5mWssQ38fOK1bxnWT4fKQBYiSI=</ds:DigestValue>
|
||||
</ds:Reference>
|
||||
<ds:Reference URI="#KeyInfo-Document-da39a3ee5e6b4b0d3255bfef95601890afd80709">
|
||||
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
|
||||
<ds:DigestValue>wwDtGZ3EpRH8tRKQ8lKgbpfDkE1Zmza9QHkjJDN1Nmw=</ds:DigestValue>
|
||||
</ds:Reference>
|
||||
</ds:SignedInfo>
|
||||
<ds:SignatureValue>___ignore___</ds:SignatureValue>
|
||||
<ds:KeyInfo Id="KeyInfo-Document-da39a3ee5e6b4b0d3255bfef95601890afd80709">
|
||||
<ds:X509Data>
|
||||
<ds:X509Certificate>MIID8jCCAtqgAwIBAgIUYBl+61DsTkNyyUFGveskbaGP/SkwDQYJKoZIhvcNAQELBQAwgYoxCzAJ
|
||||
BgNVBAYTAkJFMRIwEAYDVQQIDAlXYWxsb25uaWExEjAQBgNVBAcMCVJhbWlsbGllczENMAsGA1UE
|
||||
CgwET2RvbzEMMAoGA1UECwwDUiZEMRgwFgYDVQQDDA9ydW5ib3Qub2Rvby5jb20xHDAaBgkqhkiG
|
||||
9w0BCQEWDWluZm9Ab2Rvby5jb20wHhcNMjIwNDI2MDczMTUwWhcNMjMwNDI2MDczMTUwWjCBlTEL
|
||||
MAkGA1UEBhMCQkUxEjAQBgNVBAgMCVdhbGxvbm5pYTESMBAGA1UEBwwJUmFtaWxsaWVzMRIwEAYD
|
||||
VQQKDAlPZG9vIFMuQS4xGTAXBgNVBAsMEFImRCAtIEFjY291bnRpbmcxETAPBgNVBAMMCG9kb28u
|
||||
Y29tMRwwGgYJKoZIhvcNAQkBFg1pbmZvQG9kb28uY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
|
||||
MIIBCgKCAQEAtGUbyNJrA3yyOC01gIMR1A1rWIHCHD+afLCLCddBDZwC4Q034yFBuMqQFNWaxxLc
|
||||
9s+wFbNZqu5D7rynN3qXvWJj40VZxygoV/09y71IhaspuAZ0rdzYsqjDmTJiPSrEl6iydF2eq6sJ
|
||||
4J0ItCUFc2e88B25wz7esslAN249C20oQj5ZiGifR4P0CRQSmDy0SPYZGxTurVwtq6IsYbOqEw8/
|
||||
Wqx6ApOltperFX88DZCdbY59ZedqQrGQh2Z5Au7h/8nhmdbpz7Ixw2zocxVigR0ClNDpKKxvolX1
|
||||
virQpICkfWcAaWAYAMCL4KhvISclysD+5juDLpGCLHPtKxBXTQIDAQABo0MwQTAfBgNVHSMEGDAW
|
||||
gBTmxEG4Ub7b5wRXqWea94Vs1hB13zAJBgNVHRMEAjAAMBMGA1UdEQQMMAqCCG9kb28uY29tMA0G
|
||||
CSqGSIb3DQEBCwUAA4IBAQAFLvTlSELTVWRfIlGthoFOmkv8MrwJuo8y7qTmvsFXeA2hZtsPdNxx
|
||||
iwAGPobiUO0GCEPUFKZ7NksQa7DAKGXfb5RSwfujDfEMAhgi00+wF1VIKeKqnGt4idzCr+2NtiQY
|
||||
e9oK+Ee7o82llnNFwbWvRKx55lhHW3bwN6Tl31qUYbxacJyA9z5sQpe2zImWMVsm4g7OAjzg3Cn2
|
||||
0TFu+0XekB892n7DYh4gHiMWaMOVYmi/aEWLSqxMlbiHQr75FmPftozFvTxW26jU3ALhq+yXPVa4
|
||||
lg4r/h6HH5TbtSjYzTSJ4MvMyrECgIQYf0zsS4D6K/GvCZbu7LKHRwuC0fis</ds:X509Certificate>
|
||||
</ds:X509Data>
|
||||
<ds:KeyValue>
|
||||
<ds:RSAKeyValue>
|
||||
<ds:Modulus>tGUbyNJrA3yyOC01gIMR1A1rWIHCHD+afLCLCddBDZwC4Q034yFBuMqQFNWaxxLc9s+wFbNZqu5D
|
||||
7rynN3qXvWJj40VZxygoV/09y71IhaspuAZ0rdzYsqjDmTJiPSrEl6iydF2eq6sJ4J0ItCUFc2e8
|
||||
8B25wz7esslAN249C20oQj5ZiGifR4P0CRQSmDy0SPYZGxTurVwtq6IsYbOqEw8/Wqx6ApOltper
|
||||
FX88DZCdbY59ZedqQrGQh2Z5Au7h/8nhmdbpz7Ixw2zocxVigR0ClNDpKKxvolX1virQpICkfWcA
|
||||
aWAYAMCL4KhvISclysD+5juDLpGCLHPtKxBXTQ==</ds:Modulus>
|
||||
<ds:Exponent>AQAB</ds:Exponent>
|
||||
</ds:RSAKeyValue>
|
||||
</ds:KeyValue>
|
||||
</ds:KeyInfo>
|
||||
<ds:Object>
|
||||
<xades:QualifyingProperties xmlns:xades="http://uri.etsi.org/01903/v1.3.2#" Target="#Signature-Document-da39a3ee5e6b4b0d3255bfef95601890afd80709">
|
||||
<xades:SignedProperties Id="SignatureProperties-Document-da39a3ee5e6b4b0d3255bfef95601890afd80709">
|
||||
<xades:SignedSignatureProperties>
|
||||
<xades:SigningTime>2023-01-01T00:00:00</xades:SigningTime>
|
||||
<xades:SigningCertificateV2>
|
||||
<xades:Cert>
|
||||
<xades:CertDigest>
|
||||
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
|
||||
<ds:DigestValue>FHf2lN+5FALNa7JXV2+pByL92/dr8LeCVhpItYic5oA=</ds:DigestValue>
|
||||
</xades:CertDigest>
|
||||
<xades:IssuerSerial>
|
||||
<ds:X509IssuerName>C=BE, CN=runbot.odoo.com, L=Ramillies, O=Odoo, OU=R&D, ST=Wallonnia</ds:X509IssuerName>
|
||||
<ds:X509SerialNumber>548631688851000697209704649636588277530075594025</ds:X509SerialNumber>
|
||||
</xades:IssuerSerial>
|
||||
</xades:Cert>
|
||||
</xades:SigningCertificateV2>
|
||||
<xades:SignaturePolicyIdentifier>
|
||||
<xades:SignaturePolicyId>
|
||||
<xades:SigPolicyId>
|
||||
<xades:Identifier>http://www.facturae.es/politica_de_firma_formato_facturae/politica_de_firma_formato_facturae_v3_1.pdf</xades:Identifier>
|
||||
<xades:Description>Política de firma electrónica para facturación electrónica con formato Facturae</xades:Description>
|
||||
</xades:SigPolicyId>
|
||||
<xades:SigPolicyHash>
|
||||
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
|
||||
<ds:DigestValue>a/vDoueJq9zxWGCFwdsXdlXtkFSEek4XVtmlQCEDaE8=</ds:DigestValue>
|
||||
</xades:SigPolicyHash>
|
||||
<xades:SigPolicyQualifiers>
|
||||
<xades:SigPolicyQualifier>
|
||||
<xades:SPURI>http://www.facturae.es/politica_de_firma_formato_facturae/politica_de_firma_formato_facturae_v3_1.pdf</xades:SPURI>
|
||||
</xades:SigPolicyQualifier>
|
||||
</xades:SigPolicyQualifiers>
|
||||
</xades:SignaturePolicyId>
|
||||
</xades:SignaturePolicyIdentifier>
|
||||
</xades:SignedSignatureProperties>
|
||||
<xades:SignedDataObjectProperties>
|
||||
<xades:DataObjectFormat ObjectReference="#Reference-Document-da39a3ee5e6b4b0d3255bfef95601890afd80709">
|
||||
<xades:Description/>
|
||||
<xades:ObjectIdentifier>
|
||||
<xades:Identifier Qualifier="OIDAsURN">urn:oid:1.2.840.10003.5.109.10</xades:Identifier>
|
||||
<xades:Description/>
|
||||
</xades:ObjectIdentifier>
|
||||
<xades:MimeType>text/xml</xades:MimeType>
|
||||
<xades:Encoding/>
|
||||
</xades:DataObjectFormat>
|
||||
</xades:SignedDataObjectProperties>
|
||||
</xades:SignedProperties>
|
||||
</xades:QualifyingProperties>
|
||||
</ds:Object>
|
||||
</ds:Signature>
|
||||
</fac:Facturae>
|
||||
@@ -0,0 +1,331 @@
|
||||
<?xml version='1.0' encoding='UTF-8' standalone='yes'?>
|
||||
<fac:Facturae xmlns:fac="http://www.facturae.es/Facturae/2014/v3.2.1/Facturae">
|
||||
<FileHeader>
|
||||
<SchemaVersion>3.2.1</SchemaVersion>
|
||||
<Modality>I</Modality>
|
||||
<InvoiceIssuerType>EM</InvoiceIssuerType>
|
||||
<Batch>
|
||||
<BatchIdentifier>INV/2023/00001</BatchIdentifier>
|
||||
<InvoicesCount>1</InvoicesCount>
|
||||
<TotalInvoicesAmount>
|
||||
<TotalAmount>400.00</TotalAmount>
|
||||
</TotalInvoicesAmount>
|
||||
<TotalOutstandingAmount>
|
||||
<TotalAmount>400.00</TotalAmount>
|
||||
</TotalOutstandingAmount>
|
||||
<TotalExecutableAmount>
|
||||
<TotalAmount>400.00</TotalAmount>
|
||||
</TotalExecutableAmount>
|
||||
<InvoiceCurrencyCode>EUR</InvoiceCurrencyCode>
|
||||
</Batch>
|
||||
</FileHeader>
|
||||
<Parties>
|
||||
<SellerParty>
|
||||
<TaxIdentification>
|
||||
<PersonTypeCode>J</PersonTypeCode>
|
||||
<ResidenceTypeCode>R</ResidenceTypeCode>
|
||||
<TaxIdentificationNumber>ES59962470K</TaxIdentificationNumber>
|
||||
</TaxIdentification>
|
||||
<LegalEntity>
|
||||
<CorporateName>company_1_data</CorporateName>
|
||||
<TradeName>company_1_data</TradeName>
|
||||
<AddressInSpain>
|
||||
<Address>C. de Embajadores, 68-116</Address>
|
||||
<PostCode>12345</PostCode>
|
||||
<Town>Madrid</Town>
|
||||
<Province>Madrid</Province>
|
||||
<CountryCode>ESP</CountryCode>
|
||||
</AddressInSpain>
|
||||
</LegalEntity>
|
||||
</SellerParty>
|
||||
<BuyerParty>
|
||||
<TaxIdentification>
|
||||
<PersonTypeCode>F</PersonTypeCode>
|
||||
<ResidenceTypeCode>U</ResidenceTypeCode>
|
||||
<TaxIdentificationNumber>BE0477472701</TaxIdentificationNumber>
|
||||
</TaxIdentification>
|
||||
<Individual>
|
||||
<Name>UNKNOWN</Name>
|
||||
<FirstSurname>UNKNOWN</FirstSurname>
|
||||
<OverseasAddress>
|
||||
<Address>Rue de Bruxelles, 15000</Address>
|
||||
<PostCodeAndTown>5000 Namur</PostCodeAndTown>
|
||||
<Province>Belgium</Province>
|
||||
<CountryCode>BEL</CountryCode>
|
||||
</OverseasAddress>
|
||||
</Individual>
|
||||
</BuyerParty>
|
||||
</Parties>
|
||||
<Invoices>
|
||||
<Invoice>
|
||||
<InvoiceHeader>
|
||||
<InvoiceNumber>INV/2023/00001</InvoiceNumber>
|
||||
<InvoiceDocumentType>FC</InvoiceDocumentType>
|
||||
<InvoiceClass>OO</InvoiceClass>
|
||||
</InvoiceHeader>
|
||||
<InvoiceIssueData>
|
||||
<IssueDate>2023-01-01</IssueDate>
|
||||
<InvoiceCurrencyCode>EUR</InvoiceCurrencyCode>
|
||||
<TaxCurrencyCode>EUR</TaxCurrencyCode>
|
||||
<LanguageName>en</LanguageName>
|
||||
</InvoiceIssueData>
|
||||
<TaxesOutputs>
|
||||
<Tax>
|
||||
<TaxTypeCode>01</TaxTypeCode>
|
||||
<TaxRate>21.000</TaxRate>
|
||||
<TaxableBase>
|
||||
<TotalAmount>100.00</TotalAmount>
|
||||
</TaxableBase>
|
||||
<TaxAmount>
|
||||
<TotalAmount>21.00</TotalAmount>
|
||||
</TaxAmount>
|
||||
</Tax>
|
||||
<Tax>
|
||||
<TaxTypeCode>01</TaxTypeCode>
|
||||
<TaxRate>21.000</TaxRate>
|
||||
<TaxableBase>
|
||||
<TotalAmount>100.00</TotalAmount>
|
||||
</TaxableBase>
|
||||
<TaxAmount>
|
||||
<TotalAmount>21.00</TotalAmount>
|
||||
</TaxAmount>
|
||||
</Tax>
|
||||
<Tax>
|
||||
<TaxTypeCode>01</TaxTypeCode>
|
||||
<TaxRate>21.000</TaxRate>
|
||||
<TaxableBase>
|
||||
<TotalAmount>200.00</TotalAmount>
|
||||
</TaxableBase>
|
||||
<TaxAmount>
|
||||
<TotalAmount>42.00</TotalAmount>
|
||||
</TaxAmount>
|
||||
</Tax>
|
||||
</TaxesOutputs>
|
||||
<TaxesWithheld>
|
||||
<Tax>
|
||||
<TaxTypeCode>01</TaxTypeCode>
|
||||
<TaxRate>21.000</TaxRate>
|
||||
<TaxableBase>
|
||||
<TotalAmount>100.00</TotalAmount>
|
||||
</TaxableBase>
|
||||
<TaxAmount>
|
||||
<TotalAmount>21.00</TotalAmount>
|
||||
</TaxAmount>
|
||||
</Tax>
|
||||
<Tax>
|
||||
<TaxTypeCode>01</TaxTypeCode>
|
||||
<TaxRate>21.000</TaxRate>
|
||||
<TaxableBase>
|
||||
<TotalAmount>100.00</TotalAmount>
|
||||
</TaxableBase>
|
||||
<TaxAmount>
|
||||
<TotalAmount>21.00</TotalAmount>
|
||||
</TaxAmount>
|
||||
</Tax>
|
||||
<Tax>
|
||||
<TaxTypeCode>01</TaxTypeCode>
|
||||
<TaxRate>21.000</TaxRate>
|
||||
<TaxableBase>
|
||||
<TotalAmount>200.00</TotalAmount>
|
||||
</TaxableBase>
|
||||
<TaxAmount>
|
||||
<TotalAmount>42.00</TotalAmount>
|
||||
</TaxAmount>
|
||||
</Tax>
|
||||
</TaxesWithheld>
|
||||
<InvoiceTotals>
|
||||
<TotalGrossAmount>400.00</TotalGrossAmount>
|
||||
<TotalGrossAmountBeforeTaxes>400.00</TotalGrossAmountBeforeTaxes>
|
||||
<TotalTaxOutputs>84.00</TotalTaxOutputs>
|
||||
<TotalTaxesWithheld>84.00</TotalTaxesWithheld>
|
||||
<InvoiceTotal>400.00</InvoiceTotal>
|
||||
<TotalOutstandingAmount>400.00</TotalOutstandingAmount>
|
||||
<TotalExecutableAmount>400.00</TotalExecutableAmount>
|
||||
</InvoiceTotals>
|
||||
<Items>
|
||||
<InvoiceLine>
|
||||
<ItemDescription>product_a</ItemDescription>
|
||||
<Quantity>1.0</Quantity>
|
||||
<UnitOfMeasure>01</UnitOfMeasure>
|
||||
<UnitPriceWithoutTax>100.00</UnitPriceWithoutTax>
|
||||
<TotalCost>100.00</TotalCost>
|
||||
<GrossAmount>100.00</GrossAmount>
|
||||
<TaxesOutputs>
|
||||
<Tax>
|
||||
<TaxTypeCode>01</TaxTypeCode>
|
||||
<TaxRate>21.000</TaxRate>
|
||||
<TaxableBase>
|
||||
<TotalAmount>100.00</TotalAmount>
|
||||
</TaxableBase>
|
||||
<TaxAmount>
|
||||
<TotalAmount>21.00</TotalAmount>
|
||||
</TaxAmount>
|
||||
</Tax>
|
||||
</TaxesOutputs>
|
||||
<TaxesWithheld>
|
||||
<Tax>
|
||||
<TaxTypeCode>01</TaxTypeCode>
|
||||
<TaxRate>21.000</TaxRate>
|
||||
<TaxableBase>
|
||||
<TotalAmount>100.00</TotalAmount>
|
||||
</TaxableBase>
|
||||
<TaxAmount>
|
||||
<TotalAmount>21.00</TotalAmount>
|
||||
</TaxAmount>
|
||||
</Tax>
|
||||
</TaxesWithheld>
|
||||
</InvoiceLine>
|
||||
<InvoiceLine>
|
||||
<ItemDescription>product_a</ItemDescription>
|
||||
<Quantity>1.0</Quantity>
|
||||
<UnitOfMeasure>01</UnitOfMeasure>
|
||||
<UnitPriceWithoutTax>100.00</UnitPriceWithoutTax>
|
||||
<TotalCost>100.00</TotalCost>
|
||||
<GrossAmount>100.00</GrossAmount>
|
||||
<TaxesOutputs>
|
||||
<Tax>
|
||||
<TaxTypeCode>01</TaxTypeCode>
|
||||
<TaxRate>21.000</TaxRate>
|
||||
<TaxableBase>
|
||||
<TotalAmount>100.00</TotalAmount>
|
||||
</TaxableBase>
|
||||
<TaxAmount>
|
||||
<TotalAmount>21.00</TotalAmount>
|
||||
</TaxAmount>
|
||||
</Tax>
|
||||
</TaxesOutputs>
|
||||
<TaxesWithheld>
|
||||
<Tax>
|
||||
<TaxTypeCode>01</TaxTypeCode>
|
||||
<TaxRate>21.000</TaxRate>
|
||||
<TaxableBase>
|
||||
<TotalAmount>100.00</TotalAmount>
|
||||
</TaxableBase>
|
||||
<TaxAmount>
|
||||
<TotalAmount>21.00</TotalAmount>
|
||||
</TaxAmount>
|
||||
</Tax>
|
||||
</TaxesWithheld>
|
||||
</InvoiceLine>
|
||||
<InvoiceLine>
|
||||
<ItemDescription>product_a</ItemDescription>
|
||||
<Quantity>1.0</Quantity>
|
||||
<UnitOfMeasure>01</UnitOfMeasure>
|
||||
<UnitPriceWithoutTax>200.00</UnitPriceWithoutTax>
|
||||
<TotalCost>200.00</TotalCost>
|
||||
<GrossAmount>200.00</GrossAmount>
|
||||
<TaxesOutputs>
|
||||
<Tax>
|
||||
<TaxTypeCode>01</TaxTypeCode>
|
||||
<TaxRate>21.000</TaxRate>
|
||||
<TaxableBase>
|
||||
<TotalAmount>200.00</TotalAmount>
|
||||
</TaxableBase>
|
||||
<TaxAmount>
|
||||
<TotalAmount>42.00</TotalAmount>
|
||||
</TaxAmount>
|
||||
</Tax>
|
||||
</TaxesOutputs>
|
||||
<TaxesWithheld>
|
||||
<Tax>
|
||||
<TaxTypeCode>01</TaxTypeCode>
|
||||
<TaxRate>21.000</TaxRate>
|
||||
<TaxableBase>
|
||||
<TotalAmount>200.00</TotalAmount>
|
||||
</TaxableBase>
|
||||
<TaxAmount>
|
||||
<TotalAmount>42.00</TotalAmount>
|
||||
</TaxAmount>
|
||||
</Tax>
|
||||
</TaxesWithheld>
|
||||
</InvoiceLine>
|
||||
</Items>
|
||||
</Invoice>
|
||||
</Invoices>
|
||||
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:xd="http://uri.etsi.org/01903/v1.3.2#" Id="___ignore___">
|
||||
<ds:SignedInfo>
|
||||
<ds:CanonicalizationMethod Algorithm="___ignore___"/>
|
||||
<ds:SignatureMethod Algorithm="___ignore___"/>
|
||||
<ds:Reference Id="___ignore___" Type="___ignore___" URI="___ignore___">
|
||||
<ds:Transforms>
|
||||
<ds:Transform Algorithm="___ignore___"/>
|
||||
<ds:Transform Algorithm="___ignore___"/>
|
||||
<ds:Transform Algorithm="___ignore___">
|
||||
<ds:XPath>___ignore___</ds:XPath>
|
||||
</ds:Transform>
|
||||
</ds:Transforms>
|
||||
<ds:DigestMethod Algorithm="___ignore___"/>
|
||||
<ds:DigestValue>___ignore___</ds:DigestValue>
|
||||
</ds:Reference>
|
||||
<ds:Reference Type="___ignore___" URI="___ignore___">
|
||||
<ds:DigestMethod Algorithm="___ignore___"/>
|
||||
<ds:DigestValue>___ignore___</ds:DigestValue>
|
||||
</ds:Reference>
|
||||
<ds:Reference URI="___ignore___">
|
||||
<ds:DigestMethod Algorithm="___ignore___"/>
|
||||
<ds:DigestValue>___ignore___</ds:DigestValue>
|
||||
</ds:Reference>
|
||||
</ds:SignedInfo>
|
||||
<ds:SignatureValue>___ignore___</ds:SignatureValue>
|
||||
<ds:KeyInfo Id="___ignore___">
|
||||
<ds:X509Data>
|
||||
<ds:X509Certificate>___ignore___</ds:X509Certificate>
|
||||
</ds:X509Data>
|
||||
<ds:KeyValue>
|
||||
<ds:RSAKeyValue>
|
||||
<ds:Modulus>___ignore___</ds:Modulus>
|
||||
<ds:Exponent>___ignore___</ds:Exponent>
|
||||
</ds:RSAKeyValue>
|
||||
</ds:KeyValue>
|
||||
</ds:KeyInfo>
|
||||
<ds:Object>
|
||||
<xd:QualifyingProperties Target="___ignore___">
|
||||
<xd:SignedProperties Id="___ignore___">
|
||||
<xd:SignedSignatureProperties>
|
||||
<xd:SigningTime>___ignore___</xd:SigningTime>
|
||||
<xd:SigningCertificateV2>
|
||||
<xd:Cert>
|
||||
<xd:CertDigest>
|
||||
<ds:DigestMethod Algorithm="___ignore___"/>
|
||||
<ds:DigestValue>___ignore___</ds:DigestValue>
|
||||
</xd:CertDigest>
|
||||
<xd:IssuerSerial>
|
||||
<ds:X509IssuerName>___ignore___</ds:X509IssuerName>
|
||||
<ds:X509SerialNumber>___ignore___</ds:X509SerialNumber>
|
||||
</xd:IssuerSerial>
|
||||
</xd:Cert>
|
||||
</xd:SigningCertificateV2>
|
||||
<xd:SignaturePolicyIdentifier>
|
||||
<xd:SignaturePolicyId>
|
||||
<xd:SigPolicyId>
|
||||
<xd:Identifier>___ignore___</xd:Identifier>
|
||||
<xd:Description>___ignore___</xd:Description>
|
||||
</xd:SigPolicyId>
|
||||
<xd:SigPolicyHash>
|
||||
<ds:DigestMethod Algorithm="___ignore___"/>
|
||||
<ds:DigestValue>___ignore___</ds:DigestValue>
|
||||
</xd:SigPolicyHash>
|
||||
<xd:SigPolicyQualifiers>
|
||||
<xd:SigPolicyQualifier>
|
||||
<xd:SPURI>___ignore___</xd:SPURI>
|
||||
</xd:SigPolicyQualifier>
|
||||
</xd:SigPolicyQualifiers>
|
||||
</xd:SignaturePolicyId>
|
||||
</xd:SignaturePolicyIdentifier>
|
||||
</xd:SignedSignatureProperties>
|
||||
<xd:SignedDataObjectProperties>
|
||||
<xd:DataObjectFormat ObjectReference="___ignore___">
|
||||
<xd:Description>___ignore___</xd:Description>
|
||||
<xd:ObjectIdentifier>
|
||||
<xd:Identifier Qualifier="OIDAsURN">___ignore___</xd:Identifier>
|
||||
<xd:Description>___ignore___</xd:Description>
|
||||
</xd:ObjectIdentifier>
|
||||
<xd:MimeType>___ignore___</xd:MimeType>
|
||||
<xd:Encoding>___ignore___</xd:Encoding>
|
||||
</xd:DataObjectFormat>
|
||||
</xd:SignedDataObjectProperties>
|
||||
</xd:SignedProperties>
|
||||
</xd:QualifyingProperties>
|
||||
</ds:Object>
|
||||
</ds:Signature>
|
||||
</fac:Facturae>
|
||||
@@ -0,0 +1,222 @@
|
||||
import logging
|
||||
import random
|
||||
from base64 import b64encode
|
||||
from datetime import datetime
|
||||
from hashlib import sha1
|
||||
from unittest.mock import patch
|
||||
|
||||
import lxml
|
||||
from freezegun import freeze_time
|
||||
|
||||
from odoo import Command
|
||||
from odoo.addons.account_edi.tests.common import AccountEdiTestCommon
|
||||
from odoo.exceptions import UserError
|
||||
from odoo.tests import tagged
|
||||
from odoo.tools import file_open
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
@tagged('post_install_l10n', 'post_install', '-at_install')
|
||||
class TestEdiFacturaeXmls(AccountEdiTestCommon):
|
||||
@classmethod
|
||||
def setUpClass(cls, chart_template_ref='es_full', edi_format_ref=None):
|
||||
super().setUpClass(chart_template_ref=chart_template_ref, edi_format_ref=edi_format_ref)
|
||||
cls.frozen_today = datetime(year=2023, month=1, day=1, hour=0, minute=0, second=0)
|
||||
|
||||
# ==== Companies ====
|
||||
cls.company_data['company'].write({ # -> PersonTypeCode 'J'
|
||||
'country_id': cls.env.ref('base.es').id, # -> ResidenceTypeCode 'R'
|
||||
'street': "C. de Embajadores, 68-116",
|
||||
'state_id': cls.env.ref('base.state_es_m').id,
|
||||
'city': "Madrid",
|
||||
'zip': "12345",
|
||||
'vat': 'ES59962470K',
|
||||
})
|
||||
cls.company_data_2['company'].write({ # -> PersonTypeCode 'J'
|
||||
'country_id': cls.env.ref('base.us').id, # -> ResidenceTypeCode 'R'
|
||||
})
|
||||
|
||||
# ==== Business ====
|
||||
cls.partner_a.write({ # -> PersonTypeCode 'F'
|
||||
'country_id': cls.env.ref('base.be').id, # -> ResidenceTypeCode 'U'
|
||||
'vat': 'BE0477472701',
|
||||
'city': "Namur",
|
||||
'street': "Rue de Bruxelles, 15000",
|
||||
'zip': "5000",
|
||||
})
|
||||
|
||||
cls.password = "test"
|
||||
|
||||
cls.certificate_module = "odoo.addons.l10n_es_edi_facturae.models.l10n_es_edi_facturae_certificate"
|
||||
with freeze_time(cls.frozen_today), patch(f"{cls.certificate_module}.fields.datetime.now", lambda x=None: cls.frozen_today):
|
||||
cls.certificate = cls.env["l10n_es_edi_facturae.certificate"].sudo().create({
|
||||
"content": b64encode(file_open('l10n_es_edi_facturae/tests/data/certificate_test.pfx', 'rb').read()),
|
||||
"password": "test",
|
||||
'company_id': cls.company_data['company'].id,
|
||||
})
|
||||
|
||||
cls.tax, cls.tax_2 = cls.env['account.tax'].create([{
|
||||
'name': "IVA 21% (Bienes)",
|
||||
'company_id': cls.company_data['company'].id,
|
||||
'amount': 21.0,
|
||||
'price_include': False,
|
||||
'l10n_es_edi_facturae_tax_type': '01'
|
||||
}, {
|
||||
'name': "IVA 21% (Bienes) Included",
|
||||
'company_id': cls.company_data['company'].id,
|
||||
'amount': 21.0,
|
||||
'price_include': True,
|
||||
'l10n_es_edi_facturae_tax_type': '01'
|
||||
}
|
||||
])
|
||||
|
||||
cls.nsmap = {
|
||||
'ds': "http://www.w3.org/2000/09/xmldsig#", 'fac': "http://www.facturae.es/Facturae/2007/v3.1/Facturae",
|
||||
'xades': "http://uri.etsi.org/01903/v1.3.2#", 'xd': "http://www.w3.org/2000/09/xmldsig#",
|
||||
}
|
||||
|
||||
cls.maxDiff = None
|
||||
|
||||
@classmethod
|
||||
def create_invoice(cls, **kwargs):
|
||||
return cls.env['account.move'].with_context(edi_test_mode=True).create({
|
||||
'partner_id': cls.partner_a.id,
|
||||
'invoice_date': cls.frozen_today.isoformat(),
|
||||
'date': cls.frozen_today.isoformat(),
|
||||
**kwargs,
|
||||
'invoice_line_ids': [
|
||||
Command.create({'product_id': cls.product_a.id, 'price_unit': 1000.0, **line_vals, })
|
||||
for line_vals in kwargs.get('invoice_line_ids', [])
|
||||
],
|
||||
})
|
||||
|
||||
def test_generate_signed_xml(self, date=None):
|
||||
random.seed(42)
|
||||
date = date or self.frozen_today
|
||||
# We need to patch dates and uuid to ensure the signature's consistency
|
||||
with freeze_time(date), \
|
||||
patch(f"{self.certificate_module}.fields.datetime.now", lambda x=None: date), \
|
||||
patch(f"{self.certificate_module}.sha1", lambda x: sha1()):
|
||||
invoice = self.create_invoice(
|
||||
partner_id=self.partner_a.id,
|
||||
move_type='out_invoice',
|
||||
invoice_line_ids=[
|
||||
{'price_unit': 100.0, 'tax_ids': [self.tax.id]},
|
||||
{'price_unit': 100.0, 'tax_ids': [self.tax.id]},
|
||||
{'price_unit': 242.0, 'tax_ids': [self.tax_2.id]},
|
||||
{'price_unit': 1000.0, "discount": 10, "tax_ids": [self.tax.id]},
|
||||
{'price_unit': 1210.0, "discount": -10, "tax_ids": [self.tax_2.id]},
|
||||
],
|
||||
)
|
||||
invoice.action_post()
|
||||
generated_file = invoice._l10n_es_edi_facturae_render_facturae()
|
||||
self.assertTrue(generated_file)
|
||||
|
||||
with file_open("l10n_es_edi_facturae/tests/data/expected_signed_document.xml", "rt") as f:
|
||||
expected_xml = lxml.etree.fromstring(f.read().encode())
|
||||
self.assertXmlTreeEqual(lxml.etree.fromstring(generated_file), expected_xml)
|
||||
|
||||
def test_cannot_generate_unsigned_xml(self):
|
||||
""" Test that no valid certificate prevents a xml generation"""
|
||||
self.certificate.unlink()
|
||||
random.seed(42)
|
||||
with freeze_time(self.frozen_today), \
|
||||
patch(f"{self.certificate_module}.fields.datetime.now", lambda x=None: self.frozen_today), \
|
||||
patch(f"{self.certificate_module}.sha1", lambda x: sha1()):
|
||||
invoice = self.create_invoice(partner_id=self.partner_a.id, move_type='out_invoice', invoice_line_ids=[{'price_unit': 100.0, 'tax_ids': [self.tax.id]},],)
|
||||
invoice.action_post()
|
||||
self.assertRaises(UserError, invoice._l10n_es_edi_facturae_render_facturae)
|
||||
|
||||
def test_tax_withheld(self):
|
||||
with freeze_time(self.frozen_today), \
|
||||
patch(f"{self.certificate_module}.fields.datetime.now", lambda x=None: self.frozen_today), \
|
||||
patch(f"{self.certificate_module}.sha1", lambda x: sha1()):
|
||||
witholding_taxes = self.env["account.tax"].create([{
|
||||
'name': "IVA 21%",
|
||||
'company_id': self.company_data['company'].id,
|
||||
'amount': 21.0,
|
||||
'price_include': False,
|
||||
'l10n_es_edi_facturae_tax_type': '01'
|
||||
}, {
|
||||
'name': "IVA 21% withholding",
|
||||
'company_id': self.company_data['company'].id,
|
||||
'amount': -21.0,
|
||||
'price_include': False,
|
||||
'l10n_es_edi_facturae_tax_type': '01'
|
||||
}])
|
||||
|
||||
invoice = self.create_invoice(
|
||||
partner_id=self.partner_a.id,
|
||||
move_type='out_invoice',
|
||||
invoice_line_ids=[
|
||||
{'price_unit': 100.0, 'tax_ids': witholding_taxes.ids},
|
||||
{'price_unit': 100.0, 'tax_ids': witholding_taxes.ids},
|
||||
{'price_unit': 200.0, 'tax_ids': witholding_taxes.ids},
|
||||
],
|
||||
)
|
||||
invoice.action_post()
|
||||
generated_file = invoice._l10n_es_edi_facturae_render_facturae()
|
||||
self.assertTrue(generated_file)
|
||||
with file_open("l10n_es_edi_facturae/tests/data/expected_tax_withholding.xml", "rt") as f:
|
||||
expected_xml = lxml.etree.fromstring(f.read().encode())
|
||||
self.assertXmlTreeEqual(lxml.etree.fromstring(generated_file), expected_xml)
|
||||
|
||||
def test_in_invoice(self):
|
||||
random.seed(42)
|
||||
# We need to patch dates and uuid to ensure the signature's consistency
|
||||
with freeze_time(self.frozen_today), \
|
||||
patch(f"{self.certificate_module}.fields.datetime.now", lambda x=None: self.frozen_today), \
|
||||
patch(f"{self.certificate_module}.sha1", lambda x: sha1()):
|
||||
invoice = self.create_invoice(
|
||||
partner_id=self.partner_a.id,
|
||||
move_type='in_invoice',
|
||||
invoice_line_ids=[
|
||||
{'price_unit': 100.0, 'tax_ids': [self.tax.id]},
|
||||
{'price_unit': 100.0, 'tax_ids': [self.tax.id]},
|
||||
{'price_unit': 242.0, 'tax_ids': [self.tax_2.id]},
|
||||
{'price_unit': 1000.0, "discount": 10, "tax_ids": [self.tax.id]},
|
||||
{'price_unit': 1000.0, "discount": -10, "tax_ids": [self.tax.id]},
|
||||
],
|
||||
)
|
||||
invoice.action_post()
|
||||
generated_file = invoice._l10n_es_edi_facturae_render_facturae()
|
||||
self.assertTrue(generated_file)
|
||||
|
||||
with file_open("l10n_es_edi_facturae/tests/data/expected_in_invoice_document.xml", "rt") as f:
|
||||
expected_xml = lxml.etree.fromstring(f.read().encode())
|
||||
self.assertXmlTreeEqual(lxml.etree.fromstring(generated_file), expected_xml)
|
||||
|
||||
def test_refund_invoice(self):
|
||||
random.seed(42)
|
||||
# We need to patch dates and uuid to ensure the signature's consistency
|
||||
|
||||
with freeze_time(self.frozen_today), \
|
||||
patch(f"{self.certificate_module}.fields.datetime.now", lambda x=None: self.frozen_today), \
|
||||
patch(f"{self.certificate_module}.fields.datetime.now", lambda x=None: self.frozen_today), \
|
||||
patch(f"{self.certificate_module}.sha1", lambda x: sha1()):
|
||||
invoice = self.create_invoice(
|
||||
partner_id=self.partner_a.id,
|
||||
move_type='out_invoice',
|
||||
invoice_line_ids=[
|
||||
{'price_unit': 100.0, 'tax_ids': [self.tax.id]},
|
||||
{'price_unit': 100.0, 'tax_ids': [self.tax.id]},
|
||||
],
|
||||
)
|
||||
invoice.action_post()
|
||||
reversal_wizard = self.env['account.move.reversal'].create({
|
||||
'move_ids': invoice.ids,
|
||||
'date_mode': 'custom',
|
||||
'journal_id': invoice.journal_id.id,
|
||||
'date': self.frozen_today,
|
||||
'refund_method': 'cancel',
|
||||
'company_id': self.company_data['company'].id,
|
||||
'l10n_es_edi_facturae_reason_code': '01'
|
||||
})
|
||||
reversal_wizard.reverse_moves()
|
||||
refund = reversal_wizard.new_move_ids
|
||||
generated_file = refund._l10n_es_edi_facturae_render_facturae()
|
||||
self.assertTrue(generated_file)
|
||||
|
||||
with file_open("l10n_es_edi_facturae/tests/data/expected_refund_document.xml", "rt") as f:
|
||||
expected_xml = lxml.etree.fromstring(f.read().encode())
|
||||
self.assertXmlTreeEqual(lxml.etree.fromstring(generated_file), expected_xml)
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data>
|
||||
<menuitem id="menu_l10n_es_edi_facturae_root" name="Spain Facturae EDI" sequence="110" groups="base.group_system"
|
||||
parent="account.menu_finance_configuration">
|
||||
<menuitem id="menu_l10n_es_edi_facturae_root_certificates" name="Certificates" action="l10n_es_edi_facturae_certificate_action"
|
||||
sequence="100" groups="base.group_system"/>
|
||||
</menuitem>
|
||||
</data>
|
||||
</odoo>
|
||||
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
|
||||
<record id="account_move_send_form" model="ir.ui.view">
|
||||
<field name="name">account.move.send.form</field>
|
||||
<field name="model">account.move.send</field>
|
||||
<field name="inherit_id" ref="account.account_move_send_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//div[@name='advanced_options']" position="inside">
|
||||
<field name="l10n_es_edi_facturae_enable_xml" invisible="1"/>
|
||||
<div name="option_xml"
|
||||
attrs="{'invisible': [('l10n_es_edi_facturae_enable_xml', '=', False)]}">
|
||||
<!-- Use one field as the label for another -->
|
||||
<field name="l10n_es_edi_facturae_checkbox_xml" style="display: inline-block"/>
|
||||
<b><label for="l10n_es_edi_facturae_checkbox_xml"></label></b>
|
||||
</div>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data>
|
||||
<record id="view_tax_tree_inherit_l10n_es_edi_facturae" model="ir.ui.view">
|
||||
<field name="name">account.tax.tree.inherit.l10n_es_edi_facturae</field>
|
||||
<field name="inherit_id" ref="account.view_tax_tree"/>
|
||||
<field name="model">account.tax</field>
|
||||
<field name="arch" type="xml">
|
||||
<field name="country_id" position="after">
|
||||
<field name="country_code" invisible="1"/>
|
||||
<field name="l10n_es_edi_facturae_tax_type" string="Spanish Tax Type" optional="hide"
|
||||
attrs="{'invisible': [('country_code', '!=', 'ES')]}"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_tax_form_inherit_l10n_es_edi_facturae" model="ir.ui.view">
|
||||
<field name="name">account.tax.form.inherit.l10n_es_edi_facturae</field>
|
||||
<field name="model">account.tax</field>
|
||||
<field name="inherit_id" ref="account.view_tax_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="country_id" position="after">
|
||||
<field name="l10n_es_edi_facturae_tax_type" attrs="{'invisible': [('country_code', '!=', 'ES')]}"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
@@ -0,0 +1,47 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<odoo>
|
||||
<data>
|
||||
<record id="l10n_es_edi_facturae_certificate_form" model="ir.ui.view">
|
||||
<field name="name">l10n_es_edi_facturae.certificate.form</field>
|
||||
<field name="model">l10n_es_edi_facturae.certificate</field>
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<sheet>
|
||||
<group>
|
||||
<field name="content"/>
|
||||
<field name="password" password="True"/>
|
||||
<label for="date_start" string="Validity"/>
|
||||
<div>
|
||||
<field name="date_start"/> -
|
||||
<field name="date_end"/>
|
||||
</div>
|
||||
<field name="company_id" groups="base.group_multi_company" readonly="True"/>
|
||||
</group>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="l10n_es_edi_facturae_certificate_tree" model="ir.ui.view">
|
||||
<field name="name">l10n_es_edi_facturae.certificate.tree</field>
|
||||
<field name="model">l10n_es_edi_facturae.certificate</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree>
|
||||
<field name="date_start"/>
|
||||
<field name="date_end"/>
|
||||
<field name="company_id" groups="base.group_multi_company" readonly="True"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="l10n_es_edi_facturae_certificate_action" model="ir.actions.act_window">
|
||||
<field name="name">Certificates for Facturae EDI invoices on Spain</field>
|
||||
<field name="res_model">l10n_es_edi_facturae.certificate</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="context" eval="{'search_default_my_certificates': 1}"/>
|
||||
<field name="help" type="html">
|
||||
<p class="oe_view_nocontent_create">Create the first certificate</p>
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record id="view_company_form_inherit_l10n_es_edi_facturae" model="ir.ui.view">
|
||||
<field name="name">res.company.form.inherit.l10n_es_edi_facturae</field>
|
||||
<field name="inherit_id" ref="base.view_company_form"/>
|
||||
<field name="model">res.company</field>
|
||||
<field name="arch" type="xml">
|
||||
<field name="currency_id" position="after">
|
||||
<field name="l10n_es_edi_facturae_certificate_id" string="Facturae signature certificate"
|
||||
attrs="{'invisible': [('country_code', '!=', 'ES')]}"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
@@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record id="product_uom_tree_view_inherit_l10n_es_edi_facturae" model="ir.ui.view">
|
||||
<field name="name">uom.uom.tree.inherit.l10n_es_edi_facturae</field>
|
||||
<field name="model">uom.uom</field>
|
||||
<field name="inherit_id" ref="uom.product_uom_tree_view"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="category_id" position="after">
|
||||
<field name="l10n_es_edi_facturae_uom_code" string="Spanish Facturae EDI type"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
<record id="product_uom_form_view_inherit_l10n_es_edi_facturae" model="ir.ui.view">
|
||||
<field name="name">uom.uom.form.inherit.l10n_es_edi_facturae</field>
|
||||
<field name="model">uom.uom</field>
|
||||
<field name="inherit_id" ref="uom.product_uom_form_view"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="category_id" position="after">
|
||||
<field name="l10n_es_edi_facturae_uom_code" string="Spanish Facturae EDI type"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
<record id="product_uom_categ_form_view_inherit_l10n_es_edi_facturae" model="ir.ui.view">
|
||||
<field name="name">uom.category.form.inherit.l10n_es_edi_facturae</field>
|
||||
<field name="model">uom.category</field>
|
||||
<field name="inherit_id" ref="uom.product_uom_categ_form_view"/>
|
||||
<field name="arch" type="xml">
|
||||
<tree position="inside">
|
||||
<field name="l10n_es_edi_facturae_uom_code" string="Spanish Facturae EDI type"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
@@ -0,0 +1 @@
|
||||
from . import account_move_reversal
|
||||
@@ -0,0 +1,37 @@
|
||||
from odoo import models, fields
|
||||
|
||||
|
||||
class AccountMoveReversal(models.TransientModel):
|
||||
_inherit = 'account.move.reversal'
|
||||
|
||||
l10n_es_edi_facturae_reason_code = fields.Selection(
|
||||
selection=[
|
||||
('01', 'Invoice number'),
|
||||
('02', 'Invoice series'),
|
||||
('03', 'Date of issue'),
|
||||
('04', 'Name and surname/company name - Issuer'),
|
||||
('05', 'Name and surname/company name - Recipient'),
|
||||
('06', 'Tax identification Issuer/Oblige'),
|
||||
('07', 'Tax identification Receiver'),
|
||||
('08', 'Issuer/Oblige Address'),
|
||||
('09', 'Receiving Address'),
|
||||
('10', 'Transaction Details'),
|
||||
('11', 'Tax rate to be applied'),
|
||||
('12', 'Tax rate to be applied'),
|
||||
('13', 'Date/Period to apply'),
|
||||
('14', 'Invoice type'),
|
||||
('15', 'Statutory letters'),
|
||||
('16', 'Taxable amount'),
|
||||
('80', 'Calculation of output quotas'),
|
||||
('81', 'Calculation of withholding taxes'),
|
||||
('82', 'Taxable amount modified by return of containers/packaging'),
|
||||
('83', 'Taxable income modified by discounts and allowances'),
|
||||
('84', 'Taxable income modified by final, judicial or administrative ruling'),
|
||||
('85', 'Taxable income modified by unpaid tax assessments. Order of declaration of bankruptcy'),
|
||||
], string='Spanish Facturae EDI Reason Code', default='10')
|
||||
|
||||
def reverse_moves(self):
|
||||
# Extends account_account
|
||||
res = super(AccountMoveReversal, self).reverse_moves()
|
||||
self.new_move_ids.l10n_es_edi_facturae_reason_code = self.l10n_es_edi_facturae_reason_code
|
||||
return res
|
||||
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data>
|
||||
|
||||
<record id="view_tax_tree_inherit_l10n_es_edi_facturae" model="ir.ui.view">
|
||||
<field name="name">account.tax.tree.inherit.l10n_es_edi_facturae</field>
|
||||
<field name="inherit_id" ref="account.view_tax_tree"/>
|
||||
<field name="model">account.tax</field>
|
||||
<field name="arch" type="xml">
|
||||
<field name="country_id" position="after">
|
||||
<field name="country_code" invisible="1"/>
|
||||
<field name="l10n_es_edi_facturae_tax_type" string="Spanish Tax Type" optional="hide"
|
||||
attrs="{'invisible': [('country_code', '!=', 'ES')]}"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
<record id="view_account_move_reversal_inherit_l10n_es_edi_facturae" model="ir.ui.view">
|
||||
<field name="name">account.move.reversal.form.inherit.l10n_es_edi_facturae</field>
|
||||
<field name="inherit_id" ref="account.view_account_move_reversal"/>
|
||||
<field name="model">account.move.reversal</field>
|
||||
<field name="arch" type="xml">
|
||||
<field name="reason" position="replace">
|
||||
<field name="country_code" invisible="1"/>
|
||||
<field name="l10n_es_edi_facturae_reason_code" string="Reason" attrs="{'invisible':[('country_code', '!=', 'ES')]}"/>
|
||||
<field name="reason" string="Reason" attrs="{'invisible': [('move_type', '=', 'entry'), ('country_code', '=', 'ES')]}"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
@@ -0,0 +1,82 @@
|
||||
import base64
|
||||
import hashlib
|
||||
from base64 import b64encode
|
||||
from copy import deepcopy
|
||||
|
||||
from cryptography.hazmat.primitives import hashes
|
||||
from cryptography.hazmat.primitives.asymmetric import padding
|
||||
from lxml import etree
|
||||
|
||||
from odoo.exceptions import UserError
|
||||
|
||||
NS_MAP = {'ds': "http://www.w3.org/2000/09/xmldsig#"}
|
||||
|
||||
|
||||
def _canonicalize_node(node):
|
||||
"""
|
||||
Returns the canonical (C14N 1.0, without comments, non exclusive) representation of node.
|
||||
Speficied in: https://www.w3.org/TR/2001/REC-xml-c14n-20010315
|
||||
Required for computing digests and signatures.
|
||||
Returns an UTF-8 encoded bytes string.
|
||||
"""
|
||||
|
||||
return etree.tostring(node, method="c14n", with_comments=False, exclusive=False)
|
||||
|
||||
|
||||
def _get_uri(uri, reference, base_uri=""):
|
||||
"""
|
||||
Returns the content within `reference` that is identified by `uri`.
|
||||
Canonicalization is used to convert node reference to an octet stream.
|
||||
- URIs starting with # are same-document references
|
||||
https://www.w3.org/TR/xmldsig-core/#sec-URI
|
||||
- Empty URIs point to the whole document tree, without the signature
|
||||
https://www.w3.org/TR/xmldsig-core/#sec-EnvelopedSignature
|
||||
Returns an UTF-8 encoded bytes string.
|
||||
"""
|
||||
node = deepcopy(reference.getroottree())
|
||||
if uri == base_uri:
|
||||
# Base URI: whole document, without signature (default is empty URI)
|
||||
for signature in node.xpath('/ds:Signature', namespaces=NS_MAP):
|
||||
node = signature.getparent()
|
||||
node.remove(signature)
|
||||
return _canonicalize_node(node)
|
||||
|
||||
if uri.startswith("#"):
|
||||
path = "//*[@*[local-name() = '{}' ]=$uri]"
|
||||
results = node.xpath(path.format("Id"), uri=uri.lstrip("#")) # case-sensitive 'Id'
|
||||
if len(results) == 1:
|
||||
return _canonicalize_node(results[0])
|
||||
if len(results) > 1:
|
||||
raise UserError(f"Ambiguous reference URI {uri} resolved to {len(results)} nodes")
|
||||
|
||||
raise UserError(f'URI {uri} not found')
|
||||
|
||||
|
||||
def _reference_digests(node, base_uri=""):
|
||||
"""
|
||||
Processes the references from node and computes their digest values as specified in
|
||||
https://www.w3.org/TR/xmldsig-core/#sec-DigestMethod
|
||||
https://www.w3.org/TR/xmldsig-core/#sec-DigestValue
|
||||
"""
|
||||
for reference in node.findall("ds:Reference", namespaces=NS_MAP):
|
||||
ref_node = _get_uri(reference.get("URI", ""), reference, base_uri=base_uri)
|
||||
lib = hashlib.new("sha256", ref_node)
|
||||
reference.find("ds:DigestValue", namespaces=NS_MAP).text = b64encode(lib.digest())
|
||||
|
||||
|
||||
def _fill_signature(node, private_key):
|
||||
"""
|
||||
Uses private_key to sign the SignedInfo sub-node of `node`, as specified in:
|
||||
https://www.w3.org/TR/xmldsig-core/#sec-SignatureValue
|
||||
https://www.w3.org/TR/xmldsig-core/#sec-SignedInfo
|
||||
"""
|
||||
signed_info_xml = node.find("ds:SignedInfo", namespaces=NS_MAP)
|
||||
|
||||
# During signature generation, the digest is computed over the canonical form of the document
|
||||
signature = private_key.sign(_canonicalize_node(signed_info_xml), padding.PKCS1v15(), hashes.SHA256())
|
||||
node.find("ds:SignatureValue", namespaces=NS_MAP).text = base64.encodebytes(signature)
|
||||
|
||||
|
||||
def _int_to_bytes(number):
|
||||
""" Converts an integer to a byte string (in smallest big-endian form). """
|
||||
return number.to_bytes((number.bit_length() + 7) // 8, byteorder='big')
|
||||
Reference in New Issue
Block a user