From 58431c144c954e1bfc9b4c18bc12ff2c8d3f6528 Mon Sep 17 00:00:00 2001 From: Surya Paolo Date: Tue, 22 Apr 2025 18:30:48 +0200 Subject: [PATCH] aggiornamento cataloghi, search --- src/server/controllers/articleController.js | 8 +- src/server/models/product.js | 14 +-- src/server/models/t_web_articoli.js | 8 +- src/server/models/t_web_disponibles.js | 52 +++++++++ src/server/models/t_web_statiprodotto.js | 16 ++- src/server/models/user.js | 3 +- src/server/modules/Macro.js | 118 ++++++++++++++++---- src/server/router/users_router.js | 2 +- src/server/tools/general.js | 15 +++ 9 files changed, 194 insertions(+), 42 deletions(-) create mode 100755 src/server/models/t_web_disponibles.js diff --git a/src/server/controllers/articleController.js b/src/server/controllers/articleController.js index 020e6e2..74772a5 100644 --- a/src/server/controllers/articleController.js +++ b/src/server/controllers/articleController.js @@ -163,6 +163,7 @@ exports.getTableContentBase = async (options) => { if (options.aggregation) { records = await mymodel.aggregate(options.aggregation); + } else { const pipeline = []; @@ -462,8 +463,8 @@ exports.getTableContentBase = async (options) => { return output; } catch (error) { - output = error.message; - console.error("Errore nel recupero della tabella: ", error.message); + output = `${error.response.data.error || error.stack || error.message}`; + console.error("Errore nel recupero della tabella: ", `${error.response.data.error || error.stack || error.message}`); if (options.outhtml) { output = ` @@ -905,6 +906,7 @@ exports.updateAllBook = async (idapp, options) => { try { const macro = new Macro(idapp); // Crea un'istanza della classe Macro + options.idapp = idapp; return await macro.updateLocalDbFromGM_T_Web_Articoli(options); @@ -919,7 +921,7 @@ exports.updateAllBookRoute = async (req, res) => { try { const idapp = req.body.idapp; const options = req.body.options; - const result = this.updateAllBook(idapp, options); + const result = await this.updateAllBook(idapp, options); return res.status(200).send({ data: result }); diff --git a/src/server/models/product.js b/src/server/models/product.js index 6db85af..e25e0a6 100755 --- a/src/server/models/product.js +++ b/src/server/models/product.js @@ -262,7 +262,7 @@ module.exports.executeQueryPickup = async function (idapp, params) { $or: [ { 'productInfo.name': { - $regex: `\\b${strfind}`, // Cerca parole che iniziano con strfind + $regex: `(?i).*${tools.removeAccents(strfind)}.*`, // Cerca una o più parole che sono contenute $options: 'i' // Rende la ricerca case-insensitive } }, @@ -273,20 +273,17 @@ module.exports.executeQueryPickup = async function (idapp, params) { } }, { - 'productInfo.sku': { - $regex: `\\b${strfind}`, // Cerca parole che iniziano con strfind - $options: 'i' // Rende la ricerca case-insensitive - } + 'productInfo.sku': strfind }, { 'productInfo.authors.name': { - $regex: `\\b${strfind}`, // Cerca parole che iniziano con strfind nel nome dell'autore + $regex: `(?i).*${tools.removeAccents(strfind)}.*`, // Cerca una o più parole che sono contenute $options: 'i' // Rende la ricerca case-insensitive } }, { 'productInfo.authors.surname': { - $regex: `\\b${strfind}`, // Cerca parole che iniziano con strfind nel cognome dell'autore + $regex: `(?i)\\b${tools.removeAccents(strfind)}\\b`, // Cerca parole che iniziano con strfind, e ignora gli accenti $options: 'i' // Rende la ricerca case-insensitive } }, @@ -336,8 +333,9 @@ module.exports.executeQueryPickup = async function (idapp, params) { name: '$productInfo.name', // Nome del prodotto authors: '$productInfo.authors', productInfo: { - name: '$productInfo.name', // Nome del prodotto + name: '$productInfo.name', // Nome dell'autore authors: '$productInfo.authors', + idStatoProdotto: "$productInfo.idStatoProdotto", }, } } diff --git a/src/server/models/t_web_articoli.js b/src/server/models/t_web_articoli.js index 9dd39a4..b21da30 100755 --- a/src/server/models/t_web_articoli.js +++ b/src/server/models/t_web_articoli.js @@ -58,9 +58,9 @@ mongoose.plugin(schema => { */ const T_WEB_ArticoliSchema = new Schema({ - IdArticolo: { type: Number, index: true }, - Ean13: { type: String, index: true }, - Titolo: { type: String, index: true }, + IdArticolo: { type: Number }, + Ean13: { type: String }, + Titolo: { type: String }, ListaAutori: String, ListaArgomenti: String, IdStatoProdotto: Number, @@ -101,7 +101,7 @@ const T_WEB_ArticoliSchema = new Schema({ module.exports = mongoose.model('T_WEB_Articoli', T_WEB_ArticoliSchema); -module.exports.createIndexes() +module.exports.createIndexes({ IdArticolo: 1, DataOra: -1 }) .then(() => { }) .catch((err) => { throw err; }); diff --git a/src/server/models/t_web_disponibles.js b/src/server/models/t_web_disponibles.js new file mode 100755 index 0000000..cdbaf74 --- /dev/null +++ b/src/server/models/t_web_disponibles.js @@ -0,0 +1,52 @@ +const mongoose = require('mongoose'); + +const TWebDisponibileSchema = new mongoose.Schema({ + Progressivo: { + type: mongoose.Schema.Types.Long || Number, // Usa 'mongoose-long' se vuoi long int + required: true, + unique: true, + }, + Codice: { + type: String, + maxlength: 50, + required: true, + index: true, // usato nei lookup e nei match + }, + QtaDisponibile: { + type: mongoose.Decimal128, + default: 0, + }, + Giac: { + type: mongoose.Decimal128, + default: 0, + }, + DataOra: { + type: Date, + default: Date.now, + index: true, // per ordinamento + }, + Enabled: { + type: Boolean, + default: true, + }, + DataOraSito: { + type: Date, + }, + Ean13: { + type: String, + maxlength: 20, + }, + QtaDisponibileOld: { + type: Number, + default: 0, + }, +}, { + collection: 't_web_disponibiles', // nome della collezione esatto + timestamps: false, +}); + +module.exports = mongoose.model('TWebDisponibile', TWebDisponibileSchema); + +module.exports.createIndexes() + .then(() => { }) + .catch((err) => { throw err; }); diff --git a/src/server/models/t_web_statiprodotto.js b/src/server/models/t_web_statiprodotto.js index 5142b1a..d68b7f8 100755 --- a/src/server/models/t_web_statiprodotto.js +++ b/src/server/models/t_web_statiprodotto.js @@ -30,29 +30,33 @@ module.exports.findAllIdApp = async function () { const myfind = {}; const myquery = [ + { + $sort: { DataOra: -1 } // Prima ordina per DataOra in modo decrescente + }, { $group: { - _id: "$IdStatoProdotto", - record: { $max: "$DataOra" } + _id: "$IdStatoProdotto", // Raggruppa per IdStatoProdotto + latestRecord: { $first: "$$ROOT" } // Prendi il primo record per ogni gruppo (cioè il più recente) } }, { $lookup: { from: 't_web_statiprodottos', - localField: '_id', + localField: '_id', // Usa _id che è l'IdStatoProdotto foreignField: 'IdStatoProdotto', as: 'record' } }, { - $replaceRoot: { newRoot: { $arrayElemAt: ["$record", 0] } } + $replaceRoot: { newRoot: { $arrayElemAt: ["$record", 0] } } // Estrai il primo (e unico) record dal risultato di $lookup }, { - $sort: { IdStatoProdotto: 1 } + $sort: { IdStatoProdotto: 1 } // Ordina per IdStatoProdotto, se necessario } ]; - return await T_WEB_StatiProdotto.aggregate(myquery); + const rec = await T_WEB_StatiProdotto.aggregate(myquery); + return rec; }; diff --git a/src/server/models/user.js b/src/server/models/user.js index 645ac66..6a51d4b 100755 --- a/src/server/models/user.js +++ b/src/server/models/user.js @@ -804,7 +804,7 @@ UserSchema.statics.findByToken = async function (token, typeaccess, con_auth, wi }, project); } const end_find = process.hrtime.bigint(); - console.log(` User.findOne impiega ${Math.round(Number(end_find - start_find) / 1e6) / 1000} secondi.`); + // console.log(` User.findOne impiega ${Math.round(Number(end_find - start_find) / 1e6) / 1000} secondi.`); } else { project = { perm: 1, _id: 1, idapp: 1, username: 1, deleted: 1, aportador_solidario: 1, aportador_solidario_nome_completo: 1, 'profile.socioresidente': 1 }; @@ -822,6 +822,7 @@ UserSchema.statics.findByToken = async function (token, typeaccess, con_auth, wi const end_find = process.hrtime.bigint(); // console.log(` User.findOne LEAN impiega ${Math.round(Number(end_find - start_find) / 1e6) / 1000} secondi.`); } + if (user) { const checkExpiry = tools.getEnableTokenExpiredByIdApp(user.idapp); diff --git a/src/server/modules/Macro.js b/src/server/modules/Macro.js index 6d1a9de..8a88f8e 100644 --- a/src/server/modules/Macro.js +++ b/src/server/modules/Macro.js @@ -22,6 +22,7 @@ class Macro { let mylog = '' let numrec = 0; + try { const options = { @@ -54,6 +55,7 @@ class Macro { if (options.usaDBGMLocale) { mylog += '*** usaDBGMLocale ***\n'; miomatch = { IdStatoProdotto: { $in: [1, 4, 34, 45, 46] } }; + // options.where = { IdStatoProdotto: { $in: [1, 4, 34, 45, 46] } }; } else { options.where = ` @@ -74,6 +76,17 @@ class Macro { }; } + let filtroTipologia = null; + + // FILTRO PER LIBRI + if (true) { + filtroTipologia = { + $match: { + DescrizioneTipologia: 'Libri', + } + }; + } + if (options.usaDBGMLocale) { mylog += '*** usaDBGMLocale ***\n'; options.aggregation = [ @@ -88,19 +101,26 @@ class Macro { { $group: { _id: "$IdArticolo", - lastRecord: { $first: "$$ROOT" } // prendi il record più recente + lastRecord: { $first: "$$ROOT" } } }, { $replaceRoot: { newRoot: "$lastRecord" } }, - ...(miolimit > 0 ? [{ $limit: miolimit }] : []), { $lookup: { from: 't_web_statiprodottos', localField: 'IdStatoProdotto', foreignField: 'IdStatoProdotto', as: 'StatoProdotto', + pipeline: [ + { + $sort: { DataOra: -1 }, + }, + { + $limit: 1 + } + ] } }, { @@ -111,9 +131,17 @@ class Macro { { $lookup: { from: 't_web_tipologies', - localField: 'idTipologia', - foreignField: 'idTipologia', + localField: 'IdTipologia', + foreignField: 'IdTipologia', as: 'DescrizioneTipologia', + pipeline: [ + { + $sort: { DataOra: -1 }, + }, + { + $limit: 1 + } + ] } }, { @@ -121,6 +149,13 @@ class Macro { DescrizioneTipologia: { $arrayElemAt: ['$DescrizioneTipologia.Descrizione', 0] }, } }, + { + $match: { + $expr: { + $eq: ["$DescrizioneTipologia", "Libri"] + } + } + }, { $lookup: { from: 't_web_tipiformatos', @@ -134,6 +169,7 @@ class Macro { DescrizioneFormato: { $arrayElemAt: ['$DescrizioneFormato.Descrizione', 0] }, } }, + ...(filtroTipologia ? [filtroTipologia] : []), { $lookup: { from: 't_web_collanes', @@ -203,6 +239,12 @@ class Macro { } } }, + { + $project: { + ListaAutoriArray: 0, + AutoriDettagliati: 0, + } + }, { $addFields: { ListaArgomentiArray: { @@ -230,7 +272,8 @@ class Macro { } }, { $sort: { DataOra: -1 } }, - { $limit: 1 } + { $limit: 1 }, + { $project: { Descrizione: 1 } } ], as: 'ArgomentiDettagliati' } @@ -253,11 +296,34 @@ class Macro { } } }, - // Step: Pulisci i campi temporanei { $project: { + ArgomentiDettagliati: 0, ListaArgomentiArray: 0, - // ArgomentiDettagliati: 0 + } + }, + { + $lookup: { + from: 't_web_disponibiles', + let: { codice: { $toString: '$IdArticolo' } }, + pipeline: [ + { $match: { $expr: { $eq: ['$Codice', '$$codice'] } } }, + { $sort: { DataOra: -1 } }, + { $limit: 1 }, + { $project: { QtaDisponibile: 1 } } + ], + as: 'DisponibileDettaglio' + } + }, + { + $addFields: { + QtaDisponibile: { $arrayElemAt: ['$DisponibileDettaglio.QtaDisponibile', 0] } + } + }, + // Step: Pulisci i campi temporanei + { + $project: { + DisponibileDettaglio: 0, } }, { @@ -275,31 +341,40 @@ class Macro { }, ]; + } else { if (!options.caricatutti) { - // Singolo - options.where = 'T.IdArticolo =' + options.sku + ' AND T.Ean13 = ' + options.isbn; + if (options.sku) { + options.where = 'T.IdArticolo =' + options.sku + ' AND T.Ean13 = \'' + options.isbn + '\''; + } else { + options.where = 'T.Ean13 = \'' + options.isbn + '\''; + } } } const recproducts = await getTableContent(options); - if (!tools.isArray(recproducts)) { console.error('Error: ', recproducts); mylog += recproducts + '\n'; } else { numrec = recproducts?.length || 0; - console.log('numrec', numrec); + console.log('numrec', numrec); } + let count = 0; if (Array.isArray(recproducts)) { for (const recproduct of recproducts) { - if (!options.caricatutti) { - await this.elaboraProdotto(recproduct, opt); - } + // if (!options.caricatutti) { + await this. + elaboraProdotto(recproduct, opt); + count++; + + if (count % 50 === 0) + console.log(' *** IMPORTATI: ' + opt.imported + ' AGGIORNATI = ' + opt.updated + ' (su ' + numrec + ' RECORD)'); + //} } } @@ -443,8 +518,8 @@ class Macro { const risrecInfo = await ProductInfo.findOneAndUpdate( { code: productInfo.code }, { $set: productInfo }, - { new: true, upsert: true } - ); + { new: true, upsert: true, returnOriginal: false } + ).lean(); if (risrecInfo) { await this.aggiornaImmagineSeNecessario(risrecInfo); @@ -757,12 +832,17 @@ class Macro { const publisher = productInfo.publisher.trim(); const recpublisher = await Publisher.findOne({ idapp: this.idapp, name: publisher }).lean(); + let nuovoEditore = null; if (!recpublisher) { - const nuovoEditore = new Publisher({ idapp: this.idapp, name: publisher }); + nuovoEditore = new Publisher({ idapp: this.idapp, name: publisher }); await nuovoEditore.save(); + if (!nuovoEditore._id) { + console.error('Errore gestisciEditore: nuovoEditore non ha id'); + return; + } } - - productInfo.idPublisher = recpublisher?._id || nuovoEditore._id; + if (recpublisher?._id || nuovoEditore?._id) + productInfo.idPublisher = recpublisher?._id || nuovoEditore._id; } } diff --git a/src/server/router/users_router.js b/src/server/router/users_router.js index c018075..495108d 100755 --- a/src/server/router/users_router.js +++ b/src/server/router/users_router.js @@ -1078,7 +1078,7 @@ async function eseguiDbOp(idapp, mydata, locale, req, res) { // chiama updateAllBook const { updateAllBook } = require("../controllers/articleController"); - mystr = await updateAllBook(req, null, mydata.options); + mystr = await updateAllBook(idapp, mydata.options); ris = { mystr }; diff --git a/src/server/tools/general.js b/src/server/tools/general.js index 864ba8f..cc7fc61 100755 --- a/src/server/tools/general.js +++ b/src/server/tools/general.js @@ -6242,6 +6242,21 @@ module.exports = { return { prodInfo: null, aggiornatoimg: false }; }, + + removeAccents(mystr) { + if (!mystr) return mystr; + + const accentsMap = new Map([ + ['á', 'a'], ['à', 'a'], ['ã', 'a'], ['ä', 'a'], ['â', 'a'], + ['é', 'e'], ['è', 'e'], ['ë', 'e'], ['ê', 'e'], + ['í', 'i'], ['ì', 'i'], ['ï', 'i'], ['î', 'i'], + ['ó', 'o'], ['ò', 'o'], ['ö', 'o'], ['ô', 'o'], ['õ', 'o'], + ['ú', 'u'], ['ù', 'u'], ['ü', 'u'], ['û', 'u'], + ['ç', 'c'], ['ñ', 'n'], + ]); + + return Array.from(mystr).map(char => accentsMap.get(char) || char).join(''); + },