Billing: fatture manuali, profilo obbligatorio e piani Stripe mensile/annuale.

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>
This commit is contained in:
2026-06-02 17:10:12 +02:00
parent 148402a97c
commit a5e781729c
78 changed files with 2457 additions and 424 deletions

View File

@@ -0,0 +1,8 @@
require "rails_helper"
RSpec.describe ApplicationHelper, type: :helper do
it "formatta data e ora in italiano (fuso Rome)" do
time = Time.zone.parse("2026-07-02 13:25:00")
expect(helper.l_local(time)).to eq("02 luglio 2026 alle 13:25")
end
end

View File

@@ -1,38 +1,70 @@
require "rails_helper"
RSpec.describe Public::BillingHelper, type: :helper do
before { load Rails.root.join("db/seeds/plans.rb") }
before do
load Rails.root.join("db/seeds/plans.rb")
allow(MatchLiveTv).to receive(:stripe_enabled?).and_return(true)
allow(MatchLiveTv).to receive(:stripe_premium_light_yearly_price_id).and_return("py")
allow(MatchLiveTv).to receive(:stripe_premium_light_monthly_price_id).and_return("pm")
allow(MatchLiveTv).to receive(:stripe_premium_full_yearly_price_id).and_return("fy")
allow(MatchLiveTv).to receive(:stripe_premium_full_monthly_price_id).and_return("fm")
end
let(:premium_light) { Plan["premium_light"] }
let(:premium_full) { Plan["premium_full"] }
let(:free_plan) { Plan["free"] }
it "segna il piano corrente" do
action = helper.plan_billing_action(
current_slug: "premium_light",
target_plan: premium_light,
stripe_subscription_active: true
)
expect(action[:kind]).to eq(:current)
end
it "propone attivazione da free" do
it "propone due opzioni checkout da free" do
action = helper.plan_billing_action(
current_slug: "free",
target_plan: premium_light,
stripe_subscription_active: false
)
expect(action[:kind]).to eq(:checkout)
expect(action[:label]).to include("Attiva")
expect(action[:kind]).to eq(:checkout_options)
expect(action[:intervals]).to eq(%w[monthly yearly])
end
it "propone upgrade con abbonamento attivo" do
it "segna piano corrente quando non ci sono altri intervalli" do
allow(MatchLiveTv).to receive(:stripe_premium_light_monthly_price_id).and_return(nil)
action = helper.plan_billing_action(
current_slug: "premium_light",
target_plan: premium_light,
stripe_subscription_active: true,
current_interval: "yearly"
)
expect(action[:kind]).to eq(:current)
expect(action[:label]).to include("€39,90/anno")
end
it "propone cambio intervallo sullo stesso piano" do
action = helper.plan_billing_action(
current_slug: "premium_light",
target_plan: premium_light,
stripe_subscription_active: true,
current_interval: "yearly"
)
expect(action[:kind]).to eq(:interval_switch)
expect(action[:intervals]).to eq(["monthly"])
end
it "propone upgrade con opzioni intervallo" do
action = helper.plan_billing_action(
current_slug: "premium_light",
target_plan: premium_full,
stripe_subscription_active: true
stripe_subscription_active: true,
current_interval: "yearly"
)
expect(action[:kind]).to eq(:change)
expect(action[:label]).to include("Passa a")
expect(action[:kind]).to eq(:change_options)
expect(action[:intervals].size).to eq(2)
end
it "stile annuale pieno e mensile outline" do
expect(helper.plan_interval_button_class("yearly")).to include("btn-primary")
expect(helper.plan_interval_button_class("yearly")).not_to include("btn-outline")
expect(helper.plan_interval_button_class("monthly")).to include("btn-outline")
expect(helper.plan_interval_button_class("monthly")).not_to include("btn-primary")
end
it "mostra prima il pulsante annuale" do
expect(helper.plan_intervals_for_display(%w[monthly yearly])).to eq(%w[yearly monthly])
end
end