0

Help please!! During the execution of both await calls in createPayment() and in stripe API charges.create() the execution is made randomly not in order as expected. My code enters into createPayment() then goes back to const {payment} = await createPayment(program, user, toUser, paymentToken); then goes inside createPayment() again, it makes no sense!!!!

exports.subscribeToProgram = async function(req,res){
try {
    const {paymentToken, program} = req.body;
    const user = res.locals.user;

    //Find program to be subscribed
    const foundProgram = await Program.findOne({_id: program._id}).populate('user').exec();
    const toUser = foundProgram.user.id;
    if(toUser === user.id)
    {
        return res.status(422).send({errors: [{title: 'Invalid User!', detail: 'You can\'t subscribe to your own program!'}]})
    }

    // Create Payment
    // THIS PART IS NOT WORKING PROPERLY!!!! 
    const {payment} = await createPayment(program, user, toUser, paymentToken);
    const charge = await stripe.charges.create({
        amount: foundProgram.price * 100 * CUSTOMER_SHARE,
        currency: 'usd',
        description: 'Example charge',
        source: payment.tokenId,
    });

    //If payment was created successfully
    if(payment && charge)
    {
        //Create subscription
        //Save created subscription
        //Append a booking to bookings array
    }else{
        return res.status(422).send({errors: [{title: 'Payment declined!', detail: err }]})
    }
} catch (err) {
    console.log(err)
    return res.status(422).send(err);  
}
}

CreatePayment()

async function createPayment(program, user, toUser, token){
//Get user from booking
const userToCharge  = user;

//Create customer from stripe serices
const customer = await stripe.customers.create({
    source: token.id,
    email: userToCharge.email
});

//If custome exist
if(customer)
{
    //Update user
    User.updateOne({_id: userToCharge.id}, {$set: {stripeCustomerId: customer.id}}, () => {});

    //Create Payment
    const payment = new Payment({
        fromUser: userToCharge,
        toUser, //Destructurize value
        fromStripeCustomerId: customer.id,
        program,
        tokenId: token.id,
        amount: program.price * 100 * CUSTOMER_SHARE // 80% of value if for 
    });

    //Save payment
    try 
    {
        const savedPayment = await payment.save();
        return {payment: savedPayment}
    } 
    catch (error) 
    {
        return {err: err.message};
    }
}else{
    return { err: 'Cannot process Payment!'}
}

}

  • Does `createPayment()` return a promise? Does `stripe.charges.create()` return a promise? – jfriend00 Jan 25 '19 at 03:39
  • `stripe.charges.create()` does returns a promise. `createPayment()` does not, it returns an object, however inside that function I am calling `await stripe.customer.create()` which returns a promise too – Rodrigo Villalobos Jan 25 '19 at 03:42
  • Add to @jfriend00, also it is possible you are calling `subscribeToProgram` multiple times without `await` in the parent function. – wsw Jan 25 '19 at 03:43
  • its better if you could share the code of parent call and `createPayment` function – wsw Jan 25 '19 at 03:43
  • 1
    Why are you using `await` with `createPayment()`? `await` only does something useful when you call it on a promise. If there are async things in `createPayment()` then you need to fix it to return a promise that is resolved when those async things are done. – jfriend00 Jan 25 '19 at 03:44
  • It does make sense because something is calling `subscribeToProgram` and once execution reaches to call `createPayment`, it does not wait for it to finish because it is async and leaves the `subscribeToProgram` method. It enters `createPayment` again because `subscribeToProgram` method is called again by some code. – CodingYoshi Jan 25 '19 at 03:44
  • You need to study how `async` and `await` work. – CodingYoshi Jan 25 '19 at 03:46
  • I just edited the question with createPayment() function. I don't get Promises at all, asynchronous programming is just confusing me more and more. – Rodrigo Villalobos Jan 25 '19 at 03:48
  • 1
    Your issue with `createPayment()` is a dup of [How do I Return the Response from an Asynchronous Call](https://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call/14220323#14220323) – jfriend00 Jan 25 '19 at 03:54
  • 2
    Read the post jfriend00 cited: [How do I return the response from an asynchronous call?](https://stackoverflow.com/questions/14220321) . Then read [this](https://codeburst.io/javascript-learn-promises-f1eaa00c5461) and [this](https://codeburst.io/javascript-es-2017-learn-async-await-by-example-48acc58bad65). Rinse and repeat as needed :) – paulsm4 Jan 25 '19 at 03:57
  • 1
    @jfriend00 `createPayment` being `async` means it will implicitly return a Promise, one doesn't need to be explicitly returned. The issue looks like there is another async call (`User.updateOne`) that isn't being awaited. – James Jan 25 '19 at 03:59
  • Thanks for all the answers! I will try to add all of these, I also started reading the documentation posted by you @paulsm4 thanks for that. I will update the question as needed. – Rodrigo Villalobos Jan 25 '19 at 04:08
  • @James - The promise it returns needs to be resolved only when all the async operations inside the function are done. – jfriend00 Jan 25 '19 at 05:21
  • @jfriend00 correct, the OP had just missed one await call inside `createPayment`. – James Jan 25 '19 at 09:09

1 Answers1

2

Two issues, both inside createPayment

  1. You need to await the User.updateOne call as this is also asynchronous
  2. In the event of no customer being found, you will still need to return an object, otherwise your destructuring will throw an error.
James
  • 80,725
  • 18
  • 167
  • 237
  • Thank you so much for your answer. It is the third time I am programming asynchronous code so I am still getting used to it. I will update my code as you suggested. Thanks :) – Rodrigo Villalobos Jan 25 '19 at 04:09
  • @RodrigoVillalobos no problem, not sure if you edited `createPayment` or it was hidden by the overflow on the code but I see you *are* returning an object for no. 2. – James Jan 25 '19 at 04:15
  • You were right James, I was missing an await call inside createPayment, I also added an extra await call for charging the user inside the same function and it works perfectly! also Thanks to the resources that @paulsm4 posted I was able to understand what was happening – Rodrigo Villalobos Jan 25 '19 at 05:58