const { app, BrowserWindow, ipcMain } = require('electron') const path = require('path') const axios = require('axios') const fs = require('fs') const os = require('os') // Variable globale pour stocker les données de session let sessionData = { token: null, refreshToken: null, apiUrl: null, userData: null, tokenExpiresAt: null, // Données pour le refresh automatique authData: { tenantCode: null, username: null, password: null // Note: stocker le mot de passe n'est pas idéal pour la sécurité } } // Chemin pour sauvegarder le token const tokenFilePath = path.join(os.homedir(), '.janitor-session.json') // Charger les données de session depuis le fichier function loadSessionData() { try { if (fs.existsSync(tokenFilePath)) { const data = fs.readFileSync(tokenFilePath, 'utf8') sessionData = JSON.parse(data) console.log('Données de session chargées') } } catch (error) { console.error('Erreur lors du chargement des données de session:', error) } } // Sauvegarder les données de session dans un fichier function saveSessionData() { try { fs.writeFileSync(tokenFilePath, JSON.stringify(sessionData, null, 2)) console.log('Données de session sauvegardées') } catch (error) { console.error('Erreur lors de la sauvegarde des données de session:', error) } } // Nettoyer les données de session function clearSessionData() { sessionData = { token: null, refreshToken: null, apiUrl: null, userData: null, tokenExpiresAt: null, authData: { tenantCode: null, username: null, password: null } } try { if (fs.existsSync(tokenFilePath)) { fs.unlinkSync(tokenFilePath) console.log('Fichier de session supprimé') } } catch (error) { console.error('Erreur lors de la suppression du fichier de session:', error) } } // Fonction pour faire le refresh du token async function refreshToken() { if (!sessionData.refreshToken || !sessionData.apiUrl) { console.log('Pas de refresh token disponible') return { success: false, message: 'Pas de refresh token disponible' } } try { // Préparer les données au format x-www-form-urlencoded const params = new URLSearchParams() params.append('grant_type', 'refresh_token') params.append('refresh_token', sessionData.refreshToken) params.append('forcerevoke', '1') // Optionnel selon la doc // Utiliser le même authString que pour l'authentification initiale const authString = "R05BOklFNGU3aXFoZHQ=" // Préparer l'URL let apiUrl = sessionData.apiUrl if (apiUrl.startsWith('http://')) { apiUrl = apiUrl.replace('http://', 'https://') } else if (!apiUrl.startsWith('https://')) { apiUrl = 'https://' + apiUrl } console.log('Tentative de refresh du token...') // Faire l'appel API de refresh const response = await axios.post( `${apiUrl}/EasySTS/OAuth/Token`, params, { headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'Authorization': `Basic ${authString}` }, timeout: 30000, httpsAgent: new (require('https').Agent)({ rejectUnauthorized: false }) } ) console.log('Refresh réussi:', response.data) // Calculer la nouvelle date d'expiration const expiresIn = response.data.expires_in || 3600 const expiresAt = new Date(Date.now() + (expiresIn * 1000)) // Mettre à jour les données de session sessionData.token = response.data.access_token || response.data.token sessionData.refreshToken = response.data.refresh_token || sessionData.refreshToken // Garder l'ancien si pas de nouveau sessionData.tokenExpiresAt = expiresAt sessionData.userData = response.data // Sauvegarder la session mise à jour saveSessionData() console.log('Token refreshé avec succès, expire le:', expiresAt) return { success: true, token: sessionData.token, expiresAt: expiresAt, message: 'Token refreshé avec succès' } } catch (error) { console.error('Erreur lors du refresh du token:', error) if (error.response) { console.log('Détails de l\'erreur refresh:', error.response.data) return { success: false, message: `Erreur refresh ${error.response.status}: ${error.response.data.message || error.response.data.error_description || 'Refresh échoué'}`, error: error.response.data } } else if (error.request) { return { success: false, message: 'Impossible de contacter le serveur pour le refresh', error: 'Network error' } } else { return { success: false, message: 'Erreur de configuration refresh', error: error.message } } } } function createWindow() { const win = new BrowserWindow({ width: 1400, height: 900, icon: path.join(__dirname, 'images', 'logo.ico'), autoHideMenuBar: true, webPreferences: { nodeIntegration: false, contextIsolation: true, preload: path.join(__dirname, 'preload.js') } }) win.loadFile('index.html') return win } // Fonction pour faire l'appel API d'authentification async function authenticateUser(formData) { try { // Préparer les données au format x-www-form-urlencoded const params = new URLSearchParams() params.append('grant_type', 'password') params.append('tenant_code', formData.tenantCode) params.append('username', formData.user) params.append('password', formData.password) // Utiliser l'authString fourni (avec le = manquant) const authString = "R05BOklFNGU3aXFoZHQ=" console.log('Paramètres envoyés:', { grant_type: 'password', tenant_code: formData.tenantCode, username: formData.user, password: '***' // Masquer le mot de passe dans les logs }) // Préparer l'URL pour l'appel API let apiUrl = formData.url // CORRECTION: utiliser formData.url au lieu de data.url // Forcer HTTPS quoi qu'il arrive if (apiUrl.startsWith('http://')) { apiUrl = apiUrl.replace('http://', 'https://') } else if (!apiUrl.startsWith('https://')) { apiUrl = 'https://' + apiUrl } console.log("apiUrl : "+ apiUrl) // Faire l'appel API const response = await axios.post( `${apiUrl}/EasySTS/OAuth/Token`, // Endpoint corrigé params, { headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'Authorization': `Basic ${authString}` }, timeout: 30000, // Timeout de 30 secondes httpsAgent: new (require('https').Agent)({ rejectUnauthorized: false // Ignore les certificats SSL non vérifiés }) } ) console.log('Réponse API:', response.data) // Calculer la date d'expiration du token const expiresIn = response.data.expires_in || 3600 // Par défaut 1 heure si non spécifié const expiresAt = new Date(Date.now() + (expiresIn * 1000)) // Convertir en millisecondes return { success: true, token: response.data.access_token || response.data.token, refreshToken: response.data.refresh_token, // Peut être undefined si pas fourni expiresAt: expiresAt, message: 'Authentification réussie', data: response.data } } catch (error) { console.error('Erreur lors de l\'authentification:', error) if (error.response) { // Le serveur a répondu avec un code d'erreur console.log('Détails de l\'erreur:', error.response.data) return { success: false, message: `Erreur ${error.response.status}: ${error.response.data.message || error.response.data.error_description || 'Authentification échouée'}`, error: error.response.data } } else if (error.request) { // La requête a été faite mais pas de réponse return { success: false, message: 'Impossible de contacter le serveur', error: 'Network error' } } else { // Erreur dans la configuration de la requête return { success: false, message: 'Erreur de configuration', error: error.message } } } } // Écouter les données du formulaire ipcMain.on('form-data', async (event, data) => { console.log('Données reçues du formulaire:', { url: data.url, tenantCode: data.tenantCode, user: data.user, password: '***' // Masquer le mot de passe }) // Valider les données if (!data.url || !data.user || !data.password) { event.reply('form-response', { success: false, message: 'Tous les champs sont requis' }) return } // Valider l'URL (accepte les IPs et domaines) try { // Ajouter http:// si pas de protocole let urlToTest = data.url if (!urlToTest.startsWith('http://') && !urlToTest.startsWith('https://')) { urlToTest = 'http://' + urlToTest } new URL(urlToTest) } catch (e) { event.reply('form-response', { success: false, message: 'URL invalide' }) return } // Envoyer une réponse immédiate pour indiquer le traitement event.reply('form-response', { success: true, message: 'Authentification en cours...', loading: true }) // Faire l'appel API const authResult = await authenticateUser(data) // Envoyer le résultat final event.reply('form-response', authResult) // Si l'authentification réussit, rediriger vers le dashboard if (authResult.success && !authResult.loading) { // Stocker les données de session sessionData.token = authResult.token sessionData.refreshToken = authResult.refreshToken sessionData.apiUrl = data.url // Correction: utiliser data.url au lieu de formData.url sessionData.userData = authResult.data sessionData.tokenExpiresAt = authResult.expiresAt // Stocker les données d'authentification pour le refresh automatique sessionData.authData.tenantCode = data.tenantCode sessionData.authData.username = data.user sessionData.authData.password = data.password // Note: pas idéal pour la sécurité // Sauvegarder la session saveSessionData() console.log('Token expire le:', sessionData.tokenExpiresAt) // Attendre un petit délai pour que l'utilisateur voie le message de succès setTimeout(() => { const win = BrowserWindow.getFocusedWindow() if (win) { win.loadFile('dashboard.html') } }, 1000) // Délai d'1 seconde } }) app.whenReady().then(() => { // Charger les données de session au démarrage loadSessionData() createWindow() app.on('activate', () => { if (BrowserWindow.getAllWindows().length === 0) { createWindow() } }) }) app.on('window-all-closed', () => { if (process.platform !== 'darwin') { app.quit() } }) // Fonction pour vérifier la validité du token et refresh automatique async function verifyToken() { if (!sessionData.token || !sessionData.tokenExpiresAt) { return { valid: false, message: 'Aucun token trouvé' } } // Vérifier si le token a expiré en comparant avec la date actuelle const now = new Date() const expiresAt = new Date(sessionData.tokenExpiresAt) const timeRemaining = Math.floor((expiresAt - now) / 1000) // en secondes // Si le token expire dans moins de 3 minutes (180 secondes), essayer de le refresh if (timeRemaining <= 180 && timeRemaining > 0) { console.log(`Token expire dans ${timeRemaining} secondes, tentative de refresh...`) const refreshResult = await refreshToken() if (refreshResult.success) { console.log('Refresh automatique réussi') // Recalculer le temps restant avec le nouveau token const newExpiresAt = new Date(sessionData.tokenExpiresAt) const newTimeRemaining = Math.floor((newExpiresAt - now) / 1000) return { valid: true, message: 'Token refreshé automatiquement', expiresAt: newExpiresAt, timeRemaining: newTimeRemaining, refreshed: true } } else { console.log('Échec du refresh automatique:', refreshResult.message) // Le refresh a échoué, mais le token est peut-être encore valide pour quelques minutes if (timeRemaining > 0) { return { valid: true, message: `Token valide encore ${timeRemaining}s, refresh échoué`, expiresAt: expiresAt, timeRemaining: timeRemaining, refreshFailed: true } } } } // Si le token a expiré if (now >= expiresAt) { console.log('Token expiré:', { maintenant: now.toISOString(), expiration: expiresAt.toISOString() }) return { valid: false, message: 'Token expiré' } } // Token encore valide (plus de 3 minutes restantes) console.log(`Token valide encore ${timeRemaining} secondes`) return { valid: true, message: 'Token valide', expiresAt: expiresAt, timeRemaining: timeRemaining } } // Écouter les demandes de vérification de token ipcMain.handle('verify-token', async () => { const result = await verifyToken() if (!result.valid) { // Nettoyer les données de session clearSessionData() } return result }) // Écouter les demandes de refresh forcé du token ipcMain.handle('force-refresh-token', async () => { try { const result = await refreshToken() return result } catch (error) { console.error('Erreur lors du refresh forcé:', error) return { success: false, message: error.message } } }) // Écouter les demandes de déconnexion ipcMain.on('logout', () => { // Nettoyer les données de session clearSessionData() // Rediriger vers la page de connexion sans paramètre (session déjà nettoyée) const win = BrowserWindow.getFocusedWindow() if (win) { win.loadFile('index.html') } }) // Écouter les demandes de redirection avec message d'erreur ipcMain.on('show-token-expired', (event, message) => { // Nettoyer les données de session clearSessionData() // Rediriger vers la page de connexion avec message const win = BrowserWindow.getFocusedWindow() if (win) { // Stocker le message pour l'afficher sur la page de connexion win.webContents.once('dom-ready', () => { win.webContents.executeJavaScript(` window.tokenExpiredMessage = "${message}"; `) }) win.loadFile('index.html') } }) // Fonction pour exécuter une query de count sur une entité async function executeCountQuery(entityName, whereClause = null) { if (!sessionData.token || !sessionData.apiUrl) { throw new Error('Pas de token ou d\'URL API disponible') } try { let apiUrl = sessionData.apiUrl if (apiUrl.startsWith('http://')) { apiUrl = apiUrl.replace('http://', 'https://') } else if (!apiUrl.startsWith('https://')) { apiUrl = 'https://' + apiUrl } // Construire l'expression avec ou sans clause where let expression = `Context.${entityName}` if (whereClause) { expression += `.Where${whereClause}` } expression += '.Count()' const queryData = { "Application": "EasyWMS", "QueryType": 1, "Expression": expression } console.log(`Exécution query count pour ${entityName}${whereClause ? ' avec where' : ''}:`, queryData) const response = await axios.post( `${apiUrl}/ApplicationService/api/QueryScalarExecute`, queryData, { headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${sessionData.token}` }, timeout: 30000, httpsAgent: new (require('https').Agent)({ rejectUnauthorized: false }) } ) // Log de la réponse complète du serveur pour les WHERE personnalisés if (whereClause) { console.log('=== RÉPONSE SERVEUR COMPLÈTE ===') console.log(`URL: ${apiUrl}/ApplicationService/api/QueryScalarExecute`) console.log(`Query Data:`, queryData) console.log(`Status: ${response.status}`) console.log(`Headers:`, response.headers) console.log(`Data:`, JSON.stringify(response.data, null, 2)) console.log('===============================') } // Extraire la valeur selon le format spécifié const count = response.data.Rows?.[0]?.Values?.Column return { success: true, entity: entityName, count: count || 0, data: response.data } } catch (error) { console.error(`=== ERREUR EXECUTE COUNT QUERY ===`) console.error(`Erreur lors du count ${entityName}${whereClause ? ' avec where' : ''}:`, error) console.error(`Type d'erreur: ${error.name}`) console.error(`Message: ${error.message}`) console.error(`Stack: ${error.stack}`) if (error.response?.data) { console.error('Détails erreur API:', error.response.data) console.error('Status:', error.response.status) console.error('Headers:', error.response.headers) } console.error('=================================') return { success: false, entity: entityName, count: 0, error: { message: error.message, response: error.response?.data, status: error.response?.status, stack: error.stack, name: error.name } } } } // Fonction pour charger la liste des entités depuis le fichier JSON function loadEntitiesList() { try { const entitiesPath = path.join(__dirname, 'entities.json') const data = fs.readFileSync(entitiesPath, 'utf8') const entitiesConfig = JSON.parse(data) // Trier les entités par ordre alphabétique sur le displayName const sortedEntities = entitiesConfig.entities.sort((a, b) => a.displayName.localeCompare(b.displayName) ) return sortedEntities } catch (error) { console.error('Erreur lors du chargement des entités:', error) // Fallback sur la liste hardcodée en cas d'erreur (triée alphabétiquement) const fallbackEntities = [ { id: "Accounts", name: "Accounts", displayName: "Accounts" }, { id: "Aliases", name: "Aliases", displayName: "Aliases" }, { id: "Containers", name: "Containers", displayName: "Containers" }, { id: "InboundOrders", name: "InboundOrders", displayName: "Inbound Orders" }, { id: "Kits", name: "Kits", displayName: "Kits" }, { id: "OutboundOrders", name: "OutboundOrders", displayName: "Outbound Orders" }, { id: "ProductLocations", name: "ProductLocations", displayName: "Product Locations" }, { id: "Products", name: "Products", displayName: "Products" }, { id: "Receptions", name: "Receptions", displayName: "Receptions" }, { id: "Stocks", name: "Stocks", displayName: "Stocks" }, { id: "Suppliers", name: "Suppliers", displayName: "Suppliers" }, { id: "Tasks", name: "Tasks", displayName: "Tasks" } ] return fallbackEntities } } // Fonction pour récupérer tous les counts async function getAllEntityCounts() { const entities = loadEntitiesList() const results = {} // Créer la liste de toutes les queries à exécuter (entité principale + where clauses) const queries = [] entities.forEach(entity => { // Query principale queries.push({ entity: entity, key: entity.name, whereClause: null }) // Queries pour les clauses where let whereIndex = 1 while (entity[`where${whereIndex}`]) { queries.push({ entity: entity, key: `${entity.name}-where${whereIndex}`, whereClause: entity[`where${whereIndex}`] }) whereIndex++ } }) // Exécuter toutes les queries en parallèle const promises = queries.map(query => executeCountQuery(query.entity.name, query.whereClause)) const responses = await Promise.allSettled(promises) responses.forEach((response, index) => { const query = queries[index] const entity = query.entity if (response.status === 'fulfilled') { results[query.key] = { ...response.value, displayName: entity.displayName, description: entity.description } } else { results[query.key] = { success: false, entity: entity.name, displayName: entity.displayName, description: entity.description, count: 0, error: response.reason?.message || 'Erreur inconnue' } } }) return results } // Écouter les demandes de count d'entités ipcMain.handle('get-entity-counts', async () => { try { // Vérifier d'abord que le token est valide const tokenCheck = await verifyToken() if (!tokenCheck.valid) { return { success: false, error: 'Token invalide ou expiré' } } const counts = await getAllEntityCounts() return { success: true, counts: counts, timestamp: new Date().toISOString() } } catch (error) { console.error('Erreur lors de la récupération des counts:', error) return { success: false, error: error.message } } }) // Écouter les demandes de la liste des entités ipcMain.handle('get-entities-list', () => { try { const entities = loadEntitiesList() return { success: true, entities: entities } } catch (error) { console.error('Erreur lors de la récupération de la liste des entités:', error) return { success: false, error: error.message, entities: [] } } }) // Écouter les demandes de count personnalisées ipcMain.handle('execute-custom-count', async (event, entityName, whereClause) => { try { console.log('=== IPC CUSTOM COUNT ===') console.log(`Entité: ${entityName}`) console.log(`Clause WHERE: ${whereClause}`) // Vérifier d'abord que le token est valide const tokenCheck = await verifyToken() if (!tokenCheck.valid) { console.log('Token invalide, arrêt du processus') return { success: false, error: 'Token invalide ou expiré' } } console.log('Token valide, exécution de la query...') const result = await executeCountQuery(entityName, whereClause) console.log('Résultat de executeCountQuery:', result) console.log('=====================') return result } catch (error) { console.error('=== ERREUR IPC CUSTOM COUNT ===') console.error('Erreur lors de l\'exécution du count personnalisé:', error) console.error('Stack:', error.stack) console.error('==============================') return { success: false, error: { message: error.message, stack: error.stack, name: error.name } } } }) // Écouter les demandes de récupération des IDs avec filtre WHERE personnalisé ipcMain.handle('get-filtered-entity-ids', async (event, entityName, component, whereClause) => { try { // Vérifier d'abord que le token est valide const tokenCheck = await verifyToken() if (!tokenCheck.valid) { return { success: false, error: 'Token invalide ou expiré', ids: [] } } const result = await getEntityIds(entityName, component, null, whereClause) return result } catch (error) { console.error('Erreur lors de la récupération des IDs filtrés:', error) return { success: false, error: error.message, ids: [] } } }) // Écouter les demandes d'informations de session ipcMain.handle('get-session-info', () => { try { return { success: true, apiUrl: sessionData.apiUrl || null, tenantCode: sessionData.authData.tenantCode || null, username: sessionData.authData.username || null } } catch (error) { console.error('Erreur lors de la récupération des infos de session:', error) return { success: false, error: error.message } } }) // Fonction pour récupérer les IDs d'une entité async function getEntityIds(entityName, component, whereIndex = null, customWhereClause = null) { if (!sessionData.token || !sessionData.apiUrl) { throw new Error('Pas de token ou d\'URL API disponible') } try { let apiUrl = sessionData.apiUrl if (apiUrl.startsWith('http://')) { apiUrl = apiUrl.replace('http://', 'https://') } else if (!apiUrl.startsWith('https://')) { apiUrl = 'https://' + apiUrl } // Construire l'expression avec ou sans clause where let expression = `Context.${entityName}` // Si customWhereClause est spécifié, l'utiliser en priorité if (customWhereClause) { expression += `.Where${customWhereClause}` } // Sinon, si whereIndex est spécifié, ajouter la clause where correspondante else if (whereIndex && whereIndex > 0) { const entities = loadEntitiesList() const entity = entities.find(e => e.name === entityName) if (entity && entity[`where${whereIndex}`]) { expression += `.Where${entity[`where${whereIndex}`]}` } } expression += '.Select(z => z.Id)' const queryData = { "Application": "EasyWMS", "QueryType": 1, "Expression": expression } console.log(`Récupération des IDs pour ${entityName}:`, queryData) const response = await axios.post( `${apiUrl}/ApplicationService/api/QueryExecute`, queryData, { headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${sessionData.token}` }, timeout: 30000, // Timeout plus long pour les requêtes de suppression httpsAgent: new (require('https').Agent)({ rejectUnauthorized: false }) } ) console.log(`Réponse IDs ${entityName}:`, response.data) // Extraire les IDs depuis la réponse const ids = [] if (response.data.Table && response.data.Table.Rows && Array.isArray(response.data.Table.Rows)) { response.data.Table.Rows.forEach(row => { if (row.Values && row.Values.Column !== undefined && row.Values.Column !== null) { ids.push(row.Values.Column) } }) } return { success: true, ids: ids, count: ids.length } } catch (error) { console.error(`Erreur lors de la récupération des IDs ${entityName}:`, error) return { success: false, ids: [], error: error.response?.data?.message || error.message } } } // Fonction pour récupérer toutes les données d'une entité pour l'export async function getEntityExportData(entityName, component, customWhereClause = null) { if (!sessionData.token || !sessionData.apiUrl) { throw new Error('Pas de token ou d\'URL API disponible') } try { let apiUrl = sessionData.apiUrl if (apiUrl.startsWith('http://')) { apiUrl = apiUrl.replace('http://', 'https://') } else if (!apiUrl.startsWith('https://')) { apiUrl = 'https://' + apiUrl } // Construire l'expression pour récupérer toutes les données (pas juste les IDs) let expression = `Context.${entityName}` // Si customWhereClause est spécifié, l'utiliser if (customWhereClause) { expression += `.Where${customWhereClause}` } // Pas de .Select() pour récupérer toutes les colonnes const queryData = { "Application": "EasyWMS", "QueryType": 1, "Expression": expression } console.log(`Récupération des données d'export pour ${entityName}:`, queryData) const response = await axios.post( `${apiUrl}/ApplicationService/api/QueryExecute`, queryData, { headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${sessionData.token}` }, timeout: 60000, // Timeout plus long pour les exports httpsAgent: new (require('https').Agent)({ rejectUnauthorized: false }) } ) console.log(`Réponse données d'export ${entityName}:`, response.data) // Extraire les données depuis la réponse const data = [] if (response.data.Table && response.data.Table.Rows && Array.isArray(response.data.Table.Rows)) { const columns = response.data.Table.Columns || [] response.data.Table.Rows.forEach(row => { const rowData = {} if (row.Values && typeof row.Values === 'object') { // Si row.Values est un objet, itérer sur ses propriétés for (const [key, value] of Object.entries(row.Values)) { rowData[key] = value } } else if (Array.isArray(row.Values)) { // Si row.Values est un tableau, mapper avec les noms de colonnes columns.forEach((column, index) => { rowData[column.Name || `Column${index}`] = row.Values[index] }) } data.push(rowData) }) } return { success: true, data: data, count: data.length } } catch (error) { console.error(`Erreur lors de la récupération des données d'export ${entityName}:`, error) return { success: false, data: [], error: error.response?.data?.message || error.message } } } // Fonction pour supprimer un élément d'une entité async function deleteEntityItem(entity, itemId) { if (!sessionData.token || !sessionData.apiUrl) { throw new Error('Pas de token ou d\'URL API disponible') } try { let apiUrl = sessionData.apiUrl if (apiUrl.startsWith('http://')) { apiUrl = apiUrl.replace('http://', 'https://') } else if (!apiUrl.startsWith('https://')) { apiUrl = 'https://' + apiUrl } // Construire la commande de suppression const commandData = [{ "Name": `${entity.remove_command}, Mecalux.ITSW.EasyWMS.Modules.Contracts`, "Properties": { [entity.component]: itemId } }] // Ajouter ForceDeletionOfEmptyHolderContainer si c'est un ComponentId if (entity.component === 'ComponentId') { commandData[0].Properties.ForceDeletionOfEmptyHolderContainer = true } console.log(`Suppression de l'élément ${itemId} pour ${entity.name}:`, commandData) const response = await axios.post( `${apiUrl}/ApplicationService/api/CommandExecute`, commandData, { headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${sessionData.token}` }, timeout: 30000, httpsAgent: new (require('https').Agent)({ rejectUnauthorized: false }) } ) console.log(`Réponse suppression ${entity.name} ID ${itemId}:`, response.data) return { success: true, itemId: itemId, response: response.data } } catch (error) { console.error(`Erreur lors de la suppression ${entity.name} ID ${itemId}:`, error) let errorMessage = error.message // Extraire le message d'erreur depuis la réponse du serveur if (error.response && error.response.data) { try { // Si c'est une string JSON, la parser let errorData = error.response.data if (typeof errorData === 'string') { // Cas où il peut y avoir plusieurs objets JSON concaténés const jsonMatch = errorData.match(/\{[^}]*"Message":"([^"]*)"[^}]*\}/) if (jsonMatch) { errorMessage = jsonMatch[1] } else { errorData = JSON.parse(errorData) errorMessage = errorData.Message || errorData.message || errorMessage } } else if (errorData.Message) { // Si c'est déjà un objet avec le champ Message errorMessage = errorData.Message } else if (errorData.message) { errorMessage = errorData.message } } catch (parseError) { console.error('Erreur lors du parsing de la réponse d\'erreur:', parseError) // Garder le message d'erreur original si le parsing échoue } } return { success: false, itemId: itemId, error: errorMessage } } } // Écouter les demandes de récupération des IDs ipcMain.handle('get-entity-ids', async (event, entityName, component, whereIndex = null) => { try { // Vérifier d'abord que le token est valide const tokenCheck = await verifyToken() if (!tokenCheck.valid) { return { success: false, error: 'Token invalide ou expiré', ids: [] } } const result = await getEntityIds(entityName, component, whereIndex) return result } catch (error) { console.error('Erreur lors de la récupération des IDs:', error) return { success: false, error: error.message, ids: [] } } }) // Handler pour récupérer les données d'export d'une entité ipcMain.handle('get-entity-export-data', async (event, entityName, component, whereClause = null) => { try { // Vérifier d'abord que le token est valide const tokenCheck = await verifyToken() if (!tokenCheck.valid) { return { success: false, error: 'Token invalide ou expiré', data: [] } } const result = await getEntityExportData(entityName, component, whereClause) return result } catch (error) { console.error('Erreur lors de la récupération des données d\'export:', error) return { success: false, error: error.message, data: [] } } }) // Écouter les demandes de suppression d'éléments ipcMain.handle('delete-entity-item', async (event, entity, itemId) => { try { // Vérifier d'abord que le token est valide const tokenCheck = await verifyToken() if (!tokenCheck.valid) { return { success: false, error: 'Token invalide ou expiré' } } const result = await deleteEntityItem(entity, itemId) return result } catch (error) { console.error('Erreur lors de la suppression de l\'élément:', error) return { success: false, error: error.message } } }) // Fonction pour exécuter une action btn1 sur un élément d'une entité async function executeBtn1EntityAction(entity, itemId) { if (!sessionData.token || !sessionData.apiUrl) { throw new Error('Pas de token ou d\'URL API disponible') } try { let apiUrl = sessionData.apiUrl if (apiUrl.startsWith('http://')) { apiUrl = apiUrl.replace('http://', 'https://') } else if (!apiUrl.startsWith('https://')) { apiUrl = 'https://' + apiUrl } // Construire la commande btn1 const commandData = [{ "Name": `${entity.btn1_command}, Mecalux.ITSW.EasyWMS.Modules.Contracts`, "Properties": { [entity.component]: itemId } }] console.log(`Exécution ${entity.btn1} de l'élément ${itemId} pour ${entity.name}:`, commandData) const response = await axios.post( `${apiUrl}/ApplicationService/api/CommandExecute`, commandData, { headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${sessionData.token}` }, timeout: 30000, httpsAgent: new (require('https').Agent)({ rejectUnauthorized: false }) } ) console.log(`Réponse ${entity.btn1} ${entity.name} ID ${itemId}:`, response.data) return { success: true, itemId: itemId, response: response.data } } catch (error) { console.error(`Erreur lors de ${entity.btn1} ${entity.name} ID ${itemId}:`, error) let errorMessage = error.message // Extraire le message d'erreur depuis la réponse du serveur if (error.response && error.response.data) { try { let errorData = error.response.data if (typeof errorData === 'string') { const jsonMatch = errorData.match(/\{[^}]*"Message":"([^"]*)"[^}]*\}/) if (jsonMatch) { errorMessage = jsonMatch[1] } else { errorData = JSON.parse(errorData) errorMessage = errorData.Message || errorData.message || errorMessage } } else if (errorData.Message) { errorMessage = errorData.Message } else if (errorData.message) { errorMessage = errorData.message } } catch (parseError) { console.error('Erreur lors du parsing de la réponse d\'erreur:', parseError) } } return { success: false, itemId: itemId, error: errorMessage } } } // Écouter les demandes d'exécution d'actions btn1 ipcMain.handle('execute-btn1-action', async (event, entity, itemId) => { try { // Vérifier d'abord que le token est valide const tokenCheck = await verifyToken() if (!tokenCheck.valid) { return { success: false, error: 'Token invalide ou expiré' } } const result = await executeBtn1EntityAction(entity, itemId) return result } catch (error) { console.error('Erreur lors de l\'exécution de l\'action btn1:', error) return { success: false, error: error.message } } })