- aggiornato scheda e rigenera lista

- corretto filtro sulla Collana
This commit is contained in:
Surya Paolo
2025-04-29 02:30:19 +02:00
parent 95793fd73f
commit 3d4f8b0d04
12 changed files with 318 additions and 44 deletions

View File

@@ -888,7 +888,7 @@ exports.mssqlmigrateTables = async (req) => {
'T_WEB_Argomenti', 'T_WEB_ClientiInternet', 'T_WOO_Clienti', 'T_WEB_Autori', 'T_WEB_Collane', 'T_WEB_MarchiEditoriali', 'T_WEB_StatiProdotto', 'T_WEB_TipiFormato', 'T_WEB_Tipologie', 'T_WEB_ArticoliFatturati', 'T_WEB_IdInternetFatturati',
'T_WEB_Edizioni', 'T_WEB_Contratti'];
} else {
listaTabelle = ['T_WEB_Articoli', 'T_WEB_ArticoliFatturati'];
listaTabelle = ['T_WEB_Ordini'];
}
const migrator = new MssqlMigrator();

View File

@@ -29,8 +29,7 @@ const CatalogSchema = new Schema({
},
foto_collana: IImg,
idCollane: [{
type: Schema.Types.ObjectId,
ref: 'Collana',
type: String,
}],
argomenti: [{
type: String,
@@ -129,15 +128,15 @@ CatalogSchema.statics.findAllIdApp = async function (idapp) {
let arrrec = await Catalog.find({ idapp })
.sort({ title: 1 }) // Ordina i risultati per titolo
.populate({
/*.populate({
path: "idCollane", // Popola il campo idCollane
model: "Collana" // Specifica il modello della collezione Collana
})
})*/
.populate({
path: "lista_prodotti", // Popola il campo lista_prodotti
populate: {
path: "idProductInfo", // Popola il campo idProductInfo dentro ogni prodotto
model: "ProductInfo", // Specifica il modello della collezione ProductInfo
path: "idProductInfo",
model: "ProductInfo",
populate: [
{
path: "idCatProds",

View File

@@ -64,7 +64,7 @@ CatProdSchema.statics.updateCatDeleteEmpty = async function (idapp) {
{ $match: { idapp } },
{
$lookup: {
from: 'productinfos', // Nome della tua collezione productInfo
from: 'productinfos',
localField: '_id',
foreignField: 'idCatProds',
as: 'products'

View File

@@ -61,7 +61,7 @@ const catalogo = new Schema(
excludeproductTypes: [{ type: Number }],
editore: [{ type: String }],
argomenti: [{ type: String }],
idCollane: [{ type: Number }],
idCollane: [{ type: String }],
idTipologia: [{ type: Number }],
sort_field: { type: String },
sort_dir: { type: Number },

View File

@@ -133,7 +133,7 @@ const scheletroScheda = {
idTipologia: [{ type: Number }],
editore: [{ type: String }],
argomenti: [{ type: String }],
idCollane: [{ type: Number }],
idCollane: [{ type: String }],
author: { type: String },
sort_field: { type: String },
sort_dir: { type: Number },

View File

@@ -277,7 +277,7 @@ module.exports.executeQueryPickup = async function (idapp, params) {
const escapeRegex = w => w.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
// 🔹 Pattern per productInfo.name: tutte le parole devono essere presenti
const patternAllWords = words.map(w => `(?=.*\\b${escapeRegex(w)}\\b)`).join('') + '.*';
const patternAllWords = words.map(w => `(?=.*\\b${escapeRegex(w)})`).join('') + '.*';
// 🔹 Condizioni per autori
let authorConditions = [];
@@ -394,13 +394,13 @@ module.exports.executeQueryPickup = async function (idapp, params) {
name: '$productInfo.name', // Nome dell'autore
authors: '$productInfo.authors',
idStatoProdotto: "$productInfo.idStatoProdotto",
date_pub: "$productInfo.date_pub",
},
arrvariazioni: "$arrvariazioni",
}
},
{
$sort: {
'arrvariazioni.0.quantita': -1, // Ordina per arrvariazioni[0].quantita , decrescente
'productInfo.date_pub': -1,
'productInfo.name': 1 // Ordina per name in ordine crescente
}

View File

@@ -125,7 +125,7 @@ const productInfoSchema = new Schema({
type: String,
},
idAuthors: [{ type: Schema.Types.ObjectId, ref: 'Author' }],
idCollana: { type: Number },
idCollana: { type: Schema.Types.ObjectId, ref: 'Collana' },
idPublisher: { type: Schema.Types.ObjectId, ref: 'Publisher' },
collezione: {
type: String,
@@ -452,15 +452,18 @@ module.exports.correggiProductTypes = async function () {
module.exports.updateProductInfoByStats = async function (idapp) {
let mylog = '';
let mylog2 = '';
let mylogtot = '';
try {
const ProductInfo = this;
const T_WEB_ArticoliFatturati = require('./t_web_articolifatturati')
const T_WEB_ArticoliFatturati = require('./t_web_articolifatturati');
const T_WEB_Ordini = require('./t_web_ordini');
// Ottieni le statistiche dalla query
const statistics = await T_WEB_ArticoliFatturati.getStatistics();
mylog = "Inizio Aggiornamento Statistiche... \n";
mylogtot += mylog;
console.log(mylog);
// Itera sui risultati e aggiorna productInfo
@@ -486,15 +489,51 @@ module.exports.updateProductInfoByStats = async function (idapp) {
}
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++;
}
}
mylog2 = `Aggiornati ${countUpdate} record di productInfo`;
mylogtot += mylog2;
console.log(mylog2);
} catch (error) {
mylog = "Errore durante l'aggiornamento di productInfo:" + error;
console.error(mylog);
}
return mylog;
return mylogtot;
}
module.exports.createIndexes()

View File

@@ -118,7 +118,7 @@ module.exports.getStatistics = async function () {
sku: "$_id", // Rinomina _id in sku (equivalente a IdArticolo)
fatLast3M: 1,
fatLast6M: 1,
fatLast1Y: 1
fatLast1Y: 1,
}
}
];
@@ -131,3 +131,5 @@ module.exports.getStatistics = async function () {
throw error;
}
}

View File

@@ -41,7 +41,7 @@ const TWebDisponibileSchema = new mongoose.Schema({
default: 0,
},
}, {
collection: 't_web_disponibiles', // nome della collezione esatto
collection: 't_web_disponibiles',
timestamps: false,
});

161
src/server/models/t_web_ordini.js Executable file
View File

@@ -0,0 +1,161 @@
// allo stesso modo di t_web_articolifatturati.js
// creami il modello t_web_ordini:
// Tabella: T_WEB_Ordini
/*Codice - decimal ()
IdInternet - varchar (50)
CodArticoloGM - varchar (50)
Qta - decimal ()
PrezzoLordo - decimal ()
PercSconto - decimal ()
Enabled - int ()
DataOra - datetime ()
SovraSconto - decimal ()
Descrizione - varchar (250)
PrimaCopiaDaSpedire - int ()
*/
const mongoose = require('mongoose');
// Definizione dello schema
const ordiniSchema = new mongoose.Schema({
Codice: {
type: Number, // Decimal in MongoDB è rappresentato come Number
},
IdInternet: {
type: String,
maxlength: 50,
},
CodArticoloGM: {
type: String,
maxlength: 50,
},
Qta: {
type: Number, // Decimal in MongoDB è rappresentato come Number
},
PrezzoLordo: {
type: Number, // Decimal in MongoDB è rappresentato come Number
},
PercSconto: {
type: Number, // Decimal in MongoDB è rappresentato come Number
},
Enabled: {
type: Number, // Int in MongoDB è rappresentato come Number
},
DataOra: {
type: Date, // Datetime in MongoDB è rappresentato come Date
},
SovraSconto: {
type: Number, // Decimal in MongoDB è rappresentato come Number
},
Descrizione: {
type: String,
maxlength: 250
},
PrimaCopiaDaSpedire: {
type: Number, // Int in MongoDB è rappresentato come Number
}
}, {
timestamps: true, // Aggiunge automaticamente i campi createdAt e updatedAt
collection: 't_web_ordinis',
});
var T_WEB_Ordini = module.exports = mongoose.model('T_WEB_Ordini', ordiniSchema);
module.exports.getStatisticsFromOrders = async function () {
const currentDate = new Date();
// Calcola le date limite per i periodi di 3 mesi, 6 mesi e 1 anno
const threeMonthsAgo = new Date(currentDate);
threeMonthsAgo.setMonth(currentDate.getMonth() - 3);
const sixMonthsAgo = new Date(currentDate);
sixMonthsAgo.setMonth(currentDate.getMonth() - 6);
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);
try {
// Query di aggregazione per calcolare le statistiche
const myquery = [
{
$group: {
_id: "$CodArticoloGM", // Raggruppa per CodArticolo
totVen: {
$sum: {
$cond: [
{ $gte: ["$DataOra", allYear] }, // Condizione: DataOra totale
{ $toInt: "$Qta" }, // Se vero, somma la quantità
0 // Altrimenti, somma 0
]
}
},
vLast3M: {
$sum: {
$cond: [
{ $gte: ["$DataOra", threeMonthsAgo] }, // Condizione: DataOra >= 3 mesi fa
{ $toInt: "$Qta" }, // Se vero, somma la quantità
0 // Altrimenti, somma 0
]
}
},
vLast6M: {
$sum: {
$cond: [
{ $gte: ["$DataOra", sixMonthsAgo] }, // Condizione: DataOra >= 6 mesi fa
{ $toInt: "$Qta" }, // Se vero, somma la quantità
0 // Altrimenti, somma 0
]
}
},
vLast1Y: {
$sum: {
$cond: [
{ $gte: ["$DataOra", oneYearAgo] }, // Condizione: DataOra >= 1 anno fa
{ $toInt: "$Qta" }, // Se vero, somma la quantità
0 // Altrimenti, somma 0
]
}
},
vLast2Y: {
$sum: {
$cond: [
{ $gte: ["$DataOra", twoYearAgo] }, // Condizione: DataOra >= 1 anno fa
{ $toInt: "$Qta" }, // Se vero, somma la quantità
0 // Altrimenti, somma 0
]
}
},
}
},
{
$project: {
_id: 0, // Rimuove il campo _id dal risultato
sku: "$_id", // Rinomina _id in sku (equivalente a IdArticolo)
totVen: 1,
vLast3M: 1,
vLast6M: 1,
vLast1Y: 1,
vLast2Y: 1,
}
}
];
const statistics = await T_WEB_Ordini.aggregate(myquery);
return statistics;
} catch (error) {
console.error("Errore durante il calcolo delle statistiche:", error);
throw error;
}
}

View File

@@ -6,6 +6,7 @@ const CatProd = require('../models/catprod');
const SubCatProd = require('../models/subcatprod');
const Author = require('../models/author');
const Publisher = require('../models/publisher');
const Collana = require('../models/collana');
const Gasordine = require('../models/gasordine');
const tools = require('../tools/general'); // Assicurati di avere il file delle utility
const shared_consts = require('../tools/shared_nodejs'); // Assicurati di avere le costanti condivise
@@ -62,10 +63,21 @@ class Macro {
miomatch2 = {
$or: [
{ DescrizioneStatoProdotto: 'In commercio' },
{ DescrizioneStatoProdotto: '2023 in commercio' },
{ DescrizioneStatoProdotto: 'Vendita sito' },
{ 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: 'Prossima uscita' }
{ DescrizioneStatoProdotto: 'Vendita sito' },
{ DescrizioneStatoProdotto: '2023 in commercio' },
{ DescrizioneStatoProdotto: 'Assoluto NO Reso' },
{ DescrizioneStatoProdotto: 'Titolo esaurito' },
{ DescrizioneStatoProdotto: 'Prossima uscita' },
]
};
@@ -93,12 +105,27 @@ class Macro {
} else {
options.where = `
(DescrizioneStatoProdotto = 'In commercio' OR
DescrizioneStatoProdotto = 'Ristampa' OR
DescrizioneStatoProdotto = 'Prossima uscita/pubblicazione' OR
DescrizioneStatoProdotto = 'In promozione' OR
DescrizioneStatoProdotto = 'In fase di valutazione' OR
DescrizioneStatoProdotto = 'Titolo in esaurimento (in attesa Nuova Edizione)' OR
DescrizioneStatoProdotto = 'Titolo in esaurimento' OR
DescrizioneStatoProdotto = 'Titolo in esaurimento (in att N.E Ricopertinata)' OR
DescrizioneStatoProdotto = 'Titolo in Esaurimento (disponibile N.E.)' OR
DescrizioneStatoProdotto = 'In commercio (digitale)' OR
DescrizioneStatoProdotto = 'In prevendita' OR
DescrizioneStatoProdotto = 'Vendita sito' OR
DescrizioneStatoProdotto = '2023 in commercio' OR
DescrizioneStatoProdotto = 'Assoluto NO Reso' OR
DescrizioneStatoProdotto = 'Titolo esaurito'
DescrizioneStatoProdotto = '2023 in commercio' OR
DescrizioneStatoProdotto = 'Vendita sito' OR
DescrizioneStatoProdotto = 'In prevendita' OR
DescrizioneStatoProdotto = 'Prossima uscita') AND
(DescrizioneTipologia = 'Libri' OR
DescrizioneTipologia = 'Cartonato')
DescrizioneTipologia = 'Cartolibro' OR
DescrizioneTipologia = 'Carte')
`;
}
@@ -116,7 +143,7 @@ class Macro {
if (true) {
filtroTipologia = {
$match: {
DescrizioneTipologia: { $in: ['Libri', 'Cartolibro'] },
DescrizioneTipologia: { $in: ['Libri', 'Cartolibro', 'Carte'] },
}
};
}
@@ -200,8 +227,8 @@ class Macro {
{
$lookup: {
from: 't_web_tipiformatos',
localField: 'idFormato',
foreignField: 'idFormato',
localField: 'IdTipoFormato',
foreignField: 'IdTipoFormato',
as: 'DescrizioneFormato',
}
},
@@ -214,8 +241,8 @@ class Macro {
{
$lookup: {
from: 't_web_collanes',
localField: 'idCollana',
foreignField: 'idCollana',
localField: 'IdCollana',
foreignField: 'IdCollana',
as: 'DescrizioneCollana',
}
},
@@ -564,6 +591,8 @@ class Macro {
await this.gestisciCategorie(productInfo, product);
await this.gestisciAutori(productInfo, product);
await this.gestisciEditore(productInfo, product);
await this.gestisciCollana(productInfo, product);
const risrecInfo = await ProductInfo.findOneAndUpdate(
{ code: productInfo.code },
@@ -625,7 +654,9 @@ class Macro {
description: product.description,
short_descr: product.short_descr,
publisher: product.editore,
collezione: product.Collezione,
collezione: product.collezione,
idCollana: product.idCollana,
numCollana: product.numCollana,
link: product.link || undefined,
idCatProds: [],
idSubCatProds: [],
@@ -706,6 +737,7 @@ class Macro {
}
*/
const recproduct = {
idapp: idapp,
isbn: productGM.Ean13,
@@ -714,8 +746,8 @@ class Macro {
title: productGM.Titolo, // productInfo.name.replace(/ - Usato$| - Nuovo$| - Epub$| - Ebook$| - Mobi$| - DVD$| - Streaming$| - Download$/, "");
description: '',
short_descr: '',
editore: productGM.CasaEditrice,
collezione: productGM.DescrizioneCollana,
numCollana: productGM.IdCollana,
editore: productGM.CasaEditrice,
Autore: productGM.AutoriCompleti,
DescrArgomento: productGM.DescrArgomento,
@@ -727,10 +759,9 @@ class Macro {
Tipologia: productGM.DescrizioneTipologia,
idTipologia: productGM.IdTipologia,
idTipoFormato: productGM.IdTipoFormato,
Edizione: productGM.Edizione,
Pagine: productGM.Pagine,
misure: productGM.Misure,
edizione: productGM.Edizione,
Edizione: productGM.Edizione,
ristampa: productGM.Ristampa,
eta: productGM.FasciaEta,
// addtocart_link: '',
@@ -743,9 +774,9 @@ class Macro {
let vers = 0;
//if (productGM.DescrizioneTipologia === 'Usato')
// vers = shared_consts.PRODUCTTYPE.USATO;
/*
if (productGM.DescrizioneTipologia === 'Usato')
vers = shared_consts.PRODUCTTYPE.USATO;
if (productGM.DescrizioneTipologia === 'Download')
vers = shared_consts.PRODUCTTYPE.DOWNLOAD;
else if (productGM.DescrizioneTipologia === 'DVD')
@@ -761,9 +792,7 @@ class Macro {
else
vers = shared_consts.PRODUCTTYPE.NUOVO;
recproduct.Versione = vers;
*/
recproduct.Versione = vers;
return recproduct
}
@@ -904,6 +933,29 @@ class Macro {
}
}
/**
* Gestisce la collana del prodotto.
*/
async gestisciCollana(productInfo, product) {
if (product.collezione && product.numCollana) {
const collana = product.collezione.trim();
const reccollana = await Collana.findOne({ idapp: this.idapp, title: collana }).lean();
let nuovaCollana = null;
if (!reccollana) {
nuovaCollana = new Collana({ idapp: this.idapp, idCollana: product.numCollana, title: collana });
await nuovaCollana.save();
if (!nuovaCollana._id) {
console.error('Errore gestisciCollana: nuovaCollana non ha id');
return;
}
}
if (reccollana?._id || nuovaCollana?._id)
productInfo.idCollana = reccollana?._id || nuovaCollana._id;
}
}
/**
* Aggiorna l'immagine se necessario.
*/
@@ -920,7 +972,7 @@ class Macro {
preparaVariazione(product) {
return {
active: true,
// versione: product.Versione,
versione: product.Versione,
status: product.Stato || null,
price: product.price ? parseFloat(tools.convertPriceEurToValue(product.price)) : null,
sale_price: product.sale_price ? parseFloat(tools.convertPriceEurToValue(product.sale_price)) : null,
@@ -931,7 +983,6 @@ class Macro {
edizione: product.Edizione || '',
pagine: tools.isValidNumber(product.Pagine) ? tools.convstrToInt(product.Pagine) : 0,
misure: product.misure || '',
edizione: product.edizione || '',
ristampa: product.ristampa || '',
eta: product.eta || '',
addtocart_link: product.addtocart_link || '',

View File

@@ -806,6 +806,7 @@ router.post('/import', authenticate, async (req, res) => {
return res.status(200).send({ updated, imported, errors });
} else if (cmd === shared_consts.Cmd.MACRO_RANKING) {
/*
let updated = 0;
let imported = 0;
let errors = 0;
@@ -945,20 +946,21 @@ router.post('/import', authenticate, async (req, res) => {
//if (recproductInfoAttuale && !recproductInfoAttuale.idCollana && product.DescrizioneCollana) {
if (recproductInfoAttuale && product.DescrizioneCollana) {
const idCollanaNum = parseInt(product.IdCollana)
productInfo.idCollana = idCollanaNum;
reccollana = await Collana.findOne({ idapp, idCollana: idCollanaNum }).lean();
if (!reccollana) {
try {
// Non esiste questa collana, quindi la creo !
reccoll = new Collana({ idapp, idCollana: idCollanaNum, title: product.DescrizioneCollana });
reccollana = new Collana({ idapp, idCollana: idCollanaNum, title: product.DescrizioneCollana });
ris = await reccoll.save();
} catch (e) {
console.error('Err', e);
}
}
if (reccollana)
productInfo.idCollana = reccollana._id;
}
if (recproductInfoAttuale && product.DescrArgomento) {
@@ -989,11 +991,12 @@ router.post('/import', authenticate, async (req, res) => {
console.log('*** IMPORTATI: ', imported, ' [Prodotti = ' + indprod + '] *** NUOVI: ', newprod, 'AGGIORNATI = ' + updated + ' (su ' + dataObjects.length + ' RECORD)');
return res.status(200).send({ updated, imported, errors });
*/
} else if (cmd === shared_consts.Cmd.MACRO_CATALOGO_JSON) {
try {
const macro = new Macro(idapp, {importadaFDV: true}); // Crea un'istanza della classe Macro
const macro = new Macro(idapp, { importadaFDV: true }); // Crea un'istanza della classe Macro
const result = await macro.importaCatalogo(data); // Chiama il metodo importaCatalogo
return res.status(200).send(result);
} catch (e) {
@@ -1501,6 +1504,7 @@ async function importaCatalogo(data) {
short_descr: product.short_descr,
publisher: product.editore,
collezione: product.Collezione,
numCollana: product.numCollana,
// author: product.Autore ? product.Autore : '',
link: product.link ? product.link : '',
idCatProds: [],
@@ -1723,6 +1727,24 @@ async function importaCatalogo(data) {
console.error(e);
}
}
// Aggiorna la collana solo se non è stata già impostata nel record attuale
//if (recproductInfoAttuale && !recproductInfoAttuale.idCollana && product.DescrizioneCollana) {
if (productInfo.collezione && productInfo.numCollana) {
reccollana = await Collana.findOne({ idapp, title: collezione }).lean();
if (!reccollana) {
try {
// Non esiste questa collana, quindi la creo !
reccollana = new Collana({ idapp, idCollana: productInfo.numCollana, title: product.DescrizioneCollana });
ris = await reccoll.save();
} catch (e) {
console.error('Err', e);
}
}
if (reccollana)
productInfo.idCollana = reccollana._id;
}
if (!product.hasOwnProperty('active')) {