From 25377090c172856a6e573aed024ce61396fdd727 Mon Sep 17 00:00:00 2001 From: Surya Paolo Date: Wed, 11 Jun 2025 01:05:25 +0200 Subject: [PATCH] - corretto la gestione degli Sconti - Duplicare un Catalogo --- src/server/models/cart.js | 169 +++++++++++++++++++------------ src/server/models/order.js | 29 ++++-- src/server/models/orderscart.js | 8 ++ src/server/models/scontistica.js | 5 +- src/server/modules/Cart.js | 89 +++++++++++++--- src/server/router/cart_router.js | 48 +++++---- 6 files changed, 242 insertions(+), 106 deletions(-) diff --git a/src/server/models/cart.js b/src/server/models/cart.js index 688740e..01b894a 100755 --- a/src/server/models/cart.js +++ b/src/server/models/cart.js @@ -2,14 +2,13 @@ const mongoose = require('mongoose').set('debug', false); const Schema = mongoose.Schema; mongoose.Promise = global.Promise; -mongoose.level = "F"; +mongoose.level = 'F'; // Resolving error Unknown modifier: $pushAll -mongoose.plugin(schema => { - schema.options.usePushEach = true +mongoose.plugin((schema) => { + schema.options.usePushEach = true; }); - const CartSchema = new Schema({ idapp: { type: String, @@ -18,13 +17,14 @@ const CartSchema = new Schema({ totalQty: { type: Number, default: 0 }, totalPrice: { type: Number, default: 0 }, totalPriceCalc: { type: Number, default: 0 }, + totalPriceIntero: { type: Number, default: 0 }, department: { - type: String, ref: 'Department', + type: String, + ref: 'Department', }, items: [ { - order: - { type: Schema.Types.ObjectId, ref: 'Order' }, + order: { type: Schema.Types.ObjectId, ref: 'Order' }, }, ], note: { @@ -33,6 +33,9 @@ const CartSchema = new Schema({ codice_sconto: { type: String, }, + descr_sconto: { + type: String, + }, note_ordine_gas: { type: String, }, @@ -41,7 +44,7 @@ const CartSchema = new Schema({ }, }); -var Cart = module.exports = mongoose.model('Cart', CartSchema); +var Cart = (module.exports = mongoose.model('Cart', CartSchema)); module.exports.findAllIdApp = async function (idapp, userId) { const myfind = { idapp, userId }; @@ -51,47 +54,76 @@ module.exports.findAllIdApp = async function (idapp, userId) { module.exports.getCartByUserId = async function (uid, idapp) { try { - const Order = require('../models/order'); + const mycart = await getCart(uid, idapp); + if (!mycart) return null; - let query = { userId: uid, idapp }; - const mycart = await Cart.findOne(query).lean(); + await updateOrderDetails(mycart.items); + filterValidItems(mycart); - if (!!mycart) { - for (const idkey in mycart.items) { - try { - let idorder = mycart.items[idkey]._id.toString(); - let myorder = mycart.items[idkey].order; - if (!!myorder) { - idorder = mycart.items[idkey].order._id.toString(); - } - if (idorder) { - let myord = await Order.getTotalOrderById(idorder); - if (myord.length > 0) { - mycart.items[idkey].order = myord[0]; - } - } - } catch (e) { - console.log('err', e); - } - } - - mycart.newitems = [] - for (let item of mycart.items) { - if (item.order && item.order.hasOwnProperty('idapp') && (item.order.quantity > 0 || item.order.quantitypreordered > 0)) - mycart.newitems.push(item) - } - mycart.items = [...mycart.newitems] - mycart.newitems = [] - - return mycart; - } - return null; + return mycart; } catch (e) { console.log('getCartByUserId err', e); } - }; +module.exports.getCartCompletoByCartId = async function (id_cart, idapp) { + try { + const mycart = await getCartById(id_cart, idapp); + if (!mycart) return null; + + await updateOrderDetails(mycart.items); + filterValidItems(mycart); + + return mycart; + } catch (e) { + console.log('getCartByUserId err', e); + } +}; + +// Recupera il carrello per l'utente e l'app +async function getCart(uid, idapp) { + const query = { userId: uid, idapp }; + return await Cart.findOne(query).lean(); +} + +async function getCartById(id_cart, idapp) { + return await Cart.findOne({_id: id_cart}).lean(); +} + +// Aggiorna i dettagli dell'ordine per ogni articolo nel carrello +async function updateOrderDetails(items) { + const Order = require('../models/order'); + + for (const item of items) { + try { + const idorder = item.order ? item.order._id.toString() : item._id.toString(); + const myord = await Order.getTotalOrderById(idorder); + + if (myord.length > 0) { + item.order = myord[0]; + } + } catch (e) { + console.log('err', e); + } + } +} + +// Filtra solo gli articoli validi (con quantità > 0 o pre-ordinati) +function filterValidItems(mycart) { + mycart.newitems = []; + for (let item of mycart.items) { + if ( + item.order && + item.order.hasOwnProperty('idapp') && + (item.order.quantity > 0 || item.order.quantitypreordered > 0) + ) { + mycart.newitems.push(item); + } + } + mycart.items = [...mycart.newitems]; + mycart.newitems = []; +} + module.exports.updateCartByUserId = async function (userId, newCart) { const query = { userId: userId }; @@ -108,6 +140,7 @@ module.exports.updateCartByUserId = async function (userId, newCart) { items: newCart.items, totalQty: newCart.totalQty, totalPrice: newCart.totalPrice, + totalPriceIntero: newCart.totalPriceIntero, totalPriceCalc: newCart.totalPriceCalc, userId: userId, }, @@ -136,30 +169,40 @@ module.exports.updateCartByCartId = async function (cartId, newCart) { const totalQty = newCart.totalQty; const totalPrice = newCart.totalPrice; const totalPriceCalc = newCart.totalPriceCalc; + const totalPriceIntero = newCart.totalPriceIntero; const note = newCart.note; const codice_sconto = newCart.codice_sconto; + const descr_sconto = newCart.descr_sconto; const note_ordine_gas = newCart.note_ordine_gas; const modify_at = new Date(); - return await Cart.findOneAndUpdate({ _id: cartId }, { - $set: { - items, - totalPrice, - totalPriceCalc, - totalQty, - note, - codice_sconto, - note_ordine_gas, - modify_at: new Date(), + return await Cart.findOneAndUpdate( + { _id: cartId }, + { + $set: { + items, + totalPrice, + totalPriceCalc, + totalPriceIntero, + totalQty, + note, + codice_sconto, + descr_sconto, + note_ordine_gas, + modify_at: new Date(), + }, }, - }, { new: false }).lean().then((ris) => { - return ris; - }).catch(err => { - console.log('err', err); - return null; - }); - + { new: false } + ) + .lean() + .then((ris) => { + return ris; + }) + .catch((err) => { + console.log('err', err); + return null; + }); }; module.exports.deleteCartByCartId = async function (cartId) { @@ -170,8 +213,8 @@ module.exports.createCart = async function (newCart) { return await newCart.save(); }; - Cart.createIndexes() - .then(() => { }) - .catch((err) => { throw err; }); - + .then(() => {}) + .catch((err) => { + throw err; + }); diff --git a/src/server/models/order.js b/src/server/models/order.js index aa60f5d..b5b8fc5 100755 --- a/src/server/models/order.js +++ b/src/server/models/order.js @@ -259,12 +259,12 @@ module.exports.getOrderByID = function (id, callback) { Order.findById(id, callback); }; -module.exports.createOrder = async function (order) { +module.exports.createOrder = async function (order, codice_sconto) { try { if (order.idGasordine === '') { order.idGasordine = undefined; } - await Order.updateTotals(order); + await Order.updateTotals(order, codice_sconto); return await Order.create(order).then((ris) => { if (!!ris) return ris._id; return null; @@ -317,15 +317,27 @@ function applyNonCumulativeDiscounts(order, discounts) { while (qtadascontare > 0) { let scontoapplicato = null; + + // Filtriamo gli sconti non cumulativi for (const sconto of getNonCumulativeDiscounts(discounts)) { if (qtadascontare >= sconto.qta) { + // Se la quantità da scontare è maggiore o uguale alla quantità dello sconto, applica lo sconto completo scontoapplicato = { ...sconto, qtadascontare: sconto.qta }; + break; // Esci dal ciclo, abbiamo trovato lo sconto applicabile + } else if (qtadascontare > 0) { + // Se la quantità da scontare è inferiore allo sconto, applica solo la quantità disponibile + scontoapplicato = { ...sconto, qtadascontare: qtadascontare }; + qtadascontare = 0; // Abbiamo finito le quantità da scontare + break; } } + + // Se c'è uno sconto applicato, aggiungilo alla lista e riduci la quantità if (scontoapplicato && scontoapplicato.qtadascontare > 0) { sconti_da_applicare.push(scontoapplicato); qtadascontare -= scontoapplicato.qtadascontare; } else { + // Se non ci sono più sconti da applicare, la quantità rimasta è non scontata qtanonscontata = qtadascontare; qtadascontare = 0; } @@ -356,8 +368,10 @@ function calculateFullPrice(order) { return order.price * order.quantity + order.price * order.quantitypreordered; } -module.exports.updateTotals = async function (order) { +module.exports.updateTotals = async function (order, codice_sconto) { try { + const CartClass = require('../modules/Cart'); + if (!order) return; initOrderTotals(order); @@ -368,12 +382,8 @@ module.exports.updateTotals = async function (order) { let recscontisticheTrovate = []; - if (order?.codice_sconto) { - recscontisticheTrovate = await Scontistica.find({ - idapp: order.idapp, - code: order?.codice_sconto?.toUpperCase(), - applica: shared_consts.SCONTI_APPLICA.A_TUTTI, - }).lean(); + if (codice_sconto) { + recscontisticheTrovate = await CartClass.getRecSconto(order.idapp, codice_sconto, true); } // Se ha inserito una scontistica che esiste... @@ -390,6 +400,7 @@ module.exports.updateTotals = async function (order) { order.TotalPriceProductCalc += total; order.TotalPriceProduct += total; order.TotalPriceProductstr = parseFloat(order.TotalPriceProduct.toFixed(2)); + order.codice_sconto = codice_sconto; return order; } catch (e) { diff --git a/src/server/models/orderscart.js b/src/server/models/orderscart.js index eda9cf7..da5f722 100755 --- a/src/server/models/orderscart.js +++ b/src/server/models/orderscart.js @@ -33,6 +33,7 @@ const OrdersCartSchema = new Schema({ totalQtyPreordered: { type: Number, default: 0 }, totalPrice: { type: Number, default: 0 }, totalPriceCalc: { type: Number, default: 0 }, + totalPriceIntero: { type: Number, default: 0 }, department: { type: String, ref: 'Department' }, @@ -94,6 +95,9 @@ const OrdersCartSchema = new Schema({ codice_sconto: { type: String }, + descr_sconto: { + type: String + }, note_per_gestore: { type: String }, @@ -571,12 +575,14 @@ module.exports.updateOrdersCartById = async function(id, newOrdersCart, callback totalQtyPreordered: newOrdersCart.totalQtyPreordered, totalPrice: newOrdersCart.totalPrice, totalPriceCalc: newOrdersCart.totalPriceCalc ? newOrdersCart.totalPriceCalc : newOrdersCart.totalPrice, + totalPriceIntero: newOrdersCart.totalPriceIntero ? newOrdersCart.totalPriceIntero : newOrdersCart.totalPriceIntero, userId: userId, status: newOrdersCart.status, numorder: newOrdersCart.numorder, numord_pers: newOrdersCart.numord_pers, note: newOrdersCart.note, codice_sconto: newOrdersCart.codice_sconto, + descr_sconto: newOrdersCart.descr_sconto, modify_at: new Date(), } }, @@ -1090,9 +1096,11 @@ module.exports.updateOrdersCartTotals = async function (idOrdersCart, update) { $set: { totalPrice: newOrdersCart.totalPrice, totalPriceCalc: newOrdersCart.totalPriceCalc, + totalPriceIntero: newOrdersCart.totalPriceIntero, totalQty: newOrdersCart.totalQty, note: newOrdersCart.note, codice_sconto: newOrdersCart.codice_sconto, + descr_sconto: newOrdersCart.descr_sconto, modify_at: new Date(), }, } diff --git a/src/server/models/scontistica.js b/src/server/models/scontistica.js index aa8ea53..c26a612 100755 --- a/src/server/models/scontistica.js +++ b/src/server/models/scontistica.js @@ -16,6 +16,9 @@ const scontisticaSchema = new Schema({ idapp: { type: String, }, + attivo: { + type: Boolean, + }, code: { type: String, }, @@ -55,7 +58,7 @@ module.exports.executeQueryTable = function (idapp, params) { }; module.exports.findAllIdApp = async function (idapp) { - const myfind = { idapp }; + const myfind = { idapp, attivo: true }; return await Scontistica.find(myfind); }; diff --git a/src/server/modules/Cart.js b/src/server/modules/Cart.js index 6c4dec2..870de38 100755 --- a/src/server/modules/Cart.js +++ b/src/server/modules/Cart.js @@ -27,6 +27,7 @@ class Cart { this.totalQty = 0; this.totalPrice = 0; this.totalPriceCalc = 0; + this.totalPriceIntero = 0; for (const key in this.items) { const item = this.items[key]; @@ -37,6 +38,7 @@ class Cart { this.totalPrice = parseFloat(this.totalPrice.toFixed(2)); this.totalPriceCalc = parseFloat(this.totalPriceCalc.toFixed(2)); + this.totalPriceIntero = parseFloat(this.totalPriceIntero.toFixed(2)); } catch (e) { console.error("Errore durante l'aggiornamento del carrello:", e); } @@ -62,6 +64,7 @@ class Cart { mynewcart.modify_at = new Date(); mynewcart.note_ordine_gas = ''; mynewcart.codice_sconto = cart.codice_sconto; + mynewcart.descr_sconto = cart.descr_sconto; return mynewcart; } catch (e) { @@ -118,7 +121,7 @@ class Cart { myitem.order.modify_at = new Date(); - myitem.order = await Order.updateTotals(myitem.order); + myitem.order = await Order.updateTotals(myitem.order, this.codice_sconto); await this.updatecarttotals(false); await this.updateExtraOrder(); @@ -164,7 +167,7 @@ class Cart { myitem.order.quantity -= step; } } - myitem.order = await Order.updateTotals(myitem.order); + myitem.order = await Order.updateTotals(myitem.order, this.codice_sconto); await this.updatecarttotals(false); await this.updateExtraOrder(); @@ -182,7 +185,7 @@ class Cart { let ind = this.items.length; this.items[ind] = {}; this.items[ind].order = itemorder; - this.items[ind].order = Order.updateTotals(this.items[ind].order); + this.items[ind].order = await Order.updateTotals(this.items[ind].order, this.codice_sconto); await this.updatecarttotals(false); await this.updateExtraOrder(); @@ -203,11 +206,13 @@ class Cart { items: this.generateArray(), totalQty: this.totalQty, totalPriceCalc: this.totalPriceCalc, + totalPriceIntero: this.totalPriceIntero, totalPrice: this.totalPrice, userId: this.userId, department: this.department, note: this.note, codice_sconto: this.codice_sconto, + descr_sconto: this.descr_sconto, note_ordine_gas: this.note_ordine_gas, modify_at: this.modify_at, }); @@ -220,6 +225,10 @@ class Cart { async updateOrderTotals(order, updateCalcPrice) { order.TotalPriceProductCalc = 0; + + // PROVO A METTERE SEMPRE CHE MI RICALCOLA IL PREZZO ! + // updateCalcPrice = true; + if (updateCalcPrice) { order.TotalPriceProduct = 0; } @@ -227,14 +236,11 @@ class Cart { const qty = order.quantity + order.quantitypreordered; this.totalQty += qty; - let recscontisticheTrovate = await Scontistica.find({ - idapp: order.idapp, - code: this.codice_sconto?.toUpperCase(), - applica: shared_consts.SCONTI_APPLICA.A_TUTTI, - }).lean(); + const recscontisticheTrovate = await Cart.getRecSconto(this.idapp, this.codice_sconto, true); const scontiDaUsare = recscontisticheTrovate?.length ? recscontisticheTrovate : order.scontisticas || []; const priceCalc = this.calcolaPrezzoScontato(order, qty, scontiDaUsare); + const priceintero = this.calcolaPrezzoScontato(order, qty, []); order.TotalPriceProductCalc += priceCalc; @@ -243,8 +249,14 @@ class Cart { order.TotalPriceProductstr = parseFloat(order.TotalPriceProduct.toFixed(2)); } - this.totalPriceCalc += priceCalc; this.totalPrice += order.TotalPriceProduct; + this.totalPriceCalc += priceCalc; + this.totalPriceIntero += priceintero; + + // if (updateCalcPrice) { + // Aggiorna anche l'ordine associato + await Order.findOneAndUpdate({ _id: order._id }, { $set: order }, { new: false }); + // } } calcolaPrezzoScontato(order, qtyTotale, sconti = []) { @@ -259,11 +271,15 @@ class Cart { // Applica sconti non cumulativi while (qtaRimanente > 0) { let scontoScelto = null; - + let scontoVantaggioso = 0; for (const sconto of sconti.filter((s) => !s.cumulativo)) { - if (qtaRimanente >= s.qta) { - scontoScelto = { ...sconto, qtadascontare: s.qta }; - break; // prendi il primo valido (puoi migliorare scegliendo il più vantaggioso) + if (qtaRimanente >= sconto.qta) { + const scontoApplicato = + sconto.perc_sconto > 0 ? qtaRimanente * order.price * (1 - sconto.perc_sconto / 100) : sconto.price; + if (scontoApplicato > scontoVantaggioso) { + scontoVantaggioso = scontoApplicato; + scontoScelto = { ...sconto, qtadascontare: qtaRimanente }; + } } } @@ -330,6 +346,53 @@ class Cart { } return arr; } + + static async getRecSconto(idapp, codice_sconto, soloAttivi) { + const condSconto = { $regex: new RegExp(`^${codice_sconto}$`, 'i') }; + const query = { + idapp: idapp, + code: condSconto, + applica: shared_consts.SCONTI_APPLICA.A_TUTTI, + }; + + if (soloAttivi) { + query.attivo = true; + } + + const recscontisticheTrovate = await Scontistica.find(query).lean(); + + return recscontisticheTrovate; + } + + async updateCartIntoDB() { + const result = await cartModel.updateCartByUserId(this.userId, { + items: this.items, + totalQty: this.totalQty, + totalPrice: this.totalPrice, + totalPriceCalc: this.totalPriceCalc, + totalPriceIntero: this.totalPriceIntero, + userId: this.userId, + }); + + return result; + } + + async aggiornaCarrello() { + try { + // Rifai i calcoli ! + await this.updatecarttotals(true); + + await this.updateExtraOrder(); + + // Aggiorna i calcoli sul DB: + const mycart = await this.updateCartIntoDB(); + + // ritorna il carrello aggiornato ! + return await cartModel.getCartCompletoByCartId(mycart._id, this.idapp); + } catch (e) { + console.error("Errore durante l'aggiornamento del carrello:", e); + } + } } module.exports = Cart; diff --git a/src/server/router/cart_router.js b/src/server/router/cart_router.js index 6327f0c..99b9f88 100755 --- a/src/server/router/cart_router.js +++ b/src/server/router/cart_router.js @@ -55,14 +55,12 @@ async function aggiornaCarrello(mycartpar, userId, idapp) { if (!mycart) mycart = await Cart.getCartByUserId(userId, idapp); - if (!mycart) { - return null; - } + if (!mycart) return null; + + mycart = await Cart.getCartCompletoByCartId(mycart._id, idapp); let newCart = await CartClass.constructByCart(mycart); - // order = await Product.updateProductInOrder(order); - await newCart.updatecarttotals(true); - await newCart.updateExtraOrder(); + if (newCart) return newCart.aggiornaCarrello(); return newCart; } catch (e) { @@ -88,7 +86,7 @@ router.post('/:userId', authenticate, async function (req, res, next) { // const myorder = Order.getOrderByID(order._id); if (!addqty && !subqty && order) { - order._id = await Order.createOrder(order); + order._id = await Order.createOrder(order, mycart.codice_sconto); if (!order._id) { return res.send({ code: server_constants.RIS_CODE_ERR, cart: 0 }); } @@ -210,6 +208,7 @@ router.put('/:userId', authenticate, async function (req, res, next) { totalQty: newCart.totalQty, totalPrice: newCart.totalPrice, totalPriceCalc: newCart.totalPriceCalc, + totalPriceIntero: newCart.totalPriceIntero, userId: userId, }); res.json(result); @@ -223,6 +222,7 @@ router.put('/:userId', authenticate, async function (req, res, next) { totalQty: newCart.totalQty, totalPrice: newCart.totalPrice, totalPriceCalc: newCart.totalPriceCalc, + totalPriceIntero: newCart.totalPriceIntero, userId: userId, }; try { @@ -260,12 +260,15 @@ router.post('/:userId/app_sc', authenticate, async function (req, res, next) { let mycart = null; let valido = false; let errmsg = ''; + let recscontisticaTrovata = null; try { - let mycart = await Cart.findOne({ _id: cart_id }).lean(); + let mycart = await Cart.getCartCompletoByCartId(cart_id, idapp); + // let mycart = await Cart.findOne({ _id: cart_id }).lean(); if (codice_sconto === 'RIMUOVI') { mycart = await Cart.findOneAndUpdate({ _id: cart_id }, { $set: { codice_sconto: '' } }, { new: true }).lean(); + mycart = await aggiornaCarrello(mycart, userId, idapp); return res.send({ mycart, valido, msg: 'Codice Sconto rimosso', rimuovi: true }); } @@ -273,17 +276,16 @@ router.post('/:userId/app_sc', authenticate, async function (req, res, next) { await tools.attendiNSecondi(1); if (codice_sconto) { - const condSconto = { $regex: new RegExp(`^${codice_sconto}$`, 'i') }; - recscontisticheTrovate = await Scontistica.find({ - idapp: idapp, - code: condSconto, - applica: shared_consts.SCONTI_APPLICA.A_TUTTI, - }).lean(); - + const recscontisticheTrovate = await CartClass.getRecSconto(idapp, codice_sconto, true); if (recscontisticheTrovate && recscontisticheTrovate.length > 0) { + recscontisticaTrovata = recscontisticheTrovate[0]; + } + + if (recscontisticaTrovata) { if (mycart.codice_sconto !== codice_sconto) { mycart.codice_sconto = codice_sconto; - await Cart.updateOne({ _id: cart_id }, { $set: { codice_sconto: codice_sconto } }); + mycart.descr_sconto = recscontisticaTrovata.description; + await Cart.updateOne({ _id: cart_id }, { $set: { codice_sconto, descr_sconto: mycart.descr_sconto } }); } valido = true; @@ -293,7 +295,7 @@ router.post('/:userId/app_sc', authenticate, async function (req, res, next) { } } - return res.send({ mycart, valido, errmsg, recsconto: recscontisticheTrovate }); + return res.send({ mycart, valido, errmsg, recsconto: recscontisticaTrovata }); } catch (e) { console.error('Err Applica Sconto', e); return res.send({ valido: false, mycart: null, errmsg: e.message }); @@ -321,11 +323,13 @@ async function createOrUpdateOrderFromCart({ idapp, cart, userId, status, note } totalQty: cart.totalQty, totalPrice: cart.totalPrice, totalPriceCalc: cart.totalPriceCalc, + totalPriceIntero: cart.totalPriceIntero, note_ordine_gas: cart.note_ordine_gas, userId, status, note, codice_sconto: cart.codice_sconto, + descr_sconto: cart.descr_sconto, numorder, numord_pers, created_at: new Date(), @@ -360,10 +364,12 @@ async function handleCheckout({ myorderCart, mycart, userId, idapp, req, options //POST cart router.post('/:userId/createorderscart', authenticate, async function (req, res) { - const { idapp, cart_id, status, note, options } = req.body; - const userId = req.params.userId; - try { + const { idapp, cart_id, status, note, options } = req.body; + const userId = req.params.userId; + + // console.log('createorderscart', cart_id); + const mycart = await getCartById(cart_id); if (!mycart) { return res.send({ @@ -401,6 +407,8 @@ router.post('/:userId/createorderscart', authenticate, async function (req, res) } } + // console.log('SEND OK', statusOrderCart); + return res.send({ code: server_constants.RIS_CODE_OK, status: statusOrderCart,