diff --git a/.env.testing b/.env.testing
index 299f945da..e87932525 100644
--- a/.env.testing
+++ b/.env.testing
@@ -42,4 +42,4 @@ MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
SHOP_MAIL_FROM=test@example.com
-ADMIN_MAIL_TO=test@example.com
\ No newline at end of file
+ADMIN_MAIL_TO=test@example.com
diff --git a/.gitignore b/.gitignore
index f8f0d01e0..a19a6d127 100644
--- a/.gitignore
+++ b/.gitignore
@@ -24,6 +24,5 @@ yarn.lock
.php_cs.cache
storage/
storage/*.key
-
+/docker-compose-collection/
/resources/themes/velocity/*
-
diff --git a/packages/Webkul/Admin/src/Resources/views/cms/create.blade.php b/packages/Webkul/Admin/src/Resources/views/cms/create.blade.php
index cbe5f131c..2ad5a0f13 100644
--- a/packages/Webkul/Admin/src/Resources/views/cms/create.blade.php
+++ b/packages/Webkul/Admin/src/Resources/views/cms/create.blade.php
@@ -96,6 +96,7 @@
+
diff --git a/packages/Webkul/Admin/src/Resources/views/cms/edit.blade.php b/packages/Webkul/Admin/src/Resources/views/cms/edit.blade.php
index bf35f6b7a..052a565d9 100644
--- a/packages/Webkul/Admin/src/Resources/views/cms/edit.blade.php
+++ b/packages/Webkul/Admin/src/Resources/views/cms/edit.blade.php
@@ -104,12 +104,14 @@
+
+
diff --git a/packages/Webkul/Checkout/src/Cart.php b/packages/Webkul/Checkout/src/Cart.php
index 9157dc392..6c2c5df49 100755
--- a/packages/Webkul/Checkout/src/Cart.php
+++ b/packages/Webkul/Checkout/src/Cart.php
@@ -128,7 +128,7 @@ class Cart {
*
* @param integer $productId
* @param array $data
- * @return Cart
+ * @return Mixed Cart on success, array with warning otherwise
*/
public function addProduct($productId, $data)
{
@@ -136,8 +136,9 @@ class Cart {
$cart = $this->getCart();
- if (! $cart && ! $cart = $this->create($data))
- return;
+ if (! $cart && ! $cart = $this->create($data)) {
+ return ['warning' => __('shop::app.checkout.cart.item.error-add')];
+ }
$product = $this->productRepository->findOneByField('id', $productId);
@@ -157,8 +158,9 @@ class Cart {
foreach ($cartProducts as $cartProduct) {
$cartItem = $this->getItemByProduct($cartProduct);
- if (isset($cartProduct['parent_id']))
+ if (isset($cartProduct['parent_id'])) {
$cartProduct['parent_id'] = $parentCartItem->id;
+ }
if (! $cartItem) {
$cartItem = $this->cartItemRepository->create(array_merge($cartProduct, ['cart_id' => $cart->id]));
@@ -166,6 +168,9 @@ class Cart {
if (isset($cartProduct['parent_id']) && $cartItem->parent_id != $parentCartItem->id) {
$cartItem = $this->cartItemRepository->create(array_merge($cartProduct, ['cart_id' => $cart->id]));
} else {
+ if ($product->getTypeInstance()->showQuantityBox() === false) {
+ return ['warning' => __('shop::app.checkout.cart.integrity.qty_impossible')];
+ }
$cartItem = $this->cartItemRepository->update($cartProduct, $cartItem->id);
}
}
diff --git a/packages/Webkul/Checkout/src/Models/Cart.php b/packages/Webkul/Checkout/src/Models/Cart.php
index 936215c1c..ba13c788b 100755
--- a/packages/Webkul/Checkout/src/Models/Cart.php
+++ b/packages/Webkul/Checkout/src/Models/Cart.php
@@ -123,13 +123,29 @@ class Cart extends Model implements CartContract
public function hasDownloadableItems()
{
foreach ($this->items as $item) {
- if ($item->type == 'downloadable')
+ if (stristr($item->type,'downloadable') !== false) {
return true;
+ }
}
return false;
}
+ /**
+ * Returns true if cart contains one or many products with quantity box.
+ * (for example: simple, configurable, virtual)
+ * @return bool
+ */
+ public function hasProductsWithQuantityBox(): bool
+ {
+ foreach ($this->items as $item) {
+ if ($item->product->getTypeInstance()->showQuantityBox() === true) {
+ return true;
+ }
+ }
+ return false;
+ }
+
/**
* Checks if cart has items that allow guest checkout
*
@@ -145,4 +161,4 @@ class Cart extends Model implements CartContract
return true;
}
-}
\ No newline at end of file
+}
diff --git a/packages/Webkul/Core/src/Helpers/Laravel5Helper.php b/packages/Webkul/Core/src/Helpers/Laravel5Helper.php
index 7b8cfb7f2..b15b3d89f 100644
--- a/packages/Webkul/Core/src/Helpers/Laravel5Helper.php
+++ b/packages/Webkul/Core/src/Helpers/Laravel5Helper.php
@@ -1,4 +1,5 @@
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::dispatch('catalog.product.create.after', $product);
+
+ switch ($productType) {
+ case self::DOWNLOADABLE_PRODUCT:
+ $product = $I->haveDownloadableProduct($configs, $productStates);
+ break;
+
+ case self::VIRTUAL_PRODUCT:
+ $product = $I->haveVirtualProduct($configs, $productStates);
+ break;
+
+ case self::SIMPLE_PRODUCT:
+ default:
+ $product = $I->haveSimpleProduct($configs, $productStates);
+ }
+
+ if ($product !== null) {
+ Event::dispatch('catalog.product.create.after', $product);
+ }
+
return $product;
}
- private function createAttributeValues($id, array $attributeValues = [])
+
+ /**
+ * @param array $configs
+ * @param array $productStates
+ *
+ * @return \Webkul\Product\Models\Product
+ */
+ private function haveSimpleProduct(array $configs = [], array $productStates = []): Product
+ {
+ $I = $this;
+ if (!in_array('simple', $productStates)) {
+ $productStates = array_merge($productStates, ['simple']);
+ }
+
+ /** @var Product $product */
+ $product = $I->createProduct($configs['productAttributes'] ?? [], $productStates);
+
+ $I->createAttributeValues($product->id, $configs['attributeValues'] ?? []);
+
+ $I->createInventory($product->id, $configs['productInventory'] ?? []);
+
+ return $product->refresh();
+ }
+
+ /**
+ * @param array $configs
+ * @param array $productStates
+ *
+ * @return \Webkul\Product\Models\Product
+ */
+ private function haveVirtualProduct(array $configs = [], array $productStates = []): Product
+ {
+ $I = $this;
+ if (!in_array('virtual', $productStates)) {
+ $productStates = array_merge($productStates, ['virtual']);
+ }
+
+ /** @var Product $product */
+ $product = $I->createProduct($configs['productAttributes'] ?? [], $productStates);
+
+ $I->createAttributeValues($product->id, $configs['attributeValues'] ?? []);
+
+ $I->createInventory($product->id, $configs['productInventory'] ?? []);
+
+ return $product->refresh();
+ }
+
+ /**
+ * @param array $configs
+ * @param array $productStates
+ *
+ * @return \Webkul\Product\Models\Product
+ */
+ private function haveDownloadableProduct(array $configs = [], array $productStates = []): Product
+ {
+ $I = $this;
+ if (!in_array('downloadable', $productStates)) {
+ $productStates = array_merge($productStates, ['downloadable']);
+ }
+
+ /** @var Product $product */
+ $product = $I->createProduct($configs['productAttributes'] ?? [], $productStates);
+
+ $I->createAttributeValues($product->id, $configs['attributeValues'] ?? []);
+
+ $I->createDownloadableLink($product->id);
+
+ return $product->refresh();
+ }
+
+ /**
+ * @param array $attributes
+ * @param array $states
+ *
+ * @return \Webkul\Product\Models\Product
+ */
+ private function createProduct(array $attributes = [], array $states = []): Product
+ {
+ return factory(Product::class)->states($states)->create($attributes);
+ }
+
+ /**
+ * @param int $productId
+ * @param array $inventoryConfig
+ */
+ private function createInventory(int $productId, array $inventoryConfig = []): void
+ {
+ $I = $this;
+ $I->have(ProductInventory::class, array_merge($inventoryConfig, [
+ 'product_id' => $productId,
+ 'inventory_source_id' => 1,
+ ]));
+ }
+
+ /**
+ * @param int $productId
+ */
+ private function createDownloadableLink(int $productId): void
+ {
+ $I = $this;
+ $link = $I->have(ProductDownloadableLink::class, [
+ 'product_id' => $productId,
+ ]);
+
+ $I->have(ProductDownloadableLinkTranslation::class, [
+ 'product_downloadable_link_id' => $link->id,
+ ]);
+ }
+
+ /**
+ * @param int $productId
+ * @param array $attributeValues
+ */
+ private function createAttributeValues(int $productId, array $attributeValues = []): void
{
$I = $this;
$productAttributeValues = [
@@ -100,10 +233,10 @@ class Laravel5Helper extends Laravel5
'weight',
];
foreach ($productAttributeValues as $attribute) {
- $data = ['product_id' => $id];
+ $data = ['product_id' => $productId];
if (array_key_exists($attribute, $attributeValues)) {
$fieldName = self::getAttributeFieldName($attribute);
- if (! array_key_exists($fieldName, $data)) {
+ if (!array_key_exists($fieldName, $data)) {
$data[$fieldName] = $attributeValues[$attribute];
} else {
$data = [$fieldName => $attributeValues[$attribute]];
diff --git a/packages/Webkul/Product/src/Database/Factories/ProductDownloadableLinkFactory.php b/packages/Webkul/Product/src/Database/Factories/ProductDownloadableLinkFactory.php
index 67bace113..d7e0a45e0 100644
--- a/packages/Webkul/Product/src/Database/Factories/ProductDownloadableLinkFactory.php
+++ b/packages/Webkul/Product/src/Database/Factories/ProductDownloadableLinkFactory.php
@@ -3,6 +3,7 @@
/** @var \Illuminate\Database\Eloquent\Factory $factory */
use Faker\Generator as Faker;
+use Webkul\Product\Models\Product;
use Webkul\Product\Models\ProductDownloadableLink;
use Webkul\Product\Models\ProductDownloadableLinkTranslation;
@@ -17,6 +18,9 @@ $factory->define(ProductDownloadableLink::class, function (Faker $faker) {
'type' => 'file',
'price' => 0.0000,
'downloads' => $faker->randomNumber(1),
+ 'product_id' => function () {
+ return factory(Product::class)->create()->id;
+ },
'created_at' => $now,
'updated_at' => $now,
];
@@ -28,4 +32,3 @@ $factory->define(ProductDownloadableLinkTranslation::class, function (Faker $fak
'title' => $faker->word,
];
});
-
diff --git a/packages/Webkul/Product/src/Database/Factories/ProductDownloadableLinkTranslation.php b/packages/Webkul/Product/src/Database/Factories/ProductDownloadableLinkTranslation.php
new file mode 100644
index 000000000..28800751e
--- /dev/null
+++ b/packages/Webkul/Product/src/Database/Factories/ProductDownloadableLinkTranslation.php
@@ -0,0 +1,17 @@
+define(ProductDownloadableLinkTranslation::class, function (Faker $faker) {
+ return [
+ 'locale' => 'en',
+ 'title' => $faker->word,
+ 'product_downloadable_link_id' => function () {
+ return factory(ProductDownloadableLink::class)->create()->id;
+ },
+ ];
+});
diff --git a/packages/Webkul/Product/src/Database/Factories/ProductFactory.php b/packages/Webkul/Product/src/Database/Factories/ProductFactory.php
index 0caf3ded5..da90315f4 100644
--- a/packages/Webkul/Product/src/Database/Factories/ProductFactory.php
+++ b/packages/Webkul/Product/src/Database/Factories/ProductFactory.php
@@ -18,6 +18,11 @@ $factory->define(Product::class, function (Faker $faker) {
$factory->state(Product::class, 'simple', [
'type' => 'simple',
]);
-$factory->state(Product::class, 'downloadable_with_stock', [
+
+$factory->state(Product::class, 'virtual', [
+ 'type' => 'virtual',
+]);
+
+$factory->state(Product::class, 'downloadable', [
'type' => 'downloadable',
]);
\ No newline at end of file
diff --git a/packages/Webkul/Sales/src/Repositories/DownloadableLinkPurchasedRepository.php b/packages/Webkul/Sales/src/Repositories/DownloadableLinkPurchasedRepository.php
index 84715fdbe..ac3a901b5 100644
--- a/packages/Webkul/Sales/src/Repositories/DownloadableLinkPurchasedRepository.php
+++ b/packages/Webkul/Sales/src/Repositories/DownloadableLinkPurchasedRepository.php
@@ -55,8 +55,9 @@ class DownloadableLinkPurchasedRepository extends Repository
*/
public function saveLinks($orderItem)
{
- if (stristr($orderItem->type,'downloadable') === false || ! isset($orderItem->additional['links']))
+ if (! $this->isValidDownloadableProduct($orderItem)) {
return;
+ }
foreach ($orderItem->additional['links'] as $linkId) {
if (! $productDownloadableLink = $this->productDownloadableLinkRepository->find($linkId))
@@ -78,6 +79,19 @@ class DownloadableLinkPurchasedRepository extends Repository
}
}
+ /**
+ * Return true, if ordered item is valid downloadable product with links
+ *
+ * @param mixed $orderItem Webkul\Sales\Models\OrderItem;
+ * @return bool
+ */
+ private function isValidDownloadableProduct($orderItem) : bool {
+ if (stristr($orderItem->type,'downloadable') !== false && isset($orderItem->additional['links'])) {
+ return true;
+ }
+ return false;
+ }
+
/**
* @param OrderItem $orderItem
* @param string $status
diff --git a/packages/Webkul/Shop/src/Http/Controllers/CartController.php b/packages/Webkul/Shop/src/Http/Controllers/CartController.php
index 0c6de7e32..28070dd77 100755
--- a/packages/Webkul/Shop/src/Http/Controllers/CartController.php
+++ b/packages/Webkul/Shop/src/Http/Controllers/CartController.php
@@ -80,7 +80,12 @@ class CartController extends Controller
try {
$result = Cart::addProduct($id, request()->all());
- if ($result) {
+ if ($this->onWarningAddingToCart($result)) {
+ session()->flash('warning', $result['warning']);
+ return redirect()->back();
+ }
+
+ if ($result instanceof Cart) {
session()->flash('success', trans('shop::app.checkout.cart.item.success'));
if ($customer = auth()->guard('customer')->user())
@@ -88,8 +93,6 @@ class CartController extends Controller
if (request()->get('is_buy_now'))
return redirect()->route('shop.checkout.onepage.index');
- } else {
- session()->flash('warning', trans('shop::app.checkout.cart.item.error-add'));
}
} catch(\Exception $e) {
session()->flash('error', trans($e->getMessage()));
@@ -205,4 +208,16 @@ class CartController extends Controller
'message' => trans('shop::app.checkout.total.remove-coupon')
]);
}
+
+ /**
+ * Returns true, if result of adding product to cart
+ * is an array and contains a key "warning"
+ *
+ * @param $result
+ *
+ * @return bool
+ */
+ private function onWarningAddingToCart($result): bool {
+ return is_array($result) && isset($result['warning']);
+ }
}
\ No newline at end of file
diff --git a/packages/Webkul/Shop/src/Resources/assets/sass/app.scss b/packages/Webkul/Shop/src/Resources/assets/sass/app.scss
index 59466f38f..92b2a2e7c 100755
--- a/packages/Webkul/Shop/src/Resources/assets/sass/app.scss
+++ b/packages/Webkul/Shop/src/Resources/assets/sass/app.scss
@@ -2400,7 +2400,7 @@ section.cart {
.control-group {
font-size: 16px !important;
- margin: 0px;
+ margin: 0 15px 0 0;
width: auto;
.wrap {
@@ -2422,7 +2422,7 @@ section.cart {
.remove, .towishlist {
line-height: 35px;
- margin-left: 15px;
+ margin-right: 15px;
}
}
}
diff --git a/packages/Webkul/Shop/src/Resources/lang/en/app.php b/packages/Webkul/Shop/src/Resources/lang/en/app.php
index 548f18b4c..216d9d717 100755
--- a/packages/Webkul/Shop/src/Resources/lang/en/app.php
+++ b/packages/Webkul/Shop/src/Resources/lang/en/app.php
@@ -426,7 +426,8 @@ return [
'missing_fields' => 'Some required fields missing for this product.',
'missing_options' => 'Options are missing for this product.',
'missing_links' => 'Downloadable links are missing for this product.',
- 'qty_missing' => 'Atleast one product should have more than 1 quantity.'
+ 'qty_missing' => 'Atleast one product should have more than 1 quantity.',
+ 'qty_impossible' => 'Cannot add more than one of these products to cart.'
],
'create-error' => 'Encountered some issue while making cart instance.',
'title' => 'Shopping Cart',
diff --git a/packages/Webkul/Shop/src/Resources/views/checkout/cart/index.blade.php b/packages/Webkul/Shop/src/Resources/views/checkout/cart/index.blade.php
index 294c0c5b6..f5c66718a 100755
--- a/packages/Webkul/Shop/src/Resources/views/checkout/cart/index.blade.php
+++ b/packages/Webkul/Shop/src/Resources/views/checkout/cart/index.blade.php
@@ -68,10 +68,12 @@
{!! view_render_event('bagisto.shop.checkout.cart.item.quantity.before', ['item' => $item]) !!}
-
-
+ @if ($item->product->getTypeInstance()->showQuantityBox() === true)
+
+
+ @endif
{{ __('shop::app.checkout.cart.remove-link') }}
@@ -106,9 +108,11 @@
{{ __('shop::app.checkout.cart.continue-shopping') }}
-