Cart Module Almost Completed

This commit is contained in:
prashant-webkul 2018-09-28 18:25:48 +05:30
parent 2328d5e98b
commit fe0ffca9ee
8 changed files with 390 additions and 238 deletions

View File

@ -82,80 +82,6 @@ class Cart {
$this->product = $product;
}
/**
* Create new cart instance with the current item added.
*
* @param integer $id
* @param array $data
*
* @return Response
*/
public function createNewCart($id, $data)
{
$itemData = $this->prepareItemData($id, $data);
$cartData['channel_id'] = core()->getCurrentChannel()->id;
// this will auto set the customer id for the cart instances if customer is authenticated
if(auth()->guard('customer')->check()) {
$cartData['customer_id'] = auth()->guard('customer')->user()->id;
$cartData['is_guest'] = 0;
$cartData['customer_full_name'] = auth()->guard('customer')->user()->first_name .' '. auth()->guard('customer')->user()->last_name;
}
$cartData['is_guest'] = 1;
$cartData['items_count'] = 1;
$cartData['items_qty'] = $data['quantity'];
if($cart = $this->cart->create($cartData)) {
$itemData['parent']['cart_id'] = $cart->id;
if ($data['is_configurable'] == "true") {
//parent product entry
$itemData['parent']['additional'] = json_encode($data);
if($parent = $this->cartItem->create($itemData['parent'])) {
$itemData['child']['parent_id'] = $parent->id;
$itemData['child']['cart_id'] = $cart->id;
if($child = $this->cartItem->create($itemData['child'])) {
session()->put('cart', $cart);
session()->flash('success', 'Item Added To Cart Successfully');
return redirect()->back();
}
}
// $cart->update(['subtotal' => $itemData['parent']['price'], 'base_sub_total' => $itemData['parent']['price']]);
$this->collectTotals();
$this->collectQuantities();
} else if($data['is_configurable'] == "false") {
if($result = $this->cartItem->create($itemData['parent'])) {
session()->put('cart', $cart);
session()->flash('success', 'Item Added To Cart Successfully');
return redirect()->back();
}
// $cart->update(['subtotal' => $itemData['parent']['price'], 'base_sub_total' => $itemData['parent']['price']]);
$this->collectTotals();
$this->collectQuantities();
}
}
session()->flash('error', 'Some Error Occured');
return redirect()->back();
}
/**
* Prepare the other data for the product to be added.
*
@ -234,6 +160,129 @@ class Cart {
}
}
/**
* Create new cart instance with the current item added.
*
* @param integer $id
* @param array $data
*
* @return Response
*/
public function createNewCart($id, $data)
{
$itemData = $this->prepareItemData($id, $data);
$cartData['channel_id'] = core()->getCurrentChannel()->id;
// this will auto set the customer id for the cart instances if customer is authenticated
if(auth()->guard('customer')->check()) {
$cartData['customer_id'] = auth()->guard('customer')->user()->id;
$cartData['is_guest'] = 0;
$cartData['customer_full_name'] = auth()->guard('customer')->user()->first_name .' '. auth()->guard('customer')->user()->last_name;
} else {
$cartData['is_guest'] = 1;
}
$cartData['items_count'] = 1;
$cartData['items_qty'] = $data['quantity'];
if($cart = $this->cart->create($cartData)) {
$itemData['parent']['cart_id'] = $cart->id;
if ($data['is_configurable'] == "true") {
//parent product entry
$itemData['parent']['additional'] = json_encode($data);
if($parent = $this->cartItem->create($itemData['parent'])) {
$itemData['child']['parent_id'] = $parent->id;
$itemData['child']['cart_id'] = $cart->id;
if($child = $this->cartItem->create($itemData['child'])) {
session()->put('cart', $cart);
session()->flash('success', 'Item Added To Cart Successfully');
return redirect()->back();
}
}
// $cart->update(['subtotal' => $itemData['parent']['price'], 'base_sub_total' => $itemData['parent']['price']]);
$this->collectQuantities();
$this->collectTotals();
} else if($data['is_configurable'] == "false") {
if($result = $this->cartItem->create($itemData['parent'])) {
session()->put('cart', $cart);
session()->flash('success', 'Item Added To Cart Successfully');
return redirect()->back();
}
// $cart->update(['subtotal' => $itemData['parent']['price'], 'base_sub_total' => $itemData['parent']['price']]);
$this->collectQuantities();
$this->collectTotals();
}
}
session()->flash('error', 'Some Error Occured');
return redirect()->back();
}
/**
* Returns cart
*
* @return Mixed
*/
public function getCart()
{
if(!$cart = session()->get('cart'))
return false;
return $this->cart->find($cart->id);
}
/**
* Method to check if the product is available and its required quantity
* is available or not in the inventory sources.
*
* @param integer $id
*
* @return Array
*/
public function canAddOrUpdate($itemId, $quantity)
{
$item = $this->cartItem->findOneByField('id', $itemId);
$inventories = $item->product->inventories;
$inventory_sources = $item->product->inventory_sources;
$totalQty = 0;
foreach($inventory_sources as $inventory_source) {
if($inventory_source->status && $inventory_source->toArray()['pivot']['qty']) {
$totalQty = $totalQty + $inventory_source->toArray()['pivot']['qty'];
}
}
if ($quantity < 1) {
session()->flash('warning', 'Cannot Add Or Update Lesser than 1');
return redirect()->back();
}
if($quantity < $totalQty) {
return true;
} else {
return false;
}
}
/**
* Add Items in a cart with some cart and item details.
*
@ -259,16 +308,24 @@ class Cart {
$prevQty = $cartItem->quantity;
$newQty = $data['quantity'];
$canBe = $this->canAddOrUpdate($cartItem->id, $prevQty + $newQty);
if($canBe == false) {
session()->flash('warning', 'The requested quantity is not available, please try back later.');
return redirect()->back();
}
$cartItem->update([
'quantity' => $prevQty + $newQty,
'total' => $parentPrice * ($prevQty + $newQty),
'base_total' => $parentPrice * ($prevQty + $newQty)
'total' => $cartItem->price * ($prevQty + $newQty),
'base_total' => $cartItem->price * ($prevQty + $newQty)
]);
$this->collectTotals();
$this->collectQuantities();
$this->collectTotals();
session()->flash('success', "Product Quantity Successfully Updated");
return redirect()->back();
@ -284,16 +341,24 @@ class Cart {
$prevQty = $parent->quantity;
$newQty = $data['quantity'];
$canBe = $this->canAddOrUpdate($cartItem->child->id, $prevQty + $newQty);
if($canBe == false) {
session()->flash('warning', 'The requested quantity is not available, please try back later.');
return redirect()->back();
}
$parent->update([
'quantity' => $prevQty + $newQty,
'total' => $parentPrice * ($prevQty + $newQty),
'base_total' => $parentPrice * ($prevQty + $newQty)
]);
$this->collectTotals();
$this->collectQuantities();
$this->collectTotals();
session()->flash('success', "Product Quantity Successfully Updated");
return redirect()->back();
@ -303,19 +368,23 @@ class Cart {
}
if($data['is_configurable'] == "true") {
$this->canAddOrUpdate($parent->child->id, $parent->quantity);
$parent = $cart->items()->create($itemData['parent']);
$itemData['child']['parent_id'] = $parent->id;
$cart->items()->create($itemData['child']);
} else if($data['is_configurable'] == "false"){
// $this->canAddOrUpdate($parent->id, $parent->quantity);
$parent = $cart->items()->create($itemData['parent']);
}
$this->collectTotals();
$this->collectQuantities();
$this->collectTotals();
session()->flash('success', 'Item Successfully Added To Cart');
return redirect()->back();
@ -332,23 +401,96 @@ class Cart {
}
/**
* Use detach to remove the current product from cart tables
* Update the cart on
* cart checkout page
*/
public function update($itemIds)
{
if(session()->has('cart')) {
$cart = session()->get('cart');
$items = $cart->items;
foreach($items as $item) {
foreach($itemIds['qty'] as $id => $quantity) {
if($id == $item->id) {
if($item->type == "configurable") {
$canBe = $this->canAddOrUpdate($item->child->id, $quantity);
} else {
$canBe = $this->canAddOrUpdate($id, $quantity);
}
if($canBe == false) {
session()->flash('warning', 'The requested quantity is not available, please try back later.');
return redirect()->back();
}
$item->update(['quantity' => $quantity]);
}
}
}
$items = $cart->items;
session()->flash('success', 'Cart Updated Successfully');
return redirect()->back();
}
}
/**
* Remove the item from the cart
*
* @param Integer $id
* @return response
*/
public function remove($id)
public function removeItem($itemId)
{
$item = $this->cartItem->findOneByField('id', $id);
if(session()->has('cart')) {
$cart = session()->get('cart');
dd($item);
if($item->parent_id != "null") {
$item->delete($id);
} else {
$parentItem = $item->child;
$items = $cart->items;
dd($parentItem, $item);
foreach($items as $item) {
if($item->id == $itemId) {
if($item->type == "configurable") {
$child = $item->child;
//delete the child first
$result = $this->cartItem->delete($child->id);
if($result)
$result = $this->cartItem->delete($item->id);
$this->collectQuantities();
$this->collectTotals();
} else if($item->type == "simple" && $item->parent_id == null){
$result = $this->cartItem->delete($item->id);
$this->collectQuantities();
$this->collectTotals();
}
}
}
$countItems = $this->cart->findOneByField('id', $cart->id)->items->count();
//delete the cart instance if no items are there
if($countItems == 0) {
$result = $this->cart->delete($cart->id);
session()->forget('cart');
} else {
session()->forget('cart');
session()->put('cart', $this->cart->findOneByField('id', $cart->id));
}
if ($result) {
session()->flash('sucess', 'Item Successfully Removed From Cart');
} else {
session()->flash('error', 'Item Cannot Be Removed From Cart');
}
}
return redirect()->back();
}
/**
@ -460,6 +602,28 @@ class Cart {
return $cartPayment;
}
/**
* Update Cart Quantities, Weight
*
* @return void
*/
public function collectQuantities()
{
if(!$cart = $this->getCart())
return false;
$quantities = 0;
foreach($cart->items as $item) {
$quantities = $quantities + $item->quantity;
}
$itemCount = $cart->items->count();
$cart->update(['items_count' => $itemCount, 'items_qty' => $quantities]);
}
/**
* Updates cart totals
*
@ -493,27 +657,6 @@ class Cart {
$cart->save();
}
/**
* Update Cart Quantities, Weight
*
* @return void
*/
public function collectQuantities() {
if(!$cart = $this->getCart())
return false;
$quantities = 0;
foreach($cart->items as $item) {
$quantities = $quantities + $item->quantity;
}
$itemCount = $cart->items->count();
$cart->update(['items_count' => $itemCount, 'items_qty' => $quantities]);
}
/**
* This function handles when guest has some of cart products and then logs in.
*
@ -551,6 +694,14 @@ class Cart {
$newQty = $guestCartItem->quantity;
$canBe = $this->canAddOrUpdate($cartItem->id, $prevQty + $newQty);
if($canBe == false) {
session()->flash('warning', 'The requested quantity is not available, please try back later.');
return redirect()->back();
}
$cartItem->update([
'quantity' => $prevQty + $newQty,
'total' => $cartItem->price * ($prevQty + $newQty),
@ -560,7 +711,7 @@ class Cart {
]);
$guestCartItems->forget($key);
$this->cartItem->delete($guestCart->id);
$this->cartItem->delete($guestCartItem->id);
}
} else if($guestCartItem->type == "configurable" && $cartItem->type == "configurable") {
$guestCartItemChild = $guestCartItem->child;
@ -571,6 +722,14 @@ class Cart {
$prevQty = $guestCartItem->quantity;
$newQty = $cartItem->quantity;
$canBe = $this->canAddOrUpdate($cartItem->child->id, $prevQty + $newQty);
if($canBe == false) {
session()->flash('warning', 'The requested quantity is not available, please try back later.');
return redirect()->back();
}
$cartItem->update([
'quantity' => $prevQty + $newQty,
'total' => $cartItem->price * ($prevQty + $newQty),
@ -585,7 +744,7 @@ class Cart {
$this->cartItem->delete($guestCartItemChild->id);
//then parent will get deleted
$this->cartItem->delete($guestCart->id);
$this->cartItem->delete($guestCartItem->id);
}
}
}
@ -612,77 +771,16 @@ class Cart {
//put the customer cart instance
session()->put('cart', $cart);
$this->collectTotals();
$this->collectQuantities();
$this->collectTotals();
return redirect()->back();
} else {
return redirect()->back();
}
}
/**
* Method to check if the product is available and its required quantity
* is available or not in the inventory sources.
*
* @param integer $id
*
* @return Array
*/
public function canCheckOut($productId, $quantity)
{
$items = $cart->items;
$allProdQty = array();
$allProdQty1 = array();
$totalQty = 0;
foreach($items as $item) {
$inventories = $item->product->inventories;
$inventory_sources = $item->product->inventory_sources;
$totalQty = 0;
foreach($inventory_sources as $inventory_source) {
if($inventory_source->status!=0) {
foreach($inventories as $inventory) {
$totalQty = $totalQty + $inventory->qty;
}
array_push($allProdQty1, $totalQty);
$allProdQty[$item->product->id] = $totalQty;
}
}
}
foreach ($items as $item) {
$inventories = $item->product->inventory_sources->where('status', '=', '1');
foreach($inventories as $inventory) {
dump($inventory->status);
}
}
dd([true, false]);
}
/**
* Returns cart
*
* @return Mixed
*/
public function getCart()
{
if(!$cart = session()->get('cart'))
return false;
return $this->cart->find($cart->id);
}
/**
* Destroys the session
* maintained for cart

View File

@ -105,8 +105,28 @@ class CartController extends Controller
return redirect()->back();
}
/**
* Removes the item from
* the cart if it exists
*
* @param integer $itemId
*/
public function remove($itemId) {
Cart::remove($itemId);
Cart::removeItem($itemId);
return redirect()->back();
}
/**
* Updates the quantity of the
* items present in the cart.
*
* @return response
*/
public function updateBeforeCheckout() {
$data = request()->except('_token');
Cart::update($data);
return redirect()->back();
}

View File

@ -35,6 +35,14 @@ Route::group(['middleware' => ['web']], function () {
Route::post('product/cart/add/{id}', 'Webkul\Cart\Http\Controllers\CartController@add')->name('cart.add');
Route::get('product/cart/remove/{id}', 'Webkul\Cart\Http\Controllers\CartController@remove')->name('cart.remove');
Route::post('/checkout/cart', 'Webkul\Cart\Http\Controllers\CartController@updateBeforeCheckout')->defaults('_config',[
'redirect' => 'shop.checkout.cart.index'
])->name('shop.checkout.cart.update');
Route::get('/checkout/cart/remove/{id}', 'Webkul\Cart\Http\Controllers\CartController@remove')->defaults('_config',[
'redirect' => 'shop.checkout.cart.index'
])->name('shop.checkout.cart.remove');
//Routes for product cart ends
// Product Review routes

View File

@ -17,6 +17,10 @@ body {
font-family: "Montserrat", sans-serif;
}
.btn.btn-primary{
border-radius: 0px;
}
.header {
margin-top: 16px;
margin-bottom: 21px;
@ -1960,7 +1964,11 @@ section.cart {
float: left;
.misc-controls {
float: right;
width: 100%;
display: inline-flex;
align-items: center;
justify-content: space-between;
margin-top: 20px;
a.link {
@ -2024,14 +2032,16 @@ section.cart {
margin-right: 10px;
}
div.box {
input.box {
height: 38px;
width: 60px;
font-size: 16px;
text-align: center;
line-height: 38px;
border: 1px solid $border-color;
border-radius: 3px;
margin-right: 30px;
border-radius: 0px;
}
.remove {

View File

@ -19,79 +19,79 @@
<div class="cart-content">
<div class="left-side">
<form action="{{ route('shop.checkout.cart.update') }}" method="POST">
<div class="cart-item-list" style="margin-top: 0">
@foreach($cart->items as $item)
<div class="cart-item-list" style="margin-top: 0">
@csrf
@foreach($cart->items as $item)
<?php
$product = $item->product;
<?php
$product = $item->product;
$productBaseImage = $productImageHelper->getProductBaseImage($product);
?>
$productBaseImage = $productImageHelper->getProductBaseImage($product);
?>
<div class="item">
<div style="margin-right: 15px;">
<img class="item-image" src="{{ $productBaseImage['medium_image_url'] }}" />
</div>
<div class="item-details">
<div class="item-title">
{{ $product->name }}
<div class="item">
<div style="margin-right: 15px;">
<img class="item-image" src="{{ $productBaseImage['medium_image_url'] }}" />
</div>
<div class="price">
{{ core()->currency($item->base_price) }}
</div>
<div class="item-details">
@if ($product->type == 'configurable')
<div class="summary">
{{-- @foreach (cart::getItemAttributeOptionDetails($item) as $key => $option)
{{ (!$key ? '' : ' , ') . $option['attribute_name'] . ' : ' . $option['option_label'] }}
@endforeach --}}
<div class="item-title">
{{ $product->name }}
</div>
@endif
<div class="misc">
<div class="qty-text">{{ __('shop::app.checkout.cart.quantity') }}</div>
<div class="box">{{ $item->quantity }}</div>
@if($product->type == 'configurable')
<span class="remove"><a href="{{ route('cart.remove', $item->child->id) }}">{{ __('shop::app.checkout.cart.remove') }}</a></span>
@else
<span class="remove"><a href="{{ route('cart.remove', $item->id) }}">{{ __('shop::app.checkout.cart.remove') }}</a></span>
<div class="price">
{{ core()->currency($item->base_price) }}
</div>
@if ($product->type == 'configurable')
<div class="summary">
{{-- @foreach (cart::getItemAttributeOptionDetails($item) as $key => $option)
{{ (!$key ? '' : ' , ') . $option['attribute_name'] . ' : ' . $option['option_label'] }}
@endforeach --}}
</div>
@endif
<span class="towishlist">{{ __('shop::app.checkout.cart.move-to-wishlist') }}</span>
<div class="misc">
<div class="qty-text">{{ __('shop::app.checkout.cart.quantity') }}</div>
{{-- <div class="box">{{ $item->quantity }}</div> --}}
<input class="box" type="text" v-validate="'required|numeric|min_value:1'" name="qty[{{$item->id}}]" value="{{ $item->quantity }}">
<span class="control-error" v-if="errors.has('qty[{{$item->qty}}]')">@{{ errors.first('quantity') }}</span>
{{-- @if($product->type == 'configurable')
<span class="remove"><a href="{{ route('shop.checkout.cart.remove', $item->child->id) }}">{{ __('shop::app.checkout.cart.remove') }}</a></span>
@else --}}
<span class="remove"><a href="{{ route('shop.checkout.cart.remove', $item->id) }}">{{ __('shop::app.checkout.cart.remove') }}</a></span>
{{-- @endif --}}
<span class="towishlist">{{ __('shop::app.checkout.cart.move-to-wishlist') }}</span>
</div>
</div>
</div>
@endforeach
</div>
<div class="misc-controls">
<a href="{{ route('shop.home.index') }}" class="link">{{ __('shop::app.checkout.cart.continue-shopping') }}</a>
<div>
<input type="submit" class="btn btn-lg btn-primary" value="Update Cart" />
<a href="{{ route('shop.checkout.onepage.index') }}" class="btn btn-lg btn-primary">
{{ __('shop::app.checkout.cart.proceed-to-checkout') }}
</a>
</div>
@endforeach
</div>
<div class="misc-controls">
<a href="{{ route('shop.home.index') }}" class="link">{{ __('shop::app.checkout.cart.continue-shopping') }}</a>
<a href="{{ route('shop.checkout.onepage.index') }}" class="btn btn-lg btn-primary">
{{ __('shop::app.checkout.cart.proceed-to-checkout') }}
</a>
</div>
</div>
</form>
</div>
<div class="right-side">
@include('shop::checkout.total.summary', ['cart' => $cart])
</div>
</div>
@else
<div class="title">
{{ __('shop::app.checkout.cart.empty') }}
</div>

View File

@ -35,9 +35,10 @@
{{ $product->short_description }}
</div>
<div class="quantity control-group">
<div class="quantity control-group" :class="[errors.has('quantity') ? 'has-error' : '']">
<label class="reqiured">Quantity</label>
<input name="quantity" class="control" value="1" v-validate="'numeric'" required style="width: 60px;">
<input name="quantity" class="control" value="1" v-validate="'required|numeric|min_value:1'" style="width: 60px;">
<span class="control-error" v-if="errors.has('quantity')">@{{ errors.first('quantity') }}</span>
</div>
@if ($product->type == 'configurable')

View File

@ -27,7 +27,7 @@
<div v-for='(attribute, index) in childAttributes' class="attribute control-group" :class="[errors.has('super_attribute[' + attribute.id + ']') ? 'has-error' : '']">
<label class="reqiured">@{{ attribute.label }}</label>
<select v-validate="'required'" class="control" :name="['super_attribute[' + attribute.id + ']']" :disabled="attribute.disabled" @change="configure(attribute, $event.target.value)" :id="['attribute_' + attribute.id]" required>
<select v-validate="'required'" class="control" :name="['super_attribute[' + attribute.id + ']']" :disabled="attribute.disabled" @change="configure(attribute, $event.target.value)" :id="['attribute_' + attribute.id]">
<option v-for='(option, index) in attribute.options' :value="option.id">@{{ option.label }}</option>

View File

@ -81,6 +81,10 @@ body {
font-family: "Montserrat", sans-serif;
}
.btn.btn-primary {
border-radius: 0px;
}
.header {
margin-top: 16px;
margin-bottom: 21px;
@ -1983,7 +1987,16 @@ section.cart .cart-content .left-side {
}
section.cart .cart-content .left-side .misc-controls {
float: right;
width: 100%;
display: -webkit-inline-box;
display: -ms-inline-flexbox;
display: inline-flex;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
-webkit-box-pack: justify;
-ms-flex-pack: justify;
justify-content: space-between;
margin-top: 20px;
}
@ -2064,14 +2077,16 @@ section.cart .cart-content .right-side {
margin-right: 10px;
}
.cart-item-list .item .item-details .misc div.box {
.cart-item-list .item .item-details .misc input.box {
height: 38px;
width: 60px;
font-size: 16px;
text-align: center;
line-height: 38px;
border: 1px solid #E8E8E8;
border-radius: 3px;
margin-right: 30px;
border-radius: 0px;
}
.cart-item-list .item .item-details .misc .remove {