module Public class ClubsController < WebBaseController include BrandingAttachments before_action :require_login! before_action :set_club, only: %i[show edit update billing checkout portal] 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: "Hai già registrato una società" 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 || "Prima squadra" club.teams.create!( name: first_team_name, sport: club.sport ) plan = params[:plan].presence_in(%w[free premium_light premium_full]) || "free" Billing::AssignPlan.call(club: club, plan_slug: plan) if plan.in?(%w[premium_light premium_full]) && MatchLiveTv.stripe_enabled? unless club.billing_profile_complete? redirect_to public_club_billing_profile_path(club, plan: plan, interval: checkout_interval_param), alert: "Completa i dati di fatturazione prima di attivare un piano premium." return end interval = checkout_interval_param redirect_to public_club_checkout_path(club, plan: plan, interval: interval) else redirect_to public_club_path(club), notice: "Società e prima squadra create." 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.first @entitlements = @entitlements_team&.entitlements @teams = @club.teams.order(:name) end def edit require_club_owner!(@club) end def update require_club_owner!(@club) @club.assign_attributes(club_params) attach_branding_logo(@club) @club.save! redirect_to public_club_path(@club), notice: "Società aggiornata." rescue ActiveRecord::RecordInvalid => e flash.now[:alert] = e.record.errors.full_messages.join(", ") 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) end def checkout require_club_owner!(@club) unless MatchLiveTv.stripe_enabled? redirect_to public_club_billing_path(@club), alert: "Pagamenti non ancora configurati sul server" 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: "Sei già su #{target_plan.name} (#{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) : "il prossimo rinnovo" redirect_to public_club_billing_path(@club), notice: "Il passaggio a #{target_plan.name} è già programmato dal #{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: "Errore Stripe: #{e.message}" end def portal require_club_owner!(@club) unless MatchLiveTv.stripe_enabled? redirect_to public_club_billing_path(@club), alert: "Portale pagamenti non configurato" 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 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: "Completa i dati di fatturazione prima di attivare un piano premium." 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] = "Pagamento completato! Piano attivo: #{plan_name}." when "canceled" flash.now[:alert] = "Pagamento annullato. Nessun addebito è stato effettuato." end end end end