refactoring of validateCartItem methods of product types

This commit is contained in:
Steffen Mahler 2020-07-04 15:20:59 +02:00
parent 492ad97b6c
commit a44fa7445d
16 changed files with 373 additions and 158 deletions

View File

@ -12,6 +12,9 @@ use Webkul\BookingProduct\Repositories\BookingProductEventTicketRepository;
use Webkul\BookingProduct\Repositories\BookingProductRentalSlotRepository; use Webkul\BookingProduct\Repositories\BookingProductRentalSlotRepository;
use Webkul\BookingProduct\Repositories\BookingProductTableSlotRepository; use Webkul\BookingProduct\Repositories\BookingProductTableSlotRepository;
use Webkul\BookingProduct\Repositories\BookingRepository; use Webkul\BookingProduct\Repositories\BookingRepository;
use Webkul\Product\Datatypes\CartItemValidationResult;
use Webkul\Checkout\Models\CartItem;
class Booking class Booking
{ {
@ -93,7 +96,7 @@ class Booking
* @param string $type * @param string $type
* @return array * @return array
*/ */
public function getTypeHepler($type) public function getTypeHelper($type)
{ {
return $this->typeHelpers[$type]; return $this->typeHelpers[$type];
} }
@ -529,12 +532,20 @@ class Booking
* @param \Webkul\Checkout\Contracts\CartItem $item * @param \Webkul\Checkout\Contracts\CartItem $item
* @return void * @return void
*/ */
public function validateCartItem($item) public function validateCartItem(CartItem $item): CartItemValidationResult
{ {
$result = new CartItemValidationResult();
if ($this->isCartItemInactive($item)) {
$result->itemIsInactive();
return $result;
}
$price = $item->product->getTypeInstance()->getFinalPrice($item->quantity); $price = $item->product->getTypeInstance()->getFinalPrice($item->quantity);
if ($price == $item->base_price) { if ($price == $item->base_price) {
return; return $result;
} }
$item->base_price = $price; $item->base_price = $price;
@ -544,5 +555,24 @@ class Booking
$item->total = core()->convertPrice($price * $item->quantity); $item->total = core()->convertPrice($price * $item->quantity);
$item->save(); $item->save();
$result->cartIsDirty();
return $result;
}
/**
* Returns true, if cart item is inactive
*
* @param \Webkul\Checkout\Contracts\CartItem $item
*
* @return bool
*/
public function isCartItemInactive(\Webkul\Checkout\Contracts\CartItem $item): bool
{
if ($item->product->status === 0) {
return true;
}
return false;
} }
} }

View File

@ -5,6 +5,8 @@ namespace Webkul\BookingProduct\Helpers;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use Carbon\Carbon; use Carbon\Carbon;
use Webkul\Checkout\Facades\Cart; use Webkul\Checkout\Facades\Cart;
use Webkul\Product\Datatypes\CartItemValidationResult;
use Webkul\Checkout\Models\CartItem;
class EventTicket extends Booking class EventTicket extends Booking
{ {
@ -131,8 +133,16 @@ class EventTicket extends Booking
* @param \Webkul\Checkout\Contracts\CartItem $item * @param \Webkul\Checkout\Contracts\CartItem $item
* @return float * @return float
*/ */
public function validateCartItem($item) public function validateCartItem(CartItem $item): CartItemValidationResult
{ {
$result = new CartItemValidationResult();
if (parent::isCartItemInactive($item)) {
$result->itemIsInactive();
return $result;
}
$price = $item->product->getTypeInstance()->getFinalPrice($item->quantity); $price = $item->product->getTypeInstance()->getFinalPrice($item->quantity);
$bookingProduct = $this->bookingProductRepository->findOneByField('product_id', $item->product_id); $bookingProduct = $this->bookingProductRepository->findOneByField('product_id', $item->product_id);
@ -140,9 +150,9 @@ class EventTicket extends Booking
$ticket = $bookingProduct->event_tickets()->find($item->additional['booking']['ticket_id']); $ticket = $bookingProduct->event_tickets()->find($item->additional['booking']['ticket_id']);
if (! $ticket) { if (! $ticket) {
Cart::removeItem($item->id); $result->itemIsInactive();
return true; return $result;
} }
if ($this->isInSale($ticket)) { if ($this->isInSale($ticket)) {
@ -152,7 +162,7 @@ class EventTicket extends Booking
} }
if ($price === $item->base_price) { if ($price === $item->base_price) {
return; return $result;
} }
$item->base_price = $price; $item->base_price = $price;
@ -162,6 +172,9 @@ class EventTicket extends Booking
$item->total = core()->convertPrice($price * $item->quantity); $item->total = core()->convertPrice($price * $item->quantity);
$item->save(); $item->save();
$result->cartIsDirty();
return $result;
} }
/** /**

View File

@ -5,6 +5,8 @@ namespace Webkul\BookingProduct\Helpers;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use Carbon\Carbon; use Carbon\Carbon;
use Webkul\Checkout\Facades\Cart; use Webkul\Checkout\Facades\Cart;
use Webkul\Checkout\Models\CartItem;
use Webkul\Product\Datatypes\CartItemValidationResult;
class RentalSlot extends Booking class RentalSlot extends Booking
{ {
@ -222,8 +224,16 @@ class RentalSlot extends Booking
* @param \Webkul\Checkout\Contracts\CartItem $item * @param \Webkul\Checkout\Contracts\CartItem $item
* @return void|null * @return void|null
*/ */
public function validateCartItem($item) public function validateCartItem(CartItem $item): CartItemValidationResult
{ {
$result = new CartItemValidationResult();
if (parent::isCartItemInactive($item)) {
$result->itemIsInactive();
return $result;
}
$price = $item->product->getTypeInstance()->getFinalPrice($item->quantity); $price = $item->product->getTypeInstance()->getFinalPrice($item->quantity);
$bookingProduct = $this->bookingProductRepository->findOneByField('product_id', $item->product_id); $bookingProduct = $this->bookingProductRepository->findOneByField('product_id', $item->product_id);
@ -234,9 +244,9 @@ class RentalSlot extends Booking
if (! isset($item->additional['booking']['date_from']) if (! isset($item->additional['booking']['date_from'])
|| ! isset($item->additional['booking']['date_to']) || ! isset($item->additional['booking']['date_to'])
) { ) {
Cart::removeItem($item->id); $result->itemIsInactive();
return true; return $result;
} }
$from = Carbon::createFromTimeString($item->additional['booking']['date_from'] . " 00:00:00"); $from = Carbon::createFromTimeString($item->additional['booking']['date_from'] . " 00:00:00");
@ -247,9 +257,9 @@ class RentalSlot extends Booking
if (! isset($item->additional['booking']['slot']['from']) if (! isset($item->additional['booking']['slot']['from'])
|| ! isset($item->additional['booking']['slot']['to']) || ! isset($item->additional['booking']['slot']['to'])
) { ) {
Cart::removeItem($item->id); $result->itemIsInactive();
return true; return $result;
} }
$from = Carbon::createFromTimestamp($item->additional['booking']['slot']['from']); $from = Carbon::createFromTimestamp($item->additional['booking']['slot']['from']);
@ -259,7 +269,7 @@ class RentalSlot extends Booking
} }
if ($price == $item->base_price) { if ($price == $item->base_price) {
return; return $result;
} }
$item->base_price = $price; $item->base_price = $price;
@ -269,5 +279,8 @@ class RentalSlot extends Booking
$item->total = core()->convertPrice($price * $item->quantity); $item->total = core()->convertPrice($price * $item->quantity);
$item->save(); $item->save();
$result->cartIsDirty();
return $result;
} }
} }

