public function checkout()
{
$user_id = Auth::id();
$stripe = $this->stripe;
// Creates an order table
$order = new Order();
$order->id = fake()->numerify('######');
$order->status = 'unpaid';
$order->total_price = $this->getTotalCartPrice();
$order->user()->associate(Auth::user());
$order->save();
$carts = Cart::where('user_id', $user_id)->get();
$listOfProducts = [];
foreach($carts as $cart)
{
$listOfProducts[] = [
'price_data' => [
'currency' => 'gbp',
'product_data' => [
'name' => $cart->product->name,
],
'unit_amount' => $cart->product->price * 100,
],
'quantity' => $cart->quantity,
];
// Creates an orderItem table for each product in the cart and associates it with the order. This allows us to check what products are linked with the order
$orderItem = new OrderItem();
$orderItem->user()->associate(Auth::user());
$orderItem->product()->associate($cart->product);
$orderItem->quantity = $cart->quantity;
$orderItem->unit_price = $cart->product->price;
$orderItem->order()->associate($order->id);
$orderItem->save();
}
$sessionData = ([
'line_items' => $listOfProducts,
'mode' => 'payment',
'success_url' => route('checkout.success', [], true)."?session_id={CHECKOUT_SESSION_ID}",
'cancel_url' => route('checkout.cancel', [], true)."?session_id={CHECKOUT_SESSION_ID}",
]);
#Stripe Laravel Tests
27 messages · Page 1 of 1 (latest)
// Conditionally add coupon if it exists in session
if ($coupon = session('coupon.name')) {
$sessionData['discounts'] = [
[
'coupon' => $coupon,
],
];
}
$checkout_session = $stripe->checkout->sessions->create($sessionData);
$order->session_id = $checkout_session->id;
$order->save();
return redirect()->away($checkout_session->url); // This will direct user to checkout page and they will either go to the checkout.success or checkout.cancel route after checkout depening on their action
}
My test currently:
$user = User::factory()->create();
$carts = Cart::factory()->count(4)->create(['user_id' => $user->id]);
$this->actingAs($user);
$response = $this->post(route('checkout'));
$response->assertStatus(302);
$response->assertRedirect()
So for $response->assertRedirect() I need to ensure it gets directed to a checkout session url i assume?
Can you format your code with syntax highlight, please? It’s difficult to follow when it’s just grey text.
```php
// Your PHP code here...
Didn't know that existed, done 🙂
Thanks 👍
Couple of notes: you shouldn’t be using the env() helper outside of configuration files. Map the STRIPE_SECRET environment variable to a configuration value instead. You can add an entry to your config/services.php file:
return [
'stripe' => [
'key' => env('STRIPE_KEY'),
'secret' => env('STRIPE_SECRET'),
],
];
You can then reference these in your code as config('services.stripe.secret') etc.
Also, you’d be better off binding a well-configured instance of the StripeClient to the container in a service provider:
$this->app->singleton(StripeClient::class, function () {
return new StripeClient([
'api_key' => $this->app['config']['services.stripe.secret'],
]);
});
This way, you can just type-hint StripeClient in classes and methods that need it, and the already-configured instance will be injected instead of manually instantiating it in multiple places in your app:
class CheckoutController extends Controller
{
protected $stripe;
public function __construct(StripeClient $stripe)
{
$this->stripe = $stripe;
}
// Now all actions have access to StripeClient as $this->stripe
}
This is a lot of unnecessary duplication for the sake of adding a coupon:
if(!session()->get('coupon')) // Checks if the user has a coupon applied to cart
{
$checkout_session = $stripe->checkout->sessions->create([
'line_items' => $listOfProducts,
'mode' => 'payment',
'success_url' => route('checkout.success', [], true)."?session_id={CHECKOUT_SESSION_ID}",
'cancel_url' => route('checkout.cancel', [], true)."?session_id={CHECKOUT_SESSION_ID}",
]);
} else {
$checkout_session = $stripe->checkout->sessions->create([
'line_items' => $listOfProducts,
'mode' => 'payment',
'discounts' => [[
'coupon' => session()->get('coupon')['name'],
]],
'success_url' => route('checkout.success', [], true)."?session_id={CHECKOUT_SESSION_ID}",
'cancel_url' => route('checkout.cancel', [], true)."?session_id={CHECKOUT_SESSION_ID}",
]);
}
You can simplify by creating your “base” array, and then conditionally adding a new key if there is a coupon in the session:
$sessionData = [
'line_items' => $listOfProducts,
'mode' => 'payment',
'success_url' => route('checkout.success', [], true)."?session_id={CHECKOUT_SESSION_ID}",
'cancel_url' => route('checkout.cancel', [], true)."?session_id={CHECKOUT_SESSION_ID}",
];
// Conditionally add coupon if it exists in session
if ($coupon = session('coupon.name')) {
$sessionData['discounts'] = [
[
'coupon' => $coupon,
],
];
}
$checkout_session = $stripe->checkout->sessions->create($sessionData);
Wow, thank you
So do I add this:
$this->app->singleton(StripeClient::class, function () {
return new StripeClient([
'api_key' => $this->app['config']['services.stripe.secret'],
]);
});
Into the AppServiceProvider in boot() function?
No, register method.
I get an error of Target class [App\Http\Controllers\StripeClient] does not exist.
You need to actually import the class.
use Stripe\StripeClient;
Sorry to keep bothering you but now I get an error of No API key provided. Set your API key when constructing the StripeClient instance, or provide it on a per-request basis using the `api_key` key in the $opts argument.
Aren't we passing the api_key here: 'api_key' => $this->app['config']['services.stripe.secret'],
The STRIPE_SECRET_KEY is in my .env file
Only if you’ve actually added an entry to your config/services.php file.
I have like this:
'stripe' => [
'key' => env('STRIPE_KEY'),
'secret' => env('STRIPE_SECRET'),
]
You said you have STRIPE_SECRET_KEY in your env file, the above is looking for STRIPE_SECRET
🤦♂️ I'm sorry
Thank you
Okay, based on Martin feedback (thank you vert much btw). I have updated the OP with the cleaned code. if anyone could by any chance help me out in writing a test for this, I would appreciate it as I am very confused on how to make it work.
Can you re-phrase your question? I don’t really understand what you’re asking.
From the #rules:
Help us help you - Search the documentation before posting your issue and explain what you're doing and include any error messages you have received.