Fluxo: Cadastro de paciente¶
Subfluxo do agendamento completo. Isolado aqui porque tem armadilhas específicas.
Regra de ouro¶
Abstract
Sempre buscar por CPF antes de cadastrar. Duplicar paciente é pior do que falhar.
Fluxograma¶
flowchart TD
A[cpf + nome + data_nascimento + telefone] --> B[_only_digits em cpf e telefone]
B --> C[POST /cadastros/pacientes/cpf/CPF]
C --> D{data é dict com cpf?}
D -->|sim| E[return data como paciente]
D -->|não| F{data == CPF nao encontrado?}
F -->|sim| G[POST /paciente/multiplos<br/>com array de 1 paciente]
F -->|não| FAIL1[FALHA: resposta inesperada]
G --> H[POST /cadastros/pacientes/cpf/CPF de novo]
H --> I{Agora achou?}
I -->|sim| J[return data]
I -->|não| FAIL2[FALHA: cadastro nao confirmou]
Funções auxiliares¶
# comum aos dois projetos
def _only_digits(s: str) -> str:
return "".join(c for c in (s or "") if c.isdigit())
# busca (não lança exceção em 'não encontrado')
def _buscar_paciente_cpf(cpf: str) -> dict | None:
resp = requests.post(
f"{OTIMUS_BASE_URL}/cadastros/pacientes/cpf/{_only_digits(cpf)}",
headers=_otimus_headers(),
timeout=30,
)
resp.raise_for_status()
result = resp.json()
data = result.get("data")
if isinstance(data, dict) and data.get("cpf"):
return data
if data == "O CPF informado não foi encontrado.":
return None
return None
# cadastro
def _cadastrar_paciente(nome: str, cpf: str, data_nascimento: str, telefone: str) -> dict | None:
payload = {
"pacientes": [
{
"id": 123, # TODO: investigar se pode ser 0/omitido — hoje é hardcoded
"nome": nome,
"dataNascimento": data_nascimento, # YYYY-MM-DD
"cpf": _only_digits(cpf),
"celular": _only_digits(telefone),
}
]
}
resp = requests.post(
f"{OTIMUS_BASE_URL}/paciente/multiplos",
headers=_otimus_headers(),
json=payload,
timeout=30,
)
resp.raise_for_status()
# nao confiamos na resposta do cadastro; re-buscamos
return _buscar_paciente_cpf(cpf)
Formatos¶
| Campo | Request (cadastro) | Response (busca) |
|---|---|---|
cpf |
apenas dígitos | apenas dígitos |
celular |
apenas dígitos (DDI+DDD+número) | apenas dígitos |
dataNascimento |
YYYY-MM-DD |
DD-MM-YYYY |
nome |
maiúsculas (opcional) | livre |
Telefone com DDI
O celular no cadastro é o do paciente, não da instância. Nos projetos
atuais vem do WTS session details (telefone do contato) já no formato
internacional completo (5599...).
Campo id: 123 — o que sabemos¶
No payload de cadastro, id: 123 é hardcoded em ambos os projetos. Isso
aparentemente é ignorado pelo OTIMUS (ele gera um paciente_id novo), mas
o contrato não é explícito. Recomendações:
- Deixar como está nos projetos legados (MEDCENTER, CLINFETO) para não mexer em comportamento.
- Em projetos novos: testar enviar sem o campo ou com
"id": 0e confirmar com a clínica o comportamento.
Consistência de dados¶
O OTIMUS tem uma idiossincrasia: se você cadastra um paciente com CPF X e
alguns minutos depois busca, ele aparece. Mas se a resposta do cadastro é
malformada e você não re-busca, você não tem paciente_id. Por isso o
padrão é sempre re-buscar após cadastrar.
E se o paciente já existe com dados antigos?¶
O cadastro em duplicado geralmente falha (OTIMUS detecta CPF duplicado). O efeito prático:
_buscar_paciente_cpf()devolve o paciente existente → usamos ele.- Se o paciente deu nome/data errada na conversa, mantemos os dados antigos (não atualizamos). Atualizar é responsabilidade humana no admin do OTIMUS.
Nunca enviar CPF sem normalizar¶
Vários endpoints OTIMUS aceitam só dígitos. Mandar com máscara é um problema silencioso que aparece depois.