Skip to content

Commit

Permalink
[ADD] l10n_it_fatturapa_out: edit invoice sent SDI
Browse files Browse the repository at this point in the history
Co-authored-by: guidgaro75 <guido.garofalo75@gmail.com>
  • Loading branch information
Borruso and guidgaro75 committed Sep 30, 2023
1 parent 4282940 commit cdc58e3
Show file tree
Hide file tree
Showing 5 changed files with 267 additions and 1 deletion.
1 change: 1 addition & 0 deletions l10n_it_fatturapa_out/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"views/partner_view.xml",
"views/company_view.xml",
"data/l10n_it_fatturapa_out_data.xml",
"security/groups.xml",
"security/ir.model.access.csv",
"security/rules.xml",
],
Expand Down
219 changes: 219 additions & 0 deletions l10n_it_fatturapa_out/models/account.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
# Copyright 2014 Davide Corio
# Copyright 2016 Lorenzo Battistini - Agile Business Group

import base64

from lxml import etree

from odoo import api, fields, models
from odoo.exceptions import UserError
from odoo.http import request
from odoo.tools.translate import _

fatturapa_attachment_state_mapping = {
Expand Down Expand Up @@ -99,11 +104,225 @@ def preventive_checks(self):
)
return

def check_tag(self, new_xml, original_xml, tags, precision=None):
"""
This function check if tag in new xml generated after function write()
is the same of original xml
:param new_xml: new xml generated after function write()
:param original_xml: original xml linked to invoice
:param tags: tags of xml to check
:param precision: precision to apply on text tag for check
:return: True if tags is the same else
"""
for tag in tags:
new_tag_text = new_xml.find(tag) is not None and new_xml.find(tag).text
original_tag_text = (
original_xml.find(tag) is not None and original_xml.find(tag).text
)
if precision:
new_tag_text = "{text:.{precision}f}".format(
text=float(new_tag_text), precision=precision
)
original_tag_text = "{text:.{precision}f}".format(
text=float(original_tag_text), precision=precision
)
if (new_tag_text or "").strip() != (original_tag_text or "").strip():
raise UserError(

Check warning on line 131 in l10n_it_fatturapa_out/models/account.py

View check run for this annotation

Codecov / codecov/patch

l10n_it_fatturapa_out/models/account.py#L131

Added line #L131 was not covered by tests
_("%(tag)s isn't equal to tag in file e-invoice already created!")
% {"tag": tag[2:]}
)

def check_CessionarioCommittente(self, new_xml, original_xml):
list_tag = [
".//CessionarioCommittente/DatiAnagrafici/IdFiscaleIVA/IdPaese",
".//CessionarioCommittente/DatiAnagrafici/IdFiscaleIVA/IdCodice",
]
self.check_tag(new_xml, original_xml, list_tag)

def check_DatiGeneraliDocumento(self, new_xml, original_xml):
price_precision = self.env["decimal.precision"].precision_get(
"Product Price for XML e-invoices"
)

list_tag = [
".//DatiGeneraliDocumento/Data",
".//DatiGeneraliDocumento/TipoDocumento",
".//DatiGeneraliDocumento/Divisa",
".//DatiGeneraliDocumento/Numero",
]
self.check_tag(new_xml, original_xml, list_tag)
list_tag = [
".//DatiGeneraliDocumento/ImportoTotaleDocumento",
]
self.check_tag(new_xml, original_xml, list_tag, price_precision)

