Metadata-Version: 2.4
Name: botdtp
Version: 0.2.0
Summary: HTTP automation package for DTP and DAMSP portals.
Author: Italhub
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: requests>=2.32.0
Requires-Dist: beautifulsoup4>=4.12.0
Requires-Dist: lxml>=5.2.0
Requires-Dist: pillow>=10.0.0
Requires-Dist: langchain-core>=0.3.0
Requires-Dist: langchain-openai>=0.2.0
Requires-Dist: validate-docbr>=1.11.1
Requires-Dist: xhtml2pdf>=0.2.17
Dynamic: license-file

# botdtp

Pacote de automação para os portais SGPT e DAMSP.

## O que o projeto entrega

- `SGPTBot`: login, alteração e atualização de senhas, comprovantes de inspeção, aprovação e reprovação de inspeções e emissão de relatórios.
- `DAMSPBot`: fluxo CPF/CNPJ, emissao de licenca PF/PJ e guia PF.
- `HTTPClient` + `HTTPConfig`: retry, timeout, proxy, sleep entre requests e sessao.
- Persistencia de sessao em arquivo (`SessionStore`) com TTL.
- Janela de acesso configuravel por dia/hora/fuso.

## Requisitos

- Python `>=3.11`

## Instalacao

```bash
pip install botdtp
```

## Dependencias

Dependencias diretas do pacote (em `pyproject.toml`):

- `requests>=2.32.0`
- `beautifulsoup4>=4.12.0`
- `lxml>=5.2.0`
- `pillow>=10.0.0`
- `langchain-core>=0.3.0`
- `langchain-openai>=0.2.0`
- `validate-docbr>=1.11.1`
- `xhtml2pdf>=0.2.17`


## Contrato padrao de retorno

Toda operacao retorna `Operacao`:

- `ok: bool`
- `mensagem: str`
- `data: dict`

Comportamento em falha:

- Operacoes publicas de `Bot` e `Client` retornam imediatamente `Operacao(ok=False, ...)`.
- Nao ha propagacao de excecao para o chamador nesse contrato padrao.
- Em erros, `data` inclui:
  - `operacao`: nome do metodo executado
  - `classe`: classe da excecao interna capturada
  - `detalhe`: mensagem/detalhe tecnico da falha

## Uso de alto nivel (recomendado)

### SGPTBot