View File

@ -4,6 +4,7 @@ namespace Webkul\BookingProduct\Type;
use Illuminate\Support\Arr; use Illuminate\Support\Arr;
use Webkul\Attribute\Repositories\AttributeRepository; use Webkul\Attribute\Repositories\AttributeRepository;
use Webkul\Product\Datatypes\CartItemValidationResult;
use Webkul\Product\Repositories\ProductRepository; use Webkul\Product\Repositories\ProductRepository;
use Webkul\Product\Repositories\ProductAttributeValueRepository; use Webkul\Product\Repositories\ProductAttributeValueRepository;
use Webkul\Product\Repositories\ProductInventoryRepository; use Webkul\Product\Repositories\ProductInventoryRepository;
@ -13,6 +14,7 @@ use Webkul\BookingProduct\Repositories\BookingProductRepository;
use Webkul\BookingProduct\Helpers\Booking as BookingHelper; use Webkul\BookingProduct\Helpers\Booking as BookingHelper;
use Webkul\Product\Type\Virtual; use Webkul\Product\Type\Virtual;
use Carbon\Carbon; use Carbon\Carbon;
use Webkul\Checkout\Models\CartItem;
class Booking extends Virtual class Booking extends Virtual
{ {
@ -149,7 +151,7 @@ class Booking extends Virtual
{ {
$bookingProduct = $this->getBookingProduct($this->product->id); $bookingProduct = $this->getBookingProduct($this->product->id);
return app($this->bookingHelper->getTypeHepler($bookingProduct->type))->isItemHaveQuantity($cartItem); return app($this->bookingHelper->getTypeHelper($bookingProduct->type))->isItemHaveQuantity($cartItem);
} }
/** /**
@ -204,7 +206,7 @@ class Booking extends Virtual
$products = parent::prepareForCart($data); $products = parent::prepareForCart($data);
} }
$typeHelper = app($this->bookingHelper->getTypeHepler($bookingProduct->type)); $typeHelper = app($this->bookingHelper->getTypeHelper($bookingProduct->type));
if (! $typeHelper->isSlotAvailable($products)) { if (! $typeHelper->isSlotAvailable($products)) {
return trans('shop::app.checkout.cart.quantity.inventory_warning'); return trans('shop::app.checkout.cart.quantity.inventory_warning');
@ -250,17 +252,26 @@ class Booking extends Virtual
/** /**
* Validate cart item product price * Validate cart item product price
* *
* @param \Webkul\Checkout\Contracts\CartItem $item * @param \Webkul\Checkout\Models\CartItem $item
* @return float *
* @return \Webkul\Product\Datatypes\CartItemValidationResult
*/ */
public function validateCartItem($item) public function validateCartItem(CartItem $item): CartItemValidationResult
{ {
$result = new CartItemValidationResult();
if (parent::isCartItemInactive($item)) {
$result->itemIsInactive();
return $result;
}
$bookingProduct = $this->getBookingProduct($item->product_id); $bookingProduct = $this->getBookingProduct($item->product_id);
if (! $bookingProduct) { if (! $bookingProduct) {
return; return $result;
} }
return app($this->bookingHelper->getTypeHepler($bookingProduct->type))->validateCartItem($item); return app($this->bookingHelper->getTypeHelper($bookingProduct->type))->validateCartItem($item);
} }
} }

View File

