2025-09-17 20:56:32 -03:00
|
|
|
// src/models/ticketSyncModel.js
|
2025-10-13 06:06:52 -03:00
|
|
|
const { query } = require('winston');
|
2025-09-17 20:56:32 -03:00
|
|
|
const pool = require('../data/database');
|
2025-09-24 20:34:34 -03:00
|
|
|
const { logError } = require('../utils/logger');
|
2025-09-17 20:56:32 -03:00
|
|
|
|
|
|
|
|
class TicketSyncModel {
|
|
|
|
|
|
2025-10-13 06:06:52 -03:00
|
|
|
// Cria um registro de sincronização para um ticket
|
|
|
|
|
static async createSyncRecord(data) {
|
|
|
|
|
try {
|
2025-10-17 16:58:14 -03:00
|
|
|
|
|
|
|
|
|
2025-10-13 06:06:52 -03:00
|
|
|
const query = `INSERT INTO ticket_sync (
|
|
|
|
|
sn_ticket_id,
|
|
|
|
|
glpi_ticket_id,
|
|
|
|
|
last_sn_sync,
|
|
|
|
|
last_glpi_sync,
|
|
|
|
|
created_at,
|
|
|
|
|
updated_at,
|
|
|
|
|
sn_sync_status,
|
2025-10-23 17:30:03 -03:00
|
|
|
glpi_sync_status,
|
|
|
|
|
source_last
|
|
|
|
|
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) RETURNING id`;
|
2025-10-13 06:06:52 -03:00
|
|
|
|
2025-10-17 16:58:14 -03:00
|
|
|
const values = [
|
|
|
|
|
data.sn_ticket_id,
|
|
|
|
|
data.glpi_ticket,
|
|
|
|
|
data.last_sn_sync,
|
|
|
|
|
data.last_glpi_sync,
|
|
|
|
|
data.created_at,
|
|
|
|
|
data.updated_at,
|
|
|
|
|
data.sn_sync_status,
|
2025-10-23 17:30:03 -03:00
|
|
|
data.glpi_sync_status,
|
|
|
|
|
data.source_last
|
2025-10-17 16:58:14 -03:00
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
await pool.query(query, values);
|
2025-10-13 06:06:52 -03:00
|
|
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
logError(error, '❌ Erro ao criar registro de sincronização');
|
|
|
|
|
throw error;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2025-09-24 20:34:34 -03:00
|
|
|
// Buscar tickets que foram criados com sucesso para sincronizar comentários
|
2025-10-17 16:58:14 -03:00
|
|
|
static async getTicketsToSync(glpi_sync_status, sn_sync_status) {
|
2025-09-17 20:56:32 -03:00
|
|
|
try {
|
2025-10-17 16:58:14 -03:00
|
|
|
const query = 'SELECT id, glpi_ticket_id, sn_ticket_id FROM ticket_sync WHERE glpi_sync_status = $1 AND sn_sync_status = $2';
|
|
|
|
|
const values =[glpi_sync_status , sn_sync_status];
|
|
|
|
|
const { rows } = await pool.query(query, values);
|
2025-09-24 20:34:34 -03:00
|
|
|
return rows;
|
2025-09-17 20:56:32 -03:00
|
|
|
} catch (error) {
|
2025-09-24 20:34:34 -03:00
|
|
|
logError(error, '❌ Erro ao buscar tickets para sincronizar');
|
2025-09-17 20:56:32 -03:00
|
|
|
throw error;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-23 17:30:03 -03:00
|
|
|
// Atualiza apenas o source_last de um ticket
|
|
|
|
|
static async updateSourceLast(snTicketId, source) {
|
|
|
|
|
try {
|
|
|
|
|
const query = 'UPDATE ticket_sync SET source_last = $1 WHERE sn_ticket_id = $2';
|
|
|
|
|
await pool.query(query, [source, snTicketId]);
|
|
|
|
|
} catch (error) {
|
|
|
|
|
logError(error, `❌ Erro ao atualizar source_last para o ticket SN ID: ${snTicketId}`);
|
|
|
|
|
throw error;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-24 20:34:34 -03:00
|
|
|
// Atualiza o status de sincronização de um ticket
|
|
|
|
|
static async updateStatus(ticketSyncId, glpiStatus, snStatus) {
|
2025-09-17 20:56:32 -03:00
|
|
|
try {
|
2025-10-17 16:58:14 -03:00
|
|
|
const query = 'UPDATE ticket_sync SET glpi_sync_status = $1, sn_sync_status = $2 WHERE sn_ticket_id = $3';
|
2025-09-24 20:34:34 -03:00
|
|
|
await pool.query(query, [glpiStatus, snStatus, ticketSyncId]);
|
2025-09-17 20:56:32 -03:00
|
|
|
} catch (error) {
|
2025-10-17 16:58:14 -03:00
|
|
|
logError(`${error} ❌ Erro ao atualizar status de sincronização para o ID: ${ticketSyncId}`);
|
2025-09-17 20:56:32 -03:00
|
|
|
throw error;
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-10-23 17:30:03 -03:00
|
|
|
// Atualiza o status de sincronização de um ticket e o source last
|
|
|
|
|
static async updateStatusAndSourceLast(ticketSyncId, glpiStatus, snStatus, source_last) {
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
|
|
const query = 'UPDATE ticket_sync SET glpi_sync_status = $1, sn_sync_status= $2, source_last = $4 WHERE sn_ticket_id = $3';
|
|
|
|
|
await pool.query(query, [glpiStatus, snStatus, ticketSyncId, source_last]);
|
|
|
|
|
} catch (error) {
|
|
|
|
|
logError(`${error} ❌ Erro ao atualizar status de sincronização para o ID: ${ticketSyncId}`);
|
|
|
|
|
throw error;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Atualiza apenas o source_last de um ticket
|
|
|
|
|
static async updateSourceLast(snTicketId, source) {
|
|
|
|
|
try {
|
|
|
|
|
const query = 'UPDATE ticket_sync SET source_last = $1 WHERE sn_ticket_id = $2';
|
|
|
|
|
await pool.query(query, [source, snTicketId]);
|
|
|
|
|
} catch (error) {
|
|
|
|
|
logError(error, `❌ Erro ao atualizar source_last para o ticket SN ID: ${snTicketId}`);
|
|
|
|
|
throw error;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2025-10-10 08:12:26 -03:00
|
|
|
|
2025-10-17 16:58:14 -03:00
|
|
|
static async updateStatusAndGlpiTicket(ticketSyncId, glpiStatus, snStatus, glpiTicketId) {
|
|
|
|
|
try {
|
|
|
|
|
const query = 'UPDATE ticket_sync SET glpi_sync_status = $1, sn_sync_status = $2, glpi_ticket_id = $4 WHERE sn_ticket_id = $3';
|
|
|
|
|
await pool.query(query, [glpiStatus, snStatus, ticketSyncId, glpiTicketId]);
|
|
|
|
|
} catch (error) {
|
|
|
|
|
logError(error, `❌ Erro ao atualizar status de sincronização para o ID: ${ticketSyncId}`);
|
|
|
|
|
throw error;
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-10-10 08:12:26 -03:00
|
|
|
|
2025-09-24 20:34:34 -03:00
|
|
|
// Buscar o ID de sincronização baseado no glpi_ticket_id
|
|
|
|
|
static async getIdSyncByGlpiId(glpiTicketId) {
|
2025-09-17 20:56:32 -03:00
|
|
|
try {
|
2025-09-24 20:34:34 -03:00
|
|
|
const query = 'SELECT id FROM ticket_sync WHERE glpi_ticket_id = $1';
|
|
|
|
|
const { rows } = await pool.query(query, [glpiTicketId]);
|
|
|
|
|
return rows[0] ? rows[0].id : null;
|
2025-09-17 20:56:32 -03:00
|
|
|
} catch (error) {
|
2025-09-24 20:34:34 -03:00
|
|
|
logError(error, `❌ Erro ao buscar ID de sincronização por GLPI ID: ${glpiTicketId}`);
|
|
|
|
|
throw error;
|
2025-09-17 20:56:32 -03:00
|
|
|
}
|
|
|
|
|
}
|
2025-09-25 15:59:52 -03:00
|
|
|
|
2025-10-23 17:30:03 -03:00
|
|
|
// Buscar o ID de sincronização baseado no sys_id do SN
|
|
|
|
|
static async getBySysId(sysId) {
|
|
|
|
|
try {
|
|
|
|
|
const query = `
|
|
|
|
|
SELECT tsync.* FROM ticket_sync tsync
|
|
|
|
|
JOIN tickets_sn tsn ON tsync.sn_ticket_id = tsn.id
|
|
|
|
|
WHERE tsn.sys_id = $1`;
|
|
|
|
|
const { rows } = await pool.query(query, [sysId]);
|
|
|
|
|
return rows[0] || null;
|
|
|
|
|
} catch (error) {
|
|
|
|
|
logError(error, `❌ Erro ao buscar registro de sincronização por sys_id: ${sysId}`);
|
|
|
|
|
throw error;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-10 08:12:26 -03:00
|
|
|
// Buscar o ID de sincronização baseado no sn_ticket_id
|
|
|
|
|
static async getIdSyncBySnId(snTicketId) {
|
|
|
|
|
try {
|
|
|
|
|
const query = 'SELECT id FROM ticket_sync WHERE sn_ticket_id = $1';
|
|
|
|
|
const { rows } = await pool.query(query, [snTicketId]);
|
|
|
|
|
return rows[0] ? rows[0].id : null;
|
|
|
|
|
} catch (error) {
|
2025-10-23 17:30:03 -03:00
|
|
|
logError(error, `❌ Erro ao buscar ID de sincronização por SN ID: ${snTicketId}`);
|
2025-10-10 08:12:26 -03:00
|
|
|
throw error;
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-10-13 06:06:52 -03:00
|
|
|
static async getByTicketNumber(ticketNumber) {
|
|
|
|
|
try {
|
2025-10-17 16:58:14 -03:00
|
|
|
const query = 'SELECT * FROM ticket_sync WHERE sn_ticket_id = $1';
|
|
|
|
|
const { rows } = await pool.query(query, [ticketNumber]);
|
|
|
|
|
return rows[0] || null;
|
2025-10-10 08:12:26 -03:00
|
|
|
|
2025-10-13 06:06:52 -03:00
|
|
|
} catch (error) {
|
2025-10-17 16:58:14 -03:00
|
|
|
logError(`${error}, ❌ Erro ao buscar ticket ${ticketNumber}}` )
|
2025-10-13 06:06:52 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
2025-10-10 08:12:26 -03:00
|
|
|
|
2025-10-17 16:58:14 -03:00
|
|
|
// Buscar tickets que estão sincronizados
|
|
|
|
|
static async getTicketsSynced() {
|
|
|
|
|
try {
|
|
|
|
|
const query = `
|
|
|
|
|
SELECT
|
|
|
|
|
tsync.id,
|
|
|
|
|
tsync.glpi_ticket_id,
|
|
|
|
|
tsync.sn_ticket_id,
|
2025-10-23 17:30:03 -03:00
|
|
|
tsn.sys_id,
|
|
|
|
|
tsync.source_last
|
2025-10-17 16:58:14 -03:00
|
|
|
FROM ticket_sync tsync
|
|
|
|
|
JOIN tickets_sn tsn ON tsync.sn_ticket_id = tsn.id
|
|
|
|
|
WHERE tsync.glpi_sync_status = 'synced' AND tsync.sn_sync_status = 'synced'`;
|
|
|
|
|
const { rows } = await pool.query(query);
|
|
|
|
|
return rows;
|
|
|
|
|
} catch (error) {
|
|
|
|
|
logError(error, '❌ Erro ao buscar tickets para sincronizar');
|
|
|
|
|
throw error;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-23 17:30:03 -03:00
|
|
|
// Buscar tickets que estão ativos para monitoramento (synced ou solved)
|
|
|
|
|
static async getTicketsToMonitor() {
|
|
|
|
|
try {
|
|
|
|
|
const query = `
|
|
|
|
|
SELECT
|
|
|
|
|
tsync.id,
|
|
|
|
|
tsync.glpi_ticket_id,
|
|
|
|
|
tsync.sn_ticket_id,
|
|
|
|
|
tsn.sys_id,
|
|
|
|
|
tsync.source_last,
|
|
|
|
|
tsync.sn_sync_status,
|
|
|
|
|
tsync.glpi_sync_status
|
|
|
|
|
FROM ticket_sync tsync
|
|
|
|
|
JOIN tickets_sn tsn ON tsync.sn_ticket_id = tsn.id
|
|
|
|
|
WHERE (tsync.glpi_sync_status IN ('synced', 'solved') OR tsync.sn_sync_status IN ('synced', 'solved'))
|
|
|
|
|
AND (tsync.glpi_sync_status != 'closed' AND tsync.sn_sync_status != 'closed')`;
|
|
|
|
|
const { rows } = await pool.query(query);
|
|
|
|
|
return rows;
|
|
|
|
|
} catch (error) {
|
|
|
|
|
logError(error, '❌ Erro ao buscar tickets para monitorar');
|
|
|
|
|
throw error;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Buscar tickets que precisam ter o fechamento sincronizado
|
|
|
|
|
static async getTicketsPendingSolve() {
|
|
|
|
|
try {
|
|
|
|
|
const query = `
|
|
|
|
|
SELECT
|
|
|
|
|
tsync.id,
|
|
|
|
|
tsync.glpi_ticket_id,
|
|
|
|
|
tsync.sn_ticket_id,
|
|
|
|
|
tsync.glpi_sync_status,
|
|
|
|
|
tsync.sn_sync_status,
|
|
|
|
|
tsn.sys_id,
|
|
|
|
|
tsn.tipo
|
|
|
|
|
FROM ticket_sync tsync
|
|
|
|
|
JOIN tickets_sn tsn ON tsync.sn_ticket_id = tsn.id
|
|
|
|
|
WHERE tsync.glpi_sync_status = 'pending_solve' OR tsync.sn_sync_status = 'pending_solve'`;
|
|
|
|
|
const { rows } = await pool.query(query);
|
|
|
|
|
return rows;
|
|
|
|
|
} catch (error) {
|
|
|
|
|
logError(error, '❌ Erro ao buscar tickets pendentes de fechamento');
|
|
|
|
|
throw error;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Busca todos os tickets que estão em algum estado de erro
|
|
|
|
|
static async getTicketsInErrorState() {
|
|
|
|
|
try {
|
|
|
|
|
const query = `
|
|
|
|
|
SELECT id, sn_ticket_id, glpi_ticket_id, sn_sync_status, glpi_sync_status
|
|
|
|
|
FROM ticket_sync
|
|
|
|
|
WHERE sn_sync_status LIKE '%error%' OR glpi_sync_status LIKE '%error%'
|
|
|
|
|
`;
|
|
|
|
|
const { rows } = await pool.query(query);
|
|
|
|
|
return rows;
|
|
|
|
|
} catch (error) {
|
|
|
|
|
logError(error, '❌ Erro ao buscar tickets em estado de erro');
|
|
|
|
|
throw error;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Atualiza os timestamps de última sincronização
|
|
|
|
|
static async updateLastSync(snTicketId, system) {
|
|
|
|
|
try {
|
|
|
|
|
let fieldToUpdate;
|
|
|
|
|
if (system === 'servicenow') {
|
|
|
|
|
fieldToUpdate = 'last_sn_sync';
|
|
|
|
|
} else if (system === 'glpi') {
|
|
|
|
|
fieldToUpdate = 'last_glpi_sync';
|
|
|
|
|
} else {
|
|
|
|
|
return; // Não faz nada se o sistema for inválido
|
|
|
|
|
}
|
|
|
|
|
const query = `UPDATE ticket_sync SET ${fieldToUpdate} = NOW() WHERE sn_ticket_id = $1`;
|
|
|
|
|
await pool.query(query, [snTicketId]);
|
|
|
|
|
} catch (error) {
|
|
|
|
|
logError(`${error} ❌ Erro ao atualizar last_sync para o ID: ${snTicketId}`);
|
|
|
|
|
// Não lançar erro para não parar o fluxo principal
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Atualiza o status de sincronização de um ticket usando o GLPI ID
|
|
|
|
|
static async updateStatusByGlpiId(glpiTicketId, snStatus, glpiStatus) {
|
|
|
|
|
try {
|
|
|
|
|
const query = 'UPDATE ticket_sync SET sn_sync_status = $1, glpi_sync_status = $2 WHERE glpi_ticket_id = $3';
|
|
|
|
|
await pool.query(query, [snStatus, glpiStatus, glpiTicketId]);
|
|
|
|
|
} catch (error) {
|
|
|
|
|
logError(`${error} ❌ Erro ao atualizar status de sincronização para o GLPI ID: ${glpiTicketId}`);
|
|
|
|
|
throw error;
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-10-17 16:58:14 -03:00
|
|
|
|
2025-10-10 08:12:26 -03:00
|
|
|
|
2025-09-17 20:56:32 -03:00
|
|
|
}
|
2025-09-24 20:34:34 -03:00
|
|
|
/**
|
|
|
|
|
* @module TicketSyncModel
|
|
|
|
|
* @description Este módulo fornece métodos para interagir com a tabela de sincronização de tickets (ticket_sync) no banco de dados.
|
|
|
|
|
* Inclui funcionalidades para buscar tickets para sincronização, atualizar o status de sincronização
|
|
|
|
|
* e buscar o ID de sincronização baseado no glpi_ticket_id.
|
|
|
|
|
*
|
|
|
|
|
* A função getTicketsToSync busca todos os tickets que possuem IDs tanto no GLPI quanto no ServiceNow.
|
|
|
|
|
* A função updateStatus atualiza os status de sincronização do GLPI e do ServiceNow para um ticket específico.
|
|
|
|
|
* A função getIdSyncByGlpiId retorna o ID de sincronização baseado no glpi_ticket_id.
|
|
|
|
|
* Essas funcionalidades são essenciais para manter a consistência e o rastreamento dos tickets entre os dois sistemas.
|
|
|
|
|
*/
|
|
|
|
|
|
2025-09-17 20:56:32 -03:00
|
|
|
|
|
|
|
|
module.exports = TicketSyncModel;
|