Completed
Push — master ( dd2d89...e4f576 )
by Abdelrahman
01:21
created

PlanSubscription::cancel()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 12
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 12
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 6
nc 2
nop 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Rinvex\Subscriptions\Models;
6
7
use DB;
8
use LogicException;
9
use Spatie\Sluggable\SlugOptions;
10
use Rinvex\Support\Traits\HasSlug;
11
use Illuminate\Database\Eloquent\Model;
12
use Rinvex\Cacheable\CacheableEloquent;
13
use Illuminate\Database\Eloquent\Builder;
14
use Rinvex\Subscriptions\Services\Period;
15
use Rinvex\Support\Traits\HasTranslations;
16
use Rinvex\Support\Traits\ValidatingTrait;
17
use Rinvex\Subscriptions\Traits\BelongsToPlan;
18
use Illuminate\Database\Eloquent\Relations\HasMany;
19
use Illuminate\Database\Eloquent\Relations\MorphTo;
20
21
/**
22
 * Rinvex\Subscriptions\Models\PlanSubscription.
23
 *
24
 * @property int                                                                                                $id
25
 * @property int                                                                                                $user_id
26
 * @property string                                                                                             $user_type
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 122 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
27
 * @property int                                                                                                $plan_id
28
 * @property string                                                                                             $slug
29
 * @property array                                                                                              $name
30
 * @property array                                                                                              $description
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 124 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
31
 * @property \Carbon\Carbon                                                                                     $trial_ends_at
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 126 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
32
 * @property \Carbon\Carbon                                                                                     $starts_at
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 122 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
33
 * @property \Carbon\Carbon                                                                                     $ends_at
34
 * @property \Carbon\Carbon                                                                                     $cancels_at
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 123 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
35
 * @property \Carbon\Carbon                                                                                     $canceled_at
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 124 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
36
 * @property \Carbon\Carbon                                                                                     $created_at
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 123 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
37
 * @property \Carbon\Carbon                                                                                     $updated_at
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 123 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
38
 * @property \Carbon\Carbon                                                                                     $deleted_at
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 123 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
39
 * @property-read \Rinvex\Subscriptions\Models\Plan                                                             $plan
40
 * @property-read \Illuminate\Database\Eloquent\Collection|\Rinvex\Subscriptions\Models\PlanSubscriptionUsage[] $usage
41
 * @property-read \Illuminate\Database\Eloquent\Model|\Eloquent                                                 $user
42
 *
43
 * @method static \Illuminate\Database\Eloquent\Builder|\Rinvex\Subscriptions\Models\PlanSubscription byPlanId($planId)
44
 * @method static \Illuminate\Database\Eloquent\Builder|\Rinvex\Subscriptions\Models\PlanSubscription findEndedPeriod()
45
 * @method static \Illuminate\Database\Eloquent\Builder|\Rinvex\Subscriptions\Models\PlanSubscription findEndedTrial()
46
 * @method static \Illuminate\Database\Eloquent\Builder|\Rinvex\Subscriptions\Models\PlanSubscription findEndingPeriod($dayRange = 3)
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 133 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
47
 * @method static \Illuminate\Database\Eloquent\Builder|\Rinvex\Subscriptions\Models\PlanSubscription findEndingTrial($dayRange = 3)
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 132 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
48
 * @method static \Illuminate\Database\Eloquent\Builder|\Rinvex\Subscriptions\Models\PlanSubscription ofUser(\Illuminate\Database\Eloquent\Model $user)
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 151 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
49
 * @method static \Illuminate\Database\Eloquent\Builder|\Rinvex\Subscriptions\Models\PlanSubscription whereCanceledAt($value)
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 125 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
50
 * @method static \Illuminate\Database\Eloquent\Builder|\Rinvex\Subscriptions\Models\PlanSubscription whereCancelsAt($value)
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 124 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
51
 * @method static \Illuminate\Database\Eloquent\Builder|\Rinvex\Subscriptions\Models\PlanSubscription whereCreatedAt($value)
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 124 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
52
 * @method static \Illuminate\Database\Eloquent\Builder|\Rinvex\Subscriptions\Models\PlanSubscription whereDeletedAt($value)
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 124 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
53
 * @method static \Illuminate\Database\Eloquent\Builder|\Rinvex\Subscriptions\Models\PlanSubscription whereDescription($value)
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 126 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
54
 * @method static \Illuminate\Database\Eloquent\Builder|\Rinvex\Subscriptions\Models\PlanSubscription whereEndsAt($value)
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 121 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
55
 * @method static \Illuminate\Database\Eloquent\Builder|\Rinvex\Subscriptions\Models\PlanSubscription whereId($value)
56
 * @method static \Illuminate\Database\Eloquent\Builder|\Rinvex\Subscriptions\Models\PlanSubscription whereName($value)
57
 * @method static \Illuminate\Database\Eloquent\Builder|\Rinvex\Subscriptions\Models\PlanSubscription wherePlanId($value)
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 121 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
58
 * @method static \Illuminate\Database\Eloquent\Builder|\Rinvex\Subscriptions\Models\PlanSubscription whereSlug($value)
59
 * @method static \Illuminate\Database\Eloquent\Builder|\Rinvex\Subscriptions\Models\PlanSubscription whereStartsAt($value)
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 123 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
60
 * @method static \Illuminate\Database\Eloquent\Builder|\Rinvex\Subscriptions\Models\PlanSubscription whereTrialEndsAt($value)
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 126 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
61
 * @method static \Illuminate\Database\Eloquent\Builder|\Rinvex\Subscriptions\Models\PlanSubscription whereUpdatedAt($value)
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 124 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
62
 * @method static \Illuminate\Database\Eloquent\Builder|\Rinvex\Subscriptions\Models\PlanSubscription whereUserId($value)
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 121 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
63
 * @method static \Illuminate\Database\Eloquent\Builder|\Rinvex\Subscriptions\Models\PlanSubscription whereUserType($value)
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 123 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
64
 * @mixin \Eloquent
65
 */
