From 05fe902c77ddc4bcfb98ecb18272e5cdcd18e81a Mon Sep 17 00:00:00 2001 From: Borruso Date: Mon, 3 Oct 2022 18:03:46 +0200 Subject: [PATCH] [ADD] l10n_it_fatturapa_out: edit invoice sent SDI --- l10n_it_fatturapa_out/__manifest__.py | 1 + l10n_it_fatturapa_out/models/account.py | 164 ++++++++++++++++++ l10n_it_fatturapa_out/security/groups.xml | 12 ++ .../wizard/wizard_export_fatturapa.py | 6 +- 4 files changed, 182 insertions(+), 1 deletion(-) create mode 100644 l10n_it_fatturapa_out/security/groups.xml diff --git a/l10n_it_fatturapa_out/__manifest__.py b/l10n_it_fatturapa_out/__manifest__.py index d61a9fa28fd0..c348d8fd4c33 100644 --- a/l10n_it_fatturapa_out/__manifest__.py +++ b/l10n_it_fatturapa_out/__manifest__.py @@ -20,6 +20,7 @@ "l10n_it_fiscal_document_type", ], "data": [ + "security/groups.xml", "data/invoice_it_template.xml", "wizard/wizard_export_fatturapa_view.xml", "wizard/wizard_export_fatturapa_view_regenerate.xml", diff --git a/l10n_it_fatturapa_out/models/account.py b/l10n_it_fatturapa_out/models/account.py index e036a368a496..66d7a27febbb 100644 --- a/l10n_it_fatturapa_out/models/account.py +++ b/l10n_it_fatturapa_out/models/account.py @@ -1,6 +1,10 @@ # 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.tools.translate import _ @@ -95,11 +99,171 @@ def preventive_checks(self): ) return + def check_tag(self, new_xml, original_xml, list_tags): + for tag in list_tags: + if ( + (new_xml.find(tag) is not None and new_xml.find(tag).text) or "" + ).strip() != ( + (original_xml.find(tag) is not None and original_xml.find(tag).text) + or "" + ).strip(): + raise UserError( + _( + "{} isn't equal to tag in file e-invoice already created!".format( + 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): + list_tag = [ + ".//DatiGeneraliDocumento/Data", + ".//DatiGeneraliDocumento/ImportoTotaleDocumento", + ".//DatiGeneraliDocumento/TipoDocumento", + ".//DatiGeneraliDocumento/Divisa", + ".//DatiGeneraliDocumento/Numero", + ] + self.check_tag(new_xml, original_xml, list_tag) + + if len(new_xml.findall(".//DatiGeneraliDocumento/DatiRitenuta")) != len( + original_xml.findall(".//DatiGeneraliDocumento/DatiRitenuta") + ): + raise UserError( + _( + "{} isn't equal to tag in file e-invoice already created!".format( + "DatiGeneraliDocumento/DatiRitenuta" + ) + ) + ) + lr = 0 + for new_line_ritenuta in new_xml.findall( + ".//DatiGeneraliDocumento/DatiRitenuta" + ): + original_line_ritenuta = original_xml.findall( + ".//DatiGeneraliDocumento/DatiRitenuta" + )[lr] + list_tag_DatiRitenuta = [ + ".//TipoRitenuta", + ".//ImportoRitenuta", + ".//AliquotaRitenuta", + ".//CausalePagamento", + ] + self.check_tag( + new_line_ritenuta, original_line_ritenuta, list_tag_DatiRitenuta + ) + lr += 1 + + def check_DatiBeniServizi(self, new_xml, original_xml): + if len(new_xml.findall(".//DatiBeniServizi/DettaglioLinee")) != len( + original_xml.findall(".//DatiBeniServizi/DettaglioLinee") + ): + raise UserError( + _( + "{} isn't equal to tag in file e-invoice already created!".format( + "DatiBeniServizi/DettaglioLinee" + ) + ) + ) + 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", + ".//Quantita", + ".//PrezzoUnitario", + ".//AliquotaIVA", + ".//Natura", + ".//PrezzoTotale", + ".//Ritenuta", + ] + self.check_tag( + new_line_details, original_line_details, list_tag_DettaglioLinee + ) + ld += 1 + + if len(new_xml.findall(".//DatiBeniServizi/DatiRiepilogo")) != len( + original_xml.findall(".//DatiBeniServizi/DatiRiepilogo") + ): + raise UserError( + _( + "{} isn't equal to tag in file e-invoice already created!".format( + "DatiBeniServizi/DatiRiepilogo" + ) + ) + ) + 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, + ) + 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) + ): + 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( _( diff --git a/l10n_it_fatturapa_out/security/groups.xml b/l10n_it_fatturapa_out/security/groups.xml new file mode 100644 index 000000000000..5be0d6ffba60 --- /dev/null +++ b/l10n_it_fatturapa_out/security/groups.xml @@ -0,0 +1,12 @@ + + + + + Edit Invoice Sent SDI + Can reset to draft and then edit invoice sent to SDI + + + + diff --git a/l10n_it_fatturapa_out/wizard/wizard_export_fatturapa.py b/l10n_it_fatturapa_out/wizard/wizard_export_fatturapa.py index a279961ceddd..c71eb5ab2e38 100644 --- a/l10n_it_fatturapa_out/wizard/wizard_export_fatturapa.py +++ b/l10n_it_fatturapa_out/wizard/wizard_export_fatturapa.py @@ -238,7 +238,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 "")