{{TOC}} {{DOCVER 5.3=c06d6a2352ed8c767633aab9c20f2bf7d880c967 28.01.2017 5:00:51, 5.2=6b0b057ae6de3c88cb29188459e38383c622ec23 8.12.2016 23:00:15, 5.1=cdc24ba7426c5b11eb4d050706bd78c3ea4913cc 19.06.2016 20:08:01, 5.0=5d10040a981deee82c0fde0e8e5d2ffc49eaaecb 8.02.2016 18:09:11}} == Введение == Laravel Cashier (!!(tl_note) кассир - //прим. пер.//!!) обеспечивает выразительный и гибкий интерфейс для сервисов биллинговых подписок ((https://stripe.com Stripe)) и ((https://www.braintreepayments.com Braintree)). Он сам создаст практически весь шаблонный код биллинговых подписок, который вы боитесь писать. В дополнение к основному управлению подписками Cashier может работать с купонами, заменой подписок, "величинами" подписок, отменой льготного периода, и даже генерировать PDF-файлы счетов. .(alert) Если вы обрабатываете только разовые платежи и не предлагаете людям подписки, вам не стоит использовать Cashier. Используйте SDK Stripe и Braintree напрямую. == Настройка == === Stripe === **Composer** Сначала добавьте пакет Cashier для Stripe в свой файл %%(t)composer.json%% и выполните команду %%(sh)composer update%%: * %%(t)"laravel/cashier": "~7.0"%% %%(DOCNEW 5.2=6b0b057ae6de3c88cb29188459e38383c622ec23 8.12.2016 23:00:15, 5.1=cdc24ba7426c5b11eb4d050706bd78c3ea4913cc 19.06.2016 20:08:01, 5.0=5d10040a981deee82c0fde0e8e5d2ffc49eaaecb 8.02.2016 18:09:11) Для ранних версий: * %%(t)"laravel/cashier": "~6.0"%% - для Laravel 5.2 * %%(t)"laravel/cashier": "~5.0"%% - для Stripe SDK ~2.0 и версии Stripe APIs от 2015-02-18 и выше * %%(t)"laravel/cashier": "~4.0"%% - для версии Stripe APIs от 2015-02-18 и выше * %%(t)"laravel/cashier": "~3.0"%% - для версии Stripe APIs от 2015-02-16 включительно и выше %% **Поставщик услуг** Затем зарегистрируйте ((/docs/v5/providers сервис-провайдер)) %%(t)Laravel\Cashier\CashierServiceProvider%% в вашем файле настроек %%(t)config/app%%. **Миграции базы данных** Перед тем, как начать использовать Cashier, надо ((//docs/v5/migrations подготовить нашу БД)). %%(DOCNEW 5.3=c06d6a2352ed8c767633aab9c20f2bf7d880c967 28.01.2017 5:00:51, 5.2=6b0b057ae6de3c88cb29188459e38383c622ec23 8.12.2016 23:00:15) Надо добавить несколько столбцов в таблицу %%(t)users%% и создать новую таблицу %%(t)subscriptions%% для хранения всех подписок пользователей: ~%% Schema::table('users', function ($table) { $table->string('stripe_id')->nullable(); $table->string('card_brand')->nullable(); $table->string('card_last_four')->nullable(); $table->timestamp('trial_ends_at')->nullable(); }); Schema::create('subscriptions', function ($table) { $table->increments('id'); $table->integer('user_id'); $table->string('name'); $table->string('stripe_id'); $table->string('stripe_plan'); $table->integer('quantity'); $table->timestamp('trial_ends_at')->nullable(); $table->timestamp('ends_at')->nullable(); $table->timestamps(); }); ~%% %% %%(DOCNEW 5.1=cdc24ba7426c5b11eb4d050706bd78c3ea4913cc 19.06.2016 20:08:01, 5.0=5d10040a981deee82c0fde0e8e5d2ffc49eaaecb 8.02.2016 18:09:11) Не волнуйтесь, вы можете использовать Artisan-команду %%(sh)cashier:table%% для создания миграции, которая добавит необходимые столбцы. Например, чтобы добавить столбец в таблицу пользователей, используйте %%(sh)php artisan cashier:table users%%. %% После создания миграции выполните команду %%(sh)migrate%%. **Модель Billable** %%(DOCNEW 5.3=c06d6a2352ed8c767633aab9c20f2bf7d880c967 28.01.2017 5:00:51, 5.2=6b0b057ae6de3c88cb29188459e38383c622ec23 8.12.2016 23:00:15) Далее добавьте типаж %%(t)Billable%% в определение вашей модели. Этот типаж предоставляет различные методы для выполнения основных задач по оплате, таких как создание подписок, применение купонов, обновление информации о банковской карте: ~%% use Laravel\Cashier\Billable; class User extends Authenticatable { use Billable; } ~%% **Ключи API** Наконец, надо настроить ключ Stripe в файле настроек %%(t)services.php%%. Получить свои ключи Stripe API можно в панели управления Stripe: ~%% 'stripe' => [ 'model' => App\User::class, 'secret' => env('STRIPE_SECRET'), ], ~%% %% %%(DOCNEW 5.1=cdc24ba7426c5b11eb4d050706bd78c3ea4913cc 19.06.2016 20:08:01, 5.0=5d10040a981deee82c0fde0e8e5d2ffc49eaaecb 8.02.2016 18:09:11) Далее добавьте типаж %%(t)Billable%% и соответствующие преобразователи даты в определение вашей модели: ~%% use Laravel\Cashier\Billable; use Laravel\Cashier\Contracts\Billable as BillableContract; class User extends Model implements BillableContract { use Billable; protected $dates = ['trial_ends_at', 'subscription_ends_at']; } ~%% Добавление столбцов в свойство модели %%$dates%% даёт Eloquent команду вернуть столбцы в виде экземпляров Carbon/DateTime вместо "сырых" строк. **Stripe-ключ** Наконец, внесите ваш Stripe-ключ в конфигурационный файл %%(t)services.php%%: ~%% 'stripe' => [ 'model' => 'User', 'secret' => env('STRIPE_API_SECRET'), ], ~%% %% %%(DOCNEW 5.3=c06d6a2352ed8c767633aab9c20f2bf7d880c967 28.01.2017 5:00:51, 5.2=6b0b057ae6de3c88cb29188459e38383c622ec23 8.12.2016 23:00:15) === Braintree === **Преимущества и недостатки Braintree** Для многих операций реализация функций Cashier в Stripe и Braintree одинакова. Оба сервиса предоставляют возможность оплаты подписок банковскими картами, но Braintree также поддерживает оплату через PayPal. Однако, в Braintree нет некоторых возможностей, имеющихся в Stripe. При выборе между ними учитывайте следующее: * Braintree поддерживает PayPal, а Stripe нет. * Braintree не поддерживает методы %%increment%% и %%decrement%% для подписок. Это ограничение Braintree, а не Cashier. * Braintree не поддерживает скидки в процентах. Это ограничение Braintree, а не Cashier. **Composer** Сначала добавьте пакет Cashier для Braintree в ваш файл %%(t)composer.json%% и выполните команду %%(sh)composer update%%: %%(sh) "laravel/cashier-braintree": "~2.0" ~%% **Сервис-провайдер** Далее зарегистрируйте ((//docs/v5/providers сервис-провайдер)) %%(t)Laravel\Cashier\CashierServiceProvider%% в файле настроек %%(t)config/app%%. **Купон на скидку** Перед использованием Cashier с Braintree вам надо определить скидку для //плана оплаты// в панели настроек Braintree. Эта скидка будет использоваться для пропорционального пересчёта подписок, которые переходят с годовой на ежемесячную оплату, или наоборот с ежемесячной на годовую. Настраиваемый в панели настроек Braintree размер скидки может быть любым, на ваше усмотрение, а Cashier будет просто изменять размер по умолчанию на заданный при каждом применении купона. Этот купон необходим из-за того, что Braintree изначально не поддерживает пропорциональный пересчёт подписок для каждого выставления счёта. **Миграции базы данных** Перед использованием Cashier нам надо ((//docs/v5/migrations подготовить базу данных)). Надо добавить несколько столбцов в таблицу %%(t)users%% и создать новую таблицу %%(t)subscriptions%% для хранения всех подписок пользователей: ~%% Schema::table('users', function ($table) { $table->string('braintree_id')->nullable(); $table->string('paypal_email')->nullable(); $table->string('card_brand')->nullable(); $table->string('card_last_four')->nullable(); $table->timestamp('trial_ends_at')->nullable(); }); Schema::create('subscriptions', function ($table) { $table->increments('id'); $table->integer('user_id'); $table->string('name'); $table->string('braintree_id'); $table->string('braintree_plan'); $table->integer('quantity'); $table->timestamp('trial_ends_at')->nullable(); $table->timestamp('ends_at')->nullable(); $table->timestamps(); }); ~%% После создания миграций просто выполните Artisan-команду %%(sh)migrate%%. **Модель Billable** Далее добавьте типаж %%(t)Billable%% в определение вашей модели: ~%% use Laravel\Cashier\Billable; class User extends Authenticatable { use Billable; } ~%% **Ключи API** Далее надо настроить следующие параметры в файле настроек %%(t)services.php%%: ~%% 'braintree' => [ 'model' => App\User::class, 'environment' => env('BRAINTREE_ENV'), 'merchant_id' => env('BRAINTREE_MERCHANT_ID'), 'public_key' => env('BRAINTREE_PUBLIC_KEY'), 'private_key' => env('BRAINTREE_PRIVATE_KEY'), ], ~%% Затем надо добавить следующие вызовы Braintree SDK в метод %%boot()%% вашего сервис провайдера %%(t)AppServiceProvider%%: ~%% \Braintree_Configuration::environment(config('services.braintree.environment')); \Braintree_Configuration::merchantId(config('services.braintree.merchant_id')); \Braintree_Configuration::publicKey(config('services.braintree.public_key')); \Braintree_Configuration::privateKey(config('services.braintree.private_key')); ~%% Для версии 5.2: ~%% \Braintree_Configuration::environment(env('BRAINTREE_ENV')); \Braintree_Configuration::merchantId(env('BRAINTREE_MERCHANT_ID')); \Braintree_Configuration::publicKey(env('BRAINTREE_PUBLIC_KEY')); \Braintree_Configuration::privateKey(env('BRAINTREE_PRIVATE_KEY')); ~%% %% %%(DOCNEW 5.3=c06d6a2352ed8c767633aab9c20f2bf7d880c967 28.01.2017 5:00:51) === Настройка валюты === Стандартная валюта Cashier - доллар США (USD). Вы можете изменить валюту, вызвав метод %%Cashier::useCurrency()%% из метода %%boot()%% одного из ваших сервис-провайдеров. Метод %%useCurrency()%% принимает два строковых параметра: валюту и символ валюты: ~%% use Laravel\Cashier\Cashier; Cashier::useCurrency('eur', '€'); ~%% %% == Подписки == === Создание подписок === %%(DOCNEW 5.2=6b0b057ae6de3c88cb29188459e38383c622ec23 8.12.2016 23:00:15) Для создания подписки сначала получите экземпляр оплачиваемой модели, который обычно является экземпляром %%(t)App\User%%. Когда вы получили модель, вы можете использовать метод %%newSubscription()%% для управления подписками модели: ~%% $user = User::find(1); $user->newSubscription('main', 'monthly')->create($creditCardToken); ~%% Первый аргумент метода %%newSubscription()%% - название подписки. Если в вашем приложении используется только одна подписка, то вы можете назвать её %%(t)main%% или %%(t)primary%%. Второй аргумент - конкретный план Stripe/Braintree, на который подписывается пользователь. Это значение должно соответствовать идентификатору плана в Stripe или Braintree. Метод %%create()%% создаст подписку, а также внесёт в вашу базу данных ID заказчика и другую связанную информацию по оплате. **Дополнительная информация о пользователе** Если вы хотите указать дополнительную информацию о пользователе, передайте её вторым аргументом методу %%create()%%: ~%% $user->newSubscription('main', 'monthly')->create($creditCardToken, [ 'email' => $email, ]); ~%% Подробнее о дополнительных полях, поддерживаемых Stripe и Braintree, читайте в ((https://stripe.com/docs/api#create_customer документации по созданию заказчика)) Stripe и в ((https://developers.braintreepayments.com/reference/request/customer/create/php документации Braintree)). **Купоны** Если надо применить купон при создании подписки, используйте метод %%withCoupon()%%: ~%% $user->newSubscription('main', 'monthly') ->withCoupon('code') ->create($creditCardToken); ~%% %% %%(DOCNEW 5.1=cdc24ba7426c5b11eb4d050706bd78c3ea4913cc 19.06.2016 20:08:01, 5.0=5d10040a981deee82c0fde0e8e5d2ffc49eaaecb 8.02.2016 18:09:11) Для создания подписки сначала получите экземпляр оплачиваемой модели, который обычно является экземпляром %%(t)App\User%%. Когда вы получили модель, вы можете использовать метод %%subscription()%% для управления подписками модели: ~%% $user = User::find(1); $user->subscription('monthly')->create($creditCardToken); ~%% Метод %%create()%% автоматически создаст подписку Stripe, а также внесёт в вашу базу данных ID заказчика Stripe и другую связанную информацию по оплате. Если для вашего тарифа настроен пробный период в Stripe, то для записи пользователя автоматически будет задана дата окончания периода. Если вы хотите использовать пробные периоды, но при этом управлять ими полностью из своего приложения, а не определять их в Stripe, то вам надо задать дату окончания периода вручную: ~%% $user->trial_ends_at = Carbon::now()->addDays(14); $user->save(); ~%% **Дополнительная информация о пользователе** Если вы хотите указать дополнительную информацию о пользователе, передайте её вторым аргументом методу %%create()%%: ~%% $user->subscription('monthly')->create($creditCardToken, [ 'email' => $email, 'description' => 'Our First Customer' ]); ~%% Подробнее о дополнительных полях, поддерживаемых Stripe, читайте в ((https://stripe.com/docs/api#create_customer документации по созданию заказчика)) Stripe. **Купоны** Если надо применить купон при создании подписки, используйте метод %%withCoupon()%%: ~%% $user->subscription('monthly') ->withCoupon('code') ->create($creditCardToken); ~%% %% === Проверка статуса подписки === %%(DOCNEW 5.3=c06d6a2352ed8c767633aab9c20f2bf7d880c967 28.01.2017 5:00:51, 5.2=6b0b057ae6de3c88cb29188459e38383c622ec23 8.12.2016 23:00:15) Когда пользователь подписан на ваше приложение, вы можете легко проверить статус его подписки при помощи различных удобных методов. Во-первых, метод %%subscribed()%% возвращает %%(t)true%%, если подписка пользователя активна, даже если в данный момент она на пробном периоде: ~%% if ($user->subscribed('main')) { // } ~%% Метод %%subscribed%% создаёт отличный вариант для ((/docs/v5/middleware посредника маршрута)), позволяя вам фильтровать доступ к маршрутам и контроллерам на основе статусов подписок: ~%% public function handle($request, Closure $next) { if ($request->user() && ! $request->user()->subscribed('main')) { // Этот пользователь не оплатил подписку... return redirect('billing'); } return $next($request); } ~%% Вы также можете определить, идёт ли до сих пор пробный период у пользователя, с помощью метода %%onTrial()%%. Этот метод полезен для предупреждения пользователя о том, что он на пробном периоде: ~%% if ($user->subscription('main')->onTrial()) { // } ~%% Метод %%subscribedToPlan()%% используется для определения, подписан ли пользователь на данный тариф, на основе его Stripe/Braintree ID. В этом примере мы определим, подписана ли подписка %%(t)main%% пользователя на план %%(t)monthly%%: ~%% if ($user->subscribedToPlan('monthly', 'main')) { // } ~%% **Статус отменённой подписки** Чтобы определить, был ли пользователь ранее активным подписчиком, но позже отменил подписку, используйте метод %%cancelled()%%: ~%% if ($user->subscription('main')->cancelled()) { // } ~%% Вы можете также определить, отменил ли пользователь подписку, но находится все ещё на "льготном периоде", пока подписка полностью не истекла. Например, если пользователь отменяет подписку 5 марта, которая по плану закончится 10 марта, пользователь будет на "льготном периоде" до 10 марта. Обратите внимание на то, что метод %%subscribed()%% всё ещё возвращает %%(t)true%% в это время: ~%% if ($user->subscription('main')->onGracePeriod()) { // } ~%% %% %%(DOCNEW 5.1=cdc24ba7426c5b11eb4d050706bd78c3ea4913cc 19.06.2016 20:08:01, 5.0=5d10040a981deee82c0fde0e8e5d2ffc49eaaecb 8.02.2016 18:09:11) Когда пользователь подписан на ваше приложение, вы можете легко проверить статус его подписки при помощи различных удобных методов. Во-первых, метод %%subscribed()%% возвращает %%(t)true%%, если подписка пользователя активна, даже если в данный момент она на пробном периоде: ~%% if ($user->subscribed()) { // } ~%% Метод %%subscribed%% создаёт отличный вариант для ((/docs/v5/middleware посредника маршрута)), позволяя вам фильтровать доступ к маршрутам и контроллерам на основе статусов подписок: ~%% public function handle($request, Closure $next) { if ($request->user() && ! $request->user()->subscribed()) { // Этот пользователь не оплатил подписку... return redirect('billing'); } return $next($request); } ~%% Вы также можете определить, идёт ли до сих пор пробный период у пользователя, с помощью метода %%onTrial()%%. Этот метод полезен для предупреждения пользователя о том, что он на пробном периоде: ~%% if ($user->onTrial()) { // } ~%% Метод %%onPlan()%% используется для определения, подписан ли пользователь на данный тариф, на основе его Stripe ID: ~%% if ($user->onPlan('monthly')) { // } ~%% **Статус отменённой подписки** Чтобы определить, был ли пользователь ранее активным подписчиком, но позже отменил подписку, используйте метод %%cancelled()%%: ~%% if ($user->cancelled()) { // } ~%% Вы можете также определить, отменил ли пользователь подписку, но находится все ещё на "льготном периоде", пока подписка полностью не истекла. Например, если пользователь отменяет подписку 5 марта, которая по плану закончится 10 марта, пользователь будет на "льготном периоде" до 10 марта. Обратите внимание на то, что метод %%subscribed()%% всё ещё возвращает %%(t)true%% в это время. ~%% if ($user->onGracePeriod()) { // } ~%% Метод %%everSubscribed()%% используется для определения, подписывался ли пользователь когда-либо на ваше приложение: ~%% if ($user->everSubscribed()) { // } ~%% %% === Смена тарифа === %%(DOCNEW 5.3=c06d6a2352ed8c767633aab9c20f2bf7d880c967 28.01.2017 5:00:51, 5.2=6b0b057ae6de3c88cb29188459e38383c622ec23 8.12.2016 23:00:15) Когда пользователь подписан на ваше приложение, он может захотеть сменить свой тарифный план. Чтобы переключить пользователя на новую подписку, передайте идентификатор тарифа в метод %%swap()%%: ~%% $user = App\User::find(1); $user->subscription('main')->swap('provider-plan-id'); ~%% Если пользователь был на пробном периоде, то пробный период продолжится. Кроме того, если у подписки есть "количество", то оно тоже применится. Если вы хотите сменить план и отменить все текущие пробные периоды пользователя, используйте метод %%skipTrial()%%: ~%% $user->subscription('main') ->skipTrial() ->swap('provider-plan-id'); ~%% %% %%(DOCNEW 5.1=cdc24ba7426c5b11eb4d050706bd78c3ea4913cc 19.06.2016 20:08:01, 5.0=5d10040a981deee82c0fde0e8e5d2ffc49eaaecb 8.02.2016 18:09:11) Когда пользователь подписан на ваше приложение, он может захотеть сменить свой тарифный план. Чтобы переключить пользователя на новую подписку, используйте метод %%swap()%%. Например, мы легко можем переключить пользователя на подписку %%(t)premium%%: ~%% $user = App\User::find(1); $user->subscription('premium')->swap(); ~%% Если пользователь был на пробном периоде, то пробный период продолжится. Кроме того, если у подписки есть "количество", то оно тоже применится. При смене тарифа вы можете использовать метод %%prorate()%%, чтобы указать, что стоимость должна быть пересчитана пропорционально. Вдобавок, вы можете использовать метод %%swapAndInvoice()%% для того, чтобы выставить счёт за смену тарифа немедленно: ~%% $user->subscription('premium') ->prorate() ->swapAndInvoice(); ~%% %% === Количество подписки === %%(DOCNEW 5.3=c06d6a2352ed8c767633aab9c20f2bf7d880c967 28.01.2017 5:00:51, 5.2=6b0b057ae6de3c88cb29188459e38383c622ec23 8.12.2016 23:00:15) .(alert) Количество подписки поддерживается только версией Cashier для Stripe. В Braintree нет возможности, подобной "количеству" в Stripe. Иногда подписки зависят от "количества". Например, ваше приложение стоит $10 в месяц с **одного пользователя** учётной записи. Чтобы легко увеличить или уменьшить количество вашей подписки, используйте методы %%incrementQuantity()%% и %%decrementQuantity()%%: ~%% $user = User::find(1); $user->subscription('main')->incrementQuantity(); // Добавить 5 к текущему количеству подписок... $user->subscription('main')->incrementQuantity(5); $user->subscription('main')->decrementQuantity(); // Вычесть 5 от текущего количества подписок... $user->subscription('main')->decrementQuantity(5); ~%% Или вы можете задать конкретное количество с помощью метода %%updateQuantity()%%: ~%% $user->subscription('main')->updateQuantity(10); ~%% %% %%(DOCNEW 5.1=cdc24ba7426c5b11eb4d050706bd78c3ea4913cc 19.06.2016 20:08:01, 5.0=5d10040a981deee82c0fde0e8e5d2ffc49eaaecb 8.02.2016 18:09:11) Иногда подписки зависят от "количества". Например, ваше приложение стоит $10 в месяц с **одного пользователя** учётной записи. Чтобы легко увеличить или уменьшить количество вашей подписки, используйте методы %%increment()%% и %%decrement()%%: ~%% $user = User::find(1); $user->subscription()->increment(); // Добавить 5 к текущему количеству подписок... $user->subscription()->increment(5); $user->subscription()->decrement(); // Вычесть 5 от текущего количества подписок... $user->subscription()->decrement(5); ~%% Или вы можете задать конкретное количество с помощью метода %%updateQuantity()%%: ~%% $user->subscription()->updateQuantity(10); ~%% %% Более подробная информация о количествах подписок в ((https://stripe.com/docs/guides/subscriptions#setting-quantities документации Stripe)). === Налог на подписку === %%(DOCNEW 5.3=c06d6a2352ed8c767633aab9c20f2bf7d880c967 28.01.2017 5:00:51, 5.2=6b0b057ae6de3c88cb29188459e38383c622ec23 8.12.2016 23:00:15) Чтобы указать процент налога, который пользователь платит за подписку, реализуйте метод %%taxPercentage()%% в своей модели, и верните числовое значение от 0 до 100 с не более, чем двумя знаками после запятой. ~%% public function taxPercentage() { return 20; } ~%% %% %%(DOCNEW 5.1=cdc24ba7426c5b11eb4d050706bd78c3ea4913cc 19.06.2016 20:08:01, 5.0=5d10040a981deee82c0fde0e8e5d2ffc49eaaecb 8.02.2016 18:09:11) С помощью Cashier можно легко изменить значение %%(t)tax_percent%%, посылаемое в Stripe. Чтобы указать процент налога, который пользователь платит за подписку, реализуйте метод %%getTaxPercent()%% в своей модели, и верните числовое значение от 0 до 100 с не более, чем двумя знаками после запятой. ~%% public function getTaxPercent() { return 20; } ~%% %% Метод %%taxPercentage()%% позволяет вам использовать разные налоговые ставки по-модельно, что будет полезно при наличии пользователей из разных стран. .(alert) Метод %%taxPercentage()%% применяется только к оплате подписок. Если вы используете Cashier для разовых платежей, то в таких случаях вам надо указывать размер налога вручную. === Отмена подписки === %%(DOCNEW 5.3=c06d6a2352ed8c767633aab9c20f2bf7d880c967 28.01.2017 5:00:51, 5.2=6b0b057ae6de3c88cb29188459e38383c622ec23 8.12.2016 23:00:15) Отменить подписку можно методом %%cancel()%%: ~%% $user->subscription('main')->cancel(); ~%% При отмене подписки Cashier автоматически задаст столбец %%(t)ends_at%% в вашей базе данных. Этот столбец используется, чтобы знать, когда метод %%subscribed()%% должен начать возвращать %%(t)false%%. Например, если клиент отменит подписку 1 марта, но срок подписки по плану до 5 марта, то метод %%subscribed()%% будет продолжать возвращать %%(t)true%% до 5 марта. Вы можете определить то, что пользователь отменил подписку, но находится на "льготном периоде", при помощи метода %%onGracePeriod ()%%: ~%% if ($user->subscription('main')->onGracePeriod()) { // } ~%% %% %%(DOCNEW 5.3=c06d6a2352ed8c767633aab9c20f2bf7d880c967 28.01.2017 5:00:51) Для немедленной отмены подписки вызовите метод %%cancelNow()%% на подписке пользователя: ~%% $user->subscription('main')->cancelNow(); ~%% %% %%(DOCNEW 5.1=cdc24ba7426c5b11eb4d050706bd78c3ea4913cc 19.06.2016 20:08:01, 5.0=5d10040a981deee82c0fde0e8e5d2ffc49eaaecb 8.02.2016 18:09:11) Отменить подписку можно методом %%cancel()%%: ~%% $user->subscription()->cancel(); ~%% При отмене подписки Cashier автоматически задаст столбец %%(t)subscription_ends_at%% в вашей базе данных. Этот столбец используется, чтобы знать, когда метод %%subscribed()%% должен начать возвращать %%(t)false%%. Например, если клиент отменит подписку 1 марта, но срок подписки по плану до 5 марта, то метод %%subscribed()%% будет продолжать возвращать %%(t)true%% до 5 марта. Вы можете определить то, что пользователь отменил подписку, но находится на "льготном периоде", при помощи метода %%onGracePeriod ()%%: ~%% if ($user->onGracePeriod()) { // } ~%% %% === Возобновление подписки === %%(DOCNEW 5.3=c06d6a2352ed8c767633aab9c20f2bf7d880c967 28.01.2017 5:00:51, 5.2=6b0b057ae6de3c88cb29188459e38383c622ec23 8.12.2016 23:00:15) Если подписка была отменена пользователем, и вам надо её возобновить, используйте метод %%resume()%%. Пользователь **должен** быть по-прежнему на льготном периоде, чтобы возобновить подписку: ~%% $user->subscription('main')->resume(); ~%% %% %%(DOCNEW 5.1=cdc24ba7426c5b11eb4d050706bd78c3ea4913cc 19.06.2016 20:08:01, 5.0=5d10040a981deee82c0fde0e8e5d2ffc49eaaecb 8.02.2016 18:09:11) Если подписка была отменена пользователем, и вам надо её возобновить, используйте метод %%resume()%%: ~%% $user->subscription('monthly')->resume($creditCardToken); ~%% %% Если пользователь отменит подписку и затем возобновит её до того, как она полностью истекла, тогда не произойдет моментального расчёта оплаты. Его подписка будет просто повторно активирована, и расчёт оплаты будет происходить по изначальному циклу. %%(DOCNEW 5.3=c06d6a2352ed8c767633aab9c20f2bf7d880c967 28.01.2017 5:00:51) === Изменение банковской карты === Метод %%updateCard()%% служит для изменения информации о банковской карте клиента. Этот метод принимает Stripe-токен и назначает новую банковскую карту в качестве источника оплаты по умолчанию: ~%% $user->updateCard($creditCardToken); ~%% %% %%(DOCNEW 5.3=c06d6a2352ed8c767633aab9c20f2bf7d880c967 28.01.2017 5:00:51, 5.2=6b0b057ae6de3c88cb29188459e38383c622ec23 8.12.2016 23:00:15) == Пробные подписки == === С запросом банковской карты === Если вы хотите предлагать клиентам пробные периоды, но при этом сразу собирать данные о способе оплаты, используйте метод %%trialDays()%% при создании подписок: ~%% $user = User::find(1); $user->newSubscription('main', 'monthly') ->trialDays(10) ->create($creditCardToken); ~%% Этот метод задаст дату окончания пробного периода в записи БД о подписке, а также проинструктирует Stripe/Braintree о том, что не нужно начинать считать оплату для клиента до окончания этого периода. .(alert) Если подписка клиента не будет отменена до окончания пробного периода, ему будет выставлен счёт, как только истечёт этот период, поэтому не забывайте уведомлять своих пользователей о дате окончания их пробного периода. Вы можете определить, идёт ли до сих пор пробный период у пользователя, с помощью метода %%onTrial()%% экземпляра пользователя или с помощью метода %%onTrial()%% экземпляра подписки. Эти два примера выполняют одинаковую задачу: ~%% if ($user->onTrial('main')) { // } if ($user->subscription('main')->onTrial()) { // } ~%% === Без запроса банковской карты === Если вы хотите предлагать клиентам пробные периоды, не собирая данные о способе оплаты, вы можете просто задать значение столбца %%(t)trial_ends_at%% в записи пользователя равное дате окончания пробного периода. Это обычно делается во время регистрации пользователя: ~%% $user = User::create([ // Заполнение других свойств пользователя... 'trial_ends_at' => Carbon::now()->addDays(10), ]); ~%% .(alert) Не забудьте добавить ((//docs/v5/eloquent-mutators#преобразователи преобразователь дат)) для %%(t)trial_ends_at%% в определении вашей модели. Cashier относится к пробным периодам такого типа, как к "общим пробным периодам", поскольку они не прикреплены к какой-либо из существующих подписок. Метод %%onTrial()%% на экземпляре %%(t)User%% вернёт %%true%%, если текущая дата не превышает значение %%(t)trial_ends_at%%: ~%% if ($user->onTrial()) { // Пользователь на пробном периоде... } ~%% Если вы хотите узнать, что пользователь именно на "общем" пробном периоде и ещё не создал настоящую подписку, используйте метод %%onGenericTrial()%%: ~%% if ($user->onGenericTrial()) { // Пользователь на "общем" пробном периоде... } ~%% Когда вы готовы создать для пользователя настоящую подписку, используйте метод %%newSubscription()%% как обычно: ~%% $user = User::find(1); $user->newSubscription('main', 'monthly')->create($creditCardToken); ~%% %% == Обработка веб-хуков Stripe == Stripe и Braintree могут уведомлять ваше приложение о различных событиях через веб-хуки. Для обработки веб-хуков Stripe определите маршрут для контроллера веб-хуков Cashier. Этот контроллер будет обрабатывать все входящие веб-хук запросы и отправлять их в нужный метод контроллера: %%(DOCNEW 5.3=c06d6a2352ed8c767633aab9c20f2bf7d880c967 28.01.2017 5:00:51, 5.2=6b0b057ae6de3c88cb29188459e38383c622ec23 8.12.2016 23:00:15) ~%% Route::post( 'stripe/webhook', '\Laravel\Cashier\Http\Controllers\WebhookController@handleWebhook' ); ~%% %% %%(DOCNEW 5.1=cdc24ba7426c5b11eb4d050706bd78c3ea4913cc 19.06.2016 20:08:01, 5.0=5d10040a981deee82c0fde0e8e5d2ffc49eaaecb 8.02.2016 18:09:11) ~%% Route::post('stripe/webhook', '\Laravel\Cashier\WebhookController@handleWebhook'); ~%% %% .(alert) После регистрации маршрута не забудьте настроить URL веб-хука в панели настроек Stripe. По умолчанию этот контроллер будет автоматически обрабатывать отмену подписок, для которых произошло слишком много неудачных попыток оплаты (это число задаётся в настройках Stripe); но вскоре мы рассмотрим, что можно наследовать этот контроллер для обработки любых необходимых веб-хук событий. **Веб-хуки и CSRF-защита** Поскольку веб-хуки Stripe должны идти в обход ((/docs/v5/routing#csrf CSRF-защиты)) Laravel, не забудьте включить URI в список исключений вашего посредника %%(t)VerifyCsrfToken%% или разместить маршрут вне группы посредников %%(t)web%% (для версии 5.2 и выше): %% protected $except = [ 'stripe/*', ]; %% === Определение обработчиков веб-хук событий === Cashier автоматически обрабатывает отмену подписки при неудачной оплате, но если у вас есть дополнительные webhook-события для Stripe, которые вы хотели бы обработать, просто наследуйте контроллер %%Webhook%%. Ваши имена методов должны соответствовать принятому в Cashier соглашению, в частности, методы должны быть снабжены префиксом %%(t)handle%% и именем того webhook-события Stripe, которое вы хотите обработать, в стиле "CamelCase". Например, если вы хотите обработать webhook %%invoice.payment_succeeded%%, вы должны добавить метод %%handleInvoicePaymentSucceeded()%% в контроллер: %% charge(100); // Braintree принимает сумму в долларах... $user->charge(1); ~%% Метод %%charge()%% принимает вторым аргументом массив, позволяя вам передавать любые необходимые параметры для создания основного Stripe/Braintree-платежа. О доступных при создании платежей опциях читайте в документации Stripe и Braintree: ~%% $user->charge(100, [ 'custom_option' => $value, ]); ~%% Метод %%charge()%% выбросит исключение при ошибке платёжа. Если платёж пройдёт успешно, метод вернёт полный ответ Stripe/Braintree: ~%% try { $response = $user->charge(100); } catch (Exception $e) { // } ~%% === Платёж со счётом === Иногда бывает необходимо сделать одноразовый платёж и сгенерировать счёт-фактуру для него, чтобы вы могли предоставить клиенту PDF-квитанцию. Именно для этого служит метод %%invoiceFor()%%. Например, давайте выставим клиенту счёт $5.00 "разовой оплаты" ("One Time Fee"): ~%% // Stripe принимает сумму в центах... $user->invoiceFor('One Time Fee', 500); // Braintree принимает сумму в долларах... $user->invoiceFor('One Time Fee', 5); ~%% Счёт будет немедленно оплачен банковской картой пользователя. Метод %%invoiceFor()%% также принимает третьим аргументом массив, позволяя вам передавать любые параметры для создания платежа Stripe/Braintree: ~%% $user->invoiceFor('One Time Fee', 500, [ 'custom-option' => $value, ]); ~%% .(alert) Метод %%invoiceFor()%% создаст счёт Stripe, который будет повторять проваленные попытки оплаты. Если вы не хотите повторять проваленные платежи, вам необходимо закрывать их с помощью Stripe API после первого неудачного платежа. %% %%(DOCNEW 5.1=cdc24ba7426c5b11eb4d050706bd78c3ea4913cc 19.06.2016 20:08:01, 5.0=5d10040a981deee82c0fde0e8e5d2ffc49eaaecb 8.02.2016 18:09:11) Если вы хотите сделать "одноразовый" платёж вместо использования банковской карты подписанного пользователя, используйте метод %%charge()%% для экземпляра модели. Метод %%charge()%% принимает сумму, которую необходимо оплатить, с **наименьшим знаменателем используемой в вашем приложении валюты**. Например, в этом примере будет списано 100 центов, или $1, с банковской карты пользователя: ~%% $user->charge(100); ~%% Метод %%charge()%% принимает в качестве второго аргумента массив, позволяя вам передавать любые необходимые параметры для создания основного Stripe-платежа: ~%% $user->charge(100, [ 'source' => $token, 'receipt_email' => $user->email, ]); ~%% Метод %%charge()%% вернёт %%(t)false%%, если платёж не пройдёт. Обычно это значит, что платёж был отклонён: ~%% if ( ! $user->charge(100)) { // Платёж был отклонён... } ~%% Если платёж прошёл успешно, метод возвратит полный Stripe-ответ. %% %%(DOCNEW 5.0=5d10040a981deee82c0fde0e8e5d2ffc49eaaecb 8.02.2016 18:09:11) === Без предоплаты === Если в вашем приложении будет бесплатный пробный период, не требующий предварительного предъявления банковской карты, установите свойство %%(t)cardUpFront%% вашей модели в %%(t)false%%: ~%% protected $cardUpFront = false; ~%% При создании аккаунта не забудьте установить дату окончания пробного периода в модели: ~%% $user->trial_ends_at = Carbon::now()->addDays(14); $user->save(); ~%% %% == Счета == Вы можете легко получить массив счетов пользователя, используя метод %%invoices()%%: %% $invoices = $user->invoices(); // Включить отложенные счета в результаты... $invoices = $user->invoicesIncludingPending(); %% При просмотре счетов клиента вы можете использовать эти вспомогательные методы, чтобы вывести на экран соответствующую информацию о счёте. Например, вам может понадобиться просмотреть каждый счёт в таблице, позволив пользователю легко скачать любой из них: %%(DOCNEW 5.3=c06d6a2352ed8c767633aab9c20f2bf7d880c967 28.01.2017 5:00:51, 5.2=6b0b057ae6de3c88cb29188459e38383c622ec23 8.12.2016 23:00:15) ~%% @foreach ($invoices as $invoice) @endforeach
{{ $invoice->date()->toFormattedDateString() }} {{ $invoice->total() }} Download
~%% %% %%(DOCNEW 5.1=cdc24ba7426c5b11eb4d050706bd78c3ea4913cc 19.06.2016 20:08:01, 5.0=5d10040a981deee82c0fde0e8e5d2ffc49eaaecb 8.02.2016 18:09:11) ~%% @foreach ($invoices as $invoice) @endforeach
{{ $invoice->dateString() }} {{ $invoice->dollars() }} Download
~%% %% === Создание PDF-файлов счетов === Перед созданием PDF-файлов счетов вам необходимо установить PHP-библиотеку %%(t)dompdf%%: %%(sh) composer require dompdf/dompdf %% Затем используйте метод %%downloadInvoice()%% в маршруте или контроллере, чтобы cгенерировать PDF-файл счёта. Этот метод автоматически сгенерирует нужный HTTP-отклик чтобы отправить загрузку в браузер: %% use Illuminate\Http\Request; Route::get('user/invoice/{invoice}', function (Request $request, $invoiceId) { return $request->user()->downloadInvoice($invoiceId, [ 'vendor' => 'Your Company', 'product' => 'Your Product', ]); }); %%