diff --git a/base_report_to_printer/models/ir_actions_report.py b/base_report_to_printer/models/ir_actions_report.py index 8f0c203..e6d078c 100644 --- a/base_report_to_printer/models/ir_actions_report.py +++ b/base_report_to_printer/models/ir_actions_report.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- # Copyright (c) 2007 Ferran Pegueroles # Copyright (c) 2009 Albert Cervera i Areny # Copyright (C) 2011 Agile Business Group sagl () @@ -55,21 +56,35 @@ class IrActionsReport(models.Model): return serializable_result @api.multi - def behaviour(self): - self.ensure_one() + def _get_user_default_print_behaviour(self): printer_obj = self.env['printing.printer'] - printing_act_obj = self.env['printing.report.xml.action'] - # Retrieve user defaults or system defaults user = self.env.user - action = user.printing_action or 'client' - printer = user.printing_printer_id or printer_obj.get_default() + return dict( + action=user.printing_action or 'client', + printer=user.printing_printer_id or printer_obj.get_default(), + tray=str(user.printer_tray_id.system_name) if + user.printer_tray_id else False + ) - # Retrieve report default values + @api.multi + def _get_report_default_print_behaviour(self): + result = {} report_action = self.property_printing_action_id if report_action and report_action.action_type != 'user_default': - action = report_action.action_type + result['action'] = report_action.action_type if self.printing_printer_id: - printer = self.printing_printer_id + result['printer'] = self.printing_printer_id + if self.printer_tray_id: + result['tray'] = self.printer_tray_id.system_name + return result + + @api.multi + def behaviour(self): + self.ensure_one() + printing_act_obj = self.env['printing.report.xml.action'] + + result = self._get_user_default_print_behaviour() + result.update(self._get_report_default_print_behaviour()) # Retrieve report-user specific values print_action = printing_act_obj.search([ @@ -78,26 +93,29 @@ class IrActionsReport(models.Model): ('action', '!=', 'user_default'), ], limit=1) if print_action: - user_action = print_action.behaviour() - action = user_action['action'] - if user_action['printer']: - printer = user_action['printer'] - - return {'action': action, 'printer': printer} + # For some reason design takes report defaults over + # False action entries so we must allow for that here + result.update({k: v for k, v in + print_action.behaviour().items() if v}) + return result @api.multi def print_document(self, record_ids, data=None): """ Print a document, do not return the document file """ - document = self.with_context( + document, doc_format = self.with_context( must_skip_send_to_printer=True).render_qweb_pdf( record_ids, data=data) behaviour = self.behaviour() - printer = behaviour['printer'] + printer = behaviour.pop('printer', None) + if not printer: raise exceptions.Warning( _('No printer configured to print this report.') ) - return printer.print_document(self, document, self.report_type) + # TODO should we use doc_format instead of report_type + return printer.print_document(self, document, + doc_format=self.report_type, + **behaviour) @api.multi def _can_print_report(self, behaviour, printer, document): @@ -123,10 +141,11 @@ class IrActionsReport(models.Model): docids, data=data) behaviour = self.behaviour() - printer = behaviour['printer'] + printer = behaviour.pop('printer', None) can_print_report = self._can_print_report(behaviour, printer, document) if can_print_report: - printer.print_document(self, document, self.report_type) + printer.print_document(self, document, doc_format=self.report_type, + **behaviour) return document, doc_format diff --git a/base_report_to_printer/models/printing_printer.py b/base_report_to_printer/models/printing_printer.py index 83b7fc4..057f874 100644 --- a/base_report_to_printer/models/printing_printer.py +++ b/base_report_to_printer/models/printing_printer.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- # Copyright (c) 2007 Ferran Pegueroles # Copyright (c) 2009 Albert Cervera i Areny # Copyright (C) 2011 Agile Business Group sagl () @@ -117,36 +118,7 @@ class PrintingPrinter(models.Model): return vals @api.multi - def print_options(self, report=None, format=None, copies=1): - """ Hook to set print options """ - options = {} - if format == 'raw': - options['raw'] = 'True' - if copies > 1: - options['copies'] = str(copies) - if report is not None: - printing_act_obj = self.env['printing.report.xml.action'] - if report.printer_tray_id: - tray = report.printer_tray_id - else: - # Retrieve user default values - tray = self.env.user.printer_tray_id - - # Retrieve report-user specific values - action = printing_act_obj.search([ - ('report_id', '=', report.id), - ('user_id', '=', self.env.uid), - ('action', '!=', 'user_default'), - ], limit=1) - if action.printer_tray_id: - tray = action.printer_tray_id - - if tray: - options['InputSlot'] = str(tray.system_name) - return options - - @api.multi - def print_document(self, report, content, format, copies=1): + def print_document(self, report, content, **print_opts): """ Print a file Format could be pdf, qweb-pdf, raw, ... @@ -160,16 +132,48 @@ class PrintingPrinter(models.Model): os.close(fd) return self.print_file( - file_name, report=report, copies=copies, format=format) + file_name, report=report, **print_opts) + + @staticmethod + def _set_option_doc_format(report, value): + return {'raw': 'True'} if value == 'raw' else {} + + # Backwards compatibility of builtin used as kwarg + _set_option_format = _set_option_doc_format @api.multi - def print_file(self, file_name, report=None, copies=1, format=None): + def _set_option_tray(self, report, value): + """Note we use self here as some older PPD use tray + rather than InputSlot so we may need to query printer in override""" + return {'InputSlot': str(value)} if value else {} + + @staticmethod + def _set_option_noop(report, value): + return {} + + _set_option_action = _set_option_noop + _set_option_printer = _set_option_noop + + @api.multi + def print_options(self, report=None, **print_opts): + options = {} + if not report: + return options + + for option, value in print_opts.items(): + try: + options.update(getattr( + self, '_set_option_%s' % option)(report, value)) + except AttributeError: + options[option] = str(value) + return options + + @api.multi + def print_file(self, file_name, report=None, **print_opts): """ Print a file """ self.ensure_one() - connection = self.server_id._open_connection(raise_on_error=True) - options = self.print_options( - report=report, format=format, copies=copies) + options = self.print_options(report=report, **print_opts) _logger.debug( 'Sending job to CUPS printer %s on %s' 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 a85b750..22c5c04 100644 --- a/base_report_to_printer/tests/test_ir_actions_report.py +++ b/base_report_to_printer/tests/test_ir_actions_report.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- # Copyright 2016 LasLabs Inc. # Copyright 2016 SYLEAM # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). @@ -43,6 +44,12 @@ class TestIrActionsReportXml(TransactionCase): 'uri': 'URI', }) + def new_tray(self, vals=None, defaults=None): + values = dict(defaults) + if vals is not None: + values.update(vals) + return self.env['printing.tray'].create(values) + def test_print_action_for_report_name_gets_report(self): """ It should get report by name """ with mock.patch.object(self.Model, '_get_report_from_name') as mk: @@ -86,7 +93,9 @@ class TestIrActionsReportXml(TransactionCase): self.assertEqual(report.behaviour(), { 'action': 'client', 'printer': self.env['printing.printer'], - }) + 'tray': False, + }, + ) def test_behaviour_user_values(self): """ It should return the action and printer from user """ @@ -96,7 +105,9 @@ class TestIrActionsReportXml(TransactionCase): self.assertEqual(report.behaviour(), { 'action': 'client', 'printer': self.env.user.printing_printer_id, - }) + 'tray': False, + }, + ) def test_behaviour_report_values(self): """ It should return the action and printer from report """ @@ -105,9 +116,11 @@ class TestIrActionsReportXml(TransactionCase): report.property_printing_action_id = self.new_action() report.printing_printer_id = self.new_printer() self.assertEqual(report.behaviour(), { - 'action': report.property_printing_action_id.action_type, - 'printer': report.printing_printer_id, - }) + 'action': report.property_printing_action_id.action_type, + 'printer': report.printing_printer_id, + 'tray': False, + }, + ) def test_behaviour_user_action(self): """ It should return the action and printer from user action""" @@ -115,9 +128,11 @@ class TestIrActionsReportXml(TransactionCase): self.env.user.printing_action = 'client' report.property_printing_action_id.action_type = 'user_default' self.assertEqual(report.behaviour(), { - 'action': 'client', - 'printer': report.printing_printer_id, - }) + 'action': 'client', + 'printer': report.printing_printer_id, + 'tray': False, + }, + ) def test_behaviour_printing_action_on_wrong_user(self): """ It should return the action and printer ignoring printing action @@ -131,7 +146,9 @@ class TestIrActionsReportXml(TransactionCase): self.assertEqual(report.behaviour(), { 'action': 'client', 'printer': report.printing_printer_id, - }) + 'tray': False, + }, + ) def test_behaviour_printing_action_on_wrong_report(self): """ It should return the action and printer ignoring printing action @@ -146,7 +163,9 @@ class TestIrActionsReportXml(TransactionCase): self.assertEqual(report.behaviour(), { 'action': 'client', 'printer': report.printing_printer_id, - }) + 'tray': False, + }, + ) def test_behaviour_printing_action_with_no_printer(self): """ It should return the action from printing action and printer from other @@ -157,9 +176,11 @@ class TestIrActionsReportXml(TransactionCase): printing_action.user_id = self.env.user printing_action.report_id = report self.assertEqual(report.behaviour(), { - 'action': printing_action.action, - 'printer': report.printing_printer_id, - }) + 'action': printing_action.action, + 'printer': report.printing_printer_id, + 'tray': False, + }, + ) def test_behaviour_printing_action_with_printer(self): """ It should return the action and printer from printing action """ @@ -171,7 +192,9 @@ class TestIrActionsReportXml(TransactionCase): self.assertEqual(report.behaviour(), { 'action': printing_action.action, 'printer': printing_action.printer_id, - }) + 'tray': False, + }, + ) def test_behaviour_printing_action_user_defaults(self): """ It should return the action and printer from user with printing action @@ -182,9 +205,73 @@ class TestIrActionsReportXml(TransactionCase): printing_action.user_id = self.env.user printing_action.action = 'user_default' self.assertEqual(report.behaviour(), { - 'action': 'client', - 'printer': report.printing_printer_id, + 'action': 'client', + 'printer': report.printing_printer_id, + 'tray': False, + }, + ) + + def test_print_tray_behaviour(self): + """ + It should return the correct tray + """ + report = self.env['ir.actions.report'].search([], limit=1) + action = self.env['printing.report.xml.action'].create({ + '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, + } + 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) + + # No report passed + self.env.user.printer_tray_id = False + options = printer.print_options() + self.assertFalse('InputSlot' in options) + + # No tray defined + self.env.user.printer_tray_id = False + report.printer_tray_id = False + action.printer_tray_id = False + options = report.behaviour() + self.assertTrue('tray' in options) + + # Only user tray is defined + self.env.user.printer_tray_id = user_tray + report.printer_tray_id = False + action.printer_tray_id = False + self.assertEqual('User tray', report.behaviour()['tray']) + + # Only report tray is defined + self.env.user.printer_tray_id = False + report.printer_tray_id = report_tray + action.printer_tray_id = False + self.assertEqual('Report tray', report.behaviour()['tray']) + + # Only action tray is defined + self.env.user.printer_tray_id = False + report.printer_tray_id = False + action.printer_tray_id = action_tray + self.assertEqual('Action tray', report.behaviour()['tray']) + + # User and report tray defined + self.env.user.printer_tray_id = user_tray + report.printer_tray_id = report_tray + action.printer_tray_id = False + self.assertEqual('Report tray', report.behaviour()['tray']) + + # All trays are defined + self.env.user.printer_tray_id = user_tray + report.printer_tray_id = report_tray + action.printer_tray_id = action_tray + self.assertEqual('Action tray', report.behaviour()['tray']) def test_onchange_printer_tray_id_empty(self): action = self.env['ir.actions.report'].new( diff --git a/base_report_to_printer/tests/test_printing_printer.py b/base_report_to_printer/tests/test_printing_printer.py index ec09929..bcec2be 100644 --- a/base_report_to_printer/tests/test_printing_printer.py +++ b/base_report_to_printer/tests/test_printing_printer.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- # Copyright 2016 LasLabs Inc. # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). @@ -35,20 +36,53 @@ class TestPrintingPrinter(TransactionCase): def new_record(self): return self.Model.create(self.printer_vals) - def test_printing_options(self): + def test_option_tray(self): + """ + It should put the value in InputSlot + """ + self.assertEqual(self.Model._set_option_tray(None, 'Test Tray'), + {'InputSlot': 'Test Tray'}) + self.assertEqual(self.Model._set_option_tray(None, False), + {}) + + def test_option_noops(self): + """ + Noops should return an empty dict + """ + self.assertEqual(self.Model._set_option_action(None, 'printer'), {}) + self.assertEqual(self.Model._set_option_printer(None, self.Model), {}) + + def test_option_doc_format(self): + """ + Raw documents should set raw boolean. + """ + self.assertEqual(self.Model._set_option_doc_format(None, 'raw'), + {'raw': 'True'}) + # Deprecate _set_option_format in v12. + self.assertEqual(self.Model._set_option_format(None, 'raw'), + {'raw': 'True'}) + + self.assertEqual(self.Model._set_option_doc_format(None, 'pdf'), {}) + # Deprecate _set_option_format in v12. + self.assertEqual(self.Model._set_option_format(None, 'pdf'), {}) + + def test_print_options(self): """ It should generate the right options dictionnary """ # TODO: None here used as report - tests here should be merged # with tests in test_printing_printer_tray from when modules merged - self.assertEqual(self.Model.print_options(None, 'raw'), { - 'raw': 'True', - }) - self.assertEqual(self.Model.print_options(None, 'pdf', 2), { - 'copies': '2', - }) - self.assertEqual(self.Model.print_options(None, 'raw', 2), { - 'raw': 'True', - 'copies': '2', - }) + report = self.env['ir.actions.report'].search([], limit=1) + self.assertEqual(self.Model.print_options( + report, doc_format='raw'), {'raw': 'True'} + ) + self.assertEqual(self.Model.print_options( + report, doc_format='pdf', copies=2), {'copies': '2'} + ) + self.assertEqual(self.Model.print_options( + report, doc_format='raw', copies=2), + {'raw': 'True', 'copies': '2'} + ) + self.assertTrue('InputSlot' in self.Model.print_options(report, + tray='Test')) @mock.patch('%s.cups' % server_model) def test_print_report(self, cups): @@ -57,7 +91,8 @@ class TestPrintingPrinter(TransactionCase): with mock.patch('%s.mkstemp' % model) as mkstemp: mkstemp.return_value = fd, file_name printer = self.new_record() - printer.print_document(self.report, b'content to print', 'pdf') + printer.print_document(self.report, b'content to print', + doc_format='pdf') cups.Connection().printFile.assert_called_once_with( printer.system_name, file_name, @@ -74,7 +109,7 @@ class TestPrintingPrinter(TransactionCase): printer = self.new_record() with self.assertRaises(UserError): printer.print_document( - self.report, b'content to print', 'pdf') + self.report, b'content to print', doc_format='pdf') @mock.patch('%s.cups' % server_model) def test_print_file(self, cups): 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 72ba781..ee3f28e 100644 --- a/base_report_to_printer/tests/test_printing_printer_tray.py +++ b/base_report_to_printer/tests/test_printing_printer_tray.py @@ -99,74 +99,6 @@ class TestPrintingPrinter(TransactionCase): }, } - def test_print_options(self): - """ - It should generate the right options dictionnary - """ - report = self.env['ir.actions.report'].search([], limit=1) - action = self.env['printing.report.xml.action'].create({ - 'user_id': self.env.user.id, - 'report_id': report.id, - 'action': 'server', - }) - user_tray = self.new_tray({ - 'system_name': 'User tray', - }) - report_tray = self.new_tray({ - 'system_name': 'Report tray', - }) - action_tray = self.new_tray({ - 'system_name': 'Action tray', - }) - - # No report passed - self.env.user.printer_tray_id = False - options = self.Model.print_options() - self.assertFalse('InputSlot' in options) - - # No tray defined - self.env.user.printer_tray_id = False - report.printer_tray_id = False - action.printer_tray_id = False - options = self.Model.print_options(report, 'pdf') - self.assertFalse('InputSlot' in options) - - # Only user tray is defined - self.env.user.printer_tray_id = user_tray - report.printer_tray_id = False - action.printer_tray_id = False - options = self.Model.print_options(report, 'pdf') - self.assertEquals(options, { - 'InputSlot': 'User tray', - }) - - # Only report tray is defined - self.env.user.printer_tray_id = False - report.printer_tray_id = report_tray - action.printer_tray_id = False - options = self.Model.print_options(report, 'pdf') - self.assertEquals(options, { - 'InputSlot': 'Report tray', - }) - - # Only action tray is defined - self.env.user.printer_tray_id = False - report.printer_tray_id = False - action.printer_tray_id = action_tray - options = self.Model.print_options(report, 'pdf') - self.assertEquals(options, { - 'InputSlot': 'Action tray', - }) - - # All trays are defined - self.env.user.printer_tray_id = user_tray - report.printer_tray_id = report_tray - action.printer_tray_id = action_tray - options = self.Model.print_options(report, 'pdf') - self.assertEquals(options, { - 'InputSlot': 'Action tray', - }) - @mock.patch('%s.cups' % server_model) def test_update_printers(self, cups): """ diff --git a/base_report_to_printer/tests/test_report.py b/base_report_to_printer/tests/test_report.py index 618311d..d4d5f09 100644 --- a/base_report_to_printer/tests/test_report.py +++ b/base_report_to_printer/tests/test_report.py @@ -89,7 +89,8 @@ class TestReport(HttpCase): records = self.env[report.model].search([], limit=5) document, doc_format = report.render_qweb_pdf(records.ids) print_document.assert_called_once_with( - report, document, report.report_type) + report, document, + action='server', doc_format='qweb-pdf', tray=False) def test_print_document_not_printable(self): """ It should print the report, regardless of the defined behaviour """