@ -571,16 +571,14 @@ class Cart
* *
* @return void * @return void
*/ */
public function collectTotals() public function collectTotals(): void
{ {
$validated = $this->validateItems(); if (! $this->validateItems()) {
return;
if (! $validated) {
return false;
} }
if (! $cart = $this->getCart()) { if (! $cart = $this->getCart()) {
return false; return;
} }
Event::dispatch('checkout.cart.collect.totals.before', $cart); Event::dispatch('checkout.cart.collect.totals.before', $cart);
@ -637,37 +635,42 @@ class Cart
* *
* @return bool * @return bool
*/ */
public function validateItems() public function validateItems(): bool
{ {
$result = false;
if (! $cart = $this->getCart()) { if (! $cart = $this->getCart()) {
return; return false;
} }
if (count($cart->items) == 0) { if (count($cart->items) == 0) {
$this->cartRepository->delete($cart->id); $this->cartRepository->delete($cart->id);
return false; return false;
} else {
foreach ($cart->items as $item) {
$response = $item->product->getTypeInstance()->validateCartItem($item);
// ToDo: refactoring of all validateCartItem functions, at the moment they return nothing
if ($response) { }
return;
}
$price = ! is_null($item->custom_price) ? $item->custom_price : $item->base_price; foreach ($cart->items as $item) {
$validationResult = $item->product->getTypeInstance()->validateCartItem($item);
$this->cartItemRepository->update([ if ($validationResult->isItemInactive()) {
'price' => core()->convertPrice($price), $this->removeItem($item->id);
'base_price' => $price, session()->flash('info', __('shop::app.checkout.cart.item.inactive'));
'total' => core()->convertPrice($price * $item->quantity),
'base_total' => $price * $item->quantity,
], $item->id);
} }
return true; $price = ! is_null($item->custom_price) ? $item->custom_price : $item->base_price;
$this->cartItemRepository->update([
'price' => core()->convertPrice($price),
'base_price' => $price,
'total' => core()->convertPrice($price * $item->quantity),
'base_total' => $price * $item->quantity,
], $item->id);
$result |= $validationResult->isCartDirty();
} }
return $result;
} }
/** /**
@ -1131,15 +1134,7 @@ class Cart
* @return bool * @return bool
*/ */
private function isCartItemInactive(\Webkul\Checkout\Contracts\CartItem $item): bool { private function isCartItemInactive(\Webkul\Checkout\Contracts\CartItem $item): bool {
if ($item->product->status === 0) { return $item->product->getTypeInstance()->isCartItemInactive($item);
return true;
}
if ($item->product->type === 'configurable' && $item->child && $item->child->product->status === 0) {
return true;
}
return false;
} }
/** /**

View File

@ -0,0 +1,39 @@
<?php
namespace Webkul\Product\Datatypes;
class CartItemValidationResult
{
/** @var bool $cartIsDirty */
private $cartIsDirty = false;
/** @var bool $itemIsInactive */
private $itemIsInactive = false;
/**
* @return bool
*/
public function isCartDirty(): bool
{
return $this->cartIsDirty;
}
/**
* @return bool
*/
public function isItemInactive(): bool
{
return $this->itemIsInactive;
}
public function itemIsInactive(): void
{
$this->itemIsInactive = true;
$this->cartIsDirty = true;
}
public function cartIsDirty(): void
{
$this->cartIsDirty = true;
}
}

View File

@ -3,8 +3,8 @@
namespace Webkul\Product\Type; namespace Webkul\Product\Type;
use Illuminate\Support\Facades\Storage; use Illuminate\Support\Facades\Storage;
use phpDocumentor\Reflection\Types\Boolean;
use Webkul\Attribute\Repositories\AttributeRepository; use Webkul\Attribute\Repositories\AttributeRepository;
use Webkul\Product\Datatypes\CartItemValidationResult;
use Webkul\Product\Repositories\ProductRepository; use Webkul\Product\Repositories\ProductRepository;
use Webkul\Product\Repositories\ProductAttributeValueRepository; use Webkul\Product\Repositories\ProductAttributeValueRepository;
use Webkul\Product\Repositories\ProductInventoryRepository; use Webkul\Product\Repositories\ProductInventoryRepository;
@ -12,6 +12,7 @@ use Webkul\Product\Repositories\ProductImageRepository;
use Webkul\Product\Models\ProductAttributeValue; use Webkul\Product\Models\ProductAttributeValue;
use Webkul\Product\Helpers\ProductImage; use Webkul\Product\Helpers\ProductImage;
use Webkul\Checkout\Facades\Cart; use Webkul\Checkout\Facades\Cart;
use Webkul\Checkout\Models\CartItem;
abstract class AbstractType abstract class AbstractType
{ {
@ -54,7 +55,7 @@ abstract class AbstractType
* Product Image helper instance * Product Image helper instance
* *
* @var \Webkul\Product\Helpers\ProductImage * @var \Webkul\Product\Helpers\ProductImage
*/ */
protected $productImageHelper; protected $productImageHelper;
/** /**
@ -121,12 +122,13 @@ abstract class AbstractType
/** /**
* Create a new product type instance. * Create a new product type instance.
* *
* @param \Webkul\Attribute\Repositories\AttributeRepository $attributeRepository * @param \Webkul\Attribute\Repositories\AttributeRepository $attributeRepository
* @param \Webkul\Product\Repositories\ProductRepository $productRepository * @param \Webkul\Product\Repositories\ProductRepository $productRepository
* @param \Webkul\Product\Repositories\ProductAttributeValueRepository $attributeValueRepository * @param \Webkul\Product\Repositories\ProductAttributeValueRepository $attributeValueRepository
* @param \Webkul\Product\Repositories\ProductInventoryRepository $productInventoryRepository * @param \Webkul\Product\Repositories\ProductInventoryRepository $productInventoryRepository
* @param \Webkul\Product\Repositories\ProductImageRepository $productImageRepository * @param \Webkul\Product\Repositories\ProductImageRepository $productImageRepository
* @param \Webkul\Product\Helpers\ProductImage $productImageHelper * @param \Webkul\Product\Helpers\ProductImage $productImageHelper
*
* @return void * @return void
*/ */
public function __construct( public function __construct(
@ -136,8 +138,7 @@ abstract class AbstractType
ProductInventoryRepository $productInventoryRepository, ProductInventoryRepository $productInventoryRepository,
ProductImageRepository $productImageRepository, ProductImageRepository $productImageRepository,
ProductImage $productImageHelper ProductImage $productImageHelper
) ) {
{
$this->attributeRepository = $attributeRepository; $this->attributeRepository = $attributeRepository;
$this->productRepository = $productRepository; $this->productRepository = $productRepository;
@ -152,7 +153,8 @@ abstract class AbstractType
} }
/** /**
* @param array $data * @param array $data
*
* @return \Webkul\Product\Contracts\Product * @return \Webkul\Product\Contracts\Product
*/ */
public function create(array $data) public function create(array $data)
@ -161,9 +163,10 @@ abstract class AbstractType
} }
/** /**
* @param array $data * @param array $data
* @param int $id * @param int $id
* @param string $attribute * @param string $attribute
*
* @return \Webkul\Product\Contracts\Product * @return \Webkul\Product\Contracts\Product
*/ */
public function update(array $data, $id, $attribute = "id") public function update(array $data, $id, $attribute = "id")
@ -179,7 +182,7 @@ abstract class AbstractType
$data[$attribute->code] = isset($data[$attribute->code]) && $data[$attribute->code] ? 1 : 0; $data[$attribute->code] = isset($data[$attribute->code]) && $data[$attribute->code] ? 1 : 0;
} }
if (! isset($data[$attribute->code])) { if (!isset($data[$attribute->code])) {
continue; continue;
} }
@ -197,8 +200,8 @@ abstract class AbstractType
if ($attribute->type == 'image' || $attribute->type == 'file') { if ($attribute->type == 'image' || $attribute->type == 'file') {
$data[$attribute->code] = gettype($data[$attribute->code]) == 'object' $data[$attribute->code] = gettype($data[$attribute->code]) == 'object'
? request()->file($attribute->code)->store('product/' . $product->id) ? request()->file($attribute->code)->store('product/' . $product->id)
: NULL; : null;
} }
$attributeValue = $this->attributeValueRepository->findOneWhere([ $attributeValue = $this->attributeValueRepository->findOneWhere([
@ -208,7 +211,7 @@ abstract class AbstractType
'locale' => $attribute->value_per_locale ? $data['locale'] : null, 'locale' => $attribute->value_per_locale ? $data['locale'] : null,
]); ]);
if (! $attributeValue) { if (!$attributeValue) {
$this->attributeValueRepository->create([ $this->attributeValueRepository->create([
'product_id' => $product->id, 'product_id' => $product->id,
'attribute_id' => $attribute->id, 'attribute_id' => $attribute->id,
@ -218,8 +221,8 @@ abstract class AbstractType
]); ]);
} else { } else {
$this->attributeValueRepository->update([ $this->attributeValueRepository->update([
ProductAttributeValue::$attributeTypeFields[$attribute->type] => $data[$attribute->code] ProductAttributeValue::$attributeTypeFields[$attribute->type] => $data[$attribute->code],
], $attributeValue->id ], $attributeValue->id
); );
if ($attribute->type == 'image' || $attribute->type == 'file') { if ($attribute->type == 'image' || $attribute->type == 'file') {
@ -231,7 +234,7 @@ abstract class AbstractType
$route = request()->route() ? request()->route()->getName() : ""; $route = request()->route() ? request()->route()->getName() : "";
if ($route != 'admin.catalog.products.massupdate') { if ($route != 'admin.catalog.products.massupdate') {
if (! isset($data['categories'])) { if (!isset($data['categories'])) {
$data['categories'] = []; $data['categories'] = [];
} }
@ -247,7 +250,8 @@ abstract class AbstractType
$this->productImageRepository->uploadImages($data, $product); $this->productImageRepository->uploadImages($data, $product);
app('Webkul\Product\Repositories\ProductCustomerGroupPriceRepository')->saveCustomerGroupPrices($data, $product); app('Webkul\Product\Repositories\ProductCustomerGroupPriceRepository')->saveCustomerGroupPrices($data,
$product);
} }
return $product; return $product;
@ -256,7 +260,8 @@ abstract class AbstractType
/** /**
* Specify type instance product * Specify type instance product
* *
* @param \Webkul\Product\Contracts\Product $product * @param \Webkul\Product\Contracts\Product $product
*
* @return \Webkul\Product\Type\AbstractType * @return \Webkul\Product\Type\AbstractType
*/ */
public function setProduct($product) public function setProduct($product)
@ -293,7 +298,7 @@ abstract class AbstractType
*/ */
public function isSaleable() public function isSaleable()
{ {
if (! $this->product->status) { if (!$this->product->status) {
return false; return false;
} }
@ -341,7 +346,8 @@ abstract class AbstractType
} }
/** /**
* @param int $qty * @param int $qty
*
* @return bool * @return bool
*/ */
public function haveSufficientQuantity($qty) public function haveSufficientQuantity($qty)
@ -360,7 +366,8 @@ abstract class AbstractType
} }
/** /**
* @param \Webkul\Checkout\Contracts\CartItem $cartItem * @param \Webkul\Checkout\Contracts\CartItem $cartItem
*
* @return bool * @return bool
*/ */
public function isItemHaveQuantity($cartItem) public function isItemHaveQuantity($cartItem)
@ -376,9 +383,9 @@ abstract class AbstractType
$total = 0; $total = 0;
$channelInventorySourceIds = core()->getCurrentChannel() $channelInventorySourceIds = core()->getCurrentChannel()
->inventory_sources() ->inventory_sources()
->where('status', 1) ->where('status', 1)
->pluck('id'); ->pluck('id');
foreach ($this->product->inventories as $inventory) { foreach ($this->product->inventories as $inventory) {
if (is_numeric($index = $channelInventorySourceIds->search($inventory->inventory_source_id))) { if (is_numeric($index = $channelInventorySourceIds->search($inventory->inventory_source_id))) {
@ -387,8 +394,8 @@ abstract class AbstractType
} }
$orderedInventory = $this->product->ordered_inventories() $orderedInventory = $this->product->ordered_inventories()
->where('channel_id', core()->getCurrentChannel()->id) ->where('channel_id', core()->getCurrentChannel()->id)
->first(); ->first();
if ($orderedInventory) { if ($orderedInventory) {
$total -= $orderedInventory->qty; $total -= $orderedInventory->qty;
@ -400,7 +407,8 @@ abstract class AbstractType
/** /**
* Return true if item can be moved to cart from wishlist * Return true if item can be moved to cart from wishlist
* *
* @param \Webkul\Checkout\Contracts\CartItem $item * @param \Webkul\Checkout\Contracts\CartItem $item
*
* @return bool * @return bool
*/ */
public function canBeMovedFromWishlistToCart($item) public function canBeMovedFromWishlistToCart($item)
@ -411,18 +419,21 @@ abstract class AbstractType
/** /**
* Retrieve product attributes * Retrieve product attributes
* *
* @param \Webkul\Attribute\Contracts\Group $group * @param \Webkul\Attribute\Contracts\Group $group
* @param bool $skipSuperAttribute * @param bool $skipSuperAttribute
*
* @return \Illuminate\Support\Collection * @return \Illuminate\Support\Collection
*/ */
public function getEditableAttributes($group = null, $skipSuperAttribute = true) public function getEditableAttributes($group = null, $skipSuperAttribute = true)
{ {
if ($skipSuperAttribute) { if ($skipSuperAttribute) {
$this->skipAttributes = array_merge($this->product->super_attributes->pluck('code')->toArray(), $this->skipAttributes); $this->skipAttributes = array_merge($this->product->super_attributes->pluck('code')->toArray(),
$this->skipAttributes);
} }
if (! $group) { if (!$group) {
return $this->product->attribute_family->custom_attributes()->whereNotIn('attributes.code', $this->skipAttributes)->get(); return $this->product->attribute_family->custom_attributes()->whereNotIn('attributes.code',
$this->skipAttributes)->get();
} }
return $group->custom_attributes()->whereNotIn('code', $this->skipAttributes)->get(); return $group->custom_attributes()->whereNotIn('code', $this->skipAttributes)->get();
@ -451,7 +462,8 @@ abstract class AbstractType
/** /**
* Get product minimal price * Get product minimal price
* *
* @param int $qty * @param int $qty
*
* @return float * @return float
*/ */
public function getMinimalPrice($qty = null) public function getMinimalPrice($qty = null)
@ -476,7 +488,8 @@ abstract class AbstractType
/** /**
* Get product minimal price * Get product minimal price
* *
* @param int $qty * @param int $qty
*
* @return float * @return float
*/ */
public function getFinalPrice($qty = null) public function getFinalPrice($qty = null)
@ -487,7 +500,8 @@ abstract class AbstractType
/** /**
* Returns the product's minimal price * Returns the product's minimal price
* *
* @param int $qty * @param int $qty
*
* @return float * @return float
*/ */
public function getSpecialPrice($qty = null) public function getSpecialPrice($qty = null)
@ -496,7 +510,8 @@ abstract class AbstractType
} }
/** /**
* @param int $qty * @param int $qty
*
* @return bool * @return bool
*/ */
public function haveSpecialPrice($qty = null) public function haveSpecialPrice($qty = null)
@ -505,8 +520,8 @@ abstract class AbstractType
$rulePrice = app('Webkul\CatalogRule\Helpers\CatalogRuleProductPrice')->getRulePrice($this->product); $rulePrice = app('Webkul\CatalogRule\Helpers\CatalogRuleProductPrice')->getRulePrice($this->product);
if ((is_null($this->product->special_price) || ! (float) $this->product->special_price) if ((is_null($this->product->special_price) || !(float)$this->product->special_price)
&& ! $rulePrice && !$rulePrice
&& $customerGroupPrice == $this->product->price && $customerGroupPrice == $this->product->price
) { ) {
return false; return false;
@ -514,7 +529,7 @@ abstract class AbstractType
$haveSpecialPrice = false; $haveSpecialPrice = false;
if (! (float) $this->product->special_price) { if (!(float)$this->product->special_price) {
if ($rulePrice && $rulePrice->price < $this->product->price) { if ($rulePrice && $rulePrice->price < $this->product->price) {
$this->product->special_price = $rulePrice->price; $this->product->special_price = $rulePrice->price;
@ -526,7 +541,8 @@ abstract class AbstractType
$haveSpecialPrice = true; $haveSpecialPrice = true;
} else { } else {
if (core()->isChannelDateInInterval($this->product->special_price_from, $this->product->special_price_to)) { if (core()->isChannelDateInInterval($this->product->special_price_from,
$this->product->special_price_to)) {
$haveSpecialPrice = true; $haveSpecialPrice = true;
} elseif ($rulePrice) { } elseif ($rulePrice) {
$this->product->special_price = $rulePrice->price; $this->product->special_price = $rulePrice->price;
@ -570,11 +586,11 @@ abstract class AbstractType
$customerGroupPrices = $product->customer_group_prices()->where(function ($query) use ($customerGroupId) { $customerGroupPrices = $product->customer_group_prices()->where(function ($query) use ($customerGroupId) {
$query->where('customer_group_id', $customerGroupId) $query->where('customer_group_id', $customerGroupId)
->orWhereNull('customer_group_id'); ->orWhereNull('customer_group_id');
} }
)->get(); )->get();
if (! $customerGroupPrices->count()) { if (!$customerGroupPrices->count()) {
return $product->price; return $product->price;
} }
@ -635,7 +651,7 @@ abstract class AbstractType
'final_price' => [ 'final_price' => [
'price' => core()->convertPrice($this->getMinimalPrice()), 'price' => core()->convertPrice($this->getMinimalPrice()),
'formated_price' => core()->currency($this->getMinimalPrice()), 'formated_price' => core()->currency($this->getMinimalPrice()),
] ],
]; ];
} }
@ -660,7 +676,8 @@ abstract class AbstractType
/** /**
* Add product. Returns error message if can't prepare product. * Add product. Returns error message if can't prepare product.
* *
* @param array $data * @param array $data
*
* @return array * @return array
*/ */
public function prepareForCart($data) public function prepareForCart($data)
@ -669,7 +686,7 @@ abstract class AbstractType
$data = $this->getQtyRequest($data); $data = $this->getQtyRequest($data);
if (! $this->haveSufficientQuantity($data['quantity'])) { if (!$this->haveSufficientQuantity($data['quantity'])) {
return trans('shop::app.checkout.cart.quantity.inventory_warning'); return trans('shop::app.checkout.cart.quantity.inventory_warning');
} }
@ -690,7 +707,7 @@ abstract class AbstractType
'base_total_weight' => ($this->product->weight ?? 0) * $data['quantity'], 'base_total_weight' => ($this->product->weight ?? 0) * $data['quantity'],
'type' => $this->product->type, 'type' => $this->product->type,
'additional' => $this->getAdditionalOptions($data), 'additional' => $this->getAdditionalOptions($data),
] ],
]; ];
return $products; return $products;
@ -699,7 +716,8 @@ abstract class AbstractType
/** /**
* Get request quantity * Get request quantity
* *
* @param array $data * @param array $data
*
* @return array * @return array
*/ */
public function getQtyRequest($data) public function getQtyRequest($data)
@ -713,8 +731,9 @@ abstract class AbstractType
/** /**
* *
* @param array $options1 * @param array $options1
* @param array $options2 * @param array $options2
*
* @return bool * @return bool
*/ */
public function compareOptions($options1, $options2) public function compareOptions($options1, $options2)
@ -728,9 +747,9 @@ abstract class AbstractType
} else { } else {
return false; return false;
} }
} elseif (isset($options1['parent_id']) && ! isset($options2['parent_id'])) { } elseif (isset($options1['parent_id']) && !isset($options2['parent_id'])) {
return false; return false;
} elseif (isset($options2['parent_id']) && ! isset($options1['parent_id'])) { } elseif (isset($options2['parent_id']) && !isset($options1['parent_id'])) {
return false; return false;
} }
} }
@ -741,7 +760,8 @@ abstract class AbstractType
/** /**
* Returns additional information for items * Returns additional information for items
* *
* @param array $data * @param array $data
*
* @return array * @return array
*/ */
public function getAdditionalOptions($data) public function getAdditionalOptions($data)
@ -752,7 +772,8 @@ abstract class AbstractType
/** /**
* Get actual ordered item * Get actual ordered item
* *
* @param \Webkul\Checkout\Contracts\CartItem $item * @param \Webkul\Checkout\Contracts\CartItem $item
*
* @return \Webkul\Checkout\Contracts\CartItem|\Webkul\Sales\Contracts\OrderItem|\Webkul\Sales\Contracts\InvoiceItem|\Webkul\Sales\Contracts\ShipmentItem|\Webkul\Customer\Contracts\Wishlist * @return \Webkul\Checkout\Contracts\CartItem|\Webkul\Sales\Contracts\OrderItem|\Webkul\Sales\Contracts\InvoiceItem|\Webkul\Sales\Contracts\ShipmentItem|\Webkul\Customer\Contracts\Wishlist
*/ */
public function getOrderedItem($item) public function getOrderedItem($item)
@ -763,7 +784,8 @@ abstract class AbstractType
/** /**
* Get product base image * Get product base image
* *
* @param \Webkul\Customer\Contracts\CartItem|\Webkul\Checkout\Contracts\CartItem $item * @param \Webkul\Customer\Contracts\CartItem|\Webkul\Checkout\Contracts\CartItem $item
*
* @return array * @return array
*/ */
public function getBaseImage($item) public function getBaseImage($item)
@ -772,17 +794,26 @@ abstract class AbstractType
} }
/** /**
* Validate cart item product price * Validate cart item product price and other things
* *
* @param \Webkul\Customer\Contracts\CartItem $item * @param \Webkul\Checkout\Models\CartItem $item
* @return void *
* @return \Webkul\Product\Datatypes\CartItemValidationResult
*/ */
public function validateCartItem($item) public function validateCartItem(CartItem $item): CartItemValidationResult
{ {
$result = new CartItemValidationResult();
if ($this->isCartItemInactive($item)) {
$result->itemIsInactive();
return $result;
}
$price = $item->product->getTypeInstance()->getFinalPrice($item->quantity); $price = $item->product->getTypeInstance()->getFinalPrice($item->quantity);
if ($price == $item->base_price) { if ($price == $item->base_price) {
return; return $result;
} }
$item->base_price = $price; $item->base_price = $price;
@ -792,6 +823,9 @@ abstract class AbstractType
$item->total = core()->convertPrice($price * $item->quantity); $item->total = core()->convertPrice($price * $item->quantity);
$item->save(); $item->save();
$result->cartIsDirty();
return $result;
} }
//get product options //get product options
@ -799,4 +833,37 @@ abstract class AbstractType
{ {
return $this->productOptions; return $this->productOptions;
} }
/**
* Returns true, if cart item is inactive
*
* @param \Webkul\Checkout\Contracts\CartItem $item
*
* @return bool
*/
public function isCartItemInactive(\Webkul\Checkout\Contracts\CartItem $item): bool
{
if ($item->product->status === 0) {
return true;
}
switch ($item->product->type) {
case 'bundle':
foreach ($item->children as $child) {
if ($child->product->status === 0) {
return true;
}
}
break;
case 'configurable':
if ($item->child && $item->child->product->status === 0) {
return true;
}
break;
}
return false;
}
} }

