Merge pull request #12 from guewen/8.0-base_report_to_printer-migr

Migration of base_report_to_printer
This commit is contained in:
Pedro M. Baeza
2014-11-19 22:46:31 +01:00
21 changed files with 1139 additions and 875 deletions

View File

@@ -1,132 +0,0 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (c) 2007 Ferran Pegueroles <ferran@pegueroles.com>
# Copyright (c) 2009 Albert Cervera i Areny <albert@nan-tic.com>
# Copyright (C) 2011 Agile Business Group sagl (<http://www.agilebg.com>)
# Copyright (C) 2011 Domsense srl (<http://www.domsense.com>)
# Copyright (C) 2013 Camptocamp (<http://www.camptocamp.com>)
# 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 <http://www.gnu.org/licenses/>.
#
##############################################################################
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

View File

@@ -1,224 +0,0 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (c) 2007 Ferran Pegueroles <ferran@pegueroles.com>
# Copyright (c) 2009 Albert Cervera i Areny <albert@nan-tic.com>
# Copyright (C) 2011 Agile Business Group sagl (<http://www.agilebg.com>)
# Copyright (C) 2011 Domsense srl (<http://www.domsense.com>)
# Copyright (C) 2013 Camptocamp (<http://www.camptocamp.com>)
# 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 <http://www.gnu.org/licenses/>.
#
##############################################################################
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),
}

View File

@@ -1,77 +0,0 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (c) 2007 Ferran Pegueroles <ferran@pegueroles.com>
# Copyright (c) 2009 Albert Cervera i Areny <albert@nan-tic.com>
# Copyright (C) 2011 Agile Business Group sagl (<http://www.agilebg.com>)
# Copyright (C) 2011 Domsense srl (<http://www.domsense.com>)
# Copyright (C) 2013 Camptocamp (<http://www.camptocamp.com>)
# 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 <http://www.gnu.org/licenses/>.
#
##############################################################################
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:

View File

@@ -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 <ferran@pegueroles.com>
* Albert Cervera i Areny <albert@nan-tic.com>
* Davide Corio <davide.corio@agilebg.com>
* Lorenzo Battistini <lorenzo.battistini@agilebg.com>
* Yannick Vaucher <yannick.vaucher@camptocamp.com>
* Lionel Sausin <ls@numerigraphe.com>
* Guewen Baconnier <guewen.baconnier@camptocamp.com>

View File

@@ -5,8 +5,7 @@
# Copyright (c) 2009 Albert Cervera i Areny <albert@nan-tic.com>
# Copyright (C) 2011 Agile Business Group sagl (<http://www.agilebg.com>)
# Copyright (C) 2011 Domsense srl (<http://www.domsense.com>)
# Copyright (C) 2013 Camptocamp (<http://www.camptocamp.com>)
# All Rights Reserved
# Copyright (C) 2013-2014 Camptocamp (<http://www.camptocamp.com>)
#
# 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

View File

