Laravel Cashier (Stripe)

Вступ

Laravel Cashier Stripe надає виразний, зрозумілий інтерфейс до сервісів підписки на виставлення рахунків Stripe. Він обробляє майже весь шаблонний код для виставлення рахунків за підписку, який ви не хочете писати. Окрім базового управління підписками, Cashier може обробляти купони, зміну підписки, "кількості" підписки, періоди пільгового скасування і навіть генерувати PDF-фактури.

Оновлення Cashier

Коли ви оновлюєтеся до нової версії Cashier, важливо ретельно переглянути посібник з оновлення.

Щоб запобігти змінам, які можуть порушити сумісність, Cashier використовує фіксовану версію Stripe API. Cashier 15 використовує версію Stripe API 2023-10-16. Версія Stripe API буде оновлюватися в незначних релізах, щоб використовувати нові можливості та покращення Stripe.

Встановлення

Спочатку встановіть пакет Cashier для Stripe за допомогою менеджера пакетів компонувальник:

composer require laravel/cashier

Після встановлення пакета опублікуйте міграції Cashier за допомогою команди Artisan vendor:publish:

php artisan vendor:publish --tag="cashier-migrations"

Потім, виконайте міграцію вашої бази даних:

php artisan migrate

Міграції Cashier додадуть кілька стовпців до вашої таблиці users. Вони також створять нову таблицю subscriptions для зберігання всіх підписок ваших клієнтів і таблицю subscription_items для підписок з кількома цінами.

Якщо ви бажаєте, ви також можете опублікувати файл конфігурації Cashier, використовуючи команду Artisan vendor:publish:

php artisan vendor:publish --tag="cashier-config"

Нарешті, щоб Cashier правильно обробляв усі події Stripe, не забудьте налаштувати обробку вебхуків Cashier.

Stripe рекомендує, щоб будь-яка колонка, яка використовується для зберігання ідентифікаторів Stripe, була чутливою до регістру. Тому ви повинні переконатися, що колація колонки stripe_id встановлена на utf8_bin при використанні MySQL. Більше інформації щодо цього можна знайти в документації Stripe.

Конфігурація

Модель Billable

Перш ніж використовувати Cashier, додайте трейд Billable до визначення вашої моделі, що підлягає оплаті. Зазвичай це буде модель App\Models\User. Цей трейд надає різні методи, які дозволяють виконувати загальні завдання з виставлення рахунків, такі як створення підписок, застосування купонів та оновлення інформації про спосіб оплати:

use Laravel\Cashier\Billable;
 
class User extends Authenticatable
{
    use Billable;
}

Cashier передбачає, що ваша модель для виставлення рахунків буде класом App\Models\User, який постачається з Laravel. Якщо ви бажаєте змінити це, ви можете вказати іншу модель за допомогою методу useCustomerModel. Цей метод зазвичай слід викликати в методі boot вашого класу AppServiceProvider:

use App\Models\Cashier\User;
use Laravel\Cashier\Cashier;
 
/**
* Ініціалізувати будь-які сервіси застосунку.
*/
public function boot(): void
{
Cashier::useCustomerModel(User::class);
}

Якщо ви використовуєте модель, відмінну від моделі App\Models\User, наданої Laravel, вам потрібно опублікувати та змінити міграції Cashier, щоб вони відповідали назві таблиці вашої альтернативної моделі.

Ключі API

Далі, вам слід налаштувати ваші ключі API Stripe у файлі .env вашого застосунку. Ви можете отримати ваші ключі API Stripe з панелі керування Stripe:

STRIPE_KEY=your-stripe-key
STRIPE_SECRET=your-stripe-secret
STRIPE_WEBHOOK_SECRET=your-stripe-webhook-secret

Ви повинні переконатися, що змінна середовища STRIPE_WEBHOOK_SECRET визначена у файлі .env вашого застосунку, оскільки ця змінна використовується для забезпечення того, що вхідні вебхуки дійсно надходять від Stripe.

Конфігурація Валюти

Валюта за замовчуванням у Cashier - долари США (USD). Ви можете змінити валюту за замовчуванням, встановивши змінну середовища CASHIER_CURRENCY у файлі .env вашого застосунку:

CASHIER_CURRENCY=eur

Крім налаштування валюти Cashier, ви також можете вказати локаль, яка буде використовуватися при форматуванні грошових значень для відображення на рахунках. Внутрішньо Cashier використовує клас NumberFormatter PHP для встановлення локалі валюти:

CASHIER_CURRENCY_LOCALE=nl_BE

Щоб використовувати локалі, відмінні від en, переконайтеся, що PHP-розширення ext-intl встановлено та налаштовано на вашому сервері.

Конфігурація податків

Дякуючи Stripe Tax, можливо автоматично розраховувати податки для всіх рахунків, створених Stripe. Ви можете увімкнути автоматичний розрахунок податків, викликавши метод calculateTaxes у методі boot класу App\Providers\AppServiceProvider вашого застосунку:

use Laravel\Cashier\Cashier;
 
/**
* Ініціалізувати будь-які сервіси застосунку.
*/
public function boot(): void
{
Cashier::calculateTaxes();
}

Після увімкнення розрахунку податків, будь-які нові підписки та будь-які одноразові рахунки, що генеруються, отримають автоматичний розрахунок податків.

Для того, щоб ця функція працювала належним чином, платіжні дані вашого клієнта, такі як ім'я клієнта, адреса та податковий ідентифікатор, повинні бути синхронізовані з Stripe. Ви можете скористатися методами синхронізації даних клієнта та податкових ідентифікаторів, які пропонує Cashier, щоб досягти цього.

Логування

Cashier дозволяє вказати канал журналу, який буде використовуватися при реєстрації фатальних помилок Stripe. Ви можете вказати канал журналу, визначивши змінну середовища CASHIER_LOGGER у файлі .env вашого застосунку:

CASHIER_LOGGER=stack

Винятки, що генеруються викликами API до Stripe, будуть записані через канал журналу за замовчуванням вашого застосунку.

Використання Користувацьких Моделей

Ви можете розширити моделі, які використовуються внутрішньо Cashier, визначивши власну модель і розширивши відповідну модель Cashier:

use Laravel\Cashier\Subscription as CashierSubscription;
 
class Subscription extends CashierSubscription
{
    // ...
}

Після визначення вашої моделі, ви можете вказати Cashier використовувати вашу користувацьку модель через клас Laravel\Cashier\Cashier. Зазвичай, ви повинні повідомити Cashier про ваші користувацькі моделі в методі boot класу App\Providers\AppServiceProvider вашого застосунку:

use App\Models\Cashier\Subscription;
use App\Models\Cashier\SubscriptionItem;
 
/**
* Ініціалізувати будь-які сервіси застосунку.
*/
public function boot(): void
{
Cashier::useSubscriptionModel(Subscription::class);
Cashier::useSubscriptionItemModel(SubscriptionItem::class);
}

Швидкий старт

Продаж продуктів

Перш ніж використовувати Stripe Checkout, ви повинні визначити Продукти з фіксованими цінами у вашій панелі керування Stripe. Крім того, вам слід налаштувати обробку вебхуків Cashier.

Пропонування виставлення рахунків за продукти та підписки через ваш застосунок може бути лякаючим. Однак, завдяки Cashier та Stripe Checkout, ви можете легко створювати сучасні, надійні інтеграції платежів.

Щоб стягувати плату з клієнтів за одноразові продукти, ми будемо використовувати Cashier для перенаправлення клієнтів до Stripe Checkout, де вони нададуть свої платіжні дані та підтвердять покупку. Після того, як платіж буде здійснено через Checkout, клієнт буде перенаправлений на URL успішного завершення, який ви оберете у вашому застосунку:

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');

Як ви можете бачити у наведеному вище прикладі, ми будемо використовувати наданий Cashier метод checkout для перенаправлення клієнта до Stripe Checkout для заданого "ідентифікатора ціни". При використанні Stripe, "ціни" відносяться до визначених цін для конкретних продуктів.

Якщо необхідно, метод checkout автоматично створить клієнта в Stripe і з'єднає цей запис клієнта Stripe з відповідним користувачем у базі даних вашого застосунку. Після завершення сесії оформлення замовлення клієнт буде перенаправлений на спеціальну сторінку успіху або скасування, де ви можете відобразити інформаційне повідомлення для клієнта.

Надання метаданих для Stripe Checkout

Коли продаєте продукти, зазвичай відстежуєте завершені замовлення та придбані продукти через моделі Cart та Order, визначені вашим власним застосунком. Коли перенаправляєте клієнтів до Stripe Checkout для завершення покупки, можливо, вам потрібно буде надати існуючий ідентифікатор замовлення, щоб ви могли пов'язати завершену покупку з відповідним замовленням, коли клієнт буде перенаправлений назад до вашого застосунку.

Щоб досягти цього, ви можете надати масив metadata методу checkout. Уявімо, що очікуюче Order створюється в нашому застосунку, коли користувач починає процес оформлення замовлення. Пам'ятайте, моделі Cart та Order у цьому прикладі є ілюстративними і не надаються Cashier. Ви вільні реалізувати ці концепції відповідно до потреб вашого власного застосунку:

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');

Як ви можете побачити в наведеному вище прикладі, коли користувач починає процес оформлення замовлення, ми надамо всі пов'язані з кошиком / замовленням ідентифікатори цін Stripe методу checkout. Звичайно, ваш застосунок відповідає за асоціацію цих елементів з "кошиком" або замовленням, коли клієнт додає їх. Ми також надаємо ID замовлення до сесії Stripe Checkout через масив metadata. Нарешті, ми додали змінну шаблону CHECKOUT_SESSION_ID до маршруту успішного оформлення. Коли Stripe перенаправляє клієнтів назад до вашого застосунку, ця змінна шаблону автоматично заповнюється ID сесії Checkout.

Далі, давайте створимо маршрут успішного оформлення замовлення. Це маршрут, на який користувачі будуть перенаправлені після завершення їхньої покупки через Stripe Checkout. У цьому маршруті ми можемо отримати ID сесії Stripe Checkout та пов'язаний екземпляр Stripe Checkout, щоб отримати доступ до наданих нами метаданих і відповідно оновити замовлення нашого клієнта:

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');

Будь ласка, зверніться до документації Stripe для отримання додаткової інформації про дані, що містяться в об'єкті сесії Checkout.

Продаж підписок

Перш ніж використовувати Stripe Checkout, ви повинні визначити Продукти з фіксованими цінами у вашій панелі керування Stripe. Крім того, вам слід налаштувати обробку вебхуків Cashier.

Пропонування виставлення рахунків за продукти та підписки через ваш застосунок може бути лякаючим. Однак, завдяки Cashier та Stripe Checkout, ви можете легко створювати сучасні, надійні інтеграції платежів.

Щоб дізнатися, як продавати підписки за допомогою Cashier та Stripe Checkout, розглянемо простий сценарій сервісу підписки з базовим місячним (price_basic_monthly) та річним (price_basic_yearly) планом. Ці дві ціни можуть бути згруповані під продуктом "Basic" (pro_basic) у нашій панелі керування Stripe. Крім того, наш сервіс підписки може пропонувати план Expert як pro_expert.

Спочатку давайте дізнаємося, як клієнт може підписатися на наші послуги. Звісно, ви можете уявити, що клієнт може натиснути кнопку "підписатися" для базового плану на сторінці цін нашого застосунку. Ця кнопка або посилання повинні перенаправити користувача на маршрут Laravel, який створює сесію Stripe Checkout для обраного ними плану:

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'),
        ]);
});

Як ви можете бачити у наведеному вище прикладі, ми перенаправимо клієнта на сесію Stripe Checkout, яка дозволить їм підписатися на наш базовий план. Після успішного оформлення або скасування, клієнт буде перенаправлений назад на URL, який ми надали методу checkout. Щоб дізнатися, коли їх підписка фактично почалася (оскільки деякі платіжні методи потребують кілька секунд для обробки), нам також потрібно налаштувати обробку вебхуків Cashier.

