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,45 @@
<h1>Fattura <%= @invoice.number %> — <%= @club.name %></h1>
<p style="color:#666">
Stato: <strong><%= @invoice.status %></strong>
<% if @invoice.emailed_at.present? %>
· Inviata il <%= @invoice.emailed_at.in_time_zone.strftime("%d/%m/%Y %H:%M") %>
<% end %>
</p>
<div class="card">
<%= form_with model: @invoice, url: admin_club_billing_invoice_path(@club, @invoice), multipart: true, method: :patch do |f| %>
<%= f.label :number, "Numero fattura" %>
<%= f.text_field :number, required: true, disabled: @invoice.status.in?(%w[sent]) %>
<%= f.label :issued_on, "Data emissione" %>
<%= f.date_field :issued_on, required: true, disabled: @invoice.status.in?(%w[sent]) %>
<%= label_tag :amount_euros, "Importo (€)" %>
<%= number_field_tag "billing_invoice[amount_euros]",
@invoice.amount_cents / 100.0,
step: 0.01, min: 0.01, required: true, disabled: @invoice.status.in?(%w[sent]) %>
<% if @payment %>
<p style="color:#888;font-size:0.9rem">Pagamento: <%= @payment.display_description %> — <%= @payment.formatted_amount %></p>
<% end %>
<%= f.label :pdf, "PDF fattura" %>
<% if @invoice.pdf.attached? %>
<p style="color:#888">PDF già caricato: <%= @invoice.pdf.filename %></p>
<% end %>
<%= f.file_field :pdf, accept: "application/pdf" %>
<%= f.label :notes, "Note interne" %>
<%= f.text_area :notes, rows: 2 %>
<div style="margin-top:16px;display:flex;gap:10px;flex-wrap:wrap">
<% unless @invoice.status.in?(%w[sent]) %>
<%= f.submit "Salva bozza", class: "btn btn-secondary" %>
<%= f.submit "Emetti e invia via email", class: "btn btn-primary",
data: { turbo_confirm: "Inviare la fattura a #{@club.billing_email}?" } %>
<% end %>
</div>
<% end %>
</div>
<p><%= link_to "← Pagamenti e fatture", admin_club_billing_invoices_path(@club) %></p>

View File

@@ -1,10 +1,56 @@
<h1>Fatture — <%= @club.name %></h1>
<p><%= link_to "← Dashboard", admin_root_path %> · <%= link_to "Nuova fattura", new_admin_club_billing_invoice_path(@club), class: "btn btn-primary" %></p>
<h1>Fatturazione — <%= @club.name %></h1>
<p>
<%= link_to "← Dashboard", admin_root_path %>
· <%= link_to "Nuova fattura (senza pagamento)", new_admin_club_billing_invoice_path(@club), class: "btn btn-secondary" %>
</p>
<h2 style="margin-top:24px;font-size:1.1rem">Pagamenti</h2>
<% if @payments.any? %>
<table class="data">
<thead>
<tr>
<th>Data</th>
<th>Descrizione</th>
<th>Importo</th>
<th>Fattura</th>
<th></th>
</tr>
</thead>
<tbody>
<% @payments.each do |payment| %>
<% inv = payment.invoice %>
<tr>
<td><%= payment.paid_at&.to_date || payment.created_at.to_date %></td>
<td><%= payment.display_description %></td>
<td><%= payment.formatted_amount %></td>
<td>
<% if inv %>
<%= inv.number %> — <%= inv.status %>
<% if inv.pdf.attached? %> (PDF)<% end %>
<% else %>
<% end %>
</td>
<td>
<% if inv %>
<%= link_to "Modifica / invia PDF", edit_admin_club_billing_invoice_path(@club, inv) %>
<% else %>
<%= link_to "Crea fattura", new_admin_club_billing_invoice_path(@club, billing_payment_id: payment.id), class: "btn btn-primary", style: "padding:6px 10px;font-size:0.85rem" %>
<% end %>
</td>
</tr>
<% end %>
</tbody>
</table>
<% else %>
<p>Nessun pagamento registrato per questa società.</p>
<% end %>
<h2 style="margin-top:32px;font-size:1.1rem">Tutte le fatture</h2>
<% if @invoices.any? %>
<table class="data">
<thead>
<tr><th>Numero</th><th>Data</th><th>Importo</th><th>Stato</th><th>PDF</th></tr>
<tr><th>Numero</th><th>Data</th><th>Importo</th><th>Stato</th><th>Pagamento</th><th></th></tr>
</thead>
<tbody>
<% @invoices.each do |inv| %>
@@ -13,7 +59,8 @@
<td><%= inv.issued_on %></td>
<td><%= inv.formatted_amount %></td>
<td><%= inv.status %></td>
<td><%= inv.pdf.attached? ? "Sì" : "No" %></td>
<td><%= inv.billing_payment_id.present? ? "Sì" : "No" %></td>
<td><%= link_to "Modifica", edit_admin_club_billing_invoice_path(@club, inv) %></td>
</tr>
<% end %>
</tbody>

