1
0
forked from Mapan/odoo17e
odoo17e-kedaikipas58/addons/iot/iot_handlers/drivers/WorldlineDriver_W.py
2024-12-10 09:04:09 +07:00

182 lines
8.2 KiB
Python

# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import ctypes
import datetime
import logging
from odoo.addons.hw_drivers.iot_handlers.lib.ctypes_terminal_driver import CtypesTerminalDriver, ulong_pointer, double_pointer, import_ctypes_library, create_ctypes_string_buffer
_logger = logging.getLogger(__name__)
# Load library
easyCTEP = import_ctypes_library('ctep_w', 'libeasyctep.dll')
# int startTransaction(
easyCTEP.startTransaction.argtypes = [
ctypes.c_void_p, # CTEPManager* manager
ctypes.c_char_p, # char const* amount
ctypes.c_char_p, # char const* reference
ctypes.c_ulong, # unsigned long action_identifier
ctypes.c_char_p, # char* merchant_receipt
ctypes.c_char_p, # char* customer_receipt
ctypes.c_char_p, # char* card
ctypes.c_char_p # char* error
]
# int abortTransaction(CTEPManager* manager, char* error)
easyCTEP.abortTransaction.argtypes = [ctypes.c_void_p, ctypes.c_char_p]
# int lastTransactionStatus(
easyCTEP.lastTransactionStatus.argtypes = [
ctypes.c_void_p, # CTEPManager* manager
ulong_pointer, # unsigned long* action_identifier
double_pointer, # double* amount
ctypes.c_char_p, # char* time
ctypes.c_char_p # char* error
]
# All the terminal errors can be found in the section "Codes d'erreur" here:
# https://help.winbooks.be/pages/viewpage.action?pageId=64455643#LiaisonversleterminaldepaiementBanksysenTCP/IP-Codesd'erreur
TERMINAL_ERRORS = {
'1802': 'Terminal is busy',
'1803': 'Timeout expired',
'2629': 'User cancellation',
'2631': 'Host cancellation',
}
# Manually cancelled by cashier, do not show these errors
IGNORE_ERRORS = [
'2628', # External Equipment Cancellation
'2630', # Device Cancellation
]
class WorldlineDriver(CtypesTerminalDriver):
connection_type = 'ctep'
def __init__(self, identifier, device):
super(WorldlineDriver, self).__init__(identifier, device)
self.device_name = 'Worldline terminal %s' % self.device_identifier
self.device_manufacturer = 'Worldline'
def processTransaction(self, transaction):
if transaction['amount'] <= 0:
return self.send_status(error='The terminal cannot process negative or null transactions.', request_data=transaction)
# Force to wait before starting the transaction if necessary
self._check_transaction_delay()
# Notify transaction start
self.send_status(stage='WaitingForCard', request_data=transaction)
# Transaction
merchant_receipt = create_ctypes_string_buffer()
customer_receipt = create_ctypes_string_buffer()
card = create_ctypes_string_buffer()
error_code = create_ctypes_string_buffer()
transaction_id = transaction['TransactionID']
transaction_amount = transaction['amount'] / 100
transaction_action_identifier = transaction['actionIdentifier']
_logger.info('start transaction #%d amount: %f action_identifier: %d', transaction_id, transaction_amount, transaction_action_identifier)
try:
result = easyCTEP.startTransaction(
ctypes.cast(self.dev, ctypes.c_void_p), # CTEPManager* manager
ctypes.c_char_p(str(transaction_amount).encode('utf-8')), # char const* amount
ctypes.c_char_p(str(transaction_id).encode('utf-8')), # char const* reference
ctypes.c_ulong(transaction_action_identifier), # unsigned long action_identifier
merchant_receipt, # char* merchant_receipt
customer_receipt, # char* customer_receipt
card, # char* card
error_code, # char* error
)
_logger.debug('finished transaction #%d with result %d', transaction_id, result)
self.next_transaction_min_dt = datetime.datetime.now() + datetime.timedelta(seconds=self.DELAY_TIME_BETWEEN_TRANSACTIONS)
if result == 1:
# Transaction successful
self.send_status(
response='Approved',
ticket=customer_receipt.value,
ticket_merchant=merchant_receipt.value,
card=card.value,
transaction_id=transaction['actionIdentifier'],
request_data=transaction,
)
elif result == 0:
# Transaction failed
error_code = error_code.value.decode('utf-8')
if error_code not in IGNORE_ERRORS:
error_msg = '%s (Error code: %s)' % (TERMINAL_ERRORS.get(error_code, 'Transaction was not processed correctly'), error_code)
self.send_status(error=error_msg, request_data=transaction)
# Transaction was cancelled
else:
self.send_status(stage='Cancel', request_data=transaction)
elif result == -1:
# Terminal disconnection, check status manually
self.send_status(disconnected=True, request_data=transaction)
except OSError:
_logger.exception("Failed to perform Worldline transaction. Check for potential segmentation faults")
self.send_status(
error="An error has occured. Check the transaction result manually with the payment provider",
request_data=transaction,
)
def cancelTransaction(self, transaction):
# Force to wait before starting the transaction if necessary
self._check_transaction_delay()
self.send_status(stage='waitingCancel', request_data=transaction)
error_code = create_ctypes_string_buffer()
_logger.info("cancel transaction request")
try:
result = easyCTEP.abortTransaction(ctypes.cast(self.dev, ctypes.c_void_p), error_code)
_logger.debug("end cancel transaction request")
if not result:
error_code = error_code.value.decode('utf-8')
error_msg = '%s (Error code: %s)' % (TERMINAL_ERRORS.get(error_code, 'Transaction could not be cancelled'), error_code)
_logger.info(error_msg)
self.send_status(stage='Cancel', error=error_msg, request_data=transaction)
except OSError:
_logger.exception("Failed to cancel Worldline transaction. Check for potential segmentation faults.")
self.send_status(
stage='Cancel',
error="An error has occured when cancelling Worldline transaction. Check the transaction result manually with the payment provider",
request_data=transaction,
)
def lastTransactionStatus(self, request_data):
action_identifier = ctypes.c_ulong()
amount = ctypes.c_double()
time = create_ctypes_string_buffer()
error_code = create_ctypes_string_buffer()
_logger.info("last transaction status request")
try:
result = easyCTEP.lastTransactionStatus(ctypes.cast(self.dev, ctypes.c_void_p), ctypes.byref(action_identifier), ctypes.byref(amount), time, error_code)
if result:
self.send_status(value={
'action_identifier': action_identifier.value,
'amount': amount.value,
'time': time.value,
},
request_data=request_data,
)
else:
error_code = error_code.value.decode('utf-8')
error_msg = '%s (Error code: %s)' % (TERMINAL_ERRORS.get(error_code, 'Last Transaction was not processed correctly'), error_code)
self.send_status(
value={
'error': error_msg,
},
request_data=request_data,
)
except OSError:
_logger.exception("Failed to get last transaction status. Check for potential segmentation faults")
self.send_status(
error="An error has occured when getting last Worldline transaction status. Check the transaction result manually with the payment provider",
request_data=request_data,
)
_logger.debug("end last transaction status request")