current($tenantId); return $license !== null && ($license->grace_until ?? $license->expires_at)->isFuture(); } public function provisionInitial(Tenant $tenant, DeploymentInstallation $installation, string $planCode, bool $activate = false, ?int $issuerId = null): License { $plan = config("billing.plans.{$planCode}"); abort_unless($plan && $plan['deployment'] === $installation->deployment_type->value, 422, 'Paket tidak sesuai deployment tenant.'); $isFree = $plan['price'] === 0; $startsAt = now(); return License::withoutGlobalScope('tenant')->create([ 'tenant_id' => $tenant->id, 'deployment_installation_id' => $installation->id, 'license_key_hash' => hash('sha256', random_bytes(32)), 'plan' => $planCode, 'status' => $activate || $isFree ? LicenseStatus::Active : LicenseStatus::Pending, 'max_devices' => $plan['max_devices'], 'max_users' => $plan['max_users'], 'features' => ['device_access_management'], 'starts_at' => $startsAt, 'expires_at' => $isFree ? $startsAt->copy()->addYears(10) : $startsAt->copy()->addMonth(), 'grace_until' => $isFree ? null : $startsAt->copy()->addMonth()->addDays(7), 'issued_by' => $issuerId, ]); } public function current(int $tenantId): ?License { $license = License::withoutGlobalScope('tenant')->where('tenant_id', $tenantId) ->whereIn('status', [LicenseStatus::Active->value, LicenseStatus::Grace->value]) ->latest('created_at')->first(); if ($license) { return $license; } if (License::withoutGlobalScope('tenant')->where('tenant_id', $tenantId)->exists()) { return null; } $installation = DeploymentInstallation::withoutGlobalScope('tenant')->where('tenant_id', $tenantId)->first(); if (! $installation || $installation->deployment_type->value !== 'managed_cloud') { return null; } $plan = config('billing.plans.cloud_free'); return License::withoutGlobalScope('tenant')->create([ 'tenant_id' => $tenantId, 'deployment_installation_id' => $installation->id, 'license_key_hash' => hash('sha256', random_bytes(32)), 'plan' => 'cloud_free', 'status' => LicenseStatus::Active, 'max_devices' => $plan['max_devices'], 'max_users' => $plan['max_users'], 'features' => ['device_access_management'], 'starts_at' => now(), 'expires_at' => now()->addYears(10), ]); } public function assertCanAddDevice(int $tenantId): void { $license = $this->current($tenantId); abort_unless($license, 402, 'Lisensi tenant belum aktif.'); abort_if($license->max_devices !== null && Device::withoutGlobalScope('tenant')->where('tenant_id', $tenantId)->count() >= $license->max_devices, 422, 'Batas perangkat paket tercapai. Upgrade paket melalui menu Lisensi & Tagihan.'); } public function assertCanAddUser(int $tenantId): void { $license = $this->current($tenantId); abort_unless($license, 402, 'Lisensi tenant belum aktif.'); abort_if($license->max_users !== null && User::withoutGlobalScope('tenant')->where('tenant_id', $tenantId)->count() >= $license->max_users, 422, 'Batas user aplikasi paket tercapai. Upgrade paket melalui menu Lisensi & Tagihan.'); } }