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 @@ -113,12 +113,13 @@ } $cost = 0; + $now = Carbon::now(); // 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()); + $diffInMonths = $entitlement->updated_at->diffInMonths($now); $cost += (int) ($entitlement->cost * $discount * $diffInMonths); // this moves the hypothetical updated at forward to however many months past the original @@ -126,24 +127,21 @@ // 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. - // + // 12th 2020. Calculating the costs for the entitlement is based on the daily price - $diffInDays = $updatedAt->diffInDays(Carbon::now()); + // 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 $daysInMonth=30 - $dayOfThisMonth = Carbon::now()->day; + $diffInDays = $updatedAt->diffInDays($now); - // 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(); + if ($now->day >= $diffInDays) { + $daysInMonth = $now->daysInMonth; + } else { + $daysInMonth = \App\Utils::daysInLastMonth(); + } - $pricePerDay = (float)$entitlement->cost / $daysInLastMonth; + $pricePerDay = $entitlement->cost / $daysInMonth; $cost += (int) (round($pricePerDay * $discount * $diffInDays, 0)); 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 @@ -150,18 +150,32 @@ $wallet = $user->wallets()->first(); - $this->backdateEntitlements($user->entitlements, Carbon::now()->subWeeks(7)); + $backdate = Carbon::now()->subWeeks(7); + $this->backdateEntitlements($user->entitlements, $backdate); $charge = $wallet->chargeEntitlements(); - $this->assertTrue($wallet->balance < 0); + $this->assertSame(-1099, $wallet->balance); $balance = $wallet->balance; + $discount = \App\Discount::where('discount', 30)->first(); + $wallet->discount()->associate($discount); + $wallet->save(); $user->removeSku($storage, 4); - // we expect the wallet to have been charged. - $this->assertTrue($wallet->fresh()->balance < $balance); + // we expect the wallet to have been charged for ~3 weeks of use of + // 4 deleted storage entitlements, it should also take discount into account + $backdate->addMonthsWithoutOverflow(1); + $diffInDays = $backdate->diffInDays(Carbon::now()); + + // entitlements-num * cost * discount * days-in-month + $max = intval(4 * 25 * 0.7 * $diffInDays / 28); + $min = intval(4 * 25 * 0.7 * $diffInDays / 31); + + $wallet->refresh(); + $this->assertTrue($wallet->balance >= $balance - $max); + $this->assertTrue($wallet->balance <= $balance - $min); $transactions = \App\Transaction::where('object_id', $wallet->id) ->where('object_type', \App\Wallet::class)->get();