Blocca l'invio di numeri carta dall'API server, usa Checkout anche per i cambi piano e nasconde correttamente il placeholder video in regia. Co-authored-by: Cursor <cursoragent@cursor.com>
80 lines
2.6 KiB
Ruby
80 lines
2.6 KiB
Ruby
module Billing
|
|
module Stripe
|
|
# Solo per sincronizzazione interna/test mockati.
|
|
# I cambi piano utente devono passare da CheckoutSession (Stripe Checkout hosted).
|
|
# Non creare mai PaymentMethod con card[number] sul server (violazione PCI).
|
|
class ChangePlan
|
|
VALID_PLANS = CheckoutSession::VALID_PLANS.freeze
|
|
|
|
def self.call(club:, plan_slug:)
|
|
new(club: club, plan_slug: plan_slug).call
|
|
end
|
|
|
|
def initialize(club:, plan_slug:)
|
|
@club = club
|
|
@plan_slug = plan_slug.to_s
|
|
end
|
|
|
|
def call
|
|
raise "Stripe non configurato" unless MatchLiveTv.stripe_enabled?
|
|
raise "Piano non valido" unless VALID_PLANS.include?(@plan_slug)
|
|
|
|
sub = @club.subscription
|
|
raise "Nessun abbonamento Stripe attivo" if sub.blank? || sub.stripe_subscription_id.blank?
|
|
raise "Sei già su questo piano" if sub.plan.slug == @plan_slug
|
|
|
|
price_id = Plan[@plan_slug].stripe_price_id.presence || stripe_price_id_for(@plan_slug)
|
|
raise "Price ID Stripe mancante per #{@plan_slug}" if price_id.blank?
|
|
|
|
stripe_sub = ::Stripe::Subscription.retrieve(sub.stripe_subscription_id)
|
|
item_id = stripe_sub.items.data.first.id
|
|
|
|
updated = ::Stripe::Subscription.update(
|
|
stripe_sub.id,
|
|
items: [{ id: item_id, price: price_id }],
|
|
metadata: { club_id: @club.id, plan_slug: @plan_slug },
|
|
proration_behavior: "create_prorations"
|
|
)
|
|
|
|
apply_local_plan!(updated)
|
|
updated
|
|
end
|
|
|
|
private
|
|
|
|
def stripe_price_id_for(slug)
|
|
case slug
|
|
when "premium_light" then MatchLiveTv.stripe_premium_light_price_id
|
|
when "premium_full" then MatchLiveTv.stripe_premium_full_price_id
|
|
end
|
|
end
|
|
|
|
def apply_local_plan!(stripe_sub)
|
|
period_start, period_end = SubscriptionPeriod.times(stripe_sub)
|
|
Billing::AssignPlan.call(
|
|
club: @club,
|
|
plan_slug: @plan_slug,
|
|
status: map_status(stripe_sub.status),
|
|
stripe_attrs: {
|
|
stripe_customer_id: stripe_sub.customer,
|
|
stripe_subscription_id: stripe_sub.id,
|
|
current_period_start: period_start,
|
|
current_period_end: period_end,
|
|
cancel_at_period_end: stripe_sub.cancel_at_period_end
|
|
}
|
|
)
|
|
end
|
|
|
|
def map_status(stripe_status)
|
|
case stripe_status
|
|
when "trialing" then "trialing"
|
|
when "active" then "active"
|
|
when "past_due", "unpaid" then "past_due"
|
|
when "canceled", "incomplete_expired" then "canceled"
|
|
else "incomplete"
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|