diff --git a/report_pdf_form/README.rst b/report_pdf_form/README.rst new file mode 100644 index 0000000000..764fe5a8a1 --- /dev/null +++ b/report_pdf_form/README.rst @@ -0,0 +1,115 @@ +.. image:: https://odoo-community.org/readme-banner-image + :target: https://odoo-community.org/get-involved?utm_source=readme + :alt: Odoo Community Association + +=============== +Report PDF Form +=============== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:50d8a5bc56259a22c4c2ac64ba9b38c9d5755859dee53f93a0dbd06b84b7a15a + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Alpha-red.png + :target: https://odoo-community.org/page/development-status + :alt: Alpha +.. |badge2| image:: https://img.shields.io/badge/license-LGPL--3-blue.png + :target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html + :alt: License: LGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Freporting--engine-lightgray.png?logo=github + :target: https://github.com/OCA/reporting-engine/tree/19.0/report_pdf_form + :alt: OCA/reporting-engine +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/reporting-engine-19-0/reporting-engine-19-0-report_pdf_form + :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/reporting-engine&target_branch=19.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module allows to use PDF files having form fields as Odoo reports +to be printed with values being filled from Odoo records. + +This module mostly reuses features that were implemented by Odoo in the +sale_pdf_quotation_builder module. + +Creating PDF Form Fields +------------------------ + +To create PDFs with form fields for use with this module, you can use +various tools: + +- **docfly.com**: An online tool for adding form fields to PDFs +- **LibreOffice Draw**: Part of the LibreOffice suite, can add form + fields to PDFs +- **Scribus**: A desktop publishing application that can create PDFs + with form fields + +.. IMPORTANT:: + This is an alpha version, the data model and design can change at any time without warning. + Only for development or testing purpose, do not use in production. + `More details on development status `_ + +**Table of contents** + +.. contents:: + :local: + +Known issues / Roadmap +====================== + +Add a dedicated report type to avoid having to define a qweb template +and have everything on ir.actions.report. + +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 +------- + +* Camptocamp + +Contributors +------------ + +- Akim Juillerat akim.juillerat@camptocamp.com + +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. + +.. |maintainer-grindtildeath| image:: https://github.com/grindtildeath.png?size=40px + :target: https://github.com/grindtildeath + :alt: grindtildeath + +Current `maintainer `__: + +|maintainer-grindtildeath| + +This module is part of the `OCA/reporting-engine `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/report_pdf_form/__init__.py b/report_pdf_form/__init__.py new file mode 100644 index 0000000000..0650744f6b --- /dev/null +++ b/report_pdf_form/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/report_pdf_form/__manifest__.py b/report_pdf_form/__manifest__.py new file mode 100644 index 0000000000..3473c4c10f --- /dev/null +++ b/report_pdf_form/__manifest__.py @@ -0,0 +1,26 @@ +# Copyright 2025 Camptocamp SA +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl) +{ + "name": "Report PDF Form", + "summary": "Fill custom PDF form reports ", + "version": "19.0.1.0.0", + "development_status": "Alpha", + "category": "Reporting", + "website": "https://github.com/OCA/reporting-engine", + "author": "Camptocamp, Odoo Community Association (OCA)", + "maintainers": ["grindtildeath"], + "license": "LGPL-3", + "application": False, + "installable": True, + "preloadable": True, + "depends": [ + "web", + ], + "data": [ + "security/ir.model.access.csv", + "views/report_pdf_form.xml", + ], + "demo": [ + "demo/report_pdf_form_demo.xml", + ], +} diff --git a/report_pdf_form/demo/form_example.pdf b/report_pdf_form/demo/form_example.pdf new file mode 100644 index 0000000000..d612536c31 Binary files /dev/null and b/report_pdf_form/demo/form_example.pdf differ diff --git a/report_pdf_form/demo/report_pdf_form_demo.xml b/report_pdf_form/demo/report_pdf_form_demo.xml new file mode 100644 index 0000000000..bf2e099643 --- /dev/null +++ b/report_pdf_form/demo/report_pdf_form_demo.xml @@ -0,0 +1,84 @@ + + + + + demo_form.pdf + binary + + application/pdf + + + + + Demo Partner Report + res.partner + demo_partner_report + qweb-pdf + object.name + + + + + Demo PDF Form + + + + + report + + + + + + partner_name + dotted_path + name + + + + + partner_email + dotted_path + email + + + + + partner_phone + dotted_path + phone + + + + + + company_name + dotted_path + company_id.name + + + + + user_login + dotted_path + user_id.login + + + + + country_name + dotted_path + country_id.name + + + + + + current_date + datetime.datetime.now().strftime('%Y-%m-%d') + + diff --git a/report_pdf_form/i18n/it.po b/report_pdf_form/i18n/it.po new file mode 100644 index 0000000000..393b68368e --- /dev/null +++ b/report_pdf_form/i18n/it.po @@ -0,0 +1,493 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * report_pdf_form +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2025-12-17 10:42+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: report_pdf_form +#: model_terms:ir.ui.view,arch_db:report_pdf_form.report_pdf_form_form +msgid "" +"env: environment from the record on which the report is printed" +msgstr "" +"env: ambiente del record su cui viene stampato il resoconto" + +#. module: report_pdf_form +#: model_terms:ir.ui.view,arch_db:report_pdf_form.report_pdf_form_form +msgid "" +"float_compare(): utility function to compare floats based on a " +"specific precision" +msgstr "" +"float_compare(): funzione di utilità per confrontare i numeri " +"digitali in base a una precisione specifica" + +#. module: report_pdf_form +#: model_terms:ir.ui.view,arch_db:report_pdf_form.report_pdf_form_form +msgid "record: record on which the report is printed" +msgstr "record: record su cui viene stampato il resoconto" + +#. module: report_pdf_form +#: model_terms:ir.ui.view,arch_db:report_pdf_form.report_pdf_form_form +msgid "" +"time, datetime, dateutil, " +"timezone: useful Python libraries" +msgstr "" +"time, datetime, dateutil, " +"timezone: librerie Python utili" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__help +msgid "Action Description" +msgstr "Descrizione azione" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__name +msgid "Action Name" +msgstr "Nome azione" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__type +msgid "Action Type" +msgstr "Tipo azione" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__binding_model_id +msgid "Binding Model" +msgstr "Modello collegamento" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__binding_type +msgid "Binding Type" +msgstr "Tipo collegamento" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__binding_view_types +msgid "Binding View Types" +msgstr "Tipi vista collegamento" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form_variable__code +msgid "Code" +msgstr "Codice" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__context +msgid "Context Value" +msgstr "Valore context" + +#. module: report_pdf_form +#: model:ir.model.fields,help:report_pdf_form.field_report_pdf_form__context +msgid "" +"Context dictionary as Python expression, empty by default (Default: {})" +msgstr "" +"Dizionario context come espressione Python, predefinito come vuoto (Default: " +"{})" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__create_uid +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form_field__create_uid +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form_variable__create_uid +msgid "Created by" +msgstr "Creato da" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__create_date +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form_field__create_date +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form_variable__create_date +msgid "Created on" +msgstr "Creato il" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__display_name +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form_field__display_name +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form_variable__display_name +msgid "Display Name" +msgstr "Nome visualizzato" + +#. module: report_pdf_form +#: model:ir.model.fields,help:report_pdf_form.field_report_pdf_form_field__odoo_field_value +msgid "" +"Dot-separated path to field from the record, e.g. partner_id.name, or python" +" code" +msgstr "" +"Percorso separato da punti al campo dal record, ad esempio partner_id.name o " +"codice Python" + +#. module: report_pdf_form +#: model:ir.model.fields.selection,name:report_pdf_form.selection__report_pdf_form_field__odoo_field_evaluation__dotted_path +msgid "Dotted field path" +msgstr "Percorso di campo punteggiato" + +#. module: report_pdf_form +#: model_terms:ir.ui.view,arch_db:report_pdf_form.report_pdf_form_form +msgid "" +"Dotted field path: Can be used to access atomic fields and go through " +"Many2one relations with automatic formatting." +msgstr "" +"Percorso del campo punteggiato: può essere utilizzato per accedere ai campi " +"atomici e scorrere le relazioni Many2one con formattazione automatica." + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__encode_error_handling +msgid "Encode Error Handling" +msgstr "Gestione errore codifica" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__encoding +msgid "Encoding" +msgstr "Codifica" + +#. module: report_pdf_form +#: model:ir.model.fields,help:report_pdf_form.field_report_pdf_form__encoding +msgid "Encoding to be applied to the generated CSV file. e.g. cp932" +msgstr "Codifica da applicare al file CSV generato. Es. cp932" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__xml_id +msgid "External ID" +msgstr "ID esterno" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__footer_html +msgid "Extra Footer" +msgstr "Extra piè di pagina" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__field_mapping_ids +msgid "Field Mapping" +msgstr "Mappatura campo" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__field_variable_ids +msgid "Field Variable" +msgstr "Variabile campo" + +#. module: report_pdf_form +#: model_terms:ir.ui.view,arch_db:report_pdf_form.report_pdf_form_form +msgid "Field mapping" +msgstr "Mappatura campo" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__domain +msgid "Filter domain" +msgstr "Filtra dominio" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__groups_id +msgid "Groups" +msgstr "Gruppi" + +#. module: report_pdf_form +#: model_terms:ir.ui.view,arch_db:report_pdf_form.report_pdf_form_form +msgid "Help" +msgstr "Aiuto" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__id +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form_field__id +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form_variable__id +msgid "ID" +msgstr "ID" + +#. module: report_pdf_form +#: model:ir.model.fields,help:report_pdf_form.field_report_pdf_form__attachment_use +msgid "" +"If enabled, then the second time the user prints with same attachment name, " +"it returns the previous report." +msgstr "" +"Se abilitato, la seconda volta che l'utente stampa con lo stesso nome di " +"allegato, viene restituito il resoconto precedente." + +#. module: report_pdf_form +#: model:ir.model.fields,help:report_pdf_form.field_report_pdf_form__encode_error_handling +msgid "" +"If nothing is selected, CSV export will fail with an error message when " +"there is a character that fail to be encoded." +msgstr "" +"Se non è selezionato nulla, l'esportazione del CSV fallirà con un messaggio " +"di errore qando c'è un carattere che non può essere codificato." + +#. module: report_pdf_form +#: model:ir.model.fields,help:report_pdf_form.field_report_pdf_form__multi +msgid "" +"If set to true, the action will not be displayed on the right toolbar of a " +"form view." +msgstr "" +"Se impostato su true, l'azione non verrà visualizzata sulla barra degli " +"strumenti destra di una visualizzazione modulo." + +#. module: report_pdf_form +#: model:ir.model.fields,help:report_pdf_form.field_report_pdf_form__domain +msgid "" +"If set, the action will only appear on records that matches the domain." +msgstr "" +"Se impostata, l'azione apparirà solo sui record che corrispondono al dominio." + +#. module: report_pdf_form +#. odoo-python +#: code:addons/report_pdf_form/models/ir_actions_report.py:0 +msgid "Invalid evaluation for Odoo field" +msgstr "Valutazione errata per il campo Odoo" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__write_uid +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form_field__write_uid +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form_variable__write_uid +msgid "Last Updated by" +msgstr "Ultimo aggiornamento di" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__write_date +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form_field__write_date +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form_variable__write_date +msgid "Last Updated on" +msgstr "Ultimo aggiornamento il" + +#. module: report_pdf_form +#: model:ir.model,name:report_pdf_form.model_report_pdf_form_field +msgid "Mapping of Odoo field to PDF form field" +msgstr "Mappatura del campo Odoo nel campo del modulo PDF" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__model_id +msgid "Model" +msgstr "Modello" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__model +msgid "Model Name" +msgstr "Nome modello" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form_variable__name +msgid "Name" +msgstr "Nome" + +#. module: report_pdf_form +#. odoo-python +#: code:addons/report_pdf_form/models/ir_actions_report.py:0 +msgid "No" +msgstr "No" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form_field__odoo_field_evaluation +msgid "Odoo Field Evaluation" +msgstr "Valutazione campo Odoo" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form_field__odoo_field_value +msgid "Odoo Field Value" +msgstr "Valore campo Odoo" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__multi +msgid "On Multiple Doc." +msgstr "Su documenti multipli" + +#. module: report_pdf_form +#: model:ir.model.fields,help:report_pdf_form.field_report_pdf_form__help +msgid "" +"Optional help text for the users with a description of the target view, such" +" as its usage and purpose." +msgstr "" +"Testo di aiuto opzionale per l'utente con una descrizione della vista " +"obiettivo, come il suo utilizzo e obiettivo." + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form_field__pdf_field_name +msgid "PDF Form Field Name" +msgstr "Nome file modulo PDF" + +#. module: report_pdf_form +#: model:ir.model,name:report_pdf_form.model_report_pdf_form +msgid "PDF Form Report Template" +msgstr "Modello resoconto modulo PDF" + +#. module: report_pdf_form +#: model:ir.actions.act_window,name:report_pdf_form.report_pdf_form_action +#: model:ir.ui.menu,name:report_pdf_form.report_pdf_form_menu +msgid "PDF Form Reports" +msgstr "Resoconti modulo PDF" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__paperformat_id +msgid "Paper Format" +msgstr "Formato carta" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__path +msgid "Path to show in the URL" +msgstr "Percorso per visualizzarlo nell'URL" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__print_report_name +msgid "Printed Report Name" +msgstr "Nome del resoconto stampato" + +#. module: report_pdf_form +#: model:ir.model.fields.selection,name:report_pdf_form.selection__report_pdf_form_field__odoo_field_evaluation__code +msgid "Python code" +msgstr "Codice Python" + +#. module: report_pdf_form +#: model_terms:ir.ui.view,arch_db:report_pdf_form.report_pdf_form_form +msgid "" +"Python code: Can be used to acces what you cannot using the Dotted field " +"path. Following variables can be used:" +msgstr "" +"Codice Python: può essere utilizzato per accedere a ciò che non è possibile " +"tramite il percorso del campo puntato. È possibile utilizzare le seguenti " +"variabili:" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__pdf_attachment_id +msgid "Related attachment" +msgstr "Allegato relativo" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__attachment_use +msgid "Reload from Attachment" +msgstr "Ricarica dall'allegato" + +#. module: report_pdf_form +#: model:ir.model.fields.selection,name:report_pdf_form.selection__report_pdf_form_field__odoo_field_evaluation__repeat_field +msgid "Repeat field" +msgstr "Ripeti campo" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__report_id +msgid "Report" +msgstr "Resoconto" + +#. module: report_pdf_form +#: model:ir.model,name:report_pdf_form.model_ir_actions_report +msgid "Report Action" +msgstr "Azione resoconto" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__report_file +msgid "Report File" +msgstr "File resoconto" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form_field__report_form_id +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form_variable__report_form_id +msgid "Report Form" +msgstr "Modulo resoconto" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__report_type +msgid "Report Type" +msgstr "Tipo resoconto" + +#. module: report_pdf_form +#: model:ir.model,name:report_pdf_form.model_report_pdf_form_variable +msgid "Reusable variable to be evaluated in form fields code" +msgstr "Variabile riutilizzabile da valutare nel codice dei campi del modulo" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__attachment +msgid "Save as Attachment Prefix" +msgstr "Salva come prefisso allegato" + +#. module: report_pdf_form +#: model:ir.model.fields,help:report_pdf_form.field_report_pdf_form__binding_model_id +msgid "" +"Setting a value makes this action available in the sidebar for the given " +"model." +msgstr "" +"Impostare un valore rende questa azione disponibile nella barra laterale per " +"il dato modello." + +#. module: report_pdf_form +#: model:ir.model.fields.selection,name:report_pdf_form.selection__report_pdf_form_field__odoo_field_evaluation__text +msgid "Static text" +msgstr "Testo statico" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__report_name +msgid "Template Name" +msgstr "Nome modello" + +#. module: report_pdf_form +#: model:ir.model.fields,help:report_pdf_form.field_report_pdf_form__report_file +msgid "" +"The path to the main report file (depending on Report Type) or empty if the " +"content is in another field" +msgstr "" +"Il percorso al file del resoconto principale (a seconda del tipo di " +"resoconto) o vuoto se il contenuto è in un altro campo" + +#. module: report_pdf_form +#: model:ir.model.fields,help:report_pdf_form.field_report_pdf_form__report_type +msgid "" +"The type of the report that will be rendered, each one having its own " +"rendering method. HTML means the report will be opened directly in your " +"browser PDF means the report will be rendered using Wkhtmltopdf and " +"downloaded by the user." +msgstr "" +"Il tipo di resoconto che verrà generato, ognuno avente il suo metodo di " +"generazione. HTML vuol dire che il resoconto sarà aperto direttamente nel " +"tuo browser mentre PDF vuol dire che il resoconto sarà generato usando " +"Wkhtmltopdf e scaricato dall'utente." + +#. module: report_pdf_form +#: model_terms:ir.ui.view,arch_db:report_pdf_form.report_pdf_form_form +msgid "There are two ways to fetch value from the object:" +msgstr "Esistono due modi per recuperare il valore dall'oggetto:" + +#. module: report_pdf_form +#: model:ir.model.fields,help:report_pdf_form.field_report_pdf_form__footer_html +msgid "" +"This HTML will be displayed in the footer of this report.\n" +"It's recommended to change Paper Format to a new one that fits correctly to this report by adjusting 'Bottom Margin (mm)' accordingly." +msgstr "" +"Questo codice HTML verrà visualizzato nel piè di pagina di questo resoconto." +"\n" +"Si consiglia di modificare il formato cartaceo in modo che si adatti " +"correttamente a questo resoconto, modificando di conseguenza il " +"\"Margine inferiore (mm)\"." + +#. module: report_pdf_form +#: model:ir.model.fields,help:report_pdf_form.field_report_pdf_form__attachment +msgid "" +"This is the filename of the attachment used to store the printing result. " +"Keep empty to not save the printed reports. You can use a python expression " +"with the object and time variables." +msgstr "" +"Questo è il nome file dell'allegato utilizzato per memorizzare il risultato " +"della stampa. Lasciare vuoto per non salvare il resoconti stampati. È " +"possibile utilizzare un'espressione Python con le variabili oggetto e tempo." + +#. module: report_pdf_form +#: model:ir.model.fields,help:report_pdf_form.field_report_pdf_form__print_report_name +msgid "" +"This is the filename of the report going to download. Keep empty to not " +"change the report filename. You can use a python expression with the " +"'object' and 'time' variables." +msgstr "" +"Questo è il nome del file del resoconto che verrà scaricato. Lasciare vuoto " +"per non modificare il nome del file del resoconto. È possibile utilizzare " +"un'espressione Python con le variabili \"object\" e \"time\"." + +#. module: report_pdf_form +#: model_terms:ir.ui.view,arch_db:report_pdf_form.report_pdf_form_form +msgid "Variables" +msgstr "Variabili" + +#. module: report_pdf_form +#. odoo-python +#: code:addons/report_pdf_form/models/ir_actions_report.py:0 +msgid "Yes" +msgstr "Sì" diff --git a/report_pdf_form/i18n/nl.po b/report_pdf_form/i18n/nl.po new file mode 100644 index 0000000000..b6ad41c17f --- /dev/null +++ b/report_pdf_form/i18n/nl.po @@ -0,0 +1,496 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * report_pdf_form +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2025-12-18 10:42+0000\n" +"Last-Translator: Bosd \n" +"Language-Team: none\n" +"Language: nl\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: report_pdf_form +#: model_terms:ir.ui.view,arch_db:report_pdf_form.report_pdf_form_form +msgid "" +"env: environment from the record on which the report is printed" +msgstr "" +"env: omgeving van het record waarop het rapport wordt afgedrukt" + +#. module: report_pdf_form +#: model_terms:ir.ui.view,arch_db:report_pdf_form.report_pdf_form_form +msgid "" +"float_compare(): utility function to compare floats based on a " +"specific precision" +msgstr "" +"float_compare(): hulpfunctie om floats te vergelijken op basis " +"van een specifieke precisie" + +#. module: report_pdf_form +#: model_terms:ir.ui.view,arch_db:report_pdf_form.report_pdf_form_form +msgid "record: record on which the report is printed" +msgstr "record: record waarop het rapport wordt afgedrukt" + +#. module: report_pdf_form +#: model_terms:ir.ui.view,arch_db:report_pdf_form.report_pdf_form_form +msgid "" +"time, datetime, dateutil, " +"timezone: useful Python libraries" +msgstr "" +"time, datetime, dateutil, " +"timezone: nuttige Python-bibliotheken" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__help +msgid "Action Description" +msgstr "Beschrijving actie" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__name +msgid "Action Name" +msgstr "Naam actie" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__type +msgid "Action Type" +msgstr "Soort actie" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__binding_model_id +msgid "Binding Model" +msgstr "Bindend model" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__binding_type +msgid "Binding Type" +msgstr "Bindingstype" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__binding_view_types +msgid "Binding View Types" +msgstr "Binding weergavetypes" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form_variable__code +msgid "Code" +msgstr "Code" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__context +msgid "Context Value" +msgstr "Contextwaarde" + +#. module: report_pdf_form +#: model:ir.model.fields,help:report_pdf_form.field_report_pdf_form__context +msgid "" +"Context dictionary as Python expression, empty by default (Default: {})" +msgstr "Context dictionary als Python expressie, standaard leeg (Standaard: {})" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__create_uid +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form_field__create_uid +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form_variable__create_uid +msgid "Created by" +msgstr "Aangemaakt door" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__create_date +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form_field__create_date +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form_variable__create_date +msgid "Created on" +msgstr "Aangemaakt op" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__display_name +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form_field__display_name +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form_variable__display_name +msgid "Display Name" +msgstr "Schermnaam" + +#. module: report_pdf_form +#: model:ir.model.fields,help:report_pdf_form.field_report_pdf_form_field__odoo_field_value +msgid "" +"Dot-separated path to field from the record, e.g. partner_id.name, or python" +" code" +msgstr "" +"Pad naar veld gescheiden door punten, bijv. partner_id.name, of python code" + +#. module: report_pdf_form +#: model:ir.model.fields.selection,name:report_pdf_form.selection__report_pdf_form_field__odoo_field_evaluation__dotted_path +msgid "Dotted field path" +msgstr "Veldpad met punten" + +#. module: report_pdf_form +#: model_terms:ir.ui.view,arch_db:report_pdf_form.report_pdf_form_form +msgid "" +"Dotted field path: Can be used to access atomic fields and go through " +"Many2one relations with automatic formatting." +msgstr "" +"Veldpad met punten: Kan worden gebruikt om toegang te krijgen tot " +"individuele velden en door Many2one-relaties te navigeren met automatische " +"opmaak." + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__encode_error_handling +msgid "Encode Error Handling" +msgstr "Foutafhandeling bij codering" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__encoding +msgid "Encoding" +msgstr "Codering" + +#. module: report_pdf_form +#: model:ir.model.fields,help:report_pdf_form.field_report_pdf_form__encoding +msgid "Encoding to be applied to the generated CSV file. e.g. cp932" +msgstr "" +"Codering die moet worden toegepast op het gegenereerde CSV-bestand, bijv. " +"cp932" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__xml_id +msgid "External ID" +msgstr "Externe ID" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__footer_html +msgid "Extra Footer" +msgstr "Extra voettekst" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__field_mapping_ids +msgid "Field Mapping" +msgstr "Veldmapping" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__field_variable_ids +msgid "Field Variable" +msgstr "Veldvariabele" + +#. module: report_pdf_form +#: model_terms:ir.ui.view,arch_db:report_pdf_form.report_pdf_form_form +msgid "Field mapping" +msgstr "Veldmapping" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__domain +msgid "Filter domain" +msgstr "Filterdomein" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__groups_id +msgid "Groups" +msgstr "Groepen" + +#. module: report_pdf_form +#: model_terms:ir.ui.view,arch_db:report_pdf_form.report_pdf_form_form +msgid "Help" +msgstr "Hulp" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__id +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form_field__id +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form_variable__id +msgid "ID" +msgstr "ID" + +#. module: report_pdf_form +#: model:ir.model.fields,help:report_pdf_form.field_report_pdf_form__attachment_use +msgid "" +"If enabled, then the second time the user prints with same attachment name, " +"it returns the previous report." +msgstr "" +"Indien ingeschakeld, wordt bij een tweede afdrukpoging met dezelfde " +"bijlagenaam het eerdere rapport geretourneerd." + +#. module: report_pdf_form +#: model:ir.model.fields,help:report_pdf_form.field_report_pdf_form__encode_error_handling +msgid "" +"If nothing is selected, CSV export will fail with an error message when " +"there is a character that fail to be encoded." +msgstr "" +"Indien niets is geselecteerd, zal de CSV-export mislukken met een " +"foutmelding wanneer een teken niet kan worden gecodeerd." + +#. module: report_pdf_form +#: model:ir.model.fields,help:report_pdf_form.field_report_pdf_form__multi +msgid "" +"If set to true, the action will not be displayed on the right toolbar of a " +"form view." +msgstr "" +"Indien aangevinkt, wordt de actie niet weergegeven in de rechter werkbalk " +"van een formulierweergave." + +#. module: report_pdf_form +#: model:ir.model.fields,help:report_pdf_form.field_report_pdf_form__domain +msgid "" +"If set, the action will only appear on records that matches the domain." +msgstr "" +"Indien ingesteld, verschijnt de actie alleen bij records die aan het domein " +"voldoen." + +#. module: report_pdf_form +#. odoo-python +#: code:addons/report_pdf_form/models/ir_actions_report.py:0 +msgid "Invalid evaluation for Odoo field" +msgstr "Ongeldige evaluatie voor Odoo-veld" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__write_uid +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form_field__write_uid +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form_variable__write_uid +msgid "Last Updated by" +msgstr "Laatst bijgewerkt door" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__write_date +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form_field__write_date +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form_variable__write_date +msgid "Last Updated on" +msgstr "Laatst bijgewerkt op" + +#. module: report_pdf_form +#: model:ir.model,name:report_pdf_form.model_report_pdf_form_field +msgid "Mapping of Odoo field to PDF form field" +msgstr "Mapping van Odoo-veld naar PDF-formulierveld" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__model_id +msgid "Model" +msgstr "Model" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__model +msgid "Model Name" +msgstr "Modelnaam" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form_variable__name +msgid "Name" +msgstr "Naam" + +#. module: report_pdf_form +#. odoo-python +#: code:addons/report_pdf_form/models/ir_actions_report.py:0 +msgid "No" +msgstr "Nee" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form_field__odoo_field_evaluation +msgid "Odoo Field Evaluation" +msgstr "Odoo-veld evaluatie" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form_field__odoo_field_value +msgid "Odoo Field Value" +msgstr "Odoo-veldwaarde" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__multi +msgid "On Multiple Doc." +msgstr "Op meerdere doc." + +#. module: report_pdf_form +#: model:ir.model.fields,help:report_pdf_form.field_report_pdf_form__help +msgid "" +"Optional help text for the users with a description of the target view, such" +" as its usage and purpose." +msgstr "" +"Optionele helptekst voor de gebruikers met een beschrijving van de " +"doelweergave, zoals het gebruik en het doel ervan." + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form_field__pdf_field_name +msgid "PDF Form Field Name" +msgstr "PDF-formulierveld naam" + +#. module: report_pdf_form +#: model:ir.model,name:report_pdf_form.model_report_pdf_form +msgid "PDF Form Report Template" +msgstr "Sjabloon voor PDF-formulierrapport" + +#. module: report_pdf_form +#: model:ir.actions.act_window,name:report_pdf_form.report_pdf_form_action +#: model:ir.ui.menu,name:report_pdf_form.report_pdf_form_menu +msgid "PDF Form Reports" +msgstr "PDF-formulierrapporten" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__paperformat_id +msgid "Paper Format" +msgstr "Papierformaat" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__path +msgid "Path to show in the URL" +msgstr "Pad om in de URL te tonen" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__print_report_name +msgid "Printed Report Name" +msgstr "Naam afgedrukt rapport" + +#. module: report_pdf_form +#: model:ir.model.fields.selection,name:report_pdf_form.selection__report_pdf_form_field__odoo_field_evaluation__code +msgid "Python code" +msgstr "Python-code" + +#. module: report_pdf_form +#: model_terms:ir.ui.view,arch_db:report_pdf_form.report_pdf_form_form +msgid "" +"Python code: Can be used to acces what you cannot using the Dotted field " +"path. Following variables can be used:" +msgstr "" +"Python-code: Kan worden gebruikt om toegang te krijgen tot zaken die niet " +"via het veldpad met punten bereikbaar zijn. De volgende variabelen kunnen " +"worden gebruikt:" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__pdf_attachment_id +msgid "Related attachment" +msgstr "Gerelateerde bijlage" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__attachment_use +msgid "Reload from Attachment" +msgstr "Opnieuw laden van bijlage" + +#. module: report_pdf_form +#: model:ir.model.fields.selection,name:report_pdf_form.selection__report_pdf_form_field__odoo_field_evaluation__repeat_field +msgid "Repeat field" +msgstr "Veld herhalen" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__report_id +msgid "Report" +msgstr "Rapport" + +#. module: report_pdf_form +#: model:ir.model,name:report_pdf_form.model_ir_actions_report +msgid "Report Action" +msgstr "Rapportactie" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__report_file +msgid "Report File" +msgstr "Rapportbestand" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form_field__report_form_id +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form_variable__report_form_id +msgid "Report Form" +msgstr "Rapportformulier" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__report_type +msgid "Report Type" +msgstr "Rapporttype" + +#. module: report_pdf_form +#: model:ir.model,name:report_pdf_form.model_report_pdf_form_variable +msgid "Reusable variable to be evaluated in form fields code" +msgstr "" +"Herbruikbare variabele die moet worden geëvalueerd in de code van " +"formuliervelden" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__attachment +msgid "Save as Attachment Prefix" +msgstr "Opslaan als bijlage voorvoegsel" + +#. module: report_pdf_form +#: model:ir.model.fields,help:report_pdf_form.field_report_pdf_form__binding_model_id +msgid "" +"Setting a value makes this action available in the sidebar for the given " +"model." +msgstr "" +"Door een waarde in te stellen wordt deze actie beschikbaar in de zijbalk " +"voor het opgegeven model." + +#. module: report_pdf_form +#: model:ir.model.fields.selection,name:report_pdf_form.selection__report_pdf_form_field__odoo_field_evaluation__text +msgid "Static text" +msgstr "Statische tekst" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__report_name +msgid "Template Name" +msgstr "Sjabloonnaam" + +#. module: report_pdf_form +#: model:ir.model.fields,help:report_pdf_form.field_report_pdf_form__report_file +msgid "" +"The path to the main report file (depending on Report Type) or empty if the " +"content is in another field" +msgstr "" +"Het pad naar het hoofdrapportbestand (afhankelijk van het rapporttype) of " +"leeg als de inhoud in een ander veld staat" + +#. module: report_pdf_form +#: model:ir.model.fields,help:report_pdf_form.field_report_pdf_form__report_type +msgid "" +"The type of the report that will be rendered, each one having its own " +"rendering method. HTML means the report will be opened directly in your " +"browser PDF means the report will be rendered using Wkhtmltopdf and " +"downloaded by the user." +msgstr "" +"Het type rapport dat wordt gerenderd, elk met een eigen rendermethode. HTML " +"betekent dat het rapport direct in je browser wordt geopend. PDF betekent " +"dat het rapport wordt gerenderd met Wkhtmltopdf en wordt gedownload door de " +"gebruiker." + +#. module: report_pdf_form +#: model_terms:ir.ui.view,arch_db:report_pdf_form.report_pdf_form_form +msgid "There are two ways to fetch value from the object:" +msgstr "Er zijn twee manieren om een waarde uit het object op te halen:" + +#. module: report_pdf_form +#: model:ir.model.fields,help:report_pdf_form.field_report_pdf_form__footer_html +msgid "" +"This HTML will be displayed in the footer of this report.\n" +"It's recommended to change Paper Format to a new one that fits correctly to this report by adjusting 'Bottom Margin (mm)' accordingly." +msgstr "" +"Deze HTML wordt weergegeven in de voettekst van dit rapport.\n" +"Het wordt aanbevolen om het papierformaat te wijzigen naar een formaat dat " +"goed bij dit rapport past door de 'Ondermarge (mm)' dienovereenkomstig aan " +"te passen." + +#. module: report_pdf_form +#: model:ir.model.fields,help:report_pdf_form.field_report_pdf_form__attachment +msgid "" +"This is the filename of the attachment used to store the printing result. " +"Keep empty to not save the printed reports. You can use a python expression " +"with the object and time variables." +msgstr "" +"Dit is de bestandsnaam van de bijlage die wordt gebruikt om het " +"afdrukresultaat op te slaan. Laat leeg om de afgedrukte rapporten niet op te " +"slaan. Je kunt een python-expressie gebruiken met de variabelen 'object' en " +"'time'." + +#. module: report_pdf_form +#: model:ir.model.fields,help:report_pdf_form.field_report_pdf_form__print_report_name +msgid "" +"This is the filename of the report going to download. Keep empty to not " +"change the report filename. You can use a python expression with the " +"'object' and 'time' variables." +msgstr "" +"Dit is de bestandsnaam van het rapport dat wordt gedownload. Laat leeg om de " +"bestandsnaam niet te wijzigen. Je kunt een python-expressie gebruiken met de " +"variabelen 'object' en 'time'." + +#. module: report_pdf_form +#: model_terms:ir.ui.view,arch_db:report_pdf_form.report_pdf_form_form +msgid "Variables" +msgstr "Variabelen" + +#. module: report_pdf_form +#. odoo-python +#: code:addons/report_pdf_form/models/ir_actions_report.py:0 +msgid "Yes" +msgstr "Ja" diff --git a/report_pdf_form/i18n/report_pdf_form.pot b/report_pdf_form/i18n/report_pdf_form.pot new file mode 100644 index 0000000000..591bbb1993 --- /dev/null +++ b/report_pdf_form/i18n/report_pdf_form.pot @@ -0,0 +1,448 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * report_pdf_form +# +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: report_pdf_form +#: model_terms:ir.ui.view,arch_db:report_pdf_form.report_pdf_form_form +msgid "" +"env: environment from the record on which the report is printed" +msgstr "" + +#. module: report_pdf_form +#: model_terms:ir.ui.view,arch_db:report_pdf_form.report_pdf_form_form +msgid "" +"float_compare(): utility function to compare floats based on a " +"specific precision" +msgstr "" + +#. module: report_pdf_form +#: model_terms:ir.ui.view,arch_db:report_pdf_form.report_pdf_form_form +msgid "record: record on which the report is printed" +msgstr "" + +#. module: report_pdf_form +#: model_terms:ir.ui.view,arch_db:report_pdf_form.report_pdf_form_form +msgid "" +"time, datetime, dateutil, " +"timezone: useful Python libraries" +msgstr "" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__help +msgid "Action Description" +msgstr "" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__name +msgid "Action Name" +msgstr "" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__type +msgid "Action Type" +msgstr "" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__binding_model_id +msgid "Binding Model" +msgstr "" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__binding_type +msgid "Binding Type" +msgstr "" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__binding_view_types +msgid "Binding View Types" +msgstr "" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form_variable__code +msgid "Code" +msgstr "" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__context +msgid "Context Value" +msgstr "" + +#. module: report_pdf_form +#: model:ir.model.fields,help:report_pdf_form.field_report_pdf_form__context +msgid "" +"Context dictionary as Python expression, empty by default (Default: {})" +msgstr "" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__create_uid +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form_field__create_uid +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form_variable__create_uid +msgid "Created by" +msgstr "" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__create_date +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form_field__create_date +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form_variable__create_date +msgid "Created on" +msgstr "" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__display_name +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form_field__display_name +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form_variable__display_name +msgid "Display Name" +msgstr "" + +#. module: report_pdf_form +#: model:ir.model.fields,help:report_pdf_form.field_report_pdf_form_field__odoo_field_value +msgid "" +"Dot-separated path to field from the record, e.g. partner_id.name, or python" +" code" +msgstr "" + +#. module: report_pdf_form +#: model:ir.model.fields.selection,name:report_pdf_form.selection__report_pdf_form_field__odoo_field_evaluation__dotted_path +msgid "Dotted field path" +msgstr "" + +#. module: report_pdf_form +#: model_terms:ir.ui.view,arch_db:report_pdf_form.report_pdf_form_form +msgid "" +"Dotted field path: Can be used to access atomic fields and go through " +"Many2one relations with automatic formatting." +msgstr "" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__encode_error_handling +msgid "Encode Error Handling" +msgstr "" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__encoding +msgid "Encoding" +msgstr "" + +#. module: report_pdf_form +#: model:ir.model.fields,help:report_pdf_form.field_report_pdf_form__encoding +msgid "Encoding to be applied to the generated CSV file. e.g. cp932" +msgstr "" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__xml_id +msgid "External ID" +msgstr "" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__footer_html +msgid "Extra Footer" +msgstr "" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__field_mapping_ids +msgid "Field Mapping" +msgstr "" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__field_variable_ids +msgid "Field Variable" +msgstr "" + +#. module: report_pdf_form +#: model_terms:ir.ui.view,arch_db:report_pdf_form.report_pdf_form_form +msgid "Field mapping" +msgstr "" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__domain +msgid "Filter domain" +msgstr "" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__groups_id +msgid "Groups" +msgstr "" + +#. module: report_pdf_form +#: model_terms:ir.ui.view,arch_db:report_pdf_form.report_pdf_form_form +msgid "Help" +msgstr "" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__id +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form_field__id +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form_variable__id +msgid "ID" +msgstr "" + +#. module: report_pdf_form +#: model:ir.model.fields,help:report_pdf_form.field_report_pdf_form__attachment_use +msgid "" +"If enabled, then the second time the user prints with same attachment name, " +"it returns the previous report." +msgstr "" + +#. module: report_pdf_form +#: model:ir.model.fields,help:report_pdf_form.field_report_pdf_form__encode_error_handling +msgid "" +"If nothing is selected, CSV export will fail with an error message when " +"there is a character that fail to be encoded." +msgstr "" + +#. module: report_pdf_form +#: model:ir.model.fields,help:report_pdf_form.field_report_pdf_form__multi +msgid "" +"If set to true, the action will not be displayed on the right toolbar of a " +"form view." +msgstr "" + +#. module: report_pdf_form +#: model:ir.model.fields,help:report_pdf_form.field_report_pdf_form__domain +msgid "" +"If set, the action will only appear on records that matches the domain." +msgstr "" + +#. module: report_pdf_form +#. odoo-python +#: code:addons/report_pdf_form/models/ir_actions_report.py:0 +msgid "Invalid evaluation for Odoo field" +msgstr "" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__write_uid +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form_field__write_uid +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form_variable__write_uid +msgid "Last Updated by" +msgstr "" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__write_date +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form_field__write_date +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form_variable__write_date +msgid "Last Updated on" +msgstr "" + +#. module: report_pdf_form +#: model:ir.model,name:report_pdf_form.model_report_pdf_form_field +msgid "Mapping of Odoo field to PDF form field" +msgstr "" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__model_id +msgid "Model" +msgstr "" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__model +msgid "Model Name" +msgstr "" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form_variable__name +msgid "Name" +msgstr "" + +#. module: report_pdf_form +#. odoo-python +#: code:addons/report_pdf_form/models/ir_actions_report.py:0 +msgid "No" +msgstr "" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form_field__odoo_field_evaluation +msgid "Odoo Field Evaluation" +msgstr "" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form_field__odoo_field_value +msgid "Odoo Field Value" +msgstr "" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__multi +msgid "On Multiple Doc." +msgstr "" + +#. module: report_pdf_form +#: model:ir.model.fields,help:report_pdf_form.field_report_pdf_form__help +msgid "" +"Optional help text for the users with a description of the target view, such" +" as its usage and purpose." +msgstr "" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form_field__pdf_field_name +msgid "PDF Form Field Name" +msgstr "" + +#. module: report_pdf_form +#: model:ir.model,name:report_pdf_form.model_report_pdf_form +msgid "PDF Form Report Template" +msgstr "" + +#. module: report_pdf_form +#: model:ir.actions.act_window,name:report_pdf_form.report_pdf_form_action +#: model:ir.ui.menu,name:report_pdf_form.report_pdf_form_menu +msgid "PDF Form Reports" +msgstr "" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__paperformat_id +msgid "Paper Format" +msgstr "" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__path +msgid "Path to show in the URL" +msgstr "" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__print_report_name +msgid "Printed Report Name" +msgstr "" + +#. module: report_pdf_form +#: model:ir.model.fields.selection,name:report_pdf_form.selection__report_pdf_form_field__odoo_field_evaluation__code +msgid "Python code" +msgstr "" + +#. module: report_pdf_form +#: model_terms:ir.ui.view,arch_db:report_pdf_form.report_pdf_form_form +msgid "" +"Python code: Can be used to acces what you cannot using the Dotted field " +"path. Following variables can be used:" +msgstr "" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__pdf_attachment_id +msgid "Related attachment" +msgstr "" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__attachment_use +msgid "Reload from Attachment" +msgstr "" + +#. module: report_pdf_form +#: model:ir.model.fields.selection,name:report_pdf_form.selection__report_pdf_form_field__odoo_field_evaluation__repeat_field +msgid "Repeat field" +msgstr "" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__report_id +msgid "Report" +msgstr "" + +#. module: report_pdf_form +#: model:ir.model,name:report_pdf_form.model_ir_actions_report +msgid "Report Action" +msgstr "" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__report_file +msgid "Report File" +msgstr "" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form_field__report_form_id +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form_variable__report_form_id +msgid "Report Form" +msgstr "" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__report_type +msgid "Report Type" +msgstr "" + +#. module: report_pdf_form +#: model:ir.model,name:report_pdf_form.model_report_pdf_form_variable +msgid "Reusable variable to be evaluated in form fields code" +msgstr "" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__attachment +msgid "Save as Attachment Prefix" +msgstr "" + +#. module: report_pdf_form +#: model:ir.model.fields,help:report_pdf_form.field_report_pdf_form__binding_model_id +msgid "" +"Setting a value makes this action available in the sidebar for the given " +"model." +msgstr "" + +#. module: report_pdf_form +#: model:ir.model.fields.selection,name:report_pdf_form.selection__report_pdf_form_field__odoo_field_evaluation__text +msgid "Static text" +msgstr "" + +#. module: report_pdf_form +#: model:ir.model.fields,field_description:report_pdf_form.field_report_pdf_form__report_name +msgid "Template Name" +msgstr "" + +#. module: report_pdf_form +#: model:ir.model.fields,help:report_pdf_form.field_report_pdf_form__report_file +msgid "" +"The path to the main report file (depending on Report Type) or empty if the " +"content is in another field" +msgstr "" + +#. module: report_pdf_form +#: model:ir.model.fields,help:report_pdf_form.field_report_pdf_form__report_type +msgid "" +"The type of the report that will be rendered, each one having its own " +"rendering method. HTML means the report will be opened directly in your " +"browser PDF means the report will be rendered using Wkhtmltopdf and " +"downloaded by the user." +msgstr "" + +#. module: report_pdf_form +#: model_terms:ir.ui.view,arch_db:report_pdf_form.report_pdf_form_form +msgid "There are two ways to fetch value from the object:" +msgstr "" + +#. module: report_pdf_form +#: model:ir.model.fields,help:report_pdf_form.field_report_pdf_form__footer_html +msgid "" +"This HTML will be displayed in the footer of this report.\n" +"It's recommended to change Paper Format to a new one that fits correctly to this report by adjusting 'Bottom Margin (mm)' accordingly." +msgstr "" + +#. module: report_pdf_form +#: model:ir.model.fields,help:report_pdf_form.field_report_pdf_form__attachment +msgid "" +"This is the filename of the attachment used to store the printing result. " +"Keep empty to not save the printed reports. You can use a python expression " +"with the object and time variables." +msgstr "" + +#. module: report_pdf_form +#: model:ir.model.fields,help:report_pdf_form.field_report_pdf_form__print_report_name +msgid "" +"This is the filename of the report going to download. Keep empty to not " +"change the report filename. You can use a python expression with the " +"'object' and 'time' variables." +msgstr "" + +#. module: report_pdf_form +#: model_terms:ir.ui.view,arch_db:report_pdf_form.report_pdf_form_form +msgid "Variables" +msgstr "" + +#. module: report_pdf_form +#. odoo-python +#: code:addons/report_pdf_form/models/ir_actions_report.py:0 +msgid "Yes" +msgstr "" diff --git a/report_pdf_form/models/__init__.py b/report_pdf_form/models/__init__.py new file mode 100644 index 0000000000..a85c727aae --- /dev/null +++ b/report_pdf_form/models/__init__.py @@ -0,0 +1,4 @@ +from . import ir_actions_report +from . import report_pdf_form +from . import report_pdf_form_variable +from . import report_pdf_form_field diff --git a/report_pdf_form/models/ir_actions_report.py b/report_pdf_form/models/ir_actions_report.py new file mode 100644 index 0000000000..f2ef289831 --- /dev/null +++ b/report_pdf_form/models/ir_actions_report.py @@ -0,0 +1,201 @@ +# Copyright 2025 Camptocamp SA +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl) +import base64 +import io + +from pytz import timezone + +from odoo import api, models +from odoo.exceptions import UserError +from odoo.tools import format_amount, format_date, format_datetime, pdf +from odoo.tools.float_utils import float_compare +from odoo.tools.pdf import ( + NameObject, + NumberObject, + PdfFileReader, + PdfFileWriter, + createStringObject, +) +from odoo.tools.safe_eval import datetime, dateutil, safe_eval, time + + +class IrActionsReport(models.Model): + _inherit = "ir.actions.report" + + def _render_qweb_pdf_prepare_streams(self, report_ref, data, res_ids=None): + pdf_form_report = self.env["report.pdf.form"].search( + [("report_name", "=", report_ref)], limit=1 + ) + + if not pdf_form_report: + return super()._render_qweb_pdf_prepare_streams( + report_ref, data, res_ids=res_ids + ) + + res = {} + + records = self.env[pdf_form_report.sudo().model_id.model].browse(res_ids) + + for rec in records: + res[rec.id] = {"stream": None, "attachment": None} + form_fields_values_mapping = {} + writer = PdfFileWriter() + + self_with_rec_context = self.with_context( + # TODO Add check/option if record has partner_id field? + # use_babel=True, lang=rec.partner_id.lang or self.env.user.lang + use_babel=True, + lang=self.env.user.lang, + ) + prefix = f"template_{pdf_form_report.id}__" + self_with_rec_context._update_mapping_and_add_pages_to_writer_pdf( + writer, pdf_form_report, form_fields_values_mapping, prefix, rec + ) + + pdf.fill_form_fields_pdf(writer, form_fields=form_fields_values_mapping) + with io.BytesIO() as _buffer: + writer.write(_buffer) + stream = io.BytesIO(_buffer.getvalue()) + res[rec.id].update({"stream": stream}) + return res + + @api.model + def _update_mapping_and_add_pages_to_writer_pdf( + self, writer, template, form_fields_values_mapping, prefix, record + ): + for form_field in template.field_mapping_ids: + if form_field.odoo_field_evaluation == "dotted_path": + field_value = self._get_pdf_value_from_path(form_field, record) + elif form_field.odoo_field_evaluation == "text": + field_value = form_field.odoo_field_value + elif form_field.odoo_field_evaluation == "code": + field_value = self._get_pdf_value_from_code(form_field, record) + elif form_field.odoo_field_evaluation == "repeat_field": + continue + else: + raise UserError(self.env._("Invalid evaluation for Odoo field")) + form_fields_values_mapping[prefix + form_field.pdf_field_name] = field_value + + for form_field in template.field_mapping_ids.filtered( + lambda fld: fld.odoo_field_evaluation == "repeat_field" + ): + form_fields_values_mapping[prefix + form_field.pdf_field_name] = ( + form_fields_values_mapping[prefix + form_field.odoo_field_value] + ) + + decoded_template = base64.b64decode(template.sudo().pdf_attachment_id.datas) + self._add_pages_to_writer_pdf(writer, decoded_template, prefix) + + @api.model + def _get_pdf_value_from_code(self, form_field, record): + return safe_eval( + form_field.odoo_field_value, + self._pdf_form_eval_context(record, form_field.report_form_id), + ) + + def _pdf_form_eval_context(self, record, template): + base_ctx = { + "record": record.sudo(), + "env": record.env, + "time": time, + "datetime": datetime, + "dateutil": dateutil, + "timezone": timezone, + "float_compare": float_compare, + } + res = base_ctx.copy() + for var in template.field_variable_ids: + res[var.name] = safe_eval(var.code, base_ctx) + return res + + @api.model + def _get_pdf_value_from_path(self, form_field, record): + tz = record.env.user.tz or "UTC" + base_record = record + path = form_field.odoo_field_value + # If path = 'order_id.order_line.product_id.name' + path = path.split(".") # ['order_id', 'order_line', 'product_id', 'name'] + # Sudo to be able to follow the path set by the admin + try: + records = base_record.sudo().mapped( + ".".join(path[:-1]) + ) # product.product(id1, id2, ...) + except AttributeError: + records = base_record.browse() + field_name = path[-1] # 'name' + + def _get_formatted_value(self): + # self must be named so to be considered in the translation logic + field_ = records._fields[field_name] + field_type_ = field_.type + for record_ in records: + value_ = record_[field_name] + if field_type_ == "boolean": + formatted_value_ = self.env._("Yes") if value_ else self.env._("No") + elif field_type_ == "monetary": + currency_id_ = record_[field_.get_currency_field(record_)] + formatted_value_ = format_amount( + self.env, value_, currency_id_ or record_.currency_id + ) + elif not value_: + formatted_value_ = "" + elif field_type_ == "date": + formatted_value_ = format_date(self.env, value_) + elif field_type_ == "datetime": + formatted_value_ = format_datetime( + self.env, value_, tz=tz, dt_format=False + ) + elif field_type_ == "selection" and value_: + formatted_value_ = dict(field_._description_selection(self.env))[ + value_ + ] + elif field_type_ == "many2one" and value_: + formatted_value_ = value_.display_name + elif field_type_ in {"one2many", "many2many"}: + formatted_value_ = ( + ", ".join([v.display_name for v in value_]) if value_ else "" + ) + else: + formatted_value_ = str(value_) + + yield formatted_value_ + + return ", ".join(_get_formatted_value(self)) + + @api.model + def _add_pages_to_writer_pdf(self, writer, document, prefix=None): + reader = PdfFileReader(io.BytesIO(document), strict=False) + + field_names = set() + if prefix: + field_names = reader.getFormTextFields() + + for page_id in range(reader.getNumPages()): + page = reader.getPage(page_id) + if prefix and page.get("/Annots"): + # Modifying the annots that hold every information about the form fields + for j in range(len(page["/Annots"])): + reader_annot = page["/Annots"][j].getObject() + if reader_annot.get("/T") in field_names: + # Prefix all form fields in the document with the document + # identifier. + # This is necessary to know which value needs to be taken when + # filling the forms. + form_key = reader_annot.get("/T") + new_key = prefix + form_key + + # Modifying the form flags to force some characteristics + # 1. make all text fields read-only + # 2. make all text fields support multiline + form_flags = reader_annot.get("/Ff", 0) + readonly_flag = 1 # 1st bit sets readonly + multiline_flag = 1 << 12 # 13th bit sets multiline text + new_flags = form_flags | readonly_flag | multiline_flag + + reader_annot.update( + { + NameObject("/T"): createStringObject(new_key), + NameObject("/Ff"): NumberObject(new_flags), + } + ) + writer.addPage(page) diff --git a/report_pdf_form/models/report_pdf_form.py b/report_pdf_form/models/report_pdf_form.py new file mode 100644 index 0000000000..06abb8baa1 --- /dev/null +++ b/report_pdf_form/models/report_pdf_form.py @@ -0,0 +1,167 @@ +# Copyright 2025 Camptocamp SA +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl) +import base64 +import io + +from odoo import api, fields, models +from odoo.exceptions import UserError, ValidationError +from odoo.tools.pdf import PdfFileWriter + + +class ReportPDFForm(models.Model): + _name = "report.pdf.form" + _description = "PDF Form Report Template" + _inherits = { + "ir.actions.report": "report_id", + } + + def write(self, vals): + # Ensure report_id is unique by checking before write + if "report_id" in vals: + existing = self.search([("report_id", "=", vals["report_id"])]) + if len(existing) > 1: # If there would be duplicates after update + raise ValidationError( + self.env._("The report must be unique for a PDF form report.") + ) + return super().write(vals) + + @api.model_create_multi + def create(self, vals_list): + for vals in vals_list: + if "report_id" in vals: + existing = self.search_count([("report_id", "=", vals["report_id"])]) + if existing > 0: + raise ValidationError( + self.env._("The report must be unique for a PDF form report.") + ) + return super().create(vals_list) + + # name = fields.Char(required=True, translate=True) + # ref = fields.Char(required=True) + pdf_attachment_id = fields.Many2one( + string="Related attachment", + comodel_name="ir.attachment", + ondelete="cascade", + required=True, + ) + # TODO: Check if needed + report_id = fields.Many2one( + "ir.actions.report", + ondelete="cascade", + required=True, + ) + model_id = fields.Many2one("ir.model", ondelete="cascade", required=True) + + @api.onchange("report_id") + def _onchange_report_id(self): + """Auto-set model_id based on report_id's model.""" + if self.report_id and self.report_id.model: + model = self.env["ir.model"].search( + [("model", "=", self.report_id.model)], limit=1 + ) + if model: + self.model_id = model.id + + # TODO: + field_mapping_ids = fields.One2many( + "report.pdf.form.field", + "report_form_id", + required=True, + ) + field_variable_ids = fields.One2many( + "report.pdf.form.variable", + "report_form_id", + ) + + def action_preview_pdf(self): + """Preview the PDF form with sample data.""" + self.ensure_one() + + if not self.pdf_attachment_id: + raise UserError(self.env._("No PDF template attached to this form.")) + + # Get a sample record of the model + model_name = self.model_id.model + sample_record = self.env[model_name].search([], limit=1) + if not sample_record: + message = self.env._( + "No records found for model %(model_name)s. Cannot generate preview." + ) % {"model_name": model_name} + raise UserError(message) + + # Generate the PDF using the same logic as the report + try: + # Decode the PDF attachment + decoded_pdf = base64.b64decode(self.pdf_attachment_id.datas) + + # Create a PDF writer + writer = PdfFileWriter() + + # Add pages from the template + self.env["ir.actions.report"]._add_pages_to_writer_pdf( + writer, decoded_pdf, f"template_{self.id}__" + ) + + # Prepare form fields mapping with sample values + form_fields_values_mapping = {} + for form_field in self.field_mapping_ids: + if form_field.odoo_field_evaluation == "dotted_path": + try: + field_value = self.env[ + "ir.actions.report" + ]._get_pdf_value_from_path(form_field, sample_record) + except Exception: + field_value = ( + f"[ERROR: Invalid path {form_field.odoo_field_value}]" + ) + elif form_field.odoo_field_evaluation == "text": + field_value = form_field.odoo_field_value + elif form_field.odoo_field_evaluation == "code": + try: + field_value = self.env[ + "ir.actions.report" + ]._get_pdf_value_from_code(form_field, sample_record) + except Exception: + field_value = "[ERROR: Invalid code]" + elif form_field.odoo_field_evaluation == "repeat_field": + continue + else: + field_value = "" + + form_fields_values_mapping[ + f"template_{self.id}__{form_field.pdf_field_name}" + ] = field_value + + # Fill the form fields + from odoo.tools import pdf + + pdf.fill_form_fields_pdf(writer, form_fields=form_fields_values_mapping) + + # Save to bytes + with io.BytesIO() as buffer: + writer.write(buffer) + pdf_content = buffer.getvalue() + + # Create an attachment with the preview + attachment = self.env["ir.attachment"].create( + { + "name": f"preview_{self.name}.pdf", + "type": "binary", + "datas": base64.b64encode(pdf_content), + "mimetype": "application/pdf", + "res_model": self._name, + "res_id": self.id, + } + ) + + # Return action to open the preview + return { + "type": "ir.actions.act_url", + "url": f"/web/content/{attachment.id}/{attachment.name}", + "target": "new", + } + except Exception as e: + message = self.env._("Could not generate PDF preview: %(error)s") % { + "error": str(e) + } + raise UserError(message) from e diff --git a/report_pdf_form/models/report_pdf_form_field.py b/report_pdf_form/models/report_pdf_form_field.py new file mode 100644 index 0000000000..55c29aa970 --- /dev/null +++ b/report_pdf_form/models/report_pdf_form_field.py @@ -0,0 +1,144 @@ +# Copyright 2025 Camptocamp SA +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl) +from odoo import api, fields, models +from odoo.exceptions import ValidationError + + +class ReportPDFFormField(models.Model): + _name = "report.pdf.form.field" + _description = "Mapping of Odoo field to PDF form field" + + report_form_id = fields.Many2one( + "report.pdf.form", required=True, ondelete="cascade" + ) + pdf_field_name = fields.Char(string="PDF Form Field Name", required=True) + odoo_field_evaluation = fields.Selection( + [ + ("dotted_path", "Dotted field path"), + ("text", "Static text"), + ("code", "Python code"), + ("repeat_field", "Repeat field"), + ], + required=True, + default="dotted_path", + ) + odoo_field_value = fields.Char( + help="Dot-separated path to field from the record, e.g. partner_id.name, " + "or python code", + required=True, + ) + is_valid = fields.Boolean(compute="_compute_is_valid", store=True, readonly=True) + validation_message = fields.Char( + compute="_compute_validation_message", + store=True, + readonly=True, + ) + + @api.depends("odoo_field_evaluation", "odoo_field_value", "report_form_id.model_id") + def _compute_is_valid(self): + for record in self: + record.is_valid = record._validate_dotted_path() + + @api.depends("is_valid", "odoo_field_evaluation", "odoo_field_value") + def _compute_validation_message(self): + for record in self: + if record.odoo_field_evaluation != "dotted_path": + record.validation_message = "Validation not applicable" + elif record.is_valid: + record.validation_message = "Valid path" + else: + record.validation_message = f"Invalid path: {record.odoo_field_value}" + + def _validate_dotted_path(self): + """Validate if the dotted path is valid for the model.""" + self.ensure_one() + if self.odoo_field_evaluation != "dotted_path" or not self.odoo_field_value: + return True # Not a dotted path or empty, considered valid + + # Get the model from the parent report form + if ( + not self.report_form_id + or not self.report_form_id.model_id + or not self.report_form_id.model_id.model + ): + return True # Model not available yet, skip validation during creation + model_name = self.report_form_id.model_id.model + if not model_name or model_name not in self.env: + return True # Model not set or not in registry, skip validation + + # Split the dotted path + path_parts = self.odoo_field_value.split(".") + + # Start with the base model + current_model = self.env[model_name] + + # Traverse the path + for i, field_name in enumerate(path_parts): + if field_name not in current_model._fields: + return False # Field doesn't exist + + field = current_model._fields[field_name] + if i < len(path_parts) - 1: # Not the last part, should be a relation + if field.type not in ["many2one", "one2many", "many2many"]: + return False # Can't traverse further on non-relation field + # Move to the related model + if not field.comodel_name or field.comodel_name not in self.env: + return False # comodel not found + current_model = self.env[field.comodel_name] + + return True + + def action_validate_field(self): + """Manual validation action for the field.""" + self.ensure_one() + is_valid = self._validate_dotted_path() + if is_valid: + return { + "type": "ir.actions.client", + "tag": "display_notification", + "params": { + "title": "Success", + "message": self.env._('The dotted path "%(path)s" is valid.') + % {"path": self.odoo_field_value}, + "type": "success", + "sticky": False, + }, + } + else: + message = self.env._( + 'The dotted path "%(path)s" is invalid for model "%(model)s".' + ) % { + "path": self.odoo_field_value, + "model": self.report_form_id.model_id.name, + } + return { + "type": "ir.actions.client", + "tag": "display_notification", + "params": { + "title": "Error", + "message": message, + "type": "danger", + "sticky": True, + }, + } + + @api.constrains("odoo_field_evaluation", "odoo_field_value", "report_form_id") + def _check_dotted_path(self): + for record in self: + # Skip validation if model is not available (during creation/updates) + if ( + not record.report_form_id + or not record.report_form_id.model_id + or not record.report_form_id.model_id.model + ): + continue # Skip validation when model is not yet available + if not record._validate_dotted_path(): + model_name = ( + record.report_form_id.model_id.name + if record.report_form_id.model_id + else "Unknown" + ) + message = self.env._( + "The dotted path '%(path)s' is not valid for model '%(model)s'." + ) % {"path": record.odoo_field_value, "model": model_name} + raise ValidationError(message) diff --git a/report_pdf_form/models/report_pdf_form_variable.py b/report_pdf_form/models/report_pdf_form_variable.py new file mode 100644 index 0000000000..f8d5342ab9 --- /dev/null +++ b/report_pdf_form/models/report_pdf_form_variable.py @@ -0,0 +1,14 @@ +# Copyright 2025 Camptocamp SA +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl) +from odoo import fields, models + + +class ReportPDFFormVariable(models.Model): + _name = "report.pdf.form.variable" + _description = "Reusable variable to be evaluated in form fields code" + + report_form_id = fields.Many2one( + "report.pdf.form", required=True, ondelete="cascade" + ) + name = fields.Char() + code = fields.Char() diff --git a/report_pdf_form/pyproject.toml b/report_pdf_form/pyproject.toml new file mode 100644 index 0000000000..4231d0cccb --- /dev/null +++ b/report_pdf_form/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/report_pdf_form/readme/CONFIGURATION.md b/report_pdf_form/readme/CONFIGURATION.md new file mode 100644 index 0000000000..8c81f2f65d --- /dev/null +++ b/report_pdf_form/readme/CONFIGURATION.md @@ -0,0 +1,20 @@ +1. Go to Settings > Technical > Reporting > PDF Form Reports and create a new record. +2. Link with a dedicated Report and empty QWeb template. +3. Upload your PDF form file as an attachment (this is required). +4. Define how to fill the PDF fields using Odoo fields. + +## Uploading PDF Forms +Yes, users must upload a PDF file that contains form fields. The PDF should have interactive form fields that can be filled with data from Odoo records. You can create these PDF forms using tools like: +- LibreOffice Draw +- Scribus +- Adobe Acrobat +- Online tools like docfly.com + +## Demo Data +If you installed the module with demo data, you will have a sample configuration already set up: +- A demo PDF form template for partner records +- Field mappings for name, email, and phone (simple dotted paths) +- Field mappings with deeper dotted paths like company_id.name, user_id.login, and country_id.name +- A variable for the current date + +To use the demo data, simply go to the Contacts module, select a partner, and print the "Demo Partner Report". \ No newline at end of file diff --git a/report_pdf_form/readme/CONTRIBUTORS.md b/report_pdf_form/readme/CONTRIBUTORS.md new file mode 100644 index 0000000000..c5b86defe1 --- /dev/null +++ b/report_pdf_form/readme/CONTRIBUTORS.md @@ -0,0 +1 @@ +- Akim Juillerat diff --git a/report_pdf_form/readme/DESCRIPTION.md b/report_pdf_form/readme/DESCRIPTION.md new file mode 100644 index 0000000000..7439dc9d37 --- /dev/null +++ b/report_pdf_form/readme/DESCRIPTION.md @@ -0,0 +1,13 @@ +This module allows to use PDF files having form fields as Odoo reports +to be printed with values being filled from Odoo records. + +This module mostly reuses features that were implemented by Odoo in +the sale_pdf_quotation_builder module. + +## Creating PDF Form Fields + +To create PDFs with form fields for use with this module, you can use various tools: + +- **docfly.com**: An online tool for adding form fields to PDFs +- **LibreOffice Draw**: Part of the LibreOffice suite, can add form fields to PDFs +- **Scribus**: A desktop publishing application that can create PDFs with form fields \ No newline at end of file diff --git a/report_pdf_form/readme/ROADMAP.md b/report_pdf_form/readme/ROADMAP.md new file mode 100644 index 0000000000..424d1738c0 --- /dev/null +++ b/report_pdf_form/readme/ROADMAP.md @@ -0,0 +1,2 @@ +Add a dedicated report type to avoid having to define a qweb template and +have everything on ir.actions.report. diff --git a/report_pdf_form/security/ir.model.access.csv b/report_pdf_form/security/ir.model.access.csv new file mode 100644 index 0000000000..77fe1517ef --- /dev/null +++ b/report_pdf_form/security/ir.model.access.csv @@ -0,0 +1,7 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_report_pdf_form_manager,report.pdf.form.manager,model_report_pdf_form,base.group_system,1,1,1,1 +access_report_pdf_form_user,report.pdf.form.user,model_report_pdf_form,base.group_user,1,0,0,0 +access_report_pdf_form_field_manager,report.pdf.form.field.manager,model_report_pdf_form_field,base.group_system,1,1,1,1 +access_report_pdf_form_field_user,report.pdf.form.field.user,model_report_pdf_form_field,base.group_user,1,0,0,0 +access_report_pdf_form_variable_manager,report.pdf.form.variable.manager,model_report_pdf_form_variable,base.group_system,1,1,1,1 +access_report_pdf_form_variable_user,report.pdf.form.variable.user,model_report_pdf_form_variable,base.group_user,1,0,0,0 diff --git a/report_pdf_form/static/description/icon.png b/report_pdf_form/static/description/icon.png new file mode 100644 index 0000000000..1dcc49c24f Binary files /dev/null and b/report_pdf_form/static/description/icon.png differ diff --git a/report_pdf_form/static/description/index.html b/report_pdf_form/static/description/index.html new file mode 100644 index 0000000000..3e3de5a620 --- /dev/null +++ b/report_pdf_form/static/description/index.html @@ -0,0 +1,453 @@ + + + + + +README.rst + + + +
+ + + +Odoo Community Association + +
+