View File

@ -3,6 +3,7 @@
namespace Webkul\Product\Type; namespace Webkul\Product\Type;
use Webkul\Attribute\Repositories\AttributeRepository; use Webkul\Attribute\Repositories\AttributeRepository;
use Webkul\Product\Datatypes\CartItemValidationResult;
use Webkul\Product\Repositories\ProductRepository; use Webkul\Product\Repositories\ProductRepository;
use Webkul\Product\Repositories\ProductAttributeValueRepository; use Webkul\Product\Repositories\ProductAttributeValueRepository;
use Webkul\Product\Repositories\ProductInventoryRepository; use Webkul\Product\Repositories\ProductInventoryRepository;
@ -11,6 +12,7 @@ use Webkul\Product\Repositories\ProductBundleOptionRepository;
use Webkul\Product\Repositories\ProductBundleOptionProductRepository; use Webkul\Product\Repositories\ProductBundleOptionProductRepository;
use Webkul\Product\Helpers\ProductImage; use Webkul\Product\Helpers\ProductImage;
use Webkul\Product\Helpers\BundleOption; use Webkul\Product\Helpers\BundleOption;
use Webkul\Checkout\Models\CartItem;
class Bundle extends AbstractType class Bundle extends AbstractType
{ {
@ -634,15 +636,23 @@ class Bundle extends AbstractType
} }
/** /**
* Validate cart item product price * Validate cart item product price and other things
* *
* @param \Webkul\Checkout\Contracts\CartItem $item * @param \Webkul\Checkout\Models\CartItem $item
* @return void *
* @return \Webkul\Product\Datatypes\CartItemValidationResult
*/ */
public function validateCartItem($item) public function validateCartItem(CartItem $item): CartItemValidationResult
{ {
$result = new CartItemValidationResult();
$price = 0; $price = 0;
if (parent::isCartItemInactive($item)) {
$result->itemIsInactive();
return $result;
}
foreach ($item->children as $childItem) { foreach ($item->children as $childItem) {
$childItem->product->getTypeInstance()->validateCartItem($childItem); $childItem->product->getTypeInstance()->validateCartItem($childItem);
@ -650,7 +660,7 @@ class Bundle extends AbstractType
} }
if ($price == $item->base_price) { if ($price == $item->base_price) {
return; return $result;
} }
$item->base_price = $price; $item->base_price = $price;
@ -662,6 +672,9 @@ class Bundle extends AbstractType
$item->additional = $this->getAdditionalOptions($item->additional); $item->additional = $this->getAdditionalOptions($item->additional);
$item->save(); $item->save();
$result->cartIsDirty();
return $result;
} }
/** /**
@ -674,4 +687,5 @@ class Bundle extends AbstractType
return $options; return $options;
} }
} }

View File

@ -3,9 +3,11 @@
namespace Webkul\Product\Type; namespace Webkul\Product\Type;
use Webkul\Customer\Contracts\CartItem; use Webkul\Customer\Contracts\CartItem;
use Webkul\Product\Datatypes\CartItemValidationResult;
use Webkul\Product\Models\ProductAttributeValue; use Webkul\Product\Models\ProductAttributeValue;
use Webkul\Product\Models\ProductFlat; use Webkul\Product\Models\ProductFlat;
use Illuminate\Support\Str; use Illuminate\Support\Str;
use Webkul\Checkout\Models\CartItem;
class Configurable extends AbstractType class Configurable extends AbstractType
{ {
@ -539,18 +541,28 @@ class Configurable extends AbstractType
/** /**
* Validate cart item product price * Validate cart item product price
* *
* @param \Webkul\Checkout\Contracts\CartItem $item * @param \Webkul\Product\Type\CartItem $item
*
* @return \Webkul\Product\Datatypes\CartItemValidationResult
*/ */
public function validateCartItem($item) public function validateCartItem(CartItem $item): CartItemValidationResult
{ {
if (! $item || ! $item->child) { $result = new CartItemValidationResult();
return;
if ($this->isCartItemInactive($item)) {
$result->itemIsInactive();
return $result;
} }
// if (! $item || ! $item->child) {
// return;
// }
$price = $item->child->product->getTypeInstance()->getFinalPrice($item->quantity); $price = $item->child->product->getTypeInstance()->getFinalPrice($item->quantity);
if ($price == $item->base_price) { if ($price == $item->base_price) {
return; return $result;
} }
$item->base_price = $price; $item->base_price = $price;
@ -560,6 +572,9 @@ class Configurable extends AbstractType
$item->total = core()->convertPrice($price * $item->quantity); $item->total = core()->convertPrice($price * $item->quantity);
$item->save(); $item->save();
$result->cartIsDirty();
return $result;
} }
/** /**

View File

@ -3,6 +3,7 @@
namespace Webkul\Product\Type; namespace Webkul\Product\Type;
use Webkul\Attribute\Repositories\AttributeRepository; use Webkul\Attribute\Repositories\AttributeRepository;
use Webkul\Product\Datatypes\CartItemValidationResult;
use Webkul\Product\Repositories\ProductRepository; use Webkul\Product\Repositories\ProductRepository;
use Webkul\Product\Repositories\ProductAttributeValueRepository; use Webkul\Product\Repositories\ProductAttributeValueRepository;
use Webkul\Product\Repositories\ProductInventoryRepository; use Webkul\Product\Repositories\ProductInventoryRepository;
@ -230,11 +231,20 @@ class Downloadable extends AbstractType
/** /**
* Validate cart item product price * Validate cart item product price
* *
* @param \Webkul\Checkout\Contracts\CartItem $item * @param \Webkul\Checkout\Models\CartItem $item
* @return float *
* @return \Webkul\Product\Datatypes\CartItemValidationResult
*/ */
public function validateCartItem($item) public function validateCartItem(CartItem $item): CartItemValidationResult
{ {
$result = new CartItemValidationResult();
if (parent::isCartItemInactive($item)) {
$result->itemIsInactive();
return $result;
}
$price = $item->product->getTypeInstance()->getFinalPrice($item->quantity); $price = $item->product->getTypeInstance()->getFinalPrice($item->quantity);
foreach ($item->product->downloadable_links as $link) { foreach ($item->product->downloadable_links as $link) {
@ -246,7 +256,7 @@ class Downloadable extends AbstractType
} }
if ($price == $item->base_price) { if ($price == $item->base_price) {
return; return $result;
} }
$item->base_price = $price; $item->base_price = $price;
@ -256,5 +266,8 @@ class Downloadable extends AbstractType
$item->total = core()->convertPrice($price * $item->quantity); $item->total = core()->convertPrice($price * $item->quantity);
$item->save(); $item->save();
$result->cartIsDirty();
return $result;
} }
} }

