diff --git a/.gitignore b/.gitignore index 0158242..01169db 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,7 @@ test.py kkiapay.egg-info dist -build \ No newline at end of file +build +venv +.idea +__pycache__ \ No newline at end of file diff --git a/kkiapay/core.py b/kkiapay/core.py index 5328d80..4e66262 100644 --- a/kkiapay/core.py +++ b/kkiapay/core.py @@ -1,12 +1,22 @@ import json -import requests from collections import namedtuple +import requests -class Kkiapay: +from kkiapay.exceptions import KKiapayAlogrithmException, KKiapayDestinationTypeException + +class Kkiapay: BASE_URL = "https://api.kkiapay.me" SANDBOX_URL = "https://api-sandbox.kkiapay.me" + ALGORITHMS = {"1": 'rate', "2": 'roof'} + + RATE_FREQUENCIES = {"1": '3d', "2": '1w', "3": '1m'} + default_roof_amount = "50000" + DESTINATION_TYPES = { + "1": 'MOBILE_MONEY', + "2": 'BANK_ACCOUNT', + } def __init__(self, public_key, private_key, secret, sandbox=False): self.secret = secret @@ -53,7 +63,30 @@ def refund_transaction(self, transaction_id): ), ) - def setup_payout(self, options): - self.url += "/merchant/payouts/schedule" - r = requests.post(self.url, data=options, headers=self.headers) - return r.text + def setup_payout(self, algorithm: str, destination: str, destination_type: str, roof_amount: str = None, + send_notification: bool = True, rate_frequency: str = RATE_FREQUENCIES["1"], + country_code: str = "229"): + options = { + "destination": country_code + destination if destination_type == "1" else destination, + "send_notification": 1 if send_notification else 0, + } + + if destination_type in self.DESTINATION_TYPES.keys(): + options["destination_type"] = self.DESTINATION_TYPES[destination_type] + else: + raise KKiapayDestinationTypeException(self.DESTINATION_TYPES) + + if algorithm in self.ALGORITHMS.keys(): + options['algorithm'] = self.ALGORITHMS[algorithm] + else: + raise KKiapayAlogrithmException(self.ALGORITHMS) + if algorithm == "2": + options["roof_amount"] = roof_amount if roof_amount is not None else self.default_roof_amount + else: + options["rate_frequency"] = rate_frequency if rate_frequency in self.RATE_FREQUENCIES.values() else \ + self.RATE_FREQUENCIES["1"] + r = requests.post(self.url + '/merchant/payouts/schedule', data=options, headers=self.headers) + return { + 'response': r.json(), + 'status_code': r.status_code + } diff --git a/kkiapay/exceptions.py b/kkiapay/exceptions.py index 5ad9825..2ecba4f 100644 --- a/kkiapay/exceptions.py +++ b/kkiapay/exceptions.py @@ -1,2 +1,16 @@ class KkiapayException(Exception): pass + + +class KKiapayAlogrithmException(Exception): + def __init__(self, algorithms): + Exception.__init__(self, + "algorithm must be {}".format( + " or ".join(" if it's ".join(algorithm) for algorithm in algorithms.items()))) + + +class KKiapayDestinationTypeException(Exception): + def __init__(self, algorithms): + Exception.__init__(self, + "destination_type must be {}".format( + " or ".join(" if it's ".join(algorithm) for algorithm in algorithms.items()))) diff --git a/readme.md b/readme.md index 7903e0e..56fe06a 100644 --- a/readme.md +++ b/readme.md @@ -59,10 +59,57 @@ Here's the plan for what's coming: - [x] Sandbox and Live environments - [x] Verify Transaction - [x] Refund Transaction - `Only available on Live` -- [ ] Schedule Payout +- [x] Schedule Payout - [ ] Add better errors and exceptions handling - [ ] Add tests. + +## Schedule Payout + +### Example +Below is an example of the function usage: +```python +# Setup Scheduled Payout using 'ROOF' algorithm +schedule_payout = k.setup_payout(algorithm = '2', + roof_amount = '10000', + destination = '61000000', + destination_type = '1', + send_notification = True, + country_code = '229' + ) + +print(schedule_payout) +#{ +# 'response': +# { +# 'merchant': '5d34445784deb700073a0281', +# 'meta_data': '', +# 'algorithm': 'roof', +# 'rate_frequency': '', +# 'roof_amount': '10000', +# 'active': True, +# 'send_notification': True, +# 'destination_type': 'MOBILE_MONEY', +# 'destination': '22961000000', +# 'job_name': '', +# 'account': '5d34445784deb700073a0282' +# }, +# 'status_code': 200 +#} +``` + +### Attribute Matrix +| Name | Required | Possible Values | Description | +|:-----------------:|:--------:|:------------------------------------------:|:---------------------------------------------------------------------------------:| +| **algorithm** | **M** | {"1": 'rate', "2": 'roof'} | Specify the algorithm to be used. | +| **destination_type** | **M** | {"1": 'MOBILE_MONEY', "2": 'BANK_ACCOUNT'} | Specify the Destination type | +| **destination** | **M** | '61000000' | Specify the Destination number/account Number | +| **rate_frequency** | M/O | {"1": '3d', "2": '1w', "3": '1m'} | Specify the Rate Frequency. Required in case 'rate' algorithm is used | +| **roof_amount** | M/O | '10000' | Specify the Roof amount. | +| **send_notification** | O | Boolean (True, False) | Specify is a Notification should be sent | +| **country_code** | O | '229' | Specify the Country Code of the destination number is case 'MOBILE MONEY' is used | + + ## Contributing Check our [contribution guide](CONTRIBUTING.md). diff --git a/tests/test_kkiapay.py b/tests/test_kkiapay.py index 2ec1bc0..137e9ba 100644 --- a/tests/test_kkiapay.py +++ b/tests/test_kkiapay.py @@ -14,12 +14,55 @@ def teardown_module(module): class TestKkiapay(object): - def test_urls(self): - live = Kkiapay("public_key", "private_key", "secret") - sandbox = Kkiapay("public_key", "private_key", "secret", sandbox=True) + live = Kkiapay("public_key", "private_key", "secret") + sandbox = Kkiapay("public_key", "private_key", "secret", sandbox=True) - assert live.url == Kkiapay.BASE_URL - assert sandbox.url == Kkiapay.SANDBOX_URL + def test_urls(self): + assert self.live.url == Kkiapay.BASE_URL + assert self.sandbox.url == Kkiapay.SANDBOX_URL def test_requests(self, requests_mock): pass + + def test_setup_payout(self, monkeypatch): + results = { + 'response': { + 'merchant': '5d34445784deb700073a0281', + 'meta_data': '', + 'algorithm': 'roof', + 'rate_frequency': '', + 'roof_amount': '50000', + 'active': True, + 'send_notification': True, + 'destination_type': 'MOBILE_MONEY', + 'destination': '22961000000', + 'job_name': '', + 'account': '5d34445784deb700073a0282' + }, + 'status_code': 200} + + class MockJsonResponse: + status_code = 200 + + @staticmethod + def json(): + return { + 'merchant': '5d34445784deb700073a0281', + 'meta_data': '', + 'algorithm': 'roof', + 'rate_frequency': '', + 'roof_amount': '50000', + 'active': True, + 'send_notification': True, + 'destination_type': 'MOBILE_MONEY', + 'destination': '22961000000', + 'job_name': '', + 'account': '5d34445784deb700073a0282' + } + + def kkiapay_api_mock_return(*args, **kwargs): + return MockJsonResponse() + + monkeypatch.setattr(requests, 'post', kkiapay_api_mock_return) + assert self.sandbox.setup_payout(algorithm="2", destination="61000000", destination_type="1") == results + assert self.live.setup_payout(algorithm="1", destination="61000000", destination_type="1") == results