lopatin96 / laravel-subscription
Laravel subscription
Installs: 8 113
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 1
Forks: 0
Open Issues: 0
Requires
- php: >=8.1
- laravel-notification-channels/telegram: ^4.0
- lopatin96/laravel-nova-badges: ^1.0
Requires (Dev)
- orchestra/testbench: ^8.0
This package is auto-updated.
Last update: 2024-12-17 00:32:56 UTC
README
Migration
Run migration
php artisan migrate
Trait
Add fillable, casts and HasSubscription trait to User model
use Atin\LaravelSubscription\Traits\HasSubscription; class User extends Authenticatable { use HasSubscription, … protected $fillable = [ … 'billing_visited_at', ]; protected $casts = [ … 'billing_visited_at' => 'datetime', ];
Nova
Fields
Boolean::make('Billing', 'billing_visited_at') ->onlyOnIndex() ->sortable(), DateTime::make('Billing Visited At', 'billing_visited_at') ->hideFromIndex() ->nullable() ->readonly(),
Register
For example, in spark/app.blade.php
:
@php auth()->user()->update([ 'billing_visited_at' => now(), ]); activity() ->causedBy(auth()->user()) ->log('billing:visited'); @endphp
Views
Add subscription info component to resources/views/layouts/app.blade.php:
<body class="font-sans antialiased"> @include('laravel-subscription::subscription.info') …
Console
Add IncompleteSubscriptions
to app/Console/Kernel.php
use Atin\LaravelSubscription\Console\IncompleteSubscriptions; class Kernel extends ConsoleKernel { protected function schedule(Schedule $schedule): void { $schedule->call(new IncompleteSubscriptions)->hourly()->between('6:00', '24:00');
Config
Publish config to manage limited version of config:
php artisan vendor:publish --tag="laravel-subscription-config"
Nova
Resource
<?php namespace App\Nova; use Atin\LaravelUserStatuses\Enums\UserStatus; use Illuminate\Http\Request; use Laravel\Nova\Fields\BelongsTo; use Laravel\Nova\Fields\DateTime; use Laravel\Nova\Fields\Line; use Laravel\Nova\Fields\Number; use Laravel\Nova\Fields\Stack; use Laravel\Nova\Fields\Status; use Laravel\Nova\Http\Requests\NovaRequest; use Marshmallow\Filters\DateRangeFilter; use Atin\LaravelSubscription\Models\Subscription as SubscriptionModel; class Subscription extends Resource { public static string $model = SubscriptionModel::class; public static $title = 'stripe_id'; public static $search = [ 'id', 'stripe_id', 'user.name', 'user.email', ]; public function fields(NovaRequest $request): array { return [ Stack::make('User', [ BelongsTo::make('User') ->peekable() ->nullable() ->readonly(), Line::make(null, function () { return $this->user?->email ?: 'No email' . ($this->user->status === UserStatus::Blocked ? ' (blocked)' : null); }) ->asSmall(), Line::make(null, function () { return 'Stripe: '.($this->user?->stripe_id ?: '—'); }) ->asSmall(), Line::make(null, function () { return "User Created: {$this->user?->created_at->diffForHumans()}"; }) ->asSmall(), Line::make(null, function () { return "Last Online: {$this->user?->last_seen_at?->diffForHumans()}"; }) ->asSmall(), ]) ->sortable(), Status::make('Status', 'stripe_status') ->loadingWhen(['incomplete']) ->failedWhen(['canceled', 'past_due']) ->sortable(), // Number::make(__('Links'), function () { // return $this->user->links->count(); // }), // // Number::make(__('Clicks'), function () { // return $this->user->clicks->count(); // }), Stack::make('Trial ends At', [ DateTime::make('Trial ends At'), Line::make(null, function () { return $this->trial_ends_at ? "({$this->trial_ends_at->diffForHumans()})" : null; }) ->asSmall(), ]) ->sortable() ->readonly(), Stack::make('Ends At', [ DateTime::make('Ends At'), Line::make(null, function () { return $this->ends_at ? "({$this->ends_at->diffForHumans()})" : null; }) ->asSmall(), ]) ->sortable() ->readonly(), Stack::make('Created At', [ DateTime::make('Created At'), Line::make(null, function () { return "({$this->created_at->diffForHumans()})"; }) ->asSmall(), ]) ->sortable() ->readonly(), Stack::make('Updated At', [ DateTime::make('Created At'), Line::make(null, function () { return "({$this->updated_at->diffForHumans()})"; }) ->asSmall(), ]) ->sortable() ->readonly(), ]; } public function cards(NovaRequest $request): array { return [ new Metrics\ActiveSubscriptions, ]; } public function filters(NovaRequest $request): array { return [ new DateRangeFilter('created_at', 'Created Date'), ]; } public static function authorizedToCreate(Request $request): bool { return false; } }
Metric
<?php namespace App\Nova\Metrics; use Atin\LaravelSubscription\Models\Subscription; use Laravel\Nova\Http\Requests\NovaRequest; use Laravel\Nova\Metrics\Partition; class ActiveSubscriptions extends Partition { public $width = '1/4'; /** * Calculate the value of the metric. * * @return mixed */ public function calculate(NovaRequest $request) { return $this->count($request, Subscription::where('stripe_status', 'active'), 'stripe_price') ->label(fn ($value) => match ($value) { 'price_1MBekyFc1SsSrqC8CC7epdr9', 'price_1MBmAbFc1SsSrqC8T4zjWYq4' => 'Premium (monthly)', 'price_1MBekyFc1SsSrqC8AyZ37iye', 'price_1MBmAbFc1SsSrqC8h2aElxW2' => 'Premium (yearly)', 'price_1MzI8DFc1SsSrqC8AB0fCkPs', 'price_1MzI9MFc1SsSrqC8Mcyt219g' => 'Premium+ (monthly)', 'price_1MzI8DFc1SsSrqC8JqoNO3nx', 'price_1MzI9MFc1SsSrqC8NPKE914s' => 'Premium+ (yearly)', default => ucfirst($value) })->colors([ 'Premium (monthly)' => '#eef2ff', 'Premium (yearly)' => '#c7d2fe', 'Premium+ (monthly)' => '#818cf8', 'Premium+ (yearly)' => '#4f46e5', ]); } /** * Get the URI key for the metric. * * @return string */ public function uriKey() { return 'active-subscriptions'; } }
Publishing
Localization
php artisan vendor:publish --tag="laravel-subscription-lang"
Views
php artisan vendor:publish --tag="laravel-subscription-views"
Config
php artisan vendor:publish --tag="laravel-subscription-config"
Migrations
php artisan vendor:publish --tag="laravel-subscription-migrations"