Skip to content

Commit fb11a9e

Browse files
committed
[FIX] account_edi_ubl_cii: fix FacturX validation issues
Issue: There are several issues with the XML of FacturX. Steps to reproduce: - Create a partner with a direct debit mandate - In the Accounting tab of the partner select "FacturX" as eInvoice format - Create an invoice with this partner, pay with SDD, confirm - Send to FacturX - Verify the PDF with https://www.portinvoice.com/ - Missing namespace - In the XML the code for the payment means does not adapt to the payment method: 42 (Payment to bank account) and not 59 (SDD) Cause: - The namespaces are not there (It's not mandatory). - We always input "42" as payment mean Solution: - Added namespace `xmlns:qdt="urn:un:unece:uncefact:data:standard:QualifiedDataType:100"` and `xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"` - Added the code "59" for SDD, as a lot of codes could be added we add a dictionnary that could be used to add codes. This commit only handles the SDD code opw-4907827 closes odoo#219799 X-original-commit: 17a1fc4 Signed-off-by: Paolo Gatti (pgi) <pgi@odoo.com> Signed-off-by: Mathieu Coutant (mcou) <mcou@odoo.com>
1 parent 2114694 commit fb11a9e

3 files changed

Lines changed: 92 additions & 6 deletions

File tree

addons/account_edi_ubl_cii/data/cii_22_templates.xml

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
<t t-set="line" t-value="line_vals['line']"/>
66
<t xmlns:ram="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100"
77
xmlns:rsm="urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100"
8-
xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100">
8+
xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100"
9+
xmlns:qdt="urn:un:unece:uncefact:data:standard:QualifiedDataType:100"
10+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
911

1012
<ram:IncludedSupplyChainTradeLineItem>
1113
<!-- Line number. -->
@@ -101,7 +103,9 @@
101103
<template id="account_invoice_partner_facturx_export_22">
102104
<t xmlns:ram="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100"
103105
xmlns:rsm="urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100"
104-
xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100">
106+
xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100"
107+
xmlns:qdt="urn:un:unece:uncefact:data:standard:QualifiedDataType:100"
108+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
105109
<!-- Contact. -->
106110
<ram:Name t-out="partner.display_name"/>
107111
<ram:SpecifiedLegalOrganization t-if="specified_legal_organization_val">
@@ -127,7 +131,9 @@
127131
<template id="account_invoice_address_facturx_export_22">
128132
<t xmlns:ram="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100"
129133
xmlns:rsm="urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100"
130-
xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100">
134+
xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100"
135+
xmlns:qdt="urn:un:unece:uncefact:data:standard:QualifiedDataType:100"
136+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
131137
<!-- Address. -->
132138
<ram:PostalTradeAddress>
133139
<ram:PostcodeCode t-out="partner.zip"/>
@@ -144,7 +150,9 @@
144150
<rsm:CrossIndustryInvoice
145151
xmlns:ram="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100"
146152
xmlns:rsm="urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100"
147-
xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100">
153+
xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100"
154+
xmlns:qdt="urn:un:unece:uncefact:data:standard:QualifiedDataType:100"
155+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
148156
<!-- Factur-x level:
149157
* minimum or basicwl: urn:factur-x.eu:1p0...
150158
* basic: urn:cen.eu:en16931:2017:compliant:factur-x.eu:1p0:basic
@@ -243,7 +251,7 @@
243251

244252
<!-- Bank account. -->
245253
<ram:SpecifiedTradeSettlementPaymentMeans t-if="record.partner_bank_id.sanitized_acc_number">
246-
<ram:TypeCode>42</ram:TypeCode>
254+
<ram:TypeCode t-out="payment_means_code"/>
247255
<ram:PayeePartyCreditorFinancialAccount>
248256
<ram:IBANID
249257
t-if="record.partner_bank_id.acc_type == 'iban'"

addons/account_edi_ubl_cii/models/account_edi_xml_cii_facturx.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@
1515
'udt': "urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100",
1616
}
1717

18+
# Imcomplete, full list on https://service.unece.org/trade/untdid/d16b/tred/tred4461.htm
19+
PAYMENT_MEAN_CODES = {
20+
'Payment to bank account': 42,
21+
'SEPA direct debit': 59
22+
}
23+
1824

1925
class AccountEdiXmlCii(models.AbstractModel):
2026
_name = 'account.edi.xml.cii'
@@ -238,6 +244,11 @@ def grouping_key_generator(base_line, tax_data):
238244
template_values['tax_basis_total_amount'] = tax_details['base_amount_currency']
239245
template_values['tax_total_amount'] = tax_details['tax_amount_currency']
240246

