From 81be592709903d93340694c33fee57deca535622 Mon Sep 17 00:00:00 2001 From: Florent de Labarre Date: Fri, 20 Mar 2020 11:24:00 +0100 Subject: [PATCH] [MIG] hw_telium_payment_terminal: Migration to 12.0 --- hw_telium_payment_terminal/README.rst | 89 +++++++++++-- hw_telium_payment_terminal/__init__.py | 23 ---- hw_telium_payment_terminal/__manifest__.py | 16 +++ hw_telium_payment_terminal/__openerp__.py | 37 ----- .../controllers/__init__.py | 23 ---- .../controllers/main.py | 126 ++++++++++-------- .../i18n/hw_telium_payment_terminal.pot | 14 -- .../test-scripts/telium-test.py | 21 --- 8 files changed, 168 insertions(+), 181 deletions(-) create mode 100644 hw_telium_payment_terminal/__manifest__.py delete mode 100644 hw_telium_payment_terminal/__openerp__.py delete mode 100644 hw_telium_payment_terminal/i18n/hw_telium_payment_terminal.pot diff --git a/hw_telium_payment_terminal/README.rst b/hw_telium_payment_terminal/README.rst index 2c4f2517..b9bd5ccb 100644 --- a/hw_telium_payment_terminal/README.rst +++ b/hw_telium_payment_terminal/README.rst @@ -1,15 +1,48 @@ +================================ Hardware Telium Payment Terminal ================================ +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fpos-lightgray.png?logo=github + :target: https://github.com/OCA/pos/tree/12.0/hw_telium_payment_terminal + :alt: OCA/pos +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/pos-12-0/pos-12-0-hw_telium_payment_terminal + :alt: Translate me on Weblate + +|badge1| |badge2| |badge3| |badge4| + This module adds support for credit card reader and checks printers using Telium protocol in the Point of Sale. This module is designed to be installed on the *POSbox* (i.e. the proxy on which the USB devices are connected) and not on the main Odoo server. On the main Odoo server, you should install the module *pos_payment_terminal*. +This module has been developped during a POS code sprint at Akretion +France from July 7th to July 10th 2014. + +**Table of contents** + +.. contents:: + :local: + +Installation +============ +Add this module in the PosBox in this folder : +/home/pi/odoo/addons +Reboot the PosBox + +Configuration +============= + The configuration of the hardware is done in the configuration file of -the Odoo server of the POSbox. You should add the following entries in -the configuration file: +the Odoo server of the POSbox. You can add the following entries in +the configuration file (optional). * payment_terminal_device_name (default = /dev/ttyACM0) * payment_terminal_device_rate (default = 9600) @@ -18,7 +51,9 @@ The Telium protocol is used by Ingenico and Sagem payment terminals. It is based on the Concert protocol, so it can probably work with payment terminals from other brands. This module implements the protocol E+ (and not the protocol E), so it requires a Telium Manager version 37783600 -or superior. To get the version of the Telium Manager on an Ingenico +or superior. +Information : https://lists.launchpad.net/openerp-community/pdfcezlBjgtdJ.pdf +To get the version of the Telium Manager on an Ingenico terminal press F > 0-TELIUM MANAGER > 2-Consultation > 4-Configuration > 2-Software > 1-TERMINAL > On Display > Telium Manager and then read the field *M20S*. @@ -35,14 +70,50 @@ This module has been successfully tested with: * Ingenico iCT220 * Ingenico iCT250 * Ingenico i2200 cheque reader and writer +* Ingenico Desk/5000 (USB Mode) -This module requires the Python library *pycountry* version >= 16.11.08. +This module requires the Python library *pycountry* version >= 16.11.08, +if you use a currency different of EUR. To install it, run: ``sudo pip install pycountry`` -This module has been developped during a POS code sprint at Akretion -France from July 7th to July 10th 2014. This module is part of the POS -project of the Odoo Community Association http://odoo-community.org/. -You are invited to become a member and/or get involved in the -Association ! +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* Akretion + +Contributors +~~~~~~~~~~~~ + +* Florent de Labarre + +Maintainers +~~~~~~~~~~~ + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +This module is part of the `OCA/pos `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/hw_telium_payment_terminal/__init__.py b/hw_telium_payment_terminal/__init__.py index c535b703..e046e49f 100644 --- a/hw_telium_payment_terminal/__init__.py +++ b/hw_telium_payment_terminal/__init__.py @@ -1,24 +1 @@ -# -*- encoding: utf-8 -*- -############################################################################## -# -# Hardware Telium Payment Terminal module for Odoo -# Copyright (C) 2014 Akretion (http://www.akretion.com) -# @author Alexis de Lattre -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -############################################################################## - - from . import controllers diff --git a/hw_telium_payment_terminal/__manifest__.py b/hw_telium_payment_terminal/__manifest__.py new file mode 100644 index 00000000..5b542470 --- /dev/null +++ b/hw_telium_payment_terminal/__manifest__.py @@ -0,0 +1,16 @@ +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +{ + 'name': 'Hardware Telium Payment Terminal', + 'version': '12.0.1.0.0', + 'category': 'Hardware Drivers', + 'license': 'AGPL-3', + 'summary': 'Adds support for Payment Terminals using Telium protocol', + 'author': "Akretion,Odoo Community Association (OCA)", + 'website': 'http://www.github.com/OCA/pos', + 'depends': ['hw_proxy'], + 'external_dependencies': { + 'python': ['serial', 'pycountry'], + }, + 'data': [], + 'installable': False, +} diff --git a/hw_telium_payment_terminal/__openerp__.py b/hw_telium_payment_terminal/__openerp__.py deleted file mode 100644 index fdfb436e..00000000 --- a/hw_telium_payment_terminal/__openerp__.py +++ /dev/null @@ -1,37 +0,0 @@ -# -*- encoding: utf-8 -*- -############################################################################## -# -# Hardware Telium Payment Terminal module for Odoo -# Copyright (C) 2014 Akretion (http://www.akretion.com) -# @author Alexis de Lattre -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -############################################################################## - - -{ - 'name': 'Hardware Telium Payment Terminal', - 'version': '8.0.0.1.2', - 'category': 'Hardware Drivers', - 'license': 'AGPL-3', - 'summary': 'Adds support for Payment Terminals using Telium protocol', - 'author': "Akretion,Odoo Community Association (OCA)", - 'website': 'http://www.akretion.com', - 'depends': ['hw_proxy'], - 'external_dependencies': { - 'python': ['serial', 'pycountry'], - }, - 'data': [], -} diff --git a/hw_telium_payment_terminal/controllers/__init__.py b/hw_telium_payment_terminal/controllers/__init__.py index d91efc38..12a7e529 100644 --- a/hw_telium_payment_terminal/controllers/__init__.py +++ b/hw_telium_payment_terminal/controllers/__init__.py @@ -1,24 +1 @@ -# -*- encoding: utf-8 -*- -############################################################################## -# -# Hardware Telium Payment Terminal module for Odoo -# Copyright (C) 2014 Akretion (http://www.akretion.com) -# @author Alexis de Lattre -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -############################################################################## - - from . import main diff --git a/hw_telium_payment_terminal/controllers/main.py b/hw_telium_payment_terminal/controllers/main.py index 90346cb0..7d25da91 100644 --- a/hw_telium_payment_terminal/controllers/main.py +++ b/hw_telium_payment_terminal/controllers/main.py @@ -1,44 +1,31 @@ -# -*- encoding: utf-8 -*- -############################################################################## -# -# Hardware Telium Payment Terminal module for Odoo -# Copyright (C) 2014 Akretion (http://www.akretion.com) -# @author Alexis de Lattre -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -############################################################################## - - import logging import simplejson import time import curses.ascii from threading import Thread, Lock -from Queue import Queue -import openerp.addons.hw_proxy.controllers.main as hw_proxy -from openerp import http -from openerp.tools.config import config +from queue import Queue + +from odoo import http +from odoo.tools.config import config + +from odoo.addons.hw_proxy.controllers import main as hw_proxy logger = logging.getLogger(__name__) try: - import pycountry from serial import Serial except (ImportError, IOError) as err: logger.debug(err) +try: + import pycountry + EUR_CY_NBR = False +except (ImportError, IOError) as err: + logger.debug(err) + logger.warning( + 'Unable to import pycountry, only EUR currency is supported') + EUR_CY_NBR = 978 + class TeliumPaymentTerminalDriver(Thread): def __init__(self): @@ -68,13 +55,13 @@ class TeliumPaymentTerminalDriver(Thread): self.status['messages'] = [] if status == 'error' and message: - logger.error('Payment Terminal Error: '+message) + logger.error('Payment Terminal Error: ' + message) elif status == 'disconnected' and message: - logger.warning('Disconnected Terminal: '+message) + logger.warning('Disconnected Terminal: ' + message) def lockedstart(self): with self.lock: - if not self.isAlive(): + if not self.is_alive(): self.daemon = True self.start() @@ -84,7 +71,17 @@ class TeliumPaymentTerminalDriver(Thread): def serial_write(self, text): assert isinstance(text, str), 'text must be a string' - self.serial.write(text) + raw = text.encode() + logger.debug("%s raw send to terminal" % raw) + logger.debug("%s send to terminal" % text) + self.serial.write(raw) + + def serial_read(self, size=1): + raw = self.serial.read(size) + msg = raw.decode('ascii') + logger.debug("%s raw received from terminal" % raw) + logger.debug("%s received from terminal" % msg) + return msg def initialize_msg(self): max_attempt = 3 @@ -109,17 +106,22 @@ class TeliumPaymentTerminalDriver(Thread): logger.debug('Signal %s sent to terminal' % signal) def get_one_byte_answer(self, expected_signal): + assert isinstance(expected_signal, str), 'expected_signal must be a string' ascii_names = curses.ascii.controlnames - one_byte_read = self.serial.read(1) + one_byte_read = self.serial_read(1) expected_char = ascii_names.index(expected_signal) if one_byte_read == chr(expected_char): - logger.debug("%s received from terminal" % expected_signal) return True else: return False - def prepare_data_to_send(self, payment_info_dict): + def _get_amount(self, payment_info_dict): amount = payment_info_dict['amount'] + cur_decimals = payment_info_dict['currency_decimals'] + cur_fact = 10 ** cur_decimals + return ('%.0f' % (amount * cur_fact)).zfill(8) + + def prepare_data_to_send(self, payment_info_dict): if payment_info_dict['payment_mode'] == 'check': payment_mode = 'C' elif payment_info_dict['payment_mode'] == 'card': @@ -129,12 +131,14 @@ class TeliumPaymentTerminalDriver(Thread): "The payment mode '%s' is not supported" % payment_info_dict['payment_mode']) return False - cur_decimals = payment_info_dict['currency_decimals'] - cur_fact = 10**cur_decimals + cur_iso_letter = payment_info_dict['currency_iso'].upper() try: - cur = pycountry.currencies.get(alpha_3=cur_iso_letter) - cur_numeric = str(cur.numeric) + if EUR_CY_NBR: + cur_numeric = str(EUR_CY_NBR) + else: + cur = pycountry.currencies.get(alpha_3=cur_iso_letter) + cur_numeric = str(cur.numeric) except: logger.error("Currency %s is not recognized" % cur_iso_letter) return False @@ -145,9 +149,9 @@ class TeliumPaymentTerminalDriver(Thread): 'payment_mode': payment_mode, 'currency_numeric': cur_numeric.zfill(3), 'private': ' ' * 10, - 'delay': 'A011', + 'delay': 'A010', 'auto': 'B010', - 'amount_msg': ('%.0f' % (amount * cur_fact)).zfill(8), + 'amount_msg': self._get_amount(payment_info_dict), } return data @@ -179,9 +183,7 @@ class TeliumPaymentTerminalDriver(Thread): logger.info('Message sent to terminal') def compare_data_vs_answer(self, data, answer_data): - for field in [ - 'pos_number', 'amount_msg', - 'currency_numeric', 'private']: + for field in ['pos_number', 'amount_msg', 'currency_numeric', 'private']: if data[field] != answer_data[field]: logger.warning( "Field %s has value '%s' in data and value '%s' in answer" @@ -202,8 +204,8 @@ class TeliumPaymentTerminalDriver(Thread): def get_answer_from_terminal(self, data): ascii_names = curses.ascii.controlnames - full_msg_size = 1+2+1+8+1+3+10+1+1 - msg = self.serial.read(size=full_msg_size) + full_msg_size = 1 + 2 + 1 + 8 + 1 + 3 + 10 + 1 + 1 + msg = self.serial_read(size=full_msg_size) logger.debug('%d bytes read from terminal' % full_msg_size) assert len(msg) == full_msg_size, 'Answer has a wrong size' if msg[0] != chr(ascii_names.index('STX')): @@ -242,7 +244,8 @@ class TeliumPaymentTerminalDriver(Thread): if self.serial.isOpen(): self.set_status("connected", - "Connected to {}".format(self.device_name)) + "Connected to {} with baudrate {}".format( + self.device_name, self.device_rate)) else: self.set_status("disconnected", "Could not connect to {}" @@ -256,13 +259,28 @@ class TeliumPaymentTerminalDriver(Thread): if self.get_one_byte_answer('ACK'): self.send_one_byte_signal('EOT') - logger.info("Now expecting answer from Terminal") - if self.get_one_byte_answer('ENQ'): - self.send_one_byte_signal('ACK') - self.get_answer_from_terminal(data) - self.send_one_byte_signal('ACK') - if self.get_one_byte_answer('EOT'): - logger.info("Answer received from Terminal") + self.status['in_transaction'] = True + logger.debug("Now expecting answer from Terminal") + + # We wait the end of transaction + attempt_nr = 0 + while attempt_nr < 600: + attempt_nr += 1 + if self.get_one_byte_answer('ENQ'): + self.send_one_byte_signal('ACK') + answer = self.get_answer_from_terminal(data) + # '0' : accepted transaction + # '7' : refused transaction + if answer['transaction_result'] == '0' \ + and self._get_amount(payment_info_dict) == answer['amount_msg']: + self.status['latest_transactions'] = {payment_info_dict['order_id']: {}} + logger.info("Transaction OK") + self.send_one_byte_signal('ACK') + if self.get_one_byte_answer('EOT'): + logger.debug("Answer received from Terminal") + break + time.sleep(0.5) + self.status['in_transaction'] = False except Exception as e: logger.error('Exception in serial connection: %s' % str(e)) diff --git a/hw_telium_payment_terminal/i18n/hw_telium_payment_terminal.pot b/hw_telium_payment_terminal/i18n/hw_telium_payment_terminal.pot deleted file mode 100644 index 386b2558..00000000 --- a/hw_telium_payment_terminal/i18n/hw_telium_payment_terminal.pot +++ /dev/null @@ -1,14 +0,0 @@ -# Translation of Odoo Server. -# This file contains the translation of the following modules: -# -msgid "" -msgstr "" -"Project-Id-Version: Odoo Server 8.0\n" -"Report-Msgid-Bugs-To: \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" - diff --git a/hw_telium_payment_terminal/test-scripts/telium-test.py b/hw_telium_payment_terminal/test-scripts/telium-test.py index 653ec684..6c7df107 100755 --- a/hw_telium_payment_terminal/test-scripts/telium-test.py +++ b/hw_telium_payment_terminal/test-scripts/telium-test.py @@ -1,26 +1,5 @@ #! /usr/bin/python # -*- encoding: utf-8 -*- -############################################################################## -# -# Hardware Telium Test script -# Copyright (C) 2014 Akretion (http://www.akretion.com) -# @author Alexis de Lattre -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -############################################################################## - from serial import Serial import curses.ascii