solidgate-sdk 0.3.2__py3-none-any.whl

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.
solidgate/__init__.py ADDED
@@ -0,0 +1,2 @@
1
+ from .api_client import ApiClient
2
+ from .api_client import MerchantData
@@ -0,0 +1,129 @@
1
+ import base64
2
+ import hashlib
3
+ import hmac
4
+ import json
5
+ from datetime import datetime
6
+ from typing import Generator
7
+
8
+ import requests
9
+
10
+ from solidgate.encryption import AESCipher
11
+ from solidgate.model import MerchantData
12
+
13
+
14
+ class ApiClient:
15
+ BASE_SOLID_GATE_API_URI = 'https://pay.solidgate.com/api/v1/'
16
+ BASE_RECONCILIATION_API_URI = 'https://reports.solidgate.com/'
17
+
18
+ RECONCILIATION_ORDERS_PATH = 'api/v2/reconciliation/orders'
19
+ RECONCILIATION_CHARGEBACKS_PATH = 'api/v2/reconciliation/chargebacks'
20
+
21
+ RECONCILIATION_DATETIME_FORMAT = '%Y-%m-%d %H:%M:%S'
22
+
23
+ def __init__(self, merchant_id: str,
24
+ private_key: str,
25
+ base_solid_gate_api_uri: str = BASE_SOLID_GATE_API_URI,
26
+ base_reconciliations_api_uri: str = BASE_RECONCILIATION_API_URI):
27
+ self.__merchant_id = merchant_id
28
+ self.__private_key = private_key
29
+ self.__base_solid_gate_api_uri = base_solid_gate_api_uri
30
+ self.__base_reconciliations_api_uri = base_reconciliations_api_uri
31
+
32
+ def charge(self, attributes: dict) -> requests.models.Response:
33
+ return self.__send_solidgate_request('charge', attributes)
34
+
35
+ def recurring(self, attributes: dict) -> requests.models.Response:
36
+ return self.__send_solidgate_request('recurring', attributes)
37
+
38
+ def resign(self, attributes: dict) -> requests.models.Response:
39
+ return self.__send_solidgate_request('resign', attributes)
40
+
41
+ def status(self, attributes: dict) -> requests.models.Response:
42
+ return self.__send_solidgate_request('status', attributes)
43
+
44
+ def refund(self, attributes: dict) -> requests.models.Response:
45
+ return self.__send_solidgate_request('refund', attributes)
46
+
47
+ def auth(self, attributes: dict) -> requests.models.Response:
48
+ return self.__send_solidgate_request('auth', attributes)
49
+
50
+ def void(self, attributes: dict) -> requests.models.Response:
51
+ return self.__send_solidgate_request('void', attributes)
52
+
53
+ def settle(self, attributes: dict) -> requests.models.Response:
54
+ return self.__send_solidgate_request('settle', attributes)
55
+
56
+ def arn_code(self, attributes: dict) -> requests.models.Response:
57
+ return self.__send_solidgate_request('arn-code', attributes)
58
+
59
+ def apple_pay(self, attributes: dict) -> requests.models.Response:
60
+ return self.__send_solidgate_request('apple-pay', attributes)
61
+
62
+ def google_pay(self, attributes: dict) -> requests.models.Response:
63
+ return self.__send_solidgate_request('google-pay', attributes)
64
+
65
+ def form_merchant_data(self, attributes: dict) -> FormInitDTO:
66
+ payment_intent = AESCipher(self.__private_key).encrypt(self.__convert_request_attributes_to_str(attributes))
67
+ signature = self.__generate_signature(payment_intent)
68
+ form_init_dto = FormInitDTO(payment_intent=payment_intent, publicKey=self.__merchant_id, signature=signature)
69
+ return form_init_dto
70
+
71
+ def form_update(self, attributes: dict) -> FormUpdateDTO:
72
+ partial_intent = AESCipher(self.__private_key).encrypt(self.__convert_request_attributes_to_str(attributes))
73
+ signature = self.__generate_signature(partial_intent)
74
+ form_update_dto = FormUpdateDTO(partial_intent=partial_intent, signature=signature)
75
+ return form_update_dto
76
+
77
+ def form_resign(self, attributes: dict) -> FormInitDTO:
78
+ resign_intent = AESCipher(self.__private_key).encrypt(self.__convert_request_attributes_to_str(attributes))
79
+ signature = self.__generate_signature(resign_intent)
80
+ form_resign_dto = FormResignDTO(resign_intent=resign_intent, publicKey=self.__merchant_id, signature=signature)
81
+ return form_resign_dto
82
+
83
+ def order_reconciliation(self, date_from: datetime, date_to: datetime) -> Generator:
84
+ return self.__send_reconciliation_request(self.RECONCILIATION_ORDERS_PATH, date_from, date_to)
85
+
86
+ def chargeback_reconciliation(self, date_from: datetime, date_to: datetime) -> Generator:
87
+ return self.__send_reconciliation_request(self.RECONCILIATION_CHARGEBACKS_PATH, date_from, date_to)
88
+
89
+ def __generate_signature(self, data: str) -> str:
90
+ encrypto_data = (self.__merchant_id + data + self.__merchant_id).encode('utf-8')
91
+ sign = hmac.new(self.__private_key.encode('utf-8'), encrypto_data, hashlib.sha512).hexdigest()
92
+ return base64.b64encode(sign.encode('utf-8')).decode('utf-8')
93
+
94
+ def __send_solidgate_request(self, method: str, attributes: dict) -> requests.models.Response:
95
+ full_url = self.__base_solid_gate_api_uri + method
96
+ return self.__send_request(full_url, attributes)
97
+
98
+ def __send_reconciliation_request(self, path: str, date_from: datetime, date_to: datetime) -> Generator:
99
+ full_url = self.__base_reconciliations_api_uri + path
100
+ attributes = {'date_from': date_from.strftime(self.RECONCILIATION_DATETIME_FORMAT),
101
+ 'date_to': date_to.strftime(self.RECONCILIATION_DATETIME_FORMAT)}
102
+ while True:
103
+ try:
104
+ response = self.__send_request(full_url, attributes)
105
+ except requests.exceptions.RequestException as err:
106
+ raise Exception("Exception during request:", err)
107
+
108
+ if 200 <= response.status_code < 300:
109
+ response_content = json.loads(response.content)
110
+ for order in response_content['orders']:
111
+ yield order
112
+
113
+ attributes['next_page_iterator'] = response_content['metadata']['next_page_iterator']
114
+ if not attributes['next_page_iterator']:
115
+ break
116
+ else:
117
+ raise Exception('Request is not successful!')
118
+
119
+ def __send_request(self, path: str, attributes: dict) -> requests.models.Response:
120
+ body = self.__convert_request_attributes_to_str(attributes)
121
+ headers = {'Content-Type': 'application/json',
122
+ 'Accept': 'application/json',
123
+ 'Merchant': self.__merchant_id,
124
+ 'Signature': self.__generate_signature(body)}
125
+ return requests.post(path, headers=headers, json=attributes)
126
+
127
+ @staticmethod
128
+ def __convert_request_attributes_to_str(attributes: dict) -> str:
129
+ return json.dumps(attributes)
@@ -0,0 +1,19 @@
1
+ import base64
2
+
3
+ from Crypto import Random
4
+ from Crypto.Cipher import AES
5
+ from Crypto.Util.Padding import pad
6
+
7
+
8
+ class AESCipher:
9
+ MAX_KEY_LEN = 32
10
+
11
+ def __init__(self, key):
12
+ self.__block_size = AES.block_size
13
+ self.__key = key[:self.MAX_KEY_LEN].encode()
14
+
15
+ def encrypt(self, raw: str) -> str:
16
+ raw = pad(raw.encode(), self.__block_size, style='pkcs7')
17
+ iv = Random.new().read(self.__block_size)
18
+ cipher = AES.new(self.__key, AES.MODE_CBC, iv)
19
+ return base64.urlsafe_b64encode(iv + cipher.encrypt(raw)).decode('utf-8')
solidgate/model.py ADDED
@@ -0,0 +1,16 @@
1
+ class FormInitDTO:
2
+ def __init__(self, payment_intent: str, publicKey: str, signature: str):
3
+ self.payment_intent = payment_intent
4
+ self.merchant = publicKey
5
+ self.signature = signature
6
+
7
+ class FormUpdateDTO:
8
+ def __init__(self, partial_intent: str, signature: str):
9
+ self.partial_intent = partial_intent
10
+ self.signature = signature
11
+
12
+ class FormResignDTO:
13
+ def __init__(self, resignIntent: str, publicKey: str, signature: str):
14
+ self.resign_intent = resignIntent
15
+ self.merchant = publicKey
16
+ self.signature = signature
@@ -0,0 +1,135 @@
1
+ Metadata-Version: 2.4
2
+ Name: solidgate-sdk
3
+ Version: 0.3.2
4
+ Summary: Python API SDK for SolidGate payment gateway
5
+ Home-page: https://api-docs.solidgate.com/
6
+ Author: SolidGate
7
+ Author-email: info@solidgate.com
8
+ Classifier: Programming Language :: Python :: 3.7
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Operating System :: OS Independent
11
+ Description-Content-Type: text/markdown
12
+ License-File: LICENSE.md
13
+ Requires-Dist: requests
14
+ Requires-Dist: pycryptodome
15
+ Dynamic: author
16
+ Dynamic: author-email
17
+ Dynamic: classifier
18
+ Dynamic: description
19
+ Dynamic: description-content-type
20
+ Dynamic: home-page
21
+ Dynamic: license-file
22
+ Dynamic: requires-dist
23
+ Dynamic: summary
24
+
25
+ # Solidgate API
26
+
27
+ [![PyPI version](https://badge.fury.io/py/solidgate-sdk.svg)](https://badge.fury.io/py/solidgate-sdk)
28
+
29
+ Python SDK provides API options for integrating Solidgate’s payment orchestrator into your Python applications.
30
+
31
+ Check our
32
+ * <a href="https://docs.solidgate.com/" target="_blank">Payment guide</a> to understand business value better
33
+ * <a href="https://api-docs.solidgate.com/" target="_blank">API Reference</a> to find more examples of usage
34
+
35
+ ## Structure
36
+
37
+ <table style="width: 100%; background: transparent;">
38
+ <colgroup>
39
+ <col style="width: 50%;">
40
+ <col style="width: 50%;">
41
+ </colgroup>
42
+ <tr>
43
+ <th>SDK for Python contains</th>
44
+ <th>Table of contents</th>
45
+ </tr>
46
+ <tr>
47
+ <td>
48
+ <ul>
49
+ <li>
50
+ <code>solidgate/</code> – main library source code for development
51
+ <ul>
52
+ <li><code>__init__.py</code> – initializes the SDK package for importing</li>
53
+ <li><code>api_client.py</code> – main file for API integration and HTTP request handling</li>
54
+ <li><code>encryption.py</code> – library for encryption-related operations</li>
55
+ <li><code>model.py</code> – defines data structures for payment attributes and responses</li>
56
+ </ul>
57
+ </li>
58
+ <li><code>setup.py</code> – script for managing dependencies and library imports</li>
59
+ </ul>
60
+ </td>
61
+ <td>
62
+ <a href="https://github.com/solidgate-tech/python-sdk?tab=readme-ov-file#requirements">Requirements</a><br>
63
+ <a href="https://github.com/solidgate-tech/python-sdk?tab=readme-ov-file#installation">Installation</a><br>
64
+ <a href="https://github.com/solidgate-tech/python-sdk?tab=readme-ov-file#usage">Usage</a><br>
65
+ <a href="https://github.com/solidgate-tech/python-sdk?tab=readme-ov-file#errors">Errors</a><br>
66
+ </td>
67
+ </tr>
68
+ </table>
69
+
70
+ <br>
71
+
72
+ ## Requirements
73
+
74
+ * **Python**: 3.7 or later
75
+ * **Packages**: `requests` library
76
+ * **Solidgate account**: Public and secret key (request via <a href="mailto:sales@solidgate.com">sales@solidgate.com</a>)
77
+
78
+ <br>
79
+
80
+ ## Installation
81
+
82
+ To start using the Python SDK:
83
+
84
+ 1. Ensure you have your public and secret key.
85
+ 2. Install the SDK in your project using pip:
86
+ ```bash
87
+ pip install solidgate-card-sdk
88
+ ```
89
+ 3. Import the classes into your project:
90
+ ```
91
+ from solidgate import ApiClient
92
+ client = ApiClient(public_key='YourMerchantId', secret_key='YourPrivateKey')
93
+ ```
94
+ 4. Use test credentials for integration testing. After successful testing, switch to production credentials.
95
+
96
+ <br>
97
+
98
+ ## Usage
99
+
100
+ ### Charge a payment
101
+
102
+ Create a class instance of the `ApiClient` class.
103
+
104
+ ```
105
+ from solidgate import ApiClient
106
+
107
+ client = ApiClient(public_key, secret_key)
108
+ ```
109
+
110
+ - `public_key` - unique merchant identification
111
+ - `secret_key` - secret code for request signature, it is provided at the moment of merchant registration
112
+
113
+ ### Resign form
114
+
115
+ ```python
116
+ response = client.form_resign({'order_id': '12345'})
117
+ ```
118
+
119
+ <br>
120
+
121
+ ## Errors
122
+
123
+ Handle <a href="https://docs.solidgate.com/payments/payments-insights/error-codes/" target="_blank">errors</a>.
124
+
125
+ ```python
126
+ try:
127
+ response = client.charge({...})
128
+ except Exception as e:
129
+ print(e)
130
+ ```
131
+
132
+ ---
133
+
134
+ Looking for help? <a href="https://support.solidgate.com/support/tickets/new" target="_blank">Contact us</a> <br>
135
+ Want to contribute? <a href="https://github.com/solidgate-tech/python-sdk/pulls" target="_blank">Submit a pull request</a>
@@ -0,0 +1,9 @@
1
+ solidgate/__init__.py,sha256=nOvLT2_gmMOLcDLEdJIDCc_ED5udWhR0858SNOOIp_s,71
2
+ solidgate/api_client.py,sha256=OpOItg46-kDzV47Qwh8x6M4DPU4ELr19kPiLkSqvs1I,6237
3
+ solidgate/encryption.py,sha256=CjLdl11PxDuSb-RG-sp1WpIMjWd4gBjkYWVNas3MfcU,567
4
+ solidgate/model.py,sha256=u6rq_bHppf9wSF9Szz7yDDm8C8nO0c4dAGbnXBFReeI,580
5
+ solidgate_sdk-0.3.2.dist-info/licenses/LICENSE.md,sha256=Gjp7q0zwHb904tsXGdqKf7bNpkNUCOgoUeDihfIfCFY,609
6
+ solidgate_sdk-0.3.2.dist-info/METADATA,sha256=E8FpzHRNnj3BBTMDfWVrvGD3YVUsXCRwlpacsRDlULs,4094
7
+ solidgate_sdk-0.3.2.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
8
+ solidgate_sdk-0.3.2.dist-info/top_level.txt,sha256=g77pQ7dBSpjiJQJiDcDjyofS81wrd2jDAfTNlqxhAd4,10
9
+ solidgate_sdk-0.3.2.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (82.0.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,13 @@
1
+ Apache License, Version 2.0
2
+
3
+ Copyright 2015 - GTWS Tech Limited (https://solidgate.com/)
4
+
5
+ Licensed under the Apache License, Version 2.0 (the "License");
6
+ you may not use this file except in compliance with the License.
7
+ You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
@@ -0,0 +1 @@
1
+ solidgate