├── .gitignore ├── changelog.md ├── composer.json ├── config └── stripe-server.php ├── migrations └── 2019_06_19_101000_create_stripe_checkouts_table.php ├── phpunit.xml ├── readme.md ├── src ├── Commands │ ├── Events.php │ ├── Purge.php │ └── StripeCompletedCheckout.php ├── Events │ ├── CheckoutSessionCompleted.php │ └── StripeEvent.php ├── Facades │ └── Stripe.php ├── Models │ ├── HasStripeCheckout.php │ ├── HasStripeCheckouts.php │ └── StripeCheckout.php ├── Nova │ └── StripeCheckout.php ├── Requests │ ├── Command.php │ ├── CreateCharge.php │ ├── CreateSession.php │ ├── Events.php │ └── PaymentIntent.php ├── Stripe.php └── StripeServerServiceProvider.php └── views └── redirector.blade.php /.gitignore: -------------------------------------------------------------------------------- 1 | vendor/ 2 | composer.lock -------------------------------------------------------------------------------- /changelog.md: -------------------------------------------------------------------------------- 1 | # Laravel Stripe Server Changelog 2 | 3 | ## 1.2.0 4 | 5 | - Update `stripe-php` to `7.40` 6 | - Change author contact 7 | 8 | ## 1.1.1 9 | 10 | - Fix model on commands 11 | 12 | ## 1.1.0 13 | 14 | - Laravel 7 support 15 | 16 | ## 1.0.0 17 | 18 | - Laravel 6 19 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lab404/laravel-stripe-server", 3 | "description": "Laravel Stripe Server is a library to handle Stripe SCA checkout.", 4 | "type": "library", 5 | "keywords": [ 6 | "laravel", 7 | "package", 8 | "plugin", 9 | "stripe", 10 | "server", 11 | "payment", 12 | "sca", 13 | "checkout", 14 | "laravel-package", 15 | "laravel-plugin" 16 | ], 17 | "require": { 18 | "php": "^7.2", 19 | "laravel/framework": "^6.0 | ^7.0", 20 | "stripe/stripe-php": "^7.40" 21 | }, 22 | "license": "MIT", 23 | "authors": [ 24 | { 25 | "name": "Marceau Ka", 26 | "email": "marceau@casals.fr" 27 | } 28 | ], 29 | "autoload": { 30 | "psr-4": { 31 | "Lab404\\StripeServer\\": "src/" 32 | } 33 | }, 34 | "autoload-dev": { 35 | "psr-4": { 36 | "Lab404\\Tests\\": "tests/" 37 | } 38 | }, 39 | "extra": { 40 | "laravel": { 41 | "providers": [ 42 | "Lab404\\StripeServer\\StripeServerServiceProvider" 43 | ] 44 | } 45 | }, 46 | "minimum-stability": "dev", 47 | "prefer-stable": true 48 | } 49 | -------------------------------------------------------------------------------- /config/stripe-server.php: -------------------------------------------------------------------------------- 1 | \Lab404\StripeServer\Models\StripeCheckout::class, 6 | 7 | ]; 8 | -------------------------------------------------------------------------------- /migrations/2019_06_19_101000_create_stripe_checkouts_table.php: -------------------------------------------------------------------------------- 1 | bigIncrements('id'); 13 | $table->string('payment_intent_id')->nullable()->index(); 14 | $table->string('checkout_session_id')->nullable()->index(); 15 | $table->boolean('is_paid')->default(0)->index(); 16 | $table->string('chargeable_type'); 17 | $table->integer('chargeable_id'); 18 | $table->timestamps(); 19 | 20 | $table->index(['chargeable_type', 'chargeable_id']); 21 | }); 22 | } 23 | 24 | public function down() 25 | { 26 | Schema::dropIfExists('stripe_checkouts'); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | src/ 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Laravel Stripe Server 2 | 3 | Laravel Stripe Server is a library to handle Stripe SCA checkout for your models. 4 | 5 | - [Requirements](#requirements) 6 | - [Intended workflow](#intended-workflow) 7 | - [Installation](#installation) 8 | - [Going deeper](#going-deeper) 9 | - [Nova](#nova) 10 | - [Ideas](#ideas) 11 | - [Tests](#tests) 12 | - [Contribute](#contribute) 13 | - [Licence](#licence) 14 | 15 | ## Requirements 16 | 17 | - Laravel 6.x or 7.x 18 | - PHP >= 7.2 19 | 20 | ### Laravel support 21 | 22 | | Version | Release | 23 | |:-------------:|:-------------:| 24 | | 6.x, 7.x | 1.1 | 25 | | 6.x | 1.0 | 26 | | 5.8 | 0.3 | 27 | 28 | ## Intended workflow 29 | 30 | - You have an `Order` model with a stripe checkout. You create the order in your controller. 31 | 32 | Example model: 33 | ```php 34 | use App\Models\Order; 35 | use Lab404\StripeServer\Facades\Stripe; 36 | use Illuminate\Http\Request; 37 | 38 | class OrderController 39 | { 40 | public function store(Request $request) 41 | { 42 | // Create your order 43 | $order = new Order($request->validated()); 44 | $order->save(); 45 | 46 | // Create your checkout session 47 | $session = Stripe::requestCreateSession() 48 | ->setCustomerEmail($request->user()->email) 49 | ->setReturnUrls($confirm_url, $cancel_url) 50 | ->setProduct('T-shirt', 5000, 'EUR', 1, $picture_url) 51 | ->call(); 52 | 53 | // Create your checkout model 54 | $checkout = Stripe::registerCheckout($session, $order); 55 | 56 | return Stripe::redirectSession($response->id); 57 | } 58 | } 59 | ``` 60 | 61 | - Your user is redirected to stripe, he fills his informations and he's redirected to your success URL. The order is not paid yet. 62 | Asynchronously, the plugin will try to get new events from Stripe and will dispatch the `CheckoutSessionCompleted` event: 63 | 64 | Example listener: 65 | ```php 66 | use Lab404\StripeServer\Events\CheckoutSessionCompleted; 67 | use Lab404\StripeServer\Models\StripeCheckout; 68 | 69 | class CheckoutListener 70 | { 71 | public function handle(CheckoutSessionCompleted $event): void 72 | { 73 | /** @var StripeCheckout $checkout */ 74 | $checkout = $event->checkout; 75 | /** Your charged model */ 76 | $chargeable = $checkout->chargeable; 77 | /** The PaymentIntent returned by Stripe */ 78 | $payment = $event->paymentIntent; 79 | 80 | /** Important! Mark the checkout as paid */ 81 | $checkout->markAsPaid(); 82 | } 83 | } 84 | ``` 85 | 86 | - You can use your model like this: 87 | ```php 88 | $order = Order::with('checkout')->first(); 89 | if ($order->checkout->is_paid) { 90 | echo 'Order is paid'; 91 | } else { 92 | echo 'Order is not paid'; 93 | } 94 | ``` 95 | 96 | ## Installation 97 | 98 | 1. Require it with Composer: 99 | ```bash 100 | composer require lab404/laravel-stripe-server 101 | ``` 102 | 103 | 2. Configure your Stripe keys in `config/services.php`. 104 | 105 | 3. Publish `migrations` and `views` with `php artisan vendor:publish --tag=stripe-server`. 106 | 107 | 4. Migrate `2019_06_19_101000_create_stripe_checkouts_table.php`. 108 | 109 | 5. Schedule the command in `app\Console\Kernel.php`: 110 | ```php 111 | protected function schedule(Schedule $schedule) 112 | { 113 | $schedule->command('stripe:checkout-session-completed')->everyMinute(); 114 | } 115 | ``` 116 | 117 | 6. Add the `Lab404\StripeServer\Models\HasStripeCheckout` or `HasStripeCheckouts` (if a model can have multiple checkouts) to your chargeable models. 118 | 119 | ## Going deeper 120 | 121 | ### Stripe documentation 122 | 123 | - [Checkout Server Quickstart](https://stripe.com/docs/payments/checkout/server) 124 | - [Checkout Purchase Fulfillment](https://stripe.com/docs/payments/checkout/fulfillment) 125 | - [Going Live with Checkout](https://stripe.com/docs/payments/checkout/live) 126 | - [Strong Customer Authentication](https://stripe.com/docs/strong-customer-authentication) 127 | 128 | ### Access the Stripe Manager 129 | 130 | With facade: 131 | ```php 132 | Stripe::method(); 133 | ``` 134 | 135 | With DI: 136 | ``` 137 | public function index(Lab404\StripeServer\Stripe $stripe) 138 | { 139 | $stripe->method(); 140 | } 141 | ``` 142 | 143 | With container: 144 | ``` 145 | app('stripe')->method(); 146 | ``` 147 | 148 | ### Available methods 149 | 150 | - `redirectSession(string $session_id): Illuminate\Contracts\View\View` 151 | - `registerCheckout(\Stripe\Checkout\Session $session, Model $model): Illuminate\Database\Eloquent\Model` 152 | - `requestCreateCharge(): StripeServer\Requests\CreateCharge` 153 | - `requestCreateSession(): StripeServer\Requests\CreateSession` 154 | - `requestPaymentIntent(string $id): StripeServer\Requests\PaymentIntent` 155 | - `requestEvents(string $type, int $hours = 24): StripeServer\Requests\Events` 156 | - `requestSessionCheckoutCompletedEvents(int $hours = 24): StripeServer\Requests\Events` 157 | 158 | ### Working with your models 159 | 160 | #### Model with many checkouts 161 | 162 | When a model has the `Lab404\StripeServer\Models\HasStripeCheckouts` you have access to the following methods and scopes: 163 | ```php 164 | // Scopes 165 | Model::hasCheckouts()->get(); 166 | Model::hasPaidCheckouts()->get(); 167 | Model::hasUnpaidCheckouts()->get(); 168 | 169 | // Methods 170 | $models->checkouts(); // returns all checkout for the model 171 | 172 | // Eager loading 173 | $models = Model::with('checkouts')->get(); 174 | ``` 175 | 176 | #### Model with one checkout 177 | 178 | When a model has the `Lab404\StripeServer\Models\HasStripeCheckout` you have access to the following methods and scopes: 179 | ```php 180 | // Scopes 181 | Model::hasCheckout()->get(); 182 | Model::hasPaidCheckout()->get(); 183 | Model::hasUnpaidCheckout()->get(); 184 | 185 | // Methods 186 | $models->checkout(); // returns the checkout for the model 187 | 188 | // Eager loading 189 | $models = Model::with('checkout')->get(); 190 | ``` 191 | 192 | ### Customize the `StripeCheckout` model 193 | 194 | Configure `model` in `config/stripe-server.php`. Your custom model should extend the default one. 195 | 196 | ### Customize the redirector 197 | 198 | When you use the `redirectSession()` method, an instance of `Illuminate\View\View` is returned. You can do: 199 | 200 | ```php 201 | return Stripe::redirectSession('...')->with([ 202 | 'title' => 'My custom title', 203 | 'message' => 'My customer redirect message' 204 | ]); 205 | ``` 206 | 207 | ### Artisan commands 208 | 209 | #### `stripe:checkout-session-completed` 210 | 211 | Get all `checkout.session.completed` Stripe events and dispatch the event `CheckoutSessionCompleted` for each with the `succeeded` status. 212 | 213 | #### `stripe:events` 214 | 215 | Get all Stripe events and dispatch `StripeEvent` for each one. 216 | 217 | #### `stripe:purge` 218 | 219 | Delete all unpaid `StripeCheckout` older than the given days. Customize with the `--days` option, defaults to 7. It's convenient to call it in a scheduler: 220 | 221 | ``` 222 | $schedule->command('stripe:purge')->dailyAt('12:00'); 223 | ``` 224 | 225 | ## Nova 226 | 227 | If you're using [Laravel Nova](https://nova.laravel.com) you can add the `Lab404\StripeServer\Nova\StripeCheckout` resource: 228 | 229 | ``` 230 | Laravel\Nova\Nova::resources([ 231 | Lab404\StripeServer\Nova\StripeCheckout::class, 232 | ]); 233 | ``` 234 | 235 | This resource is not dynamically registered because it's quite simple and you may want to override it. More Nova features like Refund Action or Cards are coming. 236 | 237 | ## TODOs and ideas 238 | 239 | [x] Purge unpaid stripe checkouts 240 | [ ] Refund 241 | [ ] Nova actions 242 | 243 | ## Tests 244 | 245 | TODO 246 | 247 | ## Contribute 248 | 249 | This package is still in development, feel free to contribute! 250 | 251 | ### Contributors 252 | 253 | - [MarceauKa](https://github.com/MarceauKa) 254 | - and all others [contributors](https://github.com/404labfr/laravel-impersonate/graphs/contributors) 255 | 256 | ## Licence 257 | 258 | MIT 259 | -------------------------------------------------------------------------------- /src/Commands/Events.php: -------------------------------------------------------------------------------- 1 | requestEvents($this->option('period'))->call(); 20 | 21 | if ($events->isEmpty()) { 22 | $this->info('No events found for this period.'); 23 | } 24 | 25 | $events->each(function ($event) { 26 | $this->info('Dispatching ' . $event->id); 27 | Event::dispatch(new StripeEvent($event)); 28 | }); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Commands/Purge.php: -------------------------------------------------------------------------------- 1 | getTable()) 25 | ->where('is_paid', 0) 26 | ->where('created_at', '<=', Carbon::now()->subDays($this->option('days'))->toDateTimeString()) 27 | ->delete(); 28 | 29 | $this->info('Stripe checkouts purged.'); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Commands/StripeCompletedCheckout.php: -------------------------------------------------------------------------------- 1 | requestSessionCheckoutCompletedEvents($this->option('period'))->call(); 23 | 24 | if ($events->isEmpty()) { 25 | $this->info('No events found for this period.'); 26 | } 27 | 28 | $ids = $events->pluck('payment_intent')->toArray(); 29 | $model = Config::get('stripe-server.model'); 30 | $model = $model ?? StripeCheckout::class; 31 | 32 | /** @var Collection $checkouts */ 33 | $checkouts = $model::with('chargeable')->paymentIntentIdsAre($ids)->isNotPaid()->get(); 34 | $checkouts->each(function ($checkout) use ($stripe) { 35 | try { 36 | $this->info('Dispatching ' . $checkout->payment_intent_id); 37 | $payment = $stripe->requestPaymentIntent($checkout->payment_intent_id)->call(); 38 | if ($payment && $payment->status === 'succeeded') { 39 | Event::dispatch(new CheckoutSessionCompleted($checkout, $payment)); 40 | } 41 | } catch (\Exception $e) { 42 | unset($e); 43 | } 44 | }); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/Events/CheckoutSessionCompleted.php: -------------------------------------------------------------------------------- 1 | checkout = $checkout; 21 | $this->paymentIntent = $paymentIntent; 22 | } 23 | } -------------------------------------------------------------------------------- /src/Events/StripeEvent.php: -------------------------------------------------------------------------------- 1 | event = $event; 18 | } 19 | } -------------------------------------------------------------------------------- /src/Facades/Stripe.php: -------------------------------------------------------------------------------- 1 | morphOne(Config::get('stripe-server.model'), 'chargeable'); 19 | } 20 | 21 | public function scopeHasCheckout(Builder $query): void 22 | { 23 | $query->has('checkout'); 24 | } 25 | 26 | public function scopeHasPaidCheckout(Builder $query): void 27 | { 28 | $query->whereHas('checkout', function ($query) { 29 | $query->where('is_paid', '=', 1); 30 | }); 31 | } 32 | 33 | public function scopeHasUnpaidCheckout(Builder $query): void 34 | { 35 | $query->whereHas('checkout', function ($query) { 36 | $query->where('is_paid', '=', 0); 37 | }); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Models/HasStripeCheckouts.php: -------------------------------------------------------------------------------- 1 | morphMany(Config::get('stripe-server.model'), 'chargeable'); 19 | } 20 | 21 | public function scopeHasCheckouts(Builder $query): void 22 | { 23 | $query->has('checkouts'); 24 | } 25 | 26 | public function scopeHasPaidCheckouts(Builder $query): void 27 | { 28 | $query->whereHas('checkouts', function ($query) { 29 | $query->where('is_paid', '=', 1); 30 | }); 31 | } 32 | 33 | public function scopeHasUnpaidCheckouts(Builder $query): void 34 | { 35 | $query->whereHas('checkouts', function ($query) { 36 | $query->where('is_paid', '=', 0); 37 | }); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Models/StripeCheckout.php: -------------------------------------------------------------------------------- 1 | 'bool', 24 | ]; 25 | 26 | public function chargeable(): MorphTo 27 | { 28 | return $this->morphTo(); 29 | } 30 | 31 | public function markAsPaid(): bool 32 | { 33 | $this->attributes['is_paid'] = 1; 34 | return $this->save(); 35 | } 36 | 37 | public function scopeIsPaid(Builder $query): void 38 | { 39 | $query->where('is_paid', 1); 40 | } 41 | 42 | public function scopeIsNotPaid(Builder $query): void 43 | { 44 | $query->where('is_paid', 0); 45 | } 46 | 47 | public function scopePaymentIntentIdsAre(Builder $query, array $ids): Builder 48 | { 49 | return $query->whereIn('payment_intent_id', $ids); 50 | } 51 | 52 | public function scopePaymentIntentIdIs(Builder $query, string $payment_intent_id): Builder 53 | { 54 | return $query->where('payment_intent_id', '=', $payment_intent_id); 55 | } 56 | 57 | public function scopeCheckoutSessionIdIs(Builder $query, string $checkout_session_id): Builder 58 | { 59 | return $query->where('checkout_session_id', '=', $checkout_session_id); 60 | } 61 | 62 | public function scopeCheckoutSessionIdsAre(Builder $query, array $ids): Builder 63 | { 64 | return $query->whereIn('checkout_session_id', $ids); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/Nova/StripeCheckout.php: -------------------------------------------------------------------------------- 1 | hideFromIndex() 26 | ->asBigInt(), 27 | 28 | Boolean::make(__('Paid'), 'is_paid'), 29 | 30 | Text::make(__('Session ID'), 'checkout_session_id') 31 | ->exceptOnForms(), 32 | 33 | Text::make(__('Payment intent'), 'payment_intent_id') 34 | ->exceptOnForms(), 35 | 36 | Text::make(__('Chargeable type'), 'chargeable_type') 37 | ->exceptOnForms(), 38 | 39 | Text::make(__('Chargeable ID'), 'chargeable_id') 40 | ->exceptOnForms(), 41 | 42 | DateTime::make(__('Created at'), 'created_at') 43 | ->exceptOnForms(), 44 | 45 | DateTime::make(__('Updated at'), 'updated_at') 46 | ->exceptOnForms(), 47 | ]; 48 | } 49 | 50 | public function cards(Request $request): array 51 | { 52 | return []; 53 | } 54 | 55 | public function filters(Request $request): array 56 | { 57 | return []; 58 | } 59 | 60 | public function lenses(Request $request): array 61 | { 62 | return []; 63 | } 64 | 65 | public function actions(Request $request): array 66 | { 67 | return []; 68 | } 69 | 70 | public static function singularLabel(): string 71 | { 72 | return __('Checkout'); 73 | } 74 | 75 | public static function label(): string 76 | { 77 | return __('Checkouts'); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/Requests/Command.php: -------------------------------------------------------------------------------- 1 | class(); 20 | $method = $this->method(); 21 | 22 | try { 23 | return $class::$method($this->params); 24 | } catch (\Exception $e) { 25 | throw new \RuntimeException($e->getMessage(), $e->getCode(), $e); 26 | } 27 | } 28 | 29 | abstract protected function class(): string; 30 | 31 | abstract protected function method(): string; 32 | } 33 | -------------------------------------------------------------------------------- /src/Requests/CreateCharge.php: -------------------------------------------------------------------------------- 1 | null, 11 | 'currency' => null, 12 | 'source' => null, 13 | 'description' => null, 14 | ]; 15 | 16 | public function setAmount(int $amount): self 17 | { 18 | $this->params['amount'] = $amount; 19 | return $this; 20 | } 21 | 22 | public function setCurrency(string $currency): self 23 | { 24 | $this->params['currency'] = $currency; 25 | return $this; 26 | } 27 | 28 | public function setSource(string $source): self 29 | { 30 | $this->params['source'] = $source; 31 | return $this; 32 | } 33 | 34 | public function setDescription(string $description): self 35 | { 36 | $this->params['description'] = $description; 37 | return $this; 38 | } 39 | 40 | public function call(): StripeCharge 41 | { 42 | return parent::call(); 43 | } 44 | 45 | protected function class(): string 46 | { 47 | return \Stripe\Charge::class; 48 | } 49 | 50 | protected function method(): string 51 | { 52 | return 'create'; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/Requests/CreateSession.php: -------------------------------------------------------------------------------- 1 | null, 9 | 'payment_method_types' => ['card'], 10 | 'line_items' => [], 11 | 'locale' => 'auto', 12 | 'submit_type' => 'pay', 13 | 'success_url' => '', 14 | 'cancel_url' => '', 15 | ]; 16 | 17 | public function setCustomerEmail(string $email): self 18 | { 19 | $this->params['customer_email'] = $email; 20 | return $this; 21 | } 22 | 23 | public function setCustomer(string $identifier): self 24 | { 25 | $this->params['customer'] = $identifier; 26 | return $this; 27 | } 28 | 29 | /** 30 | * @param string|array $methods 31 | * @return self 32 | */ 33 | public function setPaymentMethods($methods = 'card'): self 34 | { 35 | $this->params['payment_method_types'] = is_array($methods) ? $methods : [$methods]; 36 | return $this; 37 | } 38 | 39 | public function setLocale(string $locale = 'auto'): self 40 | { 41 | $this->params['locale'] = $locale; 42 | return $this; 43 | } 44 | 45 | public function setSubmit(string $submit): self 46 | { 47 | $this->params['submit_type'] = $submit; 48 | return $this; 49 | } 50 | 51 | public function setSuccessUrl(string $succes_url): self 52 | { 53 | $this->params['success_url'] = $succes_url; 54 | return $this; 55 | } 56 | 57 | public function setCancelUrl(string $cancel_url): self 58 | { 59 | $this->params['cancel_url'] = $cancel_url; 60 | return $this; 61 | } 62 | 63 | public function setReturnUrls(string $success_url, string $cancel_url) 64 | { 65 | return $this->setSuccessUrl($success_url)->setCancelUrl($cancel_url); 66 | } 67 | 68 | /** 69 | * @param string $name 70 | * @param int $amount 71 | * @param string $currency 72 | * @param int $quantity 73 | * @param string|string[] $images 74 | * @return CreateSession 75 | */ 76 | public function setProduct(string $name, int $amount, string $currency, int $quantity, $images): self 77 | { 78 | $this->params['line_items'] = []; 79 | return $this->addProduct($name, $amount, $currency, $quantity, $images); 80 | } 81 | 82 | /** 83 | * @param string $name 84 | * @param int $amount 85 | * @param string $currency 86 | * @param int $quantity 87 | * @param string|string[] $images 88 | * @return CreateSession 89 | */ 90 | public function addProduct(string $name, int $amount, string $currency, int $quantity, $images): self 91 | { 92 | $this->params['line_items'][] = [ 93 | 'name' => $name, 94 | 'quantity' => $quantity, 95 | 'amount' => $amount, 96 | 'currency' => $currency, 97 | 'images' => is_array($images) ? $images : [$images], 98 | ]; 99 | return $this; 100 | } 101 | 102 | protected function class(): string 103 | { 104 | return \Stripe\Checkout\Session::class; 105 | } 106 | 107 | protected function method(): string 108 | { 109 | return 'create'; 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /src/Requests/Events.php: -------------------------------------------------------------------------------- 1 | 'all', 11 | 'created' => [], 12 | ]; 13 | 14 | public function __construct(string $type, int $hours = 24) 15 | { 16 | $this->setType($type) 17 | ->setHours($hours); 18 | } 19 | 20 | public function setType(string $type): self 21 | { 22 | $this->params['type'] = $type; 23 | return $this; 24 | } 25 | 26 | public function setHours(int $hours): self 27 | { 28 | $this->params['created'] = [ 29 | 'gte' => time() - abs($hours) * 60 * 60 30 | ]; 31 | return $this; 32 | } 33 | 34 | public function call(): Collection 35 | { 36 | $response = parent::call(); 37 | 38 | return collect($response->data)->transform(function ($item) { 39 | return $item->data->object; 40 | }); 41 | } 42 | 43 | protected function class(): string 44 | { 45 | return \Stripe\Event::class; 46 | } 47 | 48 | protected function method(): string 49 | { 50 | return 'all'; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/Requests/PaymentIntent.php: -------------------------------------------------------------------------------- 1 | params = $id; 12 | return $this; 13 | } 14 | 15 | protected function class(): string 16 | { 17 | return StripePaymentIntent::class; 18 | } 19 | 20 | protected function method(): string 21 | { 22 | return 'retrieve'; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Stripe.php: -------------------------------------------------------------------------------- 1 | key = $key; 24 | $this->secret = $secret; 25 | 26 | StripeCore::setApiKey($this->secret); 27 | } 28 | 29 | public function redirectSession(string $session_id): View 30 | { 31 | return view('stripe-server::redirector')->with([ 32 | 'session_id' => $session_id, 33 | ]); 34 | } 35 | 36 | public function registerCheckout(\Stripe\Checkout\Session $session, Model $model): Model 37 | { 38 | $class = Config::get('stripe-server.model'); 39 | 40 | $checkout = new $class([ 41 | 'payment_intent_id' => $session->payment_intent, 42 | 'checkout_session_id' => $session->id, 43 | ]); 44 | 45 | if ($model->exists) { 46 | $checkout->chargeable_type = get_class($model); 47 | $checkout->chargeable_id = $model->getKey(); 48 | } 49 | 50 | $checkout->save(); 51 | 52 | return $checkout; 53 | } 54 | 55 | public function requestCreateCharge(): CreateCharge 56 | { 57 | return new CreateCharge(); 58 | } 59 | 60 | public function requestCreateSession(): CreateSession 61 | { 62 | return new CreateSession(); 63 | } 64 | 65 | public function requestPaymentIntent(string $id): PaymentIntent 66 | { 67 | return (new PaymentIntent())->setId($id); 68 | } 69 | 70 | public function requestEvents(string $type, int $hours = 24): Events 71 | { 72 | return new Events($type, $hours); 73 | } 74 | 75 | public function requestSessionCheckoutCompletedEvents(int $hours = 24): Events 76 | { 77 | return $this->requestEvents('checkout.session.completed', $hours); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/StripeServerServiceProvider.php: -------------------------------------------------------------------------------- 1 | mergeConfig(); 19 | 20 | $this->app->singleton(Stripe::class, function () { 21 | return new Stripe( 22 | Config::get('services.stripe.key'), 23 | Config::get('services.stripe.secret') 24 | ); 25 | }); 26 | 27 | $this->app->alias(Stripe::class, 'stripe'); 28 | 29 | if ($this->app->runningInConsole()) { 30 | $this->commands([ 31 | Events::class, 32 | StripeCompletedCheckout::class, 33 | Purge::class, 34 | ]); 35 | } 36 | } 37 | 38 | public function boot() 39 | { 40 | $this->publishConfig(); 41 | $this->loadMigrationsFrom(__DIR__ . '/../migrations'); 42 | $this->loadViewsFrom(__DIR__ . '/../views', $this->configName); 43 | } 44 | 45 | protected function mergeConfig() 46 | { 47 | $configPath = __DIR__ . '/../config/' . $this->configName . '.php'; 48 | $this->mergeConfigFrom($configPath, $this->configName); 49 | } 50 | 51 | protected function publishConfig() 52 | { 53 | $configPath = __DIR__ . '/../config/' . $this->configName . '.php'; 54 | $this->publishes([$configPath => config_path($this->configName . '.php')], 'config'); 55 | } 56 | } -------------------------------------------------------------------------------- /views/redirector.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | {{ $title ?? config('app.name') }} 7 | 8 | 34 | 35 | 36 |
37 |
38 |
39 | {{ $message ?? 'Redirecting to payment...' }} 40 |
41 |
42 |
43 | 44 | 52 | 53 | --------------------------------------------------------------------------------