lunarphp / stripe
Stripe payment driver for Lunar.
Installs: 9 095
Dependents: 1
Suggesters: 0
Security: 0
Stars: 18
Watchers: 5
Forks: 11
Type:project
Requires
- php: ^8.2
- lunarphp/core: 1.0.0-alpha.16
- stripe/stripe-php: ^7.114
- dev-main
- 1.x-dev
- 1.0.x-dev
- 1.0.0-alpha.16
- 1.0.0-alpha.15
- 1.0.0-alpha.14
- 1.0.0-alpha.13
- 1.0.0-alpha.12
- 1.0.0-alpha.11
- 1.0.0-alpha.10
- 1.0.0-alpha.9
- 1.0.0-alpha.8
- 1.0.0-alpha.7
- 1.0.0-alpha.6
- 1.0.0-alpha.5
- 1.0.0-alpha.4
- 1.0.0-alpha.3
- 1.0.0-alpha.2
- 1.0.0-alpha.1
- 0.8.x-dev
- 0.8.0
- 0.7.x-dev
- 0.7.0
- 0.7.0-rc.2
- 0.7.0-rc.1
- 0.6.x-dev
- 0.6.1
- 0.6.0
- 0.5.x-dev
- 0.5.0
- 0.4.x-dev
- 0.4.0
- 0.3.x-dev
- 0.3.0
- 0.2.x-dev
- 0.2.0
- 0.2-rc1
- 0.1.x-dev
- 0.1.1
- 0.1.0
- 0.1.0-rc.1
- dev-1.0.0-alpha
- dev-alecritson-patch-1
- dev-feat/stripe-refactor
- dev-feat/webhooks
This package is auto-updated.
Last update: 2024-05-01 07:28:05 UTC
README
This addon enables Stripe payments on your Lunar storefront.
Alpha Release
This addon is currently in Alpha, whilst every step is taken to ensure this is working as intended, it will not be considered out of Alpha until more tests have been added and proved.
Tests required:
- Successful charge response from Stripe.
- Unsuccessful charge response from Stripe.
- Test
manual
config reacts appropriately. - Test
automatic
config reacts appropriately. - Ensure transactions are stored correctly in the database
- Ensure that the payment intent is not duplicated when using the same Cart
- Ensure appropriate responses are returned based on Stripe's responses.
- Test refunds and partial refunds create the expected transactions
- Make sure we can manually release a payment or part payment and handle the different responses.
Minimum Requirements
- Lunar >=
0.6
- A Stripe account with secret and public keys
Optional Requirements
- Laravel Livewire (if using frontend components)
- Alpinejs (if using frontend components)
- Javascript framework
Installation
Require the composer package
composer require lunarphp/stripe
Publish the configuration
This will publish the configuration under config/getcandy/stripe.php
.
php artisan vendor:publish --tag=getcandy.stripe.config
Publish the views (optional)
Lunar Stripe comes with some helper components for you to use on your checkout, if you intend to edit the views they provide, you can publish them.
php artisan vendor:publish --tag=getcandy.stripe.components
Enable the driver
Set the driver in config/getcandy/payments.php
<?php return [ // ... 'types' => [ 'card' => [ // ... 'driver' => 'stripe', ], ], ];
Add your Stripe credentials
Make sure you have the Stripe credentials set in config/services.php
'stripe' => [ 'key' => env('STRIPE_SECRET'), 'public_key' => env('STRIPE_PK'), ],
Keys can be found in your Stripe account https://dashboard.stripe.com/apikeys
Configuration
Below is a list of the available configuration options this package uses in config/getcandy/stripe.php
Key | Default | Description |
---|---|---|
policy |
automatic |
Determines the policy for taking payments and whether you wish to capture the payment manually later or take payment straight away. Available options manual or automatic |
Backend Usage
Create a PaymentIntent
use \Lunar\Stripe\Facades\Stripe; Stripe::createIntent(\Lunar\Models\Cart $cart);
This method will create a Stripe PaymentIntent from a Cart and add the resulting ID to the meta for retrieval later. If a PaymentIntent already exists for a cart this will fetch it from Stripe and return that instead to avoid duplicate PaymentIntents being created.
$paymentIntentId = $cart->meta['payment_intent']; // The resulting ID from the method above.
$cart->meta->payment_intent;
Fetch an existing PaymentIntent
use \Lunar\Stripe\Facades\Stripe; Stripe::fetchIntent($paymentIntentId);
Syncing an existing intent
If a payment intent has been created and there are changes to the cart, you will want to update the intent so it has the correct totals.
use \Lunar\Stripe\Facades\Stripe; Stripe::syncIntent(\Lunar\Models\Cart $cart);
Webhooks
The plugin provides a webhook you will need to add to Stripe. You can read the guide on how to do this on the Stripe website https://stripe.com/docs/webhooks/quickstart.
The 3 events you should listen to are payment_intent.payment_failed
,payment_intent.processing
,payment_intent.succeeded
.
The path to the webhook will be http:://yoursite.com/stripe/webhook
.
You can customise the path for the webhook in config/lunar/stripe.php
.
You will also need to add the webhook signing secret to the services.php
config file:
<?php return [ // ... 'stripe' => [ // ... 'webhooks' => [ 'payment_intent' => '...' ], ], ];
Storefront Examples
First we need to set up the backend API call to fetch or create the intent, this isn't Vue specific but will likely be different if you're using Livewire.
use \Lunar\Stripe\Facades\Stripe; Route::post('api/payment-intent', function () { $cart = CartSession::current(); $cartData = CartData::from($cart); if ($paymentIntent = $cartData->meta['payment_intent'] ?? false) { $intent = StripeFacade::fetchIntent($paymentIntent); } else { $intent = StripeFacade::createIntent($cart); } if ($intent->amount != $cart->total->value) { StripeFacade::syncIntent($cart); } return $intent; })->middleware('web');
Vuejs
This is just using Stripe's payment elements, for more information check out the Stripe guides
Payment component
<script setup> const { VITE_STRIPE_PK } = import.meta.env const stripe = Stripe(VITE_STRIPE_PK) const stripeElements = ref({}) const buildForm = async () => { const { data } = await axios.post("api/payment-intent") stripeElements.value = stripe.elements({ clientSecret: data.client_secret, }) const paymentElement = stripeElements.value.create("payment", { layout: "tabs", defaultValues: { billingDetails: { name: `${billingAddress.value.first_name} ${billingAddress.value?.last_name}`, phone: billingAddress.value?.contact_phone, }, }, fields: { billingDetails: "never", }, }) paymentElement.mount("#payment-element") } onMounted(async () => { await buildForm() }) // The address object can be either passed through as props or via a second API call, but it should likely come from the cart. const submit = async () => { try { const address = {...} const { error } = await stripe.confirmPayment({ //`Elements` instance that was used to create the Payment Element elements: stripeElements.value, confirmParams: { return_url: 'http://yoursite.com/checkout/complete', payment_method_data: { billing_details: { name: `${address.first_name} ${address.last_name}`, email: address.contact_email, phone: address.contact_phone, address: { city: address.city, country: address.country.iso2, line1: address.line_one, line2: address.line_two, postal_code: address.postcode, state: address.state, }, }, }, }, }) } catch (e) { } } </script>
<template> <form @submit.prevent="submit"> <div id="payment-element"> <!--Stripe.js injects the Payment Element--> </div> </form> </template>
Contributing
Contributions are welcome, if you are thinking of adding a feature, please submit an issue first so we can determine whether it should be included.
Testing
A MockClient class is used to mock responses the Stripe API will return.