Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 86
0.00% covered (danger)
0.00%
0 / 7
CRAP
0.00% covered (danger)
0.00%
0 / 1
PaymentController
0.00% covered (danger)
0.00%
0 / 86
0.00% covered (danger)
0.00%
0 / 7
506
0.00% covered (danger)
0.00%
0 / 1
 index
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 paymentMethods
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 defaultPaymentMethod
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 setDefaultPaymentMethod
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
6
 store
0.00% covered (danger)
0.00%
0 / 66
0.00% covered (danger)
0.00%
0 / 1
182
 nextBillingDate
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
6
 getPaymentMethods
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
1<?php
2
3namespace App\Http\Controllers\v1\Stripe;
4
5use App\Http\Controllers\Controller;
6use App\Http\Models\Plans;
7use App\Http\Models\Auth\User;
8use App\Http\Models\Subscription;
9use App\Http\Requests\StoreSubscriptionRequest;
10use App\Traits\SubscriptionTrait;
11use Carbon\Carbon;
12use Exception;
13use Illuminate\Http\JsonResponse;
14use Illuminate\Http\Request;
15use Illuminate\Support\Str;
16
17class PaymentController extends Controller
18{
19    use SubscriptionTrait;
20
21    public function index(Request $request): JsonResponse
22    {
23        return response()->json($request->user()->createSetupIntent());
24    }
25
26    public function paymentMethods(Request $request)
27    {
28        return $this->getPaymentMethods($request->user());
29    }
30
31    public function defaultPaymentMethod(Request $request): JsonResponse
32    {
33        return response()->json($request->user()->defaultPaymentMethod());
34    }
35
36    public function setDefaultPaymentMethod(Request $request): JsonResponse
37    {
38        $this->validate($request, [
39            'payment_method_id' => 'required',
40        ]);
41
42        try {
43            $request->user()->updateDefaultPaymentMethod($request->payment_method_id);
44
45            return response()->json(['message' => 'Successfully updated default payment method'], 201);
46        } catch (Exception $e) {
47            return response()->json(['message' => $e->getMessage()], 422);
48        }
49    }
50
51    public function store(StoreSubscriptionRequest $request): JsonResponse
52    {
53        $this->validate($request, [
54            'payment_method_id' => 'required',
55        ]);
56
57        try {
58            $user = $request->user();
59            if (!$user->hasStripeId()) {
60                $user->createAsStripeCustomer([
61                    'name' => $user->first_name . ' ' . $user->last_name,
62                    'email' => $user->email,
63                ]);
64            }
65
66            $user->updateDefaultPaymentMethod($request->payment_method_id);
67
68            $paymentMethodId = $request->payment_method_id;
69            $stripe = new \Stripe\StripeClient(config('services.stripe.secret'));
70            $paymentMethod = $stripe->paymentMethods->retrieve($paymentMethodId, []);
71            $user->addPaymentMethod($paymentMethod);
72
73            if (! $user->hasDefaultPaymentMethod()) {
74                $user->updateDefaultPaymentMethod($paymentMethod);
75            }
76
77            $plan = Plans::where('identifier', '=', $request->plan)
78                ->whereNull('pricing_version')
79                ->firstOrFail();
80
81            $subscriptionResult = null;
82
83            if ($user->subscribed('main')) {
84                $current_subscription = $user->subscriptions()->first();
85                if ($current_subscription->stripe_plan == $plan->stripe_id) {
86                    throw new Exception(Str::replaceArray('?', [$plan->title], 'You are already Subscribed to ? plan'));
87                }
88
89                $subscriptionResult = $user->subscription('main')->swapAndInvoice($plan->stripe_id);
90
91                // Give stripe a delay of 5 seconds to return webhook.
92                $attempts = 0;
93                $maxAttempts = 10;
94                $interval = 500000; // 500ms in microseconds
95
96                do {
97                    usleep($interval);
98                    $currentPlans = Subscription::where("name", "main")->where("user_id", $user->id)->get()->pluck('plan');
99                    $attempts++;
100                } while (!$currentPlans->contains('identifier', $plan->identifier) && $attempts < $maxAttempts);
101
102                $currentPlan = $currentPlans->firstWhere('identifier', $plan->identifier);
103
104                if ($subscriptionResult?->plan->identifier !== $plan->identifier || !$currentPlans->contains('identifier', $plan->identifier)) {
105                    return response()->json([
106                        'message' => 'Your subscription to ' . $plan->title . ' failed!',
107                        'data' => $currentPlan
108                    ], 422);
109                }
110            } else {
111                if (filled($request->discount_code)) {
112                    $subscriptionResult = $user->newSubscription('main', $plan->stripe_id)
113                        ->withCoupon($request->discount_code)
114                        ->create($paymentMethod, [
115                            'receipt_email' => "$user->email",
116                        ]);
117                } else {
118                    $subscriptionResult = $user->newSubscription('main', $plan->stripe_id)
119                        ->create($paymentMethod, [
120                            'receipt_email' => "$user->email",
121                        ]);
122                }
123
124                // Give stripe a delay of 5 seconds to return webhook.
125                $attempts = 0;
126                $maxAttempts = 10;
127                $interval = 500000; // 500ms in microseconds
128
129                do {
130                    usleep($interval);
131                    $currentPlans = Subscription::where("name", "main")->where("user_id", $user->id)->get()->pluck('plan');
132                    $attempts++;
133                } while (!$currentPlans->contains('identifier', $plan->identifier) && $attempts < $maxAttempts);
134
135                if ($subscriptionResult?->plan->identifier !== $plan->identifier || !$currentPlans->contains('identifier', $plan->identifier)) {
136                    return response()->json([
137                        'message' => 'Your subscription to ' . $plan->title . ' failed!',
138                    ], 422);
139                }
140            }
141
142            $currentPlan = $currentPlans->firstWhere('identifier', $plan->identifier);
143
144            return response()->json([
145                'message' => 'You are successfully subscribed to the plan ' . $plan->title,
146                'data' => $currentPlan
147            ]);
148        } catch (Exception $e) {
149            return response()->json(['message' => $e->getMessage()], 403);
150        }
151    }
152
153    public function nextBillingDate(Request $request): JsonResponse
154    {
155        $current_subscription = $request->user()->subscription('main');
156
157        if (! $current_subscription) {
158            return response()->json(false);
159        }
160
161        $now = Carbon::now();
162        $date = Carbon::createFromTimeStamp($current_subscription->asStripeSubscription()->current_period_end);
163
164        return response()->json($date->diff($now)->days);
165    }
166
167    protected function getPaymentMethods(User $user): array
168    {
169        $paymentMethods = [];
170
171        foreach ($user->paymentMethods() as $paymentMethod) {
172            $paymentMethods[] = $paymentMethod->asStripePaymentMethod();
173        }
174
175        return $paymentMethods;
176    }
177}