lopatin96 / laravel-affiliate-program
Laravel affiliate program
Installs: 4 077
Dependents: 0
Suggesters: 0
Security: 0
Stars: 1
Watchers: 1
Forks: 1
Open Issues: 0
Requires
- php: >=8.1
- lopatin96/laravel-nova-badges: ^1.0
Requires (Dev)
- orchestra/testbench: ^8.0
README
Before install composer, create a resources/markdown/affiliate-terms.md
file in you project (see Terms section belowe).
Terms
Create a resources/markdown/affiliate-terms.md
file with Terms of Service.
Migrations
Run a migration php artisan migrate
Directive
Add a blade directive to app/Providers/AppServiceProvider.php
use Illuminate\Support\Facades\Blade; public function boot() { … Blade::directive('money', static function ($amountInCents, $decimals = 2) { return "<?php echo '$' . number_format($amountInCents / 100, $decimals); ?>"; }); }
Middlewares
- Add AffiliateProgram middleware to middleware array in
app/Http/Kernel.php
- moved these two lines (
\Illuminate\Session\Middleware\StartSession::class
and\Illuminate\View\Middleware\ShareErrorsFromSession::class
) from$middlewareGroups
to$middleware
:
protected $middleware = [ … \App\Http\Middleware\EncryptCookies::class, \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class, … \Atin\LaravelAffiliateProgram\Http\Middleware\AffiliateProgram::class, ];
Listeners
Add SaveAffiliateId
and SparkAffiliateSubscriptionUpdate
to app/Providers/EventServiceProvider.php
:
use Atin\LaravelAffiliateProgram\Listeners\SaveAffiliateId; use Atin\LaravelAffiliateProgram\Listeners\SparkAffiliateSubscriptionUpdate; … protected $listen = [ Registered::class => [ SaveAffiliateId::class, ], ]; protected $subscribe = [ SparkAffiliateSubscriptionUpdate::class, ];
Trait and Casts
Add HasAffiliate
trait to User model.
use Atin\LaravelAffiliateProgram\Traits\HasAffiliate; class User extends Authenticatable { use HasAffiliate;
Nova
Add NewAffiliateCommissions
and NewAffiliateInvoices
to app/Nova/Dashboards/Main.php
public function cards() { return [ … new NewAffiliateCommissions, new NewAffiliateInvoices, … ]; }
NovaServiceProvider
MenuSection::make('Affiliate Program', [ MenuItem::resource(AffiliateCommission::class) ->name('Commissions'), MenuItem::resource(AffiliateInvoice::class) ->name('Invoices'), MenuItem::resource(AffiliatePayout::class) ->name('Payouts'), ]) ->icon('user-group'),
Metrics
AffiliateCommissionsPerDay
<?php namespace App\Nova\Metrics; use Atin\LaravelAffiliateProgram\Models\AffiliateCommission; use Laravel\Nova\Http\Requests\NovaRequest; use Laravel\Nova\Metrics\Trend; class AffiliateCommissionsPerDay extends Trend { public $width = '1/4'; public function calculate(NovaRequest $request): \Laravel\Nova\Metrics\TrendResult { return $this->countByDays($request, AffiliateCommission::class); } public function ranges(): array { return [ 30 => __('30 Days'), 60 => __('60 Days'), 90 => __('90 Days'), ]; } public function cacheFor(): \DateInterval|float|\DateTimeInterface|\Illuminate\Support\Carbon|int|null { return now()->addMinute(); } }
AffiliateInvoicesPerDay
<?php namespace App\Nova\Metrics; use Atin\LaravelAffiliateProgram\Models\AffiliateInvoice; use Laravel\Nova\Http\Requests\NovaRequest; use Laravel\Nova\Metrics\Trend; class AffiliateInvoicesPerDay extends Trend { public $width = '1/4'; public function calculate(NovaRequest $request): \Laravel\Nova\Metrics\TrendResult { return $this->countByDays($request, AffiliateInvoice::class); } public function ranges(): array { return [ 30 => __('30 Days'), 60 => __('60 Days'), 90 => __('90 Days'), ]; } public function cacheFor(): \DateInterval|float|\DateTimeInterface|\Illuminate\Support\Carbon|int|null { return now()->addMinute(); } }
AffiliatePayoutsPerDay
<?php namespace App\Nova\Metrics; use Atin\LaravelAffiliateProgram\Models\AffiliatePayout; use Laravel\Nova\Http\Requests\NovaRequest; use Laravel\Nova\Metrics\Trend; class AffiliatePayoutsPerDay extends Trend { public $width = '1/4'; public function calculate(NovaRequest $request): \Laravel\Nova\Metrics\TrendResult { return $this->countByDays($request, AffiliatePayout::class); } public function ranges(): array { return [ 30 => __('30 Days'), 60 => __('60 Days'), 90 => __('90 Days'), ]; } public function cacheFor(): \DateInterval|float|\DateTimeInterface|\Illuminate\Support\Carbon|int|null { return now()->addMinute(); } }
NewAffiliateCommissions
<?php namespace App\Nova\Metrics; use Atin\LaravelAffiliateProgram\Models\AffiliateCommission; use Laravel\Nova\Http\Requests\NovaRequest; use Laravel\Nova\Metrics\Value; class NewAffiliateCommissions extends Value { public $width = '1/4'; public function calculate(NovaRequest $request): \Laravel\Nova\Metrics\ValueResult { return $this->count($request, AffiliateCommission::class); } public function ranges(): array { return [ 'TODAY' => __('Today'), 'YESTERDAY' => __('Yesterday'), 7 => __('7 Days'), 30 => __('30 Days'), 60 => __('60 Days'), 365 => __('365 Days'), 'MTD' => __('Month To Date'), 'QTD' => __('Quarter To Date'), 'YTD' => __('Year To Date'), ]; } public function cacheFor(): \DateInterval|float|\DateTimeInterface|\Illuminate\Support\Carbon|int|null { return now()->addMinute(); } }
NewAffiliateInvoices
<?php namespace App\Nova\Metrics; use Atin\LaravelAffiliateProgram\Models\AffiliateInvoice; use Laravel\Nova\Http\Requests\NovaRequest; use Laravel\Nova\Metrics\Value; class NewAffiliateInvoices extends Value { public $width = '1/4'; public function calculate(NovaRequest $request): \Laravel\Nova\Metrics\ValueResult { return $this->count($request, AffiliateInvoice::class); } public function ranges(): array { return [ 'TODAY' => __('Today'), 'YESTERDAY' => __('Yesterday'), 7 => __('7 Days'), 30 => __('30 Days'), 60 => __('60 Days'), 365 => __('365 Days'), 'MTD' => __('Month To Date'), 'QTD' => __('Quarter To Date'), 'YTD' => __('Year To Date'), ]; } public function cacheFor(): \DateInterval|float|\DateTimeInterface|\Illuminate\Support\Carbon|int|null { return now()->addMinute(); } }
Resources
AffiliateCommission
<?php namespace App\Nova; use App\Nova\Metrics\AffiliateCommissionsPerDay; use Illuminate\Http\Request; use Laravel\Nova\Fields\BelongsTo; use Laravel\Nova\Fields\Currency; use Laravel\Nova\Fields\DateTime; use Laravel\Nova\Fields\ID; use Laravel\Nova\Fields\Line; use Laravel\Nova\Fields\Number; use Laravel\Nova\Fields\Stack; use Laravel\Nova\Fields\Text; use Laravel\Nova\Http\Requests\NovaRequest; use Marshmallow\Filters\DateRangeFilter; class AffiliateCommission extends Resource { public static $model = \Atin\LaravelAffiliateProgram\Models\AffiliateCommission::class; public static $search = [ 'id', ]; public function fields(NovaRequest $request) { return [ ID::make() ->sortable(), Stack::make('User', [ BelongsTo::make('User') ->peekable() ->nullable() ->readonly() ->displayUsing(fn ($user) => mb_strimwidth($user->name, 0, 32, '…')), Text::make('User', function () { return $this->user?->email ? mb_strimwidth($this->user->email, 0, 32, '…') : 'No email'; }) ->asHtml(), Text::make('User', function () { return 'Stripe: '.($this->user?->stripe_id ?: '—'); }) ->asHtml(), Text::make('Created At', function () { return "User Created: {$this->user?->created_at->diffForHumans()}"; }) ->asHtml(), ]) ->sortable(), Currency::make('Payment') ->asMinorUnits() ->sortable() ->readonly(), Currency::make('Commission') ->asMinorUnits() ->sortable() ->readonly(), Number::make('Revenue Percent') ->sortable() ->readonly(), Stack::make('Created At', [ DateTime::make('Created At'), Line::make(null, function () { return "({$this->created_at->diffForHumans()})"; }) ->asSmall(), ]) ->sortable() ->readonly(), ]; } public function cards(NovaRequest $request) { return [ new AffiliateCommissionsPerDay, ]; } public function filters(NovaRequest $request) { return [ new DateRangeFilter('created_at', 'Created Date'), ]; } public static function authorizedToCreate(Request $request) { return false; } public function authorizedToDelete(Request $request) { return false; } }
AffiliateInvoice
<?php namespace App\Nova; use App\Nova\Metrics\AffiliateInvoicesPerDay; use Illuminate\Http\Request; use Laravel\Nova\Fields\BelongsTo; use Laravel\Nova\Fields\Boolean; use Laravel\Nova\Fields\DateTime; use Laravel\Nova\Fields\HasOne; use Laravel\Nova\Fields\ID; use Laravel\Nova\Fields\Line; use Laravel\Nova\Fields\Stack; use Laravel\Nova\Fields\Text; use Laravel\Nova\Http\Requests\NovaRequest; use Marshmallow\Filters\DateRangeFilter; class AffiliateInvoice extends Resource { public static $model = \Atin\LaravelAffiliateProgram\Models\AffiliateInvoice::class; public static $search = [ 'id', ]; public static $with = ['affiliatePayout']; public static function indexQuery(NovaRequest $request, $query) { return $query->doesntHave('AffiliatePayout'); } public function fields(NovaRequest $request) { return [ ID::make() ->sortable(), Stack::make('User', [ BelongsTo::make('User') ->peekable() ->nullable() ->readonly() ->displayUsing(fn ($user) => mb_strimwidth($user->name, 0, 32, '…')), Text::make('User', function () { return $this->user?->email ? mb_strimwidth($this->user->email, 0, 32, '…') : 'No email'; }) ->asHtml(), Text::make('User', function () { return 'Stripe: '.($this->user?->stripe_id ?: '—'); }) ->asHtml(), Text::make('Created At', function () { return "User Created: {$this->user?->created_at->diffForHumans()}"; }) ->asHtml(), ]) ->sortable(), HasOne::make('AffiliatePayout'), Boolean::make('Paid', 'affiliatePayout') ->sortable(), Stack::make('Created At', [ DateTime::make('Created At'), Line::make(null, function () { return "({$this->created_at->diffForHumans()})"; }) ->asSmall(), ]) ->sortable() ->readonly(), ]; } public function cards(NovaRequest $request) { return [ new AffiliateInvoicesPerDay, ]; } public function filters(NovaRequest $request) { return [ new DateRangeFilter('created_at', 'Created Date'), ]; } public static function authorizedToCreate(Request $request) { return false; } public function authorizedToDelete(Request $request) { return is_null($this->affiliatePayout); } }
AffiliatePayout
<?php namespace App\Nova; use App\Nova\Metrics\AffiliateCommissionsPerDay; use App\Nova\Metrics\AffiliatePayoutsPerDay; use Illuminate\Http\Request; use Laravel\Nova\Fields\BelongsTo; use Laravel\Nova\Fields\Currency; use Laravel\Nova\Fields\DateTime; use Laravel\Nova\Fields\ID; use Laravel\Nova\Fields\Line; use Laravel\Nova\Fields\Stack; use Laravel\Nova\Http\Requests\NovaRequest; use Marshmallow\Filters\DateRangeFilter; class AffiliatePayout extends Resource { public static $model = \Atin\LaravelAffiliateProgram\Models\AffiliatePayout::class; public static $search = [ 'id', ]; public function fields(NovaRequest $request) { return [ ID::make() ->sortable(), BelongsTo::make('Affiliate Invoice') ->peekable(), Currency::make('Amount') ->asMinorUnits() ->sortable(), Stack::make('Created At', [ DateTime::make('Created At'), Line::make(null, function () { return "({$this->created_at->diffForHumans()})"; }) ->asSmall(), ]) ->sortable() ->readonly(), ]; } public function cards(NovaRequest $request) { return [ new AffiliatePayoutsPerDay, ]; } public function filters(NovaRequest $request) { return [ new DateRangeFilter('created_at', 'Created Date'), ]; } public function authorizedToDelete(Request $request) { return false; } }
Publishing
Localization
php artisan vendor:publish --tag="laravel-affiliate-program-lang"
Views
php artisan vendor:publish --tag="laravel-affiliate-program-views"
Config
php artisan vendor:publish --tag="laravel-affiliate-program-config"