Тепер, коли клієнти можуть почати підписки, нам потрібно обмежити певні частини нашого застосунку, щоб тільки підписані користувачі могли отримати до них доступ. Звісно, ми завжди можемо визначити поточний статус підписки користувача за допомогою методу subscribed, наданого трейтом Billable від Cashier:

@if ($user->subscribed())
    <p>You are subscribed.</p>
@endif

Ми можемо легко визначити, чи підписаний користувач на конкретний продукт або ціну:

@if ($user->subscribedToProduct('pro_basic'))
    <p>You are subscribed to our Basic product.</p>
@endif
 
@if ($user->subscribedToPrice('price_basic_monthly'))
    <p>You are subscribed to our monthly Basic plan.</p>
@endif

Створення Підписаного Middleware

Для зручності, ви можете створити middleware, яке визначає, чи є вхідний запит від підписаного користувача. Після того, як це middleware було визначено, ви можете легко призначити його маршруту, щоб запобігти доступу до маршруту користувачам, які не підписані:

<?php
 
namespace App\Http\Middleware;
 
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
 
class Subscribed
{
    /**
     * Обробити вхідний запит.
     */
    public function handle(Request $request, Closure $next): Response
    {
        if (! $request->user()?->subscribed()) {
            // Перенаправити користувача на сторінку оплати та попросити його підписатися...
            return redirect('/billing');
        }
 
        return $next($request);
    }
}

Після того як middleware було визначено, ви можете призначити його маршруту:

use App\Http\Middleware\Subscribed;
 
Route::get('/dashboard', function () {
    // ...
})->middleware([Subscribed::class]);

Дозвіл клієнтам керувати своїм тарифним планом

Звичайно, клієнти можуть захотіти змінити свій план підписки на інший продукт або "рівень". Найпростіший спосіб дозволити це — направити клієнтів до Порталу виставлення рахунків для клієнтів від Stripe, який надає розміщений інтерфейс користувача, що дозволяє клієнтам завантажувати рахунки, оновлювати свій платіжний метод і змінювати плани підписки.

Спочатку визначте посилання або кнопку у вашому застосунку, яка направляє користувачів до маршруту Laravel, який ми використаємо для ініціації сесії Порталу виставлення рахунків:

<a href="{{ route('billing') }}">
    Billing
</a>

Далі, давайте визначимо маршрут, який ініціює сесію Порталу виставлення рахунків Stripe для клієнта та перенаправляє користувача до Порталу. Метод redirectToBillingPortal приймає URL-адресу, на яку користувачі повинні бути повернені при виході з Порталу:

use Illuminate\Http\Request;
 
Route::get('/billing', function (Request $request) {
    return $request->user()->redirectToBillingPortal(route('dashboard'));
})->middleware(['auth'])->name('billing');

Якщо ви налаштували обробку вебхуків Cashier, Cashier автоматично підтримуватиме синхронізацію таблиць бази даних вашого застосунку, пов'язаних з Cashier, перевіряючи вхідні вебхуки від Stripe. Наприклад, коли користувач скасовує свою підписку через Портал виставлення рахунків клієнтів Stripe, Cashier отримає відповідний вебхук і позначить підписку як "скасовану" в базі даних вашого застосунку.

Клієнти

Отримання клієнтів

Ви можете отримати клієнта за його Stripe ID, використовуючи метод Cashier::findBillable. Цей метод поверне екземпляр моделі, що підлягає оплаті:

use Laravel\Cashier\Cashier;
 
$user = Cashier::findBillable($stripeId);

Створення Клієнтів

Іноді ви можете захотіти створити клієнта Stripe без початку підписки. Ви можете зробити це за допомогою методу createAsStripeCustomer:

$stripeCustomer = $user->createAsStripeCustomer();

Як тільки клієнта створено в Stripe, ви можете розпочати підписку пізніше. Ви можете надати необов'язковий масив $options, щоб передати будь-які додаткові параметри створення клієнта, які підтримуються API Stripe:

$stripeCustomer = $user->createAsStripeCustomer($options);

Ви можете використовувати метод asStripeCustomer, якщо хочете повернути об'єкт клієнта Stripe для моделі, що підлягає оплаті:

$stripeCustomer = $user->asStripeCustomer();

Метод createOrGetStripeCustomer може бути використаний, якщо ви хочете отримати об'єкт клієнта Stripe для даної моделі, що підлягає оплаті, але не впевнені, чи є ця модель вже клієнтом у Stripe. Цей метод створить нового клієнта в Stripe, якщо такий ще не існує:

$stripeCustomer = $user->createOrGetStripeCustomer();

Оновлення клієнтів

Іноді ви можете захотіти оновити клієнта Stripe безпосередньо з додатковою інформацією. Ви можете зробити це за допомогою методу updateStripeCustomer. Цей метод приймає масив опцій оновлення клієнта, підтримуваних API Stripe:

$stripeCustomer = $user->updateStripeCustomer($options);

Баланс

Stripe дозволяє зараховувати або списувати кошти з "балансу" клієнта. Пізніше цей баланс буде зараховано або списано на нових рахунках. Щоб перевірити загальний баланс клієнта, ви можете використовувати метод balance, доступний у вашій моделі, що підлягає оплаті. Метод balance поверне відформатоване рядкове представлення балансу у валюті клієнта:

$balance = $user->balance();

Щоб зарахувати баланс клієнта, ви можете надати значення методу creditBalance. Якщо бажаєте, ви також можете надати опис:

$user->creditBalance(500, 'Premium customer top-up.');

Надання значення методу debitBalance зменшить баланс клієнта:

$user->debitBalance(300, 'Bad usage penalty.');

Метод applyBalance створить нові транзакції балансу для клієнта. Ви можете отримати ці записи транзакцій за допомогою методу balanceTransactions, що може бути корисним для надання журналу кредитів і дебетів для перегляду клієнтом:

// Отримати всі транзакції...
$transactions = $user->balanceTransactions();
 
foreach ($transactions as $transaction) {
    // Сума транзакції...
    $amount = $transaction->amount(); // $2.31
 
    // Отримати пов'язаний рахунок, якщо доступний...
    $invoice = $transaction->invoice();
}

Ідентифікаційні номери платників податків

Cashier пропонує простий спосіб керування податковими ідентифікаторами клієнта. Наприклад, метод taxIds може бути використаний для отримання всіх податкових ідентифікаторів, які призначені клієнту, у вигляді колекції:

$taxIds = $user->taxIds();

Ви також можете отримати конкретний податковий ідентифікатор для клієнта за його ідентифікатором:

$taxId = $user->findTaxId('txi_belgium');

Ви можете створити новий податковий ідентифікатор, надавши дійсний тип і значення методу createTaxId:

$taxId = $user->createTaxId('eu_vat', 'BE0123456789');

Метод createTaxId негайно додасть ідентифікатор ПДВ до облікового запису клієнта. Перевірка ідентифікаторів ПДВ також здійснюється Stripe; однак, це асинхронний процес. Ви можете отримувати сповіщення про оновлення перевірки, підписавшись на подію вебхука customer.tax_id.updated і перевіряючи параметр verification ідентифікаторів ПДВ. Для отримання додаткової інформації про обробку вебхуків, будь ласка, зверніться до документації щодо визначення обробників вебхуків.

Ви можете видалити податковий ідентифікатор за допомогою методу deleteTaxId:

$user->deleteTaxId('txi_belgium');

Синхронізація даних клієнтів зі Stripe

Зазвичай, коли користувачі вашого застосунку оновлюють своє ім'я, адресу електронної пошти або іншу інформацію, яка також зберігається у Stripe, ви повинні повідомити Stripe про ці оновлення. Таким чином, копія інформації у Stripe буде синхронізована з вашим застосунком.

Щоб автоматизувати це, ви можете визначити слухача подій на вашій моделі, що підлягає оплаті, який реагує на подію updated моделі. Потім, у вашому слухачі подій, ви можете викликати метод syncStripeCustomerDetails на моделі:

use App\Models\User;
use function Illuminate\Events\queueable;
 
/**
 * Метод "booted" моделі.
 */
protected static function booted(): void
{
    static::updated(queueable(function (User $customer) {
        if ($customer->hasStripeId()) {
            $customer->syncStripeCustomerDetails();
        }
    }));
}

Тепер, кожного разу, коли ваша модель клієнта оновлюється, її інформація буде синхронізована з Stripe. Для зручності, Cashier автоматично синхронізує інформацію вашого клієнта з Stripe при початковому створенні клієнта.

Ви можете налаштувати стовпці, які використовуються для синхронізації інформації про клієнтів зі Stripe, перевизначивши різноманітні методи, надані Cashier. Наприклад, ви можете перевизначити метод stripeName, щоб налаштувати атрибут, який слід вважати "іменем" клієнта, коли Cashier синхронізує інформацію про клієнта зі Stripe:

/**
 * Отримайте ім'я клієнта, яке слід синхронізувати зі Stripe.
 */
public function stripeName(): string|null
{
    return $this->company_name;
}

Аналогічно, ви можете перевизначити методи stripeEmail, stripePhone, stripeAddress і stripePreferredLocales. Ці методи синхронізують інформацію з відповідними параметрами клієнта при оновленні об'єкта клієнта Stripe. Якщо ви бажаєте повністю контролювати процес синхронізації інформації про клієнта, ви можете перевизначити метод syncStripeCustomerDetails.

Портал для виставлення рахунків

Stripe пропонує простий спосіб налаштування порталу для виставлення рахунків, щоб ваш клієнт міг керувати своєю підпискою, методами оплати та переглядати свою історію виставлення рахунків. Ви можете перенаправити своїх користувачів до порталу для виставлення рахунків, викликавши метод redirectToBillingPortal на моделі, що підлягає оплаті, з контролера або маршруту:

use Illuminate\Http\Request;
 
Route::get('/billing-portal', function (Request $request) {
    return $request->user()->redirectToBillingPortal();
});

За замовчуванням, коли користувач завершить керування своєю підпискою, він зможе повернутися до маршруту home вашого застосунку через посилання в платіжному порталі Stripe. Ви можете надати користувачу власну URL-адресу, до якої він повинен повернутися, передавши URL-адресу як аргумент методу redirectToBillingPortal:

use Illuminate\Http\Request;
 
Route::get('/billing-portal', function (Request $request) {
    return $request->user()->redirectToBillingPortal(route('billing'));
});

Якщо ви хочете згенерувати URL-адресу до порталу виставлення рахунків без створення HTTP-перенаправлення, ви можете викликати метод billingPortalUrl:

$url = $request->user()->billingPortalUrl(route('billing'));

Методи оплати

Зберігання Способів Оплати

Для того, щоб створювати підписки або виконувати одноразові платежі з Stripe, вам потрібно зберегти платіжний метод і отримати його ідентифікатор з Stripe. Підхід, який використовується для цього, відрізняється в залежності від того, чи плануєте ви використовувати платіжний метод для підписок або одноразових платежів, тому ми розглянемо обидва варіанти нижче.

Методи оплати для підписок

Коли зберігаєте інформацію про кредитну картку клієнта для майбутнього використання підпискою, необхідно використовувати API Stripe "Setup Intents" для безпечного збору деталей платіжного методу клієнта. "Setup Intent" вказує Stripe на намір стягнути платіжний метод клієнта. Трейт Cashier Billable включає метод createSetupIntent для легкого створення нового Setup Intent. Ви повинні викликати цей метод з маршруту або контролера, який буде відображати форму для збору деталей платіжного методу вашого клієнта:

return view('update-payment-method', [
    'intent' => $user->createSetupIntent()
]);

Після того як ви створили Setup Intent і передали його до представлення, ви повинні прикріпити його секрет до елемента, який збиратиме платіжний метод. Наприклад, розгляньте цю форму "оновлення платіжного методу":

