WEBVTT

00:00.230 --> 00:00.740
Okay.

00:00.740 --> 00:03.170
Now let's take a look at populating these two methods.

00:03.170 --> 00:06.500
We need to handle what happens when the intent failed.

00:06.530 --> 00:14.000
Now we're creating the order before we know if the payment has succeeded or the payment did not succeed.

00:14.000 --> 00:18.740
And when we create an order, we do things like reduce the quantity in stock.

00:18.770 --> 00:24.140
And we also need to think about updating our order status to say that the payment failed as well.

00:24.170 --> 00:30.170
So inside the handle payment failed method, we'll first need to get hold of our order.

00:30.200 --> 00:37.430
So we'll specify var order equals await and context dot orders.

00:38.090 --> 00:44.120
And we're going to need to include our items because we need to reverse effectively what the consequences

00:44.120 --> 00:47.990
of creating an order did such as reducing stock quantity.

00:47.990 --> 00:51.020
So we're going to include the order items.

00:52.070 --> 00:57.800
And then we need to get hold of the order based on the payment intent ID.

00:58.070 --> 01:06.000
So we're going to use first or default async and we'll use x goes to x dot payment intent ID that's

01:06.000 --> 01:09.330
equal to the intent.id.

01:09.660 --> 01:14.100
And we want to make sure we have this order before we go any further.

01:14.100 --> 01:17.370
So what we can use is the double question mark.

01:17.370 --> 01:22.380
So if this returns null then we execute the code to the right of this.

01:22.380 --> 01:29.700
And we're going to throw a new exception and just say order not found as we do not want to proceed any

01:29.700 --> 01:35.670
further if we do not have the order, because we need to affect what's going on inside our database

01:35.670 --> 01:36.390
here.

01:36.540 --> 01:43.530
So on the basis that we do have the order, then we're going to loop over each item in the order items,

01:43.560 --> 01:50.730
get hold of the product from our database, and we're going to add back in the quantity of that item

01:50.730 --> 01:51.450
in stock.

01:51.450 --> 01:55.710
So we'll use a foreach loop and we'll get the snippet from that.

01:55.710 --> 02:00.930
And we'll say var item in order dot order items.

02:01.950 --> 02:04.010
And then we need to get hold of the product.

02:04.040 --> 02:09.740
So we'll save our product item equals await and context dot products.

02:10.160 --> 02:17.180
And then we're going to use the find async method and pass in the item the item ordered dot product

02:17.180 --> 02:17.690
id.

02:19.130 --> 02:22.310
And once again we need to make sure we have this product.

02:22.310 --> 02:24.350
So we'll use the double question mark again.

02:24.350 --> 02:33.680
And if we do not have the products then we're going to throw a new exception and say problem updating

02:33.710 --> 02:35.750
order stock.

02:35.780 --> 02:41.480
And below this we'll just specify a product item dot quantity and stock.

02:41.690 --> 02:43.400
And we're adding this back in.

02:43.400 --> 02:47.180
So it's going to be plus equals item dot quantity.

02:47.960 --> 02:52.580
And then below the for each loop we can set the order status.

02:52.580 --> 03:01.190
So we'll specify order auto order status equals order status and say payment failed.

03:01.220 --> 03:04.670
And we'll need to save these changes into our database.

03:04.670 --> 03:09.020
So we'll specify a weight context and save changes.

03:09.050 --> 03:10.130
Async.

03:10.430 --> 03:19.970
So the idea being that inside our method here after we call the await handle payment intent failed,

03:20.000 --> 03:22.040
we still return okay to stripe.

03:22.040 --> 03:23.510
Because stripe has done its job.

03:23.510 --> 03:25.550
It sent us the payment intent.

03:25.820 --> 03:30.920
And we've updated our database based on the failure of that payment.

03:30.950 --> 03:33.470
So even though the payment failed, we're still returning.

03:33.500 --> 03:33.890
Okay.

03:33.920 --> 03:35.960
To stripe on this.

03:35.960 --> 03:38.870
And let's update the other method inside here.

03:38.870 --> 03:40.730
The payment intent succeeded.

03:41.030 --> 03:46.700
So once again inside this method we will still need to go out and get our order.

03:46.730 --> 03:51.020
So let's just copy the code we used here inside the handle.

03:51.050 --> 03:54.380
Payment intent failed and we'll just paste it inside this one.

03:54.380 --> 03:58.310
And then we can specify the order order status.

03:59.060 --> 04:05.060
And we can set it to order status dot payment received which is true.

