const axios = require('axios'); const server_constants = require('../tools/server_constants'); const shared_consts = require('../tools/shared_nodejs'); const SERVER_A_URL = process.env.SERVER_A_URL || "http://IP_DI_SERVER_A:3000"; const API_KEY = process.env.API_KEY_MSSQL; // Funzione per ottenere i dati const getArticlesSales = async () => { try { const query = ` SELECT a.IdArticolo, a.Titolo, a.DataPubblicazione, a.Ean13 AS isbn, a.IdCollana, y.DescrizioneCollana, i2.DescrArgomento, a.ListaArgomenti, a.Pagine, a.IdTipoFormato, a.Misure, COALESCE(o.totVen, 0) as totVen, COALESCE(u.totFat, 0) as totFat, COALESCE(p.rank3M, 0) as rank3M, COALESCE(t.fatrank3M, 0) as fatrank3M, COALESCE(q.rank6M, 0) as rank6M, COALESCE(r.rank1Y, 0) as rank1Y, COALESCE(t.fat3mesi, 0) as fatLast3M, COALESCE(p.venduti3mesi, 0) as vLast3M, COALESCE(q.venduti6mesi, 0) as vLast6M, COALESCE(r.venduti1anno, 0) as vLastY, s.ultimoOrdine as dataUltimoOrdine FROM T_WEB_Articoli a LEFT JOIN (SELECT CodArticoloGM, SUM(Qta) as totVen FROM T_WEB_Ordini GROUP BY CodArticoloGM) o ON a.IdArticolo = o.CodArticoloGM LEFT JOIN (SELECT CodArticolo, SUM(TRY_CAST(Qta AS INT)) as totFat FROM T_WEB_ArticoliFatturati WHERE ISNUMERIC(Qta) = 1 GROUP BY CodArticolo) u ON a.IdArticolo = u.CodArticolo WHERE a.IdStatoProdotto IS NOT NULL ORDER BY totVen DESC; `; const response = await axios.post(SERVER_A_URL + '/query', { query }, { headers: { 'x-api-key': API_KEY } }); return response.data || []; } catch (error) { console.error("Errore nel recupero degli articoli:", error); throw new Error("Errore nel recupero degli articoli venduti."); } }; // Endpoint per ottenere i dati in formato JSON exports.getArticlesSalesHandler = async (req, res) => { try { const data = await getArticlesSales(); if (!data.length) return res.status(404).json({ message: "Nessun articolo trovato." }); res.json(data); } catch (error) { res.status(500).json({ error: error.message }); } }; // Endpoint per esportare i dati come file JSON exports.exportArticlesSalesByJSON = async (req, res) => { try { const data = await getArticlesSales(); if (!data.length) return res.status(404).json({ message: "Nessun articolo trovato." }); res.setHeader("Content-Type", "application/json"); res.setHeader("Content-Disposition", `attachment; filename="ranking_articles_${new Date().toISOString().split('T')[0]}.json"`); res.json(data); } catch (error) { res.status(500).json({ error: error.message }); } }; const formatDate = (dateValue) => { const date = new Date(dateValue); const day = String(date.getDate()).padStart(2, '0'); const month = String(date.getMonth() + 1).padStart(2, '0'); const year = date.getFullYear(); return `${day}/${month}/${year}`; }; const getTableContent = async (options) => { try { // Verifica se la tabella esiste const checkTableQuery = `SELECT COUNT(*) as tableExists FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = '${options.nameTable}'`; const checkResponse = await axios.post(SERVER_A_URL + '/query', { query: checkTableQuery }, { headers: { 'x-api-key': API_KEY } }); if (!checkResponse.data || checkResponse.data.length === 0 || checkResponse.data[0].tableExists === 0) { return `La tabella '${options.nameTable}' non esiste.`; } // Recupera le colonne della tabella principale dal catalogo const columnsQuery = `SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = '${options.nameTable}'`; const columnsResponse = await axios.post(SERVER_A_URL + '/query', { query: columnsQuery }, { headers: { 'x-api-key': API_KEY } }); const tableColumns = columnsResponse.data.map(col => col.COLUMN_NAME); // Mappatura per unire i campi (ID e Descrizione) const mergedMapping = { "IdStatoProdotto": "DescrizioneStatoProdotto", "IdTipologia": "DescrizioneTipologia", "IdTipoFormato": "DescrizioneFormato", "IdCollana": "DescrizioneCollana", "ListaArgomenti": "DescrArgomento", "ListaAutori": "AutoriCompleti", "IdMarchioEditoriale": "CasaEditrice", }; // Costruisce la query per recuperare i record let dataQuery = ""; let columnsToShow = 'T.*'; if (options.fieldGM) { columnsToShow = 'T.' + options.fieldGM; } if (options.nameTable.toLowerCase() === 't_web_articoli') { if (true) { dataQuery = ` SELECT TOP ${options.numrec} ${columnsToShow} ` + (options.campispeciali ? ` ,f.DescrizioneStatoProdotto ,i.DescrizioneTipologia ,n.DescrizioneFormato ,y.DescrizioneCollana ,z.AutoriCompleti ,i2.DescrArgomento ,z3.CasaEditrice` : ``) + (options.showQtaDisponibile ? ` ,q.QtaDisponibile ` : ``) + ` FROM T_WEB_Articoli T JOIN( SELECT IdArticolo, MAX(DataOra) AS data FROM T_WEB_Articoli GROUP BY IdArticolo ) b ON T.IdArticolo = b.IdArticolo AND T.DataOra = b.data ` + (options.campispeciali ? ` LEFT JOIN( SELECT e.IdStatoProdotto, e.Descrizione as DescrizioneStatoProdotto FROM T_WEB_StatiProdotto e JOIN( SELECT IdStatoProdotto, MAX(DataOra) as data1 FROM T_WEB_StatiProdotto GROUP BY IdStatoProdotto ) c ON e.IdStatoProdotto = c.IdStatoProdotto AND e.DataOra = c.data1 ) f ON T.IdStatoProdotto = f.IdStatoProdotto LEFT JOIN( SELECT g.IdTipologia, g.Descrizione as DescrizioneTipologia FROM T_WEB_Tipologie g JOIN( SELECT IdTipologia, MAX(DataOra) as data1 FROM T_WEB_Tipologie GROUP BY IdTipologia ) h ON g.IdTipologia = h.IdTipologia AND g.DataOra = h.data1 ) i ON T.IdTipologia = i.IdTipologia LEFT JOIN( SELECT l.IdTipoFormato, l.Descrizione as DescrizioneFormato FROM T_WEB_TipiFormato l JOIN( SELECT IdTipoFormato, MAX(DataOra) as data1 FROM T_WEB_TipiFormato GROUP BY IdTipoFormato ) m ON l.IdTipoFormato = m.IdTipoFormato AND l.DataOra = m.data1 ) n ON T.IdTipoFormato = n.IdTipoFormato LEFT JOIN( SELECT v.IdCollana, v.Descrizione as DescrizioneCollana FROM T_WEB_Collane v INNER JOIN( SELECT IdCollana, MAX(ID) as MaxID FROM T_WEB_Collane GROUP BY IdCollana ) x ON v.IdCollana = x.IdCollana AND v.ID = x.MaxID ) y ON T.IdCollana = y.IdCollana LEFT JOIN( SELECT g2.IdArgomento, g2.Descrizione as DescrArgomento FROM T_WEB_Argomenti g2 INNER JOIN( SELECT IdArgomento, MAX(DataOra) as data12 FROM T_WEB_Argomenti GROUP BY IdArgomento ) h ON g2.IdArgomento = h.IdArgomento AND g2.DataOra = h.data12 ) i2 ON T.ListaArgomenti = i2.IdArgomento LEFT JOIN( SELECT T1.IdArticolo, STUFF(( SELECT ',' + ISNULL(A2.AutoreCompleto, '') FROM( SELECT CAST('' + REPLACE(T1.ListaAutori, ',', '') + '' AS XML) AS DataXML ) X CROSS APPLY X.DataXML.nodes('/root/x') AS A(x) CROSS APPLY( SELECT TRY_CAST(LTRIM(RTRIM(A.x.value('.', 'VARCHAR(100)'))) AS INT) AS AutoreID ) CA JOIN( SELECT a.IdAutore, CONCAT(a.Nome, ' ', a.Cognome) AS AutoreCompleto FROM T_WEB_Autori a JOIN( SELECT IdAutore, MAX(DataOra) AS maxData FROM T_WEB_Autori GROUP BY IdAutore ) aa ON a.IdAutore = aa.IdAutore AND a.DataOra = aa.maxData ) A2 ON CA.AutoreID = A2.IdAutore FOR XML PATH(''), TYPE ).value('.', 'NVARCHAR(MAX)'), 1, 1, '') AS AutoriCompleti FROM T_WEB_Articoli T1 GROUP BY T1.IdArticolo, T1.ListaAutori ) z ON T.IdArticolo = z.IdArticolo LEFT JOIN( SELECT a3.IdMarchioEditoriale, a3.Descrizione as CasaEditrice FROM T_WEB_MarchiEditoriali a3 JOIN( SELECT IdMarchioEditoriale, MAX(DataOra) as maxData FROM T_WEB_MarchiEditoriali GROUP BY IdMarchioEditoriale ) aa3 ON a3.IdMarchioEditoriale = aa3.IdMarchioEditoriale AND a3.DataOra = aa3.maxData ) z3 ON T.IdMarchioEditoriale = z3.IdMarchioEditoriale ` : ``) + (options.showQtaDisponibile ? ` LEFT JOIN( SELECT o.Codice, o.QtaDisponibile FROM T_WEB_Disponibile o JOIN( SELECT Codice, MAX(DataOra) as data1 FROM T_WEB_Disponibile GROUP BY Codice ) p ON o.Codice = p.Codice AND o.DataOra = p.data1 ) q ON T.IdArticolo = q.Codice` : ``) } else { dataQuery += ` SELECT TOP ${options.numrec} T.* FROM T_WEB_Articoli T JOIN( SELECT IdArticolo, MAX(DataOra) AS data FROM T_WEB_Articoli GROUP BY IdArticolo ) b ON T.IdArticolo = b.IdArticolo AND T.DataOra = b.data `; } } else { dataQuery = `SELECT TOP ${options.numrec} * FROM ${options.nameTable} `; } if (options.where && options.where.trim() !== "") { dataQuery += ` WHERE ${options.where} `; } // Esegue la query per recuperare i dati // console.log('dataQuery', dataQuery); const dataResponse = await axios.post(SERVER_A_URL + '/query', { query: dataQuery }, { headers: { 'x-api-key': API_KEY } }); const records = dataResponse.data; if (!records || records.length === 0) { return `Nessun record trovato nella tabella '${options.nameTable}'.`; } // Determina quali colonne visualizzare. let displayColumns; if (options.nameTable.toLowerCase() === 't_web_articoli') { // Usa tutte le proprietà del record, escludendo le colonne dei campi uniti (quelle usate per il merge) displayColumns = Object.keys(records[0]).filter(col => !Object.values(mergedMapping).includes(col)); } else { displayColumns = tableColumns; } // Funzione per ottenere il valore da visualizzare, fondendo i campi se presente nella mappatura const getDisplayValue = (record, col) => { let value = record[col] ?? 'NULL'; // Format date solo se il nome della colonna indica una data/ora if ((col.toLowerCase().includes("data") || col.toLowerCase().includes("ora")) && value !== 'NULL') { if (value.includes(',')) { // Se ci sono più valori separati da virgola, formatta ciascuno se è una data valida value = value.split(',') .map(item => { const trimmed = item.trim(); const parsed = Date.parse(trimmed); return !isNaN(parsed) ? formatDate(trimmed) : trimmed; }) .join(', '); } else { const parsed = Date.parse(value); if (!isNaN(parsed)) { value = formatDate(value); } } } if (mergedMapping[col]) { return `${record[mergedMapping[col]] || ''} (${value})`; } return value; }; // Costruisce l'output HTML let output = ""; if (options.outhtml) { if (records.length === 1) { // Se c'è un solo record, visualizza una lista di chiavi e valori const record = records[0]; output += ` `; displayColumns.forEach(column => { output += ` `; }); output += `
Campo Valore
${column} ${getDisplayValue(record, column)}
`; } else { // Se ci sono più record, visualizza una tabella con intestazioni output += ""; displayColumns.forEach(column => { output += `< th style = "padding: 8px; background-color: #f2f2f2;" > ${column} `; }); output += ""; records.forEach(record => { output += ""; displayColumns.forEach(column => { output += `< td style = "padding: 8px;" > ${getDisplayValue(record, column)} `; }); output += ""; }); output += "
"; } } else { // solo dati output = {}; if (options.fieldGM) { if (records && records.length === 1) { output[options.fieldGM] = records[0][options.fieldGM]; } } else { output = []; records.forEach(record => { let myrec = {} displayColumns.forEach(column => { myrec[column] = `${getDisplayValue(record, column)} `; }); output.push(myrec) }); } } return output; } catch (error) { console.error("Errore nel recupero della tabella: ", error.message); if (options.outhtml) { output = ` Errore nel Recupero della Tabella ${options.nameTable}
Errore nel Recupero della Tabella ${options.nameTable} con query: ${options.where}
${error.response.data.error || error.stack || error.message}
`; } return output; // throw new Error("Errore nel recupero della tabella."); } }; // Endpoint per mostrare i dati della tabella exports.viewTable = async (req, res) => { try { const options = req.body.options; const tableContent = await getTableContent(options); let out = {}; if (options.outhtml) { out = `

Tabella: ${options.nameTable}

Query: ${options.where}
${tableContent}
` } else { out = tableContent; } return res.send({ code: server_constants.RIS_CODE_OK, data: out }); } catch (error) { console.error('Error: ', error); return res.send({ code: server_constants.RIS_CODE_ERR, error }); } }; // Endpoint per mostrare i dati della tabella exports.queryTable = async (req, res) => { try { const options = req.body.options; const tableContent = await getTableContent(options); let out = {}; if (options.outhtml) { out = `

Tabella: ${options.nameTable}

Query: ${options.where}
${tableContent} ` } else { out = tableContent; } return res.send({ code: server_constants.RIS_CODE_OK, data: out }); } catch (error) { console.error('Error: ', error); return res.send({ code: server_constants.RIS_CODE_ERR, error }); } };