if len(new_xml.findall(".//DatiGeneraliDocumento/DatiRitenuta")) != len(
original_xml.findall(".//DatiGeneraliDocumento/DatiRitenuta")
):
raise UserError(

Check warning on line 163 in l10n_it_fatturapa_out/models/account.py

View check run for this annotation

Codecov / codecov/patch

l10n_it_fatturapa_out/models/account.py#L163

Added line #L163 was not covered by tests
_(
"DatiGeneraliDocumento/DatiRitenuta "
"isn't equal to tag in file e-invoice already created!"
)
)
lr = 0
for new_line_ritenuta in new_xml.findall(
".//DatiGeneraliDocumento/DatiRitenuta"
):
original_line_ritenuta = original_xml.findall(

Check warning on line 173 in l10n_it_fatturapa_out/models/account.py

View check run for this annotation

Codecov / codecov/patch

l10n_it_fatturapa_out/models/account.py#L173

Added line #L173 was not covered by tests
".//DatiGeneraliDocumento/DatiRitenuta"
)[lr]
list_tag_DatiRitenuta = [

Check warning on line 176 in l10n_it_fatturapa_out/models/account.py

View check run for this annotation

Codecov / codecov/patch

l10n_it_fatturapa_out/models/account.py#L176

Added line #L176 was not covered by tests
".//TipoRitenuta",
".//CausalePagamento",
]
self.check_tag(

Check warning on line 180 in l10n_it_fatturapa_out/models/account.py

View check run for this annotation

Codecov / codecov/patch

l10n_it_fatturapa_out/models/account.py#L180

Added line #L180 was not covered by tests
new_line_ritenuta, original_line_ritenuta, list_tag_DatiRitenuta
)
list_tag_DatiRitenuta = [

Check warning on line 183 in l10n_it_fatturapa_out/models/account.py

View check run for this annotation

Codecov / codecov/patch

l10n_it_fatturapa_out/models/account.py#L183

Added line #L183 was not covered by tests
".//ImportoRitenuta",
".//AliquotaRitenuta",
]
self.check_tag(

Check warning on line 187 in l10n_it_fatturapa_out/models/account.py

View check run for this annotation

Codecov / codecov/patch

l10n_it_fatturapa_out/models/account.py#L187

Added line #L187 was not covered by tests
new_line_ritenuta,
original_line_ritenuta,
list_tag_DatiRitenuta,
price_precision,
)
lr += 1

Check warning on line 193 in l10n_it_fatturapa_out/models/account.py

View check run for this annotation

Codecov / codecov/patch

l10n_it_fatturapa_out/models/account.py#L193

Added line #L193 was not covered by tests

def check_DatiBeniServizi(self, new_xml, original_xml):
price_precision = self.env["decimal.precision"].precision_get(
"Product Price for XML e-invoices"
)
uom_precision = self.env["decimal.precision"].precision_get(
"Product Unit of Measure"
)

if len(new_xml.findall(".//DatiBeniServizi/DettaglioLinee")) != len(
original_xml.findall(".//DatiBeniServizi/DettaglioLinee")
):
raise UserError(

Check warning on line 206 in l10n_it_fatturapa_out/models/account.py

View check run for this annotation

Codecov / codecov/patch

l10n_it_fatturapa_out/models/account.py#L206

Added line #L206 was not covered by tests
_(
"DatiBeniServizi/DettaglioLinee "
"isn't equal to tag in file e-invoice already created!"
)
)
ld = 0
for new_line_details in new_xml.findall(".//DatiBeniServizi/DettaglioLinee"):
original_line_details = original_xml.findall(
".//DatiBeniServizi/DettaglioLinee"
)[ld]
list_tag_DettaglioLinee = [
".//NumeroLinea",
".//CodiceTipo",
".//CodiceValore",
".//Descrizione",
".//Natura",
".//Ritenuta",
]
self.check_tag(
new_line_details, original_line_details, list_tag_DettaglioLinee
)
list_tag_DettaglioLinee = [
".//Quantita",
]
self.check_tag(
new_line_details,
original_line_details,
list_tag_DettaglioLinee,
uom_precision,
)
list_tag_DettaglioLinee = [
".//PrezzoUnitario",
".//AliquotaIVA",
".//PrezzoTotale",
]
self.check_tag(
new_line_details,
original_line_details,
list_tag_DettaglioLinee,
price_precision,
)
ld += 1

if len(new_xml.findall(".//DatiBeniServizi/DatiRiepilogo")) != len(
original_xml.findall(".//DatiBeniServizi/DatiRiepilogo")
):
raise UserError(

Check warning on line 253 in l10n_it_fatturapa_out/models/account.py

View check run for this annotation

Codecov / codecov/patch

l10n_it_fatturapa_out/models/account.py#L253

Added line #L253 was not covered by tests
_(
"DatiBeniServizi/DatiRiepilogo "
"isn't equal to tag in file e-invoice already created!"
)
)
lr = 0
for new_line_riepilogo in new_xml.findall(".//DatiBeniServizi/DatiRiepilogo"):
original_line_riepilogo = original_xml.findall(
".//DatiBeniServizi/DatiRiepilogo"
)[lr]
list_tag_DatiRiepilogo = [
".//AliquotaIVA",
".//ImponibileImporto",
".//Imposta",
]
self.check_tag(
new_line_riepilogo,
original_line_riepilogo,
list_tag_DatiRiepilogo,
price_precision,
)
lr += 1

