This episode is for members only

Sign up to access "Build a File Marketplace with Laravel" right now.

Get started
Already a member? Sign in to continue
Playing
28. Storing product sales

Episodes

0%
Your progress
  • Total: 3h 32m
  • Played: 0m
  • Remaining: 3h 32m
Join or sign in to track your progress

Transcript

00:00
We're now going to work on storing a sale whenever the checkout gets completed. So we're going to go over to our terminal
00:07
here and just create out a model called sale. And of course, we'll create a migration alongside of that as well. So we'll head straight over to the create sales table migration, and we'll fill in some of the things that we think we'll need in here.
00:20
So the first thing and the most obvious is that we'll need a foreign ID back to the product that has actually been purchased. We're going to go ahead and constrain this in the database as normal. We're actually also going to set this to nullable.
00:34
And for the on delete, we're not going to cascade. We're actually going to set this to null. Now, the reason that we want to do this is even if products get deleted, we want to keep a record of all of the sales within an application.
00:47
That just makes it a little bit easier for us. Just in case things go missing, it's going to be a lot easier to have a record of everything that we have sold. So down here, the next thing that we want to implement is a token,
00:59
and this is going to be a randomly generated token that we can send with a link via email, and that's just going to make it a little bit more secure so people can't go in and just guess different sales and download products that they haven't actually purchased.
01:13
The next thing is going to be the email address of the user who has purchased this. So let's go ahead and create a string out with email. We're then going to have an integer in here or an unsigned integer in here,
01:24
which is going to represent the price. Now, we might be thinking, well, why are we storing the price if we know this on the product? Well, this will be the price at the time
01:32
of sale and not the price of the product as it currently is. This might differ based on changing sale prices, so we always want to log here the price that we actually purchased out. The next thing here is going to be a string that's just going to be the Stripe
01:48
session ID, and that will allow us to hook back in and find out more details from Stripe about this sale if we need to at a later date. So finally, we're going to implement a timestamp here and we're going to create out a paid at column, which can be nullable.
02:06
Now, the reason we're doing this is if we go back to our Stripe webhook controller, if at a later time the payment doesn't come in straight away, but the sale gets created, we're going to have to mark this under here as paid once the payment actually comes through in potentially weeks time.
02:22
Again, we're going to be marking this straight away, but we're going to leave this open to be a date just so we can keep it as open as possible. OK, so we're pretty much done with that. Let's go over and migrate our changes here.
02:35
And of course, we're going to head over to the product model because we want to set up a relationship here to say that this product has many sales. So again, a really simple relationship in here.
02:45
We have many sales, of course, for a particular product. So let's add the sale model into that. Great. OK, so now we're going to head over to the sale model itself and of course add
02:56
in things like the fillable fields, but what we also want to do is automatically generate this token whenever a model is created. So let's start with our fillable fields here. And we know that we're going to have an email.
03:10
This is going to be when it's paid the Stripe session ID. And the price. And finally, the token. So that's all we need in there.
03:20
What we can also do at this point is go ahead and create out a cast for the paid out date in case we need to format that using carbon. So to do this, we're going to go ahead and say paid out when we get it needs to be cast to a date time.
03:33
That means that when we get this out of the database, we can use any carbon methods on it directly as a carbon object. OK, so once this model gets created, we want to automatically assign a random
03:46
token to this using Laravel's string helper. So to do this, we're going to go ahead and create out a. Static booted method in here, what this will do is it will run when this model is booted and now we can
04:01
attach eloquent events to this, so when this is being created, not when it's being persisted in the database, we want to go ahead and run this closure, which is going to take the sale in here and then assign the token to it. So this is going to be something randomly generated.
04:18
So when we say something like product sales and create, that's going to go ahead and fire this before it gets persisted to the database and assign the token so that can get stored. Now, for the token itself, we want to use our string helper.
04:36
We want to use random and we'll choose maybe one to eight. So this will generate a 128 random string which we can use in our URLs. OK, so we've done that. We'll come back to that later if we need to.
04:48
Another thing that we want to do for the product is hook this back to a sale or in this case, hook this back to a product because the sale belongs to a product. So we're going to go ahead and return this belongs to and it belongs to our product. So if we're referencing the sale on its own,
05:06
we know that we can get the product that this particularly relates to. Now, the final thing that we want to do, because we are working, if we just open up that migration again with a price here, we want a way to get this price out of this model as a money object.
05:23
Now, we already saw that earlier within the product itself. So if we just head over here to this price attribute, we have our accessor and our mutator. So we're going to go ahead and pull this over to here.
05:37
And in actual fact, the only thing we really need in here is the accessor because we're not going to be storing this price in dollars. We're going to use the absolute value
05:47
that comes back from Stripe, which is always in cents. So let's put in attribute and we'll just implement the accessor here for now. OK, so that's pretty much it for our sale setup. Now, what we're going to do is go ahead
06:00
and actually store this sale once that Webhook comes in. So let's go over to our Stripe Webhook controller. And inside of here, this is, of course, where we need to now log that sale. Now, if we remember from earlier, when we went ahead and set up our checkout,
06:17
we went ahead and passed in the product ID under metadata. We did that because when the Webhook comes back, it will actually contain this metadata so we know which product this particular sale is for. So what we can do is go ahead and maybe create our sale variable here,
06:33
find the product so we can say find or fail, find it by a particular ID and then go ahead and create a sale for that product that we get the Webhook back for. So let's pull the product model in. How do we find the ID here?
06:49
Well, we can reference our Laravel log if we log out the Stripe Webhook. Let's just bring back what we had before and let's look for product ID. So there we go. This lives on the metadata here. You'll need to figure this out by going
07:03
through this and finding out where things live within the nest. But for us, this is payload and we have a data wrapper here. We then have a object wrapper. And then we have that metadata that we just looked at,
07:18
so we can just find that product by the product ID and then go ahead and create a sale out, so let's fill in each of the details that we need to in here. So we need to fill in the email. We need the Stripe Connect ID, or in this case, it's called Stripe Session ID.
07:34
Sorry. And we want to fill in the price of this that it was sold at and we want to fill in paid at, which we can add a condition on because at this point it may not be paid. So for the email, we've got payload.
07:48
And once again, we go into data, we go into object. And this contains a customer details object, and we have the email in there. Again, we can come over to our Laravel log, look for customer details.
08:03
And we'll see all of the customers information in here. Now, that's not the one we want. That's not within that object. So let's look for email here.
08:12
And there we go. So that's the one we want under customer details and email. OK, so we've got that. The Stripe Session ID, again, is within payload, data and object,
08:24
and it is just the idea of this object. So for the price, again, we've got payload object in here. It looks a little bit messy. We could probably refactor this later, but we've got the amount subtotal in here.
08:38
Again, let's head over to our log amount subtotal. And that's 999 under this object. So we know that that's in cents. So we don't need to mutate that in any
08:49
way before we put it back into the database. So with paid out, once again, we've got payload object and then we've got payment status. Let's just take a look at this over in our Laravel log. So let's search here for payment status.
09:05
And you can see that that says paid. So if that wasn't paid, we wouldn't want to fill in the date here. So we're going to just quickly compare this to the string paid. And if it is, we're just going to new up a new carbon object that's going to put
09:18
the timestamp into the database. Otherwise, we're going to set this to null because remember, that can be null. OK, so now that we've done this, we are pretty much ready to go through the process of checking out again
09:30
and just seeing our sale get logged in the database, which, of course, we can use to then email the customer. We can show this on our dashboard and all that other stuff. OK, so let's clear out our Laravel log just in case we have any errors here.
09:42
And of course, we can keep an eye over on Stripe as well. OK, so I filled all this information in. Let's hit pay. And then really all we need to do is wait
09:51
for that webhook to come in and create that sale out for us. So let's come over to the database, give this a refresh. And there we go. Our webhook has fired. It's hit our application.
10:01
We've had a token generated, a unique token generated for this sale. We've got the email address, the price, the date that it was paid and the session ID as well. So we are now successfully logging every sale we make.
34 episodes3 hrs 32 mins

Overview

Build a marketplace where sellers can list and sell files, while we take a cut of each sale using Stripe Connect.

We'll cover onboarding users with Stripe Connect, creating products and uploading files, payments, and delivering purchased files to your customers.

Here's everything we'll cover:

  • The Stripe Connect onboarding flow
  • Effortlessly creating products (and uploading files) with Livewire forms
  • Subdomains for your user's marketplace
  • Stripe Checkout for a beautiful, secure payment flow
  • Securely delivering files with Signed URLs in Laravel
  • Showing sales stats on a dashboard
Alex Garrett-Smith
Alex Garrett-Smith
Hey, I'm the founder of Codecourse!

Comments

No comments, yet. Be the first to leave a comment.