Skip to content

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 .

ts
/** O que o policial lista (UC-17): os despachos da guarnição que integra. */
despachos(): Promise<readonly ResumoDeDespacho[]> {
  return this.atendimento.despachosDaGuarnicao(this.usuario);
}
js
/** O que o policial lista (UC-17): os despachos da guarnição que integra. */
despachos() {
  return this.atendimento.despachosDaGuarnicao(this.usuario);
}
sh
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.

ts
/**
 * 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);
  };
}
js
/**
 * 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);
  };
}
sh
# 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.

ts
/**
 * 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 };
}
js
/**
 * 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 };
}
sh
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"}}
ts
/** No local, o que a equipe observa entra na narrativa do atendimento. */
relatarDoLocal(
  noLocal: DespachoNoLocal,
  atualizacao: AtualizacaoDeSituacao,
): Promise<void> {
  return noLocal.atualizarSituacao(atualizacao);
}
js
/** No local, o que a equipe observa entra na narrativa do atendimento. */
relatarDoLocal(noLocal, atualizacao) {
  return noLocal.atualizarSituacao(atualizacao);
}
sh
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":"…"}}'
ts
/** Encerra a participação DESTA equipe; a ocorrência continua. */
encerrarParticipacao(
  noLocal: DespachoNoLocal,
  resultado: ResultadoDaParticipacao,
): Promise<ParticipacaoEncerrada> {
  return noLocal.encerrarParticipacao(resultado);
}
js
/** Encerra a participação DESTA equipe; a ocorrência continua. */
encerrarParticipacao(noLocal, resultado) {
  return noLocal.encerrarParticipacao(resultado);
}
sh
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.

rotaverbo
GET /plugins/guarnicoes/{guarnicaoId}/despachoslistarDespachosDaGuarnicao
POST /plugins/despachos/{id}/aceiteaceitarDespacho
POST /plugins/despachos/{id}/recusarecusarDespacho
POST /plugins/despachos/{id}/deslocamentoiniciarDeslocamento
POST /plugins/despachos/{id}/chegadaregistrarChegada
POST /plugins/despachos/{despachoId}/acoesregistrarAcao
POST /plugins/despachos/{despachoId}/situacoesatualizarSituacao
POST /plugins/despachos/{despachoId}/apoiossolicitarApoio
POST /plugins/despachos/{id}/encerramentoencerrarDespacho
GET /plugins/ocorrencias/{ocorrenciaId}/registrolistarRegistro
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.