Prologo
Primi Passi
Architettura
Le Basi
- Routing
- Middleware
- Protezione da CSRF
- Controller
- Richieste
- Risposte
- Views
- Blade
- Vite
- URL
- Sessioni
- Validazione
- Errori
- Logging
Approfondimenti
- Artisan
- Broadcasting
- Cache
- Collezioni
- Concorrenza
- Contesto
- Contratti
- Eventi
- File System
- Helpers
- Client HTTP
- Localizzazione
- Notifiche
- Sviluppo di Package
- Processi
- Code
- Rate-limiting
- Stringhe
- Scheduling di Task
Sicurezza
Database
Eloquent ORM
Testing
Package
Cashier (Stripe)
- Introduzione
- Aggiornare Cashier
- Installazione
- Configurazione
- Avvio rapido
- Clienti
- Metodi di Pagamento
- Sottoscrizioni
- Prove di abbonamento
- Gestire i Webhook di Stripe
- Addebiti Singoli
- Fatture
- Checkout
- Gestione dei Pagamenti Falliti
- Strong Customer Authentication
- Stripe SDK
- Testing
Introduzione
Laravel Cashier Stripe offre un’interfaccia espressiva e fluente per i servizi di fatturazione in abbonamento di Stripe. Gestisce quasi tutto il codice di base per la fatturazione in abbonamento che potresti temere di dover scrivere. Oltre alla gestione base degli abbonamenti, Cashier può gestire coupon, cambio di abbonamento, "quantità" di abbonamento, periodi di grazia per cancellazioni e persino generare PDF delle fatture.
Aggiornare Cashier
Quando aggiorni Cashier a una nuova versione, è importante leggere attentamente la guida all’aggiornamento.
Per evitare cambiamenti che possono rompere il codice, Cashier utilizza una versione fissa dell’API di Stripe. Cashier 15 utilizza la versione dell’API di Stripe
2023-10-16
. La versione dell’API di Stripe verrà aggiornata nelle release minori per utilizzare le nuove funzionalità e miglioramenti di Stripe.
Installazione
Innanzitutto, installa il pacchetto Cashier per Stripe usando il gestore di pacchetti Composer:
composer require laravel/cashier
Dopo aver installato il pacchetto, pubblica le migrazioni di Cashier usando il comando Artisan vendor:publish
:
php artisan vendor:publish --tag="cashier-migrations"
Poi, migra il tuo database:
php artisan migrate
Le migrazioni di Cashier aggiungeranno diverse colonne alla tua tabella users
. Creeranno inoltre una nuova tabella subscriptions
per contenere tutte le sottoscrizioni dei tuoi clienti e una tabella subscription_items
per le sottoscrizioni con più prezzi.
Se vuoi, puoi anche pubblicare il file di configurazione di Cashier usando il comando Artisan vendor:publish
:
php artisan vendor:publish --tag="cashier-config"
Infine, per assicurarti che Cashier gestisca correttamente tutti gli eventi di Stripe, ricordati di configurare la gestione dei webhook di Cashier.
Stripe raccomanda che qualsiasi colonna usata per memorizzare gli identificatori di Stripe sia sensibile al maiuscolo/minuscolo. Pertanto, dovresti assicurarti che la collazione della colonna
stripe_id
sia impostata suutf8_bin
quando usi MySQL. Maggiori informazioni su questo sono disponibili nella documentazione di Stripe.
Configurazione
Model Billable
Prima di usare Cashier, aggiungi il trait Billable
alla definizione del tuo model. Tipicamente, questo sarà il modello App\Models\User
. Questo trait fornisce vari metodi che ti permettono di eseguire compiti comuni di fatturazione, come creare abbonamenti, applicare coupon e aggiornare le informazioni del metodo di pagamento:
use Laravel\Cashier\Billable;
class User extends Authenticatable
{
use Billable;
}
Cashier presuppone che il tuo modello billable sarà la classe App\Models\User
fornita con Laravel. Se desideri cambiarlo, puoi specificare un modello diverso tramite il metodo useCustomerModel
. Questo metodo solitamente deve essere chiamato nel metodo boot
della tua classe AppServiceProvider
:
use App\Models\Cashier\User;
use Laravel\Cashier\Cashier;
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Cashier::useCustomerModel(User::class);
}
Se stai usando un modello diverso dal modello
App\Models\User
fornito da Laravel, dovrai pubblicare e modificare le migrazioni di Cashier fornite per adattarle al nome della tabella del tuo modello alternativo.
Chiavi API
Successivamente, devi configurare le tue chiavi API di Stripe nel file .env
della tua applicazione. Puoi recuperare le tue chiavi API di Stripe dal pannello di controllo di Stripe:
STRIPE_KEY=your-stripe-key
STRIPE_SECRET=your-stripe-secret
STRIPE_WEBHOOK_SECRET=your-stripe-webhook-secret
Assicurati che la variabile d’ambiente
STRIPE_WEBHOOK_SECRET
sia definita nel file.env
della tua applicazione, poiché questa variabile serve a garantire che i webhook in arrivo provengano effettivamente da Stripe.
Configurazione della Valuta
La valuta predefinita di Cashier è il Dollaro Statunitense (USD). Puoi cambiare la valuta predefinita impostando la variabile d’ambiente CASHIER_CURRENCY
nel file .env
della tua applicazione:
CASHIER_CURRENCY=eur
Oltre a configurare la valuta di Cashier, puoi anche specificare una locale da usare quando formatti i valori monetari per la visualizzazione sulle fatture. Internamente, Cashier utilizza la classe NumberFormatter
di PHP per impostare la locale della valuta:
CASHIER_CURRENCY_LOCALE=nl_BE
Per utilizzare locale diverse da
en
, assicurati che l’estensione PHPext-intl
sia installata e configurata sul tuo server.
Configurazione delle Tasse
Grazie a Stripe Tax, è possibile calcolare automaticamente le tasse per tutte le fatture generate da Stripe. Puoi abilitare il calcolo automatico delle tasse invocando il metodo calculateTaxes
nel metodo boot
della classe App\Providers\AppServiceProvider
della tua applicazione:
use Laravel\Cashier\Cashier;
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Cashier::calculateTaxes();
}
Una volta abilitato il calcolo delle tasse, tutte le nuove sottoscrizioni e le fatture occasionali generate avranno il calcolo automatico delle tasse.
Perché questa funzionalità funzioni correttamente, i dettagli di fatturazione del cliente, come nome, indirizzo e ID fiscale, devono essere sincronizzati con Stripe. Puoi usare i metodi di sincronizzazione dei dati del cliente e ID fiscale offerti da Cashier per fare ciò.
Logging
Cashier ti permette di specificare il canale di log da utilizzare per registrare errori fatali di Stripe. Puoi specificare il canale di log definendo la variabile d’ambiente CASHIER_LOGGER
nel file .env
della tua applicazione:
CASHIER_LOGGER=stack
Le eccezioni generate dalle chiamate API a Stripe saranno registrate tramite il canale di log predefinito della tua applicazione.
Uso di Model Personalizzati
Puoi estendere i model utilizzati internamente da Cashier definendo il tuo model e estendendo il modello corrispondente di Cashier:
use Laravel\Cashier\Subscription as CashierSubscription;
class Subscription extends CashierSubscription
{
// ...
}
Dopo aver definito il tuo modello, puoi istruire Cashier a utilizzare il tuo modello personalizzato tramite la classe Laravel\Cashier\Cashier
. Di solito, dovresti informare Cashier dei tuoi modelli personalizzati nel metodo boot
della classe App\Providers\AppServiceProvider
della tua applicazione:
use App\Models\Cashier\Subscription;
use App\Models\Cashier\SubscriptionItem;
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Cashier::useSubscriptionModel(Subscription::class);
Cashier::useSubscriptionItemModel(SubscriptionItem::class);
}
Avvio rapido
Vendere Prodotti
Prima di utilizzare Stripe Checkout, dovresti definire i Prodotti con prezzi fissi nel tuo dashboard di Stripe. Inoltre, dovresti configurare la gestione dei webhook di Cashier.
Offrire la fatturazione di prodotti e abbonamenti tramite la tua applicazione può essere intimidatorio. Tuttavia, grazie a Cashier e a Stripe Checkout, puoi costruire facilmente integrazioni di pagamento moderne e robuste.
Per addebitare ai clienti prodotti a pagamento singolo e non ricorrenti, utilizzeremo Cashier per indirizzare i clienti a Stripe Checkout, dove forniranno i loro dati di pagamento e confermeranno l’acquisto. Una volta effettuato il pagamento tramite Checkout, il cliente sarà reindirizzato a un URL di successo a tua scelta all’interno della tua applicazione:
use Illuminate\Http\Request;
Route::get('/checkout', function (Request $request) {
$stripePriceId = 'price_deluxe_album';
$quantity = 1;
return $request->user()->checkout([$stripePriceId => $quantity], [
'success_url' => route('checkout-success'),
'cancel_url' => route('checkout-cancel'),
]);
})->name('checkout');
Route::view('/checkout/success', 'checkout.success')->name('checkout-success');
Route::view('/checkout/cancel', 'checkout.cancel')->name('checkout-cancel');
Come puoi vedere nell’esempio sopra, utilizzeremo il metodo checkout
fornito da Cashier per reindirizzare il cliente a Stripe Checkout per un determinato "identificatore di prezzo". Quando si usa Stripe, i "prezzi" si riferiscono a prezzi definiti per prodotti specifici.
Se necessario, il metodo checkout
creerà automaticamente un cliente in Stripe e collegherà quel record cliente di Stripe all’utente corrispondente nel database della tua applicazione. Dopo aver completato la sessione di checkout, il cliente sarà reindirizzato a una pagina dedicata di successo o cancellazione dove potrai mostrare un messaggio informativo al cliente.
Fornire Metadati a Stripe Checkout
Quando si vendono prodotti, è comune tenere traccia degli ordini completati e dei prodotti acquistati tramite i modelli Cart
e Order
definiti dalla propria applicazione. Quando si reindirizzano i clienti a Stripe Checkout per completare un acquisto, potrebbe essere necessario fornire un identificatore di un ordine esistente in modo da poter associare l’acquisto completato all’ordine corrispondente quando il cliente viene reindirizzato nuovamente alla propria applicazione.
Per ottenere ciò, è possibile fornire un array di metadata
al metodo checkout
. Immaginiamo che un Order
in sospeso venga creato all’interno della nostra applicazione quando un utente inizia il processo di checkout. Ricorda, i modelli Cart
e Order
in questo esempio sono illustrativi e non forniti da Cashier. Sei libero di implementare questi concetti in base alle esigenze della tua applicazione:
use App\Models\Cart;
use App\Models\Order;
use Illuminate\Http\Request;
Route::get('/cart/{cart}/checkout', function (Request $request, Cart $cart) {
$order = Order::create([
'cart_id' => $cart->id,
'price_ids' => $cart->price_ids,
'status' => 'incomplete',
]);
return $request->user()->checkout($order->price_ids, [
'success_url' => route('checkout-success').'?session_id={CHECKOUT_SESSION_ID}',
'cancel_url' => route('checkout-cancel'),
'metadata' => ['order_id' => $order->id],
]);
})->name('checkout');
Come puoi vedere nell’esempio sopra, quando un utente inizia il processo di checkout, forniremo tutti gli identificatori di prezzo Stripe associati al carrello / ordine al metodo checkout
. Naturalmente, la tua applicazione è responsabile di associare questi elementi al "carrello" o all’ordine man mano che il cliente li aggiunge. Forniamo inoltre l’ID dell’ordine alla sessione Stripe Checkout tramite l’array metadata
. Infine, abbiamo aggiunto la variabile di template CHECKOUT_SESSION_ID
alla route di successo del Checkout. Quando Stripe reindirizza i clienti alla tua applicazione, questa variabile di template sarà automaticamente popolata con l’ID della sessione Checkout.
Successivamente, creiamo la route di successo del Checkout. Questa è la route a cui gli utenti saranno reindirizzati dopo aver completato l’acquisto tramite Stripe Checkout. All’interno di questa route, possiamo recuperare l’ID della sessione Stripe Checkout e l’istanza associata di Stripe Checkout per accedere ai nostri metadati forniti e aggiornare di conseguenza l’ordine del cliente:
use App\Models\Order;
use Illuminate\Http\Request;
use Laravel\Cashier\Cashier;
Route::get('/checkout/success', function (Request $request) {
$sessionId = $request->get('session_id');
if ($sessionId === null) {
return;
}
$session = Cashier::stripe()->checkout->sessions->retrieve($sessionId);
if ($session->payment_status !== 'paid') {
return;
}
$orderId = $session['metadata']['order_id'] ?? null;
$order = Order::findOrFail($orderId);
$order->update(['status' => 'completed']);
return view('checkout-success', ['order' => $order]);
})->name('checkout-success');
Consulta la documentazione di Stripe per maggiori informazioni sui dati contenuti dall’oggetto sessione Checkout.
Vendere Abbonamenti
Prima di utilizzare Stripe Checkout, dovresti definire i Prodotti con prezzi fissi nel tuo dashboard Stripe. Inoltre, dovresti configurare la gestione dei webhook di Cashier.
Offrire il pagamento di prodotti e abbonamenti tramite la tua applicazione può sembrare complicato. Tuttavia, grazie a Cashier e a Stripe Checkout, puoi facilmente creare integrazioni di pagamento moderne e robuste.
Per imparare a vendere abbonamenti usando Cashier e Stripe Checkout, consideriamo uno scenario semplice di un servizio di abbonamento con un piano base mensile (price_basic_monthly
) e uno annuale (price_basic_yearly
). Questi due prezzi potrebbero essere raggruppati sotto un prodotto "Basic" (pro_basic
) nel nostro dashboard Stripe. Inoltre, il nostro servizio di abbonamento potrebbe offrire un piano Expert come pro_expert
.
Per prima cosa, scopriamo come un cliente può abbonarsi ai nostri servizi. Puoi immaginare che il cliente possa cliccare un pulsante "abbonati" per il piano Basic nella pagina dei prezzi della nostra applicazione. Questo pulsante o link dovrebbe indirizzare l’utente a una route di Laravel che crea la sessione Stripe Checkout per il piano scelto:
use Illuminate\Http\Request;
Route::get('/subscription-checkout', function (Request $request) {
return $request->user()
->newSubscription('default', 'price_basic_monthly')
->trialDays(5)
->allowPromotionCodes()
->checkout([
'success_url' => route('your-success-route'),
'cancel_url' => route('your-cancel-route'),
]);
});
Come puoi vedere nell’esempio sopra, reindirizzeremo il cliente a una sessione Stripe Checkout che gli permetterà di abbonarsi al nostro piano Basic. Dopo un checkout avvenuto con successo o una cancellazione, il cliente verrà reindirizzato all’URL che abbiamo fornito al metodo checkout
. Per sapere quando il loro abbonamento è effettivamente iniziato (dato che alcuni metodi di pagamento richiedono alcuni secondi per essere elaborati), dovremo anche configurare la gestione dei webhook di Cashier.
Ora che i clienti possono iniziare gli abbonamenti, dobbiamo limitare alcune parti della nostra applicazione in modo che solo gli utenti abbonati possano accedervi. Naturalmente, possiamo sempre determinare lo stato attuale dell’abbonamento di un utente tramite il metodo subscribed
fornito dal trait Billable
di Cashier:
@if ($user->subscribed())
<p>Sei abbonato.</p>
@endif
Possiamo anche determinare facilmente se un utente è abbonato a un prodotto o prezzo specifico:
@if ($user->subscribedToProduct('pro_basic'))
<p>Sei abbonato al nostro prodotto Basic.</p>
@endif
@if ($user->subscribedToPrice('price_basic_monthly'))
<p>Sei abbonato al nostro piano Basic mensile.</p>
@endif
Creare un Middleware per Utenti Abbonati
Per comodità, potresti voler creare un middleware che determina se la richiesta in arrivo proviene da un utente abbonato. Una volta definito questo middleware, puoi facilmente assegnarlo a una rotta per impedire agli utenti non abbonati di accedere alla rotta:
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
class Subscribed
{
/**
* Gestisce una richiesta in arrivo.
*/
public function handle(Request $request, Closure $next): Response
{
if (! $request->user()?->subscribed()) {
// Reindirizza l'utente alla pagina di fatturazione e chiedi di abbonarsi...
return redirect('/billing');
}
return $next($request);
}
}
Una volta definito il middleware, puoi assegnarlo a una rotta:
use App\Http\Middleware\Subscribed;
Route::get('/dashboard', function () {
// ...
})->middleware([Subscribed::class]);
Permettere ai clienti di gestire il loro piano di fatturazione
Naturalmente, i clienti potrebbero voler cambiare il proprio piano di abbonamento a un altro prodotto o "livello". Il modo più semplice per consentire questo è indirizzare i clienti al Customer Billing Portal di Stripe, che fornisce un’interfaccia utente ospitata che permette ai clienti di scaricare fatture, aggiornare il metodo di pagamento e modificare i piani di abbonamento.
Per prima cosa, definisci un link o un pulsante all’interno della tua applicazione che indirizza gli utenti a una route di Laravel che utilizzeremo per avviare una sessione del Billing Portal:
<a href="{{ route('billing') }}">
Billing
</a>
Successivamente, definiamo la route che avvia una sessione del Stripe Customer Billing Portal e reindirizza l’utente al Portal. Il metodo redirectToBillingPortal
accetta l’URL a cui gli utenti devono essere reindirizzati quando escono dal Portal:
use Illuminate\Http\Request;
Route::get('/billing', function (Request $request) {
return $request->user()->redirectToBillingPortal(route('dashboard'));
})->middleware(['auth'])->name('billing');
Finché hai configurato la gestione dei webhook di Cashier, Cashier manterrà automaticamente sincronizzate le tabelle del database relative a Cashier della tua applicazione ispezionando i webhook in arrivo da Stripe. Quindi, per esempio, quando un utente annulla il proprio abbonamento tramite il Customer Billing Portal di Stripe, Cashier riceverà il webhook corrispondente e segnerà l’abbonamento come "annullato" nel database della tua applicazione.
Clienti
Recuperare i Clienti
Puoi recuperare un cliente utilizzando il suo Stripe ID con il metodo Cashier::findBillable
. Questo metodo restituirà un’istanza del modello billable:
use Laravel\Cashier\Cashier;
$user = Cashier::findBillable($stripeId);
Creazione di Clienti
Occasionalmente, potresti voler creare un cliente Stripe senza avviare una sottoscrizione. Puoi farlo usando il metodo createAsStripeCustomer
:
$stripeCustomer = $user->createAsStripeCustomer();
Una volta creato il cliente in Stripe, puoi iniziare una sottoscrizione in un secondo momento. Puoi fornire un array opzionale $options
per passare eventuali parametri aggiuntivi di creazione del cliente supportati dall’API di Stripe:
$stripeCustomer = $user->createAsStripeCustomer($options);
Puoi usare il metodo asStripeCustomer
se vuoi ottenere l’oggetto cliente Stripe per un modello billable:
$stripeCustomer = $user->asStripeCustomer();
Il metodo createOrGetStripeCustomer
può essere usato se desideri recuperare l’oggetto cliente Stripe per un determinato modello billable ma non sei sicuro se il modello billable sia già un cliente in Stripe. Questo metodo creerà un nuovo cliente in Stripe se non esiste già:
$stripeCustomer = $user->createOrGetStripeCustomer();
Aggiornare i Clienti
Occasionalmente, potresti voler aggiornare direttamente il cliente Stripe con informazioni aggiuntive. Puoi farlo usando il metodo updateStripeCustomer
. Questo metodo accetta un array di opzioni di aggiornamento cliente supportate dall’API di Stripe:
$stripeCustomer = $user->updateStripeCustomer($options);
Bilanci
Stripe ti permette di accreditare o addebitare il "bilancio" di un cliente. Successivamente, questo bilancio verrà accreditato o addebitato nelle nuove fatture. Per controllare il bilancio totale del cliente, puoi usare il metodo balance
disponibile nel tuo modello billable. Il metodo balance
restituirà una stringa formattata del bilancio nella valuta del cliente:
$balance = $user->balance();
Per accreditare il bilancio di un cliente, puoi fornire un valore al metodo creditBalance
. Se vuoi, puoi anche fornire una descrizione:
$user->creditBalance(500, 'Ricarica cliente premium.');
Fornendo un valore al metodo debitBalance
verrà addebitato il bilancio del cliente:
$user->debitBalance(300, 'Penale per cattivo utilizzo.');
Il metodo applyBalance
creerà nuove transazioni di bilancio per il cliente. Puoi recuperare questi record di transazione usando il metodo balanceTransactions
, che può essere utile per fornire un registro di accrediti e addebiti per la revisione del cliente:
// Recupera tutte le transazioni...
$transactions = $user->balanceTransactions();
foreach ($transactions as $transaction) {
// Importo della transazione...
$amount = $transaction->amount(); // $2.31
// Recupera la fattura relativa quando disponibile...
$invoice = $transaction->invoice();
}
Identificativi Fiscali
Cashier offre un modo semplice per gestire gli identificativi fiscali di un cliente. Ad esempio, il metodo taxIds
può essere usato per recuperare tutti i tax IDs assegnati a un cliente come una collezione:
$taxIds = $user->taxIds();
Puoi anche recuperare un tax ID specifico per un cliente tramite il suo identificatore:
$taxId = $user->findTaxId('txi_belgium');
Puoi creare un nuovo Tax ID fornendo un type valido e un valore al metodo createTaxId
:
$taxId = $user->createTaxId('eu_vat', 'BE0123456789');
Il metodo createTaxId
aggiungerà immediatamente l’ID IVA all’account del cliente. La verifica degli ID IVA è effettuata anche da Stripe; tuttavia, questo è un processo asincrono. Puoi essere notificato degli aggiornamenti sulla verifica iscrivendoti all’evento webhook customer.tax_id.updated
ed esaminando il parametro verification
degli ID IVA. Per maggiori informazioni sulla gestione dei webhook, consulta la documentazione sulla definizione dei gestori di webhook.
Puoi eliminare un tax ID utilizzando il metodo deleteTaxId
:
$user->deleteTaxId('txi_belgium');
Sincronizzazione dei Dati Cliente con Stripe
Di solito, quando gli utenti della tua applicazione aggiornano il loro nome, indirizzo email o altre informazioni che sono memorizzate anche da Stripe, dovresti informare Stripe degli aggiornamenti. In questo modo, la copia delle informazioni di Stripe sarà sincronizzata con quella della tua applicazione.
Per automatizzare questo processo, puoi definire un listener di eventi sul tuo modello billable che reagisce all’evento updated
del modello. Successivamente, all’interno del listener, puoi invocare il metodo syncStripeCustomerDetails
sul modello:
use App\Models\User;
use function Illuminate\Events\queueable;
/**
* Il metodo "booted" del modello.
*/
protected static function booted(): void
{
static::updated(queueable(function (User $customer) {
if ($customer->hasStripeId()) {
$customer->syncStripeCustomerDetails();
}
}));
}
Ora, ogni volta che il modello cliente viene aggiornato, le sue informazioni saranno sincronizzate con Stripe. Per comodità, Cashier sincronizzerà automaticamente le informazioni del cliente con Stripe alla creazione iniziale del cliente.
Puoi personalizzare le colonne usate per sincronizzare le informazioni del cliente con Stripe sovrascrivendo diversi metodi forniti da Cashier. Ad esempio, puoi sovrascrivere il metodo stripeName
per personalizzare l’attributo che dovrebbe essere considerato il "nome" del cliente quando Cashier sincronizza le informazioni del cliente con Stripe:
/**
* Ottieni il nome del cliente che dovrebbe essere sincronizzato con Stripe.
*/
public function stripeName(): string|null
{
return $this->company_name;
}
Allo stesso modo, puoi sovrascrivere i metodi stripeEmail
, stripePhone
, stripeAddress
e stripePreferredLocales
. Questi metodi sincronizzeranno le informazioni con i loro corrispondenti parametri del cliente quando aggiorni l’oggetto cliente di Stripe. Se desideri avere il controllo totale sul processo di sincronizzazione delle informazioni del cliente, puoi sovrascrivere il metodo syncStripeCustomerDetails
.
Portale di Fatturazione
Stripe offre un modo semplice per configurare un portale di fatturazione in modo che i tuoi clienti possano gestire il loro abbonamento, i metodi di pagamento e visualizzare la loro cronologia delle fatture. Puoi reindirizzare i tuoi utenti al portale di fatturazione invocando il metodo redirectToBillingPortal
sul modello billable da un controller o da una route:
use Illuminate\Http\Request;
Route::get('/billing-portal', function (Request $request) {
return $request->user()->redirectToBillingPortal();
});
Per impostazione predefinita, quando l’utente ha finito di gestire il suo abbonamento, potrà tornare alla route home
della tua applicazione tramite un link all’interno del portale di fatturazione di Stripe. Puoi fornire un URL personalizzato a cui l’utente dovrebbe tornare passando l’URL come argomento al metodo redirectToBillingPortal
:
use Illuminate\Http\Request;
Route::get('/billing-portal', function (Request $request) {
return $request->user()->redirectToBillingPortal(route('billing'));
});
Se desideri generare l’URL del portale di fatturazione senza generare una risposta di reindirizzamento HTTP, puoi invocare il metodo billingPortalUrl
:
$url = $request->user()->billingPortalUrl(route('billing'));
Metodi di Pagamento
Conservare i Metodi di Pagamento
Per creare abbonamenti o effettuare addebiti "una tantum" con Stripe, devi conservare un metodo di pagamento e recuperare il suo identificatore da Stripe. L’approccio per fare questo varia a seconda che tu voglia usare il metodo di pagamento per abbonamenti o per addebiti singoli, quindi esamineremo entrambe le opzioni qui di seguito.
Metodi di Pagamento per Sottoscrizioni
Quando si memorizzano le informazioni della carta di credito di un cliente per un uso futuro da parte di un abbonamento, è necessario utilizzare l’API "Setup Intents" di Stripe per raccogliere in modo sicuro i dettagli del metodo di pagamento del cliente. Un "Setup Intent" indica a Stripe l’intenzione di addebitare il metodo di pagamento del cliente. Il trait Billable
di Cashier include il metodo createSetupIntent
per creare facilmente un nuovo Setup Intent. Dovresti invocare questo metodo dalla route o controller che renderizzerà il modulo per raccogliere i dettagli del metodo di pagamento del cliente:
return view('update-payment-method', [
'intent' => $user->createSetupIntent()
]);
Dopo aver creato il Setup Intent e passato alla vista, dovresti allegare il suo segreto all’elemento che raccoglierà il metodo di pagamento. Ad esempio, considera questo modulo per "aggiornare il metodo di pagamento":
<input id="card-holder-name" type="text">
<!-- Stripe Elements Placeholder -->
<div id="card-element"></div>
<button id="card-button" data-secret="{{ $intent->client_secret }}">
Update Payment Method
</button>
Successivamente, la libreria Stripe.js può essere utilizzata per aggiungere un Stripe Element al modulo e raccogliere in modo sicuro i dettagli del pagamento del cliente:
<script src="https://js.stripe.com/v3/"></script>
<script>
const stripe = Stripe('stripe-public-key');
const elements = stripe.elements();
const cardElement = elements.create('card');
cardElement.mount('#card-element');
</script>
Successivamente, la carta può essere verificata e un "identifier del metodo di pagamento" sicuro può essere recuperato da Stripe utilizzando il metodo confirmCardSetup
di Stripe:
const cardHolderName = document.getElementById('card-holder-name');
const cardButton = document.getElementById('card-button');
const clientSecret = cardButton.dataset.secret;
cardButton.addEventListener('click', async (e) => {
const { setupIntent, error } = await stripe.confirmCardSetup(
clientSecret, {
payment_method: {
card: cardElement,
billing_details: { name: cardHolderName.value }
}
}
);
if (error) {
// Display "error.message" to the user...
} else {
// The card has been verified successfully...
}
});
Dopo che la carta è stata verificata da Stripe, puoi passare l’identificatore setupIntent.payment_method
risultante alla tua applicazione Laravel, dove può essere associato al cliente. Il metodo di pagamento può essere aggiunto come nuovo metodo di pagamento oppure utilizzato per aggiornare il metodo di pagamento predefinito. Puoi anche utilizzare immediatamente l’identificatore del metodo di pagamento per creare un nuovo abbonamento.
Se desideri ulteriori informazioni sui Setup Intents e sulla raccolta dei dettagli del pagamento dei clienti, consulta questa panoramica fornita da Stripe.
Metodi di Pagamento per Addebiti Singoli
Quando effettui un addebito singolo sul metodo di pagamento di un cliente, useremo l’identificativo del metodo di pagamento solo una volta. A causa delle limitazioni di Stripe, non puoi utilizzare il metodo di pagamento predefinito memorizzato di un cliente per addebiti singoli. Devi permettere al cliente di inserire i dettagli del metodo di pagamento utilizzando la libreria Stripe.js. Ad esempio, considera il seguente modulo:
<input id="card-holder-name" type="text">
<!-- Stripe Elements Placeholder -->
<div id="card-element"></div>
<button id="card-button">
Process Payment
</button>
Dopo aver definito un modulo del genere, puoi usare la libreria Stripe.js per aggiungere un Stripe Element al modulo e raccogliere in modo sicuro i dettagli di pagamento del cliente:
<script src="https://js.stripe.com/v3/"></script>
<script>
const stripe = Stripe('stripe-public-key');
const elements = stripe.elements();
const cardElement = elements.create('card');
cardElement.mount('#card-element');
</script>
Successivamente, la carta può essere verificata e un "identificativo del metodo di pagamento" può essere recuperato da Stripe utilizzando il metodo createPaymentMethod
di Stripe:
const cardHolderName = document.getElementById('card-holder-name');
const cardButton = document.getElementById('card-button');
cardButton.addEventListener('click', async (e) => {
const { paymentMethod, error } = await stripe.createPaymentMethod(
'card', cardElement, {
billing_details: { name: cardHolderName.value }
}
);
if (error) {
// Mostra "error.message" all'utente...
} else {
// La carta è stata verificata con successo...
}
});
Se la carta viene verificata con successo, puoi passare paymentMethod.id
alla tua applicazione Laravel e procedere con un addebito singolo.
Ottenere i Metodi di Pagamento
Il metodo paymentMethods
sull’istanza del modello billable restituisce una collezione di istanze Laravel\Cashier\PaymentMethod
:
$paymentMethods = $user->paymentMethods();
Per impostazione predefinita, questo metodo restituirà metodi di pagamento di ogni tipo. Per ottenere metodi di pagamento di un tipo specifico, puoi passare il type
come argomento al metodo:
$paymentMethods = $user->paymentMethods('sepa_debit');
Per ottenere il metodo di pagamento predefinito del cliente, puoi utilizzare il metodo defaultPaymentMethod
:
$paymentMethod = $user->defaultPaymentMethod();
Puoi recuperare un metodo di pagamento specifico associato al modello billable utilizzando il metodo findPaymentMethod
:
$paymentMethod = $user->findPaymentMethod($paymentMethodId);
Presenza del Metodo di Pagamento
Per determinare se un modello billable ha un metodo di pagamento predefinito collegato al suo account, invoca il metodo hasDefaultPaymentMethod
:
if ($user->hasDefaultPaymentMethod()) {
// ...
}
Puoi usare il metodo hasPaymentMethod
per verificare se un modello billable ha almeno un metodo di pagamento collegato al suo account:
if ($user->hasPaymentMethod()) {
// ...
}
Questo metodo verificherà se il modello billable ha qualsiasi metodo di pagamento. Per determinare se esiste un metodo di pagamento di un tipo specifico per il modello, puoi passare il type
come argomento al metodo:
if ($user->hasPaymentMethod('sepa_debit')) {
// ...
}
Aggiornamento del Metodo di Pagamento Predefinito
Il metodo updateDefaultPaymentMethod
può essere utilizzato per aggiornare le informazioni del metodo di pagamento predefinito di un cliente. Questo metodo accetta un identificatore del metodo di pagamento di Stripe e assegnerà il nuovo metodo di pagamento come metodo di fatturazione predefinito:
$user->updateDefaultPaymentMethod($paymentMethod);
Per sincronizzare le informazioni del tuo metodo di pagamento predefinito con quelle del metodo di pagamento predefinito del cliente su Stripe, puoi usare il metodo updateDefaultPaymentMethodFromStripe
:
$user->updateDefaultPaymentMethodFromStripe();
Il metodo di pagamento predefinito di un cliente può essere utilizzato solo per la fatturazione e la creazione di nuovi abbonamenti. A causa delle limitazioni imposte da Stripe, non può essere usato per addebiti singoli.
Aggiungere Metodi di Pagamento
Per aggiungere un nuovo metodo di pagamento, puoi chiamare il metodo addPaymentMethod
sul modello billable, passando l’identificatore del metodo di pagamento:
$user->addPaymentMethod($paymentMethod);
Per sapere come recuperare gli identificatori dei metodi di pagamento, consulta la documentazione sul salvataggio dei metodi di pagamento.
Eliminare i Metodi di Pagamento
Per eliminare un metodo di pagamento, puoi chiamare il metodo delete
sull’istanza Laravel\Cashier\PaymentMethod
che desideri eliminare:
$paymentMethod->delete();
Il metodo deletePaymentMethod
eliminerà un metodo di pagamento specifico dal modello billable:
$user->deletePaymentMethod('pm_visa');
Il metodo deletePaymentMethods
eliminerà tutte le informazioni sui metodi di pagamento per il modello billable:
$user->deletePaymentMethods();
Per impostazione predefinita, questo metodo eliminerà i metodi di pagamento di ogni tipo. Per eliminare i metodi di pagamento di un tipo specifico, puoi passare il type
come argomento al metodo:
$user->deletePaymentMethods('sepa_debit');
Se un utente ha un abbonamento attivo, la tua applicazione non dovrebbe permettergli di eliminare il metodo di pagamento predefinito.
Sottoscrizioni
Le sottoscrizioni permettono di configurare pagamenti ricorrenti per i tuoi clienti. Le sottoscrizioni Stripe gestite da Cashier supportano diversi prezzi, quantità di sottoscrizione, periodi di prova e altro ancora.
Creare Abbonamenti
Per creare un abbonamento, prima recupera un’istanza del tuo modello billable, che di solito sarà un’istanza di App\Models\User
. Una volta che hai recuperato l’istanza del modello, puoi usare il metodo newSubscription
per creare l’abbonamento del modello:
use Illuminate\Http\Request;
Route::post('/user/subscribe', function (Request $request) {
$request->user()->newSubscription(
'default', 'price_monthly'
)->create($request->paymentMethodId);
// ...
});
Il primo argomento passato al metodo newSubscription
dovrebbe essere il tipo interno dell’abbonamento. Se la tua applicazione offre solo un abbonamento, potresti chiamarlo default
o primary
. Questo tipo di abbonamento è solo per uso interno dell’applicazione e non è destinato ad essere mostrato agli utenti. Inoltre, non dovrebbe contenere spazi e non dovrebbe mai essere cambiato dopo aver creato l’abbonamento. Il secondo argomento è il prezzo specifico a cui l’utente si sta abbonando. Questo valore dovrebbe corrispondere all’identificatore del prezzo in Stripe.
Il metodo create
, che accetta un identificatore del metodo di pagamento di Stripe o un oggetto PaymentMethod
di Stripe, avvierà l’abbonamento e aggiornerà il tuo database con l’ID cliente Stripe del modello billable e altre informazioni di fatturazione rilevanti.
Passare direttamente un identificatore del metodo di pagamento al metodo
create
dell’abbonamento aggiungerà automaticamente il metodo di pagamento ai metodi di pagamento memorizzati dell’utente.
Raccogliere Pagamenti Ricorrenti tramite Email di Fattura
Invece di raccogliere automaticamente i pagamenti ricorrenti di un cliente, puoi chiedere a Stripe di inviare una fattura via email al cliente ogni volta che il pagamento ricorrente è dovuto. In questo modo, il cliente può pagare manualmente la fattura una volta ricevuta. Il cliente non deve fornire un metodo di pagamento in anticipo quando raccogli pagamenti ricorrenti tramite fatture:
$user->newSubscription('default', 'price_monthly')->createAndSendInvoice();
Il tempo a disposizione del cliente per pagare la fattura prima che l’abbonamento venga annullato è determinato dall’opzione days_until_due
. Per impostazione predefinita, è di 30 giorni; tuttavia, puoi fornire un valore specifico per questa opzione se lo desideri:
$user->newSubscription('default', 'price_monthly')->createAndSendInvoice([], [
'days_until_due' => 30
]);
Quantità
Se desideri impostare una quantity specifica per il prezzo quando crei l’abbonamento, dovresti invocare il metodo quantity
sul builder dell’abbonamento prima di creare l’abbonamento:
$user->newSubscription('default', 'price_monthly')
->quantity(5)
->create($paymentMethod);
Dettagli Aggiuntivi
Se vuoi specificare opzioni aggiuntive per cliente o abbonamento supportate da Stripe, puoi farlo passando questi parametri come secondo e terzo argomento al metodo create
:
$user->newSubscription('default', 'price_monthly')->create($paymentMethod, [
'email' => $email,
], [
'metadata' => ['note' => 'Some extra information.'],
]);
Coupon
Se vuoi applicare un coupon durante la creazione dell’abbonamento, puoi usare il metodo withCoupon
:
$user->newSubscription('default', 'price_monthly')
->withCoupon('code')
->create($paymentMethod);
Oppure, se desideri applicare un codice promozionale di Stripe, puoi usare il metodo withPromotionCode
:
$user->newSubscription('default', 'price_monthly')
->withPromotionCode('promo_code_id')
->create($paymentMethod);
L’ID del codice promozionale fornito dovrebbe essere l’ID API di Stripe assegnato al codice promozionale e non il codice promozionale visibile ai clienti. Se hai bisogno di trovare un ID di codice promozionale basato su un codice promozionale visibile ai clienti, puoi usare il metodo findPromotionCode
:
// Trova un ID di codice promozionale tramite il suo codice visibile ai clienti...
$promotionCode = $user->findPromotionCode('SUMMERSALE');
// Trova un ID di codice promozionale attivo tramite il suo codice visibile ai clienti...
$promotionCode = $user->findActivePromotionCode('SUMMERSALE');
Nell’esempio sopra, l’oggetto $promotionCode
restituito è un’istanza di Laravel\Cashier\PromotionCode
. Questa classe decora un oggetto Stripe\PromotionCode
sottostante. Puoi recuperare il coupon relativo al codice promozionale invocando il metodo coupon
:
$coupon = $user->findPromotionCode('SUMMERSALE')->coupon();
L’istanza del coupon ti permette di determinare l’ammontare dello sconto e se il coupon rappresenta uno sconto fisso o percentuale:
if ($coupon->isPercentage()) {
return $coupon->percentOff().'%'; // 21.5%
} else {
return $coupon->amountOff(); // $5.99
}
Puoi anche recuperare gli sconti attualmente applicati a un cliente o a un abbonamento:
$discount = $billable->discount();
$discount = $subscription->discount();
Le istanze di Laravel\Cashier\Discount
restituite decorano un’istanza dell’oggetto Stripe\Discount
sottostante. Puoi recuperare il coupon relativo a questo sconto invocando il metodo coupon
:
$coupon = $subscription->discount()->coupon();
Se desideri applicare un nuovo coupon o codice promozionale a un cliente o a un abbonamento, puoi farlo tramite i metodi applyCoupon
o applyPromotionCode
:
$billable->applyCoupon('coupon_id');
$billable->applyPromotionCode('promotion_code_id');
$subscription->applyCoupon('coupon_id');
$subscription->applyPromotionCode('promotion_code_id');
Ricorda di usare l’ID API di Stripe assegnato al codice promozionale e non il codice promozionale visibile ai clienti. È possibile applicare un solo coupon o codice promozionale a un cliente o a un abbonamento alla volta.
Per ulteriori informazioni su questo argomento, consulta la documentazione di Stripe riguardo ai coupon e ai codici promozionali.
Aggiungere Abbonamenti
Se desideri aggiungere un abbonamento a un cliente che ha già un metodo di pagamento predefinito, puoi invocare il metodo add
sul builder dell’abbonamento:
use App\Models\User;
$user = User::find(1);
$user->newSubscription('default', 'price_monthly')->add();
Creare Abbonamenti dal Dashboard di Stripe
Puoi creare abbonamenti direttamente dal dashboard di Stripe. In questo modo, Cashier sincronizzerà i nuovi abbonamenti aggiunti e assegnerà loro un tipo di default
. Per personalizzare il tipo di abbonamento assegnato agli abbonamenti creati dal dashboard, definisci i gestori degli eventi webhook.
Inoltre, puoi creare solo un tipo di abbonamento tramite il dashboard di Stripe. Se la tua applicazione offre più abbonamenti con tipi diversi, solo un tipo di abbonamento può essere aggiunto tramite il dashboard di Stripe.
Infine, assicurati sempre di aggiungere un solo abbonamento attivo per ogni tipo di abbonamento offerto dalla tua applicazione. Se un cliente ha due abbonamenti default
, Cashier utilizzerà solo l’abbonamento aggiunto più di recente, anche se entrambi verranno sincronizzati con il database della tua applicazione.
Verifica dello stato dell’abbonamento
Una volta che un cliente è abbonato alla tua applicazione, puoi facilmente controllare il suo stato di abbonamento utilizzando diversi metodi comodi. Innanzitutto, il metodo subscribed
restituisce true
se il cliente ha un abbonamento attivo, anche se l’abbonamento è attualmente nel periodo di prova. Il metodo subscribed
accetta il tipo di abbonamento come primo argomento:
if ($user->subscribed('default')) {
// ...
}
Il metodo subscribed
è anche un’ottima candidata per un middleware di route, permettendoti di filtrare l’accesso alle route e ai controller in base allo stato di abbonamento dell’utente:
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
class EnsureUserIsSubscribed
{
/**
* Gestisce una richiesta in arrivo.
*
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle(Request $request, Closure $next): Response
{
if ($request->user() && ! $request->user()->subscribed('default')) {
// Questo utente non è un cliente pagante...
return redirect('/billing');
}
return $next($request);
}
}
Se vuoi determinare se un utente è ancora nel periodo di prova, puoi usare il metodo onTrial
. Questo metodo può essere utile per capire se devi mostrare un avviso all’utente che è ancora nel periodo di prova:
if ($user->subscription('default')->onTrial()) {
// ...
}
Il metodo subscribedToProduct
può essere utilizzato per determinare se l’utente è abbonato a un determinato prodotto basandosi sull’identificativo del prodotto in Stripe. In Stripe, i prodotti sono collezioni di prezzi. In questo esempio, determineremo se l’abbonamento default
dell’utente è attivamente abbonato al prodotto "premium" dell’applicazione. L’identificativo del prodotto Stripe fornito deve corrispondere a uno degli identificativi dei tuoi prodotti nel dashboard di Stripe:
if ($user->subscribedToProduct('prod_premium', 'default')) {
// ...
}
Passando un array al metodo subscribedToProduct
, puoi determinare se l’abbonamento default
dell’utente è attivamente abbonato ai prodotti "basic" o "premium" dell’applicazione:
if ($user->subscribedToProduct(['prod_basic', 'prod_premium'], 'default')) {
// ...
}
Il metodo subscribedToPrice
può essere usato per determinare se l’abbonamento di un cliente corrisponde a un determinativo ID prezzo:
if ($user->subscribedToPrice('price_basic_monthly', 'default')) {
// ...
}
Il metodo recurring
può essere usato per determinare se l’utente è attualmente abbonato e non è più nel periodo di prova:
if ($user->subscription('default')->recurring()) {
// ...
}
Se un utente ha due abbonamenti dello stesso tipo, il metodo
subscription
restituirà sempre l’abbonamento più recente. Ad esempio, un utente potrebbe avere due record di abbonamento di tipodefault
; tuttavia, uno degli abbonamenti potrebbe essere un abbonamento vecchio e scaduto, mentre l’altro è l’abbonamento attivo corrente. L’abbonamento più recente sarà sempre restituito mentre gli abbonamenti più vecchi vengono mantenuti nel database per una revisione storica.
Stato della Sottoscrizione Cancellata
Per determinare se l’utente è stato un abbonato attivo ma ha cancellato la sua sottoscrizione, puoi usare il metodo canceled
:
if ($user->subscription('default')->canceled()) {
// ...
}
Puoi anche verificare se un utente ha cancellato la propria sottoscrizione ma è ancora nel "periodo di grazia" fino alla scadenza completa della sottoscrizione. Ad esempio, se un utente cancella una sottoscrizione il 5 marzo che era originariamente prevista per scadere il 10 marzo, l’utente è nel "periodo di grazia" fino al 10 marzo. Nota che il metodo subscribed
restituisce ancora true
durante questo periodo:
if ($user->subscription('default')->onGracePeriod()) {
// ...
}
Per determinare se l’utente ha cancellato la propria sottoscrizione e non è più nel "periodo di grazia", puoi usare il metodo ended
:
if ($user->subscription('default')->ended()) {
// ...
}
Stato Incompleto e Scaduto
Se un abbonamento richiede un’azione di pagamento secondaria dopo la creazione, l’abbonamento sarà contrassegnato come incomplete
. Gli stati degli abbonamenti sono memorizzati nella colonna stripe_status
della tabella subscriptions
del database di Cashier.
Allo stesso modo, se è richiesta un’azione di pagamento secondaria durante il cambio dei prezzi, l’abbonamento sarà contrassegnato come past_due
. Quando il tuo abbonamento è in uno di questi stati, non sarà attivo finché il cliente non avrà confermato il pagamento. Determinare se un abbonamento ha un pagamento incompleto può essere fatto utilizzando il metodo hasIncompletePayment
sul modello billable o su un’istanza di abbonamento:
if ($user->hasIncompletePayment('default')) {
// ...
}
if ($user->subscription('default')->hasIncompletePayment()) {
// ...
}
Quando un abbonamento ha un pagamento incompleto, dovresti indirizzare l’utente alla pagina di conferma del pagamento di Cashier, passando l’identificatore latestPayment
. Puoi usare il metodo latestPayment
disponibile sull’istanza dell’abbonamento per recuperare questo identificatore:
<a href="{{ route('cashier.payment', $subscription->latestPayment()->id) }}">
Please confirm your payment.
</a>
Se desideri che l’abbonamento sia ancora considerato attivo quando è in uno stato past_due
o incomplete
, puoi usare i metodi keepPastDueSubscriptionsActive
e keepIncompleteSubscriptionsActive
forniti da Cashier. Tipicamente, questi metodi dovrebbero essere chiamati nel metodo register
del tuo App\Providers\AppServiceProvider
:
use Laravel\Cashier\Cashier;
/**
* Registra i servizi dell'applicazione.
*/
public function register(): void
{
Cashier::keepPastDueSubscriptionsActive();
Cashier::keepIncompleteSubscriptionsActive();
}
Quando un abbonamento è in stato
incomplete
, non può essere modificato finché il pagamento non viene confermato. Pertanto, i metodiswap
eupdateQuantity
genereranno un’eccezione quando l’abbonamento è in statoincomplete
.
Scope delle Sottoscrizioni
La maggior parte degli stati delle sottoscrizioni sono disponibili come scope delle query, permettendoti di interrogare facilmente il database per le sottoscrizioni in uno stato particolare:
// Ottieni tutte le sottoscrizioni attive...
$subscriptions = Subscription::query()->active()->get();
// Ottieni tutte le sottoscrizioni cancellate di un utente...
$subscriptions = $user->subscriptions()->canceled()->get();
Una lista completa degli scope disponibili è riportata di seguito:
Subscription::query()->active();
Subscription::query()->canceled();
Subscription::query()->ended();
Subscription::query()->incomplete();
Subscription::query()->notCanceled();
Subscription::query()->notOnGracePeriod();
Subscription::query()->notOnTrial();
Subscription::query()->onGracePeriod();
Subscription::query()->onTrial();
Subscription::query()->pastDue();
Subscription::query()->recurring();
Modificare i Prezzi
Dopo che un cliente si è abbonato alla tua applicazione, potrebbe occasionalmente voler cambiare il prezzo dell’abbonamento. Per passare a un nuovo prezzo, fornisci l’identificatore del prezzo di Stripe al metodo swap
. Quando si cambiano i prezzi, si assume che l’utente voglia riattivare il proprio abbonamento se era stato precedentemente cancellato. L’identificatore del prezzo fornito dovrebbe corrispondere a un identificatore di prezzo Stripe disponibile nella dashboard di Stripe:
use App\Models\User;
$user = App\Models\User::find(1);
$user->subscription('default')->swap('price_yearly');
Se il cliente è in periodo di prova, il periodo di prova sarà mantenuto. Inoltre, se esiste una "quantity" per l’abbonamento, quella quantità sarà mantenuta.
Se desideri cambiare i prezzi e annullare qualsiasi periodo di prova attualmente in corso per il cliente, puoi invocare il metodo skipTrial
:
$user->subscription('default')
->skipTrial()
->swap('price_yearly');
Se desideri cambiare i prezzi e fatturare immediatamente il cliente invece di aspettare il prossimo ciclo di fatturazione, puoi usare il metodo swapAndInvoice
:
$user = User::find(1);
$user->subscription('default')->swapAndInvoice('price_yearly');
Proratazioni
Di default, Stripe effettua una proratazione dei costi quando si cambia prezzo. Il metodo noProrate
può essere utilizzato per aggiornare il prezzo dell’abbonamento senza proratazione dei costi:
$user->subscription('default')->noProrate()->swap('price_yearly');
Per maggiori informazioni sulla proratazione degli abbonamenti, consulta la documentazione di Stripe.
Eseguire il metodo
noProrate
prima del metodoswapAndInvoice
non avrà effetto sulla proratazione. Verrà sempre emessa una fattura.
Quantità dell’Abbonamento
A volte gli abbonamenti sono influenzati dalla "quantità". Ad esempio, un’applicazione di gestione progetti potrebbe addebitare $10 al mese per progetto. Puoi usare i metodi incrementQuantity
e decrementQuantity
per aumentare o diminuire facilmente la quantità del tuo abbonamento:
use App\Models\User;
$user = User::find(1);
$user->subscription('default')->incrementQuantity();
// Aggiungi cinque alla quantità attuale dell'abbonamento...
$user->subscription('default')->incrementQuantity(5);
$user->subscription('default')->decrementQuantity();
// Sottrai cinque dalla quantità attuale dell'abbonamento...
$user->subscription('default')->decrementQuantity(5);
In alternativa, puoi impostare una quantità specifica usando il metodo updateQuantity
:
$user->subscription('default')->updateQuantity(10);
Il metodo noProrate
può essere usato per aggiornare la quantità dell’abbonamento senza proporzionare i costi:
$user->subscription('default')->noProrate()->updateQuantity(10);
Per maggiori informazioni sulle quantità degli abbonamenti, consulta la documentazione di Stripe.
Quantità per Abbonamenti con Più Prodotti
Se il tuo abbonamento è un abbonamento con più prodotti, dovresti passare l’ID del prezzo di cui desideri incrementare o decrementare la quantità come secondo argomento ai metodi increment / decrement:
$user->subscription('default')->incrementQuantity(1, 'price_chat');
Abbonamenti con Prodotti Multipli
Abbonamento con prodotti multipli ti permette di assegnare più prodotti di fatturazione a un singolo abbonamento. Ad esempio, immagina di creare un’applicazione di assistenza clienti "helpdesk" che ha un prezzo base di abbonamento di $10 al mese ma offre un prodotto aggiuntivo di chat live per $15 in più al mese. Le informazioni per gli abbonamenti con più prodotti sono memorizzate nella tabella subscription_items
del database di Cashier.
Puoi specificare più prodotti per un determinato abbonamento passando un array di prezzi come secondo argomento al metodo newSubscription
:
use Illuminate\Http\Request;
Route::post('/user/subscribe', function (Request $request) {
$request->user()->newSubscription('default', [
'price_monthly',
'price_chat',
])->create($request->paymentMethodId);
// ...
});
Nell’esempio sopra, il cliente avrà due prezzi associati al loro abbonamento default
. Entrambi i prezzi saranno addebitati nei loro rispettivi intervalli di fatturazione. Se necessario, puoi usare il metodo quantity
per indicare una quantità specifica per ogni prezzo:
$user = User::find(1);
$user->newSubscription('default', ['price_monthly', 'price_chat'])
->quantity(5, 'price_chat')
->create($paymentMethod);
Se desideri aggiungere un altro prezzo a un abbonamento esistente, puoi invocare il metodo addPrice
dell’abbonamento:
$user = User::find(1);
$user->subscription('default')->addPrice('price_chat');
L’esempio sopra aggiungerà il nuovo prezzo e al cliente verrà addebitato nel prossimo ciclo di fatturazione. Se desideri addebitare il cliente immediatamente puoi usare il metodo addPriceAndInvoice
:
$user->subscription('default')->addPriceAndInvoice('price_chat');
Se desideri aggiungere un prezzo con una quantità specifica, puoi passare la quantità come secondo argomento dei metodi addPrice
o addPriceAndInvoice
:
$user = User::find(1);
$user->subscription('default')->addPrice('price_chat', 5);
Puoi rimuovere prezzi dagli abbonamenti usando il metodo removePrice
:
$user->subscription('default')->removePrice('price_chat');
Non puoi rimuovere l’ultimo prezzo di un abbonamento. Invece, dovresti semplicemente cancellare l’abbonamento.
Cambiare i Prezzi
Puoi cambiare i prezzi associati a un abbonamento con più prodotti. Ad esempio, immagina che un cliente abbia un abbonamento price_basic
con un prodotto aggiuntivo price_chat
e desideri aggiornare il cliente da price_basic
a price_pro
:
use App\Models\User;
$user = User::find(1);
$user->subscription('default')->swap(['price_pro', 'price_chat']);
Eseguendo l’esempio sopra, l’elemento di abbonamento con price_basic
viene eliminato e quello con price_chat
viene mantenuto. Inoltre, viene creato un nuovo elemento di abbonamento per price_pro
.
Puoi anche specificare le opzioni degli elementi di abbonamento passando un array di coppie chiave/valore al metodo swap
. Ad esempio, potresti aver bisogno di specificare le quantità dei prezzi dell’abbonamento:
$user = User::find(1);
$user->subscription('default')->swap([
'price_pro' => ['quantity' => 5],
'price_chat'
]);
Se vuoi cambiare un solo prezzo in un abbonamento, puoi farlo usando il metodo swap
direttamente sull’elemento di abbonamento. Questo approccio è particolarmente utile se vuoi mantenere tutti i metadata esistenti sugli altri prezzi dell’abbonamento:
$user = User::find(1);
$user->subscription('default')
->findItemOrFail('price_basic')
->swap('price_pro');
Prorate
Di default, Stripe applica le prorate quando si aggiungono o si rimuovono prezzi da un abbonamento con più prodotti. Se desideri effettuare un aggiustamento del prezzo senza prorata, puoi concatenare il metodo noProrate
all’operazione sul prezzo:
$user->subscription('default')->noProrate()->removePrice('price_chat');
Quantità
Se desideri aggiornare le quantità sui prezzi delle singole sottoscrizioni, puoi farlo utilizzando i metodi di quantità esistenti passando l’ID del prezzo come argomento aggiuntivo al metodo:
$user = User::find(1);
$user->subscription('default')->incrementQuantity(5, 'price_chat');
$user->subscription('default')->decrementQuantity(3, 'price_chat');
$user->subscription('default')->updateQuantity(10, 'price_chat');
Quando una sottoscrizione ha più prezzi, gli attributi
stripe_price
equantity
sul modelloSubscription
sarannonull
. Per accedere agli attributi dei singoli prezzi, dovresti usare la relazioneitems
disponibile sul modelloSubscription
.
Elementi di Abbonamento
Quando un abbonamento ha più prezzi, avrà diversi "elementi" di abbonamento memorizzati nella tabella subscription_items
del tuo database. Puoi accedervi tramite la relazione items
sull’abbonamento:
use App\Models\User;
$user = User::find(1);
$subscriptionItem = $user->subscription('default')->items->first();
// Recupera il prezzo e la quantità di Stripe per un elemento specifico...
$stripePrice = $subscriptionItem->stripe_price;
$quantity = $subscriptionItem->quantity;
Puoi anche recuperare un prezzo specifico utilizzando il metodo findItemOrFail
:
$user = User::find(1);
$subscriptionItem = $user->subscription('default')->findItemOrFail('price_chat');
Abbonamenti Multipli
Stripe permette ai tuoi clienti di avere più abbonamenti contemporaneamente. Ad esempio, potresti gestire una palestra che offre un abbonamento per il nuoto e uno per il sollevamento pesi, e ogni abbonamento potrebbe avere prezzi differenti. Naturalmente, i clienti dovrebbero poter abbonarsi a uno o entrambi i piani.
Quando la tua applicazione crea abbonamenti, puoi fornire il tipo di abbonamento al metodo newSubscription
. Il tipo può essere qualsiasi stringa che rappresenta il tipo di abbonamento che l’utente sta iniziando:
use Illuminate\Http\Request;
Route::post('/swimming/subscribe', function (Request $request) {
$request->user()->newSubscription('swimming')
->price('price_swimming_monthly')
->create($request->paymentMethodId);
// ...
});
In questo esempio, abbiamo avviato un abbonamento mensile per il nuoto per il cliente. Tuttavia, potrebbe voler passare a un abbonamento annuale in un secondo momento. Quando si modifica l’abbonamento del cliente, possiamo semplicemente cambiare il prezzo sull’abbonamento swimming
:
$user->subscription('swimming')->swap('price_swimming_yearly');
Naturalmente, puoi anche annullare completamente l’abbonamento:
$user->subscription('swimming')->cancel();
Fatturazione Basata sull’Uso
La fatturazione basata sull’uso permette di addebitare i clienti in base all’utilizzo del prodotto durante un ciclo di fatturazione. Ad esempio, potresti addebitare i clienti in base al numero di messaggi di testo o email che inviano ogni mese.
Per iniziare a utilizzare la fatturazione basata sull’uso, devi prima creare un nuovo prodotto nel tuo dashboard di Stripe con un modello di fatturazione basato sull’uso e un meter. Dopo aver creato il meter, memorizza il nome dell’evento associato e l’ID del meter, che ti serviranno per segnalare e recuperare l’utilizzo. Poi, utilizza il metodo meteredPrice
per aggiungere l’ID del prezzo misurato a una sottoscrizione del cliente:
use Illuminate\Http\Request;
Route::post('/user/subscribe', function (Request $request) {
$request->user()->newSubscription('default')
->meteredPrice('price_metered')
->create($request->paymentMethodId);
// ...
});
Puoi anche avviare una sottoscrizione misurata tramite Stripe Checkout:
$checkout = Auth::user()
->newSubscription('default', [])
->meteredPrice('price_metered')
->checkout();
return view('your-checkout-view', [
'checkout' => $checkout,
]);
Report dell’utilizzo
Man mano che i tuoi clienti utilizzano la tua applicazione, dovrai segnalare il loro utilizzo a Stripe in modo che possano essere fatturati correttamente. Per segnalare l’utilizzo di un evento misurato, puoi usare il metodo reportMeterEvent
sul tuo modello Billable
:
$user = User::find(1);
$user->reportMeterEvent('emails-sent');
Per impostazione predefinita, viene aggiunta una "quantità di utilizzo" di 1 al periodo di fatturazione. In alternativa, puoi passare una quantità specifica di "utilizzo" da aggiungere all’utilizzo del cliente per il periodo di fatturazione:
$user = User::find(1);
$user->reportMeterEvent('emails-sent', quantity: 15);
Per recuperare il riepilogo degli eventi di un cliente per un contatore, puoi utilizzare il metodo meterEventSummaries
di un’istanza Billable
:
$user = User::find(1);
$meterUsage = $user->meterEventSummaries($meterId);
$meterUsage->first()->aggregated_value // 10
Per ulteriori informazioni sui riepiloghi degli eventi dei contatori, consulta la documentazione dell’oggetto Meter Event Summary di Stripe.
Per elencare tutti i contatori, puoi utilizzare il metodo meters
di un’istanza Billable
:
$user = User::find(1);
$user->meters();
Tasse sulle Sottoscrizioni
Invece di calcolare manualmente le aliquote fiscali, puoi calcolare automaticamente le tasse con Stripe Tax.
Per specificare le aliquote fiscali che un utente paga su una sottoscrizione, devi implementare il metodo taxRates
sul tuo modello billable e restituire un array contenente gli ID delle aliquote fiscali di Stripe. Puoi definire queste aliquote fiscali nel tuo dashboard Stripe:
/**
* Le aliquote fiscali che si applicano alle sottoscrizioni del cliente.
*
* @return array<int, string>
*/
public function taxRates(): array
{
return ['txr_id'];
}
Il metodo taxRates
ti permette di applicare un’aliquota fiscale per ogni cliente, utile se hai utenti in diversi paesi con diverse aliquote fiscali.
Se offri sottoscrizioni con più prodotti, puoi definire aliquote fiscali diverse per ogni prezzo implementando un metodo priceTaxRates
sul tuo modello billable:
/**
* Le aliquote fiscali che si applicano alle sottoscrizioni del cliente.
*
* @return array<string, array<int, string>>
*/
public function priceTaxRates(): array
{
return [
'price_monthly' => ['txr_id'],
];
}
Il metodo
taxRates
si applica solo agli addebiti delle sottoscrizioni. Se usi Cashier per effettuare addebiti "una tantum", dovrai specificare manualmente l’aliquota fiscale in quel momento.
Sincronizzazione delle aliquote fiscali
Quando modifichi gli ID delle aliquote fiscali codificati restituiti dal metodo taxRates
, le impostazioni fiscali delle sottoscrizioni esistenti per l’utente rimarranno invariate. Se desideri aggiornare il valore fiscale delle sottoscrizioni esistenti con i nuovi valori di taxRates
, dovresti chiamare il metodo syncTaxRates
sull’istanza della sottoscrizione dell’utente:
$user->subscription('default')->syncTaxRates();
Questo sincronizzerà anche le aliquote fiscali degli articoli per una sottoscrizione con più prodotti. Se la tua applicazione offre sottoscrizioni con più prodotti, assicurati che il tuo modello billable implementi il metodo priceTaxRates
discusso sopra.
Esenzione Fiscale
Cashier offre anche i metodi isNotTaxExempt
, isTaxExempt
e reverseChargeApplies
per determinare se il cliente è esente da tasse. Questi metodi chiameranno l’API di Stripe per verificare lo stato di esenzione fiscale di un cliente:
use App\Models\User;
$user = User::find(1);
$user->isTaxExempt();
$user->isNotTaxExempt();
$user->reverseChargeApplies();
Questi metodi sono disponibili anche su qualsiasi oggetto
Laravel\Cashier\Invoice
. Tuttavia, quando vengono invocati su un oggettoInvoice
, i metodi determineranno lo stato di esenzione al momento della creazione della fattura.
Data di Ancoraggio dell’Abbonamento
Di default, l’ancoraggio del ciclo di fatturazione è la data in cui l’abbonamento è stato creato o, se viene utilizzato un periodo di prova, la data in cui termina la prova. Se desideri modificare la data di ancoraggio della fatturazione, puoi usare il metodo anchorBillingCycleOn
:
use Illuminate\Http\Request;
Route::post('/user/subscribe', function (Request $request) {
$anchor = Carbon::parse('first day of next month');
$request->user()->newSubscription('default', 'price_monthly')
->anchorBillingCycleOn($anchor->startOfDay())
->create($request->paymentMethodId);
// ...
});
Per maggiori informazioni sulla gestione dei cicli di fatturazione degli abbonamenti, consulta la documentazione sul ciclo di fatturazione di Stripe
Cancellazione degli Abbonamenti
Per cancellare un abbonamento, chiama il metodo cancel
sull’abbonamento dell’utente:
$user->subscription('default')->cancel();
Quando un abbonamento viene cancellato, Cashier imposterà automaticamente la colonna ends_at
nella tua tabella subscriptions
del database. Questa colonna viene utilizzata per sapere quando il metodo subscribed
dovrebbe iniziare a restituire false
.
Ad esempio, se un cliente cancella un abbonamento il 1° marzo, ma l’abbonamento non era previsto per terminare fino al 5 marzo, il metodo subscribed
continuerà a restituire true
fino al 5 marzo. Questo accade perché solitamente a un utente è permesso continuare a usare un’applicazione fino alla fine del ciclo di fatturazione.
Puoi determinare se un utente ha cancellato il proprio abbonamento ma è ancora nel suo "periodo di grazia" usando il metodo onGracePeriod
:
if ($user->subscription('default')->onGracePeriod()) {
// ...
}
Se desideri cancellare un abbonamento immediatamente, chiama il metodo cancelNow
sull’abbonamento dell’utente:
$user->subscription('default')->cancelNow();
Se desideri cancellare un abbonamento immediatamente e fatturare qualsiasi utilizzo misurato rimanente non fatturato o nuovi elementi di fattura di prorata in sospeso, chiama il metodo cancelNowAndInvoice
sull’abbonamento dell’utente:
$user->subscription('default')->cancelNowAndInvoice();
Puoi anche scegliere di cancellare l’abbonamento in un momento specifico:
$user->subscription('default')->cancelAt(
now()->addDays(10)
);
Infine, dovresti sempre cancellare gli abbonamenti degli utenti prima di eliminare il modello utente associato:
$user->subscription('default')->cancelNow();
$user->delete();
Riprendere le Sottoscrizioni
Se un cliente ha annullato la sua sottoscrizione e desideri riprenderla, puoi invocare il metodo resume
sulla sottoscrizione. Il cliente deve essere ancora nel suo "periodo di grazia" per poter riprendere una sottoscrizione:
$user->subscription('default')->resume();
Se il cliente annulla una sottoscrizione e poi la riprende prima che la sottoscrizione sia completamente scaduta, non verrà addebitato immediatamente. Invece, la sua sottoscrizione sarà riattivata e verrà fatturato nel ciclo di fatturazione originale.
Prove di abbonamento
Con il Metodo di Pagamento Iniziale
Se desideri offrire periodi di prova ai tuoi clienti raccogliendo comunque le informazioni del metodo di pagamento in anticipo, dovresti usare il metodo trialDays
quando crei le tue sottoscrizioni:
use Illuminate\Http\Request;
Route::post('/user/subscribe', function (Request $request) {
$request->user()->newSubscription('default', 'price_monthly')
->trialDays(10)
->create($request->paymentMethodId);
// ...
});
Questo metodo imposterà la data di fine del periodo di prova nel record della sottoscrizione nel database e istruirà Stripe a non iniziare la fatturazione al cliente fino a dopo questa data. Quando usi il metodo trialDays
, Cashier sovrascriverà qualsiasi periodo di prova predefinito configurato per il prezzo in Stripe.
Se la sottoscrizione del cliente non viene cancellata prima della data di fine del periodo di prova, verrà addebitato non appena la prova scade. Assicurati quindi di informare i tuoi utenti della data di fine della prova.
Il metodo trialUntil
ti permette di fornire un’istanza DateTime
che specifica quando dovrebbe terminare il periodo di prova:
use Carbon\Carbon;
$user->newSubscription('default', 'price_monthly')
->trialUntil(Carbon::now()->addDays(10))
->create($paymentMethod);
Puoi verificare se un utente è ancora nel periodo di prova usando il metodo onTrial
dell’istanza utente o il metodo onTrial
dell’istanza sottoscrizione. I due esempi seguenti sono equivalenti:
if ($user->onTrial('default')) {
// ...
}
if ($user->subscription('default')->onTrial()) {
// ...
}
Puoi usare il metodo endTrial
per terminare immediatamente una prova della sottoscrizione:
$user->subscription('default')->endTrial();
Per determinare se una prova esistente è scaduta, puoi usare i metodi hasExpiredTrial
:
if ($user->hasExpiredTrial('default')) {
// ...
}
if ($user->subscription('default')->hasExpiredTrial()) {
// ...
}
Definire i giorni di prova in Stripe / Cashier
Puoi scegliere di definire quanti giorni di prova ricevono i tuoi prezzi nel dashboard di Stripe oppure passarli sempre esplicitamente utilizzando Cashier. Se scegli di definire i giorni di prova dei tuoi prezzi in Stripe, dovresti essere consapevole che le nuove sottoscrizioni, comprese quelle per un cliente che aveva una sottoscrizione in passato, riceveranno sempre un periodo di prova a meno che non chiami esplicitamente il metodo skipTrial()
.
Senza Metodo di Pagamento Iniziale
Se desideri offrire periodi di prova senza raccogliere le informazioni del metodo di pagamento dell’utente inizialmente, puoi impostare la colonna trial_ends_at
nel record dell’utente alla data di fine della prova desiderata. Questo di solito viene fatto durante la registrazione dell’utente:
use App\Models\User;
$user = User::create([
// ...
'trial_ends_at' => now()->addDays(10),
]);
Assicurati di aggiungere un date cast per l’attributo
trial_ends_at
all’interno della definizione della classe del tuo modello billable.
Cashier si riferisce a questo tipo di prova come "generic trial", poiché non è collegato a nessuna sottoscrizione esistente. Il metodo onTrial
sull’istanza del modello billable restituirà true
se la data attuale non supera il valore di trial_ends_at
:
if ($user->onTrial()) {
// L'utente è nel periodo di prova...
}
Una volta che sei pronto a creare una sottoscrizione effettiva per l’utente, puoi utilizzare il metodo newSubscription
come al solito:
$user = User::find(1);
$user->newSubscription('default', 'price_monthly')->create($paymentMethod);
Per recuperare la data di fine della prova dell’utente, puoi usare il metodo trialEndsAt
. Questo metodo restituirà un’istanza di data Carbon se l’utente è in prova o null
se non lo è. Puoi anche passare un parametro di tipo sottoscrizione opzionale se desideri ottenere la data di fine della prova per una specifica sottoscrizione diversa da quella predefinita:
if ($user->onTrial()) {
$trialEndsAt = $user->trialEndsAt('main');
}
Puoi anche usare il metodo onGenericTrial
se desideri sapere specificamente se l’utente è nel periodo di prova "generic" e non ha ancora creato una sottoscrizione effettiva:
if ($user->onGenericTrial()) {
// L'utente è nel periodo di prova "generic"...
}
Estendere le Prove
Il metodo extendTrial
ti permette di estendere il periodo di prova di un abbonamento dopo che l’abbonamento è stato creato. Se la prova è già scaduta e il cliente sta già pagando per l’abbonamento, puoi comunque offrirgli una prova estesa. Il tempo trascorso nel periodo di prova verrà detratto dalla prossima fattura del cliente:
use App\Models\User;
$subscription = User::find(1)->subscription('default');
// Termina la prova tra 7 giorni...
$subscription->extendTrial(
now()->addDays(7)
);
// Aggiungi ulteriori 5 giorni alla prova...
$subscription->extendTrial(
$subscription->trial_ends_at->addDays(5)
);
Gestire i Webhook di Stripe
Puoi usare la Stripe CLI per testare i webhook durante lo sviluppo locale.
Stripe può notificare alla tua applicazione una varietà di eventi tramite webhook. Per impostazione predefinita, una rotta che punta al controller webhook di Cashier viene registrata automaticamente dal service provider di Cashier. Questo controller gestirà tutte le richieste webhook in arrivo.
Per impostazione predefinita, il controller webhook di Cashier gestisce automaticamente la cancellazione degli abbonamenti che hanno troppi pagamenti falliti (come definito dalle tue impostazioni Stripe), aggiornamenti dei clienti, cancellazioni dei clienti, aggiornamenti degli abbonamenti e modifiche ai metodi di pagamento; tuttavia, come vedremo presto, puoi estendere questo controller per gestire qualsiasi evento webhook di Stripe tu voglia.
Per assicurarti che la tua applicazione possa gestire i webhook di Stripe, assicurati di configurare l’URL del webhook nel pannello di controllo di Stripe. Per impostazione predefinita, il controller webhook di Cashier risponde al percorso URL /stripe/webhook
. L’elenco completo dei webhook che dovresti abilitare nel pannello di controllo di Stripe è:
-
customer.subscription.created
-
customer.subscription.updated
-
customer.subscription.deleted
-
customer.updated
-
customer.deleted
-
payment_method.automatically_updated
-
invoice.payment_action_required
-
invoice.payment_succeeded
Per comodità, Cashier include un comando Artisan cashier:webhook
. Questo comando creerà un webhook in Stripe che ascolta tutti gli eventi richiesti da Cashier:
php artisan cashier:webhook
Per impostazione predefinita, il webhook creato punterà all’URL definito dalla variabile d’ambiente APP_URL
e alla rotta cashier.webhook
inclusa in Cashier. Puoi fornire l’opzione --url
quando esegui il comando se desideri usare un URL diverso:
php artisan cashier:webhook --url "https://example.com/stripe/webhook"
Il webhook creato utilizzerà la versione dell’API di Stripe con cui la tua versione di Cashier è compatibile. Se desideri usare una versione diversa di Stripe, puoi fornire l’opzione --api-version
:
php artisan cashier:webhook --api-version="2019-12-03"
Dopo la creazione, il webhook sarà attivo immediatamente. Se desideri creare il webhook ma tenerlo disabilitato fino a quando non sei pronto, puoi fornire l’opzione --disabled
quando esegui il comando:
php artisan cashier:webhook --disabled
Assicurati di proteggere le richieste webhook in arrivo da Stripe con il middleware di verifica della firma webhook incluso in Cashier.
Webhook e Protezione CSRF
Poiché i webhook di Stripe devono bypassare la protezione CSRF di Laravel, devi assicurarti che Laravel non tenti di convalidare il token CSRF per i webhook in arrivo da Stripe. Per fare ciò, dovresti escludere stripe/*
dalla protezione CSRF nel file bootstrap/app.php
della tua applicazione:
->withMiddleware(function (Middleware $middleware) {
$middleware->validateCsrfTokens(except: [
'stripe/*',
]);
})
Definire i gestori di eventi Webhook
Cashier gestisce automaticamente le cancellazioni delle sottoscrizioni per addebiti falliti e altri eventi webhook comuni di Stripe. Tuttavia, se hai eventi webhook aggiuntivi che desideri gestire, puoi farlo ascoltando i seguenti eventi dispatchati da Cashier:
-
Laravel\Cashier\Events\WebhookReceived
-
Laravel\Cashier\Events\WebhookHandled
Entrambi gli eventi contengono l’intero payload del webhook di Stripe. Ad esempio, se desideri gestire il webhook invoice.payment_succeeded
, puoi registrare un listener che gestirà l’evento:
<?php
namespace App\Listeners;
use Laravel\Cashier\Events\WebhookReceived;
class StripeEventListener
{
/**
* Gestire i webhook ricevuti da Stripe.
*/
public function handle(WebhookReceived $event): void
{
if ($event->payload['type'] === 'invoice.payment_succeeded') {
// Gestire l'evento in arrivo...
}
}
}
Verifica delle firme dei Webhook
Per proteggere i tuoi webhook, puoi utilizzare le firme dei webhook di Stripe. Per comodità, Cashier include automaticamente un middleware che valida che la richiesta webhook di Stripe in arrivo sia valida.
Per abilitare la verifica del webhook, assicurati che la variabile d’ambiente STRIPE_WEBHOOK_SECRET
sia impostata nel file .env
della tua applicazione. Il secret
del webhook può essere recuperato dal dashboard del tuo account Stripe.
Addebiti Singoli
Addebito Semplice
Se desideri effettuare un addebito una tantum su un cliente, puoi usare il metodo charge
su un’istanza del modello billable. Dovrai fornire un identificativo del metodo di pagamento come secondo argomento del metodo charge
:
use Illuminate\Http\Request;
Route::post('/purchase', function (Request $request) {
$stripeCharge = $request->user()->charge(
100, $request->paymentMethodId
);
// ...
});
Il metodo charge
accetta un array come terzo argomento, permettendoti di passare qualsiasi opzione desideri alla creazione dell’addebito sottostante di Stripe. Ulteriori informazioni riguardo alle opzioni disponibili quando si creano addebiti possono essere trovate nella documentazione di Stripe:
$user->charge(100, $paymentMethod, [
'custom_option' => $value,
]);
Puoi anche usare il metodo charge
senza un cliente o utente sottostante. Per fare ciò, invoca il metodo charge
su una nuova istanza del modello billable della tua applicazione:
use App\Models\User;
$stripeCharge = (new User)->charge(100, $paymentMethod);
Il metodo charge
genererà un’eccezione se l’addebito fallisce. Se l’addebito ha successo, verrà restituita un’istanza di Laravel\Cashier\Payment
dal metodo:
try {
$payment = $user->charge(100, $paymentMethod);
} catch (Exception $e) {
// ...
}
Il metodo
charge
accetta l’importo del pagamento nel denominatore più basso della valuta utilizzata dalla tua applicazione. Ad esempio, se i clienti pagano in Dollari Americani, gli importi devono essere specificati in centesimi.
Addebitare tramite Fattura
A volte potrebbe essere necessario effettuare un addebito una tantum e offrire una fattura PDF al tuo cliente. Il metodo invoicePrice
ti permette di fare proprio questo. Ad esempio, fatturiamo a un cliente cinque nuove magliette:
$user->invoicePrice('price_tshirt', 5);
La fattura verrà addebitata immediatamente sul metodo di pagamento predefinito dell’utente. Il metodo invoicePrice
accetta anche un array come terzo argomento. Questo array contiene le opzioni di fatturazione per l’elemento della fattura. Il quarto argomento accettato dal metodo è anch’esso un array che deve contenere le opzioni di fatturazione per la fattura stessa:
$user->invoicePrice('price_tshirt', 5, [
'discounts' => [
['coupon' => 'SUMMER21SALE']
],
], [
'default_tax_rates' => ['txr_id'],
]);
In modo simile a invoicePrice
, puoi usare il metodo tabPrice
per creare un addebito una tantum per più articoli (fino a 250 articoli per fattura) aggiungendoli al "conto" del cliente e poi fatturando il cliente. Ad esempio, possiamo fatturare a un cliente cinque magliette e due tazze:
$user->tabPrice('price_tshirt', 5);
$user->tabPrice('price_mug', 2);
$user->invoice();
Alternativamente, puoi usare il metodo invoiceFor
per effettuare un addebito "una tantum" sul metodo di pagamento predefinito del cliente:
$user->invoiceFor('One Time Fee', 500);
Sebbene il metodo invoiceFor
sia disponibile per te, è raccomandato utilizzare i metodi invoicePrice
e tabPrice
con prezzi predefiniti. In questo modo, avrai accesso a migliori analisi e dati nel tuo dashboard Stripe riguardo le tue vendite per prodotto.
I metodi
invoice
,invoicePrice
einvoiceFor
creeranno una fattura Stripe che riproverà gli addebiti falliti. Se non desideri che le fatture ripetano gli addebiti non riusciti, dovrai chiuderle utilizzando l’API di Stripe dopo il primo addebito fallito.
Creazione di Payment Intents
Puoi creare un nuovo payment intent di Stripe invocando il metodo pay
su un’istanza di modello billable. Chiamando questo metodo verrà creato un payment intent che è avvolto in un’istanza Laravel\Cashier\Payment
:
use Illuminate\Http\Request;
Route::post('/pay', function (Request $request) {
$payment = $request->user()->pay(
$request->get('amount')
);
return $payment->client_secret;
});
Dopo aver creato il payment intent, puoi restituire il client secret al frontend della tua applicazione in modo che l’utente possa completare il pagamento nel proprio browser. Per saperne di più sulla costruzione di flussi di pagamento completi utilizzando i payment intents di Stripe, consulta la documentazione di Stripe.
Quando usi il metodo pay
, i metodi di pagamento predefiniti abilitati nel tuo dashboard di Stripe saranno disponibili per il cliente. In alternativa, se desideri consentire solo alcuni metodi di pagamento specifici, puoi usare il metodo payWith
:
use Illuminate\Http\Request;
Route::post('/pay', function (Request $request) {
$payment = $request->user()->payWith(
$request->get('amount'), ['card', 'bancontact']
);
return $payment->client_secret;
});
I metodi
pay
epayWith
accettano l’importo del pagamento nel denominatore più basso della valuta utilizzata dalla tua applicazione. Ad esempio, se i clienti pagano in dollari statunitensi, gli importi devono essere specificati in penny.
Rimborso delle Commissioni
Se devi rimborsare una commissione Stripe, puoi usare il metodo refund
. Questo metodo accetta il payment intent ID di Stripe come primo argomento:
$payment = $user->charge(100, $paymentMethodId);
$user->refund($payment->id);
Fatture
Recupero delle Fatture
Puoi facilmente recuperare un array delle fatture di un modello billable usando il metodo invoices
. Il metodo invoices
restituisce una collezione di istanze di Laravel\Cashier\Invoice
:
$invoices = $user->invoices();
Se vuoi includere le fatture in sospeso nei risultati, puoi usare il metodo invoicesIncludingPending
:
$invoices = $user->invoicesIncludingPending();
Puoi usare il metodo findInvoice
per recuperare una fattura specifica tramite il suo ID:
$invoice = $user->findInvoice($invoiceId);
Visualizzazione delle Informazioni della Fattura
Quando elenchi le fatture per il cliente, puoi usare i metodi della fattura per mostrare le informazioni rilevanti. Ad esempio, potresti voler elencare ogni fattura in una tabella, permettendo all’utente di scaricarle facilmente:
<table>
@foreach ($invoices as $invoice)
<tr>
<td>{{ $invoice->date()->toFormattedDateString() }}</td>
<td>{{ $invoice->total() }}</td>
<td><a href="/user/invoice/{{ $invoice->id }}">Download</a></td>
</tr>
@endforeach
</table>
Fatture Future
Per ottenere la fattura prossima di un cliente, puoi usare il metodo upcomingInvoice
:
$invoice = $user->upcomingInvoice();
Allo stesso modo, se il cliente ha più abbonamenti, puoi anche ottenere la fattura prossima per un abbonamento specifico:
$invoice = $user->subscription('default')->upcomingInvoice();
Anteprima delle Fatture di Abbonamento
Usando il metodo previewInvoice
, puoi visualizzare un’anteprima di una fattura prima di modificare i prezzi. Questo ti permetterà di vedere come sarà la fattura del tuo cliente quando verrà effettuata una determinata modifica del prezzo:
$invoice = $user->subscription('default')->previewInvoice('price_yearly');
Puoi passare un array di prezzi al metodo previewInvoice
per visualizzare in anteprima fatture con più nuovi prezzi:
$invoice = $user->subscription('default')->previewInvoice(['price_yearly', 'price_metered']);
Generazione di PDF per le Fatture
Prima di generare i PDF delle fatture, devi usare Composer per installare la libreria Dompdf, che è il renderer predefinito delle fatture per Cashier:
composer require dompdf/dompdf
All’interno di una route o di un controller, puoi usare il metodo downloadInvoice
per generare un download PDF di una determinata fattura. Questo metodo genererà automaticamente la risposta HTTP necessaria per scaricare la fattura:
use Illuminate\Http\Request;
Route::get('/user/invoice/{invoice}', function (Request $request, string $invoiceId) {
return $request->user()->downloadInvoice($invoiceId);
});
Per impostazione predefinita, tutti i dati della fattura provengono dai dati del cliente e della fattura memorizzati in Stripe. Il nome del file si basa sul valore di configurazione app.name
. Tuttavia, puoi personalizzare alcuni di questi dati fornendo un array come secondo argomento al metodo downloadInvoice
. Questo array ti permette di personalizzare informazioni come i dettagli della tua azienda e del prodotto:
return $request->user()->downloadInvoice($invoiceId, [
'vendor' => 'Your Company',
'product' => 'Your Product',
'street' => 'Main Str. 1',
'location' => '2000 Antwerp, Belgio',
'phone' => '+32 499 00 00 00',
'email' => 'info@example.com',
'url' => 'https://example.com',
'vendorVat' => 'BE123456789',
]);
Il metodo downloadInvoice
consente anche di specificare un nome file personalizzato tramite il suo terzo argomento. Questo nome sarà automaticamente suffisso con .pdf
:
return $request->user()->downloadInvoice($invoiceId, [], 'my-invoice');
Renderer Personalizzato delle Fatture
Cashier consente anche di utilizzare un renderer personalizzato delle fatture. Per impostazione predefinita, Cashier utilizza l’implementazione DompdfInvoiceRenderer
, che sfrutta la libreria PHP dompdf per generare le fatture di Cashier. Tuttavia, puoi utilizzare qualsiasi renderer desideri implementando l’interfaccia Laravel\Cashier\Contracts\InvoiceRenderer
. Ad esempio, potresti voler generare un PDF della fattura utilizzando una chiamata API a un servizio di rendering PDF di terze parti:
use Illuminate\Support\Facades\Http;
use Laravel\Cashier\Contracts\InvoiceRenderer;
use Laravel\Cashier\Invoice;
class ApiInvoiceRenderer implements InvoiceRenderer
{
/**
* Render the given invoice and return the raw PDF bytes.
*/
public function render(Invoice $invoice, array $data = [], array $options = []): string
{
$html = $invoice->view($data)->render();
return Http::get('https://example.com/html-to-pdf', ['html' => $html])->get()->body();
}
}
Una volta che hai implementato il contratto del renderer delle fatture, dovresti aggiornare il valore di configurazione cashier.invoices.renderer
nel file di configurazione config/cashier.php
della tua applicazione. Questo valore di configurazione deve essere impostato sul nome della classe della tua implementazione del renderer personalizzato.
Checkout
Cashier Stripe fornisce anche il supporto per Stripe Checkout. Stripe Checkout semplifica l’implementazione di pagine personalizzate per accettare pagamenti offrendo una pagina di pagamento predefinita e ospitata.
Questa documentazione contiene le informazioni per iniziare a usare Stripe Checkout con Cashier. Per saperne di più su Stripe Checkout, considera di consultare anche la documentazione di Stripe su Checkout.
Acquisti di Prodotti
Puoi effettuare un checkout per un prodotto esistente creato nel tuo dashboard Stripe utilizzando il metodo checkout
su un modello billable. Il metodo checkout
avvierà una nuova sessione di Stripe Checkout. Per impostazione predefinita, è necessario passare un ID Prezzo di Stripe:
use Illuminate\Http\Request;
Route::get('/product-checkout', function (Request $request) {
return $request->user()->checkout('price_tshirt');
});
Se necessario, puoi anche specificare una quantità del prodotto:
use Illuminate\Http\Request;
Route::get('/product-checkout', function (Request $request) {
return $request->user()->checkout(['price_tshirt' => 15]);
});
Quando un cliente visita questa rotta, verrà reindirizzato alla pagina di Checkout di Stripe. Per impostazione predefinita, quando un utente completa con successo o annulla un acquisto, verrà reindirizzato alla tua rotta home
, ma puoi specificare URL di callback personalizzati usando le opzioni success_url
e cancel_url
:
use Illuminate\Http\Request;
Route::get('/product-checkout', function (Request $request) {
return $request->user()->checkout(['price_tshirt' => 1], [
'success_url' => route('your-success-route'),
'cancel_url' => route('your-cancel-route'),
]);
});
Quando definisci l’opzione success_url
per il checkout, puoi istruire Stripe ad aggiungere l’ID della sessione di checkout come parametro della stringa di query quando invoca il tuo URL. Per farlo, aggiungi la stringa letterale {CHECKOUT_SESSION_ID}
alla stringa di query del tuo success_url
. Stripe sostituirà questo segnaposto con l’effettivo ID della sessione di checkout:
use Illuminate\Http\Request;
use Stripe\Checkout\Session;
use Stripe\Customer;
Route::get('/product-checkout', function (Request $request) {
return $request->user()->checkout(['price_tshirt' => 1], [
'success_url' => route('checkout-success').'?session_id={CHECKOUT_SESSION_ID}',
'cancel_url' => route('checkout-cancel'),
]);
});
Route::get('/checkout-success', function (Request $request) {
$checkoutSession = $request->user()->stripe()->checkout->sessions->retrieve($request->get('session_id'));
return view('checkout.success', ['checkoutSession' => $checkoutSession]);
})->name('checkout-success');
Codici Promozionali
Di default, Stripe Checkout non consente codici promozionali riscattabili dagli utenti. Fortunatamente, c’è un modo semplice per abilitarli nella tua pagina di Checkout. Per farlo, puoi usare il metodo allowPromotionCodes
:
use Illuminate\Http\Request;
Route::get('/product-checkout', function (Request $request) {
return $request->user()
->allowPromotionCodes()
->checkout('price_tshirt');
});
Single Charge Checkouts
Puoi anche effettuare un addebito semplice per un prodotto ad-hoc che non è stato creato nel tuo dashboard Stripe. Per farlo, puoi usare il metodo checkoutCharge
su un modello billable e passare un importo addebitabile, un nome del prodotto e una quantità opzionale. Quando un cliente visita questa rotta, verrà reindirizzato alla pagina di Checkout di Stripe:
use Illuminate\Http\Request;
Route::get('/charge-checkout', function (Request $request) {
return $request->user()->checkoutCharge(1200, 'T-Shirt', 5);
});
Quando usi il metodo
checkoutCharge
, Stripe creerà sempre un nuovo prodotto e prezzo nel tuo dashboard Stripe. Pertanto, consigliamo di creare i prodotti in anticipo nel tuo dashboard Stripe e usare invece il metodocheckout
.
Subscription Checkouts
Utilizzare Stripe Checkout per gli abbonamenti richiede di abilitare il webhook
customer.subscription.created
nel tuo dashboard di Stripe. Questo webhook creerà il record dell’abbonamento nel tuo database e memorizzerà tutti gli elementi rilevanti dell’abbonamento.
Puoi anche usare Stripe Checkout per avviare abbonamenti. Dopo aver definito il tuo abbonamento con i metodi del builder di abbonamenti di Cashier, puoi chiamare il metodo checkout
. Quando un cliente visita questa route, verrà reindirizzato alla pagina di Checkout di Stripe:
use Illuminate\Http\Request;
Route::get('/subscription-checkout', function (Request $request) {
return $request->user()
->newSubscription('default', 'price_monthly')
->checkout();
});
Come nei checkout dei prodotti, puoi personalizzare gli URL di successo e cancellazione:
use Illuminate\Http\Request;
Route::get('/subscription-checkout', function (Request $request) {
return $request->user()
->newSubscription('default', 'price_monthly')
->checkout([
'success_url' => route('your-success-route'),
'cancel_url' => route('your-cancel-route'),
]);
});
Naturalmente, puoi anche abilitare i codici promozionali per i subscription checkouts:
use Illuminate\Http\Request;
Route::get('/subscription-checkout', function (Request $request) {
return $request->user()
->newSubscription('default', 'price_monthly')
->allowPromotionCodes()
->checkout();
});
Sfortunatamente, Stripe Checkout non supporta tutte le opzioni di fatturazione degli abbonamenti durante l’avvio degli abbonamenti. Utilizzare il metodo
anchorBillingCycleOn
sul builder dell’abbonamento, impostare il comportamento delle prorate o impostare il comportamento del pagamento non avrà alcun effetto durante le sessioni di Stripe Checkout. Consulta la documentazione dell’API Stripe Checkout Session per vedere quali parametri sono disponibili.
Stripe Checkout e Periodi di Prova
Naturalmente, puoi definire un periodo di prova quando crei un abbonamento che verrà completato utilizzando Stripe Checkout:
$checkout = Auth::user()->newSubscription('default', 'price_monthly')
->trialDays(3)
->checkout();
Tuttavia, il periodo di prova deve essere di almeno 48 ore, che è il tempo minimo supportato da Stripe Checkout.
Abbonamenti e Webhooks
Ricorda che Stripe e Cashier aggiornano lo stato degli abbonamenti tramite webhooks, quindi è possibile che un abbonamento non sia ancora attivo quando il cliente torna nell’applicazione dopo aver inserito le informazioni di pagamento. Per gestire questa situazione, potresti mostrare un messaggio che informa l’utente che il pagamento o l’abbonamento è in sospeso.
Raccogliere i Tax IDs
Checkout supporta anche la raccolta del Tax ID di un cliente. Per abilitare questa funzionalità in una sessione di checkout, invoca il metodo collectTaxIds
quando crei la sessione:
$checkout = $user->collectTaxIds()->checkout('price_tshirt');
Quando questo metodo viene invocato, ai clienti sarà disponibile una nuova casella di controllo che permette loro di indicare se stanno acquistando come azienda. In tal caso, avranno l’opportunità di fornire il loro numero di Tax ID.
Se hai già configurato la raccolta automatica delle tasse nel service provider della tua applicazione, questa funzionalità sarà abilitata automaticamente e non è necessario invocare il metodo
collectTaxIds
.
Guest Checkout
Usando il metodo Checkout::guest
, puoi avviare sessioni di checkout per gli ospiti della tua applicazione che non hanno un "account":
use Illuminate\Http\Request;
use Laravel\Cashier\Checkout;
Route::get('/product-checkout', function (Request $request) {
return Checkout::guest()->create('price_tshirt', [
'success_url' => route('your-success-route'),
'cancel_url' => route('your-cancel-route'),
]);
});
Analogamente alla creazione di sessioni di checkout per utenti esistenti, puoi utilizzare metodi aggiuntivi disponibili sull’istanza Laravel\Cashier\CheckoutBuilder
per personalizzare la sessione di checkout per gli ospiti:
use Illuminate\Http\Request;
use Laravel\Cashier\Checkout;
Route::get('/product-checkout', function (Request $request) {
return Checkout::guest()
->withPromotionCode('promo-code')
->create('price_tshirt', [
'success_url' => route('your-success-route'),
'cancel_url' => route('your-cancel-route'),
]);
});
Dopo aver completato un checkout come ospite, Stripe può inviare un evento webhook checkout.session.completed
. Assicurati di configurare il tuo webhook Stripe per inviare questo evento alla tua applicazione. Una volta abilitato il webhook nel dashboard di Stripe, puoi gestire il webhook con Cashier. L’oggetto contenuto nel payload del webhook sarà un checkout
object che puoi esaminare per completare l’ordine del tuo cliente.
Gestione dei Pagamenti Falliti
A volte i pagamenti per abbonamenti o addebiti singoli possono fallire. Quando ciò accade, Cashier lancerà un’eccezione Laravel\Cashier\Exceptions\IncompletePayment
che ti informa dell’accaduto. Dopo aver catturato questa eccezione, hai due opzioni su come procedere.
Innanzitutto, potresti reindirizzare il cliente alla pagina dedicata di conferma del pagamento inclusa con Cashier. Questa pagina ha già una route nominata associata registrata tramite il service provider di Cashier. Quindi, puoi catturare l’eccezione IncompletePayment
e reindirizzare l’utente alla pagina di conferma del pagamento:
use Laravel\Cashier\Exceptions\IncompletePayment;
try {
$subscription = $user->newSubscription('default', 'price_monthly')
->create($paymentMethod);
} catch (IncompletePayment $exception) {
return redirect()->route(
'cashier.payment',
[$exception->payment->id, 'redirect' => route('home')]
);
}
Nella pagina di conferma del pagamento, il cliente sarà invitato a inserire nuovamente le informazioni della propria carta di credito e a eseguire eventuali azioni aggiuntive richieste da Stripe, come la conferma "3D Secure". Dopo aver confermato il pagamento, l’utente sarà reindirizzato all’URL fornito dal parametro redirect
specificato sopra. Al momento del reindirizzamento, alle query string saranno aggiunte le variabili message
(stringa) e success
(intero). La pagina di pagamento supporta attualmente i seguenti tipi di metodi di pagamento:
- Carte di Credito
- Alipay
- Bancontact
- BECS Direct Debit
- EPS
- Giropay
- iDEAL
- SEPA Direct Debit
In alternativa, potresti lasciare che Stripe gestisca la conferma del pagamento per te. In questo caso, invece di reindirizzare alla pagina di conferma del pagamento, puoi configurare le email di fatturazione automatica di Stripe nel tuo dashboard di Stripe. Tuttavia, se viene catturata un’eccezione IncompletePayment
, dovresti comunque informare l’utente che riceverà un’email con ulteriori istruzioni per la conferma del pagamento.
Le eccezioni di pagamento possono essere generate per i seguenti metodi: charge
, invoiceFor
e invoice
sui modelli che utilizzano il trait Billable
. Quando si interagisce con gli abbonamenti, il metodo create
sul SubscriptionBuilder
, e i metodi incrementAndInvoice
e swapAndInvoice
sui modelli Subscription
e SubscriptionItem
possono generare eccezioni di pagamento incompleto.
Per determinare se un abbonamento esistente ha un pagamento incompleto, puoi utilizzare il metodo hasIncompletePayment
sul modello billable o su un’istanza di abbonamento:
if ($user->hasIncompletePayment('default')) {
// ...
}
if ($user->subscription('default')->hasIncompletePayment()) {
// ...
}
Puoi determinare lo stato specifico di un pagamento incompleto ispezionando la proprietà payment
sull’istanza dell’eccezione:
use Laravel\Cashier\Exceptions\IncompletePayment;
try {
$user->charge(1000, 'pm_card_threeDSecure2Required');
} catch (IncompletePayment $exception) {
// Ottieni lo stato dell'intento di pagamento...
$exception->payment->status;
// Verifica condizioni specifiche...
if ($exception->payment->requiresPaymentMethod()) {
// ...
} elseif ($exception->payment->requiresConfirmation()) {
// ...
}
}
Conferma dei Pagamenti
Alcuni metodi di pagamento richiedono dati aggiuntivi per confermare i pagamenti. Ad esempio, i metodi di pagamento SEPA richiedono dati aggiuntivi come il "mandato" durante il processo di pagamento. Puoi fornire questi dati a Cashier utilizzando il metodo withPaymentConfirmationOptions
:
$subscription->withPaymentConfirmationOptions([
'mandate_data' => '...',
])->swap('price_xxx');
Puoi consultare la documentazione dell’API Stripe per rivedere tutte le opzioni accettate durante la conferma dei pagamenti.
Strong Customer Authentication
Se la tua azienda o uno dei tuoi clienti si trova in Europa, dovrai rispettare le normative dell’UE sulla Strong Customer Authentication (SCA). Queste regole sono state introdotte nel settembre 2019 dall’Unione Europea per prevenire frodi nei pagamenti. Fortunatamente, Stripe e Cashier sono pronti per creare applicazioni conformi alla SCA.
Prima di iniziare, consulta la guida di Stripe su PSD2 e SCA e la loro documentazione sulle nuove API SCA.
Pagamenti che Richiedono Conferma Aggiuntiva
Le normative SCA spesso richiedono una verifica aggiuntiva per confermare e processare un pagamento. Quando ciò accade, Cashier lancerà un’eccezione Laravel\Cashier\Exceptions\IncompletePayment
che ti informa che è necessaria una verifica extra. Maggiori informazioni su come gestire queste eccezioni possono essere trovate nella documentazione su gestire i pagamenti falliti.
Le schermate di conferma del pagamento presentate da Stripe o Cashier possono essere personalizzate in base al flusso di pagamento di una banca o emittente di carte specifica e possono includere conferma aggiuntiva della carta, un addebito temporaneo di piccolo importo, autenticazione su dispositivo separato o altre forme di verifica.
Stato Incompleto e Scaduto
Quando un pagamento necessita di ulteriore conferma, l’abbonamento rimarrà in uno stato incomplete
o past_due
come indicato dalla colonna del database stripe_status
. Cashier attiverà automaticamente l’abbonamento del cliente non appena la conferma del pagamento sarà completata e la tua applicazione sarà notificata da Stripe tramite webhook della sua conclusione.
Per ulteriori informazioni sugli stati incomplete
e past_due
, consulta la nostra documentazione aggiuntiva su questi stati.
Notifiche di Pagamento Off-Session
Poiché le normative SCA richiedono ai clienti di verificare occasionalmente i propri dettagli di pagamento anche mentre l’abbonamento è attivo, Cashier può inviare una notifica al cliente quando è necessaria la conferma del pagamento off-session. Ad esempio, ciò può verificarsi quando un abbonamento si rinnova. La notifica di pagamento di Cashier può essere attivata impostando la variabile d’ambiente CASHIER_PAYMENT_NOTIFICATION
su una classe di notifica. Per impostazione predefinita, questa notifica è disabilitata. Naturalmente, Cashier include una classe di notifica che puoi utilizzare per questo scopo, ma puoi fornire la tua classe di notifica se lo desideri:
CASHIER_PAYMENT_NOTIFICATION=Laravel\Cashier\Notifications\ConfirmPayment
Per garantire che le notifiche di conferma del pagamento off-session vengano consegnate, verifica che i webhook di Stripe siano configurati per la tua applicazione e che il webhook invoice.payment_action_required
sia abilitato nel tuo dashboard di Stripe. Inoltre, il tuo modello Billable
dovrebbe utilizzare anche il trait Illuminate\Notifications\Notifiable
di Laravel.
Le notifiche verranno inviate anche quando i clienti effettuano manualmente un pagamento che richiede ulteriori conferme. Sfortunatamente, non esiste un modo per Stripe di sapere se il pagamento è stato fatto manualmente o "off-session". Tuttavia, un cliente vedrà semplicemente un messaggio di "Pagamento Effettuato con Successo" se visita la pagina di pagamento dopo aver già confermato il proprio pagamento. Il cliente non potrà accidentalmente confermare lo stesso pagamento due volte e incorrere in un addebito secondario accidentale.
Stripe SDK
Molti oggetti di Cashier sono wrapper attorno agli oggetti dello Stripe SDK. Se vuoi interagire direttamente con gli oggetti Stripe, puoi recuperarli facilmente usando il metodo asStripe
:
$stripeSubscription = $subscription->asStripeSubscription();
$stripeSubscription->application_fee_percent = 5;
$stripeSubscription->save();
Puoi anche utilizzare il metodo updateStripeSubscription
per aggiornare direttamente una sottoscrizione Stripe:
$subscription->updateStripeSubscription(['application_fee_percent' => 5]);
Puoi usare il metodo stripe
sulla classe Cashier
se desideri utilizzare direttamente il client Stripe\StripeClient
. Ad esempio, potresti usare questo metodo per accedere all’istanza di StripeClient
e ottenere una lista di prezzi dal tuo account Stripe:
use Laravel\Cashier\Cashier;
$prices = Cashier::stripe()->prices->all();
Testing
Quando testi un’applicazione che utilizza Cashier, puoi simulare le richieste HTTP effettive all’API di Stripe; tuttavia, questo richiede di riimplementare parzialmente il comportamento di Cashier. Perciò, consigliamo di permettere ai tuoi test di interagire direttamente con l’API di Stripe. Anche se è più lento, ti dà maggiore sicurezza che l’applicazione funzioni come previsto e i test lenti possono essere inseriti nel proprio gruppo di test Pest/PHPUnit.
Durante i test, ricorda che Cashier ha già una ottima suite di test, quindi dovresti concentrarti solo sul testare il flusso di abbonamento e pagamento della tua applicazione e non ogni comportamento sottostante di Cashier.
Per iniziare, aggiungi la versione testing del tuo segreto Stripe al file phpunit.xml
:
<env name="STRIPE_SECRET" value="sk_test_<your-key>"/>
Ora, ogni volta che interagisci con Cashier durante i test, verranno inviate richieste API effettive all’ambiente di testing di Stripe. Per comodità, dovresti precompilare il tuo account di testing Stripe con abbonamenti/prezzi che puoi utilizzare durante i test.
Per testare una varietà di scenari di fatturazione, come rifiuti e fallimenti delle carte di credito, puoi utilizzare l’ampia gamma di numeri di carte di test e token forniti da Stripe.