From 2201af66b8842a604e86ff69facf6c15b5155409 Mon Sep 17 00:00:00 2001 From: Guewen Baconnier Date: Wed, 12 Nov 2014 09:44:54 +0100 Subject: [PATCH 01/26] Move base_report_to_printer to root from __unported__ --- .../base_report_to_printer => base_report_to_printer}/__init__.py | 0 .../__openerp__.py | 0 .../i18n/base_report_to_printer.pot | 0 .../base_report_to_printer => base_report_to_printer}/i18n/fr.po | 0 .../base_report_to_printer => base_report_to_printer}/i18n/it.po | 0 .../ir_report.py | 0 .../base_report_to_printer => base_report_to_printer}/printing.py | 0 .../printing_data.xml | 0 .../printing_view.xml | 0 .../report_service.py | 0 .../report_xml_action.py | 0 .../security/security.xml | 0 .../base_report_to_printer => base_report_to_printer}/users.py | 0 .../wizard/__init__.py | 0 .../wizard/update_printers.py | 0 .../wizard/update_printers.xml | 0 16 files changed, 0 insertions(+), 0 deletions(-) rename {__unported__/base_report_to_printer => base_report_to_printer}/__init__.py (100%) rename {__unported__/base_report_to_printer => base_report_to_printer}/__openerp__.py (100%) rename {__unported__/base_report_to_printer => base_report_to_printer}/i18n/base_report_to_printer.pot (100%) rename {__unported__/base_report_to_printer => base_report_to_printer}/i18n/fr.po (100%) rename {__unported__/base_report_to_printer => base_report_to_printer}/i18n/it.po (100%) rename {__unported__/base_report_to_printer => base_report_to_printer}/ir_report.py (100%) rename {__unported__/base_report_to_printer => base_report_to_printer}/printing.py (100%) rename {__unported__/base_report_to_printer => base_report_to_printer}/printing_data.xml (100%) rename {__unported__/base_report_to_printer => base_report_to_printer}/printing_view.xml (100%) rename {__unported__/base_report_to_printer => base_report_to_printer}/report_service.py (100%) rename {__unported__/base_report_to_printer => base_report_to_printer}/report_xml_action.py (100%) rename {__unported__/base_report_to_printer => base_report_to_printer}/security/security.xml (100%) rename {__unported__/base_report_to_printer => base_report_to_printer}/users.py (100%) rename {__unported__/base_report_to_printer => base_report_to_printer}/wizard/__init__.py (100%) rename {__unported__/base_report_to_printer => base_report_to_printer}/wizard/update_printers.py (100%) rename {__unported__/base_report_to_printer => base_report_to_printer}/wizard/update_printers.xml (100%) diff --git a/__unported__/base_report_to_printer/__init__.py b/base_report_to_printer/__init__.py similarity index 100% rename from __unported__/base_report_to_printer/__init__.py rename to base_report_to_printer/__init__.py diff --git a/__unported__/base_report_to_printer/__openerp__.py b/base_report_to_printer/__openerp__.py similarity index 100% rename from __unported__/base_report_to_printer/__openerp__.py rename to base_report_to_printer/__openerp__.py diff --git a/__unported__/base_report_to_printer/i18n/base_report_to_printer.pot b/base_report_to_printer/i18n/base_report_to_printer.pot similarity index 100% rename from __unported__/base_report_to_printer/i18n/base_report_to_printer.pot rename to base_report_to_printer/i18n/base_report_to_printer.pot diff --git a/__unported__/base_report_to_printer/i18n/fr.po b/base_report_to_printer/i18n/fr.po similarity index 100% rename from __unported__/base_report_to_printer/i18n/fr.po rename to base_report_to_printer/i18n/fr.po diff --git a/__unported__/base_report_to_printer/i18n/it.po b/base_report_to_printer/i18n/it.po similarity index 100% rename from __unported__/base_report_to_printer/i18n/it.po rename to base_report_to_printer/i18n/it.po diff --git a/__unported__/base_report_to_printer/ir_report.py b/base_report_to_printer/ir_report.py similarity index 100% rename from __unported__/base_report_to_printer/ir_report.py rename to base_report_to_printer/ir_report.py diff --git a/__unported__/base_report_to_printer/printing.py b/base_report_to_printer/printing.py similarity index 100% rename from __unported__/base_report_to_printer/printing.py rename to base_report_to_printer/printing.py diff --git a/__unported__/base_report_to_printer/printing_data.xml b/base_report_to_printer/printing_data.xml similarity index 100% rename from __unported__/base_report_to_printer/printing_data.xml rename to base_report_to_printer/printing_data.xml diff --git a/__unported__/base_report_to_printer/printing_view.xml b/base_report_to_printer/printing_view.xml similarity index 100% rename from __unported__/base_report_to_printer/printing_view.xml rename to base_report_to_printer/printing_view.xml diff --git a/__unported__/base_report_to_printer/report_service.py b/base_report_to_printer/report_service.py similarity index 100% rename from __unported__/base_report_to_printer/report_service.py rename to base_report_to_printer/report_service.py diff --git a/__unported__/base_report_to_printer/report_xml_action.py b/base_report_to_printer/report_xml_action.py similarity index 100% rename from __unported__/base_report_to_printer/report_xml_action.py rename to base_report_to_printer/report_xml_action.py diff --git a/__unported__/base_report_to_printer/security/security.xml b/base_report_to_printer/security/security.xml similarity index 100% rename from __unported__/base_report_to_printer/security/security.xml rename to base_report_to_printer/security/security.xml diff --git a/__unported__/base_report_to_printer/users.py b/base_report_to_printer/users.py similarity index 100% rename from __unported__/base_report_to_printer/users.py rename to base_report_to_printer/users.py diff --git a/__unported__/base_report_to_printer/wizard/__init__.py b/base_report_to_printer/wizard/__init__.py similarity index 100% rename from __unported__/base_report_to_printer/wizard/__init__.py rename to base_report_to_printer/wizard/__init__.py diff --git a/__unported__/base_report_to_printer/wizard/update_printers.py b/base_report_to_printer/wizard/update_printers.py similarity index 100% rename from __unported__/base_report_to_printer/wizard/update_printers.py rename to base_report_to_printer/wizard/update_printers.py diff --git a/__unported__/base_report_to_printer/wizard/update_printers.xml b/base_report_to_printer/wizard/update_printers.xml similarity index 100% rename from __unported__/base_report_to_printer/wizard/update_printers.xml rename to base_report_to_printer/wizard/update_printers.xml From 20757270bca261f2a0316cd8075a0ede15716c77 Mon Sep 17 00:00:00 2001 From: Guewen Baconnier Date: Wed, 12 Nov 2014 17:03:30 +0100 Subject: [PATCH 02/26] Set module installable --- base_report_to_printer/__openerp__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base_report_to_printer/__openerp__.py b/base_report_to_printer/__openerp__.py index ffc985bd9be..b7b5eb48992 100644 --- a/base_report_to_printer/__openerp__.py +++ b/base_report_to_printer/__openerp__.py @@ -88,7 +88,7 @@ 'printing_view.xml', 'wizard/update_printers.xml', ], - 'installable': False, + 'installable': True, 'auto_install': False, 'application': True, 'external_dependencies': { From 3c65ba89a48fe3408812a1ee5e0e9b9db701a1d7 Mon Sep 17 00:00:00 2001 From: Guewen Baconnier Date: Wed, 12 Nov 2014 17:04:14 +0100 Subject: [PATCH 03/26] Extract description of the module in README.RST --- base_report_to_printer/README.rst | 49 +++++++++++++++++++++++++ base_report_to_printer/__openerp__.py | 52 --------------------------- 2 files changed, 49 insertions(+), 52 deletions(-) create mode 100644 base_report_to_printer/README.rst diff --git a/base_report_to_printer/README.rst b/base_report_to_printer/README.rst new file mode 100644 index 00000000000..3438856a9c4 --- /dev/null +++ b/base_report_to_printer/README.rst @@ -0,0 +1,49 @@ +Report to printer +----------------- +This module allows users to send reports to a printer attached to the server. + + +It adds an optional behaviour on reports to send it directly to a printer. + +* `Send to Client` is the default behavious providing you a downloadable PDF +* `Send to Printer` prints the report on selected printer + +Report behaviour is defined by settings. + + +Settings can be configured: + +* globaly +* per user +* per report +* per user and report + + +After installing enable the "Printing / Print Operator" option under access +rights to give users the ability to view the print menu. + + +To show all available printers for your server, uses +`Settings/Configuration/Printing/Update Printers from CUPS` wizard. + + +Then goto the user profile and set the users printing action and default +printer. + + +Dependencies +------------ + +This module requires pycups +https://pypi.python.org/pypi/pycups + + +Contributors +------------ + +* Ferran Pegueroles +* Albert Cervera i Areny +* Davide Corio +* Lorenzo Battistini +* Yannick Vaucher +* Lionel Sausin diff --git a/base_report_to_printer/__openerp__.py b/base_report_to_printer/__openerp__.py index b7b5eb48992..76595568d91 100644 --- a/base_report_to_printer/__openerp__.py +++ b/base_report_to_printer/__openerp__.py @@ -26,58 +26,6 @@ 'name': "Report to printer", 'version': '0.1.1', 'category': 'Generic Modules/Base', - 'description': """ -Report to printer ------------------ -This module allows users to send reports to a printer attached to the server. - - -It adds an optional behaviour on reports to send it directly to a printer. - -* `Send to Client` is the default behavious providing you a downloadable PDF -* `Send to Printer` prints the report on selected printer - -Report behaviour is defined by settings. - - -Settings can be configured: - -* globaly -* per user -* per report -* per user and report - - -After installing enable the "Printing / Print Operator" option under access -rights to give users the ability to view the print menu. - - -To show all available printers for your server, uses -`Settings/Configuration/Printing/Update Printers from CUPS` wizard. - - -Then goto the user profile and set the users printing action and default -printer. - - -Dependencies ------------- - -This module requires pycups -https://pypi.python.org/pypi/pycups - - -Contributors ------------- - -* Ferran Pegueroles -* Albert Cervera i Areny -* Davide Corio -* Lorenzo Battistini -* Yannick Vaucher -* Lionel Sausin - - """, 'author': 'Agile Business Group & Domsense, Pegueroles SCP, NaN', 'website': 'http://www.agilebg.com', 'license': 'AGPL-3', From 934b1abda9a0dd6810bfb32837372716332c716b Mon Sep 17 00:00:00 2001 From: Guewen Baconnier Date: Wed, 12 Nov 2014 17:29:24 +0100 Subject: [PATCH 04/26] base_calendar passed away --- base_report_to_printer/__openerp__.py | 3 +- base_report_to_printer/report_service.py | 87 ++++++++++++------------ 2 files changed, 46 insertions(+), 44 deletions(-) diff --git a/base_report_to_printer/__openerp__.py b/base_report_to_printer/__openerp__.py index 76595568d91..c7fadbb48d3 100644 --- a/base_report_to_printer/__openerp__.py +++ b/base_report_to_printer/__openerp__.py @@ -29,7 +29,8 @@ 'author': 'Agile Business Group & Domsense, Pegueroles SCP, NaN', 'website': 'http://www.agilebg.com', 'license': 'AGPL-3', - "depends": ['base', 'base_calendar'], + "depends": ['base', + ], 'data': [ 'security/security.xml', 'printing_data.xml', diff --git a/base_report_to_printer/report_service.py b/base_report_to_printer/report_service.py index d4f936be3f6..47a80fd4f48 100644 --- a/base_report_to_printer/report_service.py +++ b/base_report_to_printer/report_service.py @@ -22,56 +22,57 @@ # along with this program. If not, see . # ############################################################################## -import base64 +# TODO check if we have to remove +# import base64 -from openerp import pooler -from openerp.addons.base_calendar import base_calendar +# from openerp import pooler +# from openerp.addons.base_calendar import base_calendar -class virtual_report_spool(base_calendar.virtual_report_spool): +# class virtual_report_spool(base_calendar.virtual_report_spool): - def exp_report(self, db, uid, object, ids, datas=None, context=None): - res = super(virtual_report_spool, self).exp_report(db, uid, object, ids, datas, context) - self._reports[res]['report_name'] = object - return res +# def exp_report(self, db, uid, object, ids, datas=None, context=None): +# res = super(virtual_report_spool, self).exp_report(db, uid, object, ids, datas, context) +# self._reports[res]['report_name'] = object +# return res - def exp_report_get(self, db, uid, report_id): +# def exp_report_get(self, db, uid, report_id): - cr = pooler.get_db(db).cursor() - try: - pool = pooler.get_pool(cr.dbname) - # First of all load report defaults: name, action and printer - report_obj = pool.get('ir.actions.report.xml') - report = report_obj.search( - cr, uid, [('report_name', '=', self._reports[report_id]['report_name'])]) - if report: - report = report_obj.browse(cr, uid, report[0]) - data = report.behaviour()[report.id] - action = data['action'] - printer = data['printer'] - if action != 'client': - if (self._reports and self._reports.get(report_id, False) - and self._reports[report_id].get('result', False) - and self._reports[report_id].get('format', False)): - report_obj.print_direct( - cr, uid, report.id, base64.encodestring(self._reports[report_id]['result']), - self._reports[report_id]['format'], printer) - # FIXME "Warning" removed as it breaks the workflow - # it would be interesting to have a dialog box to confirm if we really want to print - # in this case it must be with a by pass parameter to allow massive impression - # raise osv.except_osv( - # _('Printing...'), - # _('Document sent to printer %s') % (printer,)) +# cr = pooler.get_db(db).cursor() +# try: +# pool = pooler.get_pool(cr.dbname) +# # First of all load report defaults: name, action and printer +# report_obj = pool.get('ir.actions.report.xml') +# report = report_obj.search( +# cr, uid, [('report_name', '=', self._reports[report_id]['report_name'])]) +# if report: +# report = report_obj.browse(cr, uid, report[0]) +# data = report.behaviour()[report.id] +# action = data['action'] +# printer = data['printer'] +# if action != 'client': +# if (self._reports and self._reports.get(report_id, False) +# and self._reports[report_id].get('result', False) +# and self._reports[report_id].get('format', False)): +# report_obj.print_direct( +# cr, uid, report.id, base64.encodestring(self._reports[report_id]['result']), +# self._reports[report_id]['format'], printer) +# # FIXME "Warning" removed as it breaks the workflow +# # it would be interesting to have a dialog box to confirm if we really want to print +# # in this case it must be with a by pass parameter to allow massive impression +# # raise osv.except_osv( +# # _('Printing...'), +# # _('Document sent to printer %s') % (printer,)) - except: - cr.rollback() - raise - finally: - cr.close() +# except: +# cr.rollback() +# raise +# finally: +# cr.close() - res = super(virtual_report_spool, self).exp_report_get(db, uid, report_id) - return res +# res = super(virtual_report_spool, self).exp_report_get(db, uid, report_id) +# return res -virtual_report_spool() +# virtual_report_spool() -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: +# # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: From 91162b1a6c5646690cdfdf804f3a2b00c91bdfb0 Mon Sep 17 00:00:00 2001 From: Guewen Baconnier Date: Fri, 14 Nov 2014 10:03:03 +0100 Subject: [PATCH 05/26] Migrate ir_report.py to new API --- base_report_to_printer/ir_report.py | 113 +++++++++++++++------------- 1 file changed, 59 insertions(+), 54 deletions(-) diff --git a/base_report_to_printer/ir_report.py b/base_report_to_printer/ir_report.py index 96cd1c17766..33b3c647d38 100644 --- a/base_report_to_printer/ir_report.py +++ b/base_report_to_printer/ir_report.py @@ -5,8 +5,7 @@ # Copyright (c) 2009 Albert Cervera i Areny # Copyright (C) 2011 Agile Business Group sagl () # Copyright (C) 2011 Domsense srl () -# Copyright (C) 2013 Camptocamp () -# All Rights Reserved +# Copyright (C) 2013-2014 Camptocamp () # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published @@ -22,30 +21,54 @@ # along with this program. If not, see . # ############################################################################## -import os import base64 -from tempfile import mkstemp import logging +import os + +from tempfile import mkstemp + import cups -from openerp.osv import orm, fields +from openerp import models, fields, api +_logger = logging.getLogger('base_report_to_printer') -class report_xml(orm.Model): + +class ReportXml(models.Model): """ Reports """ - def set_print_options(self, cr, uid, report_id, format, context=None): - """ - Hook to set print options - """ + _inherit = 'ir.actions.report.xml' + + property_printing_action = fields.Many2one( + comodel_name='printing.action', + string='Action', + company_dependent=True, + ) + printing_printer_id = fields.Many2one( + comodel_name='printing.printer', + string='Printer' + ) + printing_action_ids = fields.One2many( + comodel_name='printing.report.xml.action', + inverse_name='report_id', + string='Actions', + help='This field allows configuring action and printer on a per ' + 'user basis' + ) + + @api.multi + def set_print_options(self, format): + """ Hook to set print options """ options = {} if format == 'raw': options['raw'] = True return options - def print_direct(self, cr, uid, report_id, result, format, printer, context=None): + @api.multi + def print_direct(self, result, format, printer): + self.ensure_one() fd, file_name = mkstemp() try: os.write(fd, base64.decodestring(result)) @@ -59,74 +82,56 @@ def print_direct(self, cr, uid, report_id, result, format, printer, context=None printer_system_name = printer.system_name connection = cups.Connection() - options = self.set_print_options(cr, uid, report_id, format, context=context) + options = self.set_print_options(format) - connection.printFile(printer_system_name, file_name, file_name, options=options) - logger = logging.getLogger('base_report_to_printer') - logger.info("Printing job : '%s'" % file_name) + connection.printFile(printer_system_name, + file_name, + file_name, + options=options) + _logger.info("Printing job: '%s'" % file_name) return True - _inherit = 'ir.actions.report.xml' - _columns = { - 'property_printing_action': fields.property( - #'ir.actions.report.xml', - 'printing.action', - type='many2one', - relation='printing.action', - string='Action', - view_load=True, - method=True, - ), - 'printing_printer_id': fields.many2one('printing.printer', 'Printer'), - 'printing_action_ids': fields.one2many( - 'printing.report.xml.action', 'report_id', 'Actions', - help='This field allows configuring action and printer on a per ' - 'user basis'), - } - - def behaviour(self, cr, uid, ids, context=None): + @api.multi + def behaviour(self): result = {} - printer_obj = self.pool['printing.printer'] - printing_act_obj = self.pool['printing.report.xml.action'] + printer_obj = self.env['printing.printer'] + printing_act_obj = self.env['printing.report.xml.action'] # Set hardcoded default action default_action = 'client' # Retrieve system wide printer - default_printer = printer_obj.get_default(cr, uid, context=context) - if default_printer: - default_printer = printer_obj.browse(cr, uid, default_printer, context=context) + default_printer = printer_obj.get_default() # Retrieve user default values - user = self.pool['res.users'].browse(cr, uid, uid, context=context) + user = self.env.user if user.printing_action: default_action = user.printing_action if user.printing_printer_id: default_printer = user.printing_printer_id - for report in self.browse(cr, uid, ids, context): + for report in self: action = default_action printer = default_printer # Retrieve report default values - if (report.property_printing_action - and report.property_printing_action.type != 'user_default'): - action = report.property_printing_action.type + report_action = report.property_printing_action + if report_action and report_action.type != 'user_default': + action = report_action.type if report.printing_printer_id: printer = report.printing_printer_id # Retrieve report-user specific values - act_ids = printing_act_obj.search( - cr, uid, + print_action = printing_act_obj.search( [('report_id', '=', report.id), - ('user_id', '=', uid), - ('action', '!=', 'user_default')], context=context) - if act_ids: - user_action = printing_act_obj.behaviour(cr, uid, act_ids[0], context) + ('user_id', '=', self.env.uid), + ('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'] - result[report.id] = { - 'action': action, - 'printer': printer, - } + result[report.id] = {'action': action, + 'printer': printer, + } return result From 435c7b7860f048afe8103ca1bd2c3392d550dbb5 Mon Sep 17 00:00:00 2001 From: Guewen Baconnier Date: Fri, 14 Nov 2014 10:44:05 +0100 Subject: [PATCH 06/26] Migrate printing.py to new API --- base_report_to_printer/printing.py | 271 +++++++++++++---------------- 1 file changed, 121 insertions(+), 150 deletions(-) diff --git a/base_report_to_printer/printing.py b/base_report_to_printer/printing.py index 2d0cc1b4038..354e90126c8 100644 --- a/base_report_to_printer/printing.py +++ b/base_report_to_printer/printing.py @@ -5,8 +5,7 @@ # Copyright (c) 2009 Albert Cervera i Areny # Copyright (C) 2011 Agile Business Group sagl () # Copyright (C) 2011 Domsense srl () -# Copyright (C) 2013 Camptocamp () -# All Rights Reserved +# Copyright (C) 2013-2014 Camptocamp () # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published @@ -25,145 +24,118 @@ import time import cups + from threading import Thread from threading import Lock -from openerp import pooler -from openerp.osv import orm, fields -from openerp.tools.translate import _ +from openerp import models, fields, api, sql_db -class printing_printer(orm.Model): +class PrintingPrinter(models.Model): """ Printers """ - _name = "printing.printer" - _description = "Printer" - - _columns = { - 'name': fields.char( - 'Name', - size=64, - required=True, - select="1"), - 'system_name': fields.char( - 'System Name', - size=64, - required=True, - select="1"), - 'default': fields.boolean( - 'Default Printer', - readonly=True), - 'status': fields.selection( - [('unavailable', 'Unavailable'), - ('printing', 'Printing'), - ('unknown', 'Unknown'), - ('available', 'Available'), - ('error', 'Error'), - ('server-error', 'Server Error')], - 'Status', required=True, readonly=True), - 'status_message': fields.char( - 'Status Message', - size=500, - readonly=True), - 'model': fields.char( - 'Model', - size=500, - readonly=True), - 'location': fields.char( - 'Location', - size=500, - readonly=True), - 'uri': fields.char( - 'URI', - size=500, - readonly=True), - } - - _order = "name" - - _defaults = { - 'default': lambda *a: False, - 'status': lambda *a: 'unknown', - } + + _name = 'printing.printer' + _description = 'Printer' + _order = 'name' + + name = fields.Char(required=True, select=True) + system_name = fields.Char(required=True, select=True) + default = fields.Boolean(readonly=True) + status = fields.Selection([('unavailable', 'Unavailable'), + ('printing', 'Printing'), + ('unknown', 'Unknown'), + ('available', 'Available'), + ('error', 'Error'), + ('server-error', 'Server Error')], + required=True, + readonly=True, + default='unknown') + status_message = fields.Char(readonly=True) + model = fields.Char(readonly=True) + location = fields.Char(readonly=True) + uri = fields.Char(readonly=True) def __init__(self, pool, cr): - super(printing_printer, self).__init__(pool, cr) + super(PrintingPrinter, self).__init__(pool, cr) self.lock = Lock() self.last_update = None self.updating = False - def update_printers_status(self, db_name, uid, context=None): - db, pool = pooler.get_db_and_pool(db_name) - cr = db.cursor() - - try: - connection = cups.Connection() - printers = connection.getPrinters() - server_error = False - except: - server_error = True - - mapping = { - 3: 'available', - 4: 'printing', - 5: 'error' - } - - if context is None: - context = {} - try: - # Skip update to avoid the thread being created again - ctx = context.copy() - ctx['skip_update'] = True - ids = self.search(cr, uid, [], context=ctx) - for printer in self.browse(cr, uid, ids, context=ctx): - vals = {} - if server_error: - status = 'server-error' - elif printer.system_name in printers: - info = printers[printer.system_name] - status = mapping.get(info['printer-state'], 'unknown') - vals = { - 'model': info.get('printer-make-and-model', False), - 'location': info.get('printer-location', False), - 'uri': info.get('device-uri', False), - } - else: - status = 'unavailable' - - vals['status'] = status - self.write(cr, uid, [printer.id], vals, context=context) - cr.commit() - except: - cr.rollback() - raise - finally: - cr.close() - with self.lock: - self.updating = False - self.last_update = time.time() - - def start_printer_update(self, cr, uid, context): + @api.model + def update_printers_status(self): + cr = sql_db.db_connect(self.env.cr.dbname).cursor() + uid, context = self.env.uid, self.env.context + with api.Environment.manage(): + self.env = api.Environment(cr, uid, context) + try: + connection = cups.Connection() + printers = connection.getPrinters() + server_error = False + except: + server_error = True + + mapping = { + 3: 'available', + 4: 'printing', + 5: 'error' + } + + try: + # Skip update to avoid the thread being created again + env = self.env.with_context(skip_update=True) + printer_recs = env.search([]) + for printer in printer_recs: + vals = {} + if server_error: + status = 'server-error' + elif printer.system_name in printers: + info = printers[printer.system_name] + status = mapping.get(info['printer-state'], 'unknown') + vals = { + 'model': info.get('printer-make-and-model', False), + 'location': info.get('printer-location', False), + 'uri': info.get('device-uri', False), + } + else: + status = 'unavailable' + + vals['status'] = status + printer.write(vals) + self.env.cr.commit() + except: + self.env.cr.rollback() + raise + finally: + self.env.cr.close() + with self.lock: + self.updating = False + self.last_update = time.time() + + @api.model + def start_printer_update(self): self.lock.acquire() if self.updating: self.lock.release() return self.updating = True self.lock.release() - thread = Thread(target=self.update_printers_status, args=(cr.dbname, uid, context.copy())) + thread = Thread(target=self.update_printers_status, args=()) thread.start() - def update(self, cr, uid, context=None): + @api.model + def update(self): """Update printer status if current status is more than 10s old.""" # We won't acquire locks - we're only assigning from immutable data - if not context or 'skip_update' in context: + if not self.env.context or 'skip_update' in self.env.context: return True last_update = self.last_update now = time.time() - # Only update printer status if current status is more than 10 seconds old. + # Only update printer status if current status is more than 10 + # seconds old. if not last_update or now - last_update > 10: - self.start_printer_update(cr, uid, context) + self.start_printer_update() # Wait up to five seconds for printer status update for _dummy in range(0, 5): time.sleep(1) @@ -171,54 +143,53 @@ def update(self, cr, uid, context=None): break return True - def search(self, cr, uid, args, offset=0, limit=None, order=None, + @api.returns('self') + def search(self, cr, user, args, offset=0, limit=None, order=None, context=None, count=False): - self.update(cr, uid, context) - return super(printing_printer, self - ).search(cr, uid, args, offset, - limit, order, context, count) - - def read(self, cr, uid, ids, fields=None, context=None, load='_classic_read'): - self.update(cr, uid, context) - return super(printing_printer, self - ).read(cr, uid, ids, fields, context, load) - - def browse(self, cr, uid, ids, context=None): - self.update(cr, uid, context) - return super(printing_printer, self).browse(cr, uid, ids, context) - - def set_default(self, cr, uid, ids, context): - if not ids: + self.update() + _super = super(PrintingPrinter, self) + return _super.search(cr, user, args, offset=offset, limit=limit, + order=order, context=context, count=count) + + @api.v8 + def read(self, fields=None, load='_classic_read'): + self.update() + return super(PrintingPrinter, self).read(fields=fields, load=load) + + @api.v8 + def browse(self, arg=None): + self.update() + return super(PrintingPrinter, self).browse(arg=arg) + + @api.multi + def set_default(self): + if not self: return - default_ids = self.search(cr, uid, [('default', '=', True)]) - self.write(cr, uid, default_ids, {'default': False}, context) - self.write(cr, uid, ids[0], {'default': True}, context) + self.ensure_one() + default_printers = self.search([('default', '=', True)]) + default_printers.write({'default': False}) + self.write({'default': True}) return True - def get_default(self, cr, uid, context): - printer_ids = self.search(cr, uid, [('default', '=', True)]) - if printer_ids: - return printer_ids[0] - return False - + @api.multi + def get_default(self): + return self.search([('default', '=', True)], limit=1) # # Actions # -def _available_action_types(self, cr, uid, context=None): - return [ - ('server', _('Send to Printer')), - ('client', _('Send to Client')), - ('user_default', _("Use user's defaults")), - ] + +def _available_action_types(self): + return [('server', 'Send to Printer'), + ('client', 'Send to Client'), + ('user_default', "Use user's defaults"), + ] -class printing_action(orm.Model): +class PrintingAction(models.Model): _name = 'printing.action' _description = 'Print Job Action' - _columns = { - 'name': fields.char('Name', size=256, required=True), - 'type': fields.selection(_available_action_types, 'Type', required=True), - } + name = fields.Char(required=True) + type = fields.Selection(_available_action_types, required=True) From 03570cbc0eaffe7b2f8a970ecb7f9ea0e681c583 Mon Sep 17 00:00:00 2001 From: Guewen Baconnier Date: Fri, 14 Nov 2014 10:57:06 +0100 Subject: [PATCH 07/26] Migrate res_users.py to new API --- base_report_to_printer/users.py | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/base_report_to_printer/users.py b/base_report_to_printer/users.py index 1aa546e172d..b546bc3533f 100644 --- a/base_report_to_printer/users.py +++ b/base_report_to_printer/users.py @@ -5,8 +5,7 @@ # Copyright (c) 2009 Albert Cervera i Areny # Copyright (C) 2011 Agile Business Group sagl () # Copyright (C) 2011 Domsense srl () -# Copyright (C) 2013 Camptocamp () -# All Rights Reserved +# Copyright (C) 2013-2014 Camptocamp () # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published @@ -22,27 +21,23 @@ # along with this program. If not, see . # ############################################################################## -from openerp.osv import orm, fields +from openerp import models, fields -from printing import _available_action_types +from .printing import _available_action_types -class res_users(orm.Model): +class res_users(models.Model): """ Users """ - _name = "res.users" - _inherit = "res.users" + _name = 'res.users' + _inherit = 'res.users' - def _user_available_action_types(self, cr, uid, context=None): - if context is None: - context = {} - return [x for x in _available_action_types(self, cr, uid, context) - if x[0] != 'user_default'] + def _user_available_action_types(self): + return [(code, string) for code, string + in _available_action_types(self) + if code != 'user_default'] - _columns = { - 'printing_action': fields.selection(_user_available_action_types, 'Printing Action'), - 'printing_printer_id': fields.many2one('printing.printer', 'Default Printer'), - } - -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: + printing_action = fields.Selection(_user_available_action_types) + printing_printer_id = fields.Many2one(comodel_name='printing.printer', + string='Default Printer') From 7da56f43c51e74389858b651fd7ab72edc7915fe Mon Sep 17 00:00:00 2001 From: Guewen Baconnier Date: Fri, 14 Nov 2014 11:02:38 +0100 Subject: [PATCH 08/26] Migrate report_xml_action.py to new API --- base_report_to_printer/report_xml_action.py | 43 +++++++++++---------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/base_report_to_printer/report_xml_action.py b/base_report_to_printer/report_xml_action.py index d1ca02b6cb4..0a5dadcd2ac 100644 --- a/base_report_to_printer/report_xml_action.py +++ b/base_report_to_printer/report_xml_action.py @@ -22,29 +22,32 @@ # along with this program. If not, see . # ############################################################################## -from openerp.osv import orm, fields +from openerp import models, fields, api -from printing import _available_action_types +from .printing import _available_action_types -class report_xml_action(orm.Model): + +class ReportXmlAction(models.Model): _name = 'printing.report.xml.action' _description = 'Report Printing Actions' - _columns = { - 'report_id': fields.many2one('ir.actions.report.xml', 'Report', required=True, ondelete='cascade'), - 'user_id': fields.many2one('res.users', 'User', required=True, ondelete='cascade'), - 'action': fields.selection(_available_action_types, 'Action', required=True), - 'printer_id': fields.many2one('printing.printer', 'Printer'), - } - - def behaviour(self, cr, uid, act_id, context=None): - result = {} - if not act_id: - return False - action = self.browse(cr, uid, act_id, context=context) - return { - 'action': action.action, - 'printer': action.printer_id, - } + report_id = fields.Many2one(comodel_name='ir.actions.report.xml', + string='Report', + required=True, + ondelete='cascade') + user_id = fields.Many2one(comodel_name='res.users', + string='User', + required=True, + ondelete='cascade') + action = fields.Selection(_available_action_types, + required=True) + printer_id = fields.Many2one(comodel_name='printing.printer', + string='Printer') -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: + @api.multi + def behaviour(self): + if not self: + return {} + return {'action': self.action, + 'printer': self.printer_id, + } From c838c1eae807b52322d2ba0f66bcd41f110c8f3a Mon Sep 17 00:00:00 2001 From: Guewen Baconnier Date: Fri, 14 Nov 2014 11:10:38 +0100 Subject: [PATCH 09/26] Migrate wizard/update_printers.py to new API --- .../wizard/update_printers.py | 40 ++++++++----------- 1 file changed, 17 insertions(+), 23 deletions(-) diff --git a/base_report_to_printer/wizard/update_printers.py b/base_report_to_printer/wizard/update_printers.py index d599a0317f0..31039808352 100644 --- a/base_report_to_printer/wizard/update_printers.py +++ b/base_report_to_printer/wizard/update_printers.py @@ -4,7 +4,7 @@ # Copyright (c) 2009 Albert Cervera i Areny # Copyright (C) 2011 Agile Business Group sagl () # Copyright (C) 2011 Domsense srl () -# All Rights Reserved +# Copyright (C) 2014 Camptocamp SA () # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published @@ -23,41 +23,38 @@ import cups -from openerp.osv import orm +from openerp import models, api -class printing_printer_update_wizard(orm.TransientModel): - _name = "printing.printer.update.wizard" +class PrintingPrinterUpdateWizard(models.TransientModel): + _name = 'printing.printer.update.wizard' - _columns = { - } - - def action_cancel(self, cr, uid, ids, context=None): - return {} - - def action_ok(self, cr, uid, ids, context=None): + @api.multi + def action_ok(self): + self.ensure_one() # Update Printers - printer_obj = self.pool['printing.printer'] + printer_obj = self.env['printing.printer'] try: connection = cups.Connection() printers = connection.getPrinters() except: return {} - ids = printer_obj.search( - cr, uid, [('system_name', 'in', printers.keys())], context=context) - for printer in printer_obj.browse(cr, uid, ids, context=context): + printer_recs = printer_obj.search( + [('system_name', 'in', printers.keys())] + ) + for printer in printer_recs: del printers[printer.system_name] - for name in printers: - printer = printers[name] - self.pool.get('printing.printer').create(cr, uid, { + for name, printer in printers.iteritems(): + values = { 'name': printer['printer-info'], 'system_name': name, 'model': printer.get('printer-make-and-model', False), 'location': printer.get('printer-location', False), 'uri': printer.get('device-uri', False), - }, context) + } + self.env['printing.printer'].create(values) return { 'name': 'Printers', @@ -66,7 +63,4 @@ def action_ok(self, cr, uid, ids, context=None): 'res_model': 'printing.printer', 'type': 'ir.actions.act_window', 'target': 'current', - } - - -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: + } From 5232a64d242f90b59277269ccfe4942dfeef8288 Mon Sep 17 00:00:00 2001 From: Guewen Baconnier Date: Mon, 17 Nov 2014 09:50:45 +0100 Subject: [PATCH 10/26] Better view for wizard --- base_report_to_printer/wizard/update_printers.xml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/base_report_to_printer/wizard/update_printers.xml b/base_report_to_printer/wizard/update_printers.xml index 8ac072cbae9..d7675518c88 100644 --- a/base_report_to_printer/wizard/update_printers.xml +++ b/base_report_to_printer/wizard/update_printers.xml @@ -4,13 +4,14 @@ printing.printer.update.wizard printing.printer.update.wizard - form -
+