Files
MatchLiveTv/backend/app/controllers/public/clubs_controller.rb
T

269 lines
9.9 KiB
Ruby

module Public
class ClubsController < WebBaseController
include BrandingAttachments
before_action :require_login!
before_action :set_club, only: %i[show edit update billing checkout portal youtube_connect youtube_disconnect]
before_action :require_billing_profile_for_premium_checkout!, only: :checkout
def new
redirect_to public_club_path(current_user.primary_club) if current_user.primary_club
end
def create
if current_user.owned_clubs.exists?
redirect_to public_club_path(current_user.primary_club), alert: t("flash.clubs.already_registered")
return
end
club = Club.new(club_params)
attach_branding_logo(club)
club.save!
ClubMembership.create!(user: current_user, club: club, role: "owner")
first_team_name = params.dig(:first_team, :name).presence || t("club.new.default_first_team_name")
first_team = club.teams.create!(
name: first_team_name,
sport: club.sport
)
desired_plan = params[:plan].presence_in(%w[free premium_light premium_full]) || "free"
Billing::AssignPlan.call(club: club, plan_slug: "free")
Teams::StaffAssignment.designate_club_owner!(team: first_team, user: current_user)
if desired_plan.in?(%w[premium_light premium_full])
interval = Billing::Stripe::PriceCatalog::DEFAULT_INTERVAL
if MatchLiveTv.stripe_enabled?
unless club.billing_profile_complete?
redirect_to public_club_billing_profile_path(club, plan: desired_plan, interval: interval),
alert: t("flash.clubs.complete_billing_first")
return
end
redirect_to public_club_checkout_path(club, plan: desired_plan, interval: interval)
else
redirect_to public_club_billing_path(club), notice: t("flash.clubs.created_complete_subscription")
end
else
redirect_to public_club_path(club), notice: t("flash.clubs.created")
end
rescue ActiveRecord::RecordInvalid => e
flash.now[:alert] = e.record.errors.full_messages.join(", ")
render :new, status: :unprocessable_entity
end
def show
require_club_owner!(@club)
apply_checkout_flash!
@entitlements_team = @club.teams.visible.first
@entitlements = @entitlements_team&.entitlements
@teams = @club.teams.visible.order(:name)
@replay_stats = Recordings::ClubStats.new(@club).call if @entitlements&.can_access_recordings?
end
def edit
require_club_owner!(@club)
@entitlements = @club.teams.first&.entitlements
end
def update
require_club_owner!(@club)
@entitlements = @club.teams.first!.entitlements
@club.assign_attributes(club_params)
attach_branding_logo(@club)
attach_cover_image(@club, entitlements: @entitlements)
@club.save!
enqueue_cover_slate_generation(@club)
redirect_to public_club_path(@club), notice: t("flash.clubs.updated")
rescue ActiveRecord::RecordInvalid => e
@entitlements = @club.teams.first&.entitlements
flash.now[:alert] = e.record.errors.full_messages.join(", ")
render :edit, status: :unprocessable_entity
rescue Teams::EntitlementError, BrandingAttachments::CoverUploadError => e
@entitlements = @club.teams.first&.entitlements
flash.now[:alert] = e.message
render :edit, status: :unprocessable_entity
end
def billing
require_club_owner!(@club)
sync_checkout_return!
finalize_subscription_if_due!
@subscription = @club.subscription&.reload
apply_checkout_flash!
@team = @club.teams.first!
@entitlements = @team.entitlements
@plans = Plan.ordered
@payments = @club.billing_payments.recent.includes(:invoice).limit(50)
@quote = @club.active_billing_quote
@pending_transfer = @club.billing_transfer_orders.awaiting_payment.first
end
def checkout
require_club_owner!(@club)
if @club.subscription&.admin_comped?
redirect_to public_club_billing_path(@club),
alert: t("flash.clubs.comped_change_denied")
return
end
if @club.active_billing_quote.present?
redirect_to public_club_billing_path(@club),
alert: t("flash.club_billing.quote_checkout_denied")
return
end
unless MatchLiveTv.stripe_enabled?
redirect_to public_club_billing_path(@club), alert: t("flash.clubs.stripe_not_configured")
return
end
plan_slug = params[:plan].presence_in(%w[premium_light premium_full]) || "premium_light"
interval = checkout_interval_param
target_plan = Plan[plan_slug]
sub = @club.subscription
if sub&.stripe_subscription_id.present? && sub.active? &&
sub.plan.slug == plan_slug && sub.billing_interval == interval && !sub.plan_change_pending?
redirect_to public_club_billing_path(@club),
notice: t("flash.clubs.already_on_plan", plan: target_plan.name, price: Billing::Stripe::PriceCatalog.label(plan_slug: plan_slug, interval: interval))
return
end
if sub&.plan_change_pending? && sub.pending_plan&.slug == plan_slug &&
sub.pending_billing_interval == interval
when_label = sub.current_period_end.present? ? I18n.l(sub.current_period_end, format: :long) : t("billing.messages.next_renewal")
redirect_to public_club_billing_path(@club),
notice: t("flash.clubs.change_already_scheduled", plan: target_plan.name, date: when_label)
return
end
if sub&.stripe_subscription_id.present? && sub.active?
result = Billing::Stripe::ChangePlan.call(club: @club, plan_slug: plan_slug, interval: interval)
redirect_to public_club_billing_path(@club),
notice: Billing::Stripe::PlanChangeMessages.flash_notice(
result,
current_plan: sub.plan
)
else
url = Billing::Stripe::CheckoutSession.new(
club: @club, user: current_user, plan_slug: plan_slug, interval: interval
).url
redirect_to url, allow_other_host: true
end
rescue ArgumentError => e
redirect_to public_club_billing_path(@club), alert: e.message
rescue ::Stripe::StripeError => e
Rails.logger.warn("[Stripe checkout] #{e.message}")
redirect_to public_club_billing_path(@club), alert: t("flash.clubs.stripe_error", message: e.message)
end
def youtube_connect
require_club_owner!(@club)
entitlements = @club.teams.first!.entitlements
entitlements.assert_can_connect_youtube!
if ENV["YOUTUBE_CLIENT_ID"].blank?
redirect_to public_club_path(@club), alert: t("flash.clubs.youtube_oauth_not_configured")
return
end
return_app = params[:return_app] == "1"
state = Youtube::OauthState.for_club(
club_id: @club.id,
user_id: current_user.id,
return_app: return_app
)
redirect_to Youtube::OauthUrl.build(state: state), allow_other_host: true
rescue Teams::EntitlementError => e
redirect_to public_club_path(@club), alert: e.message
end
def youtube_disconnect
require_club_owner!(@club)
@club.youtube_credential&.destroy!
redirect_to public_club_path(@club), notice: t("flash.clubs.youtube_disconnected")
end
def portal
require_club_owner!(@club)
unless MatchLiveTv.stripe_enabled?
redirect_to public_club_billing_path(@club), alert: t("flash.clubs.portal_not_configured")
return
end
url = Billing::Stripe::CheckoutSession.new(club: @club, user: current_user).portal_url
redirect_to url, allow_other_host: true
end
private
def set_club
@club = current_user.owned_clubs.find(params[:id])
end
def club_params
p = params.require(:club).permit(
:name, :sport, :logo_url, :primary_color, :secondary_color,
:billing_entity_type, :billing_legal_name, :billing_vat_number, :billing_fiscal_code,
:billing_email, :billing_phone, :billing_address_line, :billing_city, :billing_province,
:billing_postal_code, :billing_country, :billing_recipient_code, :billing_pec
)
p[:primary_color] = normalize_hex_color(p[:primary_color], "#e53935")
p[:secondary_color] = normalize_hex_color(p[:secondary_color], "#ffffff")
p[:sport] = Sports::Catalog.normalize_key(p[:sport]) if p[:sport].present?
p
end
def require_billing_profile_for_premium_checkout!
require_club_owner!(@club)
plan_slug = params[:plan].presence_in(%w[premium_light premium_full])
return if plan_slug.blank?
return if @club.billing_profile_complete?
redirect_to public_club_billing_profile_path(
@club,
plan: plan_slug,
interval: params[:interval].presence
), alert: t("flash.clubs.complete_billing_first")
end
def checkout_interval_param
Billing::Stripe::PriceCatalog.normalize_interval(params[:interval])
rescue ArgumentError
Billing::Stripe::PriceCatalog::DEFAULT_INTERVAL
end
def finalize_subscription_if_due!
return unless MatchLiveTv.stripe_enabled?
Billing::Stripe::FinalizeSubscription.call(club: @club)
rescue ::Stripe::StripeError => e
Rails.logger.warn("[Stripe finalize subscription] #{e.message}")
end
def sync_checkout_return!
return unless params[:checkout] == "success"
return unless MatchLiveTv.stripe_enabled?
Billing::Stripe::CheckoutSync.call(
club: @club,
session_id: params[:session_id].presence
)
rescue ::Stripe::StripeError => e
Rails.logger.warn("[Stripe checkout sync] #{e.message}")
end
def apply_checkout_flash!
case params[:checkout]
when "success"
plan_name = @subscription&.plan&.name || "Premium"
flash.now[:notice] = t("flash.clubs.checkout_success", plan: plan_name)
when "canceled"
flash.now[:alert] = t("flash.clubs.checkout_canceled")
end
end
end
end