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;
|
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;
|
module.exports = LocationMappingModel;
|
||||||
@ -63,6 +63,36 @@ class TicketGlpiModel {
|
|||||||
return 0; // Default se nenhum critério for atendido
|
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) {
|
static formatDescription(ticketData) {
|
||||||
// Função auxiliar para extrair informações usando regex
|
// Função auxiliar para extrair informações usando regex
|
||||||
const extractInfo = (regex, description) => {
|
const extractInfo = (regex, description) => {
|
||||||
@ -129,7 +159,7 @@ class TicketGlpiModel {
|
|||||||
await connection.beginTransaction();
|
await connection.beginTransaction();
|
||||||
|
|
||||||
// Buscar entity_id com base no location_id ou location_name
|
// 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) {
|
if (ticketData.location_id) {
|
||||||
entityId = await LocationMappingModel.getGlpiEntityId(ticketData.location_id) || entityId;
|
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
|
// Formata a descrição para HTML
|
||||||
const formattedDescription = TicketGlpiModel.formatDescription(ticketData);
|
const formattedDescription = TicketGlpiModel.formatDescription(ticketData);
|
||||||
// Mapeia o tipo do ticket
|
// Mapeia o tipo do ticket
|
||||||
@ -157,7 +189,7 @@ class TicketGlpiModel {
|
|||||||
// Prepara os dados para o GLPI
|
// Prepara os dados para o GLPI
|
||||||
const glpiTicketData = {
|
const glpiTicketData = {
|
||||||
entities_id: entityId, // Usar o entity_id mapeado
|
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: ticketData.opened_at || new Date(),
|
||||||
date_mod: ticketData.updated_at || new Date(),
|
date_mod: ticketData.updated_at || new Date(),
|
||||||
status: TicketGlpiModel.mapStatus(ticketData.state || '1'),
|
status: TicketGlpiModel.mapStatus(ticketData.state || '1'),
|
||||||
|
|||||||
@ -4,6 +4,18 @@
|
|||||||
-- OBS: Chamados sempre são abertos pelo ServiceNow
|
-- 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
|
-- TABELA: tickets_sn
|
||||||
-- DESCRIÇÃO: Armazena tickets importados do ServiceNow
|
-- DESCRIÇÃO: Armazena tickets importados do ServiceNow
|
||||||
|
|||||||
@ -8,6 +8,7 @@ from datetime import datetime
|
|||||||
import os
|
import os
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
|
from datetime import timedelta
|
||||||
|
|
||||||
# Carrega as variáveis do .env
|
# Carrega as variáveis do .env
|
||||||
load_dotenv()
|
load_dotenv()
|
||||||
@ -43,6 +44,22 @@ GLPI_DB_CONFIG = {
|
|||||||
# Caminho para o arquivo CSV
|
# Caminho para o arquivo CSV
|
||||||
CSV_PATH = os.getenv('LOCATION_MAPPING_CSV_PATH')
|
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
|
# Função para conectar ao banco SNGLPI
|
||||||
def get_snglpi_connection():
|
def get_snglpi_connection():
|
||||||
try:
|
try:
|
||||||
@ -177,8 +194,9 @@ def update_mapping_table():
|
|||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
logging.info("Iniciando atualização de mapeamento de localizações")
|
logging.info("Iniciando atualização de mapeamento de localizações")
|
||||||
success = update_mapping_table()
|
if csv_recently_modified(minutes=2):
|
||||||
if success:
|
success = update_mapping_table()
|
||||||
logging.info("Atualização concluída com sucesso")
|
if success:
|
||||||
else:
|
logging.info("Atualização concluída com sucesso")
|
||||||
logging.error("Falha na atualização")
|
else:
|
||||||
|
logging.error("Falha na atualização")
|
||||||
Loading…
Reference in New Issue
Block a user