Changeset View
Changeset View
Standalone View
Standalone View
src/tests/Feature/WalletTest.php
Show First 20 Lines • Show All 70 Lines • ▼ Show 20 Lines | public function testBalancePositiveUnsuspend(): void | ||||
// TODO: Test group account and unsuspending domain/members | // TODO: Test group account and unsuspending domain/members | ||||
} | } | ||||
/** | /** | ||||
* Test for Wallet::balanceLastsUntil() | * Test for Wallet::balanceLastsUntil() | ||||
*/ | */ | ||||
public function testBalanceLastsUntil(): void | public function testBalanceLastsUntil(): void | ||||
{ | { | ||||
// Monthly cost of all entitlements: 999 | // Monthly cost of all entitlements: 990 | ||||
// 28 days: 35.68 per day | // 28 days: 35.36 per day | ||||
// 31 days: 32.22 per day | // 31 days: 31.93 per day | ||||
$user = $this->getTestUser('jane@kolabnow.com'); | $user = $this->getTestUser('jane@kolabnow.com'); | ||||
$package = Package::where('title', 'kolab')->first(); | $package = Package::withEnvTenantContext()->where('title', 'kolab')->first(); | ||||
$user->assignPackage($package); | $user->assignPackage($package); | ||||
$wallet = $user->wallets()->first(); | $wallet = $user->wallets()->first(); | ||||
// User/entitlements created today, balance=0 | // User/entitlements created today, balance=0 | ||||
$until = $wallet->balanceLastsUntil(); | $until = $wallet->balanceLastsUntil(); | ||||
$this->assertSame( | $this->assertSame( | ||||
Carbon::now()->addMonthsWithoutOverflow(1)->toDateString(), | Carbon::now()->addMonthsWithoutOverflow(1)->toDateString(), | ||||
$until->toDateString() | $until->toDateString() | ||||
); | ); | ||||
// User/entitlements created today, balance=-10 CHF | // User/entitlements created today, balance=-10 CHF | ||||
$wallet->balance = -1000; | $wallet->balance = -1000; | ||||
$until = $wallet->balanceLastsUntil(); | $until = $wallet->balanceLastsUntil(); | ||||
$this->assertSame(null, $until); | $this->assertSame(null, $until); | ||||
// User/entitlements created today, balance=-9,99 CHF (monthly cost) | // User/entitlements created today, balance=-9,99 CHF (monthly cost) | ||||
$wallet->balance = 999; | $wallet->balance = 990; | ||||
$until = $wallet->balanceLastsUntil(); | $until = $wallet->balanceLastsUntil(); | ||||
$daysInLastMonth = \App\Utils::daysInLastMonth(); | $daysInLastMonth = \App\Utils::daysInLastMonth(); | ||||
$this->assertSame( | $delta = Carbon::now()->addMonthsWithoutOverflow(1)->addDays($daysInLastMonth)->diff($until)->days; | ||||
Carbon::now()->addMonthsWithoutOverflow(1)->addDays($daysInLastMonth)->toDateString(), | |||||
$until->toDateString() | $this->assertTrue($delta <= 1); | ||||
); | $this->assertTrue($delta >= -1); | ||||
// Old entitlements, 100% discount | // Old entitlements, 100% discount | ||||
$this->backdateEntitlements($wallet->entitlements, Carbon::now()->subDays(40)); | $this->backdateEntitlements($wallet->entitlements, Carbon::now()->subDays(40)); | ||||
$discount = \App\Discount::where('discount', 100)->first(); | $discount = \App\Discount::withEnvTenantContext()->where('discount', 100)->first(); | ||||
$wallet->discount()->associate($discount); | $wallet->discount()->associate($discount); | ||||
$until = $wallet->refresh()->balanceLastsUntil(); | $until = $wallet->refresh()->balanceLastsUntil(); | ||||
$this->assertSame(null, $until); | $this->assertSame(null, $until); | ||||
// User with no entitlements | // User with no entitlements | ||||
$wallet->discount()->dissociate($discount); | $wallet->discount()->dissociate($discount); | ||||
$wallet->entitlements()->delete(); | $wallet->entitlements()->delete(); | ||||
$until = $wallet->refresh()->balanceLastsUntil(); | $until = $wallet->refresh()->balanceLastsUntil(); | ||||
$this->assertSame(null, $until); | $this->assertSame(null, $until); | ||||
} | } | ||||
/** | /** | ||||
* Test for Wallet::costsPerDay() | * Test for Wallet::costsPerDay() | ||||
*/ | */ | ||||
public function testCostsPerDay(): void | public function testCostsPerDay(): void | ||||
{ | { | ||||
// 999 | // 990 | ||||
// 28 days: 35.68 | // 28 days: 35.36 | ||||
// 31 days: 32.22 | // 31 days: 31.93 | ||||
$user = $this->getTestUser('jane@kolabnow.com'); | $user = $this->getTestUser('jane@kolabnow.com'); | ||||
$package = Package::where('title', 'kolab')->first(); | $package = Package::withEnvTenantContext()->where('title', 'kolab')->first(); | ||||
$mailbox = Sku::where('title', 'mailbox')->first(); | $mailbox = Sku::withEnvTenantContext()->where('title', 'mailbox')->first(); | ||||
$user->assignPackage($package); | $user->assignPackage($package); | ||||
$wallet = $user->wallets()->first(); | $wallet = $user->wallets()->first(); | ||||
$costsPerDay = $wallet->costsPerDay(); | $costsPerDay = $wallet->costsPerDay(); | ||||
$this->assertTrue($costsPerDay < 35.68); | $this->assertTrue($costsPerDay < 35.38); | ||||
$this->assertTrue($costsPerDay > 32.22); | $this->assertTrue($costsPerDay > 31.93); | ||||
} | } | ||||
/** | /** | ||||
* Verify a wallet is created, when a user is created. | * Verify a wallet is created, when a user is created. | ||||
*/ | */ | ||||
public function testCreateUserCreatesWallet(): void | public function testCreateUserCreatesWallet(): void | ||||
{ | { | ||||
$user = $this->getTestUser('UserWallet1@UserWallet.com'); | $user = $this->getTestUser('UserWallet1@UserWallet.com'); | ||||
▲ Show 20 Lines • Show All 126 Lines • ▼ Show 20 Lines | class WalletTest extends TestCase | ||||
/** | /** | ||||
* Test for charging and removing entitlements (including tenant commission calculations) | * Test for charging and removing entitlements (including tenant commission calculations) | ||||
*/ | */ | ||||
public function testChargeAndDeleteEntitlements(): void | public function testChargeAndDeleteEntitlements(): void | ||||
{ | { | ||||
$user = $this->getTestUser('jane@kolabnow.com'); | $user = $this->getTestUser('jane@kolabnow.com'); | ||||
$wallet = $user->wallets()->first(); | $wallet = $user->wallets()->first(); | ||||
$discount = \App\Discount::where('discount', 30)->first(); | $discount = \App\Discount::withEnvTenantContext()->where('discount', 30)->first(); | ||||
$wallet->discount()->associate($discount); | $wallet->discount()->associate($discount); | ||||
$wallet->save(); | $wallet->save(); | ||||
// Add 40% fee to all SKUs | // Add 40% fee to all SKUs | ||||
Sku::select()->update(['fee' => DB::raw("`cost` * 0.4")]); | Sku::select()->update(['fee' => DB::raw("`cost` * 0.4")]); | ||||
$package = Package::where('title', 'kolab')->first(); | $package = Package::withEnvTenantContext()->where('title', 'kolab')->first(); | ||||
$storage = Sku::where('title', 'storage')->first(); | $storage = Sku::withEnvTenantContext()->where('title', 'storage')->first(); | ||||
$user->assignPackage($package); | $user->assignPackage($package); | ||||
$user->assignSku($storage, 2); | $user->assignSku($storage, 5); | ||||
$user->refresh(); | $user->refresh(); | ||||
// Reset reseller's wallet balance and transactions | // Reset reseller's wallet balance and transactions | ||||
$reseller_wallet = $user->tenant->wallet(); | $reseller_wallet = $user->tenant->wallet(); | ||||
$reseller_wallet->balance = 0; | $reseller_wallet->balance = 0; | ||||
$reseller_wallet->save(); | $reseller_wallet->save(); | ||||
Transaction::where('object_id', $reseller_wallet->id)->where('object_type', \App\Wallet::class)->delete(); | Transaction::where('object_id', $reseller_wallet->id)->where('object_type', \App\Wallet::class)->delete(); | ||||
// ------------------------------------ | // ------------------------------------ | ||||
// Test normal charging of entitlements | // Test normal charging of entitlements | ||||
// ------------------------------------ | // ------------------------------------ | ||||
// Backdate and chanrge entitlements, we're expecting one month to be charged | // Backdate and charge entitlements, we're expecting one month to be charged | ||||
// Set fake NOW date to make simpler asserting results that depend on number of days in current/last month | // Set fake NOW date to make simpler asserting results that depend on number of days in current/last month | ||||
Carbon::setTestNow(Carbon::create(2021, 5, 21, 12)); | Carbon::setTestNow(Carbon::create(2021, 5, 21, 12)); | ||||
$backdate = Carbon::now()->subWeeks(7); | $backdate = Carbon::now()->subWeeks(7); | ||||
$this->backdateEntitlements($user->entitlements, $backdate); | $this->backdateEntitlements($user->entitlements, $backdate); | ||||
$charge = $wallet->chargeEntitlements(); | $charge = $wallet->chargeEntitlements(); | ||||
$wallet->refresh(); | $wallet->refresh(); | ||||
$reseller_wallet->refresh(); | $reseller_wallet->refresh(); | ||||
// TODO: Update these comments with what is actually being used to calculate these numbers | |||||
// 388 + 310 + 17 + 17 = 732 | // 388 + 310 + 17 + 17 = 732 | ||||
$this->assertSame(-732, $wallet->balance); | $this->assertSame(-778, $wallet->balance); | ||||
// 388 - 555 x 40% + 310 - 444 x 40% + 34 - 50 x 40% = 312 | // 388 - 555 x 40% + 310 - 444 x 40% + 34 - 50 x 40% = 312 | ||||
$this->assertSame(312, $reseller_wallet->balance); | $this->assertSame(332, $reseller_wallet->balance); | ||||
$transactions = Transaction::where('object_id', $wallet->id) | $transactions = Transaction::where('object_id', $wallet->id) | ||||
->where('object_type', \App\Wallet::class)->get(); | ->where('object_type', \App\Wallet::class)->get(); | ||||
$reseller_transactions = Transaction::where('object_id', $reseller_wallet->id) | $reseller_transactions = Transaction::where('object_id', $reseller_wallet->id) | ||||
->where('object_type', \App\Wallet::class)->get(); | ->where('object_type', \App\Wallet::class)->get(); | ||||
$this->assertCount(1, $reseller_transactions); | $this->assertCount(1, $reseller_transactions); | ||||
$trans = $reseller_transactions[0]; | $trans = $reseller_transactions[0]; | ||||
$this->assertSame("Charged user jane@kolabnow.com", $trans->description); | $this->assertSame("Charged user jane@kolabnow.com", $trans->description); | ||||
$this->assertSame(312, $trans->amount); | $this->assertSame(332, $trans->amount); | ||||
$this->assertSame(Transaction::WALLET_CREDIT, $trans->type); | $this->assertSame(Transaction::WALLET_CREDIT, $trans->type); | ||||
$this->assertCount(1, $transactions); | $this->assertCount(1, $transactions); | ||||
$trans = $transactions[0]; | $trans = $transactions[0]; | ||||
$this->assertSame('', $trans->description); | $this->assertSame('', $trans->description); | ||||
$this->assertSame(-732, $trans->amount); | $this->assertSame(-778, $trans->amount); | ||||
$this->assertSame(Transaction::WALLET_DEBIT, $trans->type); | $this->assertSame(Transaction::WALLET_DEBIT, $trans->type); | ||||
// TODO: Test entitlement transaction records | // TODO: Test entitlement transaction records | ||||
// ----------------------------------- | // ----------------------------------- | ||||
// Test charging on entitlement delete | // Test charging on entitlement delete | ||||
// ----------------------------------- | // ----------------------------------- | ||||
$reseller_wallet->balance = 0; | |||||
$reseller_wallet->save(); | |||||
$transactions = Transaction::where('object_id', $wallet->id) | $transactions = Transaction::where('object_id', $wallet->id) | ||||
->where('object_type', \App\Wallet::class)->delete(); | ->where('object_type', \App\Wallet::class)->delete(); | ||||
$reseller_transactions = Transaction::where('object_id', $reseller_wallet->id) | $reseller_transactions = Transaction::where('object_id', $reseller_wallet->id) | ||||
->where('object_type', \App\Wallet::class)->delete(); | ->where('object_type', \App\Wallet::class)->delete(); | ||||
$user->removeSku($storage, 2); | $user->removeSku($storage, 2); | ||||
// we expect the wallet to have been charged for 19 days of use of | // we expect the wallet to have been charged for 19 days of use of | ||||
// 2 deleted storage entitlements | // 2 deleted storage entitlements | ||||
$wallet->refresh(); | $wallet->refresh(); | ||||
$reseller_wallet->refresh(); | $reseller_wallet->refresh(); | ||||
// 2 x round(25 / 31 * 19 * 0.7) = 22 | // 2 x round(25 / 31 * 19 * 0.7) = 22 | ||||
$this->assertSame(-(732 + 22), $wallet->balance); | $this->assertSame(-(778 + 22), $wallet->balance); | ||||
// 22 - 2 x round(25 * 0.4 / 31 * 19) = 10 | // 22 - 2 x round(25 * 0.4 / 31 * 19) = 10 | ||||
$this->assertSame(312 + 10, $reseller_wallet->balance); | $this->assertSame(10, $reseller_wallet->balance); | ||||
$transactions = Transaction::where('object_id', $wallet->id) | $transactions = Transaction::where('object_id', $wallet->id) | ||||
->where('object_type', \App\Wallet::class)->get(); | ->where('object_type', \App\Wallet::class)->get(); | ||||
$reseller_transactions = Transaction::where('object_id', $reseller_wallet->id) | $reseller_transactions = Transaction::where('object_id', $reseller_wallet->id) | ||||
->where('object_type', \App\Wallet::class)->get(); | ->where('object_type', \App\Wallet::class)->get(); | ||||
$this->assertCount(2, $reseller_transactions); | $this->assertCount(2, $reseller_transactions); | ||||
$trans = $reseller_transactions[0]; | $trans = $reseller_transactions[0]; | ||||
$this->assertSame("Charged user jane@kolabnow.com", $trans->description); | $this->assertSame("Charged user jane@kolabnow.com", $trans->description); | ||||
$this->assertSame(5, $trans->amount); | $this->assertSame(5, $trans->amount); | ||||
$this->assertSame(Transaction::WALLET_CREDIT, $trans->type); | $this->assertSame(Transaction::WALLET_CREDIT, $trans->type); | ||||
$trans = $reseller_transactions[1]; | $trans = $reseller_transactions[1]; | ||||
$this->assertSame("Charged user jane@kolabnow.com", $trans->description); | $this->assertSame("Charged user jane@kolabnow.com", $trans->description); | ||||
$this->assertSame(5, $trans->amount); | $this->assertSame(5, $trans->amount); | ||||
$this->assertSame(Transaction::WALLET_CREDIT, $trans->type); | $this->assertSame(Transaction::WALLET_CREDIT, $trans->type); | ||||
$this->assertCount(2, $transactions); | $this->assertCount(2, $transactions); | ||||
$trans = $transactions[0]; | $trans = $transactions[0]; | ||||
$this->assertSame('', $trans->description); | $this->assertSame('', $trans->description); | ||||
Show All 10 Lines |