diff --git a/hr_payroll_document/README.rst b/hr_payroll_document/README.rst new file mode 100644 index 000000000..549d2ab0f --- /dev/null +++ b/hr_payroll_document/README.rst @@ -0,0 +1,104 @@ +.. image:: https://odoo-community.org/readme-banner-image + :target: https://odoo-community.org/get-involved?utm_source=readme + :alt: Odoo Community Association + +===================== +HR - Payroll Document +===================== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:c08333be78dde8601d5019413dcf1a02d2a2841443724a90e6ccf2dd39549d3e + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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%2Fpayroll-lightgray.png?logo=github + :target: https://github.com/OCA/payroll/tree/19.0/hr_payroll_document + :alt: OCA/payroll +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/payroll-19-0/payroll-19-0-hr_payroll_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/payroll&target_branch=19.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module have a wizard view to manage the different payrolls of +employees which is identified by the identification_id attribute. + +By default, the employee's payroll is encrypted using their +identification number. This behavior can be changed by the employee in +their profile or by HR in the employee's form. + +**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 +------- + +* APSL + +Contributors +------------ + +- `APSL-Nagarro `__: + + - Antoni Marroig + - Miquel Alzanillas + +- `PyTech `__: + + - Simone Rubino + +- `Tessera `__: + + - Paco Montés + +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-peluko00| image:: https://github.com/peluko00.png?size=40px + :target: https://github.com/peluko00 + :alt: peluko00 + +Current `maintainer `__: + +|maintainer-peluko00| + +This module is part of the `OCA/payroll `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/hr_payroll_document/__init__.py b/hr_payroll_document/__init__.py new file mode 100644 index 000000000..134df2743 --- /dev/null +++ b/hr_payroll_document/__init__.py @@ -0,0 +1,2 @@ +from . import wizard +from . import models diff --git a/hr_payroll_document/__manifest__.py b/hr_payroll_document/__manifest__.py new file mode 100644 index 000000000..ccf97654d --- /dev/null +++ b/hr_payroll_document/__manifest__.py @@ -0,0 +1,22 @@ +{ + "name": "HR - Payroll Document", + "summary": "Manage payroll for each employee", + "author": "APSL, Odoo Community Association (OCA)", + "website": "https://github.com/OCA/payroll", + "license": "AGPL-3", + "category": "Payrolls", + "version": "19.0.1.0.0", + "depends": ["hr", "base_vat"], + "maintainers": ["peluko00"], + "external_dependencies": { + "python": [ + "pypdf", + ], + }, + "data": [ + "wizard/payroll_management_wizard.xml", + "security/ir.model.access.csv", + "data/email_payroll_employee.xml", + "views/hr_employee_views.xml", + ], +} diff --git a/hr_payroll_document/data/email_payroll_employee.xml b/hr_payroll_document/data/email_payroll_employee.xml new file mode 100644 index 000000000..db03f7f14 --- /dev/null +++ b/hr_payroll_document/data/email_payroll_employee.xml @@ -0,0 +1,136 @@ + + + + Payroll Employee + + {{object.company_id.email}} + {{object.work_email}} + Payroll {{ctx.get('subject')}} + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + +
+ {{object.company_id.name}} +
+

+ + Payroll + +

+
+
+ + + + + + + + + + + + +
+

+

+ Hello , +

+
+

+ We send you the payroll with the subject + . +
+

+
+
+
+
+

+

+
+ + +
+
+

+ + + + diff --git a/hr_payroll_document/i18n/ca_ES.po b/hr_payroll_document/i18n/ca_ES.po new file mode 100644 index 000000000..2004c59fd --- /dev/null +++ b/hr_payroll_document/i18n/ca_ES.po @@ -0,0 +1,337 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * hr_payroll_document +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2023-12-14 10:27+0000\n" +"PO-Revision-Date: 2023-12-14 10:27+0000\n" +"Last-Translator: \n" +"Language-Team: \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: hr_payroll_document +#: model:mail.template,body_html:hr_payroll_document.payroll_employee_email_template +msgid "" +"\n" +" \n" +" \n" +" \n" +" \n" +"

