merged with master

This commit is contained in:
prashant-webkul 2018-10-05 17:38:42 +05:30
commit 301eb1959f
16 changed files with 324 additions and 150 deletions

View File

@ -6,7 +6,7 @@ return [
'title' => 'Cash On Delivery',
'description' => 'Cash On Delivery',
'class' => 'Webkul\Payment\Payment\CashOnDelivery',
'order_status' => 'Pending',
'order_status' => 'pending',
'active' => true
],
@ -15,7 +15,7 @@ return [
'title' => 'Money Transfer',
'description' => 'Money Transfer',
'class' => 'Webkul\Payment\Payment\MoneyTransfer',
'order_status' => 'Pending',
'order_status' => 'pending',
'active' => true
]
];

View File

@ -153,6 +153,7 @@ class Cart {
'total_weight' => $product->weight * $data['quantity'],
'base_total_weight' => $product->weight * $data['quantity'],
];
return ['parent' => $parentData, 'child' => null];
}
}
@ -204,8 +205,6 @@ class Cart {
session()->flash('success', trans('shop::app.checkout.cart.item.success'));
$this->collectQuantities();
$this->collectTotals();
return redirect()->back();
@ -217,8 +216,6 @@ class Cart {
session()->flash('success', trans('shop::app.checkout.cart.item.success'));
$this->collectQuantities();
$this->collectTotals();
return redirect()->back();
@ -238,15 +235,15 @@ class Cart {
*/
public function getCart()
{
$cart = null;
if(session()->has('cart')) {
$cart = session()->get('cart');
$cart = $this->cart->find(session()->get('cart')->id);
} else if(auth()->guard('customer')->check()) {
return $cart = $this->cart->findOneByField('customer_id', auth()->guard('customer')->user()->id);
$cart = $this->cart->findOneByField('customer_id', auth()->guard('customer')->user()->id);
}
return $this->cart->find($cart->id);
return $cart && $cart->is_active ? $cart : null;
}
/**
@ -299,7 +296,7 @@ class Cart {
return redirect()->back();
}
if($quantity < $totalQty) {
if($quantity <= $totalQty) {
return true;
} else {
return false;
@ -345,8 +342,6 @@ class Cart {
'base_total' => $cartItem->price * ($prevQty + $newQty)
]);
$this->collectQuantities();
$this->collectTotals();
session()->flash('success', trans('shop::app.checkout.cart.quantity.success'));
@ -379,8 +374,6 @@ class Cart {
'base_total' => $parentPrice * ($prevQty + $newQty)
]);
$this->collectQuantities();
$this->collectTotals();
session()->flash('success', trans('shop::app.checkout.cart.quantity.success'));
@ -405,8 +398,6 @@ class Cart {
$parent = $cart->items()->create($itemData['parent']);
}
$this->collectQuantities();
$this->collectTotals();
session()->flash('success', trans('shop::app.checkout.cart.item.success'));
@ -453,7 +444,6 @@ class Cart {
$item->update(['quantity' => $quantity]);
$this->collectTotals();
$this->collectQuantities();
}
}
}
@ -485,12 +475,10 @@ class Cart {
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();
}
}
@ -526,14 +514,21 @@ class Cart {
{
$data = [];
$labels = [];
foreach($item->product->super_attributes as $attribute) {
$option = $attribute->options()->where('id', $item->child->{$attribute->code})->first();
$option = $attribute->options()->where('id', $item->child->product->{$attribute->code})->first();
$data['attributes'][$attribute->code] = [
'attribute_name' => $attribute->name,
'option_label' => $option->label,
];
$labels[] = $attribute->name . ' : ' . $option->label;
}
$data['html'] = implode(', ', $labels);
return $data;
}
@ -626,28 +621,6 @@ 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
*
@ -666,8 +639,8 @@ class Cart {
$cart->base_sub_total_with_discount = 0;
foreach ($cart->items()->get() as $item) {
$cart->grand_total = (float) $cart->grand_total + $item->price * $item->quantity;
$cart->base_grand_total = (float) $cart->base_grand_total + $item->base_price * $item->quantity;
$cart->grand_total = (float) $cart->grand_total + $item->total;
$cart->base_grand_total = (float) $cart->base_grand_total + $item->base_total;
$cart->sub_total = (float) $cart->sub_total + $item->price * $item->quantity;
$cart->base_sub_total = (float) $cart->base_sub_total + $item->base_price * $item->quantity;
@ -678,6 +651,15 @@ class Cart {
$cart->base_grand_total = (float) $cart->base_grand_total + $shipping->base_price;
}
$quantities = 0;
foreach($cart->items as $item) {
$quantities = $quantities + $item->quantity;
}
$cart->items_count = $cart->items->count();
$cart->items_qty = $quantities;
$cart->save();
}
@ -795,8 +777,6 @@ class Cart {
//put the customer cart instance
session()->put('cart', $cart);
$this->collectQuantities();
$this->collectTotals();
return redirect()->back();
@ -821,6 +801,53 @@ class Cart {
}
}
/**
* Checks if cart has any error
*
* @return boolean
*/
public function hasError()
{
if(!$this->getCart())
return true;
if(!$this->isItemsHaveSufficientQuantity())
return true;
return false;
}
/**
* Checks if all cart items have sufficient quantity.
*
* @return boolean
*/
public function isItemsHaveSufficientQuantity()
{
foreach ($this->getCart()->items as $item) {
if(!$this->isItemHaveQuantity($item))
return false;
}
return true;
}
/**
* Checks if all cart items have sufficient quantity.
*
* @return boolean
*/
public function isItemHaveQuantity($item)
{
$product = $item->type == 'configurable' ? $item->child->product : $item->product;
if(!$product->haveSufficientQuantity($item->quantity))
return false;
return true;
}
/**
* Deactivates current cart
*
@ -829,7 +856,11 @@ class Cart {
public function deActivateCart()
{
if($cart = $this->getCart()) {
$this->cart->update($cart->id, ['is_active' => false]);
$this->cart->update(['is_active' => false], $cart->id);
if(session()->has('cart')) {
session()->forget('cart');
}
}
}
@ -848,7 +879,7 @@ class Cart {
'customer_email' => $data['customer_email'],
'customer_first_name' => $data['customer_first_name'],
'customer_last_name' => $data['customer_last_name'],
'customer' => auth()->guard('customer')->user,
'customer' => auth()->guard('customer')->check() ? auth()->guard('customer')->user : null,
'shipping_method' => $data['selected_shipping_rate']['method'],
'shipping_description' => $data['selected_shipping_rate']['method_description'],

View File

@ -141,15 +141,36 @@ class Product extends Model
*/
public function isSaleable()
{
if($this->status) {
if($this->inventories->sum('qty')) {
return true;
}
}
if(!$this->status)
return false;
if($this->haveSufficientQuantity(1))
return true;
return false;
}
/**
* @param integer $qty
*
* @return bool
*/
public function haveSufficientQuantity($qty)
{
$inventories = $this->inventory_sources()->orderBy('priority', 'asc')->get();
$total = 0;
foreach($inventories as $inventorySource) {
if(!$inventorySource->status)
continue;
$total += $inventorySource->pivot->qty;
}
return $qty <= $total ? true : false;
}
/**
* Get an attribute from the model.
*

View File

@ -16,6 +16,7 @@ class CreateOrdersTable extends Migration
Schema::create('orders', function (Blueprint $table) {
$table->increments('id');
$table->string('increment_id');
$table->string('status')->nullable();
$table->boolean('is_guest')->nullable();
$table->string('customer_email')->nullable();

View File

@ -13,7 +13,7 @@ class Order extends Model implements OrderContract
* Get the order items record associated with the order.
*/
public function items() {
return $this->hasMany(CartItemProxy::modelClass())->whereNull('parent_id');
return $this->hasMany(OrderItemProxy::modelClass())->whereNull('parent_id');
}
/**

View File

@ -24,4 +24,55 @@ class OrderItemInventoryRepository extends Repository
{
return 'Webkul\Sales\Contracts\OrderItemInventory';
}
/**
* @param array $data
* @return mixed
*/
public function create(array $data)
{
$orderItem = $data['orderItem'];
$orderedQuantity = $orderItem->qty_ordered;
$product = $orderItem->type == 'configurable' ? $orderItem->child->product : $orderItem->product;
if($product) {
$inventories = $product->inventory_sources()->orderBy('priority', 'asc')->get();
foreach($inventories as $inventorySource) {
if(!$orderedQuantity)
break;
$sourceQuantity = $inventorySource->pivot->qty;
if(!$inventorySource->status || !$sourceQuantity)
continue;
if($sourceQuantity >= $orderedQuantity) {
$orderItemQuantity = $orderedQuantity;
$sourceQuantity -= $orderItemQuantity;
$orderedQuantity = 0;
} else {
$orderItemQuantity = $sourceQuantity;
$sourceQuantity = 0;
$orderedQuantity -= $orderItemQuantity;
}
$this->model->create([
'qty' => $orderItemQuantity,
'order_item_id' => $orderItem->id,
'inventory_source_id' => $inventorySource->id,
]);
$inventorySource->pivot->update([
'qty' => $sourceQuantity
]);
}
}
}
}

View File

@ -31,9 +31,11 @@ class OrderItemRepository extends Repository
*/
public function create(array $data)
{
if(isset($data['product']) && $data['product'] instanceof Model) {
if(isset($data['product']) && $data['product']) {
$data['product_id'] = $data['product']->id;
$data['product_type'] = get_class($data['product']);
unset($data['product']);
}
return $this->model->create($data);

View File

@ -73,15 +73,17 @@ class OrderRepository extends Repository
DB::beginTransaction();
try {
die;
Event::fire('checkout.order.save.before', $data);
if(isset($data['customer']) && $data['customer'] instanceof Model) {
$data['customer_id'] = $data['customer']->id;
$data['customer_type'] = get_class($data['customer']);
} else {
unset($data['customer']);
}
$data['status'] = core()->getConfigData('paymentmethods.' . $data['payment']['method'] . '.status') ?? 'pending';
$order = $this->model->create(array_merge($data, ['increment_id' => $this->generateIncrementId()]));
$order->payment()->create($data['payment']);
@ -94,8 +96,10 @@ class OrderRepository extends Repository
$orderItem = $this->orderItem->create(array_merge($item, ['order_id' => $order->id]));
if(isset($item['child']) && $item['child']) {
$orderItem = $this->orderItem->create(array_merge($item['child'], ['order_id' => $order->id, 'parent_id' => $orderItem->id]));
$orderItem->child = $this->orderItem->create(array_merge($item['child'], ['order_id' => $order->id, 'parent_id' => $orderItem->id]));
}
$this->orderItemInventory->create(['orderItem' => $orderItem]);
}
} catch (\Exception $e) {
DB::rollBack();
@ -115,10 +119,10 @@ class OrderRepository extends Repository
*/
public function generateIncrementId()
{
$lastOrder = $this->orderBy('id', 'desc')->limit(1)->first();
$lastOrder = $this->model->orderBy('id', 'desc')->limit(1)->first();
$lastId = $lastOrder ? $lastOrder->id : 0;
return 000000000 + $last + 1;
return $lastId + 1;
}
}

View File

@ -53,10 +53,10 @@ class OnepageController extends Controller
*/
public function index()
{
if(!$cart = Cart::getCart())
if(Cart::hasError())
return redirect()->route('shop.checkout.cart.index');
return view($this->_config['view'])->with('cart', $cart);
return view($this->_config['view'])->with('cart', Cart::getCart());
}
/**
@ -67,7 +67,7 @@ class OnepageController extends Controller
*/
public function saveAddress(CustomerAddressForm $request)
{
if(!Cart::saveCustomerAddress(request()->all()) || !$rates = Shipping::collectRates())
if(Cart::hasError() || !Cart::saveCustomerAddress(request()->all()) || !$rates = Shipping::collectRates())
return response()->json(['redirect_url' => route('shop.checkout.cart.index')], 403);
return response()->json($rates);
@ -82,7 +82,7 @@ class OnepageController extends Controller
{
$shippingMethod = request()->get('shipping_method');
if(!$shippingMethod || !Cart::saveShippingMethod($shippingMethod))
if(Cart::hasError() || !$shippingMethod || !Cart::saveShippingMethod($shippingMethod))
return response()->json(['redirect_url' => route('shop.checkout.cart.index')], 403);
Cart::collectTotals();
@ -99,7 +99,7 @@ class OnepageController extends Controller
{
$payment = request()->get('payment');
if(!$payment || !Cart::savePaymentMethod($payment))
if(Cart::hasError() || !$payment || !Cart::savePaymentMethod($payment))
return response()->json(['redirect_url' => route('shop.checkout.cart.index')], 403);
$cart = Cart::getCart();
@ -117,6 +117,9 @@ class OnepageController extends Controller
*/
public function saveOrder()
{
if(Cart::hasError())
return response()->json(['redirect_url' => route('shop.checkout.cart.index')], 403);
Cart::collectTotals();
$this->validateOrder();

View File

@ -1339,7 +1339,11 @@ section.cart {
.towishlist {
color : $brand-color;
}
}
.error-message {
color: #ff5656;
margin-top: 17px;
}
}
}
@ -1579,6 +1583,14 @@ section.cart {
}
// checkout ends here
.order-success-content {
padding: 40px 0;
.btn {
display: inline-block;
}
}
// checkout responsive start here
@media only screen and (max-width: 770px) {

View File

@ -89,7 +89,8 @@ return [
'success' => 'Item successfully added to cart',
'success_remove' => 'Item removed successfully',
'error_add' => 'Item cannot be added to cart',
]
],
'quantity-error' => 'Requested quantity is not available.'
],
'onepage' => [
@ -131,6 +132,13 @@ return [
'grand-total' => 'Grand Total',
'delivery-charges' => 'Delivery Charges',
'price' => 'price'
],
'success' => [
'title' => 'Order successfully placed',
'thanks' => 'Thank you for your order!',
'order-id-info' => 'Your order id is #:order_id',
'info' => 'We will email you, your order details and tracking information.'
]
]
];

View File

@ -48,31 +48,29 @@
@if ($product->type == 'configurable')
<div class="summary">
{{-- @foreach (cart::getItemAttributeOptionDetails($item) as $key => $option)
{{ Cart::getItemAttributeOptionDetails($item)['html'] }}
@endforeach --}}
</div>
@endif
<div class="misc">
<div class="qty-text" :class="[errors.has('qty') ? 'has-error' : '']">{{ __('shop::app.checkout.cart.quantity.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->id}}]')">@{{ errors.first('qty') }}</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-link') }}</a></span>
{{-- @endif --}}
<span class="towishlist">{{ __('shop::app.checkout.cart.move-to-wishlist') }}</span>
</div>
@if (!cart()->isItemHaveQuantity($item))
<div class="error-message">
{{ __('shop::app.checkout.cart.quantity-error') }}
</div>
@endif
</div>
</div>
@ -83,9 +81,12 @@
<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>
@if (!cart()->hasError())
<a href="{{ route('shop.checkout.onepage.index') }}" class="btn btn-lg btn-primary">
{{ __('shop::app.checkout.cart.proceed-to-checkout') }}
</a>
@endif
</div>
</div>
</form>

View File

@ -1 +1,25 @@
{{ $order }}
@extends('shop::layouts.master')
@section('page_title')
{{ __('shop::app.checkout.success.title') }}
@stop
@section('content-wrapper')
<div class="order-success-content">
<h1>{{ __('shop::app.checkout.success.thanks') }}</h1>
<p>{{ __('shop::app.checkout.success.order-id-info', ['order_id' => $order->id]) }}</p>
<p>{{ __('shop::app.checkout.success.info') }}</p>
<div class="misc-controls">
<a href="{{ route('shop.home.index') }}" class="btn btn-lg btn-primary">
{{ __('shop::app.checkout.cart.continue-shopping') }}
</a>
</div>
</div>
@endsection

View File

@ -83,94 +83,93 @@
</li>
</ul>
<ul class="cart-dropdown-container">
<?php
$cart = cart()->getCart();
// dd($cart);
?>
<?php $cart = cart()->getCart(); ?>
@inject ('productImageHelper', 'Webkul\Product\Product\ProductImage')
<li class="cart-dropdown">
<span class="icon cart-icon"></span>
@if(isset($cart))
@php
$items = $cart->items;
@endphp
<div class="dropdown-toggle">
<div style="display: inline-block; cursor: pointer;">
@if($cart->items_qty - intval($cart->items_qty) > 0)
<span class="name"><span class="count"> {{ $cart->items_qty }} Products</span>
@else
<span class="name"><span class="count"> {{ intval($cart->items_qty) }} Products</span>
@endif
@if($cart)
@php
$items = $cart->items;
@endphp
<div class="dropdown-toggle">
<div style="display: inline-block; cursor: pointer;">
@if($cart->items_qty - intval($cart->items_qty) > 0)
<span class="name"><span class="count"> {{ $cart->items_qty }} Products</span>
@else
<span class="name"><span class="count"> {{ intval($cart->items_qty) }} Products</span>
@endif
</div>
<i class="icon arrow-down-icon active"></i>
</div>
<div class="dropdown-list" style="display: none; top: 50px; right: 0px">
<div class="dropdown-container">
<div class="dropdown-cart">
<div class="dropdown-header">
<p class="heading">Cart Subtotal - {{ $cart->sub_total }}</p>
</div>
<i class="icon arrow-down-icon active"></i>
<div class="dropdown-content">
@foreach($items as $item)
@if($item->type == "configurable")
<div class="item">
<div class="item-image" >
@php
$images = $productImageHelper->getProductBaseImage($item->child->product);
@endphp
<img src="{{ $images['small_image_url'] }}" />
</div>
</div>
<div class="dropdown-list" style="display: none; top: 50px; right: 0px">
<div class="dropdown-container">
<div class="dropdown-cart">
<div class="dropdown-header">
<p class="heading">Cart Subtotal - {{ $cart->sub_total }}</p>
</div>
<div class="item-details">
<div class="dropdown-content">
@foreach($items as $item)
@if($item->type == "configurable")
<div class="item">
<div class="item-image" >
@php
$images = $productImageHelper->getProductBaseImage($item->child->product);
@endphp
<img src="{{ $images['small_image_url'] }}" />
<div class="item-name">{{ $item->child->name }}</div>
<div class="item-price">{{ $item->total }}</div>
<div class="item-qty">Quantity - {{ $item->quantity }}</div>
</div>
</div>
@else
<div class="item">
<div class="item-image" >
@php
$images = $productImageHelper->getProductBaseImage($item->product);
@endphp
<img src="{{ $images['small_image_url'] }}" />
</div>
<div class="item-details">
<div class="item-details">
<div class="item-name">{{ $item->child->name }}</div>
<div class="item-name">{{ $item->name }}</div>
<div class="item-price">{{ $item->total }}</div>
<div class="item-price">{{ $item->total }}</div>
<div class="item-qty">Quantity - {{ $item->quantity }}</div>
</div>
</div>
@else
<div class="item">
<div class="item-image" >
@php
$images = $productImageHelper->getProductBaseImage($item->product);
@endphp
<img src="{{ $images['small_image_url'] }}" />
<div class="item-qty">Quantity - {{ $item->quantity }}</div>
</div>
</div>
@endif
@endforeach
</div>
<div class="item-details">
<div class="dropdown-footer">
<a href="{{ route('shop.checkout.cart.index') }}">View Shopping Cart</a>
<div class="item-name">{{ $item->name }}</div>
<div class="item-price">{{ $item->total }}</div>
<div class="item-qty">Quantity - {{ $item->quantity }}</div>
</div>
</div>
@endif
@endforeach
</div>
<div class="dropdown-footer">
<a href="{{ route('shop.checkout.cart.index') }}">View Shopping Cart</a>
<button class="btn btn-primary btn-lg">CHECKOUT</button>
<button class="btn btn-primary btn-lg">CHECKOUT</button>
</div>
</div>
</div>
</div>
</div>
@else
<div class="dropdown-toggle">
<div style="display: inline-block; cursor: pointer;">
<div class="dropdown-toggle">
<div style="display: inline-block; cursor: pointer;">
<span class="name"><span class="count"> 0 &nbsp;</span>Products</span>
<span class="name"><span class="count"> 0 &nbsp;</span>Products</span>
</div>
</div>
</div>
@endif
</li>
</ul>

View File

@ -1998,6 +1998,11 @@ section.cart .cart-content .right-side {
color: #0041FF;
}
.cart-item-list .item .item-details .error-message {
color: #ff5656;
margin-top: 17px;
}
.order-summary h3 {
font-size: 16px;
margin-top: 0;
@ -2228,6 +2233,14 @@ section.cart .cart-content .right-side {
padding-left: 40px;
}
.order-success-content {
padding: 40px 0;
}
.order-success-content .btn {
display: inline-block;
}
@media only screen and (max-width: 770px) {
.checkout-process .col-main {
width: 100%;

File diff suppressed because one or more lines are too long