diff --git a/queue_job_batch/README.rst b/queue_job_batch/README.rst new file mode 100644 index 0000000000..0e312e26e9 --- /dev/null +++ b/queue_job_batch/README.rst @@ -0,0 +1,137 @@ +=============== +Job Queue Batch +=============== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:b6e605728ea05be0bf98dbe6e94c197bab21882e965286ef214f719e252b444e + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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/licence-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%2Fqueue-lightgray.png?logo=github + :target: https://github.com/OCA/queue/tree/17.0/queue_job_batch + :alt: OCA/queue +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/queue-17-0/queue-17-0-queue_job_batch + :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/queue&target_branch=17.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This addon adds an a grouper for queue jobs. + +It allows to show your jobs in a batched form in order to know better +the results. + +Example: + +.. code:: python + + from odoo import models, fields, api + + + class MyModel(models.Model): + _name = 'my.model' + + def my_method(self, a, k=None): + _logger.info('executed with a: %s and k: %s', a, k) + + + class MyOtherModel(models.Model): + _name = 'my.other.model' + + @api.multi + def button_do_stuff(self): + batch = self.env['queue.job.batch'].get_new_batch('Group') + model = self.env['my.model'].with_context(job_batch=batch) + for i in range(1, 100): + model.with_delay().my_method('a', k=i) + +In the snippet of code above, when we call ``button_do_stuff``, 100 jobs +capturing the method and arguments will be postponed. It will be +executed as soon as the Jobrunner has a free bucket, which can be +instantaneous if no other job is running. + +Once all the jobs have finished, the grouper will be marked as finished. + +**Table of contents** + +.. contents:: + :local: + +Usage +===== + +You can manage your batch jobs from the Systray. A new button will be +shown with your currently executing job batches and the recently +finished job groups. + +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 +------- + +* Creu Blanca + +Contributors +------------ + +- Enric Tobella + +- `Trobz `__: + + - Hoang Diep + +- `ForgeFlow `__: + + - Lois Rilo + - Jasmin Solanki + +- `Camptocamp `__: + + - Maksym Yankin + - Iván Todorovich + +Other credits +------------- + +The migration of this module from 12.0 to 14.0 was financially supported +by Camptocamp + +Maintainers +----------- + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +This module is part of the `OCA/queue `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/queue_job_batch/__init__.py b/queue_job_batch/__init__.py new file mode 100644 index 0000000000..91c5580fed --- /dev/null +++ b/queue_job_batch/__init__.py @@ -0,0 +1,2 @@ +from . import controllers +from . import models diff --git a/queue_job_batch/__manifest__.py b/queue_job_batch/__manifest__.py new file mode 100644 index 0000000000..90d701e9dc --- /dev/null +++ b/queue_job_batch/__manifest__.py @@ -0,0 +1,33 @@ +# Copyright 2019 Creu Blanca +# Copyright 2023 ForgeFlow S.L. (http://www.forgeflow.com) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) + +{ + "name": "Job Queue Batch", + "version": "17.0.1.0.0", + "author": "Creu Blanca,Odoo Community Association (OCA)", + "website": "https://github.com/OCA/queue", + "license": "AGPL-3", + "category": "Generic Modules", + "depends": [ + "queue_job", + ], + "data": [ + # data + "data/queue_job_channel_data.xml", + "data/queue_job_function_data.xml", + # security + "security/security.xml", + "security/ir.model.access.csv", + # views + "views/queue_job_views.xml", + "views/queue_job_batch_views.xml", + ], + "assets": { + "web.assets_backend": [ + "queue_job_batch/static/src/**/*.js", + "queue_job_batch/static/src/**/*.xml", + "queue_job_batch/static/src/**/*.scss", + ], + }, +} diff --git a/queue_job_batch/controllers/__init__.py b/queue_job_batch/controllers/__init__.py new file mode 100644 index 0000000000..eb50087f1d --- /dev/null +++ b/queue_job_batch/controllers/__init__.py @@ -0,0 +1 @@ +from . import webclient diff --git a/queue_job_batch/controllers/webclient.py b/queue_job_batch/controllers/webclient.py new file mode 100644 index 0000000000..8967932795 --- /dev/null +++ b/queue_job_batch/controllers/webclient.py @@ -0,0 +1,23 @@ +# Copyright 2025 Camptocamp SA (https://www.camptocamp.com). +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo.http import request + +from odoo.addons.mail.controllers.webclient import WebclientController + + +class WebClient(WebclientController): + def _process_request_for_internal_user(self, store, **kwargs): + res = super()._process_request_for_internal_user(store, **kwargs) + if kwargs.get("systray_get_queue_job_batches"): + # sudo: bus.bus: reading non-sensitive last id + bus_last_id = request.env["bus.bus"].sudo()._bus_last_id() + batches = request.env.user._get_queue_job_batches() + store.add(batches) + store.add( + { + "queueJobBatchCounter": len(batches), + "queueJobBatchCounterBusId": bus_last_id, + } + ) + return res diff --git a/queue_job_batch/data/queue_job_channel_data.xml b/queue_job_batch/data/queue_job_channel_data.xml new file mode 100644 index 0000000000..04dd328c59 --- /dev/null +++ b/queue_job_batch/data/queue_job_channel_data.xml @@ -0,0 +1,6 @@ + + + queue.job.batch + + + diff --git a/queue_job_batch/data/queue_job_function_data.xml b/queue_job_batch/data/queue_job_function_data.xml new file mode 100644 index 0000000000..c9606d4f6d --- /dev/null +++ b/queue_job_batch/data/queue_job_function_data.xml @@ -0,0 +1,7 @@ + + + + + check_state + + diff --git a/queue_job_batch/i18n/es.po b/queue_job_batch/i18n/es.po new file mode 100644 index 0000000000..9e401cdec9 --- /dev/null +++ b/queue_job_batch/i18n/es.po @@ -0,0 +1,379 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * queue_job_batch +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2023-12-01 19:35+0000\n" +"Last-Translator: Ivorra78 \n" +"Language-Team: none\n" +"Language: es\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 4.17\n" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__message_needaction +msgid "Action Needed" +msgstr "Acción Necesaria" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__activity_ids +msgid "Activities" +msgstr "Actividades" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__activity_exception_decoration +msgid "Activity Exception Decoration" +msgstr "Decoración de Actividad de Excepción" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__activity_state +msgid "Activity State" +msgstr "Estado de la Actividad" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__activity_type_icon +msgid "Activity Type Icon" +msgstr "Icono Tipo de Actividad" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__message_attachment_count +msgid "Attachment Count" +msgstr "Recuento de Archivos Adjuntos" + +#. module: queue_job_batch +#: model:ir.model,name:queue_job_batch.model_queue_job_batch +msgid "Batch of jobs" +msgstr "Lote de trabajos" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__company_id +msgid "Company" +msgstr "Companía" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__completeness +#: model_terms:ir.ui.view,arch_db:queue_job_batch.view_queue_job_batch_form +#: model_terms:ir.ui.view,arch_db:queue_job_batch.view_queue_job_batch_tree +msgid "Completeness" +msgstr "Integridad" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__display_name +msgid "Display Name" +msgstr "Mostrar Nombre" + +#. module: queue_job_batch +#: model:ir.model.fields.selection,name:queue_job_batch.selection__queue_job_batch__state__enqueued +msgid "Enqueued" +msgstr "En Cola" + +#. module: queue_job_batch +#. odoo-javascript +#: code:addons/queue_job_batch/static/src/components/QueueJobBatchMenu.esm.js:0 +msgid "Failed" +msgstr "" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__failed_job_count +msgid "Failed Job Count" +msgstr "Recuento de Trabajos Fallidos" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__failed_percentage +msgid "Failed Percentage" +msgstr "Porcentaje Fallado" + +#. module: queue_job_batch +#. odoo-javascript +#: code:addons/queue_job_batch/static/src/components/QueueJobBatchMenu.esm.js:0 +#: model:ir.model.fields.selection,name:queue_job_batch.selection__queue_job_batch__state__finished +#: model_terms:ir.ui.view,arch_db:queue_job_batch.view_queue_job_batch_search +msgid "Finished" +msgstr "Terminado" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__finished_job_count +msgid "Finished Job Count" +msgstr "Recuento de Trabajos Terminados" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__message_follower_ids +msgid "Followers" +msgstr "Seguidores/as" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__message_partner_ids +msgid "Followers (Partners)" +msgstr "Seguidores (socios)" + +#. module: queue_job_batch +#: model:ir.model.fields,help:queue_job_batch.field_queue_job_batch__activity_type_icon +msgid "Font awesome icon e.g. fa-tasks" +msgstr "Icono de fuente impresionante, por ejemplo fa-tasks" + +#. module: queue_job_batch +#: model_terms:ir.ui.view,arch_db:queue_job_batch.view_queue_job_batch_search +msgid "Group By" +msgstr "Grupo por" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__has_message +msgid "Has Message" +msgstr "Tiene Mensaje" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__id +msgid "ID" +msgstr "ID" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__activity_exception_icon +msgid "Icon" +msgstr "Icono" + +#. module: queue_job_batch +#: model:ir.model.fields,help:queue_job_batch.field_queue_job_batch__activity_exception_icon +msgid "Icon to indicate an exception activity." +msgstr "Icono para indicar la excepción de la actividad." + +#. module: queue_job_batch +#: model:ir.model.fields,help:queue_job_batch.field_queue_job_batch__message_needaction +msgid "If checked, new messages require your attention." +msgstr "si está marcada, mensajes nuevos requieren su atención." + +#. module: queue_job_batch +#: model:ir.model.fields,help:queue_job_batch.field_queue_job_batch__message_has_error +#: model:ir.model.fields,help:queue_job_batch.field_queue_job_batch__message_has_sms_error +msgid "If checked, some messages have a delivery error." +msgstr "Si está seleccionado, algunos mensajes tienen un error de entrega." + +#. module: queue_job_batch +#: model:ir.model.fields.selection,name:queue_job_batch.selection__queue_job_batch__state__progress +msgid "In Progress" +msgstr "En Progreso" + +#. module: queue_job_batch +#: model_terms:ir.ui.view,arch_db:queue_job_batch.view_queue_job_batch_search +msgid "In progress" +msgstr "En progreso" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__message_is_follower +msgid "Is Follower" +msgstr "es Seguidor/a" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__is_read +msgid "Is Read" +msgstr "Leído" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__job_ids +msgid "Job" +msgstr "Trabajo" + +#. module: queue_job_batch +#. odoo-javascript +#: code:addons/queue_job_batch/static/src/QueueJobBatchModel.esm.js:0 +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job__job_batch_id +#: model_terms:ir.ui.view,arch_db:queue_job_batch.view_queue_job_batch_form +msgid "Job Batch" +msgstr "Lote de Trabajos" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__job_count +msgid "Job Count" +msgstr "Conteo de Trabajos" + +#. module: queue_job_batch +#: model:res.groups,name:queue_job_batch.group_queue_job_batch_user +msgid "Job Queue Batch User" +msgstr "Usuario de la Cola de Trabajos por Lotes" + +#. module: queue_job_batch +#. odoo-javascript +#: code:addons/queue_job_batch/static/src/components/QueueJobBatchMenu.xml:0 +#: model:ir.actions.act_window,name:queue_job_batch.action_queue_job_batch +#: model:ir.actions.act_window,name:queue_job_batch.action_view_your_queue_job_batch +#: model:ir.ui.menu,name:queue_job_batch.menu_queue_job_batch +msgid "Job batches" +msgstr "Lotes de trabajo" + +#. module: queue_job_batch +#: model_terms:ir.ui.view,arch_db:queue_job_batch.view_queue_job_batch_form +msgid "Jobs" +msgstr "Trabajos" + +#. module: queue_job_batch +#. odoo-javascript +#: code:addons/queue_job_batch/static/src/components/QueueJobBatchMenu.xml:0 +msgid "Mark as Read" +msgstr "Marcar como Leído" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__message_has_error +msgid "Message Delivery error" +msgstr "Error en Entrega de Mensaje" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__message_ids +msgid "Messages" +msgstr "Mensajes" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__my_activity_date_deadline +msgid "My Activity Deadline" +msgstr "Mi fecha límite de la actividad" + +#. module: queue_job_batch +#: model_terms:ir.ui.view,arch_db:queue_job_batch.view_queue_job_batch_search +msgid "My batches" +msgstr "" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__name +msgid "Name" +msgstr "Nombre" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__activity_date_deadline +msgid "Next Activity Deadline" +msgstr "Fecha limite proxima actividad" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__activity_summary +msgid "Next Activity Summary" +msgstr "Resumen de próxima actividad" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__activity_type_id +msgid "Next Activity Type" +msgstr "Tipo de siguiente actividad" + +#. module: queue_job_batch +#. odoo-javascript +#: code:addons/queue_job_batch/static/src/components/QueueJobBatchMenu.xml:0 +msgid "No jobs to view." +msgstr "Sin trabajos a visualizar." + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__message_needaction_counter +msgid "Number of Actions" +msgstr "Número de Acciones" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__message_has_error_counter +msgid "Number of errors" +msgstr "Número de errores" + +#. module: queue_job_batch +#: model:ir.model.fields,help:queue_job_batch.field_queue_job_batch__message_needaction_counter +msgid "Number of messages requiring action" +msgstr "Número de mensajes que requieren una acción" + +#. module: queue_job_batch +#: model:ir.model.fields,help:queue_job_batch.field_queue_job_batch__message_has_error_counter +msgid "Number of messages with delivery error" +msgstr "Número de mensajes con un error de entrega" + +#. module: queue_job_batch +#: model:ir.model.fields.selection,name:queue_job_batch.selection__queue_job_batch__state__pending +#: model_terms:ir.ui.view,arch_db:queue_job_batch.view_queue_job_batch_search +msgid "Pending" +msgstr "" + +#. module: queue_job_batch +#. odoo-javascript +#: code:addons/queue_job_batch/static/src/components/QueueJobBatchMenu.esm.js:0 +msgid "Planned" +msgstr "" + +#. module: queue_job_batch +#: model:ir.model,name:queue_job_batch.model_queue_job +msgid "Queue Job" +msgstr "Cola de Trabajo" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__activity_user_id +msgid "Responsible User" +msgstr "Usuario Responsable" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__message_has_sms_error +msgid "SMS Delivery error" +msgstr "" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__state +#: model_terms:ir.ui.view,arch_db:queue_job_batch.view_queue_job_batch_search +msgid "State" +msgstr "Estado" + +#. module: queue_job_batch +#: model:ir.model.fields,help:queue_job_batch.field_queue_job_batch__activity_state +msgid "" +"Status based on activities\n" +"Overdue: Due date is already passed\n" +"Today: Activity date is today\n" +"Planned: Future activities." +msgstr "" +"Estado basado en actividades\n" +"Atrasado: La fecha ya ha pasado\n" +"Hoy: La actividad es para hoy\n" +"Planeada: Actividades futuras." + +#. module: queue_job_batch +#. odoo-javascript +#: code:addons/queue_job_batch/static/src/components/QueueJobBatchMenu.esm.js:0 +msgid "Total" +msgstr "" + +#. module: queue_job_batch +#: model:ir.model.fields,help:queue_job_batch.field_queue_job_batch__activity_exception_decoration +msgid "Type of the exception activity on record." +msgstr "Tipo de actividad excepcional registrada." + +#. module: queue_job_batch +#: model_terms:ir.ui.view,arch_db:queue_job_batch.view_queue_job_batch_search +msgid "Unread" +msgstr "" + +#. module: queue_job_batch +#: model:ir.model,name:queue_job_batch.model_res_users +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__user_id +#: model_terms:ir.ui.view,arch_db:queue_job_batch.view_queue_job_batch_search +msgid "User" +msgstr "Usuario" + +#. module: queue_job_batch +#. odoo-javascript +#: code:addons/queue_job_batch/static/src/components/QueueJobBatchMenu.xml:0 +msgid "View all job batches" +msgstr "" + +#~ msgid "Draft" +#~ msgstr "Borrador" + +#, python-format +#~ msgid "" +#~ "Job\n" +#~ " Batches" +#~ msgstr "" +#~ "Trabajo\n" +#~ " Lotes" + +#~ msgid "Last Modified on" +#~ msgstr "Última Modificación el" + +#~ msgid "Main Attachment" +#~ msgstr "Archivo adjunto principal" + +#, python-format +#~ msgid "View All" +#~ msgstr "Ver todos" diff --git a/queue_job_batch/i18n/fr.po b/queue_job_batch/i18n/fr.po new file mode 100644 index 0000000000..f3d6a854a5 --- /dev/null +++ b/queue_job_batch/i18n/fr.po @@ -0,0 +1,407 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * queue_job_batch +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2020-11-20 16:54+0000\n" +"Last-Translator: Yann Papouin \n" +"Language-Team: none\n" +"Language: fr\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 3.10\n" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__message_needaction +msgid "Action Needed" +msgstr "Action requise" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__activity_ids +msgid "Activities" +msgstr "Activités" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__activity_exception_decoration +msgid "Activity Exception Decoration" +msgstr "" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__activity_state +msgid "Activity State" +msgstr "Statut de l'activité" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__activity_type_icon +msgid "Activity Type Icon" +msgstr "" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__message_attachment_count +msgid "Attachment Count" +msgstr "Compteur de pièce jointe" + +#. module: queue_job_batch +#: model:ir.model,name:queue_job_batch.model_queue_job_batch +msgid "Batch of jobs" +msgstr "Lot de travaux" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__company_id +msgid "Company" +msgstr "Société" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__completeness +#: model_terms:ir.ui.view,arch_db:queue_job_batch.view_queue_job_batch_form +#: model_terms:ir.ui.view,arch_db:queue_job_batch.view_queue_job_batch_tree +msgid "Completeness" +msgstr "Achèvement" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__display_name +msgid "Display Name" +msgstr "Nom affiché" + +#. module: queue_job_batch +#: model:ir.model.fields.selection,name:queue_job_batch.selection__queue_job_batch__state__enqueued +msgid "Enqueued" +msgstr "Mis en file d'attente" + +#. module: queue_job_batch +#. odoo-javascript +#: code:addons/queue_job_batch/static/src/components/QueueJobBatchMenu.esm.js:0 +msgid "Failed" +msgstr "" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__failed_job_count +msgid "Failed Job Count" +msgstr "Nombre de travaux échoués" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__failed_percentage +msgid "Failed Percentage" +msgstr "Pourcentage d'échec" + +#. module: queue_job_batch +#. odoo-javascript +#: code:addons/queue_job_batch/static/src/components/QueueJobBatchMenu.esm.js:0 +#: model:ir.model.fields.selection,name:queue_job_batch.selection__queue_job_batch__state__finished +#: model_terms:ir.ui.view,arch_db:queue_job_batch.view_queue_job_batch_search +msgid "Finished" +msgstr "Terminés" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__finished_job_count +msgid "Finished Job Count" +msgstr "Nombre de travaux terminés" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__message_follower_ids +msgid "Followers" +msgstr "Abonnés" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__message_partner_ids +msgid "Followers (Partners)" +msgstr "Abonnés (Partenaires)" + +#. module: queue_job_batch +#: model:ir.model.fields,help:queue_job_batch.field_queue_job_batch__activity_type_icon +msgid "Font awesome icon e.g. fa-tasks" +msgstr "" + +#. module: queue_job_batch +#: model_terms:ir.ui.view,arch_db:queue_job_batch.view_queue_job_batch_search +msgid "Group By" +msgstr "Regrouper par" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__has_message +msgid "Has Message" +msgstr "" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__id +msgid "ID" +msgstr "ID" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__activity_exception_icon +msgid "Icon" +msgstr "" + +#. module: queue_job_batch +#: model:ir.model.fields,help:queue_job_batch.field_queue_job_batch__activity_exception_icon +msgid "Icon to indicate an exception activity." +msgstr "" + +#. module: queue_job_batch +#: model:ir.model.fields,help:queue_job_batch.field_queue_job_batch__message_needaction +msgid "If checked, new messages require your attention." +msgstr "Si coché, de nouveaux messages requièrent votre attention." + +#. module: queue_job_batch +#: model:ir.model.fields,help:queue_job_batch.field_queue_job_batch__message_has_error +#: model:ir.model.fields,help:queue_job_batch.field_queue_job_batch__message_has_sms_error +msgid "If checked, some messages have a delivery error." +msgstr "Si coché, des messages n'ont pas pu être livré." + +#. module: queue_job_batch +#: model:ir.model.fields.selection,name:queue_job_batch.selection__queue_job_batch__state__progress +msgid "In Progress" +msgstr "En cours" + +#. module: queue_job_batch +#: model_terms:ir.ui.view,arch_db:queue_job_batch.view_queue_job_batch_search +msgid "In progress" +msgstr "En cours" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__message_is_follower +msgid "Is Follower" +msgstr "Est abonné" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__is_read +msgid "Is Read" +msgstr "Est lu" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__job_ids +msgid "Job" +msgstr "Poste" + +#. module: queue_job_batch +#. odoo-javascript +#: code:addons/queue_job_batch/static/src/QueueJobBatchModel.esm.js:0 +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job__job_batch_id +#: model_terms:ir.ui.view,arch_db:queue_job_batch.view_queue_job_batch_form +msgid "Job Batch" +msgstr "Lot de travaux" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__job_count +msgid "Job Count" +msgstr "Nombre de travaux" + +#. module: queue_job_batch +#: model:res.groups,name:queue_job_batch.group_queue_job_batch_user +msgid "Job Queue Batch User" +msgstr "Utilisateur des lots de file d'attente de travaux" + +#. module: queue_job_batch +#. odoo-javascript +#: code:addons/queue_job_batch/static/src/components/QueueJobBatchMenu.xml:0 +#: model:ir.actions.act_window,name:queue_job_batch.action_queue_job_batch +#: model:ir.actions.act_window,name:queue_job_batch.action_view_your_queue_job_batch +#: model:ir.ui.menu,name:queue_job_batch.menu_queue_job_batch +msgid "Job batches" +msgstr "Lots de travaux" + +#. module: queue_job_batch +#: model_terms:ir.ui.view,arch_db:queue_job_batch.view_queue_job_batch_form +msgid "Jobs" +msgstr "Travaux" + +#. module: queue_job_batch +#. odoo-javascript +#: code:addons/queue_job_batch/static/src/components/QueueJobBatchMenu.xml:0 +msgid "Mark as Read" +msgstr "Marquer comme lu" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__message_has_error +msgid "Message Delivery error" +msgstr "Erreur lors de livraison du message" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__message_ids +msgid "Messages" +msgstr "Messages" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__my_activity_date_deadline +msgid "My Activity Deadline" +msgstr "" + +#. module: queue_job_batch +#: model_terms:ir.ui.view,arch_db:queue_job_batch.view_queue_job_batch_search +msgid "My batches" +msgstr "" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__name +msgid "Name" +msgstr "Nom" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__activity_date_deadline +msgid "Next Activity Deadline" +msgstr "Échéance de la prochaine activité" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__activity_summary +msgid "Next Activity Summary" +msgstr "Résumé de la prochaine activité" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__activity_type_id +msgid "Next Activity Type" +msgstr "Type de la prochaine activité" + +#. module: queue_job_batch +#. odoo-javascript +#: code:addons/queue_job_batch/static/src/components/QueueJobBatchMenu.xml:0 +msgid "No jobs to view." +msgstr "Aucun travail à voir." + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__message_needaction_counter +msgid "Number of Actions" +msgstr "Nombre d'activités" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__message_has_error_counter +msgid "Number of errors" +msgstr "" + +#. module: queue_job_batch +#: model:ir.model.fields,help:queue_job_batch.field_queue_job_batch__message_needaction_counter +msgid "Number of messages requiring action" +msgstr "" + +#. module: queue_job_batch +#: model:ir.model.fields,help:queue_job_batch.field_queue_job_batch__message_has_error_counter +msgid "Number of messages with delivery error" +msgstr "Nombre de messages avec erreur de livraison" + +#. module: queue_job_batch +#: model:ir.model.fields.selection,name:queue_job_batch.selection__queue_job_batch__state__pending +#: model_terms:ir.ui.view,arch_db:queue_job_batch.view_queue_job_batch_search +msgid "Pending" +msgstr "" + +#. module: queue_job_batch +#. odoo-javascript +#: code:addons/queue_job_batch/static/src/components/QueueJobBatchMenu.esm.js:0 +msgid "Planned" +msgstr "Planifié" + +#. module: queue_job_batch +#: model:ir.model,name:queue_job_batch.model_queue_job +msgid "Queue Job" +msgstr "File d'attente des travaux" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__activity_user_id +msgid "Responsible User" +msgstr "Responsable" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__message_has_sms_error +msgid "SMS Delivery error" +msgstr "" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__state +#: model_terms:ir.ui.view,arch_db:queue_job_batch.view_queue_job_batch_search +msgid "State" +msgstr "État" + +#. module: queue_job_batch +#: model:ir.model.fields,help:queue_job_batch.field_queue_job_batch__activity_state +msgid "" +"Status based on activities\n" +"Overdue: Due date is already passed\n" +"Today: Activity date is today\n" +"Planned: Future activities." +msgstr "" +"Statut basé sur les activités\n" +"En retard : La date d'échéance est déjà dépassée\n" +"Aujourd'hui : L'activité est planifiée pour aujourd'hui\n" +"Planifiées : activités futures." + +#. module: queue_job_batch +#. odoo-javascript +#: code:addons/queue_job_batch/static/src/components/QueueJobBatchMenu.esm.js:0 +msgid "Total" +msgstr "" + +#. module: queue_job_batch +#: model:ir.model.fields,help:queue_job_batch.field_queue_job_batch__activity_exception_decoration +msgid "Type of the exception activity on record." +msgstr "" + +#. module: queue_job_batch +#: model_terms:ir.ui.view,arch_db:queue_job_batch.view_queue_job_batch_search +msgid "Unread" +msgstr "" + +#. module: queue_job_batch +#: model:ir.model,name:queue_job_batch.model_res_users +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__user_id +#: model_terms:ir.ui.view,arch_db:queue_job_batch.view_queue_job_batch_search +msgid "User" +msgstr "Utilisateur" + +#. module: queue_job_batch +#. odoo-javascript +#: code:addons/queue_job_batch/static/src/components/QueueJobBatchMenu.xml:0 +msgid "View all job batches" +msgstr "" + +#~ msgid "Draft" +#~ msgstr "Brouillon" + +#~ msgid "Followers (Channels)" +#~ msgstr "Abonnés (Canaux)" + +#~ msgid "If checked new messages require your attention." +#~ msgstr "Si coché, de nouveaux messages requièrent votre attention." + +#~ msgid "Job Batches" +#~ msgstr "Lots de travaux" + +#~ msgid "Last Modified on" +#~ msgstr "Dernière modification le" + +#~ msgid "Main Attachment" +#~ msgstr "Pièce jointe principale" + +#~ msgid "Number of error" +#~ msgstr "Nombre d'erreurs" + +#~ msgid "Number of messages which requires an action" +#~ msgstr "Nombre de messages qui nécessitent une action" + +#~ msgid "Number of unread messages" +#~ msgstr "Nombre de messages non lus" + +#~ msgid "Overdue" +#~ msgstr "Dû" + +#~ msgid "Today" +#~ msgstr "Aujourd'hui" + +#~ msgid "Unread Messages" +#~ msgstr "Messages non lus" + +#~ msgid "Unread Messages Counter" +#~ msgstr "Compteur de messages non-lus" + +#, python-format +#~ msgid "View All" +#~ msgstr "Voir tout" + +#~ msgid "Website Messages" +#~ msgstr "Messages du sites web" + +#~ msgid "Website communication history" +#~ msgstr "Historique de la communication du site web" diff --git a/queue_job_batch/i18n/it.po b/queue_job_batch/i18n/it.po new file mode 100644 index 0000000000..58fecf0436 --- /dev/null +++ b/queue_job_batch/i18n/it.po @@ -0,0 +1,379 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * queue_job_batch +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2025-02-21 18:06+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.6.2\n" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__message_needaction +msgid "Action Needed" +msgstr "Azione richiesta" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__activity_ids +msgid "Activities" +msgstr "Attività" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__activity_exception_decoration +msgid "Activity Exception Decoration" +msgstr "Decorazione eccezione attività" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__activity_state +msgid "Activity State" +msgstr "Stato attività" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__activity_type_icon +msgid "Activity Type Icon" +msgstr "Icona tipo attività" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__message_attachment_count +msgid "Attachment Count" +msgstr "Conteggio allegati" + +#. module: queue_job_batch +#: model:ir.model,name:queue_job_batch.model_queue_job_batch +msgid "Batch of jobs" +msgstr "Gruppo di lavori" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__company_id +msgid "Company" +msgstr "Azienda" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__completeness +#: model_terms:ir.ui.view,arch_db:queue_job_batch.view_queue_job_batch_form +#: model_terms:ir.ui.view,arch_db:queue_job_batch.view_queue_job_batch_tree +msgid "Completeness" +msgstr "Completezza" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__display_name +msgid "Display Name" +msgstr "Nome visualizzato" + +#. module: queue_job_batch +#: model:ir.model.fields.selection,name:queue_job_batch.selection__queue_job_batch__state__enqueued +msgid "Enqueued" +msgstr "In coda" + +#. module: queue_job_batch +#. odoo-javascript +#: code:addons/queue_job_batch/static/src/components/QueueJobBatchMenu.esm.js:0 +msgid "Failed" +msgstr "Fallito" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__failed_job_count +msgid "Failed Job Count" +msgstr "Conteggio lavori falliti" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__failed_percentage +msgid "Failed Percentage" +msgstr "Percentuale falliti" + +#. module: queue_job_batch +#. odoo-javascript +#: code:addons/queue_job_batch/static/src/components/QueueJobBatchMenu.esm.js:0 +#: model:ir.model.fields.selection,name:queue_job_batch.selection__queue_job_batch__state__finished +#: model_terms:ir.ui.view,arch_db:queue_job_batch.view_queue_job_batch_search +msgid "Finished" +msgstr "Completato" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__finished_job_count +msgid "Finished Job Count" +msgstr "Conteggio lavori completati" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__message_follower_ids +msgid "Followers" +msgstr "Seguito da" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__message_partner_ids +msgid "Followers (Partners)" +msgstr "Seguito da (partner)" + +#. module: queue_job_batch +#: model:ir.model.fields,help:queue_job_batch.field_queue_job_batch__activity_type_icon +msgid "Font awesome icon e.g. fa-tasks" +msgstr "Icona Font Awesome es. fa-tasks" + +#. module: queue_job_batch +#: model_terms:ir.ui.view,arch_db:queue_job_batch.view_queue_job_batch_search +msgid "Group By" +msgstr "Raggruppa per" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__has_message +msgid "Has Message" +msgstr "Ha un messaggio" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__id +msgid "ID" +msgstr "ID" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__activity_exception_icon +msgid "Icon" +msgstr "Icona" + +#. module: queue_job_batch +#: model:ir.model.fields,help:queue_job_batch.field_queue_job_batch__activity_exception_icon +msgid "Icon to indicate an exception activity." +msgstr "Icona per indicare un'attività eccezione." + +#. module: queue_job_batch +#: model:ir.model.fields,help:queue_job_batch.field_queue_job_batch__message_needaction +msgid "If checked, new messages require your attention." +msgstr "Se selezionata, nuovi messaggi richiedono attenzione." + +#. module: queue_job_batch +#: model:ir.model.fields,help:queue_job_batch.field_queue_job_batch__message_has_error +#: model:ir.model.fields,help:queue_job_batch.field_queue_job_batch__message_has_sms_error +msgid "If checked, some messages have a delivery error." +msgstr "Se selezionata, alcuni messaggi hanno un errore di consegna." + +#. module: queue_job_batch +#: model:ir.model.fields.selection,name:queue_job_batch.selection__queue_job_batch__state__progress +msgid "In Progress" +msgstr "In corso" + +#. module: queue_job_batch +#: model_terms:ir.ui.view,arch_db:queue_job_batch.view_queue_job_batch_search +msgid "In progress" +msgstr "In corso" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__message_is_follower +msgid "Is Follower" +msgstr "Segue" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__is_read +msgid "Is Read" +msgstr "È letto" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__job_ids +msgid "Job" +msgstr "Lavoro" + +#. module: queue_job_batch +#. odoo-javascript +#: code:addons/queue_job_batch/static/src/QueueJobBatchModel.esm.js:0 +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job__job_batch_id +#: model_terms:ir.ui.view,arch_db:queue_job_batch.view_queue_job_batch_form +msgid "Job Batch" +msgstr "Gruppo lavoro" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__job_count +msgid "Job Count" +msgstr "Conteggio lavori" + +#. module: queue_job_batch +#: model:res.groups,name:queue_job_batch.group_queue_job_batch_user +msgid "Job Queue Batch User" +msgstr "Utente gruppo lavoro coda lavoro" + +#. module: queue_job_batch +#. odoo-javascript +#: code:addons/queue_job_batch/static/src/components/QueueJobBatchMenu.xml:0 +#: model:ir.actions.act_window,name:queue_job_batch.action_queue_job_batch +#: model:ir.actions.act_window,name:queue_job_batch.action_view_your_queue_job_batch +#: model:ir.ui.menu,name:queue_job_batch.menu_queue_job_batch +msgid "Job batches" +msgstr "Gruppi lavoro" + +#. module: queue_job_batch +#: model_terms:ir.ui.view,arch_db:queue_job_batch.view_queue_job_batch_form +msgid "Jobs" +msgstr "Lavori" + +#. module: queue_job_batch +#. odoo-javascript +#: code:addons/queue_job_batch/static/src/components/QueueJobBatchMenu.xml:0 +msgid "Mark as Read" +msgstr "Segna come letto" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__message_has_error +msgid "Message Delivery error" +msgstr "Errore di consegna messaggio" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__message_ids +msgid "Messages" +msgstr "Messaggi" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__my_activity_date_deadline +msgid "My Activity Deadline" +msgstr "Scadenza mia attività" + +#. module: queue_job_batch +#: model_terms:ir.ui.view,arch_db:queue_job_batch.view_queue_job_batch_search +msgid "My batches" +msgstr "I miei gruppi" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__name +msgid "Name" +msgstr "Nome" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__activity_date_deadline +msgid "Next Activity Deadline" +msgstr "Scadenza prossima attività" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__activity_summary +msgid "Next Activity Summary" +msgstr "Riepilogo prossima attività" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__activity_type_id +msgid "Next Activity Type" +msgstr "Tipo prossima attività" + +#. module: queue_job_batch +#. odoo-javascript +#: code:addons/queue_job_batch/static/src/components/QueueJobBatchMenu.xml:0 +msgid "No jobs to view." +msgstr "Nssun lavoro da visualizzare." + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__message_needaction_counter +msgid "Number of Actions" +msgstr "Numero di azioni" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__message_has_error_counter +msgid "Number of errors" +msgstr "Numero di errori" + +#. module: queue_job_batch +#: model:ir.model.fields,help:queue_job_batch.field_queue_job_batch__message_needaction_counter +msgid "Number of messages requiring action" +msgstr "Numero di messaggi che richiedono un'azione" + +#. module: queue_job_batch +#: model:ir.model.fields,help:queue_job_batch.field_queue_job_batch__message_has_error_counter +msgid "Number of messages with delivery error" +msgstr "Numero di messaggi con errore di consegna" + +#. module: queue_job_batch +#: model:ir.model.fields.selection,name:queue_job_batch.selection__queue_job_batch__state__pending +#: model_terms:ir.ui.view,arch_db:queue_job_batch.view_queue_job_batch_search +msgid "Pending" +msgstr "In sospeso" + +#. module: queue_job_batch +#. odoo-javascript +#: code:addons/queue_job_batch/static/src/components/QueueJobBatchMenu.esm.js:0 +msgid "Planned" +msgstr "Pianificato" + +#. module: queue_job_batch +#: model:ir.model,name:queue_job_batch.model_queue_job +msgid "Queue Job" +msgstr "Lavoro in coda" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__activity_user_id +msgid "Responsible User" +msgstr "Utente responsabile" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__message_has_sms_error +msgid "SMS Delivery error" +msgstr "Errore consegna SMS" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__state +#: model_terms:ir.ui.view,arch_db:queue_job_batch.view_queue_job_batch_search +msgid "State" +msgstr "Stato" + +#. module: queue_job_batch +#: model:ir.model.fields,help:queue_job_batch.field_queue_job_batch__activity_state +msgid "" +"Status based on activities\n" +"Overdue: Due date is already passed\n" +"Today: Activity date is today\n" +"Planned: Future activities." +msgstr "" +"Stato in base alle attività\n" +"Scaduto: la data richiesta è trascorsa\n" +"Oggi: la data attività è oggi\n" +"Pianificato: attività future." + +#. module: queue_job_batch +#. odoo-javascript +#: code:addons/queue_job_batch/static/src/components/QueueJobBatchMenu.esm.js:0 +msgid "Total" +msgstr "Totale" + +#. module: queue_job_batch +#: model:ir.model.fields,help:queue_job_batch.field_queue_job_batch__activity_exception_decoration +msgid "Type of the exception activity on record." +msgstr "Tipo di attività eccezione sul record." + +#. module: queue_job_batch +#: model_terms:ir.ui.view,arch_db:queue_job_batch.view_queue_job_batch_search +msgid "Unread" +msgstr "Non letto" + +#. module: queue_job_batch +#: model:ir.model,name:queue_job_batch.model_res_users +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__user_id +#: model_terms:ir.ui.view,arch_db:queue_job_batch.view_queue_job_batch_search +msgid "User" +msgstr "Utente" + +#. module: queue_job_batch +#. odoo-javascript +#: code:addons/queue_job_batch/static/src/components/QueueJobBatchMenu.xml:0 +msgid "View all job batches" +msgstr "Vedi tutti i gruppi lavoro" + +#~ msgid "Draft" +#~ msgstr "Bozza" + +#, python-format +#~ msgid "" +#~ "Job\n" +#~ " Batches" +#~ msgstr "" +#~ "Gruppi\n" +#~ " lavoro" + +#~ msgid "Last Modified on" +#~ msgstr "Ultima modifica il" + +#~ msgid "Main Attachment" +#~ msgstr "Allegato principale" + +#, python-format +#~ msgid "View All" +#~ msgstr "Visualizza tutto" diff --git a/queue_job_batch/i18n/queue_job_batch.pot b/queue_job_batch/i18n/queue_job_batch.pot new file mode 100644 index 0000000000..6575846a63 --- /dev/null +++ b/queue_job_batch/i18n/queue_job_batch.pot @@ -0,0 +1,351 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * queue_job_batch +# +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: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__message_needaction +msgid "Action Needed" +msgstr "" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__activity_ids +msgid "Activities" +msgstr "" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__activity_exception_decoration +msgid "Activity Exception Decoration" +msgstr "" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__activity_state +msgid "Activity State" +msgstr "" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__activity_type_icon +msgid "Activity Type Icon" +msgstr "" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__message_attachment_count +msgid "Attachment Count" +msgstr "" + +#. module: queue_job_batch +#: model:ir.model,name:queue_job_batch.model_queue_job_batch +msgid "Batch of jobs" +msgstr "" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__company_id +msgid "Company" +msgstr "" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__completeness +#: model_terms:ir.ui.view,arch_db:queue_job_batch.view_queue_job_batch_form +#: model_terms:ir.ui.view,arch_db:queue_job_batch.view_queue_job_batch_tree +msgid "Completeness" +msgstr "" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__display_name +msgid "Display Name" +msgstr "" + +#. module: queue_job_batch +#: model:ir.model.fields.selection,name:queue_job_batch.selection__queue_job_batch__state__enqueued +msgid "Enqueued" +msgstr "" + +#. module: queue_job_batch +#. odoo-javascript +#: code:addons/queue_job_batch/static/src/components/QueueJobBatchMenu.esm.js:0 +msgid "Failed" +msgstr "" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__failed_job_count +msgid "Failed Job Count" +msgstr "" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__failed_percentage +msgid "Failed Percentage" +msgstr "" + +#. module: queue_job_batch +#. odoo-javascript +#: code:addons/queue_job_batch/static/src/components/QueueJobBatchMenu.esm.js:0 +#: model:ir.model.fields.selection,name:queue_job_batch.selection__queue_job_batch__state__finished +#: model_terms:ir.ui.view,arch_db:queue_job_batch.view_queue_job_batch_search +msgid "Finished" +msgstr "" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__finished_job_count +msgid "Finished Job Count" +msgstr "" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__message_follower_ids +msgid "Followers" +msgstr "" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__message_partner_ids +msgid "Followers (Partners)" +msgstr "" + +#. module: queue_job_batch +#: model:ir.model.fields,help:queue_job_batch.field_queue_job_batch__activity_type_icon +msgid "Font awesome icon e.g. fa-tasks" +msgstr "" + +#. module: queue_job_batch +#: model_terms:ir.ui.view,arch_db:queue_job_batch.view_queue_job_batch_search +msgid "Group By" +msgstr "" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__has_message +msgid "Has Message" +msgstr "" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__id +msgid "ID" +msgstr "" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__activity_exception_icon +msgid "Icon" +msgstr "" + +#. module: queue_job_batch +#: model:ir.model.fields,help:queue_job_batch.field_queue_job_batch__activity_exception_icon +msgid "Icon to indicate an exception activity." +msgstr "" + +#. module: queue_job_batch +#: model:ir.model.fields,help:queue_job_batch.field_queue_job_batch__message_needaction +msgid "If checked, new messages require your attention." +msgstr "" + +#. module: queue_job_batch +#: model:ir.model.fields,help:queue_job_batch.field_queue_job_batch__message_has_error +#: model:ir.model.fields,help:queue_job_batch.field_queue_job_batch__message_has_sms_error +msgid "If checked, some messages have a delivery error." +msgstr "" + +#. module: queue_job_batch +#: model:ir.model.fields.selection,name:queue_job_batch.selection__queue_job_batch__state__progress +msgid "In Progress" +msgstr "" + +#. module: queue_job_batch +#: model_terms:ir.ui.view,arch_db:queue_job_batch.view_queue_job_batch_search +msgid "In progress" +msgstr "" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__message_is_follower +msgid "Is Follower" +msgstr "" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__is_read +msgid "Is Read" +msgstr "" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__job_ids +msgid "Job" +msgstr "" + +#. module: queue_job_batch +#. odoo-javascript +#: code:addons/queue_job_batch/static/src/QueueJobBatchModel.esm.js:0 +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job__job_batch_id +#: model_terms:ir.ui.view,arch_db:queue_job_batch.view_queue_job_batch_form +msgid "Job Batch" +msgstr "" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__job_count +msgid "Job Count" +msgstr "" + +#. module: queue_job_batch +#: model:res.groups,name:queue_job_batch.group_queue_job_batch_user +msgid "Job Queue Batch User" +msgstr "" + +#. module: queue_job_batch +#. odoo-javascript +#: code:addons/queue_job_batch/static/src/components/QueueJobBatchMenu.xml:0 +#: model:ir.actions.act_window,name:queue_job_batch.action_queue_job_batch +#: model:ir.actions.act_window,name:queue_job_batch.action_view_your_queue_job_batch +#: model:ir.ui.menu,name:queue_job_batch.menu_queue_job_batch +msgid "Job batches" +msgstr "" + +#. module: queue_job_batch +#: model_terms:ir.ui.view,arch_db:queue_job_batch.view_queue_job_batch_form +msgid "Jobs" +msgstr "" + +#. module: queue_job_batch +#. odoo-javascript +#: code:addons/queue_job_batch/static/src/components/QueueJobBatchMenu.xml:0 +msgid "Mark as Read" +msgstr "" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__message_has_error +msgid "Message Delivery error" +msgstr "" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__message_ids +msgid "Messages" +msgstr "" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__my_activity_date_deadline +msgid "My Activity Deadline" +msgstr "" + +#. module: queue_job_batch +#: model_terms:ir.ui.view,arch_db:queue_job_batch.view_queue_job_batch_search +msgid "My batches" +msgstr "" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__name +msgid "Name" +msgstr "" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__activity_date_deadline +msgid "Next Activity Deadline" +msgstr "" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__activity_summary +msgid "Next Activity Summary" +msgstr "" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__activity_type_id +msgid "Next Activity Type" +msgstr "" + +#. module: queue_job_batch +#. odoo-javascript +#: code:addons/queue_job_batch/static/src/components/QueueJobBatchMenu.xml:0 +msgid "No jobs to view." +msgstr "" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__message_needaction_counter +msgid "Number of Actions" +msgstr "" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__message_has_error_counter +msgid "Number of errors" +msgstr "" + +#. module: queue_job_batch +#: model:ir.model.fields,help:queue_job_batch.field_queue_job_batch__message_needaction_counter +msgid "Number of messages requiring action" +msgstr "" + +#. module: queue_job_batch +#: model:ir.model.fields,help:queue_job_batch.field_queue_job_batch__message_has_error_counter +msgid "Number of messages with delivery error" +msgstr "" + +#. module: queue_job_batch +#: model:ir.model.fields.selection,name:queue_job_batch.selection__queue_job_batch__state__pending +#: model_terms:ir.ui.view,arch_db:queue_job_batch.view_queue_job_batch_search +msgid "Pending" +msgstr "" + +#. module: queue_job_batch +#. odoo-javascript +#: code:addons/queue_job_batch/static/src/components/QueueJobBatchMenu.esm.js:0 +msgid "Planned" +msgstr "" + +#. module: queue_job_batch +#: model:ir.model,name:queue_job_batch.model_queue_job +msgid "Queue Job" +msgstr "" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__activity_user_id +msgid "Responsible User" +msgstr "" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__message_has_sms_error +msgid "SMS Delivery error" +msgstr "" + +#. module: queue_job_batch +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__state +#: model_terms:ir.ui.view,arch_db:queue_job_batch.view_queue_job_batch_search +msgid "State" +msgstr "" + +#. module: queue_job_batch +#: model:ir.model.fields,help:queue_job_batch.field_queue_job_batch__activity_state +msgid "" +"Status based on activities\n" +"Overdue: Due date is already passed\n" +"Today: Activity date is today\n" +"Planned: Future activities." +msgstr "" + +#. module: queue_job_batch +#. odoo-javascript +#: code:addons/queue_job_batch/static/src/components/QueueJobBatchMenu.esm.js:0 +msgid "Total" +msgstr "" + +#. module: queue_job_batch +#: model:ir.model.fields,help:queue_job_batch.field_queue_job_batch__activity_exception_decoration +msgid "Type of the exception activity on record." +msgstr "" + +#. module: queue_job_batch +#: model_terms:ir.ui.view,arch_db:queue_job_batch.view_queue_job_batch_search +msgid "Unread" +msgstr "" + +#. module: queue_job_batch +#: model:ir.model,name:queue_job_batch.model_res_users +#: model:ir.model.fields,field_description:queue_job_batch.field_queue_job_batch__user_id +#: model_terms:ir.ui.view,arch_db:queue_job_batch.view_queue_job_batch_search +msgid "User" +msgstr "" + +#. module: queue_job_batch +#. odoo-javascript +#: code:addons/queue_job_batch/static/src/components/QueueJobBatchMenu.xml:0 +msgid "View all job batches" +msgstr "" diff --git a/queue_job_batch/migrations/17.0.1.0.0/pre-migrate.py b/queue_job_batch/migrations/17.0.1.0.0/pre-migrate.py new file mode 100644 index 0000000000..6d5f4e08af --- /dev/null +++ b/queue_job_batch/migrations/17.0.1.0.0/pre-migrate.py @@ -0,0 +1,19 @@ +# Copyright 2025 Camptocamp SA (https://www.camptocamp.com). +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + + +def migrate(cr, version): + cr.execute( + """ + UPDATE queue_job_batch + SET state = 'pending' + WHERE state = 'draft' + """ + ) + cr.execute( + """ + UPDATE queue_job_batch + SET is_read = FALSE + WHERE state != 'finished' AND is_read + """ + ) diff --git a/queue_job_batch/models/__init__.py b/queue_job_batch/models/__init__.py new file mode 100644 index 0000000000..b76787c9a6 --- /dev/null +++ b/queue_job_batch/models/__init__.py @@ -0,0 +1,3 @@ +from . import queue_job_batch +from . import queue_job +from . import res_users diff --git a/queue_job_batch/models/queue_job.py b/queue_job_batch/models/queue_job.py new file mode 100644 index 0000000000..ddc3efe879 --- /dev/null +++ b/queue_job_batch/models/queue_job.py @@ -0,0 +1,32 @@ +# Copyright 2019 Creu Blanca +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) + +from odoo import api, fields, models + +from odoo.addons.queue_job.job import identity_exact + + +class QueueJob(models.Model): + _inherit = "queue.job" + + job_batch_id = fields.Many2one("queue.job.batch") + + @api.model_create_multi + def create(self, vals_list): + batch = self.env.context.get("job_batch") + if batch and isinstance(batch, models.Model): + for vals in vals_list: + vals.update({"job_batch_id": batch.id}) + return super().create(vals_list) + + def write(self, vals): + if vals.get("state", "") == "done": + batches = self.env["queue.job.batch"] + for record in self: + if record.state != "done" and record.job_batch_id: + batches |= record.job_batch_id + for batch in batches: + # We need to make it with delay in order to prevent two jobs + # to work with the same batch + batch.with_delay(identity_key=identity_exact).check_state() + return super().write(vals) diff --git a/queue_job_batch/models/queue_job_batch.py b/queue_job_batch/models/queue_job_batch.py new file mode 100644 index 0000000000..e200ae8e23 --- /dev/null +++ b/queue_job_batch/models/queue_job_batch.py @@ -0,0 +1,106 @@ +# Copyright 2019 Creu Blanca +# Copyright 2023 ForgeFlow S.L. (http://www.forgeflow.com) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) + +from odoo import api, fields, models + + +class QueueJobBatch(models.Model): + _name = "queue.job.batch" + _inherit = ["mail.thread", "mail.activity.mixin"] + _description = "Batch of jobs" + _log_access = False + + name = fields.Char( + required=True, + readonly=True, + tracking=True, + ) + job_ids = fields.One2many( + "queue.job", + inverse_name="job_batch_id", + readonly=True, + ) + job_count = fields.Integer( + compute="_compute_job_count", + ) + user_id = fields.Many2one( + "res.users", + required=True, + readonly=True, + tracking=True, + ) + state = fields.Selection( + [ + ("pending", "Pending"), + ("enqueued", "Enqueued"), + ("progress", "In Progress"), + ("finished", "Finished"), + ], + default="pending", + required=True, + readonly=True, + tracking=True, + ) + finished_job_count = fields.Float( + compute="_compute_job_count", + ) + failed_job_count = fields.Float( + compute="_compute_job_count", + ) + company_id = fields.Many2one( + "res.company", + readonly=True, + ) + is_read = fields.Boolean() + completeness = fields.Float( + compute="_compute_job_count", + ) + failed_percentage = fields.Float( + compute="_compute_job_count", + ) + + def _get_state(self): + self.ensure_one() + job_states = set(self.job_ids.grouped("state").keys()) + if all(state in ("done", "cancelled", "failed") for state in job_states): + return "finished" + elif {"done", "started"} & job_states: + return "progress" + elif "enqueued" in job_states: + return "enqueued" + return "pending" + + def check_state(self): + for rec in self: + if (state := rec._get_state()) != rec.state: + rec.state = state + + def set_read(self): + for rec in self: + if rec.is_read or rec.state != "finished": + continue + rec.is_read = True + + @api.model + def get_new_batch(self, name, **kwargs): + vals = kwargs.copy() + vals.update( + { + "user_id": self.env.uid, + "name": name, + "company_id": self.env.company.id or self.env.user.company_id.id, + } + ) + record = self.sudo().create(vals).with_user(self.env.uid) + return record + + @api.depends("job_ids.state") + def _compute_job_count(self): + for rec in self: + jobs_by_state = rec.job_ids.grouped("state") + rec.job_count = len(rec.job_ids) + rec.failed_job_count = len(jobs_by_state.get("failed", [])) + rec.finished_job_count = len(jobs_by_state.get("done", [])) + rec.completeness = rec.finished_job_count / max(1, rec.job_count) + rec.failed_percentage = rec.failed_job_count / max(1, rec.job_count) diff --git a/queue_job_batch/models/res_users.py b/queue_job_batch/models/res_users.py new file mode 100644 index 0000000000..de53d2b31f --- /dev/null +++ b/queue_job_batch/models/res_users.py @@ -0,0 +1,30 @@ +# Copyright 2025 Camptocamp SA (https://www.camptocamp.com). +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import models + + +class Users(models.Model): + _name = "res.users" + _inherit = ["res.users"] + + def _init_store_data(self, store): + res = super()._init_store_data(store) + store.add( + { + "hasQueueJobBatchUserGroup": self.env.user.has_group( + "queue_job_batch.group_queue_job_batch_user" + ), + } + ) + return res + + def _get_queue_job_batches(self): + # See :meth:`controllers.webclient.WebClient._process_request_for_internal_user` + self.ensure_one() + return self.env["queue.job.batch"].search( + [ + ("user_id", "=", self.id), + ("is_read", "=", False), + ] + ) diff --git a/queue_job_batch/pyproject.toml b/queue_job_batch/pyproject.toml new file mode 100644 index 0000000000..4231d0cccb --- /dev/null +++ b/queue_job_batch/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/queue_job_batch/readme/CONTRIBUTORS.md b/queue_job_batch/readme/CONTRIBUTORS.md new file mode 100644 index 0000000000..6b13c0aa12 --- /dev/null +++ b/queue_job_batch/readme/CONTRIBUTORS.md @@ -0,0 +1,12 @@ +- Enric Tobella \<\> + +- [Trobz](https://trobz.com): + - Hoang Diep \<\> + +- [ForgeFlow](https://forgeflow.com): + - Lois Rilo \<\> + - Jasmin Solanki \<\> + +- [Camptocamp](https://camptocamp.com): + - Maksym Yankin \<\> + - Iván Todorovich \<\> diff --git a/queue_job_batch/readme/CREDITS.md b/queue_job_batch/readme/CREDITS.md new file mode 100644 index 0000000000..6184200e1b --- /dev/null +++ b/queue_job_batch/readme/CREDITS.md @@ -0,0 +1,2 @@ +The migration of this module from 12.0 to 14.0 was financially supported +by Camptocamp diff --git a/queue_job_batch/readme/DESCRIPTION.md b/queue_job_batch/readme/DESCRIPTION.md new file mode 100644 index 0000000000..c866311ee6 --- /dev/null +++ b/queue_job_batch/readme/DESCRIPTION.md @@ -0,0 +1,35 @@ +This addon adds an a grouper for queue jobs. + +It allows to show your jobs in a batched form in order to know better +the results. + +Example: + +``` python +from odoo import models, fields, api + + +class MyModel(models.Model): + _name = 'my.model' + + def my_method(self, a, k=None): + _logger.info('executed with a: %s and k: %s', a, k) + + +class MyOtherModel(models.Model): + _name = 'my.other.model' + + @api.multi + def button_do_stuff(self): + batch = self.env['queue.job.batch'].get_new_batch('Group') + model = self.env['my.model'].with_context(job_batch=batch) + for i in range(1, 100): + model.with_delay().my_method('a', k=i) +``` + +In the snippet of code above, when we call `button_do_stuff`, 100 jobs +capturing the method and arguments will be postponed. It will be +executed as soon as the Jobrunner has a free bucket, which can be +instantaneous if no other job is running. + +Once all the jobs have finished, the grouper will be marked as finished. diff --git a/queue_job_batch/readme/USAGE.md b/queue_job_batch/readme/USAGE.md new file mode 100644 index 0000000000..616eaa6d7b --- /dev/null +++ b/queue_job_batch/readme/USAGE.md @@ -0,0 +1,3 @@ +You can manage your batch jobs from the Systray. A new button will be +shown with your currently executing job batches and the recently +finished job groups. diff --git a/queue_job_batch/security/ir.model.access.csv b/queue_job_batch/security/ir.model.access.csv new file mode 100644 index 0000000000..e3da256bbb --- /dev/null +++ b/queue_job_batch/security/ir.model.access.csv @@ -0,0 +1,4 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_queue_job_batch_user,queue job manager,model_queue_job_batch,group_queue_job_batch_user,1,1,0,0 +access_queue_job_batch_manager,queue job manager,model_queue_job_batch,queue_job.group_queue_job_manager,1,1,1,1 +access_queue_job_queue_job_batch_user,queue job manager,queue_job.model_queue_job,group_queue_job_batch_user,1,0,0,0 diff --git a/queue_job_batch/security/security.xml b/queue_job_batch/security/security.xml new file mode 100644 index 0000000000..9443708ae0 --- /dev/null +++ b/queue_job_batch/security/security.xml @@ -0,0 +1,46 @@ + + + + + Job Queue Batch User + + + + + + + + + + Job Queue batch multi-company + + + ['|',('company_id','=',False),('company_id','child_of',[user.company_id.id])] + + + + Job Queue batch user filter + + + [('user_id', '=', user.id)] + + + + Job Queue batch manager + + + [(1, '=', 1)] + + + diff --git a/queue_job_batch/static/description/icon.png b/queue_job_batch/static/description/icon.png new file mode 100644 index 0000000000..a735e94d10 Binary files /dev/null and b/queue_job_batch/static/description/icon.png differ diff --git a/queue_job_batch/static/description/icon.svg b/queue_job_batch/static/description/icon.svg new file mode 100644 index 0000000000..653fcebfa6 --- /dev/null +++ b/queue_job_batch/static/description/icon.svg @@ -0,0 +1,127 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + diff --git a/queue_job_batch/static/description/index.html b/queue_job_batch/static/description/index.html new file mode 100644 index 0000000000..4818fbcc1e --- /dev/null +++ b/queue_job_batch/static/description/index.html @@ -0,0 +1,479 @@ + + + + + +Job Queue Batch + + + +
+