66
class PlanSubscription extends Model
67
{
68
    use HasSlug;
69
    use BelongsToPlan;
70
    use HasTranslations;
71
    use ValidatingTrait;
72
    use CacheableEloquent;
73
74
    /**
75
     * {@inheritdoc}
76
     */
77
    protected $fillable = [
78
        'user_id',
79
        'user_type',
80
        'plan_id',
81
        'slug',
82
        'name',
83
        'description',
84
        'trial_ends_at',
85
        'starts_at',
86
        'ends_at',
87
        'cancels_at',
88
        'canceled_at',
89
    ];
90
91
    /**
92
     * {@inheritdoc}
93
     */
94
    protected $casts = [
95
        'user_id' => 'integer',
96
        'user_type' => 'string',
97
        'plan_id' => 'integer',
98
        'slug' => 'string',
99
        'trial_ends_at' => 'datetime',
100
        'starts_at' => 'datetime',
101
        'ends_at' => 'datetime',
102
        'cancels_at' => 'datetime',
103
        'canceled_at' => 'datetime',
104
        'deleted_at' => 'datetime',
105
    ];
106
107
    /**
108
     * {@inheritdoc}
109
     */
110
    protected $observables = [
111
        'validating',
112
        'validated',
113
    ];
114
115
    /**
116
     * The attributes that are translatable.
117
     *
118
     * @var array
119
     */
120
    public $translatable = [
121
        'name',
122
        'description',
123
    ];
124
125
    /**
126
     * The default rules that the model will validate against.
127
     *
128
     * @var array
129
     */
130
    protected $rules = [];
131
132
    /**
133
     * Whether the model should throw a
134
     * ValidationException if it fails validation.
135
     *
136
     * @var bool
137
     */
138
    protected $throwValidationExceptions = true;
139
140
    /**
141
     * Create a new Eloquent model instance.
142
     *
143
     * @param array $attributes
144
     */
145
    public function __construct(array $attributes = [])
146
    {
147
        parent::__construct($attributes);
148
149
        $this->setTable(config('rinvex.subscriptions.tables.plan_subscriptions'));
150
        $this->setRules([
151
            'name' => 'required|string|max:150',
152
            'description' => 'nullable|string|max:10000',
153
            'slug' => 'required|alpha_dash|max:150|unique:'.config('rinvex.subscriptions.tables.plan_subscriptions').',slug',
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 125 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
154
            'plan_id' => 'required|integer|exists:'.config('rinvex.subscriptions.tables.plans').',id',
155
            'user_id' => 'required|integer',
156
            'user_type' => 'required|string',
157
            'trial_ends_at' => 'nullable|date',
158
            'starts_at' => 'required|date',
159
            'ends_at' => 'required|date',
160
            'cancels_at' => 'nullable|date',
161
            'canceled_at' => 'nullable|date',
162
        ]);
163
    }
164
165
    /**
166
     * {@inheritdoc}
167
     */
168
    protected static function boot()
169
    {
170
        parent::boot();
171
172
        static::validating(function (self $model) {
173
            if (! $model->starts_at || ! $model->ends_at) {
174
                $model->setNewPeriod();
175
            }
176
        });
177
    }
178
179
    /**
180
     * Get the options for generating the slug.
181
     *
182
     * @return \Spatie\Sluggable\SlugOptions
183
     */
184
    public function getSlugOptions(): SlugOptions
185
    {
186
        return SlugOptions::create()
187
                          ->doNotGenerateSlugsOnUpdate()
188
                          ->generateSlugsFrom('name')
189
                          ->saveSlugsTo('slug');
190
    }
191
192
    /**
193
     * Get the owning user.
194
     *
195
     * @return \Illuminate\Database\Eloquent\Relations\MorphTo
196
     */
197
    public function user(): MorphTo
198
    {
199
        return $this->morphTo();
200
    }
201
202
    /**
203
     * The subscription may have many usage.
204
     *
205
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
206
     */
207
    public function usage(): hasMany
208
    {
209
        return $this->hasMany(config('rinvex.subscriptions.models.plan_subscription_usage'), 'subscription_id', 'id');
210
    }
211
212
    /**
213
     * Check if subscription is active.
214
     *
215
     * @return bool
216
     */
217
    public function active(): bool
218
    {
219
        return ! $this->ended() || $this->onTrial();
220
    }
221
222
    /**
223
     * Check if subscription is inactive.
224
     *
225
     * @return bool
226
     */
227
    public function inactive(): bool
228
    {
229
        return ! $this->active();
230
    }
231
232
    /**
233
     * Check if subscription is currently on trial.
234
     *
235
     * @return bool
236
     */
237
    public function onTrial(): bool
238
    {
239
        return $this->trial_ends_at ? now()->lt($this->trial_ends_at) : false;
240
    }
241
242
    /**
243
     * Check if subscription is canceled.
244
     *
245
     * @return bool
246
     */
247
    public function canceled(): bool
248
    {
249
        return $this->canceled_at ? now()->gte($this->canceled_at) : false;
250
    }
251
252
    /**
253
     * Check if subscription period has ended.
254
     *
255
     * @return bool
256
     */
257
    public function ended(): bool
258
    {
259
        return $this->ends_at ? now()->gte($this->ends_at) : false;
260
    }
261
262
    /**
263
     * Cancel subscription.
264
     *
265
     * @param bool $immediately
266
     *
267
     * @return $this
268
     */
269
    public function cancel($immediately = false)
270
    {
271
        $this->canceled_at = now();
272
273
        if ($immediately) {
274
            $this->ends_at = $this->canceled_at;
275
        }
276
277
        $this->save();
278
279
        return $this;
280
    }
281
282
    /**
283
     * Change subscription plan.
284
     *
285
     * @param \Rinvex\Subscriptions\Models\Plan $plan
286
     *
287
     * @return $this
288
     */
289
    public function changePlan(Plan $plan)
290
    {
291
        // If plans does not have the same billing frequency
292
        // (e.g., invoice_interval and invoice_period) we will update
293
        // the billing dates starting today, and sice we are basically creating
294
        // a new billing cycle, the usage data will be cleared.
295
        if ($this->plan->invoice_interval !== $plan->invoice_interval || $this->plan->invoice_period !== $plan->invoice_period) {
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 129 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
296
            $this->setNewPeriod($plan->invoice_interval, $plan->invoice_period);
297
            $this->usage()->delete();
298
        }
299
300
        // Attach new plan to subscription
301
        $this->plan_id = $plan->getKey();
302
        $this->save();
303
304
        return $this;
305
    }
306
307
    /**
308
     * Renew subscription period.
309
     *
310
     * @throws \LogicException
311
     *
312
     * @return $this
313
     */
314
    public function renew()
315
    {
316
        if ($this->ended() && $this->canceled()) {
317
            throw new LogicException('Unable to renew canceled ended subscription.');
318
        }
319
320
        $subscription = $this;
321
322
        DB::transaction(function () use ($subscription) {
323
            // Clear usage data
324
            $subscription->usage()->delete();
325
326
            // Renew period
327
            $subscription->setNewPeriod();
328
            $subscription->canceled_at = null;
329
            $subscription->save();
330
        });
331
332
        return $this;
333
    }
334
335
    /**
336
     * Get bookings of the given user.
337
     *
338
     * @param \Illuminate\Database\Eloquent\Builder $builder
339
     * @param \Illuminate\Database\Eloquent\Model   $user
340
     *
341
     * @return \Illuminate\Database\Eloquent\Builder
342
     */
343
    public function scopeOfUser(Builder $builder, Model $user): Builder
344
    {
345
        return $builder->where('user_type', $user->getMorphClass())->where('user_id', $user->getKey());
346
    }
347
348
    /**
349
     * Scope subscriptions with ending trial.
350
     *
351
     * @param \Illuminate\Database\Eloquent\Builder $builder
352
     * @param int                                   $dayRange
353
     *
354
     * @return \Illuminate\Database\Eloquent\Builder
355
     */
356
    public function scopeFindEndingTrial(Builder $builder, int $dayRange = 3): Builder
357
    {
358
        $from = now();
359
        $to = now()->addDays($dayRange);
360
361
        return $builder->whereBetween('trial_ends_at', [$from, $to]);
362
    }
363
364
    /**
365
     * Scope subscriptions with ended trial.
366
     *
367
     * @param \Illuminate\Database\Eloquent\Builder $builder
368
     *
369
     * @return \Illuminate\Database\Eloquent\Builder
370
     */
371
    public function scopeFindEndedTrial(Builder $builder): Builder
372
    {
373
        return $builder->where('trial_ends_at', '<=', now());
374
    }
375
376
    /**
377
     * Scope subscriptions with ending periods.
378
     *
379
     * @param \Illuminate\Database\Eloquent\Builder $builder
380
     * @param int                                   $dayRange
381
     *
382
     * @return \Illuminate\Database\Eloquent\Builder
383
     */
384
    public function scopeFindEndingPeriod(Builder $builder, int $dayRange = 3): Builder
385
    {
386
        $from = now();
387
        $to = now()->addDays($dayRange);
388
389
        return $builder->whereBetween('ends_at', [$from, $to]);
390
    }
391
392
    /**
393
     * Scope subscriptions with ended periods.
394
     *
395
     * @param \Illuminate\Database\Eloquent\Builder $builder
396
     *
397
     * @return \Illuminate\Database\Eloquent\Builder
398
     */
399
    public function scopeFindEndedPeriod(Builder $builder): Builder
400
    {
401
        return $builder->where('ends_at', '<=', now());
402
    }
403
404
    /**
405
     * Set new subscription period.
406
     *
407
     * @param string $invoice_interval
408
     * @param int    $invoice_period
0 ignored issues
show
Documentation introduced by
Should the type for parameter $invoice_period not be string|integer?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
409
     * @param string $start
410
     *
411
     * @return $this
412
     */
413
    protected function setNewPeriod($invoice_interval = '', $invoice_period = '', $start = '')
414
    {
415
        if (empty($invoice_interval)) {
416
            $invoice_interval = $this->plan->invoice_interval;
417
        }
418
419
        if (empty($invoice_period)) {
420
            $invoice_period = $this->plan->invoice_period;
421
        }
422
423
        $period = new Period($invoice_interval, $invoice_period, $start);
424
425
        $this->starts_at = $period->getStartDate();
426
        $this->ends_at = $period->getEndDate();
427
428
        return $this;
429
    }
430
431
    /**
432
     * Record feature usage.
433
     *
434
     * @param string $featureSlug
435
     * @param int    $uses
436
     *
437
     * @return \Rinvex\Subscriptions\Models\PlanSubscriptionUsage
438
     */
439
    public function recordFeatureUsage(string $featureSlug, int $uses = 1, bool $incremental = true): PlanSubscriptionUsage
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 123 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
440
    {
441
        $feature = $this->plan->features()->where('slug', $featureSlug)->first();
442
443
        $usage = $this->usage()->firstOrNew([
444
            'subscription_id' => $this->getKey(),
445
            'feature_id' => $feature->getKey(),
446
        ]);
447
448
        if ($feature->resettable_period) {
449
            // Set expiration date when the usage record is new or doesn't have one.
450
            if (is_null($usage->valid_until)) {
451
                // Set date from subscription creation date so the reset
452
                // period match the period specified by the subscription's plan.
453
                $usage->valid_until = $feature->getResetDate($this->created_at);
454
            } elseif ($usage->expired()) {
455
                // If the usage record has been expired, let's assign
456
                // a new expiration date and reset the uses to zero.
457
                $usage->valid_until = $feature->getResetDate($usage->valid_until);
458
                $usage->used = 0;
459
            }
460
        }
461
462
        $usage->used = ($incremental ? $usage->used + $uses : $uses);
463
464
        $usage->save();
465
466
        return $usage;
467
    }
468
469
    /**
470
     * Reduce usage.
471
     *
472
     * @param string $featureSlug
473
     * @param int    $uses
474
     *
475
     * @return \Rinvex\Subscriptions\Models\PlanSubscriptionUsage|null
476
     */
477
    public function reduceFeatureUsage(string $featureSlug, int $uses = 1): ?PlanSubscriptionUsage
478
    {
479
        $usage = $this->usage()->byFeatureSlug($featureSlug)->first();
480
481
        if (is_null($usage)) {
482
            return null;
483
        }
484
485
        $usage->used = max($usage->used - $uses, 0);
486
487
        $usage->save();
488
489
        return $usage;
490
    }
491
492
    /**
493
     * Determine if the feature can be used.
494
     *
495
     * @param string $featureSlug
496
     *
497
     * @return bool
498
     */
499
    public function canUseFeature(string $featureSlug): bool
500
    {
501
        $featureValue = $this->getFeatureValue($featureSlug);
502
        $usage = $this->usage()->byFeatureSlug($featureSlug)->first();
503
504
        if ($featureValue === 'true') {
505
            return true;
506
        }
507
508
        // If the feature value is zero, let's return false since
509
        // there's no uses available. (useful to disable countable features)
510
        if ($usage->expired() || is_null($featureValue) || $featureValue === '0' || $featureValue === 'false') {
511
            return false;
512
        }
513
514
        // Check for available uses
515
        return $this->getFeatureRemainings($featureSlug) > 0;
516
    }
517
518
    /**
519
     * Get how many times the feature has been used.
520
     *
521
     * @param string $featureSlug
522
     *
523
     * @return int
524
     */
525
    public function getFeatureUsage(string $featureSlug): int
526
    {
527
        $usage = $this->usage()->byFeatureSlug($featureSlug)->first();
528
529
        return ! $usage->expired() ? $usage->used : 0;
530
    }
531
532
    /**
533
     * Get the available uses.
534
     *
535
     * @param string $featureSlug
536
     *
537
     * @return int
538
     */
539
    public function getFeatureRemainings(string $featureSlug): int
540
    {
541
        return $this->getFeatureValue($featureSlug) - $this->getFeatureUsage($featureSlug);
542
    }
543
544
    /**
545
     * Get feature value.
546
     *
547
     * @param string $featureSlug
548
     *
549
     * @return mixed
550
     */
551
    public function getFeatureValue(string $featureSlug)
552
    {
553
        $feature = $this->plan->features()->where('slug', $featureSlug)->first();
554
555
        return $feature->value ?? null;
556
    }
557
}
558