csc-cia-stne 0.0.63__py3-none-any.whl → 0.0.65__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/bc_sta.py +201 -2
- csc_cia_stne/utilitarios/functions/func_rdp.py +1 -0
- {csc_cia_stne-0.0.63.dist-info → csc_cia_stne-0.0.65.dist-info}/METADATA +1 -1
- {csc_cia_stne-0.0.63.dist-info → csc_cia_stne-0.0.65.dist-info}/RECORD +7 -7
- {csc_cia_stne-0.0.63.dist-info → csc_cia_stne-0.0.65.dist-info}/LICENCE +0 -0
- {csc_cia_stne-0.0.63.dist-info → csc_cia_stne-0.0.65.dist-info}/WHEEL +0 -0
- {csc_cia_stne-0.0.63.dist-info → csc_cia_stne-0.0.65.dist-info}/top_level.txt +0 -0
csc_cia_stne/bc_sta.py
CHANGED
@@ -2,8 +2,52 @@ from requests.auth import HTTPBasicAuth
|
|
2
2
|
import requests
|
3
3
|
import xml.etree.ElementTree as ET
|
4
4
|
import hashlib
|
5
|
-
from pydantic import BaseModel, ValidationError, field_validator
|
5
|
+
from pydantic import BaseModel, ValidationError, field_validator, Field, HttpUrl
|
6
6
|
from typing import Literal, Dict, Union, Optional
|
7
|
+
import json
|
8
|
+
|
9
|
+
def xml_to_dict(element):
|
10
|
+
"""Converte um elemento XML recursivamente para um dicionário."""
|
11
|
+
if not list(element): # Se não tem filhos, retorna apenas o texto
|
12
|
+
return element.text.strip() if element.text else ""
|
13
|
+
|
14
|
+
result = {}
|
15
|
+
for child in element:
|
16
|
+
child_data = xml_to_dict(child)
|
17
|
+
if child.tag in result:
|
18
|
+
if isinstance(result[child.tag], list):
|
19
|
+
result[child.tag].append(child_data)
|
20
|
+
else:
|
21
|
+
result[child.tag] = [result[child.tag], child_data]
|
22
|
+
else:
|
23
|
+
result[child.tag] = child_data
|
24
|
+
|
25
|
+
if element.attrib:
|
26
|
+
result["@atributos"] = element.attrib # Adiciona atributos XML se existirem
|
27
|
+
|
28
|
+
return result
|
29
|
+
|
30
|
+
def xml_response_to_json(response_text):
|
31
|
+
"""Converte a resposta XML para um dicionário JSON válido."""
|
32
|
+
|
33
|
+
root = ET.fromstring(response_text)
|
34
|
+
lista = xml_to_dict(root)
|
35
|
+
if not isinstance(lista, dict):
|
36
|
+
return []
|
37
|
+
return list(lista.values())[0] # Agora retorna um dicionário em vez de uma string JSON
|
38
|
+
|
39
|
+
def print_element(element, indent=0):
|
40
|
+
"""Função recursiva para exibir campos e subcampos"""
|
41
|
+
prefix = " " * (indent * 2) # Indentação para visualização hierárquica
|
42
|
+
print(f"{prefix}- {element.tag}: {element.text.strip() if element.text else ''}")
|
43
|
+
|
44
|
+
# Se o elemento tiver atributos, exibir
|
45
|
+
if element.attrib:
|
46
|
+
print(f"{prefix} Atributos: {element.attrib}")
|
47
|
+
|
48
|
+
# Percorrer subelementos
|
49
|
+
for child in element:
|
50
|
+
print_element(child, indent + 1)
|
7
51
|
|
8
52
|
# Validações dos inputs
|
9
53
|
class InitParamsValidator(BaseModel):
|
@@ -118,7 +162,34 @@ class EnviarArquivoValidator(BaseModel):
|
|
118
162
|
raise ValueError("Cada destinatário deve conter as chaves 'unidade', 'dependencia' e 'operador'. Verifique a documentação da API BC STA para entender o que colocar cada campo")
|
119
163
|
|
120
164
|
return value
|
121
|
-
|
165
|
+
|
166
|
+
class ListarArquivosParams(BaseModel):
|
167
|
+
"""
|
168
|
+
Parâmetros para listar arquivos disponíveis na API STA.
|
169
|
+
|
170
|
+
Atributos:
|
171
|
+
nivel (str): Nível de detalhe da consulta. Aceita apenas 'RES', 'BAS' ou 'COMPL'.
|
172
|
+
inicio (str): Data e hora de início no formato ISO 8601 (yyyy-MM-ddTHH:mm:ss).
|
173
|
+
situacao (Optional[str]): Situação da transmissão, podendo ser 'REC' ou 'A_REC'.
|
174
|
+
identificadorDocumento (Optional[str]): Identificador do documento, se aplicável.
|
175
|
+
qtd (int): Quantidade máxima de resultados (valor padrão: 100, máximo permitido: 100).
|
176
|
+
"""
|
177
|
+
nivel: Literal['RES', 'BAS', 'COMPL']
|
178
|
+
#inicio: str = Field(..., regex=r"^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}$")
|
179
|
+
inicio: str = Field(..., pattern=r"^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}$")
|
180
|
+
situacao: Optional[Literal['REC', 'A_REC']] = None
|
181
|
+
identificadorDocumento: Optional[str] = None
|
182
|
+
qtd: int = Field(default=100, le=100)
|
183
|
+
|
184
|
+
class DownloadArquivoParams(BaseModel):
|
185
|
+
protocolo: str = Field(..., min_length=1, description="Código do protocolo")
|
186
|
+
filename: Optional[str] = Field(None, description="Nome e caminho do arquivo")
|
187
|
+
|
188
|
+
class DownloadArquivoResponse(BaseModel):
|
189
|
+
success: bool = Field(..., description="Indica se o download foi bem-sucedido")
|
190
|
+
status_code: int = Field(..., ge=100, le=599, description="Código de status HTTP")
|
191
|
+
content: Union[bytes, str] = Field(..., description="Conteúdo do arquivo (em bytes se sucesso, em string se erro)")
|
192
|
+
|
122
193
|
class BC_STA:
|
123
194
|
|
124
195
|
def __init__(self, usuario:str, senha:str, ambiente:str):
|
@@ -414,3 +485,131 @@ class BC_STA:
|
|
414
485
|
#return f"Failed to create protocol. Status code: {response.status_code}, Reason: {response.reason}"
|
415
486
|
return resposta
|
416
487
|
|
488
|
+
def listar_arquivos_old(self, nivel: Literal['RES', 'BAS', 'COMPL'], inicio: str, situacao: Optional[Literal['REC', 'A_REC']] = None, identificadorDocumento: Optional[str] = None, qtd: int = 100):
|
489
|
+
"""
|
490
|
+
Lista os arquivos disponíveis na API STA.
|
491
|
+
|
492
|
+
Args:
|
493
|
+
nivel (str): Nível de detalhe da consulta ('RES', 'BAS' ou 'COMPL').
|
494
|
+
inicio (str): Data e hora de início no formato ISO 8601 (yyyy-MM-ddTHH:mm:ss).
|
495
|
+
situacao (Optional[str]): Situação da transmissão ('REC' ou 'A_REC').
|
496
|
+
identificadorDocumento (Optional[str]): Identificador do documento.
|
497
|
+
qtd (int): Quantidade máxima de resultados (padrão: 100, máximo: 100).
|
498
|
+
|
499
|
+
Returns:
|
500
|
+
dict: Resposta da API em formato JSON.
|
501
|
+
"""
|
502
|
+
params = ListarArquivosParams(nivel=nivel, inicio=inicio, situacao=situacao, identificadorDocumento=identificadorDocumento, qtd=qtd)
|
503
|
+
|
504
|
+
url = f"{self.base_url}/arquivos?tipoConsulta=AVANC&nivelDetalhe={params.nivel}"
|
505
|
+
url += f"&dataHoraInicio={params.inicio}&situacaoTransmissao={params.situacao}" if params.situacao else ""
|
506
|
+
url += f"&identificadorDocumento={params.identificadorDocumento}" if params.identificadorDocumento else ""
|
507
|
+
url += f"&qtdMaxResultados={params.qtd}"
|
508
|
+
|
509
|
+
response = requests.get(
|
510
|
+
url,
|
511
|
+
headers=self.headers,
|
512
|
+
auth=self.auth,
|
513
|
+
timeout=60,
|
514
|
+
)
|
515
|
+
|
516
|
+
if response.status_code == 200:
|
517
|
+
return xml_response_to_json(response.text) # Retorna um dicionário
|
518
|
+
|
519
|
+
|
520
|
+
else:
|
521
|
+
print(f"Erro ao listar arquivos: {response.status_code}")
|
522
|
+
return None
|
523
|
+
|
524
|
+
def listar_arquivos(self, nivel: Literal['RES', 'BAS', 'COMPL'], inicio: str, situacao: Optional[Literal['REC', 'A_REC']] = None, identificadorDocumento: Optional[str] = None, qtd: int = 100):
|
525
|
+
resultados = []
|
526
|
+
ultima_data = inicio
|
527
|
+
|
528
|
+
while True:
|
529
|
+
params = ListarArquivosParams(nivel=nivel, inicio=ultima_data, situacao=situacao, identificadorDocumento=identificadorDocumento, qtd=qtd)
|
530
|
+
|
531
|
+
url = f"{self.base_url}/arquivos?tipoConsulta=AVANC&nivelDetalhe={params.nivel}"
|
532
|
+
url += f"&dataHoraInicio={params.inicio}&situacaoTransmissao={params.situacao}" if params.situacao else ""
|
533
|
+
url += f"&identificadorDocumento={params.identificadorDocumento}" if params.identificadorDocumento else ""
|
534
|
+
url += f"&qtdMaxResultados={params.qtd}"
|
535
|
+
|
536
|
+
response = requests.get(
|
537
|
+
url,
|
538
|
+
headers=self.headers,
|
539
|
+
auth=self.auth,
|
540
|
+
timeout=60,
|
541
|
+
)
|
542
|
+
|
543
|
+
if response.status_code == 200:
|
544
|
+
try:
|
545
|
+
dados = xml_response_to_json(response.text)
|
546
|
+
#print(dados)
|
547
|
+
#print(type(dados))
|
548
|
+
|
549
|
+
if not dados: # Verifica se a lista está vazia
|
550
|
+
#print("lista ta vaziaaaa")
|
551
|
+
break # Sai do loop se não houver mais dados
|
552
|
+
resultados.extend(dados)
|
553
|
+
# Verifica se o campo 'DataHoraDisponibilizacao' existe no último registro
|
554
|
+
if dados and isinstance(dados, list) and 'DataHoraDisponibilizacao' in dados[-1]:
|
555
|
+
ultima_data = dados[-1]['DataHoraDisponibilizacao'] # Atualiza a data para a próxima requisição
|
556
|
+
else:
|
557
|
+
print("Campo 'DataHoraDisponibilizacao' não encontrado ou estrutura inesperada.")
|
558
|
+
break
|
559
|
+
except ET.ParseError as e:
|
560
|
+
print(f"Erro ao processar XML: {e}")
|
561
|
+
break
|
562
|
+
else:
|
563
|
+
print(f"Erro ao listar arquivos: {response.status_code}")
|
564
|
+
break
|
565
|
+
return resultados
|
566
|
+
|
567
|
+
def download_arquivo(self,protocolo:str,filename:str=None):
|
568
|
+
"""Faz o download de um arquivo de um protocolo especifico
|
569
|
+
|
570
|
+
Args:
|
571
|
+
protocolo (str): protocolo
|
572
|
+
filename (str): path+nome do arquivo
|
573
|
+
|
574
|
+
Returns:
|
575
|
+
dict: {"success": bool, "status_code": int, "content": bytes/str}
|
576
|
+
"""
|
577
|
+
|
578
|
+
# Validação dos parâmetros
|
579
|
+
try:
|
580
|
+
|
581
|
+
params = DownloadArquivoParams(protocolo=protocolo, filename=filename)
|
582
|
+
|
583
|
+
except ValidationError as e:
|
584
|
+
|
585
|
+
return Exception(str(e))
|
586
|
+
|
587
|
+
url = f"/arquivos/{protocolo}/conteudo"
|
588
|
+
response = requests.get(
|
589
|
+
self.base_url + url,
|
590
|
+
auth=self.auth,
|
591
|
+
timeout=60,
|
592
|
+
headers={"Connection": "keep-alive"},
|
593
|
+
)
|
594
|
+
|
595
|
+
if response.status_code == 200:
|
596
|
+
|
597
|
+
if filename is not None:
|
598
|
+
|
599
|
+
try:
|
600
|
+
|
601
|
+
with open(filename, "wb") as arquivo:
|
602
|
+
|
603
|
+
arquivo.write(response.content)
|
604
|
+
|
605
|
+
except Exception as e:
|
606
|
+
|
607
|
+
raise Exception(f"Falha ao salvar o arquivo em disco\n{str(e)}")
|
608
|
+
|
609
|
+
return {"success": True, "status_code": int(response.status_code), "content": response.content }
|
610
|
+
|
611
|
+
else:
|
612
|
+
|
613
|
+
return {"success": False, "status_code": int(response.status_code), "content": response.text}
|
614
|
+
|
615
|
+
|
@@ -1,6 +1,6 @@
|
|
1
1
|
csc_cia_stne/__init__.py,sha256=Io-gKis1evws5cHUqyOrcsZKNCQRviYj3zbp__5lgKU,2512
|
2
2
|
csc_cia_stne/bc_correios.py,sha256=pQAnRrcXEMrx3N1MWydZVIhEQLerh3x8-0B045zZIzk,24174
|
3
|
-
csc_cia_stne/bc_sta.py,sha256=
|
3
|
+
csc_cia_stne/bc_sta.py,sha256=bVj7o2oOrAR3V_fSD9ex0CGahLc1U6EgeYetQGUw1-0,25282
|
4
4
|
csc_cia_stne/email.py,sha256=RK_TzWBVnUfpP-s5NvjTJJjzhICy8e2fME9EuaiySMY,8162
|
5
5
|
csc_cia_stne/gcp_bigquery.py,sha256=jYxvqrWDOPkxc05U4aef7V5lL8ptqsE93lfn0dLFyvc,7385
|
6
6
|
csc_cia_stne/google_drive.py,sha256=lgcOd27vk2Mb_wP_fAWIbec-S3MIBKyh4TpRth6REXc,12788
|
@@ -17,7 +17,7 @@ csc_cia_stne/utilitarios/functions/__init__.py,sha256=nUcjSI23FxfX18AQ8Q_Gimyxme
|
|
17
17
|
csc_cia_stne/utilitarios/functions/func_b64.py,sha256=XGU34BIQQXWXBS0yM2B4A2wDlcrMl1unIJXjq4lpLnk,1254
|
18
18
|
csc_cia_stne/utilitarios/functions/func_converters.py,sha256=EY1zvlBaRX7G1MceVSiRXwwKDQDZwUO9iECBL0fe5iU,481
|
19
19
|
csc_cia_stne/utilitarios/functions/func_get_secret.py,sha256=khTtUTE-acdA9lIM8l7weejDSqoTYlf59ypBdC_F_lw,2150
|
20
|
-
csc_cia_stne/utilitarios/functions/func_rdp.py,sha256=
|
20
|
+
csc_cia_stne/utilitarios/functions/func_rdp.py,sha256=2B3DjctfU72i0i0TVO1Zk3JdEJCYcwa1MElJtKdkfk4,2855
|
21
21
|
csc_cia_stne/utilitarios/functions/func_recriar_pastas.py,sha256=4whZpB3aJQaCPJ3osMAQpKrzEhqYtJbljGWlx_OvKIM,826
|
22
22
|
csc_cia_stne/utilitarios/functions/func_settings.py,sha256=XwlfqdcfocXQ8kTsDKZ6GsAtpzr0_u44AOTIMtdem7U,2059
|
23
23
|
csc_cia_stne/utilitarios/functions/func_titulo.py,sha256=bH4tYxovTARF-g2kWUK_GIzzXt8egbVdp6mWD6fc_3I,5345
|
@@ -26,8 +26,8 @@ csc_cia_stne/utilitarios/validations/GoogleDriveValidator.py,sha256=PBo-AV2bjR__
|
|
26
26
|
csc_cia_stne/utilitarios/validations/ServiceNowValidator.py,sha256=yleKUIo1ZfyloP9fDPNjv3JJXdLcocT81WIgRSYmqEA,14423
|
27
27
|
csc_cia_stne/utilitarios/validations/__init__.py,sha256=O_qyEU2ji3u6LHUXZCXvUFsMpoMWL625qqHTXyXivTA,106
|
28
28
|
csc_cia_stne/utilitarios/validations/web_validator.py,sha256=HYKYSpDv1RvRjZIuwTPt-AbEz-9392MxM_O329iYuSA,5722
|
29
|
-
csc_cia_stne-0.0.
|
30
|
-
csc_cia_stne-0.0.
|
31
|
-
csc_cia_stne-0.0.
|
32
|
-
csc_cia_stne-0.0.
|
33
|
-
csc_cia_stne-0.0.
|
29
|
+
csc_cia_stne-0.0.65.dist-info/LICENCE,sha256=LPGMtgKki2C3KEZP7hDhA1HBrlq5JCHkIeStUCLEMx4,1073
|
30
|
+
csc_cia_stne-0.0.65.dist-info/METADATA,sha256=hq9XBuN_o_bOOi8jaqlctvRBd6Ej8MZ3sZ3gXOJiELQ,1312
|
31
|
+
csc_cia_stne-0.0.65.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
32
|
+
csc_cia_stne-0.0.65.dist-info/top_level.txt,sha256=ldo7GVv3tQx5KJvwBzdZzzQmjPys2NDVVn1rv0BOF2Q,13
|
33
|
+
csc_cia_stne-0.0.65.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|