From ca48d430bbd4b14da055d543f2e02c5634e3813c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=8Carodej?= Date: Mon, 10 Jan 2022 16:29:44 +0100 Subject: [PATCH] added subscription demo generators --- .env.example | 20 +- ...GenerateDemoSubscriptionContentCommand.php | 535 ++++++++++++++++++ src/App/Console/Kernel.php | 5 + .../AutoSubscribeForMeteredBillingAction.php | 9 +- src/App/Users/Actions/CreateNewUserAction.php | 13 +- src/App/Users/Models/UserSetting.php | 2 +- src/Support/helpers.php | 10 +- tests/App/Socialite/SocialiteTest.php | 3 +- tests/Support/Scheduler/SchedulerTest.php | 6 +- 9 files changed, 569 insertions(+), 34 deletions(-) create mode 100644 src/App/Console/Commands/GenerateDemoSubscriptionContentCommand.php diff --git a/.env.example b/.env.example index 10bdd050..eac8d3f6 100644 --- a/.env.example +++ b/.env.example @@ -47,12 +47,8 @@ S3_DEFAULT_REGION= S3_BUCKET= S3_URL= -CASHIER_LOGGER=stack -CASHIER_CURRENCY= -STRIPE_KEY= -STRIPE_SECRET= -STRIPE_WEBHOOK_SECRET= -CASHIER_PAYMENT_NOTIFICATION=App\Notifications\ConfirmPayment +STRIPE_SECRET_KEY= +STRIPE_PUBLIC_KEY= PAYSTACK_SECRET= PAYSTACK_PUBLIC_KEY= @@ -60,7 +56,13 @@ PAYSTACK_PUBLIC_KEY= PAYPAL_CLIENT_ID= PAYPAL_CLIENT_SECRET= -SANCTUM_STATEFUL_DOMAINS=localhost,localhost:8000,127.0.0.1,127.0.0.1:8000,::1 - FACEBOOK_CLIENT_ID= -FACEBOOK_CLIENT_SECRET= \ No newline at end of file +FACEBOOK_CLIENT_SECRET= + +GOOGLE_CLIENT_ID= +GOOGLE_CLIENT_SECRET= + +GITHUB_CLIENT_ID= +GITHUB_CLIENT_SECRET= + +SANCTUM_STATEFUL_DOMAINS=localhost,localhost:8000,127.0.0.1,127.0.0.1:8000,::1 diff --git a/src/App/Console/Commands/GenerateDemoSubscriptionContentCommand.php b/src/App/Console/Commands/GenerateDemoSubscriptionContentCommand.php new file mode 100644 index 00000000..a9f52c6b --- /dev/null +++ b/src/App/Console/Commands/GenerateDemoSubscriptionContentCommand.php @@ -0,0 +1,535 @@ +each(fn ($name) => DB::table($name)->truncate()); + + // Create plans and subscriptions for metered billing + if ($this->argument('type') === 'metered') { + $this->info('Setting up new metered plans demo data...'); + $this->generateMeteredPlans(); + + $this->info('Setting up new pre-paid subscriptions data...'); + $this->generateMeteredSubscription(); + } + + // Create plans and subscriptions for fixed billing + if ($this->argument('type') === 'fixed') { + $this->info('Setting up new fixed plans demo data...'); + $this->generateFixedPlans(); + + $this->info('Setting up new fixed subscriptions data...'); + $this->generateFixedSubscription(); + } + + // Set subscription type for the app + Setting::updateOrCreate([ + 'name' => 'subscription_type', + ], [ + 'value' => $this->argument('type'), + ]); + } + + public function generateMeteredSubscription(): void + { + $plan = Plan::where('name', 'Pay as You Go') + ->first(); + + User::all() + ->each(function ($user) use ($plan) { + $isHowdy = $user->email === 'howdy@hi5ve.digital'; + + $this->info("Storing {$plan->name} for {$user->email}..."); + + // 1. Create subscription + $subscription = Subscription::create([ + 'user_id' => $user->id, + 'type' => 'pre-paid', + 'plan_id' => $plan->id, + 'name' => $plan->name, + 'status' => 'active', + 'renews_at' => now()->addDays(16), + 'created_at' => now()->subDays(14), + 'updated_at' => now()->subDays(14), + ]); + + // 2. Log fake storage and bandwidth + foreach (range(1, 31) as $item) { + $this->info('Logging fake bandwidth usage...'); + + $bandwidthFeature = $plan + ->meteredFeatures() + ->where('key', 'bandwidth') + ->first(); + + $subscription->usages()->create([ + 'metered_feature_id' => $bandwidthFeature->id, + 'quantity' => random_int(111, 999), + 'created_at' => now()->subDays($item), + ]); + + $this->info('Logging fake storage usage...'); + + $storageFeature = $plan + ->meteredFeatures() + ->where('key', 'storage') + ->first(); + + $subscription->usages()->create([ + 'metered_feature_id' => $storageFeature->id, + 'quantity' => random_int(1111, 3999), + 'created_at' => now()->subDays($item), + ]); + } + + // 3. Store flat fee + $flatFeeFeature = $plan + ->meteredFeatures() + ->where('key', 'flatFee') + ->first(); + + $subscription->usages()->create([ + 'metered_feature_id' => $flatFeeFeature->id, + 'quantity' => 1, + 'created_at' => now()->subDays(2), + ]); + + // 4. Store member count + $memberFeature = $plan + ->meteredFeatures() + ->where('key', 'member') + ->first(); + + $subscription->usages()->create([ + 'metered_feature_id' => $memberFeature->id, + 'quantity' => 7, + 'created_at' => now()->subDays(2), + ]); + + // 5. Store fake transactions + $this->info("Storing transactions for {$user->email}..."); + + collect([ + [ + 'type' => 'withdrawal', + 'created_at' => now()->subDays(2), + 'amount' => $isHowdy ? 12.59 : random_int(1, 20), + 'note' => now()->subDays(2)->format('d. M') . ' - ' . now()->subDays(32)->format('d. M'), + 'driver' => 'system', + ], + [ + 'type' => 'credit', + 'created_at' => now()->subDays(26 * 1), + 'note' => __('Bonus'), + 'amount' => $isHowdy ? 12.00 : random_int(1, 20), + 'driver' => 'system', + ], + [ + 'type' => 'withdrawal', + 'created_at' => now()->subDays(26 * 1), + 'note' => now()->subDays(26 * 1)->format('d. M') . ' - ' . now()->subDays(30 + 26 * 1)->format('d. M'), + 'amount' => $isHowdy ? 2.38 : random_int(1, 20), + 'driver' => 'system', + ], + [ + 'type' => 'withdrawal', + 'created_at' => now()->subDays(26 * 2), + 'note' => now()->subDays(26 * 2)->format('d. M') . ' - ' . now()->subDays(30 + 26 * 2)->format('d. M'), + 'amount' => $isHowdy ? 5.12 : random_int(1, 20), + 'driver' => 'system', + ], + [ + 'type' => 'withdrawal', + 'created_at' => now()->subDays(26 * 3), + 'note' => now()->subDays(26 * 3)->format('d. M') . ' - ' . now()->subDays(30 + 26 * 3)->format('d. M'), + 'amount' => $isHowdy ? 3.89 : random_int(1, 20), + 'driver' => 'system', + ], + [ + 'type' => 'withdrawal', + 'created_at' => now()->subDays(26 * 4), + 'note' => now()->subDays(26 * 4)->format('d. M') . ' - ' . now()->subDays(30 + 26 * 4)->format('d. M'), + 'amount' => $isHowdy ? 7.42 : random_int(1, 20), + 'driver' => 'system', + ], + [ + 'type' => 'charge', + 'created_at' => now()->subDays(26 * 5), + 'note' => 'Account Fund', + 'amount' => $isHowdy ? 50.00 : random_int(1, 20), + 'driver' => 'paypal', + ], + ])->each( + fn ($transaction) => $user->transactions()->create([ + 'type' => $transaction['type'], + 'status' => 'completed', + 'note' => $transaction['note'], + 'currency' => $plan->currency, + 'driver' => $transaction['driver'], + 'amount' => $transaction['amount'], + 'created_at' => $transaction['created_at'], + 'reference' => Str::random(12), + ]) + ); + + // Make fake credit card + $creditCard = CreditCard::factory() + ->make(); + + // 6. Store credit card + $user->creditCards()->create([ + 'brand' => $creditCard->brand, + 'last4' => $creditCard->last4, + 'service' => $creditCard->service, + 'reference' => $creditCard->reference, + 'expiration' => $creditCard->expiration, + ]); + + // 7. Add default user balance + $user->balance()->create([ + 'currency' => 'USD', + 'amount' => $isHowdy ? 30.60 : random_int(20, 60), + ]); + + // 8. Create billing alert + $user->billingAlert()->create([ + 'amount' => $isHowdy ? 25 : random_int(30, 80), + ]); + }); + } + + public function generateFixedSubscription(): void + { + $howdy = User::where('email', 'howdy@hi5ve.digital') + ->first(); + + $alice = User::where('email', 'alice@hi5ve.digital') + ->first(); + + $johan = User::where('email', 'johan@hi5ve.digital') + ->first(); + + $professionalPackPlan = Plan::where('name', 'Professional Pack') + ->where('interval', 'month') + ->first(); + + $businessPackPlan = Plan::where('name', 'Business Pack') + ->where('interval', 'month') + ->first(); + + $this->info("Storing {$professionalPackPlan->name} for {$howdy->email}..."); + + $howdySubscription = $howdy->subscription()->create([ + 'plan_id' => $professionalPackPlan->id, + 'name' => $professionalPackPlan->name, + 'status' => 'active', + 'created_at' => now()->subDays(14), + 'updated_at' => now()->subDays(14), + ]); + + $this->info("Storing {$businessPackPlan->name} for {$alice->email}..."); + + $aliceSubscription = $alice->subscription()->create([ + 'plan_id' => $businessPackPlan->id, + 'name' => $businessPackPlan->name, + 'status' => 'active', + 'created_at' => now()->subDays(9), + 'updated_at' => now()->subDays(9), + ]); + + $this->info("Storing {$professionalPackPlan->name} for {$johan->email}..."); + + $johanSubscription = $johan->subscription()->create([ + 'plan_id' => $professionalPackPlan->id, + 'name' => $professionalPackPlan->name, + 'status' => 'cancelled', + 'ends_at' => now()->addDays(18), + 'created_at' => now()->subDays(8), + 'updated_at' => now()->subDays(8), + ]); + + $this->info("Storing transactions for {$howdy->email}..."); + + collect([ + ['created_at' => now()->subDays(2)], + ['created_at' => now()->subDays(26)], + ['created_at' => now()->subDays(26 * 2)], + ['created_at' => now()->subDays(26 * 3)], + ['created_at' => now()->subDays(26 * 4)], + ['created_at' => now()->subDays(26 * 5)], + ])->each( + fn ($transaction) => $howdy->transactions()->create([ + 'status' => 'completed', + 'note' => $professionalPackPlan->name, + 'currency' => $professionalPackPlan->currency, + 'amount' => $professionalPackPlan->amount, + 'driver' => 'paypal', + 'created_at' => $transaction['created_at'], + 'reference' => Str::random(12), + ]) + ); + + $this->info("Storing transactions for {$johan->email}..."); + + collect([ + ['created_at' => now()->subDay()], + ['created_at' => now()->subDays(29)], + ['created_at' => now()->subDays(29 * 2)], + ['created_at' => now()->subDays(29 * 3)], + ])->each( + fn ($transaction) => $johan->transactions()->create([ + 'status' => 'completed', + 'note' => $professionalPackPlan->name, + 'currency' => $professionalPackPlan->currency, + 'amount' => $professionalPackPlan->amount, + 'driver' => 'stripe', + 'created_at' => $transaction['created_at'], + 'reference' => Str::random(12), + ]) + ); + + $this->info("Storing transactions for {$alice->email}..."); + + collect([ + ['created_at' => now()], + ['created_at' => now()->subDays(28)], + ['created_at' => now()->subDays(28 * 2)], + ['created_at' => now()->subDays(28 * 3)], + ['created_at' => now()->subDays(28 * 4)], + ])->each( + fn ($transaction) => $alice->transactions()->create([ + 'status' => 'completed', + 'note' => $businessPackPlan->name, + 'currency' => $businessPackPlan->currency, + 'amount' => $businessPackPlan->amount, + 'driver' => 'paystack', + 'created_at' => $transaction['created_at'], + 'reference' => Str::random(12), + ]) + ); + + $howdySubscription->driver()->create([ + 'driver' => 'stripe', + 'driver_subscription_id' => Str::random(), + ]); + + // Make fake credit card + $creditCard = CreditCard::factory() + ->make(); + + // 6. Store credit card + $howdy->creditCards()->create([ + 'brand' => $creditCard->brand, + 'last4' => $creditCard->last4, + 'service' => $creditCard->service, + 'reference' => $creditCard->reference, + 'expiration' => $creditCard->expiration, + ]); + + $aliceSubscription->driver()->create([ + 'driver' => 'paystack', + 'driver_subscription_id' => Str::random(), + ]); + + $johanSubscription->driver()->create([ + 'driver' => 'stripe', + 'driver_subscription_id' => Str::random(), + ]); + } + + public function generateFixedPlans() + { + // Define plans + $plans = [ + [ + 'type' => 'fixed', + 'name' => 'Professional Pack', + 'description' => 'Best for all professionals', + 'currency' => 'USD', + 'features' => [ + 'max_storage_amount' => 200, + 'max_team_members' => 20, + ], + 'intervals' => [ + [ + 'interval' => 'month', + 'amount' => 9.99, + ], + [ + 'interval' => 'year', + 'amount' => 99.49, + ], + ], + ], + [ + 'type' => 'fixed', + 'name' => 'Business Pack', + 'description' => 'Best for business needs', + 'currency' => 'USD', + 'features' => [ + 'max_storage_amount' => 500, + 'max_team_members' => 50, + ], + 'intervals' => [ + [ + 'interval' => 'month', + 'amount' => 29.99, + ], + [ + 'interval' => 'year', + 'amount' => 189.99, + ], + ], + ], + [ + 'type' => 'fixed', + 'name' => 'Elite Pack', + 'description' => 'Best for all your needs', + 'currency' => 'USD', + 'features' => [ + 'max_storage_amount' => 2000, + 'max_team_members' => -1, + ], + 'intervals' => [ + [ + 'interval' => 'month', + 'amount' => 59.99, + ], + [ + 'interval' => 'year', + 'amount' => 349.99, + ], + ], + ], + ]; + + // Create plans + foreach ($plans as $plan) { + foreach ($plan['intervals'] as $interval) { + $data = CreateFixedPlanData::fromArray([ + 'type' => $plan['type'], + 'name' => $plan['name'], + 'description' => $plan['description'], + 'features' => $plan['features'], + 'currency' => $plan['currency'], + 'amount' => $interval['amount'], + 'interval' => $interval['interval'], + ]); + + $this->info("Creating plan with name: {$plan['name']} and interval: {$interval['interval']}"); + + // Store plans to the database and gateway + ($this->storeFixedPlan)($data); + } + } + } + + public function generateMeteredPlans() + { + // Define plans + $plans = [ + [ + 'type' => 'metered', + 'name' => 'Pay as You Go', + 'description' => 'Best for all professionals', + 'currency' => 'USD', + 'meters' => [ + [ + 'key' => 'bandwidth', + 'aggregate_strategy' => 'sum_of_usage', + 'tiers' => [ + [ + 'first_unit' => 1, + 'last_unit' => null, + 'per_unit' => 0.29, + 'flat_fee' => null, + ], + ], + ], + [ + 'key' => 'storage', + 'aggregate_strategy' => 'maximum_usage', + 'tiers' => [ + [ + 'first_unit' => 1, + 'last_unit' => null, + 'per_unit' => 0.19, + 'flat_fee' => null, + ], + ], + ], + [ + 'key' => 'flatFee', + 'aggregate_strategy' => 'maximum_usage', + 'tiers' => [ + [ + 'first_unit' => 1, + 'last_unit' => null, + 'per_unit' => 2.49, + 'flat_fee' => null, + ], + ], + ], + [ + 'key' => 'member', + 'aggregate_strategy' => 'maximum_usage', + 'tiers' => [ + [ + 'first_unit' => 1, + 'last_unit' => null, + 'per_unit' => 0.10, + 'flat_fee' => null, + ], + ], + ], + ], + ], + ]; + + // Create plans + foreach ($plans as $plan) { + $data = CreateMeteredPlanData::fromArray([ + 'type' => $plan['type'], + 'name' => $plan['name'], + 'meters' => $plan['meters'], + 'currency' => $plan['currency'], + 'description' => $plan['description'], + ]); + + $this->info("Creating plan with name: {$plan['name']}"); + + // Store plans to the database and gateway + ($this->storeMeteredPlan)($data); + } + } +} diff --git a/src/App/Console/Kernel.php b/src/App/Console/Kernel.php index 9ec888b1..31878905 100644 --- a/src/App/Console/Kernel.php +++ b/src/App/Console/Kernel.php @@ -9,6 +9,7 @@ use Support\Scheduler\Actions\DeleteFailedFilesAction; use Illuminate\Foundation\Console\Kernel as ConsoleKernel; use Support\Scheduler\Actions\DeleteUnverifiedUsersAction; use Support\Scheduler\Actions\DeleteExpiredShareLinksAction; +use App\Console\Commands\GenerateDemoSubscriptionContentCommand; class Kernel extends ConsoleKernel { @@ -18,8 +19,12 @@ class Kernel extends ConsoleKernel * @var array */ protected $commands = [ + // Basic demo content generator SetupDevEnvironment::class, SetupProdEnvironment::class, + + // Subscription demo generator + GenerateDemoSubscriptionContentCommand::class, ]; /** diff --git a/src/App/Users/Actions/AutoSubscribeForMeteredBillingAction.php b/src/App/Users/Actions/AutoSubscribeForMeteredBillingAction.php index 1baec91c..716e409a 100644 --- a/src/App/Users/Actions/AutoSubscribeForMeteredBillingAction.php +++ b/src/App/Users/Actions/AutoSubscribeForMeteredBillingAction.php @@ -1,5 +1,4 @@ balance()->create([ 'amount' => $settings['registration_bonus_amount'], @@ -39,17 +37,12 @@ class AutoSubscribeForMeteredBillingAction 'amount' => $settings['registration_bonus_amount'], ]); } else { - // Create balance with 0 amount $user->balance()->create([ 'currency' => $plan->currency, ]); } - // Store transaction - if (intval($settings['allowed_registration_bonus'])) { - } - // Create user subscription $user->subscription()->create([ 'plan_id' => $plan->id, @@ -59,4 +52,4 @@ class AutoSubscribeForMeteredBillingAction 'type' => 'pre-paid', ]); } -} \ No newline at end of file +} diff --git a/src/App/Users/Actions/CreateNewUserAction.php b/src/App/Users/Actions/CreateNewUserAction.php index 908cf6ea..325b4a5c 100644 --- a/src/App/Users/Actions/CreateNewUserAction.php +++ b/src/App/Users/Actions/CreateNewUserAction.php @@ -1,19 +1,18 @@ password || !intval($settings['user_verification'])) { + if (! $data->password || ! intval($settings['user_verification'])) { $user->markEmailAsVerified(); } event(new Registered($user)); // Log in if verification is disabled - if (!$data->password || !intval($settings['user_verification'])) { + if (! $data->password || ! intval($settings['user_verification'])) { $this->guard->login($user); } } diff --git a/src/App/Users/Models/UserSetting.php b/src/App/Users/Models/UserSetting.php index e0922521..18f82e58 100644 --- a/src/App/Users/Models/UserSetting.php +++ b/src/App/Users/Models/UserSetting.php @@ -55,7 +55,7 @@ class UserSetting extends Model // Return default avatar foreach (config('vuefilemanager.avatar_sizes') as $item) { - $link[$item['name']] = url("/assets/images/default-avatar.png"); + $link[$item['name']] = url('/assets/images/default-avatar.png'); } return $link; diff --git a/src/Support/helpers.php b/src/Support/helpers.php index 1f40f73e..054fae6d 100644 --- a/src/Support/helpers.php +++ b/src/Support/helpers.php @@ -1047,12 +1047,12 @@ if (! function_exists('replace_occurrence')) { { collect(config('vuefilemanager.avatar_sizes')) ->each(function ($size) use ($intervention, $avatar_name) { - // fit thumbnail - $intervention->fit($size['size'], $size['size'])->stream(); + // fit thumbnail + $intervention->fit($size['size'], $size['size'])->stream(); - // Store thumbnail to disk - Storage::put("avatars/{$size['name']}-{$avatar_name}", $intervention); - }); + // Store thumbnail to disk + Storage::put("avatars/{$size['name']}-{$avatar_name}", $intervention); + }); } } } diff --git a/tests/App/Socialite/SocialiteTest.php b/tests/App/Socialite/SocialiteTest.php index 35127d0c..f82afa22 100644 --- a/tests/App/Socialite/SocialiteTest.php +++ b/tests/App/Socialite/SocialiteTest.php @@ -1,5 +1,4 @@ each( - fn($size) => Storage::disk('local') + fn ($size) => Storage::disk('local') ->assertExists("avatars/{$size['name']}-{$user->settings->getRawOriginal('avatar')}") ); } diff --git a/tests/Support/Scheduler/SchedulerTest.php b/tests/Support/Scheduler/SchedulerTest.php index 8cbc6073..c7770507 100644 --- a/tests/Support/Scheduler/SchedulerTest.php +++ b/tests/Support/Scheduler/SchedulerTest.php @@ -1,4 +1,5 @@ create([ 'user_id' => $user->id, 'download' => 155000000, + 'upload' => 255000000, 'created_at' => now()->subDay(), ]); @@ -70,12 +72,12 @@ class SchedulerTest extends TestCase ->assertDatabaseHas('usages', [ 'metered_feature_id' => $plan->meteredFeatures()->get()[0]->id, 'subscription_id' => $subscription->id, - 'quantity' => 0.125, + 'quantity' => 125, ]) ->assertDatabaseHas('usages', [ 'metered_feature_id' => $plan->meteredFeatures()->get()[1]->id, 'subscription_id' => $subscription->id, - 'quantity' => 0.155, + 'quantity' => 410, ]); }