csc-cia-stne 0.0.30__py3-none-any.whl → 0.0.31__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.
- csc_cia_stne/__init__.py +49 -25
- csc_cia_stne/gcp_bigquery.py +2 -94
- csc_cia_stne/google_drive.py +238 -0
- csc_cia_stne/logger_json.py +43 -1
- csc_cia_stne/logger_rich.py +17 -8
- csc_cia_stne/provio.py +66 -0
- csc_cia_stne/servicenow.py +405 -218
- csc_cia_stne/utilitarios/functions/func_titulo.py +1 -3
- csc_cia_stne/utilitarios/validations/GcpBigQueryValidator.py +91 -0
- csc_cia_stne/utilitarios/validations/GoogleDriveValidator.py +39 -0
- csc_cia_stne/utilitarios/validations/ServiceNowValidator.py +164 -0
- csc_cia_stne/utilitarios/validations/__init__.py +2 -0
- {csc_cia_stne-0.0.30.dist-info → csc_cia_stne-0.0.31.dist-info}/METADATA +1 -1
- csc_cia_stne-0.0.31.dist-info/RECORD +27 -0
- csc_cia_stne-0.0.30.dist-info/RECORD +0 -21
- {csc_cia_stne-0.0.30.dist-info → csc_cia_stne-0.0.31.dist-info}/LICENCE +0 -0
- {csc_cia_stne-0.0.30.dist-info → csc_cia_stne-0.0.31.dist-info}/WHEEL +0 -0
- {csc_cia_stne-0.0.30.dist-info → csc_cia_stne-0.0.31.dist-info}/top_level.txt +0 -0
csc_cia_stne/__init__.py
CHANGED
@@ -1,36 +1,16 @@
|
|
1
1
|
import os
|
2
2
|
from dotenv import load_dotenv
|
3
|
-
|
4
|
-
|
5
|
-
load_dotenv()
|
6
|
-
logger = None # Inicializa como None
|
7
|
-
#if os.getenv('ambiente_de_execucao') is not None and os.getenv('ambiente_de_execucao') == "karavela":
|
8
|
-
# from .logger_json import logger
|
9
|
-
#else:
|
10
|
-
# from .logger_rich import logger
|
11
|
-
|
12
|
-
|
13
|
-
if os.getenv('ambiente_de_execucao') is not None and os.getenv('ambiente_de_execucao') == "karavela":
|
14
|
-
from .logger_json import get_logger as get_logger_json
|
15
|
-
def logger():
|
16
|
-
return get_logger_json()
|
17
|
-
else:
|
18
|
-
from .logger_rich import get_logger as get_logger_rich
|
19
|
-
def logger():
|
20
|
-
return get_logger_rich()
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
3
|
+
from .logger_json import get_logger as get_logger_json
|
4
|
+
from .logger_rich import get_logger as get_logger_rich
|
25
5
|
from .karavela import Karavela
|
26
|
-
#from .utilitarios.classes import Util
|
27
6
|
from .servicenow import ServiceNow
|
28
7
|
from .stne_admin import StoneAdmin
|
29
8
|
from .bc_sta import BC_STA
|
30
9
|
from .bc_correios import BC_Correios
|
31
10
|
from .gcp_bigquery import BigQuery
|
32
11
|
from .email import Email
|
33
|
-
|
12
|
+
from .provio import Provio
|
13
|
+
|
34
14
|
# Define os itens disponíveis para importação
|
35
15
|
__all__ = [
|
36
16
|
"titulo",
|
@@ -41,5 +21,49 @@ __all__ = [
|
|
41
21
|
"ServiceNow",
|
42
22
|
"Util",
|
43
23
|
"logger",
|
24
|
+
"Provio",
|
44
25
|
"Email"
|
45
|
-
]
|
26
|
+
]
|
27
|
+
|
28
|
+
diretorio_inicial = os.getcwd()
|
29
|
+
caminho_env = os.path.join(diretorio_inicial, ".env")
|
30
|
+
|
31
|
+
# Carrega .env
|
32
|
+
load_dotenv(caminho_env)
|
33
|
+
logger = None # Inicializa como None
|
34
|
+
|
35
|
+
def running_in_container():
|
36
|
+
|
37
|
+
if os.environ.get("KUBERNETES_SERVICE_HOST") or os.path.exists("/.dockerenv"):
|
38
|
+
|
39
|
+
return True
|
40
|
+
|
41
|
+
try:
|
42
|
+
|
43
|
+
with open("/proc/1/cgroup", "rt") as file:
|
44
|
+
|
45
|
+
for line in file:
|
46
|
+
|
47
|
+
if "docker" in line or "kubepods" in line:
|
48
|
+
|
49
|
+
return True
|
50
|
+
|
51
|
+
except FileNotFoundError as e:
|
52
|
+
|
53
|
+
return False
|
54
|
+
|
55
|
+
return False
|
56
|
+
|
57
|
+
def logger():
|
58
|
+
|
59
|
+
if os.getenv('ambiente_de_execucao') is not None and os.getenv('ambiente_de_execucao') == "karavela":
|
60
|
+
|
61
|
+
return get_logger_json()
|
62
|
+
|
63
|
+
elif running_in_container():
|
64
|
+
|
65
|
+
return get_logger_json()
|
66
|
+
|
67
|
+
else:
|
68
|
+
|
69
|
+
return get_logger_rich()
|
csc_cia_stne/gcp_bigquery.py
CHANGED
@@ -1,99 +1,7 @@
|
|
1
1
|
from google.cloud import bigquery
|
2
|
-
import json
|
3
|
-
import os
|
4
2
|
from google.oauth2 import service_account
|
5
|
-
from pydantic import
|
6
|
-
|
7
|
-
class InitParamsValidator(BaseModel):
|
8
|
-
limit:int
|
9
|
-
id_project:str
|
10
|
-
creds_dict:dict
|
11
|
-
creds_file:str
|
12
|
-
|
13
|
-
@field_validator('limit')
|
14
|
-
def check_input_basic(cls, value, info):
|
15
|
-
if not isinstance(value, int):
|
16
|
-
raise ValueError(f"O parametro 'limit' deve ser um inteiro e não um {type(value)}")
|
17
|
-
|
18
|
-
return value
|
19
|
-
|
20
|
-
@field_validator('id_project')
|
21
|
-
def check_str_input(cls, value, info):
|
22
|
-
if not isinstance(value, str) or not value.strip():
|
23
|
-
raise ValueError(f"O parametro 'id_project' deve ser uma string e não um {type(value)} e não vazio")
|
24
|
-
return value
|
25
|
-
|
26
|
-
@model_validator(mode="after")
|
27
|
-
def check_others_input(cls, model):
|
28
|
-
creds_dict = model.creds_dict
|
29
|
-
creds_file = model.creds_file
|
30
|
-
|
31
|
-
if isinstance(creds_dict, dict):
|
32
|
-
return model
|
33
|
-
|
34
|
-
elif isinstance(creds_file, str) and creds_file.strip():
|
35
|
-
return model
|
36
|
-
|
37
|
-
else:
|
38
|
-
raise ValueError("Pelo menos um dos parâmetros 'creds_dict' ou 'creds_file' deve ser fornecido.")
|
39
|
-
|
40
|
-
|
41
|
-
class tryQueryValidator(BaseModel):
|
42
|
-
|
43
|
-
query_to_execute:str
|
44
|
-
organize:bool
|
45
|
-
use_legacy:bool
|
46
|
-
use_cache:bool
|
47
|
-
query_parameters:list
|
48
|
-
|
49
|
-
@field_validator('query_to_execute')
|
50
|
-
def check_str_input(cls, value, info):
|
51
|
-
if not isinstance(value, str) or not value.strip():
|
52
|
-
raise ValueError(f"O parametro '{info.field_name}' deve ser uma string não vazia")
|
53
|
-
|
54
|
-
return value
|
55
|
-
|
56
|
-
@field_validator('organize','use_legacy','use_cache')
|
57
|
-
def check_bool_input(cls, value, info):
|
58
|
-
if not isinstance(value, bool):
|
59
|
-
raise ValueError(f"O parametro '{info.field_name}' deve ser um boleano")
|
60
|
-
|
61
|
-
return value
|
62
|
-
|
63
|
-
@field_validator('query_parameters')
|
64
|
-
def check_list_input(cls, value, info):
|
65
|
-
if not isinstance(value, list):
|
66
|
-
raise ValueError(f"O parametro '{info.field_name}' deve ser uma lista")
|
67
|
-
|
68
|
-
return value
|
69
|
-
|
70
|
-
|
71
|
-
class tryInsertListValidator(BaseModel):
|
72
|
-
|
73
|
-
insert_limit:int
|
74
|
-
list_to_insert:list
|
75
|
-
table:str
|
76
|
-
|
77
|
-
@field_validator('list_to_insert')
|
78
|
-
def check_list_input(cls, value, info):
|
79
|
-
if not isinstance(value, list) and len(value) > 0:
|
80
|
-
raise ValueError(f"O parametro '{info.field_name}' deve ser uma lista e não estar vazia")
|
81
|
-
|
82
|
-
return value
|
83
|
-
|
84
|
-
@field_validator('table')
|
85
|
-
def check_str_input(cls, value, info):
|
86
|
-
if not isinstance(value, str) or not value.strip():
|
87
|
-
raise ValueError(f"O parametro '{info.field_name}' deve ser uma string não vazia")
|
88
|
-
|
89
|
-
return value
|
90
|
-
|
91
|
-
@field_validator('insert_limit')
|
92
|
-
def check_int_input(cls, value, info):
|
93
|
-
if not isinstance(value, int) or value > 10000:
|
94
|
-
raise ValueError(f"O parametro '{info.field_name}' deve ser um inteiro não maior que 10000")
|
95
|
-
|
96
|
-
return value
|
3
|
+
from pydantic import ValidationError
|
4
|
+
from .utilitarios.validations.GcpBigQueryValidator import tryQueryValidator, InitParamsValidator, tryInsertListValidator
|
97
5
|
|
98
6
|
class BigQuery():
|
99
7
|
|
@@ -0,0 +1,238 @@
|
|
1
|
+
import os, time, logging, json
|
2
|
+
from .karavela import Karavela
|
3
|
+
from googleapiclient.discovery import build
|
4
|
+
from googleapiclient.http import MediaFileUpload
|
5
|
+
from googleapiclient.errors import HttpError
|
6
|
+
from io import BytesIO
|
7
|
+
from googleapiclient.discovery import build
|
8
|
+
from google.oauth2 import service_account
|
9
|
+
from .utilitarios.validations.GoogleDriveValidator import InitParamsValidator, CreateFolderValidator, ListFolderValidator
|
10
|
+
from pydantic import ValidationError
|
11
|
+
|
12
|
+
|
13
|
+
|
14
|
+
class GoogleDrive():
|
15
|
+
|
16
|
+
"""
|
17
|
+
Classe responsável por gerenciar operações no Google Drive, como upload de arquivos, criação de pastas
|
18
|
+
e listagem de conteúdo. Utiliza a API do Google Drive para realizar essas operações.
|
19
|
+
|
20
|
+
Args:
|
21
|
+
key (str): Chave de autenticação para acessar a API do Google Drive.
|
22
|
+
"""
|
23
|
+
|
24
|
+
def __init__(self, key, with_subject : str, scopes : list = ["https://www.googleapis.com/auth/drive"], version : str = "v3"):
|
25
|
+
"""
|
26
|
+
Inicializa a classe GoogleDrive e autentica o serviço usando a chave fornecida.
|
27
|
+
|
28
|
+
Args:
|
29
|
+
key (str): Chave de autenticação do Google Drive.
|
30
|
+
"""
|
31
|
+
try:
|
32
|
+
InitParamsValidator(key=key, with_subject=with_subject, scopes=scopes)
|
33
|
+
except ValidationError as e:
|
34
|
+
raise ValueError("Erro na validação dos dados de input da inicialização da instância:", e.errors())
|
35
|
+
|
36
|
+
self.__token = json.loads(Karavela.get_secret(key))
|
37
|
+
self.version = version
|
38
|
+
self.scopes = scopes
|
39
|
+
self.__auth = self.__autentica(with_subject)
|
40
|
+
self.page_size = 1000
|
41
|
+
self.service = self.create_service()
|
42
|
+
|
43
|
+
def timer_decorator(func):
|
44
|
+
"""
|
45
|
+
Classe reponsável por calcular qualquer execução que ela seja chamada.
|
46
|
+
"""
|
47
|
+
def wrapper(*args, **kwargs):
|
48
|
+
inicio = time.time()
|
49
|
+
resultado = func(*args, **kwargs)
|
50
|
+
fim = time.time()
|
51
|
+
logging.debug(f"Tempo de execução de {func.__name__}: {fim - inicio:.2f} segundos")
|
52
|
+
return resultado
|
53
|
+
return wrapper
|
54
|
+
|
55
|
+
def create_service(self):
|
56
|
+
"""
|
57
|
+
Cria um serviço para a plataforma Google especificada.
|
58
|
+
|
59
|
+
Args:
|
60
|
+
platform (str): O nome da plataforma Google para a qual o serviço será criado (por exemplo, 'drive', 'sheets').
|
61
|
+
|
62
|
+
Returns:
|
63
|
+
googleapiclient.discovery.Resource: Serviço do Google para a plataforma especificada.
|
64
|
+
bool: Retorna False se houver um erro ao criar o serviço.
|
65
|
+
"""
|
66
|
+
try:
|
67
|
+
|
68
|
+
cred = build(f"drive", f"{self.version}", credentials=self.__auth)
|
69
|
+
logging.debug(f"Serviço do Google drive criado")
|
70
|
+
return cred
|
71
|
+
except Exception as e:
|
72
|
+
logging.debug(f"Erro ao criar o serviço do Google drive: Error: {e}")
|
73
|
+
return False
|
74
|
+
|
75
|
+
def __autentica(self, with_subject : str):
|
76
|
+
"""
|
77
|
+
Autentica o serviço do Google utilizando um token e escopos fornecidos.
|
78
|
+
|
79
|
+
Args:
|
80
|
+
token (dict): As credenciais de autenticação.
|
81
|
+
scopes (list): A lista de escopos para o acesso aos serviços do Google.
|
82
|
+
|
83
|
+
Returns:
|
84
|
+
google.oauth2.service_account.Credentials: Objeto de credenciais autenticado.
|
85
|
+
bool: Retorna False em caso de erro.
|
86
|
+
"""
|
87
|
+
|
88
|
+
try:
|
89
|
+
credentials = service_account.Credentials.from_service_account_info(self.__token, scopes=self.scopes)
|
90
|
+
delegated_credencial = credentials.with_subject(with_subject)
|
91
|
+
return delegated_credencial
|
92
|
+
|
93
|
+
except Exception as e:
|
94
|
+
logging.debug(f"Erro ao tentar autenticar. Verifique o erro: {e}")
|
95
|
+
return False
|
96
|
+
|
97
|
+
@timer_decorator
|
98
|
+
def upload(self, folder_id: str, name: str, file_path: str, mimetype: str):
|
99
|
+
"""
|
100
|
+
Faz o upload de um arquivo para o Google Drive em uma pasta especificada.
|
101
|
+
|
102
|
+
Args:
|
103
|
+
folder_id (str): ID da pasta no Google Drive onde o arquivo será armazenado.
|
104
|
+
name (str): Nome do arquivo que será carregado.
|
105
|
+
file_path (str): Caminho completo do arquivo no sistema local.
|
106
|
+
mimetype (str): Tipo MIME do arquivo a ser carregado.
|
107
|
+
|
108
|
+
Returns:
|
109
|
+
dict: Informações sobre o arquivo carregado, incluindo o ID do arquivo.
|
110
|
+
None: Caso o caminho do arquivo não seja encontrado.
|
111
|
+
"""
|
112
|
+
file_metadata = {"name": name, "parents": [folder_id]}
|
113
|
+
if not os.path.exists(file_path):
|
114
|
+
logging.debug(f"Pasta {file_path} não encontrada")
|
115
|
+
return {"success" : False, "result" : None, "error" : "Diretório ou arquivo não encontrado"}
|
116
|
+
|
117
|
+
try:
|
118
|
+
logging.debug(f"Realizando o upload do arquivo")
|
119
|
+
media = MediaFileUpload(file_path, mimetype=mimetype, resumable=True)
|
120
|
+
file = (
|
121
|
+
self.service.files()
|
122
|
+
.create(body=file_metadata, media_body=media, fields="id", supportsAllDrives=True)
|
123
|
+
.execute()
|
124
|
+
)
|
125
|
+
|
126
|
+
logging.debug(f"Upload realizado com sucesso")
|
127
|
+
return {"success" : True, "result" : file}
|
128
|
+
except Exception as e:
|
129
|
+
logging.debug(f"Erro ao realizar o upload do arquivo {name} no google drive. Erro: {e}")
|
130
|
+
return {"success" : False, "result" : None, "error" : str(e)}
|
131
|
+
|
132
|
+
def create_folder(self, name: str, parent_folder_id: str):
|
133
|
+
"""
|
134
|
+
Cria uma pasta no Google Drive dentro de uma pasta existente.
|
135
|
+
|
136
|
+
Args:
|
137
|
+
name (str): Nome da pasta a ser criada.
|
138
|
+
parent_folder_id (int): ID da pasta pai onde a nova pasta será criada.
|
139
|
+
|
140
|
+
Returns:
|
141
|
+
str: ID da pasta criada.
|
142
|
+
"""
|
143
|
+
try:
|
144
|
+
CreateFolderValidator(name=name, parent_folder_id=parent_folder_id)
|
145
|
+
except ValidationError as e:
|
146
|
+
raise ValueError("Erro na validação dos dados de input da inicialização da instância:", e.errors())
|
147
|
+
|
148
|
+
try:
|
149
|
+
folder_metadata = {
|
150
|
+
"name": name,
|
151
|
+
"parents": [parent_folder_id],
|
152
|
+
"mimeType": "application/vnd.google-apps.folder",
|
153
|
+
}
|
154
|
+
folder = (
|
155
|
+
self.service.files().create(body=folder_metadata, fields="id", supportsAllDrives=True).execute()
|
156
|
+
)
|
157
|
+
return {"success" : True, "result": folder}
|
158
|
+
except Exception as e:
|
159
|
+
logging.debug(f"Não foi possível criar a pasta {name}")
|
160
|
+
return {"success" : False, "result": None, "error" : str(e)}
|
161
|
+
|
162
|
+
def list(self, query: str = "", spaces: str = "drive", fields: str = "nextPageToken, files(id, name)"):
|
163
|
+
"""
|
164
|
+
Lista os arquivos e pastas no Google Drive com base nos critérios fornecidos.
|
165
|
+
|
166
|
+
Args:
|
167
|
+
query (str, optional): Critério de busca para os arquivos ou pastas no Google Drive.
|
168
|
+
Consulte https://developers.google.com/drive/api/v3/ref-search-terms.
|
169
|
+
Defaults to "".
|
170
|
+
spaces (str, optional): Especifica os locais de armazenamento a serem consultados. Pode ser 'drive',
|
171
|
+
'appDataFolder', ou 'photos'. Defaults to 'drive'.
|
172
|
+
fields (str, optional): Campos a serem retornados na resposta. Consulte a documentação para os campos disponíveis.
|
173
|
+
Defaults to "nextPageToken, files(id, name)".
|
174
|
+
|
175
|
+
Returns:
|
176
|
+
dict: Dicionário contendo o resultado da busca.
|
177
|
+
"""
|
178
|
+
try:
|
179
|
+
ListFolderValidator(query=query, fields=fields, spaces=spaces)
|
180
|
+
except ValidationError as e:
|
181
|
+
raise ValueError("Erro na validação dos dados de input da lista:", e.errors())
|
182
|
+
try:
|
183
|
+
results = (
|
184
|
+
self.service.files()
|
185
|
+
.list(q=query,
|
186
|
+
spaces=spaces,
|
187
|
+
pageSize=self.page_size,
|
188
|
+
fields=fields,
|
189
|
+
supportsAllDrives=True,
|
190
|
+
includeItemsFromAllDrives=True)
|
191
|
+
.execute()
|
192
|
+
)
|
193
|
+
return {"success" : True, "result" : results}
|
194
|
+
except HttpError as hr:
|
195
|
+
logging.debug(f"Ocorreu um de http. Erro: {hr}")
|
196
|
+
return {"success" : False, "result" : None, "error" : str(hr)}
|
197
|
+
|
198
|
+
@timer_decorator
|
199
|
+
def get_file(self, file : str, ):
|
200
|
+
"""
|
201
|
+
Obtém o conteúdo de um arquivo armazenado no Google Drive.
|
202
|
+
|
203
|
+
Esta função acessa o Google Drive usando a API e lê os dados do arquivo especificado, retornando-os como um objeto binário de memória (`BytesIO`).
|
204
|
+
|
205
|
+
Parâmetros:
|
206
|
+
- file (str): Dicionário contendo informações do arquivo no Google Drive, incluindo as chaves:
|
207
|
+
- `"name"`: Nome do arquivo.
|
208
|
+
- `"id"`: ID do arquivo.
|
209
|
+
|
210
|
+
Retorna:
|
211
|
+
- BytesIO: Objeto em memória contendo os dados do arquivo.
|
212
|
+
- None: Caso ocorra um erro ao tentar abrir ou ler o arquivo.
|
213
|
+
|
214
|
+
Logs:
|
215
|
+
- Registra mensagens indicando o início e o término da leitura do arquivo.
|
216
|
+
- Em caso de falha, registra o erro ocorrido.
|
217
|
+
|
218
|
+
Exceções:
|
219
|
+
- Qualquer erro durante o processo será capturado e registrado no log. A função retornará `None` nesses casos.
|
220
|
+
|
221
|
+
Dependências:
|
222
|
+
- A função assume a existência de um atributo `self.service` configurado para interagir com a API do Google Drive.
|
223
|
+
"""
|
224
|
+
try:
|
225
|
+
# file_metadata = self.service.files().get(fileId=file_id, fields="name, mimeType").execute()
|
226
|
+
logging.debug(f"Lendo o arquivo {file.get("name")}")
|
227
|
+
request = self.service.files().get_media(fileId=file.get("id"))
|
228
|
+
file_data = BytesIO(request.execute())
|
229
|
+
logging.debug("Leitura do arquivo finalizada")
|
230
|
+
|
231
|
+
return {"success" : True, "result" : file_data}
|
232
|
+
|
233
|
+
except Exception as e:
|
234
|
+
logging.debug(f"Erro ao tentar abrir o arquivo. Erro {e}")
|
235
|
+
return {"success" : False, "result" : None}
|
236
|
+
|
237
|
+
|
238
|
+
|
csc_cia_stne/logger_json.py
CHANGED
@@ -2,7 +2,49 @@ import logging
|
|
2
2
|
from pythonjsonlogger import jsonlogger
|
3
3
|
|
4
4
|
def setup_json_logger():
|
5
|
-
|
5
|
+
|
6
|
+
def add_log_level(level_name, level_num, method_name=None):
|
7
|
+
"""
|
8
|
+
Adiciona um log level
|
9
|
+
|
10
|
+
Parâmetros:
|
11
|
+
level_name (str): Nome do level
|
12
|
+
level_num (int): Número do level
|
13
|
+
"""
|
14
|
+
if not method_name:
|
15
|
+
|
16
|
+
method_name = level_name.lower()
|
17
|
+
|
18
|
+
if hasattr(logging, level_name):
|
19
|
+
|
20
|
+
raise AttributeError('{} already defined in logging module'.format(level_name))
|
21
|
+
|
22
|
+
if hasattr(logging, method_name):
|
23
|
+
|
24
|
+
raise AttributeError('{} already defined in logging module'.format(method_name))
|
25
|
+
|
26
|
+
if hasattr(logging.getLoggerClass(), method_name):
|
27
|
+
|
28
|
+
raise AttributeError('{} already defined in logger class'.format(method_name))
|
29
|
+
|
30
|
+
def log_for_level(self, message, *args, **kwargs):
|
31
|
+
|
32
|
+
if self.isEnabledFor(level_num):
|
33
|
+
|
34
|
+
#self._log(level_num, message, args, **kwargs)
|
35
|
+
self._log(level_num, message, args, **{**kwargs, "stacklevel": 2})
|
36
|
+
|
37
|
+
def log_to_root(message, *args, **kwargs):
|
38
|
+
|
39
|
+
logging.log(level_num, message, *args, **kwargs)
|
40
|
+
|
41
|
+
logging.addLevelName(level_num, level_name)
|
42
|
+
setattr(logging, level_name, level_num)
|
43
|
+
setattr(logging.getLoggerClass(), method_name, log_for_level)
|
44
|
+
setattr(logging, method_name, log_to_root)
|
45
|
+
|
46
|
+
add_log_level("SUCCESS",21)
|
47
|
+
logger = logging.getLogger(__name__)
|
6
48
|
logger.setLevel(logging.INFO)
|
7
49
|
|
8
50
|
# Remove handlers anteriores, se houver
|
csc_cia_stne/logger_rich.py
CHANGED
@@ -120,21 +120,30 @@ def get_logger():
|
|
120
120
|
install()
|
121
121
|
|
122
122
|
# Definindo o nível de log baseado nas configurações
|
123
|
-
if os.getenv('log_level') is None:
|
123
|
+
if os.getenv('log_level') is None or os.getenv('log_level') == "DEBUG":
|
124
124
|
|
125
|
-
log_config_level = logging.
|
126
|
-
|
127
|
-
elif os.getenv('log_level') == "DEBUG":
|
128
|
-
|
129
|
-
log_config_level = logging.DEBUG
|
125
|
+
log_config_level = logging.INFO
|
130
126
|
|
131
127
|
elif os.getenv('log_level') == "INFO":
|
132
128
|
|
133
129
|
log_config_level = logging.INFO
|
130
|
+
|
131
|
+
elif os.getenv('log_level') == "WARNING" or os.getenv('log_level') == "WARN":
|
132
|
+
|
133
|
+
log_config_level = logging.WARNING
|
134
|
+
|
135
|
+
elif os.getenv('log_level') == "ERROR":
|
136
|
+
|
137
|
+
log_config_level = logging.ERROR
|
138
|
+
|
139
|
+
elif os.getenv('log_level') == "CRITICAL":
|
140
|
+
|
141
|
+
log_config_level = logging.CRITICAL
|
134
142
|
|
135
143
|
else:
|
136
144
|
|
137
|
-
log_config_level = logging.
|
145
|
+
log_config_level = logging.INFO # ou outro nível padrão
|
146
|
+
raise ValueError("'log_level' precisa ser 'DEBUG,'INFO','WARNING','ERROR' ou 'CRITICAL'")
|
138
147
|
|
139
148
|
# Definindo o tema customizado
|
140
149
|
custom_theme = Theme({
|
@@ -220,6 +229,6 @@ def get_logger():
|
|
220
229
|
|
221
230
|
add_log_level("SUCCESS",21)
|
222
231
|
|
223
|
-
logger = logging.getLogger()
|
232
|
+
logger = logging.getLogger(__name__)
|
224
233
|
|
225
234
|
return logger
|
csc_cia_stne/provio.py
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
import logging
|
2
|
+
import requests
|
3
|
+
from requests.auth import HTTPBasicAuth
|
4
|
+
from pydantic import BaseModel, Field, ValidationError
|
5
|
+
|
6
|
+
# Validadores
|
7
|
+
class ProvioModel(BaseModel):
|
8
|
+
username: str = Field(..., strip_whitespace=True, min_length=1)
|
9
|
+
password: str = Field(..., strip_whitespace=True, min_length=1)
|
10
|
+
|
11
|
+
class ExportarRelatorioParams(BaseModel):
|
12
|
+
ano: int = Field(..., gt=2015, description="O ano deve ser maior que 2015")
|
13
|
+
mes: int = Field(..., ge=1, le=12, description="O mês deve estar entre 1 e 12")
|
14
|
+
|
15
|
+
# Classe provio
|
16
|
+
class Provio:
|
17
|
+
|
18
|
+
def __init__(self,username:str,password:str):
|
19
|
+
|
20
|
+
# Validação usando Pydantic
|
21
|
+
data = ProvioModel(username=username, password=password)
|
22
|
+
|
23
|
+
self.api_url = "https://provio.apps.stone.com.br/api/reports"
|
24
|
+
self.auth = HTTPBasicAuth(data.username, data.password)
|
25
|
+
|
26
|
+
def exportar_relatorio_geral(self, ano:int, mes:int):
|
27
|
+
|
28
|
+
# Validação dos parâmetros
|
29
|
+
params = ExportarRelatorioParams(ano=ano, mes=mes)
|
30
|
+
periodo = f"{params.ano}-{params.mes:02d}"
|
31
|
+
skip = 0
|
32
|
+
todos_os_dados = [] # Lista para armazenar todos os resultados
|
33
|
+
requisicao = 0
|
34
|
+
try:
|
35
|
+
|
36
|
+
while True:
|
37
|
+
|
38
|
+
url = f"{self.api_url}/general/{periodo}/{skip}"
|
39
|
+
response = requests.get(url=url, auth=self.auth)
|
40
|
+
|
41
|
+
if response.status_code == 200:
|
42
|
+
|
43
|
+
dados = response.json()
|
44
|
+
|
45
|
+
# Verifica se há itens na resposta
|
46
|
+
if not dados: # Se a resposta for vazia, interrompa o loop
|
47
|
+
|
48
|
+
break
|
49
|
+
|
50
|
+
# Adiciona os dados recebidos à lista total
|
51
|
+
todos_os_dados.extend(dados)
|
52
|
+
|
53
|
+
# Incrementa o skip para buscar a próxima página
|
54
|
+
skip += 500
|
55
|
+
requisicao += 1
|
56
|
+
logging.info(f"Exportando relatório: Requisição #{str(requisicao).zfill(3)} - {len(todos_os_dados)} registros exportados")
|
57
|
+
|
58
|
+
else:
|
59
|
+
|
60
|
+
return {"success": False, "error": f"{response.status_code} - {response.text}"}
|
61
|
+
|
62
|
+
return {"success": True, "error": None, "report": todos_os_dados}
|
63
|
+
|
64
|
+
except Exception as e:
|
65
|
+
|
66
|
+
return {"success": False, "error": str(e)}
|