Completed
Push — develop ( c50c27...b28554 )
by Abdelrahman
01:13
created

PlanSubscription::inactive()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Rinvex\Subscriptions\Models;
6
7
use DB;
8
use Carbon\Carbon;
9
use LogicException;
10
use Spatie\Sluggable\SlugOptions;
11
use Rinvex\Support\Traits\HasSlug;
12
use Illuminate\Database\Eloquent\Model;
13
use Rinvex\Cacheable\CacheableEloquent;
14
use Illuminate\Database\Eloquent\Builder;
15
use Rinvex\Subscriptions\Services\Period;
16
use Rinvex\Support\Traits\HasTranslations;
17
use Rinvex\Support\Traits\ValidatingTrait;
18
use Rinvex\Subscriptions\Traits\BelongsToPlan;
19
use Illuminate\Database\Eloquent\Relations\HasMany;
20
use Illuminate\Database\Eloquent\Relations\BelongsTo;
21
use Rinvex\Subscriptions\Contracts\PlanSubscriptionContract;
22
23
/**
24
 * Rinvex\Subscriptions\Models\PlanSubscription.
25
 *
26
 * @property int                                                                                               $id
27
 * @property int                                                                                               $user_id
28
 * @property int                                                                                               $plan_id
29
 * @property string                                                                                            $slug
30
 * @property array                                                                                             $name
31
 * @property array                                                                                             $description
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...
32
 * @property \Carbon\Carbon                                                                                    $trial_ends_at
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...
33
 * @property \Carbon\Carbon                                                                                    $starts_at
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...
34
 * @property \Carbon\Carbon                                                                                    $ends_at
35
 * @property \Carbon\Carbon                                                                                    $cancels_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...
36
 * @property \Carbon\Carbon                                                                                    $canceled_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                                                                                    $created_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...
38
 * @property \Carbon\Carbon                                                                                    $updated_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...
39
 * @property \Carbon\Carbon                                                                                    $deleted_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...
40
 * @property-read \Rinvex\Subscriptions\Models\Plan                                                             $plan
41
 * @property-read \Illuminate\Database\Eloquent\Collection|\Rinvex\Subscriptions\Models\PlanSubscriptionUsage[] $usage
42
 * @property-read \Illuminate\Database\Eloquent\Model|\Eloquent                                                $user
43
 *
44
 * @method static \Illuminate\Database\Eloquent\Builder|\Rinvex\Subscriptions\Models\PlanSubscription byPlanId($planId)
45
 * @method static \Illuminate\Database\Eloquent\Builder|\Rinvex\Subscriptions\Models\PlanSubscription byUserId($userId)
46
 * @method static \Illuminate\Database\Eloquent\Builder|\Rinvex\Subscriptions\Models\PlanSubscription findEndedPeriod()
47
 * @method static \Illuminate\Database\Eloquent\Builder|\Rinvex\Subscriptions\Models\PlanSubscription findEndedTrial()
48
 * @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...
49
 * @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...
50
 * @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...
51
 * @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...
52
 * @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...
53
 * @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...
54
 * @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...
55
 * @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...
56
 * @method static \Illuminate\Database\Eloquent\Builder|\Rinvex\Subscriptions\Models\PlanSubscription whereId($value)
57
 * @method static \Illuminate\Database\Eloquent\Builder|\Rinvex\Subscriptions\Models\PlanSubscription whereName($value)
58
 * @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...
59
 * @method static \Illuminate\Database\Eloquent\Builder|\Rinvex\Subscriptions\Models\PlanSubscription whereSlug($value)
60
 * @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...
61
 * @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...
62
 * @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...
63
 * @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...
64
 * @mixin \Eloquent
65
 */
66
class PlanSubscription extends Model implements PlanSubscriptionContract
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
        'plan_id',
80
        'slug',
81
        'name',
82
        'description',
83
        'trial_ends_at',
84
        'starts_at',
85
        'ends_at',
86
        'cancels_at',
87
        'canceled_at',
88
    ];
89
90
    /**
91
     * {@inheritdoc}
92
     */
93
    protected $casts = [
94
        'user_id' => 'integer',
95
        'plan_id' => 'integer',
96
        'slug' => 'string',
97
        'trial_ends_at' => 'datetime',
98
        'starts_at' => 'datetime',
99
        'ends_at' => 'datetime',
100
        'cancels_at' => 'datetime',
101
        'canceled_at' => 'datetime',
102
        'deleted_at' => 'datetime',
103
    ];
