product_print_zpl_barcode: remove dependency on base_report_to_printer
We now print directly on the ZPL printer, without going through CUPS
This commit is contained in:
@@ -39,12 +39,12 @@ This module has been written by Alexis de Lattre from Akretion
|
|||||||
'depends': [
|
'depends': [
|
||||||
'point_of_sale',
|
'point_of_sale',
|
||||||
'barcodes',
|
'barcodes',
|
||||||
'base_report_to_printer',
|
|
||||||
],
|
],
|
||||||
'external_dependencies': {'python': ['python-barcode>=0.14.0']},
|
'external_dependencies': {'python': ['python-barcode>=0.14.0']},
|
||||||
'data': [
|
'data': [
|
||||||
'security/ir.model.access.csv',
|
'security/ir.model.access.csv',
|
||||||
'wizard/product_print_zpl_barcode_view.xml',
|
'wizard/product_print_zpl_barcode_view.xml',
|
||||||
|
'wizard/res_config_settings_view.xml',
|
||||||
'views/product.xml',
|
'views/product.xml',
|
||||||
'views/stock_picking.xml',
|
'views/stock_picking.xml',
|
||||||
'data/barcode_sequence.xml',
|
'data/barcode_sequence.xml',
|
||||||
|
|||||||
@@ -1 +1,2 @@
|
|||||||
from . import product_print_zpl_barcode
|
from . import product_print_zpl_barcode
|
||||||
|
from . import res_config_settings
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ from odoo.tools import float_compare, float_is_zero
|
|||||||
from stdnum.ean import is_valid, calc_check_digit
|
from stdnum.ean import is_valid, calc_check_digit
|
||||||
import base64
|
import base64
|
||||||
import re
|
import re
|
||||||
|
import socket
|
||||||
|
import ipaddress
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@@ -36,7 +38,8 @@ class ProductPrintZplBarcode(models.TransientModel):
|
|||||||
raise UserError(_(
|
raise UserError(_(
|
||||||
"There are no pricelist in company '%s'.") % company.name)
|
"There are no pricelist in company '%s'.") % company.name)
|
||||||
|
|
||||||
printer = self.env['printing.printer'].get_default()
|
printer_ip = self.env['ir.config_parameter'].sudo().get_param(
|
||||||
|
'product_print_zpl_barcode.printer_ip')
|
||||||
|
|
||||||
line_ids = []
|
line_ids = []
|
||||||
if self._context.get('active_model') == 'product.product':
|
if self._context.get('active_model') == 'product.product':
|
||||||
@@ -71,7 +74,7 @@ class ProductPrintZplBarcode(models.TransientModel):
|
|||||||
'company_id': company.id,
|
'company_id': company.id,
|
||||||
'nomenclature_id': nomenclature.id,
|
'nomenclature_id': nomenclature.id,
|
||||||
'pricelist_id': pricelist.id,
|
'pricelist_id': pricelist.id,
|
||||||
'zpl_printer_id': printer and printer.id or False,
|
'zpl_printer_ip': printer_ip,
|
||||||
'line_ids': line_ids,
|
'line_ids': line_ids,
|
||||||
})
|
})
|
||||||
return res
|
return res
|
||||||
@@ -108,8 +111,7 @@ class ProductPrintZplBarcode(models.TransientModel):
|
|||||||
], default='step1', readonly=True)
|
], default='step1', readonly=True)
|
||||||
zpl_file = fields.Binary(string='ZPL File', readonly=True)
|
zpl_file = fields.Binary(string='ZPL File', readonly=True)
|
||||||
zpl_filename = fields.Char('ZPL Filename')
|
zpl_filename = fields.Char('ZPL Filename')
|
||||||
zpl_printer_id = fields.Many2one(
|
zpl_printer_ip = fields.Char(string='ZPL Printer IP Address')
|
||||||
'printing.printer', string='ZPL Printer')
|
|
||||||
line_ids = fields.One2many(
|
line_ids = fields.One2many(
|
||||||
'product.print.zpl.barcode.line', 'parent_id',
|
'product.print.zpl.barcode.line', 'parent_id',
|
||||||
string='Lines', states={'step2': [('readonly', True)]})
|
string='Lines', states={'step2': [('readonly', True)]})
|
||||||
@@ -168,11 +170,27 @@ class ProductPrintZplBarcode(models.TransientModel):
|
|||||||
return action
|
return action
|
||||||
|
|
||||||
def print_zpl(self):
|
def print_zpl(self):
|
||||||
if not self.zpl_printer_id:
|
if not self.zpl_printer_ip:
|
||||||
raise UserError(_(
|
raise UserError(_(
|
||||||
"You must select a ZPL Printer."))
|
"You must configure the IP address of the ZPL Printer."))
|
||||||
self.zpl_printer_id.print_document(
|
try:
|
||||||
self.zpl_filename, base64.decodebytes(self.zpl_file), format='raw')
|
ip = ipaddress.ip_address(self.zpl_printer_ip)
|
||||||
|
except Exception as e:
|
||||||
|
raise UserError(str(e))
|
||||||
|
version = ip.version
|
||||||
|
# TODO works with DNS ?
|
||||||
|
if version == 6: # IPv6
|
||||||
|
socket_inet = socket.AF_INET6
|
||||||
|
else: # IPv4
|
||||||
|
socket_inet = socket.AF_INET
|
||||||
|
with socket.socket(socket_inet, socket.SOCK_STREAM) as s:
|
||||||
|
try:
|
||||||
|
s.connect((str(ip), 9100))
|
||||||
|
except Exception as e:
|
||||||
|
raise UserError(str(e))
|
||||||
|
zpl_file_bytes = base64.decodebytes(self.zpl_file)
|
||||||
|
s.send(zpl_file_bytes)
|
||||||
|
s.close()
|
||||||
|
|
||||||
|
|
||||||
class ProductPrintZplBarcodeLine(models.TransientModel):
|
class ProductPrintZplBarcodeLine(models.TransientModel):
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
<group name="step2" states="step2">
|
<group name="step2" states="step2">
|
||||||
<field name="zpl_file" filename="zpl_filename" />
|
<field name="zpl_file" filename="zpl_filename" />
|
||||||
<field name="zpl_filename" invisible="1"/>
|
<field name="zpl_filename" invisible="1"/>
|
||||||
<field name="zpl_printer_id" attrs="{'required': [('state', '=', 'step2')]}"/>
|
<field name="zpl_printer_ip" attrs="{'required': [('state', '=', 'step2')]}"/>
|
||||||
</group>
|
</group>
|
||||||
<group name="lines">
|
<group name="lines">
|
||||||
<field name="line_ids" colspan="2" nolabel="1">
|
<field name="line_ids" colspan="2" nolabel="1">
|
||||||
|
|||||||
24
product_print_zpl_barcode/wizard/res_config_settings.py
Normal file
24
product_print_zpl_barcode/wizard/res_config_settings.py
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
# Copyright 2023 Akretion France (http://www.akretion.com/)
|
||||||
|
# @author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||||
|
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
|
||||||
|
|
||||||
|
from odoo import api, fields, models
|
||||||
|
from odoo.exceptions import ValidationError
|
||||||
|
import ipaddress
|
||||||
|
|
||||||
|
|
||||||
|
class ResConfigSettings(models.TransientModel):
|
||||||
|
_inherit = "res.config.settings"
|
||||||
|
|
||||||
|
zpl_printer_ip = fields.Char(
|
||||||
|
config_parameter="product_print_zpl_barcode.printer_ip",
|
||||||
|
string="ZPL Printer IP Address")
|
||||||
|
|
||||||
|
@api.constrains('zpl_printer_ip')
|
||||||
|
def _check_zpl_printer_ip(self):
|
||||||
|
for wiz in self:
|
||||||
|
if wiz.zpl_printer_ip:
|
||||||
|
try:
|
||||||
|
ipaddress.ip_address(wiz.zpl_printer_ip)
|
||||||
|
except Exception as e:
|
||||||
|
raise ValidationError(str(e))
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
Copyright 2024 Akretion France (http://www.akretion.com/)
|
||||||
|
@author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||||
|
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
|
-->
|
||||||
|
|
||||||
|
<odoo>
|
||||||
|
|
||||||
|
<record id="res_config_settings_view_form" model="ir.ui.view">
|
||||||
|
<field name="model">res.config.settings</field>
|
||||||
|
<field name="inherit_id" ref="base_setup.res_config_settings_view_form" />
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<xpath expr="//div[@id='companies']" position='after'>
|
||||||
|
<h2>Barcode printing</h2>
|
||||||
|
<div class="row mt16 o_settings_container" name="zpl_printer">
|
||||||
|
<div class="col-xs-12 col-md-6 o_setting_box">
|
||||||
|
<div class="o_setting_right_pane" id="zpl_printer_ip">
|
||||||
|
<div class="row">
|
||||||
|
<label for="zpl_printer_ip" class="col-md-5" />
|
||||||
|
<field name="zpl_printer_ip" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</xpath>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
</odoo>
|
||||||
@@ -16,7 +16,7 @@ This module has been written by Alexis de Lattre from Akretion
|
|||||||
""",
|
""",
|
||||||
'author': 'Akretion',
|
'author': 'Akretion',
|
||||||
'website': 'http://www.akretion.com',
|
'website': 'http://www.akretion.com',
|
||||||
'depends': ['sale_stock'],
|
'depends': ['sale_stock', 'base_view_inheritance_extension'],
|
||||||
'data': ['views/sale_order.xml'],
|
'data': ['views/sale_order.xml'],
|
||||||
'installable': True,
|
'installable': True,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,11 @@
|
|||||||
<field name="partner_shipping_id" position="after">
|
<field name="partner_shipping_id" position="after">
|
||||||
<field name="route_id" options="{'no_create_edit': True}"/>
|
<field name="route_id" options="{'no_create_edit': True}"/>
|
||||||
</field>
|
</field>
|
||||||
|
<!-- propagate route_id to lines: it's important when you add an order line AFTER
|
||||||
|
order confirmation -->
|
||||||
|
<field name="order_line" position="attributes">
|
||||||
|
<attribute name="context" operation="python_dict" key="default_route_id">route_id</attribute>
|
||||||
|
</field>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user