\n" +" \n" +" \n" +" " + +#. module: hr_payroll_document +#: model:ir.model,name:hr_payroll_document.model_ir_attachment +#: model:ir.model.fields,field_description:hr_payroll_document.field_ir_attachment__payrol_rel +#: model:ir.model.fields,field_description:hr_payroll_document.field_product_document__payrol_rel +msgid "Attachment" +msgstr "Adjunt" + +#. module: hr_payroll_document +#: model:ir.model.fields,field_description:hr_payroll_document.field_ir_attachment_payroll_custom__attachment_id +msgid "Attachment File" +msgstr "Fitxer Adjunt" + +#. module: hr_payroll_document +#: model_terms:ir.ui.view,arch_db:hr_payroll_document.payrolls_management_wizard_form +msgid "Close" +msgstr "Tancar" + +#. module: hr_payroll_document +#: model:ir.model.fields,field_description:hr_payroll_document.field_ir_attachment_payroll_custom__create_date +msgid "Create Date" +msgstr "Data de creació" + +#. module: hr_payroll_document +#: model:ir.model.fields,field_description:hr_payroll_document.field_ir_attachment_payroll_custom__create_uid +#: model:ir.model.fields,field_description:hr_payroll_document.field_payroll_management_wizard__create_uid +msgid "Created by" +msgstr "Creat per" + +#. module: hr_payroll_document +#: model:ir.model.fields,field_description:hr_payroll_document.field_payroll_management_wizard__create_date +msgid "Created on" +msgstr "Creat el" + +#. module: hr_payroll_document +#: model_terms:ir.ui.view,arch_db:hr_payroll_document.res_users_view_form_profile_inherit +#: model_terms:ir.ui.view,arch_db:hr_payroll_document.view_employee_form +msgid "Disable encryption" +msgstr "" + +#. module: hr_payroll_document +#: model:ir.model.fields,field_description:hr_payroll_document.field_hr_employee__no_payroll_encryption +#: model:ir.model.fields,field_description:hr_payroll_document.field_res_users__no_payroll_encryption +msgid "Disable payrolls encryption" +msgstr "" + +#. module: hr_payroll_document +#: model:ir.model.fields,field_description:hr_payroll_document.field_ir_attachment_payroll_custom__display_name +#: model:ir.model.fields,field_description:hr_payroll_document.field_payroll_management_wizard__display_name +msgid "Display Name" +msgstr "Nom a mostrar" + +#. module: hr_payroll_document +#: model:ir.model.fields,field_description:hr_payroll_document.field_ir_attachment__document_type +#: model:ir.model.fields,field_description:hr_payroll_document.field_product_document__document_type +msgid "Document Type" +msgstr "" + +#. module: hr_payroll_document +#: model_terms:ir.ui.view,arch_db:hr_payroll_document.view_payroll_tree +msgid "Download" +msgstr "" + +#. module: hr_payroll_document +#: model:ir.model,name:hr_payroll_document.model_hr_employee +#: model:ir.model.fields,field_description:hr_payroll_document.field_ir_attachment_payroll_custom__employee +#: model_terms:ir.ui.view,arch_db:hr_payroll_document.view_payroll_filter +msgid "Employee" +msgstr "Empleat" + +#. module: hr_payroll_document +#. odoo-python +#: code:addons/hr_payroll_document/tests/test_hr_payroll_document.py:0 +#: code:addons/hr_payroll_document/wizard/payroll_management_wizard.py:0 +#, python-format +msgid "Employees not found" +msgstr "Empleats no trobats" + +#. module: hr_payroll_document +#: model:ir.model.fields,help:hr_payroll_document.field_payroll_management_wizard__subject +msgid "Enter the title of the payroll whether it is the month, week, day, etc." +msgstr "Introduïu el títol de la nòmina ja sigui el mes, setmana, dia, etc." + +#. module: hr_payroll_document +#: model_terms:ir.ui.view,arch_db:hr_payroll_document.view_payroll_filter +msgid "Group By" +msgstr "" + +#. module: hr_payroll_document +#: model:ir.model.fields,field_description:hr_payroll_document.field_ir_attachment_payroll_custom__id +#: model:ir.model.fields,field_description:hr_payroll_document.field_payroll_management_wizard__id +msgid "ID" +msgstr "" + +#. module: hr_payroll_document +#. odoo-python +#: code:addons/hr_payroll_document/tests/test_hr_payroll_document.py:0 +#: code:addons/hr_payroll_document/wizard/payroll_management_wizard.py:0 +#, python-format +msgid "IDs whose employee has not been found: " +msgstr "IDs dels empleats que no s'han trobat: " + +#. module: hr_payroll_document +#: model:ir.model.fields,field_description:hr_payroll_document.field_ir_attachment_payroll_custom__identification_id +#: model_terms:ir.ui.view,arch_db:hr_payroll_document.view_payroll_filter +msgid "Identification ID" +msgstr "Identificació ID" + +#. module: hr_payroll_document +#: model:ir.model.fields,help:hr_payroll_document.field_hr_employee__no_payroll_encryption +#: model:ir.model.fields,help:hr_payroll_document.field_res_users__no_payroll_encryption +msgid "" +"If this is disabled (default), the PDF payrolls are encrypted using the " +"Identification No.\n" +"Only future payrolls are affected by this change, existing payrolls will not " +"change their encryption status." +msgstr "" + +#. module: hr_payroll_document +#: model:ir.model.fields,field_description:hr_payroll_document.field_ir_attachment_payroll_custom__write_uid +#: model:ir.model.fields,field_description:hr_payroll_document.field_payroll_management_wizard__write_uid +msgid "Last Updated by" +msgstr "Darrera actualització per" + +#. module: hr_payroll_document +#: model:ir.model.fields,field_description:hr_payroll_document.field_ir_attachment_payroll_custom__write_date +#: model:ir.model.fields,field_description:hr_payroll_document.field_payroll_management_wizard__write_date +msgid "Last Updated on" +msgstr "Darrera actualització el" + +#. module: hr_payroll_document +#. odoo-python +#: code:addons/hr_payroll_document/wizard/payroll_management_wizard.py:0 +#, python-format +msgid "Missing pdf file signature" +msgstr "Els fitxers han de ser de tipus pdf" + +#. module: hr_payroll_document +#. odoo-python +#: code:addons/hr_payroll_document/wizard/payroll_management_wizard.py:0 +#: model:ir.model.fields.selection,name:hr_payroll_document.selection__ir_attachment__document_type__payroll +#: model_terms:ir.ui.view,arch_db:hr_payroll_document.res_users_view_form_profile_inherit +#, python-format +msgid "Payroll" +msgstr "Nòmina" + +#. module: hr_payroll_document +#. odoo-python +#: code:addons/hr_payroll_document/wizard/payroll_management_wizard.py:0 +#, python-format +msgid "Payroll " +msgstr "Nòmina " + +#. module: hr_payroll_document +#: model:ir.model.fields,field_description:hr_payroll_document.field_hr_employee__payroll_count +msgid "Payroll Count" +msgstr "" + +#. module: hr_payroll_document +#: model:mail.template,name:hr_payroll_document.payroll_employee_email_template +msgid "Payroll Employee" +msgstr "Nòmina Empleat" + +#. module: hr_payroll_document +#: model:ir.model,name:hr_payroll_document.model_payroll_management_wizard +msgid "Payroll Management" +msgstr "Gestió Nòmines" + +#. module: hr_payroll_document +#: model:ir.model,name:hr_payroll_document.model_ir_attachment_payroll_custom +msgid "Payroll attachment" +msgstr "Adjunt Nòmina" + +#. module: hr_payroll_document +#: model:mail.template,subject:hr_payroll_document.payroll_employee_email_template +msgid "Payroll {{ctx.get('subject')}}" +msgstr "Nòmina {{ctx.get('month')}}" + +#. module: hr_payroll_document +#: model:ir.actions.act_window,name:hr_payroll_document.payrolls_view_action +#: model:ir.model.fields,field_description:hr_payroll_document.field_payroll_management_wizard__payrolls +#: model:ir.ui.menu,name:hr_payroll_document.payrolls_menu_action +#: model_terms:ir.ui.view,arch_db:hr_payroll_document.hr_employee_view_tree_payroll +#: model_terms:ir.ui.view,arch_db:hr_payroll_document.res_users_view_form_profile_inherit +#: model_terms:ir.ui.view,arch_db:hr_payroll_document.view_payroll_filter +msgid "Payrolls" +msgstr "Nòmines" + +#. module: hr_payroll_document +#: model:ir.actions.act_window,name:hr_payroll_document.payrolls_management_wizard_action +#: model:ir.ui.menu,name:hr_payroll_document.payrolls_management_wizard_menu_action +msgid "Payrolls Management" +msgstr "Gestió Nòmines" + +#. module: hr_payroll_document +#. odoo-python +#: code:addons/hr_payroll_document/tests/test_hr_payroll_document.py:0 +#: code:addons/hr_payroll_document/wizard/payroll_management_wizard.py:0 +#, python-format +msgid "Payrolls sent" +msgstr "Nòmines enviades" + +#. module: hr_payroll_document +#. odoo-python +#: code:addons/hr_payroll_document/tests/test_hr_payroll_document.py:0 +#: code:addons/hr_payroll_document/wizard/payroll_management_wizard.py:0 +#, python-format +msgid "Payrolls sent to employees correctly" +msgstr "Nòmines envides als empleats correctament" + +#. module: hr_payroll_document +#: model_terms:ir.ui.view,arch_db:hr_payroll_document.payrolls_management_wizard_form +msgid "Send" +msgstr "Enviar" + +#. module: hr_payroll_document +#: model:ir.model.fields,field_description:hr_payroll_document.field_ir_attachment_payroll_custom__subject +#: model:ir.model.fields,field_description:hr_payroll_document.field_payroll_management_wizard__subject +#: model_terms:ir.ui.view,arch_db:hr_payroll_document.view_payroll_filter +msgid "Subject" +msgstr "Assumpte" + +#. module: hr_payroll_document +#. odoo-python +#: code:addons/hr_payroll_document/models/hr_employee.py:0 +#, python-format +msgid "The field identification ID is not valid" +msgstr "El camp identificatiu ID no és vàlid" + +#. module: hr_payroll_document +#: model:ir.model,name:hr_payroll_document.model_res_users +msgid "User" +msgstr "" + +#. module: hr_payroll_document +#. odoo-python +#: code:addons/hr_payroll_document/wizard/payroll_management_wizard.py:0 +#, python-format +msgid "You must to filled country field of company" +msgstr "Falta emplenar el camp de país de l'empresa" + +#~ msgid "Last Modified on" +#~ msgstr "Darrera modificació el" diff --git a/hr_payroll_document/i18n/es.po b/hr_payroll_document/i18n/es.po new file mode 100644 index 000000000..081279528 --- /dev/null +++ b/hr_payroll_document/i18n/es.po @@ -0,0 +1,334 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * hr_payroll_document +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 17.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-05-21 15:13+0000\n" +"PO-Revision-Date: 2024-05-21 15:13+0000\n" +"Last-Translator: \n" +"Language-Team: \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: hr_payroll_document +#: model:mail.template,body_html:hr_payroll_document.payroll_employee_email_template +msgid "" +"\n" +" \n" +" \n" +" \n" +"
\"{{object.company_id.name}}\"

