diff --git a/l10n_it_edi_related_document/README.rst b/l10n_it_edi_related_document/README.rst new file mode 100644 index 000000000000..53a9641bf0e2 --- /dev/null +++ b/l10n_it_edi_related_document/README.rst @@ -0,0 +1,98 @@ +.. image:: https://odoo-community.org/readme-banner-image + :target: https://odoo-community.org/get-involved?utm_source=readme + :alt: Odoo Community Association + +========================= +Related Documents for EDI +========================= + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:9635cb722bff9cdf86aa4c791204157e4ab84e3440f753772ca8a8484b2f5ba8 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/license-AGPL--3-blue.png + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fl10n--italy-lightgray.png?logo=github + :target: https://github.com/OCA/l10n-italy/tree/19.0/l10n_it_edi_related_document + :alt: OCA/l10n-italy +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/l10n-italy-19-0/l10n-italy-19-0-l10n_it_edi_related_document + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png + :target: https://runboat.odoo-community.org/builds?repo=OCA/l10n-italy&target_branch=19.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +**English** + +Module for managing the types of documents linked to invoices. The data +related to the linked documents is then exported in the electronic +invoice XML or imported during the creation of an invoice from an XML +file. If a related document has 0 as the line reference, it means that +it refers to the entire document and not to a specific invoice line. + +**Italiano** + +Modulo per la gestione dei tipi di documenti collegati alle fatture. I +dati relativi ai documenti collegati vengono poi esportati nell'XML +della fattura elettronica oppure importati durante la creazione di una +fattura da XML. Nel caso in cui un documento collegato abbia 0 come +riferimento linea, significa che è riferito all’intero documento e non +ad una specifica linea della fattura. + +**Table of contents** + +.. contents:: + :local: + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +------- + +* Nextev Srl + +Contributors +------------ + +- Nextev Srl +- `Stesi Consulting srl `__: + + - Michele Di Croce + +Maintainers +----------- + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +This module is part of the `OCA/l10n-italy `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/l10n_it_edi_related_document/__init__.py b/l10n_it_edi_related_document/__init__.py new file mode 100644 index 000000000000..31660d6a9650 --- /dev/null +++ b/l10n_it_edi_related_document/__init__.py @@ -0,0 +1,3 @@ +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from . import models diff --git a/l10n_it_edi_related_document/__manifest__.py b/l10n_it_edi_related_document/__manifest__.py new file mode 100644 index 000000000000..7b5b244f9187 --- /dev/null +++ b/l10n_it_edi_related_document/__manifest__.py @@ -0,0 +1,20 @@ +# Copyright 2025 Nextev Srl +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +{ + "name": "Related Documents for EDI", + "version": "19.0.1.0.0", + "category": "Localization/Italy", + "author": "Nextev Srl, Odoo Community Association (OCA)", + "website": "https://github.com/OCA/l10n-italy", + "license": "AGPL-3", + "depends": ["l10n_it_edi"], + "data": [ + "views/related_document_views.xml", + "views/l10n_it_views.xml", + "views/account_move_related_documents.xml", + "data/invoice_it_template.xml", + "security/ir.model.access.csv", + ], + "installable": True, +} diff --git a/l10n_it_edi_related_document/data/invoice_it_template.xml b/l10n_it_edi_related_document/data/invoice_it_template.xml new file mode 100644 index 000000000000..f43a628b8e68 --- /dev/null +++ b/l10n_it_edi_related_document/data/invoice_it_template.xml @@ -0,0 +1,13 @@ + + + + diff --git a/l10n_it_edi_related_document/i18n/it.po b/l10n_it_edi_related_document/i18n/it.po new file mode 100644 index 000000000000..76a2e4f2776f --- /dev/null +++ b/l10n_it_edi_related_document/i18n/it.po @@ -0,0 +1,151 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * l10n_it_edi_related_document +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2026-01-11 17:43+0000\n" +"Last-Translator: mymage \n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 5.10.4\n" + +#. module: l10n_it_edi_related_document +#: model:ir.model.fields.selection,name:l10n_it_edi_related_document.selection__account_move_related_document__type__agreement +msgid "Agreement" +msgstr "Accordo" + +#. module: l10n_it_edi_related_document +#: model:ir.model.fields,field_description:l10n_it_edi_related_document.field_account_move_related_document__cig +msgid "CIG Code" +msgstr "Codice CIG" + +#. module: l10n_it_edi_related_document +#: model:ir.model.fields,field_description:l10n_it_edi_related_document.field_account_move_related_document__cup +msgid "CUP Code" +msgstr "Codice CUP" + +#. module: l10n_it_edi_related_document +#: model:ir.model.fields.selection,name:l10n_it_edi_related_document.selection__account_move_related_document__type__contract +msgid "Contract" +msgstr "Contratto" + +#. module: l10n_it_edi_related_document +#: model:ir.model.fields,field_description:l10n_it_edi_related_document.field_account_move_related_document__create_uid +msgid "Created by" +msgstr "Creato da" + +#. module: l10n_it_edi_related_document +#: model:ir.model.fields,field_description:l10n_it_edi_related_document.field_account_move_related_document__create_date +msgid "Created on" +msgstr "Creato il" + +#. module: l10n_it_edi_related_document +#: model:ir.model.fields,field_description:l10n_it_edi_related_document.field_account_move_related_document__date +msgid "Date" +msgstr "Data" + +#. module: l10n_it_edi_related_document +#: model:ir.model.fields,field_description:l10n_it_edi_related_document.field_account_move_related_document__display_name +msgid "Display Name" +msgstr "Nome visualizzato" + +#. module: l10n_it_edi_related_document +#: model:ir.model.fields,field_description:l10n_it_edi_related_document.field_account_move_related_document__type +msgid "Document" +msgstr "Documento" + +#. module: l10n_it_edi_related_document +#: model:ir.model.fields,field_description:l10n_it_edi_related_document.field_account_move_related_document__name +msgid "Document ID" +msgstr "ID documento" + +#. module: l10n_it_edi_related_document +#: model:ir.model,name:l10n_it_edi_related_document.model_account_move_related_document +msgid "E-invoice Related Documents" +msgstr "Documenti relativi alla fattura elettronica" + +#. module: l10n_it_edi_related_document +#: model:ir.model.fields,field_description:l10n_it_edi_related_document.field_account_move_related_document__id +msgid "ID" +msgstr "ID" + +#. module: l10n_it_edi_related_document +#: model:ir.model.fields,field_description:l10n_it_edi_related_document.field_account_move_related_document__numitem +msgid "Item Num." +msgstr "Num. elemento" + +#. module: l10n_it_edi_related_document +#: model:ir.model,name:l10n_it_edi_related_document.model_account_move +msgid "Journal Entry" +msgstr "Registrazione contabile" + +#. module: l10n_it_edi_related_document +#: model:ir.model,name:l10n_it_edi_related_document.model_account_move_line +msgid "Journal Item" +msgstr "Movimento contabile" + +#. module: l10n_it_edi_related_document +#: model:ir.model.fields,field_description:l10n_it_edi_related_document.field_account_move_related_document__write_uid +msgid "Last Updated by" +msgstr "Ultimo aggiornamento di" + +#. module: l10n_it_edi_related_document +#: model:ir.model.fields,field_description:l10n_it_edi_related_document.field_account_move_related_document__write_date +msgid "Last Updated on" +msgstr "Ultimo aggiornamento il" + +#. module: l10n_it_edi_related_document +#: model:ir.model.fields,field_description:l10n_it_edi_related_document.field_account_move_related_document__lineRef +msgid "Line Ref." +msgstr "Rif. riga" + +#. module: l10n_it_edi_related_document +#: model:ir.model.fields.selection,name:l10n_it_edi_related_document.selection__account_move_related_document__type__order +msgid "Order" +msgstr "Ordine" + +#. module: l10n_it_edi_related_document +#: model:ir.model.fields,field_description:l10n_it_edi_related_document.field_account_move_related_document__code +msgid "Order Agreement Code" +msgstr "Codice commessa convenzione" + +#. module: l10n_it_edi_related_document +#: model:ir.model.fields.selection,name:l10n_it_edi_related_document.selection__account_move_related_document__type__reception +msgid "Reception" +msgstr "Ricezione" + +#. module: l10n_it_edi_related_document +#: model:ir.model.fields,field_description:l10n_it_edi_related_document.field_account_bank_statement_line__related_document_ids +#: model:ir.model.fields,field_description:l10n_it_edi_related_document.field_account_move__related_document_ids +msgid "Related Document" +msgstr "Documento correlato" + +#. module: l10n_it_edi_related_document +#: model:ir.model.fields,field_description:l10n_it_edi_related_document.field_account_move_line__related_document_ids +#: model_terms:ir.ui.view,arch_db:l10n_it_edi_related_document.account_invoice_form_related_document +msgid "Related Documents" +msgstr "Documenti collegati" + +#. module: l10n_it_edi_related_document +#: model:ir.model.fields,field_description:l10n_it_edi_related_document.field_account_move_related_document__invoice_id +#: model:ir.model.fields.selection,name:l10n_it_edi_related_document.selection__account_move_related_document__type__invoice +msgid "Related Invoice" +msgstr "Fattura collegata" + +#. module: l10n_it_edi_related_document +#: model:ir.model.fields,field_description:l10n_it_edi_related_document.field_account_move_related_document__invoice_line_id +msgid "Related Invoice Line" +msgstr "Riga fattura collegata" + +#. module: l10n_it_edi_related_document +#: model:ir.actions.act_window,name:l10n_it_edi_related_document.account_move_related_document_action +#: model:ir.ui.menu,name:l10n_it_edi_related_document.account_move_related_document_menu +msgid "Related documents" +msgstr "Documenti collegati" diff --git a/l10n_it_edi_related_document/i18n/l10n_it_edi_related_document.pot b/l10n_it_edi_related_document/i18n/l10n_it_edi_related_document.pot new file mode 100644 index 000000000000..c3430cd3957a --- /dev/null +++ b/l10n_it_edi_related_document/i18n/l10n_it_edi_related_document.pot @@ -0,0 +1,148 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * l10n_it_edi_related_document +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: l10n_it_edi_related_document +#: model:ir.model.fields.selection,name:l10n_it_edi_related_document.selection__account_move_related_document__type__agreement +msgid "Agreement" +msgstr "" + +#. module: l10n_it_edi_related_document +#: model:ir.model.fields,field_description:l10n_it_edi_related_document.field_account_move_related_document__cig +msgid "CIG Code" +msgstr "" + +#. module: l10n_it_edi_related_document +#: model:ir.model.fields,field_description:l10n_it_edi_related_document.field_account_move_related_document__cup +msgid "CUP Code" +msgstr "" + +#. module: l10n_it_edi_related_document +#: model:ir.model.fields.selection,name:l10n_it_edi_related_document.selection__account_move_related_document__type__contract +msgid "Contract" +msgstr "" + +#. module: l10n_it_edi_related_document +#: model:ir.model.fields,field_description:l10n_it_edi_related_document.field_account_move_related_document__create_uid +msgid "Created by" +msgstr "" + +#. module: l10n_it_edi_related_document +#: model:ir.model.fields,field_description:l10n_it_edi_related_document.field_account_move_related_document__create_date +msgid "Created on" +msgstr "" + +#. module: l10n_it_edi_related_document +#: model:ir.model.fields,field_description:l10n_it_edi_related_document.field_account_move_related_document__date +msgid "Date" +msgstr "" + +#. module: l10n_it_edi_related_document +#: model:ir.model.fields,field_description:l10n_it_edi_related_document.field_account_move_related_document__display_name +msgid "Display Name" +msgstr "" + +#. module: l10n_it_edi_related_document +#: model:ir.model.fields,field_description:l10n_it_edi_related_document.field_account_move_related_document__type +msgid "Document" +msgstr "" + +#. module: l10n_it_edi_related_document +#: model:ir.model.fields,field_description:l10n_it_edi_related_document.field_account_move_related_document__name +msgid "Document ID" +msgstr "" + +#. module: l10n_it_edi_related_document +#: model:ir.model,name:l10n_it_edi_related_document.model_account_move_related_document +msgid "E-invoice Related Documents" +msgstr "" + +#. module: l10n_it_edi_related_document +#: model:ir.model.fields,field_description:l10n_it_edi_related_document.field_account_move_related_document__id +msgid "ID" +msgstr "" + +#. module: l10n_it_edi_related_document +#: model:ir.model.fields,field_description:l10n_it_edi_related_document.field_account_move_related_document__numitem +msgid "Item Num." +msgstr "" + +#. module: l10n_it_edi_related_document +#: model:ir.model,name:l10n_it_edi_related_document.model_account_move +msgid "Journal Entry" +msgstr "" + +#. module: l10n_it_edi_related_document +#: model:ir.model,name:l10n_it_edi_related_document.model_account_move_line +msgid "Journal Item" +msgstr "" + +#. module: l10n_it_edi_related_document +#: model:ir.model.fields,field_description:l10n_it_edi_related_document.field_account_move_related_document__write_uid +msgid "Last Updated by" +msgstr "" + +#. module: l10n_it_edi_related_document +#: model:ir.model.fields,field_description:l10n_it_edi_related_document.field_account_move_related_document__write_date +msgid "Last Updated on" +msgstr "" + +#. module: l10n_it_edi_related_document +#: model:ir.model.fields,field_description:l10n_it_edi_related_document.field_account_move_related_document__lineRef +msgid "Line Ref." +msgstr "" + +#. module: l10n_it_edi_related_document +#: model:ir.model.fields.selection,name:l10n_it_edi_related_document.selection__account_move_related_document__type__order +msgid "Order" +msgstr "" + +#. module: l10n_it_edi_related_document +#: model:ir.model.fields,field_description:l10n_it_edi_related_document.field_account_move_related_document__code +msgid "Order Agreement Code" +msgstr "" + +#. module: l10n_it_edi_related_document +#: model:ir.model.fields.selection,name:l10n_it_edi_related_document.selection__account_move_related_document__type__reception +msgid "Reception" +msgstr "" + +#. module: l10n_it_edi_related_document +#: model:ir.model.fields,field_description:l10n_it_edi_related_document.field_account_bank_statement_line__related_document_ids +#: model:ir.model.fields,field_description:l10n_it_edi_related_document.field_account_move__related_document_ids +msgid "Related Document" +msgstr "" + +#. module: l10n_it_edi_related_document +#: model:ir.model.fields,field_description:l10n_it_edi_related_document.field_account_move_line__related_document_ids +#: model_terms:ir.ui.view,arch_db:l10n_it_edi_related_document.account_invoice_form_related_document +msgid "Related Documents" +msgstr "" + +#. module: l10n_it_edi_related_document +#: model:ir.model.fields,field_description:l10n_it_edi_related_document.field_account_move_related_document__invoice_id +#: model:ir.model.fields.selection,name:l10n_it_edi_related_document.selection__account_move_related_document__type__invoice +msgid "Related Invoice" +msgstr "" + +#. module: l10n_it_edi_related_document +#: model:ir.model.fields,field_description:l10n_it_edi_related_document.field_account_move_related_document__invoice_line_id +msgid "Related Invoice Line" +msgstr "" + +#. module: l10n_it_edi_related_document +#: model:ir.actions.act_window,name:l10n_it_edi_related_document.account_move_related_document_action +#: model:ir.ui.menu,name:l10n_it_edi_related_document.account_move_related_document_menu +msgid "Related documents" +msgstr "" diff --git a/l10n_it_edi_related_document/models/__init__.py b/l10n_it_edi_related_document/models/__init__.py new file mode 100644 index 000000000000..824386cf8c37 --- /dev/null +++ b/l10n_it_edi_related_document/models/__init__.py @@ -0,0 +1,4 @@ +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from . import account_move +from . import account_move_line diff --git a/l10n_it_edi_related_document/models/account_move.py b/l10n_it_edi_related_document/models/account_move.py new file mode 100644 index 000000000000..be75e056f785 --- /dev/null +++ b/l10n_it_edi_related_document/models/account_move.py @@ -0,0 +1,258 @@ +from odoo import api, fields, models +from odoo.exceptions import UserError + +from odoo.addons.l10n_it_edi.models.account_move import get_text + + +class AccountMoveRelatedDocumentType(models.Model): + _name = "account.move.related_document" + _description = "E-invoice Related Documents" + + type = fields.Selection( + [ + ("order", "Order"), + ("contract", "Contract"), + ("agreement", "Agreement"), + ("reception", "Reception"), + ("invoice", "Related Invoice"), + ], + "Document", + required=True, + ) + name = fields.Char("Document ID", size=20, required=True) + lineRef = fields.Integer("Line Ref.") + invoice_id = fields.Many2one( + "account.move", + "Related Invoice", + ondelete="cascade", + index=True, + readonly=True, + ) + date = fields.Date() + numitem = fields.Char("Item Num.", size=20) + code = fields.Char("Order Agreement Code", size=100) + cig = fields.Char("CIG Code", size=15) + cup = fields.Char("CUP Code", size=15) + invoice_line_id = fields.Many2one( + "account.move.line", + "Related Invoice Line", + ondelete="cascade", + index=True, + readonly=True, + ) + + @api.model_create_multi + def create(self, vals_list): + line_obj = self.env["account.move.line"] + for vals in vals_list: + if ( + vals.get("lineRef") + and not vals.get("invoice_line_id") + and vals.get("invoice_id") + ): + line = line_obj.search( + [ + ("move_id", "=", vals["invoice_id"]), + ("sequence", "=", vals["lineRef"]), + ], + limit=1, + ) + if line: + vals["invoice_line_id"] = line.id + ret = super().create(vals_list) + # after creating documents, check if one should is eligible + # to become the standard_related_document_id + for record in ret.filtered( + lambda r: r.type == "order" + and r.invoice_id + and not r.invoice_id.standard_related_document_id + ): + invoice = record.invoice_id.with_context( + l10n_it_edi_related_loop_avoid=True + ) + invoice.standard_related_document_id = record + invoice.l10n_it_origin_document_type = "purchase_order" + invoice.l10n_it_origin_document_name = record.name + invoice.l10n_it_origin_document_date = record.date + invoice.l10n_it_cig = record.cig + record.invoice_id.l10n_it_cup = record.cup + + return ret + + def _l10n_it_sync_related_document(self): + for record in self: + if record == record.invoice_id.standard_related_document_id: + document_type = record.type + if document_type == "order": + document_type = "purchase_order" + elif document_type == "reception": + # unsupported type + record.invoice_id.standard_related_document_id = False + continue + elif document_type == "invoice": + # unsupported type + record.invoice_id.standard_related_document_id = False + continue + record.invoice_id.l10n_it_origin_document_type = document_type + record.invoice_id.l10n_it_origin_document_name = record.name + record.invoice_id.l10n_it_origin_document_date = record.date + record.invoice_id.l10n_it_cig = record.cig + record.invoice_id.l10n_it_cup = record.cup + + def write(self, vals): + ret = super().write(vals) + if self.env.context.get("l10n_it_edi_related_loop_avoid"): + return ret + if vals.keys() & {"type", "name", "date", "cig", "cup"}: + self.with_context( + l10n_it_edi_related_loop_avoid=True + )._l10n_it_sync_related_document() + return ret + + +class AccountMove(models.Model): + _inherit = "account.move" + + related_document_ids = fields.One2many( + "account.move.related_document", "invoice_id", copy=False + ) + + standard_related_document_id = fields.Many2one( + comodel_name="account.move.related_document", + string="Standard Related Document", + help="Technical field to store the document corresponding to standard fields", + ) + + # override + l10n_it_origin_document_type = fields.Selection( + inverse="_inverse_original_related_document_fields" + ) + l10n_it_origin_document_name = fields.Char( + inverse="_inverse_original_related_document_fields" + ) + l10n_it_origin_document_date = fields.Date( + inverse="_inverse_original_related_document_fields" + ) + l10n_it_cig = fields.Char(inverse="_inverse_original_related_document_fields") + l10n_it_cup = fields.Char(inverse="_inverse_original_related_document_fields") + + def _inverse_original_related_document_fields(self): + for record in self: + if record.env.context.get("l10n_it_edi_related_loop_avoid"): + continue + if ( + not record.l10n_it_origin_document_type + or not record.l10n_it_origin_document_name + ): + if record.standard_related_document_id: + # deleted reference + record.related_document_ids = [ + fields.Command.unlink(record.standard_related_document_id.id) + ] + record.standard_related_document_id.unlink() + record.standard_related_document_id = False + continue + # type map + # purchase_order -> order + # contract -> contract + # agreement -> agreement + # ? -> reception + # ? -> invoice + document_type = record.l10n_it_origin_document_type + if document_type == "purchase_order": + document_type = "order" + + if ( + document_type + not in dict( + self.env["account.move.related_document"]._fields["type"].selection + ).keys() + ): + raise UserError(self.env._("Unknown document type %s", document_type)) + + vals = { + "type": document_type, + "name": record.l10n_it_origin_document_name, + "date": record.l10n_it_origin_document_date, + "cig": record.l10n_it_cig, + "cup": record.l10n_it_cup, + } + if not record.standard_related_document_id: + record.standard_related_document_id = self.env[ + "account.move.related_document" + ].create(vals) + record.related_document_ids = [ + fields.Command.link(record.standard_related_document_id.id) + ] + else: + record.standard_related_document_id.with_context( + l10n_it_edi_related_loop_avoid=True + ).update(vals) + + def _l10n_it_edi_get_values(self, pdf_values=None): + res = super()._l10n_it_edi_get_values(pdf_values=pdf_values) + updated_values = self.remove_redundant_values(res) + return updated_values + + def remove_redundant_values(self, values): + redundant_list = [ + "cig", + "cup", + "origin_document_type", + "origin_document_name", + "origin_document_date", + ] + for key in redundant_list: + values.pop(key, None) + return values + + def _l10n_it_edi_import_invoice(self, invoice, data, is_new): + res = super()._l10n_it_edi_import_invoice(invoice, data, is_new) + tree = data["xml_tree"] + rel_docs_dict = { + "order": tree.xpath(".//DatiOrdineAcquisto"), + "contract": tree.xpath(".//DatiContratto"), + "agreement": tree.xpath(".//DatiConvenzione"), + "reception": tree.xpath(".//DatiRicezione"), + "invoice": tree.xpath(".//DatiFattureCollegate"), + } + self.create_related_document(invoice, rel_docs_dict) + return res + + def create_related_document(self, invoice, rel_docs_dict): + result = [] + invoice_line_model = self.env["account.move.line"] + for key, rel_doc in rel_docs_dict.items(): + for element in rel_doc: + invoice_lineid = False + lineRef = get_text(element, "./RiferimentoNumeroLinea") + if lineRef: + invoice_line = invoice_line_model.search( + [ + ("move_id", "=", invoice.id), + ("sequence", "=", int(lineRef)), + ], + limit=1, + ) + if invoice_line: + invoice_lineid = invoice_line.id + name = get_text(element, "./IdDocumento") + if not name: + continue + entry = { + "type": key, + "lineRef": lineRef, + "name": name, + "date": get_text(element, "./Data"), + "numitem": get_text(element, "./NumItem"), + "code": get_text(element, "./CodiceCommessaConvenzione"), + "cup": get_text(element, "./CodiceCUP"), + "cig": get_text(element, "./CodiceCIG"), + "invoice_id": invoice.id, + "invoice_line_id": invoice_lineid, + } + entry = {k: v for k, v in entry.items() if v} + result.append(entry) + model = self.env["account.move.related_document"] + model.create(result) + return result diff --git a/l10n_it_edi_related_document/models/account_move_line.py b/l10n_it_edi_related_document/models/account_move_line.py new file mode 100644 index 000000000000..68ce93e5ecee --- /dev/null +++ b/l10n_it_edi_related_document/models/account_move_line.py @@ -0,0 +1,12 @@ +from odoo import fields, models + + +class AccountMoveLine(models.Model): + _inherit = "account.move.line" + + related_document_ids = fields.One2many( + "account.move.related_document", + "invoice_line_id", + "Related Documents", + copy=False, + ) diff --git a/l10n_it_edi_related_document/pyproject.toml b/l10n_it_edi_related_document/pyproject.toml new file mode 100644 index 000000000000..4231d0cccb3d --- /dev/null +++ b/l10n_it_edi_related_document/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/l10n_it_edi_related_document/readme/CONTRIBUTORS.md b/l10n_it_edi_related_document/readme/CONTRIBUTORS.md new file mode 100644 index 000000000000..afbba9b30128 --- /dev/null +++ b/l10n_it_edi_related_document/readme/CONTRIBUTORS.md @@ -0,0 +1,3 @@ +- Nextev Srl \<\> +- [Stesi Consulting srl](https://www.stesi.consulting/): + - Michele Di Croce \<\> diff --git a/l10n_it_edi_related_document/readme/DESCRIPTION.md b/l10n_it_edi_related_document/readme/DESCRIPTION.md new file mode 100644 index 000000000000..4bc41c601aa1 --- /dev/null +++ b/l10n_it_edi_related_document/readme/DESCRIPTION.md @@ -0,0 +1,19 @@ +**English** + +Module for managing the types of documents linked to invoices. +The data related to the linked documents is then exported in +the electronic invoice XML or imported during the creation of +an invoice from an XML file. +If a related document has 0 as the line reference, it means that +it refers to the entire document and not to a specific +invoice line. + +**Italiano** + +Modulo per la gestione dei tipi di documenti collegati alle fatture. +I dati relativi ai documenti collegati vengono poi esportati nell'XML +della fattura elettronica oppure importati durante la creazione di una +fattura da XML. +Nel caso in cui un documento collegato abbia 0 come riferimento linea, +significa che è riferito all’intero documento e non ad una specifica +linea della fattura. \ No newline at end of file diff --git a/l10n_it_edi_related_document/security/ir.model.access.csv b/l10n_it_edi_related_document/security/ir.model.access.csv new file mode 100644 index 000000000000..bbea922915c2 --- /dev/null +++ b/l10n_it_edi_related_document/security/ir.model.access.csv @@ -0,0 +1,2 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +l10n_it_edi_related_document.access_account_move_related_document,access_account_move_related_document,l10n_it_edi_related_document.model_account_move_related_document,account.group_account_invoice,1,1,1,1 diff --git a/l10n_it_edi_related_document/static/description/icon.png b/l10n_it_edi_related_document/static/description/icon.png new file mode 100644 index 000000000000..1dcc49c24f36 Binary files /dev/null and b/l10n_it_edi_related_document/static/description/icon.png differ diff --git a/l10n_it_edi_related_document/static/description/index.html b/l10n_it_edi_related_document/static/description/index.html new file mode 100644 index 000000000000..794389bd2662 --- /dev/null +++ b/l10n_it_edi_related_document/static/description/index.html @@ -0,0 +1,445 @@ + + + + + +README.rst + + + +
+ + + +Odoo Community Association + + +
+ + diff --git a/l10n_it_edi_related_document/tests/__init__.py b/l10n_it_edi_related_document/tests/__init__.py new file mode 100644 index 000000000000..f4dec3b04bcc --- /dev/null +++ b/l10n_it_edi_related_document/tests/__init__.py @@ -0,0 +1 @@ +from . import test_import_xml diff --git a/l10n_it_edi_related_document/tests/import_xmls/IT01234567888_FPR01_02.xml b/l10n_it_edi_related_document/tests/import_xmls/IT01234567888_FPR01_02.xml new file mode 100644 index 000000000000..c02999208755 --- /dev/null +++ b/l10n_it_edi_related_document/tests/import_xmls/IT01234567888_FPR01_02.xml @@ -0,0 +1,143 @@ + + + + + IT + 01234560157 + + 00001 + FPR12 + ABC1234 + + + + + + IT + 00313371213 + + 93026890017 + + SOCIETA' ALPHA SRL + + RF19 + + + VIALE ROMA 543 + 07100 + SASSARI + SS + IT + + + + + 01234560157 + + DITTA BETA + + + + VIA TORINO 38-B + 00145 + ROMA + RM + IT + + + + + + + TD01 + EUR + 2014-12-18 + 01234567888 + LA FATTURA FA RIFERIMENTO AD UNA OPERAZIONE AAAA BBBBBBBBBBBBBBBBBB CCC DDDDDDDDDDDDDDD E + FFFFFFFFFFFFFFFFFFFF GGGGGGGGGG HHHHHHH II LLLLLLLLLLLLLLLLL MMM NNNNN OO PPPPPPPPPPP QQQQ RRRR + SSSSSSSSSSSSSS + + SEGUE DESCRIZIONE CAUSALE NEL CASO IN CUI NON SIANO STATI SUFFICIENTI 200 CARATTERI AAAAAAAAAAA + BBBBBBBBBBBBBBBBB + + + + 16 + 1 + 2025-05-22 + 3 + 5 + 665544 + 5554466 + + + 2 + 15 + 2025-05-21 + 4 + 4 + 5678 + 1234 + + + + + IT + 24681012141 + + + Trasporto spa + + + 2012-10-22T16:46:12.000+02:00 + + + + + 1 + Cool stuff + 5.00 + 1.00 + 5.00 + 22.00 + + + 2 + OtherAccount + 3.00 + 8.00 + 24.00 + 22.00 + + + 3 + GuessTaxes + 1.00 + 10.00 + 10.00 + + + 22.00 + 29.00 + 6.38 + I + + + + TP01 + + MP01 + 2015-01-30 + 36.48 + + + + diff --git a/l10n_it_edi_related_document/tests/test_import_xml.py b/l10n_it_edi_related_document/tests/test_import_xml.py new file mode 100644 index 000000000000..d8a59708e140 --- /dev/null +++ b/l10n_it_edi_related_document/tests/test_import_xml.py @@ -0,0 +1,94 @@ +from odoo import fields + +from odoo.addons.l10n_it_edi.tests.common import TestItEdi + + +class TestItEdiImport(TestItEdi): + """Main test class for the l10n_it_edi vendor bills XML import""" + + def test_receive_vendor_bill(self): + """Test a sample e-invoice file with multiple related documents""" + self.module = "l10n_it_edi_related_document" + invoice = self._assert_import_invoice( + "IT01234567888_FPR01_02.xml", + [ + { + "move_type": "in_invoice", + "invoice_date": fields.Date.from_string("2014-12-18"), + "amount_untaxed": 39.0, + "amount_tax": 6.38, + } + ], + ) + related_document = invoice.related_document_ids + self.assertEqual(len(related_document), 2) + invoice_doc_type = related_document.filtered(lambda x: x.type == "invoice")[0] + rcp_doc_type = related_document.filtered(lambda x: x.type == "reception")[0] + self.assertTrue(invoice_doc_type) + self.assertTrue(rcp_doc_type) + self.assertEqual(invoice_doc_type.cig, "5554466") + self.assertEqual(rcp_doc_type.cup, "5678") + self.assertTrue( + invoice.line_ids.filtered(lambda x: rcp_doc_type in x.related_document_ids) + ) + + def test_standard_fields(self): + euro = self.setup_other_currency("EUR") + invoice = self.env["account.move"].create( + { + "move_type": "out_invoice", + "partner_id": self.partner_a.id, + "invoice_date": fields.Date.from_string("2016-01-01"), + "currency_id": euro.id, + "invoice_line_ids": [ + ( + 0, + None, + { + "product_id": self.product_a.id, + "quantity": 3, + "price_unit": 750, + }, + ), + ], + } + ) + + # add a document, via standard fields + # note: this must be an atomic write(), as both name and type are required + # fields and can't be assigned one a time + invoice.write( + { + "l10n_it_origin_document_name": "S00001", + "l10n_it_origin_document_type": "purchase_order", + "l10n_it_origin_document_date": invoice.invoice_date, + "l10n_it_cig": "CIG", + "l10n_it_cup": "CUP", + } + ) + self.assertEqual( + invoice.standard_related_document_id, invoice.related_document_ids[0] + ) + self.assertEqual(invoice.standard_related_document_id.type, "order") + self.assertEqual(invoice.standard_related_document_id.name, "S00001") + self.assertEqual( + invoice.standard_related_document_id.date, invoice.invoice_date + ) + self.assertEqual(invoice.standard_related_document_id.cig, "CIG") + self.assertEqual(invoice.standard_related_document_id.cup, "CUP") + + # alter the document + invoice.standard_related_document_id.name = "S00002" + invoice.standard_related_document_id.date = fields.Date.from_string( + "2016-01-02" + ) + invoice.standard_related_document_id.cig = "CIG2" + invoice.standard_related_document_id.cup = "CUP2" + + # check if standard fields changed accordingly + self.assertEqual(invoice.l10n_it_origin_document_name, "S00002") + self.assertEqual( + invoice.l10n_it_origin_document_date, fields.Date.from_string("2016-01-02") + ) + self.assertEqual(invoice.l10n_it_cig, "CIG2") + self.assertEqual(invoice.l10n_it_cup, "CUP2") diff --git a/l10n_it_edi_related_document/views/account_move_related_documents.xml b/l10n_it_edi_related_document/views/account_move_related_documents.xml new file mode 100644 index 000000000000..a9521db03973 --- /dev/null +++ b/l10n_it_edi_related_document/views/account_move_related_documents.xml @@ -0,0 +1,64 @@ + + + + + + diff --git a/l10n_it_edi_related_document/views/l10n_it_views.xml b/l10n_it_edi_related_document/views/l10n_it_views.xml new file mode 100644 index 000000000000..dfd45e6bfc1f --- /dev/null +++ b/l10n_it_edi_related_document/views/l10n_it_views.xml @@ -0,0 +1,37 @@ + + + + account.move.form.related.document + account.move + 20 + + + + 1 + + + + + + + + + + + + + + + + + + + + diff --git a/l10n_it_edi_related_document/views/related_document_views.xml b/l10n_it_edi_related_document/views/related_document_views.xml new file mode 100644 index 000000000000..cd68004b1010 --- /dev/null +++ b/l10n_it_edi_related_document/views/related_document_views.xml @@ -0,0 +1,61 @@ + + + + Tree view for related_document + account.move.related_document + + + + + + + + + + + + + + + + Form view for related_document + account.move.related_document + +
+ + + + + + + + + + + + + + + + + + +
+
+
+ + + Related documents + related-documents + account.move.related_document + form,list + + {'create': False, 'edit': False, 'delete': False} + + + +