From de039d75f45293568ed12fef87f26affd3263024 Mon Sep 17 00:00:00 2001
From: Roberto Fichera
Date: Tue, 10 Dec 2019 16:28:10 +0100
Subject: [PATCH 01/17] [10.0] ADD fiscal_epos_print
---
fiscal_epos_print/README.rst | 29 +
fiscal_epos_print/__init__.py | 3 +
fiscal_epos_print/__manifest__.py | 38 +
fiscal_epos_print/i18n/it.po | 347 ++++
fiscal_epos_print/models/__init__.py | 7 +
fiscal_epos_print/models/account.py | 12 +
fiscal_epos_print/models/account_journal.py | 25 +
fiscal_epos_print/models/point_of_sale.py | 21 +
fiscal_epos_print/models/pos_order.py | 33 +
fiscal_epos_print/models/product.py | 15 +
.../static/lib/fiscalprint/fiscalprint.js | 1435 +++++++++++++++++
.../static/lib/pikaday/pikaday.min.css | 5 +
.../static/lib/pikaday/pikaday.min.js | 1 +
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 | 658 ++++++++
fiscal_epos_print/static/src/js/models.js | 8 +
fiscal_epos_print/static/src/xml/pos.xml | 74 +
.../views/account_statement_view.xml | 31 +
fiscal_epos_print/views/assets.xml | 15 +
fiscal_epos_print/views/point_of_sale.xml | 42 +
oca_dependencies.txt | 1 +
22 files changed, 2805 insertions(+)
create mode 100644 fiscal_epos_print/README.rst
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/pos_order.py
create mode 100644 fiscal_epos_print/models/product.py
create mode 100644 fiscal_epos_print/static/lib/fiscalprint/fiscalprint.js
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/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/js/models.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/README.rst b/fiscal_epos_print/README.rst
new file mode 100644
index 000000000000..1ac3fc6d05e1
--- /dev/null
+++ b/fiscal_epos_print/README.rst
@@ -0,0 +1,29 @@
+===================
+EPoS Fiscal Printer
+===================
+
+This module allow to print receipt of point_of_sale,
+on fiscal printer Epson via EPos protocol.
+
+Configuration
+=============
+
+- 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.
+
+
+Credits
+=======
+
+Contributors
+------------
+
+* Leonardo Donelli
+* Lorenzo Battistini
+* Alessio Gerace
+
+Do not contact contributors directly about support or help with technical issues.
diff --git a/fiscal_epos_print/__init__.py b/fiscal_epos_print/__init__.py
new file mode 100644
index 000000000000..23ac4f955b7d
--- /dev/null
+++ b/fiscal_epos_print/__init__.py
@@ -0,0 +1,3 @@
+# coding=utf-8
+
+from . import models
diff --git a/fiscal_epos_print/__manifest__.py b/fiscal_epos_print/__manifest__.py
new file mode 100644
index 000000000000..21cb7e113e0f
--- /dev/null
+++ b/fiscal_epos_print/__manifest__.py
@@ -0,0 +1,38 @@
+# coding=utf-8
+# Leonardo Donelli - Creativi Quadrati
+# © 2016 Alessio Gerace - Agile Business Group
+# © 2018-2019 Lorenzo Battistini
+# © 2019 Roberto Fichera - Level Prime Srl
+# License GPL-3.0 or later (http://www.gnu.org/licenses/gpl.html).
+
+{
+ 'name': 'Driver for ePOS-Print XML compatible fiscal printers',
+ 'version': '10.0.1.0.0',
+ 'category': 'POS, Fiscal, Hardware, Driver',
+ 'summary': 'ePOS-Print XML Fiscal Printer Driver',
+ 'author': (
+ 'Agile Business Group, '
+ 'Leonardo Donelli @ Creativi Quadrati, TAKOBI, '
+ 'Level Prime Srl'
+ ),
+ 'website': 'https://takobi.online',
+ '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/models.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..4104f62d5e97
--- /dev/null
+++ b/fiscal_epos_print/i18n/it.po
@@ -0,0 +1,347 @@
+# Translation of Odoo Server.
+# This file contains the translation of the following modules:
+# * fiscal_epos_print
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Odoo Server 10.0\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2019-12-11 14:47+0000\n"
+"PO-Revision-Date: 2019-12-11 14:47+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:264
+#, python-format
+msgid "\n"
+"Old files: "
+msgstr "\n"
+"Vecchi files: "
+
+#. module: fiscal_epos_print
+#. openerp-web
+#: code:addons/fiscal_epos_print/static/src/js/fp90iii.js:264
+#, python-format
+msgid "\n"
+"Rejected files: "
+msgstr "\n"
+"Files respinti: "
+
+#. module: fiscal_epos_print
+#. openerp-web
+#: code:addons/fiscal_epos_print/static/src/js/fp90iii.js:630
+#, python-format
+msgid "ADE files status"
+msgstr "ADE files status"
+
+#. module: fiscal_epos_print
+#. openerp-web
+#: code:addons/fiscal_epos_print/static/src/xml/pos.xml:6
+#, python-format
+msgid "ADE status"
+msgstr "ADE status"
+
+#. module: fiscal_epos_print
+#. openerp-web
+#: code:addons/fiscal_epos_print/static/src/xml/pos.xml:59
+#, python-format
+msgid "Apply"
+msgstr "Applica"
+
+#. module: fiscal_epos_print
+#. openerp-web
+#: code:addons/fiscal_epos_print/static/src/xml/pos.xml:62
+#, python-format
+msgid "Cancel"
+msgstr "Cancella"
+
+#. 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 "Cheque"
+
+#. module: fiscal_epos_print
+#. openerp-web
+#: code:addons/fiscal_epos_print/static/src/js/fp90iii.js:606
+#, python-format
+msgid "Connecting to the fiscal printer"
+msgstr "Collegamento con la 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 "Carta di Credito/Ticket Index"
+
+#. module: fiscal_epos_print
+#: selection:account.journal,fiscalprinter_payment_type:0
+msgid "Credit/Credit Card"
+msgstr "Credito/Carta di Credito"
+
+#. module: fiscal_epos_print
+#. openerp-web
+#: code:addons/fiscal_epos_print/static/src/xml/pos.xml:50
+#, python-format
+msgid "DDMMYYYY"
+msgstr "DDMMYYYY"
+
+#. 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:399
+#, 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:256
+#, 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:264
+#, 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:442
+#, python-format
+msgid "Fiscal Closing"
+msgstr "Fiscal Closing"
+
+#. module: fiscal_epos_print
+#: model: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/xml/pos.xml:40
+#: code:addons/fiscal_epos_print/static/src/xml/pos.xml:45
+#, python-format
+msgid "Max 4 numbers"
+msgstr "Max 4 numeri"
+
+#. module: fiscal_epos_print
+#. openerp-web
+#: code:addons/fiscal_epos_print/static/src/js/fp90iii.js:271
+#, 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:472
+#, python-format
+msgid "No taxes found"
+msgstr "Nessuna imposta trovata"
+
+#. module: fiscal_epos_print
+#. openerp-web
+#: code:addons/fiscal_epos_print/static/src/js/fp90iii.js:337
+#, 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"
+msgstr "Tipo pagamento"
+
+#. module: fiscal_epos_print
+#: model:ir.model,name:fiscal_epos_print.model_pos_order
+msgid "Point of Sale Orders"
+msgstr "Ordini del 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:15
+#, python-format
+msgid "Product %s must have 1 tax"
+msgstr "Il prodotto %s deve avere una aliquota iva"
+
+#. module: fiscal_epos_print
+#: model:ir.model,name:fiscal_epos_print.model_product_template
+msgid "Product Template"
+msgstr "Template del Prodotto"
+
+#. module: fiscal_epos_print
+#. openerp-web
+#: code:addons/fiscal_epos_print/static/src/xml/pos.xml:53
+#: code:addons/fiscal_epos_print/static/src/xml/pos.xml:55
+#, python-format
+msgid "RT Serial"
+msgstr "Seriale RT"
+
+#. module: fiscal_epos_print
+#. openerp-web
+#: code:addons/fiscal_epos_print/static/src/xml/pos.xml:48
+#, python-format
+msgid "Receipt Date"
+msgstr "Data Scontrino"
+
+#. module: fiscal_epos_print
+#. openerp-web
+#: code:addons/fiscal_epos_print/static/src/xml/pos.xml:43
+#, python-format
+msgid "Receipt Num."
+msgstr "Num. 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 spedito alla stampante"
+
+#. module: fiscal_epos_print
+#. openerp-web
+#: code:addons/fiscal_epos_print/static/src/js/fp90iii.js:411
+#, 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 "Refund Cash Serial"
+
+#. module: fiscal_epos_print
+#. openerp-web
+#: code:addons/fiscal_epos_print/static/src/xml/pos.xml:25
+#, python-format
+msgid "Refund Data"
+msgstr "Dati Reso"
+
+#. module: fiscal_epos_print
+#: model: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:113
+#, 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:34
+#, python-format
+msgid "Refund Information Not Present"
+msgstr "Dettagli 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 "Report reference"
+
+#. module: fiscal_epos_print
+#. openerp-web
+#: code:addons/fiscal_epos_print/static/src/xml/pos.xml:38
+#, 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 "Imposta l'indice del tipo pagamento indicato. L'indice del pagamento deve essere programmato nella stampante fiscale"
+
+#. module: fiscal_epos_print
+#. openerp-web
+#: code:addons/fiscal_epos_print/static/src/xml/pos.xml:66
+#, 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
+#, python-format
+msgid "Status of files to be sent to ADE"
+msgstr "Stato del file da spedire 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 "Hostname o indirizzo IP della stampante fisica, riempi il campo se vuoi usare la stampate degli scontrini"
+
+#. 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 "Tipo di pagamento da spedire alla Stampante Fiscale."
+
+#. module: fiscal_epos_print
+#. openerp-web
+#: code:addons/fiscal_epos_print/static/src/js/fp90iii.js:35
+#, python-format
+msgid "The refund information aren't present. Please insert them before printing the receipt"
+msgstr "Le informazioni del reso non sono presenti. Si prega di inserirle prima di stampare lo scontrino"
+
+#. module: fiscal_epos_print
+#: selection:account.journal,fiscalprinter_payment_type:0
+msgid "Ticket"
+msgstr "Ticket"
+
+#. module: fiscal_epos_print
+#: model:ir.model.fields,field_description:fiscal_epos_print.field_pos_config_use_https
+msgid "Use https"
+msgstr "Usa https"
+
+#. module: fiscal_epos_print
+#. openerp-web
+#: code:addons/fiscal_epos_print/static/src/xml/pos.xml:19
+#, python-format
+msgid "display:none"
+msgstr "display:none"
+
+#. module: fiscal_epos_print
+#: model:ir.model,name:fiscal_epos_print.model_pos_config
+msgid "pos.config"
+msgstr "pos.config"
+
diff --git a/fiscal_epos_print/models/__init__.py b/fiscal_epos_print/models/__init__.py
new file mode 100644
index 000000000000..35aabec125f2
--- /dev/null
+++ b/fiscal_epos_print/models/__init__.py
@@ -0,0 +1,7 @@
+# coding=utf-8
+
+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.py b/fiscal_epos_print/models/account.py
new file mode 100644
index 000000000000..767476ad5146
--- /dev/null
+++ b/fiscal_epos_print/models/account.py
@@ -0,0 +1,12 @@
+# coding=utf-8
+
+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..24459cc89648
--- /dev/null
+++ b/fiscal_epos_print/models/account_journal.py
@@ -0,0 +1,25 @@
+# coding=utf-8
+
+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'
+ )
+
+ 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
new file mode 100644
index 000000000000..13f7b13e8b17
--- /dev/null
+++ b/fiscal_epos_print/models/point_of_sale.py
@@ -0,0 +1,21 @@
+# coding=utf-8
+
+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,
+ )
+
+ 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
new file mode 100644
index 000000000000..7a256523ba75
--- /dev/null
+++ b/fiscal_epos_print/models/product.py
@@ -0,0 +1,15 @@
+# coding=utf-8
+
+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)
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/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"),' | "},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('
");for(h='
'+u.i18n.months[a]+'
",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('");return d=''+n+u.yearSuffix+'
",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+='"),t===e._o.numberOfMonths-1&&(g+='"),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/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;
+ },
+
+ /*
+ 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_order();
+ 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': 'ADE files status',
+ 'widget': FiscalPrinterADEFilesButtonWidget,
+ 'append': '.pos-rightheader',
+ 'args': {
+ 'label': _t('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
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
new file mode 100644
index 000000000000..c3492ec57baf
--- /dev/null
+++ b/fiscal_epos_print/static/src/xml/pos.xml
@@ -0,0 +1,74 @@
+
+
+
+
+
+
+
+
+
+
+ Receipt sent to the printer
+
+
+
+
+
+ display:none
+
+
+
+
+
+ Refund Data
+
+
+
+
+
+
+
+
+
+
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..6cd577040091
--- /dev/null
+++ b/fiscal_epos_print/views/account_statement_view.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+ 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..d7c458a6bdc3
--- /dev/null
+++ b/fiscal_epos_print/views/assets.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
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..ed88cc83737f
--- /dev/null
+++ b/fiscal_epos_print/views/point_of_sale.xml
@@ -0,0 +1,42 @@
+
+
+
+
+
+ pos.config.form.printer.view
+ pos.config
+
+
+
+
+
+
+ Fiscal printer
+
+
+
+
+
+
+
+
+
+ pos.order.form
+ pos.order
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/oca_dependencies.txt b/oca_dependencies.txt
index a82a6df2f053..f3130360cebf 100644
--- a/oca_dependencies.txt
+++ b/oca_dependencies.txt
@@ -7,3 +7,4 @@ partner-contact
server-tools
stock-logistics-workflow
web
+pos
From 857c79f8afae1683b7d0e4997aa30a3c8ca6135e Mon Sep 17 00:00:00 2001
From: Roberto Fichera
Date: Thu, 12 Dec 2019 12:37:10 +0100
Subject: [PATCH 02/17] [10.0][fiscal_epos_print] Split fp90iii.js into several
source code for better maintainance
---
fiscal_epos_print/__manifest__.py | 10 +-
fiscal_epos_print/static/src/js/chrome.js | 49 ++
.../static/src/js/epson_epos_print.js | 228 ++++++
fiscal_epos_print/static/src/js/fp90iii.js | 658 ------------------
fiscal_epos_print/static/src/js/models.js | 147 +++-
fiscal_epos_print/static/src/js/popups.js | 83 +++
.../static/src/js/pos_order_mgmt.js | 48 ++
fiscal_epos_print/static/src/js/screens.js | 157 +++++
fiscal_epos_print/views/assets.xml | 10 +-
9 files changed, 724 insertions(+), 666 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
diff --git a/fiscal_epos_print/__manifest__.py b/fiscal_epos_print/__manifest__.py
index 21cb7e113e0f..8a3ca5f56500 100644
--- a/fiscal_epos_print/__manifest__.py
+++ b/fiscal_epos_print/__manifest__.py
@@ -26,9 +26,15 @@
'views/assets.xml',
],
'js': [
+ 'static/lib/fiscalprint/fiscalprint.js',
+ 'static/lib/pikaday/pikaday.min.js',
+ 'static/lib/pikaday/pikaday.min.css',
+ 'static/src/js/epson_epos_print.js',
+ 'static/src/js/screens.js',
'static/src/js/models.js',
- 'static/src/js/fp90iii.js',
- 'static/lib/fiscalprint/fiscalprint.js'
+ 'static/src/js/popups.js',
+ 'static/src/js/pos_order_mgmt.js',
+ 'static/src/js/chrome.js',
],
'qweb': [
'static/src/xml/pos.xml'
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..6cb990a53253
--- /dev/null
+++ b/fiscal_epos_print/static/src/js/chrome.js
@@ -0,0 +1,49 @@
+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': 'ADE files status',
+ 'widget': FiscalPrinterADEFilesButtonWidget,
+ 'append': '.pos-rightheader',
+ 'args': {
+ 'label': _t('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..38d737d3cbb5
--- /dev/null
+++ b/fiscal_epos_print/static/src/js/epson_epos_print.js
@@ -0,0 +1,228 @@
+odoo.define("fiscal_epos_print.epson_epos_print", function (require) {
+ "use strict";
+
+ var core = require("web.core");
+ 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 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);
+ },
+
+ });
+
+ 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 09a3cda57690..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_order();
- 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': 'ADE files status',
- 'widget': FiscalPrinterADEFilesButtonWidget,
- 'append': '.pos-rightheader',
- 'args': {
- 'label': _t('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..2e8b411e0ff4 100644
--- a/fiscal_epos_print/static/src/js/models.js
+++ b/fiscal_epos_print/static/src/js/models.js
@@ -1,8 +1,149 @@
-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;
+ },
+ 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 _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;
+ }
+ });
+
+ 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..2f7c4f27c620
--- /dev/null
+++ b/fiscal_epos_print/static/src/js/popups.js
@@ -0,0 +1,83 @@
+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..6f334ef84521
--- /dev/null
+++ b/fiscal_epos_print/static/src/js/pos_order_mgmt.js
@@ -0,0 +1,48 @@
+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) {
+ 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);
+ },
+ });
+
+});
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..bb362108ca59
--- /dev/null
+++ b/fiscal_epos_print/static/src/js/screens.js
@@ -0,0 +1,157 @@
+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_order();
+ 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;
+ }
+ },
+
+ 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);
+ }
+ });
+
+ 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/views/assets.xml b/fiscal_epos_print/views/assets.xml
index d7c458a6bdc3..f05fef8affbb 100644
--- a/fiscal_epos_print/views/assets.xml
+++ b/fiscal_epos_print/views/assets.xml
@@ -4,11 +4,15 @@
-
-
-
+
+
+
+
+
+
+
From c1c221ea90b1bc1c8067bb866b08cbfa1a401668 Mon Sep 17 00:00:00 2001
From: Roberto Fichera
Date: Thu, 12 Dec 2019 12:37:56 +0100
Subject: [PATCH 03/17] [10.0][fiscal_epos_print] Fix RefundInfoPopupWidget
layout
---
fiscal_epos_print/static/src/xml/pos.xml | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/fiscal_epos_print/static/src/xml/pos.xml b/fiscal_epos_print/static/src/xml/pos.xml
index c3492ec57baf..233469477db7 100644
--- a/fiscal_epos_print/static/src/xml/pos.xml
+++ b/fiscal_epos_print/static/src/xml/pos.xml
@@ -22,7 +22,8 @@
- Refund Data
+
+ Refund Data
@@ -35,22 +36,22 @@
-
Seq. Closing
+
Seq. Closing
-
Receipt Num.
+
Receipt Num.
-
Receipt Date
+
Receipt Date
From 14ede5033764918c27e1d022ddda701d046ac443 Mon Sep 17 00:00:00 2001
From: Roberto Fichera
Date: Thu, 12 Dec 2019 12:51:51 +0100
Subject: [PATCH 04/17] [10.0][fiscal_epos_print] Import missing round_pr() in
epson_epos_print.js
---
fiscal_epos_print/static/src/js/epson_epos_print.js | 2 ++
1 file changed, 2 insertions(+)
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 38d737d3cbb5..760d77829b8c 100644
--- a/fiscal_epos_print/static/src/js/epson_epos_print.js
+++ b/fiscal_epos_print/static/src/js/epson_epos_print.js
@@ -2,7 +2,9 @@ odoo.define("fiscal_epos_print.epson_epos_print", function (require) {
"use strict";
var core = require("web.core");
+ var utils = require('web.utils');
var _t = core._t;
+ var round_pr = utils.round_precision;
function addPadding(str, padding=4) {
var pad = new Array(padding).fill(0).join('') + str;
From ac3540ed34a067ea4abdcb9535e431164013589f Mon Sep 17 00:00:00 2001
From: Roberto Fichera
Date: Thu, 12 Dec 2019 15:27:59 +0100
Subject: [PATCH 05/17] [10.0][fiscal_epos_print] Remove js file from manifest
---
fiscal_epos_print/__manifest__.py | 11 -----------
1 file changed, 11 deletions(-)
diff --git a/fiscal_epos_print/__manifest__.py b/fiscal_epos_print/__manifest__.py
index 8a3ca5f56500..aaa7ede2f011 100644
--- a/fiscal_epos_print/__manifest__.py
+++ b/fiscal_epos_print/__manifest__.py
@@ -25,17 +25,6 @@
'views/point_of_sale.xml',
'views/assets.xml',
],
- 'js': [
- 'static/lib/fiscalprint/fiscalprint.js',
- 'static/lib/pikaday/pikaday.min.js',
- 'static/lib/pikaday/pikaday.min.css',
- 'static/src/js/epson_epos_print.js',
- 'static/src/js/screens.js',
- 'static/src/js/models.js',
- 'static/src/js/popups.js',
- 'static/src/js/pos_order_mgmt.js',
- 'static/src/js/chrome.js',
- ],
'qweb': [
'static/src/xml/pos.xml'
],
From b5ce96d95adc05bab1db2168e12da255cb5de809 Mon Sep 17 00:00:00 2001
From: Roberto Fichera
Date: Thu, 12 Dec 2019 15:28:58 +0100
Subject: [PATCH 06/17] [10.0][fiscal_epos_print] Review the discounted price
calculation to match the v12
---
fiscal_epos_print/static/src/js/epson_epos_print.js | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
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 760d77829b8c..c06224b60d42 100644
--- a/fiscal_epos_print/static/src/js/epson_epos_print.js
+++ b/fiscal_epos_print/static/src/js/epson_epos_print.js
@@ -156,17 +156,21 @@ odoo.define("fiscal_epos_print.epson_epos_print", function (require) {
_.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: l.price,
+ unitPrice: l.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 * l.price - l.price_display, self.sender.pos.currency.rounding),
+ amount: round_pr(l.quantity * full_price - l.price, self.sender.pos.currency.rounding),
});
}
}
From 4ed6e038aef07e78ce4cb978d1265d7d91e2b884 Mon Sep 17 00:00:00 2001
From: Roberto Fichera
Date: Thu, 12 Dec 2019 15:40:25 +0100
Subject: [PATCH 07/17] [10.0][fiscal_epos_print] Check if the pos is
configured with tax included as step to validate the pos.order
---
fiscal_epos_print/static/src/js/screens.js | 32 ++++++++++++++--------
1 file changed, 21 insertions(+), 11 deletions(-)
diff --git a/fiscal_epos_print/static/src/js/screens.js b/fiscal_epos_print/static/src/js/screens.js
index bb362108ca59..719e81c8d1f7 100644
--- a/fiscal_epos_print/static/src/js/screens.js
+++ b/fiscal_epos_print/static/src/js/screens.js
@@ -48,18 +48,28 @@ odoo.define("fiscal_epos_print.screens", function (require) {
},
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;
+ if (this.pos.config.printer_ip) {
+ 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;
+ }
+
+ if (!this.pos.config.iface_tax_included) {
+ 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;
+ }
}
+
return this._super(force_validation);
}
});
From 465fa34ff84b5b74a3ddcaa5ad4bba056d0bc5e2 Mon Sep 17 00:00:00 2001
From: Roberto Fichera
Date: Fri, 13 Dec 2019 15:36:43 +0100
Subject: [PATCH 08/17] [10.0][fiscal_epos_print] Fix usage of full_price when
generating the xml for the ePOS
---
fiscal_epos_print/static/src/js/epson_epos_print.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
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 c06224b60d42..4eababee9e44 100644
--- a/fiscal_epos_print/static/src/js/epson_epos_print.js
+++ b/fiscal_epos_print/static/src/js/epson_epos_print.js
@@ -163,7 +163,7 @@ odoo.define("fiscal_epos_print.epson_epos_print", function (require) {
xml += self.printRecItem({
description: l.product_name,
quantity: l.quantity,
- unitPrice: l.full_price,
+ unitPrice: full_price,
department: l.tax_department.code
});
if (l.discount) {
From da3a96086aaad3dbf648389c295c64312034a9c8 Mon Sep 17 00:00:00 2001
From: Roberto Fichera
Date: Fri, 13 Dec 2019 17:30:14 +0100
Subject: [PATCH 09/17] [10.0][fiscal_epos_print] show_popup instead of alert
---
fiscal_epos_print/static/src/js/epson_epos_print.js | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
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 4eababee9e44..b1cbae9d8f62 100644
--- a/fiscal_epos_print/static/src/js/epson_epos_print.js
+++ b/fiscal_epos_print/static/src/js/epson_epos_print.js
@@ -36,9 +36,10 @@ odoo.define("fiscal_epos_print.epson_epos_print", function (require) {
}
this.fiscalPrinter.onerror = function() {
sender.chrome.loading_hide();
- alert(
- _t('Network error. Printer can not be reached')
- );
+ sender.pos.gui.show_popup('error', {
+ 'title': _t('Network error'),
+ 'body': _t('Printer can not be reached')
+ });
}
},
From fcaf4365f5f9f8f3730a724e990149917a3c7397 Mon Sep 17 00:00:00 2001
From: eLBati
Date: Fri, 13 Dec 2019 16:52:07 +0100
Subject: [PATCH 10/17] IMP fiscal_epos_print writing fiscal receipt data to
pos.order
---
fiscal_epos_print/models/pos_order.py | 27 +++-
.../static/src/js/epson_epos_print.js | 152 +++++++++++++++++-
fiscal_epos_print/static/src/js/models.js | 16 ++
fiscal_epos_print/views/point_of_sale.xml | 18 ++-
4 files changed, 205 insertions(+), 8 deletions(-)
diff --git a/fiscal_epos_print/models/pos_order.py b/fiscal_epos_print/models/pos_order.py
index 88939f963209..c8039317c45a 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)
@@ -31,3 +37,20 @@ def _prepare_done_order_for_pos(self):
res['refund_doc_num'] = self.refund_doc_num
res['refund_cash_fiscal_serial'] = self.refund_cash_fiscal_serial
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
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 b1cbae9d8f62..f30af01da615 100644
--- a/fiscal_epos_print/static/src/js/epson_epos_print.js
+++ b/fiscal_epos_print/static/src/js/epson_epos_print.js
@@ -3,6 +3,8 @@ odoo.define("fiscal_epos_print.epson_epos_print", function (require) {
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;
@@ -11,6 +13,109 @@ odoo.define("fiscal_epos_print.epson_epos_print", function (require) {
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) {
options = options || {};
@@ -20,11 +125,12 @@ odoo.define("fiscal_epos_print.epson_epos_print", function (require) {
this.sender = sender;
this.fiscalPrinter.onreceive = function(res, tag_list_names, add_info) {
this.fpreponse = tag_list_names
+ var tagStatus = this.fpreponse.filter(getStatusField);
if (res['code'] == "EPTR_REC_EMPTY"){
sender.chrome.loading_hide();
alert(_t("Error missing paper."));
}
- if (add_info.responseCommand == "1138") {
+ 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];
@@ -33,6 +139,50 @@ odoo.define("fiscal_epos_print.epson_epos_print", function (require) {
var msg = _t("Files waiting to be sent: ") + to_be_sent + _t("\nOld files: ") + old + _t("\nRejected files: ") + rejected
alert(msg);
}
+ else if (tagStatus.length > 0 && res.success) {
+ var info = add_info[tagStatus[0]];
+ var msgPrinter = decodeFpStatus(info);
+ if (!isErrorStatus(info)) {
+ var order = sender.pos.get_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;
+
+ var def = new $.Deferred();
+ var pos_db = new PosDB();
+ if (pos_db.get_order(order.uid)) {
+ pos_db.add_order(order);
+ } else {
+ rpc.query({
+ model: 'pos.order',
+ method: 'update_fiscal_receipt_values',
+ args: [order.export_as_JSON()],
+ }).then(function (r) {
+ def.resolve();
+ }), function (type, error) {
+ sender.pos.gui.show_popup('error', {
+ 'title': _t('Error'),
+ 'body': _t('Cannot update fiscal number for order. Set it manually, in case.')
+ });
+ };
+ };
+ }
+ }
+ 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();
diff --git a/fiscal_epos_print/static/src/js/models.js b/fiscal_epos_print/static/src/js/models.js
index 2e8b411e0ff4..a62a19672dd0 100644
--- a/fiscal_epos_print/static/src/js/models.js
+++ b/fiscal_epos_print/static/src/js/models.js
@@ -20,6 +20,10 @@ odoo.define('fiscal_epos_print.models', function (require) {
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();
@@ -36,6 +40,10 @@ odoo.define('fiscal_epos_print.models', function (require) {
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() {
@@ -46,6 +54,10 @@ odoo.define('fiscal_epos_print.models', function (require) {
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;
},
@@ -56,6 +68,10 @@ odoo.define('fiscal_epos_print.models', function (require) {
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
},
diff --git a/fiscal_epos_print/views/point_of_sale.xml b/fiscal_epos_print/views/point_of_sale.xml
index ed88cc83737f..e5a10fcbddc4 100644
--- a/fiscal_epos_print/views/point_of_sale.xml
+++ b/fiscal_epos_print/views/point_of_sale.xml
@@ -26,12 +26,20 @@
-
+
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
From ecf13a188d7ea98e0475b3922438c26dd070ed15 Mon Sep 17 00:00:00 2001
From: Roberto Fichera
Date: Mon, 16 Dec 2019 19:47:36 +0100
Subject: [PATCH 11/17] [10.0][fiscal_epos_print] Add encoding in pos_order
---
fiscal_epos_print/models/pos_order.py | 2 ++
1 file changed, 2 insertions(+)
diff --git a/fiscal_epos_print/models/pos_order.py b/fiscal_epos_print/models/pos_order.py
index c8039317c45a..39bbe941794f 100644
--- a/fiscal_epos_print/models/pos_order.py
+++ b/fiscal_epos_print/models/pos_order.py
@@ -1,3 +1,5 @@
+# coding=utf-8
+
from datetime import datetime
from odoo import fields, models, api
From 82033b541d583dabd3634f2e983fc4a1e6dd6b25 Mon Sep 17 00:00:00 2001
From: Roberto Fichera
Date: Tue, 17 Dec 2019 16:31:38 +0100
Subject: [PATCH 12/17] [10.0][fiscal_epos_print] More improvement to
fiscal_epos_print writing fiscal receipt data to pos.order
---
fiscal_epos_print/models/pos_order.py | 8 ++++
.../static/src/js/epson_epos_print.js | 38 ++++++++-----------
2 files changed, 24 insertions(+), 22 deletions(-)
diff --git a/fiscal_epos_print/models/pos_order.py b/fiscal_epos_print/models/pos_order.py
index 39bbe941794f..bef27333af94 100644
--- a/fiscal_epos_print/models/pos_order.py
+++ b/fiscal_epos_print/models/pos_order.py
@@ -56,3 +56,11 @@ def update_fiscal_receipt_values(self, pos_order):
'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/src/js/epson_epos_print.js b/fiscal_epos_print/static/src/js/epson_epos_print.js
index f30af01da615..593ab557491f 100644
--- a/fiscal_epos_print/static/src/js/epson_epos_print.js
+++ b/fiscal_epos_print/static/src/js/epson_epos_print.js
@@ -3,8 +3,7 @@ odoo.define("fiscal_epos_print.epson_epos_print", function (require) {
var core = require("web.core");
var utils = require('web.utils');
- var PosDB = require('point_of_sale.DB');
- var rpc = require('web.rpc');
+ var Model = require('web.Model');
var _t = core._t;
var round_pr = utils.round_precision;
@@ -118,14 +117,15 @@ odoo.define("fiscal_epos_print.epson_epos_print", function (require) {
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.fpreponse = false;
+ this.fpresponse = false;
this.sender = sender;
this.fiscalPrinter.onreceive = function(res, tag_list_names, add_info) {
- this.fpreponse = tag_list_names
- var tagStatus = this.fpreponse.filter(getStatusField);
+ self.fpresponse = tag_list_names;
+ var tagStatus = tag_list_names.filter(getStatusField);
if (res['code'] == "EPTR_REC_EMPTY"){
sender.chrome.loading_hide();
alert(_t("Error missing paper."));
@@ -150,24 +150,18 @@ odoo.define("fiscal_epos_print.epson_epos_print", function (require) {
order.fiscal_receipt_date = add_info.fiscalReceiptDate;
order.fiscal_z_rep_number = add_info.zRepNumber;
- var def = new $.Deferred();
- var pos_db = new PosDB();
- if (pos_db.get_order(order.uid)) {
- pos_db.add_order(order);
+ if (sender.pos.get_order(order.uid)) {
+ sender.pos.db.add_order(order);
} else {
- rpc.query({
- model: 'pos.order',
- method: 'update_fiscal_receipt_values',
- args: [order.export_as_JSON()],
- }).then(function (r) {
- def.resolve();
- }), function (type, error) {
- sender.pos.gui.show_popup('error', {
- 'title': _t('Error'),
- 'body': _t('Cannot update fiscal number for order. Set it manually, in case.')
+ var P = new Model('pos.order');
+ P.call('update_fiscal_receipt_values', [order.export_as_JSON()])
+ .fail(function(error, event) {
+ sender.pos.gui.show_popup('error', {
+ 'title': _t('Error'),
+ 'body': _t('Cannot update fiscal number for order. Set it manually, in case.')
+ });
});
- };
- };
+ }
}
}
else {
@@ -364,7 +358,7 @@ odoo.define("fiscal_epos_print.epson_epos_print", function (require) {
printFiscalReport: function() {
var xml = '';
xml += '';
- xml += '';
+ xml += '';
xml += '';
this.fiscalPrinter.send(this.url, xml);
},
From 49ae195b9ddbc819cbe74f724420b1034af7f2a5 Mon Sep 17 00:00:00 2001
From: Roberto Fichera
Date: Tue, 17 Dec 2019 17:25:30 +0100
Subject: [PATCH 13/17] [10.0][fiscal_epos_print] Pass the order to print
within the printer options so that the onreceive can update it
---
fiscal_epos_print/static/src/js/epson_epos_print.js | 3 ++-
fiscal_epos_print/static/src/js/pos_order_mgmt.js | 3 ++-
fiscal_epos_print/static/src/js/screens.js | 1 +
3 files changed, 5 insertions(+), 2 deletions(-)
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 593ab557491f..ac2b872384c0 100644
--- a/fiscal_epos_print/static/src/js/epson_epos_print.js
+++ b/fiscal_epos_print/static/src/js/epson_epos_print.js
@@ -123,6 +123,7 @@ odoo.define("fiscal_epos_print.epson_epos_print", function (require) {
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);
@@ -143,7 +144,7 @@ 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 = sender.pos.get_order();
+ 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(',', '.'));
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 6f334ef84521..cf7c55b1e593 100644
--- a/fiscal_epos_print/static/src/js/pos_order_mgmt.js
+++ b/fiscal_epos_print/static/src/js/pos_order_mgmt.js
@@ -37,8 +37,9 @@ odoo.define("fiscal_epos_print.pos_order_mgmt", function (require) {
},
action_print: function (order_data, order) {
if (this.pos.config.printer_ip) {
- var receipt = order.export_for_printing();
+ var receipt = order_data.export_for_printing();
var printer_options = this.getPrinterOptions();
+ printer_options.order = order_data;
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
index 719e81c8d1f7..0dce24905749 100644
--- a/fiscal_epos_print/static/src/js/screens.js
+++ b/fiscal_epos_print/static/src/js/screens.js
@@ -41,6 +41,7 @@ odoo.define("fiscal_epos_print.screens", function (require) {
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;
From de3a127d5d1123d002ed49c4f4956bd337c089ed Mon Sep 17 00:00:00 2001
From: Roberto Fichera
Date: Tue, 17 Dec 2019 19:36:33 +0100
Subject: [PATCH 14/17] [10.0][fiscal_epos_print] Move refund details as first
line in the receipt
---
.../static/src/js/epson_epos_print.js | 58 ++++++++++++++-----
1 file changed, 43 insertions(+), 15 deletions(-)
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 ac2b872384c0..5f37b311771e 100644
--- a/fiscal_epos_print/static/src/js/epson_epos_print.js
+++ b/fiscal_epos_print/static/src/js/epson_epos_print.js
@@ -206,7 +206,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) + ' ' +
@@ -216,8 +216,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;
+ },
+
/*
Prints a receipt
*/
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) {
@@ -323,10 +350,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,
@@ -343,14 +366,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 28ee14fa7dde0907737eecf26578291101b9acea Mon Sep 17 00:00:00 2001
From: eLBati
Date: Wed, 18 Dec 2019 15:56:47 +0100
Subject: [PATCH 15/17] IMP fiscal_epos_print: avoid to print again an order
with a fiscal receipt number
---
fiscal_epos_print/models/pos_order.py | 9 ++
fiscal_epos_print/readme/ROADMAP.rst | 4 +
fiscal_epos_print/static/src/js/chrome.js | 32 +++++
.../static/src/js/epson_epos_print.js | 111 ++++++++----------
fiscal_epos_print/static/src/js/models.js | 5 +-
.../static/src/js/pos_order_mgmt.js | 7 ++
fiscal_epos_print/static/src/xml/pos.xml | 6 +
7 files changed, 110 insertions(+), 64 deletions(-)
create mode 100644 fiscal_epos_print/readme/ROADMAP.rst
diff --git a/fiscal_epos_print/models/pos_order.py b/fiscal_epos_print/models/pos_order.py
index bef27333af94..20124c12bc0c 100644
--- a/fiscal_epos_print/models/pos_order.py
+++ b/fiscal_epos_print/models/pos_order.py
@@ -64,3 +64,12 @@ def create_from_ui(self, orders):
if order['data'].get('fiscal_receipt_number'):
self.update_fiscal_receipt_values(order['data'])
return res
+
+ @api.multi
+ def _prepare_done_order_for_pos(self):
+ res = super(PosOrder, self)._prepare_done_order_for_pos()
+ 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
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/chrome.js b/fiscal_epos_print/static/src/js/chrome.js
index 6cb990a53253..d461a8b25073 100644
--- a/fiscal_epos_print/static/src/js/chrome.js
+++ b/fiscal_epos_print/static/src/js/chrome.js
@@ -32,6 +32,28 @@ odoo.define("fiscal_epos_print.chrome", function (require) {
});
+ var PrinterFiscalClosure = PosBaseWidget.extend({
+ template: 'PrinterFiscalClosure',
+
+ 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, requested_z_report: true};
+ var fp90 = new eposDriver(printer_options, this);
+ fp90.printFiscalReport();
+ },
+
+ 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',
@@ -42,8 +64,18 @@ odoo.define("fiscal_epos_print.chrome", function (require) {
},
});
+ widgets.push({
+ 'name': _t('Printer Fiscal Closure'),
+ 'widget': PrinterFiscalClosure,
+ 'append': '.pos-rightheader',
+ 'args': {
+ 'label': 'Printer Fiscal Closure',
+ },
+ });
+
return {
FiscalPrinterADEFilesButtonWidget: FiscalPrinterADEFilesButtonWidget,
+ PrinterFiscalClosure: PrinterFiscalClosure,
};
});
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 5f37b311771e..ee0bb3b5071e 100644
--- a/fiscal_epos_print/static/src/js/epson_epos_print.js
+++ b/fiscal_epos_print/static/src/js/epson_epos_print.js
@@ -124,48 +124,52 @@ odoo.define("fiscal_epos_print.epson_epos_print", function (require) {
this.fpresponse = false;
this.sender = sender;
this.order = options.order || null;
+ this.requested_z_report = options.requested_z_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();
- alert(_t("Error missing paper."));
+ sender.chrome.screens['receipt'].lock_screen(true);
+ 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("\nOld files: ") + old + _t("\nRejected files: ") + rejected
- alert(msg);
+ 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;
-
- if (sender.pos.get_order(order.uid)) {
- sender.pos.db.add_order(order);
- } else {
- var P = new Model('pos.order');
- P.call('update_fiscal_receipt_values', [order.export_as_JSON()])
- .fail(function(error, event) {
- sender.pos.gui.show_popup('error', {
- 'title': _t('Error'),
- 'body': _t('Cannot update fiscal number for order. Set it manually, in case.')
- });
- });
+ // Z report can be printed from header bar: we just need to hide the loading screen, done above
+ if (!self.requested_z_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;
+ sender.pos.db.add_order(order.export_as_JSON());
+ }
+ 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,
@@ -173,6 +177,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,
@@ -181,6 +186,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')
@@ -235,6 +241,13 @@ odoo.define("fiscal_epos_print.epson_epos_print", function (require) {
return tag;
},
+ printRecTotalRefund: function(args) {
+ var tag = '';
+ return tag;
+ },
+
/*
Adds a discount to the last line.
*/
@@ -326,46 +339,19 @@ odoo.define("fiscal_epos_print.epson_epos_print", function (require) {
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) {
- 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.price, self.sender.pos.currency.rounding),
- });
- }
- }
- else
- {
- xml += self.printRecRefund({
- 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,
+ 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,
});
- }
- });
+ });
+ }
if (has_refund) {
xml += self.printRecTotalRefund({});
}
@@ -386,7 +372,6 @@ odoo.define("fiscal_epos_print.epson_epos_print", function (require) {
printFiscalReport: function() {
var xml = '';
- xml += '';
xml += '';
xml += '';
this.fiscalPrinter.send(this.url, xml);
diff --git a/fiscal_epos_print/static/src/js/models.js b/fiscal_epos_print/static/src/js/models.js
index a62a19672dd0..876fb83ec7eb 100644
--- a/fiscal_epos_print/static/src/js/models.js
+++ b/fiscal_epos_print/static/src/js/models.js
@@ -92,7 +92,10 @@ odoo.define('fiscal_epos_print.models', function (require) {
taxname: this.pos.taxes_by_id[i].name,
}
}
- alert(_t("No taxes found"));
+ 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);
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 cf7c55b1e593..e278fbc50611 100644
--- a/fiscal_epos_print/static/src/js/pos_order_mgmt.js
+++ b/fiscal_epos_print/static/src/js/pos_order_mgmt.js
@@ -37,6 +37,13 @@ odoo.define("fiscal_epos_print.pos_order_mgmt", function (require) {
},
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;
+ }
var receipt = order_data.export_for_printing();
var printer_options = this.getPrinterOptions();
printer_options.order = order_data;
diff --git a/fiscal_epos_print/static/src/xml/pos.xml b/fiscal_epos_print/static/src/xml/pos.xml
index 233469477db7..9e0f33f0cc91 100644
--- a/fiscal_epos_print/static/src/xml/pos.xml
+++ b/fiscal_epos_print/static/src/xml/pos.xml
@@ -7,6 +7,12 @@
+
+
+
+