csc-cia-stne 0.0.43__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
@@ -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