Optimized cart

This commit is contained in:
jitendra 2022-07-11 17:51:33 +05:30
parent 22f995475d
commit 5ca30fa664
14 changed files with 183 additions and 144 deletions

View File

@ -46,17 +46,18 @@ class CartRule
/**
* Collect discount on cart
*
* @param \Webkul\Cart\Contracts\Cart $cart
* @return void
*/
public function collect()
public function collect($cart)
{
$cart = Cart::getCart();
$appliedCartRuleIds = [];
$this->calculateCartItemTotals($cart->items);
$this->calculateCartItemTotals($cart, $cart->items()->get());
foreach ($cart->items as $item) {
$itemCartRuleIds = $this->process($item);
$itemCartRuleIds = $this->process($cart, $item);
$appliedCartRuleIds = array_merge($appliedCartRuleIds, $itemCartRuleIds);
if ($item->children()->count() && $item->product->getTypeInstance()->isChildrenCalculated()) {
@ -72,7 +73,7 @@ class CartRule
$this->processFreeShippingDiscount($cart);
if (! $this->checkCouponCode()) {
if (! $this->checkCouponCode($cart)) {
cart()->removeCouponCode();
}
}
@ -80,20 +81,21 @@ class CartRule
/**
* Returns cart rules
*
* @param \Webkul\Cart\Contracts\Cart $cart
* @return \Illuminate\Support\Collection
*/
public function getCartRules()
public function getCartRules($cart)
{
$staticCartRules = new class() {
public static $cartRules;
public static $cartID;
};
if ($staticCartRules::$cartID === cart()->getCart()->id && $staticCartRules::$cartRules) {
if ($staticCartRules::$cartID === $cart->id && $staticCartRules::$cartRules) {
return $staticCartRules::$cartRules;
}
$staticCartRules::$cartID = cart()->getCart()->id;
$staticCartRules::$cartID = $cart->id;
$customerGroupId = null;
@ -110,15 +112,15 @@ class CartRule
$cartRules = $this->getCartRuleQuery($customerGroupId, core()->getCurrentChannel()->id);
$staticCartRules::$cartRules = $cartRules;
return $cartRules;
}
/**
* Check if cart rule can be applied
*
* @param $cart
* @param \Webkul\Cart\Contracts\Cart $cart
* @param \Webkul\CartRule\Contracts\CartRule $rule
*
* @return bool
*/
public function canProcessRule($cart, $rule): bool
@ -170,10 +172,11 @@ class CartRule
/**
* Cart item discount calculation process
*
* @param \Webkul\Cart\Contracts\Cart $cart
* @param \Webkul\Checkout\Models\CartItem $item
* @return array
*/
public function process(CartItem $item): array
public function process($cart, CartItem $item): array
{
$item->discount_percent = 0;
$item->discount_amount = 0;
@ -181,9 +184,7 @@ class CartRule
$appliedRuleIds = [];
$cart = Cart::getCart();
foreach ($rules = $this->getCartRules() as $rule) {
foreach ($rules = $this->getCartRules($cart) as $rule) {
if (! $this->canProcessRule($cart, $rule)) {
continue;
}
@ -304,9 +305,7 @@ class CartRule
$appliedRuleIds = [];
$cart = Cart::getCart();
foreach ($this->getCartRules() as $rule) {
foreach ($this->getCartRules($cart) as $rule) {
if (! $this->canProcessRule($cart, $rule)) {
continue;
}
@ -388,11 +387,9 @@ class CartRule
$appliedRuleIds = [];
$cart = Cart::getCart();
foreach ($cart->items->all() as $item) {
foreach ($this->getCartRules() as $rule) {
foreach ($this->getCartRules($cart) as $rule) {
if (! $this->canProcessRule($cart, $rule)) {
continue;
@ -435,14 +432,13 @@ class CartRule
/**
* Calculate cart item totals for each rule
*
* @param \Webkul\Cart\Contracts\Cart $cart
* @param \Illuminate\Support\Collecton $items
* @return \Webkul\Rule\Helpers\Validator
*/
public function calculateCartItemTotals($items)
public function calculateCartItemTotals($cart, $items)
{
$cart = Cart::getCart();
foreach ($this->getCartRules() as $rule) {
foreach ($this->getCartRules($cart) as $rule) {
if ($rule->action_type == 'cart_fixed') {
$totalPrice = $totalBasePrice = $validCount = 0;
@ -473,12 +469,11 @@ class CartRule
/**
* Check if coupon code is applied or not
*
* @param \Webkul\Cart\Contracts\Cart $cart
* @return bool
*/
public function checkCouponCode(): bool
public function checkCouponCode($cart): bool
{
$cart = cart()->getCart();
if (! $cart->coupon_code) {
return true;
}
@ -550,5 +545,4 @@ class CartRule
->orderBy('sort_order', 'asc');
})->findWhere(['status' => 1]);
}
}

View File

@ -24,6 +24,6 @@ class Cart
*/
public function applyCartRules($cart)
{
$this->cartRuleHepler->collect();
$this->cartRuleHepler->collect($cart);
}
}

View File

@ -15,6 +15,7 @@ class EventServiceProvider extends ServiceProvider
'checkout.order.save.after' => [
'Webkul\CartRule\Listeners\Order@manageCartRule'
],
'checkout.cart.collect.totals.before' => [
'Webkul\CartRule\Listeners\Cart@applyCartRules'
],

View File

@ -25,6 +25,12 @@ class Cart
{
use CartCoupons, CartTools, CartValidators;
/**
* @var \Webkul\Checkout\Contracts\Cart
*/
private $cart;
/**
* Create a new class instance.
*
@ -47,6 +53,19 @@ class Cart
protected CustomerAddressRepository $customerAddressRepository
)
{
$this->initCart();
}
/**
* Returns cart.
*
* @return \Webkul\Checkout\Contracts\Cart|null
*/
public function initCart()
{
$this->getCart();
$this->removeInactiveItems();
}
/**
@ -56,27 +75,48 @@ class Cart
*/
public function getCart(): ?\Webkul\Checkout\Contracts\Cart
{
$cart = null;
if ($this->cart) {
return $this->cart;
}
if (auth()->guard()->check()) {
$cart = $this->cartRepository->findOneWhere([
$this->cart = $this->cartRepository->findOneWhere([
'customer_id' => auth()->guard()->user()->id,
'is_active' => 1,
]);
} else if (session()->has('cart')) {
$cart = $this->cartRepository->find(session()->get('cart')->id);
$this->cart = $this->cartRepository->find(session()->get('cart')->id);
}
$this->removeInactiveItems($cart);
return $this->cart;
}
return $cart;
/**
* Set cart model to the variable for reuse
*
* @param \Webkul\Checkout\Contracts\Cart
* @return void
*/
public function setCart($cart)
{
$this->cart = $cart;
}
/**
* Reset cart
*
* @return void
*/
public function resetCart()
{
$this->cart = null;
}
/**
* Get cart item by product.
*
* @param array|null $data
* @param array $parentData
* @param array $data
* @param array|null $parentData
* @return \Webkul\Checkout\Contracts\CartItem|void
*/
public function getItemByProduct($data, $parentData = null)
@ -123,10 +163,10 @@ class Cart
$cartProducts = $product->getTypeInstance()->prepareForCart($data);
if (is_string($cartProducts)) {
if ($cart->all_items->count() <= 0) {
$this->removeCart($cart);
} else {
$this->collectTotals();
if (count($cart->all_items) <= 0) {
session()->forget('cart');
}
throw new Exception($cartProducts);
@ -203,6 +243,8 @@ class Cart
return;
}
$this->setCart($cart);
$this->putCart($cart);
return $cart;
@ -275,14 +317,10 @@ class Cart
$cartItem->delete();
if ($cart->items()->get()->count() == 0) {
$this->cartRepository->delete($cart->id);
if (session()->has('cart')) {
session()->forget('cart');
}
}
$this->removeCart($cart);
} else {
Shipping::collectRates();
}
Event::dispatch('checkout.cart.delete.after', $itemId);
@ -321,35 +359,25 @@ class Cart
/**
* Remove cart items, whose product is inactive.
*
* @param \Webkul\Checkout\Models\Cart|null $cart
* @return \Webkul\Checkout\Models\Cart|null
* @return void
*/
public function removeInactiveItems(CartModel $cart = null): ?CartModel
private function removeInactiveItems()
{
if (! $cart) {
return $cart;
if (! $cart = $this->getCart()) {
return;
}
foreach ($cart->items as $item) {
if ($this->isCartItemInactive($item)) {
$this->cartItemRepository->delete($item->id);
if ($cart->items->count() == 0) {
$this->cartRepository->delete($cart->id);
if (session()->has('cart')) {
session()->forget('cart');
}
$this->removeCart($cart);
}
session()->flash('info', __('shop::app.checkout.cart.item.inactive'));
}
}
$cart->save();
return $cart;
}
/**
@ -447,21 +475,30 @@ class Cart
Event::dispatch('checkout.cart.collect.totals.before', $cart);
$this->calculateItemsTax();
$cart->refresh();
$cart->grand_total = $cart->base_grand_total = 0;
$cart->sub_total = $cart->base_sub_total = 0;
$cart->grand_total = $cart->base_grand_total = 0;
$cart->tax_total = $cart->base_tax_total = 0;
$cart->discount_amount = $cart->base_discount_amount = 0;
$quantities = 0;
foreach ($cart->items as $item) {
$cart->discount_amount += $item->discount_amount;
$cart->base_discount_amount += $item->base_discount_amount;
$cart->sub_total = (float) $cart->sub_total + $item->total;
$cart->base_sub_total = (float) $cart->base_sub_total + $item->base_total;
$quantities += $item->quantity;
}
$cart->items_qty = $quantities;
$cart->items_count = $cart->items->count();
$cart->tax_total = Tax::getTaxTotal($cart, false);
$cart->base_tax_total = Tax::getTaxTotal($cart, true);
@ -476,17 +513,14 @@ class Cart
$cart->base_discount_amount += $shipping->base_discount_amount;
}
$cart = $this->finalizeCartTotals($cart);
$cart->discount_amount = round($cart->discount_amount, 2);
$cart->base_discount_amount = round($cart->base_discount_amount, 2);
$quantities = 0;
$cart->sub_total = round($cart->sub_total, 2);
$cart->base_sub_total = round($cart->base_sub_total, 2);
foreach ($cart->items as $item) {
$quantities = $quantities + $item->quantity;
}
$cart->items_count = $cart->items->count();
$cart->items_qty = $quantities;
$cart->grand_total = round($cart->grand_total, 2);
$cart->base_grand_total = round($cart->base_grand_total, 2);
$cart->cart_currency_code = core()->getCurrentCurrencyCode();
@ -558,14 +592,14 @@ class Cart
}
if (count($cart->items) === 0) {
$this->cartRepository->delete($cart->id);
$this->removeCart($cart);
return false;
}
$isInvalid = false;
foreach ($cart->items as $item) {
foreach ($cart->items()->get() as $item) {
$validationResult = $item->product->getTypeInstance()->validateCartItem($item);
if ($validationResult->isItemInactive()) {
@ -574,8 +608,7 @@ class Cart
$isInvalid = true;
session()->flash('info', __('shop::app.checkout.cart.item.inactive'));
}
} else {
$price = ! is_null($item->custom_price) ? $item->custom_price : $item->base_price;
$this->cartItemRepository->update([
@ -584,6 +617,7 @@ class Cart
'total' => core()->convertPrice($price * $item->quantity),
'base_total' => $price * $item->quantity,
], $item->id);
}
$isInvalid |= $validationResult->isCartInvalid();
}
@ -767,26 +801,6 @@ class Cart
}
}
/**
* Round cart totals.
*
* @param \Webkul\Checkout\Models\Cart $cart
* @return \Webkul\Checkout\Models\Cart
*/
private function finalizeCartTotals(CartModel $cart): CartModel
{
$cart->discount_amount = round($cart->discount_amount, 2);
$cart->base_discount_amount = round($cart->base_discount_amount, 2);
$cart->sub_total = round($cart->sub_total, 2);
$cart->base_sub_total = round($cart->base_sub_total, 2);
$cart->grand_total = round($cart->grand_total, 2);
$cart->base_grand_total = round($cart->base_grand_total, 2);
return $cart;
}
/**
* Returns true, if cart item is inactive.
*

View File

@ -20,10 +20,10 @@ class Cart extends Model implements CartContract
'updated_at',
];
protected $with = [
'items',
'items.children',
];
// protected $with = [
// 'items',
// 'items.children',
// ];
/**
* To get relevant associated items with the cart instance
@ -162,11 +162,11 @@ class Cart extends Model implements CartContract
public function hasProductsWithQuantityBox(): bool
{
foreach ($this->items as $item) {
if ($item->product->getTypeInstance()
->showQuantityBox() === true) {
if ($item->product->getTypeInstance()->showQuantityBox() === true) {
return true;
}
}
return false;
}

View File

@ -49,6 +49,6 @@ class CheckoutServiceProvider extends ServiceProvider
return new Cart();
});
$this->app->bind('cart', \Webkul\Checkout\Cart::class);
$this->app->singleton('cart', \Webkul\Checkout\Cart::class);
}
}

View File

@ -11,6 +11,23 @@ namespace Webkul\Checkout\Traits;
*/
trait CartTools
{
/**
* Remove cart and destroy the session
*
* @param \Webkul\Checkout\Contracts\Cart $cart
* @return void
*/
public function removeCart($cart)
{
$this->cartRepository->delete($cart->id);
if (session()->has('cart')) {
session()->forget('cart');
}
$this->resetCart();
}
/**
* Save cart for guest.
*
@ -20,7 +37,10 @@ trait CartTools
public function putCart($cart)
{
if (! auth()->guard()->check()) {
session()->put('cart', $cart);
$cartTemp = new \stdClass();
$cartTemp->id = $cart->id;
session()->put('cart', $cartTemp);
}
}
@ -37,7 +57,9 @@ trait CartTools
'is_active' => 1,
]);
$guestCart = session()->get('cart');
$this->setCart($cart);
$guestCart = $this->cartRepository->find(session()->get('cart')->id);
/**
* When the logged in customer is not having any of the cart instance previously and are active.
@ -56,9 +78,9 @@ trait CartTools
return;
}
foreach ($guestCart->items as $guestCartItem) {
foreach ($guestCart->items()->get() as $guestCartItem) {
try {
$this->addProduct($guestCartItem->product_id, $guestCartItem->additional);
$cart = $this->addProduct($guestCartItem->product_id, $guestCartItem->additional);
} catch (\Exception $e) {
//Ignore exception
}
@ -66,9 +88,7 @@ trait CartTools
$this->collectTotals();
$this->cartRepository->delete($guestCart->id);
session()->forget('cart');
$this->removeCart($guestCart);
}
}

View File

@ -55,7 +55,7 @@ class ConfigurableOption extends AbstractProduct
/**
* Get allowed attributes.
*
* @param \W\Webkul\Product\Contracts\ProductFlat $product
* @param \Webkul\Product\Contracts\ProductFlat $product
* @return \Illuminate\Support\Collection
*/
public function getAllowAttributes($product)

View File

@ -303,7 +303,7 @@ class ProductController extends Controller
return redirect()->back();
}
if ($data['massaction-type'] !== 'update') {
if (! $data['massaction-type'] == 'update') {
return redirect()->back();
}

View File

@ -573,11 +573,11 @@ abstract class AbstractType
*/
public function haveSpecialPrice($qty = null)
{
static $haveSpecialPrice = null;
// static $haveSpecialPrice = null;
if (! is_null($haveSpecialPrice)) {
return $haveSpecialPrice;
}
// if (! is_null($haveSpecialPrice)) {
// return $haveSpecialPrice;
// }
$customerGroupPrice = $this->getCustomerGroupPrice($this->product, $qty);

View File

@ -64,6 +64,7 @@ class CartController extends Controller
{
try {
$cart = Cart::getCart();
$id = request()->get('product_id');
$cart = Cart::addProduct($id, request()->all());
@ -76,12 +77,6 @@ class CartController extends Controller
}
if ($cart instanceof CartModel) {
$formattedItems = [];
foreach ($cart->items as $item) {
array_push($formattedItems, $this->velocityHelper->formatCartItem($item));
}
$response = [
'status' => 'success',
'totalCartItems' => sizeof($cart->items),
@ -97,7 +92,6 @@ class CartController extends Controller
}
}
} catch(\Exception $exception) {
session()->flash('warning', __($exception->getMessage()));
$product = $this->productRepository->find($id);

View File

@ -8,21 +8,27 @@ use Helper\Bagisto;
class CartCest
{
public $cart;
public $productWithQuantityBox;
public $productWithoutQuantityBox;
public function _before(FunctionalTester $I): void
{
$productConfig = [
'productAttributes' => [],
'productInventory' => [
'qty' => 10,
],
'attributeValues' => [
'status' => 1,
],
];
$this->productWithQuantityBox = $I->haveProduct(Bagisto::SIMPLE_PRODUCT, $productConfig);
$this->productWithoutQuantityBox = $I->haveProduct(Bagisto::DOWNLOADABLE_PRODUCT, $productConfig);
}
@ -30,6 +36,8 @@ class CartCest
{
$I->useDefaultTheme();
cart()->deactivateCurrentCartIfBuyNowIsActive();
cart()->addProduct($this->productWithQuantityBox->id, [
'_token' => session('_token'),
'product_id' => $this->productWithQuantityBox->id,
@ -37,6 +45,7 @@ class CartCest
]);
$I->amOnPage('/checkout/cart');
$I->seeElement('#update_cart_button');
}
@ -52,6 +61,7 @@ class CartCest
]);
$I->amOnPage('/checkout/cart');
$I->dontSeeElement('#update_cart_button');
}
}

View File

@ -617,7 +617,7 @@ class CartRuleCest
$expectedCartCoupon = $cartRuleWithCoupon->coupon->code;
$I->comment('I try to use coupon code ' . $expectedCartCoupon);
cart()
->setCouponCode($expectedCartCoupon)
->setCouponCode($expectedCartCoupon->toString())
->collectTotals();
} else {
$I->comment('I have no coupon');
@ -688,9 +688,9 @@ class CartRuleCest
$expectedOrder = new expectedOrder($expectedCart, $customer, $cart->id);
$I->seeRecord('orders', $expectedOrder->toArray());
auth()
->guard('customer')
->logout();
auth()->guard('customer')->logout();
cart()->setCart(null);
}
}
@ -1062,6 +1062,7 @@ class CartRuleCest
$couponSpecifications = $this->getCouponSpecifications();
$ruleConfig = $this->makeRuleConfig($couponSpecifications[$couponConfig['scenario']], $this->products, $couponConfig['products']);
$cartRule = $I->have(CartRule::class, $ruleConfig);
DB::table('cart_rule_channels')

View File

@ -204,7 +204,7 @@ class CartCest
$data['booking'] = ['qty' => [$bookingTicket1->id => 1]];
}
$I->comment('A guest is adding a first product of type ' . $product1->type . ' to cart');
$I->comment('A guest is adding a first product of type ' . $product1->type . ' with id ' . $product1->id . ' to cart');
cart()->addProduct($product1->id, $data);
$I->assertEquals(1, cart()->getCart()->items->count());
@ -215,6 +215,8 @@ class CartCest
$I->assertEquals(1, cart()->getCart()->items->count());
auth()->guard('customer')->logout();
cart()->setCart(null);
$data = [
'_token' => session('_token'),
'quantity' => 1,
@ -227,7 +229,7 @@ class CartCest
$data['booking'] = ['qty' => [$bookingTicket2->id => 1]];
}
$I->comment('Guest is adding a product of type ' . $product2->type . ' to cart.');
$I->comment('Guest is adding a product of type ' . $product2->type . ' with id ' . $product2->id . ' to cart.');
cart()->addProduct($product2->id, $data);
$I->assertEquals(1, cart()->getCart()->items->count());
@ -238,6 +240,7 @@ class CartCest
$I->assertEquals(2, cart()->getCart()->items->count());
auth()->guard('customer')->logout();
cart()->setCart(null);
$data = [
'_token' => session('_token'),
'quantity' => 2,
@ -351,6 +354,8 @@ class CartCest
auth()->guard('customer')->logout();
cart()->setCart(null);
session()->forget('cart');
}