```python
from botdtp import SGPTBot
from botdtp.sgpt import (
    SGPTLoginInput,
    SGPTAlterarSenhaInput,
    SGPTComprovanteInspecaoInput,
    SGPTAprovacaoEscolarAnualInput,
    SGPTAprovacaoEscolarSemestralInput,
    SGPTAprovacaoTaxiInput,
    SGPTReprovacaoEscolarAnualInput,
    SGPTReprovacaoEscolarSemestralInput,
    SGPTReprovacaoTaxiInput,
    SGPTReprovacaoItemInput,
    SGPTRelatorioInput,
)

def build_login() -> SGPTLoginInput:
    return SGPTLoginInput(
        base_url="https://vistoriadtp.prefeitura.sp.gov.br",
        codigo_empresa="CODIGO_DA_EMPRESA",
        usuario="USUARIO",
        senha="SUA_SENHA",
    )

sgpt = SGPTBot(
    login=build_login(),
    reautenticar=True,
)

# 1) Autenticar
sgpt.autenticar(
    build_login()
)

# 2) Alterar senha
sgpt.alterar_senha(
    SGPTAlterarSenhaInput(
        base_url="https://vistoriadtp.prefeitura.sp.gov.br",
        codigo_empresa="0035",
        usuario="123456",
        senha_atual="SENHA_ATUAL",
        nova_senha="SENHA_NOVA",
        confirmacao_nova_senha="SENHA_NOVA",
    )
)

# 3) Gerar comprovante de inspecao
sgpt.gerar_comprovante_inspecao(
    SGPTComprovanteInspecaoInput(
        numero_guia="055721",
        ano_guia="2026",
        resultado="APROVADA",  # APROVADA ou REPROVADA
    ),
    destino="tmp",
)

# 4) Aprovar inspecoes
sgpt.aprovar_escolar_anual(
    SGPTAprovacaoEscolarAnualInput(
        placa="ABC1234",
        licenca="12345678",
        inspetor_codigo="111",
        inspetor_nome="INSPETOR",
        rt_codigo="222",
        rt_nome="RESPONSAVEL TECNICO",
        ano_guia="0000",
        numero_guia="00000",
        validade_extintor="00/0000",
        sn_tacografo="S",
    ),
    destino_comprovante="tmp",
)

sgpt.aprovar_escolar_semestral(
    SGPTAprovacaoEscolarSemestralInput(
        placa="ABC1D23",
        licenca="12345678",
        inspetor_codigo="111",
        inspetor_nome="INSPETOR",
        rt_codigo="222",
        rt_nome="RESPONSAVEL TECNICO",
        validade_extintor="12/2026",
        sn_tacografo="S",
    ),
    destino_comprovante="tmp",
)

sgpt.aprovar_taxi(
    SGPTAprovacaoTaxiInput(
        placa="ABC1234",
        licenca="12345678",
        inspetor_codigo="111",
        inspetor_nome="INSPETOR",
        rt_codigo="222",
        rt_nome="RESPONSAVEL TECNICO",
        ano_guia="2026",
        numero_guia="055721",
        radio_taxi_cod="",
        radio_taxi_nome="",
    ),
    destino_comprovante="tmp",
)

# 5) Reprovar inspecoes
itens = [
    SGPTReprovacaoItemInput(
        grupo="X",
        item="X",
        subitem="X",
        valor="X",
        opcao="X",
        descricao="XXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
    )
]

sgpt.reprovar_escolar_anual(
    SGPTReprovacaoEscolarAnualInput(
        placa="ABC1234",
        licenca="12345678",
        inspetor_codigo="111",
        inspetor_nome="INSPETOR",
        rt_codigo="222",
        rt_nome="RESPONSAVEL TECNICO",
        ano_guia="2026",
        numero_guia="055721",
        itens_reprovacao=itens,
    )
)

sgpt.reprovar_escolar_semestral(
    SGPTReprovacaoEscolarSemestralInput(
        placa="ABC1D23",
        licenca="12345678",
        inspetor_codigo="111",
        inspetor_nome="INSPETOR",
        rt_codigo="222",
        rt_nome="RESPONSAVEL TECNICO",
        itens_reprovacao=itens,
    )
)

sgpt.reprovar_taxi(
    SGPTReprovacaoTaxiInput(
        placa="ABC1234",
        licenca="12345678",
        inspetor_codigo="111",
        inspetor_nome="INSPETOR",
        rt_codigo="222",
        rt_nome="RESPONSAVEL TECNICO",
        ano_guia="2026",
        numero_guia="055721",
        itens_reprovacao=itens,
    )
)

# 6) Gerar relatorio
sgpt.gerar_relatorio_inspecoes(
    SGPTRelatorioInput(
        mes=5,
        ano=2026,
        modalidade="E",  # C, E, F, T ou M
        resultado="",     # "", A, P ou R
    ),
    destino="tmp",
    nome_arquivo="relatorio_sgpt_maio_2026",
    salvar_html=True,
)
```

Politica de autenticacao SGPT:

- Login obrigatorio: passe `login=SGPTLoginInput(...)` ao instanciar o bot.
- Manual: use `sgpt.autenticar(...)` quando quiser renovar explicitamente a sessao.
- Gerenciada: com `reautenticar=True`, o bot tenta reautenticar automaticamente quando detectar `SGPTAuthenticationError`.
- Sessao: `SGPTBot` continua restaurando/salvando cookies via `SessionStore`.

### DAMSPBot

