Last active
July 6, 2016 22:27
-
-
Save jBenes/636fa89e52b47dc5d20d to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import requests | |
import ujson | |
from pprint import pprint | |
from random import SystemRandom | |
from string import digits, ascii_uppercase | |
from time import sleep | |
possible_characters = ascii_uppercase + digits | |
def gp(length=32): | |
"""Generate a random string using the OS""" | |
rng = SystemRandom() | |
return "".join([rng.choice(possible_characters) for i in range(length)]) | |
def gen_udid(): | |
""" | |
ZooZ-UDID should identify the user to prevent fraud. As we are doing the fraud detection on our side, this can be a random string. | |
Sample ZooZ-UDID: A6092EF-ASCX-ASDE-NKSD-AB75129B9375""" | |
udid = "zooz_%s-%s-%s-%s-%s" % (gp(8), gp(4), gp(4), gp(4), gp(12) ) | |
return udid | |
def check_flights(): | |
""" | |
Confirms the price of the flights | |
Use the realtime parameter to get the fastest possible response | |
The response is shortly described in the gist file below. Though, most of | |
the values in the response can be ignored by our partners. | |
The most important fields are only total, which is the total price and flights_invalid, which should be False. | |
""" | |
parameters = { | |
'v':2, # default | |
'pnum':1, # passenger number | |
'bnum':1, # bags number | |
'booking_token':"bcEuJfu3fWne+z+50B2d1FLlFWEq6njGjUEUpGFn1DvjlNr7ieM4H5cvU6x9XSmssAVHCS1pt3KjNQ2VnuHSpJl+t6nAsPvJlPJkF1OOMNALHDt6Pmjk1C118CuA4iD1aB3B113leGOLKfeW0t3sDglcz4+DVwbaUFs/cqd37ZjTTFw4gMXalcgMG+KyZ1Rw6YIXWZrN2cxX+GXn1YjfMw==", | |
'affily':'dohop', # affiliate ID | |
'booked_at':'dohop', # booked at site ID | |
'realtime': True # set to True for cases, when check flights cant be repeated or you want the response asap | |
} | |
print 'check_flights start' | |
response = requests.get('https://api.skypicker.com/api/v0.1/check_flights', params=parameters ).json() | |
print 'check_flights response' | |
pprint(response) | |
# flights must be checked and cannot be invalid | |
return response['flights_checked'] and not response['flights_invalid'] | |
def save_booking(): | |
"""Initiates the booking on Skypicker backend | |
The specified data is sent to the API as a json payload | |
The data sent to this API call should be confirmed before by the check_flights call | |
Response from save_booking is nearly the same as from check_flights, with the following parameters added | |
{ 'transaction_id': False, | |
'zooz_token': '4XWBRXPFUD4YSXXPGBKEUNSKR4', // use this token to send credit card data to Zooz | |
'booking_id': 47808, // the unique booking identified (this ID will be also passed in the callbacks to identify the booking) | |
'sandbox': True, // indicates if the payment is processed in a sandbox mode. Can be also triggered by using Test Test as a passenger name | |
'status': 'success' | |
} | |
""" | |
data = { | |
"lang":"en", # user language | |
"bags":0, # number of bags | |
"passengers":[ # array with passengers data | |
{ | |
"surname":"test", | |
"cardno":None, # ID card/passport ID. In case, check flights will return document_options.document_need 2, | |
#this needs to be filled in by the user togerther with the expiration field. Otherwise, those field can stay hidden from the booking form to increase conversion rate | |
"phone":"+44 564564568456", # needed only for the first passenger in the array | |
"birthday":724118400, # passenger birth day, utc unix timestamp in seconds | |
"nationality":"United Kingdom", | |
"checkin":"REMOVED, DEPRECATED", # DEPRECATED, leave an empty string here | |
"issuer":"REMOVED, DEPRECATED", # DEPRECATED, leave an empty string here | |
"name":"test", | |
"title":"mr", # mr/ms/mrs | |
"expiration":None, # expiration date of the ID from the cardno field | |
"email":"[email protected]" # needed only for the first passenger in the array | |
} | |
], | |
"locale":"en", | |
"customerLoginID":"unknown", # loginID for zooz payments | |
"currency":"czk", # SP only | |
'booking_token':'bcEuJfu3fWne+z+50B2d1FLlFWEq6njGjUEUpGFn1DvjlNr7ieM4H5cvU6x9XSmssAVHCS1pt3KjNQ2VnuHSpJl+t6nAsPvJlPJkF1OOMNALHDt6Pmjk1C118CuA4iD1aB3B113leGOLKfeW0t3sDglcz4+DVwbaUFs/cqd37ZjTTFw4gMXalcgMG+KyZ1Rw6YIXWZrN2cxX+GXn1YjfMw==', | |
"customerLoginName":"unknown", # login name for zooz payments | |
"affily":"dohop", # affil id, can contain any subID string, max length 64 | |
"booked_at":"dohop", # basic affil id, without any subIDs | |
} | |
url = "https://api.skypicker.com/api/v0.1/save_booking?v=2" | |
print 'save_booking start' | |
response = requests.post(url,data = ujson.dumps(data)).json() | |
pprint(response) | |
print 'save_booking response' | |
return response | |
def zooz_init(response): | |
""" | |
Sends credit card data to zooz | |
'responseStatus': 0 in the response means success | |
""" | |
uuid = gen_udid() | |
headers = { | |
"productType":"Checkout API", | |
"ZooZ-Token":response["zooz_token"], | |
"ZooZ-UDID":gen_udid(), | |
"deviceSignature":gen_udid(), | |
"ZooZResponseType":"JSon", | |
"programId":"dohop2" | |
} | |
url_zooz = "https://sandbox.zooz.co/mobile/ZooZClientPaymentAPI" # use app.zooz.com for production | |
init_data = {"cmd":"init","paymentToken":response["zooz_token"]} | |
print 'zooz_init start' | |
init_response = requests.post(url_zooz,data = ujson.dumps(init_data),headers = headers).json() | |
print 'zooz_init response' | |
pprint(init_response) | |
add_payment_method_data = { | |
"cmd":"addPaymentMethod", | |
"paymentToken":response["zooz_token"], | |
"paymentMethod":{ | |
"paymentMethodType":"CreditCard", | |
"paymentMethodDetails":{ | |
"cardNumber":"4580458045804580", | |
"cardHolderName":"testtest", | |
"expirationDate":"12/2015", | |
"cvvNumber":"321" | |
}, | |
}, | |
"email":"[email protected]", | |
"configuration": { | |
"rememberPaymentMethod":True | |
}, | |
} | |
print 'zooz_add_payment start' | |
add_payment_response = requests.post(url_zooz,data = ujson.dumps(add_payment_method_data),headers = headers).json() | |
print 'zooz_add_payment response' | |
pprint(add_payment_response) | |
return add_payment_response | |
def confirm_to_skypicker(response,add_payment_response): | |
"""Confirms the successful sending of cc data and requests a charge on the credit card for the amount sent on save_booking | |
Successful response {'status': 0} (the payment is done and the booking will be processed) | |
Error response {'msg': u'server error', 'status': u'error'} | |
""" | |
confirm_payment_data = dict( | |
paymentToken=response["zooz_token"], | |
paymentMethodToken=add_payment_response["responseObject"]["paymentMethodToken"], | |
) | |
print 'confirm_to_skypicker start' | |
final = requests.post("https://api.skypicker.com/api/v0.1/confirm_payment", data = confirm_payment_data).json() | |
print 'confirm_to_skypicker response' | |
pprint(final) | |
return final | |
#trigger the first check flight to refresh the price and sleep for a few seconds. Needed until the realtime=True parameter is not on production | |
check_flights() | |
sleep(5) | |
#check if the flight is Valid for booking | |
if check_flights(): | |
#request a Booking ID and a zooz token for initializing the payment | |
response = save_booking() | |
#init the payment on zooz | |
zooz_response = zooz_init(response) | |
#confirm success. Only response status 0 means the payment will be successful | |
if zooz_response['responseStatus'] == 0: | |
confirmation = confirm_to_skypicker(response,zooz_response) | |
if confirmation['status'] == 0: | |
print '=== Booking is successfully paid ===' | |
else: | |
print '=== Error: booking is not paid ===' | |
else: | |
print '=== Error: Zooz init failed ===' | |
else: | |
print '=== Error: check flights is probably Invalid ===' |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment