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.
Files changed (44) hide show
  1. mvola_api_lib-1.0.0/.cursor/rules/lib-mvola-best-practices.mdc +13 -0
  2. mvola_api_lib-1.0.0/.gitignore +103 -0
  3. mvola_api_lib-1.0.0/LICENSE +21 -0
  4. mvola_api_lib-1.0.0/PKG-INFO +205 -0
  5. mvola_api_lib-1.0.0/README.md +143 -0
  6. mvola_api_lib-1.0.0/api-mvola/__init__.py +24 -0
  7. mvola_api_lib-1.0.0/api-mvola/auth.py +117 -0
  8. mvola_api_lib-1.0.0/api-mvola/client.py +194 -0
  9. mvola_api_lib-1.0.0/api-mvola/constants.py +26 -0
  10. mvola_api_lib-1.0.0/api-mvola/exceptions.py +42 -0
  11. mvola_api_lib-1.0.0/api-mvola/transaction.py +408 -0
  12. mvola_api_lib-1.0.0/api-mvola/utils.py +117 -0
  13. mvola_api_lib-1.0.0/docs/api-reference/auth.md +121 -0
  14. mvola_api_lib-1.0.0/docs/api-reference/client.md +121 -0
  15. mvola_api_lib-1.0.0/docs/api-reference/exceptions.md +250 -0
  16. mvola_api_lib-1.0.0/docs/api-reference/transaction.md +233 -0
  17. mvola_api_lib-1.0.0/docs/api-reference/utils.md +216 -0
  18. mvola_api_lib-1.0.0/docs/changelog.md +31 -0
  19. mvola_api_lib-1.0.0/docs/contributing.md +141 -0
  20. mvola_api_lib-1.0.0/docs/examples/basic-usage.md +213 -0
  21. mvola_api_lib-1.0.0/docs/examples/web-integration.md +613 -0
  22. mvola_api_lib-1.0.0/docs/examples/webhook-handling.md +524 -0
  23. mvola_api_lib-1.0.0/docs/explanation/architecture.md +118 -0
  24. mvola_api_lib-1.0.0/docs/guides/authentication.md +155 -0
  25. mvola_api_lib-1.0.0/docs/guides/error-handling.md +605 -0
  26. mvola_api_lib-1.0.0/docs/guides/installation.md +64 -0
  27. mvola_api_lib-1.0.0/docs/guides/transactions.md +203 -0
  28. mvola_api_lib-1.0.0/docs/index.md +77 -0
  29. mvola_api_lib-1.0.0/examples/.env.example +14 -0
  30. mvola_api_lib-1.0.0/examples/payment_web_app.py +473 -0
  31. mvola_api_lib-1.0.0/examples/simple_payment.py +122 -0
  32. mvola_api_lib-1.0.0/examples/webhook_handler.py +122 -0
  33. mvola_api_lib-1.0.0/mkdocs.yml +73 -0
  34. mvola_api_lib-1.0.0/mvola_api/__init__.py +24 -0
  35. mvola_api_lib-1.0.0/mvola_api/auth.py +117 -0
  36. mvola_api_lib-1.0.0/mvola_api/client.py +194 -0
  37. mvola_api_lib-1.0.0/mvola_api/constants.py +26 -0
  38. mvola_api_lib-1.0.0/mvola_api/exceptions.py +42 -0
  39. mvola_api_lib-1.0.0/mvola_api/transaction.py +408 -0
  40. mvola_api_lib-1.0.0/mvola_api/utils.py +117 -0
  41. mvola_api_lib-1.0.0/pyproject.toml +72 -0
  42. mvola_api_lib-1.0.0/requirements.txt +6 -0
  43. mvola_api_lib-1.0.0/setup.py +61 -0
  44. 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"]