From a22c2e02bea44178dc51c704fde20d7e2a074117 Mon Sep 17 00:00:00 2001 From: Annika Wolff Date: Wed, 27 May 2020 11:31:35 +0200 Subject: [PATCH] introduce cronjob to automatically deactivate expired events --- app/Console/Kernel.php | 4 +- .../BookingProductEventTicketFactory.php | 19 +++++ .../Factories/BookingProductFactory.php | 20 +++++ .../BookingProductServiceProvider.php | 8 +- .../Core/src/Console/Commands/BookingCron.php | 75 +++++++++++++++++++ .../src/Providers/CoreServiceProvider.php | 10 ++- tests/_support/Helper/DataMocker.php | 2 +- tests/unit.suite.yml | 1 + tests/unit/Core/Commands/BookingCronCest.php | 55 ++++++++++++++ 9 files changed, 188 insertions(+), 6 deletions(-) create mode 100644 packages/Webkul/BookingProduct/src/Database/Factories/BookingProductEventTicketFactory.php create mode 100644 packages/Webkul/BookingProduct/src/Database/Factories/BookingProductFactory.php create mode 100644 packages/Webkul/Core/src/Console/Commands/BookingCron.php create mode 100644 tests/unit/Core/Commands/BookingCronCest.php diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index 85533a8dc..2cf59a56a 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -24,8 +24,7 @@ class Kernel extends ConsoleKernel */ protected function schedule(Schedule $schedule) { - // $schedule->command('inspire') - // ->hourly(); + $schedule->command('booking:cron')->dailyAt('3:00'); } /** @@ -36,6 +35,7 @@ class Kernel extends ConsoleKernel protected function commands() { $this->load(__DIR__.'/Commands'); + $this->load(__DIR__.'/../../packages/Webkul/Core/src/Console/Commands'); require base_path('routes/console.php'); } diff --git a/packages/Webkul/BookingProduct/src/Database/Factories/BookingProductEventTicketFactory.php b/packages/Webkul/BookingProduct/src/Database/Factories/BookingProductEventTicketFactory.php new file mode 100644 index 000000000..09f79b311 --- /dev/null +++ b/packages/Webkul/BookingProduct/src/Database/Factories/BookingProductEventTicketFactory.php @@ -0,0 +1,19 @@ +define(BookingProductEventTicket::class, function (Faker $faker, array $attributes) { + return [ + 'price' => $faker->randomFloat(4, 3, 900), + 'qty' => $faker->randomNumber(2), + 'booking_product_id' => static function () { + return factory(BookingProduct::class)->create(['type' => 'event'])->id; + } + ]; +}); \ No newline at end of file diff --git a/packages/Webkul/BookingProduct/src/Database/Factories/BookingProductFactory.php b/packages/Webkul/BookingProduct/src/Database/Factories/BookingProductFactory.php new file mode 100644 index 000000000..3b74a8a1f --- /dev/null +++ b/packages/Webkul/BookingProduct/src/Database/Factories/BookingProductFactory.php @@ -0,0 +1,20 @@ +define(BookingProduct::class, function (Faker $faker, array $attributes) { + return [ + 'type' => array_rand(['event']), + 'qty' => $faker->randomNumber(2), + 'available_from' => Carbon::yesterday(), + 'available_to' => Carbon::tomorrow(), + 'product_id' => function () { + return factory(Product::class)->create(['type' => 'booking'])->id; + } + ]; +}); \ No newline at end of file diff --git a/packages/Webkul/BookingProduct/src/Providers/BookingProductServiceProvider.php b/packages/Webkul/BookingProduct/src/Providers/BookingProductServiceProvider.php index 92bec1ff8..b31d28d7f 100644 --- a/packages/Webkul/BookingProduct/src/Providers/BookingProductServiceProvider.php +++ b/packages/Webkul/BookingProduct/src/Providers/BookingProductServiceProvider.php @@ -2,6 +2,7 @@ namespace Webkul\BookingProduct\Providers; +use Illuminate\Database\Eloquent\Factory as EloquentFactory; use Illuminate\Support\ServiceProvider; class BookingProductServiceProvider extends ServiceProvider @@ -10,8 +11,9 @@ class BookingProductServiceProvider extends ServiceProvider * Bootstrap services. * * @return void + * @throws \Illuminate\Contracts\Container\BindingResolutionException */ - public function boot() + public function boot(): void { $this->loadRoutesFrom(__DIR__ . '/../Http/front-routes.php'); @@ -26,6 +28,8 @@ class BookingProductServiceProvider extends ServiceProvider ], 'public'); $this->app->register(EventServiceProvider::class); + + $this->app->make(EloquentFactory::class)->load(__DIR__ . '/../Database/Factories'); } /** @@ -33,7 +37,7 @@ class BookingProductServiceProvider extends ServiceProvider * * @return void */ - public function register() + public function register(): void { $this->mergeConfigFrom( dirname(__DIR__) . '/Config/product_types.php', 'product_types' diff --git a/packages/Webkul/Core/src/Console/Commands/BookingCron.php b/packages/Webkul/Core/src/Console/Commands/BookingCron.php new file mode 100644 index 000000000..cc1a2b59e --- /dev/null +++ b/packages/Webkul/Core/src/Console/Commands/BookingCron.php @@ -0,0 +1,75 @@ +join('product_flat', 'booking_products.product_id', '=', 'product_flat.product_id') + ->where('booking_products.type', 'event') + ->where('booking_products.available_to', '<=', Carbon::now()) + ->where('product_flat.status', 1) + ->get(); + + if (count($expiredEvents) > 0) { + $attStatusId = Attribute::query()->select('id') + ->where('code', 'status') + ->first() + ->id; + + foreach ($expiredEvents as $expEvent) { + ProductAttributeValue::query()->where('product_id', $expEvent->product_id) + ->where('attribute_id', $attStatusId) + ->update(['boolean_value' => 0]); + + ProductFlat::query()->where('product_id', $expEvent->product_id) + ->update(['status' => 0]); + + Log::info('BookingCron: deactivated expired event', ['booking_product_id' => $expEvent->id, 'product_id' => $expEvent->product_id]); + } + $this->info('All expired events have been deactivated'); + } else { + Log::info('BookingCron: Did not find any expired events to be deactivated'); + $this->info('Did not find any expired events to be deactivated'); + } + } +} diff --git a/packages/Webkul/Core/src/Providers/CoreServiceProvider.php b/packages/Webkul/Core/src/Providers/CoreServiceProvider.php index b60cdd31e..cc6fe420b 100755 --- a/packages/Webkul/Core/src/Providers/CoreServiceProvider.php +++ b/packages/Webkul/Core/src/Providers/CoreServiceProvider.php @@ -7,6 +7,7 @@ use Illuminate\Database\Eloquent\Factory as EloquentFactory; use Illuminate\Support\ServiceProvider; use Illuminate\Support\Facades\Validator; use Illuminate\Foundation\AliasLoader; +use Webkul\Core\Console\Commands\BookingCron; use Webkul\Core\Core; use Webkul\Core\Exceptions\Handler; use Webkul\Core\Facades\Core as CoreFacade; @@ -22,6 +23,7 @@ class CoreServiceProvider extends ServiceProvider * Bootstrap services. * * @return void + * @throws \Illuminate\Contracts\Container\BindingResolutionException */ public function boot() { @@ -86,7 +88,12 @@ class CoreServiceProvider extends ServiceProvider protected function registerCommands(): void { if ($this->app->runningInConsole()) { - $this->commands([BagistoVersion::class, Install::class, ExchangeRateUpdate::class]); + $this->commands([ + BagistoVersion::class, + Install::class, + ExchangeRateUpdate::class, + BookingCron::class + ]); } } @@ -96,6 +103,7 @@ class CoreServiceProvider extends ServiceProvider * @param string $path * * @return void + * @throws \Illuminate\Contracts\Container\BindingResolutionException */ protected function registerEloquentFactoriesFrom($path): void { diff --git a/tests/_support/Helper/DataMocker.php b/tests/_support/Helper/DataMocker.php index 536e2dbef..cb351ab5a 100644 --- a/tests/_support/Helper/DataMocker.php +++ b/tests/_support/Helper/DataMocker.php @@ -15,7 +15,7 @@ class DataMocker extends Module /** * Get an instance of the faker * - * @return Generator + * @return \Faker\Generator * * @author florianbosdorff */ diff --git a/tests/unit.suite.yml b/tests/unit.suite.yml index ba6191f9a..cab8a5bc2 100644 --- a/tests/unit.suite.yml +++ b/tests/unit.suite.yml @@ -8,6 +8,7 @@ modules: - Asserts - Filesystem - \Helper\Unit + - \Helper\DataMocker - Webkul\Core\Helpers\Laravel5Helper: environment_file: .env.testing run_database_migrations: true diff --git a/tests/unit/Core/Commands/BookingCronCest.php b/tests/unit/Core/Commands/BookingCronCest.php new file mode 100644 index 000000000..455fcf2ec --- /dev/null +++ b/tests/unit/Core/Commands/BookingCronCest.php @@ -0,0 +1,55 @@ +fake()->numberBetween(2, 6); + + for ($i=0; $i<$index; $i++) { + $products[$i] = $I->haveProduct(Laravel5Helper::VIRTUAL_PRODUCT); + Product::query()->where('id', $products[$i]->id)->update(['type' => 'booking']); + + if ($I->fake()->randomDigitNotNull <= 5) { + $availableTo = Carbon::now()->subMinutes($I->fake()->numberBetween(2, 59)); + } else { + $availableTo = Carbon::now()->addMinutes($I->fake()->numberBetween(2, 59)); + } + + $bookingProducts[$i] = $I->have(BookingProduct::class, [ + 'type' => 'event', + 'available_to' => $availableTo->toDateTimeString(), + 'product_id' => $products[$i]->id, + ]); + + $I->have(BookingProductEventTicket::class, + ['booking_product_id' => $bookingProducts[$i]->id]); + + $products[$i]->refresh(); + $I->assertNotFalse($products[$i]->status); + } + + $I->callArtisan('booking:cron'); + + for ($i=0; $i<$index; $i++) { + $products[$i]->refresh(); + + if ($bookingProducts[$i]->available_to < Carbon::now()) { + $I->assertEquals(0, $products[$i]->status); + } else { + $I->assertEquals(1, $products[$i]->status); + } + } + } +} +