inpython-package 1.1.5__tar.gz → 1.1.6__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.
- {inpython_package-1.1.5/inpython_package.egg-info → inpython_package-1.1.6}/PKG-INFO +1 -1
- inpython_package-1.1.6/inpython/inqrcode/__init__.py +6 -0
- inpython_package-1.1.6/inpython/inqrcode/inqrcode.py +59 -0
- inpython_package-1.1.6/inpython/inqrcode/paymentqrcode.py +129 -0
- inpython_package-1.1.6/inpython/inrest/__init__.py +6 -0
- inpython_package-1.1.6/inpython/inrest/in_jwt.py +131 -0
- {inpython_package-1.1.5 → inpython_package-1.1.6/inpython_package.egg-info}/PKG-INFO +1 -1
- {inpython_package-1.1.5 → inpython_package-1.1.6}/inpython_package.egg-info/SOURCES.txt +5 -0
- {inpython_package-1.1.5 → inpython_package-1.1.6}/setup.py +1 -1
- {inpython_package-1.1.5 → inpython_package-1.1.6}/LICENSE.txt +0 -0
- {inpython_package-1.1.5 → inpython_package-1.1.6}/README.md +0 -0
- {inpython_package-1.1.5 → inpython_package-1.1.6}/inpython/__init__.py +0 -0
- {inpython_package-1.1.5 → inpython_package-1.1.6}/inpython/__main__.py +0 -0
- {inpython_package-1.1.5 → inpython_package-1.1.6}/inpython/aotools/__init__.py +0 -0
- {inpython_package-1.1.5 → inpython_package-1.1.6}/inpython/aotools/aogeo.py +0 -0
- {inpython_package-1.1.5 → inpython_package-1.1.6}/inpython/ingraph/__init__.py +0 -0
- {inpython_package-1.1.5 → inpython_package-1.1.6}/inpython/ingraph/ingraph.py +0 -0
- {inpython_package-1.1.5 → inpython_package-1.1.6}/inpython/intools/Servalux-devis.py +0 -0
- {inpython_package-1.1.5 → inpython_package-1.1.6}/inpython/intools/__init__.py +0 -0
- {inpython_package-1.1.5 → inpython_package-1.1.6}/inpython/intools/in_docx.py +0 -0
- {inpython_package-1.1.5 → inpython_package-1.1.6}/inpython/intools/in_projet.py +0 -0
- {inpython_package-1.1.5 → inpython_package-1.1.6}/inpython/intools/in_test.py +0 -0
- {inpython_package-1.1.5 → inpython_package-1.1.6}/inpython/intools/xls_to_csv.py +0 -0
- {inpython_package-1.1.5 → inpython_package-1.1.6}/inpython_package.egg-info/dependency_links.txt +0 -0
- {inpython_package-1.1.5 → inpython_package-1.1.6}/inpython_package.egg-info/requires.txt +0 -0
- {inpython_package-1.1.5 → inpython_package-1.1.6}/inpython_package.egg-info/top_level.txt +0 -0
- {inpython_package-1.1.5 → inpython_package-1.1.6}/setup.cfg +0 -0
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"""
|
|
2
|
+
script/fonction encode(ErrorCorrection: str = "Q", Valeur: str ) -> str:
|
|
3
|
+
qui execute python qrcode https://pypi.org/project/qrcode/ pour encoder la valeur
|
|
4
|
+
et retourner un tableau de 1010110
|
|
5
|
+
|
|
6
|
+
Usage :
|
|
7
|
+
- Python ...\inqrcode.py codeErr "Valeur"
|
|
8
|
+
Dans ce cas, la fonction sort sur un 'print(result)'
|
|
9
|
+
- from inpython.inqrcode import inqrcode.py
|
|
10
|
+
qrc = inqrcode.encode(codeErr, valeur)
|
|
11
|
+
|
|
12
|
+
"""
|
|
13
|
+
import qrcode
|
|
14
|
+
import sys
|
|
15
|
+
|
|
16
|
+
error_correction = {
|
|
17
|
+
'L': qrcode.ERROR_CORRECT_L,
|
|
18
|
+
'M': qrcode.ERROR_CORRECT_M,
|
|
19
|
+
'Q': qrcode.ERROR_CORRECT_Q,
|
|
20
|
+
'H': qrcode.ERROR_CORRECT_H,
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
def encode(codeErr: str = "M", data: str = "") -> str:
|
|
24
|
+
"""fonction qui encode la valeur pour en faire un qrcode avec le module POST
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
codeErr (str, optional): Error Correcton level. Defaults to "M".
|
|
28
|
+
The error_correction parameter controls the error correction used for the QR Code. The following four constants are made available on the qrcode package:
|
|
29
|
+
ERROR_CORRECT_L : About 7% or less errors can be corrected.
|
|
30
|
+
ERROR_CORRECT_M (default) : About 15% or less errors can be corrected.
|
|
31
|
+
ERROR_CORRECT_Q : About 25% or less errors can be corrected.
|
|
32
|
+
ERROR_CORRECT_H. : About 30% or less errors can be corrected
|
|
33
|
+
data (str, optional): _description_. Defaults to "".
|
|
34
|
+
|
|
35
|
+
Returns:
|
|
36
|
+
str: sequence de 01010101 emballé sous le format : qrcode<data>\\n-----\\n01010...\\n-----\\n. Separator 'lineFeed' (char(10))
|
|
37
|
+
Exemple :
|
|
38
|
+
qrcode<content_of_arg'data'>
|
|
39
|
+
-----
|
|
40
|
+
111111101111101111111
|
|
41
|
+
100000100011101000001
|
|
42
|
+
-----
|
|
43
|
+
|
|
44
|
+
"""
|
|
45
|
+
qr = qrcode.QRCode(error_correction=error_correction[codeErr])
|
|
46
|
+
qr.add_data(data)
|
|
47
|
+
qr.border = 0
|
|
48
|
+
qrbool = qr.get_matrix()
|
|
49
|
+
out = sys.stdout
|
|
50
|
+
result = 'qrcode<' + data + '>\n' + '-----\n'
|
|
51
|
+
for l in qrbool:
|
|
52
|
+
s = ''.join(['1' if x else '0' for x in l])
|
|
53
|
+
result += s + '\n'
|
|
54
|
+
result += '-----\n'
|
|
55
|
+
return result
|
|
56
|
+
|
|
57
|
+
if __name__ == "__main__":
|
|
58
|
+
print(encode(sys.argv[1],sys.argv[2]))
|
|
59
|
+
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import requests
|
|
2
|
+
import qrcode
|
|
3
|
+
from dotenv import load_dotenv
|
|
4
|
+
import os
|
|
5
|
+
from PIL import Image
|
|
6
|
+
|
|
7
|
+
load_dotenv()
|
|
8
|
+
|
|
9
|
+
ADYEN_API_KEY = os.getenv("ADYEN_API_KEY")
|
|
10
|
+
MERCHANT_ACCOUNT = os.getenv("MERCHANT_ACCOUNT")
|
|
11
|
+
URL = os.getenv("ADYEN_API_URL")
|
|
12
|
+
|
|
13
|
+
HEADERS = {
|
|
14
|
+
"X-API-Key": ADYEN_API_KEY,
|
|
15
|
+
"Content-Type": "application/json"
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
def create_payment_link_adyen(amount_cents: int, currency: str, reference: str, mode: str = 1, logo_path: str = None, env_path: str = None, qrcode_path: str = None ) -> str:
|
|
19
|
+
"""Crée un lien de paiement via l'API Adyen. Si mode=2, génère aussi un QR code (avec logo si fourni). Si env_path est fourni, charge les variables d'environnement depuis ce fichier."""
|
|
20
|
+
if env_path and os.path.exists(env_path):
|
|
21
|
+
from dotenv import dotenv_values
|
|
22
|
+
env_vars = dotenv_values(env_path)
|
|
23
|
+
adyen_api_key = env_vars.get("ADYEN_API_KEY")
|
|
24
|
+
merchant_account = env_vars.get("MERCHANT_ACCOUNT")
|
|
25
|
+
url = env_vars.get("ADYEN_API_URL")
|
|
26
|
+
else:
|
|
27
|
+
adyen_api_key = ADYEN_API_KEY
|
|
28
|
+
merchant_account = MERCHANT_ACCOUNT
|
|
29
|
+
url = URL
|
|
30
|
+
headers = {
|
|
31
|
+
"X-API-Key": adyen_api_key,
|
|
32
|
+
"Content-Type": "application/json"
|
|
33
|
+
}
|
|
34
|
+
payload = {
|
|
35
|
+
"amount": {
|
|
36
|
+
"value": amount_cents,
|
|
37
|
+
"currency": currency
|
|
38
|
+
},
|
|
39
|
+
"reference": reference,
|
|
40
|
+
"merchantAccount": merchant_account
|
|
41
|
+
}
|
|
42
|
+
response = requests.post(url, headers=headers, json=payload)
|
|
43
|
+
if response.status_code != 200:
|
|
44
|
+
response.raise_for_status()
|
|
45
|
+
data = response.json()
|
|
46
|
+
payment_url = data["url"]
|
|
47
|
+
if mode == 2:
|
|
48
|
+
qr_path = generate_qr_code(payment_url, reference, logo_path,qrcode_path)
|
|
49
|
+
return qr_path
|
|
50
|
+
return payment_url
|
|
51
|
+
|
|
52
|
+
def generate_qr_code(url: str, reference: str, logo_path: str = None, qrcode_path: str = None) -> None:
|
|
53
|
+
"""Génère un QR code dans le dossier ./qrcode/ (au même niveau que paymentqrcode.py), avec logo si fourni. Crée/écrase un fichier qrcode_logs.txt pour le diagnostic."""
|
|
54
|
+
import traceback
|
|
55
|
+
base_dir = os.path.dirname(os.path.abspath(__file__))
|
|
56
|
+
output_dir = os.path.join(base_dir, "qrcode")
|
|
57
|
+
|
|
58
|
+
os.makedirs(output_dir, exist_ok=True)
|
|
59
|
+
print("qrcode_path : ",qrcode_path)
|
|
60
|
+
if qrcode_path:
|
|
61
|
+
filename = os.path.join(qrcode_path, f"{reference}.jpg")
|
|
62
|
+
log_file = os.path.join(qrcode_path, "qrcode_debug.log")
|
|
63
|
+
else:
|
|
64
|
+
filename = os.path.join(output_dir, f"{reference}.jpg")
|
|
65
|
+
log_file = os.path.join(output_dir, "qrcode_debug.log")
|
|
66
|
+
|
|
67
|
+
# Supprime le fichier s’il existe
|
|
68
|
+
if os.path.exists(log_file):
|
|
69
|
+
os.remove(log_file)
|
|
70
|
+
|
|
71
|
+
log_lines = []
|
|
72
|
+
try:
|
|
73
|
+
qr = qrcode.QRCode(
|
|
74
|
+
version=1,
|
|
75
|
+
error_correction=qrcode.constants.ERROR_CORRECT_H,
|
|
76
|
+
box_size=10,
|
|
77
|
+
border=4,
|
|
78
|
+
)
|
|
79
|
+
qr.add_data(url)
|
|
80
|
+
qr.make(fit=True)
|
|
81
|
+
img_qr = qr.make_image(fill_color="black", back_color="white").convert('RGB')
|
|
82
|
+
log_lines.append(f"QR code généré pour l'URL: {url}\n")
|
|
83
|
+
if logo_path:
|
|
84
|
+
log_lines.append(f"Chemin du logo fourni: {logo_path}\n")
|
|
85
|
+
if os.path.exists(logo_path):
|
|
86
|
+
try:
|
|
87
|
+
logo = Image.open(logo_path)
|
|
88
|
+
log_lines.append(f"Logo ouvert avec succès. Mode: {logo.mode}, Taille: {logo.size}\n")
|
|
89
|
+
qr_width, qr_height = img_qr.size
|
|
90
|
+
logo_size = int(qr_width * 0.2)
|
|
91
|
+
logo = logo.resize((logo_size, logo_size), Image.LANCZOS)
|
|
92
|
+
log_lines.append(f"Logo redimensionné à: {logo.size}\n")
|
|
93
|
+
pos = ((qr_width - logo_size) // 2, (qr_height - logo_size) // 2)
|
|
94
|
+
img_qr.paste(logo, pos, mask=logo if logo.mode == 'RGBA' else None)
|
|
95
|
+
log_lines.append(f"Logo collé au centre du QR code.\n")
|
|
96
|
+
except Exception as e:
|
|
97
|
+
log_lines.append(f"Erreur lors de l'ouverture ou du collage du logo: {e}\n{traceback.format_exc()}\n")
|
|
98
|
+
else:
|
|
99
|
+
log_lines.append(f"Logo non trouvé : {logo_path}, QR code généré sans logo.\n")
|
|
100
|
+
else:
|
|
101
|
+
log_lines.append("Aucun chemin de logo fourni, QR code généré sans logo.\n")
|
|
102
|
+
img_qr.save(filename, format="JPEG")
|
|
103
|
+
log_lines.append(f"QR code enregistré : {filename}\n")
|
|
104
|
+
except Exception as e:
|
|
105
|
+
log_lines.append(f"Erreur générale lors de la génération du QR code: {e}\n{traceback.format_exc()}\n")
|
|
106
|
+
# Toujours écrire le log, même si une exception a eu lieu
|
|
107
|
+
with open(log_file, 'w') as f:
|
|
108
|
+
f.writelines(log_lines)
|
|
109
|
+
return filename
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def clean(s):
|
|
113
|
+
return s.strip('"').strip("'")
|
|
114
|
+
|
|
115
|
+
if __name__ == "__main__":
|
|
116
|
+
import sys
|
|
117
|
+
try:
|
|
118
|
+
# Utilisation : python paymentqrcode.py <mode> <montant> <devise> <reference> [chemin_logo] [chemin_env]
|
|
119
|
+
mode = int(clean(sys.argv[1]))
|
|
120
|
+
amount = int(clean(sys.argv[2]))
|
|
121
|
+
currency = sys.argv[3]
|
|
122
|
+
reference = sys.argv[4]
|
|
123
|
+
logo_path = sys.argv[5] if len(sys.argv) > 5 else ''
|
|
124
|
+
env_path = sys.argv[6] if len(sys.argv) > 6 else ''
|
|
125
|
+
qrcode_path = sys.argv[7] if len(sys.argv) > 7 else ''
|
|
126
|
+
result = create_payment_link_adyen(amount, currency, reference, mode, logo_path, env_path,qrcode_path)
|
|
127
|
+
print(result)
|
|
128
|
+
except Exception as e:
|
|
129
|
+
print("Erreur :", e)
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
#--------------------------------------------------------
|
|
2
|
+
# Manipulates a Json web token
|
|
3
|
+
#
|
|
4
|
+
#--------------------------------------------------------
|
|
5
|
+
# 22/08/2024 (JCD) : Creation fonction generateJwtClientAssertion
|
|
6
|
+
#--------------------------------------------------------
|
|
7
|
+
from cryptography.hazmat.primitives.serialization import pkcs12
|
|
8
|
+
from cryptography.hazmat.primitives import serialization
|
|
9
|
+
from cryptography.hazmat.backends import default_backend
|
|
10
|
+
import jwt
|
|
11
|
+
import datetime
|
|
12
|
+
import sys
|
|
13
|
+
import getopt
|
|
14
|
+
|
|
15
|
+
# Generates a jwt client assertion from a private key
|
|
16
|
+
def generateJwtClientAssertion(mode,path_certificate,private_key,client_id,audience,expirationTime=10):
|
|
17
|
+
""" Return jwt token assertion
|
|
18
|
+
|
|
19
|
+
Parameters
|
|
20
|
+
------------
|
|
21
|
+
mode:int
|
|
22
|
+
= 1 : Private key
|
|
23
|
+
= 2 : Private password
|
|
24
|
+
path_certificate: string
|
|
25
|
+
Path crt/cer file if mode = 1
|
|
26
|
+
Path pfx file if mode = 2
|
|
27
|
+
private_key: byte
|
|
28
|
+
Path key file file if mode = 1
|
|
29
|
+
Private password if mode = 2
|
|
30
|
+
client_id: string
|
|
31
|
+
audience: string
|
|
32
|
+
expirationTime: string, Optional
|
|
33
|
+
in minutes. Default to 10 minutes
|
|
34
|
+
"""
|
|
35
|
+
try:
|
|
36
|
+
if mode != "1" and mode != "2" :
|
|
37
|
+
raise Exception("Unmanaged mode")
|
|
38
|
+
|
|
39
|
+
if not expirationTime:
|
|
40
|
+
expirationTime = 10
|
|
41
|
+
else:
|
|
42
|
+
expirationTime = int(expirationTime)
|
|
43
|
+
|
|
44
|
+
# Load the public certificate
|
|
45
|
+
with open(path_certificate, "rb") as cert_file:
|
|
46
|
+
certificate_data = cert_file.read()
|
|
47
|
+
|
|
48
|
+
# Load the private key
|
|
49
|
+
if mode == "1":
|
|
50
|
+
with open(private_key, "rb") as key_file:
|
|
51
|
+
private_key = serialization.load_pem_private_key(
|
|
52
|
+
key_file.read(),
|
|
53
|
+
password=None,
|
|
54
|
+
backend=default_backend()
|
|
55
|
+
)
|
|
56
|
+
else:
|
|
57
|
+
private_key, certificate, additional_certs = pkcs12.load_key_and_certificates(
|
|
58
|
+
certificate_data, private_key.encode(), backend=default_backend()
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
now = datetime.datetime.now(datetime.timezone.utc)
|
|
62
|
+
# Define the JWT claims
|
|
63
|
+
claims = {
|
|
64
|
+
"iss": client_id, # The issuer, typically your client ID
|
|
65
|
+
"sub": client_id, # The subject, typically your client ID
|
|
66
|
+
"aud": audience, # The audience, typically the token endpoint URL
|
|
67
|
+
"exp": now + datetime.timedelta(expirationTime), # Expiration time
|
|
68
|
+
"jti": "unique-identifier", # JWT ID, a unique identifier for the JWT
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
# Create the JWT (client assertion)
|
|
72
|
+
if mode == 1:
|
|
73
|
+
client_assertion = jwt.encode(
|
|
74
|
+
claims,
|
|
75
|
+
private_key,
|
|
76
|
+
algorithm="RS256",
|
|
77
|
+
headers={"x5c": [certificate_data.decode("utf-8").replace("\n", "")]}
|
|
78
|
+
)
|
|
79
|
+
else:
|
|
80
|
+
client_assertion = jwt.encode(
|
|
81
|
+
claims, private_key, algorithm="RS256", headers={"alg": "RS256","typ": "JWT"}
|
|
82
|
+
)
|
|
83
|
+
return client_assertion
|
|
84
|
+
except:
|
|
85
|
+
raise # so that the caller receives the exception
|
|
86
|
+
|
|
87
|
+
def main(argv):
|
|
88
|
+
#mode = "1"
|
|
89
|
+
#private_key = "C:\\TRF\\cleanup\\Cleanup1_private.key"
|
|
90
|
+
#path_certificate = "C:\\TRF\\cleanup\\Cleanup1_request.crt"
|
|
91
|
+
#client_id = "self_service_chaman_109660_shr5ppy83v"
|
|
92
|
+
|
|
93
|
+
#mode = "2"
|
|
94
|
+
#path_certificate = "/tmp/jcd/CermiaRest.pfx"
|
|
95
|
+
#private_key = "2024infodd1648!" # Use b'' for an empty password
|
|
96
|
+
#client_id = "self_service_chaman_108306_safnfiag3h"
|
|
97
|
+
#audience = "https://services.socialsecurity.be/REST/oauth/v5/token"
|
|
98
|
+
mode = ''
|
|
99
|
+
private_key = ''
|
|
100
|
+
path_certificate = ''
|
|
101
|
+
client_id = ''
|
|
102
|
+
audience = ''
|
|
103
|
+
expirationTime = None
|
|
104
|
+
try:
|
|
105
|
+
opts, args = getopt.getopt(argv, "m:k:x:c:a:e:", ["mode=", "private_key=", "path_certificate=", "client_id=", "audience=", "expirationTime="])
|
|
106
|
+
except getopt.GetoptError:
|
|
107
|
+
print('script.py -i <inputfile> -o <outputfile>')
|
|
108
|
+
sys.exit(2)
|
|
109
|
+
|
|
110
|
+
for opt, arg in opts:
|
|
111
|
+
if opt in ("-m", "--mode"):
|
|
112
|
+
mode = arg
|
|
113
|
+
elif opt in ("-k", "--private_key"):
|
|
114
|
+
private_key = arg
|
|
115
|
+
elif opt in ("-x", "--path_certificate"):
|
|
116
|
+
path_certificate = arg
|
|
117
|
+
elif opt in ("-c", "--client_id"):
|
|
118
|
+
client_id = arg
|
|
119
|
+
elif opt in ("-a", "--audience"):
|
|
120
|
+
audience = arg
|
|
121
|
+
elif opt in ("-e", "--expirationTime"):
|
|
122
|
+
if arg != "":
|
|
123
|
+
expirationTime = arg
|
|
124
|
+
|
|
125
|
+
result = generateJwtClientAssertion(mode,path_certificate,private_key,client_id,audience,expirationTime)
|
|
126
|
+
print(result)
|
|
127
|
+
|
|
128
|
+
if __name__ == "__main__":
|
|
129
|
+
main(sys.argv[1:])
|
|
130
|
+
|
|
131
|
+
|
|
@@ -7,6 +7,11 @@ inpython/aotools/__init__.py
|
|
|
7
7
|
inpython/aotools/aogeo.py
|
|
8
8
|
inpython/ingraph/__init__.py
|
|
9
9
|
inpython/ingraph/ingraph.py
|
|
10
|
+
inpython/inqrcode/__init__.py
|
|
11
|
+
inpython/inqrcode/inqrcode.py
|
|
12
|
+
inpython/inqrcode/paymentqrcode.py
|
|
13
|
+
inpython/inrest/__init__.py
|
|
14
|
+
inpython/inrest/in_jwt.py
|
|
10
15
|
inpython/intools/Servalux-devis.py
|
|
11
16
|
inpython/intools/__init__.py
|
|
12
17
|
inpython/intools/in_docx.py
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{inpython_package-1.1.5 → inpython_package-1.1.6}/inpython_package.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|