Files
ladill-meet/app/Services/Meet/LicenseService.php
T
isaaccladandCursor 965fb992e9
Deploy Ladill Meet / deploy (push) Failing after 7s
Initial Ladill Meet release.
Phases 0–18: core meetings, webinar, breakouts, team chat, live streaming, town hall, billing, and Ladill Mail calendar wiring.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-30 23:35:29 +00:00

68 lines
2.0 KiB
PHP

<?php
namespace App\Services\Meet;
use App\Models\Organization;
use App\Models\UsageRecord;
class LicenseService
{
/** @var array<string, array<string, int>> */
public const TIERS = [
'standard' => [
'participant_minutes' => 10000,
'recording_storage_bytes' => 5_368_709_120, // 5 GB
'ai_minutes' => 120,
],
'professional' => [
'participant_minutes' => 50000,
'recording_storage_bytes' => 26_843_545_600, // 25 GB
'ai_minutes' => 600,
],
'enterprise' => [
'participant_minutes' => 500000,
'recording_storage_bytes' => 107_374_182_400, // 100 GB
'ai_minutes' => 5000,
],
];
public function quotas(Organization $organization): array
{
$tier = $organization->license_tier ?? 'standard';
$defaults = self::TIERS[$tier] ?? self::TIERS['standard'];
return array_merge($defaults, (array) ($organization->usage_quotas ?? []));
}
public function withinQuota(Organization $organization, string $metric, int $additional = 0, ?int $branchId = null): bool
{
$quotas = $this->quotas($organization);
$limit = (int) ($quotas[$metric] ?? 0);
if ($limit <= 0) {
return true;
}
$since = now()->startOfMonth();
$query = UsageRecord::where('organization_id', $organization->id)
->where('metric', $metric)
->where('recorded_at', '>=', $since);
if ($branchId) {
$query->where('branch_id', $branchId);
}
$used = (int) $query->sum('quantity');
return ($used + $additional) <= $limit;
}
public function assertCanStartSession(Organization $organization, ?int $branchId = null): void
{
abort_unless(
$this->withinQuota($organization, 'participant_minutes', 60, $branchId),
402,
'Participant-minute quota exceeded for this billing period.',
);
}
}