diff --git a/src/tests/Feature/BillingTest.php b/src/tests/Feature/BillingTest.php deleted file mode 100644 --- a/src/tests/Feature/BillingTest.php +++ /dev/null @@ -1,261 +0,0 @@ -deleteTestUser('jane@kolabnow.com'); - $this->deleteTestUser('jack@kolabnow.com'); - - \App\Package::withEnvTenantContext()->where('title', 'kolab-kube')->delete(); - - $this->user = $this->getTestUser('jane@kolabnow.com'); - $this->package = \App\Package::withEnvTenantContext()->where('title', 'kolab')->first(); - $this->user->assignPackage($this->package); - - $this->wallet = $this->user->wallets->first(); - - $this->wallet_id = $this->wallet->id; - } - - public function tearDown(): void - { - $this->deleteTestUser('jane@kolabnow.com'); - $this->deleteTestUser('jack@kolabnow.com'); - - \App\Package::withEnvTenantContext()->where('title', 'kolab-kube')->delete(); - - parent::tearDown(); - } - - /** - * Test the expected results for a user that registers and is almost immediately gone. - */ - public function testTouchAndGo(): void - { - $this->assertCount(7, $this->wallet->entitlements); - - $this->assertEquals(0, $this->wallet->expectedCharges()); - - $this->user->delete(); - - $this->assertCount(0, $this->wallet->fresh()->entitlements->where('deleted_at', null)); - - $this->assertCount(7, $this->wallet->entitlements); - } - - /** - * Verify the last day before the end of a full month's trial. - */ - public function testNearFullTrial(): void - { - $this->backdateEntitlements( - $this->wallet->entitlements, - Carbon::now()->subMonthsWithoutOverflow(1)->addDays(1) - ); - - $this->assertEquals(0, $this->wallet->expectedCharges()); - } - - /** - * Verify the exact end of the month's trial. - */ - public function testFullTrial(): void - { - $this->backdateEntitlements( - $this->wallet->entitlements, - Carbon::now()->subMonthsWithoutOverflow(1) - ); - - $this->assertEquals(990, $this->wallet->expectedCharges()); - } - - /** - * Verify that over-running the trial by a single day causes charges to be incurred. - */ - public function testOutRunTrial(): void - { - $this->backdateEntitlements( - $this->wallet->entitlements, - Carbon::now()->subMonthsWithoutOverflow(1)->subDays(1) - ); - - $this->assertEquals(990, $this->wallet->expectedCharges()); - } - - /** - * Verify additional storage configuration entitlement created 'early' does incur additional - * charges to the wallet. - */ - public function testAddtStorageEarly(): void - { - $this->backdateEntitlements( - $this->wallet->entitlements, - Carbon::now()->subMonthsWithoutOverflow(1)->subDays(1) - ); - - $this->assertEquals(990, $this->wallet->expectedCharges()); - - $sku = \App\Sku::withEnvTenantContext()->where('title', 'storage')->first(); - - $entitlement = \App\Entitlement::create( - [ - 'wallet_id' => $this->wallet_id, - 'sku_id' => $sku->id, - 'cost' => $sku->cost, - 'entitleable_id' => $this->user->id, - 'entitleable_type' => \App\User::class - ] - ); - - $this->backdateEntitlements( - [$entitlement], - Carbon::now()->subMonthsWithoutOverflow(1)->subDays(1) - ); - - $this->assertEquals(1015, $this->wallet->expectedCharges()); - } - - /** - * Verify additional storage configuration entitlement created 'late' does not incur additional - * charges to the wallet. - */ - public function testAddtStorageLate(): void - { - $this->backdateEntitlements($this->wallet->entitlements, Carbon::now()->subMonthsWithoutOverflow(1)); - - $this->assertEquals(990, $this->wallet->expectedCharges()); - - $sku = \App\Sku::withEnvTenantContext()->where(['title' => 'storage'])->first(); - - $entitlement = \App\Entitlement::create( - [ - 'wallet_id' => $this->wallet_id, - 'sku_id' => $sku->id, - 'cost' => $sku->cost, - 'entitleable_id' => $this->user->id, - 'entitleable_type' => \App\User::class - ] - ); - - $this->backdateEntitlements([$entitlement], Carbon::now()->subDays(14)); - - $this->assertEquals(990, $this->wallet->expectedCharges()); - } - - public function testFifthWeek(): void - { - $targetDateA = Carbon::now()->subWeeks(5); - $targetDateB = $targetDateA->copy()->addMonthsWithoutOverflow(1); - - $this->backdateEntitlements($this->wallet->entitlements, $targetDateA); - - $this->assertEquals(990, $this->wallet->expectedCharges()); - - $this->wallet->chargeEntitlements(); - - $this->assertEquals(-990, $this->wallet->balance); - - foreach ($this->wallet->entitlements()->get() as $entitlement) { - $this->assertTrue($entitlement->created_at->isSameSecond($targetDateA)); - $this->assertTrue($entitlement->updated_at->isSameSecond($targetDateB)); - } - } - - public function testSecondMonth(): void - { - $this->backdateEntitlements($this->wallet->entitlements, Carbon::now()->subMonthsWithoutOverflow(2)); - - $this->assertCount(7, $this->wallet->entitlements); - - $this->assertEquals(1980, $this->wallet->expectedCharges()); - - $sku = \App\Sku::withEnvTenantContext()->where('title', 'storage')->first(); - - $entitlement = \App\Entitlement::create( - [ - 'entitleable_id' => $this->user->id, - 'entitleable_type' => \App\User::class, - 'cost' => $sku->cost, - 'sku_id' => $sku->id, - 'wallet_id' => $this->wallet_id - ] - ); - - $this->backdateEntitlements([$entitlement], Carbon::now()->subMonthsWithoutOverflow(1)); - - $this->assertEquals(2005, $this->wallet->expectedCharges()); - } - - public function testWithDiscountRate(): void - { - $package = \App\Package::create( - [ - 'title' => 'kolab-kube', - 'name' => 'Kolab for Kuba Fans', - 'description' => 'Kolab for Kube fans', - 'discount_rate' => 50 - ] - ); - - $skus = [ - \App\Sku::withEnvTenantContext()->where('title', 'mailbox')->first(), - \App\Sku::withEnvTenantContext()->where('title', 'storage')->first(), - \App\Sku::withEnvTenantContext()->where('title', 'groupware')->first() - ]; - - $package->skus()->saveMany($skus); - - $package->skus()->updateExistingPivot( - \App\Sku::withEnvTenantContext()->where('title', 'storage')->first(), - ['qty' => 5], - false - ); - - $user = $this->getTestUser('jack@kolabnow.com'); - - $user->assignPackage($package); - - $wallet = $user->wallets->first(); - - $wallet_id = $wallet->id; - - $this->backdateEntitlements($wallet->entitlements, Carbon::now()->subMonthsWithoutOverflow(1)); - - $this->assertEquals(495, $wallet->expectedCharges()); - } - - /** - * Test cost calculation with a wallet discount - */ - public function testWithWalletDiscount(): void - { - $discount = \App\Discount::withEnvTenantContext()->where('code', 'TEST')->first(); - - $wallet = $this->user->wallets()->first(); - $wallet->discount()->associate($discount); - - $this->backdateEntitlements($wallet->entitlements, Carbon::now()->subMonthsWithoutOverflow(1)); - - $this->assertEquals(891, $wallet->expectedCharges()); - } -} diff --git a/src/tests/Feature/DomainOwnerTest.php b/src/tests/Feature/DomainOwnerTest.php deleted file mode 100644 --- a/src/tests/Feature/DomainOwnerTest.php +++ /dev/null @@ -1,53 +0,0 @@ -deleteTestUser('jane@kolab.org'); - } - - /** - * {@inheritDoc} - */ - public function tearDown(): void - { - $this->deleteTestUser('jane@kolab.org'); - - parent::tearDown(); - } - - public function testJohnCreateJane(): void - { - $john = User::where('email', 'john@kolab.org')->first(); - - $jane = User::create( - [ - 'name' => 'Jane Doe', - 'email' => 'jane@kolab.org', - 'password' => 'simple123', - 'email_verified_at' => now() - ] - ); - - $package = \App\Package::withEnvTenantContext()->where('title', 'kolab')->first(); - $mailbox_sku = \App\Sku::withEnvTenantContext()->where('title', 'mailbox')->first(); - - $john->assignPackage($package, $jane); - - // assert jane has a mailbox entitlement - $this->assertCount(7, $jane->entitlements); - $this->assertCount(1, $jane->entitlements()->where('sku_id', $mailbox_sku->id)->get()); - } -} diff --git a/src/tests/Feature/WalletTest.php b/src/tests/Feature/WalletTest.php --- a/src/tests/Feature/WalletTest.php +++ b/src/tests/Feature/WalletTest.php @@ -23,12 +23,6 @@ 'UserWallet1@UserWallet.com', 'UserWallet2@UserWallet.com', 'UserWallet3@UserWallet.com', - 'UserWallet4@UserWallet.com', - 'UserWallet5@UserWallet.com', - 'WalletControllerA@WalletController.com', - 'WalletControllerB@WalletController.com', - 'WalletController2A@WalletController.com', - 'WalletController2B@WalletController.com', 'jane@kolabnow.com' ]; @@ -74,7 +68,7 @@ { Queue::fake(); - $user = $this->getTestUser('UserWallet1@UserWallet.com'); + $user = $this->getTestUser('jane@kolabnow.com'); $user->suspend(); $user->degrade(); @@ -96,7 +90,6 @@ $this->assertNull($wallet->getSetting('balance_negative_since')); // Test un-restricting users on balance change - $this->deleteTestUser('UserWallet1@UserWallet.com'); $owner = $this->getTestUser('UserWallet1@UserWallet.com'); $user1 = $this->getTestUser('UserWallet2@UserWallet.com'); $user2 = $this->getTestUser('UserWallet3@UserWallet.com'); @@ -185,27 +178,20 @@ } /** - * Verify a wallet is created, when a user is created. + * Basic wallet features */ - public function testCreateUserCreatesWallet(): void + public function testWallet(): void { + // Verify a wallet is created, when a user is created. $user = $this->getTestUser('UserWallet1@UserWallet.com'); $this->assertCount(1, $user->wallets); $this->assertSame(\config('app.currency'), $user->wallets[0]->currency); $this->assertSame(0, $user->wallets[0]->balance); - } - /** - * Verify a user can haz more wallets. - */ - public function testAddWallet(): void - { - $user = $this->getTestUser('UserWallet2@UserWallet.com'); - - $user->wallets()->save( - new Wallet(['currency' => 'USD']) - ); + // Verify a user can haz more wallets. + $user->wallets()->save(new Wallet(['currency' => 'USD'])); + $user->refresh(); $this->assertCount(2, $user->wallets); @@ -217,15 +203,8 @@ // For now all wallets use system currency $this->assertFalse($user->wallets()->where('currency', 'USD')->exists()); - } - - /** - * Verify we can not delete a user wallet that holds balance. - */ - public function testDeleteWalletWithCredit(): void - { - $user = $this->getTestUser('UserWallet3@UserWallet.com'); + // Verify we can not delete a user wallet that holds balance. $user->wallets()->each( function ($wallet) { $wallet->credit(100)->save(); @@ -237,46 +216,18 @@ $this->assertFalse($wallet->delete()); } ); - } - /** - * Verify we can not delete a wallet that is the last wallet. - */ - public function testDeleteLastWallet(): void - { - $user = $this->getTestUser('UserWallet4@UserWallet.com'); - - $this->assertCount(1, $user->wallets); - - $user->wallets()->each( - function ($wallet) { - $this->assertFalse($wallet->delete()); - } - ); - } + $user->wallets()->update(['balance' => 0]); + $user->refresh(); - /** - * Verify we can remove a wallet that is an additional wallet. - */ - public function testDeleteAddtWallet(): void - { - $user = $this->getTestUser('UserWallet5@UserWallet.com'); + // Verify we can remove a wallet that is an additional wallet. + $user->wallets()->first()->delete(); + $user->refresh(); - $user->wallets()->save( - new Wallet(['currency' => 'USD']) - ); + $this->assertCount(1, $user->wallets); - // For now additional wallets with a different currency is not allowed - $this->assertFalse($user->wallets()->where('currency', 'USD')->exists()); -/* - $user->wallets()->each( - function ($wallet) { - if ($wallet->currency == 'USD') { - $this->assertNotFalse($wallet->delete()); - } - } - ); -*/ + // Verify we can not delete a wallet that is the last wallet. + $this->assertFalse($user->wallets[0]->delete()); } /** @@ -284,8 +235,8 @@ */ public function testAddController(): void { - $userA = $this->getTestUser('WalletControllerA@WalletController.com'); - $userB = $this->getTestUser('WalletControllerB@WalletController.com'); + $userA = $this->getTestUser('UserWallet1@UserWallet.com'); + $userB = $this->getTestUser('UserWallet2@UserWallet.com'); $userA->wallets()->each( function ($wallet) use ($userB) { @@ -301,12 +252,140 @@ $this->assertTrue($bAccount->id === $aWallet->id); } + /** + * Test Wallet::expectedCharges() + */ + public function testExpectedCharges(): void + { + $user = $this->getTestUser('jane@kolabnow.com'); + $package = Package::withEnvTenantContext()->where('title', 'kolab')->first(); + $user->assignPackage($package); + + $wallet = $user->wallets->first(); + + // Verify the last day before the end of a full month's trial. + $this->backdateEntitlements( + $wallet->entitlements, + Carbon::now()->subMonthsWithoutOverflow(1)->addDays(1) + ); + + $this->assertEquals(0, $wallet->expectedCharges()); + + // Verify the exact end of the month's trial. + $this->backdateEntitlements( + $wallet->entitlements, + Carbon::now()->subMonthsWithoutOverflow(1) + ); + + $this->assertEquals(990, $wallet->expectedCharges()); + + // Verify that over-running the trial by a single day causes charges to be incurred. + $this->backdateEntitlements( + $wallet->entitlements, + Carbon::now()->subMonthsWithoutOverflow(1)->subDays(1) + ); + + $this->assertEquals(990, $wallet->expectedCharges()); + + // Verify additional storage configuration entitlement created 'early' does incur additional + // charges to the wallet. + $this->backdateEntitlements( + $wallet->entitlements, + Carbon::now()->subMonthsWithoutOverflow(1)->subDays(1) + ); + + $this->assertEquals(990, $wallet->expectedCharges()); + + $sku = Sku::withEnvTenantContext()->where('title', 'storage')->first(); + + $entitlement = Entitlement::create([ + 'wallet_id' => $wallet->id, + 'sku_id' => $sku->id, + 'cost' => $sku->cost, + 'entitleable_id' => $user->id, + 'entitleable_type' => \App\User::class + ]); + + $this->backdateEntitlements( + [$entitlement], + Carbon::now()->subMonthsWithoutOverflow(1)->subDays(1) + ); + + $this->assertEquals(1015, $wallet->expectedCharges()); + + $entitlement->forceDelete(); + $wallet->refresh(); + + // Verify additional storage configuration entitlement created 'late' does not incur additional + // charges to the wallet. + $this->backdateEntitlements($wallet->entitlements, Carbon::now()->subMonthsWithoutOverflow(1)); + + $this->assertEquals(990, $wallet->expectedCharges()); + + $entitlement = \App\Entitlement::create([ + 'wallet_id' => $wallet->id, + 'sku_id' => $sku->id, + 'cost' => $sku->cost, + 'entitleable_id' => $user->id, + 'entitleable_type' => \App\User::class + ]); + + $this->backdateEntitlements([$entitlement], Carbon::now()->subDays(14)); + + $this->assertEquals(990, $wallet->expectedCharges()); + + $entitlement->forceDelete(); + $wallet->refresh(); + + // Test fifth week + $targetDateA = Carbon::now()->subWeeks(5); + $targetDateB = $targetDateA->copy()->addMonthsWithoutOverflow(1); + + $this->backdateEntitlements($wallet->entitlements, $targetDateA); + + $this->assertEquals(990, $wallet->expectedCharges()); + + $entitlement->forceDelete(); + $wallet->refresh(); + + // Test second month + $this->backdateEntitlements($wallet->entitlements, Carbon::now()->subMonthsWithoutOverflow(2)); + + $this->assertCount(7, $wallet->entitlements); + + $this->assertEquals(1980, $wallet->expectedCharges()); + + $entitlement = \App\Entitlement::create([ + 'entitleable_id' => $user->id, + 'entitleable_type' => \App\User::class, + 'cost' => $sku->cost, + 'sku_id' => $sku->id, + 'wallet_id' => $wallet->id + ]); + + $this->backdateEntitlements([$entitlement], Carbon::now()->subMonthsWithoutOverflow(1)); + + $this->assertEquals(2005, $wallet->expectedCharges()); + + $entitlement->forceDelete(); + $wallet->refresh(); + + // Test cost calculation with a wallet discount + $discount = Discount::withEnvTenantContext()->where('code', 'TEST')->first(); + + $wallet->discount()->associate($discount); + + $this->backdateEntitlements($wallet->entitlements, Carbon::now()->subMonthsWithoutOverflow(1)); + + $this->assertEquals(891, $wallet->expectedCharges()); + } + /** * Test Wallet::getMinMandateAmount() */ public function testGetMinMandateAmount(): void { - $user = $this->getTestUser('WalletControllerA@WalletController.com'); + $user = $this->getTestUser('UserWallet1@UserWallet.com'); $user->setSetting('plan_id', null); $wallet = $user->wallets()->first(); @@ -349,10 +428,10 @@ /** * Verify controllers can also be removed from wallets. */ - public function testRemoveWalletController(): void + public function testRemoveController(): void { - $userA = $this->getTestUser('WalletController2A@WalletController.com'); - $userB = $this->getTestUser('WalletController2B@WalletController.com'); + $userA = $this->getTestUser('UserWallet1@UserWallet.com'); + $userB = $this->getTestUser('UserWallet2@UserWallet.com'); $userA->wallets()->each( function ($wallet) use ($userB) { @@ -715,9 +794,9 @@ } /** - * Tests for award() and penalty() + * Tests for award/penalty/chargeback/refund/credit/debit methods */ - public function testAwardAndPenalty(): void + public function testBalanceChange(): void { $user = $this->getTestUser('UserWallet1@UserWallet.com'); $wallet = $user->wallets()->first(); @@ -741,14 +820,58 @@ $this->assertSame(-100, $transaction->amount); $this->assertSame(Transaction::WALLET_PENALTY, $transaction->type); $this->assertSame('test', $transaction->description); - } - /** - * Tests for chargeback() and refund() - */ - public function testChargebackAndRefund(): void - { - $this->markTestIncomplete(); + $wallet->transactions()->delete(); + $wallet->balance = 0; + $wallet->save(); + + // Test chargeback + $this->assertSame($wallet->id, $wallet->chargeback(100, 'test')->id); + $this->assertSame(-100, $wallet->balance); + $this->assertSame(-100, $wallet->fresh()->balance); + $transaction = $wallet->transactions()->first(); + $this->assertSame(-100, $transaction->amount); + $this->assertSame(Transaction::WALLET_CHARGEBACK, $transaction->type); + $this->assertSame('test', $transaction->description); + + $wallet->transactions()->delete(); + $wallet->balance = 0; + $wallet->save(); + + // Test refund + $this->assertSame($wallet->id, $wallet->refund(100, 'test')->id); + $this->assertSame(-100, $wallet->balance); + $this->assertSame(-100, $wallet->fresh()->balance); + $transaction = $wallet->transactions()->first(); + $this->assertSame(-100, $transaction->amount); + $this->assertSame(Transaction::WALLET_REFUND, $transaction->type); + $this->assertSame('test', $transaction->description); + + $wallet->transactions()->delete(); + $wallet->balance = 0; + $wallet->save(); + + // Test credit + $this->assertSame($wallet->id, $wallet->credit(100, 'test')->id); + $this->assertSame(100, $wallet->balance); + $this->assertSame(100, $wallet->fresh()->balance); + $transaction = $wallet->transactions()->first(); + $this->assertSame(100, $transaction->amount); + $this->assertSame(Transaction::WALLET_CREDIT, $transaction->type); + $this->assertSame('test', $transaction->description); + + $wallet->transactions()->delete(); + $wallet->balance = 0; + $wallet->save(); + + // Test debit + $this->assertSame($wallet->id, $wallet->debit(100, 'test')->id); + $this->assertSame(-100, $wallet->balance); + $this->assertSame(-100, $wallet->fresh()->balance); + $transaction = $wallet->transactions()->first(); + $this->assertSame(-100, $transaction->amount); + $this->assertSame(Transaction::WALLET_DEBIT, $transaction->type); + $this->assertSame('test', $transaction->description); } /**