Skip to content

Commit 246500e

Browse files
monen17Borruso
authored andcommitted
[IMP] l10n_it_edi_extension: Import detail level
Allow the user to import e-bills with no lines, one line for each tax rate, or all lines (default).
1 parent a5215a9 commit 246500e

File tree

10 files changed

+343
-58
lines changed

10 files changed

+343
-58
lines changed

l10n_it_edi_extension/README.rst

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,9 @@ Le funzionalità principali incluse sono:
178178
dati dei comuni italiani reperibili dal sito dell'AdE
179179
http://www.agenziaentrate.gov.it/wps/content/Nsilib/Nsi/Strumenti/Codici+attivita+e+tributo/Codici+territorio/Comuni+italia+esteri
180180

181+
5. Importazione di una fattura elettronica senza righe, con una riga per
182+
ogni aliquota, oppure con tutte le righe (default).
183+
181184
<https://www.fatturapa.gov.it>
182185

183186
**English**
@@ -326,6 +329,9 @@ The main features included are:
326329
municipality data available from the Revenue Agency website
327330
http://www.agenziaentrate.gov.it/wps/content/Nsilib/Nsi/Strumenti/Codici+attivita+e+tributo/Codici+territorio/Comuni+italia+esteri
328331

332+
5. Importing e-bills with no lines, one line for each tax rate, or all
333+
lines (default).
334+
329335
<https://www.fatturapa.gov.it>
330336

331337
**Table of contents**
@@ -384,6 +390,12 @@ necessario che siano installati e configurati i moduli dipendenti:
384390
l'invio diretto tramite Odoo (se supportato dalla configurazione
385391
generale).
386392

393+
In Fatturazione > Configurazione > Impostazioni, valorizzare "Livello di
394+
dettaglio importazione e-fatture" per importare le fatture elettroniche
395+
senza righe, con una riga per ogni aliquota, oppure con tutte le righe
396+
(default). Questa configurazione può essere sovrascritta dal campo
397+
"Livello di dettaglio importazione e-fatture" in ogni fornitore.
398+
387399
**English**
388400

389401
The only available configurations are:
@@ -428,6 +440,11 @@ modules must be installed and configured:
428440
- Optional SDI credentials configuration if direct sending through
429441
Odoo is used (if supported by general configuration).
430442

443+
In Invoicing > Configuration > Settings, fill "E-bills import detail
444+
level" to import e-bills with no lines, one line for each tax rate, or
445+
all lines (default). This setting can be overridden using the "E-bills
446+
import detail level" in each supplier.
447+
431448
Bug Tracker
432449
===========
433450

l10n_it_edi_extension/models/account_move.py

Lines changed: 150 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
from datetime import datetime
66

7-
from odoo import api, fields, models
7+
from odoo import _, api, fields, models
88
from odoo.exceptions import UserError
99
from odoo.tools import float_compare, html2plaintext
1010

@@ -408,6 +408,7 @@ def _l10n_it_edi_get_extra_info(
408408
)
409409
self.l10n_it_edi_amount_tax += get_float(element_summary, ".//Imposta")
410410

411+
extra_info["l10n_it_edi_ext_body_tree"] = body_tree
411412
return extra_info, message_to_log
412413

