Viewing File: /home/markqprx/iniasli.pro/Gateways/Stripe/StripeSubscriptions.php

<?php namespace Common\Billing\Gateways\Stripe;

use App\Models\User;
use Common\Billing\Models\Price;
use Common\Billing\Models\Product;
use Common\Billing\Subscription;
use Stripe\Exception\InvalidRequestException;
use Stripe\StripeClient;

class StripeSubscriptions
{
    public function __construct(public StripeClient $client)
    {
    }

    public function createPartial(
        Product $product,
        User $user,
        ?int $priceId = null,
    ): string {
        $price = $priceId
            ? $product->prices()->findOrFail($priceId)
            : $product->prices->firstOrFail();

        $user = $this->syncStripeCustomer($user);

        // find incomplete subscriptions for this customer and price
        $stripeSubscription = $this->client->subscriptions
            ->all([
                'customer' => $user->stripe_id,
                'price' => $price->stripe_id,
                'status' => 'incomplete',
                'expand' => ['data.latest_invoice.payment_intent'],
            ])
            ->first();

        // if matching subscription was not created yet, do it now
        if (!$stripeSubscription) {
            $stripeSubscription = $this->client->subscriptions->create([
                'customer' => $user->stripe_id,
                'items' => [
                    [
                        'price' => $price->stripe_id,
                    ],
                ],
                'payment_behavior' => 'default_incomplete',
                'payment_settings' => [
                    'save_default_payment_method' => 'on_subscription',
                ],
                'expand' => ['latest_invoice.payment_intent'],
            ]);
        }

        // return client secret, needed in frontend to complete subscription
        return $stripeSubscription->latest_invoice->payment_intent
            ->client_secret;
    }

    public function cancel(
        Subscription $subscription,
        bool $atPeriodEnd = true,
    ): bool {
        if (!$subscription->user->stripe_id) {
            return true;
        }

        try {
            $stripeSubscription = $this->client->subscriptions->retrieve(
                $subscription->gateway_id,
            );
        } catch (InvalidRequestException $e) {
            if ($e->getStripeCode() === 'resource_missing') {
                return true;
            }
            throw $e;
        }

        // cancel subscription at current period end and don't delete
        if ($atPeriodEnd) {
            $updatedSubscription = $this->client->subscriptions->update(
                $stripeSubscription->id,
                [
                    'cancel_at_period_end' => true,
                ],
            );
            return $updatedSubscription->cancel_at_period_end;
            // cancel and delete subscription instantly
        } else {
            $stripeSubscription = $this->client->subscriptions->cancel(
                $stripeSubscription->id,
            );
            return $stripeSubscription->status === 'cancelled';
        }
    }

    public function resume(Subscription $subscription, array $params): bool
    {
        $stripeSubscription = $this->client->subscriptions->retrieve(
            $subscription->gateway_id,
        );

        $updatedSubscription = $this->client->subscriptions->update(
            $stripeSubscription->id,
            array_merge(
                [
                    'cancel_at_period_end' => false,
                ],
                $params,
            ),
        );

        return $updatedSubscription->status === 'active';
    }

    public function changePlan(
        Subscription $subscription,
        Product $newProduct,
        Price $newPrice,
    ): bool {
        $stripeSubscription = $this->client->subscriptions->retrieve(
            $subscription->gateway_id,
        );

        $updatedSubscription = $this->client->subscriptions->update(
            $stripeSubscription->id,
            [
                'proration_behavior' => 'always_invoice',
                'items' => [
                    [
                        'id' => $stripeSubscription->items->data[0]->id,
                        'price' => $newPrice->stripe_id,
                    ],
                ],
            ],
        );

        return $updatedSubscription->status === 'active';
    }

    protected function syncStripeCustomer(User $user): User
    {
        // make sure user with stored stripe ID actually exists on stripe
        if ($user->stripe_id) {
            try {
                $this->client->customers->retrieve($user->stripe_id);
            } catch (InvalidRequestException $e) {
                $user->stripe_id = null;
            }
        }

        // create customer object on stripe, if it does not exist already
        if (!$user->stripe_id) {
            $customer = $this->client->customers->create([
                'email' => $user->email,
                'metadata' => [
                    'userId' => $user->id,
                ],
            ]);
            $user->fill(['stripe_id' => $customer->id])->save();
        }

        return $user;
    }
}
Back to Directory File Manager