Job Queue Batch

+ + +

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

+

This addon adds an a grouper for queue jobs.

+

It allows to show your jobs in a batched form in order to know better +the results.

+

Example:

+
+from odoo import models, fields, api
+
+
+class MyModel(models.Model):
+    _name = 'my.model'
+
+    def my_method(self, a, k=None):
+        _logger.info('executed with a: %s and k: %s', a, k)
+
+
+class MyOtherModel(models.Model):
+    _name = 'my.other.model'
+
+    @api.multi
+    def button_do_stuff(self):
+        batch = self.env['queue.job.batch'].get_new_batch('Group')
+        model = self.env['my.model'].with_context(job_batch=batch)
+        for i in range(1, 100):
+            model.with_delay().my_method('a', k=i)
+
+

In the snippet of code above, when we call button_do_stuff, 100 jobs +capturing the method and arguments will be postponed. It will be +executed as soon as the Jobrunner has a free bucket, which can be +instantaneous if no other job is running.

+

Once all the jobs have finished, the grouper will be marked as finished.

+

Table of contents

+ +
+

Usage

+

You can manage your batch jobs from the Systray. A new button will be +shown with your currently executing job batches and the recently +finished job groups.

+
+
+

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

+
    +
  • Creu Blanca
  • +
+
+
+

