From df7938dfe4a0f6bc1fd3b097a2cacc34f6840626 Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Thu, 10 Jul 2014 20:39:07 +0200 Subject: [PATCH 01/25] Add module hw_telium_payment_terminal. --- hw_telium_payment_terminal/__init__.py | 24 ++ hw_telium_payment_terminal/__openerp__.py | 56 ++++ .../controllers/__init__.py | 24 ++ .../controllers/main.py | 277 ++++++++++++++++++ 4 files changed, 381 insertions(+) create mode 100644 hw_telium_payment_terminal/__init__.py create mode 100644 hw_telium_payment_terminal/__openerp__.py create mode 100644 hw_telium_payment_terminal/controllers/__init__.py create mode 100644 hw_telium_payment_terminal/controllers/main.py diff --git a/hw_telium_payment_terminal/__init__.py b/hw_telium_payment_terminal/__init__.py new file mode 100644 index 00000000..c535b703 --- /dev/null +++ b/hw_telium_payment_terminal/__init__.py @@ -0,0 +1,24 @@ +# -*- 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/__openerp__.py b/hw_telium_payment_terminal/__openerp__.py new file mode 100644 index 00000000..2ca39fc6 --- /dev/null +++ b/hw_telium_payment_terminal/__openerp__.py @@ -0,0 +1,56 @@ +# -*- 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': '0.1', + 'category': 'Hardware Drivers', + 'license': 'AGPL-3', + 'summary': 'Adds support for Payment Terminals using Telium protocol', + 'description': """ +Hardware Telium Payment Terminal +================================ + +This module adds support for Payment Terminals 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*. + +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: + +* payment_terminal_device_name (default = /dev/ttyACM0) +* payment_terminal_device_rate (default = 9600) +* payment_terminal_device_timeout (default = 2 seconds) + +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. It has been tested a an Ingenico EFTSmart4S terminal with Telim Manager version 37784503. The protocol E is implemented (we may implement the protocol E+ in the future). + +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 ! + +Please contact Alexis de Lattre from Akretion for any help or question about this module. + """, + 'author': 'Akretion', + 'website': 'http://www.akretion.com', + 'depends': ['hw_proxy'], + 'external_dependencies': { + 'python' : ['serial'], + }, + 'data': [], + 'active': False, +} diff --git a/hw_telium_payment_terminal/controllers/__init__.py b/hw_telium_payment_terminal/controllers/__init__.py new file mode 100644 index 00000000..d91efc38 --- /dev/null +++ b/hw_telium_payment_terminal/controllers/__init__.py @@ -0,0 +1,24 @@ +# -*- 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 new file mode 100644 index 00000000..31936292 --- /dev/null +++ b/hw_telium_payment_terminal/controllers/main.py @@ -0,0 +1,277 @@ +# -*- 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 +from serial import Serial +import openerp.addons.hw_proxy.controllers.main as hw_proxy +from openerp import http +from openerp.tools.config import config + + +logger = logging.getLogger(__name__) + + +class TeliumPaymentTerminalDriver(Thread): + def __init__(self): + Thread.__init__(self) + self.queue = Queue() + self.lock = Lock() + self.status = {'status': 'connecting', 'messages': []} + self.device_name = config.get( + 'telium_terminal_device_name', '/dev/ttyACM0') + self.device_rate = int(config.get( + 'telium_terminal_device_rate', 9600)) + self.serial = False + + def get_status(self): + self.push_task('status') + return self.status + + def set_status(self, status, message=None): + if status == self.status['status']: + if message is not None and message != self.status['messages'][-1]: + self.status['messages'].append(message) + else: + self.status['status'] = status + if message: + self.status['messages'] = [message] + else: + self.status['messages'] = [] + + if status == 'error' and message: + logger.error('Payment Terminal Error: '+message) + elif status == 'disconnected' and message: + logger.warning('Disconnected Terminal: '+message) + + def lockedstart(self): + with self.lock: + if not self.isAlive(): + self.daemon = True + self.start() + + def push_task(self, task, data=None): + self.lockedstart() + self.queue.put((time.time(), task, data)) + + def serial_write(self, text): + assert isinstance(text, str), 'text must be a string' + self.serial.write(text) + + def initialize_msg(self): + max_attempt = 3 + attempt_nr = 0 + while attempt_nr < max_attempt: + attempt_nr += 1 + self.send_one_byte_signal('ENQ') + if self.get_one_byte_answer('ACK'): + return True + else: + logger.warning("Terminal : SAME PLAYER TRY AGAIN") + self.send_one_byte_signal('EOT') + # Wait 1 sec between each attempt + time.sleep(1) + return False + + def send_one_byte_signal(self, signal): + ascii_names = curses.ascii.controlnames + assert signal in ascii_names, 'Wrong signal' + char = ascii_names.index(signal) + self.serial_write(chr(char)) + logger.debug('Signal %s sent to terminal' % signal) + + def get_one_byte_answer(self, expected_signal): + ascii_names = curses.ascii.controlnames + 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): + amount = payment_info_dict['amount'] + if payment_info_dict['payment_mode'] == 'check': + payment_mode = 'C' + elif payment_info_dict['payment_mode'] == 'card': + payment_mode = '1' + else: + logger.error( + "The payment mode '%s' is not supported" + % payment_info_dict['payment_mode']) + return False + data = { + 'pos_number': str(1).zfill(2), + 'answer_flag': '0', + 'transaction_type': '0', + 'payment_mode': payment_mode, + 'currency_numeric': + payment_info_dict['currency_iso_numeric'].zfill(3), + 'private': ' ' * 10, + 'delay': 'A011', + 'auto': 'B010', + 'amount_msg': ('%.0f' % (amount * 100)).zfill(8), + } + return data + + def generate_lrc(self, real_msg_with_etx): + lrc = 0 + for char in real_msg_with_etx: + lrc ^= ord(char) + return lrc + + def send_message(self, data): + '''We use protocol E+''' + ascii_names = curses.ascii.controlnames + real_msg = ( + data['pos_number'] + + data['amount_msg'] + + data['answer_flag'] + + data['payment_mode'] + + data['transaction_type'] + + data['currency_numeric'] + + data['private'] + + data['delay'] + + data['auto'] + ) + logger.debug('Real message to send = %s' % real_msg) + assert len(real_msg) == 34, 'Wrong length for protocol E+' + real_msg_with_etx = real_msg + chr(ascii_names.index('ETX')) + lrc = self.generate_lrc(real_msg_with_etx) + message = chr(ascii_names.index('STX')) + real_msg_with_etx + chr(lrc) + self.serial_write(message) + 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']: + if data[field] != answer_data[field]: + logger.warning( + "Field %s has value '%s' in data and value '%s' in answer" + % (field, data[field], answer_data[field])) + + def parse_terminal_answer(self, real_msg, data): + answer_data = { + 'pos_number': real_msg[0:2], + 'transaction_result': real_msg[2], + 'amount_msg': real_msg[3:11], + 'payment_mode': real_msg[11], + 'currency_numeric': real_msg[12:15], + 'private': real_msg[15:26], + } + logger.debug('answer_data = %s' % answer_data) + self.compare_data_vs_answer(data, answer_data) + return answer_data + + 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) + 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')): + logger.error( + 'The first byte of the answer from terminal should be STX') + if msg[-2] != chr(ascii_names.index('ETX')): + logger.error( + 'The byte before final of the answer from terminal ' + 'should be ETX') + lrc = msg[-1] + computed_lrc = chr(self.generate_lrc(msg[1:-1])) + if computed_lrc != lrc: + logger.error( + 'The LRC of the answer from terminal is wrong') + real_msg = msg[1:-2] + logger.debug('Real answer received = %s' % real_msg) + return self.parse_terminal_answer(real_msg, data) + + def transaction_start(self, payment_info): + '''This function sends the data to the serial/usb port. + ''' + payment_info_dict = simplejson.loads(payment_info) + assert isinstance(payment_info_dict, dict), \ + 'payment_info_dict should be a dict' + logger.debug("payment_info_dict = %s" % payment_info_dict) + try: + logger.debug( + 'Opening serial port %s for payment terminal with baudrate %d' + % (self.device_name, self.device_rate)) + # IMPORTANT : don't modify timeout=3 seconds + # This parameter is very important ; the Telium spec say + # that we have to wait to up 3 seconds to get LRC + self.serial = Serial( + self.device_name, self.device_rate, + timeout=3) + logger.debug('serial.is_open = %s' % self.serial.isOpen()) + if self.initialize_msg(): + data = self.prepare_data_to_send(payment_info_dict) + if not data: + return + self.send_message(data) + 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') + answer_data = 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") + + except Exception, e: + logger.error('Exception in serial connection: %s' % str(e)) + finally: + if self.serial: + logger.debug('Closing serial port for payment terminal') + self.serial.close() + + def run(self): + while True: + try: + timestamp, task, data = self.queue.get(True) + if task == 'transaction_start': + self.transaction_start(data) + elif task == 'status': + pass + except Exception as e: + self.set_status('error', str(e)) + +driver = TeliumPaymentTerminalDriver() + +hw_proxy.drivers['telium_payment_terminal'] = driver + + +class TeliumPaymentTerminalProxy(hw_proxy.Proxy): + @http.route( + '/hw_proxy/payment_terminal_transaction_start', + type='json', auth='none', cors='*') + def payment_terminal_transaction_start(self, payment_info): + logger.debug('Telium: Call payment_terminal_transaction_start') + driver.push_task('transaction_start', payment_info) From 336e53e2e1f3745eb7338e4d5b387beddb317f9a Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Sat, 12 Jul 2014 00:13:07 +0200 Subject: [PATCH 02/25] Update description. --- hw_telium_payment_terminal/__openerp__.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/hw_telium_payment_terminal/__openerp__.py b/hw_telium_payment_terminal/__openerp__.py index 2ca39fc6..504f053c 100644 --- a/hw_telium_payment_terminal/__openerp__.py +++ b/hw_telium_payment_terminal/__openerp__.py @@ -37,9 +37,12 @@ The configuration of the hardware is done in the configuration file of the Odoo * payment_terminal_device_name (default = /dev/ttyACM0) * payment_terminal_device_rate (default = 9600) -* payment_terminal_device_timeout (default = 2 seconds) -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. It has been tested a an Ingenico EFTSmart4S terminal with Telim Manager version 37784503. The protocol E is implemented (we may implement the protocol E+ in the future). +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, press F > 0-TELIUM MANAGER > 2-Consultation > 4-Configuration > 2-Software > 1-TERMINAL > On Display > Telium Manager and then read the field *M20S*. + +You will need to configure your payment terminal to accept commands from the POS. On an Ingenico reader, press F > 0-TELIUM MANAGER > 5-Initialization > 1-Parameters > Cash Connection and then select *On* and then *USB*. After that, you should reboot the terminal. + +This module has been successfully tested with an Ingenico EFTSmart4S and an Ingenico EFTSmart2 2640 with Telim Manager version 37784503. 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 ! From aa5016d8bdb7369a67493aefdc3f600913fa0d26 Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Sat, 12 Jul 2014 00:29:04 +0200 Subject: [PATCH 03/25] Fix copyright headers PEP8 stuff --- hw_telium_payment_terminal/__openerp__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw_telium_payment_terminal/__openerp__.py b/hw_telium_payment_terminal/__openerp__.py index 504f053c..21035e94 100644 --- a/hw_telium_payment_terminal/__openerp__.py +++ b/hw_telium_payment_terminal/__openerp__.py @@ -52,7 +52,7 @@ Please contact Alexis de Lattre from Akretion for 'website': 'http://www.akretion.com', 'depends': ['hw_proxy'], 'external_dependencies': { - 'python' : ['serial'], + 'python': ['serial'], }, 'data': [], 'active': False, From b6f59d32016bb69d7d8a939b83625e991f8086d9 Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Mon, 1 Sep 2014 13:31:03 +0200 Subject: [PATCH 04/25] FIX Adapt JS code to recent changes in the code of POS v8 Update module description with my recent tests with new hardware --- hw_telium_payment_terminal/__openerp__.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/hw_telium_payment_terminal/__openerp__.py b/hw_telium_payment_terminal/__openerp__.py index 21035e94..fb98d352 100644 --- a/hw_telium_payment_terminal/__openerp__.py +++ b/hw_telium_payment_terminal/__openerp__.py @@ -42,7 +42,11 @@ The Telium protocol is used by Ingenico and Sagem payment terminals. It is based You will need to configure your payment terminal to accept commands from the POS. On an Ingenico reader, press F > 0-TELIUM MANAGER > 5-Initialization > 1-Parameters > Cash Connection and then select *On* and then *USB*. After that, you should reboot the terminal. -This module has been successfully tested with an Ingenico EFTSmart4S and an Ingenico EFTSmart2 2640 with Telim Manager version 37784503. +This module has been successfully tested with: + +* Ingenico EFTSmart4S +* Ingenico EFTSmart2 2640 with Telim Manager version 37784503 +* Ingenico i2200 cheque reader and writer 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 ! From a6258568ea0f6f39674a3d742f6fd04e4f51425e Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Thu, 23 Oct 2014 14:36:24 +0200 Subject: [PATCH 05/25] Use pycountry Add test script for credit card reader --- hw_telium_payment_terminal/__openerp__.py | 3 +- .../controllers/main.py | 13 +- .../test-scripts/telium-test.py | 219 ++++++++++++++++++ 3 files changed, 230 insertions(+), 5 deletions(-) create mode 100755 hw_telium_payment_terminal/test-scripts/telium-test.py diff --git a/hw_telium_payment_terminal/__openerp__.py b/hw_telium_payment_terminal/__openerp__.py index fb98d352..fcec8d33 100644 --- a/hw_telium_payment_terminal/__openerp__.py +++ b/hw_telium_payment_terminal/__openerp__.py @@ -56,8 +56,7 @@ Please contact Alexis de Lattre from Akretion for 'website': 'http://www.akretion.com', 'depends': ['hw_proxy'], 'external_dependencies': { - 'python': ['serial'], + 'python': ['serial', 'pycountry'], }, 'data': [], - 'active': False, } diff --git a/hw_telium_payment_terminal/controllers/main.py b/hw_telium_payment_terminal/controllers/main.py index 31936292..3dbd1b7f 100644 --- a/hw_telium_payment_terminal/controllers/main.py +++ b/hw_telium_payment_terminal/controllers/main.py @@ -28,6 +28,7 @@ import curses.ascii from threading import Thread, Lock from Queue import Queue from serial import Serial +import pycountry import openerp.addons.hw_proxy.controllers.main as hw_proxy from openerp import http from openerp.tools.config import config @@ -125,13 +126,19 @@ class TeliumPaymentTerminalDriver(Thread): "The payment mode '%s' is not supported" % payment_info_dict['payment_mode']) return False + cur_iso_letter = payment_info_dict['currency_iso'].upper() + try: + cur = pycountry.currencies.get(letter=cur_iso_letter) + cur_numeric = str(cur.numeric) + except: + logger.error("Currency %s is not recognized" % cur_iso_letter) + return False data = { 'pos_number': str(1).zfill(2), 'answer_flag': '0', 'transaction_type': '0', 'payment_mode': payment_mode, - 'currency_numeric': - payment_info_dict['currency_iso_numeric'].zfill(3), + 'currency_numeric': cur_numeric.zfill(3), 'private': ' ' * 10, 'delay': 'A011', 'auto': 'B010', @@ -240,7 +247,7 @@ class TeliumPaymentTerminalDriver(Thread): logger.info("Now expecting answer from Terminal") if self.get_one_byte_answer('ENQ'): self.send_one_byte_signal('ACK') - answer_data = self.get_answer_from_terminal(data) + 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") diff --git a/hw_telium_payment_terminal/test-scripts/telium-test.py b/hw_telium_payment_terminal/test-scripts/telium-test.py new file mode 100755 index 00000000..67245558 --- /dev/null +++ b/hw_telium_payment_terminal/test-scripts/telium-test.py @@ -0,0 +1,219 @@ +#! /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 +import time +import pycountry + + +DEVICE = '/dev/ttyACM0' +DEVICE_RATE = 9600 +PAYMENT_MODE = 'card' # 'card' ou 'check' +CURRENCY_ISO = 'EUR' +AMOUNT = 12.42 + + +def serial_write(serial, text): + assert isinstance(text, str), 'text must be a string' + serial.write(text) + + +def initialize_msg(serial): + max_attempt = 3 + attempt_nr = 0 + while attempt_nr < max_attempt: + attempt_nr += 1 + send_one_byte_signal(serial, 'ENQ') + if get_one_byte_answer(serial, 'ACK'): + return True + else: + print "Terminal : SAME PLAYER TRY AGAIN" + send_one_byte_signal(serial, 'EOT') + # Wait 1 sec between each attempt + time.sleep(1) + return False + + +def send_one_byte_signal(serial, signal): + ascii_names = curses.ascii.controlnames + assert signal in ascii_names, 'Wrong signal' + char = ascii_names.index(signal) + serial_write(serial, chr(char)) + print 'Signal %s sent to terminal' % signal + + +def get_one_byte_answer(serial, expected_signal): + ascii_names = curses.ascii.controlnames + one_byte_read = serial.read(1) + expected_char = ascii_names.index(expected_signal) + if one_byte_read == chr(expected_char): + print "%s received from terminal" % expected_signal + return True + else: + return False + + +def prepare_data_to_send(): + if PAYMENT_MODE == 'check': + payment_mode = 'C' + elif PAYMENT_MODE == 'card': + payment_mode = '1' + else: + print "The payment mode '%s' is not supported" % PAYMENT_MODE + return False + cur_iso_letter = CURRENCY_ISO.upper() + try: + cur = pycountry.currencies.get(letter=cur_iso_letter) + cur_numeric = str(cur.numeric) + except: + print "Currency %s is not recognized" % cur_iso_letter + return False + data = { + 'pos_number': str(1).zfill(2), + 'answer_flag': '0', + 'transaction_type': '0', + 'payment_mode': payment_mode, + 'currency_numeric': cur_numeric.zfill(3), + 'private': ' ' * 10, + 'delay': 'A011', + 'auto': 'B010', + 'amount_msg': ('%.0f' % (AMOUNT * 100)).zfill(8), + } + return data + + +def generate_lrc(real_msg_with_etx): + lrc = 0 + for char in real_msg_with_etx: + lrc ^= ord(char) + return lrc + + +def send_message(serial, data): + '''We use protocol E+''' + ascii_names = curses.ascii.controlnames + real_msg = ( + data['pos_number'] + + data['amount_msg'] + + data['answer_flag'] + + data['payment_mode'] + + data['transaction_type'] + + data['currency_numeric'] + + data['private'] + + data['delay'] + + data['auto'] + ) + print 'Real message to send = %s' % real_msg + assert len(real_msg) == 34, 'Wrong length for protocol E+' + real_msg_with_etx = real_msg + chr(ascii_names.index('ETX')) + lrc = generate_lrc(real_msg_with_etx) + message = chr(ascii_names.index('STX')) + real_msg_with_etx + chr(lrc) + serial_write(serial, message) + print 'Message sent to terminal' + + +def compare_data_vs_answer(data, answer_data): + for field in [ + 'pos_number', 'amount_msg', + 'currency_numeric', 'private']: + if data[field] != answer_data[field]: + print ( + "Field %s has value '%s' in data and value '%s' in answer" + % (field, data[field], answer_data[field])) + + +def parse_terminal_answer(real_msg, data): + answer_data = { + 'pos_number': real_msg[0:2], + 'transaction_result': real_msg[2], + 'amount_msg': real_msg[3:11], + 'payment_mode': real_msg[11], + 'currency_numeric': real_msg[12:15], + 'private': real_msg[15:26], + } + print 'answer_data = %s' % answer_data + compare_data_vs_answer(data, answer_data) + return answer_data + + +def get_answer_from_terminal(serial, data): + ascii_names = curses.ascii.controlnames + full_msg_size = 1+2+1+8+1+3+10+1+1 + msg = serial.read(size=full_msg_size) + print '%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')): + print 'The first byte of the answer from terminal should be STX' + if msg[-2] != chr(ascii_names.index('ETX')): + print 'The byte before final of the answer from terminal should be ETX' + lrc = msg[-1] + computed_lrc = chr(generate_lrc(msg[1:-1])) + if computed_lrc != lrc: + print 'The LRC of the answer from terminal is wrong' + real_msg = msg[1:-2] + print 'Real answer received = %s' % real_msg + return parse_terminal_answer(real_msg, data) + + +def transaction_start(): + '''This function sends the data to the serial/usb port. + ''' + serial = False + try: + print( + 'Opening serial port %s for payment terminal with ' + 'baudrate %d' % (DEVICE, DEVICE_RATE)) + # IMPORTANT : don't modify timeout=3 seconds + # This parameter is very important ; the Telium spec say + # that we have to wait to up 3 seconds to get LRC + serial = Serial( + DEVICE, DEVICE_RATE, timeout=3) + print 'serial.is_open = %s' % serial.isOpen() + if initialize_msg(serial): + data = prepare_data_to_send() + if not data: + return + send_message(serial, data) + if get_one_byte_answer(serial, 'ACK'): + send_one_byte_signal(serial, 'EOT') + + print "Now expecting answer from Terminal" + if get_one_byte_answer(serial, 'ENQ'): + send_one_byte_signal(serial, 'ACK') + get_answer_from_terminal(serial, data) + send_one_byte_signal(serial, 'ACK') + if get_one_byte_answer(serial, 'EOT'): + print "Answer received from Terminal" + + except Exception, e: + print 'Exception in serial connection: %s' % str(e) + finally: + if serial: + print 'Closing serial port for payment terminal' + serial.close() + + +if __name__ == '__main__': + transaction_start() From d206c214575c69d890b9d7ffd4dc2b6aa3902723 Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Tue, 6 Jan 2015 23:26:30 +0100 Subject: [PATCH 06/25] PEP8 --- hw_telium_payment_terminal/__openerp__.py | 33 ++++++++++++++++++----- 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/hw_telium_payment_terminal/__openerp__.py b/hw_telium_payment_terminal/__openerp__.py index fcec8d33..ca408d52 100644 --- a/hw_telium_payment_terminal/__openerp__.py +++ b/hw_telium_payment_terminal/__openerp__.py @@ -31,16 +31,32 @@ Hardware Telium Payment Terminal ================================ -This module adds support for Payment Terminals 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 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*. -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 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: * payment_terminal_device_name (default = /dev/ttyACM0) * payment_terminal_device_rate (default = 9600) -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, press F > 0-TELIUM MANAGER > 2-Consultation > 4-Configuration > 2-Software > 1-TERMINAL > On Display > Telium Manager and then read the field *M20S*. +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 +terminal press F > 0-TELIUM MANAGER > 2-Consultation > 4-Configuration +> 2-Software > 1-TERMINAL > On Display > Telium Manager and then read +the field *M20S*. -You will need to configure your payment terminal to accept commands from the POS. On an Ingenico reader, press F > 0-TELIUM MANAGER > 5-Initialization > 1-Parameters > Cash Connection and then select *On* and then *USB*. After that, you should reboot the terminal. +You will need to configure your payment terminal to accept commands +from the POS. On an Ingenico terminal press F > 0-TELIUM MANAGER > +5-Initialization > 1-Parameters > Cash Connection and then select *On* +and then *USB*. After that, you should reboot the terminal. This module has been successfully tested with: @@ -48,9 +64,14 @@ This module has been successfully tested with: * Ingenico EFTSmart2 2640 with Telim Manager version 37784503 * Ingenico i2200 cheque reader and writer -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 ! +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 ! -Please contact Alexis de Lattre from Akretion for any help or question about this module. +This module has been written by Alexis de Lattre + from Akretion. """, 'author': 'Akretion', 'website': 'http://www.akretion.com', From e8f484469f1268f03f77dc4b84b6cf0667284e29 Mon Sep 17 00:00:00 2001 From: Alexandre Fayolle Date: Mon, 2 Mar 2015 15:37:13 +0100 Subject: [PATCH 07/25] Add OCA as author of OCA addons In order to get visibility on https://www.odoo.com/apps the OCA board has decided to add the OCA as author of all the addons maintained as part of the association. --- hw_telium_payment_terminal/__openerp__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw_telium_payment_terminal/__openerp__.py b/hw_telium_payment_terminal/__openerp__.py index ca408d52..cc85a510 100644 --- a/hw_telium_payment_terminal/__openerp__.py +++ b/hw_telium_payment_terminal/__openerp__.py @@ -73,7 +73,7 @@ Association ! This module has been written by Alexis de Lattre from Akretion. """, - 'author': 'Akretion', + 'author': "Akretion,Odoo Community Association (OCA)", 'website': 'http://www.akretion.com', 'depends': ['hw_proxy'], 'external_dependencies': { From 01563a80c051da2ba2f318e7aab1a1495d5f7110 Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Fri, 12 Jun 2015 12:28:36 +0200 Subject: [PATCH 08/25] Cleaner inheritance implementation in pos_customer_display Better debug logs in hw_* modules for LCD and Telium --- hw_telium_payment_terminal/controllers/main.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/hw_telium_payment_terminal/controllers/main.py b/hw_telium_payment_terminal/controllers/main.py index 3dbd1b7f..2d916535 100644 --- a/hw_telium_payment_terminal/controllers/main.py +++ b/hw_telium_payment_terminal/controllers/main.py @@ -224,7 +224,6 @@ class TeliumPaymentTerminalDriver(Thread): payment_info_dict = simplejson.loads(payment_info) assert isinstance(payment_info_dict, dict), \ 'payment_info_dict should be a dict' - logger.debug("payment_info_dict = %s" % payment_info_dict) try: logger.debug( 'Opening serial port %s for payment terminal with baudrate %d' @@ -280,5 +279,7 @@ class TeliumPaymentTerminalProxy(hw_proxy.Proxy): '/hw_proxy/payment_terminal_transaction_start', type='json', auth='none', cors='*') def payment_terminal_transaction_start(self, payment_info): - logger.debug('Telium: Call payment_terminal_transaction_start') + logger.debug( + 'Telium: Call payment_terminal_transaction_start with ' + 'payment_info=%s', payment_info) driver.push_task('transaction_start', payment_info) From 6aee1ddd9889f99a377a256ef01a0f4688215859 Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Sun, 14 Jun 2015 11:10:49 +0200 Subject: [PATCH 09/25] PEP8 --- .../controllers/main.py | 19 +++++++++---------- .../test-scripts/telium-test.py | 19 +++++++++---------- 2 files changed, 18 insertions(+), 20 deletions(-) diff --git a/hw_telium_payment_terminal/controllers/main.py b/hw_telium_payment_terminal/controllers/main.py index 2d916535..563d2cc9 100644 --- a/hw_telium_payment_terminal/controllers/main.py +++ b/hw_telium_payment_terminal/controllers/main.py @@ -156,16 +156,15 @@ class TeliumPaymentTerminalDriver(Thread): '''We use protocol E+''' ascii_names = curses.ascii.controlnames real_msg = ( - data['pos_number'] - + data['amount_msg'] - + data['answer_flag'] - + data['payment_mode'] - + data['transaction_type'] - + data['currency_numeric'] - + data['private'] - + data['delay'] - + data['auto'] - ) + data['pos_number'] + + data['amount_msg'] + + data['answer_flag'] + + data['payment_mode'] + + data['transaction_type'] + + data['currency_numeric'] + + data['private'] + + data['delay'] + + data['auto']) logger.debug('Real message to send = %s' % real_msg) assert len(real_msg) == 34, 'Wrong length for protocol E+' real_msg_with_etx = real_msg + chr(ascii_names.index('ETX')) diff --git a/hw_telium_payment_terminal/test-scripts/telium-test.py b/hw_telium_payment_terminal/test-scripts/telium-test.py index 67245558..ee94e3cd 100755 --- a/hw_telium_payment_terminal/test-scripts/telium-test.py +++ b/hw_telium_payment_terminal/test-scripts/telium-test.py @@ -115,16 +115,15 @@ def send_message(serial, data): '''We use protocol E+''' ascii_names = curses.ascii.controlnames real_msg = ( - data['pos_number'] - + data['amount_msg'] - + data['answer_flag'] - + data['payment_mode'] - + data['transaction_type'] - + data['currency_numeric'] - + data['private'] - + data['delay'] - + data['auto'] - ) + data['pos_number'] + + data['amount_msg'] + + data['answer_flag'] + + data['payment_mode'] + + data['transaction_type'] + + data['currency_numeric'] + + data['private'] + + data['delay'] + + data['auto']) print 'Real message to send = %s' % real_msg assert len(real_msg) == 34, 'Wrong length for protocol E+' real_msg_with_etx = real_msg + chr(ascii_names.index('ETX')) From 49bb75af1ea8106275d6b9840a6c20259dd6a338 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Bidoul?= Date: Fri, 9 Oct 2015 10:01:54 +0200 Subject: [PATCH 10/25] [UPD] prefix versions with 8.0 --- hw_telium_payment_terminal/__openerp__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw_telium_payment_terminal/__openerp__.py b/hw_telium_payment_terminal/__openerp__.py index cc85a510..c6c5b3b9 100644 --- a/hw_telium_payment_terminal/__openerp__.py +++ b/hw_telium_payment_terminal/__openerp__.py @@ -23,7 +23,7 @@ { 'name': 'Hardware Telium Payment Terminal', - 'version': '0.1', + 'version': '8.0.0.1.0', 'category': 'Hardware Drivers', 'license': 'AGPL-3', 'summary': 'Adds support for Payment Terminals using Telium protocol', From 3ca320937edc1064f31db743e53b0a0f7b652e70 Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Wed, 28 Oct 2015 17:42:00 +0100 Subject: [PATCH 11/25] hw_telium_payment_terminal: add 2 tested devices --- hw_telium_payment_terminal/__openerp__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hw_telium_payment_terminal/__openerp__.py b/hw_telium_payment_terminal/__openerp__.py index c6c5b3b9..31116ea1 100644 --- a/hw_telium_payment_terminal/__openerp__.py +++ b/hw_telium_payment_terminal/__openerp__.py @@ -62,6 +62,8 @@ This module has been successfully tested with: * Ingenico EFTSmart4S * Ingenico EFTSmart2 2640 with Telim Manager version 37784503 +* Ingenico iCT220 +* Ingenico iCT250 * Ingenico i2200 cheque reader and writer This module has been developped during a POS code sprint at Akretion From f1328b6ed5d5172f2b392c4d889888958e659afe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20V=C3=A1squez?= Date: Thu, 19 Jan 2017 18:48:45 -0600 Subject: [PATCH 12/25] [FIX] Pylint on hw_customer_display and hw_telium_payment_terminal and flake8 on pos_remove_pos_category --- hw_telium_payment_terminal/controllers/main.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/hw_telium_payment_terminal/controllers/main.py b/hw_telium_payment_terminal/controllers/main.py index 563d2cc9..b2f4d124 100644 --- a/hw_telium_payment_terminal/controllers/main.py +++ b/hw_telium_payment_terminal/controllers/main.py @@ -27,15 +27,18 @@ import time import curses.ascii from threading import Thread, Lock from Queue import Queue -from serial import Serial -import pycountry import openerp.addons.hw_proxy.controllers.main as hw_proxy from openerp import http from openerp.tools.config import config - logger = logging.getLogger(__name__) +try: + import pycountry + from serial import Serial +except (ImportError, IOError) as err: + logger.debug(err) + class TeliumPaymentTerminalDriver(Thread): def __init__(self): From 3735fda75412a59f8f10c9b8508b83785e733ae0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20V=C3=A1squez?= Date: Thu, 19 Jan 2017 18:56:01 -0600 Subject: [PATCH 13/25] [FIX] Flake8 on hw_customer_display, hw_telium_payment_terminal and pos_remove_pos_category --- hw_telium_payment_terminal/controllers/main.py | 1 + 1 file changed, 1 insertion(+) diff --git a/hw_telium_payment_terminal/controllers/main.py b/hw_telium_payment_terminal/controllers/main.py index b2f4d124..8bd11ede 100644 --- a/hw_telium_payment_terminal/controllers/main.py +++ b/hw_telium_payment_terminal/controllers/main.py @@ -271,6 +271,7 @@ class TeliumPaymentTerminalDriver(Thread): except Exception as e: self.set_status('error', str(e)) + driver = TeliumPaymentTerminalDriver() hw_proxy.drivers['telium_payment_terminal'] = driver From 92df9cb011c3bca815b98ca36de54503a4ad5a92 Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Mon, 13 Nov 2017 09:37:35 +0100 Subject: [PATCH 14/25] [8.0] hw_telium_payment_terminal: Update to newer pycountry API (#222) * hw_telium_payment_terminal: Update to newer pycountry API --- hw_telium_payment_terminal/__openerp__.py | 7 ++++++- hw_telium_payment_terminal/controllers/main.py | 2 +- hw_telium_payment_terminal/test-scripts/telium-test.py | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/hw_telium_payment_terminal/__openerp__.py b/hw_telium_payment_terminal/__openerp__.py index 31116ea1..860026b0 100644 --- a/hw_telium_payment_terminal/__openerp__.py +++ b/hw_telium_payment_terminal/__openerp__.py @@ -23,7 +23,7 @@ { 'name': 'Hardware Telium Payment Terminal', - 'version': '8.0.0.1.0', + 'version': '8.0.0.1.1', 'category': 'Hardware Drivers', 'license': 'AGPL-3', 'summary': 'Adds support for Payment Terminals using Telium protocol', @@ -66,6 +66,11 @@ This module has been successfully tested with: * Ingenico iCT250 * Ingenico i2200 cheque reader and writer +This module requires the Python library *pycountry* version >= 16.11.08. +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/. diff --git a/hw_telium_payment_terminal/controllers/main.py b/hw_telium_payment_terminal/controllers/main.py index 8bd11ede..e6b35027 100644 --- a/hw_telium_payment_terminal/controllers/main.py +++ b/hw_telium_payment_terminal/controllers/main.py @@ -131,7 +131,7 @@ class TeliumPaymentTerminalDriver(Thread): return False cur_iso_letter = payment_info_dict['currency_iso'].upper() try: - cur = pycountry.currencies.get(letter=cur_iso_letter) + 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) diff --git a/hw_telium_payment_terminal/test-scripts/telium-test.py b/hw_telium_payment_terminal/test-scripts/telium-test.py index ee94e3cd..28c50701 100755 --- a/hw_telium_payment_terminal/test-scripts/telium-test.py +++ b/hw_telium_payment_terminal/test-scripts/telium-test.py @@ -85,7 +85,7 @@ def prepare_data_to_send(): return False cur_iso_letter = CURRENCY_ISO.upper() try: - cur = pycountry.currencies.get(letter=cur_iso_letter) + cur = pycountry.currencies.get(alpha_3=cur_iso_letter) cur_numeric = str(cur.numeric) except: print "Currency %s is not recognized" % cur_iso_letter From 0e18f2bc3fa90e4a6e9afa7833573c8a23bc7a0d Mon Sep 17 00:00:00 2001 From: Invitu Date: Fri, 9 Feb 2018 07:17:43 -1000 Subject: [PATCH 15/25] [FIX] fixes currencies with decimals <>2 --- hw_telium_payment_terminal/controllers/main.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hw_telium_payment_terminal/controllers/main.py b/hw_telium_payment_terminal/controllers/main.py index e6b35027..d40232b0 100644 --- a/hw_telium_payment_terminal/controllers/main.py +++ b/hw_telium_payment_terminal/controllers/main.py @@ -129,6 +129,8 @@ 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) @@ -145,7 +147,7 @@ class TeliumPaymentTerminalDriver(Thread): 'private': ' ' * 10, 'delay': 'A011', 'auto': 'B010', - 'amount_msg': ('%.0f' % (amount * 100)).zfill(8), + 'amount_msg': ('%.0f' % (amount * cur_fact)).zfill(8), } return data From a51110307278e675592c493250e9f38016828f7b Mon Sep 17 00:00:00 2001 From: Dave Lasley Date: Tue, 13 Dec 2016 12:00:24 -0800 Subject: [PATCH 16/25] [FIX] hw_telium_payment_terminal: Add guard for external import --- hw_telium_payment_terminal/controllers/main.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/hw_telium_payment_terminal/controllers/main.py b/hw_telium_payment_terminal/controllers/main.py index d40232b0..27ae84cc 100644 --- a/hw_telium_payment_terminal/controllers/main.py +++ b/hw_telium_payment_terminal/controllers/main.py @@ -40,6 +40,12 @@ except (ImportError, IOError) as err: logger.debug(err) +try: + import pycountry +except ImportError: + _logger.info('`pycountry` Python package not found') + + class TeliumPaymentTerminalDriver(Thread): def __init__(self): Thread.__init__(self) From e392c02bb372a102f7dc77214fdc2716cf517646 Mon Sep 17 00:00:00 2001 From: "Pedro M. Baeza" Date: Sat, 28 Apr 2018 14:12:48 +0200 Subject: [PATCH 17/25] [FIX] hw_*: Don't import twice --- hw_telium_payment_terminal/controllers/main.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/hw_telium_payment_terminal/controllers/main.py b/hw_telium_payment_terminal/controllers/main.py index 27ae84cc..d40232b0 100644 --- a/hw_telium_payment_terminal/controllers/main.py +++ b/hw_telium_payment_terminal/controllers/main.py @@ -40,12 +40,6 @@ except (ImportError, IOError) as err: logger.debug(err) -try: - import pycountry -except ImportError: - _logger.info('`pycountry` Python package not found') - - class TeliumPaymentTerminalDriver(Thread): def __init__(self): Thread.__init__(self) From 0674bc67a22e71ac9dd9d76fa5c79e871f69189e Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Fri, 22 Jun 2018 09:55:34 +0200 Subject: [PATCH 18/25] Fix typo --- hw_telium_payment_terminal/test-scripts/telium-test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw_telium_payment_terminal/test-scripts/telium-test.py b/hw_telium_payment_terminal/test-scripts/telium-test.py index 28c50701..704b845f 100755 --- a/hw_telium_payment_terminal/test-scripts/telium-test.py +++ b/hw_telium_payment_terminal/test-scripts/telium-test.py @@ -30,7 +30,7 @@ import pycountry DEVICE = '/dev/ttyACM0' DEVICE_RATE = 9600 -PAYMENT_MODE = 'card' # 'card' ou 'check' +PAYMENT_MODE = 'card' # 'card' or 'check' CURRENCY_ISO = 'EUR' AMOUNT = 12.42 From e2cbb9c05b1fea0c0ed5e6e9189adfed9ce64b60 Mon Sep 17 00:00:00 2001 From: oca-travis Date: Fri, 22 Jun 2018 08:05:34 +0000 Subject: [PATCH 19/25] [UPD] Update hw_telium_payment_terminal.pot --- .../i18n/hw_telium_payment_terminal.pot | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 hw_telium_payment_terminal/i18n/hw_telium_payment_terminal.pot diff --git a/hw_telium_payment_terminal/i18n/hw_telium_payment_terminal.pot b/hw_telium_payment_terminal/i18n/hw_telium_payment_terminal.pot new file mode 100644 index 00000000..386b2558 --- /dev/null +++ b/hw_telium_payment_terminal/i18n/hw_telium_payment_terminal.pot @@ -0,0 +1,14 @@ +# 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" + From 2038b8fcc43d44dbd2c7f1d9c5a0dde19af8e485 Mon Sep 17 00:00:00 2001 From: OCA-git-bot Date: Wed, 3 Apr 2019 03:12:13 +0000 Subject: [PATCH 20/25] [ADD] icon.png --- .../static/description/icon.png | Bin 0 -> 9455 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 hw_telium_payment_terminal/static/description/icon.png diff --git a/hw_telium_payment_terminal/static/description/icon.png b/hw_telium_payment_terminal/static/description/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..3a0328b516c4980e8e44cdb63fd945757ddd132d GIT binary patch literal 9455 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 z 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 Xviia!U7SGha1wx#SCgwmn*{w2TRX*I literal 0 HcmV?d00001 From e802e4198936439323ac32be58d093aa04b2855b Mon Sep 17 00:00:00 2001 From: "Pedro M. Baeza" Date: Sat, 31 Aug 2019 02:16:03 +0200 Subject: [PATCH 21/25] [IMP] hw_telium_payment_terminal: README file instead of description --- hw_telium_payment_terminal/README.rst | 48 ++++++++++++++++++++ hw_telium_payment_terminal/__openerp__.py | 53 ----------------------- 2 files changed, 48 insertions(+), 53 deletions(-) create mode 100644 hw_telium_payment_terminal/README.rst diff --git a/hw_telium_payment_terminal/README.rst b/hw_telium_payment_terminal/README.rst new file mode 100644 index 00000000..2c4f2517 --- /dev/null +++ b/hw_telium_payment_terminal/README.rst @@ -0,0 +1,48 @@ +Hardware Telium Payment Terminal +================================ + +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*. + +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: + +* payment_terminal_device_name (default = /dev/ttyACM0) +* payment_terminal_device_rate (default = 9600) + +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 +terminal press F > 0-TELIUM MANAGER > 2-Consultation > 4-Configuration +> 2-Software > 1-TERMINAL > On Display > Telium Manager and then read +the field *M20S*. + +You will need to configure your payment terminal to accept commands +from the POS. On an Ingenico terminal press F > 0-TELIUM MANAGER > +5-Initialization > 1-Parameters > Cash Connection and then select *On* +and then *USB*. After that, you should reboot the terminal. + +This module has been successfully tested with: + +* Ingenico EFTSmart4S +* Ingenico EFTSmart2 2640 with Telim Manager version 37784503 +* Ingenico iCT220 +* Ingenico iCT250 +* Ingenico i2200 cheque reader and writer + +This module requires the Python library *pycountry* version >= 16.11.08. +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 ! diff --git a/hw_telium_payment_terminal/__openerp__.py b/hw_telium_payment_terminal/__openerp__.py index 860026b0..f9a052f0 100644 --- a/hw_telium_payment_terminal/__openerp__.py +++ b/hw_telium_payment_terminal/__openerp__.py @@ -27,59 +27,6 @@ 'category': 'Hardware Drivers', 'license': 'AGPL-3', 'summary': 'Adds support for Payment Terminals using Telium protocol', - 'description': """ -Hardware Telium Payment Terminal -================================ - -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*. - -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: - -* payment_terminal_device_name (default = /dev/ttyACM0) -* payment_terminal_device_rate (default = 9600) - -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 -terminal press F > 0-TELIUM MANAGER > 2-Consultation > 4-Configuration -> 2-Software > 1-TERMINAL > On Display > Telium Manager and then read -the field *M20S*. - -You will need to configure your payment terminal to accept commands -from the POS. On an Ingenico terminal press F > 0-TELIUM MANAGER > -5-Initialization > 1-Parameters > Cash Connection and then select *On* -and then *USB*. After that, you should reboot the terminal. - -This module has been successfully tested with: - -* Ingenico EFTSmart4S -* Ingenico EFTSmart2 2640 with Telim Manager version 37784503 -* Ingenico iCT220 -* Ingenico iCT250 -* Ingenico i2200 cheque reader and writer - -This module requires the Python library *pycountry* version >= 16.11.08. -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 ! - -This module has been written by Alexis de Lattre - from Akretion. - """, 'author': "Akretion,Odoo Community Association (OCA)", 'website': 'http://www.akretion.com', 'depends': ['hw_proxy'], From e608713c95c6c0b5040cfdd3c5ce3f88ee298515 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89loi=20Rivard?= Date: Fri, 30 Aug 2019 17:25:31 +0200 Subject: [PATCH 22/25] [8.0][FIX] hw_telium_payment_terminal_status - print status, fix #372 --- hw_telium_payment_terminal/controllers/main.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/hw_telium_payment_terminal/controllers/main.py b/hw_telium_payment_terminal/controllers/main.py index d40232b0..e0bfe7bc 100644 --- a/hw_telium_payment_terminal/controllers/main.py +++ b/hw_telium_payment_terminal/controllers/main.py @@ -239,6 +239,15 @@ class TeliumPaymentTerminalDriver(Thread): self.device_name, self.device_rate, timeout=3) logger.debug('serial.is_open = %s' % self.serial.isOpen()) + + if self.serial.isOpen(): + self.set_status("connected", + "Connected to {}".format(self.device_name)) + else: + self.set_status("disconnected", + "Could not connect to {}" + .format(self.device_name)) + if self.initialize_msg(): data = self.prepare_data_to_send(payment_info_dict) if not data: @@ -257,6 +266,9 @@ class TeliumPaymentTerminalDriver(Thread): except Exception, e: logger.error('Exception in serial connection: %s' % str(e)) + self.set_status("error", + "Exception in serial connection to {}" + .format(self.device_name)) finally: if self.serial: logger.debug('Closing serial port for payment terminal') From 4fc3ac3842bbc18a26c09690aab57b0ab1f5190f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89loi=20Rivard?= Date: Thu, 29 Aug 2019 20:15:21 +0200 Subject: [PATCH 23/25] [FIX][8.0] hw_telium_payment_terminal - Make lint tools happy --- .../controllers/main.py | 2 +- .../test-scripts/telium-test.py | 41 ++++++++++--------- 2 files changed, 22 insertions(+), 21 deletions(-) diff --git a/hw_telium_payment_terminal/controllers/main.py b/hw_telium_payment_terminal/controllers/main.py index e0bfe7bc..90346cb0 100644 --- a/hw_telium_payment_terminal/controllers/main.py +++ b/hw_telium_payment_terminal/controllers/main.py @@ -264,7 +264,7 @@ class TeliumPaymentTerminalDriver(Thread): if self.get_one_byte_answer('EOT'): logger.info("Answer received from Terminal") - except Exception, e: + except Exception as e: logger.error('Exception in serial connection: %s' % str(e)) self.set_status("error", "Exception in serial connection to {}" diff --git a/hw_telium_payment_terminal/test-scripts/telium-test.py b/hw_telium_payment_terminal/test-scripts/telium-test.py index 704b845f..653ec684 100755 --- a/hw_telium_payment_terminal/test-scripts/telium-test.py +++ b/hw_telium_payment_terminal/test-scripts/telium-test.py @@ -49,7 +49,7 @@ def initialize_msg(serial): if get_one_byte_answer(serial, 'ACK'): return True else: - print "Terminal : SAME PLAYER TRY AGAIN" + print("Terminal : SAME PLAYER TRY AGAIN") send_one_byte_signal(serial, 'EOT') # Wait 1 sec between each attempt time.sleep(1) @@ -61,7 +61,7 @@ def send_one_byte_signal(serial, signal): assert signal in ascii_names, 'Wrong signal' char = ascii_names.index(signal) serial_write(serial, chr(char)) - print 'Signal %s sent to terminal' % signal + print('Signal %s sent to terminal' % signal) def get_one_byte_answer(serial, expected_signal): @@ -69,7 +69,7 @@ def get_one_byte_answer(serial, expected_signal): one_byte_read = serial.read(1) expected_char = ascii_names.index(expected_signal) if one_byte_read == chr(expected_char): - print "%s received from terminal" % expected_signal + print("%s received from terminal" % expected_signal) return True else: return False @@ -81,14 +81,14 @@ def prepare_data_to_send(): elif PAYMENT_MODE == 'card': payment_mode = '1' else: - print "The payment mode '%s' is not supported" % PAYMENT_MODE + print("The payment mode '%s' is not supported" % PAYMENT_MODE) return False cur_iso_letter = CURRENCY_ISO.upper() try: cur = pycountry.currencies.get(alpha_3=cur_iso_letter) cur_numeric = str(cur.numeric) except: - print "Currency %s is not recognized" % cur_iso_letter + print("Currency %s is not recognized" % cur_iso_letter) return False data = { 'pos_number': str(1).zfill(2), @@ -124,13 +124,13 @@ def send_message(serial, data): data['private'] + data['delay'] + data['auto']) - print 'Real message to send = %s' % real_msg + print('Real message to send = %s' % real_msg) assert len(real_msg) == 34, 'Wrong length for protocol E+' real_msg_with_etx = real_msg + chr(ascii_names.index('ETX')) lrc = generate_lrc(real_msg_with_etx) message = chr(ascii_names.index('STX')) + real_msg_with_etx + chr(lrc) serial_write(serial, message) - print 'Message sent to terminal' + print('Message sent to terminal') def compare_data_vs_answer(data, answer_data): @@ -138,7 +138,7 @@ def compare_data_vs_answer(data, answer_data): 'pos_number', 'amount_msg', 'currency_numeric', 'private']: if data[field] != answer_data[field]: - print ( + print( "Field %s has value '%s' in data and value '%s' in answer" % (field, data[field], answer_data[field])) @@ -152,7 +152,7 @@ def parse_terminal_answer(real_msg, data): 'currency_numeric': real_msg[12:15], 'private': real_msg[15:26], } - print 'answer_data = %s' % answer_data + print('answer_data = %s' % answer_data) compare_data_vs_answer(data, answer_data) return answer_data @@ -161,18 +161,19 @@ def get_answer_from_terminal(serial, data): ascii_names = curses.ascii.controlnames full_msg_size = 1+2+1+8+1+3+10+1+1 msg = serial.read(size=full_msg_size) - print '%d bytes read from terminal' % full_msg_size + print('%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')): - print 'The first byte of the answer from terminal should be STX' + print('The first byte of the answer from terminal should be STX') if msg[-2] != chr(ascii_names.index('ETX')): - print 'The byte before final of the answer from terminal should be ETX' + print('The byte before final of the answer ' + 'from terminal should be ETX') lrc = msg[-1] computed_lrc = chr(generate_lrc(msg[1:-1])) if computed_lrc != lrc: - print 'The LRC of the answer from terminal is wrong' + print('The LRC of the answer from terminal is wrong') real_msg = msg[1:-2] - print 'Real answer received = %s' % real_msg + print('Real answer received = %s' % real_msg) return parse_terminal_answer(real_msg, data) @@ -189,7 +190,7 @@ def transaction_start(): # that we have to wait to up 3 seconds to get LRC serial = Serial( DEVICE, DEVICE_RATE, timeout=3) - print 'serial.is_open = %s' % serial.isOpen() + print('serial.is_open = %s' % serial.isOpen()) if initialize_msg(serial): data = prepare_data_to_send() if not data: @@ -198,19 +199,19 @@ def transaction_start(): if get_one_byte_answer(serial, 'ACK'): send_one_byte_signal(serial, 'EOT') - print "Now expecting answer from Terminal" + print("Now expecting answer from Terminal") if get_one_byte_answer(serial, 'ENQ'): send_one_byte_signal(serial, 'ACK') get_answer_from_terminal(serial, data) send_one_byte_signal(serial, 'ACK') if get_one_byte_answer(serial, 'EOT'): - print "Answer received from Terminal" + print("Answer received from Terminal") - except Exception, e: - print 'Exception in serial connection: %s' % str(e) + except Exception as e: + print('Exception in serial connection: %s' % str(e)) finally: if serial: - print 'Closing serial port for payment terminal' + print('Closing serial port for payment terminal') serial.close() From d69b24f4304c465157e8453c0e62b726c5f8bd74 Mon Sep 17 00:00:00 2001 From: OCA-git-bot Date: Tue, 3 Sep 2019 21:03:54 +0000 Subject: [PATCH 24/25] hw_telium_payment_terminal 8.0.0.1.2 --- hw_telium_payment_terminal/__openerp__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw_telium_payment_terminal/__openerp__.py b/hw_telium_payment_terminal/__openerp__.py index f9a052f0..fdfb436e 100644 --- a/hw_telium_payment_terminal/__openerp__.py +++ b/hw_telium_payment_terminal/__openerp__.py @@ -23,7 +23,7 @@ { 'name': 'Hardware Telium Payment Terminal', - 'version': '8.0.0.1.1', + 'version': '8.0.0.1.2', 'category': 'Hardware Drivers', 'license': 'AGPL-3', 'summary': 'Adds support for Payment Terminals using Telium protocol', From 81be592709903d93340694c33fee57deca535622 Mon Sep 17 00:00:00 2001 From: Florent de Labarre Date: Fri, 20 Mar 2020 11:24:00 +0100 Subject: [PATCH 25/25] [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