```python
from botdtp import DAMSPBot
from botdtp.damsp import (
    DAMSPCPFInput,
    DAMSPCPFGuiaInput,
    DAMSPCNPJInput,
    DAMSPCategoriaServicoEnum,
    DAMSPModalidadeVeiculoEnum,
    OpenAICaptchaSolver,
)

damsp = DAMSPBot(captcha_solver=OpenAICaptchaSolver(api_key="SUA_OPENAI_KEY"))

# 1) Iniciar fluxo CPF
damsp.iniciar_fluxo_cpf(
    DAMSPCPFInput(
        cpf="529.982.247-25",
        licenca="123.456-78",
        modalidade=DAMSPModalidadeVeiculoEnum.TAXI,
    )
)

# 2) Iniciar fluxo CNPJ
damsp.iniciar_fluxo_cnpj(
    DAMSPCNPJInput(
        cpf_responsavel="529.982.247-25",
        numero_empresa="123456",
        licenca="123.456-78",
        modalidade=DAMSPModalidadeVeiculoEnum.ESCOLAR,
    )
)

# 3) Gerar licenca PF
damsp.gerar_licenca_pf(
    DAMSPCPFInput(
        cpf="529.982.247-25",
        licenca="123.456-78",
        modalidade=DAMSPModalidadeVeiculoEnum.TAXI,
    ),
    destino="tmp",
)

# 4) Gerar licenca PJ
damsp.gerar_licenca_pj(
    DAMSPCNPJInput(
        cpf_responsavel="529.982.247-25",
        numero_empresa="123456",
        licenca="123.456-78",
        modalidade=DAMSPModalidadeVeiculoEnum.ESCOLAR,
    ),
    destino="tmp",
)

# 5) Gerar guia CPF
damsp.gerar_guia_cpf(
    DAMSPCPFGuiaInput(
        cpf="529.982.247-25",
        licenca="123.456-78",
        codigo_servico=DAMSPCategoriaServicoEnum.RENOVACAO_ALVARA,
        modalidade=DAMSPModalidadeVeiculoEnum.TAXI,
    ),
    destino="tmp",
)
```

Observacao atual: `gerar_guia_cnpj` (`DAMSPBot`) e `gerar_guia_pj` (`DAMSPClient`) estao declarados, mas ainda sem implementacao.

## Uso de baixo nivel (clients)

```python
import requests

from botdtp import HTTPClient, HTTPConfig
from botdtp.damsp import DAMSPClient
from botdtp.sgpt import SGPTClient

http = HTTPClient(config=HTTPConfig(), session=requests.Session())
damsp_client = DAMSPClient(http=http)
sgpt_client = SGPTClient(http=http)
```

## Captcha DAMSP

`botdtp.damsp.captcha` contem:

- `OpenAICaptchaSolver` (automatico via OpenAI/LangChain)
- `ManualCaptchaSolver` (entrada manual)
- `OpenAICaptchaConfig`
- `converter_para_bytes_png`

Configuracao recomendada:

- Forneca `api_key` explicitamente em `OpenAICaptchaSolver`.
- Ajuste preset do modelo via `OpenAICaptchaConfig(model=..., max_tokens=..., temperature=...)`.
- Se usar env, resolva no bootstrap da aplicacao e injete os valores no construtor.

## Janela de acesso e sessao persistida

Janela padrao: segunda a sabado (`1,2,3,4,5,6`), `07:00` ate `20:00`, fuso `America/Sao_Paulo`.

Personalizacao via codigo:

- Janela: passe `ControleAcessoConfig(...)` ao criar `SGPTBot`/`DAMSPBot`.
- Persistencia: passe `SessionPersistenceConfig(...)` ao criar o bot.
- HTTP: use `HTTPConfig(...)` com timeout, retry, proxy e trace conforme necessidade.

## Scripts de runtime e testes

Exemplos de runtime:

- `examples/runtime_sgpt_smoke.py`
- `examples/runtime_sgpt_alterar_senha_smoke.py`
- `examples/runtime_sgpt_relatorio_smoke.py`
- `examples/runtime_damsp_licenca_pf_smoke.py`
- `examples/runtime_damsp_licenca_pj_smoke.py`
- `cli/sgpt_menu_cli.py` (menu interativo para teste real do SGPT)
- `cli/sgpt_menu_config.example.json` (modelo de configuracao)
- `cli/damsp_menu_cli.py` (menu interativo para teste real do DAMSP)
- `cli/damsp_menu_config.example.json` (modelo de configuracao)
- `examples/django_adapter_example.py`

Testes:

```bash
pytest -q
```
