Skip to content

Commit 14b72c7

Browse files
committed
Merge branch 'release/1.0.1' into main
2 parents a7ae78e + d2cf814 commit 14b72c7

15 files changed

+364
-131
lines changed

database/factories/FeatureConsumptionFactory.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ public function definition()
2020
return [
2121
'feature_id' => Feature::factory(),
2222
'consumption' => $this->faker->randomFloat(),
23-
'expires_at' => $this->faker->dateTime(),
23+
'expired_at' => $this->faker->dateTime(),
2424
];
2525
}
2626
}

database/factories/SubscriptionFactory.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ public function definition()
2222
'canceled_at' => null,
2323
'started_at' => $this->faker->dateTime(),
2424
'suppressed_at' => null,
25-
'expires_at' => $this->faker->dateTime(),
25+
'expired_at' => $this->faker->dateTime(),
2626
'was_switched' => false,
2727
];
2828
}
@@ -34,7 +34,7 @@ public function canceled()
3434
]);
3535
}
3636

37-
public function uncanceled()
37+
public function NotCanceled()
3838
{
3939
return $this->state(fn (array $attributes) => [
4040
'canceled_at' => null,
@@ -44,7 +44,7 @@ public function uncanceled()
4444
public function expired()
4545
{
4646
return $this->state(fn (array $attributes) => [
47-
'expires_at' => $this->faker->dateTime(),
47+
'expired_at' => $this->faker->dateTime(),
4848
]);
4949
}
5050

@@ -69,7 +69,7 @@ public function suppressed()
6969
]);
7070
}
7171