Payroll

Hello ,

We send you the payroll with the subject .



\"{{object.company_id.name}}\"

Nòmina

Hola ,


Et remetem " +"la teva nòmina del mes de .



\n" +"

\n" +" \n" +" \n" +" " + +#. module: hr_payroll_document +#: model:ir.model,name:hr_payroll_document.model_ir_attachment +#: model:ir.model.fields,field_description:hr_payroll_document.field_ir_attachment__payrol_rel +#: model:ir.model.fields,field_description:hr_payroll_document.field_product_document__payrol_rel +msgid "Attachment" +msgstr "Archivo adjunto" + +#. module: hr_payroll_document +#: model:ir.model.fields,field_description:hr_payroll_document.field_ir_attachment_payroll_custom__attachment_id +msgid "Attachment File" +msgstr "Fichero Adjunto" + +#. module: hr_payroll_document +#: model_terms:ir.ui.view,arch_db:hr_payroll_document.payrolls_management_wizard_form +msgid "Close" +msgstr "Cerrar" + +#. module: hr_payroll_document +#: model:ir.model.fields,field_description:hr_payroll_document.field_ir_attachment_payroll_custom__create_date +msgid "Create Date" +msgstr "Fecha de creación" + +#. module: hr_payroll_document +#: model:ir.model.fields,field_description:hr_payroll_document.field_ir_attachment_payroll_custom__create_uid +#: model:ir.model.fields,field_description:hr_payroll_document.field_payroll_management_wizard__create_uid +msgid "Created by" +msgstr "Creado por" + +#. module: hr_payroll_document +#: model:ir.model.fields,field_description:hr_payroll_document.field_payroll_management_wizard__create_date +msgid "Created on" +msgstr "Creado el" + +#. module: hr_payroll_document +#: model_terms:ir.ui.view,arch_db:hr_payroll_document.res_users_view_form_profile_inherit +#: model_terms:ir.ui.view,arch_db:hr_payroll_document.view_employee_form +msgid "Disable encryption" +msgstr "" + +#. module: hr_payroll_document +#: model:ir.model.fields,field_description:hr_payroll_document.field_hr_employee__no_payroll_encryption +#: model:ir.model.fields,field_description:hr_payroll_document.field_res_users__no_payroll_encryption +msgid "Disable payrolls encryption" +msgstr "" + +#. module: hr_payroll_document +#: model:ir.model.fields,field_description:hr_payroll_document.field_ir_attachment_payroll_custom__display_name +#: model:ir.model.fields,field_description:hr_payroll_document.field_payroll_management_wizard__display_name +msgid "Display Name" +msgstr "Nombre para mostrar" + +#. module: hr_payroll_document +#: model:ir.model.fields,field_description:hr_payroll_document.field_ir_attachment__document_type +#: model:ir.model.fields,field_description:hr_payroll_document.field_product_document__document_type +msgid "Document Type" +msgstr "Tipo de documento" + +#. module: hr_payroll_document +#: model_terms:ir.ui.view,arch_db:hr_payroll_document.view_payroll_tree +msgid "Download" +msgstr "Descargar" + +#. module: hr_payroll_document +#: model:ir.model,name:hr_payroll_document.model_hr_employee +#: model:ir.model.fields,field_description:hr_payroll_document.field_ir_attachment_payroll_custom__employee +#: model_terms:ir.ui.view,arch_db:hr_payroll_document.view_payroll_filter +msgid "Employee" +msgstr "Empleado" + +#. module: hr_payroll_document +#. odoo-python +#: code:addons/hr_payroll_document/tests/test_hr_payroll_document.py:0 +#: code:addons/hr_payroll_document/wizard/payroll_management_wizard.py:0 +#, python-format +msgid "Employees not found" +msgstr "Empleados no encontrados" + +#. module: hr_payroll_document +#: model:ir.model.fields,help:hr_payroll_document.field_payroll_management_wizard__subject +msgid "Enter the title of the payroll whether it is the month, week, day, etc." +msgstr "Introduzca el título de la nómina ya sea el mes, semana, día , etc.." + +#. module: hr_payroll_document +#: model_terms:ir.ui.view,arch_db:hr_payroll_document.view_payroll_filter +msgid "Group By" +msgstr "" + +#. module: hr_payroll_document +#: model:ir.model.fields,field_description:hr_payroll_document.field_ir_attachment_payroll_custom__id +#: model:ir.model.fields,field_description:hr_payroll_document.field_payroll_management_wizard__id +msgid "ID" +msgstr "" + +#. module: hr_payroll_document +#. odoo-python +#: code:addons/hr_payroll_document/tests/test_hr_payroll_document.py:0 +#: code:addons/hr_payroll_document/wizard/payroll_management_wizard.py:0 +#, python-format +msgid "IDs whose employee has not been found: " +msgstr "IDs de los empleados que no se han encontrado: " + +#. module: hr_payroll_document +#: model:ir.model.fields,field_description:hr_payroll_document.field_ir_attachment_payroll_custom__identification_id +#: model_terms:ir.ui.view,arch_db:hr_payroll_document.view_payroll_filter +msgid "Identification ID" +msgstr "Identificación ID" + +#. module: hr_payroll_document +#: model:ir.model.fields,help:hr_payroll_document.field_hr_employee__no_payroll_encryption +#: model:ir.model.fields,help:hr_payroll_document.field_res_users__no_payroll_encryption +msgid "" +"If this is disabled (default), the PDF payrolls are encrypted using the " +"Identification No.\n" +"Only future payrolls are affected by this change, existing payrolls will not " +"change their encryption status." +msgstr "" + +#. module: hr_payroll_document +#: model:ir.model.fields,field_description:hr_payroll_document.field_ir_attachment_payroll_custom__write_uid +#: model:ir.model.fields,field_description:hr_payroll_document.field_payroll_management_wizard__write_uid +msgid "Last Updated by" +msgstr "Última actualización por" + +#. module: hr_payroll_document +#: model:ir.model.fields,field_description:hr_payroll_document.field_ir_attachment_payroll_custom__write_date +#: model:ir.model.fields,field_description:hr_payroll_document.field_payroll_management_wizard__write_date +msgid "Last Updated on" +msgstr "Última actualización el" + +#. module: hr_payroll_document +#. odoo-python +#: code:addons/hr_payroll_document/wizard/payroll_management_wizard.py:0 +#, python-format +msgid "Missing pdf file signature" +msgstr "Los archivos tienen que ser de tipo pdf" + +#. module: hr_payroll_document +#. odoo-python +#: code:addons/hr_payroll_document/wizard/payroll_management_wizard.py:0 +#: model:ir.model.fields.selection,name:hr_payroll_document.selection__ir_attachment__document_type__payroll +#: model_terms:ir.ui.view,arch_db:hr_payroll_document.res_users_view_form_profile_inherit +#, python-format +msgid "Payroll" +msgstr "Nómina" + +#. module: hr_payroll_document +#. odoo-python +#: code:addons/hr_payroll_document/wizard/payroll_management_wizard.py:0 +#, python-format +msgid "Payroll " +msgstr "Nómina " + +#. module: hr_payroll_document +#: model:ir.model.fields,field_description:hr_payroll_document.field_hr_employee__payroll_count +msgid "Payroll Count" +msgstr "Recuento de Nóminas" + +#. module: hr_payroll_document +#: model:mail.template,name:hr_payroll_document.payroll_employee_email_template +msgid "Payroll Employee" +msgstr "Nómina Empleado" + +#. module: hr_payroll_document +#: model:ir.model,name:hr_payroll_document.model_payroll_management_wizard +msgid "Payroll Management" +msgstr "Gestión Nóminas" + +#. module: hr_payroll_document +#: model:ir.model,name:hr_payroll_document.model_ir_attachment_payroll_custom +msgid "Payroll attachment" +msgstr "Adjunto Nómina" + +#. module: hr_payroll_document +#: model:mail.template,subject:hr_payroll_document.payroll_employee_email_template +msgid "Payroll {{ctx.get('subject')}}" +msgstr "Nómina {{ctx.get('subject')}}" + +#. module: hr_payroll_document +#: model:ir.actions.act_window,name:hr_payroll_document.payrolls_view_action +#: model:ir.model.fields,field_description:hr_payroll_document.field_payroll_management_wizard__payrolls +#: model:ir.ui.menu,name:hr_payroll_document.payrolls_menu_action +#: model_terms:ir.ui.view,arch_db:hr_payroll_document.hr_employee_view_tree_payroll +#: model_terms:ir.ui.view,arch_db:hr_payroll_document.res_users_view_form_profile_inherit +#: model_terms:ir.ui.view,arch_db:hr_payroll_document.view_payroll_filter +msgid "Payrolls" +msgstr "Nóminas" + +#. module: hr_payroll_document +#: model:ir.actions.act_window,name:hr_payroll_document.payrolls_management_wizard_action +#: model:ir.ui.menu,name:hr_payroll_document.payrolls_management_wizard_menu_action +msgid "Payrolls Management" +msgstr "Gestión Nóminas" + +#. module: hr_payroll_document +#. odoo-python +#: code:addons/hr_payroll_document/tests/test_hr_payroll_document.py:0 +#: code:addons/hr_payroll_document/wizard/payroll_management_wizard.py:0 +#, python-format +msgid "Payrolls sent" +msgstr "Nóminas enviadas" + +#. module: hr_payroll_document +#. odoo-python +#: code:addons/hr_payroll_document/tests/test_hr_payroll_document.py:0 +#: code:addons/hr_payroll_document/wizard/payroll_management_wizard.py:0 +#, python-format +msgid "Payrolls sent to employees correctly" +msgstr "Nóminas enviadas a los empleados correctamente" + +#. module: hr_payroll_document +#: model_terms:ir.ui.view,arch_db:hr_payroll_document.payrolls_management_wizard_form +msgid "Send" +msgstr "Enviar" + +#. module: hr_payroll_document +#: model:ir.model.fields,field_description:hr_payroll_document.field_ir_attachment_payroll_custom__subject +#: model:ir.model.fields,field_description:hr_payroll_document.field_payroll_management_wizard__subject +#: model_terms:ir.ui.view,arch_db:hr_payroll_document.view_payroll_filter +msgid "Subject" +msgstr "Asunto" + +#. module: hr_payroll_document +#. odoo-python +#: code:addons/hr_payroll_document/models/hr_employee.py:0 +#, python-format +msgid "The field identification ID is not valid" +msgstr "El campo identificativo ID no es válido" + +#. module: hr_payroll_document +#: model:ir.model,name:hr_payroll_document.model_res_users +msgid "User" +msgstr "Usuario" + +#. module: hr_payroll_document +#. odoo-python +#: code:addons/hr_payroll_document/wizard/payroll_management_wizard.py:0 +#, python-format +msgid "You must to filled country field of company" +msgstr "Falta rellenar el campo del país de la empresa" diff --git a/hr_payroll_document/i18n/hr_payroll_document.pot b/hr_payroll_document/i18n/hr_payroll_document.pot new file mode 100644 index 000000000..0d31fc745 --- /dev/null +++ b/hr_payroll_document/i18n/hr_payroll_document.pot @@ -0,0 +1,256 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * hr_payroll_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: hr_payroll_document +#: model:mail.template,body_html:hr_payroll_document.payroll_employee_email_template +msgid "" +"\n" +" \n" +" \n" +"
\"{{object.company_id.name}}\"