Report PDF Form

+ +

Alpha License: LGPL-3 OCA/reporting-engine Translate me on Weblate Try me on Runboat

+

This module allows to use PDF files having form fields as Odoo reports +to be printed with values being filled from Odoo records.

+

This module mostly reuses features that were implemented by Odoo in the +sale_pdf_quotation_builder module.

+
+

Creating PDF Form Fields

+

To create PDFs with form fields for use with this module, you can use +various tools:

+
    +
  • docfly.com: An online tool for adding form fields to PDFs
  • +
  • LibreOffice Draw: Part of the LibreOffice suite, can add form +fields to PDFs
  • +
  • Scribus: A desktop publishing application that can create PDFs +with form fields
  • +
+
+

Important

+

This is an alpha version, the data model and design can change at any time without warning. +Only for development or testing purpose, do not use in production. +More details on development status

+
+

Table of contents

+ +
+

Known issues / Roadmap

+

Add a dedicated report type to avoid having to define a qweb template +and have everything on ir.actions.report.

+
+
+

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.

+
+ +
+
+

Authors

+
    +
  • Camptocamp
  • +
+
+
+

Contributors

+ +
+
+

Maintainers

+

This module is maintained by the OCA.

+ +Odoo Community Association + +

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.

+

Current maintainer:

+

grindtildeath

+

This module is part of the OCA/reporting-engine project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+ + diff --git a/report_pdf_form/tests/__init__.py b/report_pdf_form/tests/__init__.py new file mode 100644 index 0000000000..6ea1d77200 --- /dev/null +++ b/report_pdf_form/tests/__init__.py @@ -0,0 +1 @@ +from . import test_report_pdf_form diff --git a/report_pdf_form/tests/data/form_example.pdf b/report_pdf_form/tests/data/form_example.pdf new file mode 100644 index 0000000000..d612536c31 Binary files /dev/null and b/report_pdf_form/tests/data/form_example.pdf differ diff --git a/report_pdf_form/tests/data/form_example.sla b/report_pdf_form/tests/data/form_example.sla new file mode 100644 index 0000000000..e2a371e3be --- /dev/null +++ b/report_pdf_form/tests/data/form_example.sla @@ -0,0 +1,166 @@ + + + + + + + + + + + + + + + + + + + + + + + + + +