WEBSOCKETget.label

Buscar Etiquetas do Pedido

Evento WebSocket para buscar etiquetas de um pedido completado via integração SOAP com a API externa DiagnosticsBrazil. O cliente emite este evento com o ID do pedido. O servidor valida se o pedido está COMPLETED, consulta a API externa via SOAP e retorna as etiquetas formatadas. Este evento retorna uma resposta imediata via callback (status: 'receive' ou 'refused') com os dados das etiquetas e possíveis erros de integração. O frontend valida se a resposta corresponde ao pedido correto antes de processar. Este evento pode ser chamado manualmente (ao clicar em "Etiqueta") ou automaticamente quando um pedido é completado (via evento 'completed').

Access Token

Para realizar requisições GET, POST, PUT, DELETE e PATCH nos endpoints da API você precisa de uma chave de autorização. Chamamos essa chave de accessToken.

Para ter acesso ao accessToken, é necessário que o usuário master da licença efetue a liberação deste pela interface do ImageMais Clinic. O accessToken tem validade de 1 hora.

Headers

AuthorizationOBRIGATÓRIO
Tipo:string
Token de autenticação no formato Bearer {accessToken}. O token deve ser enviado durante o handshake de conexão WebSocket.

Parâmetros

orderIdOBRIGATÓRIO
Tipo:number
ID do pedido para buscar as etiquetas

ID do pedido para operações relacionadas às etiquetas. É um identificador numérico único que identifica um pedido específico no sistema.

Para encontrar o ID do pedido, para acessar a página de listar todos os pedidos do laboratório.

Fluxo passo a passo: get.label

1

Cliente emite a requisição via WebSocket com callback

O frontend emite o evento 'get.label' com o ID do pedido e gerencia o estado de loading:

// Label.tsx
async function getLabel() {
  setIsLoading(true);
  socket?.emit(
    'get.label',
    { orderId: order.id },
    (response: LabelResponseWs) => {
      // Valida se a resposta corresponde ao pedido correto
      if (response.orderId !== order.id) return;
      
      // Atualiza estado com as etiquetas
      setLabels(response.data);
      setIsLoading(false);
      
      // Exibe erros se houver
      if (response.errors?.length > 0) {
        addNotification({
          title: 'Atenção!!!',
          message: response.errors
            ?.map((error) => error.description)
            .join('|'),
          bg: 'danger',
          className: 'text-white',
          autohide: true,
        });
      }
    }
  );
}
Quem emite: frontend (Label.tsx)
Quando: ao clicar em 'Etiqueta' ou automaticamente quando pedido é completado
Payload: { orderId: number }
Callback: processa resposta imediata com data e errors
Validação: verifica se response.orderId === order.id antes de processar
Gerenciamento de estado: setIsLoading(true/false) controla estado de carregamento
2

Servidor emite evento interno e aguarda processamento

No backend (NestJS + Gateway), o servidor emite evento interno usando emitAsync para aguardar resposta dos listeners:

@SubscribeMessage('get.label')
async handleGetLabel(
  @ConnectedSocket() client: Socket,
  @MessageBody() data: { orderId: number },
) {
  try {
    // Emite evento interno e aguarda resposta (retorna array de promessas)
    const promises: {
      data: Record<string, any>[];
      errors: Error[];
    }[] = await this.eventEmitter.emitAsync(
      'get.label',
      new LabelEvent(data.orderId, client.data.payload),
    );
    
    // Processa primeira resposta (normalmente há apenas um listener)
    const response = promises.shift();
    
    // Retorna resposta formatada
    return {
      status: 'receive',
      orderId: data.orderId,
      data: response.data,
      errors: response.errors,
      timestamp: new Date().toISOString(),
    };
  } catch (e) {
    // ... tratamento de erro
  }
}
Quem recebe: servidor (Gateway WS)
Evento interno: emitAsync('get.label', LabelEvent) - aguarda resposta dos listeners
LabelEvent: contém orderId e payload (dados de autenticação)
Retorno: retorna resposta com status, orderId, data, errors e timestamp
3

Listener busca pedido e valida status

O listener escuta o evento interno, busca o pedido e valida se está COMPLETED:

// integration.listener.ts
@OnEvent('get.label')
async handleOnLabelByOrderId(labelEvent: LabelEvent) {
  try {
    // Chama serviço SOAP para buscar etiquetas
    const confirm = await this.soapService.getLabels(
      labelEvent.orderId,
      labelEvent.payload,
    );
    
    return confirm; // Retorna { data: [...], errors: [...] }
  } catch (e) {
    const error = e as Error;
    this.logger.debug(error.message, error.stack);
    return {
      errors: [e], // Retorna erros no formato esperado
    };
  }
}
O que faz: chama serviço SOAP para buscar etiquetas
Tratamento de erro: captura exceções e retorna no formato { errors: [...] }
Retorno: objeto com data (array de etiquetas) e errors (array de erros)
4

Serviço SOAP busca pedido, valida status e consulta API externa

O serviço SOAP busca o pedido, valida se está COMPLETED e consulta a API externa DiagnosticsBrazil:

// soap-diagnostics-brazil.service.ts
async getLabels(id: number, payload: PayloadTokenDto) {
  // Busca o pedido completo
  const order = await this.ordersService.findById(id, payload);
  
  // Valida se o pedido está COMPLETED (só busca etiquetas de pedidos finalizados)
  this.checkOrderStatus(order, OrdersStatusEnum.COMPLETED);
  
  // Consulta API externa via SOAP
  const [response] = await this.diagnosticsBrazilWrapper.getLabels({
    request: {
      CodigoApoiado: this.appConfigService.dbLogin,
      CodigoSenhaIntegracao: this.appConfigService.dbPassword,
      NumeroAtendimentoApoiado: `${order.patientExams.prefix}-${order.patientExams.uuid}`,
    },
  });
  
  // Formata resposta da API externa
  const result = response.EnviaAmostrasResult as EnviaAmostrasResult;
  return this.formatConfirm(
    result.Confirmacao,
    order.patientExams.patient.dateBirth,
  );
}
Validação: verifica se o pedido está COMPLETED antes de buscar
API externa: consulta DiagnosticsBrazil via SOAP
Formatação: formata resposta da API para estrutura interna
5

Serviço formata resposta com etiquetas e erros

O método formatConfirm formata os dados retornados pela API externa em estrutura interna:

// soap-diagnostics-brazil.service.ts
private formatConfirm(confirm: Confirmacao, dateBirth: Date | string) {
  return {
    // Array de etiquetas formatadas
    data: confirm.ConfirmacaoPedidov2.ct_ConfirmacaoPedidoEtiqueta_v2.flatMap(
      (obj) =>
        obj.Amostras
          ? obj.Amostras.ct_AmostraEtiqueta_v2.map((label) => ({
              numeroAmostra: label.NumeroAmostra,
              nomePaciente: label.NomePaciente,
              exames: label.Exames,
              grupoInterface: label.GrupoInterface,
              material: label.Material,
              volume: label.Volume,
              meioColeta: label.MeioColeta,
              regiaoColeta: label.RegiaoColeta,
              origem: label.Origem,
              dataNascimento: dateBirth,
              dataSistema: label.DataSistema,
              numeroAtendimento: obj.NumeroAtendimentoDB,
            }))
          : [],
    ),
    // Array de erros de integração
    errors: confirm.ConfirmacaoPedidov2.ct_ConfirmacaoPedidoEtiqueta_v2.flatMap(
      (error) =>
        error.ErroIntegracao
          ? error.ErroIntegracao.ct_ErroIntegracao_v2.map((e) => ({
              description: e.Descricao,
            }))
          : [],
    ),
  };
}
Estrutura de retorno: objeto com data (array de etiquetas) e errors (array de erros)
Dados das etiquetas: numeroAmostra, nomePaciente, exames, material, volume, etc.
Erros de integração: array de objetos com description (descrição do erro)
6

Servidor retorna resposta formatada ao cliente

O Gateway processa a resposta do listener e retorna ao cliente via callback:

// Continuação do handleGetLabel
// Processa primeira resposta (normalmente há apenas um listener)
const response = promises.shift();

// Retorna resposta formatada
return {
  status: 'receive',
  orderId: data.orderId, // Para validação no frontend
  data: response.data,    // Array de etiquetas formatadas
  errors: response.errors, // Array de erros (se houver)
  timestamp: new Date().toISOString(),
};
Resposta: retorna via callback do socket.emit
orderId: incluído para validação no frontend
data: array de etiquetas formatadas
errors: array de erros de integração (pode estar vazio)
7

Cliente valida resposta e atualiza estado

No frontend, o callback valida se a resposta corresponde ao pedido correto e atualiza o estado:

// Label.tsx - Callback do socket.emit
(response: LabelResponseWs) => {
  // Valida se a resposta corresponde ao pedido correto
  if (response.orderId !== order.id) return;
  
  // Atualiza estado com as etiquetas
  setLabels(response.data);
  setIsLoading(false);
  
  // Exibe erros se houver
  if (response.errors?.length > 0) {
    addNotification({
      title: 'Atenção!!!',
      message: response.errors
        ?.map((error) => error.description)
        .join('|'),
      bg: 'danger',
      className: 'text-white',
      autohide: true,
    });
  }
}
Validação: verifica se response.orderId === order.id antes de processar
Atualização de estado: setLabels(response.data) armazena as etiquetas
Gerenciamento de loading: setIsLoading(false) desativa estado de carregamento
Tratamento de erros: exibe notificação se houver erros de integração
8

Cliente escuta evento 'completed' e busca etiquetas automaticamente

O componente escuta o evento 'completed' e busca etiquetas automaticamente se as condições forem atendidas:

// Label.tsx
socket.on('completed', (completed: Order) => {
  // Só busca se estiver aguardando impressão
  if (!isWindowPrint.current) return;
  
  // Valida condições antes de buscar
  if (
    order.id !== completed.id ||           // Deve ser o mesmo pedido
    labels.length !== 0 ||                 // Não deve ter etiquetas já carregadas
    completed.status.name !== OrdersStatusEnum.COMPLETED // Status deve ser COMPLETED
  ) return;
  
  // Busca etiquetas automaticamente
  getLabel();
});
Quando é chamado: quando um pedido é completado (via evento 'completed')
Condições: isWindowPrint.current === true, mesmo pedido, sem etiquetas, status COMPLETED
Prevenção: evita buscas desnecessárias verificando múltiplas condições
Automação: busca etiquetas automaticamente quando pedido é finalizado

Request URL

ws://api-dev.imagemais.com
{
  "orderId": 123
}
{
  "orderId": 123
}

Respostas

{
  "status": "receive",
  "orderId": 123,
  ...
{
  "status": "receive",
  "orderId": 123,
  "data": [
    {
      "numeroAmostra": "12345",
      "nomePaciente": "João Silva",
      "exames": "Hemograma Completo",
      "grupoInterface": "LAB",
      "material": "Sangue",
      "volume": "5ml",
      "meioColeta": "Tubo EDTA",
      "regiaoColeta": "Braço direito",
      "origem": "Coleta domiciliar",
      "dataNascimento": "1990-01-01",
      "dataSistema": "2025-01-23T10:30:00.000Z",
      "numeroAtendimento": "DB123456"
    }
  ],
  "errors": [],
  "timestamp": "2025-01-23T10:30:00.000Z"
}
{
  "status": "refused",
  "message": "Erro ao buscar etiquetas",
  ...
{
  "status": "refused",
  "message": "Erro ao buscar etiquetas",
  "timestamp": "2025-01-23T10:30:00.000Z"
}