247+
if self.env['account.payment']._fields.get('sdd_mandate_id') and invoice.matched_payment_ids.sdd_mandate_id:
248+
template_values['payment_means_code'] = PAYMENT_MEAN_CODES['SEPA direct debit']
249+
else:
250+
template_values['payment_means_code'] = PAYMENT_MEAN_CODES['Payment to bank account']
251+
241252
return template_values
242253

243254
def _export_invoice(self, invoice):

addons/account_edi_ubl_cii/tests/test_ubl_cii.py

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,9 @@ def setUpClass(cls):
3535
cls.namespaces = {
3636
'rsm': "urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100",
3737
'ram': "urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100",
38-
'udt': "urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100"
38+
'udt': "urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100",
39+
'qdt': "urn:un:unece:uncefact:data:standard:QualifiedDataType:100",
40+
'xsi': "http://www.w3.org/2001/XMLSchema-instance",
3941
}
4042

4143
def import_attachment(self, attachment, journal=None):
@@ -416,3 +418,68 @@ def test_import_discount(self):
416418
imported_invoice = self.import_attachment(xml_attachment, self.company_data["default_journal_sale"])
417419
for line in imported_invoice.invoice_line_ids:
418420
self.assertFalse(line.discount, "A discount on the imported lines signals a rounding error in the discount computation")
421+
422+
def test_payment_means_code_in_facturx_xml(self):
423+
bank_ing = self.env['res.bank'].create({'name': 'ING', 'bic': 'BBRUBEBB'})
424+
partner_bank = self.env['res.partner.bank'].create({
425+
'acc_number': 'BE15001559627230',
426+
'partner_id': self.partner_a.id,
427+
'bank_id': bank_ing.id,
428+
'company_id': self.env.company.id,
429+
})
430+
invoice = self.env['account.move'].create({
431+
'partner_id': self.partner_a.id,
432+
'move_type': 'out_invoice',
433+
'invoice_line_ids': [Command.create({'product_id': self.product_a.id})],
434+
'delivery_date': "2024-12-31",
435+
'partner_bank_id': partner_bank.id,
436+
})
437+
invoice.action_post()
438+
439+
xml_attachment = self.env['ir.attachment'].create({
440+
'raw': self.env['account.edi.xml.cii']._export_invoice(invoice)[0],
441+
'name': 'test_invoice.xml',
442+
})
443+
xml_tree = etree.fromstring(xml_attachment.raw)
444+
code = xml_tree.find('.//ram:SpecifiedTradeSettlementPaymentMeans/ram:TypeCode', self.namespaces)
445+
self.assertEqual(code.text, '42')
446+
447+
if self.env['ir.module.module']._get('account_sepa_direct_debit').state == 'installed':
448+
company = self.env.company
449+
company.sdd_creditor_identifier = 'BE30ZZZ300D000000042'
450+
company_bank_journal = self.company_data['default_journal_bank']
451+
company_bank_journal.bank_acc_number = 'CH9300762011623852957'
452+
company_bank_journal.bank_account_id.bank_id = bank_ing
453+
self.partner_a.country_id = self.env.ref('base.nl').id
454+
455+
mandate = self.env['sdd.mandate'].create({
456+
'name': 'mandate ' + (self.partner_a.name or ''),
457+
'partner_bank_id': partner_bank.id,
458+
'one_off': True,
459+
'start_date': fields.Date.today(),
460+
'partner_id': self.partner_a.id,
461+
'company_id': company.id,
462+
})
463+
mandate.action_validate_mandate()
464+
invoice = self.env['account.move'].create({
465+
'partner_id': self.partner_a.id,
466+
'move_type': 'out_invoice',
467+
'invoice_line_ids': [Command.create({'product_id': self.product_a.id})],
468+
'delivery_date': "2024-12-31",
469+
})
470+
invoice.action_post()
471+
sdd_method_line = company_bank_journal.inbound_payment_method_line_ids.filtered(lambda l: l.code == 'sdd')
472+
sdd_method_line.payment_account_id = self.inbound_payment_method_line.payment_account_id
473+
self.env['account.payment.register'].with_context(active_model='account.move', active_ids=invoice.ids).create({
474+
'payment_date': invoice.invoice_date,
475+
'journal_id': company_bank_journal.id,
476+
'payment_method_line_id': sdd_method_line.id,
477+
})._create_payments()
478+
479+
xml_attachment = self.env['ir.attachment'].create({
480+
'raw': self.env['account.edi.xml.cii']._export_invoice(invoice)[0],
481+
'name': 'test_invoice.xml',
482+
})
483+
xml_tree = etree.fromstring(xml_attachment.raw)
484+
code = xml_tree.find('.//ram:SpecifiedTradeSettlementPaymentMeans/ram:TypeCode', self.namespaces)
485+
self.assertEqual(code.text, '59')

0 commit comments

Comments
 (0)