Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
96.00% covered (success)
96.00%
48 / 50
0.00% covered (danger)
0.00%
0 / 2
CRAP
0.00% covered (danger)
0.00%
0 / 1
PlanWithFeaturesResource
96.00% covered (success)
96.00%
48 / 50
0.00% covered (danger)
0.00%
0 / 2
7
0.00% covered (danger)
0.00%
0 / 1
 toArray
97.50% covered (success)
97.50%
39 / 40
0.00% covered (danger)
0.00%
0 / 1
2
 buildFeaturesMap
90.00% covered (success)
90.00%
9 / 10
0.00% covered (danger)
0.00%
0 / 1
5.03
1<?php
2
3namespace App\Http\Resources\v2;
4
5use Illuminate\Http\Request;
6use Illuminate\Http\Resources\Json\JsonResource;
7
8/**
9 * Resource for transforming Plans models with features for admin API responses.
10 *
11 * This resource includes all plan data plus the associated features
12 * from the plan_features pivot collection. Legacy fields are excluded.
13 *
14 * @property string $_id The plan ID
15 * @property string $title The plan title
16 * @property string $identifier The plan identifier
17 * @property string|null $stripe_id The Stripe price ID
18 * @property string|null $stripe_product_id The Stripe product ID
19 * @property bool|null $stripe_sync_enabled Whether Stripe sync is enabled
20 * @property \Carbon\Carbon|null $last_stripe_sync_at Last Stripe sync timestamp
21 * @property string|null $hubspot_name HubSpot plan name
22 * @property bool $has_fly_learning Whether FlyLearning is available
23 * @property int $user_custom_prompts Custom prompts limit
24 * @property int $user_persona_available Number of personas allowed
25 * @property bool $can_disable_flygrammar Whether user can disable FlyGrammar
26 * @property int $flycut_deployment FlyCut deployment daily quota
27 * @property int $flygrammar_actions FlyGrammar actions daily quota
28 * @property int $prompts_per_day AI prompts daily quota
29 * @property int $regenerate_count AI regeneration limit
30 * @property bool $is_active Whether the plan is active (no pricing version)
31 * @property int|null $active_subscriptions_count Count of active subscriptions (only present when include_subscription_counts=true)
32 * @property \Illuminate\Database\Eloquent\Collection|null $planFeatures The plan features
33 * @property \App\Http\Models\PlanHubspotConfig|null $hubspotConfig The HubSpot configuration
34 * @property \Carbon\Carbon|null $created_at When the plan was created
35 * @property \Carbon\Carbon|null $updated_at When the plan was last updated
36 */
37class PlanWithFeaturesResource extends JsonResource
38{
39    /**
40     * Transform the resource into an array.
41     *
42     * Excludes legacy fields (features, flycuts_features, legacy_features)
43     * from the response. Use plan_features relationship for feature data.
44     *
45     * @return array<string, mixed>
46     */
47    public function toArray(Request $request): array
48    {
49        return [
50            'id' => (string) $this->_id,
51            'title' => $this->title,
52            'identifier' => $this->identifier,
53            'stripe_id' => $this->stripe_id,
54            'stripe_product_id' => $this->stripe_product_id,
55            'stripe_sync_enabled' => (bool) $this->stripe_sync_enabled,
56            'last_stripe_sync_at' => $this->last_stripe_sync_at?->timestamp,
57            'hubspot_name' => $this->hubspot_name,
58            'currency' => $this->currency,
59            'interval' => $this->interval ?? 'one-time',
60            'unit_amount' => $this->unit_amount,
61            'has_fly_learning' => (bool) $this->has_fly_learning,
62            'user_custom_prompts' => (int) ($this->user_custom_prompts ?? 0),
63            'user_persona_available' => (int) ($this->user_persona_available ?? 0),
64            'can_disable_flygrammar' => (bool) $this->can_disable_flygrammar,
65            'flycut_deployment' => (int) ($this->flycut_deployment ?? 0),
66            'flygrammar_actions' => (int) ($this->flygrammar_actions ?? 0),
67            'prompts_per_day' => (int) ($this->prompts_per_day ?? 0),
68            'regenerate_count' => (int) ($this->regenerate_count ?? 0),
69            'is_active' => (bool) $this->is_active,
70            'features_count' => $this->relationLoaded('planFeatures')
71                ? $this->planFeatures->count()
72                : $this->planFeatures()->count(),
73            'active_subscriptions_count' => $this->when(
74                isset($this->active_subscriptions_count),
75                fn () => (int) $this->active_subscriptions_count
76            ),
77            'plan_features' => $this->whenLoaded('planFeatures', function () {
78                return PlanFeatureResource::collection($this->planFeatures);
79            }),
80            'features_map' => $this->when($this->relationLoaded('planFeatures'), function () {
81                return $this->buildFeaturesMap();
82            }),
83            'hubspot_config' => $this->whenLoaded('hubspotConfig', function () {
84                return new PlanHubspotConfigResource($this->hubspotConfig);
85            }),
86            'created_at' => $this->created_at?->timestamp,
87            'updated_at' => $this->updated_at?->timestamp,
88        ];
89    }
90
91    /**
92     * Build a map of feature keys to their values for easy access.
93     *
94     * @return array<string, mixed>
95     */
96    private function buildFeaturesMap(): array
97    {
98        if (! $this->planFeatures) {
99            return [];
100        }
101
102        $map = [];
103
104        foreach ($this->planFeatures as $planFeature) {
105            if ($planFeature->feature && $planFeature->is_enabled) {
106                $map[$planFeature->feature->key] = [
107                    'value' => $planFeature->value ?? $planFeature->feature->default_value,
108                    'description' => $planFeature->feature->description,
109                ];
110            }
111        }
112
113        return $map;
114    }
115}