Files
MatchLiveTv/backend/app/models/billing/payment.rb
Emiliano Frascaro 964e3f472c Admin fatturazione: coda pagamenti senza PDF e upload diretto.
Lista globale dei pagamenti da fatturare con dati intestazione, caricamento
PDF per riga che crea la fattura e invia email; rimuove il flusso bozza manuale.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-02 17:31:49 +02:00

73 lines
2.0 KiB
Ruby

module Billing
class Payment < ApplicationRecord
self.table_name = "billing_payments"
STATUSES = %w[paid failed refunded].freeze
belongs_to :club
has_one :invoice, class_name: "Billing::Invoice", foreign_key: :billing_payment_id, dependent: :nullify
validates :amount_cents, numericality: { greater_than: 0 }
validates :currency, presence: true
validates :status, inclusion: { in: STATUSES }
validates :stripe_invoice_id, uniqueness: true, allow_nil: true
scope :recent, -> { order(paid_at: :desc, created_at: :desc) }
# Pagamenti pagati senza PDF fattura caricato (da gestire in admin).
scope :awaiting_invoice_pdf, lambda {
where(status: "paid").where(
<<~SQL.squish,
NOT EXISTS (
SELECT 1 FROM billing_invoices bi
INNER JOIN active_storage_attachments asa
ON asa.record_type = 'Billing::Invoice'
AND asa.record_id = bi.id
AND asa.name = 'pdf'
WHERE bi.billing_payment_id = billing_payments.id
)
SQL
)
}
scope :with_invoice_pdf, lambda {
where(status: "paid").where(
<<~SQL.squish,
EXISTS (
SELECT 1 FROM billing_invoices bi
INNER JOIN active_storage_attachments asa
ON asa.record_type = 'Billing::Invoice'
AND asa.record_id = bi.id
AND asa.name = 'pdf'
WHERE bi.billing_payment_id = billing_payments.id
)
SQL
)
}
def awaiting_invoice_pdf?
status == "paid" && !invoice&.pdf&.attached?
end
def amount_euros
amount_cents / 100.0
end
def formatted_amount
format("%.2f €", amount_euros)
end
def display_description
PaymentDescription.for_payment(self)
end
def display_status
{ "paid" => "Pagato", "failed" => "Non riuscito", "refunded" => "Rimborsato" }[status] || status
end
def invoice_for_display
invoice
end
end
end