104
105
    /**
106
     * {@inheritdoc}
107
     */
108
    protected $observables = [
109
        'validating',
110
        'validated',
111
    ];
112
113
    /**
114
     * The attributes that are translatable.
115
     *
116
     * @var array
117
     */
118
    public $translatable = [
119
        'name',
120
        'description',
121
    ];
122
123
    /**
124
     * The default rules that the model will validate against.
125
     *
126
     * @var array
127
     */
128
    protected $rules = [];
129
130
    /**
131
     * Whether the model should throw a
132
     * ValidationException if it fails validation.
133
     *
134
     * @var bool
135
     */
136
    protected $throwValidationExceptions = true;
137
138
    /**
139
     * Create a new Eloquent model instance.
140
     *
141
     * @param array $attributes
142
     */
143
    public function __construct(array $attributes = [])
144
    {
145
        parent::__construct($attributes);
146
147
        // Get users model
148
        $userModel = config('auth.providers.'.config('auth.guards.'.config('auth.defaults.guard').'.provider').'.model');
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...
149
150
        $this->setTable(config('rinvex.subscriptions.tables.plan_subscriptions'));
151
        $this->setRules([
152
            'name' => 'required|string|max:150',
153
            'description' => 'nullable|string|max:10000',
154
            '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...
155
            'plan_id' => 'required|integer|exists:'.config('rinvex.subscriptions.tables.plans').',id',
156
            'user_id' => 'required|integer|exists:'.(new $userModel())->getTable().',id',
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
     * Boot function for using with User Events.
167
     *
168
     * @return void
169
     */
170
    protected static function boot()
171
    {
172
        parent::boot();
173
174
        static::validating(function (self $model) {
175
            if (! $model->starts_at || ! $model->ends_at) {
176
                $model->setNewPeriod();
177
            }
178
        });
179
    }
180
181
    /**
182
     * Get the options for generating the slug.
183
     *
184
     * @return \Spatie\Sluggable\SlugOptions
185
     */
186
    public function getSlugOptions(): SlugOptions
187
    {
188
        return SlugOptions::create()
189
                          ->doNotGenerateSlugsOnUpdate()
190
                          ->generateSlugsFrom('name')
191
                          ->saveSlugsTo('slug');
192
    }
193
194
    /**
195
     * The subscription must always belongs to a user.
196
     *
197
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
198
     */
199
    public function user(): belongsTo
200
    {
201
        return $this->belongsTo(config('auth.providers.users.model'), 'user_id', 'id');
202
    }
203
204
    /**
205
     * The subscription may have many usage.
206
     *
207
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
208
     */
209
    public function usage(): hasMany
210
    {
211
        return $this->hasMany(config('rinvex.subscriptions.models.plan_subscription_usage'), 'subscription_id', 'id');
212
    }
213
214
    /**
215
     * Check if subscription is active.
216
     *
217
     * @return bool
218
     */
219
    public function active()
220
    {
221
        return ! $this->ended() || $this->onTrial();
222
    }
223
224
    /**
225
     * Check if subscription is inactive.
226
     *
227
     * @return bool
228
     */
229
    public function inactive()
230
    {
231
        return ! $this->active();
232
    }
233
234
    /**
235
     * Check if subscription is currently on trial.
236
     *
237
     * @return bool
238
     */
239
    public function onTrial(): bool
240
    {
241
        return $this->trial_ends_at ? Carbon::now()->lt($this->trial_ends_at) : false;
242
    }
243
244
    /**
245
     * Check if subscription is canceled.
246
     *
247
     * @return bool
248
     */
249
    public function canceled(): bool
250
    {
251
        return $this->canceled_at ? Carbon::now()->gte($this->canceled_at) : false;
252
    }
253
254
    /**
255
     * Check if subscription period has ended.
256
     *
257
     * @return bool
258
     */
259
    public function ended(): bool
260
    {
261
        return $this->ends_at ? Carbon::now()->gte($this->ends_at) : false;
262
    }
263
264
    /**
265
     * Cancel subscription.
266
     *
267
     * @param bool $immediately
268
     *
269
     * @return $this
270
     */
271
    public function cancel($immediately = false)
272
    {
273
        $this->canceled_at = Carbon::now();
274
275
        if ($immediately) {
276
            $this->ends_at = $this->canceled_at;
277
        }
278
279
        $this->save();
280
281
        return $this;
282
    }
283
284
    /**
285
     * Change subscription plan.
286
     *
287
     * @param \Rinvex\Subscriptions\Models\Plan $plan
288
     *
289
     * @return $this
290
     */
291
    public function changePlan(Plan $plan)
292
    {
293
        // If plans does not have the same billing frequency
294
        // (e.g., invoice_interval and invoice_period) we will update
295
        // the billing dates starting today, and sice we are basically creating
296
        // a new billing cycle, the usage data will be cleared.
297
        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...
298
            $this->setNewPeriod($plan->invoice_interval, $plan->invoice_period);
299
            $this->usage()->delete();
300
        }
301
302
        // Attach new plan to subscription
303
        $this->plan_id = $plan->id;
304
        $this->save();
305
306
        return $this;
307
    }
308
309
    /**
310
     * Renew subscription period.
311
     *
312
     * @throws \LogicException
313
     *
314
     * @return $this
315
     */
316
    public function renew()
317
    {
318
        if ($this->ended() && $this->canceled()) {
319
            throw new LogicException('Unable to renew canceled ended subscription.');
320
        }
321
322
        $subscription = $this;
323
324
        DB::transaction(function () use ($subscription) {
325
            // Clear usage data
326
            $subscription->usage()->delete();
327
328
            // Renew period
329
            $subscription->setNewPeriod();
330
            $subscription->canceled_at = null;
331
            $subscription->save();
332
        });
333
334
        return $this;
335
    }
336
337
    /**
338
     * Scope subscriptions by user id.
339
     *
340
     * @param \Illuminate\Database\Eloquent\Builder $builder
341
     * @param int                                   $userId
342
     *
343
     * @return \Illuminate\Database\Eloquent\Builder
344
     */
345
    public function scopeByUserId(Builder $builder, int $userId): Builder
346
    {
347
        return $builder->where('user_id', $userId);
348
    }
349
350
    /**
351
     * Scope subscriptions with ending trial.
352
     *
353
     * @param \Illuminate\Database\Eloquent\Builder $builder
354
     * @param int                                   $dayRange
355
     *
356
     * @return \Illuminate\Database\Eloquent\Builder
357
     */
358
    public function scopeFindEndingTrial(Builder $builder, int $dayRange = 3): Builder
359
    {
360
        $from = Carbon::now();
361
        $to = Carbon::now()->addDays($dayRange);
362
363
        return $builder->whereBetween('trial_ends_at', [$from, $to]);
364
    }
365
366
    /**
367
     * Scope subscriptions with ended trial.
368
     *
369
     * @param \Illuminate\Database\Eloquent\Builder $builder
370
     *
371
     * @return \Illuminate\Database\Eloquent\Builder
372
     */
373
    public function scopeFindEndedTrial(Builder $builder): Builder
374
    {
375
        return $builder->where('trial_ends_at', '<=', Carbon::now());
376
    }
377
378
    /**
379
     * Scope subscriptions with ending periods.
380
     *
381
     * @param \Illuminate\Database\Eloquent\Builder $builder
382
     * @param int                                   $dayRange
383
     *
384
     * @return \Illuminate\Database\Eloquent\Builder
385
     */
386
    public function scopeFindEndingPeriod(Builder $builder, int $dayRange = 3): Builder
387
    {
388
        $from = Carbon::now();
389
        $to = Carbon::now()->addDays($dayRange);
390
391
        return $builder->whereBetween('ends_at', [$from, $to]);
392
    }
393
394
    /**
395
     * Scope subscriptions with ended periods.
396
     *
397
     * @param \Illuminate\Database\Eloquent\Builder $builder
398
     *
399
     * @return \Illuminate\Database\Eloquent\Builder
400
     */
401
    public function scopeFindEndedPeriod(Builder $builder): Builder
402
    {
403
        return $builder->where('ends_at', '<=', Carbon::now());
404
    }
405
406
    /**
407
     * Set new subscription period.
408
     *
409
     * @param string $invoice_interval
410
     * @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...
411
     * @param string $start
412
     *
413
     * @return $this
414
     */
415
    protected function setNewPeriod($invoice_interval = '', $invoice_period = '', $start = '')
416
    {
417
        if (empty($invoice_interval)) {
418
            $invoice_interval = $this->plan->invoice_interval;
419
        }
420
421
        if (empty($invoice_period)) {
422
            $invoice_period = $this->plan->invoice_period;
423
        }
424
425
        $period = new Period($invoice_interval, $invoice_period, $start);
426
427
        $this->starts_at = $period->getStartDate();
428
        $this->ends_at = $period->getEndDate();
429
430
        return $this;
431
    }
432
433
    /**
434
     * Record feature usage.
435
     *
436
     * @param string $featureSlug
437
     * @param int    $uses
438
     *
439
     * @return \Rinvex\Subscriptions\Models\PlanSubscriptionUsage
440
     */
441
    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...
442
    {
443
        $feature = $this->plan->features()->where('slug', $featureSlug)->first();
444
445
        $usage = $this->usage()->firstOrNew([
446
            'subscription_id' => $this->id,
447
            'feature_id' => $feature->id,
448
        ]);
449
450
        if ($feature->resettable_period) {
451
            // Set expiration date when the usage record is new or doesn't have one.
452
            if (is_null($usage->valid_until)) {
453
                // Set date from subscription creation date so the reset
454
                // period match the period specified by the subscription's plan.
455
                $usage->valid_until = $feature->getResetDate($this->created_at);
456
            } elseif ($usage->expired()) {
457
                // If the usage record has been expired, let's assign
458
                // a new expiration date and reset the uses to zero.
459
                $usage->valid_until = $feature->getResetDate($usage->valid_until);
460
                $usage->used = 0;
461
            }
462
        }
463
464
        $usage->used = ($incremental ? $usage->used + $uses : $uses);
465
466
        $usage->save();
467
468
        return $usage;
469
    }
470
471
    /**
472
     * Reduce usage.
473
     *
474
     * @param string $featureSlug
475
     * @param int    $uses
476
     *
477
     * @return \Rinvex\Subscriptions\Models\PlanSubscriptionUsage|null
478
     */
479
    public function reduceFeatureUsage(string $featureSlug, int $uses = 1)
480
    {
481
        $usage = $this->usage()->byFeatureSlug($featureSlug)->first();
482
483
        if (is_null($usage)) {
484
            return;
485
        }
486
487
        $usage->used = max($usage->used - $uses, 0);
488
489
        $usage->save();
490
491
        return $usage;
492
    }
493
494
    /**
495
     * Determine if the feature can be used.
496
     *
497
     * @param string $featureSlug
498
     *
499
     * @return bool
500
     */
501
    public function canUseFeature(string $featureSlug): bool
502
    {
503
        $featureValue = $this->getFeatureValue($featureSlug);
504
        $usage = $this->usage()->byFeatureSlug($featureSlug)->first();
505
506
        if ($featureValue === 'true') {
507
            return true;
508
        }
509
510
        // If the feature value is zero, let's return false since
511
        // there's no uses available. (useful to disable countable features)
512
        if ($usage->expired() || is_null($featureValue) || $featureValue === '0' || $featureValue === 'false') {
513
            return false;
514
        }
515
516
        // Check for available uses
517
        return $this->getFeatureRemainings($featureSlug) > 0;
518
    }
519
520
    /**
521
     * Get how many times the feature has been used.
522
     *
523
     * @param string $featureSlug
524
     *
525
     * @return int
526
     */
527
    public function getFeatureUsage(string $featureSlug): int
528
    {
529
        $usage = $this->usage()->byFeatureSlug($featureSlug)->first();
530
531
        return ! $usage->expired() ? $usage->used : 0;
532
    }
533
534
    /**
535
     * Get the available uses.
536
     *
537
     * @param string $featureSlug
538
     *
539
     * @return int
540
     */
541
    public function getFeatureRemainings(string $featureSlug): int
542
    {
543
        return $this->getFeatureValue($featureSlug) - $this->getFeatureUsage($featureSlug);
544
    }
545
546
    /**
547
     * Get feature value.
548
     *
549
     * @param string $featureSlug
550
     *
551
     * @return mixed
552
     */
553
    public function getFeatureValue(string $featureSlug)
554
    {
555
        $feature = $this->plan->features()->where('slug', $featureSlug)->first();
556
557
        return $feature->value ?? null;
558
    }
559
}
560