diff --git a/__unported__/base_report_to_printer/ir_report.py b/__unported__/base_report_to_printer/ir_report.py deleted file mode 100644 index 96cd1c1..0000000 --- a/__unported__/base_report_to_printer/ir_report.py +++ /dev/null @@ -1,132 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# Copyright (c) 2007 Ferran Pegueroles -# 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 -# -# 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 -# by the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -############################################################################## -import os -import base64 -from tempfile import mkstemp -import logging -import cups - -from openerp.osv import orm, fields - - -class report_xml(orm.Model): - """ - Reports - """ - - def set_print_options(self, cr, uid, report_id, format, context=None): - """ - 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): - fd, file_name = mkstemp() - try: - os.write(fd, base64.decodestring(result)) - finally: - os.close(fd) - printer_system_name = '' - if printer: - if isinstance(printer, (basestring)): - printer_system_name = printer - else: - printer_system_name = printer.system_name - connection = cups.Connection() - - options = self.set_print_options(cr, uid, report_id, format, context=context) - - 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) - 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): - result = {} - printer_obj = self.pool['printing.printer'] - printing_act_obj = self.pool['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) - - # Retrieve user default values - user = self.pool['res.users'].browse(cr, uid, uid, context=context) - 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): - 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 - if report.printing_printer_id: - printer = report.printing_printer_id - - # Retrieve report-user specific values - act_ids = printing_act_obj.search( - cr, uid, - [('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) - action = user_action['action'] - if user_action['printer']: - printer = user_action['printer'] - - result[report.id] = { - 'action': action, - 'printer': printer, - } - return result diff --git a/__unported__/base_report_to_printer/printing.py b/__unported__/base_report_to_printer/printing.py deleted file mode 100644 index 2d0cc1b..0000000 --- a/__unported__/base_report_to_printer/printing.py +++ /dev/null @@ -1,224 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# Copyright (c) 2007 Ferran Pegueroles -# 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 -# -# 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 -# by the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -############################################################################## -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 _ - - -class printing_printer(orm.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', - } - - def __init__(self, pool, cr): - super(printing_printer, 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): - 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.start() - - def update(self, cr, uid, context=None): - """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: - return True - last_update = self.last_update - now = time.time() - # 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) - # Wait up to five seconds for printer status update - for _dummy in range(0, 5): - time.sleep(1) - if not self.updating: - break - return True - - def search(self, cr, uid, 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: - 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) - 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 - - -# -# 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")), - ] - - -class printing_action(orm.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), - } diff --git a/__unported__/base_report_to_printer/report_service.py b/__unported__/base_report_to_printer/report_service.py deleted file mode 100644 index d4f936b..0000000 --- a/__unported__/base_report_to_printer/report_service.py +++ /dev/null @@ -1,77 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# Copyright (c) 2007 Ferran Pegueroles -# 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 -# -# 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 -# by the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -############################################################################## -import base64 - -from openerp import pooler -from openerp.addons.base_calendar import base_calendar - - -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_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,)) - - except: - cr.rollback() - raise - finally: - cr.close() - - res = super(virtual_report_spool, self).exp_report_get(db, uid, report_id) - return res - -virtual_report_spool() - -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/base_report_to_printer/README.rst b/base_report_to_printer/README.rst new file mode 100644 index 0000000..51c0e39 --- /dev/null +++ b/base_report_to_printer/README.rst @@ -0,0 +1,50 @@ +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 +* Guewen Baconnier diff --git a/__unported__/base_report_to_printer/__init__.py b/base_report_to_printer/__init__.py similarity index 93% rename from __unported__/base_report_to_printer/__init__.py rename to base_report_to_printer/__init__.py index 9f6441d..ddd67e1 100644 --- a/__unported__/base_report_to_printer/__init__.py +++ b/base_report_to_printer/__init__.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 @@ -23,6 +22,7 @@ # ############################################################################## from . import printing +from . import report from . import report_xml_action from . import report_service from . import users diff --git a/__unported__/base_report_to_printer/__openerp__.py b/base_report_to_printer/__openerp__.py similarity index 54% rename from __unported__/base_report_to_printer/__openerp__.py rename to base_report_to_printer/__openerp__.py index ffc985b..511c179 100644 --- a/__unported__/base_report_to_printer/__openerp__.py +++ b/base_report_to_printer/__openerp__.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 @@ -26,69 +25,19 @@ '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', - "depends": ['base', 'base_calendar'], + "depends": ['base', + 'report', + ], 'data': [ 'security/security.xml', 'printing_data.xml', 'printing_view.xml', 'wizard/update_printers.xml', ], - 'installable': False, + 'installable': True, 'auto_install': False, 'application': True, 'external_dependencies': { 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 58% 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 index 0d528d5..58c55d5 100644 --- a/__unported__/base_report_to_printer/i18n/base_report_to_printer.pot +++ b/base_report_to_printer/i18n/base_report_to_printer.pot @@ -1,38 +1,100 @@ # Translation of OpenERP Server. # This file contains the translation of the following modules: -# * base_report_to_printer +# * base_report_to_printer # msgid "" msgstr "" "Project-Id-Version: OpenERP Server 7.0\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2013-11-05 14:48+0000\n" -"PO-Revision-Date: 2013-11-05 14:48+0000\n" +"PO-Revision-Date: 2014-11-17 12:50+0000\n" "Last-Translator: <>\n" "Language-Team: \n" +"Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: \n" "Plural-Forms: \n" #. module: base_report_to_printer -#: selection:printing.printer,status:0 -msgid "Unavailable" +#: field:ir.actions.report.xml,property_printing_action:0 +#: field:printing.report.xml.action,action:0 +msgid "Action" msgstr "" #. module: base_report_to_printer -#: view:printing.printer.update.wizard:0 -msgid "This process will create all missing printers from the current CUPS server." +#: field:ir.actions.report.xml,printing_action_ids:0 +msgid "Actions" msgstr "" #. module: base_report_to_printer #: selection:printing.printer,status:0 -msgid "Unknown" +msgid "Available" msgstr "" #. module: base_report_to_printer -#: field:printing.printer,system_name:0 -msgid "System Name" +#: view:printing.printer.update.wizard:base_report_to_printer.printer_update_wizard +msgid "Cancel" +msgstr "" + +#. module: base_report_to_printer +#: field:printing.action,create_uid:0 field:printing.printer,create_uid:0 +#: field:printing.printer.polling,create_uid:0 +#: field:printing.printer.update.wizard,create_uid:0 +#: field:printing.report.xml.action,create_uid:0 +msgid "Created by" +msgstr "" + +#. module: base_report_to_printer +#: field:printing.action,create_date:0 field:printing.printer,create_date:0 +#: field:printing.printer.polling,create_date:0 +#: field:printing.printer.update.wizard,create_date:0 +#: field:printing.report.xml.action,create_date:0 +msgid "Created on" +msgstr "" + +#. module: base_report_to_printer +#: field:printing.printer,default:0 +msgid "Default" +msgstr "" + +#. module: base_report_to_printer +#: field:res.users,printing_printer_id:0 +msgid "Default Printer" +msgstr "" + +#. module: base_report_to_printer +#: selection:printing.printer,status:0 +msgid "Error" +msgstr "" + +#. module: base_report_to_printer +#: field:printing.action,id:0 field:printing.printer,id:0 +#: field:printing.printer.polling,id:0 +#: field:printing.printer.update.wizard,id:0 +#: field:printing.report.xml.action,id:0 +msgid "ID" +msgstr "" + +#. module: base_report_to_printer +#: field:printing.action,write_uid:0 field:printing.printer,write_uid:0 +#: field:printing.printer.polling,write_uid:0 +#: field:printing.printer.update.wizard,write_uid:0 +#: field:printing.report.xml.action,write_uid:0 +msgid "Last Updated by" +msgstr "" + +#. module: base_report_to_printer +#: field:printing.action,write_date:0 field:printing.printer,write_date:0 +#: field:printing.printer.polling,write_date:0 +#: field:printing.printer.update.wizard,write_date:0 +#: field:printing.report.xml.action,write_date:0 +msgid "Last Updated on" +msgstr "" + +#. module: base_report_to_printer +#: field:printing.printer.polling,last_update:0 +msgid "Last update" msgstr "" #. module: base_report_to_printer @@ -40,35 +102,29 @@ msgstr "" msgid "Location" msgstr "" -#. module: base_report_to_printer -#: model:ir.ui.menu,name:base_report_to_printer.menu_printing_printer_form -#: view:printing.printer:0 -msgid "Printers" -msgstr "" - -#. module: base_report_to_printer -#: view:ir.actions.report.xml:0 -msgid "Print" -msgstr "" - -#. module: base_report_to_printer -#: field:res.users,printing_action:0 -msgid "Printing Action" -msgstr "" - -#. module: base_report_to_printer -#: field:printing.action,type:0 -msgid "Type" -msgstr "" - #. module: base_report_to_printer #: field:printing.printer,model:0 msgid "Model" msgstr "" #. module: base_report_to_printer -#: selection:printing.printer,status:0 -msgid "Available" +#: field:printing.action,name:0 field:printing.printer,name:0 +msgid "Name" +msgstr "" + +#. module: base_report_to_printer +#: view:res.users:base_report_to_printer.view_printing_users_form +msgid "Preferences" +msgstr "" + +#. module: base_report_to_printer +#: view:ir.actions.report.xml:base_report_to_printer.action_report_xml_form +msgid "Print" +msgstr "" + +#. module: base_report_to_printer +#: model:ir.model,name:base_report_to_printer.model_printing_action +msgid "Print Job Action" msgstr "" #. module: base_report_to_printer @@ -79,147 +135,138 @@ msgid "Printer" msgstr "" #. module: base_report_to_printer -#: model:ir.model,name:base_report_to_printer.model_res_users -msgid "Users" +#: model:ir.ui.menu,name:base_report_to_printer.menu_printing_printer_form +#: view:printing.printer:base_report_to_printer.view_printing_printer_form +#: view:printing.printer:base_report_to_printer.view_printing_printer_search +#: view:printing.printer:base_report_to_printer.view_printing_printer_tree +msgid "Printers" msgstr "" #. module: base_report_to_printer -#: model:ir.model,name:base_report_to_printer.model_printing_report_xml_action -#: view:printing.report.xml.action:0 -msgid "Report Printing Actions" -msgstr "" - -#. module: base_report_to_printer -#: view:ir.actions.report.xml:0 -msgid "Specific actions per user" -msgstr "" - -#. module: base_report_to_printer -#: model:ir.model,name:base_report_to_printer.model_printing_action -msgid "Print Job Action" -msgstr "" - -#. module: base_report_to_printer -#: field:printing.report.xml.action,user_id:0 -msgid "User" -msgstr "" - -#. module: base_report_to_printer -#: field:printing.report.xml.action,report_id:0 -msgid "Report" -msgstr "" - -#. module: base_report_to_printer -#: field:printing.printer,status:0 -msgid "Status" -msgstr "" - -#. module: base_report_to_printer -#: model:ir.actions.act_window,name:base_report_to_printer.action_printing_printer_form -msgid "Show Printers" -msgstr "" - -#. module: base_report_to_printer -#: view:printing.printer.update.wizard:0 -msgid "Ok" -msgstr "" - -#. module: base_report_to_printer -#: field:printing.action,name:0 -#: field:printing.printer,name:0 -msgid "Name" -msgstr "" - -#. module: base_report_to_printer -#: view:printing.printer:0 -msgid "Set Default" -msgstr "" - -#. module: base_report_to_printer -#: field:printing.printer,default:0 -#: field:res.users,printing_printer_id:0 -msgid "Default Printer" -msgstr "" - -#. module: base_report_to_printer -#: code:addons/base_report_to_printer/printing.py:186 -#, python-format -msgid "Send to Client" -msgstr "" - -#. module: base_report_to_printer -#: field:printing.printer,uri:0 -msgid "URI" -msgstr "" - -#. module: base_report_to_printer -#: model:ir.actions.act_window,name:base_report_to_printer.action_printer_update_wizard -#: model:ir.ui.menu,name:base_report_to_printer.menu_printer_update_wizard -#: view:printing.printer.update.wizard:0 -msgid "Update Printers from CUPS" -msgstr "" - -#. module: base_report_to_printer -#: code:addons/base_report_to_printer/printing.py:185 -#, python-format -msgid "Send to Printer" +#: model:ir.model,name:base_report_to_printer.model_printing_printer_polling +msgid "Printers Polling" msgstr "" #. module: base_report_to_printer #: model:ir.ui.menu,name:base_report_to_printer.menu_printing_main #: selection:printing.printer,status:0 +#: view:res.users:base_report_to_printer.view_printing_users_prefs msgid "Printing" msgstr "" -#. module: base_report_to_printer -#: selection:printing.printer,status:0 -msgid "Error" -msgstr "" - -#. module: base_report_to_printer -#: field:ir.actions.report.xml,property_printing_action:0 -#: field:printing.report.xml.action,action:0 -msgid "Action" -msgstr "" - -#. module: base_report_to_printer -#: view:ir.actions.report.xml:0 -msgid "Security" -msgstr "" - -#. module: base_report_to_printer -#: field:printing.printer,status_message:0 -msgid "Status Message" -msgstr "" - -#. module: base_report_to_printer -#: help:ir.actions.report.xml,printing_action_ids:0 -msgid "This field allows configuring action and printer on a per user basis" -msgstr "" - -#. module: base_report_to_printer -#: selection:printing.printer,status:0 -msgid "Server Error" -msgstr "" - -#. module: base_report_to_printer -#: field:ir.actions.report.xml,printing_action_ids:0 -msgid "Actions" -msgstr "" - -#. module: base_report_to_printer -#: view:printing.printer.update.wizard:0 -msgid "Cancel" -msgstr "" - #. module: base_report_to_printer #: model:res.groups,name:base_report_to_printer.res_groups_printingprintoperator0 msgid "Printing / Print Operator" msgstr "" #. module: base_report_to_printer -#: code:addons/base_report_to_printer/printing.py:187 -#, python-format -msgid "Use user's defaults" +#: field:res.users,printing_action:0 +msgid "Printing action" msgstr "" +#. module: base_report_to_printer +#: model:ir.model,name:base_report_to_printer.model_report +#: field:printing.report.xml.action,report_id:0 +msgid "Report" +msgstr "" + +#. module: base_report_to_printer +#: model:ir.model,name:base_report_to_printer.model_printing_report_xml_action +#: view:printing.report.xml.action:base_report_to_printer.printing_report_xml_action_form +#: view:printing.report.xml.action:base_report_to_printer.printing_report_xml_action_tree +msgid "Report Printing Actions" +msgstr "" + +#. module: base_report_to_printer +#: model:ir.ui.menu,name:base_report_to_printer.menu_printing_reports +msgid "Reports" +msgstr "" + +#. module: base_report_to_printer +#: view:ir.actions.report.xml:base_report_to_printer.action_report_xml_form +msgid "Security" +msgstr "" + +#. module: base_report_to_printer +#: selection:printing.printer,status:0 +msgid "Server Error" +msgstr "" + +#. module: base_report_to_printer +#: view:printing.printer:base_report_to_printer.view_printing_printer_form +msgid "Set Default" +msgstr "" + +#. module: base_report_to_printer +#: model:ir.actions.act_window,name:base_report_to_printer.action_printing_printer_form +msgid "Show Printers" +msgstr "" + +#. module: base_report_to_printer +#: view:ir.actions.report.xml:base_report_to_printer.action_report_xml_form +msgid "Specific actions per user" +msgstr "" + +#. module: base_report_to_printer +#: field:printing.printer,status:0 +msgid "Status" +msgstr "" + +#. module: base_report_to_printer +#: field:printing.printer,status_message:0 +msgid "Status message" +msgstr "" + +#. module: base_report_to_printer +#: field:printing.printer,system_name:0 +msgid "System name" +msgstr "" + +#. module: base_report_to_printer +#: help:ir.actions.report.xml,printing_action_ids:0 +msgid "This field allows configuring action and printer on a per user basis" +msgstr "" + +#. module: base_report_to_printer +#: view:printing.printer.update.wizard:base_report_to_printer.printer_update_wizard +msgid "" +"This process will create all the missing printers from the current CUPS " +"server." +msgstr "" + +#. module: base_report_to_printer +#: field:printing.action,type:0 +msgid "Type" +msgstr "" + +#. module: base_report_to_printer +#: selection:printing.printer,status:0 +msgid "Unavailable" +msgstr "" + +#. module: base_report_to_printer +#: selection:printing.printer,status:0 +msgid "Unknown" +msgstr "" + +#. module: base_report_to_printer +#: model:ir.actions.act_window,name:base_report_to_printer.action_printer_update_wizard +#: model:ir.ui.menu,name:base_report_to_printer.menu_printer_update_wizard +#: view:printing.printer.update.wizard:base_report_to_printer.printer_update_wizard +msgid "Update Printers from CUPS" +msgstr "" + +#. module: base_report_to_printer +#: field:printing.printer,uri:0 +msgid "URI" +msgstr "" + +#. module: base_report_to_printer +#: field:printing.report.xml.action,user_id:0 +msgid "User" +msgstr "" + +#. module: base_report_to_printer +#: model:ir.model,name:base_report_to_printer.model_res_users +msgid "Users" +msgstr "" diff --git a/__unported__/base_report_to_printer/i18n/fr.po b/base_report_to_printer/i18n/fr.po similarity index 57% rename from __unported__/base_report_to_printer/i18n/fr.po rename to base_report_to_printer/i18n/fr.po index 19e1039..1e06bfa 100644 --- a/__unported__/base_report_to_printer/i18n/fr.po +++ b/base_report_to_printer/i18n/fr.po @@ -1,6 +1,6 @@ # Translation of OpenERP Server. # This file contains the translation of the following modules: -# * base_report_to_printer +# * base_report_to_printer # msgid "" msgstr "" @@ -8,8 +8,9 @@ msgstr "" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2013-11-05 14:48+0000\n" "PO-Revision-Date: 2014-02-25 15:06+0000\n" -"Last-Translator: Yannick Vaucher @ Camptocamp \n" +"Last-Translator: Guewen Baconnier @ Camptocamp \n" "Language-Team: \n" +"Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" @@ -17,64 +18,115 @@ msgstr "" "X-Generator: Launchpad (build 16996)\n" #. module: base_report_to_printer -#: selection:printing.printer,status:0 -msgid "Unavailable" -msgstr "Non disponible" +#: field:ir.actions.report.xml,property_printing_action:0 +#: field:printing.report.xml.action,action:0 +msgid "Action" +msgstr "Action" #. module: base_report_to_printer -#: view:printing.printer.update.wizard:0 -msgid "" -"This process will create all missing printers from the current CUPS server." +#: field:ir.actions.report.xml,printing_action_ids:0 +msgid "Actions" +msgstr "Actions" + +#. module: base_report_to_printer +#: selection:printing.printer,status:0 +msgid "Available" +msgstr "Disponible" + +#. module: base_report_to_printer +#: view:printing.printer.update.wizard:base_report_to_printer.printer_update_wizard +msgid "Cancel" +msgstr "Annuler" + +#. module: base_report_to_printer +#: field:printing.action,create_uid:0 field:printing.printer,create_uid:0 +#: field:printing.printer.polling,create_uid:0 +#: field:printing.printer.update.wizard,create_uid:0 +#: field:printing.report.xml.action,create_uid:0 +msgid "Created by" msgstr "" -"Cette opération va créer les imprimantes manquantes à partir du server CUPS " -"courant." + +#. module: base_report_to_printer +#: field:printing.action,create_date:0 field:printing.printer,create_date:0 +#: field:printing.printer.polling,create_date:0 +#: field:printing.printer.update.wizard,create_date:0 +#: field:printing.report.xml.action,create_date:0 +msgid "Created on" +msgstr "" + +#. module: base_report_to_printer +#: field:printing.printer,default:0 +msgid "Default" +msgstr "Par défaut" + +#. module: base_report_to_printer +#: field:res.users,printing_printer_id:0 +msgid "Default Printer" +msgstr "Imprimante par défaut" #. module: base_report_to_printer #: selection:printing.printer,status:0 -msgid "Unknown" -msgstr "Inconnu" +msgid "Error" +msgstr "Erreur" #. module: base_report_to_printer -#: field:printing.printer,system_name:0 -msgid "System Name" -msgstr "Nom sytème" +#: field:printing.action,id:0 field:printing.printer,id:0 +#: field:printing.printer.polling,id:0 +#: field:printing.printer.update.wizard,id:0 +#: field:printing.report.xml.action,id:0 +msgid "ID" +msgstr "" + +#. module: base_report_to_printer +#: field:printing.action,write_uid:0 field:printing.printer,write_uid:0 +#: field:printing.printer.polling,write_uid:0 +#: field:printing.printer.update.wizard,write_uid:0 +#: field:printing.report.xml.action,write_uid:0 +msgid "Last Updated by" +msgstr "" + +#. module: base_report_to_printer +#: field:printing.action,write_date:0 field:printing.printer,write_date:0 +#: field:printing.printer.polling,write_date:0 +#: field:printing.printer.update.wizard,write_date:0 +#: field:printing.report.xml.action,write_date:0 +msgid "Last Updated on" +msgstr "" + +#. module: base_report_to_printer +#: field:printing.printer.polling,last_update:0 +msgid "Last update" +msgstr "" #. module: base_report_to_printer #: field:printing.printer,location:0 msgid "Location" msgstr "Emplacement" -#. module: base_report_to_printer -#: model:ir.actions.act_window,name:base_report_to_printer.action_printing_printer_form -#: model:ir.ui.menu,name:base_report_to_printer.menu_printing_printer_form -#: view:printing.printer:0 -msgid "Printers" -msgstr "Imprimantes" - -#. module: base_report_to_printer -#: view:ir.actions.report.xml:0 -msgid "Print" -msgstr "Imprimer" - -#. module: base_report_to_printer -#: field:res.users,printing_action:0 -msgid "Printing Action" -msgstr "Activité d'impression" - -#. module: base_report_to_printer -#: field:printing.action,type:0 -msgid "Type" -msgstr "Type" - #. module: base_report_to_printer #: field:printing.printer,model:0 msgid "Model" msgstr "Modèle" #. module: base_report_to_printer -#: selection:printing.printer,status:0 -msgid "Available" -msgstr "Disponible" +#: field:printing.action,name:0 field:printing.printer,name:0 +msgid "Name" +msgstr "Nom" + +#. module: base_report_to_printer +#: view:res.users:base_report_to_printer.view_printing_users_form +msgid "Preferences" +msgstr "Préférences" + +#. module: base_report_to_printer +#: view:ir.actions.report.xml:base_report_to_printer.action_report_xml_form +msgid "Print" +msgstr "Imprimer" + +#. module: base_report_to_printer +#: model:ir.model,name:base_report_to_printer.model_printing_action +msgid "Print Job Action" +msgstr "Action d'impression" #. module: base_report_to_printer #: field:ir.actions.report.xml,printing_printer_id:0 @@ -84,147 +136,141 @@ msgid "Printer" msgstr "Imprimante" #. module: base_report_to_printer -#: model:ir.model,name:base_report_to_printer.model_res_users -msgid "Users" -msgstr "Utilisateurs" +#: model:ir.ui.menu,name:base_report_to_printer.menu_printing_printer_form +#: view:printing.printer:base_report_to_printer.view_printing_printer_form +#: view:printing.printer:base_report_to_printer.view_printing_printer_search +#: view:printing.printer:base_report_to_printer.view_printing_printer_tree +msgid "Printers" +msgstr "Imprimantes" #. module: base_report_to_printer -#: model:ir.model,name:base_report_to_printer.model_printing_report_xml_action -#: view:printing.report.xml.action:0 -msgid "Report Printing Actions" -msgstr "Rapport d'activité d'impression" +#: model:ir.model,name:base_report_to_printer.model_printing_printer_polling +msgid "Printers Polling" +msgstr "Recherche d'imprimantes" #. module: base_report_to_printer -#: view:ir.actions.report.xml:0 -msgid "Specific actions per user" -msgstr "Action spécifique par utilisateur" +#: model:ir.ui.menu,name:base_report_to_printer.menu_printing_main +#: selection:printing.printer,status:0 +#: view:res.users:base_report_to_printer.view_printing_users_prefs +msgid "Printing" +msgstr "Impression en cours" #. module: base_report_to_printer -#: model:ir.model,name:base_report_to_printer.model_printing_action -msgid "Print Job Action" -msgstr "Action de Job d'impression" +#: model:res.groups,name:base_report_to_printer.res_groups_printingprintoperator0 +msgid "Printing / Print Operator" +msgstr "Opérateur d'impression" #. module: base_report_to_printer -#: field:printing.report.xml.action,user_id:0 -msgid "User" -msgstr "Utilisateur" +#: field:res.users,printing_action:0 +msgid "Printing action" +msgstr "Action d'impression" #. module: base_report_to_printer +#: model:ir.model,name:base_report_to_printer.model_report #: field:printing.report.xml.action,report_id:0 msgid "Report" msgstr "Rapport" #. module: base_report_to_printer -#: field:printing.printer,status:0 -msgid "Status" -msgstr "Statut" +#: model:ir.model,name:base_report_to_printer.model_printing_report_xml_action +#: view:printing.report.xml.action:base_report_to_printer.printing_report_xml_action_form +#: view:printing.report.xml.action:base_report_to_printer.printing_report_xml_action_tree +msgid "Report Printing Actions" +msgstr "Actions d'impression de rapports" #. module: base_report_to_printer -#: model:ir.actions.act_window,name:base_report_to_printer.action_printing_printer_form -msgid "Show Printers" -msgstr "Afficher les imprimantes" +#: model:ir.ui.menu,name:base_report_to_printer.menu_printing_reports +msgid "Reports" +msgstr "Rapport" #. module: base_report_to_printer -#: view:printing.printer.update.wizard:0 -msgid "Ok" -msgstr "Ok" - -#. module: base_report_to_printer -#: field:printing.action,name:0 -#: field:printing.printer,name:0 -msgid "Name" -msgstr "Nom" - -#. module: base_report_to_printer -#: view:printing.printer:0 -msgid "Set Default" -msgstr "Définitir par défaut" - -#. module: base_report_to_printer -#: field:printing.printer,default:0 -#: field:res.users,printing_printer_id:0 -msgid "Default Printer" -msgstr "Imprimante par défaut" - -#. module: base_report_to_printer -#: code:addons/base_report_to_printer/printing.py:189 -#, python-format -msgid "Send to Client" -msgstr "Envoyer au client" - -#. module: base_report_to_printer -#: field:printing.printer,uri:0 -msgid "URI" -msgstr "URI" - -#. module: base_report_to_printer -#: model:ir.actions.act_window,name:base_report_to_printer.action_printer_update_wizard -#: model:ir.ui.menu,name:base_report_to_printer.menu_printer_update_wizard -#: view:printing.printer.update.wizard:0 -msgid "Update Printers from CUPS" -msgstr "Mettre à jour les imprimantes depuis CUPS" - -#. module: base_report_to_printer -#: code:addons/base_report_to_printer/printing.py:188 -#, python-format -msgid "Send to Printer" -msgstr "Envoyer à l'imprimante" - -#. module: base_report_to_printer -#: model:ir.ui.menu,name:base_report_to_printer.menu_printing_main -#: selection:printing.printer,status:0 -msgid "Printing" -msgstr "Impression en cours" - -#. module: base_report_to_printer -#: selection:printing.printer,status:0 -msgid "Error" -msgstr "Erreur" - -#. module: base_report_to_printer -#: field:ir.actions.report.xml,property_printing_action:0 -#: field:printing.report.xml.action,action:0 -msgid "Action" -msgstr "Action" - -#. module: base_report_to_printer -#: view:ir.actions.report.xml:0 +#: view:ir.actions.report.xml:base_report_to_printer.action_report_xml_form msgid "Security" msgstr "Sécurité" -#. module: base_report_to_printer -#: field:printing.printer,status_message:0 -msgid "Status Message" -msgstr "Message de Statut" - -#. module: base_report_to_printer -#: help:ir.actions.report.xml,printing_action_ids:0 -msgid "This field allows configuring action and printer on a per user basis" -msgstr "" -"Ce champs permet de configurer les action et les imprimante par utilisateur" - #. module: base_report_to_printer #: selection:printing.printer,status:0 msgid "Server Error" msgstr "Erreur serveur" #. module: base_report_to_printer -#: field:ir.actions.report.xml,printing_action_ids:0 -msgid "Actions" -msgstr "Actions" +#: view:printing.printer:base_report_to_printer.view_printing_printer_form +msgid "Set Default" +msgstr "Définir par défaut" #. module: base_report_to_printer -#: view:printing.printer.update.wizard:0 -msgid "Cancel" -msgstr "Annuler" +#: model:ir.actions.act_window,name:base_report_to_printer.action_printing_printer_form +msgid "Show Printers" +msgstr "Afficher les imprimantes" #. module: base_report_to_printer -#: model:res.groups,name:base_report_to_printer.res_groups_printingprintoperator0 -msgid "Printing / Print Operator" +#: view:ir.actions.report.xml:base_report_to_printer.action_report_xml_form +msgid "Specific actions per user" +msgstr "Action spécifique par utilisateur" + +#. module: base_report_to_printer +#: field:printing.printer,status:0 +msgid "Status" +msgstr "État" + +#. module: base_report_to_printer +#: field:printing.printer,status_message:0 +msgid "Status message" +msgstr "Message d'état" + +#. module: base_report_to_printer +#: field:printing.printer,system_name:0 +msgid "System name" +msgstr "Nom système" + +#. module: base_report_to_printer +#: help:ir.actions.report.xml,printing_action_ids:0 +msgid "This field allows configuring action and printer on a per user basis" +msgstr "" +"Ce champs permet de configurer les actions et les imprimantes par utilisateur" + +#. module: base_report_to_printer +#: view:printing.printer.update.wizard:base_report_to_printer.printer_update_wizard +msgid "" +"This process will create all the missing printers from the current CUPS " +"server." +msgstr "" +"Cette opération va créer les imprimantes manquantes à partir du serveur CUPS " +"courant." + +#. module: base_report_to_printer +#: field:printing.action,type:0 +msgid "Type" +msgstr "Type" + +#. module: base_report_to_printer +#: selection:printing.printer,status:0 +msgid "Unavailable" +msgstr "Non disponible" + +#. module: base_report_to_printer +#: selection:printing.printer,status:0 +msgid "Unknown" +msgstr "Inconnu" + +#. module: base_report_to_printer +#: model:ir.actions.act_window,name:base_report_to_printer.action_printer_update_wizard +#: model:ir.ui.menu,name:base_report_to_printer.menu_printer_update_wizard +#: view:printing.printer.update.wizard:base_report_to_printer.printer_update_wizard +msgid "Update Printers from CUPS" +msgstr "Mettre à jour les imprimantes depuis CUPS" + +#. module: base_report_to_printer +#: field:printing.printer,uri:0 +msgid "URI" msgstr "" #. module: base_report_to_printer -#: code:addons/base_report_to_printer/printing.py:190 -#, python-format -msgid "Use user's defaults" -msgstr "Utiliser la configuration par défaut de l'utilisateur" +#: field:printing.report.xml.action,user_id:0 +msgid "User" +msgstr "Utilisateur" + +#. module: base_report_to_printer +#: model:ir.model,name:base_report_to_printer.model_res_users +msgid "Users" +msgstr "Utilisateurs" 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/base_report_to_printer/ir_report.py b/base_report_to_printer/ir_report.py new file mode 100644 index 0000000..4b61054 --- /dev/null +++ b/base_report_to_printer/ir_report.py @@ -0,0 +1,98 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Copyright (c) 2007 Ferran Pegueroles +# Copyright (c) 2009 Albert Cervera i Areny +# Copyright (C) 2011 Agile Business Group sagl () +# Copyright (C) 2011 Domsense srl () +# 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 +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## +import logging + +from openerp import models, fields, api + +_logger = logging.getLogger('base_report_to_printer') + + +class ReportXml(models.Model): + """ + Reports + """ + + _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 behaviour(self): + result = {} + 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() + + # Retrieve user default values + 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: + action = default_action + printer = default_printer + + # Retrieve report default values + 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 + print_action = printing_act_obj.search( + [('report_id', '=', report.id), + ('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, + } + return result diff --git a/base_report_to_printer/printing.py b/base_report_to_printer/printing.py new file mode 100644 index 0000000..daff378 --- /dev/null +++ b/base_report_to_printer/printing.py @@ -0,0 +1,367 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Copyright (c) 2007 Ferran Pegueroles +# Copyright (c) 2009 Albert Cervera i Areny +# Copyright (C) 2011 Agile Business Group sagl () +# Copyright (C) 2011 Domsense srl () +# 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 +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## +import logging +import os + +from contextlib import contextmanager +from datetime import datetime +from tempfile import mkstemp +from threading import Thread + +import cups +import psycopg2 + +from openerp import models, fields, api, sql_db +from openerp.tools import ormcache + +_logger = logging.getLogger(__name__) + +POLL_INTERVAL = 15 # seconds + + +class PrintingPrinterPolling(models.Model): + """ Keep the last update time of printers update. + + This table will contain only 1 row, with the last time we checked + the list of printers from cups. + + The table is locked before an update so 2 processes won't be able + to do the update at the same time. + """ + _name = 'printing.printer.polling' + _description = 'Printers Polling' + + last_update = fields.Datetime() + + @api.model + def find_unique_record(self): + polling = self.search([], limit=1) + return polling + + @api.model + @ormcache() + def table_exists(self): + return self._model._table_exist(self.env.cr) + + def _create_table(self, cr): + super(PrintingPrinterPolling, self)._create_table(cr) + self.clear_caches() + + @api.model + def find_or_create_unique_record(self): + polling = self.find_unique_record() + if polling: + return polling + cr = self.env.cr + try: + # Will be released at the end of the transaction. Locks the + # full table for insert/update because we must have only 1 + # record in this table, so we prevent 2 processes to create + # each one one line at the same time. + cr.execute("LOCK TABLE %s IN SHARE ROW EXCLUSIVE MODE NOWAIT" % + self._table, log_exceptions=False) + except psycopg2.OperationalError as err: + # the lock could not be acquired, already running + if err.pgcode == '55P03': + _logger.debug('Another process/thread is already ' + 'creating the polling record.') + return self.browse() + else: + raise + return self.create({'last_update': False}) + + @api.multi + def lock(self): + """ Lock the polling record + + Lock the record in the database so we can prevent concurrent + processes to update at the same time. + + The lock is released either on commit or rollback of the + transaction. + + Returns if the record has been locked or not. + """ + self.ensure_one() + cr = self.env.cr + sql = ("SELECT id FROM %s WHERE id = %%s FOR UPDATE NOWAIT" % + self._table) + try: + cr.execute(sql, (self.id, ), log_exceptions=False) + except psycopg2.OperationalError as err: + # the lock could not be acquired, already running + if err.pgcode == '55P03': + _logger.debug('Another process/thread is already ' + 'updating the printers list.') + return False + if err.pgcode == '40001': + _logger.debug('could not serialize access due to ' + 'concurrent update') + return False + else: + raise + return True + + @contextmanager + @api.model + def start_update(self): + locked = False + polling = self.find_or_create_unique_record() + if polling: + if polling.lock(): + locked = True + yield locked + if locked: + polling.write({'last_update': fields.Datetime.now()}) + + @ormcache() + def _last_update_cached(self): + """ Get the last update's datetime, the returned value is cached """ + polling = self.find_unique_record() + if not polling: + return False + last_update = polling.last_update + if last_update: + last_update = fields.Datetime.from_string(last_update) + return last_update + + @api.model + def last_update_cached(self): + """ Returns the last update datetime from a cache + + The check if the list of printers needs to be refreshed is + called very often (each time a browse is done on ``res.users``), + so we avoid to hit the database on every updates by keeping the + last value in cache. + The cache has no expiration so we manually clear it when the + poll interval (defaulted to 10 seconds) is reached. + """ + last_update = self._last_update_cached() + now = datetime.now() + if last_update and (now - last_update).seconds >= POLL_INTERVAL: + # Invalidates last_update_cached and read a fresh value + # from the database + self.clear_caches() + return self._last_update_cached() + return last_update + + @api.model + def need_update(self): + last_update = self.last_update_cached() + now = datetime.now() + # Only update printer status if current status is more than 10 + # seconds old. + if not last_update or (now - last_update).seconds >= POLL_INTERVAL: + self.clear_caches() # invalidates last_update_cached + return True + return False + + @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(): + try: + self.env = api.Environment(cr, uid, context) + printer_obj = self.env['printing.printer'] + with self.start_update() as locked: + if not locked: + return # could not obtain lock + + printer_recs = printer_obj.search([]) + + try: + connection = cups.Connection() + printers = connection.getPrinters() + except: + printer_recs.write({'status': 'server-error'}) + else: + for printer in printer_recs: + cups_printer = printers.get(printer.system_name) + if cups_printer: + printer.update_from_cups(connection, + cups_printer) + else: + # not in cups list + printer.status = 'unavailable' + + self.env.cr.commit() + except: + self.env.cr.rollback() + raise + finally: + self.env.cr.close() + + +class PrintingPrinter(models.Model): + """ + Printers + """ + + _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(string='URI', readonly=True) + + @api.multi + def _prepare_update_from_cups(self, cups_connection, cups_printer): + mapping = { + 3: 'available', + 4: 'printing', + 5: 'error' + } + vals = { + 'model': cups_printer.get('printer-make-and-model', False), + 'location': cups_printer.get('printer-location', False), + 'uri': cups_printer.get('device-uri', False), + 'status': mapping.get(cups_printer['printer-state'], 'unknown'), + } + return vals + + @api.multi + def update_from_cups(self, cups_connection, cups_printer): + """ Update a printer from the information returned by cups. + + :param cups_connection: connection to CUPS, may be used when the + method is overriden (e.g. in printer_tray) + :param cups_printer: dict of information returned by CUPS for the + current printer + """ + vals = self._prepare_update_from_cups(cups_connection, cups_printer) + self.write(vals) + + @api.multi + def print_options(self, report, format): + """ Hook to set print options """ + options = {} + if format == 'raw': + options['raw'] = True + return options + + @api.multi + def print_document(self, report, content, format): + """ Print a file + + Format could be pdf, qweb-pdf, raw, ... + + """ + self.ensure_one() + fd, file_name = mkstemp() + try: + os.write(fd, content) + finally: + os.close(fd) + connection = cups.Connection() + + options = self.print_options(report, format) + + connection.printFile(self.system_name, + file_name, + file_name, + options=options) + _logger.info("Printing job: '%s'" % file_name) + return True + + @api.model + def start_printer_update(self): + polling_obj = self.env['printing.printer.polling'] + thread = Thread(target=polling_obj.update_printers_status, args=()) + thread.start() + + @api.model + def update(self): + """Update printer status if current status is more than 10s old.""" + polling_obj = self.env['printing.printer.polling'] + if not polling_obj.table_exists(): + # On the installation of the module, this method could be + # called before the 'printing.printer.polling' table exists + # (but the model already is in memory) + return + if polling_obj.need_update(): + self.start_printer_update() + return True + + @api.v7 + def browse(self, cr, uid, arg=None, context=None): + _super = super(PrintingPrinter, self) + recs = _super.browse(cr, uid, arg=arg, context=context) + if not recs._context.get('skip_update'): + recs.with_context(skip_update=True).update() + return recs + + @api.v8 + def browse(self, arg=None): + recs = super(PrintingPrinter, self).browse(arg=arg) + if not recs._context.get('skip_update'): + recs.with_context(skip_update=True).update() + return recs + + @api.multi + def set_default(self): + if not self: + return + self.ensure_one() + default_printers = self.search([('default', '=', True)]) + default_printers.write({'default': False}) + self.write({'default': True}) + return True + + @api.multi + def get_default(self): + return self.search([('default', '=', True)], limit=1) + +# +# Actions +# + + +def _available_action_types(self): + return [('server', 'Send to Printer'), + ('client', 'Send to Client'), + ('user_default', "Use user's defaults"), + ] + + +class PrintingAction(models.Model): + _name = 'printing.action' + _description = 'Print Job Action' + + name = fields.Char(required=True) + type = fields.Selection(_available_action_types, required=True) 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 81% rename from __unported__/base_report_to_printer/printing_view.xml rename to base_report_to_printer/printing_view.xml index d9c7986..42f4be4 100644 --- a/__unported__/base_report_to_printer/printing_view.xml +++ b/base_report_to_printer/printing_view.xml @@ -9,17 +9,28 @@ printing.printer
- - - - + +
+

+

+
+ + + + +