<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>

Далі, бібліотека Stripe.js може бути використана для приєднання елемента Stripe до форми та безпечно зібрати платіжні дані клієнта:

<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>

Далі, картка може бути перевірена, і безпечний "ідентифікатор платіжного методу" може бути отриманий від Stripe за допомогою методу Stripe confirmCardSetup:

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) {
        // Відобразити "error.message" користувачу...
    } else {
        // Картку успішно перевірено...
    }
});

Після того, як картка була перевірена за допомогою Stripe, ви можете передати отриманий ідентифікатор setupIntent.payment_method у ваш Laravel застосунок, де його можна прикріпити до клієнта. Спосіб оплати може бути або доданий як новий спосіб оплати, або використаний для оновлення способу оплати за замовчуванням. Ви також можете негайно використати ідентифікатор способу оплати для створення нової підписки.

Якщо ви хочете отримати більше інформації про Setup Intents та збір платіжних даних клієнтів, будь ласка, ознайомтеся з цим оглядом, наданим Stripe.

Методи оплати для одноразових платежів

Звичайно, при здійсненні одноразового стягнення з платіжного методу клієнта, нам потрібно буде використати ідентифікатор платіжного методу лише один раз. Через обмеження Stripe, ви не можете використовувати збережений платіжний метод за замовчуванням клієнта для одноразових стягнень. Ви повинні дозволити клієнту ввести дані свого платіжного методу за допомогою бібліотеки Stripe.js. Наприклад, розгляньте наступну форму:

<input id="card-holder-name" type="text">
 
<!-- Stripe Elements Placeholder -->
<div id="card-element"></div>
 
<button id="card-button">
    Process Payment
</button>

Після визначення такої форми, бібліотека Stripe.js може бути використана для приєднання Stripe Element до форми та безпечно зібрати платіжні дані клієнта:

<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>

Далі, картка може бути перевірена, і безпечний "ідентифікатор платіжного методу" може бути отриманий від Stripe за допомогою методу Stripe createPaymentMethod:

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) {
        // Відобразити "error.message" користувачу...
    } else {
        // Картка успішно перевірена...
    }
});

Якщо картка успішно перевірена, ви можете передати paymentMethod.id до вашого Laravel застосунку і обробити одноразовий платіж.

Отримання Способів Оплати

Метод paymentMethods на екземплярі моделі, що підлягає оплаті, повертає колекцію екземплярів Laravel\Cashier\PaymentMethod:

$paymentMethods = $user->paymentMethods();

За замовчуванням цей метод поверне платіжні методи кожного типу. Щоб отримати платіжні методи конкретного типу, ви можете передати type як аргумент до методу:

$paymentMethods = $user->paymentMethods('sepa_debit');

Щоб отримати метод оплати за замовчуванням клієнта, можна використовувати метод defaultPaymentMethod:

$paymentMethod = $user->defaultPaymentMethod();

Ви можете отримати конкретний спосіб оплати, який прикріплений до моделі, що підлягає оплаті, використовуючи метод findPaymentMethod:

$paymentMethod = $user->findPaymentMethod($paymentMethodId);

Наявність способу оплати

Щоб визначити, чи має модель, що підлягає оплаті, стандартний метод оплати, прикріплений до їхнього облікового запису, викличте метод hasDefaultPaymentMethod:

if ($user->hasDefaultPaymentMethod()) {
    // ...
}

Ви можете використовувати метод hasPaymentMethod, щоб визначити, чи має модель, що підлягає оплаті, принаймні один платіжний метод, прикріплений до їхнього облікового запису:

if ($user->hasPaymentMethod()) {
    // ...
}

Цей метод визначить, чи має модель, що підлягає оплаті, будь-який спосіб оплати взагалі. Щоб визначити, чи існує спосіб оплати конкретного типу для моделі, ви можете передати type як аргумент до методу:

if ($user->hasPaymentMethod('sepa_debit')) {
    // ...
}

Оновлення Способу Оплати за Замовчуванням

Метод updateDefaultPaymentMethod може бути використаний для оновлення інформації про спосіб оплати за замовчуванням клієнта. Цей метод приймає ідентифікатор способу оплати Stripe і призначить новий спосіб оплати як спосіб оплати за замовчуванням для виставлення рахунків:

$user->updateDefaultPaymentMethod($paymentMethod);

Щоб синхронізувати інформацію про ваш метод оплати за замовчуванням з інформацією про метод оплати за замовчуванням клієнта в Stripe, ви можете використовувати метод updateDefaultPaymentMethodFromStripe:

$user->updateDefaultPaymentMethodFromStripe();

Метод оплати за замовчуванням у клієнта може використовуватися лише для виставлення рахунків та створення нових підписок. Через обмеження, накладені Stripe, він не може використовуватися для одноразових платежів.

Додавання методів оплати

Щоб додати новий метод оплати, ви можете викликати метод addPaymentMethod на моделі, що підлягає оплаті, передаючи ідентифікатор методу оплати:

$user->addPaymentMethod($paymentMethod);

Щоб дізнатися, як отримати ідентифікатори платіжних методів, перегляньте документацію зі зберігання платіжних методів.

Видалення Способів Оплати

Щоб видалити платіжний метод, ви можете викликати метод delete на екземплярі Laravel\Cashier\PaymentMethod, який ви бажаєте видалити:

$paymentMethod->delete();

Метод deletePaymentMethod видалить конкретний спосіб оплати з моделі, що підлягає оплаті:

$user->deletePaymentMethod('pm_visa');

Метод deletePaymentMethods видалить всю інформацію про платіжні методи для моделі, що підлягає оплаті:

$user->deletePaymentMethods();

За замовчуванням цей метод видалить платіжні методи всіх типів. Щоб видалити платіжні методи конкретного типу, ви можете передати type як аргумент до методу:

$user->deletePaymentMethods('sepa_debit');

Якщо у користувача є активна підписка, ваш застосунок не повинен дозволяти йому видаляти його метод оплати за замовчуванням.

Підписки

Підписки надають спосіб налаштування регулярних платежів для ваших клієнтів. Підписки Stripe, керовані Cashier, підтримують кілька цін на підписку, кількість підписок, пробні періоди та інше.

Створення Підписок

Щоб створити підписку, спочатку отримайте екземпляр вашої моделі для виставлення рахунків, яка зазвичай буде екземпляром App\Models\User. Після того, як ви отримали екземпляр моделі, ви можете використовувати метод newSubscription для створення підписки моделі:

use Illuminate\Http\Request;
 
Route::post('/user/subscribe', function (Request $request) {
    $request->user()->newSubscription(
        'default', 'price_monthly'
    )->create($request->paymentMethodId);
 
    // ...
});

Перший аргумент, переданий методу newSubscription, повинен бути внутрішнім типом підписки. Якщо ваш застосунок пропонує лише одну підписку, ви можете назвати її default або primary. Цей тип підписки призначений лише для внутрішнього використання в застосунку і не повинен бути показаний користувачам. Крім того, він не повинен містити пробілів і ніколи не повинен змінюватися після створення підписки. Другий аргумент — це конкретна ціна, на яку підписується користувач. Це значення повинно відповідати ідентифікатору ціни в Stripe.

Метод create, який приймає ідентифікатор платіжного методу Stripe або об'єкт Stripe PaymentMethod, розпочне підписку, а також оновить вашу базу даних з ID клієнта Stripe білінгової моделі та іншою відповідною інформацією про оплату.

Передача ідентифікатора платіжного методу безпосередньо в метод create підписки також автоматично додасть його до збережених платіжних методів користувача.

Збір регулярних платежів через електронні листи з рахунками

Замість автоматичного стягнення регулярних платежів з клієнта, ви можете доручити Stripe надсилати рахунок-фактуру клієнту електронною поштою кожного разу, коли настає термін його регулярного платежу. Потім клієнт може вручну оплатити рахунок-фактуру, коли його отримає. Клієнту не потрібно надавати спосіб оплати заздалегідь при стягненні регулярних платежів через рахунки-фактури:

$user->newSubscription('default', 'price_monthly')->createAndSendInvoice();

Кількість часу, протягом якого клієнт має сплатити свій рахунок до того, як його підписка буде скасована, визначається параметром days_until_due. За замовчуванням це 30 днів; однак, ви можете вказати конкретне значення для цього параметра, якщо бажаєте:

$user->newSubscription('default', 'price_monthly')->createAndSendInvoice([], [
    'days_until_due' => 30
]);

Кількості

Якщо ви хочете встановити певну кількість для ціни при створенні підписки, ви повинні викликати метод quantity на будівнику підписки перед створенням підписки:

$user->newSubscription('default', 'price_monthly')
    ->quantity(5)
    ->create($paymentMethod);

Додаткові деталі

Якщо ви хочете вказати додаткові параметри клієнта або підписки, які підтримуються Stripe, ви можете зробити це, передавши їх як другий і третій аргументи методу create:

$user->newSubscription('default', 'price_monthly')->create($paymentMethod, [
    'email' => $email,
], [
    'metadata' => ['note' => 'Some extra information.'],
]);

Купони

Якщо ви хочете застосувати купон при створенні підписки, ви можете використовувати метод withCoupon:

$user->newSubscription('default', 'price_monthly')
    ->withCoupon('code')
    ->create($paymentMethod);

Або, якщо ви хочете застосувати промо-код Stripe, ви можете використовувати метод withPromotionCode:

$user->newSubscription('default', 'price_monthly')
    ->withPromotionCode('promo_code_id')
    ->create($paymentMethod);

Наданий ідентифікатор промо-коду повинен бути ідентифікатором API Stripe, призначеним промо-коду, а не промо-кодом, який бачить клієнт. Якщо вам потрібно знайти ідентифікатор промо-коду на основі наданого промо-коду, який бачить клієнт, ви можете використовувати метод findPromotionCode:

// Знайдіть ID промо-коду за його кодом, що відображається клієнту...
$promotionCode = $user->findPromotionCode('SUMMERSALE');
 
// Знайдіть активний промо-код за його кодом, що відображається клієнту...
$promotionCode = $user->findActivePromotionCode('SUMMERSALE');

У наведеному вище прикладі, повернутий об'єкт $promotionCode є екземпляром Laravel\Cashier\PromotionCode. Цей клас декорує базовий об'єкт Stripe\PromotionCode. Ви можете отримати купон, пов'язаний з промо-кодом, викликавши метод coupon:

$coupon = $user->findPromotionCode('SUMMERSALE')->coupon();

Екземпляр купона дозволяє визначити суму знижки та чи представляє купон фіксовану знижку або знижку у відсотках:

if ($coupon->isPercentage()) {
    return $coupon->percentOff().'%'; // 21.5%
} else {
    return $coupon->amountOff(); // $5.99
}

Ви також можете отримати знижки, які наразі застосовані до клієнта або підписки:

$discount = $billable->discount();
 
$discount = $subscription->discount();

Повернені екземпляри Laravel\Cashier\Discount декорують базовий екземпляр об'єкта Stripe\Discount. Ви можете отримати купон, пов'язаний з цією знижкою, викликавши метод coupon:

$coupon = $subscription->discount()->coupon();

Якщо ви хочете застосувати новий купон або промо-код до клієнта або підписки, ви можете зробити це за допомогою методів applyCoupon або applyPromotionCode:

$billable->applyCoupon('coupon_id');
$billable->applyPromotionCode('promotion_code_id');
 
$subscription->applyCoupon('coupon_id');
$subscription->applyPromotionCode('promotion_code_id');

Пам'ятайте, ви повинні використовувати ID API Stripe, призначений для промо-коду, а не промо-код, який бачить клієнт. Лише один купон або промо-код може бути застосований до клієнта або підписки в будь-який момент часу.

