-
-
Notifications
You must be signed in to change notification settings - Fork 306
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #81 from syleam/10.0-mig-printer_zpl2
[10.0] Migrate printer_zpl2 module
- Loading branch information
Showing
15 changed files
with
1,733 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg | ||
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html | ||
:alt: License: AGPL-3 | ||
|
||
===================== | ||
ZPL II Label printing | ||
===================== | ||
|
||
This module extends the **Report to printer** (``base_report_to_printer``) | ||
module to add a ZPL II label printing feature. | ||
|
||
This module is meant to be used as a base for module development, and does not provide a GUI on its own. | ||
See below for more details. | ||
|
||
Installation | ||
============ | ||
|
||
Nothing special, just install the module. | ||
|
||
Configuration | ||
============= | ||
|
||
To configure this module, you need to: | ||
|
||
#. Go to *Settings > Printing > Labels > ZPL II* | ||
#. Create new labels | ||
|
||
It's also possible to add a label printing wizard on any model by creating a new *ir.values* record. | ||
For example, to add the printing wizard on the *product.product* model : | ||
|
||
.. code-block:: xml | ||
<record model="ir.values" id="wizard_wizard_print_product_label"> | ||
<field name="name">Print Product Label</field> | ||
<field name="key">action</field> | ||
<field name="key2">client_action_multi</field> | ||
<field name="model">product.product</field> | ||
<field name="value" eval="'ir.actions.act_window,' + str(ref('printer_zpl2.action_wizard_print_record_label_view'))"/> | ||
</record> | ||
Usage | ||
===== | ||
|
||
To print a label, you need to call use the label printing method from anywhere (other modules, server actions, etc.). | ||
|
||
.. code-block:: python | ||
# Example : Print the label of a product | ||
self.env['printing.label.zpl2'].browse(label_id).print_label( | ||
self.env['printing.printer'].browse(printer_id), | ||
self.env['product.product'].browse(product_id)) | ||
You can also use the generic label printing wizard, if added on some models. | ||
|
||
.. 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/10.0 | ||
|
||
Known issues / Roadmap | ||
====================== | ||
|
||
* Add a button to generate the ir.values for a model | ||
* Develop a "Designer" view in a separate module, to allow drawing labels with simple mouse clicks/drags | ||
|
||
Bug Tracker | ||
=========== | ||
|
||
Bugs are tracked on `GitHub Issues | ||
<https://github.com/OCA/report-print-send/issues>`_. In case of trouble, please | ||
check there if your issue has already been reported. If you spotted it first, | ||
help us smashing it by providing a detailed and welcomed feedback. | ||
|
||
Credits | ||
======= | ||
|
||
Images | ||
------ | ||
|
||
* Odoo Community Association: `Icon <https://github.com/OCA/maintainer-tools/blob/master/template/module/static/description/icon.svg>`_. | ||
|
||
Contributors | ||
------------ | ||
|
||
* Sylvain Garancher <sylvain.garancher@syleam.fr> | ||
|
||
Maintainer | ||
---------- | ||
|
||
.. image:: https://odoo-community.org/logo.png | ||
:alt: Odoo Community Association | ||
:target: https://odoo-community.org | ||
|
||
This module is maintained by the OCA. | ||
|
||
OCA, or the Odoo Community Association, is a nonprofit organization whose | ||
mission is to support the collaborative development of Odoo features and | ||
promote its widespread use. | ||
|
||
To contribute to this module, please visit https://odoo-community.org. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
# -*- coding: utf-8 -*- | ||
# Copyright (C) 2016 SYLEAM (<http://www.syleam.fr>) | ||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). | ||
|
||
from . import models | ||
from . import wizard |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
# -*- coding: utf-8 -*- | ||
# Copyright (C) 2016 SYLEAM (<http://www.syleam.fr>) | ||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). | ||
|
||
{ | ||
'name': 'Printer ZPL II', | ||
'version': '10.0.1.0.0', | ||
'category': 'Printer', | ||
'author': 'SYLEAM, Odoo Community Association (OCA)', | ||
'website': 'http://www.syleam.fr/', | ||
'license': 'AGPL-3', | ||
'external_dependencies': { | ||
'python': ['zpl2'], | ||
}, | ||
'depends': [ | ||
'base_report_to_printer', | ||
], | ||
'data': [ | ||
'security/ir.model.access.csv', | ||
'views/printing_label_zpl2.xml', | ||
'wizard/print_record_label.xml', | ||
], | ||
'installable': True, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
# -*- coding: utf-8 -*- | ||
# Copyright (C) 2016 SYLEAM (<http://www.syleam.fr>) | ||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). | ||
|
||
from . import printing_label_zpl2_component | ||
from . import printing_label_zpl2 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,188 @@ | ||
# -*- coding: utf-8 -*- | ||
# Copyright (C) 2016 SYLEAM (<http://www.syleam.fr>) | ||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). | ||
|
||
import time | ||
import datetime | ||
import logging | ||
from odoo import api, exceptions, fields, models | ||
from odoo.tools.translate import _ | ||
from odoo.tools.safe_eval import safe_eval | ||
|
||
_logger = logging.getLogger(__name__) | ||
|
||
try: | ||
import zpl2 | ||
except ImportError: | ||
_logger.debug('Cannot `import zpl2`.') | ||
|
||
|
||
class PrintingLabelZpl2(models.Model): | ||
_name = 'printing.label.zpl2' | ||
_description = 'ZPL II Label' | ||
|
||
name = fields.Char(required=True, help='Label Name.') | ||
description = fields.Char(help='Long description for this label.') | ||
model_id = fields.Many2one( | ||
comodel_name='ir.model', string='Model', required=True, | ||
help='Model used to print this label.') | ||
origin_x = fields.Integer( | ||
required=True, default=10, | ||
help='Origin point of the contents in the label, X coordinate.') | ||
origin_y = fields.Integer( | ||
required=True, default=10, | ||
help='Origin point of the contents in the label, Y coordinate.') | ||
width = fields.Integer( | ||
required=True, default=480, | ||
help='Width of the label, will be set on the printer before printing.') | ||
component_ids = fields.One2many( | ||
comodel_name='printing.label.zpl2.component', inverse_name='label_id', | ||
string='Label Components', | ||
help='Components which will be printed on the label.') | ||
|
||
@api.multi | ||
def _generate_zpl2_components_data( | ||
self, label_data, record, page_number=1, page_count=1, | ||
label_offset_x=0, label_offset_y=0, **extra): | ||
self.ensure_one() | ||
|
||
# Add all elements to print in a list of tuples : | ||
# [(component, data, offset_x, offset_y)] | ||
to_print = [] | ||
for component in self.component_ids: | ||
eval_args = extra | ||
eval_args.update({ | ||
'object': record, | ||
'page_number': str(page_number + 1), | ||
'page_count': str(page_count), | ||
'time': time, | ||
'datetime': datetime, | ||
}) | ||
data = safe_eval(component.data, eval_args) or '' | ||
|
||
# Generate a list of elements if the component is repeatable | ||
for idx in range( | ||
component.repeat_offset, | ||
component.repeat_offset + component.repeat_count): | ||
printed_data = data | ||
# Pick the right value if data is a collection | ||
if isinstance(data, (list, tuple, set, models.BaseModel)): | ||
# If we reached the end of data, quit the loop | ||
if idx >= len(data): | ||
break | ||
|
||
# Set the real data to display | ||
printed_data = data[idx] | ||
|
||
position = idx - component.repeat_offset | ||
to_print.append(( | ||
component, printed_data, | ||
label_offset_x + component.repeat_offset_x * position, | ||
label_offset_y + component.repeat_offset_y * position, | ||
)) | ||
|
||
for (component, data, offset_x, offset_y) in to_print: | ||
component_offset_x = component.origin_x + offset_x | ||
component_offset_y = component.origin_y + offset_y | ||
if component.component_type == 'text': | ||
barcode_arguments = dict([ | ||
(field_name, component[field_name]) | ||
for field_name in [ | ||
zpl2.ARG_FONT, | ||
zpl2.ARG_ORIENTATION, | ||
zpl2.ARG_HEIGHT, | ||
zpl2.ARG_WIDTH, | ||
zpl2.ARG_REVERSE_PRINT, | ||
zpl2.ARG_IN_BLOCK, | ||
zpl2.ARG_BLOCK_WIDTH, | ||
zpl2.ARG_BLOCK_LINES, | ||
zpl2.ARG_BLOCK_SPACES, | ||
zpl2.ARG_BLOCK_JUSTIFY, | ||
zpl2.ARG_BLOCK_LEFT_MARGIN, | ||
] | ||
]) | ||
label_data.font_data( | ||
component_offset_x, component_offset_y, | ||
barcode_arguments, data) | ||
elif component.component_type == 'rectangle': | ||
label_data.graphic_box( | ||
component_offset_x, component_offset_y, { | ||
zpl2.ARG_WIDTH: component.width, | ||
zpl2.ARG_HEIGHT: component.height, | ||
zpl2.ARG_THICKNESS: component.thickness, | ||
zpl2.ARG_COLOR: component.color, | ||
zpl2.ARG_ROUNDING: component.rounding, | ||
}) | ||
elif component.component_type == 'circle': | ||
label_data.graphic_circle( | ||
component_offset_x, component_offset_y, { | ||
zpl2.ARG_DIAMETER: component.width, | ||
zpl2.ARG_THICKNESS: component.thickness, | ||
zpl2.ARG_COLOR: component.color, | ||
}) | ||
elif component.component_type == 'sublabel': | ||
component_offset_x += component.sublabel_id.origin_x | ||
component_offset_y += component.sublabel_id.origin_y | ||
component.sublabel_id._generate_zpl2_components_data( | ||
label_data, data, | ||
label_offset_x=component_offset_x, | ||
label_offset_y=component_offset_y) | ||
else: | ||
barcode_arguments = dict([ | ||
(field_name, component[field_name]) | ||
for field_name in [ | ||
zpl2.ARG_ORIENTATION, | ||
zpl2.ARG_CHECK_DIGITS, | ||
zpl2.ARG_HEIGHT, | ||
zpl2.ARG_INTERPRETATION_LINE, | ||
zpl2.ARG_INTERPRETATION_LINE_ABOVE, | ||
zpl2.ARG_SECURITY_LEVEL, | ||
zpl2.ARG_COLUMNS_COUNT, | ||
zpl2.ARG_ROWS_COUNT, | ||
zpl2.ARG_TRUNCATE, | ||
zpl2.ARG_MODULE_WIDTH, | ||
zpl2.ARG_BAR_WIDTH_RATIO, | ||
] | ||
]) | ||
label_data.barcode_data( | ||
component.origin_x + offset_x, | ||
component.origin_y + offset_y, | ||
component.component_type, barcode_arguments, data) | ||
|
||
@api.multi | ||
def _generate_zpl2_data(self, record, page_count=1, **extra): | ||
self.ensure_one() | ||
label_data = zpl2.Zpl2() | ||
|
||
for page_number in range(page_count): | ||
# Initialize printer's configuration | ||
label_data.label_start() | ||
label_data.print_width(self.width) | ||
label_data.label_encoding() | ||
|
||
label_data.label_home(self.origin_x, self.origin_y) | ||
|
||
self._generate_zpl2_components_data( | ||
label_data, record, page_number=page_number, | ||
page_count=page_count) | ||
|
||
# Restore printer's configuration and end the label | ||
label_data.configuration_update(zpl2.CONF_RECALL_LAST_SAVED) | ||
label_data.label_end() | ||
|
||
return label_data.output() | ||
|
||
@api.multi | ||
def print_label(self, printer, record, page_count=1, **extra): | ||
for label in self: | ||
if record._name != label.model_id.model: | ||
raise exceptions.UserError( | ||
_('This label cannot be used on {model}').format( | ||
model=record._name)) | ||
|
||
# Send the label to printer | ||
label_contents = label._generate_zpl2_data( | ||
record, page_count=page_count, **extra) | ||
printer.print_document(None, label_contents, 'raw') | ||
|
||
return True |
Oops, something went wrong.