04:05.060 --> 04:06.810
The payment has been received.

04:06.810 --> 04:15.060
But and there is a but here because let's give you a scenario which one of the students from the previous

04:15.060 --> 04:17.130
version of this course brought up.

04:17.280 --> 04:25.980
Supposing I went to my catalog inside here and I added something to the carts, and then I went to the

04:25.980 --> 04:26.700
baskets.

04:26.700 --> 04:31.650
And then if I click checkout, then hot reloads.

04:32.220 --> 04:35.970
So I have to go back and restart the API server, make sure there's no errors inside here.

04:35.970 --> 04:44.490
I'm just going to go to the API tab and just control R and just control R to restart the API server.

04:44.790 --> 04:54.900
And then I'll be able to explain with more clarity about the scenario I'm about to talk about once it

04:54.900 --> 04:56.730
does actually restart.

04:57.000 --> 04:57.420
Okay.

04:57.450 --> 04:59.790
So let's go back to the browser.

04:59.820 --> 05:05.370
I'll go back to the basket, I'll click checkout again and then we get taken to our checkout.

05:05.400 --> 05:10.090
Now at this point the payment intent has been created.

05:10.450 --> 05:13.810
But does that mean I cannot be sneaky?

05:13.810 --> 05:18.580
And right click the catalog and open up my application in a new tab.

05:18.820 --> 05:23.530
Now I've got access to the catalog and I can start adding more things to the cards.

05:23.530 --> 05:25.930
In this browser tab I've got two items.

05:25.930 --> 05:33.550
In this browser tab, I've got one item of $200 and the payment intent is $200.

05:33.580 --> 05:36.550
And I could check out and I could pay $200.

05:36.550 --> 05:40.930
But what I have here is two items in this basket.

05:41.560 --> 05:48.070
That's $350, and that's what's going to be saved on our basket on our API server.

05:48.070 --> 05:55.510
So there'd be a mismatch between what the user pays versus what's contained inside our order.

05:55.510 --> 06:01.390
So we're going to need to checklist effectively because we can't rely on our users to be well-behaved

06:01.390 --> 06:03.700
and not do something sneaky like this.

06:03.700 --> 06:05.680
And there's a few different approaches to this.

06:05.680 --> 06:07.780
We could lock the basket on checkout.

06:07.780 --> 06:12.160
We could add a property to our basket and say check out started at this time.

06:12.160 --> 06:18.040
And then we could give the user, let's say, 15 minutes to complete the checkout and not allow any

06:18.040 --> 06:22.360
new items to be added to that basket whilst the checkout is effectively locked.

06:22.390 --> 06:27.700
That would be one approach, and that would be a better user experience for those sneaky users that

06:27.700 --> 06:29.590
are trying to beat our system.

06:29.590 --> 06:34.780
The way that we'll approach it is we'll check the amount of the order and compare it to the payment

06:34.780 --> 06:35.710
intent.

06:35.740 --> 06:41.890
If there's a mismatch, then we're going to have a status of payment mismatch and it won't be a successful

06:41.890 --> 06:42.400
order.

06:42.400 --> 06:44.650
And then we could stop the order at that point.

06:44.680 --> 06:48.070
Now the user would still have paid and the payment would have been accepted.

06:48.070 --> 06:52.060
So that means we'd need to issue a refund, etc. via stripe.

06:52.060 --> 06:54.610
But we're really talking about edge cases here.

06:54.640 --> 07:00.160
We're talking about a user that's being sneaky on purpose, that enters a checkout and then opens the

07:00.160 --> 07:03.130
application in a new tab to be sneaky.

07:03.160 --> 07:08.740
So I'm not too worried about that user that's being sneaky for this demonstration on this training course,

07:08.740 --> 07:13.160
I just really wanted to point out that there is the possibility, the way that we're processing the

07:13.160 --> 07:20.390
payments and when we're creating one thing after another, there's potential for misbehaviour to occur.

07:20.420 --> 07:28.640
And this is one of the misbehaviors that could occur that we can catch by checking the amounts of the

07:28.640 --> 07:31.850
payment intent versus the amount of the order.

07:31.850 --> 07:34.250
So that's what we'll do inside here.

07:34.250 --> 07:45.260
And we'll check to see if the order dot get total is not equal to the intent dot amount.

07:45.470 --> 07:50.360
And if that is the case then we're going to set the order.

07:51.230 --> 07:53.540
In fact let's do this inside curly brackets.

07:53.570 --> 08:00.710
Just to be completely clear, we're going to set the order order status to be equal to.

