0

I'm trying to pass req.session.cart with updated values for prod.quantity and prod.qtyCount to the shoppingCart field in order.save()

but the problem is that an order will save with the default values for quantity and qtyCount even though I'm doing cartProducts[i].prod.quantity = productDbQty; and cartProducts[i].prod.qtyCount = getQtyArr;

what's strange is that if i do a second order, that second order will reflect the quantities for the first order. So basically if the default quantity is 100 and the new quantity passed in by the user is 50 the first order will save with the default 100 for quantity. The second order no matter what is passed in for quantity will then be saved with 50 which should have been the quantity of order 1.

in my model

// function to get an array of the quantity
module.exports.getProductCount = (qty) => {
    var productCountArr = [];  
    for (var i=0; i <= qty; i++) {
        productCountArr.push(i);
    };
    return productCountArr;
};

UPDATE I added a bunch of console.log(num) statements so I could see the order of execution that happens. It is going from step 1, 2, 3 as expected but then jumps to 9, 10, 11 which makes the order save with the default quantity. Then it goes back to step 4 where the order values are being updated. So it's saving the order too soon, before the quantity updates happen. Not sure how to fix it though.

For some reason it's skipping the Product.find() then saving the order then going back to find the product to update it but by then the order has already been saved.

output that shows the order of execution from the console.log() statements.

1
2
3
9
10
11
4
5
6
7
8

in my controller

  // save an order to the database
module.exports.saveOrder = 
    (req, res, next) => {

    // if there is a current user logged in
    if (req.user) {
        // // create a new order
        // let order = new Order({
        //     // get the shopping cart from the session
        //     shoppingCart: req.session.cart, 
        //     // get the user id from passport
        //     userId: req.user.id,
        //     orderTotal: Number(req.session.cart.cartTotal),
        //     orderQuantity: Number(req.session.cart.cartQuantity)
        // });

        console.log('1');

        // get the shopping cart object from the session
        // var cart = req.session.cart;
        var cart = new Cart(req.session.cart);

        // get the products from the session cart
        var products = cart.products;

        console.log('2');

        // loop through the products in the cart
        for (var id in products) {

            // quantity the user selected for the product in their session cart
            prodSessionCartQty = Number(products[id].quantity);

            console.log('3');

            // get the product model quantity and subtract
            Product.findById(id, (err, prod) => {
                if (err)
                    console.log("Error Selecting : %s ", err);
                if (!prod)
                    return res.render('404');

                    // the number of products in the product database collection
                    var productDbQty = Number(prod.quantity);

                    console.log('4');

                    // if their are enough products in the database
                    if (productDbQty >= prodSessionCartQty) {
                        // subtract the product session cart quantity 
                        productDbQty = productDbQty - prodSessionCartQty;
                        prod.quantity = productDbQty;  // store the new quantity

                        // update array of quantity count in product collection
                        var qty = prod.quantity;
                        var getQtyArr = ProductDb.getProductCount(qty);
                        prod.qtyCount = getQtyArr;       

                        console.log('5');

                        // get the products in the shopping cart
                        var cartProducts = cart.products;

                        // array to hold the products of an order
                        var productsArray = [];

                        // loop through the products in the cart
                        for (var i in cartProducts) {

                            console.log('6');

                            // update quantities for prods in order collection
                            cartProducts[i].prod.quantity = productDbQty;
                            cartProducts[i].prod.qtyCount = getQtyArr;

                            // push the products into an array
                            productsArray.push(cartProducts[i]);
                        };
                        // store the updated prod quantities back in the cart object
                        cart.products = productsArray;
                        req.session.cart = cart;

                        console.log('7');

                        // save the new updated quantity to the database
                        prod.save((err, updatedProd) => {

                            console.log('8');

                            console.log(err, updatedProd);
                            if (err) {
                                res.status(500).send('save failed');
                                return;
                            }
                        });

                    }//if
            }); // Product   
        } //for

        console.log('9');

        // create a new order
        let order = new Order({
            // get the shopping cart from the session
            shoppingCart: req.session.cart,
            // get the user id from passport
            userId: req.user.id,
            orderTotal: Number(req.session.cart.cartTotal),
            orderQuantity: Number(req.session.cart.cartQuantity)
        });
        console.log('10');

        order.save((err, resultCallback) => {
            console.log('11');

            // if an error occurs during checkout
            if (err) {
                console.log("Error Selecting : %s ", err);
                req.flash('errorMessage', 'Error: checkout failed!')
                res.redirect('/orders/checkout');
            }
            // else no error while checking out
            else {
                // set cart back to null so a new order can be made
                req.session.cart = null;
                req.flash('successMessage', 'Your order has been placed')
                res.redirect('/products');                
            }
        });

    // else no logged in user
    } else {
        // redirect user and send login message
        req.flash('errorMessage', 'Please login first!');
        res.redirect('/login');
    }
};
random_user_0891
  • 1,863
  • 3
  • 15
  • 39
  • In JavaScript, asynchronous code doesn't get to execute until all synchronous code is finished. – nem035 Mar 03 '19 at 17:25
  • In your case, this means that the callback passed into `Product.findById(thisCallback)` or `order.save()` won't be called until all other code around them are finished. – nem035 Mar 03 '19 at 17:26

1 Answers1

0

This line const getQtyArr = ProductDb.getProductCount(qty); is probably a promise. If that is the case the value isn't getting returned until after the loop has run. Which would explain why a following order would see the previous value. Using async/await and awaiting for this to resolve will probably solve your problem.

Dez
  • 5,702
  • 8
  • 42
  • 51
amcnutt
  • 59
  • 2
  • I'm new to node I just read up on promises, I'm not using one. I added the code for the getProductCount function to the question. thanks. – random_user_0891 Mar 03 '19 at 02:07