Для отримання додаткової інформації з цього питання, будь ласка, зверніться до документації Stripe щодо купонів та промо-кодів.

Додавання Підписок

Якщо ви хочете додати підписку до клієнта, який вже має метод оплати за замовчуванням, ви можете викликати метод add на будівнику підписки:

use App\Models\User;
 
$user = User::find(1);
 
$user->newSubscription('default', 'price_monthly')->add();

Створення підписок з панелі керування Stripe

Ви також можете створювати підписки безпосередньо з панелі керування Stripe. При цьому Cashier синхронізує нові підписки та призначає їм тип default. Щоб налаштувати тип підписки, який призначається підпискам, створеним у панелі керування, визначте обробники подій вебхуків.

Крім того, ви можете створити лише один тип підписки через панель керування Stripe. Якщо ваш застосунок пропонує кілька підписок, які використовують різні типи, лише один тип підписки може бути доданий через панель керування Stripe.

Нарешті, ви завжди повинні переконатися, що додаєте лише одну активну підписку на кожен тип підписки, запропонованої вашим застосунком. Якщо у клієнта є дві підписки default, Cashier використовуватиме лише найновішу підписку, навіть якщо обидві будуть синхронізовані з базою даних вашого застосунку.

Перевірка Статусу Підписки

Як тільки клієнт підписаний на ваш застосунок, ви можете легко перевірити статус його підписки, використовуючи різноманітні зручні методи. По-перше, метод subscribed повертає true, якщо у клієнта є активна підписка, навіть якщо підписка наразі знаходиться в пробному періоді. Метод subscribed приймає тип підписки як свій перший аргумент:

if ($user->subscribed('default')) {
    // ...
}

Метод subscribed також є чудовим кандидатом для маршрутного middleware, що дозволяє фільтрувати доступ до маршрутів і контролерів на основі статусу підписки користувача:

<?php
 
namespace App\Http\Middleware;
 
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
 
class EnsureUserIsSubscribed
{
    /**
     * Обробити вхідний запит.
     *
     * @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')) {
            // Цей користувач не є платним клієнтом...
            return redirect('/billing');
        }
 
        return $next($request);
    }
}

Якщо ви хочете визначити, чи користувач все ще знаходиться в пробному періоді, ви можете використовувати метод onTrial. Цей метод може бути корисним для визначення, чи слід відобразити попередження користувачу про те, що він все ще знаходиться в пробному періоді:

if ($user->subscription('default')->onTrial()) {
    // ...
}

Метод subscribedToProduct може бути використаний для визначення, чи підписаний користувач на певний продукт на основі ідентифікатора продукту Stripe. У Stripe продукти є колекціями цін. У цьому прикладі ми визначимо, чи підписка користувача default активно підписана на "premium" продукт застосунку. Зазначений ідентифікатор продукту Stripe повинен відповідати одному з ідентифікаторів вашого продукту в панелі керування Stripe:

if ($user->subscribedToProduct('prod_premium', 'default')) {
    // ...
}

Передаючи масив до методу subscribedToProduct, ви можете визначити, чи підписка користувача за замовчуванням активно підписана на "basic" або "premium" продукт застосунку:

if ($user->subscribedToProduct(['prod_basic', 'prod_premium'], 'default')) {
    // ...
}

Метод subscribedToPrice може бути використаний для визначення, чи відповідає підписка клієнта заданому ідентифікатору ціни:

if ($user->subscribedToPrice('price_basic_monthly', 'default')) {
    // ...
}

Метод recurring може бути використаний для визначення, чи користувач наразі підписаний і більше не знаходиться в пробному періоді:

if ($user->subscription('default')->recurring()) {
    // ...
}

Якщо у користувача є дві підписки одного типу, метод subscription завжди поверне найновішу підписку. Наприклад, у користувача можуть бути два записи підписки з типом default; однак, одна з підписок може бути старою, простроченою, тоді як інша є поточною, активною підпискою. Завжди буде повернута найновіша підписка, тоді як старі підписки зберігаються в базі даних для історичного перегляду.

Скасований Статус Підписки

Щоб визначити, чи був користувач колись активним підписником, але скасував свою підписку, ви можете використовувати метод canceled:

if ($user->subscription('default')->canceled()) {
    // ...
}

Ви також можете визначити, чи користувач скасував свою підписку, але все ще перебуває на "пільговому періоді" до повного закінчення підписки. Наприклад, якщо користувач скасовує підписку 5 березня, яка спочатку мала закінчитися 10 березня, користувач перебуває на "пільговому періоді" до 10 березня. Зверніть увагу, що метод subscribed все ще повертає true протягом цього часу:

if ($user->subscription('default')->onGracePeriod()) {
    // ...
}

Щоб визначити, чи користувач скасував свою підписку і більше не перебуває в "пільговому періоді", ви можете використовувати метод ended:

if ($user->subscription('default')->ended()) {
    // ...
}

Незавершений та Прострочений Статус

Якщо підписка вимагає вторинної платіжної дії після створення, підписка буде позначена як incomplete. Статуси підписок зберігаються в стовпці stripe_status таблиці бази даних subscriptions Cashier.

Аналогічно, якщо потрібна вторинна платіжна дія при зміні цін, підписка буде позначена як past_due. Коли ваша підписка знаходиться в будь-якому з цих станів, вона не буде активною, доки клієнт не підтвердить свій платіж. Визначити, чи має підписка неповний платіж, можна за допомогою методу hasIncompletePayment на моделі, що підлягає оплаті, або на екземплярі підписки:

if ($user->hasIncompletePayment('default')) {
    // ...
}
 
if ($user->subscription('default')->hasIncompletePayment()) {
    // ...
}

Коли підписка має неповну оплату, ви повинні направити користувача на сторінку підтвердження оплати Cashier, передаючи ідентифікатор latestPayment. Ви можете використовувати метод latestPayment, доступний на екземплярі підписки, щоб отримати цей ідентифікатор:

<a href="{{ route('cashier.payment', $subscription->latestPayment()->id) }}">
    Please confirm your payment.
</a>

Якщо ви хочете, щоб підписка все ще вважалася активною, коли вона знаходиться в стані past_due або incomplete, ви можете використовувати методи keepPastDueSubscriptionsActive та keepIncompleteSubscriptionsActive, надані Cashier. Зазвичай ці методи слід викликати в методі register вашого App\Providers\AppServiceProvider:

use Laravel\Cashier\Cashier;
 
/**
 * Зареєструйте будь-які сервіси застосунку.
 */
public function register(): void
{
    Cashier::keepPastDueSubscriptionsActive();
    Cashier::keepIncompleteSubscriptionsActive();
}

Коли підписка знаходиться в стані incomplete, її не можна змінити, поки платіж не буде підтверджено. Тому методи swap та updateQuantity викличуть виняток, коли підписка знаходиться в стані incomplete.

Області підписки

Більшість станів підписки також доступні як області запиту, щоб ви могли легко виконувати запити до вашої бази даних для підписок, які знаходяться в заданому стані:

// Отримати всі активні підписки...
$subscriptions = Subscription::query()->active()->get();
 
// Отримати всі скасовані підписки для користувача...
$subscriptions = $user->subscriptions()->canceled()->get();

Повний список доступних областей наведено нижче:

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();

Зміна Цін

Після того як клієнт підписався на ваш застосунок, він може іноді захотіти змінити ціну підписки. Щоб змінити ціну підписки клієнта, передайте ідентифікатор ціни Stripe методу swap. При зміні цін передбачається, що користувач хоче повторно активувати свою підписку, якщо вона була раніше скасована. Зазначений ідентифікатор ціни повинен відповідати ідентифікатору ціни Stripe, доступному в панелі керування Stripe:

use App\Models\User;
 
$user = App\Models\User::find(1);
 
$user->subscription('default')->swap('price_yearly');

Якщо клієнт перебуває на пробному періоді, цей пробний період буде збережено. Крім того, якщо для підписки існує "кількість", ця кількість також буде збережена.

Якщо ви хочете змінити ціни та скасувати будь-який пробний період, на якому зараз знаходиться клієнт, ви можете викликати метод skipTrial:

$user->subscription('default')
    ->skipTrial()
    ->swap('price_yearly');

Якщо ви хочете змінити ціни та негайно виставити рахунок клієнту, замість того щоб чекати на їхній наступний білінговий цикл, ви можете використовувати метод swapAndInvoice:

$user = User::find(1);
 
$user->subscription('default')->swapAndInvoice('price_yearly');

Пропорційні розрахунки

За замовчуванням, Stripe здійснює пропорційний розрахунок при зміні цін. Метод noProrate може бути використаний для оновлення ціни підписки без пропорційного розрахунку:

$user->subscription('default')->noProrate()->swap('price_yearly');

Для отримання додаткової інформації про пропорційний розрахунок підписок зверніться до документації Stripe.

Виконання методу noProrate перед методом swapAndInvoice не матиме жодного впливу на пропорційний розрахунок. Рахунок завжди буде виставлено.

Кількість підписок

Іноді підписки залежать від "кількості". Наприклад, застосунок для управління проектами може стягувати $10 на місяць за проект. Ви можете використовувати методи incrementQuantity та decrementQuantity для легкого збільшення або зменшення кількості вашої підписки:

use App\Models\User;
 
$user = User::find(1);
 
$user->subscription('default')->incrementQuantity();
 
// Додайте п'ять до поточної кількості підписки...
$user->subscription('default')->incrementQuantity(5);
 
$user->subscription('default')->decrementQuantity();
 
// Відніміть п'ять від поточної кількості підписки...
$user->subscription('default')->decrementQuantity(5);

Альтернативно, ви можете встановити конкретну кількість, використовуючи метод updateQuantity:

$user->subscription('default')->updateQuantity(10);

Метод noProrate може бути використаний для оновлення кількості підписки без пропорційного розрахунку платежів:

$user->subscription('default')->noProrate()->updateQuantity(10);

Для отримання додаткової інформації про кількість підписок зверніться до документації Stripe.

Кількості для підписок з кількома продуктами

Якщо ваша підписка є підпискою з декількома продуктами, ви повинні передати ID ціни, кількість якої ви бажаєте збільшити або зменшити, як другий аргумент до методів increment / decrement:

$user->subscription('default')->incrementQuantity(1, 'price_chat');

Підписки з декількома продуктами

Підписка з кількома продуктами дозволяє призначати кілька платіжних продуктів до однієї підписки. Наприклад, уявіть, що ви створюєте "helpdesk" застосунок для обслуговування клієнтів, який має базову ціну підписки $10 на місяць, але пропонує додатковий продукт живого чату за додаткові $15 на місяць. Інформація про підписки з кількома продуктами зберігається в таблиці бази даних Cashier subscription_items.

Ви можете вказати декілька продуктів для даної підписки, передавши масив цін як другий аргумент методу newSubscription:

use Illuminate\Http\Request;
 
Route::post('/user/subscribe', function (Request $request) {
    $request->user()->newSubscription('default', [
        'price_monthly',
        'price_chat',
    ])->create($request->paymentMethodId);
 
    // ...
});

У наведеному вище прикладі клієнт матиме дві ціни, прикріплені до їхньої підписки default. Обидві ціни будуть стягуватися за їхніми відповідними інтервалами виставлення рахунків. За потреби, ви можете використовувати метод quantity, щоб вказати конкретну кількість для кожної ціни:

$user = User::find(1);
 
$user->newSubscription('default', ['price_monthly', 'price_chat'])
    ->quantity(5, 'price_chat')
    ->create($paymentMethod);

Якщо ви хочете додати іншу ціну до існуючої підписки, ви можете викликати метод підписки addPrice:

$user = User::find(1);
 
$user->subscription('default')->addPrice('price_chat');

Приклад вище додасть нову ціну, і клієнт буде виставлений рахунок за неї в наступному платіжному циклі. Якщо ви хочете виставити рахунок клієнту негайно, ви можете використовувати метод addPriceAndInvoice:

$user->subscription('default')->addPriceAndInvoice('price_chat');

Якщо ви хочете додати ціну з певною кількістю, ви можете передати кількість як другий аргумент методів addPrice або addPriceAndInvoice:

$user = User::find(1);
 
$user->subscription('default')->addPrice('price_chat', 5);

Ви можете видалити ціни з підписок, використовуючи метод removePrice:

$user->subscription('default')->removePrice('price_chat');

Ви не можете видалити останню ціну підписки. Натомість вам слід просто скасувати підписку.

Заміна Цін

Ви також можете змінити ціни, прикріплені до підписки з декількома продуктами. Наприклад, уявіть, що у клієнта є підписка price_basic з додатковим продуктом price_chat, і ви хочете оновити клієнта з ціни price_basic до ціни price_pro:

use App\Models\User;
 
$user = User::find(1);
 
$user->subscription('default')->swap(['price_pro', 'price_chat']);

Коли виконується наведений вище приклад, основний елемент підписки з price_basic видаляється, а той, що з price_chat, зберігається. Крім того, створюється новий елемент підписки для price_pro.

Ви також можете вказати параметри елементів підписки, передаючи масив пар ключ / значення в метод swap. Наприклад, вам може знадобитися вказати кількість цін підписки:

$user = User::find(1);
 
$user->subscription('default')->swap([
    'price_pro' => ['quantity' => 5],
    'price_chat'
]);

Якщо ви хочете замінити одну ціну в підписці, ви можете зробити це за допомогою методу swap безпосередньо на елементі підписки. Цей підхід особливо корисний, якщо ви хочете зберегти всі існуючі метадані інших цін підписки:

$user = User::find(1);
 
$user->subscription('default')
    ->findItemOrFail('price_basic')
    ->swap('price_pro');

Пропорціонування

За замовчуванням, Stripe буде пропорційно розподіляти платежі при додаванні або видаленні цін з підписки з декількома продуктами. Якщо ви хочете зробити коригування ціни без пропорційного розподілу, ви повинні приєднати метод noProrate до вашої операції з ціною:

$user->subscription('default')->noProrate()->removePrice('price_chat');

Кількості

Якщо ви хочете оновити кількість для окремих цін підписки, ви можете зробити це, використовуючи існуючі методи кількості, передаючи ID ціни як додатковий аргумент до методу:

$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');

Коли підписка має декілька цін, атрибути stripe_price та quantity у моделі Subscription будуть null. Щоб отримати доступ до окремих атрибутів ціни, слід використовувати зв'язок items, доступний у моделі Subscription.

Елементи підписки

Коли підписка має декілька цін, вона матиме декілька "елементів" підписки, збережених у таблиці subscription_items вашої бази даних. Ви можете отримати доступ до них через відношення items у підписці:

use App\Models\User;
 
$user = User::find(1);
 
$subscriptionItem = $user->subscription('default')->items->first();
 
// Отримайте ціну Stripe та кількість для конкретного товару...
$stripePrice = $subscriptionItem->stripe_price;
$quantity = $subscriptionItem->quantity;

Ви також можете отримати конкретну ціну, використовуючи метод findItemOrFail:

$user = User::find(1);
 
$subscriptionItem = $user->subscription('default')->findItemOrFail('price_chat');

Кілька підписок

Stripe дозволяє вашим клієнтам мати кілька підписок одночасно. Наприклад, ви можете керувати спортзалом, який пропонує підписку на плавання та підписку на важку атлетику, і кожна підписка може мати різну ціну. Звичайно, клієнти повинні мати можливість підписатися на один або обидва плани.

Коли ваш застосунок створює підписки, ви можете вказати тип підписки в методі newSubscription. Тип може бути будь-яким рядком, що представляє тип підписки, яку користувач ініціює:

use Illuminate\Http\Request;
 
Route::post('/swimming/subscribe', function (Request $request) {
    $request->user()->newSubscription('swimming')
        ->price('price_swimming_monthly')
        ->create($request->paymentMethodId);
 
    // ...
});

У цьому прикладі ми ініціювали щомісячну підписку на плавання для клієнта. Однак, вони можуть захотіти перейти на річну підписку пізніше. При налаштуванні підписки клієнта, ми можемо просто змінити ціну на підписці swimming:

$user->subscription('swimming')->swap('price_swimming_yearly');

Звичайно, ви також можете повністю скасувати підписку:

$user->subscription('swimming')->cancel();

Виставлення рахунків на основі використання

Білінг на основі використання дозволяє стягувати плату з клієнтів на основі їх використання продукту протягом білінгового циклу. Наприклад, ви можете стягувати плату з клієнтів на основі кількості текстових повідомлень або електронних листів, які вони надсилають щомісяця.

Щоб почати використовувати білінг на основі використання, спочатку потрібно створити новий продукт у вашій панелі керування Stripe з моделлю білінгу на основі використання та лічильником. Після створення лічильника збережіть пов'язану назву події та ID лічильника, які вам знадобляться для звітування та отримання даних про використання. Потім використовуйте метод meteredPrice, щоб додати ID ціни з лічильником до підписки клієнта:

use Illuminate\Http\Request;
 
Route::post('/user/subscribe', function (Request $request) {
    $request->user()->newSubscription('default')
        ->meteredPrice('price_metered')
        ->create($request->paymentMethodId);
 
    // ...
});

Ви також можете розпочати підписку з оплатою за використання через Stripe Checkout:

$checkout = Auth::user()
    ->newSubscription('default', [])
    ->meteredPrice('price_metered')
    ->checkout();
 
return view('your-checkout-view', [
    'checkout' => $checkout,
]);

Звітність про використання

Коли ваш клієнт використовує ваш застосунок, ви будете повідомляти про їх використання до Stripe, щоб вони могли бути правильно виставлені рахунки. Щоб повідомити про використання події з лічильником, ви можете використовувати метод reportMeterEvent у вашій моделі Billable:

$user = User::find(1);
 
$user->reportMeterEvent('emails-sent');

За замовчуванням до розрахункового періоду додається "кількість використання" 1. Альтернативно, ви можете передати конкретну кількість "використання", щоб додати до використання клієнта за розрахунковий період:

$user = User::find(1);
 
$user->reportMeterEvent('emails-sent', quantity: 15);

Щоб отримати підсумок подій клієнта для лічильника, ви можете використовувати метод meterEventSummaries екземпляра Billable:

$user = User::find(1);
 
$meterUsage = $user->meterEventSummaries($meterId);
 
$meterUsage->first()->aggregated_value // 10

Будь ласка, зверніться до документації об'єкта Meter Event Summary від Stripe для отримання додаткової інформації про підсумки подій лічильника.

Щоб перелічити всі лічильники, ви можете використовувати метод meters екземпляра Billable:

$user = User::find(1);
 
$user->meters();

Податки на підписку

Замість ручного розрахунку податкових ставок, ви можете автоматично розраховувати податки за допомогою Stripe Tax

Щоб вказати податкові ставки, які користувач сплачує за підписку, ви повинні реалізувати метод taxRates у вашій моделі, що підлягає оплаті, і повернути масив, що містить ідентифікатори податкових ставок Stripe. Ви можете визначити ці податкові ставки у вашій панелі керування Stripe:

/**
 * Ставки податків, які повинні застосовуватися до підписок клієнта.
 *
 * @return array<int, string>
 */
public function taxRates(): array
{
    return ['txr_id'];
}

Метод taxRates дозволяє застосовувати податкову ставку на основі кожного окремого клієнта, що може бути корисним для бази користувачів, яка охоплює кілька країн і податкових ставок.

Якщо ви пропонуєте підписки з декількома продуктами, ви можете визначити різні податкові ставки для кожної ціни, реалізувавши метод priceTaxRates у вашій моделі, що підлягає оплаті:

/**
 * Ставки податків, які повинні застосовуватися до підписок клієнта.
 *
 * @return array<string, array<int, string>>
 */
public function priceTaxRates(): array
{
    return [
        'price_monthly' => ['txr_id'],
    ];
}

Метод taxRates застосовується лише до підписок. Якщо ви використовуєте Cashier для здійснення "одноразових" платежів, вам потрібно буде вручну вказати ставку податку в цей момент.

Синхронізація Податкових Ставок

Коли змінюються жорстко закодовані ідентифікатори податкових ставок, що повертаються методом taxRates, податкові налаштування для будь-яких існуючих підписок користувача залишаться незмінними. Якщо ви бажаєте оновити значення податку для існуючих підписок з новими значеннями taxRates, вам слід викликати метод syncTaxRates на екземплярі підписки користувача:

$user->subscription('default')->syncTaxRates();

Це також синхронізує будь-які податкові ставки для підписки з декількома продуктами. Якщо ваш застосунок пропонує підписки з декількома продуктами, ви повинні переконатися, що ваша модель, яка може бути виставлена рахунком, реалізує метод priceTaxRates обговорений вище.

Звільнення від податків

Cashier також пропонує методи isNotTaxExempt, isTaxExempt та reverseChargeApplies для визначення, чи звільнений клієнт від податків. Ці методи викликатимуть API Stripe для визначення статусу податкового звільнення клієнта:

use App\Models\User;
 
$user = User::find(1);
 
$user->isTaxExempt();
$user->isNotTaxExempt();
$user->reverseChargeApplies();

Ці методи також доступні для будь-якого об'єкта Laravel\Cashier\Invoice. Однак, коли вони викликаються на об'єкті Invoice, методи визначатимуть статус звільнення на момент створення рахунку.

Дата прив'язки підписки

За замовчуванням, точкою відліку платіжного циклу є дата створення підписки або, якщо використовується пробний період, дата закінчення пробного періоду. Якщо ви хочете змінити дату відліку платіжного циклу, ви можете використовувати метод 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);
 
    // ...
});