View File

@ -464,8 +464,8 @@ return [
'success' => 'تم بنجاح إضافة العنصر إلى العربة', 'success' => 'تم بنجاح إضافة العنصر إلى العربة',
'success-remove' => 'تم إزالة العنصر بنجاح من العربة', 'success-remove' => 'تم إزالة العنصر بنجاح من العربة',
'error-add' => 'لا يمكن إضافة العنصر إلى العربة ، رجاء حاول مرة أخرى ', 'error-add' => 'لا يمكن إضافة العنصر إلى العربة ، رجاء حاول مرة أخرى ',
'inactive' => 'An item is inactive and was removed from cart.', 'inactive' => 'An item is inactive and was removed from cart',
'inactive-add' => 'Inactive item cannot be added to cart.', 'inactive-add' => 'Inactive item cannot be added to cart',
], ],
'quantity-error' => 'الكمية المطلوبة غير متوفرة', 'quantity-error' => 'الكمية المطلوبة غير متوفرة',
'cart-subtotal' => 'المجموع الفرعي للمشتريات', 'cart-subtotal' => 'المجموع الفرعي للمشتريات',

View File

@ -431,8 +431,8 @@ return [
'success' => 'El artículp se añadió a la cesta', 'success' => 'El artículp se añadió a la cesta',
'success-remove' => 'El artículo se eliminó de la cesta', 'success-remove' => 'El artículo se eliminó de la cesta',
'error-add' => 'El artículo no se puede añadir a la cesta, inténtelo más tarde', 'error-add' => 'El artículo no se puede añadir a la cesta, inténtelo más tarde',
'inactive' => 'An item is inactive and was removed from cart.', 'inactive' => 'An item is inactive and was removed from cart',
'inactive-add' => 'Inactive item cannot be added to cart.', 'inactive-add' => 'Inactive item cannot be added to cart',
], ],
'quantity-error' => 'La cantidad solicitada no está disponible', 'quantity-error' => 'La cantidad solicitada no está disponible',
'cart-subtotal' => 'Total parcial', 'cart-subtotal' => 'Total parcial',

