Browse Source

Merge 6545b1bb9b into 45a15ac568

pull/474/merge
Jordi Ballester Alomar 4 years ago
committed by GitHub
parent
commit
aa540efa1b
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      pos_jsprintmanager/__init__.py
  2. 22
      pos_jsprintmanager/__manifest__.py
  3. 2
      pos_jsprintmanager/controllers/__init__.py
  4. 26
      pos_jsprintmanager/controllers/main.py
  5. 1
      pos_jsprintmanager/models/__init__.py
  6. 18
      pos_jsprintmanager/models/pos_config.py
  7. 11
      pos_jsprintmanager/readme/CONFIGURE.rst
  8. 6
      pos_jsprintmanager/readme/CONTRIBUTORS.rst
  9. 11
      pos_jsprintmanager/readme/DESCRIPTION.rst
  10. 3
      pos_jsprintmanager/readme/USAGE.rst
  11. 1184
      pos_jsprintmanager/static/src/js/jsprintmanager/JSPrintManager.js
  12. 31
      pos_jsprintmanager/static/src/js/jsprintmanager/bluebird.min.js
  13. 2060
      pos_jsprintmanager/static/src/js/jsprintmanager/deflate.js
  14. 20
      pos_jsprintmanager/static/src/js/jsprintmanager/html2canvas.min.js
  15. 259
      pos_jsprintmanager/static/src/js/jsprintmanager/zip-ext.js
  16. 966
      pos_jsprintmanager/static/src/js/jsprintmanager/zip.js
  17. 213
      pos_jsprintmanager/static/src/js/screen.js
  18. 20
      pos_jsprintmanager/views/assets.xml
  19. 41
      pos_jsprintmanager/views/pos_config_view.xml

2
pos_jsprintmanager/__init__.py

@ -0,0 +1,2 @@
from . import models
from . import controllers

22
pos_jsprintmanager/__manifest__.py

@ -0,0 +1,22 @@
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl).
{
"name": "Pos JS Print Manager",
"category": "Point Of Sale",
"version": "12.0.1.0.0",
"author": "ForgeFlow, "
"Odoo Community Association (OCA)",
"website": "https://github.com/OCA/pos",
"license": "LGPL-3",
"depends": [
"point_of_sale",
],
"data": [
"views/assets.xml",
"views/pos_config_view.xml",
],
"qweb": [
'static/src/xml/pos.xml',
],
"installable": True,
}

2
pos_jsprintmanager/controllers/__init__.py

@ -0,0 +1,2 @@
from . import main

26
pos_jsprintmanager/controllers/main.py

@ -0,0 +1,26 @@
# Copyright 2020 ForgeFlow, S.L.
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl).
import logging
import uuid
from hashlib import sha256
from odoo import http
from odoo.http import request
_logger = logging.getLogger(__name__)
class JsPrintManagerController(http.Controller):
@http.route('/jspm', type='http', auth="none")
def get_jspm_license(self, **kw):
""" Route called when google sends a Accept/Refuse auth """
icp = request.env['ir.config_parameter'].sudo()
license_owner = icp.get_param('jsprintmanager.license_owner')
license_key = icp.get_param('jsprintmanager.license_key')
uid = str(uuid.uuid1())
shasign = sha256((license_key + uid).encode('utf-8'))
license_hash = shasign.hexdigest()
output = "|".join([license_owner, license_hash, uid])
return request.make_response(output)

1
pos_jsprintmanager/models/__init__.py

@ -0,0 +1 @@
from . import pos_config

18
pos_jsprintmanager/models/pos_config.py

@ -0,0 +1,18 @@
from odoo import models, fields
class PosConfig(models.Model):
_inherit = 'pos.config'
use_jsprintmanager = fields.Boolean()
jsprintmanager_default_receipt_printer = fields.Char(
string='Default Printer for Receipts',
help='Enter the name of the default printer to be used in receipts')
jsprintmanager_output_format = fields.Selection(
string='Printer output format',
selection=[
('normal', 'Normal'),
('escpos', 'ESC/POS')
],
help='Enter the format used by the printer')

11
pos_jsprintmanager/readme/CONFIGURE.rst

@ -0,0 +1,11 @@
To add a logo to any given company:
#. Go to *Settings > Users & Companies > Companies*
#. Edit one and add the logo editing the top left corner image.
To configure receipt web print in the PoS (is the default setting):
#. Go to *Point of Sale > Configuration > Point of Sale*.
#. Edit the one you want to configure.
#. If the *PosBox* setting is enabled the *Receipt Printer* setting should be
disabled.

6
pos_jsprintmanager/readme/CONTRIBUTORS.rst

@ -0,0 +1,6 @@
* Endika Iglesias <endikaig@antiun.com>
* `Tecnativa <https://www.tecnativa.com>`_:
* Antonio Espinosa
* David Vidal

11
pos_jsprintmanager/readme/DESCRIPTION.rst

@ -0,0 +1,11 @@
A different receipt template is used if the PoS ticket is printed via web or
via proxy. In the case the ticket is printed via web (through the browser) the
company logo isn't printed. This module adds it.
In other hand, company_logo is loaded using `/web/binary/company_logo`
controller `that returns a 150px wide logo <https://github.com/odoo/odoo/blob/11.0/addons/point_of_sale/static/src/js/models.js#L481>`_:
but after that logo is resized to 300px width, so a pixelled logo appears even
original logo is 300px wide.
That's why we override how company_logo is loaded. We also resized it to 260px
(not 300px) wide because appears cut in PDF.

3
pos_jsprintmanager/readme/USAGE.rst

@ -0,0 +1,3 @@
#. Open a new PoS session.
#. Make an order and validate it.
#. You should see the company logo in the receipt preview.

1184
pos_jsprintmanager/static/src/js/jsprintmanager/JSPrintManager.js
File diff suppressed because it is too large
View File

31
pos_jsprintmanager/static/src/js/jsprintmanager/bluebird.min.js
File diff suppressed because it is too large
View File

2060
pos_jsprintmanager/static/src/js/jsprintmanager/deflate.js
File diff suppressed because it is too large
View File

20
pos_jsprintmanager/static/src/js/jsprintmanager/html2canvas.min.js
File diff suppressed because it is too large
View File

259
pos_jsprintmanager/static/src/js/jsprintmanager/zip-ext.js