413414
def _l10n_it_edi_create_partner(
@@ -578,68 +579,160 @@ def _l10n_it_edi_search_partner(self, company, vat, codice_fiscale, email):
578579

579580
return partner
580581

581-
def _l10n_it_edi_import_line(self, element, move_line, extra_info=None):
582-
# Admin. ref.
583-
if admin_ref := get_text(element, ".//RiferimentoAmministrazione"):
584-
move_line.l10n_it_edi_admin_ref = admin_ref
585-
586-
vals = {
587-
"line_number": int(get_text(element, ".//NumeroLinea")),
588-
"service_type": get_text(element, ".//TipoCessionePrestazione"),
589-
"name": " ".join(get_text(element, ".//Descrizione").split()),
590-
"qty": float(get_text(element, ".//Quantita") or 0),
591-
"uom": get_text(element, ".//UnitaMisura"),
592-
"period_start_date": get_date(element, ".//DataInizioPeriodo"),
593-
"period_end_date": get_date(element, ".//DataFinePeriodo"),
594-
"unit_price": get_float(element, ".//PrezzoUnitario"),
595-
"total_price": get_float(element, ".//PrezzoTotale"),
596-
"tax_amount": get_float(element, ".//AliquotaIVA"),
597-
"wt_amount": get_text(element, ".//Ritenuta"),
598-
"tax_kind": get_text(element, ".//Natura").upper(),
599-
"admin_ref": get_text(element, ".//RiferimentoAmministrazione"),
600-
"invoice_line_id": move_line.id,
601-
"invoice_id": move_line.move_id.id,
602-
}
603-
einvoice_line = self.env["l10n_it_edi.line"].create(vals)
604-
605-
if elements_code := element.xpath(".//CodiceArticolo"):
606-
for element_code in elements_code:
607-
self.env["l10n_it_edi.article_code"].create(
608-
{
609-
"name": get_text(element_code, ".//CodiceTipo"),
610-
"code_val": get_text(element_code, ".//CodiceValore"),
611-
"l10n_it_edi_line_id": einvoice_line.id,
612-
}
582+
def _l10n_it_edi_ext_import_summary_line(self, element, extra_info=None):
583+
messages_to_log = []
584+
company = self.company_id
585+
percentage = get_float(element, ".//AliquotaIVA")
586+
extra_domain = extra_info.get(
587+
"type_tax_use_domain", [("type_tax_use", "=", "purchase")]
588+
)
589+
l10n_it_exempt_reason = get_text(element, ".//Natura").upper() or False
590+
tax = self._l10n_it_edi_search_tax_for_import(
591+
company,
592+
percentage,
593+
extra_domain,
594+
l10n_it_exempt_reason=l10n_it_exempt_reason,
595+
)
596+
if tax:
597+
self.invoice_line_ids += self.env["account.move.line"].create(
598+
{
599+
"move_id": self.id,
600+
"name": _(
601+
"Summary for tax amount %(percentage)s",
602+
percentage=percentage,
603+
),
604+
"price_unit": get_float(element, ".//ImponibileImporto"),
605+
"tax_ids": tax.ids,
606+
}
607+
)
608+
else:
609+
messages_to_log.append(
610+
Markup("<br/>").join(
611+
(
612+
_(
613+
"Tax not found for summary line "
614+
"with percentage %(percentage)s.",
615+
percentage=percentage,
616+
),
617+
self._compose_info_message(element, "."),
618+
)
613619
)
620+
)
614621

615-
if elements_discount := element.xpath(".//ScontoMaggiorazione"):
616-
for element_discount in elements_discount:
617-
self.env["l10n_it_edi.discount_rise_price"].create(
618-
{
619-
"name": get_text(element_discount, ".//Tipo"),
620-
"percentage": get_float(element_discount, ".//Percentuale"),
621-
"amount": get_float(element_discount, ".//Importo"),
622-
"l10n_it_edi_line_id": einvoice_line.id,
623-
}
624-
)
622+
return messages_to_log
625623

626-
if elements_other_data := element.xpath(".//AltriDatiGestionali"):
627-
for element_other_data in elements_other_data:
628-
self.env["l10n_it_edi.line_other_data"].create(
629-
{
630-
"name": get_text(element_other_data, ".//TipoDato"),
631-
"text_ref": get_text(element_other_data, ".//RiferimentoTesto"),
632-
"num_ref": get_float(
633-
element_other_data, ".//RiferimentoNumero"
624+
def _l10n_it_edi_import_line(self, element, move_line, extra_info=None):
625+
if extra_info is None:
626+
extra_info = dict()
627+
messages_to_log = []
628+
company = move_line.company_id
629+
import_detail_level = (
630+
move_line.partner_id.l10n_it_edi_import_detail_level
631+
or company.l10n_it_edi_import_detail_level
632+
)
633+
if import_detail_level == "min":
634+
move_line.unlink()
635+
line_description = " ".join(get_text(element, ".//Descrizione").split())
636+
messages_to_log.append(
637+
Markup("<br/>").join(
638+
(
639+
_(
640+
"Line with description %(line_description)s "
641+
"has been skipped "
642+
"because import detail level is minimum.",
643+
line_description=line_description,
634644
),
635-
"date_ref": get_date(element_other_data, ".//RiferimentoData"),
636-
"l10n_it_edi_line_id": einvoice_line.id,
637-
}
645+
self._compose_info_message(element, "."),
646+
)
638647
)
648+
)
649+
elif (
650+
body_tree := extra_info.get("l10n_it_edi_ext_body_tree")
651+
) is not None and import_detail_level == "tax":
652+
move_line.unlink()
653+
tax_level_imported = extra_info.get("l10n_it_edi_ext_tax_level_imported")
654+
if not tax_level_imported:
655+
for summary_line in body_tree.xpath(".//DatiBeniServizi/DatiRiepilogo"):
656+
messages_to_log += self._l10n_it_edi_ext_import_summary_line(
657+
summary_line, extra_info=extra_info
658+
)
659+
extra_info["l10n_it_edi_ext_tax_level_imported"] = True
660+
elif import_detail_level == "max":
661+
# Admin. ref.
662+
if admin_ref := get_text(element, ".//RiferimentoAmministrazione"):
663+
move_line.l10n_it_edi_admin_ref = admin_ref
664+
665+
vals = {
666+
"line_number": int(get_text(element, ".//NumeroLinea")),
667+
"service_type": get_text(element, ".//TipoCessionePrestazione"),
668+
"name": " ".join(get_text(element, ".//Descrizione").split()),
669+
"qty": float(get_text(element, ".//Quantita") or 0),
670+
"uom": get_text(element, ".//UnitaMisura"),
671+
"period_start_date": get_date(element, ".//DataInizioPeriodo"),
672+
"period_end_date": get_date(element, ".//DataFinePeriodo"),
673+
"unit_price": get_float(element, ".//PrezzoUnitario"),
674+
"total_price": get_float(element, ".//PrezzoTotale"),
675+
"tax_amount": get_float(element, ".//AliquotaIVA"),
676+
"wt_amount": get_text(element, ".//Ritenuta"),
677+
"tax_kind": get_text(element, ".//Natura").upper(),
678+
"admin_ref": get_text(element, ".//RiferimentoAmministrazione"),
679+
"invoice_line_id": move_line.id,
680+
"invoice_id": move_line.move_id.id,
681+
}
682+
einvoice_line = self.env["l10n_it_edi.line"].create(vals)
683+
684+
if elements_code := element.xpath(".//CodiceArticolo"):
685+
for element_code in elements_code:
686+
self.env["l10n_it_edi.article_code"].create(
687+
{
688+
"name": get_text(element_code, ".//CodiceTipo"),
689+
"code_val": get_text(element_code, ".//CodiceValore"),
690+
"l10n_it_edi_line_id": einvoice_line.id,
691+
}
692+
)
639693

640-
return super()._l10n_it_edi_import_line(
641-
element, move_line, extra_info=extra_info
642-
)
694+
if elements_discount := element.xpath(".//ScontoMaggiorazione"):
695+
for element_discount in elements_discount:
696+
self.env["l10n_it_edi.discount_rise_price"].create(
697+
{
698+
"name": get_text(element_discount, ".//Tipo"),
699+
"percentage": get_float(element_discount, ".//Percentuale"),
700+
"amount": get_float(element_discount, ".//Importo"),
701+
"l10n_it_edi_line_id": einvoice_line.id,
702+
}
703+
)
704+
705+
if elements_other_data := element.xpath(".//AltriDatiGestionali"):
706+
for element_other_data in elements_other_data:
707+
self.env["l10n_it_edi.line_other_data"].create(
708+
{
709+
"name": get_text(element_other_data, ".//TipoDato"),
710+
"text_ref": get_text(
711+
element_other_data, ".//RiferimentoTesto"
712+
),
713+
"num_ref": get_float(
714+
element_other_data, ".//RiferimentoNumero"
715+
),
716+
"date_ref": get_date(
717+
element_other_data, ".//RiferimentoData"
718+
),
719+
"l10n_it_edi_line_id": einvoice_line.id,
720+
}
721+
)
722+
723+
messages_to_log += super()._l10n_it_edi_import_line(
724+
element, move_line, extra_info=extra_info
725+
)
726+
else:
727+
raise UserError(
728+
_(
729+
"Import detail level %(import_detail_level)s not supported.\n"
730+
"Please set an import detail level in company %(company)s.",
731+
import_detail_level=import_detail_level,
732+
company=company,
733+
)
734+
)
735+
return messages_to_log
643736

644737
def _l10n_it_edi_check_amount_untaxed(self):
645738
error_message = ""

l10n_it_edi_extension/models/res_company.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,23 @@ class ResCompanyInherit(models.Model):
3333
help="Automatically create the partner if it does not "
3434
"exist during the import of Electronic Invoices.",
3535
)
36+
l10n_it_edi_import_detail_level = fields.Selection(
37+
selection=[
38+
("min", "Minimum"),
39+
("tax", "Tax rate"),
40+
("max", "Maximum"),
41+
],
42+
default="max",
43+
required=True,
44+
string="E-bills import detail level",
45+
help="Minimum: the bill is created with no lines; "
46+
"the user will have to create them, according to what specified in "
47+
"the electronic bill.\n"
48+
"Tax rate: every tax rate present in the electronic bill "
49+
"will create a line in the bill.\n"
50+
"Maximum (default): every line contained in the electronic bill "
51+
"will create a line in the bill.",
52+
)
3653

3754

3855
class AccountConfigSettings(models.TransientModel):
@@ -45,3 +62,7 @@ class AccountConfigSettings(models.TransientModel):
4562
"exist during the import of Electronic Invoices.",
4663
readonly=False,
4764
)
65+
l10n_it_edi_import_detail_level = fields.Selection(
66+
related="company_id.l10n_it_edi_import_detail_level",
67+
readonly=False,
68+
)

l10n_it_edi_extension/models/res_partner.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,23 @@ class ResPartnerInherit(models.Model):
1919
)
2020
l10n_edi_it_register_code = fields.Char(string="Register Registration Number")
2121
l10n_edi_it_register_regdate = fields.Date(string="Register Registration Date")
22+
l10n_it_edi_import_detail_level = fields.Selection(
23+
selection=[
24+
("min", "Minimum"),
25+
("tax", "Tax rate"),
26+
("max", "Maximum"),
27+
],
28+
string="E-bills import detail level",
29+
help="Override the 'E-bills import detail level' of the company "
30+
"for bills of this supplier.\n"
31+
"Minimum: the bill is created with no lines; "
32+
"the user will have to create them, according to what specified in "
33+
"the electronic bill.\n"
34+
"Tax rate: every tax rate present in the electronic bill "
35+
"will create a line in the bill.\n"
36+
"Maximum: every line contained in the electronic bill "
37+
"will create a line in the bill.",
38+
)
2239

2340
@api.constrains("l10n_it_codice_fiscale", "company_type")
2441
def validate_codice_fiscale(self):

l10n_it_edi_extension/readme/CONFIGURE.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ Quindi, affinché le funzionalità di questo modulo siano utilizzabili, è neces
2020
- Configurazione delle sequenze dedicate per la numerazione delle fatture elettroniche.
2121
- Eventuale configurazione delle credenziali SDI se si utilizza l'invio diretto tramite Odoo (se supportato dalla configurazione generale).
2222

23+
In Fatturazione > Configurazione > Impostazioni, valorizzare "Livello di dettaglio importazione e-fatture" per importare le fatture elettroniche senza righe, con una riga per ogni aliquota, oppure con tutte le righe (default).
24+
Questa configurazione può essere sovrascritta dal campo "Livello di dettaglio importazione e-fatture" in ogni fornitore.
2325

2426
**English**
2527

@@ -41,4 +43,7 @@ Therefore, for this module's features to be usable, the dependent modules must b
4143
- Company data configuration (VAT number, fiscal code, tax regime, etc.).
4244
- Configuration of accounting journals for issuing electronic invoices (indicating FatturaPA/Electronic format).
4345
- Configuration of dedicated sequences for electronic invoice numbering.
44-
- Optional SDI credentials configuration if direct sending through Odoo is used (if supported by general configuration).
46+
- Optional SDI credentials configuration if direct sending through Odoo is used (if supported by general configuration).
47+
48+
In Invoicing > Configuration > Settings, fill "E-bills import detail level" to import e-bills with no lines, one line for each tax rate, or all lines (default).
49+
This setting can be overridden using the "E-bills import detail level" in each supplier.

l10n_it_edi_extension/readme/DESCRIPTION.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ Le funzionalità principali incluse sono:
7676

7777
4. Aggiunge di un wizard per calcolare i codici fiscali attingendo dai dati dei comuni italiani reperibili dal sito dell'AdE http://www.agenziaentrate.gov.it/wps/content/Nsilib/Nsi/Strumenti/Codici+attivita+e+tributo/Codici+territorio/Comuni+italia+esteri
7878

79+
5. Importazione di una fattura elettronica senza righe, con una riga per ogni aliquota, oppure con tutte le righe (default).
7980

8081
\<<https://www.fatturapa.gov.it>\>
8182

@@ -158,5 +159,6 @@ The main features included are:
158159

159160
4. Adds a wizard to calculate fiscal codes drawing from Italian municipality data available from the Revenue Agency website http://www.agenziaentrate.gov.it/wps/content/Nsilib/Nsi/Strumenti/Codici+attivita+e+tributo/Codici+territorio/Comuni+italia+esteri
160161

162+
5. Importing e-bills with no lines, one line for each tax rate, or all lines (default).
161163

162164
\<<https://www.fatturapa.gov.it>\>

0 commit comments

Comments
 (0)