diff --git a/README.md b/README.md index bd75f9e..70e9cd6 100644 --- a/README.md +++ b/README.md @@ -59,6 +59,11 @@ Before using the SDK, users must obtain credentials from merchant portal first. * [Get Voucher By Code](#get-voucher-by-code) * [Get Voucher Batches](#get-voucher-batches) * [Get Voucher Batches By Batch Key](#get-voucher-batches-by-batch-key) +* EKYC + * [Mykad Recognition](#mykad-recognition) + * [GET Mykad Result](#get-mykad-result) + * [GET EKYC Result](#get-ekyc-result) + * [Face Verification](#face-verification) ## Usage @@ -370,3 +375,28 @@ result = client.voucher.getVoucherBatchByKey(accessToken, batchKey) Detail examples can be found at [examples](https://github.com/RevenueMonster/RM-API-SDK-Python/tree/master/examples). +## EKYC + +### Mykad Recognition +```python +mykad_payload = { + "notify_url": "https://aifire.com/ekyc/result", + "query_image_content": img_b64.decode('utf-8') +} +results = client.ekyc.mykad_recog(accessToken, mykad_payload) +``` + +### GET Mykad Result +```python +mykad_results = client.ekyc.get_mykad_results(accessToken, get_result_mykad_payload) +``` + +### GET EKYC Result +```python +ekyc_results = client.ekyc.get_ekyc_results(accessToken, ekyc_payload) +``` + +### Face Verification +```python +face_verification_results = client.ekyc.face_verification(accessToken, face_verification_payload) +``` \ No newline at end of file diff --git a/examples/configs.py b/examples/configs.py index 06ce5ad..78e1c49 100644 --- a/examples/configs.py +++ b/examples/configs.py @@ -2,7 +2,7 @@ configs = { "environment": "sandbox", - "clientID": "1546849785427621041", - "clientSecret": "eNdqiTKWjbbJoSIaPEEvzGPBYrXMTWQZ", - "privateKey": "/Users/rexlow/Documents/Work/RevenueMonster/RM-API-SDK-Python/rmsdk/private.pem" + "clientID": "1604635236745642069", + "clientSecret": "TPSTBChxwEduyMdcSAzcxlhZXWNRCEJj", + "privateKey": "/workspace/rm-python-sdk/keys/private_key.pem" } \ No newline at end of file diff --git a/examples/ekyc.py b/examples/ekyc.py new file mode 100644 index 0000000..9b24db3 --- /dev/null +++ b/examples/ekyc.py @@ -0,0 +1,52 @@ +from rmsdk import RMSDK +from configs import configs +from pprint import pprint +import requests +import base64 + +def url_to_b64(img_url: str): + img_byte = requests.get(img_url).content + img_b64 = base64.b64encode(img_byte) + + return img_b64 + +if __name__ == '__main__': + # Init client + client = RMSDK(configs=configs) + accessToken = client.accessToken + + # Recognize mykad + img_url = 'https://buletinonlines.net/v7/wp-content/uploads/2016/06/Mykad-penghuni-puan-Noraini-2.jpg' + mykad_payload = { + "notify_url": "https://aifire.com/ekyc/result", + "query_image_content": url_to_b64(img_url).decode('utf-8') + } + + results = client.ekyc.mykad_recog(accessToken, mykad_payload) + pprint(results) + + # Get mykad results + get_result_mykad_payload = { + 'id': results['item']['requestID'] + } + + mykad_results = client.ekyc.get_mykad_results(accessToken, get_result_mykad_payload) + pprint(mykad_results) + + # Face verification + face_img_url = 'https://media.glamour.com/photos/5a425fd3b6bcee68da9f86f8/master/pass/best-face-oil.png' + img_b64 = url_to_b64(face_img_url) + + face_verification_payload = { + "query_image_content_1": img_b64.decode('utf-8'), + "query_image_content_2": img_b64.decode('utf-8'), + } + face_verification_results = client.ekyc.face_verification(accessToken, face_verification_payload) + pprint(face_verification_results) + + # Get EKYC Results + # ekyc_payload = { + # "id": "62201d48a694817dede84b35" + # } + # ekyc_results = client.ekyc.get_ekyc_results(accessToken, ekyc_payload) + # pprint(ekyc_results) \ No newline at end of file diff --git a/examples/signature.py b/examples/signature.py index 1dd57d5..ecf55ee 100755 --- a/examples/signature.py +++ b/examples/signature.py @@ -36,6 +36,6 @@ requestUrl="https://sb-open.revenuemonster.my/v3/payment/quickpay", signType="sha256", timestamp="1546931187.8109288", - privateKeyDest="/Users/rexlow/Documents/Work/RevenueMonster/RM-API-SDK-Python/rmsdk/private.pem") + privateKeyDest="/workspace/rm-python-sdk/keys/private_key.pem") print(signature) \ No newline at end of file diff --git a/rmsdk/RMSDK.py b/rmsdk/RMSDK.py index 77d9b82..48e5c39 100755 --- a/rmsdk/RMSDK.py +++ b/rmsdk/RMSDK.py @@ -8,7 +8,8 @@ Store, Transaction, User, - Voucher + Voucher, + EKYC ) class RMSDK(object): @@ -28,4 +29,5 @@ def __init__(self, configs={}): self.store = Store(configs) self.transaction = Transaction(configs) self.user = User(configs) - self.voucher = Voucher(configs) \ No newline at end of file + self.voucher = Voucher(configs) + self.ekyc = EKYC(configs) \ No newline at end of file diff --git a/rmsdk/__init__.py b/rmsdk/__init__.py index 4cd0303..0f21f18 100755 --- a/rmsdk/__init__.py +++ b/rmsdk/__init__.py @@ -18,4 +18,5 @@ from .payment import QuickPay, Transaction from .loyalty import Loyalty from .voucher import Voucher +from .ekyc import EKYC from .RMSDK import RMSDK \ No newline at end of file diff --git a/rmsdk/ekyc.py b/rmsdk/ekyc.py new file mode 100644 index 0000000..913f722 --- /dev/null +++ b/rmsdk/ekyc.py @@ -0,0 +1,96 @@ +import json +from .model import RMSDKModel +from .request import Request + +class EKYC(RMSDKModel): + def __init__(self, configs): + super(EKYC, self).__init__(configs) + self.defaults = { + "environment": configs["environment"], + "privateKey": configs["privateKey"], + } + + for (param, default) in self.defaults.items(): + setattr(self, param, configs.get(param, default)) + + self.payload = { + "service": "ekyc", + "version": "v1", + } + + def mykad_recog(self, accessToken: str, data: dict) -> dict: + """ + Function to make http request to get recognize mykad + + args: + accessToken (str): Access Token to allow open api to get user + data (dict): Data to send to open api server + + returns: + dict: dict containing only id for mykad recog result (require to parse the results via different route) + """ + request = Request(environment=self.defaults['environment'], endpoint='v3/service') + self.payload['function'] = 'id-mykad' + self.payload['request'] = data + + headers, data = self.getHeadersAndData(accessToken=accessToken, data=self.payload, requestUrl=request.baseUrl) + response = request.doPost(headers=headers, data=data) + return response + + def face_verification(self, accessToken: str, data: dict) -> dict: + """ + Funtion to get the similarity between two faces + + args: + accessToken (str): Access Token to allow open api to get user + data (dict): Data to send to open api server + + returns: + dict: Results if the two faces are similar or not + """ + request = Request(environment=self.defaults['environment'], endpoint='v3/service') + self.payload['function'] = 'face-compare' + self.payload['request'] = data + + headers, data = self.getHeadersAndData(accessToken=accessToken, data=self.payload, requestUrl=request.baseUrl) + + response = request.doPost(headers=headers, data=data) + return response + + def get_mykad_results(self, accessToken: str, data: dict) -> dict: + """ + Function to get the results from the recognized mykad + + args: + accessToken (str): Access Token to allow open api to get user + data (dict): Data to send to open api server + + returns: + dict: Results containing the recognize mykad + """ + self.payload['function'] = "get-mykad-result" + self.payload['request'] = data + request = Request(environment=self.defaults['environment'], endpoint='v3/service') + headers, data = self.getHeadersAndData(accessToken=accessToken, data=self.payload, requestUrl=request.baseUrl) + + response = request.doPost(headers=headers, data=data) + return response + + def get_ekyc_results(self, accessToken: str, data: dict) -> dict: + """ + Function to get the end to end ekyc results + + args: + accessToken (str): Access Token to allow open api to get user + data (dict): Data to send to open api server + + returns: + dict: Results containing the end to end including face and mykad results + """ + request = Request(environment=self.defaults['environment'], endpoint='v3/service') + self.payload['function'] = "get-ekyc-result" + self.payload['request'] = data + headers, data = self.getHeadersAndData(accessToken=accessToken, data=self.payload, requestUrl=request.baseUrl) + + response = request.doPost(headers=headers, data=data) + return response \ No newline at end of file diff --git a/rmsdk/model.py b/rmsdk/model.py index 93e0638..0f73da1 100755 --- a/rmsdk/model.py +++ b/rmsdk/model.py @@ -108,7 +108,7 @@ def getSignature(self, data, method, nonceStr, requestUrl, timestamp): def getHeadersAndData(self, accessToken, requestUrl, method="post", data=None): nonceStr = getNonce() - timestamp = str(time()) + timestamp = str(int(time())) if data is not None: data = json.dumps(orderDict(data), separators=(',', ':')) diff --git a/tests/test_rmsdk.py b/tests/test_rmsdk.py new file mode 100644 index 0000000..eb584d3 --- /dev/null +++ b/tests/test_rmsdk.py @@ -0,0 +1,48 @@ +import unittest +import base64 +import requests +from rmsdk import RMSDK +from examples.configs import configs + +class TestEKYCSDK(unittest.TestCase): + def setUp(self): + self.client = RMSDK(configs=configs) + self.accessToken = self.client.accessToken + + def to_b64(self, img_url: str): + img_byte = requests.get(img_url).content + img_b64 = base64.b64encode(img_byte) + + return img_b64 + + def test_mykad_recog(self): + img_url = 'https://buletinonlines.net/v7/wp-content/uploads/2016/06/Mykad-penghuni-puan-Noraini-2.jpg' + img_b64 = self.to_b64(img_url) + + mykad_payload = { + "notify_url": "https://aifire.com/ekyc/result", + "query_image_content": img_b64.decode('utf-8') + } + + results = self.client.ekyc.mykad_recog(self.accessToken, mykad_payload) + get_result_mykad_payload = { + 'id': results['item']['requestID'] + } + + mykad_results = self.client.ekyc.get_mykad_results(self.accessToken, get_result_mykad_payload) + self.assertIn('item', mykad_results) + + def test_face_verfication(self): + face_img_url = 'https://media.glamour.com/photos/5a425fd3b6bcee68da9f86f8/master/pass/best-face-oil.png' + img_b64 = self.to_b64(face_img_url) + + face_verification_payload = { + "query_image_content_1": img_b64.decode('utf-8'), + "query_image_content_2": img_b64.decode('utf-8') + } + face_verification_results = self.client.ekyc.face_verification(self.accessToken, face_verification_payload) + self.assertIn('item', face_verification_results) + + self.assertIn('similarity', face_verification_results['item']) + self.assertEqual(face_verification_results['item']['isSamePerson'], True) + \ No newline at end of file