3. A guarnição aceita, desloca, chega e atende
Tudo aqui é da . O não aceita pela e não registra : quem está na é quem diz que aceitou, que está a caminho e que chegou. Aceito por um integrante, aceito pela guarnição.
A cena
A cena 3D deste caso (roteiro atender) entra aqui quando a operação 3D publicar os roteiros dos casos de uso; até lá, o diagrama abaixo é a cena.
Uma viatura no local não é a ocorrência no local
A primeira chegada leva a a em_atendimento; as outras viaturas podem continuar a caminho. Guarde o estado por despachoId. Encerrar a ocorrência encerra os despachos abertos em cascata; encerrar um despacho encerra só a participação daquele .
Pelo app do policial
A lista do policial é a da guarnição que ele integra; por isso o vê o mesmo despacho que o .
/** O que o policial lista (UC-17): os despachos da guarnição que integra. */
despachos(): Promise<readonly ResumoDeDespacho[]> {
return this.atendimento.despachosDaGuarnicao(this.usuario);
}/** O que o policial lista (UC-17): os despachos da guarnição que integra. */
despachos() {
return this.atendimento.despachosDaGuarnicao(this.usuario);
}curl https://geohub.exemplo.gov.br/plugins/guarnicoes/$GUARNICAO/despachos -H "Authorization: Bearer $TOKEN"
# {"dados":[{"id":"…","status":"designado","ocorrenciaId":"…",…}]}Saber de um despacho novo sem recarregar: o evento chega pelo polling da sessão, e é só o sinal para reler.
/**
* Avisa quando algo do atendimento mudou, para a tela reler.
*
* O evento é o sinal, não a fonte: o `ocorrencia:despachada` diz que nasceu
* um despacho, e é o `listarDespachosDaGuarnicao` que diz se é desta
* guarnição. A função devolvida cancela as assinaturas.
*/
export function aoMudarOAtendimento(
hubs: HubsDoApp,
reler: () => void,
): () => void {
const sinal = (): void => {
reler();
};
hubs.ocorrencia.on('ocorrencia:despachada', sinal);
hubs.ocorrencia.on('ocorrencia:despacho-mudou-status', sinal);
hubs.ocorrencia.on('ocorrencia:mudou-status', sinal);
hubs.jornada.on('jornada:guarnicao-mudou-status', sinal);
return () => {
hubs.ocorrencia.off('ocorrencia:despachada', sinal);
hubs.ocorrencia.off('ocorrencia:despacho-mudou-status', sinal);
hubs.ocorrencia.off('ocorrencia:mudou-status', sinal);
hubs.jornada.off('jornada:guarnicao-mudou-status', sinal);
};
}/**
* Avisa quando algo do atendimento mudou, para a tela reler.
*
* O evento é o sinal, não a fonte: o `ocorrencia:despachada` diz que nasceu
* um despacho, e é o `listarDespachosDaGuarnicao` que diz se é desta
* guarnição. A função devolvida cancela as assinaturas.
*/
export function aoMudarOAtendimento(hubs, reler) {
const sinal = () => {
reler();
};
hubs.ocorrencia.on('ocorrencia:despachada', sinal);
hubs.ocorrencia.on('ocorrencia:despacho-mudou-status', sinal);
hubs.ocorrencia.on('ocorrencia:mudou-status', sinal);
hubs.jornada.on('jornada:guarnicao-mudou-status', sinal);
return () => {
hubs.ocorrencia.off('ocorrencia:despachada', sinal);
hubs.ocorrencia.off('ocorrencia:despacho-mudou-status', sinal);
hubs.ocorrencia.off('ocorrencia:mudou-status', sinal);
hubs.jornada.off('jornada:guarnicao-mudou-status', sinal);
};
}# A cada 1,5 s; a inscrição é um uuid seu
curl "https://geohub.exemplo.gov.br/plugins/ocorrencia/eventos?inscricao=$INSCRICAO" -H "Authorization: Bearer $TOKEN"
# {"eventos":[{"tipo":"ocorrencia:despachada","payload":{…},…}]}Cada ato devolve o handle do instante seguinte, e é o handle que sabe o que cabe a seguir.
/**
* Aceita, desloca e chega. Aceito por um integrante, aceito pela
* guarnição: quem abre o despacho depois de outro já ter aceitado recebe
* o handle `aceito` e segue dali.
*/
async aceitarDeslocarEChegar(
despachoId: DespachoId,
): Promise<Result<DespachoNoLocal, DespachoNaoAceitavel>> {
const recebido = await this.atendimento.receberDespacho(
this.usuario,
despachoId,
);
const aceito =
recebido.situacao === 'designado' ? await recebido.aceitar() : recebido;
if (aceito.situacao !== 'aceito') {
return {
error: { codigo: 'despacho-nao-aceitavel', situacao: aceito.situacao },
success: false,
};
}
const aCaminho = await aceito.iniciarDeslocamento();
// A primeira chegada leva a ocorrência a em_atendimento; as outras
// viaturas continuam a caminho.
return { data: await aCaminho.registrarChegada(), success: true };
}/**
* Aceita, desloca e chega. Aceito por um integrante, aceito pela
* guarnição: quem abre o despacho depois de outro já ter aceitado recebe
* o handle `aceito` e segue dali.
*/
async aceitarDeslocarEChegar(despachoId) {
const recebido = await this.atendimento.receberDespacho(
this.usuario,
despachoId,
);
const aceito =
recebido.situacao === 'designado' ? await recebido.aceitar() : recebido;
if (aceito.situacao !== 'aceito') {
return {
error: { codigo: 'despacho-nao-aceitavel', situacao: aceito.situacao },
success: false,
};
}
const aCaminho = await aceito.iniciarDeslocamento();
// A primeira chegada leva a ocorrência a em_atendimento; as outras
// viaturas continuam a caminho.
return { data: await aCaminho.registrarChegada(), success: true };
}curl -X POST https://geohub.exemplo.gov.br/plugins/despachos/$DESPACHO/aceite -H "Authorization: Bearer $TOKEN" -H "x-solicitacao-id: $(uuidv7)"
curl -X POST https://geohub.exemplo.gov.br/plugins/despachos/$DESPACHO/deslocamento -H "Authorization: Bearer $TOKEN" -H "x-solicitacao-id: $(uuidv7)"
curl -X POST https://geohub.exemplo.gov.br/plugins/despachos/$DESPACHO/chegada -H "Authorization: Bearer $TOKEN" -H "x-solicitacao-id: $(uuidv7)"
# {"dados":null} (na primeira chegada, a ocorrência vai a em_atendimento)
# 403 {"erro":{"codigo":"GUARDA_DE_DOMINIO","mensagem":"O despacho é de outra guarnição."}}
# 409 {"erro":{"codigo":"transicao-invalida"}}/** No local, o que a equipe observa entra na narrativa do atendimento. */
relatarDoLocal(
noLocal: DespachoNoLocal,
atualizacao: AtualizacaoDeSituacao,
): Promise<void> {
return noLocal.atualizarSituacao(atualizacao);
}/** No local, o que a equipe observa entra na narrativa do atendimento. */
relatarDoLocal(noLocal, atualizacao) {
return noLocal.atualizarSituacao(atualizacao);
}curl -X POST https://geohub.exemplo.gov.br/plugins/despachos/$DESPACHO/situacoes -H "Authorization: Bearer $TOKEN" -H "x-solicitacao-id: $(uuidv7)" -H "Content-Type: application/json" \
-d '{"atualizacao":{"situacao":"fato_confirmado","observacao":"…"}}'
curl -X POST https://geohub.exemplo.gov.br/plugins/despachos/$DESPACHO/acoes -H "Authorization: Bearer $TOKEN" -H "x-solicitacao-id: $(uuidv7)" -H "Content-Type: application/json" \
-d '{"acao":{"tipo":"abordagem","descricao":"…"}}'
curl -X POST https://geohub.exemplo.gov.br/plugins/despachos/$DESPACHO/apoios -H "Authorization: Bearer $TOKEN" -H "x-solicitacao-id: $(uuidv7)" -H "Content-Type: application/json" \
-d '{"pedido":{"tipo":"policial","justificativa":"…"}}'/** Encerra a participação DESTA equipe; a ocorrência continua. */
encerrarParticipacao(
noLocal: DespachoNoLocal,
resultado: ResultadoDaParticipacao,
): Promise<ParticipacaoEncerrada> {
return noLocal.encerrarParticipacao(resultado);
}/** Encerra a participação DESTA equipe; a ocorrência continua. */
encerrarParticipacao(noLocal, resultado) {
return noLocal.encerrarParticipacao(resultado);
}curl -X POST https://geohub.exemplo.gov.br/plugins/despachos/$DESPACHO/encerramento -H "Authorization: Bearer $TOKEN" -H "x-solicitacao-id: $(uuidv7)" -H "Content-Type: application/json" \
-d '{"resultado":{"descricao":"conduzidos à delegacia"}}'
# {"dados":null} (a guarnição volta ao pool)Quando a participação encerra, a guarnição volta ao pool (disponivel): é o fluxo ← despacho, ligado pelo , não pelo app.
Pela REST
Cada rota está na API, com corpo, respostas e erros.
| rota | verbo |
|---|---|
GET /plugins/guarnicoes/{guarnicaoId}/despachos | listarDespachosDaGuarnicao |
POST /plugins/despachos/{id}/aceite | aceitarDespacho |
POST /plugins/despachos/{id}/recusa | recusarDespacho |
POST /plugins/despachos/{id}/deslocamento | iniciarDeslocamento |
POST /plugins/despachos/{id}/chegada | registrarChegada |
POST /plugins/despachos/{despachoId}/acoes | registrarAcao |
POST /plugins/despachos/{despachoId}/situacoes | atualizarSituacao |
POST /plugins/despachos/{despachoId}/apoios | solicitarApoio |
POST /plugins/despachos/{id}/encerramento | encerrarDespacho |
GET /plugins/ocorrencias/{ocorrenciaId}/registro | listarRegistro |
GET /plugins/guarnicoes/{guarnicaoId}/despachos → 200 {"dados":[{"id":"…","status":"designado",…}]}
POST /plugins/despachos/{id}/aceite
POST /plugins/despachos/{id}/deslocamento
POST /plugins/despachos/{id}/chegada → ocorrência em_atendimento na primeira chegada
POST /plugins/despachos/{id}/situacoes {"atualizacao":{"situacao":"fato_confirmado","observacao":"…"}}
POST /plugins/despachos/{id}/apoios {"pedido":{"tipo":"policial","justificativa":"…"}}
POST /plugins/despachos/{id}/encerramento {"resultado":{"descricao":"conduzidos à delegacia"}}O aceite de outra guarnição volta 403 GUARDA_DE_DOMINIO ("O despacho é de outra guarnição."); o verbo fora de ordem, 409 transicao-invalida.