Merge branch 'master' of https://github.com/bagisto/bagisto
This commit is contained in:
commit
bfd36ab55f
|
|
@ -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');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ mix.js(__dirname + "/src/Resources/assets/js/app.js", "js/admin.js")
|
|||
processCssUrls: false
|
||||
});
|
||||
|
||||
if (!mix.inProduction()) {
|
||||
if (! mix.inProduction()) {
|
||||
mix.sourceMaps();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
<?php
|
||||
|
||||
/** @var \Illuminate\Database\Eloquent\Factory $factory */
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Faker\Generator as Faker;
|
||||
use Webkul\BookingProduct\Models\BookingProduct;
|
||||
use Webkul\BookingProduct\Models\BookingProductEventTicket;
|
||||
use Webkul\Product\Models\Product;
|
||||
|
||||
$factory->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;
|
||||
}
|
||||
];
|
||||
});
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
|
||||
/** @var \Illuminate\Database\Eloquent\Factory $factory */
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Faker\Generator as Faker;
|
||||
use Webkul\BookingProduct\Models\BookingProduct;
|
||||
use Webkul\Product\Models\Product;
|
||||
|
||||
$factory->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;
|
||||
}
|
||||
];
|
||||
});
|
||||
|
|
@ -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'
|
||||
|
|
|
|||
|
|
@ -0,0 +1,75 @@
|
|||
<?php
|
||||
|
||||
namespace Webkul\Core\Console\Commands;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Webkul\Attribute\Models\Attribute;
|
||||
use Webkul\BookingProduct\Models\BookingProduct;
|
||||
use Webkul\Product\Models\ProductAttributeValue;
|
||||
use Webkul\Product\Models\ProductFlat;
|
||||
|
||||
class BookingCron extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'booking:cron';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Deactivates all expired Booking Products of type event';
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$expiredEvents = BookingProduct::query()
|
||||
->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');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -36,7 +36,13 @@ class BundleOption extends AbstractProduct
|
|||
$options = [];
|
||||
|
||||
foreach ($this->product->bundle_options as $option) {
|
||||
$options[$option->id] = $this->getOptionItemData($option);
|
||||
$data = $this->getOptionItemData($option);
|
||||
|
||||
if (! count($data['products'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$options[$option->id] = $data;
|
||||
}
|
||||
|
||||
usort ($options, function($a, $b) {
|
||||
|
|
@ -79,6 +85,10 @@ class BundleOption extends AbstractProduct
|
|||
$products = [];
|
||||
|
||||
foreach ($option->bundle_option_products as $index => $bundleOptionProduct) {
|
||||
if (! $bundleOptionProduct->product->getTypeInstance()->isSaleable()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$products[$bundleOptionProduct->id] = [
|
||||
'id' => $bundleOptionProduct->id,
|
||||
'qty' => $bundleOptionProduct->qty,
|
||||
|
|
@ -110,15 +120,15 @@ class BundleOption extends AbstractProduct
|
|||
{
|
||||
$products = [];
|
||||
|
||||
$products[$product->id] = [
|
||||
'id' => $product->id,
|
||||
'qty' => $product->qty,
|
||||
'price' => $product->product->getTypeInstance()->getProductPrices(),
|
||||
'name' => $product->product->name,
|
||||
'product_id' => $product->product_id,
|
||||
'is_default' => $product->is_default,
|
||||
'sort_order' => $product->sort_order,
|
||||
];
|
||||
$products[$product->id] = [
|
||||
'id' => $product->id,
|
||||
'qty' => $product->qty,
|
||||
'price' => $product->product->getTypeInstance()->getProductPrices(),
|
||||
'name' => $product->product->name,
|
||||
'product_id' => $product->product_id,
|
||||
'is_default' => $product->is_default,
|
||||
'sort_order' => $product->sort_order,
|
||||
];
|
||||
|
||||
usort ($products, function($a, $b) {
|
||||
if ($a['sort_order'] == $b['sort_order']) {
|
||||
|
|
|
|||
|
|
@ -234,6 +234,10 @@ class Bundle extends AbstractType
|
|||
$optionPrices = [];
|
||||
|
||||
foreach ($option->bundle_option_products as $index => $bundleOptionProduct) {
|
||||
if (! $bundleOptionProduct->product->getTypeInstance()->isSaleable()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$optionPrices[] = $bundleOptionProduct->qty
|
||||
* ($minPrice
|
||||
? $bundleOptionProduct->product->getTypeInstance()->getMinimalPrice()
|
||||
|
|
@ -271,6 +275,10 @@ class Bundle extends AbstractType
|
|||
|
||||
foreach ($this->product->bundle_options as $option) {
|
||||
foreach ($option->bundle_option_products as $index => $bundleOptionProduct) {
|
||||
if (! $bundleOptionProduct->product->getTypeInstance()->isSaleable()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (in_array($option->type, ['multiselect', 'checkbox'])) {
|
||||
if (! isset($optionPrices[$option->id][0])) {
|
||||
$optionPrices[$option->id][0] = 0;
|
||||
|
|
@ -304,6 +312,10 @@ class Bundle extends AbstractType
|
|||
|
||||
foreach ($this->product->bundle_options as $option) {
|
||||
foreach ($option->bundle_option_products as $index => $bundleOptionProduct) {
|
||||
if (! $bundleOptionProduct->product->getTypeInstance()->isSaleable()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (in_array($option->type, ['multiselect', 'checkbox'])) {
|
||||
if (! isset($optionPrices[$option->id][0])) {
|
||||
$optionPrices[$option->id][0] = 0;
|
||||
|
|
@ -427,6 +439,10 @@ class Bundle extends AbstractType
|
|||
foreach ($this->getCartChildProducts($data) as $productId => $data) {
|
||||
$product = $this->productRepository->find($productId);
|
||||
|
||||
if (! $product->getTypeInstance()->isSaleable()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$cartProduct = $product->getTypeInstance()->prepareForCart(array_merge($data, ['parent_id' => $this->product->id]));
|
||||
|
||||
if (is_string($cartProduct)) {
|
||||
|
|
@ -473,6 +489,10 @@ class Bundle extends AbstractType
|
|||
'product_bundle_option_id' => $optionId,
|
||||
]);
|
||||
|
||||
if (! $optionProduct->product->getTypeInstance()->isSaleable()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$qty = $data['bundle_option_qty'][$optionId] ?? $optionProduct->qty;
|
||||
|
||||
if (! isset($products[$optionProduct->product_id])) {
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ class DataMocker extends Module
|
|||
/**
|
||||
* Get an instance of the faker
|
||||
*
|
||||
* @return Generator
|
||||
* @return \Faker\Generator
|
||||
*
|
||||
* @author florianbosdorff
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ modules:
|
|||
- Asserts
|
||||
- Filesystem
|
||||
- \Helper\Unit
|
||||
- \Helper\DataMocker
|
||||
- Webkul\Core\Helpers\Laravel5Helper:
|
||||
environment_file: .env.testing
|
||||
run_database_migrations: true
|
||||
|
|
|
|||
|
|
@ -0,0 +1,55 @@
|
|||
<?php
|
||||
|
||||
namespace Tests\Unit\Core\Commands;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use UnitTester;
|
||||
use Webkul\BookingProduct\Models\BookingProduct;
|
||||
use Webkul\BookingProduct\Models\BookingProductEventTicket;
|
||||
use Webkul\Core\Helpers\Laravel5Helper;
|
||||
use Webkul\Product\Models\Product;
|
||||
|
||||
class BookingCronCest
|
||||
{
|
||||
public function testBookingCronDeactivateSomeEvents(UnitTester $I): void
|
||||
{
|
||||
$index = $I->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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue