diff --git a/composer.json b/composer.json index 27fe171..1b12a0c 100644 --- a/composer.json +++ b/composer.json @@ -10,7 +10,8 @@ } ], "require": { - "laravel/framework": "5.*", + "php": "^7.1.3", + "laravel/framework": "5.*|6.*", "stripe/stripe-php": "4.*|5.*|6.*" }, "autoload": { diff --git a/src/Console/Commands/CreateStripeEndpoints.php b/src/Console/Commands/CreateStripeEndpoints.php new file mode 100644 index 0000000..e10de25 --- /dev/null +++ b/src/Console/Commands/CreateStripeEndpoints.php @@ -0,0 +1,96 @@ +info('Creating endpoints ...'); + + try { + $this->deleteEndpoints(); + $this->createEndpoints(); + } catch (\Stripe\Error\InvalidRequest | \Stripe\Exception\InvalidRequest $e) { + $this->error($e->getMessage()); + } + + $this->info('Finished'); + } + + /** + * Delete all endpoints in Stripe + * + * @param array $plans + */ + protected function deleteEndpoints() + { + $endpoints =\Stripe\WebhookEndpoint::all(); + foreach ($endpoints as $endpoint) { + $this->info('Deleted webhook endpoint:'.$endpoint->url); + + $endpoint->delete(); + } + } + + /** + * Try and create endpoints in Stripe + * + * @param array $plans + */ + protected function createEndpoints() + { + $url = config('app.url').'webhook/stripe'; + + \Stripe\WebhookEndpoint::create([ + 'url' => $url, + 'enabled_events' => [ + 'customer.subscription.updated', + 'customer.subscription.deleted', + 'customer.updated', + 'customer.deleted', + 'invoice.payment_action_required', + 'invoice.payment_succeeded', + 'invoice.created', + ] + ]); + + $this->info('Created webhook endpoint:'.$url); + } +} diff --git a/src/Console/Commands/CreateStripePlans.php b/src/Console/Commands/CreateStripePlans.php index a0ade3f..38cc23a 100644 --- a/src/Console/Commands/CreateStripePlans.php +++ b/src/Console/Commands/CreateStripePlans.php @@ -23,6 +23,12 @@ class CreateStripePlans extends Command */ protected $description = 'Creates plans in Stripe based on the plans defined in Spark'; + /** + * Product Stripe IDs + * + * @var array + */ + private $productStripeIds = []; /** * Create a new command instance. * @@ -42,6 +48,9 @@ public function handle() { Stripe\Stripe::setApiKey(config('services.stripe.secret')); + $this->info('Fetch products...'); + $this->fetchProducts(); + $this->info('Creating user plans...'); $this->createStripePlans(Spark::$plans); @@ -52,47 +61,94 @@ public function handle() } /** - * Try and create plans in Stripe + * Try and create product in Stripe * * @param array $plans */ - protected function createStripePlans($plans) + protected function fetchProducts() { - foreach ($plans as $plan) { - if ($this->planExists($plan)) { - $this->line('Stripe plan ' . $plan->id . ' already exists'); - } else { - Stripe\Plan::create([ - 'id' => $plan->id, - 'name' => Spark::$details['product'] . ' ' . $plan->name . ' (' . - Cashier::usesCurrencySymbol() . $plan->price . ' ' . $plan->interval . - ')', - 'amount' => $plan->price * 100, - 'interval' => str_replace('ly', '', $plan->interval), - 'currency' => Cashier::usesCurrency(), - 'statement_descriptor' => Spark::$details['vendor'], - 'trial_period_days' => $plan->trialDays, - ]); - - $this->info('Stripe plan created: ' . $plan->id); + try { + /** @var \Stripe\Product[] $products */ + $products = Stripe\Product::all(); + foreach ($products as $product) { + $this->productStripeIds[] = $product->id; } + + $this->info('Fetched products'); + } catch (\Stripe\Error\InvalidRequest | \Stripe\Exception\InvalidRequest $e) { + $this->line('Unable to fetch products'); } + } /** - * Check if a plan already exists + * Create product in Stripe if needed and return the id * - * @param $plan - * @return bool + * @param array $plans */ - private function planExists($plan) + protected function getProductId($name = null) { + $name = $name ?? Spark::$details['product']; + + $id = strtolower(str_replace(' ', '-', $name)); + + $this->info('Creating looking up id for: '.$id); + + if (in_array($id, $this->productStripeIds)) { + return $id; + } + + $this->info('Creating product: '.$id); + try { - Stripe\Plan::retrieve($plan->id); - return true; - } catch (\Exception $e) { + $product = Stripe\Product::create([ + 'id' => $id, + 'name' => $name, + 'statement_descriptor' => Spark::$details['vendor'], + 'unit_label' => Spark::$details['unit_label'] ?? null, + 'type' => 'service', + ]); + + $this->productStripeIds[] = $product->id; + + $this->info('Stripe product created: ' . $id); + } catch (\Stripe\Error\InvalidRequest | \Stripe\Exception\InvalidRequest $e) { + $this->line('Stripe product ' . $id . ' already exists'); } - return false; + return $id; + } + + /** + * Try and create plans in Stripe + * + * @param array $plans + */ + protected function createStripePlans($plans) + { + foreach ($plans as $plan) { + if ($plan->id === 'free') { + $this->line('Skipping free plan, since the "free" plan is handled by Spark internally.'); + continue; + } + + try { + Stripe\Plan::create([ + 'id' => $plan->id, + 'nickname' => $plan->name, + 'product' => $this->getProductId($plan->attribute('product')), + 'amount' => $plan->price * 100, + 'interval' => str_replace('ly', '', $plan->interval), + 'currency' => config('cashier.currency'), + 'trial_period_days' => $plan->trialDays, + 'billing_scheme' => 'per_unit', + 'usage_type' => 'licensed', + ]); + + $this->info('Stripe plan created: ' . $plan->id); + } catch (\Stripe\Error\InvalidRequest | \Stripe\Exception\InvalidRequest $e) { + $this->line('Stripe plan ' . $plan->id . ' already exists: '.$e->getMessage()); + } + } } } diff --git a/src/CreateStripePlansServiceProvider.php b/src/CreateStripePlansServiceProvider.php index a1b35d8..e93d3de 100644 --- a/src/CreateStripePlansServiceProvider.php +++ b/src/CreateStripePlansServiceProvider.php @@ -8,6 +8,7 @@ class CreateStripePlansServiceProvider extends ServiceProvider { protected $commands = [ \Gilbitron\Laravel\Spark\Console\Commands\CreateStripePlans::class, + \Gilbitron\Laravel\Spark\Console\Commands\CreateStripeEndpoints::class, ]; /** @@ -29,4 +30,4 @@ public function register() { $this->commands($this->commands); } -} \ No newline at end of file +}