Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
86.55% covered (warning)
86.55%
103 / 119
50.00% covered (danger)
50.00%
1 / 2
CRAP
0.00% covered (danger)
0.00%
0 / 1
RolePlayWebhookController
86.55% covered (warning)
86.55%
103 / 119
50.00% covered (danger)
50.00%
1 / 2
24.29
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 stripe
86.44% covered (warning)
86.44%
102 / 118
0.00% covered (danger)
0.00%
0 / 1
23.21
1<?php
2
3namespace App\Http\Controllers\v2\RolePlay;
4
5use App\Http\Controllers\Controller;
6use App\Http\Models\AddOns;
7use App\Http\Models\Auth\User;
8use App\Http\Models\Invoices;
9use App\Http\Models\UserAddOns;
10use App\Traits\SubscriptionTrait;
11use Illuminate\Http\JsonResponse;
12use Illuminate\Http\Request;
13use Illuminate\Support\Facades\Log;
14use Stripe\Exception\SignatureVerificationException;
15use Stripe\Webhook;
16
17class RolePlayWebhookController extends Controller
18{
19    use SubscriptionTrait;
20
21    public function __construct() {}
22
23    public function stripe(Request $request): JsonResponse
24    {
25        $webhookSecret = config('app.stripe.role_play_webhook');
26
27        $signature = $request->header('Stripe-Signature');
28
29        try {
30            $event = Webhook::constructEvent(
31                $request->getContent(),
32                $signature,
33                $webhookSecret
34            );
35        } catch (SignatureVerificationException $e) {
36            return response()->json(['status' => 'Webhook Failed'], 400);
37        }
38
39        $addonProductIds = AddOns::where('product', 'RolePlay')->select('stripe_id')->get()->pluck('stripe_id')->toArray();
40
41        $eventType = $event->type;
42        $eventObject = $event->data->object;
43
44        $isAddonEvent = false;
45
46        if (in_array($eventType, ['customer.subscription.created', 'customer.subscription.updated', 'customer.subscription.deleted'])) {
47            if (isset($eventObject->items->data[0]->price->product) && in_array($eventObject->items->data[0]->price->product, $addonProductIds)) {
48                $isAddonEvent = true;
49            }
50        } elseif (in_array($eventType, ['invoice.paid', 'invoice.payment_failed'])) {
51            foreach ($eventObject->lines->data as $lineItem) {
52                if (isset($lineItem->price->product) && in_array($lineItem->price->product, $addonProductIds)) {
53                    $isAddonEvent = true;
54                    break;
55                }
56            }
57        }
58
59        if (! $isAddonEvent) {
60            return response()->json(['status' => 'Webhook Ignored'], 200);
61        }
62
63        $user = User::where('stripe_id', $eventObject->customer)->first();
64
65        if (! $user) {
66            Log::warning('User not found for Stripe customer ID: ', ['data' => $eventObject->customer]);
67
68            return response()->json(['status' => 'User not found.'], 404);
69        }
70
71        switch ($eventType) {
72            case 'customer.subscription.updated':
73                $subscription = $event->data->object;
74                $userAddon = UserAddOns::where('stripe_id', $subscription->id)->first();
75
76                if (! $userAddon) {
77                    $user = User::where('stripe_id', $subscription->customer)->first();
78                    if ($user) {
79                        $stripeProductId = $eventObject->items->data[0]->price->product ?? null;
80                        $addOn = AddOns::where('stripe_id', $stripeProductId)->first();
81
82                        UserAddOns::create([
83                            'user_id' => $user->id,
84                            'add_on_id' => $addOn->id,
85                            'product' => 'RolePlay',
86                            'stripe_price_id' => $subscription->items->data[0]->price->id,
87                            'status' => $subscription->status,
88                            'starts_at' => now(),
89                            'ends_at' => \Carbon\Carbon::createFromTimestamp($subscription->current_period_end),
90                            'quantity' => 1,
91                            'stripe_id' => $subscription->id,
92                        ]);
93                    }
94                } else {
95                    $userAddon->update([
96                        'status' => $subscription->status,
97                        'stripe_price_id' => $subscription->items->data[0]->price->id,
98                        'ends_at' => \Carbon\Carbon::createFromTimestamp($subscription->current_period_end),
99                    ]);
100                }
101                break;
102
103            case 'customer.subscription.created':
104                $subscription = $event->data->object;
105                $stripeProductId = $eventObject->items->data[0]->price->product ?? null;
106                $addOn = AddOns::where('stripe_id', $stripeProductId)->first();
107
108                UserAddOns::create([
109                    'user_id' => $user->id,
110                    'add_on_id' => $addOn->id,
111                    'product' => 'RolePlay',
112                    'status' => $subscription->status,
113                    'stripe_price_id' => $subscription->items->data[0]->price->id ?? null,
114                    'starts_at' => now(),
115                    'ends_at' => \Carbon\Carbon::createFromTimestamp($subscription->current_period_end),
116                    'quantity' => 1,
117                    'stripe_id' => $subscription->id,
118                ]);
119                break;
120
121            case 'invoice.paid':
122                $invoice = $event->data->object;
123                $subscriptionId = $invoice->subscription;
124                $paidAt = \Carbon\Carbon::createFromTimestamp($invoice->created);
125
126                Invoices::create([
127                    'user_id' => $user->id,
128                    'stripe_id' => $invoice->id,
129                    'stripe_price_id' => $eventObject->lines->data[0]->price->id ?? null,
130                    'stripe_subscription_id' => $subscriptionId,
131                    'stripe_product_id' => $eventObject->lines->data[0]->price->product ?? null,
132                    'amount' => $invoice->amount_paid / 100,
133                    'currency' => strtoupper($invoice->currency),
134                    'paid_at' => $paidAt,
135                    'status' => 'paid',
136                ]);
137
138                $userAddon = UserAddons::where('stripe_id', $subscriptionId)->first();
139
140                if ($userAddon) {
141                    $userAddon->update([
142                        'status' => 'active',
143                        'ends_at' => \Carbon\Carbon::createFromTimestamp($invoice->period_end),
144                    ]);
145                }
146                break;
147
148            case 'invoice.payment_failed':
149                $invoice = $event->data->object;
150                $subscriptionId = $invoice->subscription;
151
152                Invoices::create([
153                    'user_id' => $user->id,
154                    'stripe_id' => $invoice->id,
155                    'stripe_price_id' => $eventObject->lines->data[0]->price->id ?? null,
156                    'stripe_subscription_id' => $subscriptionId,
157                    'stripe_product_id' => $eventObject->lines->data[0]->price->product ?? null,
158                    'amount' => $invoice->amount_due / 100,
159                    'currency' => strtoupper($invoice->currency),
160                    'paid_at' => null,
161                    'status' => 'failed',
162                ]);
163
164                $userAddon = UserAddOns::where('stripe_id', $subscriptionId)->first();
165
166                if ($userAddon) {
167                    $userAddon->update(['status' => 'payment_failed']);
168                }
169                break;
170
171            case 'customer.subscription.deleted':
172                $subscription = $event->data->object;
173                $subscriptionId = $subscription->id;
174
175                $userAddon = UserAddons::where('stripe_id', $subscriptionId)->first();
176
177                if ($userAddon) {
178                    if ($subscription->cancel_at_period_end) {
179                        $userAddon->update(['status' => 'canceled_at_period_end']);
180                    } else {
181                        $userAddon->update(['status' => 'canceled']);
182                    }
183                }
184                break;
185        }
186
187        return response()->json(['status' => 'Webhook Handled'], 200);
188    }
189}