Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implementing Bpay #3

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 72 additions & 5 deletions BeemAfrica/Bpay.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,92 @@
import sys
import requests
import json
from BeemAfrica import secured, get_header

BPAY_BALANCE_URL = 'https://apitopup.beem.africa/v1/credit-balance?app_name={}'
BPAY_BALANCE_URL = "https://apitopup.beem.africa/v1/credit-balance?app_name={}"
BPAY_CHECKOUT_URL = "https://checkout.beem.africa/v1/checkout"
BPAY_WHITELIST_URL = "https://checkout.beem.africa/v1/whitelist/add-to-list"


class Bpay(object):
def __init__(self) -> None:
super().__init__()

@secured
def get_balance(self, app_name='USSD'):
def get_balance(self, app_name="USSD"):
try:
return requests.get(
BPAY_BALANCE_URL.format(app_name),
headers=get_header()
BPAY_BALANCE_URL.format(app_name), headers=get_header()
).json()

except (requests.ConnectionError, requests.ConnectTimeout):
raise ConnectionError(
'Connection to the USSD Get balance API Refused, Please check your internet connections')
"Connection to the USSD Get balance API Refused, Please check your internet connections"
)

@secured
def checkout(
self,
amount: int = None,
reference_number: str = None,
mobile: str = None,
transaction_id: str = None,
sendSource: bool = True,
):
"""
QUERY
Field Type Description
amount string
The amount that the customer has to pay, Decimals not allowed

transaction_id string
Transaction ID to track the payment. Should be UUIDv4. E.g. 96f9cc09-afa0-40cf-928a-d7e2b27b2408

reference_number string
Reference number to track the payment. Should be alphanumeric.The prefix pattern should be added when creating collections & checkout products. Example: SAMPLE-12345

mobile optional string
Mobile Number with country code prefix e.g. 255701000000

sendSource optional boolean
If set to true, response will be a SRC redirect link (recommended if redirect is handled from backend)
If set to false, response will be a redirection with code 302 (recommended if redirect is handled from the front)
"""
params = {
"amount": amount,
"reference_number": reference_number,
"mobile": mobile,
"sendSource": sendSource,
"transaction_id": transaction_id,
}
try:
return requests.get(
BPAY_CHECKOUT_URL, params=params, headers=get_header()
).json()

except (requests.ConnectionError, requests.ConnectTimeout):
raise ConnectionError(
"Connection to the BPay checkout, Please check your internet connections"
)

@secured
def whitelist_website(self, website: str) -> dict:
"""The application / website domain that implements the Checkout library needs to be whitelisted (approved authorized access).
To whitelist a domain, Send a request to the following endpoint with the given parameters:
"""
try:
return requests.post(
BPAY_WHITELIST_URL,
data=json.dumps(
{
"website": website,
}
),
).json()
except (requests.ConnectionError, requests.ConnectTimeout):
raise ConnectionError(
"Connection to the BEEM API Refused, Please check your internet connections"
)


sys.modules[__name__] = Bpay()
67 changes: 47 additions & 20 deletions BeemAfrica/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,27 @@
from dataclasses import dataclass


Tokens = ''
Tokens = ""


@dataclass
class Token(object):
access_key: str = ''
secret_key: str = ''
access_key: str = ""
secret_key: str = ""
beem_secure_token: str = ""


class Authorize(object):
def __init__(self, access_key: str = None, secret_key: str = None):
def __init__(
self,
access_key: str = None,
secret_key: str = None,
beem_secure_token: str = None,
):
if not isinstance(access_key, str) or not isinstance(secret_key, str):
raise TypeError(
'Both access_key and secret key should be of type <str>')
self.token = Token(access_key, secret_key)
globals()['Tokens'] = self.token
raise TypeError("Both access_key and secret key should be of type <str>")
self.token = Token(access_key, secret_key, beem_secure_token)
globals()["Tokens"] = self.token

@property
def access_key(self) -> str:
Expand All @@ -27,10 +32,21 @@ def access_key(self) -> str:
@access_key.setter
def access_key(self, access_key: str):
if not isinstance(access_key, str):
raise TypeError(
f'access_key should of Type <str> not {type(access_key)}')
raise TypeError(f"access_key should of Type <str> not {type(access_key)}")
self.token.access_key = access_key

@property
def beem_secure_token(self) -> str:
return self.token.beem_secure_token

@beem_secure_token.setter
def beem_secure_token(self, beem_secure_token: str):
if not isinstance(beem_secure_token, str):
raise TypeError(
f"beem_secure_token should of Type <str> not {type(beem_secure_token)}"
)
self.token.beem_secure_token = beem_secure_token

@property
def secret_key(self) -> str:
return self.token.secret_key
Expand All @@ -39,33 +55,44 @@ def secret_key(self) -> str:
def secret_key(self, secret_key: str):
if not isinstance(secret_key, str):
raise TypeError(
f'secret_key should be of Type <str> not {type(secret_key)}')
f"secret_key should be of Type <str> not {type(secret_key)}"
)
self.token.secret_key = secret_key