def elements_equal(self, new_xml, original_xml):
self.check_CessionarioCommittente(new_xml, original_xml)
self.check_DatiGeneraliDocumento(new_xml, original_xml)
self.check_DatiBeniServizi(new_xml, original_xml)

def write(self, vals):
is_draft = {}
for move in self:
is_draft[move.id] = True if move.state == "draft" else False
res = super(AccountInvoice, self).write(vals)
for move in self:
if (
move.is_sale_document()
and move.fatturapa_attachment_out_id
and is_draft[move.id]
and not move.state == "cancel"
and not move.env.context.get("skip_check_xml", False)
and not (
request
and request.params.get("method", False)
and request.params["method"] == "button_draft"
)
):
context_partner = self.env.context.copy()
context_partner.update({"lang": move.partner_id.lang})
context_partner.update(skip_check_xml=True)
fatturapa, progressivo_invio = self.env[
"wizard.export.fatturapa"
].exportInvoiceXML(move.partner_id, [move.id], context=context_partner)
new_xml_content = fatturapa.to_xml(self.env)
original_xml_content = base64.decodebytes(
move.fatturapa_attachment_out_id.datas
)
parser = etree.XMLParser(remove_blank_text=True)
new_xml = etree.fromstring(new_xml_content, parser)
original_xml = etree.fromstring(original_xml_content, parser)
move.elements_equal(new_xml, original_xml)
if not move.state == "posted":
move.with_context(skip_check_xml=True).action_post()
return res

def button_draft(self):
for invoice in self:
if (
invoice.fatturapa_state != "error"
and invoice.fatturapa_attachment_out_id
and not self.env.user.has_group(
"l10n_it_fatturapa_out.group_edit_invoice_sent_sdi"
)
):
raise UserError(
_(
Expand Down
12 changes: 12 additions & 0 deletions l10n_it_fatturapa_out/security/groups.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>

<record id="group_edit_invoice_sent_sdi" model="res.groups">
<field name="name">Edit Invoice Sent SDI</field>
<field
name="comment"
>Can reset to draft and then edit invoice sent to SDI</field>
<field name="category_id" ref="base.module_category_hidden" />
</record>

</odoo>
30 changes: 30 additions & 0 deletions l10n_it_fatturapa_out/tests/test_fatturapa_xml_validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -938,3 +938,33 @@ def test_validate_invoice(self):
invoice.action_post()

self.assertEqual(invoice.state, "posted")

def test_edit_invoice_sent_sdi(self):
"""
Check e-invoice tags after edit invoice.
"""
invoice = self._create_invoice()
invoice.action_post()
self.run_wizard(invoice.id)
self.assertEqual(invoice.state, "posted")
self.assertTrue(invoice.fatturapa_attachment_out_id.exists())

with self.assertRaises(UserError), self.cr.savepoint():
invoice.with_user(self.account_manager.id).button_draft()

self.account_manager.groups_id += self.env.ref(
"l10n_it_fatturapa_out.group_edit_invoice_sent_sdi"
)
invoice.with_user(self.account_manager.id).button_draft()
self.assertEqual(invoice.state, "draft")

with self.assertRaises(UserError), self.cr.savepoint():
move_form = Form(invoice)
with move_form.invoice_line_ids.edit(0) as line_form:
line_form.price_unit = 800
move_form.save()

move_form = Form(invoice)
move_form.invoice_payment_term_id = self.account_payment_term
move_form.save()
self.assertEqual(invoice.state, "posted")
6 changes: 5 additions & 1 deletion l10n_it_fatturapa_out/wizard/wizard_export_fatturapa.py
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,11 @@ def exportInvoiceXML(self, partner, invoice_ids, attach=False, context=None):

# generate attachments (PDF version of invoice)
for inv in invoice_ids:
if not attach and inv.fatturapa_attachment_out_id:
if (
not attach
and inv.fatturapa_attachment_out_id
and not context.get("skip_check_xml", False)
):
raise UserError(
_("E-invoice export file still present for invoice %s.")
% (inv.name or "")
Expand Down

0 comments on commit cdc58e3

Please sign in to comment.