csc-cia-stne 0.0.43__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.
@@ -0,0 +1,597 @@
1
+ import requests
2
+ import jwt
3
+ from datetime import datetime, timedelta
4
+ import time
5
+ #import subprocess
6
+ import json
7
+ #from modules.pdf import gerar_pdf_extrato
8
+ #import csv
9
+ #import io
10
+ #import sys
11
+ #import logging
12
+ from pydantic import BaseModel, StrictStr, StrictInt, ValidationError, field_validator, FieldValidationInfo
13
+ from typing import Literal
14
+
15
+ # Validações dos inputs
16
+ class InitParamsValidator(BaseModel):
17
+ client_id: str
18
+ user_agent: str
19
+ private_key: str
20
+ ambiente: Literal["prd", "sdx"] # Aceita apenas "prd" ou "sdx"
21
+
22
+ # Validação para garantir que cada parâmetro é uma string não vazia
23
+ @field_validator('client_id', 'user_agent', 'private_key')
24
+ def check_non_empty_string(cls, value, info):
25
+ if not isinstance(value, str) or not value.strip():
26
+
27
+ raise ValueError(f"O parâmetro '{info.field_name}' deve ser uma string não vazia.")
28
+
29
+ return value
30
+
31
+ class DocumentoValidator(BaseModel):
32
+
33
+ documento: StrictStr | StrictInt # Aceita apenas str ou int
34
+
35
+ # Valida se 'documento' não é vazio
36
+ @field_validator('documento')
37
+ def documento_nao_vazio(cls, value: StrictStr | StrictInt, info: FieldValidationInfo):
38
+
39
+ if isinstance(value, str) and not value.strip():
40
+
41
+ raise ValueError("O parâmetro 'documento' não pode ser uma string vazia.")
42
+
43
+ return value
44
+
45
+ class AccountIDValidator(BaseModel):
46
+
47
+ account_id: StrictStr # Aceita apenas str
48
+
49
+ # Valida se 'client_id' não é vazio
50
+ @field_validator('account_id')
51
+ def account_id_nao_vazio(cls, value: StrictStr, info: FieldValidationInfo):
52
+
53
+ if isinstance(value, str) and not value.strip():
54
+
55
+ raise ValueError("O parâmetro 'account_id' não pode ser uma string vazia.")
56
+
57
+ return value
58
+
59
+ class ExtratoParamsValidator(BaseModel):
60
+
61
+ account_id: str
62
+ data_inicio: datetime
63
+ data_fim: datetime
64
+ async_mode: bool
65
+
66
+ # Valida se 'client_id' não é vazio
67
+ @field_validator('account_id')
68
+ def account_id_nao_vazio(cls, value: StrictStr, info: FieldValidationInfo):
69
+
70
+ if isinstance(value, str) and not value.strip():
71
+
72
+ raise ValueError("O parâmetro 'account_id' não pode ser uma string vazia.")
73
+
74
+ return value
75
+
76
+ # Valida se 'data_inicio' está no formato datetime
77
+ @field_validator('data_inicio', 'data_fim')
78
+ def check_datetime_format(cls, value, info: FieldValidationInfo):
79
+
80
+ if not isinstance(value, datetime):
81
+
82
+ raise ValueError(f"O parâmetro '{info.field_name}' deve estar no formato datetime.")
83
+
84
+ return value
85
+
86
+ # Valida se 'data_fim' é posterior a 'data_inicio'
87
+ @field_validator('data_fim')
88
+ def check_data_fim_posterior(cls, data_fim, values):
89
+ data_inicio = values.get('data_inicio')
90
+
91
+ if data_inicio and data_fim and data_fim <= data_inicio:
92
+
93
+ raise ValueError("O parâmetro 'data_fim' deve ser posterior a data_inicio.")
94
+
95
+ return data_fim
96
+
97
+ # Valida se 'async_mode' é um valor booleano
98
+ @field_validator('async_mode')
99
+ def check_async_mode(cls, async_mode):
100
+
101
+ if not isinstance(async_mode, bool):
102
+
103
+ raise ValueError("O parâmetro 'async_mode' deve ser um valor booleano.")
104
+
105
+ return async_mode
106
+
107
+ class ReceiptIDValidator(BaseModel):
108
+
109
+ receipt_id: StrictStr # Aceita apenas str
110
+
111
+ # Valida se 'receipt_id' não é vazio
112
+ @field_validator('receipt_id')
113
+ def receipt_id_nao_vazio(cls, value: StrictStr, info: FieldValidationInfo):
114
+
115
+ if isinstance(value, str) and not value.strip():
116
+
117
+ raise ValueError("O parâmetro 'receipt_id' não pode ser uma string vazia.")
118
+
119
+ return value
120
+
121
+ class StoneAdmin:
122
+
123
+ def __init__(self, client_id:str, user_agent:str, private_key:str, ambiente:str):
124
+ """
125
+ Inicializa uma instância da classe STNEAdmin.
126
+ Parâmetros:
127
+ - client_id (str): O ID do cliente.
128
+ - user_agent (str): O agente do usuário.
129
+ - private_key (str): A chave privada.
130
+ - ambiente (str): O ambiente de execução ('prd' para produção ou qualquer outro valor para sandbox).
131
+ Exemplo de uso:
132
+ ```
133
+ client_id = '123456789'
134
+ user_agent = 'MyApp/1.0'
135
+ private_key = 'my_private_key'
136
+ ambiente = 'prd'
137
+ admin = STNEAdmin(client_id, user_agent, private_key, ambiente)
138
+ ```
139
+ """
140
+
141
+ try:
142
+
143
+ InitParamsValidator(client_id=client_id, user_agent=user_agent, private_key=private_key, ambiente=ambiente)
144
+
145
+ except ValidationError as e:
146
+
147
+ raise ValueError("Erro na validação dos dados de input da inicialização da instância:", e.errors())
148
+
149
+ # Produção
150
+ if ambiente == 'prd':
151
+
152
+ self.base_url = 'https://api.openbank.stone.com.br/resources/v1'
153
+ self.base_auth_url = 'https://accounts.openbank.stone.com.br'
154
+
155
+ # Sandbox
156
+ else:
157
+
158
+ self.base_url = 'https://sandbox-api.openbank.stone.com.br/resources/v1'
159
+ self.base_auth_url = 'https://sandbox-accounts.openbank.stone.com.br'
160
+
161
+ self.client_id = client_id
162
+ self.user_agent = user_agent
163
+ self.private_key = private_key
164
+ self.token = self.__get_token()
165
+ self.authenticated_header = {
166
+ 'Authorization' : f"Bearer {self.token}",
167
+ 'User-Agent': self.user_agent,
168
+ #'Client-ID': self.client_id
169
+ }
170
+
171
+ def __get_token(self):
172
+ """
173
+ Obtém um token de autenticação para acessar a API do Stone Bank.
174
+ Returns:
175
+ str: O token de acesso gerado.
176
+ Raises:
177
+ requests.exceptions.RequestException: Se ocorrer um erro durante a solicitação HTTP.
178
+ KeyError: Se a resposta da solicitação não contiver a chave 'access_token'.
179
+ Exemplo:
180
+ >>> token = self.__get_token()
181
+ """
182
+ base_url = f'{self.base_auth_url}/auth/realms/stone_bank'
183
+ auth_url = f'{base_url}/protocol/openid-connect/token'
184
+ payload = {
185
+ 'exp': int(time.time()) + 3600,
186
+ 'nbf': int(time.time()),
187
+ 'aud': base_url,
188
+ 'realm': 'stone_bank',
189
+ 'sub': self.client_id,
190
+ 'clientId': self.client_id,
191
+ 'jti': str(time.time()),
192
+ 'iat': int(time.time()),
193
+ 'iss': self.client_id
194
+ }
195
+
196
+ token = jwt.encode(payload, self.private_key, algorithm='RS256')
197
+
198
+ headers = {
199
+ 'Content-Type': 'application/x-www-form-urlencoded',
200
+ 'User-Agent': self.user_agent
201
+ }
202
+
203
+ token_payload = {
204
+ 'client_id': self.client_id,
205
+ 'grant_type': 'client_credentials',
206
+ 'client_assertion': token,
207
+ 'client_assertion_type': 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer'
208
+ }
209
+
210
+ response = requests.post(auth_url, data=token_payload, headers=headers, timeout=60)
211
+ #print(response.json())
212
+ return response.json()['access_token']
213
+
214
+ def renew_authorization(self):
215
+ """
216
+ Renova a autorização do usuário.
217
+
218
+ Esta função renova a autorização do usuário, obtendo um novo token de autenticação
219
+ e atualizando o cabeçalho de autenticação.
220
+
221
+ Parâmetros:
222
+ - Nenhum
223
+
224
+ Retorno:
225
+ - Nenhum
226
+
227
+ Exemplo de uso:
228
+ ```
229
+ obj = ClassName()
230
+ obj.renew_authorization()
231
+ ```
232
+ """
233
+ self.token = self.__get_token()
234
+ self.authenticated_header = {
235
+ 'Authorization' : f"Bearer {self.token}",
236
+ 'User-Agent': self.user_agent,
237
+ #'Client-ID': self.client_id
238
+ }
239
+
240
+ def verificar_cliente(self,documento:str)->dict:
241
+ """
242
+ Verifica se um cliente com o documento fornecido existe e se a conta associada está ativa.
243
+ Args:
244
+ documento (str): O número do documento do cliente.
245
+ Returns:
246
+ dict: Um dicionário contendo as informações do cliente e da conta, se encontrado.
247
+ - success (bool): Indica se a operação foi bem-sucedida.
248
+ - status_code (int): O código de status da resposta da API.
249
+ - error (Exception): O erro ocorrido, se houver.
250
+ - encontrado (bool): Indica se o cliente foi encontrado.
251
+ - detalhes (list): Uma lista de dicionários contendo os detalhes das contas encontradas.
252
+ - account_code (str): O código da conta.
253
+ - account_id (str): O ID da conta.
254
+ - owner_id (str): O ID do proprietário da conta.
255
+ - closed_at (str): A data de encerramento da conta, se estiver fechada.
256
+ - created_at (str): A data de criação da conta.
257
+ - conta_ativa (bool): Indica se a conta está ativa.
258
+ Raises:
259
+ ValueError: Se ocorrer um erro na validação dos dados de entrada.
260
+ ValueError: Se ocorrer um erro na requisição à API Stone Admin.
261
+ Example:
262
+ # Instanciar o objeto da classe
263
+ stne_admin = StneAdmin()
264
+ # Chamar a função verificar_cliente
265
+ resultado = stne_admin.verificar_cliente("123456789")
266
+ # Verificar se a operação foi bem-sucedida
267
+ if resultado["success"]:
268
+ # Verificar se o cliente foi encontrado
269
+ if resultado["encontrado"]:
270
+ # Acessar os detalhes das contas encontradas
271
+ detalhes = resultado["detalhes"]
272
+ for conta in detalhes:
273
+ print(f"Conta: {conta['account_code']}")
274
+ print(f"Status: {'Ativa' if conta['conta_ativa'] else 'Inativa'}")
275
+ print("Cliente não encontrado.")
276
+ print(f"Erro: {resultado['error']}")
277
+ """
278
+
279
+ try:
280
+
281
+ DocumentoValidator(documento=documento)
282
+
283
+ except ValidationError as e:
284
+
285
+ raise ValueError("Erro na validação dos dados de input do método:", e.errors())
286
+
287
+ params_conta_ativa = {'owner_document': documento}
288
+ params_conta_inativa = {'owner_document': documento,'status':'closed'}
289
+
290
+ try:
291
+
292
+ # Verificando se existe cliente com esse documento, com a conta ativa
293
+ response = requests.get(f"{self.base_url}/accounts", params=params_conta_ativa, headers=self.authenticated_header, timeout=60)
294
+
295
+ # Retorno esperado pela API Stone Admin - consulta cliente ativo
296
+ if response.status_code == 200:
297
+
298
+ # Não existe cliente com esse documento e com a conta ativa
299
+ if len(response.json()) == 0:
300
+
301
+ # Verificando se existe cliente com esse documento, com a conta inativa
302
+ encontrado = False
303
+ response = requests.get(f"{self.base_url}/accounts", params=params_conta_inativa, headers=self.authenticated_header, timeout=60)
304
+
305
+ # Retorno esperado pela API Stone Admin - consulta cliente inativo
306
+ if response.status_code == 200:
307
+
308
+ resposta = response.json()
309
+
310
+ # Existe cliente com esse documento, mas com a conta inativa
311
+ if len(resposta) != 0:
312
+
313
+ encontrado = True
314
+
315
+ # Algum erro na API Stone Admin - retorna erro
316
+ else:
317
+
318
+ return False, ValueError(response.json())
319
+
320
+ # Cliente econtrado e com a conta ativa
321
+ else:
322
+
323
+ encontrado = True
324
+ resposta = response.json()
325
+
326
+ retorno = []
327
+
328
+ # Monta JSON , pode ter mais de uma conta
329
+ for registro in resposta:
330
+
331
+ retorno_item = {}
332
+ account_code = registro["account_code"]
333
+ account_id = registro["id"]
334
+ owner_id = registro["owner_id"]
335
+ closed_at = registro["closed_at"]
336
+ created_at = registro["created_at"]
337
+
338
+ # Status atual da conta
339
+ if closed_at is None:
340
+
341
+ registro["conta_ativa"] = True
342
+
343
+ else:
344
+
345
+ registro["conta_ativa"] = False
346
+
347
+ retorno.append(registro)
348
+
349
+ retorno_json = {
350
+ "success":True,
351
+ "status_code": response.status_code,
352
+ "error": None,
353
+ "encontrado": encontrado,
354
+ "detalhes": retorno
355
+ }
356
+ return retorno_json
357
+
358
+ # Retorno inesperado pela API Stone Admin - consulta cliente ativo, retorna erro
359
+ else:
360
+
361
+ retorno_json = {
362
+ "success":False,
363
+ "status_code": response.status_code,
364
+ "error": ValueError(response.json())
365
+ }
366
+ return retorno_json
367
+
368
+ # Erro inesperado como a requisição à API Stone Admin - consulta cliente ativo, retorna erro
369
+ except Exception as e:
370
+
371
+ retorno_json = {
372
+ "success":False,
373
+ "status_code": response.status_code,
374
+ "error": e
375
+ }
376
+ return retorno_json
377
+
378
+ def balance_da_conta(self,account_id:str):
379
+ """
380
+ Retorna o saldo da conta especificada.
381
+ Parâmetros:
382
+ - account_id (str): O ID da conta.
383
+ Retorna:
384
+ - response (objeto): A resposta da requisição GET contendo o saldo da conta.
385
+ Exemplo de uso:
386
+ ```
387
+ account_id = "123456789"
388
+ response = balance_da_conta(account_id)
389
+ print(response)
390
+ ```
391
+ """
392
+ try:
393
+
394
+ AccountIDValidator(account_id=account_id)
395
+
396
+ except ValidationError as e:
397
+
398
+ raise ValueError("Erro na validação dos dados de input do método:", e.errors())
399
+
400
+ # Captura o balance da conta
401
+ response = requests.get(f"{self.base_url}/accounts/{account_id}", headers=self.authenticated_header)
402
+ return response
403
+
404
+ def detalhar_titular_cpf(self,documento:str):
405
+ """
406
+ Detalha o titular do CPF fornecido.
407
+ Args:
408
+ documento (str): O número do CPF do titular.
409
+ Returns:
410
+ requests.Response: A resposta da requisição HTTP.
411
+ Raises:
412
+ ValueError: Se houver um erro na validação dos dados de input.
413
+ Example:
414
+ >>> admin = StneAdmin()
415
+ >>> response = admin.detalhar_titular_cpf('12345678900')
416
+ """
417
+
418
+ try:
419
+
420
+ DocumentoValidator(documento=documento)
421
+
422
+ except ValidationError as e:
423
+
424
+ raise ValueError("Erro na validação dos dados de input do método:", e.errors())
425
+
426
+ # Detalha o titular
427
+
428
+ # Verificar na rota /users (CPF)
429
+ filtro = {'document': documento}
430
+ param = {
431
+ 'filter': json.dumps(filtro) # Transforma o dicionário em uma string JSON
432
+ }
433
+ response = requests.get(f"{self.base_url}/users", params=param, headers=self.authenticated_header)
434
+ return response
435
+
436
+ def detalhar_titular_cnpj(self,documento:str):
437
+ """
438
+ Detalha o titular de um CNPJ.
439
+ Args:
440
+ documento (str): O número do CNPJ a ser consultado.
441
+ Returns:
442
+ requests.Response: A resposta da requisição HTTP.
443
+ Raises:
444
+ ValueError: Se houver um erro na validação dos dados de input.
445
+ Example:
446
+ >>> admin = StneAdmin()
447
+ >>> response = admin.detalhar_titular_cnpj('12345678901234')
448
+ """
449
+
450
+ try:
451
+
452
+ DocumentoValidator(documento=documento)
453
+
454
+ except ValidationError as e:
455
+
456
+ raise ValueError("Erro na validação dos dados de input do método:", e.errors())
457
+
458
+ # Verificar na rota /organizations (CNPJ)
459
+ filtro = {'document': documento}
460
+ param = {
461
+ 'filter': json.dumps(filtro) # Transforma o dicionário em uma string JSON
462
+ }
463
+ response = requests.get(f"{self.base_url}/organizations", params=param, headers=self.authenticated_header)
464
+ return response
465
+
466
+ def extrair_extrato(self,account_id:str,data_inicio:datetime,data_fim:datetime,async_mode:bool=False):
467
+ """
468
+ Extrai o extrato de uma conta.
469
+ Args:
470
+ account_id (str): O ID da conta.
471
+ data_inicio (datetime): A data de início do extrato.
472
+ data_fim (datetime): A data de fim do extrato.
473
+ async_mode (bool, optional): Modo assíncrono. Defaults to False.
474
+ Returns:
475
+ dict: Um dicionário contendo informações sobre o resultado da operação.
476
+ - Se async_mode for False e a resposta for bem-sucedida, retorna:
477
+ {
478
+ "success": True,
479
+ "status_code": int,
480
+ "error": None,
481
+ "pdf_content": bytes
482
+ }
483
+ - Se async_mode for True e a resposta for bem-sucedida, retorna:
484
+ {
485
+ "success": True,
486
+ "status_code": int,
487
+ "error": None,
488
+ "receipt_id": str
489
+ }
490
+ - Se a resposta não for bem-sucedida, retorna:
491
+ {
492
+ "success": False,
493
+ "status_code": int,
494
+ "error": str,
495
+ "pdf_content": None
496
+ }
497
+ - Se ocorrer uma exceção, retorna:
498
+ {
499
+ "success": False,
500
+ "status_code": int,
501
+ "error": Exception,
502
+ "pdf_content": None
503
+ }
504
+ """
505
+
506
+ try:
507
+
508
+ ExtratoParamsValidator(account_id=account_id, data_inicio=data_inicio, data_fim=data_fim, async_mode=async_mode)
509
+
510
+ except ValidationError as e:
511
+
512
+ raise ValueError("Erro na validação dos dados de input do método:", e.errors())
513
+
514
+ # Validação do async_mode
515
+ if not isinstance(async_mode, bool):
516
+
517
+ raise ValueError("async_mode deve ser um valor booleano.")
518
+
519
+
520
+ data_inicio = data_inicio.strftime('%Y-%m-%d')
521
+ data_fim = data_fim + timedelta(days=1)
522
+ data_fim = data_fim.strftime('%Y-%m-%d')
523
+
524
+ try:
525
+
526
+ if async_mode:
527
+
528
+ response = requests.get(f"{self.base_url}/exports/accounts/{account_id}/statement?start_date={data_inicio}&end_date={data_fim}&format=pdf&async=true", headers=self.authenticated_header, timeout=60)
529
+
530
+ else:
531
+
532
+ response = requests.get(f"{self.base_url}/exports/accounts/{account_id}/statement?start_date={data_inicio}&end_date={data_fim}&format=pdf&async=false", headers=self.authenticated_header, timeout=120)
533
+
534
+ if response.status_code == 200 and not async_mode:
535
+
536
+ return {"success":True, "status_code": response.status_code, "error": None, "pdf_content": response.content}
537
+
538
+ elif response.status_code == 202 and async_mode:
539
+
540
+ return {"success":True, "status_code": response.status_code, "error": None, "receipt_id":response.json()["id"]}
541
+
542
+ else:
543
+
544
+ return {"success":False, "status_code": response.status_code, "error": str(response.text), "pdf_content": None}
545
+
546
+ except Exception as e:
547
+
548
+ return {"success": False, "status_code": response.status_code, "error": e, "pdf_content": None}
549
+
550
+ def download_receipt(self,receipt_id:str):
551
+ """
552
+ Faz o download de um recibo a partir de um ID de recibo.
553
+ Args:
554
+ receipt_id (str): O ID do recibo a ser baixado.
555
+ Returns:
556
+ dict: Um dicionário contendo os seguintes campos:
557
+ - 'result' (bool): Indica se o download foi bem-sucedido.
558
+ - 'status_code' (int): O código de status da resposta HTTP.
559
+ - 'error' (str ou dict): O erro retornado, se houver.
560
+ - 'pdf_content' (bytes): O conteúdo do arquivo PDF, se o download for bem-sucedido.
561
+ Raises:
562
+ ValueError: Se ocorrer um erro na validação dos dados de entrada.
563
+ Example:
564
+ >>> admin = STNEAdmin()
565
+ >>> result = admin.download_receipt("123456")
566
+ >>> print(result)
567
+ {'result': True, 'status_code': 200, 'error': None, 'pdf_content': b'%PDF-1.7\n%����\n1 0 obj\n<<\n/Type /Catalog\n/Pages 2 0 R\n>>\nendobj\n2 0 obj\n<<\n/Type /Pages\n/Kids [3 0 R]\n/Count 1\n>>\nendobj\n3 0 obj\n<<\n/Type /Page\n/Parent 2 0 R\n/Resources <<\n/Font <<\n/F1 4 0 R\n>>\n/ProcSet 5 0 R\n>>\n/MediaBox [0 0 595.276 841.890]\n/Contents 6 0 R\n>>\nendobj\n4 0 obj\n<<\n/Type /Font\n/Subtype /Type1\n/Name /F1\n/BaseFont /Helvetica\n/Encoding /MacRomanEncoding\n>>\nendobj\n5 0 obj\n[/PDF /Text]\nendobj\n6 0 obj\n<<\n/Length 44\n>>\nstream\nBT\n/F1 24 Tf\n100 100 Td\n(Hello, World!) Tj\nET\nendstream\nendobj\nxref\n0 7\n0000000000 65535 f \n0000000010 00000 n \n0000000077 00000 n \n0000000178 00000 n \n0000000302 00000 n \n0000000406 00000 n \n0000000519 00000 n \ntrailer\n<<\n/Size 7\n/Root 1 0 R\n>>\nstartxref\n614\n%%EOF\n'}
568
+ """
569
+
570
+ try:
571
+
572
+ ReceiptIDValidator(receipt_id=receipt_id)
573
+
574
+ except ValidationError as e:
575
+
576
+ raise ValueError("Erro na validação dos dados de input do método:", e.errors())
577
+
578
+ try:
579
+
580
+ response = requests.get(f"https://api.openbank.stone.com.br/resources/v1/exports/receipt_requests/download/{receipt_id}", headers=self.authenticated_header, timeout=120)
581
+
582
+ if response.status_code == 200:
583
+
584
+ # Decodificando o conteúdo usando UTF-8
585
+ #decoded_content = response.content.decode('utf-8')
586
+ print("header:",response.headers['Content-Type'])
587
+ print(f"type do content: {type(response.content)}")
588
+ return {'result':True, 'status_code': response.status_code, 'error': None, 'pdf_content':response.content}
589
+ #return {'result':True, 'status_code': response.status_code, 'error': None, 'pdf_content':decoded_content}
590
+
591
+ else:
592
+
593
+ return {'result': False, 'status_code': response.status_code, 'error': response.json(), 'pdf_content': None}
594
+
595
+ except Exception as e:
596
+
597
+ return {'result': False, 'status_code': None, 'error': e, 'pdf_content': None}
@@ -0,0 +1,9 @@
1
+ from .functions import titulo, recriar_pasta, b64encode, b64decode, convert_bquery_result_to_json,get_config
2
+ __all__ = [
3
+ "titulo",
4
+ "recriar_pasta",
5
+ "b64encode",
6
+ "b64decode",
7
+ "convert_bquery_result_to_json",
8
+ "get_config"
9
+ ]
@@ -0,0 +1,14 @@
1
+ from .func_titulo import titulo
2
+ from .func_recriar_pastas import recriar_pasta
3
+ from .func_b64 import b64decode, b64encode
4
+ from .func_converters import convert_bquery_result_to_json
5
+ from .func_settings import get_config
6
+
7
+ __all__ = [
8
+ "titulo",
9
+ "recriar_pasta",
10
+ "b64encode",
11
+ "b64decode",
12
+ "convert_bquery_result_to_json",
13
+ "get_config"
14
+ ]
@@ -0,0 +1,50 @@
1
+ import base64
2
+
3
+ def b64decode(b64_string:str=None)->str:
4
+ """Faz o decode de uma string em base64
5
+
6
+ Args:
7
+ b64_string (str): string em base64
8
+
9
+ Returns:
10
+ str: string em texto
11
+ """
12
+
13
+ if b64_string is None or b64_string == "":
14
+
15
+ raise ValueError("Uma string Base64 precisa ser informada com o parâmetro 'b64_string'")
16
+
17
+ try:
18
+
19
+ b64_decode_output = base64.b64decode(b64_string).decode('utf-8')
20
+
21
+ except:
22
+
23
+ raise TypeError("A string informada não está em formato Base64")
24
+
25
+ return b64_decode_output
26
+
27
+ def b64encode(string_to_convert:str=None)->base64:
28
+ """Faz o encode de uma string para base64
29
+
30
+ Args:
31
+ string_to_convert (str): string para converter em base64
32
+
33
+ Returns:
34
+ base64: string convertida para base64
35
+ """
36
+
37
+ if string_to_convert is None or string_to_convert == "":
38
+
39
+ raise ValueError("Uma string precisa ser informada com o parâmetro 'string_to_convert'")
40
+
41
+ try:
42
+
43
+ b64_encode_output = base64.b64encode(str(string_to_convert).encode('utf-8')).decode('utf-8')
44
+
45
+ except Exception as e:
46
+
47
+ raise TypeError(f"Erro ao converter a string para Base64: {e}")
48
+
49
+ return b64_encode_output
50
+
@@ -0,0 +1,18 @@
1
+ def convert_bquery_result_to_json(query_result:list)->list:
2
+ """Converte o resultado de uma query do BigQuery em uma lista de dicionários JSON
3
+
4
+ Args:
5
+ query_result (list): resultado da query do BigQuery (query.result)
6
+
7
+ Returns:
8
+ list: lista de dicionários JSON
9
+ """
10
+
11
+ try:
12
+
13
+ #return [dict(row) for row in query_result]
14
+ return [dict(row._asdict()) for row in query_result]
15
+
16
+ except Exception as e:
17
+
18
+ raise e