@@ -5,8 +5,7 @@
# Copyright (c) 2009 Albert Cervera i Areny <albert@nan-tic.com>
# Copyright (C) 2011 Agile Business Group sagl (<http://www.agilebg.com>)
# Copyright (C) 2011 Domsense srl (<http://www.domsense.com>)
# Copyright (C) 2013 Camptocamp (<http://www.camptocamp.com>)
# All Rights Reserved
# Copyright (C) 2013-2014 Camptocamp (<http://www.camptocamp.com>)
#
# 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 <ferran@pegueroles.com>
* Albert Cervera i Areny <albert@nan-tic.com>
* Davide Corio <davide.corio@agilebg.com>
* Lorenzo Battistini <lorenzo.battistini@agilebg.com>
* Yannick Vaucher <yannick.vaucher@camptocamp.com>
* Lionel Sausin <ls@numerigraphe.com>
""",
'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': {

View File

@@ -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 ""

View File

@@ -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 <Unknown>\n"
"Last-Translator: Guewen Baconnier @ Camptocamp <Unknown>\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"

View File

@@ -0,0 +1,98 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (c) 2007 Ferran Pegueroles <ferran@pegueroles.com>
# Copyright (c) 2009 Albert Cervera i Areny <albert@nan-tic.com>
# Copyright (C) 2011 Agile Business Group sagl (<http://www.agilebg.com>)
# Copyright (C) 2011 Domsense srl (<http://www.domsense.com>)
# Copyright (C) 2013-2014 Camptocamp (<http://www.camptocamp.com>)
#
# 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 <http://www.gnu.org/licenses/>.
#
##############################################################################
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

View File

@@ -0,0 +1,367 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (c) 2007 Ferran Pegueroles <ferran@pegueroles.com>
# Copyright (c) 2009 Albert Cervera i Areny <albert@nan-tic.com>
# Copyright (C) 2011 Agile Business Group sagl (<http://www.agilebg.com>)
# Copyright (C) 2011 Domsense srl (<http://www.domsense.com>)
# Copyright (C) 2013-2014 Camptocamp (<http://www.camptocamp.com>)
#
# 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 <http://www.gnu.org/licenses/>.
#
##############################################################################
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)

View File

@@ -9,17 +9,28 @@
<field name="model">printing.printer</field>
<field name="arch" type="xml">
<form string="Printers">
<field name="name" select="1"/>
<field name="system_name" select="1"/>
<group col="3" colspan="2">
<field name="default" select="1"/>
<sheet>
<div class="oe_title">
<h1>
<label for="name"/>
<field name="name"/>
</h1>
</div>
<group>
<field name="system_name"/>
</group>
<group col="3" colspan="4">
<field name="default"/>
<button name="set_default" string="Set Default" type="object"/>
</group>
<field name="uri" select="2"/>
<field name="model" select="2"/>
<field name="location" select="2"/>
<field name="status" select="1"/>
<field name="status_message" select="2"/>
<group>
<field name="uri"/>
<field name="model"/>
<field name="location"/>
<field name="status"/>
<field name="status_message"/>
</group>
</sheet>
</form>
</field>
</record>
@@ -37,6 +48,19 @@
</field>
</record>
<record model="ir.ui.view" id="view_printing_printer_search">
<field name="name">printing.printer.search</field>
<field name="model">printing.printer</field>
<field name="arch" type="xml">
<search string="Printers">
<field name="name"/>
<field name="system_name"/>
<field name="location"/>
<field name="status"/>
</search>
</field>
</record>
<record model="ir.actions.act_window" id="action_printing_printer_form">
<field name="name">Show Printers</field>
<field name="type">ir.actions.act_window</field>

View File

@@ -0,0 +1,39 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Author: Guewen Baconnier
# Copyright 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 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 Affero 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 <http://www.gnu.org/licenses/>.
#
##############################################################################
from openerp import models
class Report(models.Model):
_inherit = 'report'
def get_pdf(self, cr, uid, ids, report_name, html=None,
data=None, context=None):
result = super(Report, self).get_pdf(cr, uid, ids, report_name,
html=html, data=data,
context=context)
report = self._get_report_from_name(cr, uid, report_name)
data = report.behaviour()[report.id]
action = data['action']
printer = data['printer']
if action != 'client' and result:
printer.print_document(report, result, report.report_type)
return result

View File

@@ -0,0 +1,86 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (c) 2007 Ferran Pegueroles <ferran@pegueroles.com>
# Copyright (c) 2009 Albert Cervera i Areny <albert@nan-tic.com>
# Copyright (C) 2011 Agile Business Group sagl (<http://www.agilebg.com>)
# Copyright (C) 2011 Domsense srl (<http://www.domsense.com>)
# Copyright (C) 2013-2014 Camptocamp (<http://www.camptocamp.com>)
#
# 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 <http://www.gnu.org/licenses/>.
#
##############################################################################
import openerp
from openerp.service.report import self_reports
original_exp_report = openerp.service.report.exp_report
def exp_report(db, uid, object, ids, datas=None, context=None):
""" Export Report """
# We can't use the named args because a monkey patch in 'calendar'
# doesn't use them and use a different name for 'datas'
res = original_exp_report(db, uid, object, ids, datas, context)
self_reports[res]['report_name'] = object
return res
openerp.service.report.exp_report = exp_report
original_exp_report_get = openerp.service.report.exp_report_get
def exp_report_get(db, uid, report_id):
registry = openerp.registry(db)
cr = registry.cursor()
try:
# First of all load report defaults: name, action and printer
report_obj = registry['ir.actions.report.xml']
report_name = self_reports[report_id]['report_name']
report = report_obj.search(cr, uid,
[('report_name', '=', 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)
and self_reports[report_id].get('result')
and self_reports[report_id].get('format')):
printer.print_document(report,
self_reports[report_id]['result'],
self_reports[report_id]['format'])
# 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
# prints
# raise osv.except_osv(
# _('Printing...'),
# _('Document sent to printer %s') % (printer,))
except:
cr.rollback()
raise
finally:
cr.close()
return original_exp_report_get(db, uid, report_id)
openerp.service.report.exp_report_get = exp_report_get

View File

@@ -5,8 +5,7 @@
# Copyright (c) 2009 Albert Cervera i Areny <albert@nan-tic.com>
# Copyright (C) 2011 Agile Business Group sagl (<http://www.agilebg.com>)
# Copyright (C) 2011 Domsense srl (<http://www.domsense.com>)
# Copyright (C) 2013 Camptocamp (<http://www.camptocamp.com>)
# All Rights Reserved
# Copyright (C) 2013-2014 Camptocamp (<http://www.camptocamp.com>)
#
# 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,29 +21,32 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
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'),
}
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')
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,
}
# 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,
}

View File

@@ -5,8 +5,7 @@
# Copyright (c) 2009 Albert Cervera i Areny <albert@nan-tic.com>
# Copyright (C) 2011 Agile Business Group sagl (<http://www.agilebg.com>)
# Copyright (C) 2011 Domsense srl (<http://www.domsense.com>)
# Copyright (C) 2013 Camptocamp (<http://www.camptocamp.com>)
# All Rights Reserved
# Copyright (C) 2013-2014 Camptocamp (<http://www.camptocamp.com>)
#
# 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 <http://www.gnu.org/licenses/>.
#
##############################################################################
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')

View File

@@ -4,7 +4,6 @@
# Copyright (c) 2009 Albert Cervera i Areny <albert@nan-tic.com>
# Copyright (C) 2011 Agile Business Group sagl (<http://www.agilebg.com>)
# Copyright (C) 2011 Domsense srl (<http://www.domsense.com>)
# 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

View File

@@ -4,7 +4,7 @@
# Copyright (c) 2009 Albert Cervera i Areny <albert@nan-tic.com>
# Copyright (C) 2011 Agile Business Group sagl (<http://www.agilebg.com>)
# Copyright (C) 2011 Domsense srl (<http://www.domsense.com>)
# All Rights Reserved
# Copyright (C) 2014 Camptocamp SA (<http://www.camptocamp.com>)
#
# 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 @@ class printing_printer_update_wizard(orm.TransientModel):
'res_model': 'printing.printer',
'type': 'ir.actions.act_window',
'target': 'current',
}
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
}

View File

@@ -4,13 +4,14 @@
<record id="printer_update_wizard" model="ir.ui.view">
<field name="name">printing.printer.update.wizard</field>
<field name="model">printing.printer.update.wizard</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Update Printers from CUPS" col="2">
<form string="Update Printers from CUPS">
<label string="This process will create all missing printers from the current CUPS server." colspan="2"/>
<separator string="" colspan="2"/>
<button name="action_cancel" icon="gtk-cancel" string="Cancel" special="cancel"/>
<button name="action_ok" type="object" icon="gtk-ok" string="Ok"/>
<footer>
<button name="action_ok" string="Ok" type="object" class="oe_highlight"/>
or
<button string="Cancel" class="oe_link" special="cancel"/>
</footer>
</form>
</field>
</record>