FEAT: Titulo da solicitação adicionado dinamicamente
- Adição de Titulo composto dinamicamente "TIPO - ENTIDADE - PROBLEMA" - Adicionado Fluxo completo da criação do banco de dados - Adicionado verificação se o arquivo .csv foi modificado nos ultimos 2 minutos, se sim a tabela de mapping é atualizada
This commit is contained in:
parent
07230dd1e4
commit
9df7e62cf5
@ -47,6 +47,66 @@ class LocationMappingModel {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Buscar entity (id e name) do GLPI baseado no location_id do ServiceNow
|
||||
static async getGlpiEntity(snLocationId) {
|
||||
try {
|
||||
const query = `
|
||||
SELECT glpi_entity_id, glpi_entity_name
|
||||
FROM location_mapping
|
||||
WHERE sn_location_id = $1
|
||||
`;
|
||||
|
||||
const result = await pool.query(query, [snLocationId]);
|
||||
|
||||
if (result.rows.length > 0) {
|
||||
return {
|
||||
id: result.rows[0].glpi_entity_id,
|
||||
name: result.rows[0].glpi_entity_name
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
} catch (error) {
|
||||
logError(error, `Erro ao buscar entity para location_id: ${snLocationId}`);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Buscar entity (id e name) do GLPI baseado no location_name do ServiceNow
|
||||
static async getGlpiEntityByName(snLocationName) {
|
||||
try {
|
||||
const query = `
|
||||
SELECT glpi_entity_id, glpi_entity_name
|
||||
FROM location_mapping
|
||||
WHERE sn_location_name = $1
|
||||
`;
|
||||
|
||||
const result = await pool.query(query, [snLocationName]);
|
||||
|
||||
if (result.rows.length > 0) {
|
||||
return {
|
||||
id: result.rows[0].glpi_entity_id,
|
||||
name: result.rows[0].glpi_entity_name
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
} catch (error) {
|
||||
logError(error, `Erro ao buscar entity para location_name: ${snLocationName}`);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
module.exports = LocationMappingModel;
|
||||
@ -63,6 +63,36 @@ class TicketGlpiModel {
|
||||
return 0; // Default se nenhum critério for atendido
|
||||
}
|
||||
|
||||
// Formata o título do ticket
|
||||
static async formatTitle(ticketData) {
|
||||
try {
|
||||
let entityData = null;
|
||||
|
||||
if (ticketData.location_id) {
|
||||
entityData = await LocationMappingModel.getGlpiEntity(ticketData.location_id);
|
||||
} else if (ticketData.location_name) {
|
||||
entityData = await LocationMappingModel.getGlpiEntityByName(ticketData.location_name);
|
||||
}
|
||||
|
||||
const entityName = entityData?.name || 'Sem Entidade';
|
||||
const tipo = ticketData.type === 'requisicao' ? 'REQUISIÇÃO' : 'INCIDENTE';
|
||||
const tituloSn = ticketData.short_description || 'Sem título';
|
||||
|
||||
return {
|
||||
title: `${tipo} - ${entityName} - ${tituloSn}`,
|
||||
entityId: entityData?.id || 127 // fallback para entity_id default
|
||||
};
|
||||
} catch (error) {
|
||||
logError(error, 'Erro ao formatar título do ticket');
|
||||
const tipo = ticketData.type === 'requisicao' ? 'REQUISIÇÃO' : 'INCIDENTE';
|
||||
return {
|
||||
title: `${tipo} - ${ticketData.short_description || 'Sem título'}`,
|
||||
entityId: 127
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static formatDescription(ticketData) {
|
||||
// Função auxiliar para extrair informações usando regex
|
||||
const extractInfo = (regex, description) => {
|
||||
@ -129,7 +159,7 @@ class TicketGlpiModel {
|
||||
await connection.beginTransaction();
|
||||
|
||||
// Buscar entity_id com base no location_id ou location_name
|
||||
let entityId = 1371; // Valor padrão (fallback)
|
||||
let entityId = 127; // Valor padrão (fallback)
|
||||
|
||||
if (ticketData.location_id) {
|
||||
entityId = await LocationMappingModel.getGlpiEntityId(ticketData.location_id) || entityId;
|
||||
@ -147,6 +177,8 @@ class TicketGlpiModel {
|
||||
}
|
||||
}
|
||||
|
||||
// Formata o título do ticket
|
||||
const { title: formattedTitle } = await TicketGlpiModel.formatTitle(ticketData);
|
||||
// Formata a descrição para HTML
|
||||
const formattedDescription = TicketGlpiModel.formatDescription(ticketData);
|
||||
// Mapeia o tipo do ticket
|
||||
@ -157,7 +189,7 @@ class TicketGlpiModel {
|
||||
// Prepara os dados para o GLPI
|
||||
const glpiTicketData = {
|
||||
entities_id: entityId, // Usar o entity_id mapeado
|
||||
name: ticketData.short_description || 'Ticket sem descrição',
|
||||
name: formattedTitle,
|
||||
date: ticketData.opened_at || new Date(),
|
||||
date_mod: ticketData.updated_at || new Date(),
|
||||
status: TicketGlpiModel.mapStatus(ticketData.state || '1'),
|
||||
|
||||
@ -4,6 +4,18 @@
|
||||
-- OBS: Chamados sempre são abertos pelo ServiceNow
|
||||
-- =============================================
|
||||
|
||||
CREATE DATABASE snglpi
|
||||
WITH
|
||||
OWNER = desenvolvimento
|
||||
ENCODING = 'UTF8'
|
||||
LC_COLLATE = 'en_US.UTF-8'
|
||||
LC_CTYPE = 'en_US.UTF-8'
|
||||
LOCALE_PROVIDER = 'libc'
|
||||
TABLESPACE = pg_default
|
||||
CONNECTION LIMIT = -1
|
||||
IS_TEMPLATE = False;
|
||||
|
||||
|
||||
-- =============================================
|
||||
-- TABELA: tickets_sn
|
||||
-- DESCRIÇÃO: Armazena tickets importados do ServiceNow
|
||||
|
||||
@ -8,6 +8,7 @@ from datetime import datetime
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
import pandas as pd
|
||||
from datetime import timedelta
|
||||
|
||||
# Carrega as variáveis do .env
|
||||
load_dotenv()
|
||||
@ -43,6 +44,22 @@ GLPI_DB_CONFIG = {
|
||||
# Caminho para o arquivo CSV
|
||||
CSV_PATH = os.getenv('LOCATION_MAPPING_CSV_PATH')
|
||||
|
||||
# Função para verificar se o CSV foi modificado recentemente
|
||||
def csv_recently_modified(minutes=2):
|
||||
if not os.path.exists(CSV_PATH):
|
||||
logging.error(f"Arquivo CSV não encontrado: {CSV_PATH}")
|
||||
return False
|
||||
|
||||
last_mod_time = datetime.fromtimestamp(os.path.getmtime(CSV_PATH))
|
||||
if datetime.now() - last_mod_time <= timedelta(minutes=minutes):
|
||||
logging.info(f"CSV modificado recentemente ({last_mod_time}), rodando atualização.")
|
||||
return True
|
||||
else:
|
||||
logging.info(f"CSV não foi modificado nos últimos {minutes} minutos (última modificação: {last_mod_time}).")
|
||||
return False
|
||||
|
||||
|
||||
|
||||
# Função para conectar ao banco SNGLPI
|
||||
def get_snglpi_connection():
|
||||
try:
|
||||
@ -177,8 +194,9 @@ def update_mapping_table():
|
||||
|
||||
if __name__ == "__main__":
|
||||
logging.info("Iniciando atualização de mapeamento de localizações")
|
||||
success = update_mapping_table()
|
||||
if success:
|
||||
logging.info("Atualização concluída com sucesso")
|
||||
else:
|
||||
logging.error("Falha na atualização")
|
||||
if csv_recently_modified(minutes=2):
|
||||
success = update_mapping_table()
|
||||
if success:
|
||||
logging.info("Atualização concluída com sucesso")
|
||||
else:
|
||||
logging.error("Falha na atualização")
|
||||
Loading…
Reference in New Issue
Block a user