Changeset View
Changeset View
Standalone View
Standalone View
src/app/Wallet.php
Show First 20 Lines • Show All 52 Lines • ▼ Show 20 Lines | class Wallet extends Model | ||||
*/ | */ | ||||
public function addController(User $user) | public function addController(User $user) | ||||
{ | { | ||||
if (!$this->controllers->contains($user)) { | if (!$this->controllers->contains($user)) { | ||||
$this->controllers()->save($user); | $this->controllers()->save($user); | ||||
} | } | ||||
} | } | ||||
public function chargeEntitlements($apply = true) | /** | ||||
* Charge entitlements in the wallet | |||||
* | |||||
* @param bool $apply Set to false for a dry-run mode | |||||
* | |||||
* @return int Charged amount in cents | |||||
*/ | |||||
public function chargeEntitlements($apply = true): int | |||||
{ | { | ||||
// This wallet has been created less than a month ago, this is the trial period | // This wallet has been created less than a month ago, this is the trial period | ||||
if ($this->owner->created_at >= Carbon::now()->subMonthsWithoutOverflow(1)) { | if ($this->owner->created_at >= Carbon::now()->subMonthsWithoutOverflow(1)) { | ||||
// Move all the current entitlement's updated_at timestamps forward to one month after | // Move all the current entitlement's updated_at timestamps forward to one month after | ||||
// this wallet was created. | // this wallet was created. | ||||
$freeMonthEnds = $this->owner->created_at->copy()->addMonthsWithoutOverflow(1); | $freeMonthEnds = $this->owner->created_at->copy()->addMonthsWithoutOverflow(1); | ||||
foreach ($this->entitlements()->get()->fresh() as $entitlement) { | foreach ($this->entitlements()->get()->fresh() as $entitlement) { | ||||
if ($entitlement->updated_at < $freeMonthEnds) { | if ($entitlement->updated_at < $freeMonthEnds) { | ||||
$entitlement->updated_at = $freeMonthEnds; | $entitlement->updated_at = $freeMonthEnds; | ||||
$entitlement->save(); | $entitlement->save(); | ||||
} | } | ||||
} | } | ||||
return 0; | return 0; | ||||
} | } | ||||
$charges = 0; | $charges = 0; | ||||
$discount = $this->getDiscountRate(); | $discount = $this->getDiscountRate(); | ||||
$isDegraded = $this->owner->isDegraded(); | |||||
if ($apply) { | |||||
DB::beginTransaction(); | DB::beginTransaction(); | ||||
} | |||||
// used to parent individual entitlement billings to the wallet debit. | // used to parent individual entitlement billings to the wallet debit. | ||||
$entitlementTransactions = []; | $entitlementTransactions = []; | ||||
foreach ($this->entitlements()->get()->fresh() as $entitlement) { | foreach ($this->entitlements()->get() as $entitlement) { | ||||
// This entitlement has been created less than or equal to 14 days ago (this is at | // This entitlement has been created less than or equal to 14 days ago (this is at | ||||
// maximum the fourteenth 24-hour period). | // maximum the fourteenth 24-hour period). | ||||
if ($entitlement->created_at > Carbon::now()->subDays(14)) { | if ($entitlement->created_at > Carbon::now()->subDays(14)) { | ||||
continue; | continue; | ||||
} | } | ||||
// This entitlement was created, or billed last, less than a month ago. | // This entitlement was created, or billed last, less than a month ago. | ||||
if ($entitlement->updated_at > Carbon::now()->subMonthsWithoutOverflow(1)) { | if ($entitlement->updated_at > Carbon::now()->subMonthsWithoutOverflow(1)) { | ||||
continue; | continue; | ||||
} | } | ||||
// updated last more than a month ago -- was it billed? | // updated last more than a month ago -- was it billed? | ||||
if ($entitlement->updated_at <= Carbon::now()->subMonthsWithoutOverflow(1)) { | if ($entitlement->updated_at <= Carbon::now()->subMonthsWithoutOverflow(1)) { | ||||
$diff = $entitlement->updated_at->diffInMonths(Carbon::now()); | $diff = $entitlement->updated_at->diffInMonths(Carbon::now()); | ||||
$cost = (int) ($entitlement->cost * $discount * $diff); | $cost = (int) ($entitlement->cost * $discount * $diff); | ||||
if ($isDegraded) { | |||||
$cost = 0; | |||||
} | |||||
$charges += $cost; | $charges += $cost; | ||||
// if we're in dry-run, you know... | // if we're in dry-run, you know... | ||||
if (!$apply) { | if (!$apply) { | ||||
continue; | continue; | ||||
} | } | ||||
$entitlement->updated_at = $entitlement->updated_at->copy() | $entitlement->updated_at = $entitlement->updated_at->copy() | ||||
Show All 9 Lines | public function chargeEntitlements($apply = true): int | ||||
\App\Transaction::ENTITLEMENT_BILLED, | \App\Transaction::ENTITLEMENT_BILLED, | ||||
$cost | $cost | ||||
); | ); | ||||
} | } | ||||
} | } | ||||
if ($apply) { | if ($apply) { | ||||
$this->debit($charges, $entitlementTransactions); | $this->debit($charges, $entitlementTransactions); | ||||
} | |||||
DB::commit(); | DB::commit(); | ||||
} | |||||
return $charges; | return $charges; | ||||
} | } | ||||
/** | /** | ||||
* Calculate for how long the current balance will last. | * Calculate for how long the current balance will last. | ||||
* | * | ||||
* Returns NULL for balance < 0 or discount = 100% or on a fresh account | * Returns NULL for balance < 0 or discount = 100% or on a fresh account | ||||
▲ Show 20 Lines • Show All 251 Lines • ▼ Show 20 Lines | class Wallet extends Model | ||||
{ | { | ||||
return \App\Transaction::where( | return \App\Transaction::where( | ||||
[ | [ | ||||
'object_id' => $this->id, | 'object_id' => $this->id, | ||||
'object_type' => \App\Wallet::class | 'object_type' => \App\Wallet::class | ||||
] | ] | ||||
); | ); | ||||
} | } | ||||
/** | |||||
* Force-update entitlements' updated_at, charge if needed. | |||||
* | |||||
* @param bool $withCost When enabled the cost will be charged | |||||
* | |||||
* @return int Charged amount in cents | |||||
*/ | |||||
public function updateEntitlements($withCost = true): int | |||||
{ | |||||
$charges = 0; | |||||
$discount = $this->getDiscountRate(); | |||||
$now = Carbon::now(); | |||||
DB::beginTransaction(); | |||||
// used to parent individual entitlement billings to the wallet debit. | |||||
$entitlementTransactions = []; | |||||
foreach ($this->entitlements()->get() as $entitlement) { | |||||
$cost = 0; | |||||
$diffInDays = $entitlement->updated_at->diffInDays($now); | |||||
// This entitlement has been created less than or equal to 14 days ago (this is at | |||||
// maximum the fourteenth 24-hour period). | |||||
if ($entitlement->created_at > Carbon::now()->subDays(14)) { | |||||
// $cost=0 | |||||
} elseif ($withCost && $diffInDays > 0) { | |||||
// The price per day is based on the number of days in the last month | |||||
// or the current month if the period does not overlap with the previous month | |||||
// FIXME: This really should be simplified to constant $daysInMonth=30 | |||||
if ($now->day >= $diffInDays && $now->month == $entitlement->updated_at->month) { | |||||
$daysInMonth = $now->daysInMonth; | |||||
} else { | |||||
$daysInMonth = \App\Utils::daysInLastMonth(); | |||||
} | |||||
$pricePerDay = $entitlement->cost / $daysInMonth; | |||||
$cost = (int) (round($pricePerDay * $discount * $diffInDays, 0)); | |||||
} | |||||
if ($diffInDays > 0) { | |||||
$entitlement->updated_at = $entitlement->updated_at->setDateFrom($now); | |||||
$entitlement->save(); | |||||
} | |||||
if ($cost == 0) { | |||||
continue; | |||||
} | |||||
$charges += $cost; | |||||
// FIXME: Shouldn't we store also cost=0 transactions (to have the full history)? | |||||
$entitlementTransactions[] = $entitlement->createTransaction( | |||||
\App\Transaction::ENTITLEMENT_BILLED, | |||||
$cost | |||||
); | |||||
} | |||||
if ($charges > 0) { | |||||
$this->debit($charges, $entitlementTransactions); | |||||
} | |||||
DB::commit(); | |||||
return $charges; | |||||
} | |||||
} | } |