Skip to content

Instantly share code, notes, and snippets.

@koriaf
Created August 14, 2015 15:41
Show Gist options
  • Save koriaf/c2b839ac29e55f8be04e to your computer and use it in GitHub Desktop.
Save koriaf/c2b839ac29e55f8be04e to your computer and use it in GitHub Desktop.
django-okpay (or python-okpay) payment processing script. Simple version, without full support of API and tests.
class OkpayProcessor(object):
'''OKPAY payment notification check and enrollment class.
https://dev.okpay.com/en/manual/ipn/listener-implementation.html
https://dev.okpay.com/en/manual/ipn/testing.html
https://dev.okpay.com/en/guides/accepting-payments.html#ipn
https://dev.okpay.com/en/guides/client-verification.html#code
Usage:
processor = MyWebsiteOkpayProcessor(request.POST, logger=transactions_logger)
verification_success = processor.verify_ipn()
if not verification_success:
transactions_logger.error('Wow. Wrong data from okpay. Such suspicious. Much strange. Wow.')
return HttpResponse('verification failed')
else:
processor.enroll()
'''
OKPAY_VERIFICATION_URL = 'https://checkout.okpay.com/ipn-verify'
OKPAY_IPN_INVALID = b'INVALID'
OKPAY_IPN_VERIFIED = b'VERIFIED'
OKPAY_IPN_TEST = b'TEST'
OKPAY_STATUS_COMPLETED = 'completed'
# to check it every time something database-modifying called
__verification_result = False
def __init__(self, request_data, logger):
if 'ok_verify' in request_data:
raise Exception("ok_verify must not be present in initial request data for {}".format(
self.__class__.__name__
))
self._request_data = request_data
self.logger = logger
return
def allow_test_requests(self):
return settings.DEBUG
def verify_ipn(self):
self.__verification_result = False
headers = {
'Content-Type': 'application/x-www-form-urlencoded',
}
verify_request_payload = {
'ok_verify': 'true',
}
verify_request_payload.update(self._request_data)
resp = requests.post(self.OKPAY_VERIFICATION_URL, data=verify_request_payload, headers=headers)
msg = 'resp is {} for verification of request {}'.format(
resp.content, verify_request_payload
)
self.logger.info(msg)
# if resp.content == self.OKPAY_IPN_VERIFIED or (resp.content == self.OKPAY_IPN_TEST and self.allow_test_requests()): # NOQA
# if resp.content == self.OKPAY_IPN_VERIFIED or resp.content == self.OKPAY_IPN_TEST:
if resp.content == self.OKPAY_IPN_VERIFIED: # anyway disable test on production.
self.__verification_result = True
return self.__verification_result
def enroll(self):
if not self.__verification_result:
raise Exception("Trying to enroll while verifications is failed or ommited!")
# check status: https://dev.okpay.com/en/manual/ipn/variables.html#ok_txn_status
if self._request_data['ok_txn_status'] != self.OKPAY_STATUS_COMPLETED:
self.logger.error("Status {} != completed".format(self._request_data['ok_txn_status']))
return False
if self._request_data['ok_txn_currency'] != "USD":
# Remove it if you need to.
self.logger.error("Currency {} != USD".format(self._request_data['ok_txn_currency']))
return False
return self._do_enroll()
@transaction.atomic
def _do_enroll(self):
# here you can do whatever you want with self._request_data, it's validated.
# don't forget to check ok_ipn_test, don't forget about multiple fields with money amount (gross, tax, etc),
# and about ok_txn_status - now everything except completed is ignored, but you may implement refund/freeze/etc.
raise NotImplementedError('Please subclass OkpayProcessor and implement _do_enroll')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment