import { NotFoundError } from "../shared/errors/index.js"; import { fetchAtendimentoJson, salvarAtendimento, sincronizarProtocolosAbertos, sincronizarTodosProtocolosAbertos, sincronizarAtendimentoPorId, listarAtendimentos, obterAtendimento } from "../services/atendimentosService.js"; import { avaliarAtendimento, avaliarPendentes, listarAvaliacoes, estatisticasAvaliacoes, listarSetores, rankingAtendentes } from "../services/atendimentoAvaliacaoService.js"; import { gerarRelatorioNaoResolvidosPdf } from "../services/relatorioNaoResolvidosPdfService.js"; import { gerarRankingAtendentesPdf } from "../services/rankingAtendentesPdfService.js"; import { listarGoldenSet, salvarGoldenLabel, aceitarGoldenLabelComoIa } from "../services/atendimentoGoldenLabelService.js"; import { estruturarMensagem, montarUrlMidia } from "../utils/atendimentoFormat.js"; import { parseFiltrosAvaliacoes } from "../utils/atendimentoAvaliacaoFiltros.js"; import { config } from "../config/index.js"; export const AtendimentosController = { Ingerir: async function (req, res, next) { try { const { atendimento } = req.body; const result = await salvarAtendimento({ payload: atendimento }); res.json({ ok: true, ...result }); } catch (err) { next(err); } }, IngerirUrl: async function (req, res, next) { try { const { url } = req.body; const payload = await fetchAtendimentoJson(url); const result = await salvarAtendimento({ payload, sourceUrl: url }); res.json({ ok: true, ...result }); } catch (err) { next(err); } }, Sincronizar: async function (req, res, next) { try { const result = await sincronizarProtocolosAbertos(req.body); res.json({ ok: true, ...result }); } catch (err) { next(err); } }, SincronizarTudo: async function (req, res, next) { try { const result = await sincronizarTodosProtocolosAbertos(req.body); res.json({ ok: true, ...result }); } catch (err) { next(err); } }, Listar: async function (req, res, next) { try { const page = Math.max(1, Number(req.query.page) || 1); const pageSize = Math.min(100, Math.max(1, Number(req.query.pageSize) || 20)); const setor = typeof req.query.setor === "string" && req.query.setor.trim() ? req.query.setor.trim() : undefined; const status = req.query.status !== undefined ? Number(req.query.status) : undefined; const result = await listarAtendimentos({ page, pageSize, setor, status: Number.isInteger(status) ? status : undefined }); res.json(result); } catch (err) { next(err); } }, Obter: async function (req, res, next) { try { const atendimento = await obterAtendimento(req.params.id); if (!atendimento) throw new NotFoundError("atendimento_not_found"); const mensagens = (atendimento.mensagens ?? []) .map((m) => { const { papel, autor, texto } = estruturarMensagem(m); if (!texto) return null; const transcricao = typeof m.Transcricao === "string" && m.Transcricao.trim() ? m.Transcricao.trim() : null; const transcricaoWhisper = typeof m.TranscricaoWhisper === "string" && m.TranscricaoWhisper.trim() ? m.TranscricaoWhisper.trim() : null; return { Id: m.Id, Papel: papel, Autor: autor, Texto: texto, Transcricao: transcricao, TranscricaoWhisper: transcricaoWhisper, Timestamp: m.Timestamp, Tipodemidia: m.Tipodemidia, Midia: m.Midia, MidiaUrl: montarUrlMidia(m, config.ifbot.mediaBaseUrl) }; }) .filter(Boolean); res.json({ ...atendimento.toJSON(), mensagens }); } catch (err) { next(err); } }, AvaliarPendentes: async function (req, res, next) { try { const result = await avaliarPendentes(req.body); res.json({ ok: true, ...result }); } catch (err) { next(err); } }, AvaliarUm: async function (req, res, next) { try { const result = await avaliarAtendimento(req.params.id); res.json({ ok: true, ...result }); } catch (err) { next(err); } }, SincronizarUm: async function (req, res, next) { try { const result = await sincronizarAtendimentoPorId(req.params.id); res.json({ ok: true, ...result }); } catch (err) { next(err); } }, ListarAvaliacoes: async function (req, res, next) { try { const page = Math.max(1, Number(req.query.page) || 1); const pageSize = Math.min(100, Math.max(1, Number(req.query.pageSize) || 20)); const filtros = parseFiltrosAvaliacoes(req.query); const result = await listarAvaliacoes({ page, pageSize, ...filtros }); res.json(result); } catch (err) { next(err); } }, EstatisticasAvaliacoes: async function (req, res, next) { try { const filtros = parseFiltrosAvaliacoes(req.query); const result = await estatisticasAvaliacoes(filtros); res.json(result); } catch (err) { next(err); } }, ListarSetoresAvaliacoes: async function (req, res, next) { try { const results = await listarSetores(); res.json({ results }); } catch (err) { next(err); } }, RankingAtendentesAvaliacoes: async function (req, res, next) { try { const { setor, dataInicio, dataFim } = parseFiltrosAvaliacoes(req.query); const { resultados, metadados } = await rankingAtendentes({ setor, dataInicio, dataFim }); res.json({ results: resultados, metadados }); } catch (err) { next(err); } }, GerarRelatorioRankingAtendentes: async function (req, res, next) { try { const { setor, dataInicio, dataFim } = parseFiltrosAvaliacoes(req.query); const { buffer } = await gerarRankingAtendentesPdf({ setor, dataInicio, dataFim }); const dataArquivo = new Date().toISOString().slice(0, 10); res.setHeader("Content-Type", "application/pdf"); res.setHeader("Content-Disposition", `attachment; filename="ranking-atendentes-${dataArquivo}.pdf"`); res.setHeader("Content-Length", buffer.length); res.send(buffer); } catch (err) { next(err); } }, GerarRelatorioNaoResolvidos: async function (req, res, next) { try { const filtros = parseFiltrosAvaliacoes(req.query); const { buffer } = await gerarRelatorioNaoResolvidosPdf({ ...filtros, resolvido: "nao" }); const dataArquivo = new Date().toISOString().slice(0, 10); res.setHeader("Content-Type", "application/pdf"); res.setHeader("Content-Disposition", `attachment; filename="atendimentos-nao-resolvidos-${dataArquivo}.pdf"`); res.setHeader("Content-Length", buffer.length); res.send(buffer); } catch (err) { next(err); } }, ListarGoldenSet: async function (req, res, next) { try { const status = typeof req.query.status === "string" && req.query.status.trim() ? req.query.status.trim() : undefined; const setor = typeof req.query.setor === "string" && req.query.setor.trim() ? req.query.setor.trim() : undefined; const results = await listarGoldenSet({ status, setor }); res.json({ results }); } catch (err) { next(err); } }, SalvarGoldenLabel: async function (req, res, next) { try { const result = await salvarGoldenLabel(req.params.id, req.body); res.json(result); } catch (err) { next(err); } }, AceitarGoldenLabel: async function (req, res, next) { try { const result = await aceitarGoldenLabelComoIa(req.params.id); res.json(result); } catch (err) { next(err); } } }; export default AtendimentosController;