From 82471a7a121744496bad8c9ab9c0cb4430706bda Mon Sep 17 00:00:00 2001 From: David Date: Wed, 20 Sep 2023 11:19:15 +0200 Subject: [PATCH 1/4] [FIX] base_report_to_printer: update printers wizard - Add access rules to the wizard - Set a fallback name for the printers and respect the user custom ones TT45159 --- base_report_to_printer/__manifest__.py | 1 + base_report_to_printer/models/printing_printer.py | 2 +- base_report_to_printer/models/printing_server.py | 5 +++++ base_report_to_printer/security/ir.model.access.csv | 2 ++ base_report_to_printer/tests/test_printing_printer_tray.py | 7 ++++--- 5 files changed, 13 insertions(+), 4 deletions(-) create mode 100644 base_report_to_printer/security/ir.model.access.csv diff --git a/base_report_to_printer/__manifest__.py b/base_report_to_printer/__manifest__.py index a399b15..1d8e9d7 100644 --- a/base_report_to_printer/__manifest__.py +++ b/base_report_to_printer/__manifest__.py @@ -18,6 +18,7 @@ "data": [ "data/printing_data.xml", "security/security.xml", + "security/ir.model.access.csv", "views/printing_printer.xml", "views/printing_server.xml", "views/printing_job.xml", diff --git a/base_report_to_printer/models/printing_printer.py b/base_report_to_printer/models/printing_printer.py index dec7605..845dc1e 100644 --- a/base_report_to_printer/models/printing_printer.py +++ b/base_report_to_printer/models/printing_printer.py @@ -71,7 +71,7 @@ class PrintingPrinter(models.Model): def _prepare_update_from_cups(self, cups_connection, cups_printer): mapping = {3: "available", 4: "printing", 5: "error"} cups_vals = { - "name": cups_printer["printer-info"], + "name": self.name or cups_printer["printer-info"], "model": cups_printer.get("printer-make-and-model", False), "location": cups_printer.get("printer-location", False), "uri": cups_printer.get("device-uri", False), diff --git a/base_report_to_printer/models/printing_server.py b/base_report_to_printer/models/printing_server.py index 06de8fa..69c9eb3 100644 --- a/base_report_to_printer/models/printing_server.py +++ b/base_report_to_printer/models/printing_server.py @@ -121,6 +121,11 @@ class PrintingServer(models.Model): printer_values["server_id"] = server.id updated_printers.append(name) + # We want to keep any existing customized name over existing printer + # We want also to rely in the system name as a fallback to avoid + # empty names. + if not printer_values.get("name") and not printer.name: + printer_values["name"] = name if not printer: printer_values["system_name"] = name printer.create(printer_values) diff --git a/base_report_to_printer/security/ir.model.access.csv b/base_report_to_printer/security/ir.model.access.csv new file mode 100644 index 0000000..b97fc91 --- /dev/null +++ b/base_report_to_printer/security/ir.model.access.csv @@ -0,0 +1,2 @@ +id,name,model_id/id,group_id/id,perm_read,perm_write,perm_create,perm_unlink +access_printing_printer_update_wizard,printers update,model_printing_printer_update_wizard,base.group_system,1,1,1,1 diff --git a/base_report_to_printer/tests/test_printing_printer_tray.py b/base_report_to_printer/tests/test_printing_printer_tray.py index 22bbcc4..6440206 100644 --- a/base_report_to_printer/tests/test_printing_printer_tray.py +++ b/base_report_to_printer/tests/test_printing_printer_tray.py @@ -40,7 +40,7 @@ class TestPrintingPrinter(TransactionCase): self.server = self.env["printing.server"].create({}) self.printer = self.env["printing.printer"].create( { - "name": "Printer", + "name": "", "server_id": self.server.id, "system_name": "Sys Name", "default": True, @@ -105,10 +105,11 @@ class TestPrintingPrinter(TransactionCase): Check that the update_printers method calls _prepare_update_from_cups """ self.mock_cups_ppd(cups, file_name=False) - - self.assertEqual(self.printer.name, "Printer") self.ServerModel.update_printers() self.assertEqual(self.printer.name, "info") + self.printer.name = "My custom name" + self.ServerModel.update_printers() + self.assertEqual(self.printer.name, "My custom name") @mock.patch("%s.cups" % server_model) def test_prepare_update_from_cups_no_ppd(self, cups): From 05ac999d110738b42796d7f7947959eb8facc925 Mon Sep 17 00:00:00 2001 From: sergio-teruel Date: Sat, 26 Oct 2024 23:32:27 +0200 Subject: [PATCH 2/4] [IMP] base_report_to_printer: Add printer option to launch reports in new thread --- base_report_to_printer/README.rst | 5 ++++ .../models/ir_actions_report.py | 27 ++++++++++++++++++- .../models/printing_printer.py | 10 ++++++- .../models/printing_server.py | 1 + .../readme/CONTRIBUTORS.rst | 5 ++++ .../static/description/index.html | 5 ++++ .../static/src/js/qweb_action_manager.esm.js | 10 +++---- .../tests/test_ir_actions_report.py | 17 ++++++++++++ .../views/printing_printer.xml | 1 + .../views/printing_server.xml | 1 + 10 files changed, 75 insertions(+), 7 deletions(-) diff --git a/base_report_to_printer/README.rst b/base_report_to_printer/README.rst index 2f19149..afa482c 100644 --- a/base_report_to_printer/README.rst +++ b/base_report_to_printer/README.rst @@ -163,6 +163,11 @@ Contributors * Akim Juillerat * Jacques-Etienne Baudoux (BCIM) +* `Tecnativa `_: + + * Sergio Teruel + * David Vidal + Maintainers ~~~~~~~~~~~ diff --git a/base_report_to_printer/models/ir_actions_report.py b/base_report_to_printer/models/ir_actions_report.py index 0547709..395837f 100644 --- a/base_report_to_printer/models/ir_actions_report.py +++ b/base_report_to_printer/models/ir_actions_report.py @@ -3,9 +3,11 @@ # Copyright (C) 2011 Agile Business Group sagl () # Copyright (C) 2011 Domsense srl () # Copyright (C) 2013-2014 Camptocamp () +# Copyright 2024 Tecnativa - Sergio Teruel # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +import threading -from odoo import _, api, exceptions, fields, models +from odoo import _, api, exceptions, fields, models, registry from odoo.tools.safe_eval import safe_eval, time REPORT_TYPES = {"qweb-pdf": "pdf", "qweb-text": "text"} @@ -118,6 +120,29 @@ class IrActionsReport(models.Model): result["printer_exception"] = True return result + def print_document_client_action(self, record_ids, data=None): + behaviour = self.behaviour() + printer = behaviour.pop("printer", None) + if printer.multi_thread: + + @self.env.cr.postcommit.add + def _launch_print_thread(): + threaded_calculation = threading.Thread( + target=self.print_document_threaded, + args=(self.id, record_ids, data), + ) + threaded_calculation.start() + + return True + else: + return self.print_document(record_ids, data=data) + + def print_document_threaded(self, report_id, record_ids, data): + with registry(self._cr.dbname).cursor() as cr: + self = self.with_env(self.env(cr=cr)) + report = self.env["ir.actions.report"].browse(report_id) + report.print_document(record_ids, data) + def print_document(self, record_ids, data=None): """Print a document, do not return the document file""" report_type = REPORT_TYPES.get(self.report_type) diff --git a/base_report_to_printer/models/printing_printer.py b/base_report_to_printer/models/printing_printer.py index 845dc1e..efd04e0 100644 --- a/base_report_to_printer/models/printing_printer.py +++ b/base_report_to_printer/models/printing_printer.py @@ -12,7 +12,7 @@ import logging import os from tempfile import mkstemp -from odoo import fields, models +from odoo import api, fields, models _logger = logging.getLogger(__name__) @@ -67,6 +67,14 @@ class PrintingPrinter(models.Model): tray_ids = fields.One2many( comodel_name="printing.tray", inverse_name="printer_id", string="Paper Sources" ) + multi_thread = fields.Boolean( + compute="_compute_multi_thread", readonly=False, store=True + ) + + @api.depends("server_id.multi_thread") + def _compute_multi_thread(self): + for printer in self: + printer.multi_thread = printer.server_id.multi_thread def _prepare_update_from_cups(self, cups_connection, cups_printer): mapping = {3: "available", 4: "printing", 5: "error"} diff --git a/base_report_to_printer/models/printing_server.py b/base_report_to_printer/models/printing_server.py index 69c9eb3..0135870 100644 --- a/base_report_to_printer/models/printing_server.py +++ b/base_report_to_printer/models/printing_server.py @@ -42,6 +42,7 @@ class PrintingServer(models.Model): string="Printers List", help="List of printers available on this server.", ) + multi_thread = fields.Boolean() def _open_connection(self, raise_on_error=False): self.ensure_one() diff --git a/base_report_to_printer/readme/CONTRIBUTORS.rst b/base_report_to_printer/readme/CONTRIBUTORS.rst index 4626c55..3223d01 100644 --- a/base_report_to_printer/readme/CONTRIBUTORS.rst +++ b/base_report_to_printer/readme/CONTRIBUTORS.rst @@ -15,3 +15,8 @@ * Hughes Damry * Akim Juillerat * Jacques-Etienne Baudoux (BCIM) + +* `Tecnativa `_: + + * Sergio Teruel + * David Vidal diff --git a/base_report_to_printer/static/description/index.html b/base_report_to_printer/static/description/index.html index 431a96b..a9808b2 100644 --- a/base_report_to_printer/static/description/index.html +++ b/base_report_to_printer/static/description/index.html @@ -512,6 +512,11 @@ If you spotted it first, help us to smash it by providing a detailed and welcome
  • Hughes Damry <hughes.damry@acsone.eu>
  • Akim Juillerat <akim.juillerat@camptocamp.com>
  • Jacques-Etienne Baudoux (BCIM) <je@bcim.be>
  • +
  • Tecnativa:
      +
    • Sergio Teruel
    • +
    • David Vidal
    • +
    +
  • diff --git a/base_report_to_printer/static/src/js/qweb_action_manager.esm.js b/base_report_to_printer/static/src/js/qweb_action_manager.esm.js index 370fd94..640e0df 100644 --- a/base_report_to_printer/static/src/js/qweb_action_manager.esm.js +++ b/base_report_to_printer/static/src/js/qweb_action_manager.esm.js @@ -15,11 +15,11 @@ async function cupsReportActionHandler(action, options, env) { print_action.action === "server" && !print_action.printer_exception ) { - const result = await orm.call("ir.actions.report", "print_document", [ - action.id, - action.context.active_ids, - action.data, - ]); + const result = await orm.call( + "ir.actions.report", + "print_document_client_action", + [action.id, action.context.active_ids, action.data] + ); if (result) { env.services.notification.add(env._t("Successfully sent to printer!"), { type: "success", diff --git a/base_report_to_printer/tests/test_ir_actions_report.py b/base_report_to_printer/tests/test_ir_actions_report.py index e010dd8..61fd527 100644 --- a/base_report_to_printer/tests/test_ir_actions_report.py +++ b/base_report_to_printer/tests/test_ir_actions_report.py @@ -295,3 +295,20 @@ class TestIrActionsReportXml(TransactionCase): self.assertEqual(action.printer_tray_id, tray) action.onchange_printing_printer_id() self.assertFalse(action.printer_tray_id) + + def test_print_in_new_thread(self): + """It should return the action and printer from printing action in other thread""" + report = self.Model.search([], limit=1) + self.env.user.printing_action = "server" + printing_action = self.new_printing_action() + printing_action.user_id = self.env.user + printing_action.printer_id = self.new_printer() + printing_action.printer_id.multi_thread = True + self.assertEqual( + report.behaviour(), + { + "action": printing_action.action, + "printer": printing_action.printer_id, + "tray": False, + }, + ) diff --git a/base_report_to_printer/views/printing_printer.xml b/base_report_to_printer/views/printing_printer.xml index d64a208..49bae3e 100644 --- a/base_report_to_printer/views/printing_printer.xml +++ b/base_report_to_printer/views/printing_printer.xml @@ -78,6 +78,7 @@ + diff --git a/base_report_to_printer/views/printing_server.xml b/base_report_to_printer/views/printing_server.xml index 153b85f..c43d682 100644 --- a/base_report_to_printer/views/printing_server.xml +++ b/base_report_to_printer/views/printing_server.xml @@ -31,6 +31,7 @@ + From 8f92ce85b6a47130c798e9783f3499db18493b6e Mon Sep 17 00:00:00 2001 From: David Date: Mon, 11 Nov 2024 13:31:15 +0100 Subject: [PATCH 3/4] [IMP] base_report_to_printer: exceptions notifications Better handling of exceptions feedback. A notification will show up with the issued printer and report and a button for the user to download the report as a fallback to the failure. TT51628 --- base_report_to_printer/README.rst | 7 ++ .../models/ir_actions_report.py | 8 ++- base_report_to_printer/readme/ROADMAP.rst | 3 + .../static/description/index.html | 41 +++++++----- .../static/src/js/qweb_action_manager.esm.js | 66 +++++++++++++++---- 5 files changed, 94 insertions(+), 31 deletions(-) create mode 100644 base_report_to_printer/readme/ROADMAP.rst diff --git a/base_report_to_printer/README.rst b/base_report_to_printer/README.rst index afa482c..8fc4a22 100644 --- a/base_report_to_printer/README.rst +++ b/base_report_to_printer/README.rst @@ -106,6 +106,13 @@ Guidelines for use: When no tray is configured for a report and a user, the default tray setup on the CUPS server is used. +Known issues / Roadmap +====================== + +- With threaded printing there's no download fallback when the issue isn't detected by + the CUPS Odoo backend. To able to do it, we would need to notify the bus or use + web_notify for it. + Changelog ========= diff --git a/base_report_to_printer/models/ir_actions_report.py b/base_report_to_printer/models/ir_actions_report.py index 395837f..8af5143 100644 --- a/base_report_to_printer/models/ir_actions_report.py +++ b/base_report_to_printer/models/ir_actions_report.py @@ -59,6 +59,8 @@ class IrActionsReport(models.Model): "skip_printer_exception" ): serializable_result["printer_exception"] = True + if self.env.context.get("force_print_to_client"): + serializable_result["action"] = "client" return serializable_result def _get_user_default_print_behaviour(self): @@ -135,7 +137,10 @@ class IrActionsReport(models.Model): return True else: - return self.print_document(record_ids, data=data) + try: + return self.print_document(record_ids, data=data) + except Exception: + return def print_document_threaded(self, report_id, record_ids, data): with registry(self._cr.dbname).cursor() as cr: @@ -171,6 +176,7 @@ class IrActionsReport(models.Model): else: title = self.report_name behaviour["title"] = title + behaviour["res_ids"] = record_ids # TODO should we use doc_format instead of report_type return printer.print_document( self, document, doc_format=self.report_type, **behaviour diff --git a/base_report_to_printer/readme/ROADMAP.rst b/base_report_to_printer/readme/ROADMAP.rst new file mode 100644 index 0000000..a7b6610 --- /dev/null +++ b/base_report_to_printer/readme/ROADMAP.rst @@ -0,0 +1,3 @@ +- With threaded printing there's no download fallback when the issue isn't detected by + the CUPS Odoo backend. To able to do it, we would need to notify the bus or use + web_notify for it. diff --git a/base_report_to_printer/static/description/index.html b/base_report_to_printer/static/description/index.html index a9808b2..741565a 100644 --- a/base_report_to_printer/static/description/index.html +++ b/base_report_to_printer/static/description/index.html @@ -396,16 +396,17 @@ preprinted paper such as payment slip.

  • Installation
  • Configuration
  • Usage
  • -
  • Changelog
  • +
    +

    Known issues / Roadmap

    +
      +
    • With threaded printing there’s no download fallback when the issue isn’t detected by +the CUPS Odoo backend. To able to do it, we would need to notify the bus or use +web_notify for it.
    • +
    +
    -

    Bug Tracker

    +

    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 @@ -480,9 +489,9 @@ If you spotted it first, help us to smash it by providing a detailed and welcome

    Do not contact contributors directly about support or help with technical issues.

    -

    Credits

    +

    Credits

    -

    Authors

    +

    Authors

    • Agile Business Group & Domsense
    • Pegueroles SCP
    • @@ -493,7 +502,7 @@ If you spotted it first, help us to smash it by providing a detailed and welcome
    -

    Contributors

    +

    Contributors

    -

    Maintainers

    +

    Maintainers

    This module is maintained by the OCA.

    Odoo Community Association diff --git a/base_report_to_printer/static/src/js/qweb_action_manager.esm.js b/base_report_to_printer/static/src/js/qweb_action_manager.esm.js index 640e0df..c75a7ba 100644 --- a/base_report_to_printer/static/src/js/qweb_action_manager.esm.js +++ b/base_report_to_printer/static/src/js/qweb_action_manager.esm.js @@ -1,4 +1,5 @@ /** @odoo-module */ +import {Markup} from "web.utils"; import {registry} from "@web/core/registry"; async function cupsReportActionHandler(action, options, env) { @@ -8,13 +9,12 @@ async function cupsReportActionHandler(action, options, env) { const print_action = await orm.call( "ir.actions.report", "print_action_for_report_name", - [action.report_name] + [action.report_name], + {context: {force_print_to_client: action.context.force_print_to_client}} ); - if ( - print_action && - print_action.action === "server" && - !print_action.printer_exception - ) { + var printer_exception = print_action.printer_exception; + if (print_action && print_action.action === "server" && !printer_exception) { + // The Odoo CUPS backend is ok. We try to print into the printer const result = await orm.call( "ir.actions.report", "print_document_client_action", @@ -24,20 +24,58 @@ async function cupsReportActionHandler(action, options, env) { env.services.notification.add(env._t("Successfully sent to printer!"), { type: "success", }); - } else { - env.services.notification.add(env._t("Could not send to printer!"), { - type: "danger", - }); + return true; + // In case of exception during the job, we won't get any response. So we + // should flag the exception and notify the user } - return true; + env.services.notification.add(env._t("Could not sent to printer!"), { + type: "danger", + }); + printer_exception = true; } - if (print_action.printer_exception) { - env.services.notification.add( - env._t("The printer couldn't be reached. Downloading document instead"), + if (print_action && print_action.action === "server" && printer_exception) { + // Just so the translation engine detects them as it doesn't do it inside + // template strings + const terms = { + the_report: env._t("The report"), + couldnt_be_printed: env._t( + "couldn't be printed. Click on the button below to download it" + ), + issue_on: env._t("Issue on"), + }; + const notificationRemove = env.services.notification.add( + Markup( + `

    ${terms.the_report} ${action.name} ${terms.couldnt_be_printed}

    ` + ), { + title: `${terms.issue_on} ${print_action.printer_name}`, type: "warning", + sticky: true, + messageIsHtml: true, + buttons: [ + { + name: env._t("Print"), + primary: true, + icon: "fa-print", + onClick: async () => { + const context = { + force_print_to_client: true, + must_skip_send_to_printer: true, + }; + env.services.user.updateContext(context); + await env.services.action.doAction( + {type: "ir.actions.report", ...action}, + { + additionalContext: context, + } + ); + notificationRemove(); + }, + }, + ], } ); + return true; } } } From 4fd5eb6b14367b912fc86e42c22c129415fed4a9 Mon Sep 17 00:00:00 2001 From: David Date: Tue, 12 Nov 2024 09:40:21 +0100 Subject: [PATCH 4/4] oca-port: blacklist PR(s) 275 for base_report_to_printer --- .oca/oca-port/blacklist/base_report_to_printer.json | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .oca/oca-port/blacklist/base_report_to_printer.json diff --git a/.oca/oca-port/blacklist/base_report_to_printer.json b/.oca/oca-port/blacklist/base_report_to_printer.json new file mode 100644 index 0000000..9f49464 --- /dev/null +++ b/.oca/oca-port/blacklist/base_report_to_printer.json @@ -0,0 +1,5 @@ +{ + "pull_requests": { + "OCA/report-print-send#275": "It's the migration PR..." + } +}