room; $organization = $room->organization; $minutes = $this->participantMinutes($session); UsageRecord::create([ 'owner_ref' => $session->owner_ref, 'organization_id' => $organization->id, 'branch_id' => $room->branch_id, 'metric' => 'participant_minutes', 'quantity' => $minutes, 'metadata' => ['session_uuid' => $session->uuid, 'room_uuid' => $room->uuid], 'recorded_at' => now(), ]); $this->maybeDebit($organization, $minutes, 'participant_minutes', $session->uuid); } public function recordRecordingStorage(Organization $organization, int $bytes, string $recordingUuid): void { UsageRecord::create([ 'owner_ref' => $organization->owner_ref, 'organization_id' => $organization->id, 'metric' => 'recording_storage_bytes', 'quantity' => $bytes, 'metadata' => ['recording_uuid' => $recordingUuid], 'recorded_at' => now(), ]); } public function recordAiMinutes(Organization $organization, int $minutes, string $sessionUuid): void { UsageRecord::create([ 'owner_ref' => $organization->owner_ref, 'organization_id' => $organization->id, 'metric' => 'ai_minutes', 'quantity' => $minutes, 'metadata' => ['session_uuid' => $sessionUuid], 'recorded_at' => now(), ]); $this->maybeDebit($organization, $minutes, 'ai_minutes', $sessionUuid); } public function usageSummary(Organization $organization, ?int $branchId = null, int $days = 30): array { $since = now()->subDays($days); $query = UsageRecord::where('organization_id', $organization->id) ->where('recorded_at', '>=', $since); if ($branchId) { $query->where('branch_id', $branchId); } return $query ->selectRaw('metric, SUM(quantity) as total') ->groupBy('metric') ->pluck('total', 'metric') ->all(); } protected function participantMinutes(Session $session): int { if (! $session->started_at) { return 0; } $ended = $session->ended_at ?? now(); $durationMinutes = max(1, (int) ceil($session->started_at->diffInSeconds($ended) / 60)); $participants = max(1, $session->participants()->count()); return $durationMinutes * $participants; } protected function maybeDebit(Organization $organization, int $quantity, string $metric, string $reference): void { $rates = config('meet.billing.rates', []); $rateMinor = (int) ($rates[$metric] ?? 0); if ($rateMinor <= 0) { return; } $amountMinor = $quantity * $rateMinor; try { $this->billing->debit( $organization->owner_ref, $amountMinor, 'meet_'.$metric, 'meet-usage-'.$reference, 'Ladill Meet '.$metric, ); } catch (\Throwable $e) { Log::warning('Meet usage billing debit failed', [ 'organization' => $organization->id, 'metric' => $metric, 'error' => $e->getMessage(), ]); } } }