[ADD] pos_epson_printer: Use Receipt printer without IoT Box
Add possibility to print receipts on an ePOS compatible Epson receipt printer located in the same local network than the browser running the pos. TaskID: 2033442
This commit is contained in:
@@ -204,6 +204,7 @@ class PosConfig(models.Model):
|
||||
payment_method_ids = fields.Many2many('pos.payment.method', string='Payment Methods', default=lambda self: self._default_payment_methods())
|
||||
company_has_template = fields.Boolean(string="Company has chart of accounts", compute="_compute_company_has_template")
|
||||
current_user_id = fields.Many2one('res.users', string='Current Session Responsible', compute='_compute_current_session_user')
|
||||
other_devices = fields.Boolean(string="Other Devices", help="Connect devices to your PoS without an IoT Box.")
|
||||
|
||||
@api.depends('company_id')
|
||||
def _compute_company_has_template(self):
|
||||
|
||||
@@ -812,7 +812,7 @@ var Chrome = PosBaseWidget.extend(AbstractAction.prototype, {
|
||||
'name': 'sale_details',
|
||||
'widget': SaleDetailsButton,
|
||||
'append': '.pos-rightheader',
|
||||
'condition': function(){ return this.pos.config.use_proxy; },
|
||||
'condition': function(){ return this.pos.proxy.printer; },
|
||||
},{
|
||||
'name': 'proxy_status',
|
||||
'widget': ProxyStatusWidget,
|
||||
|
||||
@@ -109,6 +109,7 @@ exports.PosModel = Backbone.Model.extend({
|
||||
|
||||
return this.connect_to_proxy();
|
||||
}
|
||||
return Promise.resolve();
|
||||
},
|
||||
// releases ressources holds by the model at the end of life of the posmodel
|
||||
destroy: function(){
|
||||
|
||||
@@ -32,11 +32,20 @@ var PrinterMixin = {
|
||||
process_next_job();
|
||||
},
|
||||
|
||||
/**
|
||||
* Generate a jpeg image from a canvas
|
||||
* @param {DOMElement} canvas
|
||||
*/
|
||||
process_canvas: function (canvas) {
|
||||
return canvas.toDataURL('image/jpeg').replace('data:image/jpeg;base64,','');
|
||||
},
|
||||
|
||||
/**
|
||||
* Renders the html as an image to print it
|
||||
* @param {String} receipt: The receipt to be printed, in HTML
|
||||
*/
|
||||
htmlToImg: function (receipt) {;
|
||||
htmlToImg: function (receipt) {
|
||||
var self = this;
|
||||
$('.pos-receipts').html(receipt);
|
||||
$('.pos-receipt').addClass('pos-receipt-print');
|
||||
var promise = new Promise(function (resolve, reject) {
|
||||
@@ -52,7 +61,7 @@ var PrinterMixin = {
|
||||
}
|
||||
}).then(function (canvas) {
|
||||
$('.pos-receipts').empty();
|
||||
resolve(canvas.toDataURL('image/jpeg').replace('data:image/jpeg;base64,',''));
|
||||
resolve(self.process_canvas(canvas));
|
||||
});
|
||||
});
|
||||
return promise;
|
||||
|
||||
@@ -1631,7 +1631,7 @@ var ReceiptScreenWidget = ScreenWidget.extend({
|
||||
should_close_immediately: function() {
|
||||
var order = this.pos.get_order();
|
||||
var invoiced_finalized = order.is_to_invoice() ? order.finalized : true;
|
||||
return this.pos.config.iface_print_via_proxy && this.pos.config.iface_print_skip_screen && invoiced_finalized;
|
||||
return this.pos.proxy.printer && this.pos.config.iface_print_skip_screen && invoiced_finalized;
|
||||
},
|
||||
lock_screen: function(locked) {
|
||||
this._locked = locked;
|
||||
@@ -1680,7 +1680,7 @@ var ReceiptScreenWidget = ScreenWidget.extend({
|
||||
print: function() {
|
||||
var self = this;
|
||||
|
||||
if (!this.pos.config.iface_print_via_proxy) { // browser (html) printing
|
||||
if (!this.pos.proxy.printer) { // browser (html) printing
|
||||
|
||||
// The problem is that in chrome the print() is asynchronous and doesn't
|
||||
// execute until all rpc are finished. So it conflicts with the rpc used
|
||||
|
||||
@@ -143,20 +143,20 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<h2>IoT Box</h2>
|
||||
<h2>Connected Devices</h2>
|
||||
<div class="row mt16 o_settings_container" id="posbox_reference">
|
||||
<div class="col-12 col-lg-6 o_setting_box">
|
||||
<div class="o_setting_left_pane">
|
||||
<field name="is_posbox"/>
|
||||
</div>
|
||||
<div class="o_setting_right_pane">
|
||||
<label for="is_posbox" string="IoT Box"/>
|
||||
<label for="is_posbox" string="IoT Box Devices"/>
|
||||
<div class="text-muted">
|
||||
Connect devices to your PoS (ticket printer, barcode scanner, scale, etc.)
|
||||
Connect devices to your PoS through an IoT Box
|
||||
</div>
|
||||
<div class="content-group" attrs="{'invisible' : [('is_posbox', '=', False)]}">
|
||||
<div class="row mt16">
|
||||
<label string="IP Address" for="proxy_ip" class="col-lg-3 o_light_label"/>
|
||||
<label string="IoT Box IP Address" for="proxy_ip" class="col-lg-3 o_light_label"/>
|
||||
<field name="proxy_ip"/>
|
||||
</div>
|
||||
<div class="row">
|
||||
@@ -167,14 +167,14 @@
|
||||
<label string="Electronic Scale" for="iface_electronic_scale" class="col-lg-3 o_light_label"/>
|
||||
<field name="iface_electronic_scale"/>
|
||||
</div>
|
||||
<div class="row">
|
||||
<label string="Cashdrawer" for="iface_cashdrawer" class="col-lg-3 o_light_label"/>
|
||||
<field name="iface_cashdrawer"/>
|
||||
</div>
|
||||
<div class="row">
|
||||
<label string="Receipt Printer" for="iface_print_via_proxy" class="col-lg-3 o_light_label"/>
|
||||
<field name="iface_print_via_proxy"/>
|
||||
</div>
|
||||
<div class="row" attrs="{'invisible': [('iface_print_via_proxy', '=', False)]}">
|
||||
<label string="Cashdrawer" for="iface_cashdrawer" class="col-lg-3 o_light_label"/>
|
||||
<field name="iface_cashdrawer"/>
|
||||
</div>
|
||||
<div class="row">
|
||||
<label string="Customer Display" for="iface_customer_facing_display" class="col-lg-3 o_light_label"/>
|
||||
<field name="iface_customer_facing_display"/>
|
||||
@@ -183,6 +183,17 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-lg-6 o_setting_box" id="other_devices">
|
||||
<div class="o_setting_left_pane">
|
||||
<field name="other_devices"/>
|
||||
</div>
|
||||
<div class="o_setting_right_pane">
|
||||
<label for="other_devices" string="Other Devices"/>
|
||||
<div class="text-muted mb16">
|
||||
Connect devices to your PoS
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="barcode_scanner" class="col-12 col-lg-6 o_setting_box">
|
||||
<div class="o_setting_left_pane">
|
||||
</div>
|
||||
@@ -405,7 +416,7 @@
|
||||
<div class="text-muted">
|
||||
Print receipts automatically once the payment is registered
|
||||
</div>
|
||||
<div class="content-group mt16" attrs="{'invisible' : ['|', ('iface_print_auto', '=', False), ('is_posbox', '=', False)]}">
|
||||
<div class="content-group mt16" attrs="{'invisible' : ['|', ('iface_print_auto', '=', False), '&', ('is_posbox', '=', False), ('other_devices', '=', False)]}">
|
||||
<div>
|
||||
<field name="iface_print_skip_screen" class="oe_inline"/><span class="oe_inline"><b>Skip Preview Screen</b></span>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import models
|
||||
@@ -0,0 +1,22 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
|
||||
{
|
||||
'name': 'pos_epson_printer',
|
||||
'version': '1.0',
|
||||
'category': 'Point of Sale',
|
||||
'sequence': 6,
|
||||
'summary': 'Epson ePOS Printers in PoS',
|
||||
'description': """
|
||||
|
||||
Use Epson ePOS Printers without IoT Box in the Point of Sale
|
||||
""",
|
||||
'depends': ['point_of_sale'],
|
||||
'data': [
|
||||
'views/point_of_sale_assets.xml',
|
||||
'views/pos_config_views.xml',
|
||||
],
|
||||
'installable': True,
|
||||
'auto_install': True,
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import pos_config
|
||||
@@ -0,0 +1,9 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import fields, models
|
||||
|
||||
class PosConfig(models.Model):
|
||||
_inherit = 'pos.config'
|
||||
|
||||
epson_printer_ip = fields.Char(string='Epson Printer IP', help="Local IP address of an Epson receipt printer.")
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,20 @@
|
||||
odoo.define('pos_epson_printer.pos_epson_printer', function (require) {
|
||||
"use strict";
|
||||
|
||||
var models = require('point_of_sale.models');
|
||||
var PaymentScreenWidget = require('point_of_sale.screens').PaymentScreenWidget;
|
||||
var EpsonPrinter = require('pos_epson_printer.Printer');
|
||||
|
||||
var posmodel_super = models.PosModel.prototype;
|
||||
models.PosModel = models.PosModel.extend({
|
||||
after_load_server_data: function () {
|
||||
var self = this;
|
||||
return posmodel_super.after_load_server_data.apply(this, arguments).then(function () {
|
||||
if (self.config.other_devices && self.config.epson_printer_ip) {
|
||||
self.proxy.printer = new EpsonPrinter(self.config.epson_printer_ip , self);
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
});
|
||||
@@ -0,0 +1,98 @@
|
||||
|
||||
odoo.define('pos_epson_printer.Printer', function (require) {
|
||||
"use strict";
|
||||
|
||||
var core = require('web.core');
|
||||
var PrinterMixin = require('point_of_sale.Printer').PrinterMixin;
|
||||
|
||||
var _t = core._t;
|
||||
|
||||
var EpsonPrinter = core.Class.extend(PrinterMixin, {
|
||||
init: function (ip, pos) {
|
||||
PrinterMixin.init.call(this, arguments);
|
||||
this.pos = pos;
|
||||
this.ePOSDevice = new epson.ePOSDevice();
|
||||
var port = window.location.protocol === 'http:' ? '8008' : '8043';
|
||||
this.ePOSDevice.connect(ip, port, this.callback_connect.bind(this), {eposprint: true});
|
||||
},
|
||||
|
||||
callback_connect: function (resultConnect) {
|
||||
var deviceId = 'local_printer';
|
||||
var options = {'crypto' : false, 'buffer' : false};
|
||||
if ((resultConnect == 'OK') || (resultConnect == 'SSL_CONNECT_OK')) {
|
||||
this.ePOSDevice.createDevice(deviceId, this.ePOSDevice.DEVICE_TYPE_PRINTER, options, this.callback_createDevice.bind(this));
|
||||
} else {
|
||||
this.pos.gui.show_popup('error', {
|
||||
'title': _t('Connection to the printer failed'),
|
||||
'body': _t('Please check if the printer is still connected, if the configured IP address is correct and if your printer supports the ePOS protocol.'),
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
callback_createDevice: function (deviceObj, errorCode) {
|
||||
var self = this;
|
||||
if (deviceObj === null) {
|
||||
this.pos.gui.show_popup('error', {
|
||||
'title': _t('Connection to the printer failed'),
|
||||
'body': _t('Please check if the printer is still connected. Error code: ') + errorCode,
|
||||
});
|
||||
return;
|
||||
}
|
||||
this.printer = deviceObj;
|
||||
this.printer.onreceive = function(response){
|
||||
if (!response.success) {
|
||||
self.pos.gui.show_popup('error', {
|
||||
'title': _t('Epson ePOS Error'),
|
||||
'body': _t('An error happened while sending data to the printer. Error code: ') + response.code,
|
||||
});
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Create the print request for webPRNT from a canvas
|
||||
*
|
||||
* @override
|
||||
*/
|
||||
process_canvas: function (canvas) {
|
||||
if (this.printer) {
|
||||
this.printer.addTextAlign(this.printer.ALIGN_CENTER);
|
||||
this.printer.addImage(canvas.getContext('2d'), 0, 0, canvas.width, canvas.height);
|
||||
this.printer.addCut();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
open_cashbox: function () {
|
||||
if (this.printer) {
|
||||
this.printer.addPulse();
|
||||
this.printer.send();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
send_printing_job: function () {
|
||||
if (this.printer) {
|
||||
this.printer.send();
|
||||
}
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Handlers
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Not applicable to Epson ePOS
|
||||
* @override
|
||||
*/
|
||||
_onIoTActionFail: function () {},
|
||||
_onIoTActionResult: function () {},
|
||||
});
|
||||
|
||||
return EpsonPrinter;
|
||||
|
||||
});
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<template id="assets" inherit_id="point_of_sale.assets">
|
||||
<xpath expr="." position="inside">
|
||||
<script type="text/javascript" src="/pos_epson_printer/static/src/js/pos_epson_printer.js"></script>
|
||||
<script type="text/javascript" src="/pos_epson_printer/static/src/js/printers.js"></script>
|
||||
<script type="text/javascript" src="/pos_epson_printer/static/lib/epos-2.12.0.js"></script>
|
||||
</xpath>
|
||||
</template>
|
||||
</odoo>
|
||||
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record id="pos_iot_config_view_form" model="ir.ui.view">
|
||||
<field name="name">pos.iot.config.form.view</field>
|
||||
<field name="model">pos.config</field>
|
||||
<field name="inherit_id" ref="point_of_sale.pos_config_view_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//div[@id='other_devices']//div[hasclass('o_setting_right_pane')]" position="inside">
|
||||
<div class="content-group" attrs="{'invisible' : [('other_devices', '=', False)]}">
|
||||
<div class="row">
|
||||
<label string="Epson Receipt Printer IP Address" for="epson_printer_ip" class="col-lg-3 o_light_label"/>
|
||||
<field name="epson_printer_ip"/>
|
||||
</div>
|
||||
<div class="row" attrs="{'invisible': [('epson_printer_ip', 'in', [False, ''])]}">
|
||||
<label string="Cashdrawer" for="iface_cashdrawer" class="col-lg-3 o_light_label"/>
|
||||
<field name="iface_cashdrawer"/>
|
||||
</div>
|
||||
</div>
|
||||
<div role="alert" class="alert alert-warning" attrs="{'invisible': ['|', '|', ('iface_print_via_proxy', '!=', True), ('other_devices', '!=', True), ('epson_printer_ip', 'in', [False, ''])]}">
|
||||
The Epson receipt printer will be used instead of the receipt printer connected to the IoT Box.
|
||||
</div>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
@@ -794,7 +794,7 @@ chrome.OrderSelectorWidget.include({
|
||||
var _super_posmodel = models.PosModel.prototype;
|
||||
models.PosModel = models.PosModel.extend({
|
||||
after_load_server_data: function() {
|
||||
_super_posmodel.after_load_server_data.call(this);
|
||||
var res = _super_posmodel.after_load_server_data.call(this);
|
||||
if (this.config.iface_floorplan) {
|
||||
var self = this;
|
||||
this.table = null;
|
||||
@@ -805,6 +805,7 @@ models.PosModel = models.PosModel.extend({
|
||||
$('.screen').not('.floor-screen').onscroll = function() {self.set_idle_timer()}; // scrolling with arrow keys
|
||||
$('.screen').not('.floor-screen').onkeypress = function() {self.set_idle_timer()};
|
||||
}
|
||||
return res;
|
||||
},
|
||||
|
||||
transfer_order_to_different_table: function () {
|
||||
|
||||
Reference in New Issue
Block a user