user()->hasRole(SystemRole::TenantAdmin->value), 403); $installation = DeploymentInstallation::query()->firstOrFail(); $license = $entitlements->current($request->user()->tenant_id); return Inertia::render('billing/index', [ 'installation' => ['deployment_type' => $installation->deployment_type->value, 'status' => $installation->status], 'license' => $license ? ['plan' => $license->plan, 'status' => $license->status->value, 'max_devices' => $license->max_devices, 'max_users' => $license->max_users, 'expires_at' => $license->expires_at?->toIso8601String(), 'grace_until' => $license->grace_until?->toIso8601String()] : null, 'plans' => collect(config('billing.plans'))->filter(fn ($plan) => $plan['deployment'] === $installation->deployment_type->value)->map(fn ($plan, $code) => ['code' => $code, ...$plan])->values(), 'orders' => BillingOrder::query()->latest()->limit(20)->get(['uuid', 'plan_code', 'gateway', 'status', 'total', 'currency', 'checkout_url', 'created_at', 'expires_at']), 'pendingOrder' => BillingOrder::query()->where('status', 'pending')->where('expires_at', '>', now())->latest()->first(['uuid', 'plan_code', 'total', 'currency', 'expires_at']), 'gateways' => [config('billing.default_gateway')], ]); } public function store(Request $request): RedirectResponse { abort_unless($request->user()->hasRole(SystemRole::TenantAdmin->value), 403); $data = $request->validate([ 'plan_code' => ['required', Rule::in(array_keys(config('billing.plans')))], 'gateway' => ['required', Rule::in(array_keys(config('billing.gateways')))], ]); $plan = config("billing.plans.{$data['plan_code']}"); $installation = DeploymentInstallation::query()->firstOrFail(); abort_unless($plan['deployment'] === $installation->deployment_type->value, 422, 'Paket tidak sesuai dengan deployment tenant.'); abort_if($plan['price'] === 0, 422, 'Paket gratis tidak membutuhkan checkout.'); BillingOrder::query()->where('status', 'pending')->where('expires_at', '<=', now())->update(['status' => 'expired']); $pending = BillingOrder::query()->where('status', 'pending')->where('expires_at', '>', now())->latest()->first(); if ($pending) { return to_route('checkout.show', $pending->uuid)->with('info', 'Selesaikan pembayaran yang masih pending sebelum membuat perpanjangan baru.'); } $order = BillingOrder::create([ 'tenant_id' => $request->user()->tenant_id, 'plan_code' => $data['plan_code'], 'gateway' => $data['gateway'], 'status' => 'pending', 'subtotal' => $plan['price'], 'tax' => 0, 'total' => $plan['price'], 'currency' => 'IDR', 'expires_at' => now()->addDay(), ]); return to_route('checkout.show', $order->uuid); } }