mirror of
https://github.com/OCA/report-print-send.git
synced 2025-02-16 07:11:31 +02:00
[WIP] Commit before rebase on latest #109 for user and view updates
Migration of printer_tray to v11 and integration with base_report_to_printer
This commit is contained in:
committed by
Rod Schouteden
parent
877e5cbcc9
commit
52a8e0ec2b
@@ -8,18 +8,25 @@ 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 behaviour providing you a downloadable PDF
|
||||
* `Send to Printer` prints the report on selected printer
|
||||
|
||||
It detects trays on printers installation plus permits to select the
|
||||
paper source on which you want to print directly.
|
||||
|
||||
Report behaviour is defined by settings.
|
||||
|
||||
You will find this option on default user config, on default report
|
||||
config and on specific config per user per report.
|
||||
|
||||
This allows you to dedicate a specific paper source for example for
|
||||
preprinted paper such as payment slip.
|
||||
|
||||
Settings can be configured:
|
||||
|
||||
* globaly
|
||||
* globally
|
||||
* per user
|
||||
* per report
|
||||
* per user and report
|
||||
@@ -47,12 +54,17 @@ rights to give users the ability to view the print menu.
|
||||
Usage
|
||||
=====
|
||||
|
||||
To show all available printers for your server, use the
|
||||
`Settings/Configuration/Printing/Update Printers from CUPS` wizard.
|
||||
* To update the CUPS printers in *Settings > Printing > Update Printers
|
||||
from CUPS*
|
||||
* If you want to print a report on a specific printer or tray, you can change
|
||||
these in *Settings > Printing > Reports* to define default behaviour.
|
||||
* If you want to print a report on a specific printer and/or tray for a user, you can
|
||||
change these in *Settings > Printing > Reports* in
|
||||
*Specific actions per user*
|
||||
* Users may also select a default action, printer or tray in their preferences
|
||||
|
||||
|
||||
Then go to the user profile and set the users printing action and default
|
||||
printer.
|
||||
When no tray is configured for a report and a user, the
|
||||
default tray setup on the CUPS server is used.
|
||||
|
||||
Caveat
|
||||
------
|
||||
@@ -62,7 +74,7 @@ displayed for the deprecated report types (RML, Webkit, ...).
|
||||
|
||||
.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas
|
||||
:alt: Try me on Runbot
|
||||
:target: https://runbot.odoo-community.org/runbot/144/9.0
|
||||
:target: https://runbot.odoo-community.org/runbot/144/11.0
|
||||
|
||||
|
||||
Known issues / Roadmap
|
||||
|
||||
@@ -8,10 +8,10 @@
|
||||
|
||||
{
|
||||
'name': "Report to printer",
|
||||
'version': '11.0.1.0.1',
|
||||
'version': '11.0.2.0.0',
|
||||
'category': 'Generic Modules/Base',
|
||||
'author': "Agile Business Group & Domsense, Pegueroles SCP, NaN,"
|
||||
" LasLabs, Odoo Community Association (OCA)",
|
||||
" LasLabs, Camptocamp, Odoo Community Association (OCA)",
|
||||
'website': 'http://www.agilebg.com',
|
||||
'license': 'AGPL-3',
|
||||
"depends": ['web'],
|
||||
|
||||
@@ -6,4 +6,5 @@ from . import printing_job
|
||||
from . import printing_printer
|
||||
from . import printing_server
|
||||
from . import printing_report_xml_action
|
||||
from . import printing_tray
|
||||
from . import res_users
|
||||
|
||||
@@ -21,6 +21,11 @@ class IrActionsReport(models.Model):
|
||||
comodel_name='printing.printer',
|
||||
string='Default Printer'
|
||||
)
|
||||
printer_tray_id = fields.Many2one(
|
||||
comodel_name='printing.tray',
|
||||
string='Paper Source',
|
||||
domain="[('printer_id', '=', printing_printer_id)]",
|
||||
)
|
||||
printing_action_ids = fields.One2many(
|
||||
comodel_name='printing.report.xml.action',
|
||||
inverse_name='report_id',
|
||||
@@ -29,6 +34,11 @@ class IrActionsReport(models.Model):
|
||||
'user basis'
|
||||
)
|
||||
|
||||
@api.onchange('printing_printer_id')
|
||||
def onchange_printing_printer_id(self):
|
||||
""" Reset the tray when the printer is changed """
|
||||
self.printer_tray_id = False
|
||||
|
||||
@api.model
|
||||
def print_action_for_report_name(self, report_name):
|
||||
""" Returns if the action is a direct print or pdf
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
# Copyright (C) 2016 SYLEAM (<http://www.syleam.fr>)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
import errno
|
||||
import logging
|
||||
|
||||
import os
|
||||
from tempfile import mkstemp
|
||||
|
||||
@@ -17,6 +17,11 @@ from odoo import models, fields, api
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
try:
|
||||
import cups
|
||||
except ImportError:
|
||||
_logger.debug('Cannot `import cups`.')
|
||||
|
||||
|
||||
class PrintingPrinter(models.Model):
|
||||
"""
|
||||
@@ -52,6 +57,55 @@ class PrintingPrinter(models.Model):
|
||||
model = fields.Char(readonly=True)
|
||||
location = fields.Char(readonly=True)
|
||||
uri = fields.Char(string='URI', readonly=True)
|
||||
tray_ids = fields.One2many(comodel_name='printing.tray',
|
||||
inverse_name='printer_id',
|
||||
string='Paper Sources')
|
||||
|
||||
@api.multi
|
||||
def _prepare_update_from_cups(self, cups_connection, cups_printer):
|
||||
vals = super(PrintingPrinter, self)._prepare_update_from_cups(
|
||||
cups_connection, cups_printer)
|
||||
|
||||
printer_uri = cups_printer['printer-uri-supported']
|
||||
printer_system_name = printer_uri[printer_uri.rfind('/') + 1:]
|
||||
ppd_info = cups_connection.getPPD3(printer_system_name)
|
||||
ppd_path = ppd_info[2]
|
||||
if not ppd_path:
|
||||
return vals
|
||||
|
||||
ppd = cups.PPD(ppd_path)
|
||||
option = ppd.findOption('InputSlot')
|
||||
try:
|
||||
os.unlink(ppd_path)
|
||||
except OSError as err:
|
||||
# ENOENT means No such file or directory
|
||||
# The file has already been deleted, we can continue the update
|
||||
if err.errno != errno.ENOENT:
|
||||
raise
|
||||
if not option:
|
||||
return vals
|
||||
|
||||
vals['tray_ids'] = []
|
||||
cups_trays = {
|
||||
tray_option['choice']: tray_option['text']
|
||||
for tray_option in option.choices
|
||||
}
|
||||
|
||||
# Add new trays
|
||||
vals['tray_ids'].extend([
|
||||
(0, 0, {'name': text, 'system_name': choice})
|
||||
for choice, text in cups_trays.items()
|
||||
if choice not in self.tray_ids.mapped('system_name')
|
||||
])
|
||||
|
||||
# Remove deleted trays
|
||||
vals['tray_ids'].extend([
|
||||
(2, tray.id)
|
||||
for tray in self.tray_ids.filtered(
|
||||
lambda record: record.system_name not in cups_trays.keys())
|
||||
])
|
||||
|
||||
return vals
|
||||
|
||||
@api.multi
|
||||
def _prepare_update_from_cups(self, cups_connection, cups_printer):
|
||||
@@ -79,6 +133,25 @@ class PrintingPrinter(models.Model):
|
||||
options['raw'] = 'True'
|
||||
if copies > 1:
|
||||
options['copies'] = str(copies)
|
||||
if report is not None:
|
||||
printing_act_obj = self.env['printing.report.xml.action']
|
||||
if report.printer_tray_id:
|
||||
tray = report.printer_tray_id
|
||||
else:
|
||||
# Retrieve user default values
|
||||
tray = self.env.user.printer_tray_id
|
||||
|
||||
# Retrieve report-user specific values
|
||||
action = printing_act_obj.search([
|
||||
('report_id', '=', report.id),
|
||||
('user_id', '=', self.env.uid),
|
||||
('action', '!=', 'user_default'),
|
||||
], limit=1)
|
||||
if action.printer_tray_id:
|
||||
tray = action.printer_tray_id
|
||||
|
||||
if tray:
|
||||
options['InputSlot'] = str(tray.system_name)
|
||||
return options
|
||||
|
||||
@api.multi
|
||||
|
||||
@@ -28,6 +28,17 @@ class PrintingReportXmlAction(models.Model):
|
||||
printer_id = fields.Many2one(comodel_name='printing.printer',
|
||||
string='Printer')
|
||||
|
||||
printer_tray_id = fields.Many2one(
|
||||
comodel_name='printing.tray',
|
||||
string='Paper Source',
|
||||
domain="[('printer_id', '=', printer_id)]",
|
||||
)
|
||||
|
||||
@api.onchange('printer_id')
|
||||
def onchange_printer_id(self):
|
||||
""" Reset the tray when the printer is changed """
|
||||
self.printer_tray_id = False
|
||||
|
||||
@api.multi
|
||||
def behaviour(self):
|
||||
if not self:
|
||||
@@ -35,4 +46,5 @@ class PrintingReportXmlAction(models.Model):
|
||||
return {
|
||||
'action': self.action,
|
||||
'printer': self.printer_id,
|
||||
'tray': self.printer_tray_id.system_name
|
||||
}
|
||||
|
||||
22
base_report_to_printer/models/printing_tray.py
Normal file
22
base_report_to_printer/models/printing_tray.py
Normal file
@@ -0,0 +1,22 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2013-2014 Camptocamp (<http://www.camptocamp.com>)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class PrinterTray(models.Model):
|
||||
_name = 'printing.tray'
|
||||
_description = 'Printer Tray'
|
||||
|
||||
_order = 'name asc'
|
||||
|
||||
name = fields.Char(required=True)
|
||||
system_name = fields.Char(required=True, readonly=True)
|
||||
printer_id = fields.Many2one(
|
||||
comodel_name='printing.printer',
|
||||
string='Printer',
|
||||
required=True,
|
||||
readonly=True,
|
||||
ondelete='cascade',
|
||||
)
|
||||
@@ -37,3 +37,15 @@ class ResUsers(models.Model):
|
||||
'printing_action',
|
||||
'printing_printer_id',
|
||||
])
|
||||
|
||||
printer_tray_id = fields.Many2one(
|
||||
comodel_name='printing.tray',
|
||||
string='Default Printer Paper Source',
|
||||
domain="[('printer_id', '=', printing_printer_id)]",
|
||||
)
|
||||
|
||||
@api.onchange('printing_printer_id')
|
||||
def onchange_printing_printer_id(self):
|
||||
""" Reset the tray when the printer is changed """
|
||||
self.printer_tray_id = False
|
||||
|
||||
|
||||
@@ -1,96 +1,115 @@
|
||||
<?xml version="1.0" ?>
|
||||
<odoo>
|
||||
<data noupdate="1">
|
||||
<record id="printing_group_manager" model="res.groups">
|
||||
<field name="name">Printing / Print Manager</field>
|
||||
<field name="users" eval="[(4, ref('base.user_root'))]"/>
|
||||
</record>
|
||||
<record id="printing_group_user" model="res.groups">
|
||||
<field name="name">Printing / Print User</field>
|
||||
</record>
|
||||
<record id="printing_server_group_manager" model="ir.model.access">
|
||||
<field name="name">Printing Server Manager</field>
|
||||
<field name="model_id" ref="model_printing_server"/>
|
||||
<field name="group_id" ref="printing_group_manager"/>
|
||||
<field eval="1" name="perm_read"/>
|
||||
<field eval="1" name="perm_unlink"/>
|
||||
<field eval="1" name="perm_write"/>
|
||||
<field eval="1" name="perm_create"/>
|
||||
</record>
|
||||
<record id="printing_printer_group_manager" model="ir.model.access">
|
||||
<field name="name">Printing Printer Manager</field>
|
||||
<field name="model_id" ref="model_printing_printer"/>
|
||||
<field name="group_id" ref="printing_group_manager"/>
|
||||
<field eval="1" name="perm_read"/>
|
||||
<field eval="1" name="perm_unlink"/>
|
||||
<field eval="1" name="perm_write"/>
|
||||
<field eval="1" name="perm_create"/>
|
||||
</record>
|
||||
<record id="printing_action_group_manager" model="ir.model.access">
|
||||
<field name="name">Printing Action Manager</field>
|
||||
<field name="model_id" ref="model_printing_action"/>
|
||||
<field name="group_id" ref="printing_group_manager"/>
|
||||
<field eval="1" name="perm_read"/>
|
||||
<field eval="1" name="perm_unlink"/>
|
||||
<field eval="1" name="perm_write"/>
|
||||
<field eval="1" name="perm_create"/>
|
||||
</record>
|
||||
<record id="printing_report_xml_action_group_manager" model="ir.model.access">
|
||||
<field name="name">Printing Report Xml Action Manager</field>
|
||||
<field name="model_id" ref="model_printing_report_xml_action"/>
|
||||
<field name="group_id" ref="printing_group_manager"/>
|
||||
<field eval="1" name="perm_read"/>
|
||||
<field eval="1" name="perm_unlink"/>
|
||||
<field eval="1" name="perm_write"/>
|
||||
<field eval="1" name="perm_create"/>
|
||||
</record>
|
||||
<data noupdate="1">
|
||||
<record id="printing_group_manager" model="res.groups">
|
||||
<field name="name">Printing / Print Manager</field>
|
||||
<field name="users" eval="[(4, ref('base.user_root'))]"/>
|
||||
</record>
|
||||
<record id="printing_group_user" model="res.groups">
|
||||
<field name="name">Printing / Print User</field>
|
||||
</record>
|
||||
<record id="printing_server_group_manager" model="ir.model.access">
|
||||
<field name="name">Printing Server Manager</field>
|
||||
<field name="model_id" ref="model_printing_server"/>
|
||||
<field name="group_id" ref="printing_group_manager"/>
|
||||
<field eval="1" name="perm_read"/>
|
||||
<field eval="1" name="perm_unlink"/>
|
||||
<field eval="1" name="perm_write"/>
|
||||
<field eval="1" name="perm_create"/>
|
||||
</record>
|
||||
<record id="printing_printer_group_manager" model="ir.model.access">
|
||||
<field name="name">Printing Printer Manager</field>
|
||||
<field name="model_id" ref="model_printing_printer"/>
|
||||
<field name="group_id" ref="printing_group_manager"/>
|
||||
<field eval="1" name="perm_read"/>
|
||||
<field eval="1" name="perm_unlink"/>
|
||||
<field eval="1" name="perm_write"/>
|
||||
<field eval="1" name="perm_create"/>
|
||||
</record>
|
||||
<record id="printing_action_group_manager" model="ir.model.access">
|
||||
<field name="name">Printing Action Manager</field>
|
||||
<field name="model_id" ref="model_printing_action"/>
|
||||
<field name="group_id" ref="printing_group_manager"/>
|
||||
<field eval="1" name="perm_read"/>
|
||||
<field eval="1" name="perm_unlink"/>
|
||||
<field eval="1" name="perm_write"/>
|
||||
<field eval="1" name="perm_create"/>
|
||||
</record>
|
||||
<record id="printing_report_xml_action_group_manager" model="ir.model.access">
|
||||
<field name="name">Printing Report Xml Action Manager</field>
|
||||
<field name="model_id" ref="model_printing_report_xml_action"/>
|
||||
<field name="group_id" ref="printing_group_manager"/>
|
||||
<field eval="1" name="perm_read"/>
|
||||
<field eval="1" name="perm_unlink"/>
|
||||
<field eval="1" name="perm_write"/>
|
||||
<field eval="1" name="perm_create"/>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
<data>
|
||||
<record id="printing_server_group_user" model="ir.model.access">
|
||||
<field name="name">Printing Server User</field>
|
||||
<field name="model_id" ref="model_printing_server"/>
|
||||
<field name="group_id" ref="printing_group_user"/>
|
||||
<field eval="1" name="perm_read"/>
|
||||
<field eval="0" name="perm_unlink"/>
|
||||
<field eval="0" name="perm_write"/>
|
||||
<field eval="0" name="perm_create"/>
|
||||
</record>
|
||||
<record id="printing_printer_group_user" model="ir.model.access">
|
||||
<field name="name">Printing Printer User</field>
|
||||
<field name="model_id" ref="model_printing_printer"/>
|
||||
<field name="group_id" ref="printing_group_user"/>
|
||||
<field eval="1" name="perm_read"/>
|
||||
<field eval="0" name="perm_unlink"/>
|
||||
<field eval="0" name="perm_write"/>
|
||||
<field eval="0" name="perm_create"/>
|
||||
</record>
|
||||
<record id="printing_job_group_user" model="ir.model.access">
|
||||
<field name="name">Printing Job User</field>
|
||||
<field name="model_id" ref="model_printing_job"/>
|
||||
<field name="group_id" ref="printing_group_user"/>
|
||||
<field eval="1" name="perm_read"/>
|
||||
<field eval="0" name="perm_unlink"/>
|
||||
<field eval="0" name="perm_write"/>
|
||||
<field eval="0" name="perm_create"/>
|
||||
</record>
|
||||
<record id="printing_action_group_user" model="ir.model.access">
|
||||
<field name="name">Printing Action User</field>
|
||||
<field name="model_id" ref="model_printing_action"/>
|
||||
<field name="group_id" ref="printing_group_user"/>
|
||||
<field eval="1" name="perm_read"/>
|
||||
<field eval="0" name="perm_unlink"/>
|
||||
<field eval="0" name="perm_write"/>
|
||||
<field eval="0" name="perm_create"/>
|
||||
</record>
|
||||
<record id="printing_report_xml_action_group_user" model="ir.model.access">
|
||||
<field name="name">Printing Report Xml Action User</field>
|
||||
<field name="model_id" ref="model_printing_report_xml_action"/>
|
||||
<field name="group_id" ref="printing_group_user"/>
|
||||
<field eval="1" name="perm_read"/>
|
||||
<field eval="0" name="perm_unlink"/>
|
||||
<field eval="0" name="perm_write"/>
|
||||
<field eval="0" name="perm_create"/>
|
||||
</record>
|
||||
</data>
|
||||
</data>
|
||||
<data>
|
||||
<record id="printing_server_group_user" model="ir.model.access">
|
||||
<field name="name">Printing Server User</field>
|
||||
<field name="model_id" ref="model_printing_server"/>
|
||||
<field name="group_id" ref="printing_group_user"/>
|
||||
<field eval="1" name="perm_read"/>
|
||||
<field eval="0" name="perm_unlink"/>
|
||||
<field eval="0" name="perm_write"/>
|
||||
<field eval="0" name="perm_create"/>
|
||||
</record>
|
||||
<record id="printing_printer_group_user" model="ir.model.access">
|
||||
<field name="name">Printing Printer User</field>
|
||||
<field name="model_id" ref="model_printing_printer"/>
|
||||
<field name="group_id" ref="printing_group_user"/>
|
||||
<field eval="1" name="perm_read"/>
|
||||
<field eval="0" name="perm_unlink"/>
|
||||
<field eval="0" name="perm_write"/>
|
||||
<field eval="0" name="perm_create"/>
|
||||
</record>
|
||||
<record id="printing_job_group_user" model="ir.model.access">
|
||||
<field name="name">Printing Job User</field>
|
||||
<field name="model_id" ref="model_printing_job"/>
|
||||
<field name="group_id" ref="printing_group_user"/>
|
||||
<field eval="1" name="perm_read"/>
|
||||
<field eval="0" name="perm_unlink"/>
|
||||
<field eval="0" name="perm_write"/>
|
||||
<field eval="0" name="perm_create"/>
|
||||
</record>
|
||||
<record id="printing_action_group_user" model="ir.model.access">
|
||||
<field name="name">Printing Action User</field>
|
||||
<field name="model_id" ref="model_printing_action"/>
|
||||
<field name="group_id" ref="printing_group_user"/>
|
||||
<field eval="1" name="perm_read"/>
|
||||
<field eval="0" name="perm_unlink"/>
|
||||
<field eval="0" name="perm_write"/>
|
||||
<field eval="0" name="perm_create"/>
|
||||
</record>
|
||||
<record id="printing_report_xml_action_group_user" model="ir.model.access">
|
||||
<field name="name">Printing Report Xml Action User</field>
|
||||
<field name="model_id" ref="model_printing_report_xml_action"/>
|
||||
<field name="group_id" ref="printing_group_user"/>
|
||||
<field eval="1" name="perm_read"/>
|
||||
<field eval="0" name="perm_unlink"/>
|
||||
<field eval="0" name="perm_write"/>
|
||||
<field eval="0" name="perm_create"/>
|
||||
</record>
|
||||
<!--Ported from printing_tray -->
|
||||
<record id="access_printing_tray_all" model="ir.model.access">
|
||||
<field name="name">Printing Tray User</field>
|
||||
<field name="model_id" ref="model_printing_tray"/>
|
||||
<field name="group_id" ref="printing_group_user"/>
|
||||
<field eval="1" name="perm_read"/>
|
||||
<field eval="0" name="perm_unlink"/>
|
||||
<field eval="0" name="perm_write"/>
|
||||
<field eval="0" name="perm_create"/>
|
||||
</record>
|
||||
<record id="access_printing_tray_operator" model="ir.model.access">
|
||||
<field name="name">Printing Tray User</field>
|
||||
<field name="model_id" ref="model_printing_tray"/>
|
||||
<field name="group_id" ref="printing_group_manager"/>
|
||||
<field eval="1" name="perm_read"/>
|
||||
<field eval="1" name="perm_unlink"/>
|
||||
<field eval="1" name="perm_write"/>
|
||||
<field eval="1" name="perm_create"/>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
|
||||
@@ -4,7 +4,9 @@
|
||||
|
||||
from . import test_printing_job
|
||||
from . import test_printing_printer
|
||||
from . import test_printing_printer_tray
|
||||
from . import test_printing_server
|
||||
from . import test_printing_tray
|
||||
from . import test_report
|
||||
from . import test_res_users
|
||||
from . import test_ir_actions_report
|
||||
|
||||
@@ -204,3 +204,34 @@ class TestIrActionsReportXml(TransactionCase):
|
||||
'printer': report.printing_printer_id,
|
||||
},
|
||||
})
|
||||
|
||||
def test_onchange_printer_tray_id_empty(self):
|
||||
action = self.env['ir.actions.report'].new(
|
||||
{'printer_tray_id': False})
|
||||
action.onchange_printing_printer_id()
|
||||
self.assertFalse(action.printer_tray_id)
|
||||
|
||||
def test_onchange_printer_tray_id_not_empty(self):
|
||||
server = self.env['printing.server'].create({})
|
||||
printer = self.env['printing.printer'].create({
|
||||
'name': 'Printer',
|
||||
'server_id': server.id,
|
||||
'system_name': 'Sys Name',
|
||||
'default': True,
|
||||
'status': 'unknown',
|
||||
'status_message': 'Msg',
|
||||
'model': 'res.users',
|
||||
'location': 'Location',
|
||||
'uri': 'URI',
|
||||
})
|
||||
tray = self.env['printing.tray'].create({
|
||||
'name': 'Tray',
|
||||
'system_name': 'TrayName',
|
||||
'printer_id': printer.id,
|
||||
})
|
||||
|
||||
action = self.env['ir.actions.report'].new(
|
||||
{'printer_tray_id': tray.id})
|
||||
self.assertEqual(action.printer_tray_id, tray)
|
||||
action.onchange_printing_printer_id()
|
||||
self.assertFalse(action.printer_tray_id)
|
||||
|
||||
330
base_report_to_printer/tests/test_printing_printer_tray.py
Normal file
330
base_report_to_printer/tests/test_printing_printer_tray.py
Normal file
@@ -0,0 +1,330 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2016 LasLabs Inc.
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
import errno
|
||||
import mock
|
||||
import tempfile
|
||||
from odoo.tests.common import TransactionCase
|
||||
|
||||
|
||||
model = 'odoo.addons.base_report_to_printer.models.printing_printer'
|
||||
server_model = 'odoo.addons.base_report_to_printer.models.printing_server'
|
||||
|
||||
ppd_header = '*PPD-Adobe: "4.3"'
|
||||
ppd_input_slot_header = """
|
||||
*OpenUI *InputSlot: PickOne
|
||||
*DefaultInputSlot: Auto
|
||||
*InputSlot Auto/Auto (Default): "
|
||||
<< /DeferredMediaSelection true /ManualFeed false
|
||||
/MediaPosition null /MediaType null >> setpagedevice
|
||||
userdict /TSBMediaType 0 put"
|
||||
*End
|
||||
"""
|
||||
ppd_input_slot_body = """
|
||||
*InputSlot {name}/{text}: "
|
||||
<< /DeferredMediaSelection true /ManualFeed false
|
||||
/MediaPosition null /MediaType null >> setpagedevice
|
||||
userdict /TSBMediaType 0 put"
|
||||
*End
|
||||
"""
|
||||
ppd_input_slot_footer = """
|
||||
*CloseUI: *InputSlot
|
||||
"""
|
||||
|
||||
|
||||
class TestPrintingPrinter(TransactionCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestPrintingPrinter, self).setUp()
|
||||
self.Model = self.env['printing.printer']
|
||||
self.ServerModel = self.env['printing.server']
|
||||
self.server = self.env['printing.server'].create({})
|
||||
self.printer = self.env['printing.printer'].create({
|
||||
'name': 'Printer',
|
||||
'server_id': self.server.id,
|
||||
'system_name': 'Sys Name',
|
||||
'default': True,
|
||||
'status': 'unknown',
|
||||
'status_message': 'Msg',
|
||||
'model': 'res.users',
|
||||
'location': 'Location',
|
||||
'uri': 'URI',
|
||||
})
|
||||
self.tray_vals = {
|
||||
'name': 'Tray',
|
||||
'system_name': 'TrayName',
|
||||
'printer_id': self.printer.id,
|
||||
}
|
||||
|
||||
def new_tray(self, vals=None):
|
||||
values = self.tray_vals
|
||||
if vals is not None:
|
||||
values.update(vals)
|
||||
return self.env['printing.tray'].create(values)
|
||||
|
||||
def build_ppd(self, input_slots=None):
|
||||
"""
|
||||
Builds a fake PPD file declaring defined input slots
|
||||
"""
|
||||
ppd_contents = ppd_header
|
||||
ppd_contents += ppd_input_slot_header
|
||||
if input_slots is not None:
|
||||
for input_slot in input_slots:
|
||||
ppd_contents += ppd_input_slot_body.format(
|
||||
name=input_slot['name'],
|
||||
text=input_slot['text'],
|
||||
)
|
||||
ppd_contents += ppd_input_slot_footer
|
||||
|
||||
return ppd_contents
|
||||
|
||||
def mock_cups_ppd(self, cups, file_name=None, input_slots=None):
|
||||
"""
|
||||
Create a fake PPD file (if needed), then mock the getPPD3 method
|
||||
return value to give that file
|
||||
"""
|
||||
if file_name is None:
|
||||
fd, file_name = tempfile.mkstemp()
|
||||
|
||||
if file_name:
|
||||
ppd_contents = self.build_ppd(input_slots=input_slots)
|
||||
with open(file_name, 'w') as fp:
|
||||
fp.write(ppd_contents)
|
||||
|
||||
cups.Connection().getPPD3.return_value = (200, 0, file_name)
|
||||
cups.Connection().getPrinters.return_value = {
|
||||
self.printer.system_name: {
|
||||
'printer-info': 'info',
|
||||
'printer-uri-supported': 'uri',
|
||||
},
|
||||
}
|
||||
|
||||
def test_print_options(self):
|
||||
"""
|
||||
It should generate the right options dictionnary
|
||||
"""
|
||||
report = self.env['ir.actions.report'].search([], limit=1)
|
||||
action = self.env['printing.report.xml.action'].create({
|
||||
'user_id': self.env.user.id,
|
||||
'report_id': report.id,
|
||||
'action': 'server',
|
||||
})
|
||||
user_tray = self.new_tray({
|
||||
'system_name': 'User tray',
|
||||
})
|
||||
report_tray = self.new_tray({
|
||||
'system_name': 'Report tray',
|
||||
})
|
||||
action_tray = self.new_tray({
|
||||
'system_name': 'Action tray',
|
||||
})
|
||||
|
||||
# No report passed
|
||||
self.env.user.printer_tray_id = False
|
||||
options = self.Model.print_options()
|
||||
self.assertFalse('InputSlot' in options)
|
||||
|
||||
# No tray defined
|
||||
self.env.user.printer_tray_id = False
|
||||
report.printer_tray_id = False
|
||||
action.printer_tray_id = False
|
||||
options = self.Model.print_options(report, 'pdf')
|
||||
self.assertFalse('InputSlot' in options)
|
||||
|
||||
# Only user tray is defined
|
||||
self.env.user.printer_tray_id = user_tray
|
||||
report.printer_tray_id = False
|
||||
action.printer_tray_id = False
|
||||
options = self.Model.print_options(report, 'pdf')
|
||||
self.assertEquals(options, {
|
||||
'InputSlot': 'User tray',
|
||||
})
|
||||
|
||||
# Only report tray is defined
|
||||
self.env.user.printer_tray_id = False
|
||||
report.printer_tray_id = report_tray
|
||||
action.printer_tray_id = False
|
||||
options = self.Model.print_options(report, 'pdf')
|
||||
self.assertEquals(options, {
|
||||
'InputSlot': 'Report tray',
|
||||
})
|
||||
|
||||
# Only action tray is defined
|
||||
self.env.user.printer_tray_id = False
|
||||
report.printer_tray_id = False
|
||||
action.printer_tray_id = action_tray
|
||||
options = self.Model.print_options(report, 'pdf')
|
||||
self.assertEquals(options, {
|
||||
'InputSlot': 'Action tray',
|
||||
})
|
||||
|
||||
# All trays are defined
|
||||
self.env.user.printer_tray_id = user_tray
|
||||
report.printer_tray_id = report_tray
|
||||
action.printer_tray_id = action_tray
|
||||
options = self.Model.print_options(report, 'pdf')
|
||||
self.assertEquals(options, {
|
||||
'InputSlot': 'Action tray',
|
||||
})
|
||||
|
||||
@mock.patch('%s.cups' % server_model)
|
||||
def test_update_printers(self, cups):
|
||||
"""
|
||||
Check that the update_printers method calls _prepare_update_from_cups
|
||||
"""
|
||||
self.mock_cups_ppd(cups, file_name=False)
|
||||
|
||||
self.assertEqual(self.printer.name, 'Printer')
|
||||
self.ServerModel.update_printers()
|
||||
self.assertEqual(self.printer.name, 'info')
|
||||
|
||||
@mock.patch('%s.cups' % server_model)
|
||||
def test_prepare_update_from_cups_no_ppd(self, cups):
|
||||
"""
|
||||
Check that the tray_ids field has no value when no PPD is available
|
||||
"""
|
||||
self.mock_cups_ppd(cups, file_name=False)
|
||||
|
||||
connection = cups.Connection()
|
||||
cups_printer = connection.getPrinters()[self.printer.system_name]
|
||||
|
||||
vals = self.printer._prepare_update_from_cups(connection, cups_printer)
|
||||
self.assertFalse('tray_ids' in vals)
|
||||
|
||||
@mock.patch('%s.cups' % server_model)
|
||||
def test_prepare_update_from_cups_empty_ppd(self, cups):
|
||||
"""
|
||||
Check that the tray_ids field has no value when the PPD file has
|
||||
no input slot declared
|
||||
"""
|
||||
fd, file_name = tempfile.mkstemp()
|
||||
self.mock_cups_ppd(cups, file_name=file_name)
|
||||
# Replace the ppd file's contents by an empty file
|
||||
with open(file_name, 'w') as fp:
|
||||
fp.write(ppd_header)
|
||||
|
||||
connection = cups.Connection()
|
||||
cups_printer = connection.getPrinters()[self.printer.system_name]
|
||||
|
||||
vals = self.printer._prepare_update_from_cups(connection, cups_printer)
|
||||
self.assertFalse('tray_ids' in vals)
|
||||
|
||||
@mock.patch('%s.cups' % server_model)
|
||||
@mock.patch('os.unlink')
|
||||
def test_prepare_update_from_cups_unlink_error(self, os_unlink, cups):
|
||||
"""
|
||||
When OSError other than ENOENT is encountered, the exception is raised
|
||||
"""
|
||||
# Break os.unlink
|
||||
os_unlink.side_effect = OSError(errno.EIO, 'Error')
|
||||
|
||||
self.mock_cups_ppd(cups)
|
||||
|
||||
connection = cups.Connection()
|
||||
cups_printer = connection.getPrinters()[self.printer.system_name]
|
||||
|
||||
with self.assertRaises(OSError):
|
||||
self.printer._prepare_update_from_cups(connection, cups_printer)
|
||||
|
||||
@mock.patch('%s.cups' % server_model)
|
||||
@mock.patch('os.unlink')
|
||||
def test_prepare_update_from_cups_unlink_error_enoent(
|
||||
self, os_unlink, cups):
|
||||
"""
|
||||
When a ENOENT error is encountered, the file has already been unlinked
|
||||
|
||||
This is not an issue, as we were trying to delete the file.
|
||||
The update can continue.
|
||||
"""
|
||||
# Break os.unlink
|
||||
os_unlink.side_effect = OSError(errno.ENOENT, 'Error')
|
||||
|
||||
self.mock_cups_ppd(cups)
|
||||
|
||||
connection = cups.Connection()
|
||||
cups_printer = connection.getPrinters()[self.printer.system_name]
|
||||
|
||||
vals = self.printer._prepare_update_from_cups(connection, cups_printer)
|
||||
self.assertEqual(vals['tray_ids'], [(0, 0, {
|
||||
'name': 'Auto (Default)',
|
||||
'system_name': 'Auto',
|
||||
})])
|
||||
|
||||
@mock.patch('%s.cups' % server_model)
|
||||
def test_prepare_update_from_cups(self, cups):
|
||||
"""
|
||||
Check the return value when adding a single tray
|
||||
"""
|
||||
self.mock_cups_ppd(cups)
|
||||
|
||||
connection = cups.Connection()
|
||||
cups_printer = connection.getPrinters()[self.printer.system_name]
|
||||
|
||||
vals = self.printer._prepare_update_from_cups(connection, cups_printer)
|
||||
self.assertEqual(vals['tray_ids'], [(0, 0, {
|
||||
'name': 'Auto (Default)',
|
||||
'system_name': 'Auto',
|
||||
})])
|
||||
|
||||
@mock.patch('%s.cups' % server_model)
|
||||
def test_prepare_update_from_cups_with_multiple_trays(self, cups):
|
||||
"""
|
||||
Check the return value when adding multiple trays at once
|
||||
"""
|
||||
self.mock_cups_ppd(cups, input_slots=[
|
||||
{'name': 'Tray1', 'text': 'Tray 1'},
|
||||
])
|
||||
|
||||
connection = cups.Connection()
|
||||
cups_printer = connection.getPrinters()[self.printer.system_name]
|
||||
|
||||
vals = self.printer._prepare_update_from_cups(connection, cups_printer)
|
||||
self.assertItemsEqual(vals['tray_ids'], [(0, 0, {
|
||||
'name': 'Auto (Default)',
|
||||
'system_name': 'Auto',
|
||||
}), (0, 0, {
|
||||
'name': 'Tray 1',
|
||||
'system_name': 'Tray1',
|
||||
})])
|
||||
|
||||
@mock.patch('%s.cups' % server_model)
|
||||
def test_prepare_update_from_cups_already_known_trays(self, cups):
|
||||
"""
|
||||
Check that calling the method twice doesn't create the trays multiple
|
||||
times
|
||||
"""
|
||||
self.mock_cups_ppd(cups, input_slots=[
|
||||
{'name': 'Tray1', 'text': 'Tray 1'},
|
||||
])
|
||||
|
||||
connection = cups.Connection()
|
||||
cups_printer = connection.getPrinters()[self.printer.system_name]
|
||||
|
||||
# Create a tray which is in the PPD file
|
||||
self.new_tray({'system_name': 'Tray1'})
|
||||
|
||||
vals = self.printer._prepare_update_from_cups(connection, cups_printer)
|
||||
self.assertEqual(vals['tray_ids'], [(0, 0, {
|
||||
'name': 'Auto (Default)',
|
||||
'system_name': 'Auto',
|
||||
})])
|
||||
|
||||
@mock.patch('%s.cups' % server_model)
|
||||
def test_prepare_update_from_cups_unknown_trays(self, cups):
|
||||
"""
|
||||
Check that trays which are not in the PPD file are removed from Odoo
|
||||
"""
|
||||
self.mock_cups_ppd(cups)
|
||||
|
||||
connection = cups.Connection()
|
||||
cups_printer = connection.getPrinters()[self.printer.system_name]
|
||||
|
||||
# Create a tray which is absent from the PPD file
|
||||
tray = self.new_tray()
|
||||
|
||||
vals = self.printer._prepare_update_from_cups(connection, cups_printer)
|
||||
self.assertEqual(vals['tray_ids'], [(0, 0, {
|
||||
'name': 'Auto (Default)',
|
||||
'system_name': 'Auto',
|
||||
}), (2, tray.id)])
|
||||
@@ -56,3 +56,34 @@ class TestPrintingReportXmlAction(TransactionCase):
|
||||
})
|
||||
|
||||
self.assertEqual(self.Model.behaviour(), {})
|
||||
|
||||
def test_onchange_printer_tray_id_empty(self):
|
||||
action = self.env['printing.report.xml.action'].new(
|
||||
{'printer_tray_id': False})
|
||||
action.onchange_printer_id()
|
||||
self.assertFalse(action.printer_tray_id)
|
||||
|
||||
def test_onchange_printer_tray_id_not_empty(self):
|
||||
server = self.env['printing.server'].create({})
|
||||
printer = self.env['printing.printer'].create({
|
||||
'name': 'Printer',
|
||||
'server_id': server.id,
|
||||
'system_name': 'Sys Name',
|
||||
'default': True,
|
||||
'status': 'unknown',
|
||||
'status_message': 'Msg',
|
||||
'model': 'res.users',
|
||||
'location': 'Location',
|
||||
'uri': 'URI',
|
||||
})
|
||||
tray = self.env['printing.tray'].create({
|
||||
'name': 'Tray',
|
||||
'system_name': 'TrayName',
|
||||
'printer_id': printer.id,
|
||||
})
|
||||
|
||||
action = self.env['printing.report.xml.action'].new(
|
||||
{'printer_tray_id': tray.id})
|
||||
self.assertEqual(action.printer_tray_id, tray)
|
||||
action.onchange_printer_id()
|
||||
self.assertFalse(action.printer_tray_id)
|
||||
|
||||
52
base_report_to_printer/tests/test_printing_tray.py
Normal file
52
base_report_to_printer/tests/test_printing_tray.py
Normal file
@@ -0,0 +1,52 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2016 LasLabs Inc.
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from odoo.tests.common import TransactionCase
|
||||
|
||||
|
||||
model = 'odoo.addons.base_report_to_printer.models.printing_server'
|
||||
|
||||
|
||||
class TestPrintingTray(TransactionCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestPrintingTray, self).setUp()
|
||||
self.Model = self.env['printing.tray']
|
||||
self.server = self.env['printing.server'].create({})
|
||||
self.printer = self.env['printing.printer'].create({
|
||||
'name': 'Printer',
|
||||
'server_id': self.server.id,
|
||||
'system_name': 'Sys Name',
|
||||
'default': True,
|
||||
'status': 'unknown',
|
||||
'status_message': 'Msg',
|
||||
'model': 'res.users',
|
||||
'location': 'Location',
|
||||
'uri': 'URI',
|
||||
})
|
||||
self.tray_vals = {
|
||||
'name': 'Tray',
|
||||
'system_name': 'TrayName',
|
||||
'printer_id': self.printer.id,
|
||||
}
|
||||
|
||||
def new_tray(self):
|
||||
return self.env['printing.tray'].create(self.tray_vals)
|
||||
|
||||
def test_report_behaviour(self):
|
||||
""" It should add the selected tray in the report data """
|
||||
ir_report = self.env['ir.actions.report'].search([], limit=1)
|
||||
report = self.env['printing.report.xml.action'].create({
|
||||
'user_id': self.env.user.id,
|
||||
'report_id': ir_report.id,
|
||||
'action': 'server',
|
||||
})
|
||||
report.printer_tray_id = False
|
||||
behaviour = report.behaviour()
|
||||
self.assertEqual(behaviour['tray'], False)
|
||||
|
||||
# Check that we have te right value
|
||||
report.printer_tray_id = self.new_tray()
|
||||
behaviour = report.behaviour()
|
||||
self.assertEqual(behaviour['tray'], report.printer_tray_id.system_name)
|
||||
@@ -26,3 +26,34 @@ class TestResUsers(TransactionCase):
|
||||
""" It should still contain other valid keys """
|
||||
self.user_vals['printing_action'] = 'server'
|
||||
self.assertTrue(self.new_record())
|
||||
|
||||
def test_onchange_printer_tray_id_empty(self):
|
||||
user = self.env['res.users'].new(
|
||||
{'printer_tray_id': False})
|
||||
user.onchange_printing_printer_id()
|
||||
self.assertFalse(user.printer_tray_id)
|
||||
|
||||
def test_onchange_printer_tray_id_not_empty(self):
|
||||
server = self.env['printing.server'].create({})
|
||||
printer = self.env['printing.printer'].create({
|
||||
'name': 'Printer',
|
||||
'server_id': server.id,
|
||||
'system_name': 'Sys Name',
|
||||
'default': True,
|
||||
'status': 'unknown',
|
||||
'status_message': 'Msg',
|
||||
'model': 'res.users',
|
||||
'location': 'Location',
|
||||
'uri': 'URI',
|
||||
})
|
||||
tray = self.env['printing.tray'].create({
|
||||
'name': 'Tray',
|
||||
'system_name': 'TrayName',
|
||||
'printer_id': printer.id,
|
||||
})
|
||||
|
||||
user = self.env['res.users'].new(
|
||||
{'printer_tray_id': tray.id})
|
||||
self.assertEqual(user.printer_tray_id, tray)
|
||||
user.onchange_printing_printer_id()
|
||||
self.assertFalse(user.printer_tray_id)
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
<group>
|
||||
<field name="property_printing_action_id"/>
|
||||
<field name="printing_printer_id"/>
|
||||
<field name="printer_tray_id"/>
|
||||
</group>
|
||||
|
||||
<separator string="Specific actions per user"/>
|
||||
|
||||
@@ -23,22 +23,32 @@
|
||||
<field name="name"/>
|
||||
</h1>
|
||||
</div>
|
||||
<group>
|
||||
<group name="name">
|
||||
<field name="system_name"/>
|
||||
</group>
|
||||
<group col="4" colspan="4">
|
||||
<group col="4" colspan="4" name="default">
|
||||
<field name="default"/>
|
||||
<button name="set_default" string="Set Default" type="object" attrs="{'invisible': [('default','=', True)]}"/>
|
||||
<button name="unset_default" string="Unset Default" type="object" attrs="{'invisible': [('default','=', False)]}"/>
|
||||
</group>
|
||||
<group>
|
||||
<group name="details">
|
||||
<field name="uri"/>
|
||||
<field name="model"/>
|
||||
<field name="location"/>
|
||||
<field name="status"/>
|
||||
<field name="status_message"/>
|
||||
</group>
|
||||
<group>
|
||||
<group string="Trays" name="trays">
|
||||
<field name="tray_ids" nolabel="1">
|
||||
<form>
|
||||
<group name="name_fields">
|
||||
<field name="name"/>
|
||||
<field name="system_name"/>
|
||||
</group>
|
||||
</form>
|
||||
</field>
|
||||
</group>
|
||||
<group name="jobs">
|
||||
<separator string="Jobs" colspan="2"/>
|
||||
<field name="job_ids" nolabel="1"/>
|
||||
</group>
|
||||
|
||||
@@ -1,35 +1,38 @@
|
||||
<?xml version="1.0"?>
|
||||
<odoo>
|
||||
|
||||
<record model="ir.ui.view" id="printing_report_xml_action_view_form">
|
||||
<field name="name">printing.report.xml.action.form</field>
|
||||
<field name="model">printing.report.xml.action</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Report Printing Actions">
|
||||
<group col="2">
|
||||
<field name="user_id" options="{'no_create': True}"/>
|
||||
<field name="action"/>
|
||||
<field name="printer_id" options="{'no_create': True}"/>
|
||||
</group>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
<record model="ir.ui.view" id="printing_report_xml_action_view_tree">
|
||||
<field name="name">printing.report.xml.action.tree</field>
|
||||
<field name="model">printing.report.xml.action</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Report Printing Actions" editable="bottom">
|
||||
<field name="user_id" options="{'no_create': True}"/>
|
||||
<field name="action" />
|
||||
<field name="printer_id" options="{'no_create': True}"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
<record model="ir.ui.view" id="printing_report_xml_action_view_form">
|
||||
<field name="name">printing.report.xml.action.form</field>
|
||||
<field name="model">printing.report.xml.action</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Report Printing Actions">
|
||||
<group col="2">
|
||||
<field name="user_id"/>
|
||||
<field name="action"/>
|
||||
<field name="printer_id" select="1"/>
|
||||
<field name="printer_tray_id"/>
|
||||
</group>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Add a shorcut to "Actions/Report" in the Printing menu -->
|
||||
<menuitem id="printing_report_xml_action_menu"
|
||||
sequence="30"
|
||||
parent="printing_menu"
|
||||
action="base.ir_action_report"/>
|
||||
<record model="ir.ui.view" id="printing_report_xml_action_view_tree">
|
||||
<field name="name">printing.report.xml.action.tree</field>
|
||||
<field name="model">printing.report.xml.action</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Report Printing Actions">
|
||||
<field name="user_id"/>
|
||||
<field name="action"/>
|
||||
<field name="printer_id"/>
|
||||
<field name="printer_tray_id"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Add a shorcut to "Actions/Report" in the Printing menu -->
|
||||
<menuitem id="printing_report_xml_action_menu"
|
||||
sequence="30"
|
||||
parent="printing_menu"
|
||||
action="base.ir_action_report"/>
|
||||
|
||||
</odoo>
|
||||
|
||||
Reference in New Issue
Block a user