Skip to content

Commit d7d3a94

Browse files
committed
Add alternative payment methods support (like Google Pay)
1 parent 64d31aa commit d7d3a94

File tree

9 files changed

+143
-9
lines changed

9 files changed

+143
-9
lines changed

.github/workflows/pythonpackage.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ jobs:
88
runs-on: ubuntu-latest
99
strategy:
1010
matrix:
11-
python-version: ['3.9', '3.10', '3.11', '3.12']
11+
python-version: ['3.9', '3.10', '3.11', '3.12', '3.13']
1212

1313
steps:
1414
- uses: actions/checkout@v1

README.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,26 @@ new_payment.command_data_set().add_payment_method_data_source(gateway.DATA_SOURC
145145
new_payment.command_data_set().add_payment_method_data_token('initial gateway-transaction-id')
146146
```
147147

148+
### Using alternative payment methods
149+
150+
To use an alternative payment method (like Google Pay), send a received token AS-IS or data from a decrypted token.
151+
152+
```python
153+
# set a corresponding flag that indicates a token provider
154+
payment.command_data_set().add_payment_method_type('google_pay')
155+
156+
# option 1: send received token AS-IS
157+
payment.payment_method_set().add_token('<token>')
158+
159+
# option 2: send data from decrypted token
160+
payment.payment_method_set().add_pan_number('4111111111111111')
161+
payment.payment_method_set().add_pan_cardholder_name('John Doe')
162+
payment.payment_method_set().add_pan_expiry_date('12/30')
163+
payment.payment_method_set().add_external_token_cryptogram('<cryptogram from token>')
164+
payment.payment_method_set().add_external_token_eci('<ECI from token>')
165+
payment.payment_method_set().add_external_token_cardholder_authenticated(decryptedToken.paymentMethodDetails.assuranceDetails.cardHolderAuthenticated)
166+
```
167+
148168
### Callback validation
149169

150170
```python

gateway/builders/command_data_builder.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,3 +135,22 @@ def add_payment_method_data_token(self, token=None):
135135
new_key=self.__COMMAND_DATA_KEY,
136136
new_dict={self.__data_sets.COMMAND_DATA_PAYMENT_METHOD_DATA_TOKEN: token}
137137
)
138+
139+
def add_payment_method_type(self, type=None):
140+
"""
141+
Add payment method type
142+
143+
Args:
144+
type (str): payment method type
145+
cc: card data
146+
google_pay: Google Pay token
147+
apple_pay: Apple Pay token
148+
click2pay: Click to Pay token
149+
"""
150+
151+
self.__data_structure_util.add_to_dict(
152+
source_dict=self.__command_data_set,
153+
working_dict=self.__command_data_nested_structure,
154+
new_key=self.__COMMAND_DATA_KEY,
155+
new_dict={self.__data_sets.COMMAND_DATA_PAYMENT_METHOD_TYPE: type}
156+
)

gateway/builders/payment_data_builder.py

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ class PaymentDataBuilder(object):
3434
__PAYMENT_METHOD_DATA_KEY = 'payment-method-data'
3535
# Nested layer of external 3-D Secure data set
3636
__EXTERNAL_MPI_DATA_KEY = 'external-mpi-data'
37+
# Nested layer of decrypted token's data set
38+
__EXTERNAL_TOKEN_DATA_KEY = 'external-token-data'
3739

3840
def __init__(self, __client_transaction_data_set, __client_mandatory_fields):
3941
self.__payment_data_structure = {
@@ -44,6 +46,10 @@ def __init__(self, __client_transaction_data_set, __client_mandatory_fields):
4446
self.__EXTERNAL_MPI_DATA_KEY: None
4547
}
4648

49+
self.__external_token_data_structure = {
50+
self.__EXTERNAL_TOKEN_DATA_KEY: None
51+
}
52+
4753
self.__data_structure_util = DataStructuresUtils
4854
self.__data_sets = RequestParameters
4955
self.__data_types = RequestParametersTypes
@@ -54,6 +60,10 @@ def __setup_external_mpi_data(self):
5460
if self.__EXTERNAL_MPI_DATA_KEY not in self.__payment_data_structure:
5561
self.__payment_data_structure[self.__EXTERNAL_MPI_DATA_KEY] = self.__external_mpi_data_structure
5662

