diff --git a/src/app/Console/Commands/WalletUntil.php b/src/app/Console/Commands/WalletUntil.php --- a/src/app/Console/Commands/WalletUntil.php +++ b/src/app/Console/Commands/WalletUntil.php @@ -43,8 +43,8 @@ return 1; } - $lastsUntil = $wallet->balanceLastsUntil(); + $until = $wallet->balanceLastsUntil(); - $this->info("Lasts until: {$lastsUntil}"); + $this->info("Lasts until: " . ($until ? $until->toDateString() : 'unknown')); } } diff --git a/src/app/Http/Controllers/API/V4/WalletsController.php b/src/app/Http/Controllers/API/V4/WalletsController.php --- a/src/app/Http/Controllers/API/V4/WalletsController.php +++ b/src/app/Http/Controllers/API/V4/WalletsController.php @@ -6,6 +6,7 @@ use App\Wallet; use App\Http\Controllers\Controller; use App\Providers\PaymentProvider; +use Carbon\Carbon; use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; @@ -47,15 +48,33 @@ } /** - * Display the specified resource. + * Return data of the specified wallet. * - * @param string $id + * @param string $id A wallet identifier * - * @return \Illuminate\Http\JsonResponse + * @return \Illuminate\Http\JsonResponse The response */ public function show($id) { - return $this->errorResponse(404); + $wallet = Wallet::find($id); + + if (empty($wallet)) { + return $this->errorResponse(404); + } + + // Only owner (or admin) has access to the wallet + if (!Auth::guard()->user()->canRead($wallet)) { + return $this->errorResponse(403); + } + + $result = $wallet->toArray(); + + $provider = \App\Providers\PaymentProvider::factory($wallet); + + $result['provider'] = $provider->name(); + $result['notice'] = $this->getWalletNotice($wallet); + + return response()->json($result); } /** @@ -257,4 +276,43 @@ 'page' => $page, ]); } + + /** + * Returns human readable notice about the wallet state. + * + * @param \App\Wallet $wallet The wallet + */ + protected function getWalletNotice(Wallet $wallet): ?string + { + if ($wallet->balance < 0) { + return \trans('app.wallet-notice-nocredit'); + } + + if ($wallet->discount && $wallet->discount->discount == 100) { + return null; + } + + if ($wallet->owner->created_at > Carbon::now()->subDays(14)) { + return \trans('app.wallet-notice-trial'); + } + + if ($until = $wallet->balanceLastsUntil()) { + if ($until->isToday()) { + if ($wallet->owner->created_at > Carbon::now()->subDays(30)) { + return \trans('app.wallet-notice-trial-end'); + } + + return \trans('app.wallet-notice-today'); + } + + $params = [ + 'date' => $until->toDateString(), + 'days' => Carbon::now()->diffForHumans($until, Carbon::DIFF_ABSOLUTE), + ]; + + return \trans('app.wallet-notice-date', $params); + } + + return null; + } } diff --git a/src/app/Wallet.php b/src/app/Wallet.php --- a/src/app/Wallet.php +++ b/src/app/Wallet.php @@ -119,11 +119,15 @@ /** * Calculate for how long the current balance will last. * - * @return \Carbon\Carbon Date + * Returns NULL for balance < 0 or discount = 100% or on a fresh account + * + * @return \Carbon\Carbon|null Date */ public function balanceLastsUntil() { - $balance = $this->balance; + if ($this->balance < 0 || $this->getDiscount() == 100) { + return null; + } // retrieve any expected charges $expectedCharge = $this->expectedCharges(); @@ -131,37 +135,24 @@ // get the costs per day for all entitlements billed against this wallet $costsPerDay = $this->costsPerDay(); + if (!$costsPerDay) { + return null; + } + // the number of days this balance, minus the expected charges, would last - $daysDelta = ($balance - $expectedCharge) / $costsPerDay; + $daysDelta = ($this->balance - $expectedCharge) / $costsPerDay; // calculate from the last entitlement billed $entitlement = $this->entitlements()->orderBy('updated_at', 'desc')->first(); - return $entitlement->updated_at->copy()->addDays($daysDelta); - } + $until = $entitlement->updated_at->copy()->addDays($daysDelta); - /** - * A helper to display human-readable amount of money using - * the wallet currency and specified locale. - * - * @param int $amount A amount of money (in cents) - * @param string $locale A locale for the output - * - * @return string String representation, e.g. "9.99 CHF" - */ - public function money(int $amount, $locale = 'de_DE') - { - $amount = round($amount / 100, 2); - - // Prefer intl extension's number formatter - if (class_exists('NumberFormatter')) { - $nf = new \NumberFormatter($locale, \NumberFormatter::CURRENCY); - $result = $nf->formatCurrency($amount, $this->currency); - // Replace non-breaking space - return str_replace("\xC2\xA0", " ", $result); + // Don't return dates from the past + if ($until < Carbon::now() && !$until->isToday()) { + return null; } - return sprintf('%.2f %s', $amount, $this->currency); + return $until; } /** @@ -308,6 +299,30 @@ return (100 - $this->getDiscount()) / 100; } + /** + * A helper to display human-readable amount of money using + * the wallet currency and specified locale. + * + * @param int $amount A amount of money (in cents) + * @param string $locale A locale for the output + * + * @return string String representation, e.g. "9.99 CHF" + */ + public function money(int $amount, $locale = 'de_DE') + { + $amount = round($amount / 100, 2); + + // Prefer intl extension's number formatter + if (class_exists('NumberFormatter')) { + $nf = new \NumberFormatter($locale, \NumberFormatter::CURRENCY); + $result = $nf->formatCurrency($amount, $this->currency); + // Replace non-breaking space + return str_replace("\xC2\xA0", " ", $result); + } + + return sprintf('%.2f %s', $amount, $this->currency); + } + /** * The owner of the wallet -- the wallet is in his/her back pocket. * diff --git a/src/resources/js/app.js b/src/resources/js/app.js --- a/src/resources/js/app.js +++ b/src/resources/js/app.js @@ -145,8 +145,8 @@ link.click() }) }, - price(price) { - return (price/100).toLocaleString('de-DE', { style: 'currency', currency: 'CHF' }) + price(price, currency) { + return (price/100).toLocaleString('de-DE', { style: 'currency', currency: currency || 'CHF' }) }, priceLabel(cost, units = 1, discount) { let index = '' diff --git a/src/resources/lang/en/app.php b/src/resources/lang/en/app.php --- a/src/resources/lang/en/app.php +++ b/src/resources/lang/en/app.php @@ -44,4 +44,10 @@ 'wallet-award-success' => 'The bonus has been added to the wallet successfully.', 'wallet-penalty-success' => 'The penalty has been added to the wallet successfully.', 'wallet-update-success' => 'User wallet updated successfully.', + + 'wallet-notice-date' => 'With your current subscriptions your account balance will last until about :date (:days).', + 'wallet-notice-nocredit' => 'You are out of credit, top up your balance now.', + 'wallet-notice-today' => 'You will run out of credit today, top up your balance now.', + 'wallet-notice-trial' => 'You are in your free trial period.', + 'wallet-notice-trial-end' => 'Your free trial is about to end, top up to continue.', ]; diff --git a/src/resources/vue/Wallet.vue b/src/resources/vue/Wallet.vue --- a/src/resources/vue/Wallet.vue +++ b/src/resources/vue/Wallet.vue @@ -1,12 +1,11 @@