Для отримання додаткової інформації про управління циклами виставлення рахунків за підписку, зверніться до документації з циклу виставлення рахунків Stripe

Скасування підписок

Щоб скасувати підписку, викличте метод cancel на підписці користувача:

$user->subscription('default')->cancel();

Коли підписка скасована, Cashier автоматично встановить стовпець ends_at у вашій таблиці бази даних subscriptions. Цей стовпець використовується, щоб знати, коли метод subscribed повинен почати повертати false.

Наприклад, якщо клієнт скасовує підписку 1 березня, але підписка не повинна була закінчитися до 5 березня, метод subscribed продовжуватиме повертати true до 5 березня. Це робиться тому, що користувачеві зазвичай дозволяється продовжувати використовувати застосунок до кінця їхнього платіжного циклу.

Ви можете визначити, чи користувач скасував свою підписку, але все ще перебуває в "пільговому періоді", використовуючи метод onGracePeriod:

if ($user->subscription('default')->onGracePeriod()) {
    // ...
}

Якщо ви бажаєте негайно скасувати підписку, викличте метод cancelNow на підписці користувача:

$user->subscription('default')->cancelNow();

Якщо ви бажаєте негайно скасувати підписку та виставити рахунок за будь-яке невиставлене за метрикою використання або нові/очікуючі нарахування, викличте метод cancelNowAndInvoice для підписки користувача:

$user->subscription('default')->cancelNowAndInvoice();

Ви також можете вибрати скасування підписки в конкретний момент часу:

$user->subscription('default')->cancelAt(
    now()->addDays(10)
);

Нарешті, ви завжди повинні скасувати підписки користувача перед видаленням пов'язаної моделі користувача:

$user->subscription('default')->cancelNow();
 
$user->delete();

Відновлення підписок

Якщо клієнт скасував свою підписку і ви бажаєте її відновити, ви можете викликати метод resume на підписці. Клієнт повинен все ще бути в межах свого "пільгового періоду", щоб відновити підписку:

$user->subscription('default')->resume();

