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>
237 lines
5.9 KiB
Ruby
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
|