""" Modelos do conector. Modulo folha: nao importa nada do projeto, so pydantic. Config e contrato moram aqui; quem le o configs.json e o app/config.py. """ from datetime import datetime from pydantic import BaseModel # --------------------------------------------------------------------------- # Config # --------------------------------------------------------------------------- class ApiConfig(BaseModel): port: int ambiente: str workers: int class DocsConfig(BaseModel): user: str password: str class BancoConfig(BaseModel): """Oracle do cliente. Fase 2 — o conector ainda nao insere.""" user: str password: str dns: str class VpsConfig(BaseModel): """Como a VPS da FLS se identifica e como abrimos o que ela manda.""" # Chave PRIVADA (PEM). Abre o envelope cifrado com a nossa publica. # Nunca sai daqui — e o que garante que so o conector le o payload. chave_privada: str # Segredo compartilhado, esperado no header X-Token. Sem isso a rota # fica aberta pra quem souber a URL. token: str # Allowlist de origem. Vazio = desligado (util em teste local). ips_permitidos: list[str] = [] class Settings(BaseModel): api: ApiConfig docs: DocsConfig vps: VpsConfig banco: BancoConfig | None = None log_level: str = "INFO" # --------------------------------------------------------------------------- # Contrato com a API da VPS # --------------------------------------------------------------------------- class Envelope(BaseModel): """O que chega no corpo do POST, ainda cifrado.""" alg: str chave: str nonce: str dados: str class Parcela(BaseModel): valor: float vencimento: datetime | None = None class PayloadCompras(BaseModel): """ O que sai de dentro do envelope depois de decifrado. Espelha o PayloadCompras da API da VPS. Se um lado mudar, o outro tem que mudar junto — e o jeito de descobrir e o teste, nao a producao. """ # Chave de deduplicacao: id do processo no Holmes. O MERGE no Oracle # vai por aqui, senao reentrega de webhook vira linha duplicada. id_processo: str protocolo: str cnpj: str pedido_linx: str fornecedor: str tipo: str nf_entrada: str | None = None aprovador: str valor_total: float parcelas: dict[int, Parcela]