Contributors

+ +
+
+

Other credits

+

The migration of this module from 12.0 to 14.0 was financially supported +by Camptocamp

+
+
+

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.

+

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

+

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

+
+
+
+ + diff --git a/queue_job_batch/static/src/MailCoreWeb.esm.js b/queue_job_batch/static/src/MailCoreWeb.esm.js new file mode 100644 index 0000000000..0bfe7302d0 --- /dev/null +++ b/queue_job_batch/static/src/MailCoreWeb.esm.js @@ -0,0 +1,27 @@ +/* @odoo-module */ + +import {MailCoreWeb} from "@mail/core/web/mail_core_web_service"; +import {patch} from "@web/core/utils/patch"; + +patch(MailCoreWeb.prototype, { + setup() { + super.setup(); + this.busService.subscribe( + "queue.job.batch/updated", + (payload, {id: notifId}) => { + if ( + payload.batch_created && + notifId > this.store.queueJobBatchCounterBusId + ) { + this.store.queueJobBatchCounter++; + } + if ( + payload.batch_read && + notifId > this.store.queueJobBatchCounterBusId + ) { + this.store.queueJobBatchCounter--; + } + } + ); + }, +}); diff --git a/queue_job_batch/static/src/QueueJobBatchModel.esm.js b/queue_job_batch/static/src/QueueJobBatchModel.esm.js new file mode 100644 index 0000000000..46f44f2488 --- /dev/null +++ b/queue_job_batch/static/src/QueueJobBatchModel.esm.js @@ -0,0 +1,71 @@ +/* @odoo-module */ + +import {Record} from "@mail/core/common/record"; +import {_t} from "@web/core/l10n/translation"; + +export class QueueJobBatch extends Record { + static id = "id"; + + /** @type {Object.} */ + static records = {}; + + /** @returns {QueueJobBatch} */ + static get() { + return super.get(...arguments); + } + + /** @returns {QueueJobBatch|QueueJobBatch[]} */ + static insert() { + return super.insert(...arguments); + } + + /** @type {Number} */ + id; + + /** @type {String} */ + name; + + /** @type {Number} */ + job_count; + + /** @type {Number} */ + completeness; + + /** @type {Number} */ + failed_percentage; + + /** @type {Number} */ + finished_job_count; + + /** @type {Number} */ + failed_job_count; + + /** @type {'pending'|'enqueued'|'progress'|'finished'} */ + state; + + async open() { + this.store.env.services.action.doAction( + { + type: "ir.actions.act_window", + name: _t("Job Batch"), + res_model: "queue.job.batch", + view_mode: "form", + views: [[false, "form"]], + res_id: this.id, + target: "current", + }, + { + clearBreadcrumbs: true, + } + ); + } + + async markAsRead() { + await this.store.env.services.orm.silent.call("queue.job.batch", "set_read", [ + [this.id], + ]); + this.delete(); + } +} + +QueueJobBatch.register(); diff --git a/queue_job_batch/static/src/Store.esm.js b/queue_job_batch/static/src/Store.esm.js new file mode 100644 index 0000000000..a1370a8afa --- /dev/null +++ b/queue_job_batch/static/src/Store.esm.js @@ -0,0 +1,20 @@ +/* @odoo-module */ + +import {Store} from "@mail/core/common/store_service"; +import {patch} from "@web/core/utils/patch"; + +// PyToJsModels["queue.job.batch"] = "QueueJobBatch"; + +patch(Store.prototype, { + hasQueueJobBatchUserGroup: false, + queueJobBatchCounterBusId: 0, + queueJobBatchCounter: 0, + + /** @override */ + get initMessagingParams() { + return { + ...super.initMessagingParams, + systray_get_queue_job_batches: true, + }; + }, +}); diff --git a/queue_job_batch/static/src/components/QueueJobBatchMenu.esm.js b/queue_job_batch/static/src/components/QueueJobBatchMenu.esm.js new file mode 100644 index 0000000000..b4ca4a0b3a --- /dev/null +++ b/queue_job_batch/static/src/components/QueueJobBatchMenu.esm.js @@ -0,0 +1,104 @@ +/* @odoo-module */ + +import {Component, useState} from "@odoo/owl"; +import {ColumnProgress} from "@web/views/view_components/column_progress"; +import {Dropdown} from "@web/core/dropdown/dropdown"; +import {registry} from "@web/core/registry"; +import {useDiscussSystray} from "@mail/utils/common/hooks"; +import {useDropdownState} from "@web/core/dropdown/dropdown_hooks"; +import {useService} from "@web/core/utils/hooks"; +import {user} from "@web/core/user"; +import {_t} from "@web/core/l10n/translation"; + +export class QueueJobBatchMenu extends Component { + static template = "queue_job_batch.QueueJobBatchMenu"; + static components = {Dropdown, ColumnProgress}; + static props = []; + + /** + * @override + */ + setup() { + super.setup(); + this.discussSystray = useDiscussSystray(); + this.store = useState(useService("mail.store")); + this.action = useService("action"); + this.userId = user.userId; + this.ui = useState(useService("ui")); + this.dropdown = useDropdownState(); + } + + onBeforeOpen() { + this.store.fetchData({systray_get_queue_job_batches: true}); + } + + getGroupInfo(batch) { + const types = { + planned: { + label: _t("Planned"), + color: "warning", + value: + batch.job_count - + (batch.finished_job_count + batch.failed_job_count), + }, + finished: { + label: _t("Finished"), + color: "success", + value: batch.finished_job_count, + }, + failed: { + label: _t("Failed"), + color: "danger", + value: batch.failed_job_count, + }, + }; + // Build progress bar data + const progressBar = {bars: []}; + for (const [value, count] of Object.entries(types)) { + if (count.value) { + progressBar.bars.push({ + count: count.value, + value, + string: types[value].label, + color: count.color, + }); + } + } + return { + aggregate: { + title: _t("Total"), + value: batch.job_count, + }, + count: batch.job_count, + progressBar, + }; + } + + openMyJobBatches() { + this.dropdown.close(); + this.action.doAction("queue_job_batch.action_view_your_queue_job_batch", { + clearBreadcrumbs: true, + }); + } + + async onClickItem(ev, batch) { + ev.preventDefault(); + ev.stopPropagation(); + this.dropdown.close(); + return batch.open(); + } + + async onClickMarkAsRead(ev, batch) { + ev.preventDefault(); + ev.stopPropagation(); + return batch.markAsRead(); + } +} + +registry + .category("systray") + .add( + "queue_job_batch.QueueJobBatchMenu", + {Component: QueueJobBatchMenu}, + {sequence: 90} + ); diff --git a/queue_job_batch/static/src/components/QueueJobBatchMenu.scss b/queue_job_batch/static/src/components/QueueJobBatchMenu.scss new file mode 100644 index 0000000000..7ddd882f22 --- /dev/null +++ b/queue_job_batch/static/src/components/QueueJobBatchMenu.scss @@ -0,0 +1,21 @@ +.o-queue-job-batch-QueueJobBatchMenu { + width: 350px; + max-height: 400px; + min-height: 50px; + + .o-queue-job-batch-QueueJobBatchMenu-item { + &:hover { + .o-queue-job-batch-QueueJobBatchMenu-markAsRead { + visibility: visible; + } + } + + .o-queue-job-batch-QueueJobBatchMenu-markAsRead { + visibility: hidden; + + &:hover { + color: $success; + } + } + } +} diff --git a/queue_job_batch/static/src/components/QueueJobBatchMenu.xml b/queue_job_batch/static/src/components/QueueJobBatchMenu.xml new file mode 100644 index 0000000000..d43103d16f --- /dev/null +++ b/queue_job_batch/static/src/components/QueueJobBatchMenu.xml @@ -0,0 +1,103 @@ + + + + + + + +
+
+ No jobs to view. +
+
+ +
+
+ + + +
+
+ + + + +
+
+ +
+
+
+ + View all job batches + +
+
+
+
+
+
diff --git a/queue_job_batch/views/queue_job_batch_views.xml b/queue_job_batch/views/queue_job_batch_views.xml new file mode 100644 index 0000000000..a89909b921 --- /dev/null +++ b/queue_job_batch/views/queue_job_batch_views.xml @@ -0,0 +1,146 @@ + + + + queue.job.batch.tree + queue.job.batch + + + + + + + + + + + + queue.job.batch.form + queue.job.batch + +
+
+ +
+ +
+ +
+

