mongoose = require('mongoose').set('debug', false) const Schema = mongoose.Schema; const tools = require('../tools/general'); const Producer = require('../models/producer'); const Storehouse = require('../models/storehouse'); const Provider = require('../models/provider'); const CatProd = require('../models/catprod'); const SubCatProd = require('../models/subcatprod'); const Gasordine = require('../models/gasordine'); const Scontistica = require('../models/scontistica'); const shared_consts = require('../tools/shared_nodejs'); const { ObjectId } = require('mongodb'); mongoose.Promise = global.Promise; mongoose.level = "F"; // A1P // Resolving error Unknown modifier: $pushAll mongoose.plugin(schema => { schema.options.usePushEach = true }); const productSchema = new Schema({ idapp: { type: String, }, active: { type: Boolean, default: true, }, isbn: { type: String, }, idProductInfo: { type: Schema.Types.ObjectId, ref: 'ProductInfo' }, idProducer: { type: Schema.Types.ObjectId, ref: 'Producer' }, idStorehouses: [ { type: Schema.Types.ObjectId, ref: 'Storehouse' } ], idGasordine: { type: Schema.Types.ObjectId, ref: 'Gasordine' }, idScontisticas: [ { type: Schema.Types.ObjectId, ref: 'Scontistica' } ], idProvider: { type: Schema.Types.ObjectId, ref: 'Provider' }, prezzo_ivato: { // Con IVA type: Number }, perc_iva: { // 4, 10, 22 & type: Number }, price: { type: Number, required: true, }, arrvariazioni: [ { active: { type: Boolean, }, versione: { type: Number, }, status: { //publish type: String, }, price: { type: Number, }, sale_price: { type: Number, }, quantita: { // in magazzino type: Number, }, pagine: { type: Number, }, misure: { type: String, }, formato: { type: String, }, tipologia: { type: String, }, edizione: { type: String, }, preOrderDate: { type: Date }, addtocart_link: { type: String }, eta: { type: String }, } ], price_acquistato: { type: Number, required: true, }, after_price: { type: String }, minBuyQty: { // quantità minima acquistabile type: Number, default: 1, required: true, }, minStepQty: { // step quantità acquistabile type: Number, default: 1, required: true, }, maxBookableSinglePersQty: { // quantità massima Pre-ordinabile (singolarmente) type: Number, default: 0, }, stockQty: { // in magazzino type: Number, default: 0, }, 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 }, note: { type: String, }, producer_name: { type: String, }, provider_name: { type: String, }, magazzino_name: { type: String, }, cat_name: { type: String, }, subcat_name: { type: String, }, sconto1: { type: String, }, sconto2: { type: String, }, gas_name: { type: String, }, date_created: { type: Date, default: Date.now }, date_updated: { type: Date, }, }); var Product = module.exports = mongoose.model('Product', productSchema); productSchema.index({ idapp: 1 }); module.exports.getFieldsForSearch = function () { return [ { field: 'name', type: tools.FieldType.string }, { field: 'description', type: tools.FieldType.string }, ] }; module.exports.executeQueryTable = function (idapp, params) { params.fieldsearch = this.getFieldsForSearch(); return tools.executeQueryTable(this, idapp, params); }; module.exports.executeQueryPickup = async function (idapp, params) { let strfind = params.search; strfind = strfind.replace(/[-@]/g, ''); if (strfind === '' && !params.filter) { return []; } let filterfindexact = {}; if (strfind) { filterfindexact = { comune: strfind }; } let limit = 10; let risexact = []; let filterfind = { idapp, 'productInfo.name': { $regex: `\\b${strfind}`, // Usa \\b per trovare solo le parole che iniziano con strfind $options: 'i' // Rendi la ricerca case-insensitive } }; /* let aggr1 = [ { $lookup: { from: 'productinfos', localField: 'idProductInfo', foreignField: '_id', as: 'productInfo' } }, { $lookup: { from: 'authors', localField: 'idAuthors', foreignField: '_id', as: 'authors' } }, { $match: { 'productInfo.name': strfind }, }, { $limit: 1 }, { $project: { name: { $concat: ["$productInfo.name", " (", "$authors", ")"] }, }, }, ]; if (params.filter) { filterfind = { ...params.filter, ...filterfind }; limit = 200; } else { // risexact = await City.find(filterfindexact, {comune: 1, prov: 1, reg: 1}).lean(); risexact = await City.aggregate(aggr1); } */ if (params.filter) { filterfind = { ...params.filter, ...filterfind }; limit = 200; } let aggr2 = [ { $lookup: { from: 'productinfos', localField: 'idProductInfo', foreignField: '_id', as: 'productInfo' } }, { $unwind: { path: '$productInfo', preserveNullAndEmptyArrays: true, }, }, { $lookup: { from: 'authors', localField: 'idAuthors', foreignField: '_id', as: 'authors' } }, { $match: filterfind, }, { $limit: limit }, { $project: { name: '$productInfo.name', }, }, ]; // let ris = await City.find(filterfind, {comune: 1, prov: 1, reg: 1}).lean().limit(limit); let ris = await this.aggregate(aggr2).limit(limit); return [...risexact, ...ris]; }; module.exports.getProductByCode = function (idapp, code) { return Product.findAllIdApp(idapp, code); } module.exports.getProductById = async function (id) { const arrris = await Product.findAllIdApp('', '', id); return arrris && arrris.length > 0 ? arrris[0] : null } module.exports.getInStockById = async function (id) { const myprod = await Product.findOne({ _id: id }); if (myprod) { let instock = 0; if (myprod.idGasordine) { instock = myprod.maxbookableGASQty; } else { instock = myprod.stockQty; } return instock } return null; } module.exports.isLowQuantityInStockById = async function (id) { const instock = await Product.getInStockById(id); const myprod = await Product.findOne({ _id: id }); if (instock) { return (instock <= (myprod.quantityLow + 1)); } return false; } module.exports.findAllIdApp = async function (idapp, code, id, all) { let myfind = {}; let myqueryadd = {}; let query = []; try { if (idapp) { myfind = { idapp }; } if (!all) { myfind = { ...myfind, active: true } } if (code) { myfind = { ...myfind, code } } if (id) { myqueryadd = { $addFields: { myId1: { $toObjectId: id, }, }, } myfind = { $expr: { $eq: ["$_id", "$myId1"], }, } query.push(myqueryadd); } // DA TOGLIEREE // myfind = { ...myfind, code: '4012824406094' }; // return await Product.find(myfind); query.push( { $match: myfind }, { $lookup: { from: 'producers', localField: 'idProducer', foreignField: '_id', as: 'producer' } }, { $unwind: { path: '$producer', preserveNullAndEmptyArrays: true, }, }, { $lookup: { from: 'productinfos', localField: 'idProductInfo', foreignField: '_id', as: 'productInfo' } }, { $unwind: { path: '$productInfo', preserveNullAndEmptyArrays: true, }, }, { $lookup: { from: 'gasordines', localField: 'idGasordine', foreignField: '_id', as: 'gasordine' } }, { $unwind: { path: '$gasordine', preserveNullAndEmptyArrays: true, }, }, { $match: { $or: [ { 'gasordine.active': true }, // Include documents where gasordines.active is true { 'gasordine': { $exists: false } } // Include documents where gasordines array doesn't exist ] } }, { $group: { _id: '$_id', gasordine: { $first: '$gasordine' }, originalFields: { $first: '$$ROOT' } // Preserve all existing fields } }, { $replaceRoot: { newRoot: { $mergeObjects: ['$originalFields', { gasordine: '$gasordine' }] } } }, { $lookup: { from: 'providers', localField: 'idProvider', foreignField: '_id', as: 'provider' } }, { $unwind: { path: '$provider', preserveNullAndEmptyArrays: true, }, }, { $lookup: { from: 'authors', localField: 'productInfo.idAuthors', foreignField: '_id', as: 'productInfo.authors' } }, { $lookup: { from: 'publishers', localField: 'productInfo.idPublisher', foreignField: '_id', as: 'productInfo.publisher' } }, { $unwind: { path: '$productInfo.publisher', preserveNullAndEmptyArrays: true, }, }, { $lookup: { from: 'collanas', localField: 'productInfo.idCollana', foreignField: '_id', as: 'productInfo.collana' } }, { $unwind: { path: '$productInfo.collana', preserveNullAndEmptyArrays: true, }, }, { $lookup: { from: 'catprods', localField: 'productInfo.idCatProds', foreignField: '_id', as: 'productInfo.catprods' } }, { $lookup: { from: 'subcatprods', localField: 'productInfo.idSubCatProds', foreignField: '_id', as: 'productInfo.subcatprods' } }, { $lookup: { from: 'scontisticas', localField: 'idScontisticas', foreignField: '_id', as: 'scontisticas' } }, { $lookup: { from: 'storehouses', localField: 'idStorehouses', foreignField: '_id', as: 'storehouses' } }, { $lookup: { from: 'orders', let: { productId: '$_id' }, pipeline: [ { $match: { $expr: { $and: [ { $eq: ['$idProduct', '$$productId'] }, { $or: [ { $eq: ['$status', shared_consts.OrderStatus.CHECKOUT_SENT] }, { $and: [{ $lt: ['$status', shared_consts.OrderStatus.CHECKOUT_SENT] }, { $gt: [ '$modify_at', { $subtract: [new Date(), 60 * 60 * 1000] } // 1 hour in milliseconds 60 * 60 ] }] } ] } ] } } }, { $group: { _id: null, totalQty: { $sum: '$quantity' }, } } ], as: 'productOrders' } }, { $lookup: { from: 'orders', let: { productId: '$_id' }, pipeline: [ { $match: { $expr: { $and: [ { $eq: ['$idProduct', '$$productId'] }, { $or: [ { $eq: ['$status', shared_consts.OrderStatus.CHECKOUT_SENT] }, { $and: [{ $lt: ['$status', shared_consts.OrderStatus.CHECKOUT_SENT] }, { $gt: [ '$modify_at', { $subtract: [new Date(), 60 * 60 * 1000] } // 1 hour in milliseconds 60 * 60 ] }] } ] } ] } } }, { $group: { _id: null, totalQtyPreordered: { $sum: '$quantitypreordered' } } } ], as: 'productPreOrders' } }, { $addFields: { QuantitaOrdinateInAttesa: { $ifNull: [ { $cond: { if: { $isArray: '$productOrders' }, then: { $arrayElemAt: ['$productOrders.totalQty', 0] }, else: 0 } }, 0 ] }, QuantitaPrenotateInAttesa: { $ifNull: [ { $cond: { if: { $isArray: '$productPreOrders' }, then: { $arrayElemAt: ['$productPreOrders.totalQtyPreordered', 0] }, else: 0 } }, 0 ] }, }, }, { $addFields: { quantityAvailable: { $subtract: ["$stockQty", "$QuantitaOrdinateInAttesa"], }, bookableAvailableQty: { $subtract: ["$maxbookableGASQty", "$QuantitaPrenotateInAttesa"], } } }, { $unset: 'productOrders' }, { $unset: 'productPreOrders' }, { $sort: { 'productInfo.name': 1 // 1 for ascending order, -1 for descending order } }, ); // console.log('query=', query); let ris = await Product.aggregate(query) // console.table('ris', ris); return ris; } catch (e) { console.error('E', e); } }; module.exports.getAllProducts = function (query, sort, callback) { Product.find(query, null, sort, callback) } module.exports.getProductByDepartment = function (query, sort, callback) { Product.find(query, null, sort, callback) } module.exports.getProductByCatProd = function (query, sort, callback) { Product.find(query, null, sort, callback) } module.exports.getProductByTitle = function (query, sort, callback) { Product.find(query, null, sort, callback) } module.exports.filterProductByDepartment = function (department, callback) { let regexp = new RegExp(`^${department}$`, 'i') var query = { department: { $regex: regexp } }; Product.find(query, callback) } module.exports.filterProductByCatProd = function (catprod, callback) { let regexp = new RegExp(`^${catprod}$`, 'i') var query = { catprod: { $regex: regexp } }; Product.find(query, callback); } module.exports.filterProductByTitle = function (title, callback) { let regexp = new RegExp(`^${title}$`, 'i') var query = { title: { $regex: regexp } }; Product.find(query, callback); } module.exports.getProductByID = function (id, callback) { Product.findById(id, callback); } module.exports.updateProductInOrder = async function (order) { if (order.product) order.product = await Product.getProductById(order.product._id); return order; } module.exports.createIndexes() .then(() => { }) .catch((err) => { throw err; }); module.exports.convertAfterImportALLPROD = async function (idapp, dataObjects) { const arrprod = await Product.find({ idapp }).lean(); for (const prod of arrprod) { await this.singlerecconvert_AfterImport_AndSave(prod); } }; module.exports.getArrCatProds = async function (idapp, cosa) { try { let addquery = []; let arr = []; if (cosa === shared_consts.PROD.GAS) { addquery = [ { $match: { idapp, idGasordine: { $exists: true, $ne: null, $type: 'objectId' } } } ]; addquery.push( { $lookup: { from: 'gasordines', localField: 'idGasordine', foreignField: '_id', as: 'gasordine' } } ); addquery.push( { $match: { "gasordine.active": true } } ); } else if (cosa === shared_consts.PROD.BOTTEGA) { addquery = [{ $match: { idapp, $or: [ { idGasordine: { $exists: false } }, { idGasordine: { $exists: true, $eq: null } } ] } }] } else { addquery = [{ $match: { idapp } }]; } let myquery = [...addquery, { $lookup: { from: "productinfos", localField: "idProductInfo", foreignField: "_id", as: "productInfo", }, }, { $lookup: { from: "catprods", localField: "productInfo.idCatProds", foreignField: "_id", as: "category" } }, { $unwind: "$category" }, { $group: { _id: "$category._id", name: { $first: "$category.name" } } }, { $sort: { name: 1 } } ]; try { let arr = []; arr = await Product.aggregate(myquery); // arr = result.map(category => category.name); return arr; } catch (e) { console.error('err', e); } // Ora uniqueCategories contiene l'array delle categorie univoche utilizzate in tutti i prodotti con active = true return arr; } catch (e) { console.error('err', e); return []; } } module.exports.singlerecconvert_AfterImport_AndSave = async function (idapp, prod, isnuovo) { let setta = false; try { let objtoset = {} let rec = null // Impostazioni Base: if (isnuovo) { objtoset = { idapp, // minBuyQty: 1, // minStepQty: 1, maxBookableSinglePersQty: 0, bookedGASQtyOrdered: 0, bookableGASBloccatiQty: 0, bookedGASQtyConfirmed: 0, // qtyToReachForGas: 0, // maxbookableGASQty: 0, } } if (prod.producer_name) { // Cerca il produttore let recproducer = await Producer.findOne({ idapp, name: prod.producer_name }).lean(); if (!recproducer) { // Non esiste questo produttore, quindi lo creo ! recproducer = new Producer({ idapp, name: prod.producer_name }); ris = await recproducer.save(); recproducer = await Producer.findOne({ idapp, name: prod.producer_name }).lean(); } if (recproducer) { objtoset = { ...objtoset, idProducer: recproducer._id, } setta = true; } } if (prod.magazzino_name) { // Cerca il produttore let recstorehouse = await Storehouse.findOne({ idapp, name: prod.magazzino_name }).lean(); if (!recstorehouse) { // Non esiste questo produttore, quindi lo creo ! recstorehouse = new Storehouse({ idapp, name: prod.magazzino_name }); ris = await recstorehouse.save(); recstorehouse = await Storehouse.findOne({ idapp, name: prod.magazzino_name }).lean(); } if (recstorehouse) { objtoset = { ...objtoset, idStorehouses: [recstorehouse._id], } setta = true; } } if (prod.provider_name) { // Cerca il produttore let recprovider = await Provider.findOne({ idapp, name: prod.provider_name }).lean(); if (!recprovider) { recprovider = new Provider({ idapp, name: prod.provider_name }); // Non esiste questo produttore, quindi lo creo ! ris = await recprovider.save(); recprovider = await Provider.findOne({ idapp, name: prod.provider_name }).lean(); } if (recprovider) { objtoset = { ...objtoset, idProvider: recprovider._id, } setta = true; } } if (prod.gas_name) { // Cerca il GAS rec = await Gasordine.findOne({ idapp, name: prod.gas_name }).lean(); if (!rec) { rec = new Gasordine({ idapp, name: prod.gas_name, active: true }); // Non esiste questo GAS, quindi lo creo ! ris = await rec.save(); rec = await Gasordine.findOne({ idapp, name: prod.gas_name }).lean(); } if (rec) { objtoset = { ...objtoset, idGasordine: rec._id, } setta = true; } } let arrsconti = [] if (prod.sconto1) { // Cerca la scontistica let recscontistica = await Scontistica.findOne({ idapp, code: prod.sconto1 }).lean(); if (!recscontistica) { recscontistica = new Scontistica({ idapp, code: prod.sconto1 }); // Non esiste questa scontistica, quindi lo creo ! ris = await recscontistica.save(); recscontistica = await Scontistica.findOne({ idapp, code: prod.sconto1 }).lean(); } if (recscontistica) { arrsconti.push(recscontistica); } } if (prod.sconto2) { // Cerca la scontistica let recscontistica = await Scontistica.findOne({ idapp, code: prod.sconto2 }).lean(); if (!recscontistica) { recscontistica = new Scontistica({ idapp, code: prod.sconto2 }); // Non esiste questa scontistica, quindi lo creo ! ris = await recscontistica.save(); recscontistica = await Scontistica.findOne({ idapp, code: prod.sconto2 }).lean(); } if (recscontistica) { arrsconti.push(recscontistica); } } if (arrsconti.length > 0) { objtoset = { ...objtoset, idScontisticas: arrsconti, } setta = true; } // Aggiorna il prezzo ? const aggiornaprezzo = false; if (aggiornaprezzo) { // cerca il prodotto const myprodinput = dataObjects.find((rec) => rec._id === prod._id) if (myprodinput) { objtoset = { ...objtoset, price: myprodinput.price, } } } if (!tools.isObjectEmpty(objtoset)) { ris = await Product.findOneAndUpdate({ _id: new ObjectId(prod._id) }, { $set: objtoset }) const objDelete = { cat_name: 1, subcat_name: 1, producer_name: 1, provider_name: 1, magazzino_name: 1, sconto1: 1, sconto2: 1, gas_name: 1, }; ris = await Product.updateOne({ _id: new ObjectId(prod._id) }, { $unset: objDelete }) if (ris && ris.nModified > 0) { console.log('Modificato: ', objtoset.name); } // const campodarimuovere = 'producer_name'; // await Product.findOneAndUpdate({ _id: prod._id }, { $unset: { [campodarimuovere]: 1 } }) } } catch (e) { console.error('Err', e); } }