diff --git a/app/Aggregates/MembershipAggregate.php b/app/Aggregates/MembershipAggregate.php index 843a2f03..96e40fa2 100644 --- a/app/Aggregates/MembershipAggregate.php +++ b/app/Aggregates/MembershipAggregate.php @@ -47,7 +47,7 @@ public function __construct() $booted = []; foreach (class_uses_recursive($class) as $trait) { - $method = 'boot'.class_basename($trait); + $method = 'boot' . class_basename($trait); if (method_exists($class, $method) && ! in_array($method, $booted)) { $this->$method(); @@ -234,6 +234,8 @@ public function deleteUserMembership($membership): static $this->recordThat(new UserMembershipDeleted($membership)); + $this->handleUserMembershipDeleted($membership['id']); + return $this; } diff --git a/app/Aggregates/MembershipTraits/Cards.php b/app/Aggregates/MembershipTraits/Cards.php index 040d5ee0..a16ec12a 100644 --- a/app/Aggregates/MembershipTraits/Cards.php +++ b/app/Aggregates/MembershipTraits/Cards.php @@ -26,7 +26,7 @@ trait Cards public Collection $cardsEverActivated; // Cards that have ever been activated. Cards are not removed on deactivation. - public function bootCards() + public function bootCards(): void { $this->cardsOnAccount = collect(); $this->cardsNeedingActivation = collect(); diff --git a/app/Aggregates/MembershipTraits/UserMembership.php b/app/Aggregates/MembershipTraits/UserMembership.php index 9da87f76..4458e253 100644 --- a/app/Aggregates/MembershipTraits/UserMembership.php +++ b/app/Aggregates/MembershipTraits/UserMembership.php @@ -9,6 +9,12 @@ trait UserMembership { public bool $activeFullMemberPlan = false; + public array $userMembershipIdToPlanId; + + public function bootUserMembership(): void + { + $this->userMembershipIdToPlanId = []; + } public function handleUserMembership($userMembership): void { @@ -17,6 +23,19 @@ public function handleUserMembership($userMembership): void } } + public function handleUserMembershipDeleted($userMembershipId): void + { + if (! array_key_exists($userMembershipId, $this->userMembershipIdToPlanId)) { + // This shouldn't happen, but we'd like to report the exception just in case so someone can investigate. + throw new \Exception("Did not find deleted user membership: $userMembershipId"); + } + + $planId = $this->userMembershipIdToPlanId[$userMembershipId]; + if ($planId == \App\Models\UserMembership::MEMBERSHIP_FULL_MEMBER) { + $this->deactivateMembershipIfNeeded(); + } + } + protected function handleFullMemberPlan($userMembership): void { $currentStatus = $userMembership['status']; @@ -47,6 +66,8 @@ protected function applyUserMembershipImported(UserMembershipImported $event): v protected function updateUserMembershipStatus($userMembership): void { + $this->userMembershipIdToPlanId[$userMembership['id']] = $userMembership['plan_id']; + if ($userMembership['plan_id'] == \App\Models\UserMembership::MEMBERSHIP_FULL_MEMBER) { if ($userMembership['status'] == 'active') { $this->activeFullMemberPlan = true; diff --git a/tests/Unit/Aggregates/MembershipAggregate/ActiveMembershipTest.php b/tests/Unit/Aggregates/MembershipAggregate/ActiveMembershipTest.php index 442e1f4f..5d6b66fb 100644 --- a/tests/Unit/Aggregates/MembershipAggregate/ActiveMembershipTest.php +++ b/tests/Unit/Aggregates/MembershipAggregate/ActiveMembershipTest.php @@ -10,6 +10,7 @@ use App\StorableEvents\WooCommerce\CustomerCreated; use App\StorableEvents\WooCommerce\CustomerUpdated; use App\StorableEvents\WooCommerce\UserMembershipCreated; +use App\StorableEvents\WooCommerce\UserMembershipDeleted; use App\StorableEvents\WooCommerce\UserMembershipUpdated; use Illuminate\Support\Facades\Event; use Spatie\EventSourcing\Facades\Projectionist; @@ -185,6 +186,52 @@ public function user_membership_from_active_to_expired_deactivates_membership(): ]); } + /** @test */ + public function user_membership_deleted_deactivates_membership(): void + { + $customer = $this->customer(); + + $oldUserMembership = $this->userMembership()->plan(UserMembership::MEMBERSHIP_FULL_MEMBER) + ->status('active'); + $deletedPayload = ['id' => $oldUserMembership->id]; + + MembershipAggregate::fakeCustomer($customer) + ->given([ + new CustomerCreated($customer), + new UserMembershipCreated($oldUserMembership), + new MembershipActivated($customer->id), + ]) + ->deleteUserMembership($deletedPayload) + ->assertRecorded([ + new UserMembershipDeleted($deletedPayload), + new MembershipDeactivated($customer->id), + ]); + } + + /** @test */ + public function user_membership_deleted_does_not_deactivate_if_plan_is_not_membership_plan(): void + { + $customer = $this->customer(); + + $userMembershipMember = $this->userMembership()->id(5)->plan(UserMembership::MEMBERSHIP_FULL_MEMBER) + ->status('active'); + $userMembership3DP = $this->userMembership()->id(6)->plan(UserMembership::MEMBERSHIP_3DP_USER) + ->status('active'); + $deletedPayload = ['id' => $userMembership3DP->id]; + + MembershipAggregate::fakeCustomer($customer) + ->given([ + new CustomerCreated($customer), + new UserMembershipCreated($userMembership3DP), + new UserMembershipCreated($userMembershipMember), + new MembershipActivated($customer->id), + ]) + ->deleteUserMembership($deletedPayload) + ->assertRecorded([ + new UserMembershipDeleted($deletedPayload), + ]); + } + /** @test */ public function user_membership_from_active_to_active_does_nothing(): void {