Payroll

Hello ,

We send you the payroll with the subject .



\"{{object.company_id.name}}\"

Nómina

Hola ,


Te enviamos " +"la nómina con el asunto .



\"{{object.company_id.name}}\"/

Payroll

Hello ,


We send you the payroll with the subject .



\n" +"

\n" +" " +msgstr "" + +#. module: hr_payroll_document +#: model:ir.model,name:hr_payroll_document.model_ir_attachment +#: model:ir.model.fields,field_description:hr_payroll_document.field_ir_attachment__payrol_rel +#: model:ir.model.fields,field_description:hr_payroll_document.field_product_document__payrol_rel +msgid "Attachment" +msgstr "" + +#. module: hr_payroll_document +#: model:ir.model.fields,field_description:hr_payroll_document.field_ir_attachment_payroll_custom__attachment_id +msgid "Attachment File" +msgstr "" + +#. module: hr_payroll_document +#: model_terms:ir.ui.view,arch_db:hr_payroll_document.payrolls_management_wizard_form +msgid "Close" +msgstr "" + +#. module: hr_payroll_document +#: model:ir.model.fields,field_description:hr_payroll_document.field_ir_attachment_payroll_custom__create_date +msgid "Create Date" +msgstr "" + +#. module: hr_payroll_document +#: model:ir.model.fields,field_description:hr_payroll_document.field_ir_attachment_payroll_custom__create_uid +#: model:ir.model.fields,field_description:hr_payroll_document.field_payroll_management_wizard__create_uid +msgid "Created by" +msgstr "" + +#. module: hr_payroll_document +#: model:ir.model.fields,field_description:hr_payroll_document.field_payroll_management_wizard__create_date +msgid "Created on" +msgstr "" + +#. module: hr_payroll_document +#: model_terms:ir.ui.view,arch_db:hr_payroll_document.res_users_view_form_profile_inherit +#: model_terms:ir.ui.view,arch_db:hr_payroll_document.view_employee_form +msgid "Disable encryption" +msgstr "" + +#. module: hr_payroll_document +#: model:ir.model.fields,field_description:hr_payroll_document.field_hr_employee__no_payroll_encryption +#: model:ir.model.fields,field_description:hr_payroll_document.field_res_users__no_payroll_encryption +msgid "Disable payrolls encryption" +msgstr "" + +#. module: hr_payroll_document +#: model:ir.model.fields,field_description:hr_payroll_document.field_ir_attachment_payroll_custom__display_name +#: model:ir.model.fields,field_description:hr_payroll_document.field_payroll_management_wizard__display_name +msgid "Display Name" +msgstr "" + +#. module: hr_payroll_document +#: model:ir.model.fields,field_description:hr_payroll_document.field_ir_attachment__document_type +#: model:ir.model.fields,field_description:hr_payroll_document.field_product_document__document_type +msgid "Document Type" +msgstr "" + +#. module: hr_payroll_document +#: model_terms:ir.ui.view,arch_db:hr_payroll_document.view_payroll_tree +msgid "Download" +msgstr "" + +#. module: hr_payroll_document +#: model:ir.model,name:hr_payroll_document.model_hr_employee +#: model:ir.model.fields,field_description:hr_payroll_document.field_ir_attachment_payroll_custom__employee +#: model_terms:ir.ui.view,arch_db:hr_payroll_document.view_payroll_filter +msgid "Employee" +msgstr "" + +#. module: hr_payroll_document +#. odoo-python +#: code:addons/hr_payroll_document/tests/test_hr_payroll_document.py:0 +#: code:addons/hr_payroll_document/wizard/payroll_management_wizard.py:0 +msgid "Employees not found" +msgstr "" + +#. module: hr_payroll_document +#: model:ir.model.fields,help:hr_payroll_document.field_payroll_management_wizard__subject +msgid "" +"Enter the title of the payroll whether it is the month, week, day, etc." +msgstr "" + +#. module: hr_payroll_document +#: model_terms:ir.ui.view,arch_db:hr_payroll_document.view_payroll_filter +msgid "Group By" +msgstr "" + +#. module: hr_payroll_document +#: model:ir.model.fields,field_description:hr_payroll_document.field_ir_attachment_payroll_custom__id +#: model:ir.model.fields,field_description:hr_payroll_document.field_payroll_management_wizard__id +msgid "ID" +msgstr "" + +#. module: hr_payroll_document +#. odoo-python +#: code:addons/hr_payroll_document/tests/test_hr_payroll_document.py:0 +#: code:addons/hr_payroll_document/wizard/payroll_management_wizard.py:0 +msgid "IDs whose employee has not been found: " +msgstr "" + +#. module: hr_payroll_document +#: model:ir.model.fields,field_description:hr_payroll_document.field_ir_attachment_payroll_custom__identification_id +#: model_terms:ir.ui.view,arch_db:hr_payroll_document.view_payroll_filter +msgid "Identification ID" +msgstr "" + +#. module: hr_payroll_document +#: model:ir.model.fields,help:hr_payroll_document.field_hr_employee__no_payroll_encryption +#: model:ir.model.fields,help:hr_payroll_document.field_res_users__no_payroll_encryption +msgid "" +"If this is disabled (default), the PDF payrolls are encrypted using the Identification No.\n" +"Only future payrolls are affected by this change, existing payrolls will not change their encryption status." +msgstr "" + +#. module: hr_payroll_document +#: model:ir.model.fields,field_description:hr_payroll_document.field_ir_attachment_payroll_custom__write_uid +#: model:ir.model.fields,field_description:hr_payroll_document.field_payroll_management_wizard__write_uid +msgid "Last Updated by" +msgstr "" + +#. module: hr_payroll_document +#: model:ir.model.fields,field_description:hr_payroll_document.field_ir_attachment_payroll_custom__write_date +#: model:ir.model.fields,field_description:hr_payroll_document.field_payroll_management_wizard__write_date +msgid "Last Updated on" +msgstr "" + +#. module: hr_payroll_document +#. odoo-python +#: code:addons/hr_payroll_document/wizard/payroll_management_wizard.py:0 +msgid "Missing pdf file signature" +msgstr "" + +#. module: hr_payroll_document +#. odoo-python +#: code:addons/hr_payroll_document/wizard/payroll_management_wizard.py:0 +#: model:ir.model.fields.selection,name:hr_payroll_document.selection__ir_attachment__document_type__payroll +#: model_terms:ir.ui.view,arch_db:hr_payroll_document.res_users_view_form_profile_inherit +#: model_terms:ir.ui.view,arch_db:hr_payroll_document.view_employee_form +msgid "Payroll" +msgstr "" + +#. module: hr_payroll_document +#. odoo-python +#: code:addons/hr_payroll_document/wizard/payroll_management_wizard.py:0 +msgid "Payroll " +msgstr "" + +#. module: hr_payroll_document +#: model:ir.model.fields,field_description:hr_payroll_document.field_hr_employee__payroll_count +msgid "Payroll Count" +msgstr "" + +#. module: hr_payroll_document +#: model:mail.template,name:hr_payroll_document.payroll_employee_email_template +msgid "Payroll Employee" +msgstr "" + +#. module: hr_payroll_document +#: model:ir.model,name:hr_payroll_document.model_payroll_management_wizard +msgid "Payroll Management" +msgstr "" + +#. module: hr_payroll_document +#: model:ir.model,name:hr_payroll_document.model_ir_attachment_payroll_custom +msgid "Payroll attachment" +msgstr "" + +#. module: hr_payroll_document +#: model:mail.template,subject:hr_payroll_document.payroll_employee_email_template +msgid "Payroll {{ctx.get('subject')}}" +msgstr "" + +#. module: hr_payroll_document +#: model:ir.actions.act_window,name:hr_payroll_document.payrolls_view_action +#: model:ir.model.fields,field_description:hr_payroll_document.field_payroll_management_wizard__payrolls +#: model:ir.ui.menu,name:hr_payroll_document.payrolls_menu_action +#: model_terms:ir.ui.view,arch_db:hr_payroll_document.hr_employee_view_tree_payroll +#: model_terms:ir.ui.view,arch_db:hr_payroll_document.res_users_view_form_profile_inherit +#: model_terms:ir.ui.view,arch_db:hr_payroll_document.view_payroll_filter +msgid "Payrolls" +msgstr "" + +#. module: hr_payroll_document +#: model:ir.actions.act_window,name:hr_payroll_document.payrolls_management_wizard_action +#: model:ir.ui.menu,name:hr_payroll_document.payrolls_management_wizard_menu_action +msgid "Payrolls Management" +msgstr "" + +#. module: hr_payroll_document +#. odoo-python +#: code:addons/hr_payroll_document/tests/test_hr_payroll_document.py:0 +#: code:addons/hr_payroll_document/wizard/payroll_management_wizard.py:0 +msgid "Payrolls sent" +msgstr "" + +#. module: hr_payroll_document +#. odoo-python +#: code:addons/hr_payroll_document/tests/test_hr_payroll_document.py:0 +#: code:addons/hr_payroll_document/wizard/payroll_management_wizard.py:0 +msgid "Payrolls sent to employees correctly" +msgstr "" + +#. module: hr_payroll_document +#: model_terms:ir.ui.view,arch_db:hr_payroll_document.payrolls_management_wizard_form +msgid "Send" +msgstr "" + +#. module: hr_payroll_document +#: model:ir.model.fields,field_description:hr_payroll_document.field_ir_attachment_payroll_custom__subject +#: model:ir.model.fields,field_description:hr_payroll_document.field_payroll_management_wizard__subject +#: model_terms:ir.ui.view,arch_db:hr_payroll_document.view_payroll_filter +msgid "Subject" +msgstr "" + +#. module: hr_payroll_document +#. odoo-python +#: code:addons/hr_payroll_document/models/hr_employee.py:0 +msgid "The field identification ID is not valid" +msgstr "" + +#. module: hr_payroll_document +#: model:ir.model,name:hr_payroll_document.model_res_users +msgid "User" +msgstr "" + +#. module: hr_payroll_document +#. odoo-python +#: code:addons/hr_payroll_document/wizard/payroll_management_wizard.py:0 +msgid "You must to filled country field of company" +msgstr "" diff --git a/hr_payroll_document/i18n/it.po b/hr_payroll_document/i18n/it.po new file mode 100644 index 000000000..0ede2190c --- /dev/null +++ b/hr_payroll_document/i18n/it.po @@ -0,0 +1,343 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * hr_payroll_document +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2026-01-05 20: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: hr_payroll_document +#: model:mail.template,body_html:hr_payroll_document.payroll_employee_email_template +msgid "" +"\n" +" \n" +" \n" +" \n" +" +