View File

@ -463,8 +463,8 @@ return [
'success' => 'مورد با موفقیت به سبد خرید اضافه شد', 'success' => 'مورد با موفقیت به سبد خرید اضافه شد',
'success-remove' => 'مورد با موفقیت از سبد خرید حذف شد', 'success-remove' => 'مورد با موفقیت از سبد خرید حذف شد',
'error-add' => 'لطفاً موردی را به سبد خرید اضافه نکرد ، لطفا بعداً دوباره امتحان کنید', 'error-add' => 'لطفاً موردی را به سبد خرید اضافه نکرد ، لطفا بعداً دوباره امتحان کنید',
'inactive' => 'An item is inactive and was removed from cart.', 'inactive' => 'An item is inactive and was removed from cart',
'inactive-add' => 'Inactive item cannot be added to cart.', 'inactive-add' => 'Inactive item cannot be added to cart',
], ],
'quantity-error' => 'مقدار درخواستی در دسترس نیست', 'quantity-error' => 'مقدار درخواستی در دسترس نیست',

View File

@ -425,8 +425,8 @@ return [
'success' => 'アイテムがカートに追加されました。', 'success' => 'アイテムがカートに追加されました。',
'success-remove' => 'アイテムがカートから削除されました。', 'success-remove' => 'アイテムがカートから削除されました。',
'error-add' => 'アイテムをカートに追加できません。しばらくしてから再度お試し下さい。', 'error-add' => 'アイテムをカートに追加できません。しばらくしてから再度お試し下さい。',
'inactive' => 'An item is inactive and was removed from cart.', 'inactive' => 'An item is inactive and was removed from cart',
'inactive-add' => 'Inactive item cannot be added to cart.', 'inactive-add' => 'Inactive item cannot be added to cart',
], ],
'quantity-error' => 'ご希望の数量の在庫が現在ございません。', 'quantity-error' => 'ご希望の数量の在庫が現在ございません。',
'cart-subtotal' => '小計', 'cart-subtotal' => '小計',