+ +

+ + + + + +
+ + +
+
+ + + queue.job.batch.search + queue.job.batch + + + + + + + + + + + + + + + + + + + + + + + Job batches + queue.job.batch + + { + 'search_default_pending': 1, + 'search_default_progress': 1, + } + + list,form + + + + Job batches + queue.job.batch + + { + 'search_default_my_batches': 1, + 'search_default_unread': 1, + } + + [] + list,form + + + +
diff --git a/queue_job_batch/views/queue_job_views.xml b/queue_job_batch/views/queue_job_views.xml new file mode 100644 index 0000000000..5657745ca9 --- /dev/null +++ b/queue_job_batch/views/queue_job_views.xml @@ -0,0 +1,24 @@ + + + + queue.job.form + queue.job + + + + + + + + + + queue.job.search + queue.job + + + + + + + + diff --git a/test_queue_job_batch/README.rst b/test_queue_job_batch/README.rst new file mode 100644 index 0000000000..36814c6af0 --- /dev/null +++ b/test_queue_job_batch/README.rst @@ -0,0 +1,88 @@ +==================== +Test Job Queue Batch +==================== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:e01f2caa1024599ec16d5cf1ae3a33cd9559ffaa5786195f2be98a5fc09710e2 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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/licence-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%2Fqueue-lightgray.png?logo=github + :target: https://github.com/OCA/queue/tree/17.0/test_queue_job_batch + :alt: OCA/queue +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/queue-17-0/queue-17-0-test_queue_job_batch + :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/queue&target_branch=17.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This addon is used to test the queue job batch functionality + +**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 +------- + +* Creu Blanca + +Contributors +------------ + +- Enric Tobella + +- Lois Rilo + +- `Trobz `__: + + - Hoang Diep + +Other credits +------------- + +The migration of this module from 12.0 to 14.0 was financially supported +by Camptocamp + +Maintainers +----------- + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +This module is part of the `OCA/queue `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/test_queue_job_batch/__init__.py b/test_queue_job_batch/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test_queue_job_batch/__manifest__.py b/test_queue_job_batch/__manifest__.py new file mode 100644 index 0000000000..132d90aab6 --- /dev/null +++ b/test_queue_job_batch/__manifest__.py @@ -0,0 +1,15 @@ +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) + + +{ + "name": "Test Job Queue Batch", + "version": "17.0.1.0.0", + "author": "Creu Blanca,Odoo Community Association (OCA)", + "website": "https://github.com/OCA/queue", + "license": "AGPL-3", + "category": "Generic Modules", + "depends": [ + "queue_job_batch", + "test_queue_job", + ], +} diff --git a/test_queue_job_batch/i18n/fr.po b/test_queue_job_batch/i18n/fr.po new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test_queue_job_batch/i18n/it.po b/test_queue_job_batch/i18n/it.po new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test_queue_job_batch/i18n/test_queue_job_batch.pot b/test_queue_job_batch/i18n/test_queue_job_batch.pot new file mode 100644 index 0000000000..aadee09bfe --- /dev/null +++ b/test_queue_job_batch/i18n/test_queue_job_batch.pot @@ -0,0 +1,13 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# +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" diff --git a/test_queue_job_batch/pyproject.toml b/test_queue_job_batch/pyproject.toml new file mode 100644 index 0000000000..4231d0cccb --- /dev/null +++ b/test_queue_job_batch/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/test_queue_job_batch/readme/CONTRIBUTORS.md b/test_queue_job_batch/readme/CONTRIBUTORS.md new file mode 100644 index 0000000000..aa6ae84916 --- /dev/null +++ b/test_queue_job_batch/readme/CONTRIBUTORS.md @@ -0,0 +1,6 @@ +- Enric Tobella \<\> + +- Lois Rilo \<\> + +- [Trobz](https://trobz.com): + - Hoang Diep \<\> diff --git a/test_queue_job_batch/readme/CREDITS.md b/test_queue_job_batch/readme/CREDITS.md new file mode 100644 index 0000000000..6184200e1b --- /dev/null +++ b/test_queue_job_batch/readme/CREDITS.md @@ -0,0 +1,2 @@ +The migration of this module from 12.0 to 14.0 was financially supported +by Camptocamp diff --git a/test_queue_job_batch/readme/DESCRIPTION.md b/test_queue_job_batch/readme/DESCRIPTION.md new file mode 100644 index 0000000000..e647a1de27 --- /dev/null +++ b/test_queue_job_batch/readme/DESCRIPTION.md @@ -0,0 +1 @@ +This addon is used to test the queue job batch functionality diff --git a/test_queue_job_batch/static/description/icon.png b/test_queue_job_batch/static/description/icon.png new file mode 100644 index 0000000000..a735e94d10 Binary files /dev/null and b/test_queue_job_batch/static/description/icon.png differ diff --git a/test_queue_job_batch/static/description/icon.svg b/test_queue_job_batch/static/description/icon.svg new file mode 100644 index 0000000000..653fcebfa6 --- /dev/null +++ b/test_queue_job_batch/static/description/icon.svg @@ -0,0 +1,127 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test_queue_job_batch/static/description/index.html b/test_queue_job_batch/static/description/index.html new file mode 100644 index 0000000000..098bcd9f9d --- /dev/null +++ b/test_queue_job_batch/static/description/index.html @@ -0,0 +1,434 @@ + + + + + +Test Job Queue Batch + + + +
+

