Browse Source

[MIG] hw_telium_payment_terminal: Migration to 12.0

pull/471/head
Florent de Labarre 5 years ago
parent
commit
81be592709
  1. 89
      hw_telium_payment_terminal/README.rst
  2. 23
      hw_telium_payment_terminal/__init__.py
  3. 16
      hw_telium_payment_terminal/__manifest__.py
  4. 37
      hw_telium_payment_terminal/__openerp__.py
  5. 23
      hw_telium_payment_terminal/controllers/__init__.py
  6. 126
      hw_telium_payment_terminal/controllers/main.py
  7. 14
      hw_telium_payment_terminal/i18n/hw_telium_payment_terminal.pot
  8. 21
      hw_telium_payment_terminal/test-scripts/telium-test.py

89
hw_telium_payment_terminal/README.rst

@ -1,15 +1,48 @@
================================
Hardware Telium Payment Terminal 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 This module adds support for credit card reader and checks printers
using Telium protocol in the Point of Sale. This module is designed to 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 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, are connected) and not on the main Odoo server. On the main Odoo server,
you should install the module *pos_payment_terminal*. 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 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_name (default = /dev/ttyACM0)
* payment_terminal_device_rate (default = 9600) * 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 is based on the Concert protocol, so it can probably work with payment
terminals from other brands. This module implements the protocol E+ (and terminals from other brands. This module implements the protocol E+ (and
not the protocol E), so it requires a Telium Manager version 37783600 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 terminal press F > 0-TELIUM MANAGER > 2-Consultation > 4-Configuration
> 2-Software > 1-TERMINAL > On Display > Telium Manager and then read > 2-Software > 1-TERMINAL > On Display > Telium Manager and then read
the field *M20S*. the field *M20S*.
@ -35,14 +70,50 @@ This module has been successfully tested with:
* Ingenico iCT220 * Ingenico iCT220
* Ingenico iCT250 * Ingenico iCT250
* Ingenico i2200 cheque reader and writer * 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: To install it, run:
``sudo pip install pycountry`` ``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 <https://github.com/OCA/pos/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 <https://github.com/OCA/pos/issues/new?body=module:%20hw_telium_payment_terminal%0Aversion:%2012.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
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 <https://github.com/OCA/pos/tree/12.0/hw_telium_payment_terminal>`_ project on GitHub.
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

23
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 <alexis.delattre@akretion.com>
#
# 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 <http://www.gnu.org/licenses/>.
#
##############################################################################
from . import controllers from . import controllers

16
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,
}

37
hw_telium_payment_terminal/__openerp__.py

@ -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 <alexis.delattre@akretion.com>
#
# 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 <http://www.gnu.org/licenses/>.
#
##############################################################################
{
'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': [],
}

23
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 <alexis.delattre@akretion.com>
#
# 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 <http://www.gnu.org/licenses/>.
#
##############################################################################
from . import main from . import main

