Files
ladill-transfer/app/Http/Controllers/Qr/AccountController.php
T
isaaccladandCursor 45ccd04163
Deploy Ladill Transfer / deploy (push) Successful in 27s
Differentiate Billing from Wallet with storage usage breakdown.
Billing lists per-transfer storage costs and monthly estimates; Wallet stays focused on balance and top-up.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-08 10:43:56 +00:00

112 lines
3.6 KiB
PHP

<?php
namespace App\Http\Controllers\Qr;
use App\Http\Controllers\Controller;
use App\Models\QrSetting;
use App\Models\Transfer;
use App\Services\Billing\BillingClient;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\View\View;
class AccountController extends Controller
{
public function __construct(private BillingClient $billing) {}
private function topupUrl(): string
{
return 'https://'.config('app.account_domain').'/wallet';
}
/** @return array{0: int, 1: array<string, mixed>} */
private function billingSnapshot(?string $publicId): array
{
if (! $publicId) {
return [0, []];
}
$balanceMinor = $this->billing->balanceMinor($publicId);
$ledger = $this->billing->serviceLedger($publicId, config('billing.service', 'transfer'));
return [$balanceMinor, $ledger];
}
public function wallet(): View
{
$user = ladill_account();
[$balanceMinor, $ledger] = $this->billingSnapshot($user?->public_id);
return view('qr.account.wallet', [
'balanceMinor' => $balanceMinor,
'spentMinor' => (int) ($ledger['spent_minor'] ?? 0),
'creditedMinor' => (int) ($ledger['credited_minor'] ?? 0),
'topupUrl' => $this->topupUrl(),
]);
}
public function billing(): View
{
$user = ladill_account();
[$balanceMinor, $ledger] = $this->billingSnapshot($user?->public_id);
$activeTransfers = Transfer::query()
->where('user_id', $user->id)
->where('status', Transfer::STATUS_ACTIVE)
->where(function ($query) {
$query->whereNull('expires_at')->orWhere('expires_at', '>', now());
})
->orderByDesc('storage_bytes')
->get();
$storageBytes = (int) $activeTransfers->sum('storage_bytes');
$storageGb = round($storageBytes / (1024 * 1024 * 1024), 2);
$pricePerGb = (float) config('transfer.price_per_gb_month', 1.0);
$monthlyTotalGhs = round($activeTransfers->sum(fn (Transfer $transfer) => $transfer->monthlyCostGhs()), 2);
return view('qr.account.billing', [
'balanceMinor' => $balanceMinor,
'spentMinor' => (int) ($ledger['spent_minor'] ?? 0),
'creditedMinor' => (int) ($ledger['credited_minor'] ?? 0),
'activeTransfers' => $activeTransfers,
'storageBytes' => $storageBytes,
'storageGb' => $storageGb,
'pricePerGb' => $pricePerGb,
'monthlyTotalGhs' => $monthlyTotalGhs,
'walletUrl' => route('account.wallet'),
'topupUrl' => $this->topupUrl(),
]);
}
public function settings(): View
{
$account = ladill_account();
$settings = $account->getOrCreateQrSetting();
return view('transfer.settings', [
'account' => $account,
'settings' => $settings,
]);
}
public function updateSettings(Request $request): RedirectResponse
{
$account = ladill_account();
$data = $request->validate([
'notify_email' => ['nullable', 'email', 'max:255'],
'product_updates' => ['nullable', 'boolean'],
]);
QrSetting::updateOrCreate(
['user_id' => $account->id],
[
'notify_email' => $data['notify_email'] ?? null,
'product_updates' => $request->boolean('product_updates'),
],
);
return redirect()->route('account.settings')->with('success', 'Settings saved.');
}
}