Якщо клієнт скасовує підписку, а потім поновлює її до того, як підписка повністю закінчиться, клієнт не буде виставлений рахунок негайно. Замість цього, їх підписка буде повторно активована, і рахунок буде виставлений за оригінальним циклом виставлення рахунків.

Пробні Періоди Підписки

З попереднім вибором способу оплати

Якщо ви хочете запропонувати пробні періоди вашим клієнтам, при цьому збираючи інформацію про платіжний метод заздалегідь, ви повинні використовувати метод trialDays при створенні ваших підписок:

use Illuminate\Http\Request;
 
Route::post('/user/subscribe', function (Request $request) {
    $request->user()->newSubscription('default', 'price_monthly')
        ->trialDays(10)
        ->create($request->paymentMethodId);
 
    // ...
});

Цей метод встановить дату закінчення пробного періоду в записі підписки в базі даних і вкаже Stripe не починати виставлення рахунків клієнту до цієї дати. При використанні методу trialDays, Cashier перезапише будь-який стандартний пробний період, налаштований для ціни в Stripe.

Якщо підписка клієнта не буде скасована до дати закінчення пробного періоду, з нього буде стягнуто плату, як тільки пробний період закінчиться, тому ви повинні переконатися, що повідомили своїх користувачів про дату закінчення їхнього пробного періоду.

Метод trialUntil дозволяє вам надати екземпляр DateTime, який визначає, коли має закінчитися пробний період:

use Carbon\Carbon;
 
$user->newSubscription('default', 'price_monthly')
    ->trialUntil(Carbon::now()->addDays(10))
    ->create($paymentMethod);

Ви можете визначити, чи знаходиться користувач у пробному періоді, використовуючи метод onTrial екземпляра користувача або метод onTrial екземпляра підписки. Два приклади нижче є еквівалентними:

if ($user->onTrial('default')) {
    // ...
}
 
if ($user->subscription('default')->onTrial()) {
    // ...
}

Ви можете використовувати метод endTrial, щоб негайно завершити пробний період підписки:

$user->subscription('default')->endTrial();

Щоб визначити, чи закінчився існуючий пробний період, ви можете використовувати методи hasExpiredTrial:

if ($user->hasExpiredTrial('default')) {
    // ...
}
 
if ($user->subscription('default')->hasExpiredTrial()) {
    // ...
}

Визначення Днів Пробного Періоду в Stripe / Cashier

Ви можете вибрати, скільки днів пробного періоду отримують ваші ціни в панелі керування Stripe, або завжди передавати їх явно, використовуючи Cashier. Якщо ви вирішите визначити дні пробного періоду для ваших цін у Stripe, слід знати, що нові підписки, включаючи нові підписки для клієнта, який мав підписку в минулому, завжди отримуватимуть пробний період, якщо ви явно не викличете метод skipTrial().

Без Попереднього Введення Способу Оплати

Якщо ви хочете запропонувати пробні періоди без збору інформації про платіжний метод користувача заздалегідь, ви можете встановити стовпець trial_ends_at у записі користувача на бажану дату закінчення пробного періоду. Це зазвичай робиться під час реєстрації користувача:

use App\Models\User;
 
$user = User::create([
    // ...
    'trial_ends_at' => now()->addDays(10),
]);

Обов'язково додайте перетворення дати для атрибута trial_ends_at у визначенні класу вашої моделі, що підлягає оплаті.

Cashier називає цей тип пробного періоду "загальним пробним періодом", оскільки він не прив'язаний до жодної існуючої підписки. Метод onTrial на екземплярі моделі, що підлягає оплаті, поверне true, якщо поточна дата не перевищує значення trial_ends_at:

if ($user->onTrial()) {
    // Користувач знаходиться в межах пробного періоду...
}

Як тільки ви готові створити фактичну підписку для користувача, ви можете використовувати метод newSubscription як зазвичай:

$user = User::find(1);
 
$user->newSubscription('default', 'price_monthly')->create($paymentMethod);

Щоб отримати дату закінчення пробного періоду користувача, ви можете використовувати метод trialEndsAt. Цей метод поверне екземпляр дати Carbon, якщо користувач знаходиться на пробному періоді, або null, якщо ні. Ви також можете передати необов'язковий параметр типу підписки, якщо ви хочете отримати дату закінчення пробного періоду для конкретної підписки, відмінної від стандартної:

if ($user->onTrial()) {
    $trialEndsAt = $user->trialEndsAt('main');
}

Ви також можете використовувати метод onGenericTrial, якщо хочете дізнатися, що користувач знаходиться в своєму "загальному" пробному періоді і ще не створив фактичну підписку:

if ($user->onGenericTrial()) {
    // Користувач знаходиться в періоді "загального" пробного використання...
}

Розширення пробних періодів

Метод extendTrial дозволяє продовжити пробний період підписки після того, як підписка була створена. Якщо пробний період вже закінчився і клієнт вже оплачує підписку, ви все одно можете запропонувати їм продовжений пробний період. Час, проведений у пробному періоді, буде вирахувано з наступного рахунку клієнта:

use App\Models\User;
 
$subscription = User::find(1)->subscription('default');
 
// Завершити пробний період через 7 днів...
$subscription->extendTrial(
    now()->addDays(7)
);
 
// Додайте додаткові 5 днів до пробного періоду...
$subscription->extendTrial(
    $subscription->trial_ends_at->addDays(5)
);

Обробка Stripe Webhooks

Ви можете використовувати Stripe CLI, щоб допомогти тестувати вебхуки під час локальної розробки.

Stripe може повідомляти ваш застосунок про різноманітні події через вебхуки. За замовчуванням, маршрут, який вказує на контролер вебхуків Cashier, автоматично реєструється сервіс-провайдером Cashier. Цей контролер буде обробляти всі вхідні запити вебхуків.

За замовчуванням контролер вебхуків Cashier автоматично оброблятиме скасування підписок, які мають занадто багато невдалих стягнень (як визначено у ваших налаштуваннях Stripe), оновлення клієнтів, видалення клієнтів, оновлення підписок та зміни способу оплати; однак, як ми незабаром дізнаємося, ви можете розширити цей контролер для обробки будь-якої події вебхука Stripe, яка вам подобається.

Щоб переконатися, що ваш застосунок може обробляти вебхуки Stripe, обов'язково налаштуйте URL вебхука в панелі керування Stripe. За замовчуванням контролер вебхуків Cashier відповідає на шлях URL /stripe/webhook. Повний список усіх вебхуків, які ви повинні увімкнути в панелі керування 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

Для зручності, Cashier включає команду Artisan cashier:webhook. Ця команда створить вебхук у Stripe, який прослуховує всі події, необхідні для Cashier:

php artisan cashier:webhook

За замовчуванням створений вебхук буде вказувати на URL, визначений змінною середовища APP_URL і маршрутом cashier.webhook, який включений у Cashier. Ви можете надати опцію --url при виклику команди, якщо хочете використовувати інший URL:

php artisan cashier:webhook --url "https://example.com/stripe/webhook"

Вебхук, який створюється, використовуватиме версію API Stripe, сумісну з вашою версією Cashier. Якщо ви хочете використовувати іншу версію Stripe, ви можете вказати опцію --api-version:

php artisan cashier:webhook --api-version="2019-12-03"

Після створення вебхук буде одразу активним. Якщо ви бажаєте створити вебхук, але залишити його вимкненим, поки ви не будете готові, ви можете вказати опцію --disabled при виклику команди:

php artisan cashier:webhook --disabled

Переконайтеся, що ви захищаєте вхідні запити Stripe webhook за допомогою включеного в Cashier перевірки підпису webhook middleware.

Вебхуки та захист від CSRF

Оскільки вебхуки Stripe повинні обходити CSRF-захист Laravel, ви повинні переконатися, що Laravel не намагається перевірити CSRF-токен для вхідних вебхуків Stripe. Щоб досягти цього, ви повинні виключити stripe/* з CSRF-захисту у файлі bootstrap/app.php вашого застосунку:

->withMiddleware(function (Middleware $middleware) {
    $middleware->validateCsrfTokens(except: [
        'stripe/*',
    ]);
})

Визначення Обробників Подій Webhook

Cashier автоматично обробляє скасування підписок для невдалих платежів та інших загальних подій вебхуків Stripe. Однак, якщо у вас є додаткові події вебхуків, які ви хотіли б обробити, ви можете зробити це, прослуховуючи наступні події, які відправляються Cashier:

  • Laravel\Cashier\Events\WebhookReceived
  • Laravel\Cashier\Events\WebhookHandled

Обидві події містять повний вміст Stripe webhook. Наприклад, якщо ви бажаєте обробити webhook invoice.payment_succeeded, ви можете зареєструвати слухача, який буде обробляти цю подію:

<?php
 
namespace App\Listeners;
 
use Laravel\Cashier\Events\WebhookReceived;
 
class StripeEventListener
{
    /**
     * Обробка отриманих Stripe вебхуків.
     */
    public function handle(WebhookReceived $event): void
    {
        if ($event->payload['type'] === 'invoice.payment_succeeded') {
            // Обробити вхідну подію...
        }
    }
}

Перевірка підписів вебхуків

Щоб захистити ваші вебхуки, ви можете використовувати підписи вебхуків Stripe. Для зручності, Cashier автоматично включає middleware, яке перевіряє, що вхідний запит вебхука Stripe є дійсним.

Щоб увімкнути перевірку вебхука, переконайтеся, що змінна середовища STRIPE_WEBHOOK_SECRET встановлена у файлі .env вашого застосунку. secret вебхука можна отримати з панелі керування вашого облікового запису Stripe.

Одиночні стягнення

Простий платіж

Якщо ви хочете здійснити одноразове стягнення з клієнта, ви можете використовувати метод charge на екземплярі моделі, що підлягає оплаті. Вам потрібно надати ідентифікатор платіжного методу як другий аргумент до методу charge:

use Illuminate\Http\Request;
 
Route::post('/purchase', function (Request $request) {
    $stripeCharge = $request->user()->charge(
        100, $request->paymentMethodId
    );
 
    // ...
});

Метод charge приймає масив як третій аргумент, дозволяючи передавати будь-які параметри, які ви бажаєте, для створення платежу через Stripe. Більше інформації про доступні параметри при створенні платежів можна знайти в документації Stripe:

$user->charge(100, $paymentMethod, [
    'custom_option' => $value,
]);

Ви також можете використовувати метод charge без базового клієнта або користувача. Щоб це зробити, викличте метод charge на новому екземплярі білінгової моделі вашого застосунку:

use App\Models\User;
 
$stripeCharge = (new User)->charge(100, $paymentMethod);

Метод charge викине виняток, якщо стягнення не вдасться. Якщо стягнення успішне, з методу буде повернено екземпляр Laravel\Cashier\Payment:

try {
    $payment = $user->charge(100, $paymentMethod);
} catch (Exception $e) {
    // ...
}

Метод charge приймає суму платежу в найменшому знаменнику валюти, що використовується вашим застосунком. Наприклад, якщо клієнти платять у доларах США, суми повинні бути вказані в центах.

Стягнення з рахунком-фактурою

Іноді вам може знадобитися здійснити одноразовий платіж і запропонувати PDF-рахунок вашому клієнту. Метод invoicePrice дозволяє зробити саме це. Наприклад, давайте виставимо рахунок клієнту за п'ять нових сорочок:

$user->invoicePrice('price_tshirt', 5);

Рахунок буде негайно списаний з основного способу оплати користувача. Метод invoicePrice також приймає масив як третій аргумент. Цей масив містить параметри виставлення рахунку для елемента рахунку. Четвертий аргумент, який приймає метод, також є масивом, який повинен містити параметри виставлення рахунку для самого рахунку:

$user->invoicePrice('price_tshirt', 5, [
    'discounts' => [
        ['coupon' => 'SUMMER21SALE']
    ],
], [
    'default_tax_rates' => ['txr_id'],
]);

