From c4db591109fc4aa6c1f898df50c3ce43aa03f1df Mon Sep 17 00:00:00 2001
From: eLBati
Date: Tue, 10 Dec 2019 14:46:09 +0100
Subject: [PATCH 01/65] ADD fiscal_epos_print
---
fiscal_epos_print/__init__.py | 1 +
fiscal_epos_print/__manifest__.py | 33 +
fiscal_epos_print/i18n/it.po | 152 ++
fiscal_epos_print/models/__init__.py | 4 +
fiscal_epos_print/models/account.py | 10 +
fiscal_epos_print/models/account_journal.py | 16 +
fiscal_epos_print/models/point_of_sale.py | 16 +
fiscal_epos_print/models/product.py | 17 +
fiscal_epos_print/readme/CONFIGURE.rst | 6 +
fiscal_epos_print/readme/CONTRIBUTORS.rst | 4 +
fiscal_epos_print/readme/DESCRIPTION.rst | 7 +
.../static/lib/fiscalprint/fiscalprint.js | 1435 +++++++++++++++++
fiscal_epos_print/static/src/css/pos.css | 5 +
fiscal_epos_print/static/src/img/ade-logo.png | Bin 0 -> 1323 bytes
fiscal_epos_print/static/src/js/fp90iii.js | 318 ++++
fiscal_epos_print/static/src/xml/pos.xml | 29 +
.../views/account_statement_view.xml | 37 +
fiscal_epos_print/views/assets.xml | 11 +
fiscal_epos_print/views/point_of_sale.xml | 25 +
19 files changed, 2126 insertions(+)
create mode 100644 fiscal_epos_print/__init__.py
create mode 100644 fiscal_epos_print/__manifest__.py
create mode 100644 fiscal_epos_print/i18n/it.po
create mode 100644 fiscal_epos_print/models/__init__.py
create mode 100644 fiscal_epos_print/models/account.py
create mode 100644 fiscal_epos_print/models/account_journal.py
create mode 100644 fiscal_epos_print/models/point_of_sale.py
create mode 100644 fiscal_epos_print/models/product.py
create mode 100644 fiscal_epos_print/readme/CONFIGURE.rst
create mode 100644 fiscal_epos_print/readme/CONTRIBUTORS.rst
create mode 100644 fiscal_epos_print/readme/DESCRIPTION.rst
create mode 100644 fiscal_epos_print/static/lib/fiscalprint/fiscalprint.js
create mode 100644 fiscal_epos_print/static/src/css/pos.css
create mode 100644 fiscal_epos_print/static/src/img/ade-logo.png
create mode 100644 fiscal_epos_print/static/src/js/fp90iii.js
create mode 100644 fiscal_epos_print/static/src/xml/pos.xml
create mode 100644 fiscal_epos_print/views/account_statement_view.xml
create mode 100644 fiscal_epos_print/views/assets.xml
create mode 100644 fiscal_epos_print/views/point_of_sale.xml
diff --git a/fiscal_epos_print/__init__.py b/fiscal_epos_print/__init__.py
new file mode 100644
index 000000000000..0650744f6bc6
--- /dev/null
+++ b/fiscal_epos_print/__init__.py
@@ -0,0 +1 @@
+from . import models
diff --git a/fiscal_epos_print/__manifest__.py b/fiscal_epos_print/__manifest__.py
new file mode 100644
index 000000000000..b00f450a1b86
--- /dev/null
+++ b/fiscal_epos_print/__manifest__.py
@@ -0,0 +1,33 @@
+# Leonardo Donelli - Creativi Quadrati
+# © 2016 Alessio Gerace - Agile Business Group
+# © 2018-2019 Lorenzo Battistini
+# License GPL-3.0 or later (http://www.gnu.org/licenses/gpl.html).
+
+{
+ 'name': 'Driver for ePOS-Print XML compatible fiscal printers',
+ 'version': '12.0.1.0.0',
+ 'category': 'POS, Fiscal, Hardware, Driver',
+ 'summary': 'ePOS-Print XML Fiscal Printer Driver - Compatible Epson printers: '
+ 'FP81II, FP90III',
+ 'author': (
+ 'Odoo Community Association (OCA), Agile Business Group, '
+ 'Leonardo Donelli @ Creativi Quadrati, TAKOBI'
+ ),
+ 'license': 'GPL-3',
+ 'website': 'https://github.com/OCA/l10n-italy',
+ 'depends': ['point_of_sale', 'pos_order_mgmt'],
+ 'data': [
+ 'views/account_statement_view.xml',
+ 'views/point_of_sale.xml',
+ 'views/assets.xml',
+ ],
+ 'js': [
+ 'static/src/js/fp90iii.js',
+ 'static/lib/fiscalprint/fiscalprint.js'
+ ],
+ 'qweb': [
+ 'static/src/xml/pos.xml'
+ ],
+ 'installable': True,
+ 'auto_install': False,
+}
diff --git a/fiscal_epos_print/i18n/it.po b/fiscal_epos_print/i18n/it.po
new file mode 100644
index 000000000000..177c792d61f9
--- /dev/null
+++ b/fiscal_epos_print/i18n/it.po
@@ -0,0 +1,152 @@
+# Translation of Odoo Server.
+# This file contains the translation of the following modules:
+# * fiscal_epos_print
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Odoo Server 12.0\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2019-10-29 10:20+0000\n"
+"PO-Revision-Date: 2019-10-29 10:20+0000\n"
+"Last-Translator: <>\n"
+"Language-Team: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: \n"
+"Plural-Forms: \n"
+
+#. module: fiscal_epos_print
+#. openerp-web
+#: code:addons/fiscal_epos_print/static/src/js/fp90iii.js:32
+#, python-format
+msgid "\n"
+"Old files: "
+msgstr "\nFile vecchi: "
+
+#. module: fiscal_epos_print
+#. openerp-web
+#: code:addons/fiscal_epos_print/static/src/js/fp90iii.js:32
+#, python-format
+msgid "\n"
+"Rejected files: "
+msgstr "\nFile rifiutati: "
+
+#. module: fiscal_epos_print
+#. openerp-web
+#: code:addons/fiscal_epos_print/static/src/xml/pos.xml:6
+#, python-format
+msgid "ADE status"
+msgstr "Stato ADE"
+
+#. module: fiscal_epos_print
+#: selection:account.journal,fiscalprinter_payment_type:0
+msgid "Cash"
+msgstr "Contanti"
+
+#. module: fiscal_epos_print
+#: selection:account.journal,fiscalprinter_payment_type:0
+msgid "Cheque"
+msgstr "Assegni"
+
+#. module: fiscal_epos_print
+#. openerp-web
+#: code:addons/fiscal_epos_print/static/src/js/fp90iii.js:260
+#, python-format
+msgid "Connecting to the fiscal printer"
+msgstr "Connessione alla stampante fiscale"
+
+#. module: fiscal_epos_print
+#: selection:account.journal,fiscalprinter_payment_type:0
+msgid "Credit/Credit Card"
+msgstr "Carta di credito"
+
+#. module: fiscal_epos_print
+#: model:ir.model.fields,field_description:fiscal_epos_print.field_account_tax__fpdeptax
+msgid "Department group tax on fiscal printer 1~99"
+msgstr "Reparto sulla stampante fiscale 1~99"
+
+#. module: fiscal_epos_print
+#. openerp-web
+#: code:addons/fiscal_epos_print/static/src/js/fp90iii.js:24
+#, python-format
+msgid "Error missing paper."
+msgstr "Errore Manca La carta."
+
+#. module: fiscal_epos_print
+#. openerp-web
+#: code:addons/fiscal_epos_print/static/src/js/fp90iii.js:32
+#, python-format
+msgid "Files waiting to be sent: "
+msgstr "File in attesa di essere inviati: "
+
+#. module: fiscal_epos_print
+#: model_terms:ir.ui.view,arch_db:fiscal_epos_print.view_pos_config_printer_form
+msgid "Fiscal printer"
+msgstr "Stampante fiscale"
+
+#. module: fiscal_epos_print
+#: model:ir.model,name:fiscal_epos_print.model_account_journal
+msgid "Journal"
+msgstr "Registro"
+
+#. module: fiscal_epos_print
+#. openerp-web
+#: code:addons/fiscal_epos_print/static/src/js/fp90iii.js:39
+#, python-format
+msgid "Network error. Printer can not be reached"
+msgstr "Errore di rete. La stampante non può essere raggiunta"
+
+#. module: fiscal_epos_print
+#. openerp-web
+#: code:addons/fiscal_epos_print/static/src/js/fp90iii.js:162
+#, python-format
+msgid "No taxes found"
+msgstr "Nessuna imposta trovata"
+
+#. module: fiscal_epos_print
+#: model:ir.model.fields,field_description:fiscal_epos_print.field_account_journal__fiscalprinter_payment_type
+msgid "Payment type"
+msgstr "Tipo di pagamento"
+
+#. module: fiscal_epos_print
+#: model:ir.model,name:fiscal_epos_print.model_pos_config
+msgid "Point of Sale Configuration"
+msgstr "Configurazione punto vendita"
+
+#. module: fiscal_epos_print
+#: model:ir.model.fields,field_description:fiscal_epos_print.field_pos_config__printer_ip
+msgid "Printer IP Address"
+msgstr "Indirizzo IP stampante"
+
+#. module: fiscal_epos_print
+#. openerp-web
+#: code:addons/fiscal_epos_print/static/src/xml/pos.xml:6
+#, python-format
+msgid "Status of files to be sent to ADE"
+msgstr "Stato dei file da inviare all'ADE"
+
+#. module: fiscal_epos_print
+#: model:ir.model,name:fiscal_epos_print.model_account_tax
+msgid "Tax"
+msgstr "Imposta"
+
+#. module: fiscal_epos_print
+#: model:ir.model.fields,help:fiscal_epos_print.field_pos_config__printer_ip
+msgid "The hostname or ip address of the hardware printer, please fill this field if you want use you receipts printer"
+msgstr ""
+
+#. module: fiscal_epos_print
+#: model:ir.model.fields,help:fiscal_epos_print.field_account_journal__fiscalprinter_payment_type
+msgid "The payment type to send to the Fiscal Printer."
+msgstr ""
+
+#. module: fiscal_epos_print
+#: selection:account.journal,fiscalprinter_payment_type:0
+msgid "Ticket"
+msgstr ""
+
+#. module: fiscal_epos_print
+#: model:ir.model.fields,field_description:fiscal_epos_print.field_pos_config__use_https
+msgid "Use https"
+msgstr "Usa HTTPS"
+
diff --git a/fiscal_epos_print/models/__init__.py b/fiscal_epos_print/models/__init__.py
new file mode 100644
index 000000000000..e58ce761f35d
--- /dev/null
+++ b/fiscal_epos_print/models/__init__.py
@@ -0,0 +1,4 @@
+from . import account_journal
+from . import point_of_sale
+from . import account
+from . import product
diff --git a/fiscal_epos_print/models/account.py b/fiscal_epos_print/models/account.py
new file mode 100644
index 000000000000..1833ddd6de93
--- /dev/null
+++ b/fiscal_epos_print/models/account.py
@@ -0,0 +1,10 @@
+from odoo import fields, models
+
+
+class AccountTax(models.Model):
+ _inherit = 'account.tax'
+
+ fpdeptax = fields.Char(
+ 'Department group tax on fiscal printer 1~99',
+ size=1, default="1"
+ )
diff --git a/fiscal_epos_print/models/account_journal.py b/fiscal_epos_print/models/account_journal.py
new file mode 100644
index 000000000000..1403b7ad5c2a
--- /dev/null
+++ b/fiscal_epos_print/models/account_journal.py
@@ -0,0 +1,16 @@
+from odoo import fields, models
+
+
+class AccountJournal(models.Model):
+ _inherit = 'account.journal'
+ fiscalprinter_payment_type = fields.Selection(
+ [
+ ('0', 'Cash'),
+ ('1', 'Cheque'),
+ ('2', 'Credit/Credit Card'),
+ ('3', 'Ticket')
+ ],
+ 'Payment type',
+ help='The payment type to send to the Fiscal Printer.',
+ default='0'
+ )
diff --git a/fiscal_epos_print/models/point_of_sale.py b/fiscal_epos_print/models/point_of_sale.py
new file mode 100644
index 000000000000..8a48ebfe3fa9
--- /dev/null
+++ b/fiscal_epos_print/models/point_of_sale.py
@@ -0,0 +1,16 @@
+from odoo import fields, models
+
+
+class PosConfig(models.Model):
+ _inherit = 'pos.config'
+
+ printer_ip = fields.Char(
+ 'Printer IP Address',
+ help='The hostname or ip address of the hardware printer, '
+ 'please fill this field if you want use you receipts printer',
+ size=45
+ )
+ use_https = fields.Boolean(
+ string='Use https',
+ default=False,
+ )
diff --git a/fiscal_epos_print/models/product.py b/fiscal_epos_print/models/product.py
new file mode 100644
index 000000000000..d6472dec9972
--- /dev/null
+++ b/fiscal_epos_print/models/product.py
@@ -0,0 +1,17 @@
+from odoo import models, api, _
+from odoo.exceptions import ValidationError
+
+
+class Product(models.Model):
+ _inherit = 'product.template'
+
+ @api.constrains('available_in_pos', 'taxes_id')
+ def _check_pos_prod_taxes(self):
+ if self.available_in_pos:
+ if len(self.taxes_id) != 1:
+ raise ValidationError(
+ _("Product %s must have 1 tax") % self.display_name)
+ if not self.taxes_id[0].price_include:
+ raise ValidationError(
+ _("Tax %s must be included in price")
+ % self.taxes_id[0].display_name)
diff --git a/fiscal_epos_print/readme/CONFIGURE.rst b/fiscal_epos_print/readme/CONFIGURE.rst
new file mode 100644
index 000000000000..9ed99d8d874e
--- /dev/null
+++ b/fiscal_epos_print/readme/CONFIGURE.rst
@@ -0,0 +1,6 @@
+- print list departments of your fiscal printer
+- mapping odoo sale taxes with group taxes - departments of fiscal printer, for each sale tax on odoo, using field "Department group tax on fiscal printer 1~99"
+- In odoo, use taxes included in price
+- connect your fiscal printer on network and find IP
+- open point_of_sale configuration and fill Printer IP Address field, with printer IP
+- that's all, at validation of payment on POS session system print fiscal receipt.
diff --git a/fiscal_epos_print/readme/CONTRIBUTORS.rst b/fiscal_epos_print/readme/CONTRIBUTORS.rst
new file mode 100644
index 000000000000..bfba346293a9
--- /dev/null
+++ b/fiscal_epos_print/readme/CONTRIBUTORS.rst
@@ -0,0 +1,4 @@
+* Leonardo Donelli
+* Lorenzo Battistini
+* Alessio Gerace
+* Roberto Fichera
diff --git a/fiscal_epos_print/readme/DESCRIPTION.rst b/fiscal_epos_print/readme/DESCRIPTION.rst
new file mode 100644
index 000000000000..6eafa67be6fb
--- /dev/null
+++ b/fiscal_epos_print/readme/DESCRIPTION.rst
@@ -0,0 +1,7 @@
+This module allows to print receipt of point_of_sale,
+on fiscal printer Epson via EPos protocol.
+
+Supported printers:
+
+- FP81II
+- FP90III
diff --git a/fiscal_epos_print/static/lib/fiscalprint/fiscalprint.js b/fiscal_epos_print/static/lib/fiscalprint/fiscalprint.js
new file mode 100644
index 000000000000..5fc128e5ca6b
--- /dev/null
+++ b/fiscal_epos_print/static/lib/fiscalprint/fiscalprint.js
@@ -0,0 +1,1435 @@
+//
+// ePOS-Print and Fiscal Print API
+//
+// Version 1.0.0
+//
+// Copyright (C) SEIKO EPSON CORPORATION 2012. All rights reserved.
+//
+
+(function (window)
+{
+ //
+ // Function: ePOSBuilder constructor
+ // Description: initialize an ePOS-Print XML Builder object
+ // Parameters: none
+ // Return: none
+ //
+ function ePOSBuilder() {
+ // properties
+ this.message = '';
+ // constants
+ this.FONT_A = 'font_a';
+ this.FONT_B = 'font_b';
+ this.FONT_C = 'font_c';
+ this.FONT_SPECIAL_A = 'special_a';
+ this.FONT_SPECIAL_B = 'special_b';
+ this.ALIGN_LEFT = 'left';
+ this.ALIGN_CENTER = 'center';
+ this.ALIGN_RIGHT = 'right';
+ this.COLOR_NONE = 'none';
+ this.COLOR_1 = 'color_1';
+ this.COLOR_2 = 'color_2';
+ this.COLOR_3 = 'color_3';
+ this.COLOR_4 = 'color_4';
+ this.BARCODE_UPC_A = 'upc_a';
+ this.BARCODE_UPC_E = 'upc_e';
+ this.BARCODE_EAN13 = 'ean13';
+ this.BARCODE_JAN13 = 'jan13';
+ this.BARCODE_EAN8 = 'ean8';
+ this.BARCODE_JAN8 = 'jan8';
+ this.BARCODE_CODE39 = 'code39';
+ this.BARCODE_ITF = 'itf';
+ this.BARCODE_CODABAR = 'codabar';
+ this.BARCODE_CODE93 = 'code93';
+ this.BARCODE_CODE128 = 'code128';
+ this.BARCODE_GS1_128 = 'gs1_128';
+ this.BARCODE_GS1_DATABAR_OMNIDIRECTIONAL = 'gs1_databar_omnidirectional';
+ this.BARCODE_GS1_DATABAR_TRUNCATED = 'gs1_databar_truncated';
+ this.BARCODE_GS1_DATABAR_LIMITED = 'gs1_databar_limited';
+ this.BARCODE_GS1_DATABAR_EXPANDED = 'gs1_databar_expanded';
+ this.HRI_NONE = 'none';
+ this.HRI_ABOVE = 'above';
+ this.HRI_BELOW = 'below';
+ this.HRI_BOTH = 'both';
+ this.SYMBOL_PDF417_STANDARD = 'pdf417_standard';
+ this.SYMBOL_PDF417_TRUNCATED = 'pdf417_truncated';
+ this.SYMBOL_QRCODE_MODEL_1 = 'qrcode_model_1';
+ this.SYMBOL_QRCODE_MODEL_2 = 'qrcode_model_2';
+ this.SYMBOL_MAXICODE_MODE_2 = 'maxicode_mode_2';
+ this.SYMBOL_MAXICODE_MODE_3 = 'maxicode_mode_3';
+ this.SYMBOL_MAXICODE_MODE_4 = 'maxicode_mode_4';
+ this.SYMBOL_MAXICODE_MODE_5 = 'maxicode_mode_5';
+ this.SYMBOL_MAXICODE_MODE_6 = 'maxicode_mode_6';
+ this.SYMBOL_GS1_DATABAR_STACKED = 'gs1_databar_stacked';
+ this.SYMBOL_GS1_DATABAR_STACKED_OMNIDIRECTIONAL = 'gs1_databar_stacked_omnidirectional';
+ this.SYMBOL_GS1_DATABAR_EXPANDED_STACKED = 'gs1_databar_expanded_stacked';
+ this.LEVEL_0 = 'level_0';
+ this.LEVEL_1 = 'level_1';
+ this.LEVEL_2 = 'level_2';
+ this.LEVEL_3 = 'level_3';
+ this.LEVEL_4 = 'level_4';
+ this.LEVEL_5 = 'level_5';
+ this.LEVEL_6 = 'level_6';
+ this.LEVEL_7 = 'level_7';
+ this.LEVEL_8 = 'level_8';
+ this.LEVEL_L = 'level_l';
+ this.LEVEL_M = 'level_m';
+ this.LEVEL_Q = 'level_q';
+ this.LEVEL_H = 'level_h';
+ this.LEVEL_DEFAULT = 'default';
+ this.LINE_THIN = 'thin';
+ this.LINE_MEDIUM = 'medium';
+ this.LINE_THICK = 'thick';
+ this.LINE_THIN_DOUBLE = 'thin_double';
+ this.LINE_MEDIUM_DOUBLE = 'medium_double';
+ this.LINE_THICK_DOUBLE = 'thick_double';
+ this.DIRECTION_LEFT_TO_RIGHT = 'left_to_right';
+ this.DIRECTION_BOTTOM_TO_TOP = 'bottom_to_top';
+ this.DIRECTION_RIGHT_TO_LEFT = 'right_to_left';
+ this.DIRECTION_TOP_TO_BOTTOM = 'top_to_bottom';
+ this.CUT_NO_FEED = 'no_feed';
+ this.CUT_FEED = 'feed';
+ this.CUT_RESERVE = 'reserve';
+ this.DRAWER_1 = 'drawer_1';
+ this.DRAWER_2 = 'drawer_2';
+ this.PULSE_100 = 'pulse_100';
+ this.PULSE_200 = 'pulse_200';
+ this.PULSE_300 = 'pulse_300';
+ this.PULSE_400 = 'pulse_400';
+ this.PULSE_500 = 'pulse_500';
+ this.PATTERN_NONE = 'none';
+ this.PATTERN_A = 'pattern_a';
+ this.PATTERN_B = 'pattern_b';
+ this.PATTERN_C = 'pattern_c';
+ this.PATTERN_D = 'pattern_d';
+ this.PATTERN_E = 'pattern_e';
+ this.PATTERN_ERROR = 'error';
+ this.PATTERN_PAPER_END = 'paper_end';
+ }
+
+ //
+ // Function: addFeedUnit method
+ // Description: append the XML element to print and feed paper
+ // Parameters:
+ // unit unsignedbyte paper feed amount (units)
+ // Return: object ePOSBuilder object
+ // Throws: object invalid parameter
+ //
+ ePOSBuilder.prototype.addFeedUnit = function (unit) {
+ // create empty string
+ var s = '';
+ // check parameter
+ s += getUByteAttr('unit', unit);
+ // append element
+ this.message += ' ';
+ // return builder object
+ return this;
+ }
+
+ //
+ // Function: addFeedLine method
+ // Description: append the XML element to print and feed n lines
+ // Parameters:
+ // line unsignedbyte paper feed amount (lines)
+ // Return: object ePOSBuilder object
+ // Throws: object invalid parameter
+ //
+ ePOSBuilder.prototype.addFeedLine = function (line) {
+ // create empty string
+ var s = '';
+ // check parameter
+ s += getUByteAttr('line', line);
+ // append element
+ this.message += ' ';
+ // return builder object
+ return this;
+ }
+
+ //
+ // Function: addText method
+ // Description: append the XML element to print characters
+ // Parameters:
+ // data string characters
+ // Return: object ePOSBuilder object
+ //
+ ePOSBuilder.prototype.addText = function (data) {
+ // append element
+ this.message += '' + encodeXmlEntity(data) + ' ';
+ // return builder object
+ return this;
+ }
+
+ //
+ // Function: addTextLang method
+ // Description: append the XML element to select language
+ // Parameters:
+ // lang string language code and country code (en, en-US, ja, ja-JP, etc.)
+ // Return: object ePOSBuilder object
+ //
+ ePOSBuilder.prototype.addTextLang = function (lang) {
+ // append element
+ this.message += ' ';
+ // return builder object
+ return this;
+ }
+
+ //
+ // Function: addTextAlign method
+ // Description: append the XML element to set alignment
+ // Parameters:
+ // align string alignment (ALIGN_* constants)
+ // Return: object ePOSBuilder object
+ // Throws: object invalid parameter
+ //
+ ePOSBuilder.prototype.addTextAlign = function (align) {
+ // create empty string
+ var s = '';
+ // check parameter
+ s += getEnumAttr('align', align, regexAlign);
+ // append element
+ this.message += ' ';
+ // return builder object
+ return this;
+ }
+
+ //
+ // Function: addTextRotate method
+ // Description: append the XML element to turn upside-down print mode on/off
+ // Parameters:
+ // rotate boolean when true, upside-down print mode is turned on
+ // Return: object ePOSBuilder object
+ // Throws: object invalid parameter
+ //
+ ePOSBuilder.prototype.addTextRotate = function (rotate) {
+ // create empty string
+ var s = '';
+ // check parameter
+ s += getBoolAttr('rotate', rotate);
+ // append element
+ this.message += ' ';
+ // return builder object
+ return this;
+ }
+
+ //
+ // Function: addTextLineSpace method
+ // Description: append the XML element to set line spacing
+ // Parameters:
+ // linespc unsignedByte the amount of line spacing
+ // Return: object ePOSBuilder object
+ // Throws: object invalid parameter
+ //
+ ePOSBuilder.prototype.addTextLineSpace = function (linespc) {
+ // create empty string
+ var s = '';
+ // check parameter
+ s += getUByteAttr('linespc', linespc);
+ // append element
+ this.message += ' ';
+ // return builder object
+ return this;
+ }
+
+ //
+ // Function: addTextFont method
+ // Description: append the XML element to select character font
+ // Parameters:
+ // font string font (FONT_* constants)
+ // Return: object ePOSBuilder object
+ // Throws: object invalid parameter
+ //
+ ePOSBuilder.prototype.addTextFont = function (font) {
+ // create empty string
+ var s = '';
+ // check parameter
+ s += getEnumAttr('font', font, regexFont);
+ // append element
+ this.message += ' ';
+ // return builder object
+ return this;
+ }
+
+ //
+ // Function: addTextSmooth method
+ // Description: append the XML element to turn smoothing mode on/off
+ // Parameters:
+ // smooth boolean when true, smoothing mode is turned on
+ // Return: object ePOSBuilder object
+ // Throws: object invalid parameter
+ //
+ ePOSBuilder.prototype.addTextSmooth = function (smooth) {
+ // create empty string
+ var s = '';
+ // check parameter
+ s += getBoolAttr('smooth', smooth);
+ // append element
+ this.message += ' ';
+ // return builder object
+ return this;
+ }
+
+ //
+ // Function: addTextDouble method
+ // Description: append the XML element to turn double-wide/double-high mode on/off
+ // Parameters:
+ // dw boolean when true, double-wide mode is turned on [option]
+ // dh boolean when true, double-high mode is turned on [option]
+ // Return: object ePOSBuilder object
+ // Throws: object invalid parameter
+ //
+ ePOSBuilder.prototype.addTextDouble = function (dw, dh) {
+ // create empty string
+ var s = '';
+ // check parameter (option)
+ if (dw !== undefined) {
+ s += getBoolAttr('dw', dw);
+ }
+ // check parameter (option)
+ if (dh !== undefined) {
+ s += getBoolAttr('dh', dh);
+ }
+ // append element
+ this.message += ' ';
+ // return builder object
+ return this;
+ }
+
+ //
+ // Function: addTextSize method
+ // Description: append the XML element to select character size
+ // Parameters:
+ // width unsignedByte character width (1 to 8) [option]
+ // height unsignedByte character height (1 to 8) [option]
+ // Return: object ePOSBuilder object
+ // Throws: object invalid parameter
+ //
+ ePOSBuilder.prototype.addTextSize = function (width, height) {
+ // create empty string
+ var s = '';
+ // check parameter (option)
+ if (width !== undefined) {
+ s += getIntAttr('width', width, 1, 8);
+ }
+ // check parameter (option)
+ if (height !== undefined) {
+ s += getIntAttr('height', height, 1, 8);
+ }
+ // append element
+ this.message += ' ';
+ // return builder object
+ return this;
+ }
+
+ //
+ // Function: addTextStyle method
+ // Description: append the XML element to select character style
+ // Parameters:
+ // reverse boolean when true, black/white reverse print mode is turned on [option]
+ // ul boolean when true, underline mode is turned on [option]
+ // em boolean when true, emphasized mode is turned on [option]
+ // color string color (COLOR_* constants) [option]
+ // Return: object ePOSBuilder object
+ // Throws: object invalid parameter
+ //
+ ePOSBuilder.prototype.addTextStyle = function (reverse, ul, em, color) {
+ // create empty string
+ var s = '';
+ // check parameter (option)
+ if (reverse !== undefined) {
+ s += getBoolAttr('reverse', reverse);
+ }
+ // check parameter (option)
+ if (ul !== undefined) {
+ s += getBoolAttr('ul', ul);
+ }
+ // check parameter (option)
+ if (em !== undefined) {
+ s += getBoolAttr('em', em);
+ }
+ // check parameter (option)
+ if (color !== undefined) {
+ s += getEnumAttr('color', color, regexColor);
+ }
+ // append element
+ this.message += ' ';
+ // return builder object
+ return this;
+ }
+
+ //
+ // Function: addTextPosition method
+ // Description: append the XML element to set absolute print position
+ // Parameters:
+ // x unsignedShort X start position
+ // Return: object ePOSBuilder object
+ // Throws: object invalid parameter
+ //
+ ePOSBuilder.prototype.addTextPosition = function (x) {
+ // create empty string
+ var s = '';
+ // check parameter
+ s += getUShortAttr('x', x);
+ // append element
+ this.message += ' ';
+ // return builder object
+ return this;
+ }
+
+ //
+ // Function: addImage method
+ // Description: append the XML element to print the graphics data (raster format)
+ // Parameters:
+ // context object the 2-D context of HTML 5 Canvas
+ // x unsignedShort X start position
+ // y unsignedShort Y start position
+ // width unsignedShort horizontal size
+ // height unsignedShort vertical size
+ // color string color (COLOR_* constants) [option]
+ // Return: object ePOSBuilder object
+ // Throws: object invalid parameter
+ //
+ ePOSBuilder.prototype.addImage = function (context, x, y, width, height, color) {
+ // create empty string
+ var s = '';
+ // check parameter
+ getUShortAttr('x', x);
+ // check parameter
+ getUShortAttr('y', y);
+ // check parameter
+ s += getUShortAttr('width', width);
+ // check parameter
+ s += getUShortAttr('height', height);
+ // check parameter (option)
+ if (color !== undefined) {
+ s += getEnumAttr('color', color, regexColor);
+ }
+ // create image data
+ var image = encodeRasterImage(context.getImageData(x, y, width, height).data, width, height);
+ // append element
+ this.message += '' + encodeBase64Binary(image) + ' ';
+ // return builder object
+ return this;
+ }
+
+ //
+ // Function: addLogo method
+ // Description: append the XML element to print specified NV graphics data
+ // Parameters:
+ // key1 unsignedShort key code 1
+ // key2 unsignedShort key code 2
+ // Return: object ePOSBuilder object
+ // Throws: object invalid parameter
+ //
+ ePOSBuilder.prototype.addLogo = function (key1, key2) {
+ // create empty string
+ var s = '';
+ // check parameter
+ s += getUByteAttr('key1', key1);
+ // check parameter
+ s += getUByteAttr('key2', key2);
+ // append element
+ this.message += ' ';
+ // return builder object
+ return this;
+ }
+
+ //
+ // Function: addBarcode method
+ // Description: append the XML element to print bar code
+ // Parameters:
+ // data object bar code data (characters, escape sequences '\xnn', '\\')
+ // type string bar code type (BARCODE_* constants)
+ // hri string print position of HRI characters (HRI_* constants) [option]
+ // font string font for HRI characters (FONT_* constants) [option]
+ // width unsignedByte bar code module width [option]
+ // height unsignedByte bar code module height [option]
+ // Return: object ePOSBuilder object
+ // Throws: object invalid parameter
+ //
+ ePOSBuilder.prototype.addBarcode = function (data, type, hri, font, width, height) {
+ // create empty string
+ var s = '';
+ // check parameter
+ s += getEnumAttr('type', type, regexBarcode);
+ // check parameter (option)
+ if (hri !== undefined) {
+ s += getEnumAttr('hri', hri, regexHri);
+ }
+ // check parameter (option)
+ if (font !== undefined) {
+ s += getEnumAttr('font', font, regexFont);
+ }
+ // check parameter (option)
+ if (width !== undefined) {
+ s += getUByteAttr('width', width);
+ }
+ // check parameter (option)
+ if (height !== undefined) {
+ s += getUByteAttr('height', height);
+ }
+ // append element
+ this.message += '' + escapeText(encodeXmlEntity(data)) + ' ';
+ // return builder object
+ return this;
+ }
+
+ //
+ // Function: addSymbol method
+ // Description: append the XML element to print two dimension code
+ // Parameters:
+ // data object symbol data (characters, escape sequences '\xnn', '\\')
+ // type string symbol type (SYMBOL_* constants)
+ // level string error correction level (LEVEL_* constants) [option]
+ // width unsignedByte module width (PDF417, QR Code, GS1 DataBar) [option]
+ // height unsignedByte module height (PDF417) [option]
+ // size unsignedShort the number of columns (PDF417), maximum width (GS1 DataBar) [option]
+ // Return: object ePOSBuilder object
+ // Throws: object invalid parameter
+ //
+ ePOSBuilder.prototype.addSymbol = function (data, type, level, width, height, size) {
+ // create empty string
+ var s = '';
+ // check parameter
+ s += getEnumAttr('type', type, regexSymbol);
+ // check parameter (option)
+ if (level !== undefined) {
+ s += getEnumAttr('level', level, regexLevel);
+ }
+ // check parameter (option)
+ if (width !== undefined) {
+ s += getUByteAttr('width', width);
+ }
+ // check parameter (option)
+ if (height !== undefined) {
+ s += getUByteAttr('height', height);
+ }
+ // check parameter (option)
+ if (size !== undefined) {
+ s += getUShortAttr('size', size);
+ }
+ // append element
+ this.message += '' + escapeText(encodeXmlEntity(data)) + ' ';
+ // return builder object
+ return this;
+ }
+
+ //
+ // Function: addCommand method
+ // Description: append the XML element to send commands
+ // Parameters:
+ // data string commands
+ // Return: object ePOSBuilder object
+ //
+ ePOSBuilder.prototype.addCommand = function (data) {
+ // append element
+ this.message += '' + encodeHexBinary(data) + ' ';
+ // return builder object
+ return this;
+ }
+
+ //
+ // Function: addHLine method
+ // Description: append the XML element to draw horizontal line
+ // Parameters:
+ // x1 unsignedShort X start position
+ // x2 unsignedShort X end position
+ // style string the style of line (LINE_* constants) [option]
+ // Return: object ePOSBuilder object
+ // Throws: object invalid parameter
+ //
+ ePOSBuilder.prototype.addHLine = function (x1, x2, style) {
+ // create empty string
+ var s = '';
+ // check parameter
+ s += getUShortAttr('x1', x1);
+ // check parameter
+ s += getUShortAttr('x2', x2);
+ // check parameter (option)
+ if (style !== undefined) {
+ s += getEnumAttr('style', style, regexLine);
+ }
+ // append element
+ this.message += ' ';
+ // return builder object
+ return this;
+ }
+
+ //
+ // Function: addVLineBegin method
+ // Description: append the XML element to draw vertical line
+ // Parameters:
+ // x unsignedShort X start position
+ // style string the style of line (LINE_* constants) [option]
+ // Return: object ePOSBuilder object
+ // Throws: object invalid parameter
+ //
+ ePOSBuilder.prototype.addVLineBegin = function (x, style) {
+ // create empty string
+ var s = '';
+ // check parameter
+ s += getUShortAttr('x', x);
+ // check parameter (option)
+ if (style !== undefined) {
+ s += getEnumAttr('style', style, regexLine);
+ }
+ // append element
+ this.message += ' ';
+ // return builder object
+ return this;
+ }
+
+ //
+ // Function: addVLineEnd method
+ // Description: append the XML element to draw vertical line
+ // Parameters:
+ // x unsignedShort X end position
+ // style string the style of line (LINE_* constants) [option]
+ // Return: object ePOSBuilder object
+ // Throws: object invalid parameter
+ //
+ ePOSBuilder.prototype.addVLineEnd = function (x, style) {
+ // create empty string
+ var s = '';
+ // check parameter
+ s += getUShortAttr('x', x);
+ // check parameter (option)
+ if (style !== undefined) {
+ s += getEnumAttr('style', style, regexLine);
+ }
+ // append element
+ this.message += ' ';
+ // return builder object
+ return this;
+ }
+
+ //
+ // Function: addPageBegin method
+ // Description: append the XML element to select page mode
+ // Parameters: none
+ // Return: object ePOSBuilder object
+ //
+ ePOSBuilder.prototype.addPageBegin = function () {
+ // append element
+ this.message += '';
+ // return builder object
+ return this;
+ }
+
+ //
+ // Function: addPageEnd method
+ // Description: append the XML element to print and return to standard mode (in page mode)
+ // Parameters: none
+ // Return: object ePOSBuilder object
+ //
+ ePOSBuilder.prototype.addPageEnd = function () {
+ // append element
+ this.message += ' ';
+ // return builder object
+ return this;
+ }
+
+ //
+ // Function: addPageArea method
+ // Description: append the XML element to set print area in page mode
+ // Parameters:
+ // x unsignedShort horizontal logical origin
+ // y unsignedShort vertical logical origin
+ // width unsignedShort print area width
+ // height unsignedShort print area height
+ // Return: object ePOSBuilder object
+ // Throws: object invalid parameter
+ //
+ ePOSBuilder.prototype.addPageArea = function (x, y, width, height) {
+ // create empty string
+ var s = '';
+ // check parameter
+ s += getUShortAttr('x', x);
+ // check parameter
+ s += getUShortAttr('y', y);
+ // check parameter
+ s += getUShortAttr('width', width);
+ // check parameter
+ s += getUShortAttr('height', height);
+ // append element
+ this.message += ' ';
+ // return builder object
+ return this;
+ }
+
+ //
+ // Function: addPageDirection method
+ // Description: append the XML element to select print direction in page mode
+ // Parameters:
+ // dir string direction (DIRECTION_* constants)
+ // Return: object ePOSBuilder object
+ // Throws: object invalid parameter
+ //
+ ePOSBuilder.prototype.addPageDirection = function (dir) {
+ // create empty string
+ var s = '';
+ // check parameter
+ s += getEnumAttr('dir', dir, regexDirection);
+ // append element
+ this.message += ' ';
+ // return builder object
+ return this;
+ }
+
+ //
+ // Function: addPagePosition method
+ // Description: append the XML element to set absolute print position in page mode
+ // Parameters:
+ // x unsignedShort horizontal position
+ // y unsignedShort vertical position
+ // Return: object ePOSBuilder object
+ // Throws: object invalid parameter
+ //
+ ePOSBuilder.prototype.addPagePosition = function (x, y) {
+ // create empty string
+ var s = '';
+ // check parameter
+ s += getUShortAttr('x', x);
+ // check parameter
+ s += getUShortAttr('y', y);
+ // append element
+ this.message += ' ';
+ // return builder object
+ return this;
+ }
+
+ //
+ // Function: addPageLine method
+ // Description: append the XML element to draw line in page mode
+ // Parameters:
+ // x1 unsignedShort X start position
+ // y1 unsignedShort Y start position
+ // x2 unsignedShort X end position
+ // y2 unsignedShort Y end position
+ // style string the style of line (LINE_* constants) [option]
+ // Return: object ePOSBuilder object
+ // Throws: object invalid parameter
+ //
+ ePOSBuilder.prototype.addPageLine = function (x1, y1, x2, y2, style) {
+ // create empty string
+ var s = '';
+ // check parameter
+ s += getUShortAttr('x1', x1);
+ // check parameter
+ s += getUShortAttr('y1', y1);
+ // check parameter
+ s += getUShortAttr('x2', x2);
+ // check parameter
+ s += getUShortAttr('y2', y2);
+ // check parameter (option)
+ if (style !== undefined) {
+ s += getEnumAttr('style', style, regexLine);
+ }
+ // append element
+ this.message += ' ';
+ // return builder object
+ return this;
+ }
+
+ //
+ // Function: addPageRectangle method
+ // Description: append the XML element to draw rectangle in page mode
+ // Parameters:
+ // x1 unsignedShort X start position
+ // y1 unsignedShort Y start position
+ // x2 unsignedShort X end position
+ // y2 unsignedShort Y end position
+ // style string the style of line (LINE_* constants) [option]
+ // Return: object ePOSBuilder object
+ // Throws: object invalid parameter
+ //
+ ePOSBuilder.prototype.addPageRectangle = function (x1, y1, x2, y2, style) {
+ // create empty string
+ var s = '';
+ // check parameter
+ s += getUShortAttr('x1', x1);
+ // check parameter
+ s += getUShortAttr('y1', y1);
+ // check parameter
+ s += getUShortAttr('x2', x2);
+ // check parameter
+ s += getUShortAttr('y2', y2);
+ // check parameter (option)
+ if (style !== undefined) {
+ s += getEnumAttr('style', style, regexLine);
+ }
+ // append element
+ this.message += ' ';
+ // return builder object
+ return this;
+ }
+
+ //
+ // Function: addCut method
+ // Description: append the XML element to cut paper
+ // Parameters:
+ // type string cut mode (CUT_* constants) [option]
+ // Return: object ePOSBuilder object
+ // Throws: object invalid parameter
+ //
+ ePOSBuilder.prototype.addCut = function (type) {
+ // create empty string
+ var s = '';
+ // check parameter (option)
+ if (type !== undefined) {
+ s += getEnumAttr('type', type, regexCut);
+ }
+ // append element
+ this.message += ' ';
+ // return builder object
+ return this;
+ }
+
+ //
+ // Function: addPulse method
+ // Description: append the XML element to generate pulse
+ // Parameters:
+ // drawer string drawer kick-out connector pin (DRAWER_* constants) [option]
+ // time string the pulse on/off time [option]
+ // Return: object ePOSBuilder object
+ // Throws: object invalid parameter
+ //
+ ePOSBuilder.prototype.addPulse = function (drawer, time) {
+ // create empty string
+ var s = '';
+ // check parameter (option)
+ if (drawer !== undefined) {
+ s += getEnumAttr('drawer', drawer, regexDrawer);
+ }
+ // check parameter (option)
+ if (time !== undefined) {
+ s += getEnumAttr('time', time, regexPulse);
+ }
+ // append element
+ this.message += ' ';
+ // return builder object
+ return this;
+ }
+
+ //
+ // Function: addSound method
+ // Description: append the XML element to sound buzzer
+ // Parameters:
+ // pattern string a pattern (PATTERN_* constants) [option]
+ // repeat unsignedByte the number of times [option]
+ // Return: object ePOSBuilder object
+ // Throws: object invalid parameter
+ //
+ ePOSBuilder.prototype.addSound = function (pattern, repeat) {
+ // create empty string
+ var s = '';
+ // check parameter (option)
+ if (pattern !== undefined) {
+ s += getEnumAttr('pattern', pattern, regexPattern);
+ }
+ // check parameter (option)
+ if (repeat !== undefined) {
+ s += getUByteAttr('repeat', repeat);
+ }
+ // append element
+ this.message += ' ';
+ // return builder object
+ return this;
+ }
+
+ //
+ // Method: toString
+ // Description: get the ePOS-Print XML message
+ // Parameters: none
+ // Return: string XML message
+ //
+ ePOSBuilder.prototype.toString = function () {
+ // append root element
+ var epos = '' +
+ this.message + ' ';
+ // return message
+ return epos;
+ }
+
+ //
+ // Function: encodeHexBinary method
+ // Description: encode binary data to hex binary data
+ // Parameters:
+ // s string binary data
+ // Return: string hex binary data
+ //
+ function encodeHexBinary(s) {
+ var r = '';
+ for (i = 0; i < s.length; i++) {
+ r += ('0' + s.charCodeAt(i).toString(16)).slice(-2);
+ }
+ return r;
+ }
+
+ //
+ // Function: encodeBase64Binary method
+ // Description: encode binary data to base64 binary data
+ // Parameters:
+ // s string binary data
+ // Return: string base64 binary data
+ //
+ function encodeBase64Binary(s) {
+ var r = '';
+ var l = s.length;
+ var t = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
+ s += '\x00\x00';
+ for (var i = 0; i < l; i += 3) {
+ var n = (s.charCodeAt(i) << 16) | (s.charCodeAt(i + 1) << 8) | s.charCodeAt(i + 2);
+ r += t.charAt((n >> 18) & 63) + t.charAt((n >> 12) & 63) + t.charAt((n >> 6) & 63) + t.charAt(n & 63);
+ }
+ var p = (3 - l % 3) % 3;
+ return r.slice(0, r.length - p) + '=='.slice(0, p);
+ }
+
+ //
+ // Function: encodeRasterImage method
+ // Description: encode image data to raster bit image data
+ // Parameters:
+ // data byte[] RGBA image data
+ // w int image width
+ // h int image height
+ // Return: string raster bit image data
+ //
+ function encodeRasterImage(data, w, h) {
+ var d8 = [
+ [0, 32, 8, 40, 2, 34, 10, 42],
+ [48, 16, 56, 24, 50, 18, 58, 26],
+ [12, 44, 4, 36, 14, 46, 6, 38],
+ [60, 28, 52, 20, 62, 30, 54, 22],
+ [3, 35, 11, 43, 1, 33, 9, 41],
+ [51, 19, 59, 27, 49, 17, 57, 25],
+ [15, 47, 7, 39, 13, 45, 5, 37],
+ [63, 31, 55, 23, 61, 29, 53, 21]
+ ];
+ var s = '', n = 0, p = 0;
+ for (var y = 0; y < h; y++) {
+ for (var x = 0; x < w; x++) {
+ var r = data[p++], g = data[p++], b = data[p++], a = data[p++];
+ var v = 255 - a + ((r * 29891 + g * 58661 + b * 11448) * a + 12750000) / 25500000;
+ var d = (d8[y & 7][x & 7] << 2) + 2;
+ if (v < d) {
+ n |= 0x80 >> (x & 7);
+ }
+ if ((x & 7) == 7 || x == w - 1) {
+ s += String.fromCharCode(n == 16 ? 32 : n);
+ n = 0;
+ }
+ }
+ }
+ return s;
+ }
+
+ //
+ // Function: encodeXmlEntity method
+ // Description: encode markup character to XML entity
+ // Parameters:
+ // s string text data
+ // Return: string text data with XML entity
+ //
+ function encodeXmlEntity(s) {
+ var markup = /[<>&'"\t\n\r]/g;
+ if (markup.test(s)) {
+ s = s.replace(markup, function (c) {
+ var r = '';
+ switch (c) {
+ case '<':
+ r = '<';
+ break;
+ case '>':
+ r = '>';
+ break;
+ case '&':
+ r = '&';
+ break;
+ case "'":
+ r = ''';
+ break;
+ case '"':
+ r = '"';
+ break;
+ case '\t':
+ r = ' ';
+ break;
+ case '\n':
+ r = '
';
+ break;
+ case '\r':
+ r = '
';
+ break;
+ default:
+ break;
+ }
+ return r;
+ });
+ }
+ return s;
+ }
+
+ //
+ // Function: escapeText method
+ // Description: escape sequence for bar code and symbol
+ // Parameters:
+ // s string text data
+ // Return: string text data with escape sequence
+ //
+ function escapeText(s) {
+ var escape = /[\\\x00-\x1f\x7f-\xff]/g;
+ if (escape.test(s)) {
+ s = s.replace(escape, function (c) {
+ return (c == '\\') ? '\\\\' : '\\x' + ('0' + c.charCodeAt(0).toString(16)).slice(-2);
+ });
+ }
+ return s;
+ }
+
+ //
+ // Function: regular expressions
+ // Description: enumeration check pattern
+ //
+ var regexFont = /^(font_[abc]|special_[ab])$/;
+ var regexAlign = /^(left|center|right)$/;
+ var regexColor = /^(none|color_[1-4])$/;
+ var regexBarcode = /^(upc_[ae]|[ej]an13|[ej]an8|code(39|93|128)|itf|codabar|gs1_128|gs1_databar_(omnidirectional|truncated|limited|expanded))$/;
+ var regexHri = /^(none|above|below|both)$/;
+ var regexSymbol = /^(pdf417_(standard|truncated)|qrcode_model_[12]|maxicode_mode_[2-6]|gs1_databar_(stacked(_omnidirectional)?|expanded_stacked))$/;
+ var regexLevel = /^(level_[0-8lmqh]|default)$/;
+ var regexLine = /^(thin|medium|thick)(_double)?$/;
+ var regexDirection = /^(left_to_right|bottom_to_top|right_to_left|top_to_bottom)$/;
+ var regexCut = /^(no_feed|feed|reserve)$/;
+ var regexDrawer = /^(drawer_1|drawer_2)$/;
+ var regexPulse = /^pulse_[1-5]00$/;
+ var regexPattern = /^(none|pattern_[a-e]|error|paper_end)$/;
+
+ //
+ // Function: getEnumAttr method
+ // Description: get a XML attribute from a parameter (enumration)
+ // Parameters:
+ // name string parameter name
+ // value string parameter value
+ // regex regex check pattern
+ // Return: string XML attribute (' name="value"')
+ // Throws: object invalid parameter
+ //
+ function getEnumAttr(name, value, regex) {
+ if (!regex.test(value)) {
+ throw new Error('Parameter "' + name + '" is invalid');
+ }
+ return ' ' + name + '="' + value + '"';
+ }
+
+ //
+ // Function: getBoolAttr method
+ // Description: get a XML attribute from a parameter (boolean)
+ // Parameters:
+ // name string parameter name
+ // value boolean parameter value
+ // Return: string XML attribute (' name="value"')
+ //
+ function getBoolAttr(name, value) {
+ return ' ' + name + '="' + !!value + '"';
+ }
+
+ //
+ // Function: getIntAttr method
+ // Description: get a XML attribute from a parameter (integer)
+ // Parameters:
+ // name string parameter name
+ // value integer parameter value
+ // min integer minumum value
+ // max integer maximum value
+ // Return: string XML attribute (' name="value"')
+ // Throws: object invalid parameter
+ //
+ function getIntAttr(name, value, min, max) {
+ if (isNaN(value) || value < min || value > max) {
+ throw new Error('Parameter "' + name + '" is invalid');
+ }
+ return ' ' + name + '="' + value + '"';
+ }
+
+ //
+ // Function: getUByteAttr method
+ // Description: get a XML attribute from a parameter (unsigned byte)
+ // Parameters:
+ // name string parameter name
+ // value integer parameter value
+ // Return: string XML attribute (' name="value"')
+ // Throws: object invalid parameter
+ //
+ function getUByteAttr(name, value) {
+ return getIntAttr(name, value, 0, 255);
+ }
+
+ //
+ // Function: getUShortAttr method
+ // Description: get a XML attribute from a parameter (unsigned short)
+ // Parameters:
+ // name string parameter name
+ // value integer parameter value
+ // Return: string XML attribute (' name="value"')
+ // Throws: object invalid parameter
+ //
+ function getUShortAttr(name, value) {
+ return getIntAttr(name, value, 0, 65535);
+ }
+
+ //
+ // Function: ePOSPrint constructor
+ // Description: initialize an ePOS-Print object
+ // Parameters: none
+ // Return: none
+ //
+ function ePOSPrint() {
+ // events
+ this.onreceive = null;
+ this.onerror = null;
+ // constants
+ this.ASB_NO_RESPONSE = 0x00000001;
+ this.ASB_PRINT_SUCCESS = 0x00000002;
+ this.ASB_DRAWER_KICK = 0x00000004;
+ this.ASB_OFF_LINE = 0x00000008;
+ this.ASB_COVER_OPEN = 0x00000020;
+ this.ASB_PAPER_FEED = 0x00000040;
+ this.ASB_WAIT_ON_LINE = 0x00000100;
+ this.ASB_PANEL_SWITCH = 0x00000200;
+ this.ASB_MECHANICAL_ERR = 0x00000400;
+ this.ASB_AUTOCUTTER_ERR = 0x00000800;
+ this.ASB_UNRECOVER_ERR = 0x00002000;
+ this.ASB_AUTORECOVER_ERR = 0x00004000;
+ this.ASB_RECEIPT_NEAR_END = 0x00020000;
+ this.ASB_RECEIPT_END = 0x00080000;
+ this.ASB_BUZZER = 0x01000000;
+ this.ASB_SPOOLER_IS_STOPPED = 0x80000000;
+ }
+
+ //
+ // Function: ePOSprint send method
+ // Description: send the ePOS-Print XML message
+ // Parameters:
+ // address string the address of ePOS-Print service
+ // request string request message
+ // Return: none
+ // Throws: object the browser does not equip XMLHttpRequest
+ //
+ ePOSPrint.prototype.send = function (address, request) {
+ // create SOAP envelope
+ var soap = '' +
+ '' +
+ request + ' ';
+ // create XMLHttpRequest object
+ var xhr = createXMLHttpRequest();
+ xhr.open('POST', address, true);
+ // set headers
+ xhr.setRequestHeader('Content-Type', 'text/xml; charset=UTF-8');
+ xhr.setRequestHeader('If-Modified-Since', 'Thu, 01 Jan 1970 00:00:00 GMT');
+ xhr.setRequestHeader('SOAPAction', '""');
+ // receive event
+ var epos = this;
+ xhr.onreadystatechange = function () {
+ // receive response message
+ if (xhr.readyState == 4) {
+ if (xhr.status == 200) {
+ fireReceiveEvent(epos, xhr);
+ }
+ else {
+ fireErrorEvent(epos, xhr);
+ }
+ }
+ }
+ // send request message
+ xhr.send(soap);
+ }
+
+
+ /*
+ Function: createXMLHttpRequest method
+ Description: create an XMLHttpRequest object
+ Parameters: none
+ Return: object XMLHttpRequest object
+ Throws: object the browser does not equip XMLHttpRequest
+ */
+
+ function createXMLHttpRequest()
+ {
+ var xhr = null;
+ if (window.XMLHttpRequest)
+ {
+ xhr = new XMLHttpRequest();
+ }
+ else if (window.ActiveXObject)
+ {
+ xhr = new ActiveXObject('Msxml2.XMLHTTP');
+ }
+ else
+ {
+ throw new Error('XMLHttpRequest is not supported');
+ }
+ return xhr;
+ }
+
+
+ //
+ // Function: fireReceiveEvent method
+ // Description: generate the onreceive event
+ // Parameters:
+ // epos object ePOSPrint object
+ // xhr object XMLHttpRequest object
+ // Return: none
+ //
+ function fireReceiveEvent(epos, xhr) {
+ if (epos.onreceive) {
+ var res = xhr.responseXML.getElementsByTagName('response');
+ if (res.length > 0) {
+ // fire onreceive event
+ epos.onreceive({
+ success: /^(1|true)$/.test(res[0].getAttribute('success')),
+ code: res[0].getAttribute('code'),
+ status: parseInt(res[0].getAttribute('status'))
+ });
+ }
+ else {
+ fireErrorEvent(epos, xhr);
+ }
+ }
+ }
+
+ //
+ // Function: fireErrorEvent method
+ // Description: generate the onerror event
+ // Parameters:
+ // epos object ePOSPrint object
+ // xhr object XMLHttpRequest object
+ // Return: none
+ //
+ function fireErrorEvent(epos, xhr) {
+ // fire onerror event
+ if (epos.onerror) {
+ epos.onerror({
+ status: xhr.status,
+ responseText: xhr.responseText
+ });
+ }
+ }
+
+
+// F I S C A L --- F I S C A L --- F I S C A L --- F I S C A L --- F I S C A L
+
+ /*
+ Function: fiscalPrint constructor
+ Description: initialize a fiscalPrint object
+ Parameters: none
+ Return: none
+ */
+
+ function fiscalPrint()
+ {
+ // events
+ this.onreceive = null;
+ this.onerror = null;
+
+ // constants
+ this.ASB_NO_RESPONSE = 0x00000001;
+ this.ASB_PRINT_SUCCESS = 0x00000002;
+ this.ASB_DRAWER_KICK = 0x00000004;
+ this.ASB_OFF_LINE = 0x00000008;
+ this.ASB_COVER_OPEN = 0x00000020;
+ this.ASB_PAPER_FEED = 0x00000040;
+ this.ASB_WAIT_ON_LINE = 0x00000100;
+ this.ASB_PANEL_SWITCH = 0x00000200;
+ this.ASB_MECHANICAL_ERR = 0x00000400;
+ this.ASB_AUTOCUTTER_ERR = 0x00000800;
+ this.ASB_UNRECOVER_ERR = 0x00002000;
+ this.ASB_AUTORECOVER_ERR = 0x00004000;
+ this.ASB_RECEIPT_NEAR_END = 0x00020000;
+ this.ASB_RECEIPT_END = 0x00080000;
+ this.ASB_BUZZER = 0x01000000;
+ this.ASB_SPOOLER_IS_STOPPED = 0x80000000;
+ }
+
+
+ /*
+ Function: fiscalPrint send method
+ Description: send the fiscal ePOS-Print XML message
+ Parameters:
+ address string The address where fpmate.cgi resides
+ request string Request message
+ Return: none
+ Throws: object The browser does not equip XMLHttpRequest
+ */
+
+ fiscalPrint.prototype.send = function (address, request)
+ {
+ // create SOAP envelope
+ var soap = '\n' +
+ '\n' +
+ '\n' +
+ request +
+ ' \n' +
+ ' \n';
+ // create XMLHttpRequest object
+ var xhr = createXMLHttpRequest();
+ xhr.open('POST', address, true);
+ // set headers
+ xhr.setRequestHeader('Content-Type', 'text/xml; charset=UTF-8');
+ xhr.setRequestHeader('If-Modified-Since', 'Thu, 01 Jan 1970 00:00:00 GMT');
+ xhr.setRequestHeader('SOAPAction', '""');
+ // receive event
+ var epos = this;
+ xhr.onreadystatechange = function ()
+ {
+ // receive response message
+ // alert("xhr.readyState = " + xhr.readyState + "\n" + "xhr.status = " + xhr.status);
+ if (xhr.readyState == 4)
+ {
+ if (xhr.status == 200)
+ {
+ fireFiscalReceiveEvent(epos, xhr);
+ }
+ else
+ {
+ fireFiscalErrorEvent(epos, xhr);
+ }
+ }
+ }
+ // send request message
+ xhr.send(soap);
+ }
+
+
+ /*
+ Function: fireFiscalReceiveEvent method
+ Description: generate the onreceive event
+ Parameters:
+ epos object ePOSPrint object
+ xhr object XMLHttpRequest object
+ Return: none
+ */
+
+ function fireFiscalReceiveEvent(epos, xhr)
+ {
+ if (epos.onreceive)
+ {
+ var res = xhr.responseXML.getElementsByTagName('response');
+ // alert (xhr.responseXML.xml);
+ // document.write(xhr.responseXML.xml);
+
+ if (res.length > 0)
+ {
+ // fire onreceive event
+ var result =
+ {
+ success: /^(1|true)$/.test(res[0].getAttribute('success')),
+ code: res[0].getAttribute('code'),
+ status: parseInt(res[0].getAttribute('status'))
+ };
+
+ // look for additional info
+ var res_add = res[0].getElementsByTagName('addInfo');
+ if (res_add.length > 0)
+ {
+ var list = res_add[0].getElementsByTagName('elementList');
+ var list_len = list.length;
+ var tag_names_list = list[0].childNodes[0].nodeValue;
+ var tag_names_array = tag_names_list.split(',');
+ var add_info = {};
+ for (var i = 0; i < tag_names_array.length; i++)
+ {
+ var node = res_add[0].getElementsByTagName(tag_names_array[i])[0];
+ var node_child = node.childNodes[0];
+ var node_val = node_child.nodeValue;
+ add_info[tag_names_array[i]] = node_val;
+ }
+ }
+ epos.onreceive(result, tag_names_array, add_info)
+ }
+ else // res.length <= 0
+ {
+ // alert ("res.length = " + res.length);
+ fireFiscalErrorEvent(epos, xhr);
+ } // end if (res.length > 0)
+ } // end if (epos.onreceive)
+ } // end function fireFiscalReceiveEvent(epos, xhr)
+
+
+ /*
+ Function: fireFiscalErrorEvent method
+ Description: generate the onerror event
+ Parameters:
+ epos object ePOSPrint object
+ xhr object XMLHttpRequest object
+ Return: none
+ */
+
+ function fireFiscalErrorEvent(epos, xhr)
+ {
+ // fire onerror event
+ // alert("Error event called");
+ if (epos.onerror)
+ {
+ epos.onerror({
+ status: xhr.status,
+ responseText: xhr.responseText
+ });
+ }
+ }
+
+
+ //
+ // Function: CanvasPrint constructor
+ // Description: initialize a Canvas-Print object
+ // Parameters: none
+ // Return: none
+ //
+
+ function CanvasPrint() {
+ }
+ // inherit from ePOSPrint object
+ CanvasPrint.prototype = new ePOSPrint();
+ CanvasPrint.prototype.constructor = CanvasPrint;
+
+ //
+ // Function: print method
+ // Description: print the HTML 5 Canvas
+ // Parameters:
+ // address string the address of ePOS-Print service
+ // canvas object HTML 5 Canvas object
+ // cut boolean when true, cut paper [option]
+ // Return: none
+ // Throws: object the browser does not equip Canvas
+ //
+ CanvasPrint.prototype.print = function (address, canvas, cut) {
+ // check parameter
+ if (!canvas.getContext) {
+ throw new Error('Canvas is not supported');
+ }
+ // get HTML 5 Canvas
+ var context = canvas.getContext('2d');
+ var width = canvas.getAttribute('width');
+ var height = canvas.getAttribute('height');
+ // create ePOS-Print XML message
+ var builder = new ePOSBuilder();
+ builder.addImage(context, 0, 0, width, height);
+ if (cut) {
+ builder.addCut(builder.CUT_FEED);
+ }
+ // send request message
+ this.send(address, builder.toString());
+ };
+
+
+ /*
+ Function: epson object
+ Description: append constructors to window object
+ */
+ window.epson = {
+ ePOSBuilder: ePOSBuilder,
+ ePOSPrint: ePOSPrint,
+ fiscalPrint: fiscalPrint,
+ CanvasPrint: CanvasPrint
+ };
+
+})(window);
diff --git a/fiscal_epos_print/static/src/css/pos.css b/fiscal_epos_print/static/src/css/pos.css
new file mode 100644
index 000000000000..7ade28c334e5
--- /dev/null
+++ b/fiscal_epos_print/static/src/css/pos.css
@@ -0,0 +1,5 @@
+/* Disabilitato finchè non gestiamo i resi */
+
+.orderlist-screen .order-line .order-list-return {
+ display:none;
+}
diff --git a/fiscal_epos_print/static/src/img/ade-logo.png b/fiscal_epos_print/static/src/img/ade-logo.png
new file mode 100644
index 0000000000000000000000000000000000000000..2a01e0fa97518955eaba3ac142c1f70a4b4f95ba
GIT binary patch
literal 1323
zcmV+`1=RY9P)Al>qT9o?9-vL^tlJA=}BQ4BNyRyss`K~91S0b_xCfjpouurL-+
zZ0I$BG{kfeGZsHpw{F{k{@QLH;dy>xYtkWU+n3L|*|pnN&b)N8V))$}V?`{Uc%s(;
zzW(JD$4{IwN=piN*^c*s<+wSP?Wphe9mcUeCXFqn)pEqLUCXkZJv-iiWk%)F#Vo5@
zf6F-lK%a5X0$?@&^X`O^gMGtLk10hIP+AM$|9phK2aln(q&K6Y%21C#GJlQ!vOd2O
zAUyi%TL*BDZGn_~X_}a{L7rIk5&oBF+@b8AkivbB7<;UPVi*jpew$<9JO;$1yD1CF!_WmV;%xVmU6B?P58OSeA$7
zI3#UXw^~ktWjTFq*QNG!Jz8rM7!#N^(tf>gCn7_szz>Ff@!oQ@zIybBwa5SwK|~NO
zXsr
z;i=tv$%`{|C}hxkrYOjZHU+6vr`t5#d9cOeIWs=D9q)zq#V;beMToR1dre-sP9{NT
zB7hRDlxP%M6e^T;n7XgDSy7g`@;d`$Iz7*?5|P>0BvUMUvwB%3Q47>pTyX*##lVD_NG-}R+Kfx;)$X&7h2BQt~VrU
zxorPtA8V?&5Q=2I8kjYep;$RLJKZw2^SQBd(#ny65pVzfg;#QHZA=8RWATJ@6`;K&
zW<}Xh;4JV~w7Tw{z^B9vUUEDHczBmQh@p6=lW1381LMVLr@TzP~u-`3HSJz_wkIjzfJz
z6H8WY#Pw1=&BVV>PCfKsN>p9u)dh?ZYVw`aCY9y~fnF(s3xc7#U7}Zj4Fa*m
hw1cMwUhDYe_!p8yX-584&fow5002ovPDHLkV1f+ ';
+ return tag;
+ },
+
+ /*
+ Adds a discount to the last line.
+ */
+ printRecItemAdjustment: function(args) {
+ var tag = ' ';
+ return tag;
+ },
+
+ /*
+ Prints a payment.
+ */
+ printRecTotal: function(args) {
+ var tag = ' ';
+ return tag;
+ },
+
+ /*
+ Prints a receipt
+ */
+ printFiscalReceipt: function(receipt) {
+ var self = this;
+ var xml = ' ';
+ _.each(receipt.orderlines, function(l, i, list) {
+ if (l.price >= 0) {
+ xml += self.printRecItem({
+ description: l.product_name,
+ quantity: l.quantity,
+ unitPrice: l.price,
+ department: l.tax_department.code
+ });
+ if (l.discount) {
+ xml += self.printRecItemAdjustment({
+ adjustmentType: 0,
+ description: 'Sconto ' + l.discount + '%',
+ amount: round_pr(l.quantity * l.price - l.price_display, self.sender.pos.currency.rounding),
+ });
+ }
+ }
+ else {
+ xml += self.printRecItemAdjustment({
+ adjustmentType: 3,
+ description: l.product_name,
+ department: l.tax_department.code,
+ amount: -l.price,
+ });
+ }
+ });
+ _.each(receipt.paymentlines, function(l, i, list) {
+ xml += self.printRecTotal({
+ payment: l.amount,
+ paymentType: l.type,
+ description: l.journal,
+ });
+ });
+ xml += ' ';
+ this.fiscalPrinter.send(this.url, xml);
+ console.log(xml);
+ },
+
+ printFiscalReport: function() {
+ var xml = '';
+ xml += ' ';
+ xml += ' ';
+ xml += ' ';
+ this.fiscalPrinter.send(this.url, xml);
+ },
+
+ getStatusOfFilesForADE: function() {
+ var xml = '';
+ xml += ' ';
+ xml += ' ';
+ this.fiscalPrinter.send(this.url, xml);
+ },
+
+ });
+
+ var _orderline_super = models.Orderline.prototype;
+ models.Orderline = models.Orderline.extend({
+ export_for_printing: function(){
+ var res = _orderline_super.export_for_printing.call(this, arguments);
+ res['tax_department'] = this.get_tax_details_r();
+ return res;
+ },
+ get_tax_details_r: function(){
+ var details = this.get_all_prices();
+ for (var i in details.taxDetails){
+ return {
+ code: this.pos.taxes_by_id[i].fpdeptax,
+ taxname: this.pos.taxes_by_id[i].name,
+ }
+ }
+ alert(_t("No taxes found"));
+ },
+ compute_all: function(taxes, price_unit, quantity, currency_rounding, no_map_tax) {
+ var res = _orderline_super.compute_all.call(this, taxes, price_unit, quantity, currency_rounding, no_map_tax);
+ var self = this;
+
+ var total_excluded = round_pr(price_unit * quantity, currency_rounding);
+ var total_included = total_excluded;
+ var base = total_excluded;
+ var list_taxes = res.taxes;
+ // amount_type 'group' not handled (used only for purchases, in Italy)
+ _(taxes).each(function(tax) {
+ if (!no_map_tax){
+ tax = self._map_tax_fiscal_position(tax);
+ }
+ if (!tax){
+ return;
+ }
+ var tax_amount = self._compute_all(tax, base, quantity);
+ tax_amount = round_pr(tax_amount, currency_rounding);
+ if (!tax_amount){
+ // Intervene here: also add taxes with 0 amount
+ if (tax.price_include) {
+ total_excluded -= tax_amount;
+ base -= tax_amount;
+ }
+ else {
+ total_included += tax_amount;
+ }
+ if (tax.include_base_amount) {
+ base += tax_amount;
+ }
+ var data = {
+ id: tax.id,
+ amount: tax_amount,
+ name: tax.name,
+ };
+ list_taxes.push(data);
+ }
+ });
+ res.taxes = list_taxes;
+
+ return res;
+ },
+ });
+
+ /*
+ Overwrite Paymentline.export_for_printing() in order
+ to make it export the payment type that must be passed
+ to the fiscal printer.
+ */
+ var original = models.Paymentline.prototype.export_for_printing;
+ models.Paymentline = models.Paymentline.extend({
+ export_for_printing: function() {
+ var res = original.apply(this, arguments);
+ res.type = this.cashregister.journal.fiscalprinter_payment_type;
+ return res;
+ }
+ });
+
+ // when print order i validate call print receipt
+ screens.PaymentScreenWidget.include({
+ getPrinterOptions: function (){
+ var protocol = ((this.pos.config.use_https) ? 'https://' : 'http://');
+ var printer_url = protocol + this.pos.config.printer_ip + '/cgi-bin/fpmate.cgi';
+ return {url: printer_url};
+ },
+ sendToPrinter: function(receipt, printer_options) {
+ var fp90 = new eposDriver(printer_options, this);
+ fp90.printFiscalReceipt(receipt);
+ },
+ finalize_validation: function() {
+ this._super.apply(this, arguments);
+ var currentOrder = this.pos.get('selectedOrder');
+ if (!currentOrder.is_to_invoice()) {
+ var printer_options = this.getPrinterOptions();
+ var receipt = currentOrder.export_for_printing();
+ this.sendToPrinter(receipt, printer_options);
+ this.pos.get('selectedOrder')._printed = true;
+ }
+ }
+
+ });
+
+ var _super_posmodel = models.PosModel.prototype;
+ models.PosModel = models.PosModel.extend({
+ initialize: function (session, attributes) {
+ var tax_model = _.find(this.models, function(model){ return model.model === 'account.tax'; });
+ tax_model.fields.push('fpdeptax');
+ return _super_posmodel.initialize.call(this, session, attributes);
+ },
+ });
+
+ OrderListScreenWidget.include({
+ // copiato da screens.PaymentScreenWidget
+ getPrinterOptions: function (){
+ var protocol = ((this.pos.config.use_https) ? 'https://' : 'http://');
+ var printer_url = protocol + this.pos.config.printer_ip + '/cgi-bin/fpmate.cgi';
+ return [{url: printer_url}];
+ },
+ // copiato da screens.PaymentScreenWidget
+ sendToPrinter: function(receipt, printer_options) {
+ for (var i = 0; i < printer_options.length; i++){
+ var printer_option = printer_options[i];
+ var fp90 = new eposDriver(printer_option, this);
+ fp90.printFiscalReceipt(receipt);
+ }
+ },
+ action_print: function (order_data, order) {
+ var receipt = order.export_for_printing();
+ var printer_options = this.getPrinterOptions();
+ this.sendToPrinter(receipt, printer_options);
+ return this._super(order_data, order);
+ },
+ });
+
+ var FiscalPrinterADEFilesButtonWidget = PosBaseWidget.extend({
+ template: 'FiscalPrinterADEFilesButtonWidget',
+
+ button_click: function () {
+ this.chrome.loading_show();
+ this.chrome.loading_message(_t('Connecting to the fiscal printer'));
+ var protocol = ((this.pos.config.use_https) ? 'https://' : 'http://');
+ var printer_url = protocol + this.pos.config.printer_ip + '/cgi-bin/fpmate.cgi';
+ var printer_options = {url: printer_url};
+ var fp90 = new eposDriver(printer_options, this);
+ fp90.getStatusOfFilesForADE();
+ },
+
+ renderElement: function () {
+ var self = this;
+ this._super();
+ this.$el.click(function () {
+ self.button_click();
+ });
+ },
+
+ });
+
+ var widgets = chrome.Chrome.prototype.widgets;
+ widgets.push({
+ 'name': 'ADE files status',
+ 'widget': FiscalPrinterADEFilesButtonWidget,
+ 'append': '.pos-rightheader',
+ 'args': {
+ 'label': 'ADE files status',
+ },
+ });
+
+ return {
+ eposDriver: eposDriver,
+ FiscalPrinterADEFilesButtonWidget: FiscalPrinterADEFilesButtonWidget,
+ };
+
+});
diff --git a/fiscal_epos_print/static/src/xml/pos.xml b/fiscal_epos_print/static/src/xml/pos.xml
new file mode 100644
index 000000000000..4b314984f7eb
--- /dev/null
+++ b/fiscal_epos_print/static/src/xml/pos.xml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+ display:none
+
+
+
+ Scontrino inviato alla stampante
+
+
+ Fattura registrata
+
+
+
+
+
+ display:none
+
+
+
+
diff --git a/fiscal_epos_print/views/account_statement_view.xml b/fiscal_epos_print/views/account_statement_view.xml
new file mode 100644
index 000000000000..38912cccd980
--- /dev/null
+++ b/fiscal_epos_print/views/account_statement_view.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ POS Journal - Fiscal Printer field
+ account.journal
+
+
+
+
+
+
+
+
+
+ account.tax.printer.form.view
+ account.tax
+
+
+
+
+
+
+
+
+
+
diff --git a/fiscal_epos_print/views/assets.xml b/fiscal_epos_print/views/assets.xml
new file mode 100644
index 000000000000..6e4b06b30570
--- /dev/null
+++ b/fiscal_epos_print/views/assets.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/fiscal_epos_print/views/point_of_sale.xml b/fiscal_epos_print/views/point_of_sale.xml
new file mode 100644
index 000000000000..b8b68a4ce362
--- /dev/null
+++ b/fiscal_epos_print/views/point_of_sale.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+ pos.config.form.printer.view
+ pos.config
+
+
+
+ Fiscal printer
+
+
+
+
+
+
+
+
+
+
+
+
From d46d9093629a37eca4efa0eec177425f2a8bd74a Mon Sep 17 00:00:00 2001
From: Roberto Fichera
Date: Mon, 2 Dec 2019 18:07:57 +0100
Subject: [PATCH 02/65] [fiscal_epos_print] Add refund support to ePOS fiscal
printer
[10.0][fiscal_epos_print] Renamed Cassa to RT in the refund dialog
[10.0][fiscal_epos_print] Check if the update_refund_info_button property has been passed before to call it
[10.0][fiscal_epos_print] Add support of pos.config header and footer when set
[fiscal_epos_print] Export refund_info_button widget for inheritance purposes
Add support for payment type index
Allow to configure whether to Show receipt preview or not
---
fiscal_epos_print/__manifest__.py | 2 +-
fiscal_epos_print/models/__init__.py | 2 +-
fiscal_epos_print/models/account_journal.py | 7 +
fiscal_epos_print/models/point_of_sale.py | 2 +
fiscal_epos_print/models/pos_order.py | 33 ++
fiscal_epos_print/models/product.py | 17 -
.../static/lib/pikaday/pikaday.min.css | 5 +
.../static/lib/pikaday/pikaday.min.js | 1 +
fiscal_epos_print/static/src/js/fp90iii.js | 390 ++++++++++++++++--
fiscal_epos_print/static/src/js/models.js | 8 +
fiscal_epos_print/static/src/xml/pos.xml | 58 ++-
.../views/account_statement_view.xml | 12 +-
fiscal_epos_print/views/assets.xml | 5 +
fiscal_epos_print/views/point_of_sale.xml | 20 +-
14 files changed, 501 insertions(+), 61 deletions(-)
create mode 100644 fiscal_epos_print/models/pos_order.py
delete mode 100644 fiscal_epos_print/models/product.py
create mode 100644 fiscal_epos_print/static/lib/pikaday/pikaday.min.css
create mode 100644 fiscal_epos_print/static/lib/pikaday/pikaday.min.js
create mode 100644 fiscal_epos_print/static/src/js/models.js
diff --git a/fiscal_epos_print/__manifest__.py b/fiscal_epos_print/__manifest__.py
index b00f450a1b86..e3aa3b4f44d8 100644
--- a/fiscal_epos_print/__manifest__.py
+++ b/fiscal_epos_print/__manifest__.py
@@ -11,7 +11,7 @@
'FP81II, FP90III',
'author': (
'Odoo Community Association (OCA), Agile Business Group, '
- 'Leonardo Donelli @ Creativi Quadrati, TAKOBI'
+ 'Leonardo Donelli, TAKOBI, Level Prime Srl'
),
'license': 'GPL-3',
'website': 'https://github.com/OCA/l10n-italy',
diff --git a/fiscal_epos_print/models/__init__.py b/fiscal_epos_print/models/__init__.py
index e58ce761f35d..ff3a2d6bd6e6 100644
--- a/fiscal_epos_print/models/__init__.py
+++ b/fiscal_epos_print/models/__init__.py
@@ -1,4 +1,4 @@
from . import account_journal
from . import point_of_sale
from . import account
-from . import product
+from . import pos_order
diff --git a/fiscal_epos_print/models/account_journal.py b/fiscal_epos_print/models/account_journal.py
index 1403b7ad5c2a..7d4e272ec43f 100644
--- a/fiscal_epos_print/models/account_journal.py
+++ b/fiscal_epos_print/models/account_journal.py
@@ -3,6 +3,7 @@
class AccountJournal(models.Model):
_inherit = 'account.journal'
+
fiscalprinter_payment_type = fields.Selection(
[
('0', 'Cash'),
@@ -14,3 +15,9 @@ class AccountJournal(models.Model):
help='The payment type to send to the Fiscal Printer.',
default='0'
)
+
+ fiscalprinter_payment_index = fields.Integer(
+ string='Credit Card/Ticket Index',
+ help='Set the index of the given payment type to specify the detail. '
+ 'Such index of the payment type must programmed on the fiscal '
+ 'printer')
diff --git a/fiscal_epos_print/models/point_of_sale.py b/fiscal_epos_print/models/point_of_sale.py
index 8a48ebfe3fa9..3d60ddb9e3fc 100644
--- a/fiscal_epos_print/models/point_of_sale.py
+++ b/fiscal_epos_print/models/point_of_sale.py
@@ -14,3 +14,5 @@ class PosConfig(models.Model):
string='Use https',
default=False,
)
+ show_receipt_when_printing = fields.Boolean(
+ string='Show receipt on screen when printing', default=True)
diff --git a/fiscal_epos_print/models/pos_order.py b/fiscal_epos_print/models/pos_order.py
new file mode 100644
index 000000000000..88939f963209
--- /dev/null
+++ b/fiscal_epos_print/models/pos_order.py
@@ -0,0 +1,33 @@
+# coding=utf-8
+
+from odoo import fields, models, api
+
+
+class PosOrder(models.Model):
+ _inherit = 'pos.order'
+
+ refund_date = fields.Date(string='Refund date reference')
+ refund_report = fields.Integer(string='Report reference', digits=(4, 0))
+ refund_doc_num = fields.Integer(string='Document Number', digits=(4, 0))
+ refund_cash_fiscal_serial = fields.Char(string='Refund Cash Serial')
+
+ @api.model
+ def _order_fields(self, ui_order):
+ res = super(PosOrder, self)._order_fields(ui_order)
+ res['refund_date'] = ui_order['refund_date'] or False
+ res['refund_report'] = ui_order['refund_report'] or False
+ res['refund_doc_num'] = ui_order['refund_doc_num'] or False
+ res['refund_cash_fiscal_serial'] = \
+ ui_order['refund_cash_fiscal_serial'] or False
+ return res
+
+ # This is on pos_order_mgmt to send back the fields of already existing
+ # pos.order
+ @api.multi
+ def _prepare_done_order_for_pos(self):
+ res = super(PosOrder, self)._prepare_done_order_for_pos()
+ res['refund_date'] = self.refund_date
+ res['refund_report'] = self.refund_report
+ res['refund_doc_num'] = self.refund_doc_num
+ res['refund_cash_fiscal_serial'] = self.refund_cash_fiscal_serial
+ return res
diff --git a/fiscal_epos_print/models/product.py b/fiscal_epos_print/models/product.py
deleted file mode 100644
index d6472dec9972..000000000000
--- a/fiscal_epos_print/models/product.py
+++ /dev/null
@@ -1,17 +0,0 @@
-from odoo import models, api, _
-from odoo.exceptions import ValidationError
-
-
-class Product(models.Model):
- _inherit = 'product.template'
-
- @api.constrains('available_in_pos', 'taxes_id')
- def _check_pos_prod_taxes(self):
- if self.available_in_pos:
- if len(self.taxes_id) != 1:
- raise ValidationError(
- _("Product %s must have 1 tax") % self.display_name)
- if not self.taxes_id[0].price_include:
- raise ValidationError(
- _("Tax %s must be included in price")
- % self.taxes_id[0].display_name)
diff --git a/fiscal_epos_print/static/lib/pikaday/pikaday.min.css b/fiscal_epos_print/static/lib/pikaday/pikaday.min.css
new file mode 100644
index 000000000000..92f41e33c90b
--- /dev/null
+++ b/fiscal_epos_print/static/lib/pikaday/pikaday.min.css
@@ -0,0 +1,5 @@
+@charset "UTF-8";/*!
+ * Pikaday
+ * Copyright © 2014 David Bushell | BSD & MIT license | https://dbushell.com/
+ */.pika-single{z-index:9999;display:block;position:relative;color:#333;background:#fff;border:1px solid #ccc;border-bottom-color:#bbb;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif}.pika-single:after,.pika-single:before{content:" ";display:table}.pika-single:after{clear:both}.pika-single.is-hidden{display:none}.pika-single.is-bound{position:absolute;box-shadow:0 5px 15px -5px rgba(0,0,0,.5)}.pika-lendar{float:left;width:240px;margin:8px}.pika-title{position:relative;text-align:center}.pika-label{display:inline-block;position:relative;z-index:9999;overflow:hidden;margin:0;padding:5px 3px;font-size:14px;line-height:20px;font-weight:700;background-color:#fff}.pika-title select{cursor:pointer;position:absolute;z-index:9998;margin:0;left:0;top:5px;opacity:0}.pika-next,.pika-prev{display:block;cursor:pointer;position:relative;outline:0;border:0;padding:0;width:20px;height:30px;text-indent:20px;white-space:nowrap;overflow:hidden;background-color:transparent;background-position:center center;background-repeat:no-repeat;background-size:75% 75%;opacity:.5}.pika-next:hover,.pika-prev:hover{opacity:1}.is-rtl .pika-next,.pika-prev{float:left;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAeCAYAAAAsEj5rAAAAUklEQVR42u3VMQoAIBADQf8Pgj+OD9hG2CtONJB2ymQkKe0HbwAP0xucDiQWARITIDEBEnMgMQ8S8+AqBIl6kKgHiXqQqAeJepBo/z38J/U0uAHlaBkBl9I4GwAAAABJRU5ErkJggg==)}.is-rtl .pika-prev,.pika-next{float:right;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAeCAYAAAAsEj5rAAAAU0lEQVR42u3VOwoAMAgE0dwfAnNjU26bYkBCFGwfiL9VVWoO+BJ4Gf3gtsEKKoFBNTCoCAYVwaAiGNQGMUHMkjGbgjk2mIONuXo0nC8XnCf1JXgArVIZAQh5TKYAAAAASUVORK5CYII=)}.pika-next.is-disabled,.pika-prev.is-disabled{cursor:default;opacity:.2}.pika-select{display:inline-block}.pika-table{width:100%;border-collapse:collapse;border-spacing:0;border:0}.pika-table td,.pika-table th{width:14.285714285714286%;padding:0}.pika-table th{color:#999;font-size:12px;line-height:25px;font-weight:700;text-align:center}.pika-button{cursor:pointer;display:block;box-sizing:border-box;-moz-box-sizing:border-box;outline:0;border:0;margin:0;width:100%;padding:5px;color:#666;font-size:12px;line-height:15px;text-align:right;background:#f5f5f5}.pika-week{font-size:11px;color:#999}.is-today .pika-button{color:#3af;font-weight:700}.has-event .pika-button,.is-selected .pika-button{color:#fff;font-weight:700;background:#3af;box-shadow:inset 0 1px 3px #178fe5;border-radius:3px}.has-event .pika-button{background:#005da9;box-shadow:inset 0 1px 3px #0076c9}.is-disabled .pika-button,.is-inrange .pika-button{background:#d5e9f7}.is-startrange .pika-button{color:#fff;background:#6cb31d;box-shadow:none;border-radius:3px}.is-endrange .pika-button{color:#fff;background:#3af;box-shadow:none;border-radius:3px}.is-disabled .pika-button{pointer-events:none;cursor:default;color:#999;opacity:.3}.is-outside-current-month .pika-button{color:#999;opacity:.3}.is-selection-disabled{pointer-events:none;cursor:default}.pika-button:hover,.pika-row.pick-whole-week:hover .pika-button{color:#fff;background:#ff8000;box-shadow:none;border-radius:3px}.pika-table abbr{border-bottom:none;cursor:help}
+/*# sourceMappingURL=pikaday.min.css.map */
\ No newline at end of file
diff --git a/fiscal_epos_print/static/lib/pikaday/pikaday.min.js b/fiscal_epos_print/static/lib/pikaday/pikaday.min.js
new file mode 100644
index 000000000000..078c1b5d6238
--- /dev/null
+++ b/fiscal_epos_print/static/lib/pikaday/pikaday.min.js
@@ -0,0 +1 @@
+!function(e,t){"use strict";var n;if("object"==typeof exports){try{n=require("moment")}catch(e){}module.exports=t(n)}else"function"==typeof define&&define.amd?define(function(e){try{n=e("moment")}catch(e){}return t(n)}):e.Pikaday=t(e.moment)}(this,function(n){"use strict";var s="function"==typeof n,o=!!window.addEventListener,c=window.document,h=window.setTimeout,r=function(e,t,n,a){o?e.addEventListener(t,n,!!a):e.attachEvent("on"+t,n)},t=function(e,t,n,a){o?e.removeEventListener(t,n,!!a):e.detachEvent("on"+t,n)},l=function(e,t){return-1!==(" "+e.className+" ").indexOf(" "+t+" ")},f=function(e,t){l(e,t)||(e.className=""===e.className?t:e.className+" "+t)},g=function(e,t){var n;e.className=(n=(" "+e.className+" ").replace(" "+t+" "," ")).trim?n.trim():n.replace(/^\s+|\s+$/g,"")},y=function(e){return/Array/.test(Object.prototype.toString.call(e))},F=function(e){return/Date/.test(Object.prototype.toString.call(e))&&!isNaN(e.getTime())},L=function(e,t){return[31,(n=e,n%4==0&&n%100!=0||n%400==0?29:28),31,30,31,30,31,31,30,31,30,31][t];var n},P=function(e){F(e)&&e.setHours(0,0,0,0)},B=function(e,t){return e.getTime()===t.getTime()},d=function(e,t,n){var a,i;for(a in t)(i=void 0!==e[a])&&"object"==typeof t[a]&&null!==t[a]&&void 0===t[a].nodeName?F(t[a])?n&&(e[a]=new Date(t[a].getTime())):y(t[a])?n&&(e[a]=t[a].slice(0)):e[a]=d({},t[a],n):!n&&i||(e[a]=t[a]);return e},i=function(e,t,n){var a;c.createEvent?((a=c.createEvent("HTMLEvents")).initEvent(t,!0,!1),a=d(a,n),e.dispatchEvent(a)):c.createEventObject&&(a=c.createEventObject(),a=d(a,n),e.fireEvent("on"+t,a))},a=function(e){return e.month<0&&(e.year-=Math.ceil(Math.abs(e.month)/12),e.month+=12),11';t.push("is-outside-current-month"),e.enableSelectionDaysInNextAndPreviousMonths||t.push("is-selection-disabled")}return e.isDisabled&&t.push("is-disabled"),e.isToday&&t.push("is-today"),e.isSelected&&(t.push("is-selected"),n="true"),e.hasEvent&&t.push("has-event"),e.isInRange&&t.push("is-inrange"),e.isStartRange&&t.push("is-startrange"),e.isEndRange&&t.push("is-endrange"),''+e.day+" "},p=function(e,t,n,a,i,s){var o,r,l,h,d,u=e._o,c=n===u.minYear,f=n===u.maxYear,g='',m=!0,p=!0;for(l=[],o=0;o<12;o++)l.push('
u.maxMonth?'disabled="disabled"':"")+">"+u.i18n.months[o]+" ");for(h='
'+u.i18n.months[a]+''+l.join("")+"
",y(u.yearRange)?(o=u.yearRange[0],r=u.yearRange[1]+1):(o=n-u.yearRange,r=1+n+u.yearRange),l=[];o
=u.minYear&&l.push('"+o+" ");return d=''+n+u.yearSuffix+''+l.join("")+"
",u.showMonthAfterYear?g+=d+h:g+=h+d,c&&(0===a||u.minMonth>=a)&&(m=!1),f&&(11===a||u.maxMonth<=a)&&(p=!1),0===t&&(g+=''+u.i18n.previousMonth+" "),t===e._o.numberOfMonths-1&&(g+=''+u.i18n.nextMonth+" "),g+" "},V=function(e,t,n){return''+function(e){var t,n=[];for(e.showWeekNumber&&n.push(" "),t=0;t<7;t++)n.push(''+m(e,t,!0)+" ");return""+(e.isRTL?n.reverse():n).join("")+" "}(e)+(""+t.join("")+" ")+"
"},e=function(e){var a=this,i=a.config(e);a._onMouseDown=function(e){if(a._v){var t=(e=e||window.event).target||e.srcElement;if(t)if(l(t,"is-disabled")||(!l(t,"pika-button")||l(t,"is-empty")||l(t.parentNode,"is-disabled")?l(t,"pika-prev")?a.prevMonth():l(t,"pika-next")&&a.nextMonth():(a.setDate(new Date(t.getAttribute("data-pika-year"),t.getAttribute("data-pika-month"),t.getAttribute("data-pika-day"))),i.bound&&h(function(){a.hide(),i.blurFieldOnSelect&&i.field&&i.field.blur()},100))),l(t,"pika-select"))a._c=!0;else{if(!e.preventDefault)return e.returnValue=!1;e.preventDefault()}}},a._onChange=function(e){var t=(e=e||window.event).target||e.srcElement;t&&(l(t,"pika-select-month")?a.gotoMonth(t.value):l(t,"pika-select-year")&&a.gotoYear(t.value))},a._onKeyChange=function(e){if(e=e||window.event,a.isVisible())switch(e.keyCode){case 13:case 27:i.field&&i.field.blur();break;case 37:e.preventDefault(),a.adjustDate("subtract",1);break;case 38:a.adjustDate("subtract",7);break;case 39:a.adjustDate("add",1);break;case 40:a.adjustDate("add",7)}},a._onInputChange=function(e){var t;e.firedBy!==a&&(t=i.parse?i.parse(i.field.value,i.format):s?(t=n(i.field.value,i.format,i.formatStrict))&&t.isValid()?t.toDate():null:new Date(Date.parse(i.field.value)),F(t)&&a.setDate(t),a._v||a.show())},a._onInputFocus=function(){a.show()},a._onInputClick=function(){a.show()},a._onInputBlur=function(){var e=c.activeElement;do{if(l(e,"pika-single"))return}while(e=e.parentNode);a._c||(a._b=h(function(){a.hide()},50)),a._c=!1},a._onClick=function(e){var t=(e=e||window.event).target||e.srcElement,n=t;if(t){!o&&l(t,"pika-select")&&(t.onchange||(t.setAttribute("onchange","return;"),r(t,"change",a._onChange)));do{if(l(n,"pika-single")||n===i.trigger)return}while(n=n.parentNode);a._v&&t!==i.trigger&&n!==i.trigger&&a.hide()}},a.el=c.createElement("div"),a.el.className="pika-single"+(i.isRTL?" is-rtl":"")+(i.theme?" "+i.theme:""),r(a.el,"mousedown",a._onMouseDown,!0),r(a.el,"touchend",a._onMouseDown,!0),r(a.el,"change",a._onChange),i.keyboardInput&&r(c,"keydown",a._onKeyChange),i.field&&(i.container?i.container.appendChild(a.el):i.bound?c.body.appendChild(a.el):i.field.parentNode.insertBefore(a.el,i.field.nextSibling),r(i.field,"change",a._onInputChange),i.defaultDate||(s&&i.field.value?i.defaultDate=n(i.field.value,i.format).toDate():i.defaultDate=new Date(Date.parse(i.field.value)),i.setDefaultDate=!0));var t=i.defaultDate;F(t)?i.setDefaultDate?a.setDate(t,!0):a.gotoDate(t):a.gotoDate(new Date),i.bound?(this.hide(),a.el.className+=" is-bound",r(i.trigger,"click",a._onInputClick),r(i.trigger,"focus",a._onInputFocus),r(i.trigger,"blur",a._onInputBlur)):this.show()};return e.prototype={config:function(e){this._o||(this._o=d({},u,!0));var t=d(this._o,e,!0);t.isRTL=!!t.isRTL,t.field=t.field&&t.field.nodeName?t.field:null,t.theme="string"==typeof t.theme&&t.theme?t.theme:null,t.bound=!!(void 0!==t.bound?t.field&&t.bound:t.field),t.trigger=t.trigger&&t.trigger.nodeName?t.trigger:t.field,t.disableWeekends=!!t.disableWeekends,t.disableDayFn="function"==typeof t.disableDayFn?t.disableDayFn:null;var n=parseInt(t.numberOfMonths,10)||1;if(t.numberOfMonths=4=i&&(this._y=i,!isNaN(o)&&this._m>o&&(this._m=o)),t="pika-title-"+Math.random().toString(36).replace(/[^a-z]+/g,"").substr(0,2);for(var l=0;l'+p(this,l,this.calendars[l].year,this.calendars[l].month,this.calendars[0].year,t)+this.render(this.calendars[l].year,this.calendars[l].month,t)+"";this.el.innerHTML=r,n.bound&&"hidden"!==n.field.type&&h(function(){n.trigger.focus()},1),"function"==typeof this._o.onDraw&&this._o.onDraw(this),n.bound&&n.field.setAttribute("aria-label",n.ariaLabel)}},adjustPosition:function(){var e,t,n,a,i,s,o,r,l,h,d,u;if(!this._o.container){if(this.el.style.position="absolute",t=e=this._o.trigger,n=this.el.offsetWidth,a=this.el.offsetHeight,i=window.innerWidth||c.documentElement.clientWidth,s=window.innerHeight||c.documentElement.clientHeight,o=window.pageYOffset||c.body.scrollTop||c.documentElement.scrollTop,u=d=!0,"function"==typeof e.getBoundingClientRect)r=(h=e.getBoundingClientRect()).left+window.pageXOffset,l=h.bottom+window.pageYOffset;else for(r=t.offsetLeft,l=t.offsetTop+t.offsetHeight;t=t.offsetParent;)r+=t.offsetLeft,l+=t.offsetTop;(this._o.reposition&&ia.maxDate||a.disableWeekends&&(void 0,0===(w=R.getDay())||6===w)||a.disableDayFn&&a.disableDayFn(R),isEmpty:I,isStartRange:O,isEndRange:j,isInRange:W,showDaysInNextAndPreviousMonths:a.showDaysInNextAndPreviousMonths,enableSelectionDaysInNextAndPreviousMonths:a.enableSelectionDaysInNextAndPreviousMonths};a.pickWholeWeek&&N&&(M=!0),l.push(H(A)),7==++x&&(a.showWeekNumber&&l.unshift((D=k-o,v=t,b=e,_=void 0,_=new Date(b,0,1),''+Math.ceil(((new Date(b,v,D)-_)/864e5+_.getDay()+1)/7)+" ")),r.push((p=l,y=a.isRTL,''+(y?p.reverse():p).join("")+" ")),x=0,M=!(l=[]))}return V(a,r,n)},isVisible:function(){return this._v},show:function(){this.isVisible()||(this._v=!0,this.draw(),g(this.el,"is-hidden"),this._o.bound&&(r(c,"click",this._onClick),this.adjustPosition()),"function"==typeof this._o.onOpen&&this._o.onOpen.call(this))},hide:function(){var e=this._v;!1!==e&&(this._o.bound&&t(c,"click",this._onClick),this.el.style.position="static",this.el.style.left="auto",this.el.style.top="auto",f(this.el,"is-hidden"),this._v=!1,void 0!==e&&"function"==typeof this._o.onClose&&this._o.onClose.call(this))},destroy:function(){var e=this._o;this.hide(),t(this.el,"mousedown",this._onMouseDown,!0),t(this.el,"touchend",this._onMouseDown,!0),t(this.el,"change",this._onChange),e.keyboardInput&&t(c,"keydown",this._onKeyChange),e.field&&(t(e.field,"change",this._onInputChange),e.bound&&(t(e.trigger,"click",this._onInputClick),t(e.trigger,"focus",this._onInputFocus),t(e.trigger,"blur",this._onInputBlur))),this.el.parentNode&&this.el.parentNode.removeChild(this.el)}},e});
\ No newline at end of file
diff --git a/fiscal_epos_print/static/src/js/fp90iii.js b/fiscal_epos_print/static/src/js/fp90iii.js
index f58d774d5748..5cf310696b04 100644
--- a/fiscal_epos_print/static/src/js/fp90iii.js
+++ b/fiscal_epos_print/static/src/js/fp90iii.js
@@ -4,13 +4,256 @@ odoo.define("fiscal_epos_print.models", function (require) {
var models = require("point_of_sale.models");
var core = require("web.core");
var screens = require('point_of_sale.screens');
- var _t = core._t;
var utils = require('web.utils');
var PosBaseWidget = require('point_of_sale.BaseWidget');
var chrome = require('point_of_sale.chrome');
var round_pr = utils.round_precision;
var pos_order_mgmt = require('pos_order_mgmt.widgets');
+ var pos_popup = require('point_of_sale.popups');
+ var gui = require('point_of_sale.gui');
+ var _t = core._t;
var OrderListScreenWidget = pos_order_mgmt.OrderListScreenWidget;
+ var OrderSuper = models.Order;
+ var RefundInfoPopupWidgetSuper = pos_popup;
+ var PaymentScreenWidget = screens.PaymentScreenWidget;
+ var ReceiptScreenWidget = screens.ReceiptScreenWidget;
+
+ function addPadding(str, padding=4) {
+ var pad = new Array(padding).fill(0).join('') + str;
+ return pad.substr(pad.length - padding, padding);
+ }
+
+ ReceiptScreenWidget.include({
+ show: function(){
+ if (!this.pos.config.printer_ip || (this.pos.config.printer_ip && this.pos.config.show_receipt_when_printing) ){
+ this._super();
+ }
+ else
+ {
+ this.click_next();
+ }
+ }
+ });
+
+ PaymentScreenWidget.include({
+ order_is_valid: function(force_validation) {
+ var self = this;
+ var receipt = this.pos.get_order();
+ if (receipt.has_refund && (receipt.refund_date == null || receipt.refund_date === '' ||
+ receipt.refund_doc_num == null || receipt.refund_doc_num == '' ||
+ receipt.refund_cash_fiscal_serial == null || receipt.refund_cash_fiscal_serial == '' ||
+ receipt.refund_report == null || receipt.refund_report == '')) {
+ this.gui.show_popup('error',{
+ 'title': _t('Refund Information Not Present'),
+ 'body': _t("The refund information aren't present. Please insert them before printing the receipt"),
+ });
+ return false;
+ }
+ return this._super(force_validation);
+ }
+ });
+
+ models.Order = models.Order.extend({
+ initialize: function(attributes, options){
+ OrderSuper.prototype.initialize.call(this, attributes,options);
+ this.refund_report = null;
+ this.refund_date = null;
+ this.refund_doc_num = null;
+ this.refund_cash_fiscal_serial = null;
+ this.has_refund = false;
+ },
+ check_order_has_refund: function() {
+ var order = this.pos.get_order();
+ if (order) {
+ var lines = order.orderlines;
+ order.has_refund = lines.find(function(line){ return line.quantity < 0.0;}) != undefined;
+ }
+ },
+
+ init_from_JSON: function (json) {
+ OrderSuper.prototype.init_from_JSON.apply(this, arguments);
+ this.refund_report = json.refund_report;
+ this.refund_date = json.refund_date;
+ this.refund_doc_num = json.refund_doc_num;
+ this.refund_cash_fiscal_serial = json.refund_cash_fiscal_serial;
+ this.check_order_has_refund();
+ },
+
+ export_as_JSON: function() {
+ var result = OrderSuper.prototype.export_as_JSON.call(this);
+ result.refund_report = this.refund_report;
+ result.refund_date = this.refund_date ? this.refund_date.substr(4, 4) + '-' + // year
+ this.refund_date.substr(2, 2) + '-' + // month
+ this.refund_date.substr(0, 2) : null; // day
+ result.refund_doc_num = this.refund_doc_num;
+ result.refund_cash_fiscal_serial = this.refund_cash_fiscal_serial;
+ return result;
+ },
+
+ export_for_printing: function(){
+ var receipt = OrderSuper.prototype.export_for_printing.call(this);
+
+ receipt.refund_date = this.refund_date;
+ receipt.refund_report = this.refund_report;
+ receipt.refund_doc_num = this.refund_doc_num;
+ receipt.refund_cash_fiscal_serial = this.refund_cash_fiscal_serial;
+
+ return receipt
+ },
+ });
+
+ var set_refund_info_button = screens.ActionButtonWidget.extend({
+ template: 'SetRefundInfoButton',
+ init: function(parent, options) {
+ var self = this;
+ this._super(parent, options);
+ this.pos.bind('change:selectedOrder',function(){
+ this.orderline_change();
+ this.bind_order_events();
+ },this);
+ this.bind_order_events();
+ this.orderline_change();
+ },
+ renderElement: function() {
+ this._super();
+ var color = this.refund_get_button_color();
+ this.$el.css('background', color);
+ },
+ button_click: function () {
+ var self = this;
+ var current_order = self.pos.get_order();
+ self.gui.show_popup('refundinfo', {
+ title: _t('Refund Information Details'),
+ refund_date: current_order.refund_date,
+ refund_report: current_order.refund_report,
+ refund_doc_num: current_order.refund_doc_num,
+ refund_cash_fiscal_serial: current_order.refund_cash_fiscal_serial,
+ update_refund_info_button: function(){
+ self.renderElement();
+ },
+ });
+ },
+ bind_order_events: function() {
+ var self = this;
+ var order = this.pos.get_order();
+
+ if (!order) {
+ return;
+ }
+
+ if(this.old_order) {
+ this.old_order.unbind(null,null,this);
+ }
+
+ this.pos.bind('change:selectedOrder', this.orderline_change, this);
+
+ var lines = order.orderlines;
+ lines.unbind('add', this.orderline_change, this);
+ lines.bind('add', this.orderline_change, this);
+ lines.unbind('remove', this.orderline_change, this);
+ lines.bind('remove', this.orderline_change, this);
+ lines.unbind('change', this.orderline_change, this);
+ lines.bind('change', this.orderline_change, this);
+
+ this.old_order = order;
+ },
+ refund_get_button_color: function() {
+ var order = this.pos.get_order();
+ var lines = order.orderlines;
+ var has_refund = lines.find(function(line){ return line.quantity < 0.0;}) != undefined;
+ var color = '#e2e2e2';
+ if (has_refund == true)
+ {
+ if (order.refund_date && order.refund_date != '' && order.refund_doc_num && order.refund_doc_num != '' &&
+ order.refund_cash_fiscal_serial && order.refund_cash_fiscal_serial != '' && order.refund_report && order.refund_report != '') {
+ color = 'lightgreen';
+ }
+ else
+ {
+ color = 'red';
+ }
+ }
+ return color;
+ },
+ orderline_change: function(){
+ var order = this.pos.get_order();
+ var lines = order.orderlines;
+ order.has_refund = lines.find(function(line){ return line.quantity < 0.0;}) != undefined;
+ this.renderElement();
+ },
+ });
+
+ screens.define_action_button({
+ 'name': 'set_refund_info',
+ 'widget': set_refund_info_button,
+ });
+
+ var RefundInfoPopupWidget = pos_popup.extend({
+ template: 'RefundInfoPopupWidget',
+ init: function(parent) {
+ this.refund_report = null;
+ this.refund_date = null;
+ this.refund_doc_num = null;
+ this.refund_cash_fiscal_serial = null;
+ this.datepicker = null;
+ return this._super(parent);
+ },
+ show: function(options){
+ options = options || {};
+ this._super(options);
+ this.update_refund_info_button = options.update_refund_info_button;
+ this.renderElement();
+ this.datepicker = null;
+ this.$('refund_report').focus();
+ this.initializeDatePicker();
+ },
+ click_confirm: function(){
+ var self = this;
+ function allValid() {
+ return self.$('input').toArray().every(function(element) {
+ return element.value && element.value != ''
+ })
+ }
+
+ if (allValid()) {
+ this.$('#error-message-dialog').hide()
+
+ var order = this.pos.get_order();
+ order.refund_report = this.$('#refund_report').val();
+ order.refund_date = this.$('#refund_date').val();
+ order.refund_doc_num = this.$('#refund_doc_num').val();
+ order.refund_cash_fiscal_serial = this.$('#refund_cash_fiscal_serial').val();
+ this.gui.close_popup();
+ if (this.update_refund_info_button && this.update_refund_info_button instanceof Function) {
+ this.update_refund_info_button();
+ }
+ } else {
+ this.$('#error-message-dialog').show()
+ }
+ },
+ initializeDatePicker: function() {
+ var self = this,
+ element = this.$('#refund_date').get(0);
+
+ if (element && !this.datepicker) {
+ this.datepicker = new Pikaday({
+ field: element,
+ parse: function(str) {
+ return new Date(str.slice(4, 8),
+ str.slice(2, 4),
+ str.slice(0, 2))
+ },
+ toString: function(date) {
+ var str = date.toLocaleDateString().split('/');
+ return addPadding(str[1], 2) +
+ addPadding(str[0], 2) +
+ addPadding(str[2]);
+ }
+ });
+ }
+ },
+ });
+ gui.define_popup({name:'refundinfo', widget: RefundInfoPopupWidget});
var eposDriver = core.Class.extend({
init: function(options, sender) {
@@ -58,6 +301,31 @@ odoo.define("fiscal_epos_print.models", function (require) {
return tag;
},
+ /*
+ Prints a sale refund item line.
+ */
+ printRecRefund: function(args) {
+ var message = 'REFUND ' +
+ addPadding(args.refund_report) + ' ' +
+ addPadding(args.refund_doc_num) + ' ' +
+ args.refund_date + ' ' +
+ args.refund_cash_fiscal_serial;
+
+ var tag = ' \n'
+ + ' ';
+ return tag;
+ },
+
/*
Adds a discount to the last line.
*/
@@ -79,32 +347,84 @@ odoo.define("fiscal_epos_print.models", function (require) {
printRecTotal: function(args) {
var tag = ' ';
return tag;
},
+ // Remember that the header goes after
+ // but before otherwise it will not be printed
+ // as additional header messageType=1
+ printFiscalReceiptHeader: function(receipt){
+ var msg = '';
+ if (receipt.header != '' && receipt.header.length > 0) {
+ var hdr = receipt.header.split(/\r\n|\r|\n/);
+ _.each(hdr, function(m, i) {
+ msg += ' '
+ });
+ }
+ return msg;
+ },
+
+ // Remember that the footer goes within
+ // as PROMO code messageType=3
+ printFiscalReceiptFooter: function(receipt){
+ var msg = '';
+ if (receipt.footer != '' && receipt.footer.length > 0) {
+ var hdr = receipt.footer.split(/\r\n|\r|\n/);
+ _.each(hdr, function(m, i) {
+ msg += ' '
+ });
+ }
+ return msg;
+ },
+
/*
Prints a receipt
*/
printFiscalReceipt: function(receipt) {
var self = this;
- var xml = ' ';
+ var xml = '';
+ // header must be printed before beginning a fiscal receipt
+ xml += this.printFiscalReceiptHeader(receipt);
+ xml += ' ';
+ // footer can go only as promo code so within a fiscal receipt body
+ xml += this.printFiscalReceiptFooter(receipt);
_.each(receipt.orderlines, function(l, i, list) {
if (l.price >= 0) {
- xml += self.printRecItem({
- description: l.product_name,
- quantity: l.quantity,
- unitPrice: l.price,
- department: l.tax_department.code
- });
- if (l.discount) {
- xml += self.printRecItemAdjustment({
- adjustmentType: 0,
- description: 'Sconto ' + l.discount + '%',
- amount: round_pr(l.quantity * l.price - l.price_display, self.sender.pos.currency.rounding),
+ if(l.quantity>=0) {
+ xml += self.printRecItem({
+ description: l.product_name,
+ quantity: l.quantity,
+ unitPrice: l.price,
+ department: l.tax_department.code
+ });
+ if (l.discount) {
+ xml += self.printRecItemAdjustment({
+ adjustmentType: 0,
+ description: _t('Discount') + ' ' + l.discount + '%',
+ amount: round_pr(l.quantity * l.price - l.price_display, self.sender.pos.currency.rounding),
+ });
+ }
+ }
+ else
+ {
+ xml += self.printRecRefund({
+ refund_date: receipt.refund_date,
+ refund_report: receipt.refund_report,
+ refund_doc_num: receipt.refund_doc_num,
+ refund_cash_fiscal_serial: receipt.refund_cash_fiscal_serial,
+ description: _t('Refund >>> ') + l.product_name,
+ quantity: l.quantity * -1.0,
+ unitPrice: l.price,
+ department: l.tax_department.code
});
}
}
@@ -121,6 +441,7 @@ odoo.define("fiscal_epos_print.models", function (require) {
xml += self.printRecTotal({
payment: l.amount,
paymentType: l.type,
+ paymentIndex: l.type_index,
description: l.journal,
});
});
@@ -131,7 +452,7 @@ odoo.define("fiscal_epos_print.models", function (require) {
printFiscalReport: function() {
var xml = '';
- xml += ' ';
+ xml += ' ';
xml += ' ';
xml += ' ';
this.fiscalPrinter.send(this.url, xml);
@@ -217,6 +538,7 @@ odoo.define("fiscal_epos_print.models", function (require) {
export_for_printing: function() {
var res = original.apply(this, arguments);
res.type = this.cashregister.journal.fiscalprinter_payment_type;
+ res.type_index = this.cashregister.journal.fiscalprinter_payment_index;
return res;
}
});
@@ -228,18 +550,21 @@ odoo.define("fiscal_epos_print.models", function (require) {
var printer_url = protocol + this.pos.config.printer_ip + '/cgi-bin/fpmate.cgi';
return {url: printer_url};
},
- sendToPrinter: function(receipt, printer_options) {
+ sendToFP90Printer: function(receipt, printer_options) {
var fp90 = new eposDriver(printer_options, this);
fp90.printFiscalReceipt(receipt);
},
finalize_validation: function() {
- this._super.apply(this, arguments);
+ // we need to get currentOrder before calling the _super()
+ // otherwise we will likely get a empty order when we want to skip
+ // the receipt preview
var currentOrder = this.pos.get('selectedOrder');
- if (!currentOrder.is_to_invoice()) {
+ this._super.apply(this, arguments);
+ if (this.pos.config.printer_ip && !currentOrder.is_to_invoice()) {
var printer_options = this.getPrinterOptions();
var receipt = currentOrder.export_for_printing();
- this.sendToPrinter(receipt, printer_options);
- this.pos.get('selectedOrder')._printed = true;
+ this.sendToFP90Printer(receipt, printer_options);
+ currentOrder._printed = true;
}
}
@@ -255,6 +580,18 @@ odoo.define("fiscal_epos_print.models", function (require) {
});
OrderListScreenWidget.include({
+ _prepare_order_from_order_data: function (order_data, action) {
+ var order = this._super(order_data, action);
+ order.refund_report = order_data.refund_report;
+ order.refund_date = order_data.refund_date ? order_data.refund_date.substr(8, 2) + // day
+ order_data.refund_date.substr(5, 2) + // month
+ order_data.refund_date.substr(0, 4) // year
+ : null;
+ order.refund_doc_num = order_data.refund_doc_num;
+ order.refund_cash_fiscal_serial = order_data.refund_cash_fiscal_serial;
+
+ return order;
+ },
// copiato da screens.PaymentScreenWidget
getPrinterOptions: function (){
var protocol = ((this.pos.config.use_https) ? 'https://' : 'http://');
@@ -262,7 +599,7 @@ odoo.define("fiscal_epos_print.models", function (require) {
return [{url: printer_url}];
},
// copiato da screens.PaymentScreenWidget
- sendToPrinter: function(receipt, printer_options) {
+ sendToFP90Printer: function(receipt, printer_options) {
for (var i = 0; i < printer_options.length; i++){
var printer_option = printer_options[i];
var fp90 = new eposDriver(printer_option, this);
@@ -270,9 +607,11 @@ odoo.define("fiscal_epos_print.models", function (require) {
}
},
action_print: function (order_data, order) {
- var receipt = order.export_for_printing();
- var printer_options = this.getPrinterOptions();
- this.sendToPrinter(receipt, printer_options);
+ if (this.pos.config.printer_ip) {
+ var receipt = order.export_for_printing();
+ var printer_options = this.getPrinterOptions();
+ this.sendToFP90Printer(receipt, printer_options);
+ }
return this._super(order_data, order);
},
});
@@ -302,7 +641,7 @@ odoo.define("fiscal_epos_print.models", function (require) {
var widgets = chrome.Chrome.prototype.widgets;
widgets.push({
- 'name': 'ADE files status',
+ 'name': _t('ADE files status'),
'widget': FiscalPrinterADEFilesButtonWidget,
'append': '.pos-rightheader',
'args': {
@@ -313,6 +652,7 @@ odoo.define("fiscal_epos_print.models", function (require) {
return {
eposDriver: eposDriver,
FiscalPrinterADEFilesButtonWidget: FiscalPrinterADEFilesButtonWidget,
+ RefundInfoButtonActionWidget: set_refund_info_button
};
});
diff --git a/fiscal_epos_print/static/src/js/models.js b/fiscal_epos_print/static/src/js/models.js
new file mode 100644
index 000000000000..cde2df08ea8e
--- /dev/null
+++ b/fiscal_epos_print/static/src/js/models.js
@@ -0,0 +1,8 @@
+odoo.define('fiscal_epos_print.fiscalcode_field', function (require) {
+ "use strict";
+
+ var pos_models = require('point_of_sale.models');
+ pos_models.load_fields("account.journal",
+ ["fiscalprinter_payment_type", "fiscalprinter_payment_index"]);
+
+});
diff --git a/fiscal_epos_print/static/src/xml/pos.xml b/fiscal_epos_print/static/src/xml/pos.xml
index 4b314984f7eb..41c636c659b2 100644
--- a/fiscal_epos_print/static/src/xml/pos.xml
+++ b/fiscal_epos_print/static/src/xml/pos.xml
@@ -8,15 +8,12 @@
-
- display:none
-
- Scontrino inviato alla stampante
+ Receipt sent to the printer
- Fattura registrata
+ Invoice recorded
@@ -26,4 +23,55 @@
+
+
+ Refund Data
+
+
+
+
+
+
+
+
+
diff --git a/fiscal_epos_print/views/account_statement_view.xml b/fiscal_epos_print/views/account_statement_view.xml
index 38912cccd980..6cd577040091 100644
--- a/fiscal_epos_print/views/account_statement_view.xml
+++ b/fiscal_epos_print/views/account_statement_view.xml
@@ -2,14 +2,6 @@
-
-
-
-
-
-
-
-
POS Journal - Fiscal Printer field
account.journal
@@ -17,7 +9,9 @@
ref="point_of_sale.view_account_journal_pos_user_form"/>
-
+
+
diff --git a/fiscal_epos_print/views/assets.xml b/fiscal_epos_print/views/assets.xml
index 6e4b06b30570..a2a564263fd6 100644
--- a/fiscal_epos_print/views/assets.xml
+++ b/fiscal_epos_print/views/assets.xml
@@ -3,7 +3,12 @@
+
+
+
+
+
diff --git a/fiscal_epos_print/views/point_of_sale.xml b/fiscal_epos_print/views/point_of_sale.xml
index b8b68a4ce362..e16ba5d2b367 100644
--- a/fiscal_epos_print/views/point_of_sale.xml
+++ b/fiscal_epos_print/views/point_of_sale.xml
@@ -6,20 +6,34 @@
pos.config.form.printer.view
pos.config
-
+
Fiscal printer
+
-
+
+ pos.order.form
+ pos.order
+
+
+
+
+
+
+
+
+
+
+
+
From e363d83ed6ced920907453731744b823e6c4d41f Mon Sep 17 00:00:00 2001
From: eLBati
Date: Tue, 3 Dec 2019 12:16:03 +0100
Subject: [PATCH 03/65] Move Refund Info to a tab
trans
FIX journal form showing fiscalprinter data for bank journals
Allow to use tax exclude prices in products and force to set "Tax-Included Price" in pos config
REF file structure splitting fp90iii.js
Move "Wrong tax configuration" check before creating receipt
Update library ePOS-Print and Fiscal Print API
IMP fiscal_epos_print writing fiscal receipt data to pos.order
show_popup instead of alert
---
fiscal_epos_print/__manifest__.py | 6 +-
fiscal_epos_print/i18n/it.po | 260 ++++++-
fiscal_epos_print/models/pos_order.py | 39 +-
.../static/lib/fiscalprint/fiscalprint.js | 244 ++++++-
fiscal_epos_print/static/src/js/chrome.js | 48 ++
.../static/src/js/epson_epos_print.js | 375 ++++++++++
fiscal_epos_print/static/src/js/fp90iii.js | 658 ------------------
fiscal_epos_print/static/src/js/models.js | 165 ++++-
fiscal_epos_print/static/src/js/popups.js | 82 +++
.../static/src/js/pos_order_mgmt.js | 46 ++
fiscal_epos_print/static/src/js/screens.js | 162 +++++
fiscal_epos_print/static/src/xml/pos.xml | 11 +-
...account_statement_view.xml => account.xml} | 12 +-
fiscal_epos_print/views/assets.xml | 10 +-
fiscal_epos_print/views/point_of_sale.xml | 24 +-
15 files changed, 1414 insertions(+), 728 deletions(-)
create mode 100644 fiscal_epos_print/static/src/js/chrome.js
create mode 100644 fiscal_epos_print/static/src/js/epson_epos_print.js
delete mode 100644 fiscal_epos_print/static/src/js/fp90iii.js
create mode 100644 fiscal_epos_print/static/src/js/popups.js
create mode 100644 fiscal_epos_print/static/src/js/pos_order_mgmt.js
create mode 100644 fiscal_epos_print/static/src/js/screens.js
rename fiscal_epos_print/views/{account_statement_view.xml => account.xml} (66%)
diff --git a/fiscal_epos_print/__manifest__.py b/fiscal_epos_print/__manifest__.py
index e3aa3b4f44d8..7a9861da1ee9 100644
--- a/fiscal_epos_print/__manifest__.py
+++ b/fiscal_epos_print/__manifest__.py
@@ -17,14 +17,10 @@
'website': 'https://github.com/OCA/l10n-italy',
'depends': ['point_of_sale', 'pos_order_mgmt'],
'data': [
- 'views/account_statement_view.xml',
+ 'views/account.xml',
'views/point_of_sale.xml',
'views/assets.xml',
],
- 'js': [
- 'static/src/js/fp90iii.js',
- 'static/lib/fiscalprint/fiscalprint.js'
- ],
'qweb': [
'static/src/xml/pos.xml'
],
diff --git a/fiscal_epos_print/i18n/it.po b/fiscal_epos_print/i18n/it.po
index 177c792d61f9..f63d6a12af31 100644
--- a/fiscal_epos_print/i18n/it.po
+++ b/fiscal_epos_print/i18n/it.po
@@ -6,8 +6,8 @@ msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 12.0\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2019-10-29 10:20+0000\n"
-"PO-Revision-Date: 2019-10-29 10:20+0000\n"
+"POT-Creation-Date: 2019-12-12 08:14+0000\n"
+"PO-Revision-Date: 2019-12-12 08:14+0000\n"
"Last-Translator: <>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
@@ -17,19 +17,30 @@ msgstr ""
#. module: fiscal_epos_print
#. openerp-web
-#: code:addons/fiscal_epos_print/static/src/js/fp90iii.js:32
+#: code:addons/fiscal_epos_print/static/src/js/fp90iii.js:34
+#: code:addons/fiscal_epos_print/static/src/js/fp90iii.js:277
#, python-format
msgid "\n"
"Old files: "
-msgstr "\nFile vecchi: "
+msgstr "\n"
+"File vecchi: "
#. module: fiscal_epos_print
#. openerp-web
-#: code:addons/fiscal_epos_print/static/src/js/fp90iii.js:32
+#: code:addons/fiscal_epos_print/static/src/js/fp90iii.js:34
+#: code:addons/fiscal_epos_print/static/src/js/fp90iii.js:277
#, python-format
msgid "\n"
"Rejected files: "
-msgstr "\nFile rifiutati: "
+msgstr "\n"
+"File rifiutati: "
+
+#. module: fiscal_epos_print
+#. openerp-web
+#: code:addons/fiscal_epos_print/static/src/js/fp90iii.js:644
+#, python-format
+msgid "ADE files status"
+msgstr "Stato dei file ADE"
#. module: fiscal_epos_print
#. openerp-web
@@ -38,6 +49,20 @@ msgstr "\nFile rifiutati: "
msgid "ADE status"
msgstr "Stato ADE"
+#. module: fiscal_epos_print
+#. openerp-web
+#: code:addons/fiscal_epos_print/static/src/xml/pos.xml:62
+#, python-format
+msgid "Apply"
+msgstr "Applica"
+
+#. module: fiscal_epos_print
+#. openerp-web
+#: code:addons/fiscal_epos_print/static/src/xml/pos.xml:65
+#, python-format
+msgid "Cancel"
+msgstr "Annulla"
+
#. module: fiscal_epos_print
#: selection:account.journal,fiscalprinter_payment_type:0
msgid "Cash"
@@ -50,16 +75,29 @@ msgstr "Assegni"
#. module: fiscal_epos_print
#. openerp-web
-#: code:addons/fiscal_epos_print/static/src/js/fp90iii.js:260
+#: code:addons/fiscal_epos_print/static/src/js/fp90iii.js:285
+#: code:addons/fiscal_epos_print/static/src/js/fp90iii.js:624
#, python-format
msgid "Connecting to the fiscal printer"
msgstr "Connessione alla stampante fiscale"
+#. module: fiscal_epos_print
+#: model:ir.model.fields,field_description:fiscal_epos_print.field_account_journal__fiscalprinter_payment_index
+msgid "Credit Card/Ticket Index"
+msgstr "Index carta di credito / ticket"
+
#. module: fiscal_epos_print
#: selection:account.journal,fiscalprinter_payment_type:0
msgid "Credit/Credit Card"
msgstr "Carta di credito"
+#. module: fiscal_epos_print
+#. openerp-web
+#: code:addons/fiscal_epos_print/static/src/xml/pos.xml:53
+#, python-format
+msgid "DDMMYYYY"
+msgstr "GGMMAAAA"
+
#. module: fiscal_epos_print
#: model:ir.model.fields,field_description:fiscal_epos_print.field_account_tax__fpdeptax
msgid "Department group tax on fiscal printer 1~99"
@@ -67,23 +105,58 @@ msgstr "Reparto sulla stampante fiscale 1~99"
#. module: fiscal_epos_print
#. openerp-web
-#: code:addons/fiscal_epos_print/static/src/js/fp90iii.js:24
+#: code:addons/fiscal_epos_print/static/src/js/fp90iii.js:412
+#, python-format
+msgid "Discount"
+msgstr "Sconto"
+
+#. module: fiscal_epos_print
+#: model:ir.model.fields,field_description:fiscal_epos_print.field_pos_order__refund_doc_num
+msgid "Document Number"
+msgstr "Numero documento"
+
+#. module: fiscal_epos_print
+#. openerp-web
+#: code:addons/fiscal_epos_print/static/src/js/fp90iii.js:26
+#: code:addons/fiscal_epos_print/static/src/js/fp90iii.js:269
#, python-format
msgid "Error missing paper."
msgstr "Errore Manca La carta."
#. module: fiscal_epos_print
#. openerp-web
-#: code:addons/fiscal_epos_print/static/src/js/fp90iii.js:32
+#: code:addons/fiscal_epos_print/static/src/xml/pos.xml:18
+#, python-format
+msgid "Fattura registrata"
+msgstr ""
+
+#. module: fiscal_epos_print
+#. openerp-web
+#: code:addons/fiscal_epos_print/static/src/js/fp90iii.js:34
+#: code:addons/fiscal_epos_print/static/src/js/fp90iii.js:277
#, python-format
msgid "Files waiting to be sent: "
msgstr "File in attesa di essere inviati: "
+#. module: fiscal_epos_print
+#. openerp-web
+#: code:addons/fiscal_epos_print/static/src/js/fp90iii.js:455
+#, python-format
+msgid "Fiscal Closing"
+msgstr "Chiusura fiscale"
+
#. module: fiscal_epos_print
#: model_terms:ir.ui.view,arch_db:fiscal_epos_print.view_pos_config_printer_form
msgid "Fiscal printer"
msgstr "Stampante fiscale"
+#. module: fiscal_epos_print
+#. openerp-web
+#: code:addons/fiscal_epos_print/static/src/xml/pos.xml:15
+#, python-format
+msgid "Invoice recorded"
+msgstr "Fattura registrata"
+
#. module: fiscal_epos_print
#: model:ir.model,name:fiscal_epos_print.model_account_journal
msgid "Journal"
@@ -91,18 +164,42 @@ msgstr "Registro"
#. module: fiscal_epos_print
#. openerp-web
-#: code:addons/fiscal_epos_print/static/src/js/fp90iii.js:39
+#: code:addons/fiscal_epos_print/static/src/xml/pos.xml:43
+#: code:addons/fiscal_epos_print/static/src/xml/pos.xml:48
+#, python-format
+msgid "Max 4 numbers"
+msgstr "Massimo 4 numeri"
+
+#. module: fiscal_epos_print
+#. openerp-web
+#: code:addons/fiscal_epos_print/static/src/js/fp90iii.js:41
+#: code:addons/fiscal_epos_print/static/src/js/fp90iii.js:284
#, python-format
msgid "Network error. Printer can not be reached"
msgstr "Errore di rete. La stampante non può essere raggiunta"
#. module: fiscal_epos_print
#. openerp-web
-#: code:addons/fiscal_epos_print/static/src/js/fp90iii.js:162
+#: code:addons/fiscal_epos_print/static/src/js/fp90iii.js:164
+#: code:addons/fiscal_epos_print/static/src/js/fp90iii.js:485
#, python-format
msgid "No taxes found"
msgstr "Nessuna imposta trovata"
+#. module: fiscal_epos_print
+#. openerp-web
+#: code:addons/fiscal_epos_print/static/src/xml/pos.xml:46
+#, python-format
+msgid "Num. Scontrino"
+msgstr ""
+
+#. module: fiscal_epos_print
+#. openerp-web
+#: code:addons/fiscal_epos_print/static/src/js/fp90iii.js:350
+#, python-format
+msgid "Payment"
+msgstr "Pagamento"
+
#. module: fiscal_epos_print
#: model:ir.model.fields,field_description:fiscal_epos_print.field_account_journal__fiscalprinter_payment_type
msgid "Payment type"
@@ -113,11 +210,128 @@ msgstr "Tipo di pagamento"
msgid "Point of Sale Configuration"
msgstr "Configurazione punto vendita"
+#. module: fiscal_epos_print
+#: model:ir.model,name:fiscal_epos_print.model_pos_order
+msgid "Point of Sale Orders"
+msgstr "Ordini punto vendita"
+
#. module: fiscal_epos_print
#: model:ir.model.fields,field_description:fiscal_epos_print.field_pos_config__printer_ip
msgid "Printer IP Address"
msgstr "Indirizzo IP stampante"
+#. module: fiscal_epos_print
+#: code:addons/fiscal_epos_print/models/product.py:12
+#, python-format
+msgid "Product %s must have 1 tax"
+msgstr "Il prodotto %s deve avere un'imposta"
+
+#. module: fiscal_epos_print
+#: model:ir.model,name:fiscal_epos_print.model_product_template
+msgid "Product Template"
+msgstr "Modello prodotto"
+
+#. module: fiscal_epos_print
+#. openerp-web
+#: code:addons/fiscal_epos_print/static/src/xml/pos.xml:56
+#: code:addons/fiscal_epos_print/static/src/xml/pos.xml:58
+#, python-format
+msgid "RT Serial"
+msgstr "Seriale RT"
+
+#. module: fiscal_epos_print
+#. openerp-web
+#: code:addons/fiscal_epos_print/static/src/xml/pos.xml:51
+#, python-format
+msgid "Receipt Date"
+msgstr "Data scontrino"
+
+#. module: fiscal_epos_print
+#. openerp-web
+#: code:addons/fiscal_epos_print/static/src/xml/pos.xml:12
+#, python-format
+msgid "Receipt sent to the printer"
+msgstr "Scontrino inviato alla stampante"
+
+#. module: fiscal_epos_print
+#. openerp-web
+#: code:addons/fiscal_epos_print/static/src/js/fp90iii.js:424
+#, python-format
+msgid "Refund >>> "
+msgstr "Reso >>> "
+
+#. module: fiscal_epos_print
+#: model:ir.model.fields,field_description:fiscal_epos_print.field_pos_order__refund_cash_fiscal_serial
+msgid "Refund Cash Serial"
+msgstr "Matricola RT"
+
+#. module: fiscal_epos_print
+#. openerp-web
+#: code:addons/fiscal_epos_print/static/src/xml/pos.xml:28
+#, python-format
+msgid "Refund Data"
+msgstr "Dati reso"
+
+#. module: fiscal_epos_print
+#: model_terms:ir.ui.view,arch_db:fiscal_epos_print.view_pos_pos_form_refund_info
+msgid "Refund Info"
+msgstr "Informazioni reso"
+
+#. module: fiscal_epos_print
+#. openerp-web
+#: code:addons/fiscal_epos_print/static/src/js/fp90iii.js:126
+#, python-format
+msgid "Refund Information Details"
+msgstr "Dettagli reso"
+
+#. module: fiscal_epos_print
+#. openerp-web
+#: code:addons/fiscal_epos_print/static/src/js/fp90iii.js:47
+#, python-format
+msgid "Refund Information Not Present"
+msgstr "Informazioni reso non presenti"
+
+#. module: fiscal_epos_print
+#: model:ir.model.fields,field_description:fiscal_epos_print.field_pos_order__refund_date
+msgid "Refund date reference"
+msgstr "Data riferimento reso"
+
+#. module: fiscal_epos_print
+#: model:ir.model.fields,field_description:fiscal_epos_print.field_pos_order__refund_report
+msgid "Report reference"
+msgstr "Riferimento report"
+
+#. module: fiscal_epos_print
+#. openerp-web
+#: code:addons/fiscal_epos_print/static/src/xml/pos.xml:15
+#, python-format
+msgid "Scontrino inviato alla stampante"
+msgstr ""
+
+#. module: fiscal_epos_print
+#. openerp-web
+#: code:addons/fiscal_epos_print/static/src/xml/pos.xml:41
+#, python-format
+msgid "Seq. Closing"
+msgstr "Seq. Chiusura"
+
+#. module: fiscal_epos_print
+#: model:ir.model.fields,help:fiscal_epos_print.field_account_journal__fiscalprinter_payment_index
+msgid "Set the index of the given payment type to specify the detail. Such index of the payment type must programmed on the fiscal printer"
+msgstr "Impostare l'index del relativo tipo di pagamento, per specificare il dettaglio. Tale index deve essere impostato sulla stampante fiscale."
+
+#. module: fiscal_epos_print
+#: model:ir.model.fields,field_description:fiscal_epos_print.field_pos_config__show_receipt_when_printing
+msgid "Show receipt on screen when printing"
+msgstr "Mostrare a schermo lo scontrino in fase di stampa"
+
+#. module: fiscal_epos_print
+#. openerp-web
+#: code:addons/fiscal_epos_print/static/src/xml/pos.xml:69
+#, python-format
+msgid "Some fields are empty."
+msgstr "Alcuni campi sono vuoti."
+
#. module: fiscal_epos_print
#. openerp-web
#: code:addons/fiscal_epos_print/static/src/xml/pos.xml:6
@@ -130,6 +344,12 @@ msgstr "Stato dei file da inviare all'ADE"
msgid "Tax"
msgstr "Imposta"
+#. module: fiscal_epos_print
+#: code:addons/fiscal_epos_print/models/product.py:14
+#, python-format
+msgid "Tax %s must be included in price"
+msgstr "L'imposta %s deve essere inclusa nel prezzo"
+
#. module: fiscal_epos_print
#: model:ir.model.fields,help:fiscal_epos_print.field_pos_config__printer_ip
msgid "The hostname or ip address of the hardware printer, please fill this field if you want use you receipts printer"
@@ -138,7 +358,14 @@ msgstr ""
#. module: fiscal_epos_print
#: model:ir.model.fields,help:fiscal_epos_print.field_account_journal__fiscalprinter_payment_type
msgid "The payment type to send to the Fiscal Printer."
-msgstr ""
+msgstr "Il tipo di pagamento da inviare alla stampante fiscale."
+
+#. module: fiscal_epos_print
+#. openerp-web
+#: code:addons/fiscal_epos_print/static/src/js/fp90iii.js:48
+#, python-format
+msgid "The refund information aren't present. Please insert them before printing the receipt"
+msgstr "Le informazioni di reso non sono presenti. Prego inserirle prima di stampare lo scontrino"
#. module: fiscal_epos_print
#: selection:account.journal,fiscalprinter_payment_type:0
@@ -150,3 +377,12 @@ msgstr ""
msgid "Use https"
msgstr "Usa HTTPS"
+#. module: fiscal_epos_print
+#. openerp-web
+#: code:addons/fiscal_epos_print/static/src/xml/pos.xml:12
+#: code:addons/fiscal_epos_print/static/src/xml/pos.xml:22
+#: code:addons/fiscal_epos_print/static/src/xml/pos.xml:25
+#, python-format
+msgid "display:none"
+msgstr ""
+
diff --git a/fiscal_epos_print/models/pos_order.py b/fiscal_epos_print/models/pos_order.py
index 88939f963209..881e53b5b1f7 100644
--- a/fiscal_epos_print/models/pos_order.py
+++ b/fiscal_epos_print/models/pos_order.py
@@ -1,5 +1,4 @@
-# coding=utf-8
-
+from datetime import datetime
from odoo import fields, models, api
@@ -11,6 +10,13 @@ class PosOrder(models.Model):
refund_doc_num = fields.Integer(string='Document Number', digits=(4, 0))
refund_cash_fiscal_serial = fields.Char(string='Refund Cash Serial')
+ fiscal_receipt_number = fields.Integer(
+ string='Fiscal receipt number', digits=(4, 0))
+ fiscal_receipt_amount = fields.Float("Fiscal receipt amount")
+ fiscal_receipt_date = fields.Date(
+ "Fiscal receipt date", digits=(4, 0))
+ fiscal_z_rep_number = fields.Integer("Fiscal closure number")
+
@api.model
def _order_fields(self, ui_order):
res = super(PosOrder, self)._order_fields(ui_order)
@@ -30,4 +36,33 @@ def _prepare_done_order_for_pos(self):
res['refund_report'] = self.refund_report
res['refund_doc_num'] = self.refund_doc_num
res['refund_cash_fiscal_serial'] = self.refund_cash_fiscal_serial
+ res['fiscal_receipt_number'] = self.fiscal_receipt_number
+ res['fiscal_receipt_amount'] = self.fiscal_receipt_amount
+ res['fiscal_receipt_date'] = self.fiscal_receipt_date
+ res['fiscal_z_rep_number'] = self.fiscal_z_rep_number
+ return res
+
+ @api.model
+ def update_fiscal_receipt_values(self, pos_order):
+ po = self.search([('pos_reference', '=', pos_order.get('name'))])
+ receipt_no = int(pos_order.get('fiscal_receipt_number'))
+ receipt_date = datetime.strptime(pos_order.get(
+ 'fiscal_receipt_date'), '%d/%m/%Y').date().strftime('%Y-%m-%d')
+ receipt_amount = float(pos_order.get('fiscal_receipt_amount'))
+ fiscal_z_rep_number = int(pos_order.get('fiscal_z_rep_number'))
+ if po:
+ po.write({
+ 'fiscal_receipt_number': receipt_no,
+ 'fiscal_receipt_date': receipt_date,
+ 'fiscal_receipt_amount': receipt_amount,
+ 'fiscal_z_rep_number': fiscal_z_rep_number
+ })
+ return True
+
+ @api.model
+ def create_from_ui(self, orders):
+ res = super(PosOrder, self).create_from_ui(orders)
+ for order in orders:
+ if order['data'].get('fiscal_receipt_number'):
+ self.update_fiscal_receipt_values(order['data'])
return res
diff --git a/fiscal_epos_print/static/lib/fiscalprint/fiscalprint.js b/fiscal_epos_print/static/lib/fiscalprint/fiscalprint.js
index 5fc128e5ca6b..00763f0eb36f 100644
--- a/fiscal_epos_print/static/lib/fiscalprint/fiscalprint.js
+++ b/fiscal_epos_print/static/lib/fiscalprint/fiscalprint.js
@@ -1,13 +1,34 @@
//
// ePOS-Print and Fiscal Print API
//
-// Version 1.0.0
+// Version 1.1.0
//
-// Copyright (C) SEIKO EPSON CORPORATION 2012. All rights reserved.
+// Copyright (C) SEIKO EPSON CORPORATION 2018. All rights reserved.
//
+// 06/12/2012 1.0.0
+// First release.
+
+// 01/09/2014 1.0.1
+// 1. Added send timeout parameter (argument).
+// 2. Added onreceive res_add argument so that complete response can also be returned.
+// 3. onerror response generates FP_NO_ANSWER_NETWORK fixed text instead of xhr response.
+// 4. encodeBase64Binary object added for future use.
+
+
+// 23/03/2018 1.1.0
+// 1. Added empty node exception handling.
+// 2. Added "statusText" string field in result variable as "status" field is Integer which doesn't manage text
+// present in certain replies.
+// 3. Added callMode argument in send method so that either asynchronous or synchronous mode can be selected.
+// Use "async" for asynchronous otherwise defaults to synchronous.
+// If null, defaults to async.
+// Timeout only valid for async mode.
+
+
(function (window)
{
+
//
// Function: ePOSBuilder constructor
// Description: initialize an ePOS-Print XML Builder object
@@ -1144,7 +1165,7 @@
xhr.send(soap);
}
-
+
/*
Function: createXMLHttpRequest method
Description: create an XMLHttpRequest object
@@ -1152,7 +1173,7 @@
Return: object XMLHttpRequest object
Throws: object the browser does not equip XMLHttpRequest
*/
-
+
function createXMLHttpRequest()
{
var xhr = null;
@@ -1216,7 +1237,8 @@
}
-// F I S C A L --- F I S C A L --- F I S C A L --- F I S C A L --- F I S C A L
+// F I S C A L --- F I S C A L --- F I S C A L --- F I S C A L --- F I S C A L --- F I S C A L --- F I S C A L --- F I S C A L
+
/*
Function: fiscalPrint constructor
@@ -1224,13 +1246,13 @@
Parameters: none
Return: none
*/
-
+
function fiscalPrint()
{
// events
this.onreceive = null;
this.onerror = null;
-
+
// constants
this.ASB_NO_RESPONSE = 0x00000001;
this.ASB_PRINT_SUCCESS = 0x00000002;
@@ -1260,9 +1282,12 @@
Return: none
Throws: object The browser does not equip XMLHttpRequest
*/
-
- fiscalPrint.prototype.send = function (address, request)
+
+ fiscalPrint.prototype.send = function (address, request, timeout, callMode)
{
+ timeout = timeout || 0;
+ callMode = callMode || "async";
+
// create SOAP envelope
var soap = '\n' +
'\n' +
@@ -1272,13 +1297,31 @@
' \n';
// create XMLHttpRequest object
var xhr = createXMLHttpRequest();
- xhr.open('POST', address, true);
+ if (callMode == "async")
+ {
+ xhr.open('POST', address, true);
+ }
+ else
+ {
+ xhr.open('POST', address, false); // PHIL false = sincrono
+ }
// set headers
xhr.setRequestHeader('Content-Type', 'text/xml; charset=UTF-8');
xhr.setRequestHeader('If-Modified-Since', 'Thu, 01 Jan 1970 00:00:00 GMT');
xhr.setRequestHeader('SOAPAction', '""');
// receive event
var epos = this;
+
+ // PHIL timeout non va con le richieste sincrone
+ if (callMode == "async")
+ {
+ xhr.timeout = timeout;
+ xhr.ontimeout = function () {
+ console.log("Timed out!!!");
+ fireFiscalErrorEvent(epos, xhr);
+ }
+ }
+
xhr.onreadystatechange = function ()
{
// receive response message
@@ -1295,11 +1338,11 @@
}
}
}
+
// send request message
xhr.send(soap);
}
-
/*
Function: fireFiscalReceiveEvent method
Description: generate the onreceive event
@@ -1313,18 +1356,17 @@
{
if (epos.onreceive)
{
+ // alert ("xhr.responseXML.xml = " + xhr.responseXML.xml);
var res = xhr.responseXML.getElementsByTagName('response');
- // alert (xhr.responseXML.xml);
- // document.write(xhr.responseXML.xml);
-
if (res.length > 0)
{
// fire onreceive event
- var result =
+ var result =
{
success: /^(1|true)$/.test(res[0].getAttribute('success')),
code: res[0].getAttribute('code'),
- status: parseInt(res[0].getAttribute('status'))
+ status: parseInt(res[0].getAttribute('status')),
+ statusText: res[0].getAttribute('status')
};
// look for additional info
@@ -1336,20 +1378,35 @@
var tag_names_list = list[0].childNodes[0].nodeValue;
var tag_names_array = tag_names_list.split(',');
var add_info = {};
- for (var i = 0; i < tag_names_array.length; i++)
+
+ for (var tnai = 0; tnai < tag_names_array.length; tnai++)
{
- var node = res_add[0].getElementsByTagName(tag_names_array[i])[0];
+ var node = res_add[0].getElementsByTagName(tag_names_array[tnai])[0];
var node_child = node.childNodes[0];
- var node_val = node_child.nodeValue;
- add_info[tag_names_array[i]] = node_val;
+ var node_val = "";
+ // 21/02/2018 Philip Barnett. Alcuni comandi tornano con responseData vuoto. Senza la verifica, possono vericarsi i null Exceptiom.
+ // Questa riga non ha risolto il problema - if(node_child.nodeValue != null && node_child.nodeValue != "")
+ try
+ {
+ node_val = node_child.nodeValue;
+ }
+ catch(err) // Blank lines generate exceptions
+ {
+ // node_val = "Elemento " + node.childNodes[0] + " vuoto";
+ }
+ add_info[tag_names_array[tnai]] = node_val;
}
}
- epos.onreceive(result, tag_names_array, add_info)
+ else {
+ var tag_names_array = "";
+ var add_info = "";
+ }
+
+ epos.onreceive(result, tag_names_array, add_info, res_add)
}
else // res.length <= 0
{
// alert ("res.length = " + res.length);
- fireFiscalErrorEvent(epos, xhr);
} // end if (res.length > 0)
} // end if (epos.onreceive)
} // end function fireFiscalReceiveEvent(epos, xhr)
@@ -1370,10 +1427,14 @@
// alert("Error event called");
if (epos.onerror)
{
- epos.onerror({
- status: xhr.status,
- responseText: xhr.responseText
- });
+ var result =
+ {
+ success: 'false',
+ code: "FP_NO_ANSWER_NETWORK",
+ status: 0
+ };
+
+ epos.onerror(result)
}
}
@@ -1420,16 +1481,143 @@
this.send(address, builder.toString());
};
-
+
/*
Function: epson object
Description: append constructors to window object
*/
+
window.epson = {
ePOSBuilder: ePOSBuilder,
ePOSPrint: ePOSPrint,
fiscalPrint: fiscalPrint,
- CanvasPrint: CanvasPrint
+ CanvasPrint: CanvasPrint,
+ encodeBase64Binary: encodeBase64Binary
};
+
})(window);
+
+
+/*
+Function: decodeFpStatus
+Description: Decodes the five printer status bytes
+Parameters: add_info.fpstatus
+Return: printer, ej, receipt, cash_drawer and mode
+*/
+
+
+/*
+function decodeFpStatus(add_info.fpStatus)
+{
+
+ var printer = "";
+ var ej = "";
+ var cash_drawer = "";
+ var receipt = "";
+ var mode = "";
+
+ switch(add_info.fpStatus.substring(0,1)) {
+ case "0":
+ printer = "OK";
+ break;
+ case "2":
+ printer = "Carta in esaurimento";
+ break;
+ case "3":
+ printer = "Offline (fine carta o coperchio aperto)";
+ break;
+ default:
+ printer = "Risposta errata";
+ }
+
+ switch(add_info.fpStatus.substring(1,2)) {
+ case "0":
+ ej = "OK";
+ break;
+ case "1":
+ ej = "Prossimo ad Esaurimento";
+ break;
+ case "2":
+ ej = "Da formattare";
+ break;
+ case "3":
+ ej = "Precedente";
+ break;
+ case "4":
+ ej = "Di altro misuratore";
+ break;
+ case "5":
+ ej = "Esaurito";
+ break;
+ default:
+ ej = "Risposta errata";
+ }
+
+ switch(add_info.fpStatus.substring(2,3)) {
+ case "0":
+ cash_drawer = "Aperto";
+ break;
+ case "1":
+ cash_drawer = "Chiuso";
+ break;
+ default:
+ cash_drawer = "Risposta errata";
+ }
+
+ switch(add_info.fpStatus.substring(3,4)) {
+ case "0":
+ receipt = "Fiscale aperto";
+ break;
+ case "1":
+ receipt = "Fiscale/Non fiscale chiuso";
+ break;
+ case "2":
+ receipt = "Non fiscale aperto";
+ break;
+ case "3":
+ receipt = "Pagamento in corso";
+ break;
+ case "4":
+ receipt = "Errore ultimo comando ESC/POS con Fiscale/Non fiscale chiuso";
+ break;
+ case "5":
+ receipt = "Scontrino in negativo";
+ break;
+ case "6":
+ receipt = "Errore ultimo comando ESC/POS con Non fiscale aperto";
+ break;
+ case "7":
+ receipt = "Attesa chiusura scontrino modalità JAVAPOS";
+ break;
+ case "8":
+ receipt = "Documento fiscale aperto";
+ break;
+ case "A":
+ receipt = "Titolo aperto";
+ break;
+ case "2":
+ receipt = "Titolo chiuso";
+ break;
+ default:
+ receipt = "Risposta errata";
+ }
+
+ switch(add_info.fpStatus.substring(4,5)) {
+ case "0":
+ mode = "Stato registrazione";
+ break;
+ case "1":
+ mode = "Stato X";
+ break;
+ case "2":
+ mode = "Stato Z";
+ break;
+ case "3":
+ mode = "Stato Set";
+ break;
+ default:
+ mode = "Risposta errata";
+ }
+}
+*/
diff --git a/fiscal_epos_print/static/src/js/chrome.js b/fiscal_epos_print/static/src/js/chrome.js
new file mode 100644
index 000000000000..dcc2dfc8ff9d
--- /dev/null
+++ b/fiscal_epos_print/static/src/js/chrome.js
@@ -0,0 +1,48 @@
+odoo.define("fiscal_epos_print.chrome", function (require) {
+ "use strict";
+
+ var core = require("web.core");
+ var PosBaseWidget = require('point_of_sale.BaseWidget');
+ var chrome = require('point_of_sale.chrome');
+ var epson_epos_print = require('fiscal_epos_print.epson_epos_print');
+ var _t = core._t;
+ var eposDriver = epson_epos_print.eposDriver;
+
+ var FiscalPrinterADEFilesButtonWidget = PosBaseWidget.extend({
+ template: 'FiscalPrinterADEFilesButtonWidget',
+
+ button_click: function () {
+ this.chrome.loading_show();
+ this.chrome.loading_message(_t('Connecting to the fiscal printer'));
+ var protocol = ((this.pos.config.use_https) ? 'https://' : 'http://');
+ var printer_url = protocol + this.pos.config.printer_ip + '/cgi-bin/fpmate.cgi';
+ var printer_options = {url: printer_url};
+ var fp90 = new eposDriver(printer_options, this);
+ fp90.getStatusOfFilesForADE();
+ },
+
+ renderElement: function () {
+ var self = this;
+ this._super();
+ this.$el.click(function () {
+ self.button_click();
+ });
+ },
+
+ });
+
+ var widgets = chrome.Chrome.prototype.widgets;
+ widgets.push({
+ 'name': _t('ADE files status'),
+ 'widget': FiscalPrinterADEFilesButtonWidget,
+ 'append': '.pos-rightheader',
+ 'args': {
+ 'label': 'ADE files status',
+ },
+ });
+
+ return {
+ FiscalPrinterADEFilesButtonWidget: FiscalPrinterADEFilesButtonWidget,
+ };
+
+});
diff --git a/fiscal_epos_print/static/src/js/epson_epos_print.js b/fiscal_epos_print/static/src/js/epson_epos_print.js
new file mode 100644
index 000000000000..af3bb25bba22
--- /dev/null
+++ b/fiscal_epos_print/static/src/js/epson_epos_print.js
@@ -0,0 +1,375 @@
+odoo.define("fiscal_epos_print.epson_epos_print", function (require) {
+ "use strict";
+
+ var core = require("web.core");
+ var utils = require('web.utils');
+ var PosDB = require('point_of_sale.DB');
+ var rpc = require('web.rpc');
+ var _t = core._t;
+ var round_pr = utils.round_precision;
+
+ function addPadding(str, padding=4) {
+ var pad = new Array(padding).fill(0).join('') + str;
+ return pad.substr(pad.length - padding, padding);
+ }
+
+ function isErrorStatus(printerStatus) {
+ var error = false;
+ switch (printerStatus.substring(0, 2)) {
+ case "00":
+ case "01":
+ case "20":
+ case "21":
+ error = false;
+ break;
+ default:
+ error = true;
+ }
+ return error;
+ }
+
+ function decodeFpStatus(printerStatus) {
+ var printer = "";
+ var ej = "";
+ var receipt = "";
+
+ switch (printerStatus.substring(0, 1)) {
+ case "0":
+ printer = false;
+ break;
+ case "2":
+ printer = _t("Paper running low");
+ break;
+ case "3":
+ printer = _t("Offline (end of paper or open cover)");
+ break;
+ default:
+ printer = _t("Wrong answer");
+ }
+
+ switch (printerStatus.substring(1, 2)) {
+ case "0":
+ ej = false;
+ break;
+ case "1":
+ ej = _t("Running low");
+ break;
+ case "2":
+ ej = _t("To format");
+ break;
+ case "3":
+ ej = _t("Previous");
+ break;
+ case "4":
+ ej = _t("From other measurement device");
+ break;
+ case "5":
+ ej = _t("Finished");
+ break;
+ default:
+ ej = _t("Wrong answer");
+ }
+
+ switch (printerStatus.substring(3, 4)) {
+ case "0":
+ receipt = _t("Fiscal open");
+ break;
+ case "1":
+ receipt = false;
+ //receipt = "Fiscale/Non fiscale chiuso";
+ break;
+ case "2":
+ receipt = _t("Non fiscal open");
+ break;
+ case "3":
+ receipt = _t("Payment in progress");
+ break;
+ case "4":
+ receipt = _t("Error on last ESC/POS command with Fiscal/Non fiscal closed");
+ break;
+ case "5":
+ receipt = _t("Negative receipt");
+ break;
+ case "6":
+ receipt = _t("Error on last ESC/POS command with Non fiscal open");
+ break;
+ case "7":
+ receipt = _t("Waiting for receipt closing in JAVAPOS mode");
+ break;
+ case "8":
+ receipt = _t("Fiscal document open");
+ break;
+ case "A":
+ receipt = _t("Title open");
+ break;
+ case "B":
+ receipt = _t("Title closed");
+ break;
+ default:
+ receipt = _t("Wrong answer");
+ }
+
+ return printer || ej || receipt;
+ }
+
+ function getStatusField(tag){
+ return tag === 'printerStatus' || tag === 'fsStatus';
+ }
+
+ var eposDriver = core.Class.extend({
+ init: function(options, sender) {
+ var self = this;
+ options = options || {};
+ this.url = options.url || 'http://192.168.1.1/cgi-bin/fpmate.cgi';
+ this.fiscalPrinter = new epson.fiscalPrint();
+ this.fpresponse = false;
+ this.sender = sender;
+ this.order = options.order || null;
+ this.fiscalPrinter.onreceive = function(res, tag_list_names, add_info) {
+ self.fpresponse = tag_list_names
+ var tagStatus = tag_list_names.filter(getStatusField);
+ if (res['code'] == "EPTR_REC_EMPTY"){
+ sender.chrome.loading_hide();
+ sender.pos.gui.show_popup('error', {
+ 'title': _t('Error'),
+ 'body': _t('Missing paper'),
+ });
+ }
+ else if (add_info.responseCommand == "1138") {
+ // coming from FiscalPrinterADEFilesButtonWidget
+ sender.chrome.loading_hide();
+ var to_be_sent = add_info.responseData[9] + add_info.responseData[10] + add_info.responseData[11] + add_info.responseData[12];
+ var old = add_info.responseData[13] + add_info.responseData[14] + add_info.responseData[15] + add_info.responseData[16];
+ var rejected = add_info.responseData[17] + add_info.responseData[18] + add_info.responseData[19] + add_info.responseData[20];
+ var msg = _t("Files waiting to be sent: ") + to_be_sent + "; " + _t("Old files: ") + old + "; " + _t("Rejected files: ") + rejected;
+ sender.pos.gui.show_popup('alert', {
+ 'title': _t('ADE files'),
+ 'body': msg,
+ });
+ }
+ else if (tagStatus.length > 0 && res.success) {
+ var info = add_info[tagStatus[0]];
+ var msgPrinter = decodeFpStatus(info);
+ if (!isErrorStatus(info)) {
+ var order = self.order;
+ if (!order.fiscal_receipt_number) {
+ order.fiscal_receipt_number = parseInt(add_info.fiscalReceiptNumber);
+ order.fiscal_receipt_amount = parseFloat(add_info.fiscalReceiptAmount.replace(',', '.'));
+ order.fiscal_receipt_date = add_info.fiscalReceiptDate;
+ order.fiscal_z_rep_number = add_info.zRepNumber;
+ sender.pos.db.add_order(order.export_as_JSON());
+ }
+ }
+ else {
+ sender.pos.gui.show_popup('error', {
+ 'title': _t('Connection to the printer failed'),
+ 'body': msgPrinter,
+ });
+ };
+ }
+ else {
+ sender.pos.gui.show_popup('error', {
+ 'title': _t('Connection to the printer failed'),
+ 'body': _t('An error happened while sending data to the printer. Error code: ') + res.code,
+ });
+ };
+ }
+ this.fiscalPrinter.onerror = function() {
+ sender.chrome.loading_hide();
+ sender.pos.gui.show_popup('error', {
+ 'title': _t('Network error'),
+ 'body': _t('Printer can not be reached')
+ });
+ }
+ },
+
+ /*
+ Prints a sale item line.
+ */
+ printRecItem: function(args) {
+ var tag = ' ';
+ return tag;
+ },
+
+ /*
+ Prints a sale refund item line.
+ */
+ printRecRefund: function(args) {
+ var message = 'REFUND ' +
+ addPadding(args.refund_report) + ' ' +
+ addPadding(args.refund_doc_num) + ' ' +
+ args.refund_date + ' ' +
+ args.refund_cash_fiscal_serial;
+
+ var tag = ' \n'
+ + ' ';
+ return tag;
+ },
+
+ /*
+ Adds a discount to the last line.
+ */
+ printRecItemAdjustment: function(args) {
+ var tag = ' ';
+ return tag;
+ },
+
+ /*
+ Prints a payment.
+ */
+ printRecTotal: function(args) {
+ var tag = ' ';
+ return tag;
+ },
+
+ // Remember that the header goes after
+ // but before otherwise it will not be printed
+ // as additional header messageType=1
+ printFiscalReceiptHeader: function(receipt){
+ var msg = '';
+ if (receipt.header != '' && receipt.header.length > 0) {
+ var hdr = receipt.header.split(/\r\n|\r|\n/);
+ _.each(hdr, function(m, i) {
+ msg += ' '
+ });
+ }
+ return msg;
+ },
+
+ // Remember that the footer goes within
+ // as PROMO code messageType=3
+ printFiscalReceiptFooter: function(receipt){
+ var msg = '';
+ if (receipt.footer != '' && receipt.footer.length > 0) {
+ var hdr = receipt.footer.split(/\r\n|\r|\n/);
+ _.each(hdr, function(m, i) {
+ msg += ' '
+ });
+ }
+ return msg;
+ },
+
+ /*
+ Prints a receipt
+ */
+ printFiscalReceipt: function(receipt) {
+ var self = this;
+ var xml = '';
+ // header must be printed before beginning a fiscal receipt
+ xml += this.printFiscalReceiptHeader(receipt);
+ xml += ' ';
+ // footer can go only as promo code so within a fiscal receipt body
+ xml += this.printFiscalReceiptFooter(receipt);
+ _.each(receipt.orderlines, function(l, i, list) {
+ if (l.price >= 0) {
+ if(l.quantity>=0) {
+ var full_price = l.price;
+ if (l.discount) {
+ full_price = round_pr(l.price / (1 - (l.discount / 100)), self.sender.pos.currency.rounding);
+ }
+ xml += self.printRecItem({
+ description: l.product_name,
+ quantity: l.quantity,
+ unitPrice: full_price,
+ department: l.tax_department.code
+ });
+ if (l.discount) {
+ xml += self.printRecItemAdjustment({
+ adjustmentType: 0,
+ description: _t('Discount') + ' ' + l.discount + '%',
+ amount: round_pr((l.quantity * full_price) - (l.quantity * l.price), self.sender.pos.currency.rounding),
+ });
+ }
+ }
+ else
+ {
+ xml += self.printRecRefund({
+ refund_date: receipt.refund_date,
+ refund_report: receipt.refund_report,
+ refund_doc_num: receipt.refund_doc_num,
+ refund_cash_fiscal_serial: receipt.refund_cash_fiscal_serial,
+ description: _t('Refund >>> ') + l.product_name,
+ quantity: l.quantity * -1.0,
+ unitPrice: l.price,
+ department: l.tax_department.code
+ });
+ }
+ }
+ else {
+ xml += self.printRecItemAdjustment({
+ adjustmentType: 3,
+ description: l.product_name,
+ department: l.tax_department.code,
+ amount: -l.price,
+ });
+ }
+ });
+ _.each(receipt.paymentlines, function(l, i, list) {
+ xml += self.printRecTotal({
+ payment: l.amount,
+ paymentType: l.type,
+ paymentIndex: l.type_index,
+ description: l.journal,
+ });
+ });
+ xml += ' ';
+ this.fiscalPrinter.send(this.url, xml);
+ console.log(xml);
+ },
+
+ printFiscalReport: function() {
+ var xml = '';
+ xml += ' ';
+ xml += ' ';
+ xml += ' ';
+ this.fiscalPrinter.send(this.url, xml);
+ },
+
+ getStatusOfFilesForADE: function() {
+ var xml = '';
+ xml += ' ';
+ xml += ' ';
+ this.fiscalPrinter.send(this.url, xml);
+ },
+
+ });
+
+ return {
+ eposDriver: eposDriver
+ }
+
+});
diff --git a/fiscal_epos_print/static/src/js/fp90iii.js b/fiscal_epos_print/static/src/js/fp90iii.js
deleted file mode 100644
index 5cf310696b04..000000000000
--- a/fiscal_epos_print/static/src/js/fp90iii.js
+++ /dev/null
@@ -1,658 +0,0 @@
-odoo.define("fiscal_epos_print.models", function (require) {
- "use strict";
-
- var models = require("point_of_sale.models");
- var core = require("web.core");
- var screens = require('point_of_sale.screens');
- var utils = require('web.utils');
- var PosBaseWidget = require('point_of_sale.BaseWidget');
- var chrome = require('point_of_sale.chrome');
- var round_pr = utils.round_precision;
- var pos_order_mgmt = require('pos_order_mgmt.widgets');
- var pos_popup = require('point_of_sale.popups');
- var gui = require('point_of_sale.gui');
- var _t = core._t;
- var OrderListScreenWidget = pos_order_mgmt.OrderListScreenWidget;
- var OrderSuper = models.Order;
- var RefundInfoPopupWidgetSuper = pos_popup;
- var PaymentScreenWidget = screens.PaymentScreenWidget;
- var ReceiptScreenWidget = screens.ReceiptScreenWidget;
-
- function addPadding(str, padding=4) {
- var pad = new Array(padding).fill(0).join('') + str;
- return pad.substr(pad.length - padding, padding);
- }
-
- ReceiptScreenWidget.include({
- show: function(){
- if (!this.pos.config.printer_ip || (this.pos.config.printer_ip && this.pos.config.show_receipt_when_printing) ){
- this._super();
- }
- else
- {
- this.click_next();
- }
- }
- });
-
- PaymentScreenWidget.include({
- order_is_valid: function(force_validation) {
- var self = this;
- var receipt = this.pos.get_order();
- if (receipt.has_refund && (receipt.refund_date == null || receipt.refund_date === '' ||
- receipt.refund_doc_num == null || receipt.refund_doc_num == '' ||
- receipt.refund_cash_fiscal_serial == null || receipt.refund_cash_fiscal_serial == '' ||
- receipt.refund_report == null || receipt.refund_report == '')) {
- this.gui.show_popup('error',{
- 'title': _t('Refund Information Not Present'),
- 'body': _t("The refund information aren't present. Please insert them before printing the receipt"),
- });
- return false;
- }
- return this._super(force_validation);
- }
- });
-
- models.Order = models.Order.extend({
- initialize: function(attributes, options){
- OrderSuper.prototype.initialize.call(this, attributes,options);
- this.refund_report = null;
- this.refund_date = null;
- this.refund_doc_num = null;
- this.refund_cash_fiscal_serial = null;
- this.has_refund = false;
- },
- check_order_has_refund: function() {
- var order = this.pos.get_order();
- if (order) {
- var lines = order.orderlines;
- order.has_refund = lines.find(function(line){ return line.quantity < 0.0;}) != undefined;
- }
- },
-
- init_from_JSON: function (json) {
- OrderSuper.prototype.init_from_JSON.apply(this, arguments);
- this.refund_report = json.refund_report;
- this.refund_date = json.refund_date;
- this.refund_doc_num = json.refund_doc_num;
- this.refund_cash_fiscal_serial = json.refund_cash_fiscal_serial;
- this.check_order_has_refund();
- },
-
- export_as_JSON: function() {
- var result = OrderSuper.prototype.export_as_JSON.call(this);
- result.refund_report = this.refund_report;
- result.refund_date = this.refund_date ? this.refund_date.substr(4, 4) + '-' + // year
- this.refund_date.substr(2, 2) + '-' + // month
- this.refund_date.substr(0, 2) : null; // day
- result.refund_doc_num = this.refund_doc_num;
- result.refund_cash_fiscal_serial = this.refund_cash_fiscal_serial;
- return result;
- },
-
- export_for_printing: function(){
- var receipt = OrderSuper.prototype.export_for_printing.call(this);
-
- receipt.refund_date = this.refund_date;
- receipt.refund_report = this.refund_report;
- receipt.refund_doc_num = this.refund_doc_num;
- receipt.refund_cash_fiscal_serial = this.refund_cash_fiscal_serial;
-
- return receipt
- },
- });
-
- var set_refund_info_button = screens.ActionButtonWidget.extend({
- template: 'SetRefundInfoButton',
- init: function(parent, options) {
- var self = this;
- this._super(parent, options);
- this.pos.bind('change:selectedOrder',function(){
- this.orderline_change();
- this.bind_order_events();
- },this);
- this.bind_order_events();
- this.orderline_change();
- },
- renderElement: function() {
- this._super();
- var color = this.refund_get_button_color();
- this.$el.css('background', color);
- },
- button_click: function () {
- var self = this;
- var current_order = self.pos.get_order();
- self.gui.show_popup('refundinfo', {
- title: _t('Refund Information Details'),
- refund_date: current_order.refund_date,
- refund_report: current_order.refund_report,
- refund_doc_num: current_order.refund_doc_num,
- refund_cash_fiscal_serial: current_order.refund_cash_fiscal_serial,
- update_refund_info_button: function(){
- self.renderElement();
- },
- });
- },
- bind_order_events: function() {
- var self = this;
- var order = this.pos.get_order();
-
- if (!order) {
- return;
- }
-
- if(this.old_order) {
- this.old_order.unbind(null,null,this);
- }
-
- this.pos.bind('change:selectedOrder', this.orderline_change, this);
-
- var lines = order.orderlines;
- lines.unbind('add', this.orderline_change, this);
- lines.bind('add', this.orderline_change, this);
- lines.unbind('remove', this.orderline_change, this);
- lines.bind('remove', this.orderline_change, this);
- lines.unbind('change', this.orderline_change, this);
- lines.bind('change', this.orderline_change, this);
-
- this.old_order = order;
- },
- refund_get_button_color: function() {
- var order = this.pos.get_order();
- var lines = order.orderlines;
- var has_refund = lines.find(function(line){ return line.quantity < 0.0;}) != undefined;
- var color = '#e2e2e2';
- if (has_refund == true)
- {
- if (order.refund_date && order.refund_date != '' && order.refund_doc_num && order.refund_doc_num != '' &&
- order.refund_cash_fiscal_serial && order.refund_cash_fiscal_serial != '' && order.refund_report && order.refund_report != '') {
- color = 'lightgreen';
- }
- else
- {
- color = 'red';
- }
- }
- return color;
- },
- orderline_change: function(){
- var order = this.pos.get_order();
- var lines = order.orderlines;
- order.has_refund = lines.find(function(line){ return line.quantity < 0.0;}) != undefined;
- this.renderElement();
- },
- });
-
- screens.define_action_button({
- 'name': 'set_refund_info',
- 'widget': set_refund_info_button,
- });
-
- var RefundInfoPopupWidget = pos_popup.extend({
- template: 'RefundInfoPopupWidget',
- init: function(parent) {
- this.refund_report = null;
- this.refund_date = null;
- this.refund_doc_num = null;
- this.refund_cash_fiscal_serial = null;
- this.datepicker = null;
- return this._super(parent);
- },
- show: function(options){
- options = options || {};
- this._super(options);
- this.update_refund_info_button = options.update_refund_info_button;
- this.renderElement();
- this.datepicker = null;
- this.$('refund_report').focus();
- this.initializeDatePicker();
- },
- click_confirm: function(){
- var self = this;
- function allValid() {
- return self.$('input').toArray().every(function(element) {
- return element.value && element.value != ''
- })
- }
-
- if (allValid()) {
- this.$('#error-message-dialog').hide()
-
- var order = this.pos.get_order();
- order.refund_report = this.$('#refund_report').val();
- order.refund_date = this.$('#refund_date').val();
- order.refund_doc_num = this.$('#refund_doc_num').val();
- order.refund_cash_fiscal_serial = this.$('#refund_cash_fiscal_serial').val();
- this.gui.close_popup();
- if (this.update_refund_info_button && this.update_refund_info_button instanceof Function) {
- this.update_refund_info_button();
- }
- } else {
- this.$('#error-message-dialog').show()
- }
- },
- initializeDatePicker: function() {
- var self = this,
- element = this.$('#refund_date').get(0);
-
- if (element && !this.datepicker) {
- this.datepicker = new Pikaday({
- field: element,
- parse: function(str) {
- return new Date(str.slice(4, 8),
- str.slice(2, 4),
- str.slice(0, 2))
- },
- toString: function(date) {
- var str = date.toLocaleDateString().split('/');
- return addPadding(str[1], 2) +
- addPadding(str[0], 2) +
- addPadding(str[2]);
- }
- });
- }
- },
- });
- gui.define_popup({name:'refundinfo', widget: RefundInfoPopupWidget});
-
- var eposDriver = core.Class.extend({
- init: function(options, sender) {
- options = options || {};
- this.url = options.url || 'http://192.168.1.1/cgi-bin/fpmate.cgi';
- this.fiscalPrinter = new epson.fiscalPrint();
- this.fpreponse = false;
- this.sender = sender;
- this.fiscalPrinter.onreceive = function(res, tag_list_names, add_info) {
- this.fpreponse = tag_list_names
- if (res['code'] == "EPTR_REC_EMPTY"){
- sender.chrome.loading_hide();
- alert(_t("Error missing paper."));
- }
- if (add_info.responseCommand == "1138") {
- // coming from FiscalPrinterADEFilesButtonWidget
- sender.chrome.loading_hide();
- var to_be_sent = add_info.responseData[9] + add_info.responseData[10] + add_info.responseData[11] + add_info.responseData[12];
- var old = add_info.responseData[13] + add_info.responseData[14] + add_info.responseData[15] + add_info.responseData[16];
- var rejected = add_info.responseData[17] + add_info.responseData[18] + add_info.responseData[19] + add_info.responseData[20];
- var msg = _t("Files waiting to be sent: ") + to_be_sent + _t("\nOld files: ") + old + _t("\nRejected files: ") + rejected
- alert(msg);
- }
- }
- this.fiscalPrinter.onerror = function() {
- sender.chrome.loading_hide();
- alert(
- _t('Network error. Printer can not be reached')
- );
- }
- },
-
- /*
- Prints a sale item line.
- */
- printRecItem: function(args) {
- var tag = ' ';
- return tag;
- },
-
- /*
- Prints a sale refund item line.
- */
- printRecRefund: function(args) {
- var message = 'REFUND ' +
- addPadding(args.refund_report) + ' ' +
- addPadding(args.refund_doc_num) + ' ' +
- args.refund_date + ' ' +
- args.refund_cash_fiscal_serial;
-
- var tag = ' \n'
- + ' ';
- return tag;
- },
-
- /*
- Adds a discount to the last line.
- */
- printRecItemAdjustment: function(args) {
- var tag = ' ';
- return tag;
- },
-
- /*
- Prints a payment.
- */
- printRecTotal: function(args) {
- var tag = ' ';
- return tag;
- },
-
- // Remember that the header goes after
- // but before otherwise it will not be printed
- // as additional header messageType=1
- printFiscalReceiptHeader: function(receipt){
- var msg = '';
- if (receipt.header != '' && receipt.header.length > 0) {
- var hdr = receipt.header.split(/\r\n|\r|\n/);
- _.each(hdr, function(m, i) {
- msg += ' '
- });
- }
- return msg;
- },
-
- // Remember that the footer goes within
- // as PROMO code messageType=3
- printFiscalReceiptFooter: function(receipt){
- var msg = '';
- if (receipt.footer != '' && receipt.footer.length > 0) {
- var hdr = receipt.footer.split(/\r\n|\r|\n/);
- _.each(hdr, function(m, i) {
- msg += ' '
- });
- }
- return msg;
- },
-
- /*
- Prints a receipt
- */
- printFiscalReceipt: function(receipt) {
- var self = this;
- var xml = '';
- // header must be printed before beginning a fiscal receipt
- xml += this.printFiscalReceiptHeader(receipt);
- xml += ' ';
- // footer can go only as promo code so within a fiscal receipt body
- xml += this.printFiscalReceiptFooter(receipt);
- _.each(receipt.orderlines, function(l, i, list) {
- if (l.price >= 0) {
- if(l.quantity>=0) {
- xml += self.printRecItem({
- description: l.product_name,
- quantity: l.quantity,
- unitPrice: l.price,
- department: l.tax_department.code
- });
- if (l.discount) {
- xml += self.printRecItemAdjustment({
- adjustmentType: 0,
- description: _t('Discount') + ' ' + l.discount + '%',
- amount: round_pr(l.quantity * l.price - l.price_display, self.sender.pos.currency.rounding),
- });
- }
- }
- else
- {
- xml += self.printRecRefund({
- refund_date: receipt.refund_date,
- refund_report: receipt.refund_report,
- refund_doc_num: receipt.refund_doc_num,
- refund_cash_fiscal_serial: receipt.refund_cash_fiscal_serial,
- description: _t('Refund >>> ') + l.product_name,
- quantity: l.quantity * -1.0,
- unitPrice: l.price,
- department: l.tax_department.code
- });
- }
- }
- else {
- xml += self.printRecItemAdjustment({
- adjustmentType: 3,
- description: l.product_name,
- department: l.tax_department.code,
- amount: -l.price,
- });
- }
- });
- _.each(receipt.paymentlines, function(l, i, list) {
- xml += self.printRecTotal({
- payment: l.amount,
- paymentType: l.type,
- paymentIndex: l.type_index,
- description: l.journal,
- });
- });
- xml += ' ';
- this.fiscalPrinter.send(this.url, xml);
- console.log(xml);
- },
-
- printFiscalReport: function() {
- var xml = '';
- xml += ' ';
- xml += ' ';
- xml += ' ';
- this.fiscalPrinter.send(this.url, xml);
- },
-
- getStatusOfFilesForADE: function() {
- var xml = '';
- xml += ' ';
- xml += ' ';
- this.fiscalPrinter.send(this.url, xml);
- },
-
- });
-
- var _orderline_super = models.Orderline.prototype;
- models.Orderline = models.Orderline.extend({
- export_for_printing: function(){
- var res = _orderline_super.export_for_printing.call(this, arguments);
- res['tax_department'] = this.get_tax_details_r();
- return res;
- },
- get_tax_details_r: function(){
- var details = this.get_all_prices();
- for (var i in details.taxDetails){
- return {
- code: this.pos.taxes_by_id[i].fpdeptax,
- taxname: this.pos.taxes_by_id[i].name,
- }
- }
- alert(_t("No taxes found"));
- },
- compute_all: function(taxes, price_unit, quantity, currency_rounding, no_map_tax) {
- var res = _orderline_super.compute_all.call(this, taxes, price_unit, quantity, currency_rounding, no_map_tax);
- var self = this;
-
- var total_excluded = round_pr(price_unit * quantity, currency_rounding);
- var total_included = total_excluded;
- var base = total_excluded;
- var list_taxes = res.taxes;
- // amount_type 'group' not handled (used only for purchases, in Italy)
- _(taxes).each(function(tax) {
- if (!no_map_tax){
- tax = self._map_tax_fiscal_position(tax);
- }
- if (!tax){
- return;
- }
- var tax_amount = self._compute_all(tax, base, quantity);
- tax_amount = round_pr(tax_amount, currency_rounding);
- if (!tax_amount){
- // Intervene here: also add taxes with 0 amount
- if (tax.price_include) {
- total_excluded -= tax_amount;
- base -= tax_amount;
- }
- else {
- total_included += tax_amount;
- }
- if (tax.include_base_amount) {
- base += tax_amount;
- }
- var data = {
- id: tax.id,
- amount: tax_amount,
- name: tax.name,
- };
- list_taxes.push(data);
- }
- });
- res.taxes = list_taxes;
-
- return res;
- },
- });
-
- /*
- Overwrite Paymentline.export_for_printing() in order
- to make it export the payment type that must be passed
- to the fiscal printer.
- */
- var original = models.Paymentline.prototype.export_for_printing;
- models.Paymentline = models.Paymentline.extend({
- export_for_printing: function() {
- var res = original.apply(this, arguments);
- res.type = this.cashregister.journal.fiscalprinter_payment_type;
- res.type_index = this.cashregister.journal.fiscalprinter_payment_index;
- return res;
- }
- });
-
- // when print order i validate call print receipt
- screens.PaymentScreenWidget.include({
- getPrinterOptions: function (){
- var protocol = ((this.pos.config.use_https) ? 'https://' : 'http://');
- var printer_url = protocol + this.pos.config.printer_ip + '/cgi-bin/fpmate.cgi';
- return {url: printer_url};
- },
- sendToFP90Printer: function(receipt, printer_options) {
- var fp90 = new eposDriver(printer_options, this);
- fp90.printFiscalReceipt(receipt);
- },
- finalize_validation: function() {
- // we need to get currentOrder before calling the _super()
- // otherwise we will likely get a empty order when we want to skip
- // the receipt preview
- var currentOrder = this.pos.get('selectedOrder');
- this._super.apply(this, arguments);
- if (this.pos.config.printer_ip && !currentOrder.is_to_invoice()) {
- var printer_options = this.getPrinterOptions();
- var receipt = currentOrder.export_for_printing();
- this.sendToFP90Printer(receipt, printer_options);
- currentOrder._printed = true;
- }
- }
-
- });
-
- var _super_posmodel = models.PosModel.prototype;
- models.PosModel = models.PosModel.extend({
- initialize: function (session, attributes) {
- var tax_model = _.find(this.models, function(model){ return model.model === 'account.tax'; });
- tax_model.fields.push('fpdeptax');
- return _super_posmodel.initialize.call(this, session, attributes);
- },
- });
-
- OrderListScreenWidget.include({
- _prepare_order_from_order_data: function (order_data, action) {
- var order = this._super(order_data, action);
- order.refund_report = order_data.refund_report;
- order.refund_date = order_data.refund_date ? order_data.refund_date.substr(8, 2) + // day
- order_data.refund_date.substr(5, 2) + // month
- order_data.refund_date.substr(0, 4) // year
- : null;
- order.refund_doc_num = order_data.refund_doc_num;
- order.refund_cash_fiscal_serial = order_data.refund_cash_fiscal_serial;
-
- return order;
- },
- // copiato da screens.PaymentScreenWidget
- getPrinterOptions: function (){
- var protocol = ((this.pos.config.use_https) ? 'https://' : 'http://');
- var printer_url = protocol + this.pos.config.printer_ip + '/cgi-bin/fpmate.cgi';
- return [{url: printer_url}];
- },
- // copiato da screens.PaymentScreenWidget
- sendToFP90Printer: function(receipt, printer_options) {
- for (var i = 0; i < printer_options.length; i++){
- var printer_option = printer_options[i];
- var fp90 = new eposDriver(printer_option, this);
- fp90.printFiscalReceipt(receipt);
- }
- },
- action_print: function (order_data, order) {
- if (this.pos.config.printer_ip) {
- var receipt = order.export_for_printing();
- var printer_options = this.getPrinterOptions();
- this.sendToFP90Printer(receipt, printer_options);
- }
- return this._super(order_data, order);
- },
- });
-
- var FiscalPrinterADEFilesButtonWidget = PosBaseWidget.extend({
- template: 'FiscalPrinterADEFilesButtonWidget',
-
- button_click: function () {
- this.chrome.loading_show();
- this.chrome.loading_message(_t('Connecting to the fiscal printer'));
- var protocol = ((this.pos.config.use_https) ? 'https://' : 'http://');
- var printer_url = protocol + this.pos.config.printer_ip + '/cgi-bin/fpmate.cgi';
- var printer_options = {url: printer_url};
- var fp90 = new eposDriver(printer_options, this);
- fp90.getStatusOfFilesForADE();
- },
-
- renderElement: function () {
- var self = this;
- this._super();
- this.$el.click(function () {
- self.button_click();
- });
- },
-
- });
-
- var widgets = chrome.Chrome.prototype.widgets;
- widgets.push({
- 'name': _t('ADE files status'),
- 'widget': FiscalPrinterADEFilesButtonWidget,
- 'append': '.pos-rightheader',
- 'args': {
- 'label': 'ADE files status',
- },
- });
-
- return {
- eposDriver: eposDriver,
- FiscalPrinterADEFilesButtonWidget: FiscalPrinterADEFilesButtonWidget,
- RefundInfoButtonActionWidget: set_refund_info_button
- };
-
-});
diff --git a/fiscal_epos_print/static/src/js/models.js b/fiscal_epos_print/static/src/js/models.js
index cde2df08ea8e..2bc217566e49 100644
--- a/fiscal_epos_print/static/src/js/models.js
+++ b/fiscal_epos_print/static/src/js/models.js
@@ -1,8 +1,167 @@
-odoo.define('fiscal_epos_print.fiscalcode_field', function (require) {
+odoo.define('fiscal_epos_print.models', function (require) {
"use strict";
- var pos_models = require('point_of_sale.models');
- pos_models.load_fields("account.journal",
+ var models = require('point_of_sale.models');
+ var core = require("web.core");
+ var utils = require('web.utils');
+ var _t = core._t;
+ var round_pr = utils.round_precision;
+ var OrderSuper = models.Order;
+
+ models.load_fields("account.journal",
["fiscalprinter_payment_type", "fiscalprinter_payment_index"]);
+ models.Order = models.Order.extend({
+ initialize: function(attributes, options){
+ OrderSuper.prototype.initialize.call(this, attributes,options);
+ this.refund_report = null;
+ this.refund_date = null;
+ this.refund_doc_num = null;
+ this.refund_cash_fiscal_serial = null;
+ this.has_refund = false;
+ this.fiscal_receipt_number = null;
+ this.fiscal_receipt_amount = null;
+ this.fiscal_receipt_date = null;
+ this.fiscal_z_rep_number = null;
+ },
+ check_order_has_refund: function() {
+ var order = this.pos.get_order();
+ if (order) {
+ var lines = order.orderlines;
+ order.has_refund = lines.find(function(line){ return line.quantity < 0.0;}) != undefined;
+ }
+ },
+
+ init_from_JSON: function (json) {
+ OrderSuper.prototype.init_from_JSON.apply(this, arguments);
+ this.refund_report = json.refund_report;
+ this.refund_date = json.refund_date;
+ this.refund_doc_num = json.refund_doc_num;
+ this.refund_cash_fiscal_serial = json.refund_cash_fiscal_serial;
+ this.check_order_has_refund();
+ this.fiscal_receipt_number = json.fiscal_receipt_number;
+ this.fiscal_receipt_amount = json.fiscal_receipt_amount;
+ this.fiscal_receipt_date = json.fiscal_receipt_date;
+ this.fiscal_z_rep_number = json.fiscal_z_rep_number;
+ },
+
+ export_as_JSON: function() {
+ var result = OrderSuper.prototype.export_as_JSON.call(this);
+ result.refund_report = this.refund_report;
+ result.refund_date = this.refund_date ? this.refund_date.substr(4, 4) + '-' + // year
+ this.refund_date.substr(2, 2) + '-' + // month
+ this.refund_date.substr(0, 2) : null; // day
+ result.refund_doc_num = this.refund_doc_num;
+ result.refund_cash_fiscal_serial = this.refund_cash_fiscal_serial;
+ result.fiscal_receipt_number = this.fiscal_receipt_number;
+ result.fiscal_receipt_amount = this.fiscal_receipt_amount;
+ result.fiscal_receipt_date = this.fiscal_receipt_date; // parsed by backend
+ result.fiscal_z_rep_number = this.fiscal_z_rep_number;
+ return result;
+ },
+
+ export_for_printing: function(){
+ var receipt = OrderSuper.prototype.export_for_printing.call(this);
+
+ receipt.refund_date = this.refund_date;
+ receipt.refund_report = this.refund_report;
+ receipt.refund_doc_num = this.refund_doc_num;
+ receipt.refund_cash_fiscal_serial = this.refund_cash_fiscal_serial;
+ receipt.fiscal_receipt_number = this.fiscal_receipt_number;
+ receipt.fiscal_receipt_amount = this.fiscal_receipt_amount;
+ receipt.fiscal_receipt_date = this.fiscal_receipt_date;
+ receipt.fiscal_z_rep_number = this.fiscal_z_rep_number;
+
+ return receipt
+ },
+ });
+
+ var _orderline_super = models.Orderline.prototype;
+ models.Orderline = models.Orderline.extend({
+ export_for_printing: function(){
+ var res = _orderline_super.export_for_printing.call(this, arguments);
+ res['tax_department'] = this.get_tax_details_r();
+ return res;
+ },
+ get_tax_details_r: function(){
+ var details = this.get_all_prices();
+ for (var i in details.taxDetails){
+ return {
+ code: this.pos.taxes_by_id[i].fpdeptax,
+ taxname: this.pos.taxes_by_id[i].name,
+ }
+ }
+ this.pos.gui.show_popup('error', {
+ 'title': _t('Error'),
+ 'body': _t('No taxes found'),
+ });
+ },
+ compute_all: function(taxes, price_unit, quantity, currency_rounding, no_map_tax) {
+ var res = _orderline_super.compute_all.call(this, taxes, price_unit, quantity, currency_rounding, no_map_tax);
+ var self = this;
+
+ var total_excluded = round_pr(price_unit * quantity, currency_rounding);
+ var total_included = total_excluded;
+ var base = total_excluded;
+ var list_taxes = res.taxes;
+ // amount_type 'group' not handled (used only for purchases, in Italy)
+ _(taxes).each(function(tax) {
+ if (!no_map_tax){
+ tax = self._map_tax_fiscal_position(tax);
+ }
+ if (!tax){
+ return;
+ }
+ var tax_amount = self._compute_all(tax, base, quantity);
+ tax_amount = round_pr(tax_amount, currency_rounding);
+ if (!tax_amount){
+ // Intervene here: also add taxes with 0 amount
+ if (tax.price_include) {
+ total_excluded -= tax_amount;
+ base -= tax_amount;
+ }
+ else {
+ total_included += tax_amount;
+ }
+ if (tax.include_base_amount) {
+ base += tax_amount;
+ }
+ var data = {
+ id: tax.id,
+ amount: tax_amount,
+ name: tax.name,
+ };
+ list_taxes.push(data);
+ }
+ });
+ res.taxes = list_taxes;
+
+ return res;
+ },
+ });
+
+ /*
+ Overwrite Paymentline.export_for_printing() in order
+ to make it export the payment type that must be passed
+ to the fiscal printer.
+ */
+ var original = models.Paymentline.prototype.export_for_printing;
+ models.Paymentline = models.Paymentline.extend({
+ export_for_printing: function() {
+ var res = original.apply(this, arguments);
+ res.type = this.cashregister.journal.fiscalprinter_payment_type;
+ res.type_index = this.cashregister.journal.fiscalprinter_payment_index;
+ return res;
+ }
+ });
+
+ var _super_posmodel = models.PosModel.prototype;
+ models.PosModel = models.PosModel.extend({
+ initialize: function (session, attributes) {
+ var tax_model = _.find(this.models, function(model){ return model.model === 'account.tax'; });
+ tax_model.fields.push('fpdeptax');
+ return _super_posmodel.initialize.call(this, session, attributes);
+ },
+ });
+
});
diff --git a/fiscal_epos_print/static/src/js/popups.js b/fiscal_epos_print/static/src/js/popups.js
new file mode 100644
index 000000000000..c2e14c4eab14
--- /dev/null
+++ b/fiscal_epos_print/static/src/js/popups.js
@@ -0,0 +1,82 @@
+odoo.define("fiscal_epos_print.popups", function (require) {
+ "use strict";
+
+ var core = require("web.core");
+ var popups = require('point_of_sale.popups');
+ var gui = require('point_of_sale.gui');
+ var _t = core._t;
+
+ function addPadding(str, padding=4) {
+ var pad = new Array(padding).fill(0).join('') + str;
+ return pad.substr(pad.length - padding, padding);
+ }
+
+ var RefundInfoPopupWidget = popups.extend({
+ template: 'RefundInfoPopupWidget',
+ init: function(parent) {
+ this.refund_report = null;
+ this.refund_date = null;
+ this.refund_doc_num = null;
+ this.refund_cash_fiscal_serial = null;
+ this.datepicker = null;
+ return this._super(parent);
+ },
+ show: function(options){
+ options = options || {};
+ this._super(options);
+ this.update_refund_info_button = options.update_refund_info_button;
+ this.renderElement();
+ this.datepicker = null;
+ this.$('refund_report').focus();
+ this.initializeDatePicker();
+ },
+ click_confirm: function(){
+ var self = this;
+ function allValid() {
+ return self.$('input').toArray().every(function(element) {
+ return element.value && element.value != ''
+ })
+ }
+
+ if (allValid()) {
+ this.$('#error-message-dialog').hide()
+
+ var order = this.pos.get_order();
+ order.refund_report = this.$('#refund_report').val();
+ order.refund_date = this.$('#refund_date').val();
+ order.refund_doc_num = this.$('#refund_doc_num').val();
+ order.refund_cash_fiscal_serial = this.$('#refund_cash_fiscal_serial').val();
+ this.gui.close_popup();
+ if (this.update_refund_info_button && this.update_refund_info_button instanceof Function) {
+ this.update_refund_info_button();
+ }
+ } else {
+ this.$('#error-message-dialog').show()
+ }
+ },
+ initializeDatePicker: function() {
+ var self = this,
+ element = this.$('#refund_date').get(0);
+
+ if (element && !this.datepicker) {
+ this.datepicker = new Pikaday({
+ field: element,
+ parse: function(str) {
+ return new Date(str.slice(4, 8),
+ str.slice(2, 4),
+ str.slice(0, 2))
+ },
+ toString: function(date) {
+ var str = date.toLocaleDateString().split('/');
+ return addPadding(str[1], 2) +
+ addPadding(str[0], 2) +
+ addPadding(str[2]);
+ }
+ });
+ }
+ },
+ });
+
+ gui.define_popup({name:'refundinfo', widget: RefundInfoPopupWidget});
+
+});
diff --git a/fiscal_epos_print/static/src/js/pos_order_mgmt.js b/fiscal_epos_print/static/src/js/pos_order_mgmt.js
new file mode 100644
index 000000000000..1a74dfcf5ffd
--- /dev/null
+++ b/fiscal_epos_print/static/src/js/pos_order_mgmt.js
@@ -0,0 +1,46 @@
+odoo.define("fiscal_epos_print.pos_order_mgmt", function (require) {
+ "use strict";
+
+ var core = require("web.core");
+ var pos_order_mgmt = require('pos_order_mgmt.widgets');
+ var epson_epos_print = require('fiscal_epos_print.epson_epos_print');
+ var _t = core._t;
+ var OrderListScreenWidget = pos_order_mgmt.OrderListScreenWidget;
+ var eposDriver = epson_epos_print.eposDriver;
+
+ OrderListScreenWidget.include({
+ _prepare_order_from_order_data: function (order_data, action) {
+ var order = this._super(order_data, action);
+ order.refund_report = order_data.refund_report;
+ order.refund_date = order_data.refund_date ? order_data.refund_date.substr(8, 2) + // day
+ order_data.refund_date.substr(5, 2) + // month
+ order_data.refund_date.substr(0, 4) // year
+ : null;
+ order.refund_doc_num = order_data.refund_doc_num;
+ order.refund_cash_fiscal_serial = order_data.refund_cash_fiscal_serial;
+
+ return order;
+ },
+ // copiato da screens.PaymentScreenWidget
+ getPrinterOptions: function (){
+ var protocol = ((this.pos.config.use_https) ? 'https://' : 'http://');
+ var printer_url = protocol + this.pos.config.printer_ip + '/cgi-bin/fpmate.cgi';
+ return {url: printer_url};
+ },
+ // copiato da screens.PaymentScreenWidget
+ sendToFP90Printer: function(receipt, printer_options) {
+ var fp90 = new eposDriver(printer_options, this);
+ fp90.printFiscalReceipt(receipt);
+ },
+ action_print: function (order_data, order) {
+ if (this.pos.config.printer_ip) {
+ var receipt = order.export_for_printing();
+ var printer_options = this.getPrinterOptions();
+ printer_options.order = order;
+ this.sendToFP90Printer(receipt, printer_options);
+ }
+ return this._super(order_data, order);
+ },
+ });
+
+});
diff --git a/fiscal_epos_print/static/src/js/screens.js b/fiscal_epos_print/static/src/js/screens.js
new file mode 100644
index 000000000000..c4c971176a79
--- /dev/null
+++ b/fiscal_epos_print/static/src/js/screens.js
@@ -0,0 +1,162 @@
+odoo.define("fiscal_epos_print.screens", function (require) {
+ "use strict";
+
+ var core = require("web.core");
+ var screens = require('point_of_sale.screens');
+ var epson_epos_print = require('fiscal_epos_print.epson_epos_print');
+ var _t = core._t;
+ var PaymentScreenWidget = screens.PaymentScreenWidget;
+ var ReceiptScreenWidget = screens.ReceiptScreenWidget;
+ var eposDriver = epson_epos_print.eposDriver;
+
+ ReceiptScreenWidget.include({
+ show: function(){
+ if (!this.pos.config.printer_ip || (this.pos.config.printer_ip && this.pos.config.show_receipt_when_printing) ){
+ this._super();
+ }
+ else
+ {
+ this.click_next();
+ }
+ }
+ });
+
+ PaymentScreenWidget.include({
+ getPrinterOptions: function (){
+ var protocol = ((this.pos.config.use_https) ? 'https://' : 'http://');
+ var printer_url = protocol + this.pos.config.printer_ip + '/cgi-bin/fpmate.cgi';
+ return {url: printer_url};
+ },
+ sendToFP90Printer: function(receipt, printer_options) {
+ var fp90 = new eposDriver(printer_options, this);
+ fp90.printFiscalReceipt(receipt);
+ },
+ finalize_validation: function() {
+ // we need to get currentOrder before calling the _super()
+ // otherwise we will likely get a empty order when we want to skip
+ // the receipt preview
+ var currentOrder = this.pos.get('selectedOrder');
+ this._super.apply(this, arguments);
+ if (this.pos.config.printer_ip && !currentOrder.is_to_invoice()) {
+ var printer_options = this.getPrinterOptions();
+ printer_options.order = currentOrder;
+ var receipt = currentOrder.export_for_printing();
+ this.sendToFP90Printer(receipt, printer_options);
+ currentOrder._printed = true;
+ }
+ },
+ order_is_valid: function(force_validation) {
+ if (this.pos.config.iface_tax_included == 'subtotal') {
+ this.gui.show_popup('error',{
+ 'title': _t('Wrong tax configuration'),
+ 'body': _t("Product prices on receipts must be set to 'Tax-Included Price' in POS configuration"),
+ });
+ return false;
+ }
+ var self = this;
+ var receipt = this.pos.get_order();
+ if (receipt.has_refund && (receipt.refund_date == null || receipt.refund_date === '' ||
+ receipt.refund_doc_num == null || receipt.refund_doc_num == '' ||
+ receipt.refund_cash_fiscal_serial == null || receipt.refund_cash_fiscal_serial == '' ||
+ receipt.refund_report == null || receipt.refund_report == '')) {
+ this.gui.show_popup('error',{
+ 'title': _t('Refund Information Not Present'),
+ 'body': _t("The refund information aren't present. Please insert them before printing the receipt"),
+ });
+ return false;
+ }
+ return this._super(force_validation);
+ }
+ });
+
+ var set_refund_info_button = screens.ActionButtonWidget.extend({
+ template: 'SetRefundInfoButton',
+ init: function(parent, options) {
+ var self = this;
+ this._super(parent, options);
+ this.pos.bind('change:selectedOrder',function(){
+ this.orderline_change();
+ this.bind_order_events();
+ },this);
+ this.bind_order_events();
+ this.orderline_change();
+ },
+ renderElement: function() {
+ this._super();
+ var color = this.refund_get_button_color();
+ this.$el.css('background', color);
+ },
+ button_click: function () {
+ var self = this;
+ var current_order = self.pos.get_order();
+ self.gui.show_popup('refundinfo', {
+ title: _t('Refund Information Details'),
+ refund_date: current_order.refund_date,
+ refund_report: current_order.refund_report,
+ refund_doc_num: current_order.refund_doc_num,
+ refund_cash_fiscal_serial: current_order.refund_cash_fiscal_serial,
+ update_refund_info_button: function(){
+ self.renderElement();
+ },
+ });
+ },
+ bind_order_events: function() {
+ var self = this;
+ var order = this.pos.get_order();
+
+ if (!order) {
+ return;
+ }
+
+ if(this.old_order) {
+ this.old_order.unbind(null,null,this);
+ }
+
+ this.pos.bind('change:selectedOrder', this.orderline_change, this);
+
+ var lines = order.orderlines;
+ lines.unbind('add', this.orderline_change, this);
+ lines.bind('add', this.orderline_change, this);
+ lines.unbind('remove', this.orderline_change, this);
+ lines.bind('remove', this.orderline_change, this);
+ lines.unbind('change', this.orderline_change, this);
+ lines.bind('change', this.orderline_change, this);
+
+ this.old_order = order;
+ },
+ refund_get_button_color: function() {
+ var order = this.pos.get_order();
+ var lines = order.orderlines;
+ var has_refund = lines.find(function(line){ return line.quantity < 0.0;}) != undefined;
+ var color = '#e2e2e2';
+ if (has_refund == true)
+ {
+ if (order.refund_date && order.refund_date != '' && order.refund_doc_num && order.refund_doc_num != '' &&
+ order.refund_cash_fiscal_serial && order.refund_cash_fiscal_serial != '' && order.refund_report && order.refund_report != '') {
+ color = 'lightgreen';
+ }
+ else
+ {
+ color = 'red';
+ }
+ }
+ return color;
+ },
+ orderline_change: function(){
+ var order = this.pos.get_order();
+ var lines = order.orderlines;
+ order.has_refund = lines.find(function(line){ return line.quantity < 0.0;}) != undefined;
+ this.renderElement();
+ },
+ });
+
+ screens.define_action_button({
+ 'name': 'set_refund_info',
+ 'widget': set_refund_info_button,
+ });
+
+ return {
+ RefundInfoButtonActionWidget: set_refund_info_button
+ };
+
+});
diff --git a/fiscal_epos_print/static/src/xml/pos.xml b/fiscal_epos_print/static/src/xml/pos.xml
index 41c636c659b2..f92a69701e3c 100644
--- a/fiscal_epos_print/static/src/xml/pos.xml
+++ b/fiscal_epos_print/static/src/xml/pos.xml
@@ -25,7 +25,8 @@
- Refund Data
+
+ Refund Data
@@ -38,22 +39,22 @@
-
Seq. Closing
+
Seq. Closing
-
Num. Scontrino
+
Num. Scontrino
-
Receipt Date
+
Receipt Date
diff --git a/fiscal_epos_print/views/account_statement_view.xml b/fiscal_epos_print/views/account.xml
similarity index 66%
rename from fiscal_epos_print/views/account_statement_view.xml
rename to fiscal_epos_print/views/account.xml
index 6cd577040091..600767866192 100644
--- a/fiscal_epos_print/views/account_statement_view.xml
+++ b/fiscal_epos_print/views/account.xml
@@ -8,11 +8,13 @@
-
-
-
-
+
+
+
+
+
+
diff --git a/fiscal_epos_print/views/assets.xml b/fiscal_epos_print/views/assets.xml
index a2a564263fd6..ddfddd6477ae 100644
--- a/fiscal_epos_print/views/assets.xml
+++ b/fiscal_epos_print/views/assets.xml
@@ -4,11 +4,15 @@
-
-
-
+
+
+
+
+
+
+
diff --git a/fiscal_epos_print/views/point_of_sale.xml b/fiscal_epos_print/views/point_of_sale.xml
index e16ba5d2b367..1bcf086a6722 100644
--- a/fiscal_epos_print/views/point_of_sale.xml
+++ b/fiscal_epos_print/views/point_of_sale.xml
@@ -24,13 +24,23 @@
pos.order
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
From b9f7cf38f652a0257db4a952562fc697e3e679ff Mon Sep 17 00:00:00 2001
From: Roberto Fichera
Date: Tue, 17 Dec 2019 19:36:33 +0100
Subject: [PATCH 04/65] FIX [fiscal_epos_print] Move refund details as first
line in the receipt
---
fiscal_epos_print/readme/ROADMAP.rst | 4 ++
.../static/src/js/epson_epos_print.js | 58 ++++++++++++++-----
2 files changed, 47 insertions(+), 15 deletions(-)
create mode 100644 fiscal_epos_print/readme/ROADMAP.rst
diff --git a/fiscal_epos_print/readme/ROADMAP.rst b/fiscal_epos_print/readme/ROADMAP.rst
new file mode 100644
index 000000000000..c8d69d427cd7
--- /dev/null
+++ b/fiscal_epos_print/readme/ROADMAP.rst
@@ -0,0 +1,4 @@
+* Resi:
+ - Aggiungere controllo "rendibilità"
+ - Generare reso dalla lista di pos_order_mgmt
+ - Stampare sullo scontrino un barcode identificativo, in modo da generare il reso facendone la scansione
diff --git a/fiscal_epos_print/static/src/js/epson_epos_print.js b/fiscal_epos_print/static/src/js/epson_epos_print.js
index af3bb25bba22..ff54f0e42edc 100644
--- a/fiscal_epos_print/static/src/js/epson_epos_print.js
+++ b/fiscal_epos_print/static/src/js/epson_epos_print.js
@@ -201,7 +201,7 @@ odoo.define("fiscal_epos_print.epson_epos_print", function (require) {
/*
Prints a sale refund item line.
*/
- printRecRefund: function(args) {
+ printFiscalRefundDetails: function(args) {
var message = 'REFUND ' +
addPadding(args.refund_report) + ' ' +
addPadding(args.refund_doc_num) + ' ' +
@@ -211,8 +211,15 @@ odoo.define("fiscal_epos_print.epson_epos_print", function (require) {
var tag = ' \n'
- + ' \n';
+ return tag;
+ },
+
+ /*
+ Prints a sale refund item line.
+ */
+ printRecRefund: function(args) {
+ var tag = ' ';
+ return tag;
+ },
+
// Remember that the header goes after
// but before otherwise it will not be printed
// as additional header messageType=1
@@ -288,12 +302,25 @@ odoo.define("fiscal_epos_print.epson_epos_print", function (require) {
*/
printFiscalReceipt: function(receipt) {
var self = this;
+ var has_refund = _.every(receipt.orderlines, function(line) {
+ return line.quantity < 0;
+ });
var xml = '';
// header must be printed before beginning a fiscal receipt
xml += this.printFiscalReceiptHeader(receipt);
- xml += ' ';
+ if (!has_refund) {
+ xml += ' ';
+ }
// footer can go only as promo code so within a fiscal receipt body
xml += this.printFiscalReceiptFooter(receipt);
+ if (has_refund)
+ {
+ xml += this.printFiscalRefundDetails({
+ refund_date: receipt.refund_date,
+ refund_report: receipt.refund_report,
+ refund_doc_num: receipt.refund_doc_num,
+ refund_cash_fiscal_serial: receipt.refund_cash_fiscal_serial});
+ }
_.each(receipt.orderlines, function(l, i, list) {
if (l.price >= 0) {
if(l.quantity>=0) {
@@ -318,10 +345,6 @@ odoo.define("fiscal_epos_print.epson_epos_print", function (require) {
else
{
xml += self.printRecRefund({
- refund_date: receipt.refund_date,
- refund_report: receipt.refund_report,
- refund_doc_num: receipt.refund_doc_num,
- refund_cash_fiscal_serial: receipt.refund_cash_fiscal_serial,
description: _t('Refund >>> ') + l.product_name,
quantity: l.quantity * -1.0,
unitPrice: l.price,
@@ -338,14 +361,19 @@ odoo.define("fiscal_epos_print.epson_epos_print", function (require) {
});
}
});
- _.each(receipt.paymentlines, function(l, i, list) {
- xml += self.printRecTotal({
- payment: l.amount,
- paymentType: l.type,
- paymentIndex: l.type_index,
- description: l.journal,
+ if (has_refund) {
+ xml += self.printRecTotalRefund({});
+ }
+ else {
+ _.each(receipt.paymentlines, function(l, i, list) {
+ xml += self.printRecTotal({
+ payment: l.amount,
+ paymentType: l.type,
+ paymentIndex: l.type_index,
+ description: l.journal,
+ });
});
- });
+ }
xml += ' ';
this.fiscalPrinter.send(this.url, xml);
console.log(xml);
From 96bf890bf0ec199373a8028bbdd69de79e0c23bb Mon Sep 17 00:00:00 2001
From: eLBati
Date: Wed, 18 Dec 2019 15:56:47 +0100
Subject: [PATCH 05/65] IMP fiscal_epos_print: avoid to print again an order
with a fiscal receipt number
Lock receipt screen until printer communication ends.
Prevent user to go to next order if receipt not correctly printed.
Allow user to retry printing in case of errors
ADD print fiscal closure widget (Z report)
and X report
ADD refund management from OrderListScreenWidget
FIX Restaurant compatibility
---
fiscal_epos_print/__manifest__.py | 1 +
fiscal_epos_print/models/point_of_sale.py | 1 +
fiscal_epos_print/models/pos_order.py | 15 +++-
fiscal_epos_print/readme/ROADMAP.rst | 1 -
fiscal_epos_print/static/src/css/pos.css | 5 --
fiscal_epos_print/static/src/img/X.png | Bin 0 -> 344 bytes
fiscal_epos_print/static/src/img/Z.png | Bin 0 -> 364 bytes
fiscal_epos_print/static/src/js/chrome.js | 82 ++++++++++++++++++
.../static/src/js/epson_epos_print.js | 49 ++++++++---
fiscal_epos_print/static/src/js/models.js | 16 +++-
.../static/src/js/pos_order_mgmt.js | 38 ++++----
fiscal_epos_print/static/src/js/screens.js | 77 ++++++++++------
fiscal_epos_print/static/src/xml/pos.xml | 22 ++++-
fiscal_epos_print/views/assets.xml | 1 -
fiscal_epos_print/views/point_of_sale.xml | 2 +
15 files changed, 242 insertions(+), 68 deletions(-)
delete mode 100644 fiscal_epos_print/static/src/css/pos.css
create mode 100644 fiscal_epos_print/static/src/img/X.png
create mode 100644 fiscal_epos_print/static/src/img/Z.png
diff --git a/fiscal_epos_print/__manifest__.py b/fiscal_epos_print/__manifest__.py
index 7a9861da1ee9..331aeac062c2 100644
--- a/fiscal_epos_print/__manifest__.py
+++ b/fiscal_epos_print/__manifest__.py
@@ -1,6 +1,7 @@
# Leonardo Donelli - Creativi Quadrati
# © 2016 Alessio Gerace - Agile Business Group
# © 2018-2019 Lorenzo Battistini
+# © 2019-2020 Roberto Fichera - Level Prime Srl
# License GPL-3.0 or later (http://www.gnu.org/licenses/gpl.html).
{
diff --git a/fiscal_epos_print/models/point_of_sale.py b/fiscal_epos_print/models/point_of_sale.py
index 3d60ddb9e3fc..a019f10d0bff 100644
--- a/fiscal_epos_print/models/point_of_sale.py
+++ b/fiscal_epos_print/models/point_of_sale.py
@@ -16,3 +16,4 @@ class PosConfig(models.Model):
)
show_receipt_when_printing = fields.Boolean(
string='Show receipt on screen when printing', default=True)
+ fiscal_printer_serial = fields.Char(string='Fiscal Printer Serial')
diff --git a/fiscal_epos_print/models/pos_order.py b/fiscal_epos_print/models/pos_order.py
index 881e53b5b1f7..3df785183fb8 100644
--- a/fiscal_epos_print/models/pos_order.py
+++ b/fiscal_epos_print/models/pos_order.py
@@ -16,6 +16,7 @@ class PosOrder(models.Model):
fiscal_receipt_date = fields.Date(
"Fiscal receipt date", digits=(4, 0))
fiscal_z_rep_number = fields.Integer("Fiscal closure number")
+ fiscal_printer_serial = fields.Char(string='Fiscal Printer Serial')
@api.model
def _order_fields(self, ui_order):
@@ -25,6 +26,14 @@ def _order_fields(self, ui_order):
res['refund_doc_num'] = ui_order['refund_doc_num'] or False
res['refund_cash_fiscal_serial'] = \
ui_order['refund_cash_fiscal_serial'] or False
+ res['fiscal_receipt_number'] = \
+ ui_order['fiscal_receipt_number'] or False
+ res['fiscal_receipt_amount'] = \
+ ui_order['fiscal_receipt_amount'] or False
+ res['fiscal_receipt_date'] = ui_order['fiscal_receipt_date'] or False
+ res['fiscal_z_rep_number'] = ui_order['fiscal_z_rep_number'] or False
+ res['fiscal_printer_serial'] = \
+ ui_order['fiscal_printer_serial'] or False
return res
# This is on pos_order_mgmt to send back the fields of already existing
@@ -40,6 +49,7 @@ def _prepare_done_order_for_pos(self):
res['fiscal_receipt_amount'] = self.fiscal_receipt_amount
res['fiscal_receipt_date'] = self.fiscal_receipt_date
res['fiscal_z_rep_number'] = self.fiscal_z_rep_number
+ res['fiscal_printer_serial'] = self.fiscal_printer_serial
return res
@api.model
@@ -50,12 +60,15 @@ def update_fiscal_receipt_values(self, pos_order):
'fiscal_receipt_date'), '%d/%m/%Y').date().strftime('%Y-%m-%d')
receipt_amount = float(pos_order.get('fiscal_receipt_amount'))
fiscal_z_rep_number = int(pos_order.get('fiscal_z_rep_number'))
+ fiscal_printer_serial = pos_order.get('fiscal_printer_serial') or \
+ self.config_id.fiscal_printer_serial
if po:
po.write({
'fiscal_receipt_number': receipt_no,
'fiscal_receipt_date': receipt_date,
'fiscal_receipt_amount': receipt_amount,
- 'fiscal_z_rep_number': fiscal_z_rep_number
+ 'fiscal_z_rep_number': fiscal_z_rep_number,
+ 'fiscal_printer_serial': fiscal_printer_serial,
})
return True
diff --git a/fiscal_epos_print/readme/ROADMAP.rst b/fiscal_epos_print/readme/ROADMAP.rst
index c8d69d427cd7..c6e3f2993281 100644
--- a/fiscal_epos_print/readme/ROADMAP.rst
+++ b/fiscal_epos_print/readme/ROADMAP.rst
@@ -1,4 +1,3 @@
* Resi:
- Aggiungere controllo "rendibilità"
- - Generare reso dalla lista di pos_order_mgmt
- Stampare sullo scontrino un barcode identificativo, in modo da generare il reso facendone la scansione
diff --git a/fiscal_epos_print/static/src/css/pos.css b/fiscal_epos_print/static/src/css/pos.css
deleted file mode 100644
index 7ade28c334e5..000000000000
--- a/fiscal_epos_print/static/src/css/pos.css
+++ /dev/null
@@ -1,5 +0,0 @@
-/* Disabilitato finchè non gestiamo i resi */
-
-.orderlist-screen .order-line .order-list-return {
- display:none;
-}
diff --git a/fiscal_epos_print/static/src/img/X.png b/fiscal_epos_print/static/src/img/X.png
new file mode 100644
index 0000000000000000000000000000000000000000..92a1d55b05b99682151912196292dc786a19181c
GIT binary patch
literal 344
zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjEX7WqAsj$Z!;#Vf4nJ
zFj|8!qx}8+LZF~ziEBhjaDG}zd16s2LwR|*US?i)adKios$PCk`s{Z$Qb0vlJzX3_
zJUZWAbo6Qp6ggU$x#*qZOXsGj0F4`BO&qtnIP@0G+QKH7-W0gjrI2yIn*Xkvy-xS9
zudpdl|6Xuj{#@?XzF+&D_={~8O#WzHafD~NYD4t=St)-!KjeEch?*&;NbE_xkzY_|
zpuo!ObU{qqVtwQK?nBHfVIL;b
z_v)4^^*F!Co;CNF@8R{Y_NMyMrVIqesF&}Lsi5B&F?-X
kAA3}Pu`~Dmvi`-u{9;4nJ
zFj|8!qx}8+LZF~ziEBhjaDG}zd16s2LwR|*US?i)adKios$PCk`s{Z$Qb0v7JzX3_
zJUZWAG4x_~lxTbSo&9o$nIVU!%Nv#6d(Qm}mVIE^CU)<@Av=XzH*ZIEiF+u|a1#jG
z!hP%KEgwVIO@%3|CajMtoA&&7dV-kP%-=`0u$D^iV7rzkp?|>9#YWt8b^1SB_5XJd
zie8wxVGrM$CC?2vNDD4rBx@p)ziR%?FYciaTDD(l=aCON9DLBVjsNP?SwHsun*3qo
zt<|0RE97r}`8%t^d++%Vr?V=wEY5#$FWsuPZ~ENd+jj+LnZ$0zZ}-aZ~)!mnP{e7d{r-!MrW)%qO-xBEI`i)I1gU_GNFJ`)c+@pr;u;UHx3v
IIVCg!0IG7CZ2$lO
literal 0
HcmV?d00001
diff --git a/fiscal_epos_print/static/src/js/chrome.js b/fiscal_epos_print/static/src/js/chrome.js
index dcc2dfc8ff9d..04cd45e13905 100644
--- a/fiscal_epos_print/static/src/js/chrome.js
+++ b/fiscal_epos_print/static/src/js/chrome.js
@@ -31,6 +31,70 @@ odoo.define("fiscal_epos_print.chrome", function (require) {
});
+ var PrinterFiscalClosure = PosBaseWidget.extend({
+ template: 'PrinterFiscalClosure',
+
+ button_click: function () {
+ var self = this;
+ this.chrome.loading_show();
+ this.chrome.loading_message(_t('Connecting to the fiscal printer'));
+ var protocol = ((this.pos.config.use_https) ? 'https://' : 'http://');
+ var printer_url = protocol + this.pos.config.printer_ip + '/cgi-bin/fpmate.cgi';
+ var printer_options = {url: printer_url, requested_report: true};
+ var fp90 = new eposDriver(printer_options, this);
+ this.gui.show_popup('confirm',{
+ 'title': _t('Confirm Printer Fiscal Closure (Report Z)?'),
+ 'body': _t('Please confirm to execute the Printer Fiscal Closure'),
+ confirm: function(){
+ fp90.printFiscalReport();
+ },
+ cancel: function(){
+ self.chrome.loading_hide();
+ },
+ });
+ },
+
+ renderElement: function () {
+ var self = this;
+ this._super();
+ this.$el.click(function () {
+ self.button_click();
+ });
+ },
+ });
+
+ var PrinterFiscalXReport = PosBaseWidget.extend({
+ template: 'PrinterFiscalXReport',
+
+ button_click: function () {
+ var self = this;
+ this.chrome.loading_show();
+ this.chrome.loading_message(_t('Connecting to the fiscal printer'));
+ var protocol = ((this.pos.config.use_https) ? 'https://' : 'http://');
+ var printer_url = protocol + this.pos.config.printer_ip + '/cgi-bin/fpmate.cgi';
+ var printer_options = {url: printer_url, requested_report: true};
+ var fp90 = new eposDriver(printer_options, this);
+ this.gui.show_popup('confirm',{
+ 'title': _t('Confirm Printer Daily Financial Report (Report X)?'),
+ 'body': _t('Please confirm to execute the Printer Daily Financial Report'),
+ confirm: function(){
+ fp90.printFiscalXReport();
+ },
+ cancel: function(){
+ self.chrome.loading_hide();
+ },
+ });
+ },
+
+ renderElement: function () {
+ var self = this;
+ this._super();
+ this.$el.click(function () {
+ self.button_click();
+ });
+ },
+ });
+
var widgets = chrome.Chrome.prototype.widgets;
widgets.push({
'name': _t('ADE files status'),
@@ -40,9 +104,27 @@ odoo.define("fiscal_epos_print.chrome", function (require) {
'label': 'ADE files status',
},
});
+ widgets.push({
+ 'name': _t('Printer Fiscal Closure'),
+ 'widget': PrinterFiscalClosure,
+ 'append': '.pos-rightheader',
+ 'args': {
+ 'label': 'Printer Fiscal Closure',
+ },
+ });
+ widgets.push({
+ 'name': _t('Printer Fiscal X Report'),
+ 'widget': PrinterFiscalXReport,
+ 'append': '.pos-rightheader',
+ 'args': {
+ 'label': 'Printer Fiscal X Report',
+ },
+ });
return {
FiscalPrinterADEFilesButtonWidget: FiscalPrinterADEFilesButtonWidget,
+ PrinterFiscalClosure: PrinterFiscalClosure,
+ PrinterFiscalXReport: PrinterFiscalXReport,
};
});
diff --git a/fiscal_epos_print/static/src/js/epson_epos_print.js b/fiscal_epos_print/static/src/js/epson_epos_print.js
index ff54f0e42edc..04c057a22c99 100644
--- a/fiscal_epos_print/static/src/js/epson_epos_print.js
+++ b/fiscal_epos_print/static/src/js/epson_epos_print.js
@@ -125,11 +125,13 @@ odoo.define("fiscal_epos_print.epson_epos_print", function (require) {
this.fpresponse = false;
this.sender = sender;
this.order = options.order || null;
+ this.requested_report = options.requested_report || false;
this.fiscalPrinter.onreceive = function(res, tag_list_names, add_info) {
+ sender.chrome.loading_hide();
self.fpresponse = tag_list_names
var tagStatus = tag_list_names.filter(getStatusField);
if (res['code'] == "EPTR_REC_EMPTY"){
- sender.chrome.loading_hide();
+ sender.chrome.screens['receipt'].lock_screen(true);
sender.pos.gui.show_popup('error', {
'title': _t('Error'),
'body': _t('Missing paper'),
@@ -137,7 +139,6 @@ odoo.define("fiscal_epos_print.epson_epos_print", function (require) {
}
else if (add_info.responseCommand == "1138") {
// coming from FiscalPrinterADEFilesButtonWidget
- sender.chrome.loading_hide();
var to_be_sent = add_info.responseData[9] + add_info.responseData[10] + add_info.responseData[11] + add_info.responseData[12];
var old = add_info.responseData[13] + add_info.responseData[14] + add_info.responseData[15] + add_info.responseData[16];
var rejected = add_info.responseData[17] + add_info.responseData[18] + add_info.responseData[19] + add_info.responseData[20];
@@ -151,16 +152,28 @@ odoo.define("fiscal_epos_print.epson_epos_print", function (require) {
var info = add_info[tagStatus[0]];
var msgPrinter = decodeFpStatus(info);
if (!isErrorStatus(info)) {
- var order = self.order;
- if (!order.fiscal_receipt_number) {
- order.fiscal_receipt_number = parseInt(add_info.fiscalReceiptNumber);
- order.fiscal_receipt_amount = parseFloat(add_info.fiscalReceiptAmount.replace(',', '.'));
- order.fiscal_receipt_date = add_info.fiscalReceiptDate;
- order.fiscal_z_rep_number = add_info.zRepNumber;
- sender.pos.db.add_order(order.export_as_JSON());
+ // Z report can be printed from header bar: we just need to hide the loading screen, done above
+ if (!self.requested_report) {
+ sender.chrome.screens['receipt'].lock_screen(false);
+ var order = self.order;
+ order._printed = true;
+ if (!order.fiscal_receipt_number) {
+ order.fiscal_receipt_number = parseInt(add_info.fiscalReceiptNumber);
+ order.fiscal_receipt_amount = parseFloat(add_info.fiscalReceiptAmount.replace(',', '.'));
+ order.fiscal_receipt_date = add_info.fiscalReceiptDate;
+ order.fiscal_z_rep_number = add_info.zRepNumber;
+ order.fiscal_printer_serial = sender.pos.config.fiscal_printer_serial;
+ sender.pos.db.add_order(order.export_as_JSON());
+ // try to save the order
+ sender.pos.push_order();
+ }
+ if (!sender.pos.config.show_receipt_when_printing) {
+ sender.chrome.screens['receipt'].click_next();
+ }
}
}
else {
+ sender.chrome.screens['receipt'].lock_screen(true);
sender.pos.gui.show_popup('error', {
'title': _t('Connection to the printer failed'),
'body': msgPrinter,
@@ -168,6 +181,7 @@ odoo.define("fiscal_epos_print.epson_epos_print", function (require) {
};
}
else {
+ sender.chrome.screens['receipt'].lock_screen(true);
sender.pos.gui.show_popup('error', {
'title': _t('Connection to the printer failed'),
'body': _t('An error happened while sending data to the printer. Error code: ') + res.code,
@@ -176,6 +190,7 @@ odoo.define("fiscal_epos_print.epson_epos_print", function (require) {
}
this.fiscalPrinter.onerror = function() {
sender.chrome.loading_hide();
+ sender.chrome.screens['receipt'].lock_screen(true);
sender.pos.gui.show_popup('error', {
'title': _t('Network error'),
'body': _t('Printer can not be reached')
@@ -205,8 +220,10 @@ odoo.define("fiscal_epos_print.epson_epos_print", function (require) {
var message = 'REFUND ' +
addPadding(args.refund_report) + ' ' +
addPadding(args.refund_doc_num) + ' ' +
- args.refund_date + ' ' +
- args.refund_cash_fiscal_serial;
+ args.refund_date.substr(8, 2) + // day
+ args.refund_date.substr(5, 2) + // month
+ args.refund_date.substr(0, 4) + // year
+ ' ' + args.refund_cash_fiscal_serial;
var tag = ' ';
+ xml += ' ';
}
// footer can go only as promo code so within a fiscal receipt body
xml += this.printFiscalReceiptFooter(receipt);
@@ -381,12 +398,18 @@ odoo.define("fiscal_epos_print.epson_epos_print", function (require) {
printFiscalReport: function() {
var xml = '';
- xml += ' ';
xml += ' ';
xml += ' ';
this.fiscalPrinter.send(this.url, xml);
},
+ printFiscalXReport: function() {
+ var xml = '';
+ xml += ' ';
+ xml += ' ';
+ this.fiscalPrinter.send(this.url, xml);
+ },
+
getStatusOfFilesForADE: function() {
var xml = '';
xml += ' ';
diff --git a/fiscal_epos_print/static/src/js/models.js b/fiscal_epos_print/static/src/js/models.js
index 2bc217566e49..af4c03f34cb5 100644
--- a/fiscal_epos_print/static/src/js/models.js
+++ b/fiscal_epos_print/static/src/js/models.js
@@ -13,7 +13,7 @@ odoo.define('fiscal_epos_print.models', function (require) {
models.Order = models.Order.extend({
initialize: function(attributes, options){
- OrderSuper.prototype.initialize.call(this, attributes,options);
+ OrderSuper.prototype.initialize.call(this, attributes, options);
this.refund_report = null;
this.refund_date = null;
this.refund_doc_num = null;
@@ -23,6 +23,7 @@ odoo.define('fiscal_epos_print.models', function (require) {
this.fiscal_receipt_amount = null;
this.fiscal_receipt_date = null;
this.fiscal_z_rep_number = null;
+ this.fiscal_printer_serial = this.pos.config.fiscal_printer_serial || null;
},
check_order_has_refund: function() {
var order = this.pos.get_order();
@@ -43,20 +44,20 @@ odoo.define('fiscal_epos_print.models', function (require) {
this.fiscal_receipt_amount = json.fiscal_receipt_amount;
this.fiscal_receipt_date = json.fiscal_receipt_date;
this.fiscal_z_rep_number = json.fiscal_z_rep_number;
+ this.fiscal_printer_serial = json.fiscal_printer_serial;
},
export_as_JSON: function() {
var result = OrderSuper.prototype.export_as_JSON.call(this);
result.refund_report = this.refund_report;
- result.refund_date = this.refund_date ? this.refund_date.substr(4, 4) + '-' + // year
- this.refund_date.substr(2, 2) + '-' + // month
- this.refund_date.substr(0, 2) : null; // day
+ result.refund_date = this.refund_date;
result.refund_doc_num = this.refund_doc_num;
result.refund_cash_fiscal_serial = this.refund_cash_fiscal_serial;
result.fiscal_receipt_number = this.fiscal_receipt_number;
result.fiscal_receipt_amount = this.fiscal_receipt_amount;
result.fiscal_receipt_date = this.fiscal_receipt_date; // parsed by backend
result.fiscal_z_rep_number = this.fiscal_z_rep_number;
+ result.fiscal_printer_serial = this.fiscal_printer_serial || null;
return result;
},
@@ -71,9 +72,16 @@ odoo.define('fiscal_epos_print.models', function (require) {
receipt.fiscal_receipt_amount = this.fiscal_receipt_amount;
receipt.fiscal_receipt_date = this.fiscal_receipt_date;
receipt.fiscal_z_rep_number = this.fiscal_z_rep_number;
+ receipt.fiscal_printer_serial = this.fiscal_printer_serial;
return receipt
},
+
+ getPrinterOptions: function (){
+ var protocol = ((this.pos.config.use_https) ? 'https://' : 'http://');
+ var printer_url = protocol + this.pos.config.printer_ip + '/cgi-bin/fpmate.cgi';
+ return {url: printer_url};
+ },
});
var _orderline_super = models.Orderline.prototype;
diff --git a/fiscal_epos_print/static/src/js/pos_order_mgmt.js b/fiscal_epos_print/static/src/js/pos_order_mgmt.js
index 1a74dfcf5ffd..e060df06509e 100644
--- a/fiscal_epos_print/static/src/js/pos_order_mgmt.js
+++ b/fiscal_epos_print/static/src/js/pos_order_mgmt.js
@@ -11,31 +11,39 @@ odoo.define("fiscal_epos_print.pos_order_mgmt", function (require) {
OrderListScreenWidget.include({
_prepare_order_from_order_data: function (order_data, action) {
var order = this._super(order_data, action);
- order.refund_report = order_data.refund_report;
- order.refund_date = order_data.refund_date ? order_data.refund_date.substr(8, 2) + // day
- order_data.refund_date.substr(5, 2) + // month
- order_data.refund_date.substr(0, 4) // year
- : null;
- order.refund_doc_num = order_data.refund_doc_num;
- order.refund_cash_fiscal_serial = order_data.refund_cash_fiscal_serial;
-
+ if (action === 'print') {
+ order.refund_report = order_data.refund_report;
+ order.refund_date = order_data.refund_date;
+ order.refund_doc_num = order_data.refund_doc_num;
+ order.refund_cash_fiscal_serial = order_data.refund_cash_fiscal_serial;
+ }
+ else if (action === 'return') {
+ order.refund_report = order_data.fiscal_z_rep_number;
+ order.refund_date = order_data.fiscal_receipt_date;
+ order.refund_doc_num = order_data.fiscal_receipt_number;
+ order.refund_cash_fiscal_serial = order_data.fiscal_printer_serial;
+ }
+ // for action === 'copy' we don't need to do anything
return order;
},
// copiato da screens.PaymentScreenWidget
- getPrinterOptions: function (){
- var protocol = ((this.pos.config.use_https) ? 'https://' : 'http://');
- var printer_url = protocol + this.pos.config.printer_ip + '/cgi-bin/fpmate.cgi';
- return {url: printer_url};
- },
- // copiato da screens.PaymentScreenWidget
sendToFP90Printer: function(receipt, printer_options) {
var fp90 = new eposDriver(printer_options, this);
fp90.printFiscalReceipt(receipt);
},
action_print: function (order_data, order) {
if (this.pos.config.printer_ip) {
+ if (order_data.fiscal_receipt_number) {
+ this.pos.gui.show_popup('error', {
+ 'title': _t('Order already printed'),
+ 'body': order_data.pos_reference + _t(": order already has a fiscal number, ") + order_data.fiscal_receipt_number,
+ });
+ return;
+ }
+ this.chrome.loading_show();
+ this.chrome.loading_message(_t('Connecting to the fiscal printer'));
var receipt = order.export_for_printing();
- var printer_options = this.getPrinterOptions();
+ var printer_options = order.getPrinterOptions();
printer_options.order = order;
this.sendToFP90Printer(receipt, printer_options);
}
diff --git a/fiscal_epos_print/static/src/js/screens.js b/fiscal_epos_print/static/src/js/screens.js
index c4c971176a79..b76a71278425 100644
--- a/fiscal_epos_print/static/src/js/screens.js
+++ b/fiscal_epos_print/static/src/js/screens.js
@@ -10,23 +10,43 @@ odoo.define("fiscal_epos_print.screens", function (require) {
var eposDriver = epson_epos_print.eposDriver;
ReceiptScreenWidget.include({
- show: function(){
- if (!this.pos.config.printer_ip || (this.pos.config.printer_ip && this.pos.config.show_receipt_when_printing) ){
- this._super();
- }
- else
- {
- this.click_next();
+
+ lock_screen: function(locked) {
+ this._super.apply(this, arguments);
+ if (locked) {
+ this.$('.receipt-sent').hide();
+ this.$('.printing-error').show();
+ this.$('.printing-retry').show();
+ } else {
+ this.$('.receipt-sent').show();
+ this.$('.printing-error').hide();
+ this.$('.printing-retry').hide();
}
+ },
+
+ sendToFP90Printer: function(receipt, printer_options) {
+ var fp90 = new eposDriver(printer_options, this);
+ fp90.printFiscalReceipt(receipt);
+ },
+
+ render_receipt: function() {
+ var self = this;
+ this._super();
+ this.$('.printing-retry').click(function(){
+ if (self._locked) {
+ var currentOrder = self.pos.get_order();
+ self.chrome.loading_show();
+ self.chrome.loading_message(_t('Connecting to the fiscal printer'));
+ var printer_options = currentOrder.getPrinterOptions();
+ printer_options.order = currentOrder;
+ var receipt = currentOrder.export_for_printing();
+ self.sendToFP90Printer(receipt, printer_options);
+ }
+ });
}
});
PaymentScreenWidget.include({
- getPrinterOptions: function (){
- var protocol = ((this.pos.config.use_https) ? 'https://' : 'http://');
- var printer_url = protocol + this.pos.config.printer_ip + '/cgi-bin/fpmate.cgi';
- return {url: printer_url};
- },
sendToFP90Printer: function(receipt, printer_options) {
var fp90 = new eposDriver(printer_options, this);
fp90.printFiscalReceipt(receipt);
@@ -38,11 +58,12 @@ odoo.define("fiscal_epos_print.screens", function (require) {
var currentOrder = this.pos.get('selectedOrder');
this._super.apply(this, arguments);
if (this.pos.config.printer_ip && !currentOrder.is_to_invoice()) {
- var printer_options = this.getPrinterOptions();
+ this.chrome.loading_show();
+ this.chrome.loading_message(_t('Connecting to the fiscal printer'));
+ var printer_options = currentOrder.getPrinterOptions();
printer_options.order = currentOrder;
var receipt = currentOrder.export_for_printing();
this.sendToFP90Printer(receipt, printer_options);
- currentOrder._printed = true;
}
},
order_is_valid: function(force_validation) {
@@ -126,26 +147,30 @@ odoo.define("fiscal_epos_print.screens", function (require) {
},
refund_get_button_color: function() {
var order = this.pos.get_order();
- var lines = order.orderlines;
- var has_refund = lines.find(function(line){ return line.quantity < 0.0;}) != undefined;
var color = '#e2e2e2';
- if (has_refund == true)
- {
- if (order.refund_date && order.refund_date != '' && order.refund_doc_num && order.refund_doc_num != '' &&
- order.refund_cash_fiscal_serial && order.refund_cash_fiscal_serial != '' && order.refund_report && order.refund_report != '') {
- color = 'lightgreen';
- }
- else
+ if(order) {
+ var lines = order.orderlines;
+ var has_refund = lines.find(function(line){ return line.quantity < 0.0;}) != undefined;
+ if (has_refund == true)
{
- color = 'red';
+ if (order.refund_date && order.refund_date != '' && order.refund_doc_num && order.refund_doc_num != '' &&
+ order.refund_cash_fiscal_serial && order.refund_cash_fiscal_serial != '' && order.refund_report && order.refund_report != '') {
+ color = 'lightgreen';
+ }
+ else
+ {
+ color = 'red';
+ }
}
}
return color;
},
orderline_change: function(){
var order = this.pos.get_order();
- var lines = order.orderlines;
- order.has_refund = lines.find(function(line){ return line.quantity < 0.0;}) != undefined;
+ if (order) {
+ var lines = order.orderlines;
+ order.has_refund = lines.find(function(line){ return line.quantity < 0.0;}) != undefined;
+ }
this.renderElement();
},
});
diff --git a/fiscal_epos_print/static/src/xml/pos.xml b/fiscal_epos_print/static/src/xml/pos.xml
index f92a69701e3c..41c2d5dd272e 100644
--- a/fiscal_epos_print/static/src/xml/pos.xml
+++ b/fiscal_epos_print/static/src/xml/pos.xml
@@ -7,14 +7,32 @@
+
+
+
+
+
+
+
+
-
+
+
+
+
diff --git a/fiscal_epos_print/views/assets.xml b/fiscal_epos_print/views/assets.xml
index ccce1fa1f5c6..49e624b26ad5 100644
--- a/fiscal_epos_print/views/assets.xml
+++ b/fiscal_epos_print/views/assets.xml
@@ -5,6 +5,7 @@
+
diff --git a/fiscal_epos_print/views/point_of_sale.xml b/fiscal_epos_print/views/point_of_sale.xml
index dbb04f9ca2b0..204ffbb43663 100644
--- a/fiscal_epos_print/views/point_of_sale.xml
+++ b/fiscal_epos_print/views/point_of_sale.xml
@@ -15,6 +15,7 @@
+
From de2e8ee7ac81a0b4bca091abac18e9780af24477 Mon Sep 17 00:00:00 2001
From: Gianluigi Tiesi
Date: Sun, 12 Jan 2020 12:54:49 +0100
Subject: [PATCH 07/65] epos config widget restyle
---
fiscal_epos_print/static/src/css/pos.css | 14 +++++++++++---
fiscal_epos_print/static/src/img/X.png | Bin 344 -> 0 bytes
fiscal_epos_print/static/src/img/X.svg | 1 +
fiscal_epos_print/static/src/img/Z.png | Bin 364 -> 0 bytes
fiscal_epos_print/static/src/img/Z.svg | 1 +
fiscal_epos_print/static/src/img/ade-logo.png | Bin 1323 -> 0 bytes
fiscal_epos_print/static/src/img/ade-logo.svg | 1 +
fiscal_epos_print/static/src/img/cashdrawer.png | Bin 3548 -> 0 bytes
fiscal_epos_print/static/src/img/cashdrawer.svg | 1 +
fiscal_epos_print/static/src/img/epos.png | Bin 19191 -> 0 bytes
fiscal_epos_print/static/src/img/epos.svg | 1 +
fiscal_epos_print/static/src/img/reprint.png | Bin 3449 -> 0 bytes
fiscal_epos_print/static/src/img/reprint.svg | 1 +
fiscal_epos_print/static/src/xml/pos.xml | 14 +++++++-------
14 files changed, 24 insertions(+), 10 deletions(-)
delete mode 100644 fiscal_epos_print/static/src/img/X.png
create mode 100644 fiscal_epos_print/static/src/img/X.svg
delete mode 100644 fiscal_epos_print/static/src/img/Z.png
create mode 100644 fiscal_epos_print/static/src/img/Z.svg
delete mode 100644 fiscal_epos_print/static/src/img/ade-logo.png
create mode 100644 fiscal_epos_print/static/src/img/ade-logo.svg
delete mode 100644 fiscal_epos_print/static/src/img/cashdrawer.png
create mode 100644 fiscal_epos_print/static/src/img/cashdrawer.svg
delete mode 100644 fiscal_epos_print/static/src/img/epos.png
create mode 100644 fiscal_epos_print/static/src/img/epos.svg
delete mode 100644 fiscal_epos_print/static/src/img/reprint.png
create mode 100644 fiscal_epos_print/static/src/img/reprint.svg
diff --git a/fiscal_epos_print/static/src/css/pos.css b/fiscal_epos_print/static/src/css/pos.css
index 1f6335d7b718..0906fc61eec6 100644
--- a/fiscal_epos_print/static/src/css/pos.css
+++ b/fiscal_epos_print/static/src/css/pos.css
@@ -5,8 +5,8 @@
position: absolute;
right: 10px;
top: 10px;
- width: 200px;
- font-size: 13px;
+ width: 236px;
+ font-size: 14px;
background: rgba(0,0,0,0.82);
color: white;
@@ -14,6 +14,9 @@
cursor: move;
-webkit-transform: translate3d(0,0,0);
}
+.pos .pos-rightheader .header-button > img {
+ vertical-align: middle;
+}
.pos .epson-fp81ii-widget .toggle {
position: absolute;
font-size: 16px;
@@ -38,6 +41,7 @@
padding-left: 10px;
margin: 0px;
font-weight: bold;
+ font-size: 16px;
padding-top:3px;
padding-bottom:3px;
}
@@ -47,9 +51,13 @@
display: block;
cursor:pointer;
}
+.pos .epson-fp81ii-widget .button:hover{
+ background: #546E7A;
+}
.pos .epson-fp81ii-widget .category-label {
position: relative;
- top: -8px;
+ padding: 4px;
+ top: -12px;
}
.pos .epson-fp81ii-widget li img {
min-width: 32px;
diff --git a/fiscal_epos_print/static/src/img/X.png b/fiscal_epos_print/static/src/img/X.png
deleted file mode 100644
index 92a1d55b05b99682151912196292dc786a19181c..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 344
zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjEX7WqAsj$Z!;#Vf4nJ
zFj|8!qx}8+LZF~ziEBhjaDG}zd16s2LwR|*US?i)adKios$PCk`s{Z$Qb0vlJzX3_
zJUZWAbo6Qp6ggU$x#*qZOXsGj0F4`BO&qtnIP@0G+QKH7-W0gjrI2yIn*Xkvy-xS9
zudpdl|6Xuj{#@?XzF+&D_={~8O#WzHafD~NYD4t=St)-!KjeEch?*&;NbE_xkzY_|
zpuo!ObU{qqVtwQK?nBHfVIL;b
z_v)4^^*F!Co;CNF@8R{Y_NMyMrVIqesF&}Lsi5B&F?-X
kAA3}Pu`~Dmvi`-u{9;
\ No newline at end of file
diff --git a/fiscal_epos_print/static/src/img/Z.png b/fiscal_epos_print/static/src/img/Z.png
deleted file mode 100644
index 5358fe8872e7860faceefd5336644b3e228cb20d..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 364
zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjEX7WqAsj$Z!;#Vf4nJ
zFj|8!qx}8+LZF~ziEBhjaDG}zd16s2LwR|*US?i)adKios$PCk`s{Z$Qb0v7JzX3_
zJUZWAG4x_~lxTbSo&9o$nIVU!%Nv#6d(Qm}mVIE^CU)<@Av=XzH*ZIEiF+u|a1#jG
z!hP%KEgwVIO@%3|CajMtoA&&7dV-kP%-=`0u$D^iV7rzkp?|>9#YWt8b^1SB_5XJd
zie8wxVGrM$CC?2vNDD4rBx@p)ziR%?FYciaTDD(l=aCON9DLBVjsNP?SwHsun*3qo
zt<|0RE97r}`8%t^d++%Vr?V=wEY5#$FWsuPZ~ENd+jj+LnZ$0zZ}-aZ~)!mnP{e7d{r-!MrW)%qO-xBEI`i)I1gU_GNFJ`)c+@pr;u;UHx3v
IIVCg!0IG7CZ2$lO
diff --git a/fiscal_epos_print/static/src/img/Z.svg b/fiscal_epos_print/static/src/img/Z.svg
new file mode 100644
index 000000000000..4eb71e9c0886
--- /dev/null
+++ b/fiscal_epos_print/static/src/img/Z.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/fiscal_epos_print/static/src/img/ade-logo.png b/fiscal_epos_print/static/src/img/ade-logo.png
deleted file mode 100644
index 2a01e0fa97518955eaba3ac142c1f70a4b4f95ba..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 1323
zcmV+`1=RY9P)Al>qT9o?9-vL^tlJA=}BQ4BNyRyss`K~91S0b_xCfjpouurL-+
zZ0I$BG{kfeGZsHpw{F{k{@QLH;dy>xYtkWU+n3L|*|pnN&b)N8V))$}V?`{Uc%s(;
zzW(JD$4{IwN=piN*^c*s<+wSP?Wphe9mcUeCXFqn)pEqLUCXkZJv-iiWk%)F#Vo5@
zf6F-lK%a5X0$?@&^X`O^gMGtLk10hIP+AM$|9phK2aln(q&K6Y%21C#GJlQ!vOd2O
zAUyi%TL*BDZGn_~X_}a{L7rIk5&oBF+@b8AkivbB7<;UPVi*jpew$<9JO;$1yD1CF!_WmV;%xVmU6B?P58OSeA$7
zI3#UXw^~ktWjTFq*QNG!Jz8rM7!#N^(tf>gCn7_szz>Ff@!oQ@zIybBwa5SwK|~NO
zXsr
z;i=tv$%`{|C}hxkrYOjZHU+6vr`t5#d9cOeIWs=D9q)zq#V;beMToR1dre-sP9{NT
zB7hRDlxP%M6e^T;n7XgDSy7g`@;d`$Iz7*?5|P>0BvUMUvwB%3Q47>pTyX*##lVD_NG-}R+Kfx;)$X&7h2BQt~VrU
zxorPtA8V?&5Q=2I8kjYep;$RLJKZw2^SQBd(#ny65pVzfg;#QHZA=8RWATJ@6`;K&
zW<}Xh;4JV~w7Tw{z^B9vUUEDHczBmQh@p6=lW1381LMVLr@TzP~u-`3HSJz_wkIjzfJz
z6H8WY#Pw1=&BVV>PCfKsN>p9u)dh?ZYVw`aCY9y~fnF(s3xc7#U7}Zj4Fa*m
hw1cMwUhDYe_!p8yX-584&fow5002ovPDHLkV1f+
\ No newline at end of file
diff --git a/fiscal_epos_print/static/src/img/cashdrawer.png b/fiscal_epos_print/static/src/img/cashdrawer.png
deleted file mode 100644
index 4f38abdc94f01c7990ba241073f9fce6c5b1c3de..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 3548
zcmV<24I}c2P)
zaB^>EX>4U6ba`-PAZ2)IW&i+q+Ra*7lH;(B{KqNg2;7(BaE+K7%<*3Wq<6V2SJ#V}
zc2`N3We~~)5+GSL{_lS${SW^6pcFYDQ^*0QO1bQ^DL6@L{mb%OD<{9#o6BeV@j6{U
zFt}uKwCimw`~HIK{`Q5do%(p4(*DGxZD@aRF=%;YgOh&mB(9rvUAt{4k987qiubNo
zvyN@wD6Z@u8^!e12*0QM3oZhs?s1njW>{^N{C3L&yM79OwET|daz$H1I5>Op1b{p|
z-sPy&JwOj2U(VI5l6Jc5qNg5m
zY`VckXNCbM#+YWTTub06nVF=9(E~EiRj@FIvXUGG0T}chxm+H5$f1
z^7|M4^x-!znzJ!PTBR#i@XK)I!VPAQf8#Dtpy%ez3&5AxreEE~4?-0TdVx9N0gI~3
zMD_X>TUL0sxX~MA47~W#T-kr$t9mciYcX>N;cU-1APuT=9F_T#ZbXO1-1(AFSt@owbfN$
zLya}nTuVdvG}n9!EwIAq@SV9)QJEzPsFWd6(xb
z5NJlXJ^*gca#y?jW#*Q@H*aGcxH(l_#!TpDLWbIPGdeOi7nK9ZLa3Jk*8&9v#u17(
z)RG#P=rDbe2MjlIKXXezlgnwylF9Zs5GKbS=OqF!t&9t;G8(jF&p{z1_Anero)|~$
z`GxEP`zI--#|vZNK`h6P>(Jr|X&BW*IATB|I0GDl5C9Rzj#7}$2HdB3qq70`Dcq+*$WzPZVwhZg_tw>9#*p+h5Xaza!NUfF#O#pB0F6ZO;R}T5L-+7i5o1}N9pb$n
zT=0@ybNkt~zdifUB}lyjNI>uizsGF7L3eWu6kXgZ+E2l#CsQ07tZ)iEGvRYNWjyj$
zXlNLYUFvC-9F&ZEHt0~_Pvq8fYSD+>It2CzSNaXGN4U}{U{6E>ZI1d&+M&`JG4kJ6qc;^9bJGu~$P*`%gVS$#?Bds(@!XP0tD2leb(
z45bqhG2ErsUZOr$iF)nR$~D-icQ#ho!-hnCX>rS`=hO*rS|)msKmdA6v(-Qaz5A!M
z3gm05ffOVgRds2iqBK!F!LbbkmnUFe0eUDF^js~zD)@Kxo{kE>Mtg;1(E()38xB*L
zL)^n$3Mv75knT&zOm1;aI;t3L6|#{~u1vIuTeQRo@?u$BfsY(`aIj?~4${R##Pmx?
zlI;!l#k2&=hW$!4(6F8^a10QV;-mjVhX?~;B1(`wR?&`0acXz!PVdJ0
zwo{__QgvFXxVK33EJD&lvJ8FMS?+2%-SZv*yT&%VM!+up4g7UN&5N8&zq#PV16=5-}7^9lD_BX*d+Z6<@YA(
zZ=y(Q|6fE=^Yk}SWIFv#6xBw56Gdgx-$aov^fyr?ti8G!jFfzpr!!JPP;DbB2!wii
zlS|Af>87J3jRH-Be0ohH){sd^suHnYi$brHkPj_A9ryIM^ZKtz&y%V5M^e9CWV<$u
zO?pLo?oPjMPWNPt&dtU?FSOFvV7xif*I>Nq;AkEI!kzPiWcB<}dj1DUUP6PupY9!p
z2JI6R=@u&YuM*7MPmCOkY$>4qn5Ls_!=5iKq*k=6)(kXJ(c6r-m_d$=hPFRX2wvv{
zYXx+scWn@HM%a0(sRBIQGai#nkEDDsm`*JFNZvbR(E-VJflsTcDXsP5fmg^SJIr@{
z80hUA{Tl@=}Nw*5zVkQ7VhDny65-J^V@~-pTq5Qw9&b6dx{gwk_j`kMyh-@ILHc>u@w`F$1manPbe5GTgL`F&
z|JG{CN)Fwv42*eQ%2`VT!R?hCC`pXQ$V$$Pdu`|`Apg61bf7nfa^pI$qiN*7Csytd
z!d_qKCgkCf4|{zfNXweNEHB)3tYh33J=UrL?G3ZNUAF3}tap_4w4e7ySHY)?#RG%9
zt|Kg+*{-9Ld$Au4(wCdNZw=BfcZ**P(m!rLUk%c^J2I*e|@&7|)A1fDKq>Fn`oQ(C?DMf{m#3U-OjE=s+qZ*@+Ko?PROqeIb!M*6}
z5(Q{&?_saHW?l@0JjtT#!&+c&Kd&UypZv|xIYW5%jDY(O_oDql&;E8K0004mX+uL$
zNkc;*aB^>EX>4Tx0C=2zkv&MmP!xqvQ>CI6hjtKg$WWauh!%0wDionYs1;guFnQ@8
zG%+M8E{=k0!NH%!s)LKOt`4q(Aov5~9J6k5c1;qgAsyXWxUeSpxYGR^85
z2Q=L_GpVGQ%dd!`R|F731bs-z%ra&rDGlHHx~FccyExDC@B6d*)q=%=bb^8^S!16O+6ztI4u
zKS{5*wb&6bunk;Xw>4!CxZD8-pA6ZQT`5RQC>DYDGy0}H5V-|+9=(e}AH)qF-NMva+(#(b3`I
z;eddEo12^4+uO^_%VJ_;d3kx)*Vi~WIOgW&R8&-sj*h0LrfOo2NMh|VY}S>0000>NklYHpa3ud0TwZs1gb0(vJNI9
zjADWcL#3FAlVE_0BP5v6?O+usDW5NMHh5NMO=PK1Oy7oP{QV)4lj5NCW`7
WKLOD{*yjoW0000
\ No newline at end of file
diff --git a/fiscal_epos_print/static/src/img/epos.png b/fiscal_epos_print/static/src/img/epos.png
deleted file mode 100644
index a3af9cd79781671fd3caba7efe3a283d1a7a20d7..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 19191
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
\ No newline at end of file
diff --git a/fiscal_epos_print/static/src/img/reprint.png b/fiscal_epos_print/static/src/img/reprint.png
deleted file mode 100644
index bebef86039ada9dd6deba69fa4eb295dd9473d57..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 3449
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
\ No newline at end of file
diff --git a/fiscal_epos_print/static/src/xml/pos.xml b/fiscal_epos_print/static/src/xml/pos.xml
index dc8c22f85a6b..8537e170c24e 100644
--- a/fiscal_epos_print/static/src/xml/pos.xml
+++ b/fiscal_epos_print/static/src/xml/pos.xml
@@ -2,8 +2,8 @@
-