mirror of
https://github.com/OCA/report-print-send.git
synced 2025-02-16 07:11:31 +02:00
[MIG] base_report_to_printer: Migration to 18.0
This commit is contained in:
@@ -175,6 +175,13 @@ Contributors
|
||||
- Hughes Damry <hughes.damry@acsone.eu>
|
||||
- Akim Juillerat <akim.juillerat@camptocamp.com>
|
||||
- Jacques-Etienne Baudoux (BCIM) <je@bcim.be>
|
||||
- Tris Doan <tridm@trobz.com>
|
||||
|
||||
Other credits
|
||||
-------------
|
||||
|
||||
The migration of this module from 17.0 to 18.0 was financially supported
|
||||
by Camptocamp.
|
||||
|
||||
Maintainers
|
||||
-----------
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
{
|
||||
"name": "Report to printer",
|
||||
"version": "17.0.1.0.1",
|
||||
"version": "18.0.1.0.0",
|
||||
"category": "Generic Modules/Base",
|
||||
"author": "Agile Business Group & Domsense, Pegueroles SCP, NaN,"
|
||||
" LasLabs, Camptocamp, Odoo Community Association (OCA),"
|
||||
|
||||
@@ -9,25 +9,19 @@
|
||||
<field name="name">Send to Client</field>
|
||||
<field name="action_type">client</field>
|
||||
</record>
|
||||
<!-- properties -->
|
||||
<record forcecreate="True" id="property_printing_action_id" model="ir.property">
|
||||
<field name="name">property_printing_action_id</field>
|
||||
<field
|
||||
name="fields_id"
|
||||
search="[('model', '=', 'ir.actions.report'), ('name', '=', 'property_printing_action_id')]"
|
||||
/>
|
||||
<field name="value" eval="'printing.action,' + str(printing_action_2)" />
|
||||
</record>
|
||||
<record forcecreate="True" id="ir_cron_update_printers" model="ir.cron">
|
||||
<field name="name">Update Printers Jobs</field>
|
||||
<field name="active" eval="True" />
|
||||
<field name="user_id" ref="base.user_root" />
|
||||
<field name="interval_number">1</field>
|
||||
<field name="interval_type">minutes</field>
|
||||
<field name="numbercall">-1</field>
|
||||
<field name="doall" eval="False" />
|
||||
<field name="model_id" ref="base_report_to_printer.model_printing_server" />
|
||||
<field name="state">code</field>
|
||||
<field name="code">model.action_update_jobs()</field>
|
||||
</record>
|
||||
<function
|
||||
model="ir.default"
|
||||
name="set"
|
||||
eval="('ir.actions.report', 'property_printing_action_id', obj().env.ref('base_report_to_printer.printing_action_2').id)"
|
||||
/>
|
||||
</odoo>
|
||||
|
||||
@@ -157,7 +157,7 @@ class IrActionsReport(models.Model):
|
||||
_("This report type (%s) is not supported by direct printing!")
|
||||
% str(self.report_type)
|
||||
)
|
||||
method_name = "_render_qweb_%s" % (report_type)
|
||||
method_name = f"_render_qweb_{report_type}"
|
||||
document, doc_format = getattr(
|
||||
self.with_context(must_skip_send_to_printer=True), method_name
|
||||
)(self.report_name, record_ids, data=data)
|
||||
|
||||
@@ -5,14 +5,14 @@
|
||||
# Copyright (C) 2013-2014 Camptocamp (<http://www.camptocamp.com>)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import api, fields, models
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class PrintingAction(models.Model):
|
||||
_name = "printing.action"
|
||||
_description = "Print Job Action"
|
||||
|
||||
@api.model
|
||||
@property
|
||||
def _available_action_types(self):
|
||||
return [
|
||||
("server", "Send to Printer"),
|
||||
|
||||
@@ -178,7 +178,7 @@ class PrintingPrinter(models.Model):
|
||||
options = {}
|
||||
for option, value in print_opts.items():
|
||||
try:
|
||||
options.update(getattr(self, "_set_option_%s" % option)(report, value))
|
||||
options.update(getattr(self, f"_set_option_{option}")(report, value))
|
||||
except AttributeError:
|
||||
options[option] = str(value)
|
||||
return options
|
||||
|
||||
@@ -22,7 +22,7 @@ class PrintingReportXmlAction(models.Model):
|
||||
comodel_name="res.users", string="User", required=True, ondelete="cascade"
|
||||
)
|
||||
action = fields.Selection(
|
||||
selection=lambda s: s.env["printing.action"]._available_action_types(),
|
||||
selection=lambda s: s.env["printing.action"]._available_action_types,
|
||||
required=True,
|
||||
)
|
||||
printer_id = fields.Many2one(comodel_name="printing.printer", string="Printer")
|
||||
|
||||
@@ -11,19 +11,27 @@ from odoo import api, fields, models
|
||||
class ResUsers(models.Model):
|
||||
_inherit = "res.users"
|
||||
|
||||
@api.model
|
||||
@property
|
||||
def _user_available_action_types(self):
|
||||
return [
|
||||
(code, string)
|
||||
for code, string in self.env["printing.action"]._available_action_types()
|
||||
for code, string in self.env["printing.action"]._available_action_types
|
||||
if code != "user_default"
|
||||
]
|
||||
|
||||
printing_action = fields.Selection(selection=_user_available_action_types)
|
||||
printing_action = fields.Selection(
|
||||
selection=lambda self: self._user_available_action_types
|
||||
)
|
||||
printing_printer_id = fields.Many2one(
|
||||
comodel_name="printing.printer", string="Default Printer"
|
||||
)
|
||||
|
||||
@api.constrains("printing_action")
|
||||
def _check_printing_action(self):
|
||||
for rec in self:
|
||||
if rec.printing_action == "user_default":
|
||||
raise ValueError("user_default should not be available")
|
||||
|
||||
@property
|
||||
def SELF_READABLE_FIELDS(self):
|
||||
return super().SELF_READABLE_FIELDS + ["printing_action", "printing_printer_id"]
|
||||
|
||||
@@ -15,3 +15,4 @@
|
||||
- Hughes Damry \<<hughes.damry@acsone.eu>\>
|
||||
- Akim Juillerat \<<akim.juillerat@camptocamp.com>\>
|
||||
- Jacques-Etienne Baudoux (BCIM) \<<je@bcim.be>\>
|
||||
- Tris Doan \<<tridm@trobz.com>\>
|
||||
|
||||
1
base_report_to_printer/readme/CREDITS.md
Normal file
1
base_report_to_printer/readme/CREDITS.md
Normal file
@@ -0,0 +1 @@
|
||||
The migration of this module from 17.0 to 18.0 was financially supported by Camptocamp.
|
||||
@@ -409,7 +409,8 @@ preprinted paper such as payment slip.</p>
|
||||
<li><a class="reference internal" href="#credits" id="toc-entry-9">Credits</a><ul>
|
||||
<li><a class="reference internal" href="#authors" id="toc-entry-10">Authors</a></li>
|
||||
<li><a class="reference internal" href="#contributors" id="toc-entry-11">Contributors</a></li>
|
||||
<li><a class="reference internal" href="#maintainers" id="toc-entry-12">Maintainers</a></li>
|
||||
<li><a class="reference internal" href="#other-credits" id="toc-entry-12">Other credits</a></li>
|
||||
<li><a class="reference internal" href="#maintainers" id="toc-entry-13">Maintainers</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -528,10 +529,16 @@ If you spotted it first, help us to smash it by providing a detailed and welcome
|
||||
<li>Hughes Damry <<a class="reference external" href="mailto:hughes.damry@acsone.eu">hughes.damry@acsone.eu</a>></li>
|
||||
<li>Akim Juillerat <<a class="reference external" href="mailto:akim.juillerat@camptocamp.com">akim.juillerat@camptocamp.com</a>></li>
|
||||
<li>Jacques-Etienne Baudoux (BCIM) <<a class="reference external" href="mailto:je@bcim.be">je@bcim.be</a>></li>
|
||||
<li>Tris Doan <<a class="reference external" href="mailto:tridm@trobz.com">tridm@trobz.com</a>></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="other-credits">
|
||||
<h2><a class="toc-backref" href="#toc-entry-12">Other credits</a></h2>
|
||||
<p>The migration of this module from 17.0 to 18.0 was financially supported
|
||||
by Camptocamp.</p>
|
||||
</div>
|
||||
<div class="section" id="maintainers">
|
||||
<h2><a class="toc-backref" href="#toc-entry-12">Maintainers</a></h2>
|
||||
<h2><a class="toc-backref" href="#toc-entry-13">Maintainers</a></h2>
|
||||
<p>This module is maintained by the OCA.</p>
|
||||
<a class="reference external image-reference" href="https://odoo-community.org">
|
||||
<img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" />
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
/** @odoo-module */
|
||||
import {Markup} from "web.utils";
|
||||
import {markup} from "@odoo/owl";
|
||||
import {_t} from "@web/core/l10n/translation";
|
||||
import {registry} from "@web/core/registry";
|
||||
|
||||
@@ -38,14 +37,14 @@ async function cupsReportActionHandler(action, options, env) {
|
||||
// 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(
|
||||
the_report: _t("The report"),
|
||||
couldnt_be_printed: _t(
|
||||
"couldn't be printed. Click on the button below to download it"
|
||||
),
|
||||
issue_on: env._t("Issue on"),
|
||||
issue_on: _t("Issue on"),
|
||||
};
|
||||
const notificationRemove = env.services.notification.add(
|
||||
Markup(
|
||||
markup(
|
||||
`<p>${terms.the_report} <strong>${action.name}</strong> ${terms.couldnt_be_printed}</p>`
|
||||
),
|
||||
{
|
||||
@@ -55,7 +54,7 @@ async function cupsReportActionHandler(action, options, env) {
|
||||
messageIsHtml: true,
|
||||
buttons: [
|
||||
{
|
||||
name: env._t("Print"),
|
||||
name: _t("Print"),
|
||||
primary: true,
|
||||
icon: "fa-print",
|
||||
onClick: async () => {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
# Copyright 2016 SYLEAM
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
import logging
|
||||
from unittest import mock
|
||||
|
||||
from odoo.tests.common import TransactionCase
|
||||
@@ -57,14 +58,14 @@ class TestIrActionsReportXml(TransactionCase):
|
||||
|
||||
def test_print_action_for_report_name_gets_report(self):
|
||||
"""It should get report by name"""
|
||||
with mock.patch("%s._get_report_from_name" % model) as mk:
|
||||
with mock.patch(f"{model}._get_report_from_name") as mk:
|
||||
expect = "test"
|
||||
self.Model.print_action_for_report_name(expect)
|
||||
mk.assert_called_once_with(expect)
|
||||
|
||||
def test_print_action_for_report_name_returns_if_no_report(self):
|
||||
"""It should return empty dict when no matching report"""
|
||||
with mock.patch("%s._get_report_from_name" % model) as mk:
|
||||
with mock.patch(f"{model}._get_report_from_name") as mk:
|
||||
expect = "test"
|
||||
mk.return_value = False
|
||||
res = self.Model.print_action_for_report_name(expect)
|
||||
@@ -72,7 +73,7 @@ class TestIrActionsReportXml(TransactionCase):
|
||||
|
||||
def test_print_action_for_report_name_returns_if_report(self):
|
||||
"""It should return correct serializable result for behaviour"""
|
||||
with mock.patch("%s._get_report_from_name" % model) as mk:
|
||||
with mock.patch(f"{model}._get_report_from_name") as mk:
|
||||
res = self.Model.print_action_for_report_name("test")
|
||||
behaviour = mk().behaviour()
|
||||
expect = {
|
||||
@@ -102,6 +103,9 @@ class TestIrActionsReportXml(TransactionCase):
|
||||
report = self.Model.search([], limit=1)
|
||||
self.env.user.printing_action = "client"
|
||||
self.env.user.printing_printer_id = self.new_printer()
|
||||
with (
|
||||
self.assertLogs(level=logging.WARNING) as logs,
|
||||
):
|
||||
self.assertEqual(
|
||||
report.behaviour(),
|
||||
{
|
||||
@@ -110,6 +114,8 @@ class TestIrActionsReportXml(TransactionCase):
|
||||
"tray": False,
|
||||
},
|
||||
)
|
||||
self.assertEqual(len(logs.records), 1)
|
||||
self.assertEqual(logs.records[0].levelno, logging.WARNING)
|
||||
|
||||
def test_behaviour_report_values(self):
|
||||
"""It should return the action and printer from report"""
|
||||
@@ -117,6 +123,9 @@ class TestIrActionsReportXml(TransactionCase):
|
||||
self.env.user.printing_action = "client"
|
||||
report.property_printing_action_id = self.new_action()
|
||||
report.printing_printer_id = self.new_printer()
|
||||
with (
|
||||
self.assertLogs(level=logging.WARNING) as logs,
|
||||
):
|
||||
self.assertEqual(
|
||||
report.behaviour(),
|
||||
{
|
||||
@@ -125,6 +134,8 @@ class TestIrActionsReportXml(TransactionCase):
|
||||
"tray": False,
|
||||
},
|
||||
)
|
||||
self.assertEqual(len(logs.records), 1)
|
||||
self.assertEqual(logs.records[0].levelno, logging.WARNING)
|
||||
|
||||
def test_behaviour_user_action(self):
|
||||
"""It should return the action and printer from user action"""
|
||||
@@ -188,6 +199,9 @@ class TestIrActionsReportXml(TransactionCase):
|
||||
printing_action = self.new_printing_action()
|
||||
printing_action.user_id = self.env.user
|
||||
printing_action.printer_id = self.new_printer()
|
||||
with (
|
||||
self.assertLogs(level=logging.WARNING) as logs,
|
||||
):
|
||||
self.assertEqual(
|
||||
report.behaviour(),
|
||||
{
|
||||
@@ -196,6 +210,8 @@ class TestIrActionsReportXml(TransactionCase):
|
||||
"tray": False,
|
||||
},
|
||||
)
|
||||
self.assertEqual(len(logs.records), 1)
|
||||
self.assertEqual(logs.records[0].levelno, logging.WARNING)
|
||||
|
||||
def test_behaviour_printing_action_user_defaults(self):
|
||||
"""It should return the action and printer from user with printing
|
||||
@@ -215,12 +231,23 @@ class TestIrActionsReportXml(TransactionCase):
|
||||
"""
|
||||
It should return the correct tray
|
||||
"""
|
||||
with (
|
||||
self.assertLogs(level=logging.WARNING) as logs,
|
||||
):
|
||||
report = self.Model.search([], limit=1)
|
||||
action = self.env["printing.report.xml.action"].create(
|
||||
{"user_id": self.env.user.id, "report_id": report.id, "action": "server"}
|
||||
{
|
||||
"user_id": self.env.user.id,
|
||||
"report_id": report.id,
|
||||
"action": "server",
|
||||
}
|
||||
)
|
||||
printer = self.new_printer()
|
||||
tray_vals = {"name": "Tray", "system_name": "Tray", "printer_id": printer.id}
|
||||
tray_vals = {
|
||||
"name": "Tray",
|
||||
"system_name": "Tray",
|
||||
"printer_id": printer.id,
|
||||
}
|
||||
user_tray = self.new_tray({"system_name": "User tray"}, tray_vals)
|
||||
report_tray = self.new_tray({"system_name": "Report tray"}, tray_vals)
|
||||
action_tray = self.new_tray({"system_name": "Action tray"}, tray_vals)
|
||||
@@ -266,6 +293,9 @@ class TestIrActionsReportXml(TransactionCase):
|
||||
report.printer_tray_id = report_tray
|
||||
action.printer_tray_id = action_tray
|
||||
self.assertEqual("Action tray", report.behaviour()["tray"])
|
||||
self.assertEqual(len(logs.records), 6)
|
||||
for record in logs.records:
|
||||
self.assertEqual(record.levelno, logging.WARNING)
|
||||
|
||||
def test_onchange_printer_tray_id_empty(self):
|
||||
action = self.Model.new({"printer_tray_id": False})
|
||||
@@ -305,6 +335,9 @@ class TestIrActionsReportXml(TransactionCase):
|
||||
printing_action.user_id = self.env.user
|
||||
printing_action.printer_id = self.new_printer()
|
||||
printing_action.printer_id.multi_thread = True
|
||||
with (
|
||||
self.assertLogs(level=logging.WARNING) as logs,
|
||||
):
|
||||
self.assertEqual(
|
||||
report.behaviour(),
|
||||
{
|
||||
@@ -313,3 +346,5 @@ class TestIrActionsReportXml(TransactionCase):
|
||||
"tray": False,
|
||||
},
|
||||
)
|
||||
self.assertEqual(len(logs.records), 1)
|
||||
self.assertEqual(logs.records[0].levelno, logging.WARNING)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# Copyright 2016 LasLabs Inc.
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
import logging
|
||||
from unittest import mock
|
||||
|
||||
from odoo import fields
|
||||
@@ -42,9 +43,12 @@ class TestPrintingJob(TransactionCase):
|
||||
values["printer_id"] = printer.id
|
||||
return self.env["printing.job"].create(values)
|
||||
|
||||
@mock.patch("%s.cups" % model)
|
||||
def test_cancel_job_error(self, cups):
|
||||
def test_cancel_job_error(self):
|
||||
"""It should catch any exception from CUPS and update status"""
|
||||
with (
|
||||
mock.patch(f"{model}.cups") as cups,
|
||||
self.assertLogs(level=logging.WARNING) as logs,
|
||||
):
|
||||
cups.Connection.side_effect = Exception
|
||||
printer = self.new_printer()
|
||||
job = self.new_job(printer, {"job_id_cups": 2})
|
||||
@@ -52,7 +56,10 @@ class TestPrintingJob(TransactionCase):
|
||||
cups.Connection.side_effect = None
|
||||
self.assertEqual(cups.Connection().cancelJob.call_count, 0)
|
||||
|
||||
@mock.patch("%s.cups" % model)
|
||||
self.assertEqual(len(logs.records), 3)
|
||||
self.assertEqual(logs.records[0].levelno, logging.WARNING)
|
||||
|
||||
@mock.patch(f"{model}.cups")
|
||||
def test_cancel_job(self, cups):
|
||||
"""It should catch any exception from CUPS and update status"""
|
||||
printer = self.new_printer()
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# Copyright 2016 LasLabs Inc.
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
import logging
|
||||
import tempfile
|
||||
from unittest import mock
|
||||
|
||||
@@ -79,11 +80,11 @@ class TestPrintingPrinter(TransactionCase):
|
||||
)
|
||||
self.assertTrue("InputSlot" in self.Model.print_options(report, tray="Test"))
|
||||
|
||||
@mock.patch("%s.cups" % server_model)
|
||||
@mock.patch(f"{server_model}.cups")
|
||||
def test_print_report(self, cups):
|
||||
"""It should print a report through CUPS"""
|
||||
fd, file_name = tempfile.mkstemp()
|
||||
with mock.patch("%s.mkstemp" % model) as mkstemp:
|
||||
with mock.patch(f"{model}.mkstemp") as mkstemp:
|
||||
mkstemp.return_value = fd, file_name
|
||||
printer = self.new_record()
|
||||
printer.print_document(self.report, b"content to print", doc_format="pdf")
|
||||
@@ -91,37 +92,52 @@ class TestPrintingPrinter(TransactionCase):
|
||||
printer.system_name, file_name, file_name, options={}
|
||||
)
|
||||
|
||||
@mock.patch("%s.cups" % server_model)
|
||||
def test_print_report_error(self, cups):
|
||||
def test_print_report_error(self):
|
||||
"""It should print a report through CUPS"""
|
||||
with (
|
||||
mock.patch(f"{model}.cups") as cups,
|
||||
self.assertLogs(level=logging.WARNING) as logs,
|
||||
):
|
||||
cups.Connection.side_effect = Exception
|
||||
fd, file_name = tempfile.mkstemp()
|
||||
with mock.patch("%s.mkstemp" % model) as mkstemp:
|
||||
with mock.patch(f"{model}.mkstemp") as mkstemp:
|
||||
mkstemp.return_value = fd, file_name
|
||||
printer = self.new_record()
|
||||
with self.assertRaises(UserError):
|
||||
printer.print_document(
|
||||
self.report, b"content to print", doc_format="pdf"
|
||||
)
|
||||
self.assertEqual(len(logs.records), 1)
|
||||
self.assertEqual(logs.records[0].levelno, logging.WARNING)
|
||||
|
||||
@mock.patch("%s.cups" % server_model)
|
||||
def test_print_file(self, cups):
|
||||
def test_print_file(self):
|
||||
"""It should print a file through CUPS"""
|
||||
with (
|
||||
mock.patch(f"{server_model}.cups") as cups,
|
||||
self.assertLogs(level=logging.WARNING) as logs,
|
||||
):
|
||||
file_name = "file_name"
|
||||
printer = self.new_record()
|
||||
printer.print_file(file_name, "pdf")
|
||||
cups.Connection().printFile.assert_called_once_with(
|
||||
printer.system_name, file_name, file_name, options={}
|
||||
)
|
||||
self.assertEqual(len(logs.records), 1)
|
||||
self.assertEqual(logs.records[0].levelno, logging.WARNING)
|
||||
|
||||
@mock.patch("%s.cups" % server_model)
|
||||
def test_print_file_error(self, cups):
|
||||
def test_print_file_error(self):
|
||||
"""It should print a file through CUPS"""
|
||||
with (
|
||||
mock.patch(f"{server_model}.cups") as cups,
|
||||
self.assertLogs(level=logging.WARNING) as logs,
|
||||
):
|
||||
cups.Connection.side_effect = Exception
|
||||
file_name = "file_name"
|
||||
printer = self.new_record()
|
||||
with self.assertRaises(UserError):
|
||||
printer.print_file(file_name)
|
||||
self.assertEqual(len(logs.records), 1)
|
||||
self.assertEqual(logs.records[0].levelno, logging.WARNING)
|
||||
|
||||
def test_set_default(self):
|
||||
"""It should set a single record as default"""
|
||||
@@ -142,7 +158,7 @@ class TestPrintingPrinter(TransactionCase):
|
||||
printer.unset_default()
|
||||
self.assertFalse(printer.default)
|
||||
|
||||
@mock.patch("%s.cups" % server_model)
|
||||
@mock.patch(f"{server_model}.cups")
|
||||
def test_cancel_all_jobs(self, cups):
|
||||
"""It should cancel all jobs"""
|
||||
printer = self.new_record()
|
||||
@@ -151,7 +167,7 @@ class TestPrintingPrinter(TransactionCase):
|
||||
name=printer.system_name, purge_jobs=False
|
||||
)
|
||||
|
||||
@mock.patch("%s.cups" % server_model)
|
||||
@mock.patch(f"{server_model}.cups")
|
||||
def test_cancel_and_purge_all_jobs(self, cups):
|
||||
"""It should cancel all jobs"""
|
||||
printer = self.new_record()
|
||||
@@ -160,21 +176,21 @@ class TestPrintingPrinter(TransactionCase):
|
||||
name=printer.system_name, purge_jobs=True
|
||||
)
|
||||
|
||||
@mock.patch("%s.cups" % server_model)
|
||||
@mock.patch(f"{server_model}.cups")
|
||||
def test_enable_printer(self, cups):
|
||||
"""It should enable the printer"""
|
||||
printer = self.new_record()
|
||||
printer.enable()
|
||||
cups.Connection().enablePrinter.assert_called_once_with(printer.system_name)
|
||||
|
||||
@mock.patch("%s.cups" % server_model)
|
||||
@mock.patch(f"{server_model}.cups")
|
||||
def test_disable_printer(self, cups):
|
||||
"""It should disable the printer"""
|
||||
printer = self.new_record()
|
||||
printer.disable()
|
||||
cups.Connection().disablePrinter.assert_called_once_with(printer.system_name)
|
||||
|
||||
@mock.patch("%s.cups" % server_model)
|
||||
@mock.patch(f"{server_model}.cups")
|
||||
def test_print_test_page(self, cups):
|
||||
"""It should print a test page"""
|
||||
printer = self.new_record()
|
||||
|
||||
@@ -99,7 +99,7 @@ class TestPrintingPrinter(TransactionCase):
|
||||
}
|
||||
}
|
||||
|
||||
@mock.patch("%s.cups" % server_model)
|
||||
@mock.patch(f"{server_model}.cups")
|
||||
def test_update_printers(self, cups):
|
||||
"""
|
||||
Check that the update_printers method calls _prepare_update_from_cups
|
||||
@@ -111,7 +111,7 @@ class TestPrintingPrinter(TransactionCase):
|
||||
self.ServerModel.update_printers()
|
||||
self.assertEqual(self.printer.name, "My custom name")
|
||||
|
||||
@mock.patch("%s.cups" % server_model)
|
||||
@mock.patch(f"{server_model}.cups")
|
||||
def test_prepare_update_from_cups_no_ppd(self, cups):
|
||||
"""
|
||||
Check that the tray_ids field has no value when no PPD is available
|
||||
@@ -124,7 +124,7 @@ class TestPrintingPrinter(TransactionCase):
|
||||
vals = self.printer._prepare_update_from_cups(connection, cups_printer)
|
||||
self.assertFalse("tray_ids" in vals)
|
||||
|
||||
@mock.patch("%s.cups" % server_model)
|
||||
@mock.patch(f"{server_model}.cups")
|
||||
def test_prepare_update_from_cups_empty_ppd(self, cups):
|
||||
"""
|
||||
Check that the tray_ids field has no value when the PPD file has
|
||||
@@ -142,7 +142,7 @@ class TestPrintingPrinter(TransactionCase):
|
||||
vals = self.printer._prepare_update_from_cups(connection, cups_printer)
|
||||
self.assertFalse("tray_ids" in vals)
|
||||
|
||||
@mock.patch("%s.cups" % server_model)
|
||||
@mock.patch(f"{server_model}.cups")
|
||||
@mock.patch("os.unlink")
|
||||
def test_prepare_update_from_cups_unlink_error(self, os_unlink, cups):
|
||||
"""
|
||||
@@ -159,7 +159,7 @@ class TestPrintingPrinter(TransactionCase):
|
||||
with self.assertRaises(OSError):
|
||||
self.printer._prepare_update_from_cups(connection, cups_printer)
|
||||
|
||||
@mock.patch("%s.cups" % server_model)
|
||||
@mock.patch(f"{server_model}.cups")
|
||||
@mock.patch("os.unlink")
|
||||
def test_prepare_update_from_cups_unlink_error_enoent(self, os_unlink, cups):
|
||||
"""
|
||||
@@ -181,7 +181,7 @@ class TestPrintingPrinter(TransactionCase):
|
||||
[(0, 0, {"name": "Auto (Default)", "system_name": "Auto"})],
|
||||
)
|
||||
|
||||
@mock.patch("%s.cups" % server_model)
|
||||
@mock.patch(f"{server_model}.cups")
|
||||
def test_prepare_update_from_cups(self, cups):
|
||||
"""
|
||||
Check the return value when adding a single tray
|
||||
@@ -197,7 +197,7 @@ class TestPrintingPrinter(TransactionCase):
|
||||
[(0, 0, {"name": "Auto (Default)", "system_name": "Auto"})],
|
||||
)
|
||||
|
||||
@mock.patch("%s.cups" % server_model)
|
||||
@mock.patch(f"{server_model}.cups")
|
||||
def test_prepare_update_from_cups_with_multiple_trays(self, cups):
|
||||
"""
|
||||
Check the return value when adding multiple trays at once
|
||||
@@ -216,7 +216,7 @@ class TestPrintingPrinter(TransactionCase):
|
||||
],
|
||||
)
|
||||
|
||||
@mock.patch("%s.cups" % server_model)
|
||||
@mock.patch(f"{server_model}.cups")
|
||||
def test_prepare_update_from_cups_already_known_trays(self, cups):
|
||||
"""
|
||||
Check that calling the method twice doesn't create the trays multiple
|
||||
@@ -236,7 +236,7 @@ class TestPrintingPrinter(TransactionCase):
|
||||
[(0, 0, {"name": "Auto (Default)", "system_name": "Auto"})],
|
||||
)
|
||||
|
||||
@mock.patch("%s.cups" % server_model)
|
||||
@mock.patch(f"{server_model}.cups")
|
||||
def test_prepare_update_from_cups_unknown_trays(self, cups):
|
||||
"""
|
||||
Check that trays which are not in the PPD file are removed from Odoo
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# Copyright 2016 LasLabs Inc.
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
import logging
|
||||
from unittest import mock
|
||||
|
||||
from odoo.exceptions import UserError
|
||||
@@ -36,7 +37,7 @@ class TestPrintingPrinterWizard(TransactionCase):
|
||||
"uri": self.printer_vals["device-uri"],
|
||||
}
|
||||
|
||||
@mock.patch("%s.cups" % model)
|
||||
@mock.patch(f"{model}.cups")
|
||||
def test_action_ok_inits_connection(self, cups):
|
||||
"""It should initialize CUPS connection"""
|
||||
self.Model.action_ok()
|
||||
@@ -44,7 +45,7 @@ class TestPrintingPrinterWizard(TransactionCase):
|
||||
host=self.server.address, port=self.server.port
|
||||
)
|
||||
|
||||
@mock.patch("%s.cups" % model)
|
||||
@mock.patch(f"{model}.cups")
|
||||
def test_action_ok_gets_printers(self, cups):
|
||||
"""It should get printers from CUPS"""
|
||||
cups.Connection().getPrinters.return_value = {"sys_name": self.printer_vals}
|
||||
@@ -52,14 +53,19 @@ class TestPrintingPrinterWizard(TransactionCase):
|
||||
self.Model.action_ok()
|
||||
cups.Connection().getPrinters.assert_called_once_with()
|
||||
|
||||
@mock.patch("%s.cups" % model)
|
||||
def test_action_ok_raises_warning_on_error(self, cups):
|
||||
def test_action_ok_raises_warning_on_error(self):
|
||||
"""It should raise Warning on any error"""
|
||||
with (
|
||||
mock.patch(f"{model}.cups") as cups,
|
||||
self.assertLogs(level=logging.WARNING) as logs,
|
||||
):
|
||||
cups.Connection.side_effect = StopTest
|
||||
with self.assertRaises(UserError):
|
||||
self.Model.action_ok()
|
||||
self.assertEqual(len(logs.records), 1)
|
||||
self.assertEqual(logs.records[0].levelno, logging.WARNING)
|
||||
|
||||
@mock.patch("%s.cups" % model)
|
||||
@mock.patch(f"{model}.cups")
|
||||
def test_action_ok_creates_new_printer(self, cups):
|
||||
"""It should create new printer w/ proper vals"""
|
||||
cups.Connection().getPrinters.return_value = {"sys_name": self.printer_vals}
|
||||
@@ -75,7 +81,7 @@ class TestPrintingPrinterWizard(TransactionCase):
|
||||
|
||||
self.assertEqual(val, rec_id[key])
|
||||
|
||||
@mock.patch("%s.cups" % model)
|
||||
@mock.patch(f"{model}.cups")
|
||||
def test_action_ok_skips_existing_printer(self, cups):
|
||||
"""It should not recreate existing printers"""
|
||||
cups.Connection().getPrinters.return_value = {"sys_name": self.printer_vals}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# Copyright 2016 LasLabs Inc.
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
import logging
|
||||
from unittest import mock
|
||||
|
||||
from odoo import fields
|
||||
@@ -43,15 +44,20 @@ class TestPrintingServer(TransactionCase):
|
||||
values["printer_id"] = printer.id
|
||||
return self.env["printing.job"].create(values)
|
||||
|
||||
@mock.patch("%s.cups" % model)
|
||||
def test_update_printers_error(self, cups):
|
||||
def test_update_printers_error(self):
|
||||
"""It should catch any exception from CUPS and update status"""
|
||||
with (
|
||||
mock.patch(f"{model}.cups") as cups,
|
||||
self.assertLogs(level=logging.WARNING) as logs,
|
||||
):
|
||||
cups.Connection.side_effect = Exception
|
||||
rec_id = self.new_printer()
|
||||
self.Model.update_printers()
|
||||
self.assertEqual("server-error", rec_id.status)
|
||||
self.assertEqual(len(logs.records), 1)
|
||||
self.assertEqual(logs.records[0].levelno, logging.WARNING)
|
||||
|
||||
@mock.patch("%s.cups" % model)
|
||||
@mock.patch(f"{model}.cups")
|
||||
def test_update_printers_inits_cups(self, cups):
|
||||
"""It should init CUPS connection"""
|
||||
self.new_printer()
|
||||
@@ -60,29 +66,29 @@ class TestPrintingServer(TransactionCase):
|
||||
host=self.server.address, port=self.server.port
|
||||
)
|
||||
|
||||
@mock.patch("%s.cups" % model)
|
||||
@mock.patch(f"{model}.cups")
|
||||
def test_update_printers_gets_all_printers(self, cups):
|
||||
"""It should get all printers from CUPS server"""
|
||||
self.new_printer()
|
||||
self.Model.update_printers()
|
||||
cups.Connection().getPrinters.assert_called_once_with()
|
||||
|
||||
@mock.patch("%s.cups" % model)
|
||||
@mock.patch(f"{model}.cups")
|
||||
def test_update_printers_search(self, cups):
|
||||
"""It should search all when no domain"""
|
||||
with mock.patch("%s.search" % model_base) as search:
|
||||
with mock.patch(f"{model_base}.search") as search:
|
||||
self.Model.update_printers()
|
||||
search.assert_called_once_with([])
|
||||
|
||||
@mock.patch("%s.cups" % model)
|
||||
@mock.patch(f"{model}.cups")
|
||||
def test_update_printers_search_domain(self, cups):
|
||||
"""It should use specific domain for search"""
|
||||
with mock.patch("%s.search" % model_base) as search:
|
||||
with mock.patch(f"{model_base}.search") as search:
|
||||
expect = [("id", ">", 0)]
|
||||
self.Model.update_printers(expect)
|
||||
search.assert_called_once_with(expect)
|
||||
|
||||
@mock.patch("%s.cups" % model)
|
||||
@mock.patch(f"{model}.cups")
|
||||
def test_update_printers_update_unavailable(self, cups):
|
||||
"""It should update status when printer is unavailable"""
|
||||
rec_id = self.new_printer()
|
||||
@@ -90,7 +96,7 @@ class TestPrintingServer(TransactionCase):
|
||||
self.Model.action_update_printers()
|
||||
self.assertEqual("unavailable", rec_id.status)
|
||||
|
||||
@mock.patch("%s.cups" % model)
|
||||
@mock.patch(f"{model}.cups")
|
||||
def test_update_archived_printers(self, cups):
|
||||
"""It should update status even if printer is archived"""
|
||||
rec_id = self.new_printer()
|
||||
@@ -103,7 +109,7 @@ class TestPrintingServer(TransactionCase):
|
||||
rec_id.status,
|
||||
)
|
||||
|
||||
@mock.patch("%s.cups" % model)
|
||||
@mock.patch(f"{model}.cups")
|
||||
def test_update_jobs_cron(self, cups):
|
||||
"""It should get all jobs from CUPS server"""
|
||||
self.new_printer()
|
||||
@@ -125,7 +131,7 @@ class TestPrintingServer(TransactionCase):
|
||||
],
|
||||
)
|
||||
|
||||
@mock.patch("%s.cups" % model)
|
||||
@mock.patch(f"{model}.cups")
|
||||
def test_update_jobs_button(self, cups):
|
||||
"""It should get all jobs from CUPS server"""
|
||||
self.new_printer()
|
||||
@@ -147,17 +153,22 @@ class TestPrintingServer(TransactionCase):
|
||||
],
|
||||
)
|
||||
|
||||
@mock.patch("%s.cups" % model)
|
||||
def test_update_jobs_error(self, cups):
|
||||
def test_update_jobs_error(self):
|
||||
"""It should catch any exception from CUPS and update status"""
|
||||
with (
|
||||
mock.patch(f"{model}.cups") as cups,
|
||||
self.assertLogs(level=logging.WARNING) as logs,
|
||||
):
|
||||
cups.Connection.side_effect = Exception
|
||||
self.new_printer()
|
||||
self.server.update_jobs()
|
||||
cups.Connection.assert_called_with(
|
||||
host=self.server.address, port=self.server.port
|
||||
)
|
||||
self.assertEqual(len(logs.records), 2)
|
||||
self.assertEqual(logs.records[0].levelno, logging.WARNING)
|
||||
|
||||
@mock.patch("%s.cups" % model)
|
||||
@mock.patch(f"{model}.cups")
|
||||
def test_update_jobs_uncompleted(self, cups):
|
||||
"""
|
||||
It should search which jobs have been completed since last update
|
||||
@@ -182,7 +193,7 @@ class TestPrintingServer(TransactionCase):
|
||||
],
|
||||
)
|
||||
|
||||
@mock.patch("%s.cups" % model)
|
||||
@mock.patch(f"{model}.cups")
|
||||
def test_update_jobs(self, cups):
|
||||
"""
|
||||
It should update all jobs, known or not
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
# Copyright 2017 Tecnativa - Jairo Llopis
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
import logging
|
||||
from unittest import mock
|
||||
|
||||
from odoo import exceptions
|
||||
@@ -128,11 +129,14 @@ class TestReport(common.HttpCase):
|
||||
|
||||
def test_render_qweb_pdf_printable(self):
|
||||
"""It should print the report, only if it is printable"""
|
||||
with mock.patch(
|
||||
with (
|
||||
mock.patch(
|
||||
"odoo.addons.base_report_to_printer.models."
|
||||
"printing_printer.PrintingPrinter."
|
||||
"print_document"
|
||||
) as print_document:
|
||||
) as print_document,
|
||||
self.assertLogs(level=logging.WARNING) as logs,
|
||||
):
|
||||
self.report.property_printing_action_id.action_type = "server"
|
||||
self.report.printing_printer_id = self.new_printer()
|
||||
document = self.report._render_qweb_pdf(
|
||||
@@ -145,14 +149,19 @@ class TestReport(common.HttpCase):
|
||||
doc_format="qweb-pdf",
|
||||
tray=False,
|
||||
)
|
||||
self.assertEqual(len(logs.records), 1)
|
||||
self.assertEqual(logs.records[0].levelno, logging.WARNING)
|
||||
|
||||
def test_render_qweb_text_printable(self):
|
||||
"""It should print the report, only if it is printable"""
|
||||
with mock.patch(
|
||||
with (
|
||||
mock.patch(
|
||||
"odoo.addons.base_report_to_printer.models."
|
||||
"printing_printer.PrintingPrinter."
|
||||
"print_document"
|
||||
) as print_document:
|
||||
) as print_document,
|
||||
self.assertLogs(level=logging.WARNING) as logs,
|
||||
):
|
||||
self.report_text.property_printing_action_id.action_type = "server"
|
||||
self.report_text.printing_printer_id = self.new_printer()
|
||||
document = self.report_text._render_qweb_text(
|
||||
@@ -165,29 +174,41 @@ class TestReport(common.HttpCase):
|
||||
doc_format="qweb-text",
|
||||
tray=False,
|
||||
)
|
||||
self.assertEqual(len(logs.records), 1)
|
||||
self.assertEqual(logs.records[0].levelno, logging.WARNING)
|
||||
|
||||
def test_print_document_not_printable(self):
|
||||
"""It should print the report, regardless of the defined behaviour"""
|
||||
self.report.printing_printer_id = self.new_printer()
|
||||
with mock.patch(
|
||||
with (
|
||||
mock.patch(
|
||||
"odoo.addons.base_report_to_printer.models."
|
||||
"printing_printer.PrintingPrinter."
|
||||
"print_document"
|
||||
) as print_document:
|
||||
) as print_document,
|
||||
self.assertLogs(level=logging.WARNING) as logs,
|
||||
):
|
||||
self.report.print_document(self.partners.ids)
|
||||
print_document.assert_called_once()
|
||||
self.assertEqual(len(logs.records), 2)
|
||||
self.assertEqual(logs.records[0].levelno, logging.WARNING)
|
||||
|
||||
def test_print_document_printable(self):
|
||||
"""It should print the report, regardless of the defined behaviour"""
|
||||
self.report.property_printing_action_id.action_type = "server"
|
||||
self.report.printing_printer_id = self.new_printer()
|
||||
with mock.patch(
|
||||
with (
|
||||
mock.patch(
|
||||
"odoo.addons.base_report_to_printer.models."
|
||||
"printing_printer.PrintingPrinter."
|
||||
"print_document"
|
||||
) as print_document:
|
||||
) as print_document,
|
||||
self.assertLogs(level=logging.WARNING) as logs,
|
||||
):
|
||||
self.report.print_document(self.partners.ids)
|
||||
print_document.assert_called_once()
|
||||
self.assertEqual(len(logs.records), 2)
|
||||
self.assertEqual(logs.records[0].levelno, logging.WARNING)
|
||||
|
||||
def test_print_document_no_printer(self):
|
||||
"""It should raise an error"""
|
||||
|
||||
@@ -36,11 +36,11 @@
|
||||
<field name="name">printing.job.tree (in base_report_to_printer)</field>
|
||||
<field name="model">printing.job</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree>
|
||||
<list>
|
||||
<field name="name" />
|
||||
<field name="job_id_cups" />
|
||||
<field name="job_state" />
|
||||
</tree>
|
||||
</list>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
|
||||
@@ -101,7 +101,7 @@
|
||||
<field name="name">printing.printer.tree (in base_report_to_printer)</field>
|
||||
<field name="model">printing.printer</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree
|
||||
<list
|
||||
decoration-success="status=='available'"
|
||||
decoration-warning="status=='printing'"
|
||||
decoration-danger="status not in ['printing', 'available']"
|
||||
@@ -111,7 +111,7 @@
|
||||
<field name="system_name" />
|
||||
<field name="server_id" />
|
||||
<field name="status" />
|
||||
</tree>
|
||||
</list>
|
||||
</field>
|
||||
</record>
|
||||
<record model="ir.ui.view" id="printing_printer_view_search">
|
||||
@@ -135,7 +135,7 @@
|
||||
<field name="name">Show Printers</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">printing.printer</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="view_mode">list,form</field>
|
||||
</record>
|
||||
<menuitem
|
||||
name="Printers"
|
||||
|
||||
@@ -21,12 +21,12 @@
|
||||
>printing.report.xml.action.tree (in base_report_to_printer)</field>
|
||||
<field name="model">printing.report.xml.action</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree>
|
||||
<list>
|
||||
<field name="user_id" />
|
||||
<field name="action" />
|
||||
<field name="printer_id" />
|
||||
<field name="printer_tray_id" />
|
||||
</tree>
|
||||
</list>
|
||||
</field>
|
||||
</record>
|
||||
<!-- Add a shorcut to "Actions/Report" in the Printing menu -->
|
||||
|
||||
@@ -45,11 +45,11 @@
|
||||
<field name="name">printing.server.tree (in base_report_to_printer)</field>
|
||||
<field name="model">printing.server</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree>
|
||||
<list>
|
||||
<field name="name" />
|
||||
<field name="address" />
|
||||
<field name="port" />
|
||||
</tree>
|
||||
</list>
|
||||
</field>
|
||||
</record>
|
||||
<record model="ir.ui.view" id="printing_server_view_search">
|
||||
@@ -67,7 +67,7 @@
|
||||
<field name="name">Servers</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">printing.server</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="view_mode">list,form</field>
|
||||
</record>
|
||||
<menuitem
|
||||
name="Servers"
|
||||
|
||||
@@ -8,11 +8,11 @@
|
||||
<group>
|
||||
<field name="printer_id" />
|
||||
<field name="attachment_line_ids">
|
||||
<tree editable="top">
|
||||
<list editable="top">
|
||||
<field name="attachment_id" create="0" />
|
||||
<field name="record_name" />
|
||||
<field name="copies" />
|
||||
</tree>
|
||||
</list>
|
||||
</field>
|
||||
</group>
|
||||
<footer>
|
||||
|
||||
@@ -20,7 +20,7 @@ class PrintingPrinterUpdateWizard(models.TransientModel):
|
||||
|
||||
return {
|
||||
"name": "Printers",
|
||||
"view_mode": "tree,form",
|
||||
"view_mode": "list,form",
|
||||
"res_model": "printing.printer",
|
||||
"type": "ir.actions.act_window",
|
||||
"target": "current",
|
||||
|
||||
Reference in New Issue
Block a user