diff --git a/src/server/controllers/articleController.js b/src/server/controllers/articleController.js index c49603b..909c11c 100644 --- a/src/server/controllers/articleController.js +++ b/src/server/controllers/articleController.js @@ -29,7 +29,7 @@ const getArticlesSales = async () => { COALESCE(t.fat3mesi, 0) as fatLast3M, COALESCE(t2.fat6mesi, 0) as fatLast6M, COALESCE(p.venduti3mesi, 0) as vLast3M, - COALESCE(q.venduti6mesi, 0) as vLast6M, COALESCE(r.venduti1anno, 0) as vLastY, + COALESCE(q.venduti6mesi, 0) as vLast6M, COALESCE(r.venduti1anno, 0) as vLast1Y, 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 diff --git a/src/server/models/catalog.js b/src/server/models/catalog.js index 690cf39..6cf5093 100755 --- a/src/server/models/catalog.js +++ b/src/server/models/catalog.js @@ -28,13 +28,21 @@ const CatalogSchema = new Schema({ type: String, }, foto_collana: IImg, + idCollane: [{ type: String, }], + argomenti: [{ type: String, }], + condition_andor: { + type: Number, + default: 0, + }, + editore: [{ type: String }], + descr_introduttiva: { type: String, }, diff --git a/src/server/models/catprod.js b/src/server/models/catprod.js index c8dee87..cd1b6e5 100755 --- a/src/server/models/catprod.js +++ b/src/server/models/catprod.js @@ -126,6 +126,11 @@ CatProdSchema.statics.getCatProdWithTitleCount = async function (idapp) { $project: { _id: 1, name: 1, + idArgomento: 1, + descr_estesa: 1, + img: 1, + icon: 1, + color: 1, quanti: { $size: '$myproducts' }, // Conta il numero di prodotti per ciascun CatProd products: { $map: { diff --git a/src/server/models/collana.js b/src/server/models/collana.js index cf15962..8e417a2 100755 --- a/src/server/models/collana.js +++ b/src/server/models/collana.js @@ -52,6 +52,64 @@ module.exports.findAllIdApp = async function (idapp) { return await Collana.find(myfind).sort({title: 1}).lean(); }; +module.exports.getCollaneWithTitleCount = async function (idapp) { + try { + + const myquery = [ + { $match: { idapp } }, + { + $lookup: { + from: 'productinfos', // Nome della tua collezione productInfo + localField: '_id', + foreignField: 'idCollana', + as: 'products' + } + }, + { + $addFields: { + myproducts: { + $filter: { + input: "$products", + as: "prod", + cond: { + $in: ["$$prod.idStatoProdotto", [1, 4, 34, 45, 46]] + } + } + } + } + }, { + $project: { + _id: 1, + title: 1, + idCollana: 1, + dataOra: 1, + quanti: { $size: '$myproducts' }, + products: { + $map: { + input: "$myproducts", + as: "prod", + in: { + name: "$$prod.name" + } + } + } + } + }, + { $match: { quanti: { $gt: 0 } } }, // esclude i record con quanti = 0 + { $sort: { title: 1 } } // Ordina i risultati per nome + ]; + + const result = await Collana.aggregate(myquery); + + return result; + } catch (error) { + console.error('Error retrieving idCollana with title count:', error); + throw error; + } +} + + + module.exports.createIndexes() .then(() => { }) .catch((err) => { throw err; }); diff --git a/src/server/models/product.js b/src/server/models/product.js index fcb58d1..9f33829 100755 --- a/src/server/models/product.js +++ b/src/server/models/product.js @@ -133,7 +133,6 @@ const productSchema = new Schema({ }, maxBookableSinglePersQty: { // quantità massima Pre-ordinabile (singolarmente) type: Number, - default: 0, }, stockQty: { // in magazzino type: Number, @@ -141,58 +140,45 @@ const productSchema = new Schema({ }, stockBloccatiQty: { // Prenotati Bloccati type: Number, - default: 0, }, bookedQtyOrdered: { // Quantità Prenotate ordinate (in Lavorazione) type: Number, - default: 0, }, bookedQtyConfirmed: { // Quantità Prenotate Confermate Totali type: Number, - default: 0, }, // GAS: qtyToReachForGas: { // Quantità minima da raggiungere per fare l'ordine GAS type: Number, - default: 0, }, maxbookableGASQty: { // Quantità massima (ancora disponibile) Ordine GAS prenotabile (Complessivamente tra tutti gli ordini) type: Number, - default: 0, }, bookedGASQtyOrdered: { // Quantità Ordine GAS Prenotate Totali type: Number, - default: 0, }, bookedGASQtyConfirmed: { // Quantità Ordine GAS Confermate Totali type: Number, - default: 0, }, bookableGASBloccatiQty: { // Quantità Prenotate Bloccate GAS type: Number, - default: 0, }, quantityLow: { //Soglia disponibilità bassa type: Number, - default: 0, }, visibilityProductOutOfStock: { // Visibilità prodotto "esaurito" type: Boolean, - default: false, }, canBeShipped: { // è spedibile type: Boolean, - default: false, }, canBeBuyOnline: { // è acquistabile online type: Boolean, - default: false, }, stars: { type: Number, - default: 0, }, dateAvailableFrom: { type: Date @@ -279,48 +265,24 @@ module.exports.executeQueryPickup = async function (idapp, params) { // 🔹 Pattern per productInfo.name: tutte le parole devono essere presenti const patternAllWords = words.map(w => `(?=.*\\b${escapeRegex(w)})`).join('') + '.*'; - // 🔹 Condizioni per autori let authorConditions = []; - // Se ci sono esattamente 2 parole (es. "antonio graziano") - if (words.length === 2) { - const [w1, w2] = words.map(escapeRegex); - - authorConditions = [ - { - 'productInfo.authors': { - $elemMatch: { - name: { $regex: `^${w1}`, $options: 'i' }, - surname: { $regex: `^${w2}`, $options: 'i' } - } - } - }, - { - 'productInfo.authors': { - $elemMatch: { - name: { $regex: `^${w2}`, $options: 'i' }, - surname: { $regex: `^${w1}`, $options: 'i' } - } - } - } - ]; - } - - // Se c'è solo una parola (es. "antonio") - if (words.length === 1) { - const word = escapeRegex(words[0]); - authorConditions = [ - { + if (words.length > 0) { + authorConditions = words.map((word) => { + const regex = new RegExp(escapeRegex(word), 'i'); + return { 'productInfo.authors': { $elemMatch: { $or: [ - { name: { $regex: `^${word}`, $options: 'i' } }, - { surname: { $regex: `^${word}`, $options: 'i' } } + { name: regex }, + { surname: regex } ] } } - } - ]; + }; + }); + + authorConditions = [{ $and: authorConditions }]; } // 🔹 Filtro finale @@ -780,6 +742,7 @@ module.exports.findAllIdApp = async function (idapp, code, id, all) { } catch (e) { console.error('E', e); + return []; } diff --git a/src/server/models/productInfo.js b/src/server/models/productInfo.js index 3756a41..8901de3 100755 --- a/src/server/models/productInfo.js +++ b/src/server/models/productInfo.js @@ -67,11 +67,9 @@ const productInfoSchema = new Schema({ }, unit: { type: Number, - default: 0, }, unit_lordo: { type: Number, - default: 0, }, sfuso: { // serve se moltiplicare le qta (es: 12 kg) oppure fare (2 x 20 ml) type: Boolean @@ -157,8 +155,9 @@ const productInfoSchema = new Schema({ fatLast3M: Number, fatLast6M: Number, fatLast1Y: Number, + fatLast2Y: Number, vLast6M: Number, - vLastY: Number, + vLast1Y: Number, vLast2Y: Number, dataUltimoOrdine: Date, rank3M: Number, @@ -467,61 +466,16 @@ module.exports.updateProductInfoByStats = async function (idapp) { console.log(mylog); // Itera sui risultati e aggiorna productInfo - let countUpdate = 0; - for (const stat of statistics) { - const result = await ProductInfo.updateOne( - { - sku: stat.sku, - idapp - }, // Cerca il documento con lo stesso sku - { - $set: { - fatLast3M: stat.fatLast3M, - fatLast6M: stat.fatLast6M, - fatLast1Y: stat.fatLast1Y - } - }, - { upsert: false } // Non crea il documento se non esiste - ); - if (result.modifiedCount > 0) { - countUpdate++; - } - } mylog = `Aggiornati ${countUpdate} record di productInfo`; mylogtot += mylog; console.log(mylog); - // Ottieni le statistiche dalla query - const statisticsordini = await T_WEB_Ordini.getStatisticsFromOrders(); - mylog2 = "Inizio Aggiornamento Statistiche Ordini ... \n"; mylogtot += mylog2; console.log(mylog2); - // Itera sui risultati e aggiorna productInfo - countUpdate = 0; - for (const stat of statisticsordini) { - const result = await ProductInfo.updateOne( - { - sku: stat.sku, - idapp - }, // Cerca il documento con lo stesso sku - { - $set: { - totVen: stat.totVen, - vLast3M: stat.vLast3M, - vLast6M: stat.vLast6M, - vLastY: stat.vLastY, - vLast2Y: stat.vLast2Y, - } - }, - { upsert: false } // Non crea il documento se non esiste - ); - if (result.modifiedCount > 0) { - countUpdate++; - } - } + countUpdate = await T_WEB_Ordini.updateStatisticsOrders('', idapp, true); mylog2 = `Aggiornati ${countUpdate} record di productInfo`; mylogtot += mylog2; diff --git a/src/server/models/publisher.js b/src/server/models/publisher.js index 982b96f..6da8439 100755 --- a/src/server/models/publisher.js +++ b/src/server/models/publisher.js @@ -45,6 +45,62 @@ module.exports.findAllIdApp = async function (idapp) { return await Publisher.find(myfind).sort({ name: 1 }).lean(); }; +module.exports.getEditoriWithTitleCount = async function (idapp) { + try { + + const myquery = [ + { $match: { idapp } }, + { + $lookup: { + from: 'productinfos', // Nome della tua collezione productInfo + localField: '_id', + foreignField: 'idPublisher', + as: 'products' + } + }, + { + $addFields: { + myproducts: { + $filter: { + input: "$products", + as: "prod", + cond: { + $in: ["$$prod.idStatoProdotto", [1, 4, 34, 45, 46]] + } + } + } + } + }, { + $project: { + _id: 1, + name: 1, + quanti: { $size: '$myproducts' }, + products: { + $map: { + input: "$myproducts", + as: "prod", + in: { + name: "$$prod.name" + } + } + } + } + }, + { $match: { quanti: { $gt: 0 } } }, // esclude i record con quanti = 0 + { $sort: { name: 1 } } // Ordina i risultati per nome + ]; + + const result = await Publisher.aggregate(myquery); + + return result; + } catch (error) { + console.error('Error retrieving idCollana with title count:', error); + throw error; + } +} + + + module.exports.createIndexes() .then(() => { }) .catch((err) => { throw err; }); diff --git a/src/server/models/t_web_articolifatturati.js b/src/server/models/t_web_articolifatturati.js index 0e6e1b6..eeddeee 100755 --- a/src/server/models/t_web_articolifatturati.js +++ b/src/server/models/t_web_articolifatturati.js @@ -1,5 +1,7 @@ const mongoose = require('mongoose'); +const ProductInfo = require('../models/productInfo'); + // Definizione dello schema const articoliFatturatiSchema = new mongoose.Schema({ Codice: { @@ -59,7 +61,7 @@ const articoliFatturatiSchema = new mongoose.Schema({ var articoliFatturati = module.exports = mongoose.model('T_WEB_ArticoliFatturati', articoliFatturatiSchema); // Funzione per calcolare le statistiche -module.exports.getStatistics = async function () { +module.exports.updateStatisticsFatt = async function (CodArticolo, idapp, update) { const currentDate = new Date(); // Calcola le date limite per i periodi di 3 mesi, 6 mesi e 1 anno @@ -71,15 +73,30 @@ module.exports.getStatistics = async function () { const oneYearAgo = new Date(currentDate); oneYearAgo.setFullYear(currentDate.getFullYear() - 1); + const twoYearAgo = new Date(currentDate); + twoYearAgo.setFullYear(currentDate.getFullYear() - 2); + + const fiveYearAgo = new Date(currentDate); + fiveYearAgo.setFullYear(currentDate.getFullYear() - 5); try { + let myquery = []; + // Query di aggregazione per calcolare le statistiche - const myquery = [ + myquery.push( { $match: { - DataOra: { $gte: oneYearAgo } // Filtra solo i record degli ultimi 12 mesi + DataOra: { $gte: fiveYearAgo } // Filtra solo i record degli ultimi 12 mesi } - }, + }); + + if (CodArticolo) { + myquery.push({ + $match: { $expr: { $eq: ["$CodArticolo", CodArticolo] } } + }) + } + + myquery.push( { $group: { _id: "$CodArticolo", // Raggruppa per CodArticolo @@ -109,7 +126,25 @@ module.exports.getStatistics = async function () { 0 // Altrimenti, somma 0 ] } - } + }, + fatLast2Y: { + $sum: { + $cond: [ + { $gte: ["$DataOra", twoYearAgo] }, // Condizione: DataOra >= 1 anno fa + { $toInt: "$Qta" }, // Se vero, somma la quantità + 0 // Altrimenti, somma 0 + ] + } + }, + totFat: { + $sum: { + $cond: [ + { $gte: ["$DataOra", fiveYearAgo] }, // + { $toInt: "$Qta" }, // Se vero, somma la quantità + 0 // Altrimenti, somma 0 + ] + } + }, } }, { @@ -119,16 +154,45 @@ module.exports.getStatistics = async function () { fatLast3M: 1, fatLast6M: 1, fatLast1Y: 1, + fatLast2Y: 1, + totFat: 1, } } - ]; + ); const statistics = await articoliFatturati.aggregate(myquery); - return statistics; + let countUpdate = 0; + + if (update) { + for (const stat of statistics) { + const result = await ProductInfo.updateOne( + { + sku: stat.sku, + idapp + }, // Cerca il documento con lo stesso sku + { + $set: { + fatLast3M: stat.fatLast3M, + fatLast6M: stat.fatLast6M, + fatLast1Y: stat.fatLast1Y, + fatLast2Y: stat.fatLast2Y, + totFat: stat.totFat, + } + }, + { upsert: false } // Non crea il documento se non esiste + ); + if (result.modifiedCount > 0) { + countUpdate++; + } + } + } + + return countUpdate; } catch (error) { console.error("Errore durante il calcolo delle statistiche:", error); - throw error; + // throw error; + return 0; } } diff --git a/src/server/models/t_web_ordini.js b/src/server/models/t_web_ordini.js index 75efcab..0983dbf 100755 --- a/src/server/models/t_web_ordini.js +++ b/src/server/models/t_web_ordini.js @@ -18,6 +18,8 @@ PrimaCopiaDaSpedire - int () const mongoose = require('mongoose'); +const ProductInfo = require('../models/productInfo'); + // Definizione dello schema const ordiniSchema = new mongoose.Schema({ Codice: { @@ -63,7 +65,7 @@ const ordiniSchema = new mongoose.Schema({ var T_WEB_Ordini = module.exports = mongoose.model('T_WEB_Ordini', ordiniSchema); -module.exports.getStatisticsFromOrders = async function () { +module.exports.updateStatisticsOrders = async function (CodArticoloGM, idapp, update) { const currentDate = new Date(); // Calcola le date limite per i periodi di 3 mesi, 6 mesi e 1 anno @@ -75,24 +77,31 @@ module.exports.getStatisticsFromOrders = async function () { const oneYearAgo = new Date(currentDate); oneYearAgo.setFullYear(currentDate.getFullYear() - 1); - + const twoYearAgo = new Date(currentDate); twoYearAgo.setFullYear(currentDate.getFullYear() - 2); - const allYear = new Date(currentDate); - allYear.setFullYear(currentDate.getFullYear() - 20); + const fiveYear = new Date(currentDate); + fiveYear.setFullYear(currentDate.getFullYear() - 5); try { + let myquery = []; // Query di aggregazione per calcolare le statistiche - const myquery = [ + myquery.push( + { + $match: { + CodArticoloGM: CodArticoloGM, + }, + }); + myquery.push( { $group: { _id: "$CodArticoloGM", // Raggruppa per CodArticolo totVen: { $sum: { $cond: [ - { $gte: ["$DataOra", allYear] }, // Condizione: DataOra totale + { $gte: ["$DataOra", fiveYear] }, // Condizione: DataOra totale { $toInt: "$Qta" }, // Se vero, somma la quantità 0 // Altrimenti, somma 0 ] @@ -147,14 +156,41 @@ module.exports.getStatisticsFromOrders = async function () { vLast2Y: 1, } } - ]; + ); const statistics = await T_WEB_Ordini.aggregate(myquery); - return statistics; + let countUpdate = 0; + + if (update) { + for (const stat of statistics) { + + const result = await ProductInfo.updateOne( + { + sku: stat.sku, + idapp, + }, // Cerca il documento con lo stesso sku + { + $set: { + totVen: stat.totVen, + vLast3M: stat.vLast3M, + vLast6M: stat.vLast6M, + vLast1Y: stat.vLast1Y, + vLast2Y: stat.vLast2Y, + } + }, + { upsert: false } // Non crea il documento se non esiste + ); + if (result.modifiedCount > 0) { + countUpdate++; + } + } + } + + return countUpdate; } catch (error) { console.error("Errore durante il calcolo delle statistiche:", error); - throw error; + return 0; } } diff --git a/src/server/modules/Macro.js b/src/server/modules/Macro.js index 69fecba..5b625a4 100644 --- a/src/server/modules/Macro.js +++ b/src/server/modules/Macro.js @@ -13,6 +13,9 @@ const shared_consts = require('../tools/shared_nodejs'); // Assicurati di avere const { getTableContent } = require('../controllers/articleController'); +const T_WEB_ArticoliFatturati = require('../models/t_web_articolifatturati'); +const T_WEB_Ordini = require('../models/t_web_ordini'); + class Macro { constructor(idapp, options) { this.idapp = idapp; @@ -58,26 +61,15 @@ class Macro { if (options.usaDBGMLocale) { mylog += '*** usaDBGMLocale ***\n'; - //miomatch2 = { IdStatoProdotto: { $in: [1, 3, 4, 6, 7, 8, 9, 20, 26, 33, 34, 45, 46, 47, 48] } }; + //miomatch2 = { IdStatoProdotto: { $in: [1, 4, 34, 45, 46] } }; miomatch2 = { $or: [ { DescrizioneStatoProdotto: 'In commercio' }, - { DescrizioneStatoProdotto: 'Ristampa' }, { DescrizioneStatoProdotto: 'Prossima uscita/pubblicazione' }, - { DescrizioneStatoProdotto: 'In promozione' }, - { DescrizioneStatoProdotto: 'In fase di valutazione' }, - { DescrizioneStatoProdotto: 'Titolo in esaurimento (in attesa Nuova Edizione)' }, - { DescrizioneStatoProdotto: 'Titolo in esaurimento' }, - { DescrizioneStatoProdotto: 'Titolo in esaurimento (in att N.E Ricopertinata)' }, - { DescrizioneStatoProdotto: 'Titolo in Esaurimento (disponibile N.E.)' }, - { DescrizioneStatoProdotto: 'In commercio (digitale)' }, { DescrizioneStatoProdotto: 'In prevendita' }, { DescrizioneStatoProdotto: 'Vendita sito' }, { DescrizioneStatoProdotto: '2023 in commercio' }, - { DescrizioneStatoProdotto: 'Assoluto NO Reso' }, - { DescrizioneStatoProdotto: 'Titolo esaurito' }, - { DescrizioneStatoProdotto: 'Prossima uscita' }, ] }; @@ -439,6 +431,13 @@ class Macro { for (const recproduct of recproducts) { // if (!options.caricatutti) { await this.elaboraProdotto(recproduct, opt); + + const sku = recproduct.IdArticolo; + + if (sku) { + await T_WEB_ArticoliFatturati.updateStatisticsFatt(sku.toString(), options.idapp, true); + await T_WEB_Ordini.updateStatisticsOrders(sku.toString(), options.idapp, true); + } count++; if (count % 50 === 0) { @@ -776,7 +775,7 @@ class Macro { if (productGM.DescrizioneTipologia === 'Usato') vers = shared_consts.PRODUCTTYPE.USATO; - + if (productGM.DescrizioneTipologia === 'Download') vers = shared_consts.PRODUCTTYPE.DOWNLOAD; else if (productGM.DescrizioneTipologia === 'DVD') @@ -791,8 +790,8 @@ class Macro { vers = shared_consts.PRODUCTTYPE.STREAMING; else vers = shared_consts.PRODUCTTYPE.NUOVO; - - recproduct.Versione = vers; + + recproduct.Versione = vers; return recproduct } diff --git a/src/server/router/admin_router.js b/src/server/router/admin_router.js index 1f7f2e6..a99afb1 100755 --- a/src/server/router/admin_router.js +++ b/src/server/router/admin_router.js @@ -883,7 +883,7 @@ router.post('/import', authenticate, async (req, res) => { totFat: 0, vLast3M: 0, vLast6M: 0, - vLastY: 0, + vLast1Y: 0, vLast2Y: 0, rank3M: 0, rank6M: 0, @@ -929,7 +929,7 @@ router.post('/import', authenticate, async (req, res) => { fatLast3M: product.fatLast3M || 0, fatLast6M: product.fatLast6M || 0, vLast6M: product.vLast6M || 0, - vLastY: product.vLastY || 0, + vLast1Y: product.vLast1Y || 0, vLast2Y: product.vLast2Y || 0, rank3M: product.rank3M || 0, rank6M: product.rank6M || 0, diff --git a/src/server/router/index_router.js b/src/server/router/index_router.js index c773180..8b5d0df 100755 --- a/src/server/router/index_router.js +++ b/src/server/router/index_router.js @@ -2016,9 +2016,9 @@ async function load(req, res, version = '0') { catprods_gas: version >= 91 ? Product.getArrCatProds(idapp, shared_consts.PROD.GAS) : Promise.resolve([]), catAI: version >= 91 ? CatAI.findAllIdApp(idapp) : Promise.resolve([]), authors: version >= 91 ? Author.findAllIdApp(idapp) : Promise.resolve([]), - publishers: version >= 91 ? Publisher.findAllIdApp(idapp) : Promise.resolve([]), + publishers: version >= 91 ? Publisher.getEditoriWithTitleCount(idapp) : Promise.resolve([]), myschedas: version >= 91 ? MyElem.findallSchedeTemplate(idapp) : Promise.resolve([]), - collane: version >= 91 ? Collana.findAllIdApp(idapp) : Promise.resolve([]), + collane: version >= 91 ? Collana.getCollaneWithTitleCount(idapp) : Promise.resolve([]), catalogs: version >= 91 ? Catalog.findAllIdApp(idapp) : Promise.resolve([]), catprtotali: version >= 91 ? CatProd.getCatProdWithTitleCount(idapp) : Promise.resolve([]), stati_prodotto: version >= 91 ? T_WEB_StatiProdotto.findAllIdApp() : Promise.resolve([]),