@ -0,0 +1,259 @@
/*
Copyright (c) 2013 Gildas Lormeau. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the distribution.
3. The names of the authors may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
(function() {
"use strict";
var ERR_HTTP_RANGE = "HTTP Range not supported.";
var Reader = zip.Reader;
var Writer = zip.Writer;
var ZipDirectoryEntry;
var appendABViewSupported;
try {
appendABViewSupported = new Blob([ new DataView(new ArrayBuffer(0)) ]).size === 0;
} catch (e) {
}
function isHttpFamily(url) {
var a = document.createElement("a");
a.href = url;
return a.protocol === "http:" || a.protocol === "https:";
}
function HttpReader(url) {
var that = this;
function getData(callback, onerror) {
var request;
if (!that.data) {
request = new XMLHttpRequest();
request.addEventListener("load", function() {
if (!that.size)
that.size = Number(request.getResponseHeader("Content-Length")) || Number(request.response.byteLength);
that.data = new Uint8Array(request.response);
callback();
}, false);
request.addEventListener("error", onerror, false);
request.open("GET", url);
request.responseType = "arraybuffer";
request.send();
} else
callback();
}
function init(callback, onerror) {
if (!isHttpFamily(url)) {
// For schemas other than http(s), HTTP HEAD may be unavailable,
// so use HTTP GET instead.
getData(callback, onerror);
return;
}
var request = new XMLHttpRequest();
request.addEventListener("load", function() {
that.size = Number(request.getResponseHeader("Content-Length"));
// If response header doesn't return size then prefetch the content.
if (!that.size) {
getData(callback, onerror);
} else {
callback();
}
}, false);
request.addEventListener("error", onerror, false);
request.open("HEAD", url);
request.send();
}
function readUint8Array(index, length, callback, onerror) {
getData(function() {
callback(new Uint8Array(that.data.subarray(index, index + length)));
}, onerror);
}
that.size = 0;
that.init = init;
that.readUint8Array = readUint8Array;
}
HttpReader.prototype = new Reader();
HttpReader.prototype.constructor = HttpReader;
function HttpRangeReader(url) {
var that = this;
function init(callback, onerror) {
var request = new XMLHttpRequest();
request.addEventListener("load", function() {
that.size = Number(request.getResponseHeader("Content-Length"));
if (request.getResponseHeader("Accept-Ranges") == "bytes")
callback();
else
onerror(ERR_HTTP_RANGE);
}, false);
request.addEventListener("error", onerror, false);
request.open("HEAD", url);
request.send();
}
function readArrayBuffer(index, length, callback, onerror) {
var request = new XMLHttpRequest();
request.open("GET", url);
request.responseType = "arraybuffer";
request.setRequestHeader("Range", "bytes=" + index + "-" + (index + length - 1));
request.addEventListener("load", function() {
callback(request.response);
}, false);
request.addEventListener("error", onerror, false);
request.send();
}
function readUint8Array(index, length, callback, onerror) {
readArrayBuffer(index, length, function(arraybuffer) {
callback(new Uint8Array(arraybuffer));
}, onerror);
}
that.size = 0;
that.init = init;
that.readUint8Array = readUint8Array;
}
HttpRangeReader.prototype = new Reader();
HttpRangeReader.prototype.constructor = HttpRangeReader;
function ArrayBufferReader(arrayBuffer) {
var that = this;
function init(callback, onerror) {
that.size = arrayBuffer.byteLength;
callback();
}
function readUint8Array(index, length, callback, onerror) {
callback(new Uint8Array(arrayBuffer.slice(index, index + length)));
}
that.size = 0;
that.init = init;
that.readUint8Array = readUint8Array;
}
ArrayBufferReader.prototype = new Reader();
ArrayBufferReader.prototype.constructor = ArrayBufferReader;
function ArrayBufferWriter() {
var array, that = this;
function init(callback, onerror) {
array = new Uint8Array();
callback();
}
function writeUint8Array(arr, callback, onerror) {
var tmpArray = new Uint8Array(array.length + arr.length);
tmpArray.set(array);
tmpArray.set(arr, array.length);
array = tmpArray;
callback();
}
function getData(callback) {
callback(array.buffer);
}
that.init = init;
that.writeUint8Array = writeUint8Array;
that.getData = getData;
}
ArrayBufferWriter.prototype = new Writer();
ArrayBufferWriter.prototype.constructor = ArrayBufferWriter;
function FileWriter(fileEntry, contentType) {
var writer, that = this;
function init(callback, onerror) {
fileEntry.createWriter(function(fileWriter) {
writer = fileWriter;
callback();
}, onerror);
}
function writeUint8Array(array, callback, onerror) {
var blob = new Blob([ appendABViewSupported ? array : array.buffer ], {
type : contentType
});
writer.onwrite = function() {
writer.onwrite = null;
callback();
};
writer.onerror = onerror;
writer.write(blob);
}
function getData(callback) {
fileEntry.file(callback);
}
that.init = init;
that.writeUint8Array = writeUint8Array;
that.getData = getData;
}
FileWriter.prototype = new Writer();
FileWriter.prototype.constructor = FileWriter;
zip.FileWriter = FileWriter;
zip.HttpReader = HttpReader;
zip.HttpRangeReader = HttpRangeReader;
zip.ArrayBufferReader = ArrayBufferReader;
zip.ArrayBufferWriter = ArrayBufferWriter;
if (zip.fs) {
ZipDirectoryEntry = zip.fs.ZipDirectoryEntry;
ZipDirectoryEntry.prototype.addHttpContent = function(name, URL, useRangeHeader) {
function addChild(parent, name, params, directory) {
if (parent.directory)
return directory ? new ZipDirectoryEntry(parent.fs, name, params, parent) : new zip.fs.ZipFileEntry(parent.fs, name, params, parent);
else
throw "Parent entry is not a directory.";
}
return addChild(this, name, {
data : URL,
Reader : useRangeHeader ? HttpRangeReader : HttpReader
});
};
ZipDirectoryEntry.prototype.importHttpContent = function(URL, useRangeHeader, onend, onerror) {
this.importZip(useRangeHeader ? new HttpRangeReader(URL) : new HttpReader(URL), onend, onerror);
};
zip.fs.FS.prototype.importHttpContent = function(URL, useRangeHeader, onend, onerror) {
this.entries = [];
this.root = new ZipDirectoryEntry(this);
this.root.importHttpContent(URL, useRangeHeader, onend, onerror);
};
}
})();

966
pos_jsprintmanager/static/src/js/jsprintmanager/zip.js

@ -0,0 +1,966 @@
/*
Copyright (c) 2013 Gildas Lormeau. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the distribution.
3. The names of the authors may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
(function(obj) {
"use strict";
var ERR_BAD_FORMAT = "File format is not recognized.";
var ERR_CRC = "CRC failed.";
var ERR_ENCRYPTED = "File contains encrypted entry.";
var ERR_ZIP64 = "File is using Zip64 (4gb+ file size).";
var ERR_READ = "Error while reading zip file.";
var ERR_WRITE = "Error while writing zip file.";
var ERR_WRITE_DATA = "Error while writing file data.";
var ERR_READ_DATA = "Error while reading file data.";
var ERR_DUPLICATED_NAME = "File already exists.";
var CHUNK_SIZE = 512 * 1024;
var TEXT_PLAIN = "text/plain";
var appendABViewSupported;
try {
appendABViewSupported = new Blob([ new DataView(new ArrayBuffer(0)) ]).size === 0;
} catch (e) {
}
function Crc32() {
this.crc = -1;
}
Crc32.prototype.append = function append(data) {
var crc = this.crc | 0, table = this.table;
for (var offset = 0, len = data.length | 0; offset < len; offset++)
crc = (crc >>> 8) ^ table[(crc ^ data[offset]) & 0xFF];
this.crc = crc;
};
Crc32.prototype.get = function get() {
return ~this.crc;
};
Crc32.prototype.table = (function() {
var i, j, t, table = []; // Uint32Array is actually slower than []
for (i = 0; i < 256; i++) {
t = i;
for (j = 0; j < 8; j++)
if (t & 1)
t = (t >>> 1) ^ 0xEDB88320;
else
t = t >>> 1;
table[i] = t;
}
return table;
})();
// "no-op" codec
function NOOP() {}
NOOP.prototype.append = function append(bytes, onprogress) {
return bytes;
};
NOOP.prototype.flush = function flush() {};
function blobSlice(blob, index, length) {
if (index < 0 || length < 0 || index + length > blob.size)
throw new RangeError('offset:' + index + ', length:' + length + ', size:' + blob.size);
if (blob.slice)
return blob.slice(index, index + length);
else if (blob.webkitSlice)
return blob.webkitSlice(index, index + length);
else if (blob.mozSlice)
return blob.mozSlice(index, index + length);
else if (blob.msSlice)
return blob.msSlice(index, index + length);
}
function getDataHelper(byteLength, bytes) {
var dataBuffer, dataArray;
dataBuffer = new ArrayBuffer(byteLength);
dataArray = new Uint8Array(dataBuffer);
if (bytes)
dataArray.set(bytes, 0);
return {
buffer : dataBuffer,
array : dataArray,
view : new DataView(dataBuffer)
};
}
// Readers
function Reader() {
}
function TextReader(text) {
var that = this, blobReader;
function init(callback, onerror) {
var blob = new Blob([ text ], {
type : TEXT_PLAIN
});
blobReader = new BlobReader(blob);
blobReader.init(function() {
that.size = blobReader.size;
callback();
}, onerror);
}
function readUint8Array(index, length, callback, onerror) {
blobReader.readUint8Array(index, length, callback, onerror);
}
that.size = 0;
that.init = init;
that.readUint8Array = readUint8Array;
}
TextReader.prototype = new Reader();
TextReader.prototype.constructor = TextReader;
function Data64URIReader(dataURI) {
var that = this, dataStart;
function init(callback) {
var dataEnd = dataURI.length;
while (dataURI.charAt(dataEnd - 1) == "=")
dataEnd--;
dataStart = dataURI.indexOf(",") + 1;
that.size = Math.floor((dataEnd - dataStart) * 0.75);
callback();
}
function readUint8Array(index, length, callback) {
var i, data = getDataHelper(length);
var start = Math.floor(index / 3) * 4;
var end = Math.ceil((index + length) / 3) * 4;
var bytes = obj.atob(dataURI.substring(start + dataStart, end + dataStart));
var delta = index - Math.floor(start / 4) * 3;
for (i = delta; i < delta + length; i++)
data.array[i - delta] = bytes.charCodeAt(i);
callback(data.array);
}
that.size = 0;
that.init = init;
that.readUint8Array = readUint8Array;
}
Data64URIReader.prototype = new Reader();
Data64URIReader.prototype.constructor = Data64URIReader;
function BlobReader(blob) {
var that = this;
function init(callback) {
that.size = blob.size;
callback();
}
function readUint8Array(index, length, callback, onerror) {
var reader = new FileReader();
reader.onload = function(e) {
callback(new Uint8Array(e.target.result));
};
reader.onerror = onerror;
try {
reader.readAsArrayBuffer(blobSlice(blob, index, length));
} catch (e) {
onerror(e);
}
}
that.size = 0;
that.init = init;
that.readUint8Array = readUint8Array;
}
BlobReader.prototype = new Reader();
BlobReader.prototype.constructor = BlobReader;
// Writers
function Writer() {
}
Writer.prototype.getData = function(callback) {
callback(this.data);
};
function TextWriter(encoding) {
var that = this, blob;
function init(callback) {
blob = new Blob([], {
type : TEXT_PLAIN
});
callback();
}
function writeUint8Array(array, callback) {
blob = new Blob([ blob, appendABViewSupported ? array : array.buffer ], {
type : TEXT_PLAIN
});
callback();
}
function getData(callback, onerror) {
var reader = new FileReader();
reader.onload = function(e) {
callback(e.target.result);
};
reader.onerror = onerror;
reader.readAsText(blob, encoding);
}
that.init = init;
that.writeUint8Array = writeUint8Array;
that.getData = getData;
}
TextWriter.prototype = new Writer();
TextWriter.prototype.constructor = TextWriter;
function Data64URIWriter(contentType) {
var that = this, data = "", pending = "";
function init(callback) {
data += "data:" + (contentType || "") + ";base64,";
callback();
}
function writeUint8Array(array, callback) {
var i, delta = pending.length, dataString = pending;
pending = "";
for (i = 0; i < (Math.floor((delta + array.length) / 3) * 3) - delta; i++)
dataString += String.fromCharCode(array[i]);
for (; i < array.length; i++)
pending += String.fromCharCode(array[i]);
if (dataString.length > 2)
data += obj.btoa(dataString);
else
pending = dataString;
callback();
}
function getData(callback) {
callback(data + obj.btoa(pending));
}
that.init = init;
that.writeUint8Array = writeUint8Array;
that.getData = getData;
}
Data64URIWriter.prototype = new Writer();
Data64URIWriter.prototype.constructor = Data64URIWriter;
function BlobWriter(contentType) {
var blob, that = this;
function init(callback) {
blob = new Blob([], {
type : contentType
});
callback();
}
function writeUint8Array(array, callback) {
blob = new Blob([ blob, appendABViewSupported ? array : array.buffer ], {
type : contentType
});
callback();
}
function getData(callback) {
callback(blob);
}
that.init = init;
that.writeUint8Array = writeUint8Array;
that.getData = getData;
}
BlobWriter.prototype = new Writer();
BlobWriter.prototype.constructor = BlobWriter;
/**
* inflate/deflate core functions
* @param worker {Worker} web worker for the task.
* @param initialMessage {Object} initial message to be sent to the worker. should contain
* sn(serial number for distinguishing multiple tasks sent to the worker), and codecClass.
* This function may add more properties before sending.
*/
function launchWorkerProcess(worker, initialMessage, reader, writer, offset, size, onprogress, onend, onreaderror, onwriteerror) {
var chunkIndex = 0, index, outputSize, sn = initialMessage.sn, crc;
function onflush() {
worker.removeEventListener('message', onmessage, false);
onend(outputSize, crc);
}
function onmessage(event) {
var message = event.data, data = message.data, err = message.error;
if (err) {
err.toString = function () { return 'Error: ' + this.message; };
onreaderror(err);
return;
}
if (message.sn !== sn)
return;
if (typeof message.codecTime === 'number')
worker.codecTime += message.codecTime; // should be before onflush()
if (typeof message.crcTime === 'number')
worker.crcTime += message.crcTime;
switch (message.type) {
case 'append':
if (data) {
outputSize += data.length;
writer.writeUint8Array(data, function() {
step();
}, onwriteerror);
} else
step();
break;
case 'flush':
crc = message.crc;
if (data) {
outputSize += data.length;
writer.writeUint8Array(data, function() {
onflush();
}, onwriteerror);
} else
onflush();
break;
case 'progress':
if (onprogress)
onprogress(index + message.loaded, size);
break;
case 'importScripts': //no need to handle here
case 'newTask':
case 'echo':
break;
default:
console.warn('zip.js:launchWorkerProcess: unknown message: ', message);
}
}
function step() {
index = chunkIndex * CHUNK_SIZE;
// use `<=` instead of `<`, because `size` may be 0.
if (index <= size) {
reader.readUint8Array(offset + index, Math.min(CHUNK_SIZE, size - index), function(array) {
if (onprogress)
onprogress(index, size);
var msg = index === 0 ? initialMessage : {sn : sn};
msg.type = 'append';
msg.data = array;
// posting a message with transferables will fail on IE10
try {
worker.postMessage(msg, [array.buffer]);
} catch(ex) {
worker.postMessage(msg); // retry without transferables
}
chunkIndex++;
}, onreaderror);
} else {
worker.postMessage({
sn: sn,
type: 'flush'
});
}
}
outputSize = 0;
worker.addEventListener('message', onmessage, false);
step();
}
function launchProcess(process, reader, writer, offset, size, crcType, onprogress, onend, onreaderror, onwriteerror) {
var chunkIndex = 0, index, outputSize = 0,
crcInput = crcType === 'input',
crcOutput = crcType === 'output',
crc = new Crc32();
function step() {
var outputData;
index = chunkIndex * CHUNK_SIZE;
if (index < size)
reader.readUint8Array(offset + index, Math.min(CHUNK_SIZE, size - index), function(inputData) {
var outputData;
try {
outputData = process.append(inputData, function(loaded) {
if (onprogress)
onprogress(index + loaded, size);
});
} catch (e) {
onreaderror(e);
return;
}
if (outputData) {
outputSize += outputData.length;
writer.writeUint8Array(outputData, function() {
chunkIndex++;
setTimeout(step, 1);
}, onwriteerror);
if (crcOutput)
crc.append(outputData);
} else {
chunkIndex++;
setTimeout(step, 1);
}
if (crcInput)
crc.append(inputData);
if (onprogress)
onprogress(index, size);
}, onreaderror);
else {
try {
outputData = process.flush();
} catch (e) {
onreaderror(e);
return;
}
if (outputData) {
if (crcOutput)
crc.append(outputData);
outputSize += outputData.length;
writer.writeUint8Array(outputData, function() {
onend(outputSize, crc.get());
}, onwriteerror);
} else
onend(outputSize, crc.get());
}
}
step();
}
function inflate(worker, sn, reader, writer, offset, size, computeCrc32, onend, onprogress, onreaderror, onwriteerror) {
var crcType = computeCrc32 ? 'output' : 'none';
if (obj.zip.useWebWorkers) {
var initialMessage = {
sn: sn,
codecClass: 'Inflater',
crcType: crcType,
};
launchWorkerProcess(worker, initialMessage, reader, writer, offset, size, onprogress, onend, onreaderror, onwriteerror);
} else
launchProcess(new obj.zip.Inflater(), reader, writer, offset, size, crcType, onprogress, onend, onreaderror, onwriteerror);
}
function deflate(worker, sn, reader, writer, level, onend, onprogress, onreaderror, onwriteerror) {
var crcType = 'input';
if (obj.zip.useWebWorkers) {
var initialMessage = {
sn: sn,
options: {level: level},
codecClass: 'Deflater',
crcType: crcType,
};
launchWorkerProcess(worker, initialMessage, reader, writer, 0, reader.size, onprogress, onend, onreaderror, onwriteerror);
} else
launchProcess(new obj.zip.Deflater(), reader, writer, 0, reader.size, crcType, onprogress, onend, onreaderror, onwriteerror);
}
function copy(worker, sn, reader, writer, offset, size, computeCrc32, onend, onprogress, onreaderror, onwriteerror) {
var crcType = 'input';
if (obj.zip.useWebWorkers && computeCrc32) {
var initialMessage = {
sn: sn,
codecClass: 'NOOP',
crcType: crcType,
};
launchWorkerProcess(worker, initialMessage, reader, writer, offset, size, onprogress, onend, onreaderror, onwriteerror);
} else
launchProcess(new NOOP(), reader, writer, offset, size, crcType, onprogress, onend, onreaderror, onwriteerror);
}
// ZipReader
function decodeASCII(str) {
var i, out = "", charCode, extendedASCII = [ '\u00C7', '\u00FC', '\u00E9', '\u00E2', '\u00E4', '\u00E0', '\u00E5', '\u00E7', '\u00EA', '\u00EB',
'\u00E8', '\u00EF', '\u00EE', '\u00EC', '\u00C4', '\u00C5', '\u00C9', '\u00E6', '\u00C6', '\u00F4', '\u00F6', '\u00F2', '\u00FB', '\u00F9',
'\u00FF', '\u00D6', '\u00DC', '\u00F8', '\u00A3', '\u00D8', '\u00D7', '\u0192', '\u00E1', '\u00ED', '\u00F3', '\u00FA', '\u00F1', '\u00D1',
'\u00AA', '\u00BA', '\u00BF', '\u00AE', '\u00AC', '\u00BD', '\u00BC', '\u00A1', '\u00AB', '\u00BB', '_', '_', '_', '\u00A6', '\u00A6',
'\u00C1', '\u00C2', '\u00C0', '\u00A9', '\u00A6', '\u00A6', '+', '+', '\u00A2', '\u00A5', '+', '+', '-', '-', '+', '-', '+', '\u00E3',
'\u00C3', '+', '+', '-', '-', '\u00A6', '-', '+', '\u00A4', '\u00F0', '\u00D0', '\u00CA', '\u00CB', '\u00C8', 'i', '\u00CD', '\u00CE',
'\u00CF', '+', '+', '_', '_', '\u00A6', '\u00CC', '_', '\u00D3', '\u00DF', '\u00D4', '\u00D2', '\u00F5', '\u00D5', '\u00B5', '\u00FE',
'\u00DE', '\u00DA', '\u00DB', '\u00D9', '\u00FD', '\u00DD', '\u00AF', '\u00B4', '\u00AD', '\u00B1', '_', '\u00BE', '\u00B6', '\u00A7',
'\u00F7', '\u00B8', '\u00B0', '\u00A8', '\u00B7', '\u00B9', '\u00B3', '\u00B2', '_', ' ' ];
for (i = 0; i < str.length; i++) {
charCode = str.charCodeAt(i) & 0xFF;
if (charCode > 127)
out += extendedASCII[charCode - 128];
else
out += String.fromCharCode(charCode);
}
return out;
}
function decodeUTF8(string) {
return decodeURIComponent(escape(string));
}
function getString(bytes) {
var i, str = "";
for (i = 0; i < bytes.length; i++)
str += String.fromCharCode(bytes[i]);
return str;
}
function getDate(timeRaw) {
var date = (timeRaw & 0xffff0000) >> 16, time = timeRaw & 0x0000ffff;
try {
return new Date(1980 + ((date & 0xFE00) >> 9), ((date & 0x01E0) >> 5) - 1, date & 0x001F, (time & 0xF800) >> 11, (time & 0x07E0) >> 5,
(time & 0x001F) * 2, 0);
} catch (e) {
}
}
function readCommonHeader(entry, data, index, centralDirectory, onerror) {
entry.version = data.view.getUint16(index, true);
entry.bitFlag = data.view.getUint16(index + 2, true);
entry.compressionMethod = data.view.getUint16(index + 4, true);
entry.lastModDateRaw = data.view.getUint32(index + 6, true);
entry.lastModDate = getDate(entry.lastModDateRaw);
if ((entry.bitFlag & 0x01) === 0x01) {
onerror(ERR_ENCRYPTED);
return;
}
if (centralDirectory || (entry.bitFlag & 0x0008) != 0x0008) {
entry.crc32 = data.view.getUint32(index + 10, true);
entry.compressedSize = data.view.getUint32(index + 14, true);
entry.uncompressedSize = data.view.getUint32(index + 18, true);
}
if (entry.compressedSize === 0xFFFFFFFF || entry.uncompressedSize === 0xFFFFFFFF) {
onerror(ERR_ZIP64);
return;
}
entry.filenameLength = data.view.getUint16(index + 22, true);
entry.extraFieldLength = data.view.getUint16(index + 24, true);
}
function createZipReader(reader, callback, onerror) {
var inflateSN = 0;
function Entry() {
}
Entry.prototype.getData = function(writer, onend, onprogress, checkCrc32) {
var that = this;
function testCrc32(crc32) {
var dataCrc32 = getDataHelper(4);
dataCrc32.view.setUint32(0, crc32);
return that.crc32 == dataCrc32.view.getUint32(0);
}
function getWriterData(uncompressedSize, crc32) {
if (checkCrc32 && !testCrc32(crc32))
onerror(ERR_CRC);
else
writer.getData(function(data) {
onend(data);
});
}
function onreaderror(err) {
onerror(err || ERR_READ_DATA);
}
function onwriteerror(err) {
onerror(err || ERR_WRITE_DATA);
}
reader.readUint8Array(that.offset, 30, function(bytes) {
var data = getDataHelper(bytes.length, bytes), dataOffset;
if (data.view.getUint32(0) != 0x504b0304) {
onerror(ERR_BAD_FORMAT);
return;
}
readCommonHeader(that, data, 4, false, onerror);
dataOffset = that.offset + 30 + that.filenameLength + that.extraFieldLength;
writer.init(function() {
if (that.compressionMethod === 0)
copy(that._worker, inflateSN++, reader, writer, dataOffset, that.compressedSize, checkCrc32, getWriterData, onprogress, onreaderror, onwriteerror);
else
inflate(that._worker, inflateSN++, reader, writer, dataOffset, that.compressedSize, checkCrc32, getWriterData, onprogress, onreaderror, onwriteerror);
}, onwriteerror);
}, onreaderror);
};
function seekEOCDR(eocdrCallback) {
// "End of central directory record" is the last part of a zip archive, and is at least 22 bytes long.
// Zip file comment is the last part of EOCDR and has max length of 64KB,
// so we only have to search the last 64K + 22 bytes of a archive for EOCDR signature (0x06054b50).
var EOCDR_MIN = 22;
if (reader.size < EOCDR_MIN) {
onerror(ERR_BAD_FORMAT);
return;
}
var ZIP_COMMENT_MAX = 256 * 256, EOCDR_MAX = EOCDR_MIN + ZIP_COMMENT_MAX;
// In most cases, the EOCDR is EOCDR_MIN bytes long
doSeek(EOCDR_MIN, function() {
// If not found, try within EOCDR_MAX bytes
doSeek(Math.min(EOCDR_MAX, reader.size), function() {
onerror(ERR_BAD_FORMAT);
});
});
// seek last length bytes of file for EOCDR
function doSeek(length, eocdrNotFoundCallback) {
reader.readUint8Array(reader.size - length, length, function(bytes) {
for (var i = bytes.length - EOCDR_MIN; i >= 0; i--) {
if (bytes[i] === 0x50 && bytes[i + 1] === 0x4b && bytes[i + 2] === 0x05 && bytes[i + 3] === 0x06) {
eocdrCallback(new DataView(bytes.buffer, i, EOCDR_MIN));
return;
}
}
eocdrNotFoundCallback();
}, function() {
onerror(ERR_READ);
});
}
}
var zipReader = {
getEntries : function(callback) {
var worker = this._worker;
// look for End of central directory record
seekEOCDR(function(dataView) {
var datalength, fileslength;
datalength = dataView.getUint32(16, true);
fileslength = dataView.getUint16(8, true);
if (datalength < 0 || datalength >= reader.size) {
onerror(ERR_BAD_FORMAT);
return;
}
reader.readUint8Array(datalength, reader.size - datalength, function(bytes) {
var i, index = 0, entries = [], entry, filename, comment, data = getDataHelper(bytes.length, bytes);
for (i = 0; i < fileslength; i++) {
entry = new Entry();
entry._worker = worker;
if (data.view.getUint32(index) != 0x504b0102) {
onerror(ERR_BAD_FORMAT);
return;
}
readCommonHeader(entry, data, index + 6, true, onerror);
entry.commentLength = data.view.getUint16(index + 32, true);
entry.directory = ((data.view.getUint8(index + 38) & 0x10) == 0x10);
entry.offset = data.view.getUint32(index + 42, true);
filename = getString(data.array.subarray(index + 46, index + 46 + entry.filenameLength));
entry.filename = ((entry.bitFlag & 0x0800) === 0x0800) ? decodeUTF8(filename) : decodeASCII(filename);
if (!entry.directory && entry.filename.charAt(entry.filename.length - 1) == "/")
entry.directory = true;
comment = getString(data.array.subarray(index + 46 + entry.filenameLength + entry.extraFieldLength, index + 46
+ entry.filenameLength + entry.extraFieldLength + entry.commentLength));
entry.comment = ((entry.bitFlag & 0x0800) === 0x0800) ? decodeUTF8(comment) : decodeASCII(comment);
entries.push(entry);
index += 46 + entry.filenameLength + entry.extraFieldLength + entry.commentLength;
}
callback(entries);
}, function() {
onerror(ERR_READ);
});
});
},
close : function(callback) {
if (this._worker) {
this._worker.terminate();
this._worker = null;
}
if (callback)
callback();
},
_worker: null
};
if (!obj.zip.useWebWorkers)
callback(zipReader);
else {
createWorker('inflater',
function(worker) {
zipReader._worker = worker;
callback(zipReader);
},
function(err) {
onerror(err);
}
);
}
}
// ZipWriter
function encodeUTF8(string) {
return unescape(encodeURIComponent(string));
}
function getBytes(str) {
var i, array = [];
for (i = 0; i < str.length; i++)
array.push(str.charCodeAt(i));
return array;
}
function createZipWriter(writer, callback, onerror, dontDeflate) {
var files = {}, filenames = [], datalength = 0;
var deflateSN = 0;
function onwriteerror(err) {
onerror(err || ERR_WRITE);
}
function onreaderror(err) {
onerror(err || ERR_READ_DATA);
}
var zipWriter = {
add : function(name, reader, onend, onprogress, options) {
var header, filename, date;
var worker = this._worker;
function writeHeader(callback) {
var data;
date = options.lastModDate || new Date();
header = getDataHelper(26);
files[name] = {
headerArray : header.array,
directory : options.directory,
filename : filename,
offset : datalength,
comment : getBytes(encodeUTF8(options.comment || ""))
};
header.view.setUint32(0, 0x14000808);
if (options.version)
header.view.setUint8(0, options.version);
if (!dontDeflate && options.level !== 0 && !options.directory)
header.view.setUint16(4, 0x0800);
header.view.setUint16(6, (((date.getHours() << 6) | date.getMinutes()) << 5) | date.getSeconds() / 2, true);
header.view.setUint16(8, ((((date.getFullYear() - 1980) << 4) | (date.getMonth() + 1)) << 5) | date.getDate(), true);
header.view.setUint16(22, filename.length, true);
data = getDataHelper(30 + filename.length);
data.view.setUint32(0, 0x504b0304);
data.array.set(header.array, 4);
data.array.set(filename, 30);
datalength += data.array.length;
writer.writeUint8Array(data.array, callback, onwriteerror);
}
function writeFooter(compressedLength, crc32) {
var footer = getDataHelper(16);
datalength += compressedLength || 0;
footer.view.setUint32(0, 0x504b0708);
if (typeof crc32 != "undefined") {
header.view.setUint32(10, crc32, true);
footer.view.setUint32(4, crc32, true);
}
if (reader) {
footer.view.setUint32(8, compressedLength, true);
header.view.setUint32(14, compressedLength, true);
footer.view.setUint32(12, reader.size, true);
header.view.setUint32(18, reader.size, true);
}
writer.writeUint8Array(footer.array, function() {
datalength += 16;
onend();
}, onwriteerror);
}
function writeFile() {
options = options || {};
name = name.trim();
if (options.directory && name.charAt(name.length - 1) != "/")
name += "/";
if (files.hasOwnProperty(name)) {
onerror(ERR_DUPLICATED_NAME);
return;
}
filename = getBytes(encodeUTF8(name));
filenames.push(name);
writeHeader(function() {
if (reader)
if (dontDeflate || options.level === 0)
copy(worker, deflateSN++, reader, writer, 0, reader.size, true, writeFooter, onprogress, onreaderror, onwriteerror);
else
deflate(worker, deflateSN++, reader, writer, options.level, writeFooter, onprogress, onreaderror, onwriteerror);
else
writeFooter();
}, onwriteerror);
}
if (reader)
reader.init(writeFile, onreaderror);
else
writeFile();
},
close : function(callback) {
if (this._worker) {
this._worker.terminate();
this._worker = null;
}
var data, length = 0, index = 0, indexFilename, file;
for (indexFilename = 0; indexFilename < filenames.length; indexFilename++) {
file = files[filenames[indexFilename]];
length += 46 + file.filename.length + file.comment.length;
}
data = getDataHelper(length + 22);
for (indexFilename = 0; indexFilename < filenames.length; indexFilename++) {
file = files[filenames[indexFilename]];
data.view.setUint32(index, 0x504b0102);
data.view.setUint16(index + 4, 0x1400);
data.array.set(file.headerArray, index + 6);
data.view.setUint16(index + 32, file.comment.length, true);
if (file.directory)
data.view.setUint8(index + 38, 0x10);
data.view.setUint32(index + 42, file.offset, true);
data.array.set(file.filename, index + 46);
data.array.set(file.comment, index + 46 + file.filename.length);
index += 46 + file.filename.length + file.comment.length;
}
data.view.setUint32(index, 0x504b0506);
data.view.setUint16(index + 8, filenames.length, true);
data.view.setUint16(index + 10, filenames.length, true);
data.view.setUint32(index + 12, length, true);
data.view.setUint32(index + 16, datalength, true);
writer.writeUint8Array(data.array, function() {
writer.getData(callback);
}, onwriteerror);
},
_worker: null
};
if (!obj.zip.useWebWorkers)
callback(zipWriter);
else {
createWorker('deflater',
function(worker) {
zipWriter._worker = worker;
callback(zipWriter);
},
function(err) {
onerror(err);
}
);
}
}
function resolveURLs(urls) {
var a = document.createElement('a');
return urls.map(function(url) {
a.href = url;
return a.href;
});
}
var DEFAULT_WORKER_SCRIPTS = {
deflater: ['z-worker.js', 'deflate.js'],
inflater: ['z-worker.js', 'inflate.js']
};
function createWorker(type, callback, onerror) {
if (obj.zip.workerScripts !== null && obj.zip.workerScriptsPath !== null) {
onerror(new Error('Either zip.workerScripts or zip.workerScriptsPath may be set, not both.'));
return;
}
var scripts;
if (obj.zip.workerScripts) {
scripts = obj.zip.workerScripts[type];
if (!Array.isArray(scripts)) {
onerror(new Error('zip.workerScripts.' + type + ' is not an array!'));
return;
}
scripts = resolveURLs(scripts);
} else {
scripts = DEFAULT_WORKER_SCRIPTS[type].slice(0);
scripts[0] = (obj.zip.workerScriptsPath || '') + scripts[0];
}
var worker = new Worker(scripts[0]);
// record total consumed time by inflater/deflater/crc32 in this worker
worker.codecTime = worker.crcTime = 0;
worker.postMessage({ type: 'importScripts', scripts: scripts.slice(1) });
worker.addEventListener('message', onmessage);
function onmessage(ev) {
var msg = ev.data;
if (msg.error) {
worker.terminate(); // should before onerror(), because onerror() may throw.
onerror(msg.error);
return;
}
if (msg.type === 'importScripts') {
worker.removeEventListener('message', onmessage);
worker.removeEventListener('error', errorHandler);
callback(worker);
}
}
// catch entry script loading error and other unhandled errors
worker.addEventListener('error', errorHandler);
function errorHandler(err) {
worker.terminate();
onerror(err);
}
}
function onerror_default(error) {
console.error(error);
}
obj.zip = {
Reader : Reader,
Writer : Writer,
BlobReader : BlobReader,
Data64URIReader : Data64URIReader,
TextReader : TextReader,
BlobWriter : BlobWriter,
Data64URIWriter : Data64URIWriter,
TextWriter : TextWriter,
createReader : function(reader, callback, onerror) {
onerror = onerror || onerror_default;
reader.init(function() {
createZipReader(reader, callback, onerror);
}, onerror);
},
createWriter : function(writer, callback, onerror, dontDeflate) {
onerror = onerror || onerror_default;
dontDeflate = !!dontDeflate;
writer.init(function() {
createZipWriter(writer, callback, onerror, dontDeflate);
}, onerror);
},
useWebWorkers : true,
/**
* Directory containing the default worker scripts (z-worker.js, deflate.js, and inflate.js), relative to current base url.
* E.g.: zip.workerScripts = './';
*/
workerScriptsPath : null,
/**
* Advanced option to control which scripts are loaded in the Web worker. If this option is specified, then workerScriptsPath must not be set.
* workerScripts.deflater/workerScripts.inflater should be arrays of urls to scripts for deflater/inflater, respectively.
* Scripts in the array are executed in order, and the first one should be z-worker.js, which is used to start the worker.
* All urls are relative to current base url.
* E.g.:
* zip.workerScripts = {
* deflater: ['z-worker.js', 'deflate.js'],
* inflater: ['z-worker.js', 'inflate.js']
* };
*/
workerScripts : null,
};
})(this);

