Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F117837360
D1297.1775306828.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Authored By
Unknown
Size
9 KB
Referenced Files
None
Subscribers
None
D1297.1775306828.diff
View Options
diff --git a/src/app/Observers/EntitlementObserver.php b/src/app/Observers/EntitlementObserver.php
--- a/src/app/Observers/EntitlementObserver.php
+++ b/src/app/Observers/EntitlementObserver.php
@@ -92,4 +92,55 @@
$entitlement->createTransaction(\App\Transaction::ENTITLEMENT_DELETED);
}
+
+ public function deleting(Entitlement $entitlement)
+ {
+ // Start calculating the costs for the consumption of this entitlement if the
+ // existing consumption spans >= 14 days.
+ // anything's free for 14 days
+ if ($entitlement->created_at >= Carbon::now()->subDays(14)) {
+ return;
+ }
+
+ $cost = 0;
+
+ // get the discount rate applied to the wallet.
+ $discount = $entitlement->wallet->getDiscountRate();
+
+ // just in case this had not been billed yet, ever
+ $diffInMonths = $entitlement->updated_at->diffInMonths(Carbon::now());
+ $cost += (int) ($entitlement->cost * $discount * $diffInMonths);
+
+ // this moves the hypothetical updated at forward to however many months past the original
+ $updatedAt = $entitlement->updated_at->copy()->addMonthsWithoutOverflow($diffInMonths);
+
+ // now we have the diff in days since the last "billed" period end.
+ // This may be an entitlement paid up until February 28th, 2020, with today being March
+ // 12th 2020. Calculating the costs for the entitlement is based on the daily price for the
+ // past month -- i.e. $price/29 in the case at hand -- times the number of (full) days in
+ // between the period end and now.
+ //
+ // a) The number of days left in the past month, 1
+ // b) The cost divided by the number of days in the past month, for example, 555/29,
+ // c) a) + Todays day-of-month, 12, so 13.
+ //
+
+ $diffInDays = $updatedAt->diffInDays(Carbon::now());
+
+ $dayOfThisMonth = Carbon::now()->day;
+
+ // days in the month for the month prior to this one.
+ // the price per day is based on the number of days left in the last month
+ $daysInLastMonth = \App\Utils::daysInLastMonth();
+
+ $pricePerDay = (float)$entitlement->cost / $daysInLastMonth;
+
+ $cost += (int) (round($pricePerDay * $diffInDays, 0));
+
+ if ($cost == 0) {
+ return;
+ }
+
+ $entitlement->wallet->debit($cost);
+ }
}
diff --git a/src/app/Transaction.php b/src/app/Transaction.php
--- a/src/app/Transaction.php
+++ b/src/app/Transaction.php
@@ -143,14 +143,14 @@
return null;
}
- $entitleable = $entitlement->entitleable;
+ $user = \App\User::withTrashed()->where('id', $entitlement->object_id)->first();
- if (!$entitleable) {
+ if (!$user) {
\Log::debug("No entitleable for {$entitlement->id} ?");
return null;
}
- return $entitleable->email;
+ return $user->email;
}
/**
diff --git a/src/app/User.php b/src/app/User.php
--- a/src/app/User.php
+++ b/src/app/User.php
@@ -183,7 +183,7 @@
\App\Entitlement::create([
'wallet_id' => $wallet->id,
'sku_id' => $sku->id,
- 'cost' => $sku->units_free >= $exists ? $sku->cost : 0,
+ 'cost' => $exists >= $sku->units_free ? $sku->cost : 0,
'entitleable_id' => $this->id,
'entitleable_type' => User::class
]);
@@ -455,6 +455,33 @@
return $name;
}
+ /**
+ * Remove a number of entitlements for the SKU.
+ *
+ * @param \App\Sku $sku
+ * @param int $count
+ *
+ * @return User
+ */
+ public function removeSku($sku, int $count = 1): User
+ {
+ $entitlements = $this->entitlements()->where('sku_id', $sku->id)
+ ->orderBy('cost', 'desc')->get();
+
+ foreach ($entitlements as $entitlement) {
+ if ($this->entitlements()->where('sku_id', $sku->id)->count() <= $sku->units_free) {
+ continue;
+ }
+
+ if ($count > 0) {
+ $entitlement->delete();
+ $count--;
+ }
+ }
+
+ return $this;
+ }
+
/**
* Any (additional) properties of this user.
*
diff --git a/src/tests/Feature/EntitlementTest.php b/src/tests/Feature/EntitlementTest.php
--- a/src/tests/Feature/EntitlementTest.php
+++ b/src/tests/Feature/EntitlementTest.php
@@ -37,11 +37,11 @@
*/
public function testUserAddEntitlement(): void
{
- $package_domain = Package::where('title', 'domain-hosting')->first();
- $package_kolab = Package::where('title', 'kolab')->first();
+ $packageDomain = Package::where('title', 'domain-hosting')->first();
+ $packageKolab = Package::where('title', 'kolab')->first();
- $sku_domain = Sku::where('title', 'domain-hosting')->first();
- $sku_mailbox = Sku::where('title', 'mailbox')->first();
+ $skuDomain = Sku::where('title', 'domain-hosting')->first();
+ $skuMailbox = Sku::where('title', 'mailbox')->first();
$owner = $this->getTestUser('entitlement-test@kolabnow.com');
$user = $this->getTestUser('entitled-user@custom-domain.com');
@@ -54,19 +54,22 @@
]
);
- $domain->assignPackage($package_domain, $owner);
+ $domain->assignPackage($packageDomain, $owner);
- $owner->assignPackage($package_kolab);
- $owner->assignPackage($package_kolab, $user);
+ $owner->assignPackage($packageKolab);
+ $owner->assignPackage($packageKolab, $user);
$wallet = $owner->wallets->first();
$this->assertCount(4, $owner->entitlements()->get());
- $this->assertCount(1, $sku_domain->entitlements()->where('wallet_id', $wallet->id)->get());
- $this->assertCount(2, $sku_mailbox->entitlements()->where('wallet_id', $wallet->id)->get());
+ $this->assertCount(1, $skuDomain->entitlements()->where('wallet_id', $wallet->id)->get());
+ $this->assertCount(2, $skuMailbox->entitlements()->where('wallet_id', $wallet->id)->get());
$this->assertCount(9, $wallet->entitlements);
- $this->backdateEntitlements($owner->entitlements, Carbon::now()->subMonthsWithoutOverflow(1));
+ $this->backdateEntitlements(
+ $owner->entitlements,
+ Carbon::now()->subMonthsWithoutOverflow(1)
+ );
$wallet->chargeEntitlements();
@@ -92,17 +95,55 @@
$sku = \App\Sku::where('title', 'mailbox')->first();
$this->assertNotNull($sku);
- $entitlement = Entitlement::where('wallet_id', $wallet->id)->where('sku_id', $sku->id)->first();
+ $entitlement = Entitlement::where('wallet_id', $wallet->id)
+ ->where('sku_id', $sku->id)->first();
+
$this->assertNotNull($entitlement);
- $e_sku = $entitlement->sku;
- $this->assertSame($sku->id, $e_sku->id);
+ $eSKU = $entitlement->sku;
+ $this->assertSame($sku->id, $eSKU->id);
+
+ $eWallet = $entitlement->wallet;
+ $this->assertSame($wallet->id, $eWallet->id);
+
+ $eEntitleable = $entitlement->entitleable;
+ $this->assertEquals($user->id, $eEntitleable->id);
+ $this->assertTrue($eEntitleable instanceof \App\User);
+ }
+
+ public function testBillDeletedEntitlement(): void
+ {
+ $user = $this->getTestUser('entitlement-test@kolabnow.com');
+ $package = \App\Package::where('title', 'kolab')->first();
+
+ $storage = \App\Sku::where('title', 'storage')->first();
+
+ $user->assignPackage($package);
+ // some additional SKUs so we have something to delete.
+ $user->assignSku($storage, 4);
+
+ // the mailbox, the groupware, the 2 original storage and the additional 4
+ $this->assertCount(8, $user->fresh()->entitlements);
+
+ $wallet = $user->wallets()->first();
+
+ $this->backdateEntitlements($user->entitlements, Carbon::now()->subWeeks(7));
+
+ $charge = $wallet->chargeEntitlements();
+
+ $this->assertTrue($wallet->balance < 0);
+
+ $balance = $wallet->balance;
+
+ $user->removeSku($storage, 4);
+
+ // we expect the wallet to have been charged.
+ $this->assertTrue($wallet->fresh()->balance < $balance);
- $e_wallet = $entitlement->wallet;
- $this->assertSame($wallet->id, $e_wallet->id);
+ $transactions = \App\Transaction::where('object_id', $wallet->id)
+ ->where('object_type', \App\Wallet::class)->get();
- $e_entitleable = $entitlement->entitleable;
- $this->assertEquals($user->id, $e_entitleable->id);
- $this->assertTrue($e_entitleable instanceof \App\User);
+ // one round of the monthly invoicing, four sku deletions getting invoiced
+ $this->assertCount(5, $transactions);
}
}
diff --git a/src/tests/Unit/TransactionTest.php b/src/tests/Unit/TransactionTest.php
--- a/src/tests/Unit/TransactionTest.php
+++ b/src/tests/Unit/TransactionTest.php
@@ -58,4 +58,25 @@
]
);
}
+
+ public function testEntitlementForWallet(): void
+ {
+ $transaction = \App\Transaction::where('object_type', \App\Wallet::class)
+ ->whereIn('object_id', \App\Wallet::all()->pluck('id'))->first();
+
+ $entitlement = $transaction->entitlement();
+ $this->assertNull($entitlement);
+ $this->assertNotNull($transaction->wallet());
+ }
+
+ public function testWalletForEntitlement(): void
+ {
+ $transaction = \App\Transaction::where('object_type', \App\Entitlement::class)
+ ->whereIn('object_id', \App\Entitlement::all()->pluck('id'))->first();
+
+ $wallet = $transaction->wallet();
+ $this->assertNull($wallet);
+
+ $this->assertNotNull($transaction->entitlement());
+ }
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Apr 4, 12:47 PM (19 h, 20 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
18829500
Default Alt Text
D1297.1775306828.diff (9 KB)
Attached To
Mode
D1297: Make sure we bill for entitlements that are deleted
Attached
Detach File
Event Timeline