[IMP] {l10n_}account_edi_ubl_cii{_tests},l10n_{ro,sa}_edi: add standard fields on UBL 2.0

The aim of this commit is mainly to add optional standard node directly
on UBL 2.0.
This will allow national customization of ubl to be easier to implement.

List of modification:
- Add the following nodes:
    - AddressFormatCode
    - BuildingNumber
    - PlotIdentification
    - CitySubdivisionName
    - Name under TaxScheme
    - DocumentTypeCode
- reduce zatca customization
- add attrs to several place to ease customization of attributes
- add a hook from which customization can override all decimal places to
  enforce a maximum
- add a hook to ease the modification of the `legal_monetary_total_vals`
  sub dict
- add method to allow customization to provide attributes for
  DocumentTypeCode node.

Notes:
Regarding PlotIdentification and CitySubdivisionName, I decided to not
populate some of those field for now because I didn't think of a
reliable way to get their value while zatca benefits from fields created
in l10n_sa_edi.

Task-id: 3326977
Part-of: odoo/odoo#136072
This commit is contained in:
Brice bib Bartoletti
2023-09-20 17:18:09 +00:00
parent 7e8c0846a5
commit 04a30d8091
23 changed files with 90 additions and 55 deletions
@@ -5,7 +5,11 @@
<t xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2"
xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2"
xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2">
<cbc:AddressFormatCode t-att="vals.get('address_format_code_attrs', {})" t-out="vals.get('address_format_code')"/>
<cbc:StreetName t-out="vals.get('street_name')"/>
<cbc:BuildingNumber t-out="vals.get('building_number')"/>
<cbc:PlotIdentification t-out="vals.get('plot_identification')"/>
<cbc:CitySubdivisionName t-out="vals.get('city_subdivision_name ')"/>
<cbc:AdditionalStreetName t-out="vals.get('additional_street_name')"/>
<cbc:CityName t-out="vals.get('city_name')"/>
<cbc:PostalZone t-out="vals.get('postal_zone')"/>
@@ -58,7 +62,10 @@
</t>
</cac:RegistrationAddress>
<cac:TaxScheme>
<cbc:ID t-out="foreach_vals.get('tax_scheme_id')"/>
<cbc:ID
t-att="foreach_vals.get('tax_scheme_id_attrs', {})"
t-out="foreach_vals.get('tax_scheme_id')"/>
<cbc:Name t-out="foreach_vals.get('tax_name')"/>
</cac:TaxScheme>
</cac:PartyTaxScheme>
</t>
@@ -67,8 +74,8 @@
<cac:PartyLegalEntity>
<cbc:RegistrationName t-out="foreach_vals.get('registration_name')"/>
<cbc:CompanyID
t-att="foreach_vals.get('company_id_attrs', {})"
t-out="foreach_vals.get('company_id')"/>
t-att="foreach_vals.get('company_id_attrs', {})"
t-out="foreach_vals.get('company_id')"/>
<cac:RegistrationAddress>
<t t-call="{{AddressType_template}}">
<t t-set="vals" t-value="foreach_vals.get('registration_address_vals', {})"/>
@@ -139,7 +146,11 @@
<cbc:TaxExemptionReason
t-out="vals.get('tax_exemption_reason')"/>
<cac:TaxScheme>
<cbc:ID t-translation="off" t-out="vals.get('tax_scheme_id')"/>
<cbc:ID
t-translation="off"
t-att="vals.get('tax_scheme_id_attrs')"
t-out="vals.get('tax_scheme_id')"/>
<cbc:Name t-translation="off" t-out="vals.get('tax_scheme_name')"/>
</cac:TaxScheme>
</t>
</template>
@@ -263,7 +274,9 @@
xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2">
<cbc:UBLVersionID t-out="vals.get('ubl_version_id')"/>
<cbc:CustomizationID t-out="vals.get('customization_id')"/>
<cbc:ProfileID t-out="vals.get('profile_id')"/>
<cbc:ProfileID
t-att="vals.get('profile_id_attrs', {})"
t-out="vals.get('profile_id')"/>
<cbc:ID t-out="vals.get('id')"/>
<cbc:IssueDate t-out="vals.get('issue_date')"/>
<cbc:InvoiceTypeCode
@@ -1,5 +1,3 @@
# -*- coding: utf-8 -*-
from odoo import _, models, Command
from odoo.tools import float_repr
from odoo.exceptions import UserError, ValidationError
@@ -104,6 +102,10 @@ class AccountEdiCommon(models.AbstractModel):
return None
return float_repr(float_round(amount, precision_digits), precision_digits)
def _get_currency_decimal_places(self, currency_id):
# Allows other documents to easily override in case there is a flat max precision number
return currency_id.decimal_places
def _get_uom_unece_code(self, line):
"""
list of codes: https://docs.peppol.eu/poacc/billing/3.0/codelist/UNECERec20/
@@ -1,9 +1,9 @@
# -*- coding: utf-8 -*-
from lxml import etree
from odoo import models, _
from odoo.osv import expression
from odoo.tools import html2plaintext, cleanup_xml_node, find_xml_value
from lxml import etree
class AccountEdiXmlUBL20(models.AbstractModel):
@@ -169,7 +169,7 @@ class AccountEdiXmlUBL20(models.AbstractModel):
def _get_invoice_tax_totals_vals_list(self, invoice, taxes_vals):
tax_totals_vals = {
'currency': invoice.currency_id,
'currency_dp': invoice.currency_id.decimal_places,
'currency_dp': self._get_currency_decimal_places(invoice.currency_id),
'tax_amount': taxes_vals['tax_amount_currency'],
'tax_subtotal_vals': [],
}
@@ -177,7 +177,7 @@ class AccountEdiXmlUBL20(models.AbstractModel):
if grouping_key['tax_amount_type'] != 'fixed':
tax_totals_vals['tax_subtotal_vals'].append({
'currency': invoice.currency_id,
'currency_dp': invoice.currency_id.decimal_places,
'currency_dp': self._get_currency_decimal_places(invoice.currency_id),
'taxable_amount': vals['base_amount_currency'],
'tax_amount': vals['tax_amount_currency'],
'percent': vals['_tax_category_vals_']['percent'],
@@ -235,7 +235,7 @@ class AccountEdiXmlUBL20(models.AbstractModel):
if grouping_key['tax_amount_type'] == 'fixed':
fixed_tax_charge_vals_list.append({
'currency_name': line.currency_id.name,
'currency_dp': line.currency_id.decimal_places,
'currency_dp': self._get_currency_decimal_places(line.currency_id),
'charge_indicator': 'true',
'allowance_charge_reason_code': 'AEO',
'allowance_charge_reason': tax_details['tax_name'],
@@ -255,7 +255,7 @@ class AccountEdiXmlUBL20(models.AbstractModel):
allowance_vals = {
'currency_name': line.currency_id.name,
'currency_dp': line.currency_id.decimal_places,
'currency_dp': self._get_currency_decimal_places(line.currency_id),
# Must be 'false' since this method is for allowances.
'charge_indicator': 'false',
@@ -292,7 +292,7 @@ class AccountEdiXmlUBL20(models.AbstractModel):
return {
'currency': line.currency_id,
'currency_dp': line.currency_id.decimal_places,
'currency_dp': self._get_currency_decimal_places(line.currency_id),
# The price of an item, exclusive of VAT, after subtracting item price discount.
'price_amount': gross_price_unit,
@@ -321,7 +321,7 @@ class AccountEdiXmlUBL20(models.AbstractModel):
)
return {
'currency': line.currency_id,
'currency_dp': line.currency_id.decimal_places,
'currency_dp': self._get_currency_decimal_places(line.currency_id),
'id': line_id + 1,
'invoiced_quantity': line.quantity,
'invoiced_quantity_attrs': {'unitCode': uom},
@@ -332,13 +332,25 @@ class AccountEdiXmlUBL20(models.AbstractModel):
'price_vals': self._get_invoice_line_price_vals(line),
}
def _get_invoice_legal_monetary_total_vals(self, invoice, taxes_vals, line_extension_amount, allowance_total_amount):
""" Method used to fill the cac:LegalMonetaryTotal node"""
return {
'currency': invoice.currency_id,
'currency_dp': self._get_currency_decimal_places(invoice.currency_id),
'line_extension_amount': line_extension_amount,
'tax_exclusive_amount': taxes_vals['base_amount_currency'],
'tax_inclusive_amount': invoice.amount_total,
'allowance_total_amount': allowance_total_amount or None,
'prepaid_amount': invoice.amount_total - invoice.amount_residual,
'payable_amount': invoice.amount_residual,
}
def _apply_invoice_tax_filter(self, base_line, tax_values):
"""
To be overridden to apply a specific tax filter
"""
return True
def _apply_invoice_line_filter(self, invoice_line):
"""
To be overridden to apply a specific invoice line filter
@@ -451,18 +463,9 @@ class AccountEdiXmlUBL20(models.AbstractModel):
# allowances at the document level, the allowances on invoices (eg. discount) are on invoice_line_vals
'allowance_charge_vals': document_allowance_charge_vals_list,
'tax_total_vals': self._get_invoice_tax_totals_vals_list(invoice, taxes_vals),
'legal_monetary_total_vals': {
'currency': invoice.currency_id,
'currency_dp': invoice.currency_id.decimal_places,
'line_extension_amount': line_extension_amount,
'tax_exclusive_amount': taxes_vals['base_amount_currency'],
'tax_inclusive_amount': invoice.amount_total,
'allowance_total_amount': allowance_total_amount or None,
'prepaid_amount': invoice.amount_total - invoice.amount_residual,
'payable_amount': invoice.amount_residual,
},
'legal_monetary_total_vals': self._get_invoice_legal_monetary_total_vals(invoice, taxes_vals, line_extension_amount, allowance_total_amount),
'invoice_line_vals': invoice_line_vals_list,
'currency_dp': invoice.currency_id.decimal_places, # currency decimal places
'currency_dp': self._get_currency_decimal_places(invoice.currency_id), # currency decimal places
},
}
@@ -474,6 +477,7 @@ class AccountEdiXmlUBL20(models.AbstractModel):
vals['vals']['credit_note_type_code'] = 381
return vals
def _export_invoice_constraints(self, invoice, vals):
constraints = self._invoice_constraints_common(invoice)
constraints.update({
@@ -491,6 +495,13 @@ class AccountEdiXmlUBL20(models.AbstractModel):
xml_content = self.env['ir.qweb']._render(vals['main_template'], vals)
return etree.tostring(cleanup_xml_node(xml_content), xml_declaration=True, encoding='UTF-8'), set(errors)
def _get_document_type_code_vals(self, invoice, invoice_data):
"""Returns the values used for the `DocumentTypeCode` node"""
# To be overriden by custom format if required
# http://www.datypic.com/sc/ubl20/e-cbc_DocumentTypeCode.html
document_type_code = 380 if invoice.move_type == 'out_invoice' else 381
return {'attrs': {}, 'value': document_type_code}
# -------------------------------------------------------------------------
# IMPORT
# -------------------------------------------------------------------------
@@ -56,3 +56,10 @@ class AccountMove(models.Model):
def _get_edi_doc_attachments_to_export(self):
# EXTENDS 'account'
return super()._get_edi_doc_attachments_to_export() + self.ubl_cii_xml_id
def _need_ubl_cii_xml(self):
self.ensure_one()
return not self.invoice_pdf_report_id \
and not self.ubl_cii_xml_id \
and self.is_sale_document() \
and bool(self.partner_id.ubl_cii_format)
@@ -17,16 +17,9 @@ class AccountMoveSend(models.Model):
_inherit = 'account.move.send'
enable_ubl_cii_xml = fields.Boolean(compute='_compute_send_mail_extra_fields')
checkbox_ubl_cii_label = fields.Char(compute='_compute_checkbox_ubl_cii_label') # label for the checkbox_ubl_cii_xml field
checkbox_ubl_cii_label = fields.Char(compute='_compute_checkbox_ubl_cii_label')
checkbox_ubl_cii_xml = fields.Boolean(compute='_compute_checkbox_ubl_cii_xml', store=True, readonly=False)
@api.model
def _get_default_enable_ubl_cii_xml(self, move):
return not move.invoice_pdf_report_id \
and not move.ubl_cii_xml_id \
and move.is_sale_document() \
and bool(move.partner_id.ubl_cii_format)
def _get_available_field_values_in_multi(self, move):
# EXTENDS 'account'
values = super()._get_available_field_values_in_multi(move)
@@ -51,7 +44,7 @@ class AccountMoveSend(models.Model):
# EXTENDS 'account'
super()._compute_send_mail_extra_fields()
for wizard in self:
wizard.enable_ubl_cii_xml = any(wizard._get_default_enable_ubl_cii_xml(m) for m in wizard.move_ids)
wizard.enable_ubl_cii_xml = any(m._need_ubl_cii_xml() for m in wizard.move_ids)
@api.depends('checkbox_ubl_cii_xml')
def _compute_mail_attachments_widget(self):
@@ -99,9 +92,8 @@ class AccountMoveSend(models.Model):
# EXTENDS 'account'
super()._hook_invoice_document_before_pdf_report_render(invoice, invoice_data)
if self.mode == 'invoice_single' and self.checkbox_ubl_cii_xml and self._get_default_enable_ubl_cii_xml(invoice):
if self.mode == 'invoice_single' and self.checkbox_ubl_cii_xml and invoice._need_ubl_cii_xml():
builder = invoice.partner_id._get_edi_builder()
xml_content, errors = builder._export_invoice(invoice)
filename = builder._export_invoice_filename(invoice)
@@ -136,8 +128,8 @@ class AccountMoveSend(models.Model):
if 'ubl_cii_xml_options' in invoice_data and invoice_data['ubl_cii_xml_options']['ubl_cii_format'] != 'facturx':
self._postprocess_invoice_ubl_xml(invoice, invoice_data)
# Always silently generate a Factur-X and embed it inside the PDF (inter-portability)
if 'ubl_cii_xml_options' in invoice_data and invoice_data['ubl_cii_xml_options']['ubl_cii_format'] == 'facturx':
# Always silently generate a Factur-X and embed it inside the PDF for inter-portability
if invoice_data.get('ubl_cii_xml_options', {}).get('ubl_cii_format') == 'facturx':
xml_facturx = invoice_data['ubl_cii_xml_attachment_values']['raw']
else:
xml_facturx = self.env['account.edi.xml.cii']._export_invoice(invoice)[0]
@@ -163,8 +155,7 @@ class AccountMoveSend(models.Model):
writer.addAttachment('factur-x.xml', xml_facturx, subtype='text/xml')
# PDF-A.
if 'ubl_cii_xml_options' in invoice_data \
and invoice_data['ubl_cii_xml_options']['ubl_cii_format'] == 'facturx' \
if invoice_data.get('ubl_cii_xml_options', {}).get('ubl_cii_format') == 'facturx' \
and not writer.is_pdfa:
try:
writer.convert_to_pdfa()
@@ -189,7 +180,7 @@ class AccountMoveSend(models.Model):
writer_buffer.close()
def _postprocess_invoice_ubl_xml(self, invoice, invoice_data):
# Add PDF to XML
# Adding the PDF to the XML
tree = etree.fromstring(invoice_data['ubl_cii_xml_attachment_values']['raw'])
anchor_elements = tree.xpath("//*[local-name()='AccountingSupplierParty']")
if not anchor_elements:
@@ -197,12 +188,19 @@ class AccountMoveSend(models.Model):
filename = invoice_data['pdf_attachment_values']['name']
content = invoice_data['pdf_attachment_values']['raw']
edi_model = invoice_data["ubl_cii_xml_options"]["builder"]
doc_type_code_vals = edi_model._get_document_type_code_vals(invoice, invoice_data)
document_type_code_attributes = " ".join(f'{name}="{value}"' for name, value in doc_type_code_vals['attrs'].items())
document_type_code_value = doc_type_code_vals.get('value', '')
to_inject = f'''
<cac:AdditionalDocumentReference
xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2"
xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2"
xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2">
<cbc:ID>{escape(filename)}</cbc:ID>
<cbc:DocumentTypeCode {document_type_code_attributes}>{document_type_code_value}</cbc:DocumentTypeCode>
<cac:Attachment>
<cbc:EmbeddedDocumentBinaryObject
mimeCode="application/pdf"
@@ -14,6 +14,7 @@
</cac:OrderReference>
<cac:AdditionalDocumentReference>
<cbc:ID>___ignore___</cbc:ID>
<cbc:DocumentTypeCode>380</cbc:DocumentTypeCode>
<cbc:Attachment>
<cbc:EmbeddedDocumentBinaryObject>___ignore___</cbc:EmbeddedDocumentBinaryObject>
</cbc:Attachment>
@@ -13,6 +13,7 @@
</cac:OrderReference>
<cac:AdditionalDocumentReference>
<cbc:ID>___ignore___</cbc:ID>
<cbc:DocumentTypeCode>381</cbc:DocumentTypeCode>
<cbc:Attachment>
<cbc:EmbeddedDocumentBinaryObject>___ignore___</cbc:EmbeddedDocumentBinaryObject>
</cbc:Attachment>
@@ -17,6 +17,7 @@
</cac:OrderReference>
<cac:AdditionalDocumentReference>
<cbc:ID>___ignore___</cbc:ID>
<cbc:DocumentTypeCode>380</cbc:DocumentTypeCode>
<cbc:Attachment>
<cbc:EmbeddedDocumentBinaryObject mimeCode="___ignore___" filename="___ignore___">___ignore___</cbc:EmbeddedDocumentBinaryObject>
</cbc:Attachment>
@@ -17,6 +17,7 @@
</cac:OrderReference>
<cac:AdditionalDocumentReference>
<cbc:ID>___ignore___</cbc:ID>
<cbc:DocumentTypeCode>380</cbc:DocumentTypeCode>
<cbc:Attachment>
<cbc:EmbeddedDocumentBinaryObject mimeCode="___ignore___" filename="___ignore___">___ignore___</cbc:EmbeddedDocumentBinaryObject>
</cbc:Attachment>
@@ -17,6 +17,7 @@
</cac:OrderReference>
<cac:AdditionalDocumentReference>
<cbc:ID>___ignore___</cbc:ID>
<cbc:DocumentTypeCode>380</cbc:DocumentTypeCode>
<cbc:Attachment>
<cbc:EmbeddedDocumentBinaryObject mimeCode="___ignore___" filename="___ignore___">___ignore___</cbc:EmbeddedDocumentBinaryObject>
</cbc:Attachment>
@@ -14,6 +14,7 @@
</cac:OrderReference>
<cac:AdditionalDocumentReference>
<cbc:ID>___ignore___</cbc:ID>
<cbc:DocumentTypeCode>380</cbc:DocumentTypeCode>
<cbc:Attachment>
<cbc:EmbeddedDocumentBinaryObject>___ignore___</cbc:EmbeddedDocumentBinaryObject>
</cbc:Attachment>
@@ -14,6 +14,7 @@
</cac:OrderReference>
<cac:AdditionalDocumentReference>
<cbc:ID>___ignore___</cbc:ID>
<cbc:DocumentTypeCode>380</cbc:DocumentTypeCode>
<cbc:Attachment>
<cbc:EmbeddedDocumentBinaryObject>___ignore___</cbc:EmbeddedDocumentBinaryObject>
</cbc:Attachment>
@@ -17,6 +17,7 @@
</cac:OrderReference>
<cac:AdditionalDocumentReference>
<cbc:ID>___ignore___</cbc:ID>
<cbc:DocumentTypeCode>380</cbc:DocumentTypeCode>
<cbc:Attachment>
<cbc:EmbeddedDocumentBinaryObject mimeCode="___ignore___" filename="___ignore___">
___ignore___
@@ -13,6 +13,7 @@
</cac:OrderReference>
<cac:AdditionalDocumentReference>
<cbc:ID>___ignore___</cbc:ID>
<cbc:DocumentTypeCode>381</cbc:DocumentTypeCode>
<cbc:Attachment>
<cbc:EmbeddedDocumentBinaryObject>___ignore___</cbc:EmbeddedDocumentBinaryObject>
</cbc:Attachment>
@@ -14,6 +14,7 @@
</cac:OrderReference>
<cac:AdditionalDocumentReference>
<cbc:ID>___ignore___</cbc:ID>
<cbc:DocumentTypeCode>380</cbc:DocumentTypeCode>
<cbc:Attachment>
<cbc:EmbeddedDocumentBinaryObject>___ignore___</cbc:EmbeddedDocumentBinaryObject>
</cbc:Attachment>
@@ -18,6 +18,7 @@
</cac:BillingReference>
<cac:AdditionalDocumentReference>
<cbc:ID>___ignore___</cbc:ID>
<cbc:DocumentTypeCode>381</cbc:DocumentTypeCode>
<cbc:Attachment>
<cbc:EmbeddedDocumentBinaryObject>___ignore___</cbc:EmbeddedDocumentBinaryObject>
</cbc:Attachment>
@@ -14,6 +14,7 @@
</cac:OrderReference>
<cac:AdditionalDocumentReference>
<cbc:ID>___ignore___</cbc:ID>
<cbc:DocumentTypeCode>380</cbc:DocumentTypeCode>
<cbc:Attachment>
<cbc:EmbeddedDocumentBinaryObject>___ignore___</cbc:EmbeddedDocumentBinaryObject>
</cbc:Attachment>
@@ -13,6 +13,7 @@
</cac:OrderReference>
<cac:AdditionalDocumentReference>
<cbc:ID>___ignore___</cbc:ID>
<cbc:DocumentTypeCode>381</cbc:DocumentTypeCode>
<cbc:Attachment>
<cbc:EmbeddedDocumentBinaryObject>___ignore___</cbc:EmbeddedDocumentBinaryObject>
</cbc:Attachment>
@@ -15,6 +15,7 @@
</cac:OrderReference>
<cac:AdditionalDocumentReference>
<cbc:ID>INV_2017_00001.pdf</cbc:ID>
<cbc:DocumentTypeCode>380</cbc:DocumentTypeCode>
<cac:Attachment>
<cbc:EmbeddedDocumentBinaryObject mimeCode="application/pdf" filename="INV_2017_00001.pdf">___ignore___</cbc:EmbeddedDocumentBinaryObject>
</cac:Attachment>
@@ -15,6 +15,7 @@
</cac:OrderReference>
<cac:AdditionalDocumentReference>
<cbc:ID>INV_2017_00001.pdf</cbc:ID>
<cbc:DocumentTypeCode>380</cbc:DocumentTypeCode>
<cac:Attachment>
<cbc:EmbeddedDocumentBinaryObject mimeCode="application/pdf" filename="INV_2017_00001.pdf">___ignore___</cbc:EmbeddedDocumentBinaryObject>
</cac:Attachment>
@@ -14,6 +14,7 @@
</cac:OrderReference>
<cac:AdditionalDocumentReference xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2">
<cbc:ID>RINV_2017_00001.pdf</cbc:ID>
<cbc:DocumentTypeCode>381</cbc:DocumentTypeCode>
<cac:Attachment>
<cbc:EmbeddedDocumentBinaryObject mimeCode="application/pdf" filename="RINV_2017_00001.pdf">___ignore___</cbc:EmbeddedDocumentBinaryObject>
</cac:Attachment>
-12
View File
@@ -176,18 +176,6 @@
<template id="ubl_21_AddressType_zatca" inherit_id="account_edi_ubl_cii.ubl_20_AddressType" primary="True">
<!-- AdditionalStreetName causes the Validation SDK to crash, so it has to be removed -->
<xpath expr="//*[local-name()='AdditionalStreetName']" position="replace"/>
<xpath expr="//*[local-name()='StreetName']" position="after">
<t xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2"
xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2"
xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2">
<!-- Add Building number in compliance with rules KSA-17 (seller)/ KSA-18 (customer) -->
<cbc:BuildingNumber t-out="vals.get('building_number')"/>
<!-- Add Plot identification in compliance with rules KSA-23 (seller)/ KSA-19 (customer) -->
<cbc:PlotIdentification t-out="vals.get('plot_identification')"/>
<!-- Add Neighborhood in compliance with rules KSA-3 (seller)/ KSA-4 (customer) -->
<cbc:CitySubdivisionName t-out="vals.get('neighborhood')"/>
</t>
</xpath>
</template>
<template id="ubl_21_InvoiceType_zatca" inherit_id="account_edi_ubl_cii.ubl_21_InvoiceType" primary="True">
@@ -118,7 +118,7 @@ class AccountEdiXmlUBL21Zatca(models.AbstractModel):
return {
**super()._get_partner_address_vals(partner),
'building_number': partner.l10n_sa_edi_building_number,
'neighborhood': partner.street2,
'city_subdivision_name ': partner.street2,
'plot_identification': partner.l10n_sa_edi_plot_identification,
}