Beta License: AGPL-3 OCA/payroll Translate me on Weblate Try me on Runboat

+

This module have a wizard view to manage the different payrolls of +employees which is identified by the identification_id attribute.

+

By default, the employee’s payroll is encrypted using their +identification number. This behavior can be changed by the employee in +their profile or by HR in the employee’s form.

+

Table of contents

+ +
+

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

+
    +
  • APSL
  • +
+
+
+

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:

+

peluko00

+

This module is part of the OCA/payroll project on GitHub.

+

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

+
+
+ + + + diff --git a/hr_payroll_document/tests/__init__.py b/hr_payroll_document/tests/__init__.py new file mode 100644 index 000000000..75f544418 --- /dev/null +++ b/hr_payroll_document/tests/__init__.py @@ -0,0 +1 @@ +from . import test_hr_payroll_document diff --git a/hr_payroll_document/tests/common.py b/hr_payroll_document/tests/common.py new file mode 100644 index 000000000..58dfd15fd --- /dev/null +++ b/hr_payroll_document/tests/common.py @@ -0,0 +1,80 @@ +# Part of Odoo. See LICENSE file for full copyright and licensing details. +import base64 +import contextlib +import logging +from unittest import mock + +from odoo.tests import common +from odoo.tools.misc import file_path + +from odoo.addons.mail.tests.common import mail_new_test_user + +_logger = logging.getLogger(__name__) + + +class TestHrPayrollDocument(common.TransactionCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.env.user.tz = "Europe/Brussels" + cls.user_admin = cls.env.ref("base.user_admin") + + # Fix Company without country + cls.env.company.country_id = False + + # Test users to use through the various tests + cls.user_employee = mail_new_test_user( + cls.env, login="david", groups="base.group_user" + ) + cls.user_employee_id = cls.user_employee.id + + # Hr Data + cls.employee_emp = cls.env["hr.employee"].create( + { + "name": "David Employee", + "user_id": cls.user_employee_id, + "company_id": 1, + "identification_id": "30831011V", + } + ) + + cls.wizard = cls._create_wizard("January", "hr_payroll_document/tests/test.pdf") + + @classmethod + def _create_wizard(cls, subject, original_file_path): + with open(file_path(original_file_path), "rb") as pdf_file: + encoded_string = base64.b64encode(pdf_file.read()) + ir_values = { + "name": "test", + "type": "binary", + "datas": encoded_string, + "store_fname": encoded_string, + "res_model": "payroll.management.wizard", + "res_id": 1, + } + cls.attachment = cls.env["ir.attachment"].create(ir_values) + cls.subject = subject + return cls.env["payroll.management.wizard"].create( + {"payrolls": [cls.attachment.id], "subject": cls.subject} + ) + + @contextlib.contextmanager + def _mock_valid_identification(self, employee, identification_code): + def _mocked_validate_payroll_identification(self, code=None): + if code is None: + code = employee.identification_id + return code == identification_code + + with mock.patch.object( + type(employee), + "_validate_payroll_identification", + _mocked_validate_payroll_identification, + ) as patch: + patch.side_effect = _mocked_validate_payroll_identification + yield + + def fill_company_id(self): + self.env.company.country_id = self.env["res.country"].search( + [("name", "=", "Spain")] + ) + _logger.info(f"{self.env.company.country_id.code}") diff --git a/hr_payroll_document/tests/test.docx b/hr_payroll_document/tests/test.docx new file mode 100644 index 000000000..8a2af5ab5 Binary files /dev/null and b/hr_payroll_document/tests/test.docx differ diff --git a/hr_payroll_document/tests/test.pdf b/hr_payroll_document/tests/test.pdf new file mode 100644 index 000000000..8138280c2 Binary files /dev/null and b/hr_payroll_document/tests/test.pdf differ diff --git a/hr_payroll_document/tests/test_hr_payroll_document.py b/hr_payroll_document/tests/test_hr_payroll_document.py new file mode 100644 index 000000000..168ce4766 --- /dev/null +++ b/hr_payroll_document/tests/test_hr_payroll_document.py @@ -0,0 +1,115 @@ +import base64 +import io + +import pypdf + +from odoo.exceptions import UserError, ValidationError + +from odoo.addons.hr_payroll_document.tests.common import TestHrPayrollDocument + + +class TestHRPayrollDocument(TestHrPayrollDocument): + def test_extension_error(self): + self.wizard = self._create_wizard( + "January", "hr_payroll_document/tests/test.docx" + ) + with self.assertRaises(ValidationError): + self.wizard.send_payrolls() + + def test_company_id_required(self): + with self.assertRaises(UserError): + self.wizard.send_payrolls() + + def test_employee_vat_not_valid(self): + self.fill_company_id() + with self.assertRaises(ValidationError): + employees = self.env["hr.employee"].search([]) + for employee in employees: + if not employee.identification_id: + employee.identification_id = "XXXXXXX" + + def test_one_employee_not_found(self): + self.fill_company_id() + self.env["hr.employee"].search([("id", "=", 1)]).identification_id = "37936636E" + self.assertEqual( + self.wizard.send_payrolls()["params"]["title"], + self.env._("Employees not found"), + ) + self.assertEqual( + self.wizard.send_payrolls()["params"]["message"], + self.env._("IDs whose employee has not been found: ") + "51000278D", + ) + + def test_send_payrolls_correctly(self): + self.fill_company_id() + self.env["hr.employee"].search([("id", "=", 1)]).identification_id = "51000278D" + self.assertEqual( + self.wizard.send_payrolls()["params"]["title"], self.env._("Payrolls sent") + ) + self.assertEqual( + self.wizard.send_payrolls()["params"]["message"], + self.env._("Payrolls sent to employees correctly"), + ) + + def test_optional_encryption(self): + """The employee's payroll can be not encrypted.""" + # Arrange + self.fill_company_id() + employee = self.employee_emp + employee.update( + { + "identification_id": "51000278D", + "no_payroll_encryption": True, + } + ) + # pre-condition + self.assertTrue(employee.no_payroll_encryption) + + # Act + self.wizard.send_payrolls() + + # Assert + payroll = ( + self.env["ir.attachment.payroll.custom"] + .search( + [ + ("identification_id", "=", employee.identification_id), + ] + ) + .attachment_id + ) + self.assertTrue(payroll) + payroll_content = base64.b64decode(payroll.datas) + payroll_pdf = pypdf.PdfReader(io.BytesIO(payroll_content)) + self.assertFalse(payroll_pdf.is_encrypted) + + def test_attachment_name_has_pdf_extension(self): + """Payroll attachments must be sent with a .pdf extension.""" + # Arrange + self.fill_company_id() + employee = self.employee_emp + employee.identification_id = "51000278D" + + # Act + self.wizard.send_payrolls() + + # Assert + payroll = ( + self.env["ir.attachment.payroll.custom"] + .search([("identification_id", "=", employee.identification_id)]) + .attachment_id + ) + self.assertTrue(payroll.name.endswith(".pdf")) + + def test_optional_encryption_fetch(self): + """If the user can't access the employees, + the optional encryption field is not fetched.""" + # Arrange + employee = self.employee_emp + employee_with_self = employee.with_user(employee.user_id) + # pre-condition + self.assertFalse(employee_with_self.has_access("read")) + + # Assert: reading a field triggers fetching all the accessible fields + employee_with_self.invalidate_recordset() + self.assertTrue(employee_with_self.user_id) diff --git a/hr_payroll_document/views/hr_employee_views.xml b/hr_payroll_document/views/hr_employee_views.xml new file mode 100644 index 000000000..070a1c43d --- /dev/null +++ b/hr_payroll_document/views/hr_employee_views.xml @@ -0,0 +1,124 @@ + + + + + payroll.view.list + ir.attachment.payroll.custom + + + + + + + + + + + + + hr.res_user.view.form.inherit.document + res.users + + + +
+ +
+
+ + + +
+
+ + + hr.employee.form + hr.employee + + + + + + + + + +
diff --git a/hr_payroll_document/wizard/__init__.py b/hr_payroll_document/wizard/__init__.py new file mode 100644 index 000000000..72e4cc533 --- /dev/null +++ b/hr_payroll_document/wizard/__init__.py @@ -0,0 +1 @@ +from . import payroll_management_wizard diff --git a/hr_payroll_document/wizard/payroll_management_wizard.py b/hr_payroll_document/wizard/payroll_management_wizard.py new file mode 100644 index 000000000..c977f3063 --- /dev/null +++ b/hr_payroll_document/wizard/payroll_management_wizard.py @@ -0,0 +1,220 @@ +import base64 +from base64 import b64decode + +from pypdf import PdfReader, PdfWriter, errors + +from odoo import fields, models +from odoo.exceptions import UserError, ValidationError +from odoo.fields import Command + + +class PayrollManagamentWizard(models.TransientModel): + _name = "payroll.management.wizard" + _description = "Payroll Management" + + subject = fields.Char( + help="Enter the title of the payroll whether it is the month, week, day, etc.", + required=True, + ) + payrolls = fields.Many2many( + "ir.attachment", "payrol_rel", "doc_id", "attach_id3", copy=False, required=True + ) + + def _get_fallback_reader(self, pdf_reader): + # Override to use another reader + pass + + def _read_page_content(self, pdf_reader, page, fallback_reader=None): + try: + page_content = page.extract_text().split() + except errors.PdfReadError: + if fallback_reader: + # The original page cannot be read: + # read the simplified page in the fallback_reader + page_number = pdf_reader.get_page_number(page) + fallback_page = fallback_reader.get_page(page_number) + page_content = fallback_page.extract_text().split() + else: + raise + return page_content + + def _extract_employees(self, pdf_reader, fallback_reader=None): + employee_to_pages = dict() + not_found_ids = set() + + # Find all IDs of the employees + for page in pdf_reader.pages: + page_content = self._read_page_content( + pdf_reader, page, fallback_reader=fallback_reader + ) + for value in page_content: + if self.validate_id(value) and value != self.env.company.vat: + employee = self.env["hr.employee"].search( + [("identification_id", "=", value)] + ) + if employee: + employee_to_pages.setdefault(employee, []).append(page) + else: + not_found_ids.add(value) + break + + return employee_to_pages, not_found_ids + + def _build_employee_payroll(self, file_name, pdf_pages, encryption_key=None): + """Return the path to the created payroll. + + Optionally encrypt the payroll file with `encryption_key`. + """ + pdfWriter = PdfWriter() + for page in pdf_pages: + pdfWriter.add_page(page) + + path = "/tmp/" + file_name + + if encryption_key: + pdfWriter.encrypt(encryption_key, algorithm="AES-256") + + with open(path, "wb") as f: + pdfWriter.write(f) + return path + + def _show_employees_action(self): + return { + "name": self.env._("Payrolls sent"), + "type": "ir.actions.act_window", + "res_model": "hr.employee", + "views": [ + (False, "kanban"), + (False, "tree"), + (False, "form"), + (False, "activity"), + ], + } + + def send_payrolls(self): + self.merge_pdfs() + # Validate if company have country + if not self.env.company.country_id: + raise UserError(self.env._("You must to filled country field of company")) + + reader = PdfReader("/tmp/merged-pdf.pdf") + + try: + employee_to_pages, not_found = self._extract_employees(reader) + except errors.PdfReadError: + # Couldn't read the file, try again with another reader + fallback_reader = self._get_fallback_reader(reader) + if fallback_reader: + employee_to_pages, not_found = self._extract_employees( + reader, fallback_reader=fallback_reader + ) + else: + raise + + for employee, pages in employee_to_pages.items(): + encryption_key = ( + None if employee.no_payroll_encryption else employee.identification_id + ) + path = self._build_employee_payroll( + self.env._( + "Payroll %(subject)s %(employee)s.pdf", + employee=employee.name, + subject=self.subject, + ), + pages, + encryption_key=encryption_key, + ) + # Send payroll to the employee + self.send_mail(employee, path) + + next_action = self._show_employees_action() + if not_found: + return { + "type": "ir.actions.client", + "tag": "display_notification", + "params": { + "title": self.env._("Employees not found"), + "message": self.env._("IDs whose employee has not been found: ") + + ", ".join(list(not_found)), + "sticky": True, + "type": "warning", + "next": next_action, + }, + } + + return { + "type": "ir.actions.client", + "tag": "display_notification", + "params": { + "title": self.env._("Payrolls sent"), + "message": self.env._("Payrolls sent to employees correctly"), + "sticky": False, + "type": "success", + "next": next_action, + }, + } + + def merge_pdfs(self): + # Merge the pdfs together + pdfs = [] + for file in self.payrolls: + b64 = file.datas + btes = b64decode(b64, validate=True) + if btes[0:4] != b"%PDF": + raise ValidationError(self.env._("Missing pdf file signature")) + f = open("/tmp/" + file.name, "wb") + f.write(btes) + f.close() + pdfs.append(f.name) + + merger = PdfWriter() + + for pdf in pdfs: + merger.append(pdf) + + merger.write("/tmp/merged-pdf.pdf") + merger.close() + + def send_mail(self, employee, path): + # Open Payrolls of employee and encode content + with open(path, "rb") as pdf_file: + encoded_string = base64.b64encode(pdf_file.read()) + + # Attach file to email + ir_values = { + "name": self.env._("Payroll") + + "_" + + self.subject + + "_" + + employee.name + + ".pdf", + "type": "binary", + "datas": encoded_string, + "store_fname": encoded_string, + "res_model": "hr.employee", + "res_id": employee.id, + "document_type": "payroll", + } + + # Save payroll attachment to all employee payrolls attachments + self.env["ir.attachment.payroll.custom"].create( + { + "attachment_id": self.env["ir.attachment"].create(ir_values).id, + "employee": employee.name, + "subject": self.subject, + "identification_id": employee.identification_id, + } + ) + + # Send mail + mail_template = self.env.ref( + "hr_payroll_document.payroll_employee_email_template" + ) + data_id = [Command.set(self.env["ir.attachment"].create(ir_values).ids)] + mail_template.attachment_ids = data_id + mail_template.with_context(**{"subject": self.subject}).send_mail( + employee.id, force_send=True + ) + + def validate_id(self, code): + return self.env["hr.employee"]._validate_payroll_identification(code=code) diff --git a/hr_payroll_document/wizard/payroll_management_wizard.xml b/hr_payroll_document/wizard/payroll_management_wizard.xml new file mode 100644 index 000000000..29d0b60f5 --- /dev/null +++ b/hr_payroll_document/wizard/payroll_management_wizard.xml @@ -0,0 +1,43 @@ + + + + payroll.management.wizard.form + payroll.management.wizard + +
+ + + + + +
+
+
+ +
+
+ + Payrolls Management + payroll.management.wizard + + form + new + + + +
diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 000000000..1ab56ace6 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +# generated from manifests external_dependencies +pypdf
\"{{object.company_id.name}}\"

Payroll

Hello ,

We send you the payroll with the subject .



\"{{object.company_id.name}}\"

Stipendio

Hello ,

Abbiamo inviato la retribuzione con soggetto.