module Billing class RequestBankTransfer class Error < StandardError; end PLAN_SLUGS = %w[premium_light premium_full].freeze def self.call(club:, user:, plan_slug:, interval:) new(club: club, user: user, plan_slug: plan_slug, interval: interval).call end def initialize(club:, user:, plan_slug:, interval:) @club = club @user = user @plan_slug = plan_slug.to_s @interval = interval end def call raise Error, "Bonifico non configurato sul server" unless MatchLiveTv.bank_transfer_configured? raise Error, "Piano non valido" unless @plan_slug.in?(PLAN_SLUGS) raise Error, "Completa i dati di fatturazione prima di richiedere il bonifico." unless @club.billing_profile_complete? raise Error, "Il piano è un abbonamento omaggio. Contatta il supporto per passarlo a pagamento." if @club.subscription&.admin_comped? @interval = Billing::Stripe::PriceCatalog.normalize_interval(@interval) quote = @club.active_billing_quote amount_cents, kind = resolve_amount(quote) existing = @club.billing_transfer_orders.awaiting_payment.first if existing if existing.plan_slug == @plan_slug && existing.billing_interval == @interval && existing.amount_cents == amount_cents return existing end existing.cancel! end order = nil ApplicationRecord.transaction do payment = @club.billing_payments.create!( provider: "bank_transfer", amount_cents: amount_cents, currency: "eur", status: "pending", plan_slug: @plan_slug, description: payment_description(kind, amount_cents) ) order = @club.billing_transfer_orders.create!( billing_club_quote: kind == "commercial_quote" ? quote : nil, billing_payment: payment, plan_slug: @plan_slug, billing_interval: @interval, amount_cents: amount_cents, currency: "eur", kind: kind, status: "awaiting_payment", reference_code: generate_reference_code, requested_by_user: @user ) end # Le istruzioni (IBAN/causale) le manda a mano l'admin da /admin/billing. Rails.logger.info("[BankTransfer] ordine #{order.reference_code} in attesa, nessuna mail istruzioni") order end private def resolve_amount(quote) if quote unless quote.matches?(@plan_slug, @interval) raise Error, "Per questa società è attivo un prezzo concordato su #{quote.plan.name} (#{quote.price_label})." end return [quote.amount_cents, "commercial_quote"] end [Billing::Stripe::PriceCatalog.amount_cents(plan_slug: @plan_slug, interval: @interval), "list_price"] end def payment_description(kind, amount_cents) label = Billing::Stripe::PriceCatalog.format_interval_price(amount_cents, @interval) suffix = kind == "commercial_quote" ? "prezzo concordato, bonifico" : "bonifico" "#{Plan[@plan_slug].name} — #{label} (#{suffix})" end def generate_reference_code 8.times do code = "MLTV-#{SecureRandom.alphanumeric(6).upcase}" return code unless TransferOrder.exists?(reference_code: code) end raise Error, "Impossibile generare il riferimento del bonifico" end end end