Подібно до invoicePrice, ви можете використовувати метод tabPrice для створення одноразового стягнення за декілька товарів (до 250 товарів на рахунок) шляхом додавання їх до "рахунку" клієнта, а потім виставлення рахунку клієнту. Наприклад, ми можемо виставити рахунок клієнту за п'ять сорочок і дві кружки:

$user->tabPrice('price_tshirt', 5);
$user->tabPrice('price_mug', 2);
$user->invoice();

Альтернативно, ви можете використовувати метод invoiceFor для здійснення "одноразового" стягнення з використанням стандартного платіжного методу клієнта:

$user->invoiceFor('One Time Fee', 500);

Хоча метод invoiceFor доступний для використання, рекомендується використовувати методи invoicePrice та tabPrice з попередньо визначеними цінами. Таким чином, ви матимете доступ до кращої аналітики та даних у вашій панелі керування Stripe щодо ваших продажів на основі кожного продукту.

Методи invoice, invoicePrice та invoiceFor створять рахунок-фактуру Stripe, який повторно спробує здійснити невдалі спроби виставлення рахунку. Якщо ви не хочете, щоб рахунки-фактури повторно намагалися стягнути невдалі платежі, вам потрібно закрити їх за допомогою API Stripe після першої невдалої спроби стягнення.

Створення Платіжних Намірів

Ви можете створити новий платіжний намір Stripe, викликавши метод pay на екземплярі моделі, що підлягає оплаті. Виклик цього методу створить платіжний намір, який буде обгорнуто в екземпляр Laravel\Cashier\Payment:

use Illuminate\Http\Request;
 
Route::post('/pay', function (Request $request) {
    $payment = $request->user()->pay(
        $request->get('amount')
    );
 
    return $payment->client_secret;
});

Після створення платіжного наміру, ви можете повернути секрет клієнта на фронтенд вашого застосунку, щоб користувач міг завершити платіж у своєму браузері. Щоб дізнатися більше про створення повних платіжних потоків за допомогою платіжних намірів Stripe, будь ласка, зверніться до документації Stripe.

Коли ви використовуєте метод pay, стандартні методи оплати, які увімкнені у вашій панелі керування Stripe, будуть доступні для клієнта. Альтернативно, якщо ви хочете дозволити використовувати лише деякі конкретні методи оплати, ви можете використовувати метод payWith:

use Illuminate\Http\Request;
 
Route::post('/pay', function (Request $request) {
    $payment = $request->user()->payWith(
        $request->get('amount'), ['card', 'bancontact']
    );
 
    return $payment->client_secret;
});

Методи pay та payWith приймають суму платежу в найменшому знаменнику валюти, що використовується вашим застосунком. Наприклад, якщо клієнти платять у доларах США, суми повинні бути вказані в центах.

Повернення коштів

Якщо вам потрібно повернути платіж Stripe, ви можете використовувати метод refund. Цей метод приймає ідентифікатор платіжного наміру Stripe як свій перший аргумент:

$payment = $user->charge(100, $paymentMethodId);
 
$user->refund($payment->id);

Рахунки

Отримання рахунків

Ви можете легко отримати масив рахунків моделі, що підлягає оплаті, використовуючи метод invoices. Метод invoices повертає колекцію екземплярів Laravel\Cashier\Invoice:

$invoices = $user->invoices();

Якщо ви хочете включити неоплачені рахунки у результати, ви можете використати метод invoicesIncludingPending:

$invoices = $user->invoicesIncludingPending();

Ви можете використовувати метод findInvoice для отримання конкретного рахунку за його ID:

$invoice = $user->findInvoice($invoiceId);

Відображення інформації про рахунок-фактуру

Коли ви перераховуєте рахунки для клієнта, ви можете використовувати методи рахунку для відображення відповідної інформації про рахунок. Наприклад, ви можете захотіти перерахувати кожен рахунок у таблиці, дозволяючи користувачу легко завантажити будь-який з них:

<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>

Майбутні рахунки-фактури

Щоб отримати майбутній рахунок для клієнта, ви можете використовувати метод upcomingInvoice:

$invoice = $user->upcomingInvoice();

Аналогічно, якщо у клієнта є кілька підписок, ви також можете отримати майбутній рахунок для конкретної підписки:

$invoice = $user->subscription('default')->upcomingInvoice();

Попередній перегляд рахунків за підписку

Використовуючи метод previewInvoice, ви можете переглянути рахунок-фактуру перед внесенням змін у ціну. Це дозволить вам визначити, як виглядатиме рахунок-фактура вашого клієнта після внесення певної зміни в ціну:

$invoice = $user->subscription('default')->previewInvoice('price_yearly');

Ви можете передати масив цін до методу previewInvoice, щоб переглянути рахунки з кількома новими цінами:

$invoice = $user->subscription('default')->previewInvoice(['price_yearly', 'price_metered']);

Генерація PDF рахунків-фактур

Перш ніж генерувати PDF-файли рахунків, ви повинні використовувати компонувальник для встановлення бібліотеки Dompdf, яка є стандартним рендерером рахунків для Cashier:

composer require dompdf/dompdf

З маршруту або контролера ви можете використовувати метод downloadInvoice для створення завантаження PDF певного рахунку. Цей метод автоматично згенерує відповідь HTTP, необхідну для завантаження рахунку:

use Illuminate\Http\Request;
 
Route::get('/user/invoice/{invoice}', function (Request $request, string $invoiceId) {
    return $request->user()->downloadInvoice($invoiceId);
});

За замовчуванням всі дані на рахунку-фактурі отримуються з даних клієнта та рахунку, збережених у Stripe. Ім'я файлу базується на значенні конфігурації app.name. Однак, ви можете налаштувати деякі з цих даних, надавши масив як другий аргумент методу downloadInvoice. Цей масив дозволяє налаштувати інформацію, таку як деталі вашої компанії та продукту:

return $request->user()->downloadInvoice($invoiceId, [
    'vendor' => 'Your Company',
    'product' => 'Your Product',
    'street' => 'Main Str. 1',
    'location' => '2000 Antwerp, Belgium',
    'phone' => '+32 499 00 00 00',
    'email' => 'example@example.com',
    'url' => 'https://example.com',
    'vendorVat' => 'BE123456789',
]);

Метод downloadInvoice також дозволяє використовувати власне ім'я файлу через свій третій аргумент. Це ім'я файлу автоматично буде доповнено суфіксом .pdf:

return $request->user()->downloadInvoice($invoiceId, [], 'my-invoice');

Спеціальний Рендерер Рахунків

Cashier також дозволяє використовувати власний рендерер рахунків. За замовчуванням Cashier використовує реалізацію DompdfInvoiceRenderer, яка використовує PHP-бібліотеку dompdf для створення рахунків Cashier. Однак, ви можете використовувати будь-який рендерер, який забажаєте, реалізувавши інтерфейс Laravel\Cashier\Contracts\InvoiceRenderer. Наприклад, ви можете захотіти створити PDF рахунку за допомогою API-запиту до стороннього сервісу рендерингу PDF:

use Illuminate\Support\Facades\Http;
use Laravel\Cashier\Contracts\InvoiceRenderer;
use Laravel\Cashier\Invoice;
 
class ApiInvoiceRenderer implements InvoiceRenderer
{
    /**
     * Відобразити наданий рахунок-фактуру та повернути необроблені байти PDF.
     */
    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();
    }
}

Після того як ви реалізували контракт рендерера рахунків, вам слід оновити значення конфігурації cashier.invoices.renderer у файлі конфігурації config/cashier.php вашого застосунку. Це значення конфігурації має бути встановлено на ім'я класу вашої власної реалізації рендерера.

Оформлення замовлення

Cashier Stripe також підтримує Stripe Checkout. Stripe Checkout позбавляє від необхідності створювати власні сторінки для прийому платежів, надаючи попередньо створену, розміщену сторінку оплати.

Наступна документація містить інформацію про те, як почати використовувати Stripe Checkout з Cashier. Щоб дізнатися більше про Stripe Checkout, вам також слід розглянути можливість перегляду власної документації Stripe про Checkout.

Оформлення замовлень продуктів

Ви можете виконати оформлення замовлення для існуючого продукту, який був створений у вашій панелі керування Stripe, використовуючи метод checkout на моделі, що підлягає оплаті. Метод checkout ініціює нову сесію Stripe Checkout. За замовчуванням, ви повинні передати Stripe Price ID:

use Illuminate\Http\Request;
 
Route::get('/product-checkout', function (Request $request) {
    return $request->user()->checkout('price_tshirt');
});

Якщо потрібно, ви також можете вказати кількість продукту:

use Illuminate\Http\Request;
 
Route::get('/product-checkout', function (Request $request) {
    return $request->user()->checkout(['price_tshirt' => 15]);
});

Коли клієнт відвідує цей маршрут, його буде перенаправлено на сторінку оформлення замовлення Stripe. За замовчуванням, коли користувач успішно завершує або скасовує покупку, його буде перенаправлено на місце розташування вашого маршруту home, але ви можете вказати власні URL-адреси зворотного виклику, використовуючи параметри success_url та 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'),
    ]);
});

Коли ви визначаєте опцію оформлення success_url, ви можете вказати Stripe додати ідентифікатор сесії оформлення як параметр рядка запиту при виклику вашого URL. Для цього додайте буквальний рядок {CHECKOUT_SESSION_ID} до рядка запиту вашого success_url. Stripe замінить цей заповнювач фактичним ідентифікатором сесії оформлення:

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');

Коди промоакцій

За замовчуванням, Stripe Checkout не дозволяє промокоди, які можуть бути використані користувачами. На щастя, є простий спосіб увімкнути їх для вашої сторінки Checkout. Для цього ви можете викликати метод allowPromotionCodes:

use Illuminate\Http\Request;
 
Route::get('/product-checkout', function (Request $request) {
    return $request->user()
        ->allowPromotionCodes()
        ->checkout('price_tshirt');
});

Оформлення одноразового платежу

Ви також можете виконати простий платіж за разовий продукт, який не був створений у вашій панелі керування Stripe. Для цього ви можете використовувати метод checkoutCharge на моделі, що підлягає оплаті, і передати йому суму для оплати, назву продукту та необов'язкову кількість. Коли клієнт відвідає цей маршрут, його буде перенаправлено на сторінку Checkout у Stripe:

use Illuminate\Http\Request;
 
Route::get('/charge-checkout', function (Request $request) {
    return $request->user()->checkoutCharge(1200, 'T-Shirt', 5);
});

Коли ви використовуєте метод checkoutCharge, Stripe завжди створюватиме новий продукт і ціну у вашій панелі керування Stripe. Тому ми рекомендуємо створювати продукти заздалегідь у вашій панелі керування Stripe і використовувати метод checkout замість цього.

Оформлення підписок

Використання Stripe Checkout для підписок вимагає увімкнення вебхука customer.subscription.created у вашій панелі керування Stripe. Цей вебхук створить запис підписки у вашій базі даних і збереже всі відповідні елементи підписки.

Ви також можете використовувати Stripe Checkout для ініціації підписок. Після визначення вашої підписки за допомогою методів побудови підписок Cashier, ви можете викликати метод checkout. Коли клієнт відвідує цей маршрут, він буде перенаправлений на сторінку Checkout Stripe:

use Illuminate\Http\Request;
 
Route::get('/subscription-checkout', function (Request $request) {
    return $request->user()
        ->newSubscription('default', 'price_monthly')
        ->checkout();
});

Так само, як і з оформленням замовлень, ви можете налаштувати URL-адреси успіху та скасування:

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'),
        ]);
});

Звичайно, ви також можете увімкнути промо-коди для оформлення підписки:

use Illuminate\Http\Request;
 
Route::get('/subscription-checkout', function (Request $request) {
    return $request->user()
        ->newSubscription('default', 'price_monthly')
        ->allowPromotionCodes()
        ->checkout();
});

