Rimuove link al portale Stripe in area cliente, aggiunge flusso admin per PDF fattura e email, blocca checkout senza dati di fatturazione, allinea prezzi a €4,90/€39,90 e €9,90/€69,90, locale italiano e documentazione deploy. Co-authored-by: Cursor <cursoragent@cursor.com>
150 lines
6.1 KiB
Ruby
150 lines
6.1 KiB
Ruby
require "rails_helper"
|
|
|
|
RSpec.describe "Public club billing", type: :request do
|
|
let!(:coach) do
|
|
User.create!(email: "billing-coach@test.it", name: "Coach", password: "password123", role: "coach")
|
|
end
|
|
let!(:club) do
|
|
c = Club.create!(name: "Billing HTTP Club", sport: "volleyball", primary_color: "#e53935", secondary_color: "#ffffff",
|
|
billing_entity_type: "company", billing_legal_name: "ASD Billing", billing_email: "bill@test.it",
|
|
billing_address_line: "Via 1", billing_city: "Milano", billing_province: "MI", billing_postal_code: "20100",
|
|
billing_country: "IT", billing_vat_number: "12345678901", billing_recipient_code: "ABCDEFG")
|
|
ClubMembership.create!(user: coach, club: c, role: "owner")
|
|
c.teams.create!(name: "U15", sport: "volleyball")
|
|
load Rails.root.join("db/seeds/plans.rb")
|
|
Billing::AssignPlan.call(club: c, plan_slug: "free")
|
|
c
|
|
end
|
|
|
|
def login!
|
|
post public_login_path, params: { email: coach.email, password: "password123" }
|
|
end
|
|
|
|
it "mostra pagamenti e fatture in billing" do
|
|
club.billing_payments.create!(
|
|
amount_cents: 4000, currency: "eur", status: "paid", paid_at: Time.current,
|
|
description: "Premium Light", stripe_invoice_id: "in_spec_#{SecureRandom.hex(6)}"
|
|
)
|
|
payment = club.billing_payments.reload.first
|
|
club.billing_invoices.create!(
|
|
number: "2026/100", issued_on: Date.current, amount_cents: 4000, status: "draft",
|
|
source: "manual", billing_payment: payment
|
|
)
|
|
|
|
login!
|
|
get public_club_billing_path(club)
|
|
|
|
expect(response).to have_http_status(:ok)
|
|
expect(response.body).to include("Pagamenti e fatture")
|
|
expect(response.body).not_to include("Ricevuta Stripe")
|
|
expect(response.body).not_to include("Sincronizza pagamenti")
|
|
expect(response.body).not_to include("Gestisci fatturazione su Stripe")
|
|
expect(response.body).to include("Premium Light")
|
|
expect(response.body).to include("2026/100")
|
|
expect(response.body).to include("In preparazione")
|
|
end
|
|
|
|
it "salva profilo fatturazione" do
|
|
club.update!(billing_recipient_code: nil, billing_pec: nil)
|
|
login!
|
|
patch public_club_billing_profile_path(club), params: {
|
|
club: { billing_recipient_code: "XYZABC1", billing_pec: "" }
|
|
}
|
|
expect(response).to redirect_to(public_club_billing_path(club))
|
|
expect(club.reload.billing_recipient_code).to eq("XYZABC1")
|
|
end
|
|
|
|
it "blocca checkout premium senza profilo completo" do
|
|
club.update!(billing_vat_number: nil, billing_fiscal_code: nil)
|
|
allow(MatchLiveTv).to receive(:stripe_enabled?).and_return(true)
|
|
|
|
login!
|
|
get public_club_checkout_path(club, plan: "premium_light")
|
|
|
|
expect(response).to redirect_to(public_club_billing_profile_path(club, plan: "premium_light"))
|
|
end
|
|
|
|
it "non mostra pulsanti checkout se profilo incompleto" do
|
|
club.update!(billing_vat_number: nil)
|
|
allow(MatchLiveTv).to receive(:stripe_enabled?).and_return(true)
|
|
|
|
login!
|
|
get public_club_billing_path(club)
|
|
|
|
expect(response.body).to include("Completa dati di fatturazione")
|
|
expect(response.body).not_to include("Attiva Premium Light — €39,90/anno")
|
|
end
|
|
|
|
it "dopo profilo completo reindirizza al checkout" do
|
|
club.update!(
|
|
billing_entity_type: "company",
|
|
billing_vat_number: nil,
|
|
billing_fiscal_code: nil,
|
|
billing_recipient_code: nil,
|
|
billing_pec: nil
|
|
)
|
|
login!
|
|
patch public_club_billing_profile_path(club, plan: "premium_light", interval: "yearly"), params: {
|
|
club: {
|
|
billing_entity_type: "company",
|
|
billing_legal_name: "ASD Billing",
|
|
billing_vat_number: "12345678901",
|
|
billing_email: "bill@test.it",
|
|
billing_address_line: "Via 1",
|
|
billing_city: "Milano",
|
|
billing_province: "MI",
|
|
billing_postal_code: "20100",
|
|
billing_country: "IT",
|
|
billing_recipient_code: "ABCDEFG"
|
|
}
|
|
}
|
|
|
|
expect(response).to redirect_to(public_club_checkout_path(club, plan: "premium_light", interval: "yearly"))
|
|
end
|
|
|
|
it "mostra pulsanti per intervallo e avvia checkout annuale" do
|
|
allow(MatchLiveTv).to receive(:stripe_enabled?).and_return(true)
|
|
allow(MatchLiveTv).to receive(:stripe_premium_light_yearly_price_id).and_return("price_y")
|
|
allow(MatchLiveTv).to receive(:stripe_premium_light_monthly_price_id).and_return("price_m")
|
|
allow(MatchLiveTv).to receive(:stripe_premium_full_yearly_price_id).and_return("price_fy")
|
|
allow(MatchLiveTv).to receive(:stripe_premium_full_monthly_price_id).and_return("price_fm")
|
|
|
|
login!
|
|
get public_club_billing_path(club)
|
|
expect(response.body).to include("Attiva Premium Light — €39,90/anno")
|
|
expect(response.body).to include("Attiva Premium Light — €4,90/mese")
|
|
|
|
allow(Billing::Stripe::CheckoutSession).to receive(:new).and_return(
|
|
instance_double(Billing::Stripe::CheckoutSession, url: "https://checkout.stripe.com/test")
|
|
)
|
|
get public_club_checkout_path(club, plan: "premium_light", interval: "yearly")
|
|
expect(response).to redirect_to("https://checkout.stripe.com/test")
|
|
expect(Billing::Stripe::CheckoutSession).to have_received(:new).with(
|
|
hash_including(club: club, plan_slug: "premium_light", interval: "yearly")
|
|
)
|
|
end
|
|
|
|
it "sincronizza il piano al ritorno da checkout success" do
|
|
allow(MatchLiveTv).to receive(:stripe_enabled?).and_return(true)
|
|
allow(Billing::Stripe::FinalizeSubscription).to receive(:call).and_return(false)
|
|
allow(Billing::Stripe::CheckoutSync).to receive(:call) do |**kwargs|
|
|
Billing::AssignPlan.call(
|
|
club: kwargs[:club].reload,
|
|
plan_slug: "premium_light",
|
|
status: "active",
|
|
stripe_attrs: { stripe_subscription_id: "sub_ui", billing_interval: "monthly" }
|
|
)
|
|
end
|
|
|
|
login!
|
|
get public_club_billing_path(club, checkout: "success", session_id: "cs_test")
|
|
|
|
expect(response).to have_http_status(:ok)
|
|
expect(club.reload.subscription.plan.slug).to eq("premium_light")
|
|
expect(response.body).to include("Piano attuale: <strong>Premium Light</strong>")
|
|
expect(Billing::Stripe::CheckoutSync).to have_received(:call).with(
|
|
club: club, session_id: "cs_test"
|
|
)
|
|
end
|
|
end
|