63+
def __setup_external_token_data(self):
64+
if self.__EXTERNAL_TOKEN_DATA_KEY not in self.__payment_data_structure:
65+
self.__payment_data_structure[self.__EXTERNAL_TOKEN_DATA_KEY] = self.__external_token_data_structure
66+
5767
def add_pan_number(self, pan_number=None):
5868
"""
5969
Add credit card number
@@ -115,6 +125,21 @@ def add_pan_cardholder_name(self, first_last_name=None):
115125
new_dict={self.__data_sets.PAYMENT_METHOD_DATA_CARDHOLDER_NAME: first_last_name}
116126
)
117127

128+
def add_token(self, token=None):
129+
"""
130+
Add token
131+
132+
Args:
133+
token (str): Token AS-IS
134+
"""
135+
136+
self.__data_structure_util.add_to_dict(
137+
source_dict=self.__payment_data_set,
138+
working_dict=self.__payment_data_structure,
139+
new_key=self.__PAYMENT_METHOD_DATA_KEY,
140+
new_dict={self.__data_sets.PAYMENT_METHOD_DATA_TOKEN: token}
141+
)
142+
118143
def add_external_mpi_protocol_version(self, protocol_version=None):
119144
"""
120145
Add 3-D Secure protocolVersion
@@ -194,3 +219,51 @@ def add_external_mpi_trans_status(self, trans_status=None):
194219
new_key=self.__EXTERNAL_MPI_DATA_KEY,
195220
new_dict={self.__data_sets.PAYMENT_METHOD_DATA_EXTERNAL_MPI_TRANS_STATUS: trans_status}
196221
)
222+
223+
def add_external_token_cryptogram(self, cryptogram=None):
224+
"""
225+
Add cryptogram from decrypted token's data
226+
227+
Args:
228+
cryptogram (str): token cryptogram (TAVV etc.)
229+
"""
230+
231+
self.__setup_external_token_data()
232+
self.__data_structure_util.add_to_dict(
233+
source_dict=self.__payment_data_structure[self.__PAYMENT_METHOD_DATA_KEY],
234+
working_dict=self.__external_token_data_structure,
235+
new_key=self.__EXTERNAL_TOKEN_DATA_KEY,
236+
new_dict={self.__data_sets.PAYMENT_METHOD_DATA_EXTERNAL_TOKEN_CRYPTOGRAM: cryptogram}
237+
)
238+
239+
def add_external_token_eci(self, eci=None):
240+
"""
241+
Add ECI from decrypted token's data
242+
243+
Args:
244+
eci (str): token ECI
245+
"""
246+
247+
self.__setup_external_token_data()
248+
self.__data_structure_util.add_to_dict(
249+
source_dict=self.__payment_data_structure[self.__PAYMENT_METHOD_DATA_KEY],
250+
working_dict=self.__external_token_data_structure,
251+
new_key=self.__EXTERNAL_TOKEN_DATA_KEY,
252+
new_dict={self.__data_sets.PAYMENT_METHOD_DATA_EXTERNAL_TOKEN_ECI: eci}
253+
)
254+
255+
def add_external_token_cardholder_authenticated(self, cardholder_authenticated=None):
256+
"""
257+
Add cardHolderAuthenticated from decrypted Google Pay token's data
258+
259+
Args:
260+
cardholder_authenticated (bool): value of paymentMethodDetails.assuranceDetails.cardHolderAuthenticated from Google Pay token
261+
"""
262+
263+
self.__setup_external_token_data()
264+
self.__data_structure_util.add_to_dict(
265+
source_dict=self.__payment_data_structure[self.__PAYMENT_METHOD_DATA_KEY],
266+
working_dict=self.__external_token_data_structure,
267+
new_key=self.__EXTERNAL_TOKEN_DATA_KEY,
268+
new_dict={self.__data_sets.PAYMENT_METHOD_DATA_EXTERNAL_TOKEN_AUTHENTICATED: cardholder_authenticated}
269+
)

gateway/data_sets/request_parameters.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ class RequestParameters:
4040
COMMAND_DATA_CARDS_VERIFICATION = 'card-verification'
4141
COMMAND_DATA_PAYMENT_METHOD_DATA_SOURCE = 'payment-method-data-source'
4242
COMMAND_DATA_PAYMENT_METHOD_DATA_TOKEN = 'payment-method-data-token'
43+
COMMAND_DATA_PAYMENT_METHOD_TYPE = 'payment-method-type'
4344