126
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 <alexis.delattre@akretion.com>
#
# 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 <http://www.gnu.org/licenses/>.
#
##############################################################################
import logging import logging
import simplejson import simplejson
import time import time
import curses.ascii import curses.ascii
from threading import Thread, Lock 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__) logger = logging.getLogger(__name__)
try: try:
import pycountry
from serial import Serial from serial import Serial
except (ImportError, IOError) as err: except (ImportError, IOError) as err:
logger.debug(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): class TeliumPaymentTerminalDriver(Thread):
def __init__(self): def __init__(self):
@ -68,13 +55,13 @@ class TeliumPaymentTerminalDriver(Thread):
self.status['messages'] = [] self.status['messages'] = []
if status == 'error' and message: if status == 'error' and message:
logger.error('Payment Terminal Error: '+message)
logger.error('Payment Terminal Error: ' + message)
elif status == 'disconnected' and message: elif status == 'disconnected' and message:
logger.warning('Disconnected Terminal: '+message)
logger.warning('Disconnected Terminal: ' + message)
def lockedstart(self): def lockedstart(self):
with self.lock: with self.lock:
if not self.isAlive():
if not self.is_alive():
self.daemon = True self.daemon = True
self.start() self.start()
@ -84,7 +71,17 @@ class TeliumPaymentTerminalDriver(Thread):
def serial_write(self, text): def serial_write(self, text):
assert isinstance(text, str), 'text must be a string' 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): def initialize_msg(self):
max_attempt = 3 max_attempt = 3
@ -109,17 +106,22 @@ class TeliumPaymentTerminalDriver(Thread):
logger.debug('Signal %s sent to terminal' % signal) logger.debug('Signal %s sent to terminal' % signal)
def get_one_byte_answer(self, expected_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 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) expected_char = ascii_names.index(expected_signal)
if one_byte_read == chr(expected_char): if one_byte_read == chr(expected_char):
logger.debug("%s received from terminal" % expected_signal)
return True return True
else: else:
return False return False
def prepare_data_to_send(self, payment_info_dict):
def _get_amount(self, payment_info_dict):
amount = payment_info_dict['amount'] 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': if payment_info_dict['payment_mode'] == 'check':
payment_mode = 'C' payment_mode = 'C'
elif payment_info_dict['payment_mode'] == 'card': elif payment_info_dict['payment_mode'] == 'card':
@ -129,12 +131,14 @@ class TeliumPaymentTerminalDriver(Thread):
"The payment mode '%s' is not supported" "The payment mode '%s' is not supported"
% payment_info_dict['payment_mode']) % payment_info_dict['payment_mode'])
return False return False
cur_decimals = payment_info_dict['currency_decimals']
cur_fact = 10**cur_decimals
cur_iso_letter = payment_info_dict['currency_iso'].upper() cur_iso_letter = payment_info_dict['currency_iso'].upper()
try: 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: except:
logger.error("Currency %s is not recognized" % cur_iso_letter) logger.error("Currency %s is not recognized" % cur_iso_letter)
return False return False
@ -145,9 +149,9 @@ class TeliumPaymentTerminalDriver(Thread):
'payment_mode': payment_mode, 'payment_mode': payment_mode,
'currency_numeric': cur_numeric.zfill(3), 'currency_numeric': cur_numeric.zfill(3),
'private': ' ' * 10, 'private': ' ' * 10,
'delay': 'A011',
'delay': 'A010',
'auto': 'B010', 'auto': 'B010',
'amount_msg': ('%.0f' % (amount * cur_fact)).zfill(8),
'amount_msg': self._get_amount(payment_info_dict),
} }
return data return data
@ -179,9 +183,7 @@ class TeliumPaymentTerminalDriver(Thread):
logger.info('Message sent to terminal') logger.info('Message sent to terminal')
def compare_data_vs_answer(self, data, answer_data): 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]: if data[field] != answer_data[field]:
logger.warning( logger.warning(
"Field %s has value '%s' in data and value '%s' in answer" "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): def get_answer_from_terminal(self, data):
ascii_names = curses.ascii.controlnames 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) logger.debug('%d bytes read from terminal' % full_msg_size)
assert len(msg) == full_msg_size, 'Answer has a wrong size' assert len(msg) == full_msg_size, 'Answer has a wrong size'
if msg[0] != chr(ascii_names.index('STX')): if msg[0] != chr(ascii_names.index('STX')):
@ -242,7 +244,8 @@ class TeliumPaymentTerminalDriver(Thread):
if self.serial.isOpen(): if self.serial.isOpen():
self.set_status("connected", self.set_status("connected",
"Connected to {}".format(self.device_name))
"Connected to {} with baudrate {}".format(
self.device_name, self.device_rate))
else: else:
self.set_status("disconnected", self.set_status("disconnected",
"Could not connect to {}" "Could not connect to {}"
@ -256,13 +259,28 @@ class TeliumPaymentTerminalDriver(Thread):
if self.get_one_byte_answer('ACK'): if self.get_one_byte_answer('ACK'):
self.send_one_byte_signal('EOT') 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: except Exception as e:
logger.error('Exception in serial connection: %s' % str(e)) logger.error('Exception in serial connection: %s' % str(e))

14
hw_telium_payment_terminal/i18n/hw_telium_payment_terminal.pot

@ -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"

21
hw_telium_payment_terminal/test-scripts/telium-test.py

@ -1,26 +1,5 @@
#! /usr/bin/python #! /usr/bin/python
# -*- encoding: utf-8 -*- # -*- encoding: utf-8 -*-
##############################################################################
#
# Hardware Telium Test script
# Copyright (C) 2014 Akretion (http://www.akretion.com)
# @author Alexis de Lattre <alexis.delattre@akretion.com>
#
# 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 <http://www.gnu.org/licenses/>.
#
##############################################################################
from serial import Serial from serial import Serial
import curses.ascii import curses.ascii

Loading…
Cancel
Save