Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
97.14% covered (success)
97.14%
34 / 35
75.00% covered (warning)
75.00%
3 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
SubscriptionRepository
97.14% covered (success)
97.14%
34 / 35
75.00% covered (warning)
75.00%
3 / 4
9
0.00% covered (danger)
0.00%
0 / 1
 getActiveSubscription
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
3
 isSubscriptionValid
88.89% covered (warning)
88.89%
8 / 9
0.00% covered (danger)
0.00%
0 / 1
4.02
 getFreemiumPlan
100.00% covered (success)
100.00%
17 / 17
100.00% covered (success)
100.00%
1 / 1
1
 getPlanByIdentifier
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3namespace App\Http\Repositories;
4
5use App\Http\Models\Auth\User;
6use App\Http\Models\Plans;
7use App\Http\Models\Subscription;
8use App\Http\Repositories\interfaces\ISubscriptionRepository;
9
10/**
11 * Repository for subscription data access operations.
12 *
13 * This repository handles all database queries related to subscriptions,
14 * keeping data access logic separate from business logic.
15 */
16class SubscriptionRepository implements ISubscriptionRepository
17{
18    /**
19     * Get the active subscription for a user.
20     *
21     * This method fixes the bug where the original subscription() method
22     * could return a deactivated subscription. It queries all subscriptions
23     * ordered by created_at DESC and returns the first valid one.
24     *
25     * @param  User  $user  The user to get the subscription for
26     * @param  string  $name  The subscription name (default: 'main')
27     * @return Subscription|null The active subscription or null if none found
28     */
29    public function getActiveSubscription(User $user, string $name = 'main'): ?Subscription
30    {
31        $subscriptions = Subscription::where('user_id', $user->getKey())
32            ->where('name', $name)
33            ->orderBy('created_at', 'desc')
34            ->get();
35
36        foreach ($subscriptions as $subscription) {
37            if ($this->isSubscriptionValid($subscription)) {
38                return $subscription;
39            }
40        }
41
42        return null;
43    }
44
45    /**
46     * Check if a subscription is valid considering team plan specifics.
47     */
48    private function isSubscriptionValid(Subscription $subscription): bool
49    {
50        if (! $subscription->valid() || ! filled($subscription->plan)) {
51            return false;
52        }
53
54        $isTeamUser = in_array($subscription->plan->identifier, [
55            Plans::ProPlanTeamsSMB,
56            Plans::ProPlanTeamsENT,
57        ]);
58
59        if ($isTeamUser) {
60            return ! $subscription->proTeamEnded();
61        }
62
63        return true;
64    }
65
66    /**
67     * Get the freemium plan.
68     *
69     * @return Plans The freemium plan
70     */
71    public function getFreemiumPlan(): Plans
72    {
73        return Plans::select(
74            'title',
75            'identifier',
76            'features',
77            'currency',
78            'interval',
79            'unit_amount',
80            'user_persona_available',
81            'user_custom_prompts',
82            'has_fly_learning',
83            'regenerate_count',
84            'flygrammar_actions',
85            'flycut_deployment',
86            'prompts_per_day',
87            'can_disable_flygrammar',
88            'flycuts_features'
89        )->firstWhere('identifier', Plans::FREEMIUM_IDENTIFIER);
90    }
91
92    /**
93     * Get a plan by its identifier.
94     *
95     * @param  string  $identifier  The plan identifier
96     * @return Plans|null The plan or null if not found
97     */
98    public function getPlanByIdentifier(string $identifier): ?Plans
99    {
100        return Plans::firstWhere('identifier', $identifier);
101    }
102}