213
pos_jsprintmanager/static/src/js/screen.js

@ -0,0 +1,213 @@
/* License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl). */
odoo.define("pos_jsprintmanager.screen", function (require) {
"use strict";
var core = require('web.core');
var _t = core._t;
var PosBaseWidget = require('point_of_sale.BaseWidget');
var screens = require('point_of_sale.screens');
screens.ReceiptScreenWidget.include({
//Check JSPM WebSocket status
jspmWSStatus: function() {
if (JSPM.JSPrintManager.websocket_status == JSPM.WSStatus.Open)
return true;
else if (JSPM.JSPrintManager.websocket_status == JSPM.WSStatus.Closed) {
alert('JSPrintManager (JSPM) is not installed or not running! Download JSPM Client App from https://neodynamic.com/downloads/jspm');
return false;
}
else if (JSPM.JSPrintManager.websocket_status == JSPM.WSStatus.BlackListed) {
alert('JSPM has blacklisted this website!');
return false;
}
},
init: function(parent,options){
this._super(parent,options);
JSPM.JSPrintManager.auto_reconnect = true;
JSPM.JSPrintManager.start();
var jspmWSStatus = this.jspmWSStatus()
JSPM.JSPrintManager.WS.onStatusChanged = function () {
if (jspmWSStatus) {
//get client installed printers
JSPM.JSPrintManager.getPrinters().then(function (myPrinters) {
var options = '';
for (var i = 0; i < myPrinters.length; i++) {
options += '<option>' + myPrinters[i] + '</option>';
}
$('#installedPrinterName').html(options);
})
}
}
// Variables definition
this.esc = '\x1B'; //ESC byte in hex notation
this.line_feed = '\x0A'; //LF byte in hex notation
this.page_width = 48;
this.qty_width = 12;
this.price_width = 12;
this.totals_width = 24;
this.name_width = this.page_width - this.qty_width - this.price_width;
},
center_align_string: function(s, width) {
return s.padStart(
Math.floor((width - s.length) / 2 + s.length),
' '
);
},
right_align_string: function(s, width) {
return s.padStart(width, ' ');
},
get_escpos_receipt_cmds: function() {
var cmds = '';
var order = this.pos.get_order();
var receipt = order.export_for_printing();
var orderlines = order.get_orderlines();
var paymentlines = order.get_paymentlines();
//Initializes the printer (ESC @)
cmds += this.esc + "@";
cmds += this.esc + "\x70" + "\x00"; // Drawer kick, pin 2 (first drawer)
cmds += this.esc + "1\x02" // Codepage 850
// Header of receipt with Company data
cmds += receipt.company.contact_address ? receipt.company.contact_address + this.line_feed : "";
cmds += receipt.company.phone ? _t("Tel: ") + receipt.company.phone + this.line_feed : "";
cmds += receipt.company.vat ? _t("VAT: ") + receipt.company.vat + this.line_feed : "";
cmds += receipt.company.email ? receipt.company.email + this.line_feed : "";
cmds += receipt.company.website ? receipt.company.website + this.line_feed : "";
cmds += receipt.company.header ? receipt.company.header + this.line_feed : "";
cmds += this.line_feed + this.line_feed;
// Date and Order ID
cmds += this.center_align_string(
receipt.date.localestring + ' ' + receipt.name,
this.page_width
);
cmds += this.line_feed + this.line_feed;
// Order Lines
for (const line of orderlines) {
let name = line.get_product().display_name;
let qty = "" + line.get_quantity_str_with_unit();
let price = "" + this.format_currency(line.get_display_price());
cmds += name.substring(0, this.name_width).padEnd(this.name_width, ' ');
cmds += this.right_align_string(qty, this.qty_width);
cmds += this.right_align_string(price, this.price_width);
cmds += this.line_feed;
if (line.discount > 0) {
cmds += _(' - with a ') + line.discountStr + '% ' + _(' discount');
cmds += this.line_feed;
}
}
cmds += this.line_feed;
// Subtotal
var total_without_tax = this.format_currency(order.get_total_without_tax());
cmds += _t("Subtotal: ").padEnd(this.totals_width, ' ');
cmds += this.right_align_string(this.format_currency(order.get_total_without_tax()), this.totals_width)
cmds += this.line_feed;
// Taxes
for (const taxdetail of order.get_tax_details()) {
cmds += taxdetail.name.padEnd(this.totals_width, ' ');
cmds += this.right_align_string(this.format_currency(taxdetail.amount), this.totals_width);
}
cmds += this.line_feed;
// Discount
if (order.get_total_discount() > 0) {
cmds += _t("Discount: ").padEnd(this.totals_width, ' ');
cmds += this.right_align_string(this.format_currency(order.get_total_discount()), this.totals_width);
}
cmds += this.line_feed;
// Total amount
cmds += this.esc + '!' + '\x10'; // Double-height
cmds += _t("Total: ").padEnd(this.totals_width, ' ');
cmds += this.right_align_string(this.format_currency(order.get_total_with_tax()), this.totals_width);
cmds += this.esc + '!' + '\x00'; // Normal character
cmds += this.line_feed + this.line_feed;
// Payment Lines
for (const line of paymentlines) {
cmds += line.name.padEnd(this.totals_width, ' ');
cmds += this.right_align_string(this.format_currency(line.get_amount()), this.totals_width);
}
cmds += this.line_feed;
// Change
cmds += _t("Change: ").padEnd(this.totals_width, ' ');
cmds += this.right_align_string(this.format_currency(order.get_change()), this.totals_width);
cmds += this.line_feed;
return cmds
},
get_escpos_receipt_cmds_footer: function () {
var cmds = '';
var order = this.pos.get_order();
var receipt = order.export_for_printing();
if (receipt.footer) {
cmds += receipt.footer;
}
cmds += this.line_feed + this.line_feed + this.line_feed + this.line_feed; // Space before cut
cmds += "\x1dV\x00"; // Full cut
cmds += this.line_feed + this.line_feed;
return cmds
},
print_web: function() {
if (this.jspmWSStatus && this.pos.config.use_jsprintmanager == true) {
var outputFormat = this.pos.config.jsprintmanager_output_format;
var default_printer = this.pos.config.jsprintmanager_default_receipt_printer;
console.log(outputFormat)
//Create a ClientPrintJob
var cpj = new JSPM.ClientPrintJob();
if (default_printer) {
cpj.clientPrinter = new JSPM.InstalledPrinter(default_printer);
} else {
cpj.clientPrinter = new JSPM.DefaultPrinter();
}
if (outputFormat == 'escpos'){
//Set content to print...
//Create ESP/POS commands for sample label
var cmds = [this.get_escpos_receipt_cmds(), this.get_escpos_receipt_cmds_footer()].join("")
cpj.printerCommands = cmds;
//Send print job to printer!
cpj.sendToClient();
} else {
//generate an image of HTML content through html2canvas utility
var ticket = document.getElementsByClassName('pos-sale-ticket')[0]
html2canvas(ticket, {scale: 10, width: 900}).then(function (canvas) {
//Set content to print...
var b64Prefix = "data:image/png;base64,";
var imgBase64DataUri = canvas.toDataURL("image/png");
var imgBase64Content = imgBase64DataUri.substring(b64Prefix.length, imgBase64DataUri.length);
var myImageFile = new JSPM.PrintFile(imgBase64Content, JSPM.FileSourceType.Base64, 'myFileToPrint.png', 1);
//add file to print job
cpj.files.push(myImageFile);
//Send print job to printer!
cpj.sendToClient();
});
}
this.pos.get_order()._printed = true;
} else {
return this._super();
}
},
})
});