View File

@ -453,8 +453,8 @@ return [
'success' => 'Item foi adicionado com sucesso ao carrinho', 'success' => 'Item foi adicionado com sucesso ao carrinho',
'success-remove' => 'Item foi removido com sucesso do carrinho', 'success-remove' => 'Item foi removido com sucesso do carrinho',
'error-add' => 'Item não pode ser adicionado ao carrinho, por favor, tente novamente mais tarde', 'error-add' => 'Item não pode ser adicionado ao carrinho, por favor, tente novamente mais tarde',
'inactive' => 'An item is inactive and was removed from cart.', 'inactive' => 'An item is inactive and was removed from cart',
'inactive-add' => 'Inactive item cannot be added to cart.', 'inactive-add' => 'Inactive item cannot be added to cart',
], ],
'quantity-error' => 'Quantidade solicitada não está disponível', 'quantity-error' => 'Quantidade solicitada não está disponível',
'cart-subtotal' => 'Subtotal do carrinho', 'cart-subtotal' => 'Subtotal do carrinho',

View File

@ -75,6 +75,8 @@ class CartCest
$I->assertFalse(cart()->hasError()); $I->assertFalse(cart()->hasError());
$I->comment('sP2 is inactive'); $I->comment('sP2 is inactive');
cart()->validateItems();
$I->assertEquals(3, count(cart()->getCart()->items)); $I->assertEquals(3, count(cart()->getCart()->items));
$I->comment('add dP2 to cart'); $I->comment('add dP2 to cart');
@ -106,6 +108,7 @@ class CartCest
'links' => $this->downloadableProduct1->downloadable_links->pluck('id')->all(), 'links' => $this->downloadableProduct1->downloadable_links->pluck('id')->all(),
]); ]);
cart()->validateItems();
$I->assertEquals(4, count(cart()->getCart()->items)); $I->assertEquals(4, count(cart()->getCart()->items));
$I->comment('deactivate vP2'); $I->comment('deactivate vP2');
@ -125,6 +128,8 @@ class CartCest
$cartItemId => 5 $cartItemId => 5
], ],
]); ]);
// now lets check without validating cart before
$I->assertEquals(3, count(cart()->getCart()->items)); $I->assertEquals(3, count(cart()->getCart()->items));
$I->assertEquals(5, cart()->getCart()->items()->find($cartItemId)->quantity); $I->assertEquals(5, cart()->getCart()->items()->find($cartItemId)->quantity);