View File

@@ -1,8 +1,12 @@
<h1>Nuova fattura Aruba — <%= @club.name %></h1>
<p style="color:#666">Carica il PDF emesso da Aruba Fatture e collega il pagamento se disponibile.</p>
<h1>Nuova fattura — <%= @club.name %></h1>
<% if @payment %>
<p style="color:#666">Collegata al pagamento del <%= @payment.paid_at&.to_date || @payment.created_at.to_date %> (<%= @payment.formatted_amount %>).</p>
<% end %>
<div class="card">
<%= form_with model: @invoice, url: admin_club_billing_invoices_path(@club), multipart: true do |f| %>
<%= form_with model: @invoice, url: admin_club_billing_invoices_path(@club) do |f| %>
<%= f.hidden_field :billing_payment_id if @payment %>
<%= f.label :number, "Numero fattura" %>
<%= f.text_field :number, required: true %>
@@ -10,27 +14,19 @@
<%= f.date_field :issued_on, required: true %>
<%= label_tag :amount_euros, "Importo (€)" %>
<%= number_field_tag "billing_invoice[amount_euros]", nil, step: 0.01, min: 0.01, required: true %>
<%= number_field_tag "billing_invoice[amount_euros]",
(@invoice.amount_cents ? @invoice.amount_cents / 100.0 : nil),
step: 0.01, min: 0.01, required: true %>
<%= f.label :status, "Stato" %>
<%= f.select :status, Billing::Invoice::STATUSES %>
<%= f.label :billing_payment_id, "Pagamento collegato (opzionale)" %>
<%= f.collection_select :billing_payment_id, @club.billing_payments.recent, :id,
->(p) { "#{p.paid_at&.to_date || p.created_at.to_date} — #{p.formatted_amount}" },
{ include_blank: "Nessuno" } %>
<%= f.label :aruba_document_id, "ID documento Aruba (opzionale)" %>
<%= f.text_field :aruba_document_id %>
<%= f.label :pdf, "PDF fattura" %>
<%= f.file_field :pdf, accept: "application/pdf", required: true %>
<%= f.label :notes, "Note interne" %>
<%= f.label :notes, "Note interne (opzionale)" %>
<%= f.text_area :notes, rows: 2 %>
<%= f.submit "Registra fattura", class: "btn btn-primary" %>
<p style="color:#666;font-size:0.9rem;margin-top:12px">
Salva la bozza, poi carica il PDF e inviala al cliente dalla schermata successiva.
</p>
<%= f.submit "Crea bozza fattura", class: "btn btn-primary" %>
<% end %>
</div>
<p><%= link_to "← Elenco fatture", admin_club_billing_invoices_path(@club) %></p>
<p><%= link_to "← Pagamenti e fatture", admin_club_billing_invoices_path(@club) %></p>