4445
# Customer data sets
4546
GENERAL_DATA_CUSTOMER_DATA_EMAIL = 'email'
@@ -81,11 +82,15 @@ class RequestParameters:
8182
PAYMENT_METHOD_DATA_EXPIRE = 'exp-mm-yy'
8283
PAYMENT_METHOD_DATA_CVV = 'cvv'
8384
PAYMENT_METHOD_DATA_CARDHOLDER_NAME = 'cardholder-name'
85+
PAYMENT_METHOD_DATA_TOKEN = 'token'
8486
PAYMENT_METHOD_DATA_EXTERNAL_MPI_PROTOCOL = 'protocolVersion'
8587
PAYMENT_METHOD_DATA_EXTERNAL_MPI_DS_TRANS_ID = 'dsTransID'
8688
PAYMENT_METHOD_DATA_EXTERNAL_MPI_XID = 'xid'
8789
PAYMENT_METHOD_DATA_EXTERNAL_MPI_CAVV = 'cavv'
8890
PAYMENT_METHOD_DATA_EXTERNAL_MPI_TRANS_STATUS = 'transStatus'
91+
PAYMENT_METHOD_DATA_EXTERNAL_TOKEN_CRYPTOGRAM = 'cryptogram'
92+
PAYMENT_METHOD_DATA_EXTERNAL_TOKEN_ECI = 'eci'
93+
PAYMENT_METHOD_DATA_EXTERNAL_TOKEN_AUTHENTICATED = 'cardHolderAuthenticated'
8994

9095
# Money data sets
9196
MONEY_DATA_AMOUNT = 'amount'
@@ -133,6 +138,7 @@ class RequestParametersTypes(RequestParameters):
133138
COMMAND_DATA_CARDS_VERIFICATION = int
134139
COMMAND_DATA_PAYMENT_METHOD_DATA_SOURCE = int
135140
COMMAND_DATA_PAYMENT_METHOD_DATA_TOKEN = str
141+
COMMAND_DATA_PAYMENT_METHOD_TYPE = str
136142

137143
# Customer data sets
138144
GENERAL_DATA_CUSTOMER_DATA_EMAIL = str
@@ -174,11 +180,15 @@ class RequestParametersTypes(RequestParameters):
174180
PAYMENT_METHOD_DATA_EXPIRE = str
175181
PAYMENT_METHOD_DATA_CVV = str
176182
PAYMENT_METHOD_DATA_CARDHOLDER_NAME = str
183+
PAYMENT_METHOD_DATA_TOKEN = str
177184
PAYMENT_METHOD_DATA_EXTERNAL_MPI_PROTOCOL = str
178185
PAYMENT_METHOD_DATA_EXTERNAL_MPI_DS_TRANS_ID = str
179186
PAYMENT_METHOD_DATA_EXTERNAL_MPI_XID = str
180187
PAYMENT_METHOD_DATA_EXTERNAL_MPI_CAVV = str
181188
PAYMENT_METHOD_DATA_EXTERNAL_MPI_TRANS_STATUS = str
189+
PAYMENT_METHOD_DATA_EXTERNAL_TOKEN_CRYPTOGRAM = str
190+
PAYMENT_METHOD_DATA_EXTERNAL_TOKEN_ECI = str
191+
PAYMENT_METHOD_DATA_EXTERNAL_TOKEN_AUTHENTICATED = bool
182192

183193
# Money data sets
184194
MONEY_DATA_AMOUNT = int

gateway/transport/transport.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ def new_http_client(cli_name='requests', *args, **kwargs):
7575

7676
class HttpTransport(object):
7777
def __init__(self, verify_ssl=True, proxy=None, timeout=60):
78-
if verify_ssl is bool:
78+
if isinstance(verify_ssl, bool):
7979
self.verify_ssl = verify_ssl
8080
else:
8181
self.verify_ssl = True

setup.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
try:
1010
import pypandoc
1111

12-
LONG_DESCRIPTION = pypandoc.convert('README.md', 'rst')
12+
LONG_DESCRIPTION = pypandoc.convert_file('README.md', 'rst')
1313
except (IOError, ImportError, OSError, RuntimeError):
1414
LONG_DESCRIPTION = ''
1515