08:00.740 --> 08:06.530
And in fact let's create another status in our order status enum.

08:06.830 --> 08:11.660
And we'll also have a payment mismatch.

08:13.020 --> 08:22.500
To clarify that the order doesn't match the payment intent, and we'll set that to order status of payment

08:22.500 --> 08:23.700
mismatch.

08:23.700 --> 08:26.220
And then we'll have an else condition.

08:28.440 --> 08:32.790
Which goes below the if statement and open curly brackets here.

08:32.790 --> 08:36.810
And then we'll set the order to payment received for this one.

08:36.810 --> 08:43.500
So at this stage as well we'll take the opportunity to remove the basket from our database.

08:43.530 --> 08:48.240
At the same time there's no more need to have that basket stored in our database at this stage.

08:48.240 --> 08:57.000
So we'll get a hold of our baskets and we'll set this equal to await and context baskets first or default

08:57.030 --> 08:57.990
async.

08:57.990 --> 09:02.040
And we'll use our payment intent ID to get hold of this.

09:02.070 --> 09:07.050
So x dot payment intent ID that's equal to the intent.id.

09:09.120 --> 09:11.460
And let's just move this down.

09:11.460 --> 09:16.030
And then we'll check to make sure the basket is not equal to null.

09:17.200 --> 09:23.830
And if that is the case, we'll say context dot baskets dot remove and pass in the baskets.

09:24.160 --> 09:26.680
And then below this we can save our changes.

09:26.680 --> 09:32.530
So we'll just use await context and save changes async.

09:33.430 --> 09:38.350
And we're not returning anything from this that's being handled in the method above.

09:38.680 --> 09:44.230
So that's our intent succeeded and intent failed handled.

09:44.230 --> 09:46.420
And there's another small adjustment we need to make.

09:46.420 --> 09:53.290
Because if the payment does fail, then we still want our user to be able to update the order at a future

09:53.290 --> 09:54.070
point.

09:54.430 --> 10:00.250
So we'll need to go back to our orders controller so that we can accommodate an order being updated,

10:00.250 --> 10:02.770
as well as an order being created.

10:02.770 --> 10:06.250
So we'll go to our orders controller.

10:06.430 --> 10:11.770
And inside here at the moment we're only accommodating a new order.

10:11.770 --> 10:15.650
So after we've created the subtotal and delivery fee.

10:15.680 --> 10:21.140
We will then interrogate our database to see if we do have an order in our database.

10:21.140 --> 10:28.250
So above the var order I'll say var order equals await context dot orders.

10:28.790 --> 10:31.940
And we'll include the order items.

10:33.740 --> 10:37.160
And we'll specify first or default async.

10:37.160 --> 10:39.800
And we'll use the payment intent ID.

10:42.050 --> 10:46.550
Equal to the basket dot payment intent ID.

10:47.360 --> 10:50.540
And then we can check to see if we have this order.

10:50.900 --> 10:52.040
So.

10:52.070 --> 10:58.820
So just above where I've got var order that's currently in an error I'll say if the order is equal to

10:58.850 --> 11:02.990
null then we will be creating a new order.

11:02.990 --> 11:08.300
So I'll cut this code and paste it inside the if statement.

11:09.590 --> 11:14.150
And we don't need the var because we've got the order declared above.

11:14.660 --> 11:23.100
And then we can create the new order, and we'll also move up our context, add orders into the if statement

11:23.100 --> 11:28.740
as well, and below the if statement we'll have the else statements.

11:30.240 --> 11:33.960
So that means we're effectively updating an existing order.

11:34.050 --> 11:36.300
And they could have changed the order items.

11:36.300 --> 11:42.000
So we'll specify the order order items is equal to the items.

11:42.660 --> 11:47.310
Otherwise everything's going to stay the same inside here.

11:47.310 --> 11:50.370
And I've got the basket remove code inside here.

11:50.370 --> 11:54.090
But we're handling this in our stripe webhook which is a better place to do this.

11:54.090 --> 11:57.450
And we're also deleting the cookie from the client side as well.

11:57.450 --> 12:04.350
So we don't need either of these two lines of code inside here anymore as they're just duplicating things

12:04.350 --> 12:06.600
that are already happening anyway.

12:06.690 --> 12:10.320
And that's our webhook code created now.

12:10.320 --> 12:16.170
So our next step is to take a look and see how we can use this webhook with stripe.

12:16.170 --> 12:18.480
And we'll take a look at that next.
