Files
MatchLiveTv/backend/app/services/teams/entitlements.rb
Emiliano Frascaro f4b7be0f80 Billing Stripe, link regia mobile e staff solo trasmissione.
Aggiunge fatturazione club, pagina regia condivisibile senza account, roster squadre e rimuove la modalità controller dall'app (v1.1.0).

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-29 07:23:13 +02:00

237 lines
5.9 KiB
Ruby

module Teams
class Entitlements
ACTIVE_STREAM_STATUSES = %w[idle connecting live reconnecting paused].freeze
def initialize(team)
@team = team
@club = team.club
end
def subscription
@subscription ||= @club.subscription || ensure_free_subscription!
end
def plan
subscription.plan
end
def active?
subscription.active?
end
def premium_active?
subscription.premium?
end
def premium_full?
subscription.premium_full?
end
def youtube_enabled?
active? && plan.youtube_enabled?
end
def phone_download_enabled?
active? && plan.phone_download_enabled?
end
def max_staff_transmission
plan.max_staff_transmission
end
def max_staff_regia
plan.max_staff_regia
end
def max_staff
plan.max_staff
end
def staff_count
staff_count_for("transmission")
end
def staff_count_for(_kind = "transmission")
staff_coverage.covered_count
end
def staff_assigned_for(_kind = "transmission")
staff_coverage.assigned_count
end
def members_count
@team.user_teams.where(role: "member").count
end
def members_count_for(kind)
@team.user_teams.where(staff_kind: kind).count
end
def pending_invitations_count
@team.team_invitations.pending.count
end
def pending_invitations_count_for(kind)
@team.team_invitations.pending.where(staff_kind: kind).count
end
def concurrent_streams_limit
plan.concurrent_streams_limit
end
def concurrent_streams_used
StreamSession.joins(match: :team)
.where(teams: { club_id: @club.id })
.where(status: ACTIVE_STREAM_STATUSES)
.count
end
def concurrent_streams_limit_reached?
limit = concurrent_streams_limit
return false if limit.nil?
concurrent_streams_used >= limit
end
def can_stream_on?(platform)
return false unless active?
platform = platform.to_s
return false unless plan.allows_platform?(platform)
true
end
def assert_can_stream_on!(platform)
platform = platform.to_s
unless active?
raise EntitlementError.new(
"Abbonamento non attivo per la società",
code: "subscription_inactive",
billing_url: billing_url
)
end
if platform == "youtube" && !youtube_enabled?
raise EntitlementError.new(
"YouTube richiede un piano Premium",
code: "premium_required",
billing_url: billing_url
)
end
if platform == "youtube" && premium_full? == false && plan.youtube_mode != "matchlivetv_light"
raise EntitlementError.new(
"Il canale YouTube della società richiede Premium Full",
code: "premium_full_required",
billing_url: billing_url
)
end
return if plan.allows_platform?(platform)
raise EntitlementError.new("Piattaforma non consentita", code: "platform_denied", billing_url: billing_url)
end
def assert_concurrent_stream!(excluding_session: nil)
return unless active?
used = concurrent_streams_used
used -= 1 if excluding_session && ACTIVE_STREAM_STATUSES.include?(excluding_session.status)
limit = concurrent_streams_limit
return if limit.nil?
return if used < limit
raise EntitlementError.new(
"Limite dirette concorrenti raggiunto (#{limit}). Chiudi una diretta o passa a un piano superiore.",
code: "concurrent_limit_reached",
billing_url: billing_url
)
end
def assert_can_invite!(staff_kind: "transmission")
return unless active?
limit = max_staff_transmission
return if limit.nil?
used = staff_assigned_for
return if used < limit
raise EntitlementError.new(
"Limite responsabili trasmissione raggiunto (#{limit} all'anno). Passa a un piano superiore.",
code: "staff_limit_reached",
billing_url: billing_url
)
end
def assert_can_connect_youtube!
unless premium_full?
raise EntitlementError.new(
"Collegamento al canale YouTube della società richiede Premium Full",
code: "premium_full_required",
billing_url: billing_url
)
end
assert_can_stream_on!("youtube")
end
def can_access_recordings?
active? && plan.recordings_enabled?
end
def recording_enabled_for_mediamtx?
can_access_recordings?
end
def recording_retention_days
plan.recording_days
end
def billing_url
"#{MatchLiveTv.app_public_url.chomp('/')}/clubs/#{@club.id}/billing"
end
def staff_manage_url
"#{MatchLiveTv.app_public_url.chomp('/')}/teams/#{@team.id}/dashboard"
end
def as_json
{
plan_slug: plan.slug,
plan_name: plan.name,
premium_active: premium_active?,
premium_full: premium_full?,
subscription_status: subscription.status,
features: plan.features,
billing_url: billing_url,
staff_manage_url: staff_manage_url,
max_staff: max_staff,
max_staff_transmission: max_staff_transmission,
staff_used: staff_count,
staff_transmission_used: staff_count_for("transmission"),
concurrent_streams_used: concurrent_streams_used,
concurrent_streams_limit: concurrent_streams_limit,
recordings_enabled: can_access_recordings?,
recording_retention_days: recording_retention_days,
phone_download_enabled: phone_download_enabled?,
youtube_enabled: youtube_enabled?,
youtube_mode: plan.youtube_mode
}
end
def staff_coverage
@staff_coverage ||= StaffCoverage.new(@team)
end
private
def ensure_free_subscription!
Billing::AssignPlan.call(club: @club, plan_slug: "free")
@club.reload.subscription
end
end
end