diff --git a/package.json b/package.json
index 88cbe757f..103d618f3 100755
--- a/package.json
+++ b/package.json
@@ -13,12 +13,16 @@
"devDependencies": {
"axios": "^0.18",
"bootstrap": "^4.0.0",
- "popper.js": "^1.12",
"cross-env": "^5.1",
"jquery": "^3.2",
- "laravel-mix": "^2.0",
+ "laravel-mix": "^5.0.1",
"lodash": "^4.17.4",
- "vue": "^2.5.7"
+ "popper.js": "^1.12",
+ "resolve-url-loader": "^3.1.0",
+ "sass": "^1.24.5",
+ "sass-loader": "^8.0.2",
+ "vue": "^2.5.7",
+ "vue-template-compiler": "^2.6.11"
},
"dependencies": {
"opencollective-postinstall": "^2.0.1",
diff --git a/packages/Webkul/Admin/src/Config/system.php b/packages/Webkul/Admin/src/Config/system.php
index d9a39ee19..39148ce20 100644
--- a/packages/Webkul/Admin/src/Config/system.php
+++ b/packages/Webkul/Admin/src/Config/system.php
@@ -87,10 +87,21 @@ return [
'key' => 'catalog.products',
'name' => 'admin::app.admin.system.products',
'sort' => 2
+ ], [
+ 'key' => 'catalog.products.guest-checkout',
+ 'name' => 'admin::app.admin.system.guest-checkout',
+ 'sort' => 1,
+ 'fields' => [
+ [
+ 'name' => 'allow-guest-checkout',
+ 'title' => 'admin::app.admin.system.allow-guest-checkout',
+ 'type' => 'boolean'
+ ]
+ ]
], [
'key' => 'catalog.products.review',
'name' => 'admin::app.admin.system.review',
- 'sort' => 1,
+ 'sort' => 2,
'fields' => [
[
'name' => 'guest_review',
diff --git a/packages/Webkul/Admin/src/Resources/lang/en/app.php b/packages/Webkul/Admin/src/Resources/lang/en/app.php
index 71aa08dac..adae4ecc7 100755
--- a/packages/Webkul/Admin/src/Resources/lang/en/app.php
+++ b/packages/Webkul/Admin/src/Resources/lang/en/app.php
@@ -1202,6 +1202,9 @@ return [
'system' => [
'catalog' => 'Catalog',
'products' => 'Products',
+ 'guest-checkout' => 'Guest Checkout',
+ 'allow-guest-checkout' => 'Allow Guest Checkout',
+ 'allow-guest-checkout-hint' => 'Hint: If turned on, this option can be configured for each product specifically.',
'review' => 'Review',
'allow-guest-review' => 'Allow Guest Review',
'inventory' => 'Inventory',
diff --git a/packages/Webkul/Admin/src/Resources/views/catalog/products/edit.blade.php b/packages/Webkul/Admin/src/Resources/views/catalog/products/edit.blade.php
index e76ff2035..6adba4afc 100755
--- a/packages/Webkul/Admin/src/Resources/views/catalog/products/edit.blade.php
+++ b/packages/Webkul/Admin/src/Resources/views/catalog/products/edit.blade.php
@@ -77,6 +77,10 @@
@foreach ($customAttributes as $attribute)
code == 'guest_checkout' && ! core()->getConfigData('catalog.products.guest-checkout.allow-guest-checkout')) {
+ continue;
+ }
+
$validations = [];
if ($attribute->is_required) {
diff --git a/packages/Webkul/Admin/src/Resources/views/configuration/index.blade.php b/packages/Webkul/Admin/src/Resources/views/configuration/index.blade.php
index cf1de3a02..a8b39c936 100755
--- a/packages/Webkul/Admin/src/Resources/views/configuration/index.blade.php
+++ b/packages/Webkul/Admin/src/Resources/views/configuration/index.blade.php
@@ -65,6 +65,11 @@
@include ('admin::configuration.field-type', ['field' => $field])
+ @php ($hint = $field['title'] . '-hint')
+ @if ($hint !== __($hint))
+ {{ __($hint) }}
+ @endif
+
@endforeach
diff --git a/packages/Webkul/Attribute/src/Database/Seeders/AttributeFamilyTableSeeder.php b/packages/Webkul/Attribute/src/Database/Seeders/AttributeFamilyTableSeeder.php
index c93bec117..9926ecd3d 100755
--- a/packages/Webkul/Attribute/src/Database/Seeders/AttributeFamilyTableSeeder.php
+++ b/packages/Webkul/Attribute/src/Database/Seeders/AttributeFamilyTableSeeder.php
@@ -3,16 +3,20 @@
namespace Webkul\Attribute\Database\Seeders;
use Illuminate\Database\Seeder;
-use DB;
+use Illuminate\Support\Facades\DB;
class AttributeFamilyTableSeeder extends Seeder
{
public function run()
{
+ DB::statement('SET FOREIGN_KEY_CHECKS=0;');
+
DB::table('attribute_families')->delete();
DB::table('attribute_families')->insert([
['id' => '1','code' => 'default','name' => 'Default','status' => '0','is_user_defined' => '1']
]);
+
+ DB::statement('SET FOREIGN_KEY_CHECKS=1;');
}
}
\ No newline at end of file
diff --git a/packages/Webkul/Attribute/src/Database/Seeders/AttributeGroupTableSeeder.php b/packages/Webkul/Attribute/src/Database/Seeders/AttributeGroupTableSeeder.php
index 92fa5db6c..394c5ac48 100755
--- a/packages/Webkul/Attribute/src/Database/Seeders/AttributeGroupTableSeeder.php
+++ b/packages/Webkul/Attribute/src/Database/Seeders/AttributeGroupTableSeeder.php
@@ -3,12 +3,17 @@
namespace Webkul\Attribute\Database\Seeders;
use Illuminate\Database\Seeder;
-use DB;
+use Illuminate\Support\Facades\DB;
class AttributeGroupTableSeeder extends Seeder
{
public function run()
{
+ DB::statement('SET FOREIGN_KEY_CHECKS=0;');
+
+ DB::table('attribute_groups')->delete();
+ DB::table('attribute_group_mappings')->delete();
+
DB::table('attribute_groups')->delete();
DB::table('attribute_groups')->insert([
@@ -42,9 +47,12 @@ class AttributeGroupTableSeeder extends Seeder
['attribute_id' => '20','attribute_group_id' => '5','position' => '2'],
['attribute_id' => '21','attribute_group_id' => '5','position' => '3'],
['attribute_id' => '22','attribute_group_id' => '5','position' => '4'],
- ['attribute_id' => '23','attribute_group_id' => '1','position' => '9'],
- ['attribute_id' => '24','attribute_group_id' => '1','position' => '10'],
- ['attribute_id' => '25','attribute_group_id' => '1','position' => '11']
+ ['attribute_id' => '23','attribute_group_id' => '1','position' => '10'],
+ ['attribute_id' => '24','attribute_group_id' => '1','position' => '11'],
+ ['attribute_id' => '25','attribute_group_id' => '1','position' => '12'],
+ ['attribute_id' => '26','attribute_group_id' => '1','position' => '9']
]);
+
+ DB::statement('SET FOREIGN_KEY_CHECKS=0;');
}
}
\ No newline at end of file
diff --git a/packages/Webkul/Attribute/src/Database/Seeders/AttributeOptionTableSeeder.php b/packages/Webkul/Attribute/src/Database/Seeders/AttributeOptionTableSeeder.php
index 992c625c0..5bdc0ba9e 100755
--- a/packages/Webkul/Attribute/src/Database/Seeders/AttributeOptionTableSeeder.php
+++ b/packages/Webkul/Attribute/src/Database/Seeders/AttributeOptionTableSeeder.php
@@ -3,7 +3,7 @@
namespace Webkul\Attribute\Database\Seeders;
use Illuminate\Database\Seeder;
-use DB;
+use Illuminate\Support\Facades\DB;
class AttributeOptionTableSeeder extends Seeder
{
@@ -11,6 +11,7 @@ class AttributeOptionTableSeeder extends Seeder
public function run()
{
DB::table('attribute_options')->delete();
+ DB::table('attribute_option_translations')->delete();
DB::table('attribute_options')->insert([
['id' => '1', 'admin_name' => 'Red', 'sort_order' => '1', 'attribute_id' => '23'],
diff --git a/packages/Webkul/Attribute/src/Database/Seeders/AttributeTableSeeder.php b/packages/Webkul/Attribute/src/Database/Seeders/AttributeTableSeeder.php
index 595b37411..829ce982f 100755
--- a/packages/Webkul/Attribute/src/Database/Seeders/AttributeTableSeeder.php
+++ b/packages/Webkul/Attribute/src/Database/Seeders/AttributeTableSeeder.php
@@ -2,9 +2,9 @@
namespace Webkul\Attribute\Database\Seeders;
-use Illuminate\Database\Seeder;
-use DB;
use Carbon\Carbon;
+use Illuminate\Database\Seeder;
+use Illuminate\Support\Facades\DB;
class AttributeTableSeeder extends Seeder
{
@@ -12,6 +12,7 @@ class AttributeTableSeeder extends Seeder
public function run()
{
DB::table('attributes')->delete();
+ DB::table('attribute_translations')->delete();
$now = Carbon::now();
@@ -59,9 +60,11 @@ class AttributeTableSeeder extends Seeder
['id' => '23','code' => 'color','admin_name' => 'Color','type' => 'select','validation' => NULL,'position' => '23','is_required' => '0','is_unique' => '0','value_per_locale' => '0','value_per_channel' => '0','is_filterable' => '1','is_configurable' => '1','is_user_defined' => '1','is_visible_on_front' => '0',
'use_in_flat' => '1','created_at' => $now,'updated_at' => $now],
['id' => '24','code' => 'size','admin_name' => 'Size','type' => 'select','validation' => NULL,'position' => '24','is_required' => '0','is_unique' => '0','value_per_locale' => '0','value_per_channel' => '0','is_filterable' => '1','is_configurable' => '1','is_user_defined' => '1','is_visible_on_front' => '0',
- 'use_in_flat' => '1','created_at' => $now,'updated_at' => $now],
+ 'use_in_flat' => '1','created_at' => $now,'updated_at' => $now],
['id' => '25','code' => 'brand','admin_name' => 'Brand','type' => 'select','validation' => NULL,'position' => '25','is_required' => '0','is_unique' => '0','value_per_locale' => '0','value_per_channel' => '0','is_filterable' => '1','is_configurable' => '0','is_user_defined' => '0','is_visible_on_front' => '1',
- 'use_in_flat' => '1','created_at' => $now,'updated_at' => $now]
+ 'use_in_flat' => '1','created_at' => $now,'updated_at' => $now],
+ ['id' => '26','code' => 'guest_checkout','admin_name' => 'Guest Checkout','type' => 'boolean','validation' => NULL,'position' => '8','is_required' => '1','is_unique' => '0','value_per_locale' => '0','value_per_channel' => '0','is_filterable' => '0','is_configurable' => '0','is_user_defined' => '0','is_visible_on_front' => '0',
+ 'use_in_flat' => '1','created_at' => $now,'updated_at' => $now],
]);
@@ -90,7 +93,8 @@ class AttributeTableSeeder extends Seeder
['id' => '22','locale' => 'en','name' => 'Weight','attribute_id' => '22'],
['id' => '23','locale' => 'en','name' => 'Color','attribute_id' => '23'],
['id' => '24','locale' => 'en','name' => 'Size','attribute_id' => '24'],
- ['id' => '25','locale' => 'en','name' => 'Brand','attribute_id' => '25']
+ ['id' => '25','locale' => 'en','name' => 'Brand','attribute_id' => '25'],
+ ['id' => '26','locale' => 'en','name' => 'Allow Guest Checkout','attribute_id' => '26']
]);
}
}
\ No newline at end of file
diff --git a/packages/Webkul/Attribute/src/Database/Seeders/DatabaseSeeder.php b/packages/Webkul/Attribute/src/Database/Seeders/DatabaseSeeder.php
index b1f9df4a8..148b85486 100755
--- a/packages/Webkul/Attribute/src/Database/Seeders/DatabaseSeeder.php
+++ b/packages/Webkul/Attribute/src/Database/Seeders/DatabaseSeeder.php
@@ -13,9 +13,9 @@ class DatabaseSeeder extends Seeder
*/
public function run()
{
- $this->call(AttributeTableSeeder::class);
- $this->call(AttributeOptionTableSeeder::class);
$this->call(AttributeFamilyTableSeeder::class);
$this->call(AttributeGroupTableSeeder::class);
+ $this->call(AttributeTableSeeder::class);
+ $this->call(AttributeOptionTableSeeder::class);
}
}
diff --git a/packages/Webkul/CMS/src/Database/Seeders/CMSPagesTableSeeder.php b/packages/Webkul/CMS/src/Database/Seeders/CMSPagesTableSeeder.php
index c8ab922f7..92430ab43 100644
--- a/packages/Webkul/CMS/src/Database/Seeders/CMSPagesTableSeeder.php
+++ b/packages/Webkul/CMS/src/Database/Seeders/CMSPagesTableSeeder.php
@@ -2,15 +2,16 @@
namespace Webkul\CMS\Database\Seeders;
-use Illuminate\Database\Seeder;
-use DB;
use Carbon\Carbon;
+use Illuminate\Database\Seeder;
+use Illuminate\Support\Facades\DB;
class CMSPagesTableSeeder extends Seeder
{
public function run()
{
DB::table('cms_pages')->delete();
+ DB::table('cms_page_translations')->delete();
DB::table('cms_pages')->insert([
[
diff --git a/packages/Webkul/Checkout/src/Models/Cart.php b/packages/Webkul/Checkout/src/Models/Cart.php
index 9088531fa..936215c1c 100755
--- a/packages/Webkul/Checkout/src/Models/Cart.php
+++ b/packages/Webkul/Checkout/src/Models/Cart.php
@@ -116,11 +116,11 @@ class Cart extends Model implements CartContract
}
/**
- * Checks if cart have downloadable items
+ * Checks if cart has downloadable items
*
* @return boolean
*/
- public function haveDownloadableItems()
+ public function hasDownloadableItems()
{
foreach ($this->items as $item) {
if ($item->type == 'downloadable')
@@ -129,4 +129,20 @@ class Cart extends Model implements CartContract
return false;
}
+
+ /**
+ * Checks if cart has items that allow guest checkout
+ *
+ * @return boolean
+ */
+ public function hasGuestCheckoutItems()
+ {
+ foreach ($this->items as $item) {
+ if ($item->product->getAttribute('guest_checkout') === 0) {
+ return false;
+ }
+ }
+
+ return true;
+ }
}
\ No newline at end of file
diff --git a/packages/Webkul/Core/src/Database/Seeders/ConfigTableSeeder.php b/packages/Webkul/Core/src/Database/Seeders/ConfigTableSeeder.php
new file mode 100644
index 000000000..fc8e7ec13
--- /dev/null
+++ b/packages/Webkul/Core/src/Database/Seeders/ConfigTableSeeder.php
@@ -0,0 +1,27 @@
+delete();
+
+ $now = Carbon::now();
+
+ DB::table('core_config')->insert([
+ 'id' => 1,
+ 'code' => 'catalog.products.guest-checkout.allow-guest-checkout',
+ 'value' => '1',
+ 'channel_code' => null,
+ 'locale_code' => null,
+ 'created_at' => $now,
+ 'updated_at' => $now
+ ]);
+ }
+}
\ No newline at end of file
diff --git a/packages/Webkul/Core/src/Database/Seeders/DatabaseSeeder.php b/packages/Webkul/Core/src/Database/Seeders/DatabaseSeeder.php
index 919a033ef..6d5013d4f 100755
--- a/packages/Webkul/Core/src/Database/Seeders/DatabaseSeeder.php
+++ b/packages/Webkul/Core/src/Database/Seeders/DatabaseSeeder.php
@@ -18,5 +18,6 @@ class DatabaseSeeder extends Seeder
$this->call(CountriesTableSeeder::class);
$this->call(StatesTableSeeder::class);
$this->call(ChannelTableSeeder::class);
+ $this->call(ConfigTableSeeder::class);
}
}
diff --git a/packages/Webkul/Core/src/Helpers/Laravel5Helper.php b/packages/Webkul/Core/src/Helpers/Laravel5Helper.php
new file mode 100644
index 000000000..99a4f1a1e
--- /dev/null
+++ b/packages/Webkul/Core/src/Helpers/Laravel5Helper.php
@@ -0,0 +1,115 @@
+ 'integer_value',
+ 'sku' => 'text_value',
+ 'name' => 'text_value',
+ 'url_key' => 'text_value',
+ 'tax_category_id' => 'integer_value',
+ 'new' => 'boolean_value',
+ 'featured' => 'boolean_value',
+ 'visible_individually' => 'boolean_value',
+ 'status' => 'boolean_value',
+ 'short_description' => 'text_value',
+ 'description' => 'text_value',
+ 'price' => 'float_value',
+ 'cost' => 'float_value',
+ 'special_price' => 'float_value',
+ 'special_price_from' => 'date_value',
+ 'special_price_to' => 'date_value',
+ 'meta_title' => 'text_value',
+ 'meta_keywords' => 'text_value',
+ 'meta_description' => 'text_value',
+ 'width' => 'integer_value',
+ 'height' => 'integer_value',
+ 'depth' => 'integer_value',
+ 'weight' => 'integer_value',
+ 'color' => 'integer_value',
+ 'size' => 'integer_value',
+ 'brand' => 'text_value',
+ 'guest_checkout' => 'boolean_value',
+ ];
+ if (!array_key_exists($attribute, $attributes)) {
+ return null;
+ }
+ return $attributes[$attribute];
+ }
+ /**
+ * @param array $attributeValueStates
+ *
+ * @return \Webkul\Product\Models\Product
+ * @part ORM
+ */
+ public function haveProduct(
+ array $configs = [],
+ array $productStates = []
+ ): Product {
+ $I = $this;
+ /** @var Product $product */
+ $product = factory(Product::class)->states($productStates)->create($configs['productAttributes'] ?? []);;
+ $I->createAttributeValues($product->id,$configs['attributeValues'] ?? []);
+ $I->have(ProductInventory::class, array_merge($configs['productInventory'] ?? [], [
+ 'product_id' => $product->id,
+ 'inventory_source_id' => 1,
+ ]));
+ Event::fire('catalog.product.create.after', $product);
+ return $product;
+ }
+ private function createAttributeValues($id, array $attributeValues = [])
+ {
+ $I = $this;
+ $productAttributeValues = [
+ 'sku',
+ 'url_key',
+ 'tax_category_id',
+ 'price',
+ 'cost',
+ 'name',
+ 'new',
+ 'visible_individually',
+ 'featured',
+ 'status',
+ 'guest_checkout',
+ 'short_description',
+ 'description',
+ 'meta_title',
+ 'meta_keywords',
+ 'meta_description',
+ 'weight',
+ ];
+ foreach ($productAttributeValues as $attribute) {
+ $data = ['product_id' => $id];
+ if (array_key_exists($attribute, $attributeValues)) {
+ $fieldName = self::getAttributeFieldName($attribute);
+ if (! array_key_exists($fieldName, $data)) {
+ $data[$fieldName] = $attributeValues[$attribute];
+ } else {
+ $data = [$fieldName => $attributeValues[$attribute]];
+ }
+ }
+ $I->have(ProductAttributeValue::class, $data, $attribute);
+ }
+ }
+}
\ No newline at end of file
diff --git a/packages/Webkul/Inventory/src/Database/Factories/InventorySourceFactory.php b/packages/Webkul/Inventory/src/Database/Factories/InventorySourceFactory.php
new file mode 100644
index 000000000..53234a1a5
--- /dev/null
+++ b/packages/Webkul/Inventory/src/Database/Factories/InventorySourceFactory.php
@@ -0,0 +1,27 @@
+define(InventorySource::class, function (Faker $faker) {
+ $now = date("Y-m-d H:i:s");
+ $code = $faker->unique()->word;
+ return [
+ 'code' => $faker->unique()->word,
+ 'name' => $code,
+ 'description' => $faker->sentence,
+ 'contact_name' => $faker->name,
+ 'contact_email' => $faker->safeEmail,
+ 'contact_number' => $faker->phoneNumber,
+ 'country' => $faker->countryCode,
+ 'state' => $faker->state,
+ 'city' => $faker->city,
+ 'street' => $faker->streetAddress,
+ 'postcode' => $faker->postcode,
+ 'priority' => 0,
+ 'status' => 1,
+ 'created_at' => $now,
+ 'updated_at' => $now,
+ ];
+});
\ No newline at end of file
diff --git a/packages/Webkul/Product/src/Database/Factories/ProductAttributeValueFactory.php b/packages/Webkul/Product/src/Database/Factories/ProductAttributeValueFactory.php
new file mode 100644
index 000000000..4da6ddaf0
--- /dev/null
+++ b/packages/Webkul/Product/src/Database/Factories/ProductAttributeValueFactory.php
@@ -0,0 +1,261 @@
+defineAs(ProductAttributeValue::class, 'sku', function (Faker $faker) {
+ return [
+ 'product_id' => function () {
+ return factory(Product::class)->create()->id;
+ },
+ 'text_value' => $faker->uuid,
+ 'attribute_id' => 1,
+ ];
+});
+$factory->defineAs(ProductAttributeValue::class, 'name', function (Faker $faker) {
+ return [
+ 'product_id' => function () {
+ return factory(Product::class)->create()->id;
+ },
+ 'locale' => 'en', //$faker->languageCode,
+ 'channel' => 'default',
+ 'text_value' => $faker->words(2, true),
+ 'attribute_id' => 2,
+ ];
+});
+$factory->defineAs(ProductAttributeValue::class, 'url_key', function (Faker $faker) {
+ return [
+ 'product_id' => function () {
+ return factory(Product::class)->create()->id;
+ },
+ 'text_value' => $faker->unique()->slug,
+ 'attribute_id' => 3,
+ ];
+});
+$factory->defineAs(ProductAttributeValue::class, 'tax_category_id', function (Faker $faker) {
+ return [
+ 'product_id' => function () {
+ return factory(Product::class)->create()->id;
+ },
+ 'channel' => 'default',
+ 'integer_value' => null, // ToDo
+ 'attribute_id' => 4,
+ ];
+});
+$factory->defineAs(ProductAttributeValue::class, 'new', function (Faker $faker) {
+ return [
+ 'product_id' => function () {
+ return factory(Product::class)->create()->id;
+ },
+ 'boolean_value' => 1,
+ 'attribute_id' => 5,
+ ];
+});
+$factory->defineAs(ProductAttributeValue::class, 'featured', function (Faker $faker) {
+ return [
+ 'product_id' => function () {
+ return factory(Product::class)->create()->id;
+ },
+ 'boolean_value' => 1,
+ 'attribute_id' => 6,
+ ];
+});
+$factory->defineAs(ProductAttributeValue::class, 'visible_individually', function (Faker $faker) {
+ return [
+ 'product_id' => function () {
+ return factory(Product::class)->create()->id;
+ },
+ 'boolean_value' => 1,
+ 'attribute_id' => 7,
+ ];
+});
+$factory->defineAs(ProductAttributeValue::class, 'status', function (Faker $faker) {
+ return [
+ 'product_id' => function () {
+ return factory(Product::class)->create()->id;
+ },
+ 'boolean_value' => 1,
+ 'attribute_id' => 8,
+ ];
+});
+$factory->defineAs(ProductAttributeValue::class, 'short_description', function (Faker $faker) {
+ return [
+ 'product_id' => function () {
+ return factory(Product::class)->create()->id;
+ },
+ 'locale' => 'en', //$faker->languageCode,
+ 'channel' => 'default',
+ 'text_value' => $faker->sentence,
+ 'attribute_id' => 9,
+ ];
+});
+$factory->defineAs(ProductAttributeValue::class, 'description', function (Faker $faker) {
+ return [
+ 'product_id' => function () {
+ return factory(Product::class)->create()->id;
+ },
+ 'locale' => 'en', //$faker->languageCode,
+ 'channel' => 'default',
+ 'text_value' => $faker->sentences(3, true),
+ 'attribute_id' => 10,
+ ];
+});
+$factory->defineAs(ProductAttributeValue::class, 'price', function (Faker $faker) {
+ return [
+ 'product_id' => function () {
+ return factory(Product::class)->create()->id;
+ },
+ 'float_value' => $faker->randomFloat(4, 0, 1000),
+ 'attribute_id' => 11,
+ ];
+});
+$factory->defineAs(ProductAttributeValue::class, 'cost', function (Faker $faker) {
+ return [
+ 'product_id' => function () {
+ return factory(Product::class)->create()->id;
+ },
+ 'channel' => 'default',
+ 'float_value' => $faker->randomFloat(4, 0, 10),
+ 'attribute_id' => 12,
+ ];
+});
+$factory->defineAs(ProductAttributeValue::class, 'special_price', function (Faker $faker) {
+ return [
+ 'product_id' => function () {
+ return factory(Product::class)->create()->id;
+ },
+ 'float_value' => $faker->randomFloat(4, 0, 100),
+ 'attribute_id' => 13,
+ ];
+});
+$factory->defineAs(ProductAttributeValue::class, 'special_price_from', function (Faker $faker) {
+ return [
+ 'product_id' => function () {
+ return factory(Product::class)->create()->id;
+ },
+ 'channel' => 'default',
+ 'date_value' => $faker->dateTimeBetween('-5 days', 'now', 'Europe/Berlin'),
+ 'attribute_id' => 14,
+ ];
+});
+$factory->defineAs(ProductAttributeValue::class, 'special_price_to', function (Faker $faker) {
+ return [
+ 'product_id' => function () {
+ return factory(Product::class)->create()->id;
+ },
+ 'channel' => 'default',
+ 'date_value' => $faker->dateTimeBetween('now', '+ 5 days', 'Europe/Berlin'),
+ 'attribute_id' => 15,
+ ];
+});
+$factory->defineAs(ProductAttributeValue::class, 'meta_title', function (Faker $faker) {
+ return [
+ 'product_id' => function () {
+ return factory(Product::class)->create()->id;
+ },
+ 'locale' => 'en', //$faker->languageCode,
+ 'channel' => 'default',
+ 'text_value' => $faker->words(2, true),
+ 'attribute_id' => 16,
+ ];
+});
+$factory->defineAs(ProductAttributeValue::class, 'meta_keywords', function (Faker $faker) {
+ return [
+ 'product_id' => function () {
+ return factory(Product::class)->create()->id;
+ },
+ 'locale' => 'en', //$faker->languageCode,
+ 'channel' => 'default',
+ 'text_value' => $faker->words(5, true),
+ 'attribute_id' => 17,
+ ];
+});
+$factory->defineAs(ProductAttributeValue::class, 'meta_description', function (Faker $faker) {
+ return [
+ 'product_id' => function () {
+ return factory(Product::class)->create()->id;
+ },
+ 'locale' => 'en', //$faker->languageCode,
+ 'channel' => 'default',
+ 'text_value' => $faker->sentence,
+ 'attribute_id' => 18,
+ ];
+});
+$factory->defineAs(ProductAttributeValue::class, 'width', function (Faker $faker) {
+ return [
+ 'product_id' => function () {
+ return factory(Product::class)->create()->id;
+ },
+ 'integer_value' => $faker->numberBetween(1, 50),
+ 'attribute_id' => 19,
+ ];
+});
+$factory->defineAs(ProductAttributeValue::class, 'height', function (Faker $faker) {
+ return [
+ 'product_id' => function () {
+ return factory(Product::class)->create()->id;
+ },
+ 'integer_value' => $faker->numberBetween(1, 50),
+ 'attribute_id' => 20,
+ ];
+});
+$factory->defineAs(ProductAttributeValue::class, 'depth', function (Faker $faker) {
+ return [
+ 'product_id' => function () {
+ return factory(Product::class)->create()->id;
+ },
+ 'integer_value' => $faker->numberBetween(1, 50),
+ 'attribute_id' => 21,
+ ];
+});
+$factory->defineAs(ProductAttributeValue::class, 'weight', function (Faker $faker) {
+ return [
+ 'product_id' => function () {
+ return factory(Product::class)->create()->id;
+ },
+ 'integer_value' => $faker->numberBetween(1, 50),
+ 'attribute_id' => 22,
+ ];
+});
+$factory->defineAs(ProductAttributeValue::class, 'color', function (Faker $faker) {
+ return [
+ 'product_id' => function () {
+ return factory(Product::class)->create()->id;
+ },
+ 'integer_value' => $faker->numberBetween(1, 5),
+ 'attribute_id' => 23,
+ ];
+});
+$factory->defineAs(ProductAttributeValue::class, 'size', function (Faker $faker) {
+ return [
+ 'product_id' => function () {
+ return factory(Product::class)->create()->id;
+ },
+ 'integer_value' => $faker->numberBetween(1, 5),
+ 'attribute_id' => 24,
+ ];
+});
+$factory->defineAs(ProductAttributeValue::class, 'brand', function (Faker $faker) {
+ return [
+ 'product_id' => function () {
+ return factory(Product::class)->create()->id;
+ },
+ 'attribute_id' => 25,
+ 'integer_value' => function () {
+ return factory(AttributeOption::class)->create()->id;
+ },
+ ];
+});
+$factory->defineAs(ProductAttributeValue::class, 'guest_checkout', function ( Faker $faker) {
+ return [
+ 'product_id' => function() {
+ return factory(Product::class)->create()->id;
+ },
+ 'boolean_value' => 1,
+ 'attribute_id' => 26,
+ ];
+});
\ No newline at end of file
diff --git a/packages/Webkul/Product/src/Database/Factories/ProductFactory.php b/packages/Webkul/Product/src/Database/Factories/ProductFactory.php
new file mode 100644
index 000000000..0caf3ded5
--- /dev/null
+++ b/packages/Webkul/Product/src/Database/Factories/ProductFactory.php
@@ -0,0 +1,23 @@
+define(Product::class, function (Faker $faker) {
+ $now = date("Y-m-d H:i:s");
+ return [
+ 'sku' => $faker->uuid,
+ 'created_at' => $now,
+ 'updated_at' => $now,
+ 'attribute_family_id' => 1,
+ ];
+});
+
+$factory->state(Product::class, 'simple', [
+ 'type' => 'simple',
+]);
+$factory->state(Product::class, 'downloadable_with_stock', [
+ 'type' => 'downloadable',
+]);
\ No newline at end of file
diff --git a/packages/Webkul/Product/src/Database/Factories/ProductInventoryFactory.php b/packages/Webkul/Product/src/Database/Factories/ProductInventoryFactory.php
new file mode 100644
index 000000000..fc3b9d122
--- /dev/null
+++ b/packages/Webkul/Product/src/Database/Factories/ProductInventoryFactory.php
@@ -0,0 +1,20 @@
+define(ProductInventory::class, function (Faker $faker) {
+ return [
+ 'qty' => $faker->numberBetween(1, 20),
+ 'product_id' => function () {
+ return factory(Product::class)->create()->id;
+ },
+ 'inventory_source_id' => function () {
+ return factory(InventorySource::class)->create()->id;
+ },
+ ];
+});
\ No newline at end of file
diff --git a/packages/Webkul/Product/src/Providers/ProductServiceProvider.php b/packages/Webkul/Product/src/Providers/ProductServiceProvider.php
index 902f5261b..e95c7563f 100755
--- a/packages/Webkul/Product/src/Providers/ProductServiceProvider.php
+++ b/packages/Webkul/Product/src/Providers/ProductServiceProvider.php
@@ -2,6 +2,7 @@
namespace Webkul\Product\Providers;
+use Illuminate\Database\Eloquent\Factory as EloquentFactory;
use Illuminate\Support\ServiceProvider;
use Webkul\Product\Models\ProductProxy;
use Webkul\Product\Observers\ProductObserver;
@@ -32,14 +33,21 @@ class ProductServiceProvider extends ServiceProvider
*
* @return void
*/
- public function register()
+ public function register(): void
{
$this->registerConfig();
$this->registerCommands();
+
+ $this->registerEloquentFactoriesFrom(__DIR__ . '/../Database/Factories');
}
- public function registerConfig() {
+ /**
+ * Register Configuration
+ *
+ * @return void
+ */
+ public function registerConfig(): void {
$this->mergeConfigFrom(
dirname(__DIR__) . '/Config/product_types.php', 'product_types'
);
@@ -47,10 +55,24 @@ class ProductServiceProvider extends ServiceProvider
/**
* Register the console commands of this package
+ *
+ * @return void
*/
- protected function registerCommands()
+ protected function registerCommands(): void
{
- if ($this->app->runningInConsole())
+ if ($this->app->runningInConsole()) {
$this->commands([PriceUpdate::class,]);
+ }
+ }
+
+ /**
+ * Register factories.
+ *
+ * @param string $path
+ * @return void
+ */
+ protected function registerEloquentFactoriesFrom($path): void
+ {
+ $this->app->make(EloquentFactory::class)->load($path);
}
}
\ No newline at end of file
diff --git a/packages/Webkul/Product/src/Type/Downloadable.php b/packages/Webkul/Product/src/Type/Downloadable.php
index aaf97acdf..fa7cd8c9b 100644
--- a/packages/Webkul/Product/src/Type/Downloadable.php
+++ b/packages/Webkul/Product/src/Type/Downloadable.php
@@ -22,14 +22,14 @@ class Downloadable extends AbstractType
{
/**
* ProductDownloadableLinkRepository instance
- *
+ *
* @var ProductDownloadableLinkRepository
*/
protected $productDownloadableLinkRepository;
/**
* ProductDownloadableSampleRepository instance
- *
+ *
* @var ProductDownloadableSampleRepository
*/
protected $productDownloadableSampleRepository;
@@ -39,11 +39,11 @@ class Downloadable extends AbstractType
*
* @var array
*/
- protected $skipAttributes = ['width', 'height', 'depth', 'weight'];
+ protected $skipAttributes = ['width', 'height', 'depth', 'weight', 'guest_checkout'];
/**
* These blade files will be included in product edit page
- *
+ *
* @var array
*/
protected $additionalViews = [
@@ -111,7 +111,7 @@ class Downloadable extends AbstractType
if (request()->route()->getName() != 'admin.catalog.products.massupdate') {
$this->productDownloadableLinkRepository->saveLinks($data, $product);
-
+
$this->productDownloadableSampleRepository->saveSamples($data, $product);
}
@@ -127,11 +127,11 @@ class Downloadable extends AbstractType
{
if (! $this->product->status)
return false;
-
+
if ($this->product->downloadable_links()->count())
return true;
- return false;
+ return false;
}
/**
@@ -177,7 +177,7 @@ class Downloadable extends AbstractType
return $products;
}
-
+
/**
*
* @param array $options1
diff --git a/packages/Webkul/Shop/src/Http/Controllers/OnepageController.php b/packages/Webkul/Shop/src/Http/Controllers/OnepageController.php
index 12dad01aa..06fa3dacc 100755
--- a/packages/Webkul/Shop/src/Http/Controllers/OnepageController.php
+++ b/packages/Webkul/Shop/src/Http/Controllers/OnepageController.php
@@ -64,13 +64,22 @@ class OnepageController extends Controller
*/
public function index()
{
+ if (! auth()->guard('customer')->check() && ! core()->getConfigData('catalog.products.guest-checkout.allow-guest-checkout')) {
+ return redirect()->route('customer.session.index');
+ }
+
if (Cart::hasError())
return redirect()->route('shop.checkout.cart.index');
$cart = Cart::getCart();
- if (! auth()->guard('customer')->check() && $cart->haveDownloadableItems())
+ if (! auth()->guard('customer')->check() && $cart->hasDownloadableItems()) {
return redirect()->route('customer.session.index');
+ }
+
+ if (! auth()->guard('customer')->check() && ! $cart->hasGuestCheckoutItems()) {
+ return redirect()->route('customer.session.index');
+ }
Cart::collectTotals();
diff --git a/tests/_support/AcceptanceTester.php b/tests/_support/AcceptanceTester.php
index 95c00ec21..9adb03862 100644
--- a/tests/_support/AcceptanceTester.php
+++ b/tests/_support/AcceptanceTester.php
@@ -23,4 +23,20 @@ class AcceptanceTester extends \Codeception\Actor
/**
* Define custom actions here
*/
+
+ /**
+ * Logging in as an Admin
+ */
+ public function loginAsAdmin()
+ {
+ $I = $this;
+ $I->amOnPage('/admin');
+ $I->see('Sign In');
+ $I->fillField('email', 'admin@example.com');
+ $I->fillField('password', 'admin123');
+ $I->dontSee('The "Email" field is required.');
+ $I->dontSee('The "Password" field is required.');
+ $I->click('Sign In');
+ $I->see('Dashboard', '//h1');
+ }
}
diff --git a/tests/_support/FunctionalTester.php b/tests/_support/FunctionalTester.php
index ea07902b1..38b53fd7d 100644
--- a/tests/_support/FunctionalTester.php
+++ b/tests/_support/FunctionalTester.php
@@ -2,6 +2,7 @@
use Illuminate\Routing\RouteCollection;
use Illuminate\Support\Facades\Auth;
+use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Route;
use Webkul\User\Models\Admin;
@@ -58,4 +59,26 @@ class FunctionalTester extends \Codeception\Actor
$I->assertContains('admin', $middlewares, 'check that admin middleware is applied');
}
+ /**
+ * Set specific Webkul/Core configuration keys to a given value
+ *
+ * // TODO: change method as soon as there is a method to set core config data
+ *
+ * @param $data array containing 'code => value' pairs
+ * @return void
+ */
+ public function setConfigData($data): void {
+ foreach ($data as $key => $value) {
+ if (DB::table('core_config')->where('code', '=', $key)->exists()) {
+ DB::table('core_config')->where('code', '=', $key)->update(['value' => $value]);
+ } else {
+ DB::table('core_config')->insert([
+ 'code' => $key,
+ 'value' => $value,
+ 'created_at' => date('Y-m-d H:i:s'),
+ 'updated_at' => date('Y-m-d H:i:s')
+ ]);
+ }
+ }
+ }
}
diff --git a/tests/acceptance.suite.yml b/tests/acceptance.suite.yml
index 267af5b80..ba234fcea 100644
--- a/tests/acceptance.suite.yml
+++ b/tests/acceptance.suite.yml
@@ -7,7 +7,23 @@
actor: AcceptanceTester
modules:
enabled:
- - PhpBrowser:
- url: http://localhost
- - \Helper\Acceptance
- step_decorators: ~
\ No newline at end of file
+ - \Helper\Acceptance
+ - Asserts
+ - WebDriver:
+ url: http://nginx/
+ host: selenium-chrome
+ browser: chrome
+ window_size: 1920x1080
+ restart: true
+ wait: 20
+ pageload_timeout: 10
+ connection_timeout: 60
+ request_timeout: 60
+ log_js_errors: true
+ - Laravel5:
+ part: ORM
+ cleanup: false
+ environment_file: .env
+ database_seeder_class: DatabaseSeeder
+ url: http://nginx
+step_decorators: ~
\ No newline at end of file
diff --git a/tests/acceptance/GuestCheckoutCest.php b/tests/acceptance/GuestCheckoutCest.php
new file mode 100644
index 000000000..f862a34bf
--- /dev/null
+++ b/tests/acceptance/GuestCheckoutCest.php
@@ -0,0 +1,59 @@
+faker = Factory::create();
+ }
+
+ function testToConfigureGlobalGuestCheckout(AcceptanceTester $I)
+ {
+ $I->loginAsAdmin();
+
+ $I->amGoingTo('turn ON the global guest checkout configuration');
+ $I->amOnPage('/admin/configuration/catalog/products');
+ $I->see(__('admin::app.admin.system.allow-guest-checkout'));
+ $I->selectOption('catalog[products][guest-checkout][allow-guest-checkout]', 1);
+ $I->click(__('admin::app.configuration.save-btn-title'));
+ $I->seeRecord('core_config', ['code' => 'catalog.products.guest-checkout.allow-guest-checkout', 'value' => 1]);
+
+ $I->amGoingTo('assert that the product guest checkout configuration is shown');
+ $I->amOnPage('admin/catalog/products');
+ $I->click(__('admin::app.catalog.products.add-product-btn-title'));
+ $I->selectOption('attribute_family_id', 1);
+ $I->fillField('sku', $this->faker->uuid);
+ $I->dontSeeInSource('The "SKU" field is required.');
+ $I->click(__('admin::app.catalog.products.save-btn-title'));
+ $I->seeInCurrentUrl('admin/catalog/products/edit');
+ $I->scrollTo('#new');
+ $I->see('Guest Checkout');
+ $I->seeInSource('amGoingTo('turn OFF the global guest checkout configuration');
+ $I->amOnPage('/admin/configuration/catalog/products');
+ $I->see(__('admin::app.admin.system.allow-guest-checkout'));
+ $I->selectOption('catalog[products][guest-checkout][allow-guest-checkout]', 0);
+ $I->click(__('admin::app.configuration.save-btn-title'));
+ $I->seeRecord('core_config', ['code' => 'catalog.products.guest-checkout.allow-guest-checkout', 'value' => 0]);
+
+ $I->amGoingTo('assert that the product guest checkout configuration is not shown');
+ $I->amOnPage('admin/catalog/products');
+ $I->click(__('admin::app.catalog.products.add-product-btn-title'));
+ $I->selectOption('attribute_family_id', 1);
+ $I->fillField('sku', $this->faker->uuid);
+ $I->dontSeeInSource('The "SKU" field is required.');
+ $I->click(__('admin::app.catalog.products.save-btn-title'));
+ $I->seeInCurrentUrl('admin/catalog/products/edit');
+ $I->scrollTo('#new');
+ $I->dontSee('Guest Checkout');
+ $I->dontSeeInSource('selectOption('select#attribute_family_id', $attributeFamily->id);
- $sku = $this->faker->randomNumber(3);
+ $sku = $this->faker->uuid;
$I->fillField('sku', $sku);
$I->click(__('admin::app.catalog.products.save-btn-title'));
diff --git a/tests/functional/Shop/GuestCheckoutCest.php b/tests/functional/Shop/GuestCheckoutCest.php
new file mode 100644
index 000000000..d6a66f732
--- /dev/null
+++ b/tests/functional/Shop/GuestCheckoutCest.php
@@ -0,0 +1,90 @@
+faker = Factory::create();
+
+ $pConfigDefault = [
+ 'productInventory' => ['qty' => $this->faker->randomNumber(2)],
+ 'attributeValues' => [
+ 'status' => true,
+ 'new' => 1,
+ 'guest_checkout' => 0
+ ],
+ ];
+ $pConfigGuestCheckout = [
+ 'productInventory' => ['qty' => $this->faker->randomNumber(2)],
+ 'attributeValues' => [
+ 'status' => true,
+ 'new' => 1,
+ 'guest_checkout' => 1
+ ],
+ ];
+
+ $this->productNoGuestCheckout = $I->haveProduct($pConfigDefault, ['simple']);
+ $this->productNoGuestCheckout->refresh();
+
+ $this->productGuestCheckout = $I->haveProduct($pConfigGuestCheckout, ['simple']);
+ $this->productGuestCheckout->refresh();
+ }
+
+ public function testGuestCheckout(FunctionalTester $I) {
+ $I->amGoingTo('try to add products to cart with guest checkout turned on or off');
+
+ $scenarios = [
+ [
+ 'name' => 'false / false',
+ 'globalConfig' => 0,
+ 'product' => $this->productNoGuestCheckout,
+ 'expectedRoute' => 'customer.session.index'
+ ],
+ [
+ 'name' => 'false / true',
+ 'globalConfig' => 0,
+ 'product' => $this->productGuestCheckout,
+ 'expectedRoute' => 'customer.session.index'
+ ],
+ [
+ 'name' => 'true / false',
+ 'globalConfig' => 1,
+ 'product' => $this->productNoGuestCheckout,
+ 'expectedRoute' => 'customer.session.index'
+ ],
+ [
+ 'name' => 'true / true',
+ 'globalConfig' => 1,
+ 'product' => $this->productGuestCheckout,
+ 'expectedRoute' => 'shop.checkout.onepage.index'
+ ],
+ ];
+
+ foreach ($scenarios as $scenario) {
+ $I->wantTo('test conjunction "' . $scenario['name'] . '" with globalConfig = ' . $scenario['globalConfig'] . ' && product config = ' . $scenario['product']->getAttribute('guest_checkout'));
+ $I->setConfigData(['catalog.products.guest-checkout.allow-guest-checkout' => $scenario['globalConfig']]);
+ $I->assertEquals($scenario['globalConfig'], core()->getConfigData('catalog.products.guest-checkout.allow-guest-checkout'));
+ $I->amOnRoute('shop.home.index');
+ $I->see($scenario['product']->name, '//div[@class="product-information"]/div[@class="product-name"]');
+ $I->click(__('shop::app.products.add-to-cart'),
+ '//form[input[@name="product_id"][@value="' . $scenario['product']->id . '"]]/button');
+ $I->seeInSource(__('shop::app.checkout.cart.item.success'));
+ $I->amOnRoute('shop.checkout.cart.index');
+ $I->see('Shopping Cart', '//div[@class="title"]');
+ $I->makeHtmlSnapshot('guestCheckout_'.$scenario['globalConfig'].'_'.$scenario['product']->getAttribute('guest_checkout'));
+ $I->see($scenario['product']->name, '//div[@class="item-title"]');
+ $I->click( __('shop::app.checkout.cart.proceed-to-checkout'), '//a[@href="' . route('shop.checkout.onepage.index') . '"]');
+ $I->seeCurrentRouteIs($scenario['expectedRoute']);
+ $cart = Cart::getCart();
+ $I->assertTrue(Cart::removeItem($cart->items[0]->id));
+ }
+ }
+}
\ No newline at end of file