def secured(beem_method):
@wraps(beem_method)
def verify(*args, **kwargs):
_Tokens = globals()['Tokens']
if not isinstance(Tokens, Token) or not (_Tokens.access_key and _Tokens.secret_key):
_Tokens = globals()["Tokens"]
if not isinstance(Tokens, Token) or not (
_Tokens.access_key and _Tokens.secret_key
):
raise ValueError(
f'''
f"""
You need to set the value of access_key and secret_key

do this to setup !!!

>>> from BeemAfrica import Authorize
>>> Authorize(access_key, secret_key)
''')
"""
)
return beem_method(*args, **kwargs)

return verify


def get_header():
token = globals()['Tokens']
token = globals()["Tokens"]
beem_secure_token = token.beem_secure_token
encoded_token = b64encode(
f'{token.access_key}:{token.secret_key}'.encode()).decode()
return {
'Content-Type': 'application/json',
'Authorization': f'Basic {encoded_token}'
f"{token.access_key}:{token.secret_key}".encode()
).decode()

headers = {
"Content-Type": "application/json",
"Authorization": f"Basic {encoded_token}",
}
if beem_secure_token:
headers["beem_secure_token"] = beem_secure_token
return headers
29 changes: 12 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
# [python-client](#)
A Python library to easy the integration with the Beem Africa SMS Gateway

A Python library to easy the integration with the Beem Africa SMS Gateway

[![Downloads](https://pepy.tech/badge/beem-africa)](https://pepy.tech/project/beem-africa)
[![Downloads](https://pepy.tech/badge/beem-africa/month)](https://pepy.tech/project/beem-africa)
[![Downloads](https://pepy.tech/badge/beem-africa/week)](https://pepy.tech/project/beem-africa)

## Features to be Implemented

## Features to be Implemented

- [x] Airtime
- [x] Airtime
- [x] OTP
- [x] SMS
- [x] SMS
- [ ] Two way SMS
- [ ] USSD
- [ ] Bpay

- [x] Bpay

## Getting started

Expand Down Expand Up @@ -61,7 +60,7 @@ The above example is that I'm assuming you're using default BeemAfrica sender ID
```python
>>> SMS.send_sms(
'You\'re now verified',
'255xxxxxxxxx',
'255xxxxxxxxx',
sender_id='new-sender-id'
)

Expand All @@ -72,9 +71,9 @@ You can also schedule message to be sent after a certain time or at a specific t

```python
>>> SMS.send_sms(
'You have won a 10 Million',
'2557xxxxxxxxx',
sender_id='new-sender-d',
'You have won a 10 Million',
'2557xxxxxxxxx',
sender_id='new-sender-d',
schedule_time='scheduled time'
)
{'successful': True, 'request_id': 35918915, 'code': 100, 'message': 'Message Submitted Successfully', 'valid': 1, 'invalid': 0, 'duplicates': 0}
Expand All @@ -100,16 +99,14 @@ Here how to send OTP with Beem !!
```

To verify the OTP send to user do this !!

Note: Use pin_id from response you just recieve while sending an OTP and the PIN sent to user phone to verify the OTP, its going to look like this !!

Note: Use pin_id from response you just recieve while sending an OTP and the PIN sent to user phone to verify the OTP, its going to look like this !!

```python
>>> OTP.verify(pin_id='4a5c2141-c965-4a9d-aca4-54f58063e831', pin='122496')
{'data': {'message': {'code': 117, 'message': 'Valid Pin'}}}
```


## AirTime

BeemAfrica also provide interface to interact with AirTime allowing you to easily transfer AirTime from BeemAfrica Credit to customer mobile !!
Expand All @@ -132,7 +129,6 @@ You can also check balance of remaining credit balance by doing this

Well these are the only implemented features by now !


## Issues

Are you facing any issue with the integration of beem-africa libray, please raise an Issue so as we can fix as soon as we can !!
Expand All @@ -145,7 +141,6 @@ Would you like to contribute to beem-africa python-client, Contributions of any

Was this repository useful to you in any means, well then give it a star so as more people can get to know it.


## Credits

All the credits to [kalebu](https://github.com/kalebu) and all the future contributors
All the credits to [kalebu](https://github.com/kalebu) and all the future contributors
4 changes: 2 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

setup(
name="beem-africa",
version="0.1.0",
version="0.2.0",
description="A Python library to easy the integration with the Beem Africa SMS Gateway",
url="https://github.com/beem-africa/python-client",
download_url="https://github.com/beem-africa/python-client/releases/tag/0.1",
Expand All @@ -19,7 +19,7 @@
"python-tanzania",
],
install_requires=[
'requests',
"requests",
],
include_package_data=True,
python_requires=">=3.6",
Expand Down