Db schema, models and repositories added for bundle type product
This commit is contained in:
parent
e2bd18e916
commit
ec567d624f
|
|
@ -13,8 +13,6 @@ class Product extends JsonResource
|
|||
*/
|
||||
public function __construct($resource)
|
||||
{
|
||||
$this->productPriceHelper = app('Webkul\Product\Helpers\Price');
|
||||
|
||||
$this->productImageHelper = app('Webkul\Product\Helpers\ProductImage');
|
||||
|
||||
$this->productReviewHelper = app('Webkul\Product\Helpers\Review');
|
||||
|
|
@ -37,25 +35,25 @@ class Product extends JsonResource
|
|||
'type' => $product->type,
|
||||
'name' => $this->name,
|
||||
'url_key' => $this->url_key,
|
||||
'price' => $product->type == 'configurable' ? $this->productPriceHelper->getVariantMinPrice($product) : $this->price,
|
||||
'formated_price' => $product->type == 'configurable' ? core()->currency($this->productPriceHelper->getVariantMinPrice($product)) : core()->currency($this->price),
|
||||
'price' => $product->getTypeInstance()->getMinimalPrice(),
|
||||
'formated_price' => core()->currency($product->getTypeInstance()->getMinimalPrice()),
|
||||
'short_description' => $this->short_description,
|
||||
'description' => $this->description,
|
||||
'sku' => $this->sku,
|
||||
'images' => ProductImage::collection($product->images),
|
||||
'base_image' => $this->productImageHelper->getProductBaseImage($product),
|
||||
'variants' => Self::collection($this->variants),
|
||||
'in_stock' => $product->type == 'configurable' ? 1 : $product->haveSufficientQuantity(1),
|
||||
'in_stock' => $product->haveSufficientQuantity(1),
|
||||
$this->mergeWhen($product->type == 'configurable', [
|
||||
'super_attributes' => Attribute::collection($product->super_attributes),
|
||||
]),
|
||||
'special_price' => $this->when(
|
||||
$this->productPriceHelper->haveSpecialPrice($product),
|
||||
$this->productPriceHelper->getSpecialPrice($product)
|
||||
$product->getTypeInstance()->haveSpecialPrice(),
|
||||
$product->getTypeInstance()->getSpecialPrice()
|
||||
),
|
||||
'formated_special_price' => $this->when(
|
||||
$this->productPriceHelper->haveSpecialPrice($product),
|
||||
core()->currency($this->productPriceHelper->getSpecialPrice($product))
|
||||
$product->getTypeInstance()->haveSpecialPrice(),
|
||||
core()->currency($product->getTypeInstance()->getSpecialPrice())
|
||||
),
|
||||
'reviews' => [
|
||||
'total' => $total = $this->productReviewHelper->getTotalReviews($product),
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ namespace Webkul\Admin\Listeners;
|
|||
|
||||
use Webkul\Product\Repositories\ProductRepository;
|
||||
use Webkul\Product\Repositories\ProductFlatRepository;
|
||||
use Webkul\Product\Helpers\Price;
|
||||
|
||||
/**
|
||||
* Products Event handler
|
||||
|
|
@ -18,13 +17,6 @@ class Product {
|
|||
*/
|
||||
protected $product;
|
||||
|
||||
/**
|
||||
* Price Object
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $price;
|
||||
|
||||
/**
|
||||
* Product Flat Object
|
||||
*
|
||||
|
|
@ -39,15 +31,12 @@ class Product {
|
|||
|
||||
public function __construct(
|
||||
ProductRepository $product,
|
||||
ProductFlatRepository $productFlat,
|
||||
Price $price
|
||||
ProductFlatRepository $productFlat
|
||||
)
|
||||
{
|
||||
$this->product = $product;
|
||||
|
||||
$this->productFlat = $productFlat;
|
||||
|
||||
$this->price = $price;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -63,7 +52,7 @@ class Product {
|
|||
'type' => $product->type,
|
||||
'name' => $product->name,
|
||||
'attribute_family_name' => $product->toArray()['attribute_family']['name'],
|
||||
'price' => $this->price->getMinimalPrice($product),
|
||||
'price' => $product->getTypeInstance()->getMinimalPrice(),
|
||||
'status' => $product->status
|
||||
];
|
||||
|
||||
|
|
|
|||
|
|
@ -386,7 +386,8 @@ return [
|
|||
'searching' => 'Searching ...',
|
||||
'grouped-products' => 'Grouped Products',
|
||||
'search-products' => 'Search Products',
|
||||
'no-result-found' => 'Products not found with same name.'
|
||||
'no-result-found' => 'Products not found with same name.',
|
||||
'bundle-items' => 'Bundle Items'
|
||||
],
|
||||
'attributes' => [
|
||||
'title' => 'الصفات',
|
||||
|
|
|
|||
|
|
@ -416,7 +416,8 @@ return [
|
|||
'grouped-products' => 'Grouped Products',
|
||||
'search-products' => 'Search Products',
|
||||
'no-result-found' => 'Products not found with same name.',
|
||||
'channel' => 'Channels'
|
||||
'channel' => 'Channels',
|
||||
'bundle-items' => 'Bundle Items'
|
||||
],
|
||||
|
||||
'attributes' => [
|
||||
|
|
|
|||
|
|
@ -398,7 +398,8 @@ return [
|
|||
'related-products' => 'محصولات مرتبط',
|
||||
'product-search-hint' => 'شروع به تایپ نام محصول کنید',
|
||||
'no-result-found' => 'محصولاتی با همین نام یافت نشد',
|
||||
'searching' => 'جست و جو ...'
|
||||
'searching' => 'جست و جو ...',
|
||||
'bundle-items' => 'Bundle Items'
|
||||
],
|
||||
|
||||
'attributes' => [
|
||||
|
|
|
|||
|
|
@ -392,7 +392,8 @@ return [
|
|||
'searching' => 'Procurando ...',
|
||||
'grouped-products' => 'Grouped Products',
|
||||
'search-products' => 'Search Products',
|
||||
'no-result-found' => 'Products not found with same name.'
|
||||
'no-result-found' => 'Products not found with same name.',
|
||||
'bundle-items' => 'Bundle Items'
|
||||
],
|
||||
'attributes' => [
|
||||
'title' => 'Atributos',
|
||||
|
|
|
|||
|
|
@ -0,0 +1,11 @@
|
|||
{!! view_render_event('bagisto.admin.catalog.product.edit_form_accordian.bundle.before', ['product' => $product]) !!}
|
||||
|
||||
<accordian :title="'{{ __('admin::app.catalog.products.bundle-items') }}'" :active="true">
|
||||
<div slot="body">
|
||||
|
||||
{!! view_render_event('bagisto.admin.catalog.product.edit_form_accordian.bundle.controls.before', ['product' => $product]) !!}
|
||||
|
||||
{!! view_render_event('bagisto.admin.catalog.product.edit_form_accordian.bundle.controls.after', ['product' => $product]) !!}
|
||||
|
||||
</div>
|
||||
</accordian>
|
||||
|
|
@ -11,7 +11,6 @@ use Webkul\Checkout\Models\CartItem;
|
|||
use Webkul\Checkout\Models\CartPayment;
|
||||
use Webkul\Customer\Repositories\WishlistRepository;
|
||||
use Webkul\Customer\Repositories\CustomerAddressRepository;
|
||||
use Webkul\Product\Helpers\Price;
|
||||
use Illuminate\Support\Facades\Event;
|
||||
|
||||
/**
|
||||
|
|
@ -72,11 +71,6 @@ class Cart {
|
|||
*/
|
||||
protected $customerAddressRepository;
|
||||
|
||||
/**
|
||||
* Product price helper instance
|
||||
*/
|
||||
protected $price;
|
||||
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
|
|
@ -98,8 +92,7 @@ class Cart {
|
|||
ProductRepository $productRepository,
|
||||
TaxCategoryRepository $taxCategoryRepository,
|
||||
WishlistRepository $wishlistRepository,
|
||||
CustomerAddressRepository $customerAddressRepository,
|
||||
Price $price
|
||||
CustomerAddressRepository $customerAddressRepository
|
||||
)
|
||||
{
|
||||
$this->cartRepository = $cartRepository;
|
||||
|
|
@ -115,8 +108,6 @@ class Cart {
|
|||
$this->wishlistRepository = $wishlistRepository;
|
||||
|
||||
$this->customerAddressRepository = $customerAddressRepository;
|
||||
|
||||
$this->price = $price;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -242,7 +233,9 @@ class Cart {
|
|||
throw new \Exception(trans('shop::app.checkout.cart.quantity.illegal'));
|
||||
}
|
||||
|
||||
if ($item->product->isStockable() && ! $item->product->haveSufficientQuantity($quantity))
|
||||
$item->quantity = $quantity;
|
||||
|
||||
if (! $this->isItemHaveQuantity($item))
|
||||
throw new \Exception(trans('shop::app.checkout.cart.quantity.inventory_warning'));
|
||||
|
||||
Event::fire('checkout.cart.update.before', $item);
|
||||
|
|
@ -343,9 +336,9 @@ class Cart {
|
|||
if (! $cartItem->product->getTypeInstance()->compareOptions($cartItem->additional, $guestCartItem->additional))
|
||||
continue;
|
||||
|
||||
$newQuantity = $cartItem->quantity + $guestCartItem->quantity;
|
||||
$cartItem->quantity = $newQuantity = $cartItem->quantity + $guestCartItem->quantity;
|
||||
|
||||
if ($cartItem->product->isStockable() && ! $cartItem->product->haveSufficientQuantity($newQuantity)) {
|
||||
if ($this->isItemHaveQuantity($cartItem)) {
|
||||
$this->cartItemRepository->delete($guestCartItem->id);
|
||||
|
||||
continue;
|
||||
|
|
@ -667,7 +660,7 @@ class Cart {
|
|||
if ($item->product_flat->getTypeInstance()->getMinimalPrice($item) == $item->price)
|
||||
continue;
|
||||
|
||||
$price = ! is_null($item->custom_price) ? $item->custom_price : $this->price->getMinimalPrice($productFlat);
|
||||
$price = ! is_null($item->custom_price) ? $item->custom_price : $productFlat->getTypeInstance()->getMinimalPrice();
|
||||
|
||||
$this->cartItemRepository->update([
|
||||
'price' => core()->convertPrice($price),
|
||||
|
|
|
|||
|
|
@ -109,7 +109,7 @@ class Cart extends Model implements CartContract
|
|||
*/
|
||||
public function haveStockableItems()
|
||||
{
|
||||
foreach ($this->all_items as $item) {
|
||||
foreach ($this->items as $item) {
|
||||
if ($item->product->isStockable())
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,5 +30,11 @@ return [
|
|||
'name' => 'Downloadable',
|
||||
'class' => 'Webkul\Product\Type\Downloadable',
|
||||
'sort' => 5
|
||||
],
|
||||
'bundle' => [
|
||||
'key' => 'bundle',
|
||||
'name' => 'Bundle',
|
||||
'class' => 'Webkul\Product\Type\Bundle',
|
||||
'sort' => 6
|
||||
]
|
||||
];
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
<?php
|
||||
|
||||
namespace Webkul\Product\Contracts;
|
||||
|
||||
interface ProductBundleOption
|
||||
{
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
<?php
|
||||
|
||||
namespace Webkul\Product\Contracts;
|
||||
|
||||
interface ProductBundleOptionTranslation
|
||||
{
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
<?php
|
||||
|
||||
namespace Webkul\Product\Contracts;
|
||||
|
||||
interface ProductBundleProduct
|
||||
{
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class CreateProductBundleOptionsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('product_bundle_options', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->string('type');
|
||||
$table->boolean('is_required')->default(1);
|
||||
$table->integer('sort_order')->default(0);
|
||||
|
||||
$table->integer('product_id')->unsigned();
|
||||
$table->foreign('product_id')->references('id')->on('products')->onDelete('cascade');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('product_bundle_options');
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class CreateProductBundleOptionTranslationsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('product_bundle_option_translations', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->string('locale');
|
||||
$table->text('label')->nullable();
|
||||
$table->integer('product_bundle_option_id')->unsigned();
|
||||
$table->unique(['product_bundle_option_id', 'locale'], 'product_bundle_option_translations_option_id_locale_unique');
|
||||
$table->foreign('product_bundle_option_id', 'product_bundle_option_translations_option_id_foreign')->references('id')->on('product_bundle_options')->onDelete('cascade');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('product_bundle_option_translations');
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class CreateProductBundleProductsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('product_bundle_products', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->integer('qty')->default(0);
|
||||
$table->integer('sort_order')->default(0);
|
||||
|
||||
$table->integer('product_bundle_option_id')->unsigned();
|
||||
$table->foreign('product_bundle_option_id')->references('id')->on('product_bundle_options')->onDelete('cascade');
|
||||
|
||||
$table->integer('product_id')->unsigned();
|
||||
$table->foreign('product_id')->references('id')->on('products')->onDelete('cascade');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('product_bundle_products');
|
||||
}
|
||||
}
|
||||
|
|
@ -3,8 +3,6 @@
|
|||
namespace Webkul\Product\Helpers;
|
||||
|
||||
use Webkul\Attribute\Repositories\AttributeOptionRepository as AttributeOption;
|
||||
use Webkul\Product\Helpers\ProductImage;
|
||||
use Webkul\Product\Helpers\Price;
|
||||
use Webkul\Product\Models\Product;
|
||||
use Webkul\Product\Models\ProductAttributeValue;
|
||||
|
||||
|
|
@ -30,32 +28,21 @@ class ConfigurableOption extends AbstractProduct
|
|||
*/
|
||||
protected $productImage;
|
||||
|
||||
/**
|
||||
* Price object
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $price;
|
||||
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
* @param Webkul\Attribute\Repositories\AttributeOptionRepository $attributeOption
|
||||
* @param Webkul\Product\Helpers\ProductImage $productImage
|
||||
* @param Webkul\Product\Helpers\Price $price
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(
|
||||
AttributeOption $attributeOption,
|
||||
ProductImage $productImage,
|
||||
Price $price
|
||||
ProductImage $productImage
|
||||
)
|
||||
{
|
||||
$this->attributeOption = $attributeOption;
|
||||
|
||||
$this->productImage = $productImage;
|
||||
|
||||
$this->price = $price;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -94,8 +81,8 @@ class ConfigurableOption extends AbstractProduct
|
|||
'attributes' => $this->getAttributesData($product, $options),
|
||||
'index' => isset($options['index']) ? $options['index'] : [],
|
||||
'regular_price' => [
|
||||
'formated_price' => core()->currency($this->price->getMinimalPrice($product)),
|
||||
'price' => $this->price->getMinimalPrice($product)
|
||||
'formated_price' => core()->currency($product->getTypeInstance()->getMinimalPrice()),
|
||||
'price' => $product->getTypeInstance()->getMinimalPrice()
|
||||
],
|
||||
'variant_prices' => $this->getVariantPrices($product),
|
||||
'variant_images' => $this->getVariantImages($product),
|
||||
|
|
@ -237,8 +224,8 @@ class ConfigurableOption extends AbstractProduct
|
|||
'price' => $variant->price
|
||||
],
|
||||
'final_price' => [
|
||||
'formated_price' => core()->currency($this->price->getMinimalPrice($variant)),
|
||||
'price' => $this->price->getMinimalPrice($variant)
|
||||
'formated_price' => core()->currency($variant->getTypeInstance()->getMinimalPrice()),
|
||||
'price' => $variant->getTypeInstance()->getMinimalPrice()
|
||||
]
|
||||
];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,32 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Webkul\Product\Helpers;
|
||||
|
||||
use Webkul\Product\Repositories\ProductGroupedProductRepository;
|
||||
|
||||
/**
|
||||
* Grouped Product Helper
|
||||
*
|
||||
* @author Jitendra Singh <jitendra@webkul.com>
|
||||
* @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com)
|
||||
*/
|
||||
class GroupedProduct extends AbstractProduct
|
||||
{
|
||||
/**
|
||||
* ProductGroupedProductRepository object
|
||||
*
|
||||
* @var object
|
||||
*/
|
||||
protected $productGroupedProductRepository;
|
||||
|
||||
/**
|
||||
* Create a new helper instance.
|
||||
*
|
||||
* @param Webkul\Product\Repositories\ProductGroupedProductRepository $productGroupedProductRepository
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(ProductGroupedProductRepository $productGroupedProductRepository)
|
||||
{
|
||||
$this->productGroupedProductRepository = $productGroupedProductRepository;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,137 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Webkul\Product\Helpers;
|
||||
|
||||
use Webkul\Attribute\Repositories\AttributeRepository as Attribute;
|
||||
use Webkul\Product\Models\ProductAttributeValue;
|
||||
use Webkul\Product\Models\Product;
|
||||
use Webkul\Product\Models\ProductFlat;
|
||||
|
||||
/**
|
||||
* Price Helper
|
||||
*
|
||||
* @author Jitendra Singh <jitendra@webkul.com>
|
||||
* @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com)
|
||||
*/
|
||||
class Price extends AbstractProduct
|
||||
{
|
||||
/**
|
||||
* AttributeRepository object
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $attribute;
|
||||
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
* @param Webkul\Attribute\Repositories\AttributeRepository $attribute
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Attribute $attribute)
|
||||
{
|
||||
$this->attribute = $attribute;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the product's minimal price
|
||||
*
|
||||
* @param Product $product
|
||||
* @return float
|
||||
*/
|
||||
public function getMinimalPrice($product)
|
||||
{
|
||||
static $price = [];
|
||||
|
||||
if(array_key_exists($product->id, $price))
|
||||
return $price[$product->id];
|
||||
|
||||
if ($product->type == 'configurable') {
|
||||
return $price[$product->id] = $this->getVariantMinPrice($product);
|
||||
} else {
|
||||
if ($this->haveSpecialPrice($product)) {
|
||||
return $price[$product->id] = $product->special_price;
|
||||
}
|
||||
|
||||
return $price[$product->id] = $product->price;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the product's minimal price
|
||||
*
|
||||
* @param Product $product
|
||||
* @return float
|
||||
*/
|
||||
public function getVariantMinPrice($product)
|
||||
{
|
||||
static $price = [];
|
||||
|
||||
$finalPrice = [];
|
||||
|
||||
if (array_key_exists($product->id, $price))
|
||||
return $price[$product->id];
|
||||
|
||||
if ($product instanceof ProductFlat) {
|
||||
$productId = $product->product_id;
|
||||
} else {
|
||||
$productId = $product->id;
|
||||
}
|
||||
|
||||
$qb = ProductFlat::join('products', 'product_flat.product_id', '=', 'products.id')
|
||||
->where('products.parent_id', $productId);
|
||||
|
||||
$result = $qb
|
||||
->distinct()
|
||||
->selectRaw('IF( product_flat.special_price_from IS NOT NULL
|
||||
AND product_flat.special_price_to IS NOT NULL , IF( NOW( ) >= product_flat.special_price_from
|
||||
AND NOW( ) <= product_flat.special_price_to, IF( product_flat.special_price IS NULL OR product_flat.special_price = 0 , product_flat.price, LEAST( product_flat.special_price, product_flat.price ) ) , product_flat.price ) , IF( product_flat.special_price_from IS NULL , IF( product_flat.special_price_to IS NULL , IF( product_flat.special_price IS NULL OR product_flat.special_price = 0 , product_flat.price, LEAST( product_flat.special_price, product_flat.price ) ) , IF( NOW( ) <= product_flat.special_price_to, IF( product_flat.special_price IS NULL OR product_flat.special_price = 0 , product_flat.price, LEAST( product_flat.special_price, product_flat.price ) ) , product_flat.price ) ) , IF( product_flat.special_price_to IS NULL , IF( NOW( ) >= product_flat.special_price_from, IF( product_flat.special_price IS NULL OR product_flat.special_price = 0 , product_flat.price, LEAST( product_flat.special_price, product_flat.price ) ) , product_flat.price ) , product_flat.price ) ) ) AS final_price')
|
||||
->where('product_flat.channel', core()->getCurrentChannelCode())
|
||||
->where('product_flat.locale', app()->getLocale())
|
||||
->get();
|
||||
|
||||
foreach ($result as $price) {
|
||||
$finalPrice[] = $price->final_price;
|
||||
}
|
||||
|
||||
if (empty($finalPrice))
|
||||
return $price[$product->id] = 0;
|
||||
|
||||
return $price[$product->id] = min($finalPrice);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the product's minimal price
|
||||
*
|
||||
* @param Product $product
|
||||
* @return float
|
||||
*/
|
||||
public function getSpecialPrice($product)
|
||||
{
|
||||
static $price = [];
|
||||
|
||||
if(array_key_exists($product->id, $price))
|
||||
return $price[$product->id];
|
||||
|
||||
if ($this->haveSpecialPrice($product)) {
|
||||
return $price[$product->id] = $product->special_price;
|
||||
} else {
|
||||
return $price[$product->id] = $product->price;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Product $product
|
||||
* @return boolean
|
||||
*/
|
||||
public function haveSpecialPrice($product)
|
||||
{
|
||||
if (is_null($product->special_price) || ! (float) $product->special_price)
|
||||
return false;
|
||||
|
||||
if (core()->isChannelDateInInterval($product->special_price_from, $product->special_price_to))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -229,11 +229,7 @@ class ProductFlat
|
|||
}
|
||||
}
|
||||
|
||||
if ($product->type == 'configurable' && $attribute->code == 'price') {
|
||||
$productFlat->{$attribute->code} = app('Webkul\Product\Helpers\Price')->getVariantMinPrice($product);
|
||||
} else {
|
||||
$productFlat->{$attribute->code} = $productAttributeValue[ProductAttributeValue::$attributeTypeFields[$attribute->type]];
|
||||
}
|
||||
$productFlat->{$attribute->code} = $productAttributeValue[ProductAttributeValue::$attributeTypeFields[$attribute->type]];
|
||||
|
||||
if ($attribute->type == 'select') {
|
||||
$attributeOption = $this->attributeOptionRepository->find($product->{$attribute->code});
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
|
||||
namespace Webkul\Product\Models;
|
||||
|
||||
use Webkul\Core\Eloquent\TranslatableModel;
|
||||
use Webkul\Product\Contracts\ProductBundleOption as ProductBundleOptionContract;
|
||||
|
||||
class ProductBundleOption extends TranslatableModel implements ProductBundleOptionContract
|
||||
{
|
||||
public $timestamps = false;
|
||||
|
||||
public $translatedAttributes = ['label'];
|
||||
|
||||
protected $fillable = ['type', 'is_required', 'sort_order', 'product_id'];
|
||||
|
||||
/**
|
||||
* Get the product that owns the image.
|
||||
*/
|
||||
public function product()
|
||||
{
|
||||
return $this->belongsTo(ProductProxy::modelClass());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
|
||||
namespace Webkul\Product\Models;
|
||||
|
||||
use Konekt\Concord\Proxies\ModelProxy;
|
||||
|
||||
class ProductBundleOptionProxy extends ModelProxy
|
||||
{
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
|
||||
namespace Webkul\Product\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Webkul\Product\Contracts\ProductBundleOptionTranslation as ProductBundleOptionTranslationContract;
|
||||
|
||||
class ProductBundleOptionTranslation extends Model implements ProductBundleOptionTranslationContract
|
||||
{
|
||||
public $timestamps = false;
|
||||
|
||||
protected $fillable = ['label'];
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
|
||||
namespace Webkul\Product\Models;
|
||||
|
||||
use Konekt\Concord\Proxies\ModelProxy;
|
||||
|
||||
class ProductBundleOptionTranslationProxy extends ModelProxy
|
||||
{
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
namespace Webkul\Product\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Webkul\Product\Contracts\ProductBundleProduct as ProductBundleProductContract;
|
||||
|
||||
class ProductBundleProduct extends Model implements ProductBundleProductContract
|
||||
{
|
||||
public $timestamps = false;
|
||||
|
||||
protected $fillable = ['qty', 'sort_order', 'product_bundle_option_id', 'product_id'];
|
||||
|
||||
/**
|
||||
* Get the product that owns the image.
|
||||
*/
|
||||
public function product()
|
||||
{
|
||||
return $this->belongsTo(ProductProxy::modelClass());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
|
||||
namespace Webkul\Product\Models;
|
||||
|
||||
use Konekt\Concord\Proxies\ModelProxy;
|
||||
|
||||
class ProductBundleProductProxy extends ModelProxy
|
||||
{
|
||||
|
||||
}
|
||||
|
|
@ -7,9 +7,9 @@ use Webkul\Product\Contracts\ProductGroupedProduct as ProductGroupedProductContr
|
|||
|
||||
class ProductGroupedProduct extends Model implements ProductGroupedProductContract
|
||||
{
|
||||
protected $fillable = ['qty', 'sort_order', 'product_id', 'associated_product_id'];
|
||||
|
||||
public $timestamps = false;
|
||||
|
||||
protected $fillable = ['qty', 'sort_order', 'product_id', 'associated_product_id'];
|
||||
|
||||
/**
|
||||
* Get the product that owns the image.
|
||||
|
|
|
|||
|
|
@ -17,6 +17,9 @@ class ModuleServiceProvider extends BaseModuleServiceProvider
|
|||
\Webkul\Product\Models\ProductSalableInventory::class,
|
||||
\Webkul\Product\Models\ProductDownloadableSample::class,
|
||||
\Webkul\Product\Models\ProductDownloadableLink::class,
|
||||
\Webkul\Product\Models\ProductGroupedProduct::class
|
||||
\Webkul\Product\Models\ProductGroupedProduct::class,
|
||||
\Webkul\Product\Models\ProductBundleOption::class,
|
||||
\Webkul\Product\Models\ProductBundleOptionTranslation::class,
|
||||
\Webkul\Product\Models\ProductBundleProduct::class,
|
||||
];
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
<?php
|
||||
|
||||
namespace Webkul\Product\Repositories;
|
||||
|
||||
use Webkul\Core\Eloquent\Repository;
|
||||
|
||||
/**
|
||||
* ProductBundleOption Repository
|
||||
*
|
||||
* @author Jitendra Singh <jitendra@webkul.com>
|
||||
* @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com)
|
||||
*/
|
||||
class ProductBundleOptionRepository extends Repository
|
||||
{
|
||||
public function model()
|
||||
{
|
||||
return 'Webkul\Product\Contracts\ProductBundleOption';
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
<?php
|
||||
|
||||
namespace Webkul\Product\Repositories;
|
||||
|
||||
use Webkul\Core\Eloquent\Repository;
|
||||
|
||||
/**
|
||||
* ProductBundleProduct Repository
|
||||
*
|
||||
* @author Jitendra Singh <jitendra@webkul.com>
|
||||
* @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com)
|
||||
*/
|
||||
class ProductBundleProductRepository extends Repository
|
||||
{
|
||||
public function model()
|
||||
{
|
||||
return 'Webkul\Product\Contracts\ProductBundleProduct';
|
||||
}
|
||||
}
|
||||
|
|
@ -2,15 +2,14 @@
|
|||
|
||||
namespace Webkul\Product\Type;
|
||||
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Webkul\Attribute\Repositories\AttributeRepository;
|
||||
use Webkul\Product\Repositories\ProductRepository;
|
||||
use Webkul\Product\Repositories\ProductAttributeValueRepository;
|
||||
use Webkul\Product\Repositories\ProductInventoryRepository;
|
||||
use Webkul\Product\Repositories\ProductImageRepository;
|
||||
use Webkul\Product\Models\ProductAttributeValue;
|
||||
use Webkul\Product\Helpers\Price;
|
||||
use Webkul\Product\Helpers\ProductImage;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Cart;
|
||||
|
||||
/**
|
||||
|
|
@ -56,13 +55,6 @@ abstract class AbstractType
|
|||
*/
|
||||
protected $productImageRepository;
|
||||
|
||||
/**
|
||||
* Product price helper instance
|
||||
*
|
||||
* @var Price
|
||||
*/
|
||||
protected $priceHelper;
|
||||
|
||||
/**
|
||||
* Product Image helper instance
|
||||
*
|
||||
|
|
@ -85,7 +77,6 @@ abstract class AbstractType
|
|||
* @param Webkul\Product\Repositories\ProductAttributeValueRepository $attributeValueRepository
|
||||
* @param Webkul\Product\Repositories\ProductInventoryRepository $productInventoryRepository
|
||||
* @param Webkul\Product\Repositories\ProductImageRepository $productImageRepository
|
||||
* @param Webkul\Product\Helpers\Price $priceHelper
|
||||
* @param Webkul\Product\Helpers\ProductImage $productImageHelper
|
||||
* @return void
|
||||
*/
|
||||
|
|
@ -95,7 +86,6 @@ abstract class AbstractType
|
|||
ProductAttributeValueRepository $attributeValueRepository,
|
||||
ProductInventoryRepository $productInventoryRepository,
|
||||
ProductImageRepository $productImageRepository,
|
||||
Price $priceHelper,
|
||||
ProductImage $productImageHelper
|
||||
)
|
||||
{
|
||||
|
|
@ -109,8 +99,6 @@ abstract class AbstractType
|
|||
|
||||
$this->productImageRepository = $productImageRepository;
|
||||
|
||||
$this->priceHelper = $priceHelper;
|
||||
|
||||
$this->productImageHelper = $productImageHelper;
|
||||
}
|
||||
|
||||
|
|
@ -225,7 +213,7 @@ abstract class AbstractType
|
|||
*/
|
||||
public function isStockable()
|
||||
{
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -236,6 +224,16 @@ abstract class AbstractType
|
|||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this product can have inventory
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function showQuantityBox()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param CartItem $cartItem
|
||||
|
|
@ -294,6 +292,71 @@ abstract class AbstractType
|
|||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get product minimal price
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function getMinimalPrice()
|
||||
{
|
||||
if ($this->haveSpecialPrice())
|
||||
return $this->product->special_price;
|
||||
|
||||
return $this->product->price;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get product maximam price
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function getMaximamPrice()
|
||||
{
|
||||
return $this->product->price;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the product's minimal price
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function getSpecialPrice()
|
||||
{
|
||||
return $this->haveSpecialPrice() ? $this->product->special_price : $this->product->price;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return boolean
|
||||
*/
|
||||
public function haveSpecialPrice()
|
||||
{
|
||||
if (is_null($this->product->special_price) || ! (float) $this->product->special_price)
|
||||
return false;
|
||||
|
||||
if (core()->isChannelDateInInterval($this->product->special_price_from, $this->product->special_price_to))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get product minimal price
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getPriceHtml()
|
||||
{
|
||||
if ($this->haveSpecialPrice()) {
|
||||
$html = '<div class="sticker sale">' . trans('shop::app.products.sale') . '</div>'
|
||||
. '<span class="regular-price">' . core()->currency($this->product->price) . '</span>'
|
||||
. '<span class="special-price">' . core()->currency($this->getSpecialPrice()) . '</span>';
|
||||
} else {
|
||||
$html = '<span>' . core()->currency($this->product->price) . '</span>';
|
||||
}
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add product. Returns error message if can't prepare product.
|
||||
*
|
||||
|
|
@ -307,7 +370,7 @@ abstract class AbstractType
|
|||
if ($this->isStockable() && ! $this->haveSufficientQuantity($data['quantity']))
|
||||
return trans('shop::app.checkout.cart.quantity.inventory_warning');
|
||||
|
||||
$price = $this->priceHelper->getMinimalPrice($this->product);
|
||||
$price = $this->getMinimalPrice();
|
||||
|
||||
$products = [
|
||||
[
|
||||
|
|
@ -398,15 +461,4 @@ abstract class AbstractType
|
|||
{
|
||||
return $this->productImageHelper->getProductBaseImage($item->product);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get product base image
|
||||
*
|
||||
* @param CartItem $item
|
||||
* @return float
|
||||
*/
|
||||
public function getMinimalPrice($item)
|
||||
{
|
||||
return $this->priceHelper->getMinimalPrice($item->product);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
namespace Webkul\Product\Type;
|
||||
|
||||
/**
|
||||
* Class Bundle.
|
||||
*
|
||||
* @author Jitendra Singh <jitendra@webkul.com>
|
||||
* @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com)
|
||||
*/
|
||||
class Bundle extends AbstractType
|
||||
{
|
||||
/**
|
||||
* Skip attribute for Bundle product type
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $skipAttributes = ['price', 'cost', 'special_price', 'special_price_from', 'special_price_to', 'width', 'height', 'depth', 'weight'];
|
||||
|
||||
/**
|
||||
* These blade files will be included in product edit page
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $additionalViews = [
|
||||
'admin::catalog.products.accordians.images',
|
||||
'admin::catalog.products.accordians.categories',
|
||||
'admin::catalog.products.accordians.bundle-items',
|
||||
'admin::catalog.products.accordians.product-links'
|
||||
];
|
||||
}
|
||||
|
|
@ -3,6 +3,7 @@
|
|||
namespace Webkul\Product\Type;
|
||||
|
||||
use Webkul\Product\Models\ProductAttributeValue;
|
||||
use Webkul\Product\Models\ProductFlat;
|
||||
|
||||
/**
|
||||
* Class Configurable.
|
||||
|
|
@ -263,6 +264,16 @@ class Configurable extends AbstractType
|
|||
{
|
||||
return $cartItem->child->product->getTypeInstance()->haveSufficientQuantity($cartItem->quantity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this product can have inventory
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function showQuantityBox()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns validation rules
|
||||
|
|
@ -293,6 +304,64 @@ class Configurable extends AbstractType
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get product minimal price
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function getMinimalPrice()
|
||||
{
|
||||
$minPrices = [];
|
||||
|
||||
$result = ProductFlat::join('products', 'product_flat.product_id', '=', 'products.id')
|
||||
->distinct()
|
||||
->where('products.parent_id', $this->product->id)
|
||||
->selectRaw('IF( product_flat.special_price_from IS NOT NULL
|
||||
AND product_flat.special_price_to IS NOT NULL , IF( NOW( ) >= product_flat.special_price_from
|
||||
AND NOW( ) <= product_flat.special_price_to, IF( product_flat.special_price IS NULL OR product_flat.special_price = 0 , product_flat.price, LEAST( product_flat.special_price, product_flat.price ) ) , product_flat.price ) , IF( product_flat.special_price_from IS NULL , IF( product_flat.special_price_to IS NULL , IF( product_flat.special_price IS NULL OR product_flat.special_price = 0 , product_flat.price, LEAST( product_flat.special_price, product_flat.price ) ) , IF( NOW( ) <= product_flat.special_price_to, IF( product_flat.special_price IS NULL OR product_flat.special_price = 0 , product_flat.price, LEAST( product_flat.special_price, product_flat.price ) ) , product_flat.price ) ) , IF( product_flat.special_price_to IS NULL , IF( NOW( ) >= product_flat.special_price_from, IF( product_flat.special_price IS NULL OR product_flat.special_price = 0 , product_flat.price, LEAST( product_flat.special_price, product_flat.price ) ) , product_flat.price ) , product_flat.price ) ) ) AS min_price')
|
||||
->where('product_flat.channel', core()->getCurrentChannelCode())
|
||||
->where('product_flat.locale', app()->getLocale())
|
||||
->get();
|
||||
|
||||
foreach ($result as $price) {
|
||||
$minPrices[] = $price->min_price;
|
||||
}
|
||||
|
||||
if (empty($minPrices))
|
||||
return 0;
|
||||
|
||||
return min($minPrices);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get product maximam price
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function getMaximamPrice()
|
||||
{
|
||||
$productFlat = ProductFlat::join('products', 'product_flat.product_id', '=', 'products.id')
|
||||
->distinct()
|
||||
->where('products.parent_id', $this->product->id)
|
||||
->selectRaw('MAX(product_flat.price) AS max_price')
|
||||
->where('product_flat.channel', core()->getCurrentChannelCode())
|
||||
->where('product_flat.locale', app()->getLocale())
|
||||
->first();
|
||||
|
||||
return $productFlat ? $productFlat->max_price : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get product minimal price
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getPriceHtml()
|
||||
{
|
||||
return '<span class="price-label">' . trans('shop::app.products.price-label') . '</span>'
|
||||
. '<span class="final-price">' . core()->currency($this->getMinimalPrice()) . '</span>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Add product. Returns error message if can't prepare product.
|
||||
*
|
||||
|
|
@ -311,7 +380,7 @@ class Configurable extends AbstractType
|
|||
if (! $childProduct->haveSufficientQuantity($data['quantity']))
|
||||
return trans('shop::app.checkout.cart.quantity.inventory_warning');
|
||||
|
||||
$price = $this->priceHelper->getMinimalPrice($childProduct);
|
||||
$price = $this->getMinimalPrice();
|
||||
|
||||
$products = [
|
||||
[
|
||||
|
|
@ -419,15 +488,4 @@ class Configurable extends AbstractType
|
|||
|
||||
return $this->productImageHelper->getProductBaseImage($product);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get product base image
|
||||
*
|
||||
* @param CartItem $item
|
||||
* @return array
|
||||
*/
|
||||
public function getMinimalPrice($item)
|
||||
{
|
||||
return $this->priceHelper->getMinimalPrice($item->child->product);
|
||||
}
|
||||
}
|
||||
|
|
@ -10,7 +10,6 @@ use Webkul\Product\Repositories\ProductImageRepository;
|
|||
use Webkul\Product\Repositories\ProductDownloadableLinkRepository;
|
||||
use Webkul\Product\Repositories\ProductDownloadableSampleRepository;
|
||||
use Webkul\Product\Models\ProductAttributeValue;
|
||||
use Webkul\Product\Helpers\Price;
|
||||
use Webkul\Product\Helpers\ProductImage;
|
||||
use Webkul\Checkout\Models\CartItem;
|
||||
|
||||
|
|
@ -71,13 +70,6 @@ class Downloadable extends AbstractType
|
|||
*/
|
||||
protected $productDownloadableSampleRepository;
|
||||
|
||||
/**
|
||||
* Product price helper instance
|
||||
*
|
||||
* @var Price
|
||||
*/
|
||||
protected $priceHelper;
|
||||
|
||||
/**
|
||||
* Product Image helper instance
|
||||
*
|
||||
|
|
@ -114,7 +106,6 @@ class Downloadable extends AbstractType
|
|||
* @param Webkul\Product\Repositories\ProductImageRepository $productImageRepository
|
||||
* @param Webkul\Product\Repositories\ProductDownloadableLinkRepository $productDownloadableLinkRepository
|
||||
* @param Webkul\Product\Repositories\ProductDownloadableSampleRepository $productDownloadableSampleRepository
|
||||
* @param Webkul\Product\Helpers\Price $priceHelper
|
||||
* @param Webkul\Product\Helpers\ProductImage $productImageHelper
|
||||
* @return void
|
||||
*/
|
||||
|
|
@ -126,7 +117,6 @@ class Downloadable extends AbstractType
|
|||
productImageRepository $productImageRepository,
|
||||
ProductDownloadableLinkRepository $productDownloadableLinkRepository,
|
||||
ProductDownloadableSampleRepository $productDownloadableSampleRepository,
|
||||
Price $priceHelper,
|
||||
ProductImage $productImageHelper
|
||||
)
|
||||
{
|
||||
|
|
@ -136,7 +126,6 @@ class Downloadable extends AbstractType
|
|||
$attributeValueRepository,
|
||||
$productInventoryRepository,
|
||||
$productImageRepository,
|
||||
$priceHelper,
|
||||
$productImageHelper
|
||||
);
|
||||
|
||||
|
|
@ -180,6 +169,16 @@ class Downloadable extends AbstractType
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this product can have inventory
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function isStockable()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns validation rules
|
||||
*
|
||||
|
|
|
|||
|
|
@ -8,9 +8,9 @@ use Webkul\Product\Repositories\ProductAttributeValueRepository;
|
|||
use Webkul\Product\Repositories\ProductInventoryRepository;
|
||||
use Webkul\Product\Repositories\ProductImageRepository;
|
||||
use Webkul\Product\Repositories\ProductGroupedProductRepository;
|
||||
use Webkul\Product\Models\ProductAttributeValue;
|
||||
use Webkul\Product\Helpers\Price;
|
||||
use Webkul\Product\Helpers\ProductImage;
|
||||
use Webkul\Product\Models\ProductAttributeValue;
|
||||
use Webkul\Product\Models\ProductFlat;
|
||||
|
||||
/**
|
||||
* Class Grouped.
|
||||
|
|
@ -62,13 +62,6 @@ class Grouped extends AbstractType
|
|||
*/
|
||||
protected $productGroupedProductRepository;
|
||||
|
||||
/**
|
||||
* Product price helper instance
|
||||
*
|
||||
* @var Price
|
||||
*/
|
||||
protected $priceHelper;
|
||||
|
||||
/**
|
||||
* Product Image helper instance
|
||||
*
|
||||
|
|
@ -104,7 +97,6 @@ class Grouped extends AbstractType
|
|||
* @param Webkul\Product\Repositories\ProductInventoryRepository $productInventoryRepository
|
||||
* @param Webkul\Product\Repositories\ProductImageRepository $productImageRepository
|
||||
* @param Webkul\Product\Repositories\ProductGroupedProductRepository $productGroupedProductRepository
|
||||
* @param Webkul\Product\Helpers\Price $priceHelper
|
||||
* @param Webkul\Product\Helpers\ProductImage $productImageHelper
|
||||
* @return void
|
||||
*/
|
||||
|
|
@ -115,7 +107,6 @@ class Grouped extends AbstractType
|
|||
ProductInventoryRepository $productInventoryRepository,
|
||||
ProductImageRepository $productImageRepository,
|
||||
ProductGroupedProductRepository $productGroupedProductRepository,
|
||||
Price $priceHelper,
|
||||
ProductImage $productImageHelper
|
||||
)
|
||||
{
|
||||
|
|
@ -125,7 +116,6 @@ class Grouped extends AbstractType
|
|||
$attributeValueRepository,
|
||||
$productInventoryRepository,
|
||||
$productImageRepository,
|
||||
$priceHelper,
|
||||
$productImageHelper
|
||||
);
|
||||
|
||||
|
|
@ -149,14 +139,42 @@ class Grouped extends AbstractType
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns validation rules
|
||||
* Get product minimal price
|
||||
*
|
||||
* @return array
|
||||
* @return float
|
||||
*/
|
||||
public function getTypeValidationRules()
|
||||
public function getMinimalPrice()
|
||||
{
|
||||
return [
|
||||
];
|
||||
$minPrices = [];
|
||||
|
||||
$result = $this->product->grouped_products()
|
||||
->join('product_flat', 'product_grouped_products.associated_product_id', '=', 'product_flat.product_id')
|
||||
->selectRaw('IF( product_flat.special_price_from IS NOT NULL
|
||||
AND product_flat.special_price_to IS NOT NULL , IF( NOW( ) >= product_flat.special_price_from
|
||||
AND NOW( ) <= product_flat.special_price_to, IF( product_flat.special_price IS NULL OR product_flat.special_price = 0 , product_flat.price, LEAST( product_flat.special_price, product_flat.price ) ) , product_flat.price ) , IF( product_flat.special_price_from IS NULL , IF( product_flat.special_price_to IS NULL , IF( product_flat.special_price IS NULL OR product_flat.special_price = 0 , product_flat.price, LEAST( product_flat.special_price, product_flat.price ) ) , IF( NOW( ) <= product_flat.special_price_to, IF( product_flat.special_price IS NULL OR product_flat.special_price = 0 , product_flat.price, LEAST( product_flat.special_price, product_flat.price ) ) , product_flat.price ) ) , IF( product_flat.special_price_to IS NULL , IF( NOW( ) >= product_flat.special_price_from, IF( product_flat.special_price IS NULL OR product_flat.special_price = 0 , product_flat.price, LEAST( product_flat.special_price, product_flat.price ) ) , product_flat.price ) , product_flat.price ) ) ) AS min_price')
|
||||
->where('product_flat.channel', core()->getCurrentChannelCode())
|
||||
->where('product_flat.locale', app()->getLocale())
|
||||
->get();
|
||||
|
||||
foreach ($result as $price) {
|
||||
$minPrices[] = $price->min_price;
|
||||
}
|
||||
|
||||
if (empty($minPrices))
|
||||
return 0;
|
||||
|
||||
return min($minPrices);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get product minimal price
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getPriceHtml()
|
||||
{
|
||||
return '<span class="price-label">' . trans('shop::app.products.starting-at') . '</span>'
|
||||
. '<span class="final-price">' . core()->currency($this->getMinimalPrice()) . '</span>';
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -45,16 +45,6 @@ class Simple extends AbstractType
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this product can have inventory
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function isStockable()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param integer $qty
|
||||
*
|
||||
|
|
@ -64,6 +54,16 @@ class Simple extends AbstractType
|
|||
{
|
||||
return $qty <= $this->totalQuantity() ? true : (core()->getConfigData('catalog.inventory.stock_options.backorders') ? true : false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this product can have inventory
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function showQuantityBox()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return integer
|
||||
|
|
|
|||
|
|
@ -27,4 +27,14 @@ class Virtual extends AbstractType
|
|||
'admin::catalog.products.accordians.categories',
|
||||
'admin::catalog.products.accordians.product-links'
|
||||
];
|
||||
|
||||
/**
|
||||
* Return true if this product can have inventory
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function isStockable()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -154,7 +154,7 @@ class Order extends Model implements OrderContract
|
|||
*/
|
||||
public function haveStockableItems()
|
||||
{
|
||||
foreach ($this->all_items as $item) {
|
||||
foreach ($this->items as $item) {
|
||||
if ($item->getTypeInstance()->isStockable())
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ class OrderItem extends Model implements OrderItemContract
|
|||
*/
|
||||
public function canShip()
|
||||
{
|
||||
if ($this->type != 'configurable' && ! $this->isStockable())
|
||||
if (! $this->isStockable())
|
||||
return false;
|
||||
|
||||
if ($this->qty_to_ship > 0)
|
||||
|
|
@ -61,7 +61,7 @@ class OrderItem extends Model implements OrderItemContract
|
|||
*/
|
||||
public function getQtyToShipAttribute()
|
||||
{
|
||||
if ($this->type != 'configurable' && ! $this->isStockable())
|
||||
if (! $this->isStockable())
|
||||
return 0;
|
||||
|
||||
return $this->qty_ordered - $this->qty_shipped - $this->qty_refunded - $this->qty_canceled;
|
||||
|
|
|
|||
|
|
@ -181,7 +181,7 @@ class OrderRepository extends Repository
|
|||
$totalQtyOrdered += $item->qty_ordered;
|
||||
$totalQtyInvoiced += $item->qty_invoiced;
|
||||
|
||||
if ($item->type != 'configurable' && ! $item->isStockable()) {
|
||||
if (! $item->isStockable()) {
|
||||
$totalQtyShipped += $item->qty_ordered;
|
||||
} else {
|
||||
$totalQtyShipped += $item->qty_shipped;
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ class FlatRate extends AbstractShipping
|
|||
|
||||
if ($this->getConfigData('type') == 'per_unit') {
|
||||
foreach ($cart->items as $item) {
|
||||
if ($item->type == 'configurable' || $item->type == 'configurable') {
|
||||
if ($item->product->getTypeInstance()->isStockable()) {
|
||||
$object->price += core()->convertPrice($this->getConfigData('default_rate')) * $item->quantity;
|
||||
$object->base_price += $this->getConfigData('default_rate') * $item->quantity;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -192,6 +192,7 @@ input {
|
|||
.price-label {
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.regular-price {
|
||||
|
|
@ -341,6 +342,7 @@ input {
|
|||
|
||||
.product-card {
|
||||
position: relative;
|
||||
padding: 15px;
|
||||
|
||||
.product-image {
|
||||
max-height: 350px;
|
||||
|
|
@ -421,13 +423,10 @@ input {
|
|||
}
|
||||
|
||||
.product-card:hover {
|
||||
box-shadow: 0 1px 2px rgba(0,0,0,0.05);
|
||||
-webkit-box-shadow: 0px 2px 16px 4px rgba(40, 44, 63, 0.07);
|
||||
-moz-box-shadow: 0px 2px 16px 4px rgba(40, 44, 63, 0.07);
|
||||
box-shadow: 0px 2px 16px 4px rgba(40, 44, 63, 0.07);
|
||||
padding: 10px;
|
||||
transition: .3s;
|
||||
outline: 1px solid $outline-hvr;
|
||||
outline: 1px solid #eaeaec;
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, .05);
|
||||
-webkit-box-shadow: 0 2px 16px 4px rgba(40, 44, 63, .07);
|
||||
box-shadow: 0 2px 16px 4px rgba(40, 44, 63, .07)
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 580px) {
|
||||
|
|
@ -2786,6 +2785,8 @@ section.review {
|
|||
}
|
||||
|
||||
.product-price {
|
||||
margin-top: 10px;
|
||||
|
||||
.pro-price {
|
||||
color: $disc-price;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -323,7 +323,8 @@ return [
|
|||
'in-stock' => 'في الأسهم',
|
||||
'out-of-stock' => 'خارج الأسهم',
|
||||
'view-all' => 'عرض الكل',
|
||||
'less-quantity' => 'Quantity can not be less than one.'
|
||||
'less-quantity' => 'Quantity can not be less than one.',
|
||||
'starting-at' => 'Starting at'
|
||||
],
|
||||
|
||||
'wishlist' => [
|
||||
|
|
|
|||
|
|
@ -353,7 +353,8 @@ return [
|
|||
'links' => 'Links',
|
||||
'sample' => 'Sample',
|
||||
'name' => 'Name',
|
||||
'qty' => 'Qty'
|
||||
'qty' => 'Qty',
|
||||
'starting-at' => 'Starting at'
|
||||
],
|
||||
|
||||
'wishlist' => [
|
||||
|
|
|
|||
|
|
@ -333,7 +333,8 @@ return [
|
|||
'out-of-stock' => 'تمام شده',
|
||||
'view-all' => 'مشاهده همه',
|
||||
'select-above-options' => 'لطفا ابتدا گزینه های بالا را انتخاب کنید',
|
||||
'less-quantity' => 'کمیت نمی تواند کمتر از یک باشد.'
|
||||
'less-quantity' => 'کمیت نمی تواند کمتر از یک باشد.',
|
||||
'starting-at' => 'Starting at'
|
||||
],
|
||||
|
||||
'wishlist' => [
|
||||
|
|
|
|||
|
|
@ -328,7 +328,8 @@ return [
|
|||
'out-of-stock' => 'Fora de Estoque',
|
||||
'view-all' => 'Ver Tudo',
|
||||
'select-above-options' => 'Por favor, selecione as opções acima primeiro.',
|
||||
'less-quantity' => 'Quantity can not be less than one.'
|
||||
'less-quantity' => 'Quantity can not be less than one.',
|
||||
'starting-at' => 'Starting at'
|
||||
],
|
||||
|
||||
'wishlist' => [
|
||||
|
|
|
|||
|
|
@ -1,25 +1,7 @@
|
|||
{!! view_render_event('bagisto.shop.products.price.before', ['product' => $product]) !!}
|
||||
|
||||
<div class="product-price">
|
||||
@inject ('priceHelper', 'Webkul\Product\Helpers\Price')
|
||||
|
||||
@if ($product->type == 'configurable')
|
||||
<span class="price-label">{{ __('shop::app.products.price-label') }}</span>
|
||||
|
||||
<span class="final-price">{{ core()->currency($priceHelper->getMinimalPrice($product)) }}</span>
|
||||
@else
|
||||
@if ($priceHelper->haveSpecialPrice($product))
|
||||
<div class="sticker sale">
|
||||
{{ __('shop::app.products.sale') }}
|
||||
</div>
|
||||
|
||||
<span class="regular-price">{{ core()->currency($product->price) }}</span>
|
||||
|
||||
<span class="special-price">{{ core()->currency($priceHelper->getSpecialPrice($product)) }}</span>
|
||||
@else
|
||||
<span>{{ core()->currency($product->price) }}</span>
|
||||
@endif
|
||||
@endif
|
||||
{!! $product->getTypeInstance()->getPriceHtml() !!}
|
||||
</div>
|
||||
|
||||
{!! view_render_event('bagisto.shop.products.price.after', ['product' => $product]) !!}
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
<div class="product-price mt-10">
|
||||
@inject ('priceHelper', 'Webkul\Product\Helpers\Price')
|
||||
|
||||
@if ($product->type == 'configurable')
|
||||
<span class="pro-price">{{ core()->currency($priceHelper->getMinimalPrice($product)) }}</span>
|
||||
@else
|
||||
@if ($priceHelper->haveSpecialPrice($product))
|
||||
<span class="pro-price">{{ core()->currency($priceHelper->getSpecialPrice($product)) }}</span>
|
||||
@else
|
||||
<span class="pro-price">{{ core()->currency($product->price) }}</span>
|
||||
@endif
|
||||
@endif
|
||||
</div>
|
||||
|
|
@ -26,7 +26,7 @@
|
|||
</a>
|
||||
</div>
|
||||
|
||||
@include('shop::products.review-price')
|
||||
@include('shop::products.price')
|
||||
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -10,8 +10,8 @@
|
|||
|
||||
<div class="review-layouter">
|
||||
@inject ('productImageHelper', 'Webkul\Product\Helpers\ProductImage')
|
||||
|
||||
@inject ('reviewHelper', 'Webkul\Product\Helpers\Review')
|
||||
@inject ('priceHelper', 'Webkul\Product\Helpers\Price')
|
||||
|
||||
<?php $productBaseImage = $productImageHelper->getProductBaseImage($product); ?>
|
||||
|
||||
|
|
@ -29,15 +29,10 @@
|
|||
</div>
|
||||
|
||||
<div class="product-price mt-10">
|
||||
@inject ('priceHelper', 'Webkul\Product\Helpers\Price')
|
||||
@if ($product->type == 'configurable')
|
||||
<span class="pro-price">{{ core()->currency($priceHelper->getMinimalPrice($product)) }}</span>
|
||||
@if ($product->getTypeInstance()->haveSpecialPrice())
|
||||
<span class="pro-price">{{ core()->currency($product->getTypeInstance()->getSpecialPrice()) }}</span>
|
||||
@else
|
||||
@if ($priceHelper->haveSpecialPrice($product))
|
||||
<span class="pro-price">{{ core()->currency($priceHelper->getSpecialPrice($product)) }}</span>
|
||||
@else
|
||||
<span class="pro-price">{{ core()->currency($product->price) }}</span>
|
||||
@endif
|
||||
<span class="pro-price">{{ core()->currency($product->price) }}</span>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@
|
|||
|
||||
{!! view_render_event('bagisto.shop.products.view.quantity.before', ['product' => $product]) !!}
|
||||
|
||||
@if ($product->type == 'configurable' || $product->isStockable())
|
||||
@if ($product->getTypeInstance()->showQuantityBox())
|
||||
<div class="quantity control-group" :class="[errors.has('quantity') ? 'has-error' : '']">
|
||||
|
||||
<label class="required">{{ __('shop::app.products.quantity') }}</label>
|
||||
|
|
|
|||
Loading…
Reference in New Issue