Test Job Queue Batch

+ + +

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

+

This addon is used to test the queue job batch functionality

+

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

+
    +
  • Creu Blanca
  • +
+
+
+

Contributors

+ +
+
+

Other credits

+

The migration of this module from 12.0 to 14.0 was financially supported +by Camptocamp

+
+
+

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.

+

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

+

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

+
+
+
+ + diff --git a/test_queue_job_batch/tests/__init__.py b/test_queue_job_batch/tests/__init__.py new file mode 100644 index 0000000000..39cec46423 --- /dev/null +++ b/test_queue_job_batch/tests/__init__.py @@ -0,0 +1 @@ +from . import test_queue_job_batch diff --git a/test_queue_job_batch/tests/test_queue_job_batch.py b/test_queue_job_batch/tests/test_queue_job_batch.py new file mode 100644 index 0000000000..1534b72cfd --- /dev/null +++ b/test_queue_job_batch/tests/test_queue_job_batch.py @@ -0,0 +1,61 @@ +from odoo.tests.common import TransactionCase + +from odoo.addons.queue_job.job import Job + + +class TestQueueJobGroup(TransactionCase): + def test_batch(self): + self.cr.execute("delete from queue_job") + batch = self.env["queue.job.batch"].get_new_batch("TEST") + self.assertFalse(batch.job_ids) + model = self.env["test.queue.job"].with_context(job_batch=batch) + job_1 = model.with_delay().testing_method() + self.assertEqual(job_1.db_record().state, "pending") + job_2 = model.with_delay().testing_method() + self.assertEqual(job_2.db_record().state, "pending") + jobs = job_1.db_record() + jobs |= job_2.db_record() + self.assertEqual(jobs, batch.job_ids) + batch.set_read() + self.assertFalse(batch.is_read, "Not marked as read because not yet finished") + self.assertEqual(batch.state, "pending") + self.assertEqual(job_2.state, "pending") + self.assertEqual(job_2.state, "pending") + job_domain = [ + ("uuid", "!=", job_1.uuid), + ("uuid", "!=", job_2.uuid), + ] + update = self.env["queue.job"].search(job_domain) + self.assertFalse(update) + job = Job.load(self.env, job_1.uuid) + job.perform() + job.set_done() + job.store() + update = self.env["queue.job"].search(job_domain) + self.assertTrue(update) + self.assertEqual(1, len(update)) + job = Job.load(self.env, update.uuid) + job.perform() + job.set_done() + job.store() + self.assertEqual(batch.state, "progress") + self.assertEqual(batch.completeness, 0.5) + job_domain.append(("uuid", "!=", update.uuid)) + update = self.env["queue.job"].search(job_domain) + self.assertFalse(update) + job = Job.load(self.env, job_2.uuid) + job.perform() + job.set_done() + job.store() + update = self.env["queue.job"].search(job_domain) + self.assertTrue(update) + self.assertEqual(1, len(update)) + job = Job.load(self.env, update.uuid) + job.perform() + job.set_done() + job.store() + self.assertEqual(batch.state, "finished") + self.assertEqual(batch.completeness, 1) + self.assertFalse(batch.is_read) + batch.set_read() + self.assertTrue(batch.is_read, "Marked as read because it's finished")