@@ -21,12 +21,11 @@
2121
'Operating System :: OS Independent',
2222
'Programming Language :: Python',
2323
'Programming Language :: Python :: 3',
24-
'Programming Language :: Python :: 3.6',
25-
'Programming Language :: Python :: 3.7',
26-
'Programming Language :: Python :: 3.8',
2724
'Programming Language :: Python :: 3.9',
2825
'Programming Language :: Python :: 3.10',
2926
'Programming Language :: Python :: 3.11',
27+
'Programming Language :: Python :: 3.12',
28+
'Programming Language :: Python :: 3.13',
3029
'Topic :: Software Development :: Libraries :: Python Modules'
3130
]
3231

@@ -36,7 +35,7 @@
3635

3736
setuptools.setup(
3837
name='transactpro-gw3-client',
39-
version='1.7.8',
38+
version='1.7.9',
4039
description='Transact PRO Gateway3 implementation in Python.',
4140
long_description=LONG_DESCRIPTION,
4241
long_description_content_type="text/markdown",
@@ -48,5 +47,5 @@
4847
license='MIT',
4948
classifiers=CLASSIFIERS,
5049
keywords='GW3 gateway3 integration gateway TransactPRO python python3',
51-
python_requires='>=3.6',
50+
python_requires='>=3.9',
5251
)

tests/builders/test_command_data_builder.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ def test_mandatory_and_data_fields(self):
4747
new.add_card_verification_mode(321)
4848
new.add_payment_method_data_source(456)
4949
new.add_payment_method_data_token('mega-token')
50+
new.add_payment_method_type('google_pay')
5051
from gateway.data_sets.request_parameters import (RequestParameters, RequestParametersTypes)
5152
valid_fields_types = {
5253
RequestParameters.COMMAND_DATA_GATEWAY_TRANSACTION_ID:
@@ -60,7 +61,8 @@ def test_mandatory_and_data_fields(self):
6061
'form-id': '#Bravo345',
6162
'card-verification': 321,
6263
'payment-method-data-source': 456,
63-
'payment-method-data-token': 'mega-token'
64+
'payment-method-data-token': 'mega-token',
65+
'payment-method-type': 'google_pay'
6466
}
6567
}
6668
self.assertDictEqual(valid_data_structure, self.DATA)

tests/builders/test_payment_data_builder.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,13 +67,18 @@ def test_additional_data_fields(self):
6767
new.add_pan_cvv_code(cvv_number='442')
6868
new.add_pan_expiry_date(mm_yy='12/30')
6969
new.add_pan_number(pan_number='4222222222222')
70+
new.add_token(token='qwerty')
7071

7172
new.add_external_mpi_protocol_version('2.2.0')
7273
new.add_external_mpi_ds_trans_id('26221368-1c3d-4f3c-ba34-2efb76644c320')
7374
new.add_external_mpi_xid('b+f8duAy8jNTQ0DB4U3mSmPyp8s=')
7475
new.add_external_mpi_cavv('kBMI/uGZvlKCygBkcQIlLJeBTPLG')
7576
new.add_external_mpi_trans_status('Y')
7677

78+
new.add_external_token_cryptogram('AAMI/uGZvlKCygBkcQIlLJeBTPLG')
79+
new.add_external_token_eci('07')
80+
new.add_external_token_cardholder_authenticated(True)
81+
7782
from gateway.data_sets.request_parameters import (RequestParameters, RequestParametersTypes)
7883
valid_fields_types = {
7984
RequestParameters.PAYMENT_METHOD_DATA_PAN:
@@ -86,12 +91,18 @@ def test_additional_data_fields(self):
8691
'pan': '4222222222222',
8792
'cardholder-name': 'Jane Doe',
8893
'exp-mm-yy': '12/30',
94+
'token': 'qwerty',
8995
'external-mpi-data': {
9096
'protocolVersion': '2.2.0',
9197
'dsTransID': '26221368-1c3d-4f3c-ba34-2efb76644c320',
9298
'xid': 'b+f8duAy8jNTQ0DB4U3mSmPyp8s=',
9399
'cavv': 'kBMI/uGZvlKCygBkcQIlLJeBTPLG',
94100
'transStatus': 'Y'
101+
},
102+
'external-token-data': {
103+
'cryptogram': 'AAMI/uGZvlKCygBkcQIlLJeBTPLG',
104+
'eci': '07',
105+
'cardHolderAuthenticated': True
95106
}
96107
}
97108
}

0 commit comments

Comments
 (0)