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 Illuminate\Http\Request;
6use App\Traits\SubscriptionTrait;
7use Illuminate\Http\JsonResponse;
8use App\Http\Controllers\Controller;
9use App\Http\Models\AddOns;
10use App\Http\Models\Auth\User;
11use App\Http\Models\Invoices;
12use App\Http\Models\UserAddOns;
13use Illuminate\Support\Facades\Log;
14use Stripe\Webhook;
15use Stripe\Exception\SignatureVerificationException;
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            return response()->json(['status' => 'User not found.'], 404);
68        }
69
70        switch ($eventType) {
71            case 'customer.subscription.updated':
72                $subscription = $event->data->object;
73                $userAddon = UserAddOns::where('stripe_id', $subscription->id)->first();
74
75                if (!$userAddon) {
76                    $user = User::where('stripe_id', $subscription->customer)->first();
77                    if ($user) {
78                        $stripeProductId = $eventObject->items->data[0]->price->product ?? null;
79                        $addOn = AddOns::where('stripe_id', $stripeProductId)->first();
80
81                        UserAddOns::create([
82                            'user_id' => $user->id,
83                            'add_on_id' => $addOn->id,
84                            'product' => 'RolePlay',
85                            'stripe_price_id' => $subscription->items->data[0]->price->id,
86                            'status' => $subscription->status,
87                            'starts_at' => now(),
88                            'ends_at' => \Carbon\Carbon::createFromTimestamp($subscription->current_period_end),
89                            'quantity' => 1,
90                            'stripe_id' => $subscription->id,
91                        ]);
92                    }
93                } else {
94                    $userAddon->update([
95                        'status' => $subscription->status,
96                        'stripe_price_id' => $subscription->items->data[0]->price->id,
97                        'ends_at' => \Carbon\Carbon::createFromTimestamp($subscription->current_period_end)
98                    ]);
99                }
100                break;
101
102            case 'customer.subscription.created':
103                $subscription = $event->data->object;
104                $stripeProductId = $eventObject->items->data[0]->price->product ?? null;
105                $addOn = AddOns::where('stripe_id', $stripeProductId)->first();
106
107                UserAddOns::create([
108                    'user_id' => $user->id,
109                    'add_on_id' => $addOn->id,
110                    'product' => 'RolePlay',
111                    'status' => $subscription->status,
112                    'stripe_price_id' => $subscription->items->data[0]->price->id ?? null,
113                    'starts_at' => now(),
114                    'ends_at' => \Carbon\Carbon::createFromTimestamp($subscription->current_period_end),
115                    'quantity' => 1,
116                    'stripe_id' => $subscription->id,
117                ]);
118                break;
119
120            case 'invoice.paid':
121                $invoice = $event->data->object;
122                $subscriptionId = $invoice->subscription;
123                $paidAt = \Carbon\Carbon::createFromTimestamp($invoice->created);
124
125                Invoices::create([
126                    'user_id' => $user->id,
127                    'stripe_id' => $invoice->id,
128                    'stripe_price_id' => $eventObject->lines->data[0]->price->id ?? null,
129                    'stripe_subscription_id' => $subscriptionId,
130                    'stripe_product_id' => $eventObject->lines->data[0]->price->product ?? null,
131                    'amount' => $invoice->amount_paid / 100,
132                    'currency' => strtoupper($invoice->currency),
133                    'paid_at' => $paidAt,
134                    'status' => 'paid',
135                ]);
136
137                $userAddon = UserAddons::where('stripe_id', $subscriptionId)->first();
138
139                if ($userAddon) {
140                    $userAddon->update([
141                        'status' => 'active',
142                        'ends_at' => \Carbon\Carbon::createFromTimestamp($invoice->period_end)
143                    ]);
144                }
145                break;
146
147            case 'invoice.payment_failed':
148                $invoice = $event->data->object;
149                $subscriptionId = $invoice->subscription;
150
151                Invoices::create([
152                    'user_id' => $user->id,
153                    'stripe_id' => $invoice->id,
154                    'stripe_price_id' => $eventObject->lines->data[0]->price->id ?? null,
155                    'stripe_subscription_id' => $subscriptionId,
156                    'stripe_product_id' => $eventObject->lines->data[0]->price->product ?? null,
157                    'amount' => $invoice->amount_due / 100,
158                    'currency' => strtoupper($invoice->currency),
159                    'paid_at' => null,
160                    'status' => 'failed',
161                ]);
162
163                $userAddon = UserAddOns::where('stripe_id', $subscriptionId)->first();
164
165                if ($userAddon) {
166                    $userAddon->update(['status' => 'payment_failed']);
167                }
168                break;
169
170            case 'customer.subscription.deleted':
171                $subscription = $event->data->object;
172                $subscriptionId = $subscription->id;
173
174                $userAddon = UserAddons::where('stripe_id', $subscriptionId)->first();
175
176                if ($userAddon) {
177                    if ($subscription->cancel_at_period_end) {
178                        $userAddon->update(['status' => 'canceled_at_period_end']);
179                    } else {
180                        $userAddon->update(['status' => 'canceled']);
181                    }
182                }
183                break;
184        }
185
186        return response()->json(['status' => 'Webhook Handled'], 200);
187    }
188}