[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:
Graeme Gellatly
2017-10-06 01:16:33 +13:00
committed by Rod Schouteden
parent 877e5cbcc9
commit 52a8e0ec2b
18 changed files with 788 additions and 136 deletions

View File

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

View File

@@ -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'],

View File

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

View File

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

View File

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

View File

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

View 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',
)

View File

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

View File

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

View File

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

View File

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

View 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)])

View File

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

View 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)

View File

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

View File

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

View File

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

View File

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