20
pos_jsprintmanager/views/assets.xml

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2020-Today: ForgeFlow, S.L. (<https://www.forgeflow.com/>)
@author: Jordi Ballester Alomar (https://twitter.com/jordibforgeflow)
License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
-->
<odoo>
<template id="assets_frontend" inherit_id="point_of_sale.assets">
<xpath expr="." position="inside">
<script type="text/javascript" src="/pos_jsprintmanager/static/src/js/jsprintmanager/zip.js"/>
<script type="text/javascript" src="/pos_jsprintmanager/static/src/js/jsprintmanager/zip-ext.js"/>
<script type="text/javascript" src="/pos_jsprintmanager/static/src/js/jsprintmanager/deflate.js"/>
<script type="text/javascript" src="/pos_jsprintmanager/static/src/js/jsprintmanager/JSPrintManager.js"/>
<script type="text/javascript" src="/pos_jsprintmanager/static/src/js/jsprintmanager/html2canvas.min.js"/>
<script type="text/javascript" src="/pos_jsprintmanager/static/src/js/jsprintmanager/bluebird.min.js"/>
<script type="text/javascript" src="/pos_jsprintmanager/static/src/js/screen.js"/>
</xpath>
</template>
</odoo>

41
pos_jsprintmanager/views/pos_config_view.xml

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="view_pos_config_view_form_jsprintmanager" model="ir.ui.view">
<field name="name">pos.config.form.jsprintmanager</field>
<field name="model">pos.config</field>
<field name="inherit_id" ref="point_of_sale.pos_config_view_form"/>
<field name="priority" eval="30"/>
<field name="arch" type="xml">
<xpath expr="//div[@id='receipt']" position="inside">
<div class="col-12 col-lg-6 o_setting_box" id="use_jsprintmanager">
<div class="o_setting_left_pane">
<field name="use_jsprintmanager"/>
</div>
<div class="o_setting_right_pane">
<label for="use_jsprintmanager"/>
<div class="text-muted">
Use JS Print Manager to print receipts
</div>
</div>
<div id='jsprintmanager_default_receipt_printer' class="o_setting_right_pane" attrs="{'invisible' : [('use_jsprintmanager', '=', False)]}">
<span class="o_form_label">Default Printer for Receipts</span>
<div class="content-group mt16">
<field name="jsprintmanager_default_receipt_printer" colspan="4"
nolabel="1"/>
</div>
</div>
<div id='jsprintmanager_output_format' class="o_setting_right_pane" attrs="{'invisible' : [('use_jsprintmanager', '=', False)]}">
<span class="o_form_label">Output format</span>
<div class="content-group mt16">
<field name="jsprintmanager_output_format" colspan="4"
nolabel="1"/>
</div>
</div>
</div>
</xpath>
</field>
</record>
</odoo>
Loading…
Cancel
Save