Page MenuHomePhorge

D1297.1775306828.diff
No OneTemporary

Authored By
Unknown
Size
9 KB
Referenced Files
None
Subscribers
None

D1297.1775306828.diff

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

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)

Event Timeline