Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
42.59% covered (danger)
42.59%
46 / 108
50.00% covered (danger)
50.00%
5 / 10
CRAP
0.00% covered (danger)
0.00%
0 / 1
RolePlaySubscriptionController
42.59% covered (danger)
42.59%
46 / 108
50.00% covered (danger)
50.00%
5 / 10
71.68
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
 createUserAdvancedPlan
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
2
 createUserExpertPlan
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
2
 createUserFreemiumPlan
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
1
 getUserPlan
60.00% covered (warning)
60.00%
9 / 15
0.00% covered (danger)
0.00%
0 / 1
6.60
 info
100.00% covered (success)
100.00%
15 / 15
100.00% covered (success)
100.00%
1 / 1
1
 getAvailableTime
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 getAvailableSessions
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
2
 create
0.00% covered (danger)
0.00%
0 / 23
0.00% covered (danger)
0.00%
0 / 1
6
 destroy
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
6
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\Admin\CompanyLicenses;
11use App\Http\Models\Auth\User;
12use App\Http\Models\RolePlayConversations;
13use App\Http\Models\UserAddOns;
14use App\Http\Requests\v2\RolePlay\DestroyUserAddOnRequest;
15use Stripe\Stripe;
16use Stripe\Subscription;
17use Stripe\Checkout\Session;
18use Stripe\Exception\ApiErrorException;
19
20class RolePlaySubscriptionController extends Controller
21{
22    use SubscriptionTrait;
23
24    public function __construct()
25    {
26        Stripe::setApiKey(config('app.stripe.secret'));
27    }
28
29    private function createUserAdvancedPlan(User $user): UserAddOns
30    {
31        $addOn = AddOns::where('identifier', 'roleplay-advanced-monthly')->where('recurrency_type', 'monthly')->first();
32
33        return UserAddOns::create([
34            'user_id' => $user->id,
35            'add_on_id' => $addOn->id,
36            'product' => 'RolePlay',
37            'status' => 'active',
38            'starts_at' => now(),
39            'ends_at' => null,
40            'quantity' => 1,
41            'stripe_id' => null,
42        ]);
43    }
44
45    private function createUserExpertPlan(User $user): UserAddOns
46    {
47        $addOn = AddOns::where('identifier', 'roleplay-expert-monthly')->where('recurrency_type', 'monthly')->first();
48
49        return UserAddOns::create([
50            'user_id' => $user->id,
51            'add_on_id' => $addOn->id,
52            'product' => 'RolePlay',
53            'status' => 'active',
54            'starts_at' => now(),
55            'ends_at' => null,
56            'quantity' => 1,
57            'stripe_id' => null,
58        ]);
59    }
60
61    private function createUserFreemiumPlan(User $user): UserAddOns
62    {
63        $freemiumAddOn = AddOns::where('identifier', 'roleplay-beginner')->first();
64
65        return UserAddOns::create([
66            'user_id' => $user->id,
67            'add_on_id' => $freemiumAddOn->id,
68            'product' => 'RolePlay',
69            'status' => 'active',
70            'starts_at' => now(),
71            'ends_at' => null,
72            'quantity' => 1,
73            'stripe_id' => null,
74        ]);
75    }
76
77    private function getUserPlan(User $user): UserAddOns
78    {
79        $rolePlayAddOn = UserAddOns::where('user_id', $user->id)
80            ->where('product', 'RolePlay')
81            ->where('status', 'active')
82            ->orderBy('created_at', 'desc')
83            ->first();
84
85        if (!$rolePlayAddOn) {
86            if (!empty($user->company_id)) {
87                $companyLicense = CompanyLicenses::where('company_id', $user->company_id)->first();
88                $community = $companyLicense->business_pro_enterprise_plus ?? [];
89                $isPro = in_array('yes_dedicated', $community) || in_array('yes_community', $community);
90
91                if ($isPro) {
92                    $rolePlayAddOn = $this->createUserExpertPlan($user);
93                } else {
94                    $rolePlayAddOn = $this->createUserAdvancedPlan($user);
95                }
96            } else {
97                $rolePlayAddOn = $this->createUserFreemiumPlan($user);
98            }
99        }
100
101        return $rolePlayAddOn;
102    }
103
104    public function info(Request $request): JsonResponse
105    {
106        $user = $request->user();
107        $plan = $this->getUserPlan($user);
108        $addOn = AddOns::find($plan->add_on_id);
109        $availableTime = $this->getAvailableTime($user, $addOn);
110        $availableSessions = $this->getAvailableSessions($user, $addOn);
111
112        return response()->json([
113            'status' => 'success',
114            'data' => [
115                'user' => $user,
116                'plan' => $plan,
117                'add_on' => $addOn,
118                'available_time_seconds' => $availableTime,
119                'available_sessions' => $availableSessions,
120            ],
121        ]);
122    }
123
124    private function getAvailableTime(User $user, AddOns $product): int
125    {
126        $total = $product->features['monthly_total_time_credits'] ?? 0;
127        $used = RolePlayConversations::where('user_id', $user->id)
128            ->whereBetween('created_at', [now()->startOfMonth(), now()->endOfMonth()])
129            ->sum('duration');
130
131        return max(0, $total - $used);
132    }
133
134    private function getAvailableSessions(User $user, AddOns $product): int
135    {
136        $total = $product->features['monthly_roleplay_credits'] ?? 0;
137        $used = RolePlayConversations::where('user_id', $user->id)
138            ->whereBetween('created_at', [now()->startOfMonth(), now()->endOfMonth()])
139            ->count();
140
141        return $total === -1 ? -1 : max(0, $total - $used);
142    }
143
144    public function create(Request $request, AddOns $addOn): JsonResponse
145    {
146        $user = $request->user();
147        try {
148            $session = Session::create([
149                'payment_method_types' => ['card'],
150                'customer' => $user->stripe_id,
151                'line_items' => [[
152                    'price' => $addOn->stripe_price_id,
153                    'quantity' => 1,
154                ]],
155                'mode' => 'subscription',
156                'success_url' => config('app.role_play_url') . 'settings/subscription?session_id={CHECKOUT_SESSION_ID}',
157                'cancel_url' => config('app.role_play_url') . 'settings/subscription',
158            ]);
159
160            return response()->json([
161                'status' => 'success',
162                'data' => [
163                    'sessionId' => $session->id,
164                ]
165            ], 200);
166        } catch (ApiErrorException $e) {
167            return response()->json([
168                'status' => 'error',
169                'message' => 'Failed to create subscription: ' . $e->getMessage()
170            ], 400);
171        }
172    }
173
174    public function destroy(DestroyUserAddOnRequest $request, UserAddOns $userAddOn): JsonResponse
175    {
176        try {
177            $subscription = Subscription::retrieve($userAddOn->stripe_id);
178            $subscription->cancel();
179
180            return response()->json([
181                'status' => 'success',
182                'message' => 'Subscription canceled successfully.'
183            ], 200);
184        } catch (ApiErrorException $e) {
185            return response()->json([
186                'status' => 'error',
187                'message' => 'Failed to cancel subscription: ' . $e->getMessage()
188            ], 500);
189        }
190    }
191}