Gli admin possono concedere o revocare Premium Light/Full senza Stripe; il piano omaggio ha priorità sui webhook e la società vede un messaggio dedicato. Co-authored-by: Cursor <cursoragent@cursor.com>
218 lines
7.8 KiB
Ruby
218 lines
7.8 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]
|
|
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)
|
|
if @club.subscription&.admin_comped?
|
|
redirect_to public_club_billing_path(@club),
|
|
alert: "Il piano è un abbonamento omaggio gestito da Match Live TV. Per passare a un abbonamento a pagamento contatta il supporto."
|
|
return
|
|
end
|
|
|
|
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
|