Changeset View
Changeset View
Standalone View
Standalone View
src/tests/Feature/BillingTest.php
- This file was added.
<?php | |||||
namespace Tests\Feature; | |||||
use Carbon\Carbon; | |||||
use Illuminate\Support\Facades\Queue; | |||||
use Tests\TestCase; | |||||
class BillingTest extends TestCase | |||||
{ | |||||
public function setUp(): void | |||||
{ | |||||
parent::setUp(); | |||||
$this->deleteTestUser('jane@kolabnow.com'); | |||||
$this->deleteTestUser('jack@kolabnow.com'); | |||||
\App\Package::where('title', 'kolab-kube')->delete(); | |||||
$this->user = $this->getTestUser('jane@kolabnow.com'); | |||||
$this->package = \App\Package::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::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(4, $this->changelogEntries($this->wallet)); | |||||
$this->assertEquals(0, $this->wallet->expectedCharges()); | |||||
$this->user->delete(); | |||||
$this->assertCount(0, $this->changelogEntries($this->wallet)); | |||||
$this->assertCount(4, $this->changelogEntries($this->wallet, true)); | |||||
} | |||||
/** | |||||
* Verify the 13th 24-hour period does not incur charges to the wallet. | |||||
*/ | |||||
public function testNearFullTrial(): void | |||||
{ | |||||
$entries = $this->changelogEntries($this->wallet); | |||||
$this->assertCount(4, $entries); | |||||
foreach ($entries as $entry) { | |||||
$entry->created_at = Carbon::now()->subDays(13); | |||||
$entry->updated_at = Carbon::now()->subDays(13); | |||||
$entry->save(); | |||||
} | |||||
$this->assertEquals(0, $this->wallet->expectedCharges()); | |||||
} | |||||
/** | |||||
* Verify the 14th 24-hour period does incur charges to the wallet. | |||||
*/ | |||||
public function testFullTrial(): void | |||||
{ | |||||
$entries = $this->changelogEntries($this->wallet); | |||||
$this->assertCount(4, $entries); | |||||
foreach ($entries as $entry) { | |||||
$entry->created_at = Carbon::now()->subDays(14); | |||||
$entry->updated_at = Carbon::now()->subDays(14); | |||||
$entry->save(); | |||||
} | |||||
$this->assertEquals(999, $this->wallet->expectedCharges()); | |||||
} | |||||
/** | |||||
* Verify additional storage configuration entitlement created 'early' does incur additional | |||||
* charges to the wallet. | |||||
*/ | |||||
public function testAddtStorageEarly(): void | |||||
{ | |||||
$entries = $this->changelogEntries($this->wallet); | |||||
foreach ($entries as $entry) { | |||||
$entry->created_at = Carbon::now()->subDays(16); | |||||
$entry->updated_at = Carbon::now()->subDays(16); | |||||
$entry->save(); | |||||
} | |||||
$this->assertCount(4, $entries); | |||||
$this->assertEquals(999, $this->wallet->expectedCharges()); | |||||
$sku = \App\Sku::where(['title' => 'storage'])->first(); | |||||
$entitlement = \App\Entitlement::create( | |||||
[ | |||||
'owner_id' => $this->user->id, | |||||
'wallet_id' => $this->wallet_id, | |||||
'sku_id' => $sku->id, | |||||
'cost' => $sku->cost, | |||||
'entitleable_id' => $this->user->id, | |||||
'entitleable_type' => \App\User::class | |||||
] | |||||
); | |||||
$entries = $this->changelogEntries($this->wallet); | |||||
$this->assertCount(5, $entries); | |||||
$entry = \App\Changelog::where('entitlement_id', $entitlement->id)->first(); | |||||
$entry->created_at = Carbon::now()->subDays(16); | |||||
$entry->updated_at = Carbon::now()->subDays(16); | |||||
$entry->save(); | |||||
$this->assertEquals(1024, $this->wallet->expectedCharges()); | |||||
} | |||||
/** | |||||
* Verify additional storage configuration entitlement created 'late' does not incur additional | |||||
* charges to the wallet. | |||||
*/ | |||||
public function testAddtStorageLate(): void | |||||
{ | |||||
$entries = $this->changelogEntries($this->wallet); | |||||
foreach ($entries as $entry) { | |||||
$entry->created_at = Carbon::now()->subDays(16); | |||||
$entry->updated_at = Carbon::now()->subDays(16); | |||||
$entry->save(); | |||||
} | |||||
$this->assertCount(4, $entries); | |||||
$this->assertEquals(999, $this->wallet->expectedCharges()); | |||||
$sku = \App\Sku::where(['title' => 'storage'])->first(); | |||||
$entitlement = \App\Entitlement::create( | |||||
[ | |||||
'owner_id' => $this->user->id, | |||||
'wallet_id' => $this->wallet_id, | |||||
'sku_id' => $sku->id, | |||||
'cost' => $sku->cost, | |||||
'entitleable_id' => $this->user->id, | |||||
'entitleable_type' => \App\User::class | |||||
] | |||||
); | |||||
$entries = $this->changelogEntries($this->wallet); | |||||
$this->assertCount(5, $entries); | |||||
$entry = \App\Changelog::where('entitlement_id', $entitlement->id)->first(); | |||||
$entry->created_at = Carbon::now()->subDays(7); | |||||
$entry->updated_at = Carbon::now()->subDays(7); | |||||
$entry->save(); | |||||
$this->assertEquals(999, $this->wallet->expectedCharges()); | |||||
} | |||||
/** | |||||
* Verify that over-running the trial by a single day causes charges to be incurred. | |||||
*/ | |||||
public function testOutRunTrial(): void | |||||
{ | |||||
$entries = $this->changelogEntries($this->wallet); | |||||
foreach ($entries as $entry) { | |||||
$entry->created_at = Carbon::now()->subDays(15); | |||||
$entry->updated_at = Carbon::now()->subDays(15); | |||||
$entry->save(); | |||||
} | |||||
$this->assertCount(4, $entries); | |||||
$this->assertEquals(999, $this->wallet->expectedCharges()); | |||||
} | |||||
public function testFifthWeek(): void | |||||
{ | |||||
$entries = $this->changelogEntries($this->wallet); | |||||
$this->assertCount(4, $entries); | |||||
$targetDateA = Carbon::now()->subWeeks(5); | |||||
$targetDateB = $targetDateA->copy()->addMonths(1); | |||||
foreach ($entries as $entry) { | |||||
$entry->created_at = $targetDateA; | |||||
$entry->updated_at = $targetDateA; | |||||
$entry->save(); | |||||
} | |||||
$this->assertEquals(999, $this->wallet->expectedCharges()); | |||||
foreach ($this->wallet->entitlements as $entitlement) { | |||||
$entitlement->chargeWallet(); | |||||
} | |||||
$this->wallet->refresh(); | |||||
$this->assertEquals(-999, $this->wallet->balance); | |||||
$entries = $this->changelogEntries($this->wallet); | |||||
foreach ($entries as $entry) { | |||||
$this->assertTrue($entry->created_at->isSameSecond($targetDateA)); | |||||
$this->assertTrue($entry->updated_at->isSameSecond($targetDateB)); | |||||
} | |||||
} | |||||
public function testSecondMonth(): void | |||||
{ | |||||
$entries = $this->changelogEntries($this->wallet); | |||||
foreach ($entries as $entry) { | |||||
$entry->created_at = Carbon::now()->subMonths(2); | |||||
$entry->updated_at = Carbon::now()->subMonths(2); | |||||
$entry->save(); | |||||
} | |||||
$this->assertCount(4, $entries); | |||||
$this->assertEquals(1998, $this->wallet->expectedCharges()); | |||||
$sku = \App\Sku::where(['title' => 'storage'])->first(); | |||||
$entitlement = \App\Entitlement::create( | |||||
[ | |||||
'owner_id' => $this->user->id, | |||||
'entitleable_id' => $this->user->id, | |||||
'entitleable_type' => \App\User::class, | |||||
'cost' => $sku->cost, | |||||
'sku_id' => $sku->id, | |||||
'wallet_id' => $this->wallet_id | |||||
] | |||||
); | |||||
// A fresh query should now return 5 entries. | |||||
$entries = $this->changelogEntries($this->wallet); | |||||
$this->assertCount(5, $entries); | |||||
$entry = \App\Changelog::where('entitlement_id', $entitlement->id)->first(); | |||||
$entry->created_at = Carbon::now()->subMonths(1); | |||||
$entry->updated_at = Carbon::now()->subMonths(1); | |||||
$entry->save(); | |||||
$this->assertEquals(2023, $this->wallet->expectedCharges()); | |||||
} | |||||
public function testWithDiscount(): void | |||||
{ | |||||
$package = \App\Package::create( | |||||
[ | |||||
'title' => 'kolab-kube', | |||||
'description' => 'Kolab for Kube fans', | |||||
'discount_rate' => 50 | |||||
] | |||||
); | |||||
$skus = [ | |||||
\App\Sku::firstOrCreate(['title' => 'mailbox']), | |||||
\App\Sku::firstOrCreate(['title' => 'storage']), | |||||
\App\Sku::firstOrCreate(['title' => 'groupware']) | |||||
]; | |||||
$package->skus()->saveMany($skus); | |||||
$package->skus()->updateExistingPivot( | |||||
\App\Sku::firstOrCreate(['title' => 'storage']), | |||||
['qty' => 2], | |||||
false | |||||
); | |||||
$user = $this->getTestUser('jack@kolabnow.com'); | |||||
$user->assignPackage($package); | |||||
$wallet = $user->wallets->first(); | |||||
$wallet_id = $wallet->id; | |||||
$entries = $this->changelogEntries($wallet); | |||||
$this->assertCount(4, $entries); | |||||
foreach ($entries as $entry) { | |||||
$entry->created_at = Carbon::now()->subDays(15); | |||||
$entry->updated_at = Carbon::now()->subDays(15); | |||||
$entry->save(); | |||||
} | |||||
$this->assertEquals(500, $wallet->expectedCharges()); | |||||
} | |||||
private function changelogEntries($wallet, $withTrashed = false) | |||||
{ | |||||
$entitlement_ids = $this->walletEntitlements($wallet, $withTrashed); | |||||
if ($withTrashed) { | |||||
return \App\Changelog::withTrashed() | |||||
->whereIn('entitlement_id', $entitlement_ids)->get(); | |||||
} | |||||
return \App\Changelog::whereIn('entitlement_id', $entitlement_ids)->get(); | |||||
} | |||||
private function walletEntitlements($wallet, $withTrashed = false) | |||||
{ | |||||
$entitlement_ids = []; | |||||
if ($withTrashed) { | |||||
$entitlements = $wallet->entitlements()->withTrashed()->get()->fresh(); | |||||
} else { | |||||
$entitlements = $wallet->entitlements()->get()->fresh(); | |||||
} | |||||
foreach ($entitlements as $entitlement) { | |||||
$entitlement_ids[] = $entitlement->id; | |||||
} | |||||
return $entitlement_ids; | |||||
} | |||||
} |