72-
public function unsuppressed()
72+
public function NotSuppressed()
7373
{
7474
return $this->state(fn (array $attributes) => [
7575
'suppressed_at' => null,

database/migrations/2022_02_01_235539_create_subscriptions_table.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public function up()
1717
$table->id();
1818
$table->foreignIdFor(\LucasDotDev\Soulbscription\Models\Plan::class);
1919
$table->timestamp('canceled_at')->nullable();
20-
$table->timestamp('expires_at');
20+
$table->timestamp('expired_at');
2121
$table->date('started_at');
2222
$table->timestamp('suppressed_at')->nullable();
2323
$table->boolean('was_switched')->default(false);

database/migrations/2022_02_02_000527_create_feature_consumptions_table.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ public function up()
1515
Schema::create('feature_consumptions', function (Blueprint $table) {
1616
$table->id();
1717
$table->unsignedDecimal('consumption')->nullable();
18-
$table->timestamp('expires_at')->nullable();
18+
$table->timestamp('expired_at')->nullable();
1919
$table->foreignIdFor(\LucasDotDev\Soulbscription\Models\Feature::class)->constrained()->cascadeOnDelete();
2020
$table->timestamps();
2121

src/Models/Concerns/Expires.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
namespace LucasDotDev\Soulbscription\Models\Concerns;
4+
5+
use LucasDotDev\Soulbscription\Models\Scopes\ExpiringScope;
6+
7+
trait Expires
8+
{
9+
public static function bootExpires()
10+
{
11+
static::addGlobalScope(new ExpiringScope());
12+
}
13+
14+
public function initializeExpires()
15+
{
16+
if (! isset($this->casts['expired_at'])) {
17+
$this->casts['expired_at'] = 'datetime';
18+
}
19+
}
20+
21+
public function expired()
22+
{
23+
return ! is_null($this->expired_at);
24+
}
25+
26+
public function notExpired()
27+
{
28+
return is_null($this->expired_at);
29+
}
30+
}

src/Models/Concerns/HasSubscriptions.php

Lines changed: 13 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
namespace LucasDotDev\Soulbscription\Models\Concerns;
44

5-
use Illuminate\Database\Eloquent\Builder;
65
use LucasDotDev\Soulbscription\Models\Feature;
76
use LucasDotDev\Soulbscription\Models\FeatureConsumption;
87
use LucasDotDev\Soulbscription\Models\Plan;
@@ -13,44 +12,19 @@
1312

1413
trait HasSubscriptions
1514
{
16-
public function activePlans()
17-
{
18-
return $this->plans()
19-
->wherePivot('expires_at', '>', now());
20-
}
21-
2215
public function featureConsumptions()
2316
{
2417
return $this->morphMany(FeatureConsumption::class, 'subscriber');
2518
}
2619

27-
public function plans()
28-
{
29-
return $this->belongsToMany(Plan::class, 'subscriptions', 'subscriber_id')
30-
->as('subscription')
31-
->withPivot([
32-
'canceled_at',
33-
'expires_at',
34-
'started_at',
35-
'suppressed_at',
36-
'was_switched',
37-
])
38-
->withTimestamps();
39-
}
40-
4120
public function renewals()
4221
{
4322
return $this->hasManyThrough(SubscriptionRenewal::class, Subscription::class, 'subscriber_id');
4423
}
4524

4625
public function subscription()
4726
{
48-
return $this->morphOne(Subscription::class, 'subscriber')->ofMany(
49-
[
50-
'started_at' => 'max',
51-
],
52-
fn (Builder $query) => $query->started(),
53-
);
27+
return $this->morphOne(Subscription::class, 'subscriber')->ofMany('started_at', 'MAX');
5428
}
5529

5630
public function canConsume($featureName, ?float $consumption = null): bool
@@ -65,7 +39,6 @@ public function canConsume($featureName, ?float $consumption = null): bool
6539

6640
$currentConsumption = $this->featureConsumptions()
6741
->whereBelongsTo($feature)
68-
->unexpired()
6942
->sum('consumption');
7043

7144
return ($currentConsumption + $consumption) <= $feature->pivot->charges;
@@ -100,17 +73,16 @@ public function consume($featureName, ?float $consumption = null)
10073
'The feature has no enough charges to this consumption.',
10174
));
10275

103-
$consumedPlan = $this->activePlans->first(fn (Plan $plan) => $plan->features->firstWhere('name', $featureName));
104-
$feature = $consumedPlan->features->firstWhere('name', $featureName);
76+
$feature = $this->subscription->plan->features->firstWhere('name', $featureName);
10577

10678
$consumptionExpiration = $feature->consumable
107-
? $feature->calculateNextRecurrenceEnd($consumedPlan->subscription->started_at)
79+
? $feature->calculateNextRecurrenceEnd($this->subscription->started_at)
10880
: null;
10981

11082
$this->featureConsumptions()
11183
->make([
11284
'consumption' => $consumption,
113-
'expires_at' => $consumptionExpiration,
85+
'expired_at' => $consumptionExpiration,
11486
])
11587
->feature()
11688
->associate($feature)
@@ -123,12 +95,10 @@ public function subscribeTo(Plan $plan, $expiration = null, $startDate = null):
12395

12496
return tap(
12597
$this->subscription()
126-
->make([
127-
'expires_at' => $expiration,
128-
])
98+
->make(['expired_at' => $expiration])
12999
->start($startDate)
130100
->plan()
131-
->associate($plan),
101+
->associate($plan)
132102
)->save();
133103
}
134104

@@ -147,17 +117,20 @@ public function switchTo(Plan $plan, $expiration = null, $immediately = true): S
147117
->markAsSwitched()
148118
->save();
149119

150-
$startDate = $this->subscription->expires_at;
120+
$startDate = $this->subscription->expired_at;
151121

152122
return $this->subscribeTo($plan, startDate: $startDate);
153123
}
154124

155125
private function getAvailableFeature(string $featureName): ?Feature
156126
{
157-
$this->loadMissing('activePlans.features');
127+
$this->loadMissing('subscription.plan.features');
128+
129+
if (empty($this->subscription)) {
130+
return null;
131+
}
158132

159-
$availableFeatures = $this->activePlans->flatMap(fn (Plan $plan) => $plan->features);
160-
$feature = $availableFeatures->firstWhere('name', $featureName);
133+
$feature = $this->subscription->plan->features->firstWhere('name', $featureName);
161134

162135
return $feature;
163136
}

src/Models/Concerns/Starts.php

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
3+
namespace LucasDotDev\Soulbscription\Models\Concerns;
4+
5+
use Illuminate\Support\Carbon;
6+
use LucasDotDev\Soulbscription\Models\Scopes\StartingScope;
7+
8+
trait Starts
9+
{
10+
public static function bootStarts()
11+
{
12+
static::addGlobalScope(new StartingScope());
13+
}
14+
15+
public function initializeStarts()
16+
{
17+
if (! isset($this->casts['started_at'])) {
18+
$this->casts['started_at'] = 'datetime';
19+
}
20+
}
21+
22+
public function start(?Carbon $startDate = null)
23+
{
24+
return $this->fill([
25+
'started_at' => $startDate ?: today(),
26+
]);
27+
}
28+
29+
public function started()
30+
{
31+
return ! is_null($this->started_at);
32+
}
33+
34+
public function notStarted()
35+
{
36+
return is_null($this->started_at);
37+
}
38+
}

src/Models/Concerns/Suppresses.php

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
3+
namespace LucasDotDev\Soulbscription\Models\Concerns;
4+
5+
use Illuminate\Support\Carbon;
6+
use LucasDotDev\Soulbscription\Models\Scopes\SuppressingScope;
7+
8+
trait Suppresses
9+
{
10+
public static function bootSuppresses()
11+
{
12+
static::addGlobalScope(new SuppressingScope());
13+
}
14+
15+
public function initializeSuppresses()
16+
{
17+
if (! isset($this->casts['suppressed_at'])) {
18+
$this->casts['suppressed_at'] = 'datetime';
19+
}
20+
}
21+
22+
public function suppress(?Carbon $suppressation = null)
23+
{
24+
return $this->fill([
25+
'suppressed_at' => $suppressation ?: now(),
26+
]);
27+
}
28+
29+
public function suppressed()
30+
{
31+
return ! is_null($this->suppressed_at);
32+
}
33+
34+
public function notSuppressed()
35+
{
36+
return is_null($this->suppressed_at);
37+
}
38+
}

src/Models/FeatureConsumption.php

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,18 @@
22

33
namespace LucasDotDev\Soulbscription\Models;
44

5-
use Illuminate\Database\Eloquent\Builder;
65
use Illuminate\Database\Eloquent\Factories\HasFactory;
76
use Illuminate\Database\Eloquent\Model;
7+
use LucasDotDev\Soulbscription\Models\Concerns\Expires;
88

99
class FeatureConsumption extends Model
1010
{
11+
use Expires;
1112
use HasFactory;
1213

13-
protected $dates = [
14-
'expires_at',
15-
];
16-
1714
protected $fillable = [
1815
'consumption',
19-
'expires_at',
16+
'expired_at',
2017
];
2118

2219
public function feature()
@@ -28,14 +25,4 @@ public function subscriber()
2825
{
2926
return $this->morphTo('subscriber');
3027
}
31-
32-
public function scopeExpired(Builder $query)
33-
{
34-
return $query->where('expires_at', '<', now());
35-
}
36-
37-
public function scopeUnexpired(Builder $query)
38-
{
39-
return $query->where('expires_at', '>', now());
40-
}
4128
}

0 commit comments

Comments
 (0)