На жаль, Stripe Checkout не підтримує всі параметри виставлення рахунків за підписку при початку підписок. Використання методу anchorBillingCycleOn на конструкторі підписки, встановлення поведінки пропорційності або встановлення поведінки оплати не матиме жодного ефекту під час сесій Stripe Checkout. Будь ласка, зверніться до документації API сесій Stripe Checkout, щоб переглянути, які параметри доступні.

Stripe Checkout і Пробні Періоди

Звичайно, ви можете визначити пробний період при створенні підписки, яка буде завершена за допомогою Stripe Checkout:

$checkout = Auth::user()->newSubscription('default', 'price_monthly')
    ->trialDays(3)
    ->checkout();

Однак, пробний період повинен тривати щонайменше 48 годин, що є мінімальною кількістю часу для пробного періоду, підтримуваною Stripe Checkout.

Підписки та Webhooks

Пам'ятайте, Stripe і Cashier оновлюють статуси підписок через вебхуки, тому існує ймовірність, що підписка може ще не бути активною, коли клієнт повертається до застосунку після введення платіжної інформації. Щоб обробити цей сценарій, ви можете відобразити повідомлення, яке інформує користувача, що його платіж або підписка очікує на обробку.

Збір податкових ідентифікаторів

Checkout також підтримує збір податкового ідентифікатора клієнта. Щоб увімкнути це в сесії оформлення замовлення, викличте метод collectTaxIds при створенні сесії:

$checkout = $user->collectTaxIds()->checkout('price_tshirt');

Коли цей метод викликається, клієнту буде доступний новий прапорець, який дозволяє вказати, чи здійснюється покупка як компанія. Якщо так, вони матимуть можливість надати свій податковий ідентифікаційний номер.

Якщо ви вже налаштували автоматичний збір податків у сервіс-провайдері вашого застосунку, тоді ця функція буде увімкнена автоматично, і немає потреби викликати метод collectTaxIds.

Гостьові покупки

Використовуючи метод Checkout::guest, ви можете ініціювати сесії оформлення замовлення для гостей вашого застосунку, які не мають "акаунта":

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'),
    ]);
});

Аналогічно до створення сесій оформлення замовлення для існуючих користувачів, ви можете використовувати додаткові методи, доступні в екземплярі Laravel\Cashier\CheckoutBuilder, щоб налаштувати сесію оформлення замовлення для гостей:

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'),
        ]);
});

Після завершення гостьової покупки, Stripe може відправити подію вебхука checkout.session.completed, тому переконайтеся, що ви налаштували свій вебхук Stripe для фактичної відправки цієї події до вашого застосунку. Після того, як вебхук було увімкнено в панелі керування Stripe, ви можете обробити вебхук за допомогою Cashier. Об'єкт, що міститься в навантаженні вебхука, буде об'єктом checkout, який ви можете перевірити, щоб виконати замовлення вашого клієнта.

Обробка невдалих платежів

Іноді платежі за підписки або одноразові стягнення можуть не вдаватись. Коли це трапляється, Cashier викине виняток Laravel\Cashier\Exceptions\IncompletePayment, який повідомляє вас про це. Після перехоплення цього винятку у вас є два варіанти, як діяти далі.

First, you could redirect your customer to the dedicated payment confirmation page which is included with Cashier. This page already has an associated named route that is registered via Cashier's Сервіс-провайдер. So, you may catch the IncompletePayment exception and redirect the user to the payment confirmation page:

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')]
    );
}

На сторінці підтвердження оплати клієнту буде запропоновано знову ввести інформацію про кредитну картку та виконати будь-які додаткові дії, які вимагає Stripe, такі як підтвердження "3D Secure". Після підтвердження оплати користувач буде перенаправлений на URL-адресу, вказану параметром redirect, зазначеним вище. Після перенаправлення до URL-адреси будуть додані змінні рядка запиту message (рядок) та success (ціле число). Сторінка оплати наразі підтримує такі типи платіжних методів:

  • Кредитні картки
  • Alipay
  • Bancontact
  • BECS Direct Debit
  • EPS
  • Giropay
  • iDEAL
  • SEPA Direct Debit

Альтернативно, ви можете дозволити Stripe обробляти підтвердження платежу за вас. У цьому випадку, замість перенаправлення на сторінку підтвердження платежу, ви можете налаштувати автоматичні електронні листи для виставлення рахунків у Stripe у вашій панелі керування Stripe. Однак, якщо буде перехоплено виняток IncompletePayment, ви все одно повинні повідомити користувача, що він отримає електронний лист з подальшими інструкціями щодо підтвердження платежу.

Винятки оплати можуть бути викликані для наступних методів: charge, invoiceFor і invoice на моделях, які використовують трейд Billable. При взаємодії з підписками, метод create на SubscriptionBuilder, а також методи incrementAndInvoice і swapAndInvoice на моделях Subscription і SubscriptionItem можуть викликати винятки неповної оплати.

Визначення, чи має існуюча підписка незавершений платіж, може бути здійснено за допомогою методу hasIncompletePayment на моделі, що підлягає оплаті, або на екземплярі підписки:

if ($user->hasIncompletePayment('default')) {
    // ...
}
 
if ($user->subscription('default')->hasIncompletePayment()) {
    // ...
}

Ви можете визначити конкретний статус незавершеного платежу, перевіривши властивість payment у екземплярі винятку:

use Laravel\Cashier\Exceptions\IncompletePayment;
 
try {
    $user->charge(1000, 'pm_card_threeDSecure2Required');
} catch (IncompletePayment $exception) {
    // Отримати статус наміру платежу...
    $exception->payment->status;
 
    // Перевірте конкретні умови...
    if ($exception->payment->requiresPaymentMethod()) {
        // ...
    } elseif ($exception->payment->requiresConfirmation()) {
        // ...
    }
}

Підтвердження платежів

Деякі методи оплати вимагають додаткових даних для підтвердження платежів. Наприклад, методи оплати SEPA вимагають додаткових даних "mandate" під час процесу оплати. Ви можете надати ці дані Cashier, використовуючи метод withPaymentConfirmationOptions:

$subscription->withPaymentConfirmationOptions([
    'mandate_data' => '...',
])->swap('price_xxx');

Ви можете звернутися до документації Stripe API, щоб переглянути всі параметри, які приймаються при підтвердженні платежів.

Сильна автентифікація клієнта

Якщо ваш бізнес або один з ваших клієнтів базується в Європі, вам потрібно дотримуватися регламентів ЄС щодо сильної автентифікації клієнтів (SCA). Ці регламенти були введені у вересні 2019 року Європейським Союзом для запобігання шахрайству з платежами. На щастя, Stripe і Cashier готові до створення застосунків, що відповідають вимогам SCA.

Перш ніж почати, перегляньте посібник Stripe щодо PSD2 та SCA, а також їх документацію щодо нових SCA API.

Платежі, що вимагають додаткового підтвердження

Регламенти SCA часто вимагають додаткової перевірки для підтвердження та обробки платежу. Коли це відбувається, Cashier викине виняток Laravel\Cashier\Exceptions\IncompletePayment, який інформує вас про те, що потрібна додаткова перевірка. Більше інформації про те, як обробляти ці винятки, можна знайти в документації на сторінці обробка невдалих платежів.

Екрани підтвердження платежу, представлені Stripe або Cashier, можуть бути адаптовані до платіжного процесу конкретного банку або емітента картки і можуть включати додаткове підтвердження картки, тимчасове невелике стягнення, автентифікацію на окремому пристрої або інші форми перевірки.

Незавершений та Прострочений Стан

Коли платіж потребує додаткового підтвердження, підписка залишатиметься в стані incomplete або past_due, як зазначено в стовпці бази даних stripe_status. Cashier автоматично активує підписку клієнта, як тільки підтвердження платежу буде завершено, і ваш застосунок буде повідомлено про це Stripe через webhook.

Для отримання додаткової інформації про стани incomplete та past_due, будь ласка, зверніться до нашої додаткової документації щодо цих станів.

Сповіщення про платежі поза сесією

Оскільки правила SCA вимагають від клієнтів періодично перевіряти свої платіжні дані навіть під час активної підписки, Cashier може надіслати сповіщення клієнту, коли потрібне підтвердження платежу поза сесією. Наприклад, це може статися, коли підписка поновлюється. Сповіщення про платіж Cashier можна увімкнути, встановивши змінну середовища CASHIER_PAYMENT_NOTIFICATION на клас сповіщення. За замовчуванням це сповіщення вимкнено. Звичайно, Cashier включає клас сповіщення, який ви можете використовувати для цієї мети, але ви можете надати свій власний клас сповіщення, якщо бажаєте:

CASHIER_PAYMENT_NOTIFICATION=Laravel\Cashier\Notifications\ConfirmPayment

Щоб гарантувати доставку сповіщень про підтвердження платежу поза сесією, переконайтеся, що вебхуки Stripe налаштовані для вашого застосунку і вебхук invoice.payment_action_required увімкнено у вашій панелі керування Stripe. Крім того, ваша модель Billable повинна також використовувати трейд Illuminate\Notifications\Notifiable Laravel.

Сповіщення будуть надіслані навіть тоді, коли клієнти вручну здійснюють платіж, що вимагає додаткового підтвердження. На жаль, немає способу для Stripe дізнатися, що платіж був здійснений вручну або "поза сесією". Але клієнт просто побачить повідомлення "Платіж успішний", якщо відвідає сторінку платежу після вже підтвердженого платежу. Клієнту не буде дозволено випадково підтвердити той самий платіж двічі та отримати випадкове друге стягнення.

Stripe SDK

Багато об'єктів Cashier є обгортками навколо об'єктів Stripe SDK. Якщо ви хочете взаємодіяти з об'єктами Stripe безпосередньо, ви можете зручно отримати їх, використовуючи метод asStripe:

$stripeSubscription = $subscription->asStripeSubscription();
 
$stripeSubscription->application_fee_percent = 5;
 
$stripeSubscription->save();

Ви також можете використовувати метод updateStripeSubscription для безпосереднього оновлення підписки Stripe:

$subscription->updateStripeSubscription(['application_fee_percent' => 5]);

Ви можете викликати метод stripe на класі Cashier, якщо ви хочете використовувати клієнт Stripe\StripeClient безпосередньо. Наприклад, ви можете використовувати цей метод, щоб отримати доступ до екземпляра StripeClient і отримати список цін з вашого облікового запису Stripe:

use Laravel\Cashier\Cashier;
 
$prices = Cashier::stripe()->prices->all();

Тестування

Коли тестуєте застосунок, що використовує Cashier, ви можете імітувати фактичні HTTP-запити до Stripe API; однак це вимагає часткового повторного впровадження власної поведінки Cashier. Тому ми рекомендуємо дозволити вашим тестам звертатися до фактичного Stripe API. Хоча це повільніше, це забезпечує більше впевненості в тому, що ваш застосунок працює як очікується, і будь-які повільні тести можуть бути розміщені в окремій групі тестування Pest / PHPUnit.

Коли тестуєте, пам'ятайте, що Cashier вже має чудовий набір тестів, тому вам слід зосередитися лише на тестуванні підписки та платіжного процесу вашого власного застосунку, а не на кожній поведінці Cashier.

Щоб розпочати, додайте тестову версію вашого Stripe секрету до вашого файлу phpunit.xml:

<env name="STRIPE_SECRET" value="sk_test_<your-key>"/>

Тепер, коли ви взаємодієте з Cashier під час тестування, він буде надсилати фактичні API-запити до вашого тестового середовища Stripe. Для зручності, ви повинні попередньо заповнити свій тестовий обліковий запис Stripe підписками / цінами, які ви можете використовувати під час тестування.

Для тестування різноманітних сценаріїв виставлення рахунків, таких як відмови та збої кредитних карток, ви можете скористатися широким спектром тестових номерів карток і токенів, наданих Stripe.