mvola-api-lib 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mvola_api_lib-1.0.0/.cursor/rules/lib-mvola-best-practices.mdc +13 -0
- mvola_api_lib-1.0.0/.gitignore +103 -0
- mvola_api_lib-1.0.0/LICENSE +21 -0
- mvola_api_lib-1.0.0/PKG-INFO +205 -0
- mvola_api_lib-1.0.0/README.md +143 -0
- mvola_api_lib-1.0.0/api-mvola/__init__.py +24 -0
- mvola_api_lib-1.0.0/api-mvola/auth.py +117 -0
- mvola_api_lib-1.0.0/api-mvola/client.py +194 -0
- mvola_api_lib-1.0.0/api-mvola/constants.py +26 -0
- mvola_api_lib-1.0.0/api-mvola/exceptions.py +42 -0
- mvola_api_lib-1.0.0/api-mvola/transaction.py +408 -0
- mvola_api_lib-1.0.0/api-mvola/utils.py +117 -0
- mvola_api_lib-1.0.0/docs/api-reference/auth.md +121 -0
- mvola_api_lib-1.0.0/docs/api-reference/client.md +121 -0
- mvola_api_lib-1.0.0/docs/api-reference/exceptions.md +250 -0
- mvola_api_lib-1.0.0/docs/api-reference/transaction.md +233 -0
- mvola_api_lib-1.0.0/docs/api-reference/utils.md +216 -0
- mvola_api_lib-1.0.0/docs/changelog.md +31 -0
- mvola_api_lib-1.0.0/docs/contributing.md +141 -0
- mvola_api_lib-1.0.0/docs/examples/basic-usage.md +213 -0
- mvola_api_lib-1.0.0/docs/examples/web-integration.md +613 -0
- mvola_api_lib-1.0.0/docs/examples/webhook-handling.md +524 -0
- mvola_api_lib-1.0.0/docs/explanation/architecture.md +118 -0
- mvola_api_lib-1.0.0/docs/guides/authentication.md +155 -0
- mvola_api_lib-1.0.0/docs/guides/error-handling.md +605 -0
- mvola_api_lib-1.0.0/docs/guides/installation.md +64 -0
- mvola_api_lib-1.0.0/docs/guides/transactions.md +203 -0
- mvola_api_lib-1.0.0/docs/index.md +77 -0
- mvola_api_lib-1.0.0/examples/.env.example +14 -0
- mvola_api_lib-1.0.0/examples/payment_web_app.py +473 -0
- mvola_api_lib-1.0.0/examples/simple_payment.py +122 -0
- mvola_api_lib-1.0.0/examples/webhook_handler.py +122 -0
- mvola_api_lib-1.0.0/mkdocs.yml +73 -0
- mvola_api_lib-1.0.0/mvola_api/__init__.py +24 -0
- mvola_api_lib-1.0.0/mvola_api/auth.py +117 -0
- mvola_api_lib-1.0.0/mvola_api/client.py +194 -0
- mvola_api_lib-1.0.0/mvola_api/constants.py +26 -0
- mvola_api_lib-1.0.0/mvola_api/exceptions.py +42 -0
- mvola_api_lib-1.0.0/mvola_api/transaction.py +408 -0
- mvola_api_lib-1.0.0/mvola_api/utils.py +117 -0
- mvola_api_lib-1.0.0/pyproject.toml +72 -0
- mvola_api_lib-1.0.0/requirements.txt +6 -0
- mvola_api_lib-1.0.0/setup.py +61 -0
- mvola_api_lib-1.0.0/tests/test_mvola_api.py +253 -0
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
---
|
|
2
|
+
description:
|
|
3
|
+
globs:
|
|
4
|
+
alwaysApply: true
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Best practices for creating the Mvola library payment solution in Python globs
|
|
8
|
+
|
|
9
|
+
- Use the official Mvola SDK for secure and reliable integration
|
|
10
|
+
- Implement proper error handling and logging for payment transactions
|
|
11
|
+
- Ensure compliance with Mvola's security guidelines and regulations
|
|
12
|
+
- Regularly update the Mvola library to benefit from the latest features and security patches
|
|
13
|
+
- Test payment flows thoroughly in a sandbox environment before going live
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
*.so
|
|
6
|
+
.Python
|
|
7
|
+
build/
|
|
8
|
+
develop-eggs/
|
|
9
|
+
dist/
|
|
10
|
+
downloads/
|
|
11
|
+
eggs/
|
|
12
|
+
.eggs/
|
|
13
|
+
lib/
|
|
14
|
+
lib64/
|
|
15
|
+
parts/
|
|
16
|
+
sdist/
|
|
17
|
+
var/
|
|
18
|
+
wheels/
|
|
19
|
+
*.egg-info/
|
|
20
|
+
.installed.cfg
|
|
21
|
+
*.egg
|
|
22
|
+
MANIFEST
|
|
23
|
+
|
|
24
|
+
# Environnements virtuels
|
|
25
|
+
venv/
|
|
26
|
+
ENV/
|
|
27
|
+
env/
|
|
28
|
+
.venv/
|
|
29
|
+
.env/
|
|
30
|
+
env.bak/
|
|
31
|
+
venv.bak/
|
|
32
|
+
|
|
33
|
+
# Documentation MkDocs
|
|
34
|
+
site/
|
|
35
|
+
|
|
36
|
+
# Distribution / packaging
|
|
37
|
+
.Python
|
|
38
|
+
env/
|
|
39
|
+
build/
|
|
40
|
+
develop-eggs/
|
|
41
|
+
dist/
|
|
42
|
+
downloads/
|
|
43
|
+
eggs/
|
|
44
|
+
.eggs/
|
|
45
|
+
lib/
|
|
46
|
+
lib64/
|
|
47
|
+
parts/
|
|
48
|
+
sdist/
|
|
49
|
+
var/
|
|
50
|
+
wheels/
|
|
51
|
+
*.egg-info/
|
|
52
|
+
.installed.cfg
|
|
53
|
+
*.egg
|
|
54
|
+
|
|
55
|
+
# Tests unitaires / couverture
|
|
56
|
+
htmlcov/
|
|
57
|
+
.tox/
|
|
58
|
+
.coverage
|
|
59
|
+
.coverage.*
|
|
60
|
+
.cache
|
|
61
|
+
nosetests.xml
|
|
62
|
+
coverage.xml
|
|
63
|
+
*.cover
|
|
64
|
+
.hypothesis/
|
|
65
|
+
.pytest_cache/
|
|
66
|
+
|
|
67
|
+
# Jupyter Notebook
|
|
68
|
+
.ipynb_checkpoints
|
|
69
|
+
|
|
70
|
+
# Logs
|
|
71
|
+
logs/
|
|
72
|
+
*.log
|
|
73
|
+
npm-debug.log*
|
|
74
|
+
yarn-debug.log*
|
|
75
|
+
yarn-error.log*
|
|
76
|
+
|
|
77
|
+
# Fichiers d'environnement
|
|
78
|
+
.env
|
|
79
|
+
.env.test
|
|
80
|
+
.env.local
|
|
81
|
+
|
|
82
|
+
# Fichiers IDE
|
|
83
|
+
# VS Code
|
|
84
|
+
.vscode/
|
|
85
|
+
.history/
|
|
86
|
+
*.code-workspace
|
|
87
|
+
|
|
88
|
+
# PyCharm
|
|
89
|
+
.idea/
|
|
90
|
+
*.iml
|
|
91
|
+
*.iws
|
|
92
|
+
*.ipr
|
|
93
|
+
*.iws
|
|
94
|
+
.idea_modules/
|
|
95
|
+
|
|
96
|
+
# Fichiers système
|
|
97
|
+
.DS_Store
|
|
98
|
+
Thumbs.db
|
|
99
|
+
*.swp
|
|
100
|
+
*~
|
|
101
|
+
._*
|
|
102
|
+
.Spotlight-V100
|
|
103
|
+
.Trashes
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Niainarisoa
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mvola-api-lib
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Une bibliothèque Python robuste pour l'intégration de l'API de paiement MVola
|
|
5
|
+
Project-URL: Homepage, https://github.com/Niainarisoa01/Mvlola_API_Lib
|
|
6
|
+
Project-URL: Bug Tracker, https://github.com/Niainarisoa01/Mvlola_API_Lib/issues
|
|
7
|
+
Project-URL: Documentation, https://niainarisoa01.github.io/Mvlola_API_Lib
|
|
8
|
+
Author-email: Niainarisoa <niainarisoa.mail@gmail.com>
|
|
9
|
+
License: MIT License
|
|
10
|
+
|
|
11
|
+
Copyright (c) 2025 Niainarisoa
|
|
12
|
+
|
|
13
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
14
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
15
|
+
in the Software without restriction, including without limitation the rights
|
|
16
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
17
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
18
|
+
furnished to do so, subject to the following conditions:
|
|
19
|
+
|
|
20
|
+
The above copyright notice and this permission notice shall be included in all
|
|
21
|
+
copies or substantial portions of the Software.
|
|
22
|
+
|
|
23
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
24
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
25
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
26
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
27
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
28
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
29
|
+
SOFTWARE.
|
|
30
|
+
License-File: LICENSE
|
|
31
|
+
Keywords: api,fintech,madagascar,mvola,payment
|
|
32
|
+
Classifier: Development Status :: 4 - Beta
|
|
33
|
+
Classifier: Intended Audience :: Developers
|
|
34
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
35
|
+
Classifier: Programming Language :: Python :: 3
|
|
36
|
+
Classifier: Programming Language :: Python :: 3.7
|
|
37
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
38
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
39
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
40
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
41
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
42
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
43
|
+
Classifier: Topic :: Office/Business :: Financial
|
|
44
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
45
|
+
Requires-Python: >=3.7
|
|
46
|
+
Requires-Dist: python-dotenv>=0.19.0
|
|
47
|
+
Requires-Dist: requests>=2.25.0
|
|
48
|
+
Provides-Extra: dev
|
|
49
|
+
Requires-Dist: black>=21.5b2; extra == 'dev'
|
|
50
|
+
Requires-Dist: flake8>=3.9.2; extra == 'dev'
|
|
51
|
+
Requires-Dist: isort>=5.9.1; extra == 'dev'
|
|
52
|
+
Requires-Dist: pytest-cov>=2.12.0; extra == 'dev'
|
|
53
|
+
Requires-Dist: pytest>=6.0; extra == 'dev'
|
|
54
|
+
Provides-Extra: docs
|
|
55
|
+
Requires-Dist: mkdocs-material>=8.2.8; extra == 'docs'
|
|
56
|
+
Requires-Dist: mkdocs>=1.3.0; extra == 'docs'
|
|
57
|
+
Requires-Dist: mkdocstrings-python>=0.7.1; extra == 'docs'
|
|
58
|
+
Requires-Dist: mkdocstrings>=0.18.0; extra == 'docs'
|
|
59
|
+
Provides-Extra: examples
|
|
60
|
+
Requires-Dist: flask>=2.0.0; extra == 'examples'
|
|
61
|
+
Description-Content-Type: text/markdown
|
|
62
|
+
|
|
63
|
+
# MVola API Python Library
|
|
64
|
+
|
|
65
|
+
A robust Python library for integrating with MVola mobile payment API in Madagascar.
|
|
66
|
+
|
|
67
|
+
## Installation
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
pip install mvola_api
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Features
|
|
74
|
+
|
|
75
|
+
- Simple and intuitive API for MVola payment integration
|
|
76
|
+
- Handles authentication token generation and management
|
|
77
|
+
- Supports merchant payment operations
|
|
78
|
+
- Comprehensive error handling
|
|
79
|
+
- Logging support
|
|
80
|
+
- Built-in parameter validation
|
|
81
|
+
- Works with both sandbox and production environments
|
|
82
|
+
|
|
83
|
+
## Quick Start
|
|
84
|
+
|
|
85
|
+
```python
|
|
86
|
+
from mvola_api import MVolaClient, SANDBOX_URL
|
|
87
|
+
|
|
88
|
+
# Initialize the client
|
|
89
|
+
client = MVolaClient(
|
|
90
|
+
consumer_key="your_consumer_key",
|
|
91
|
+
consumer_secret="your_consumer_secret",
|
|
92
|
+
partner_name="Your Application Name",
|
|
93
|
+
partner_msisdn="0340000000", # Your merchant number
|
|
94
|
+
sandbox=True # Use sandbox environment
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
# Generate a token
|
|
98
|
+
token_data = client.generate_token()
|
|
99
|
+
print(f"Token generated: {token_data['access_token'][:10]}...")
|
|
100
|
+
|
|
101
|
+
# Initiate a payment
|
|
102
|
+
result = client.initiate_payment(
|
|
103
|
+
amount=10000,
|
|
104
|
+
debit_msisdn="0343500003", # Customer phone number
|
|
105
|
+
credit_msisdn="0343500004", # Merchant phone number
|
|
106
|
+
description="Payment for service",
|
|
107
|
+
callback_url="https://example.com/callback"
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
# Track the server correlation ID for status checks
|
|
111
|
+
server_correlation_id = result['response']['serverCorrelationId']
|
|
112
|
+
print(f"Transaction initiated with correlation ID: {server_correlation_id}")
|
|
113
|
+
|
|
114
|
+
# Check transaction status
|
|
115
|
+
status = client.get_transaction_status(server_correlation_id)
|
|
116
|
+
print(f"Transaction status: {status['response']['status']}")
|
|
117
|
+
|
|
118
|
+
# Once transaction is completed, get details using transaction ID
|
|
119
|
+
transaction_id = status['response'].get('objectReference')
|
|
120
|
+
if transaction_id:
|
|
121
|
+
details = client.get_transaction_details(transaction_id)
|
|
122
|
+
print(f"Transaction details: {details['response']}")
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## Sandbox Testing
|
|
126
|
+
|
|
127
|
+
For sandbox testing, use the following test phone numbers:
|
|
128
|
+
- 0343500003
|
|
129
|
+
- 0343500004
|
|
130
|
+
|
|
131
|
+
## Error Handling
|
|
132
|
+
|
|
133
|
+
The library provides custom exceptions for different error types:
|
|
134
|
+
|
|
135
|
+
```python
|
|
136
|
+
from mvola_api import MVolaClient, MVolaError, MVolaAuthError, MVolaTransactionError
|
|
137
|
+
|
|
138
|
+
client = MVolaClient(...)
|
|
139
|
+
|
|
140
|
+
try:
|
|
141
|
+
result = client.initiate_payment(...)
|
|
142
|
+
except MVolaAuthError as e:
|
|
143
|
+
print(f"Authentication error: {e}")
|
|
144
|
+
except MVolaTransactionError as e:
|
|
145
|
+
print(f"Transaction error: {e}")
|
|
146
|
+
except MVolaError as e:
|
|
147
|
+
print(f"General MVola error: {e}")
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## API Documentation
|
|
151
|
+
|
|
152
|
+
### MVolaClient
|
|
153
|
+
|
|
154
|
+
The main client class for interacting with MVola API.
|
|
155
|
+
|
|
156
|
+
#### Initialization
|
|
157
|
+
|
|
158
|
+
```python
|
|
159
|
+
client = MVolaClient(
|
|
160
|
+
consumer_key, # Consumer key from MVola Developer Portal
|
|
161
|
+
consumer_secret, # Consumer secret from MVola Developer Portal
|
|
162
|
+
partner_name, # Your application/merchant name
|
|
163
|
+
partner_msisdn=None, # Partner MSISDN (phone number)
|
|
164
|
+
sandbox=True, # Use sandbox environment
|
|
165
|
+
logger=None # Custom logger
|
|
166
|
+
)
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
#### Methods
|
|
170
|
+
|
|
171
|
+
- `generate_token(force_refresh=False)`: Generate an access token
|
|
172
|
+
- `initiate_payment(amount, debit_msisdn, credit_msisdn, description, ...)`: Initiate a merchant payment
|
|
173
|
+
- `get_transaction_status(server_correlation_id, user_language="FR")`: Get transaction status
|
|
174
|
+
- `get_transaction_details(transaction_id, user_language="FR")`: Get transaction details
|
|
175
|
+
|
|
176
|
+
## Best Practices
|
|
177
|
+
|
|
178
|
+
1. **Token Management**: The library handles token refresh automatically, but you can force a refresh if needed.
|
|
179
|
+
2. **Error Handling**: Always implement proper error handling in your application.
|
|
180
|
+
3. **Logging**: The library includes logging, but you can provide your own logger.
|
|
181
|
+
4. **Sandbox Testing**: Always test your integration in the sandbox environment before going live.
|
|
182
|
+
5. **Webhook Handling**: Implement proper webhook handling for transaction notifications.
|
|
183
|
+
|
|
184
|
+
## Development
|
|
185
|
+
|
|
186
|
+
### Requirements
|
|
187
|
+
|
|
188
|
+
- Python 3.6+
|
|
189
|
+
- requests library
|
|
190
|
+
|
|
191
|
+
### Installation for Development
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
git clone https://github.com/yourusername/mvola_api.git
|
|
195
|
+
cd mvola_api
|
|
196
|
+
pip install -e .
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
## License
|
|
200
|
+
|
|
201
|
+
MIT
|
|
202
|
+
|
|
203
|
+
## Credits
|
|
204
|
+
|
|
205
|
+
Developed based on the official MVola API documentation.
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# MVola API Python Library
|
|
2
|
+
|
|
3
|
+
A robust Python library for integrating with MVola mobile payment API in Madagascar.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install mvola_api
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
- Simple and intuitive API for MVola payment integration
|
|
14
|
+
- Handles authentication token generation and management
|
|
15
|
+
- Supports merchant payment operations
|
|
16
|
+
- Comprehensive error handling
|
|
17
|
+
- Logging support
|
|
18
|
+
- Built-in parameter validation
|
|
19
|
+
- Works with both sandbox and production environments
|
|
20
|
+
|
|
21
|
+
## Quick Start
|
|
22
|
+
|
|
23
|
+
```python
|
|
24
|
+
from mvola_api import MVolaClient, SANDBOX_URL
|
|
25
|
+
|
|
26
|
+
# Initialize the client
|
|
27
|
+
client = MVolaClient(
|
|
28
|
+
consumer_key="your_consumer_key",
|
|
29
|
+
consumer_secret="your_consumer_secret",
|
|
30
|
+
partner_name="Your Application Name",
|
|
31
|
+
partner_msisdn="0340000000", # Your merchant number
|
|
32
|
+
sandbox=True # Use sandbox environment
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
# Generate a token
|
|
36
|
+
token_data = client.generate_token()
|
|
37
|
+
print(f"Token generated: {token_data['access_token'][:10]}...")
|
|
38
|
+
|
|
39
|
+
# Initiate a payment
|
|
40
|
+
result = client.initiate_payment(
|
|
41
|
+
amount=10000,
|
|
42
|
+
debit_msisdn="0343500003", # Customer phone number
|
|
43
|
+
credit_msisdn="0343500004", # Merchant phone number
|
|
44
|
+
description="Payment for service",
|
|
45
|
+
callback_url="https://example.com/callback"
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
# Track the server correlation ID for status checks
|
|
49
|
+
server_correlation_id = result['response']['serverCorrelationId']
|
|
50
|
+
print(f"Transaction initiated with correlation ID: {server_correlation_id}")
|
|
51
|
+
|
|
52
|
+
# Check transaction status
|
|
53
|
+
status = client.get_transaction_status(server_correlation_id)
|
|
54
|
+
print(f"Transaction status: {status['response']['status']}")
|
|
55
|
+
|
|
56
|
+
# Once transaction is completed, get details using transaction ID
|
|
57
|
+
transaction_id = status['response'].get('objectReference')
|
|
58
|
+
if transaction_id:
|
|
59
|
+
details = client.get_transaction_details(transaction_id)
|
|
60
|
+
print(f"Transaction details: {details['response']}")
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Sandbox Testing
|
|
64
|
+
|
|
65
|
+
For sandbox testing, use the following test phone numbers:
|
|
66
|
+
- 0343500003
|
|
67
|
+
- 0343500004
|
|
68
|
+
|
|
69
|
+
## Error Handling
|
|
70
|
+
|
|
71
|
+
The library provides custom exceptions for different error types:
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
from mvola_api import MVolaClient, MVolaError, MVolaAuthError, MVolaTransactionError
|
|
75
|
+
|
|
76
|
+
client = MVolaClient(...)
|
|
77
|
+
|
|
78
|
+
try:
|
|
79
|
+
result = client.initiate_payment(...)
|
|
80
|
+
except MVolaAuthError as e:
|
|
81
|
+
print(f"Authentication error: {e}")
|
|
82
|
+
except MVolaTransactionError as e:
|
|
83
|
+
print(f"Transaction error: {e}")
|
|
84
|
+
except MVolaError as e:
|
|
85
|
+
print(f"General MVola error: {e}")
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## API Documentation
|
|
89
|
+
|
|
90
|
+
### MVolaClient
|
|
91
|
+
|
|
92
|
+
The main client class for interacting with MVola API.
|
|
93
|
+
|
|
94
|
+
#### Initialization
|
|
95
|
+
|
|
96
|
+
```python
|
|
97
|
+
client = MVolaClient(
|
|
98
|
+
consumer_key, # Consumer key from MVola Developer Portal
|
|
99
|
+
consumer_secret, # Consumer secret from MVola Developer Portal
|
|
100
|
+
partner_name, # Your application/merchant name
|
|
101
|
+
partner_msisdn=None, # Partner MSISDN (phone number)
|
|
102
|
+
sandbox=True, # Use sandbox environment
|
|
103
|
+
logger=None # Custom logger
|
|
104
|
+
)
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
#### Methods
|
|
108
|
+
|
|
109
|
+
- `generate_token(force_refresh=False)`: Generate an access token
|
|
110
|
+
- `initiate_payment(amount, debit_msisdn, credit_msisdn, description, ...)`: Initiate a merchant payment
|
|
111
|
+
- `get_transaction_status(server_correlation_id, user_language="FR")`: Get transaction status
|
|
112
|
+
- `get_transaction_details(transaction_id, user_language="FR")`: Get transaction details
|
|
113
|
+
|
|
114
|
+
## Best Practices
|
|
115
|
+
|
|
116
|
+
1. **Token Management**: The library handles token refresh automatically, but you can force a refresh if needed.
|
|
117
|
+
2. **Error Handling**: Always implement proper error handling in your application.
|
|
118
|
+
3. **Logging**: The library includes logging, but you can provide your own logger.
|
|
119
|
+
4. **Sandbox Testing**: Always test your integration in the sandbox environment before going live.
|
|
120
|
+
5. **Webhook Handling**: Implement proper webhook handling for transaction notifications.
|
|
121
|
+
|
|
122
|
+
## Development
|
|
123
|
+
|
|
124
|
+
### Requirements
|
|
125
|
+
|
|
126
|
+
- Python 3.6+
|
|
127
|
+
- requests library
|
|
128
|
+
|
|
129
|
+
### Installation for Development
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
git clone https://github.com/yourusername/mvola_api.git
|
|
133
|
+
cd mvola_api
|
|
134
|
+
pip install -e .
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## License
|
|
138
|
+
|
|
139
|
+
MIT
|
|
140
|
+
|
|
141
|
+
## Credits
|
|
142
|
+
|
|
143
|
+
Developed based on the official MVola API documentation.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"""
|
|
2
|
+
MVola API Python Library
|
|
3
|
+
|
|
4
|
+
A robust Python library for MVola payment integration.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from .auth import MVolaAuth
|
|
8
|
+
from .client import MVolaClient
|
|
9
|
+
from .constants import PRODUCTION_URL, SANDBOX_URL
|
|
10
|
+
from .exceptions import MVolaAuthError, MVolaError, MVolaTransactionError
|
|
11
|
+
from .transaction import MVolaTransaction
|
|
12
|
+
|
|
13
|
+
__version__ = "1.0.0"
|
|
14
|
+
|
|
15
|
+
__all__ = [
|
|
16
|
+
"MVolaClient",
|
|
17
|
+
"MVolaAuth",
|
|
18
|
+
"MVolaTransaction",
|
|
19
|
+
"SANDBOX_URL",
|
|
20
|
+
"PRODUCTION_URL",
|
|
21
|
+
"MVolaError",
|
|
22
|
+
"MVolaAuthError",
|
|
23
|
+
"MVolaTransactionError",
|
|
24
|
+
]
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
"""
|
|
2
|
+
MVola API Authentication Module
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import base64
|
|
6
|
+
import time
|
|
7
|
+
from urllib.parse import urljoin
|
|
8
|
+
|
|
9
|
+
import requests
|
|
10
|
+
|
|
11
|
+
from .constants import GRANT_TYPE, TOKEN_ENDPOINT, TOKEN_SCOPE
|
|
12
|
+
from .exceptions import MVolaAuthError
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class MVolaAuth:
|
|
16
|
+
"""
|
|
17
|
+
Class for managing authentication with MVola API
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
def __init__(self, consumer_key, consumer_secret, base_url):
|
|
21
|
+
"""
|
|
22
|
+
Initialize the auth module
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
consumer_key (str): Consumer key from MVola Developer Portal
|
|
26
|
+
consumer_secret (str): Consumer secret from MVola Developer Portal
|
|
27
|
+
base_url (str): Base URL for the API (sandbox or production)
|
|
28
|
+
"""
|
|
29
|
+
self.consumer_key = consumer_key
|
|
30
|
+
self.consumer_secret = consumer_secret
|
|
31
|
+
self.base_url = base_url
|
|
32
|
+
self.token = None
|
|
33
|
+
self.token_expiry = 0
|
|
34
|
+
|
|
35
|
+
def _encode_credentials(self):
|
|
36
|
+
"""
|
|
37
|
+
Encode consumer key and secret for Basic Auth
|
|
38
|
+
|
|
39
|
+
Returns:
|
|
40
|
+
str: Base64 encoded credentials
|
|
41
|
+
"""
|
|
42
|
+
credentials = f"{self.consumer_key}:{self.consumer_secret}"
|
|
43
|
+
encoded = base64.b64encode(credentials.encode()).decode()
|
|
44
|
+
return encoded
|
|
45
|
+
|
|
46
|
+
def generate_token(self, force_refresh=False):
|
|
47
|
+
"""
|
|
48
|
+
Generate an access token for MVola API
|
|
49
|
+
|
|
50
|
+
Args:
|
|
51
|
+
force_refresh (bool): Force token refresh even if current token is valid
|
|
52
|
+
|
|
53
|
+
Returns:
|
|
54
|
+
dict: Token response with access_token, token_type, expires_in, scope
|
|
55
|
+
|
|
56
|
+
Raises:
|
|
57
|
+
MVolaAuthError: If token generation fails
|
|
58
|
+
"""
|
|
59
|
+
# Check if token is still valid (with 60 seconds buffer)
|
|
60
|
+
current_time = time.time()
|
|
61
|
+
if not force_refresh and self.token and current_time < self.token_expiry - 60:
|
|
62
|
+
return self.token
|
|
63
|
+
|
|
64
|
+
# Set up the request
|
|
65
|
+
url = urljoin(self.base_url, TOKEN_ENDPOINT)
|
|
66
|
+
headers = {
|
|
67
|
+
"Authorization": f"Basic {self._encode_credentials()}",
|
|
68
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
69
|
+
"Cache-Control": "no-cache",
|
|
70
|
+
}
|
|
71
|
+
data = {"grant_type": GRANT_TYPE, "scope": TOKEN_SCOPE}
|
|
72
|
+
|
|
73
|
+
try:
|
|
74
|
+
response = requests.post(url, headers=headers, data=data)
|
|
75
|
+
response.raise_for_status() # Raise exception for non-200 responses
|
|
76
|
+
|
|
77
|
+
token_data = response.json()
|
|
78
|
+
# Calculate token expiry time
|
|
79
|
+
self.token = token_data
|
|
80
|
+
self.token_expiry = current_time + token_data.get("expires_in", 3600)
|
|
81
|
+
|
|
82
|
+
return token_data
|
|
83
|
+
|
|
84
|
+
except requests.exceptions.RequestException as e:
|
|
85
|
+
error_message = "Failed to generate token"
|
|
86
|
+
|
|
87
|
+
# Try to extract error details if available
|
|
88
|
+
if hasattr(e, "response") and e.response is not None:
|
|
89
|
+
try:
|
|
90
|
+
error_data = e.response.json()
|
|
91
|
+
if "error" in error_data:
|
|
92
|
+
error_message = f"{error_message}: {error_data.get('error_description', error_data['error'])}"
|
|
93
|
+
except (ValueError, KeyError):
|
|
94
|
+
pass
|
|
95
|
+
|
|
96
|
+
raise MVolaAuthError(
|
|
97
|
+
message=error_message,
|
|
98
|
+
code=(
|
|
99
|
+
e.response.status_code
|
|
100
|
+
if hasattr(e, "response") and e.response
|
|
101
|
+
else None
|
|
102
|
+
),
|
|
103
|
+
response=e.response if hasattr(e, "response") else None,
|
|
104
|
+
) from e
|
|
105
|
+
|
|
106
|
+
def get_access_token(self, force_refresh=False):
|
|
107
|
+
"""
|
|
108
|
+
Get current access token or generate a new one
|
|
109
|
+
|
|
110
|
+
Args:
|
|
111
|
+
force_refresh (bool): Force token refresh
|
|
112
|
+
|
|
113
|
+
Returns:
|
|
114
|
+
str: Access token string
|
|
115
|
+
"""
|
|
116
|
+
token_data = self.generate_token(force_refresh)
|
|
117
|
+
return token_data["access_token"]
|