Changeset View
Standalone View
src/app/Observers/EntitlementObserver.php
Show First 20 Lines • Show All 61 Lines • ▼ Show 20 Lines | class EntitlementObserver | ||||
* @param \App\Entitlement $entitlement The entitlement. | * @param \App\Entitlement $entitlement The entitlement. | ||||
* | * | ||||
* @return void | * @return void | ||||
*/ | */ | ||||
public function created(Entitlement $entitlement) | public function created(Entitlement $entitlement) | ||||
{ | { | ||||
$entitlement->entitleable->updated_at = Carbon::now(); | $entitlement->entitleable->updated_at = Carbon::now(); | ||||
$entitlement->entitleable->save(); | $entitlement->entitleable->save(); | ||||
\App\Transaction::create( | |||||
[ | |||||
'user_email' => \App\Utils::userEmailOrNull(), | |||||
'object_id' => $entitlement->id, | |||||
'object_type' => \App\Entitlement::class, | |||||
'type' => 'created' | |||||
] | |||||
); | |||||
} | } | ||||
/** | /** | ||||
* Handle the entitlement "deleted" event. | * Handle the entitlement "deleted" event. | ||||
* | * | ||||
* @param \App\Entitlement $entitlement The entitlement. | * @param \App\Entitlement $entitlement The entitlement. | ||||
* | * | ||||
* @return void | * @return void | ||||
*/ | */ | ||||
public function deleted(Entitlement $entitlement) | public function deleted(Entitlement $entitlement) | ||||
{ | { | ||||
// Remove all configured 2FA methods from Roundcube database | // Remove all configured 2FA methods from Roundcube database | ||||
if ($entitlement->sku->title == '2fa') { | if ($entitlement->sku->title == '2fa') { | ||||
// FIXME: Should that be an async job? | // FIXME: Should that be an async job? | ||||
$sf = new \App\Auth\SecondFactor($entitlement->entitleable); | $sf = new \App\Auth\SecondFactor($entitlement->entitleable); | ||||
$sf->removeFactors(); | $sf->removeFactors(); | ||||
} | } | ||||
$entitlement->entitleable->updated_at = Carbon::now(); | $entitlement->entitleable->updated_at = Carbon::now(); | ||||
$entitlement->entitleable->save(); | $entitlement->entitleable->save(); | ||||
\App\Transaction::create( | |||||
[ | |||||
'user_email' => \App\Utils::userEmailOrNull(), | |||||
'object_id' => $entitlement->id, | |||||
'object_type' => \App\Entitlement::class, | |||||
'type' => 'deleted' | |||||
] | |||||
); | |||||
$cost = 0; | |||||
$discount = $entitlement->wallet->getDiscountRate(); | |||||
// anything's free for 14 days | |||||
if ($entitlement->created_at >= Carbon::now()->subDays(14)) { | |||||
return; | |||||
} | |||||
// 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 | |||||
$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(); | |||||
$daysLeftInLastMonth = $daysInLastMonth - $updatedAt->day; | |||||
machniak: Will this work properly when updatedAt->day is e.g. March 30. Could we just calculate… | |||||
vanmeeuwenAuthorUnsubmitted Done Inline ActionsIf $daysLeftInLastMonth ends up 0, the $dayOfThisMonth is also 1. From 03/30 to 04/01, is one day (or two days, edges included, but that's not what we're doing). I would argue that it does work properly. vanmeeuwen: If `$daysLeftInLastMonth` ends up 0, the `$dayOfThisMonth` is also 1. From 03/30 to 04/01, is… | |||||
machniakUnsubmitted Done Inline ActionsMy point is that if $updatedAt->day is 30 (or 31) and $daysInLastMonth is 28 (or 29 or 30) we end up with $daysLeftInLastMonth < 0. It's maybe not a problem, but you've got the case for a test. machniak: My point is that if $updatedAt->day is 30 (or 31) and $daysInLastMonth is 28 (or 29 or 30) we… | |||||
vanmeeuwenAuthorUnsubmitted Done Inline ActionsAll full months not already billed moving forward up to the point where there is not another full month left. $daysInLastMonth is therefore 28, 29, 30 or 31. $updatedAt, as a copy of having moved forward by monthWithoutOverflow should not yield a March date for anything having moved forward a month from January 31st. It should yield in the 28th or 29th day of the month of February. If you think of a reason I'm wrong, please point out the flaw in my thinking. Otherwise, yes, it is indeed a case of testing. vanmeeuwen: All full months not already billed moving forward up to the point where there is not another… | |||||
$pricePerDay = (float)$entitlement->cost / $daysInLastMonth; | |||||
$daysToBill = $daysLeftInLastMonth + $dayOfThisMonth; | |||||
$cost += (int) (round($pricePerDay * $daysToBill, 0)); | |||||
if ($cost == 0) { | |||||
return; | |||||
} | |||||
$transaction = \App\Transaction::create( | |||||
machniakUnsubmitted Done Inline ActionsI see similar code in a few places. Probably adding Entitlement::createTransaction($type, $amount) method would be useful. machniak: I see similar code in a few places. Probably adding Entitlement::createTransaction($type… | |||||
vanmeeuwenAuthorUnsubmitted Done Inline ActionsYes, a better version of these de-duplicating code would indeed improve the overall consistency. vanmeeuwen: Yes, a better version of these de-duplicating code would indeed improve the overall consistency. | |||||
[ | |||||
'user_email' => \App\Utils::userEmailOrNull(), | |||||
'object_id' => $entitlement->id, | |||||
'object_type' => \App\Entitlement::class, | |||||
'type' => 'billed', | |||||
'amount' => $cost | |||||
] | |||||
); | |||||
$entitlement->wallet->debit($cost, [$transaction]); | |||||
} | } | ||||
} | } |
Will this work properly when updatedAt->day is e.g. March 30. Could we just calculate $pricePerDay as 1/30 of the monthly cost?