Refactoring cart rule on front end

This commit is contained in:
Prashant Singh 2019-06-06 19:33:52 +05:30
parent a78cc0b3b7
commit b6d64b251b
10 changed files with 119 additions and 228 deletions

View File

@ -21,7 +21,7 @@ class CartRuleDataGrid extends DataGrid
{
$queryBuilder = DB::table('cart_rules')
->select('id')
->addSelect('id', 'name', 'starts_from', 'ends_till', 'usage_limit', 'per_customer', 'status', 'end_other_rules', 'action_type');
->addSelect('id', 'name', 'starts_from', 'ends_till', 'priority', 'usage_limit', 'per_customer', 'status', 'end_other_rules', 'is_guest', 'action_type');
$this->setQueryBuilder($queryBuilder);
}
@ -47,21 +47,12 @@ class CartRuleDataGrid extends DataGrid
]);
$this->addColumn([
'index' => 'per_customer',
'label' => trans('admin::app.datagrid.per-cust'),
'type' => 'string',
'index' => 'priority',
'label' => trans('admin::app.datagrid.priority'),
'type' => 'number',
'searchable' => false,
'sortable' => true,
'filterable' => true
]);
$this->addColumn([
'index' => 'usage_limit',
'label' => trans('admin::app.datagrid.usage-throttle'),
'type' => 'string',
'searchable' => false,
'sortable' => true,
'filterable' => true
'filterable' => true,
]);
$this->addColumn([
@ -72,10 +63,25 @@ class CartRuleDataGrid extends DataGrid
'sortable' => true,
'filterable' => true,
'wrapper' => function($value) {
if ($value->end_other_rules == 1)
return 'true';
if ($value->status == 1)
return 'True';
else
return 'false';
return 'False';
}
]);
$this->addColumn([
'index' => 'is_guest',
'label' => trans('admin::app.datagrid.for-guest'),
'type' => 'boolean',
'searchable' => false,
'sortable' => true,
'filterable' => true,
'wrapper' => function($value) {
if ($value->is_guest == 1)
return 'True';
else
return 'False';
}
]);
@ -88,9 +94,9 @@ class CartRuleDataGrid extends DataGrid
'filterable' => true,
'wrapper' => function($value) {
if ($value->end_other_rules == 1)
return 'true';
return 'True';
else
return 'false';
return 'False';
}
]);

View File

@ -157,7 +157,8 @@ return [
'starts-from' => 'Starts From',
'ends-till' => 'Ends Till',
'per-cust' => 'Per Customer',
'usage-throttle' => 'Usage Times'
'usage-throttle' => 'Usage Times',
'for-guest' => 'For Guest'
],
'account' => [

View File

@ -67,8 +67,7 @@ return [
'actions' => [
'percent_of_product' => 'Percentage of product',
'fixed_amount' => 'Apply as fixed amount',
'buy_a_get_b' => 'Get B units free',
'fixed_amount_cart' => 'Fixed amount for whole cart'
'buy_a_get_b' => 'Get B amount back',
],
'validation' => [

View File

@ -516,7 +516,7 @@ class Discount
$appliedRule = null;
if (! isset($rules['id'])) {
return response()->json(['message' => trans('admin::app.promotion.status.no-coupon')], 200);
return ['message' => trans('admin::app.promotion.status.no-coupon'), 'success' => false];
}
foreach($rules['id'] as $rule) {
@ -532,13 +532,13 @@ class Discount
}
if (! isset($appliedRule)) {
return response()->json(['message' => trans('admin::app.promotion.status.no-coupon')], 200);
return ['message' => trans('admin::app.promotion.status.no-coupon'), 'success' => false];
}
$race = $this->endRace($appliedRule);
if (! $race) {
return response()->json(['message' => trans('admin::app.promotion.status.no-coupon')], 200);
return ['message' => trans('admin::app.promotion.status.no-coupon'), 'success' => false];
}
$cart = \Cart::getCart();
@ -578,6 +578,7 @@ class Discount
} else {
if ($appliedRule->starts_from != null && $appliedRule->ends_till != null) {
if (Carbon::parse($appliedRule->starts_from) < now() && now() < Carbon::parse($appliedRule->ends_till)) {
$result = 1;
} else {
$result = 0;
}
@ -595,13 +596,14 @@ class Discount
$newQuantity = 0;
if ($cart->items_qty >= $disc_threshold && $disc_quantity > 0) {
if ($disc_quantity > 1) {
$disc_amount = $disc_amount * $disc_quantity;
}
// add the time conditions if rule is expired and active then make it in active
$leastWorthItem = \Cart::leastWorthItem();
$realQty = $leastWorthItem['quantity'];
if ($disc_quantity > 1) {
$disc_amount = $disc_amount * $disc_quantity;
}
if ($action_type == config('pricerules.cart.validation.0')) {
if ($realQty <= $disc_quantity) {
$amountDiscounted = (($leastWorthItem['total'] / $realQty) * ($disc_amount / 100)) * $disc_quantity;
@ -624,92 +626,36 @@ class Discount
}
} else if ($action_type == config('pricerules.cart.validation.2')) {
if ($realQty <= $disc_quantity) {
$newQuantity = $this->cartItem->find($leastWorthItem['id'])->quantity + $disc_amount;
$amountDiscounted = $this->cartItem->find($leastWorthItem['id'])->quantity + $disc_amount;
} else {
$newQuantity = $this->cartItem->find($leastWorthItem['id'])->quantity + $disc_quantity;
$amountDiscounted = $this->cartItem->find($leastWorthItem['id'])->quantity + $disc_quantity;
}
} else if ($action_type == config('pricerules.cart.validation.3')) {
$amountDiscounted = $disc_amount;
}
if ($action_type == config('pricerules.cart.validation.2')) {
$cartRuleCart = $this->cartRuleCart->findWhere([
'cart_id' => $cart->id,
]);
if (count($cartRuleCart)) {
$this->cartRuleCart->update([
'cart_id' => $cart->id,
'cart_rule_id' => $appliedRule->id
], $cartRuleCart->first()->id);
} else {
$this->cartRuleCart->create([
'cart_id' => $cart->id,
'cart_rule_id' => $appliedRule->id
]);
}
return response()->json([
'message' => trans('admin::app.promotion.status.coupon-applied'),
'action' => $action_type,
'amount_given' => false,
'amount_payable' => $newQuantity,
'amount' => null,
'success' => true
]);
} else {
$cartRuleCart = $this->cartRuleCart->findWhere([
$amountDiscounted = 0;
}
$cartRuleCart = $this->cartRuleCart->findWhere([
'cart_id' => $cart->id,
]);
if (count($cartRuleCart)) {
$this->cartRuleCart->update([
'cart_id' => $cart->id,
]);
if (count($cartRuleCart)) {
$this->cartRuleCart->update([
'cart_id' => $cart->id,
'cart_rule_id' => $appliedRule->id
], $cartRuleCart->first()->id);
} else {
$this->cartRuleCart->create([
'cart_id' => $cart->id,
'cart_rule_id' => $appliedRule->id
]);
}
return response()->json([
'id' => $appliedRule->id,
'rule' => $appliedRule,
'item_id' => $leastWorthItem['id'],
'message' => trans('admin::app.promotion.status.coupon-applied'),
'amount_given' => true,
'amount' => core()->currency($amountDiscounted + $cart->tax_total),
'action_type' => $action_type,
'success' => true
'cart_rule_id' => $appliedRule->id
], $cartRuleCart->first()->id);
} else {
$this->cartRuleCart->create([
'cart_id' => $cart->id,
'cart_rule_id' => $appliedRule->id
]);
}
dd($amountDiscounted);
return ['message' => trans('admin::app.promotion.status.coupon-applied'), 'success' => true, 'amount' => $amountDiscounted];
} else {
return response()->json([
'id' => null,
'rule' => null,
'item_id' => null,
'message' => trans('admin::app.promotion.status.coupon-failed'),
'action' => $action_type,
'amount_given' => null,
'amount' => null,
'least_value_item' => null,
'success' => false
]);
return ['message' => trans('admin::app.promotion.status.coupon-failed'), 'success' => false, 'amount' => $amountDiscounted];
}
} else {
return response()->json([
'id' => null,
'rule' => null,
'item_id' => null,
'message' => trans('admin::app.promotion.status.coupon-failed'),
'action' => null,
'amount_given' => null,
'amount' => null,
'least_value_item' => null,
'success' => false
]);
return ['message' => trans('admin::app.promotion.status.coupon-failed'), 'success' => false, 'amount' => $amountDiscounted];
}
}
@ -769,6 +715,11 @@ class Discount
}
}
/**
* Used when race condition occurs between
* any two rules possibly a discounted and
* a non discounted rule
*/
public function analyzeImpact($rule)
{
$cart = \Cart::getCart();
@ -947,7 +898,6 @@ class Discount
protected function testAllConditionAreFalse($conditions, $cart) {
$shipping_address = $cart->getShippingAddressAttribute();
$shipping_method = $cart->shipping_method;
$shipping_country = $shipping_address->country;
$shipping_state = $shipping_address->state;

View File

@ -162,12 +162,12 @@ class CartRuleController extends Controller
$data['actions'] = json_encode($data['actions']);
if (! isset($data['all_conditions'])) {
if (! isset($data['all_conditions']) || $data['all_conditions'] == "[]") {
$data['conditions'] = null;
} else {
$data['conditions'] = json_encode($data['all_conditions']);
unset($data['all_conditions']);
}
unset($data['all_conditions']);
if ($data['use_coupon']) {
// if (isset($data['auto_generation']) && $data['auto_generation']) {
@ -318,7 +318,7 @@ class CartRuleController extends Controller
}
$data['actions'] = json_encode($data['actions']);
if (! isset($data['all_conditions'])) {
if (! isset($data['all_conditions']) || $data['all_conditions'] == "[]") {
$data['conditions'] = null;
} else {
$data['conditions'] = json_encode($data['all_conditions']);

File diff suppressed because one or more lines are too long

View File

@ -256,7 +256,7 @@ class CartController extends Controller
$code = request()->input('code');
$result = Cart::applyCoupon($code);
dd($result);
return $result;
}

View File

@ -2174,7 +2174,7 @@ section.cart {
}
}
.payble-amount {
.payable-amount {
margin-top: 17px;
border-top: 1px solid $border-color;
padding-top: 12px;
@ -3710,7 +3710,7 @@ section.review {
}
}
.order-summary .item-detail, .payble-amount {
.order-summary .item-detail, .payable-amount {
label.right {
float: left;
}

View File

@ -5,18 +5,35 @@
@stop
@section('content-wrapper')
<checkout></checkout>
@endsection
@push('scripts')
<script type="text/x-template" id="discount-template">
<div class="discount">
<div class="discount-group">
<form class="coupon-form" method="post" @submit.prevent="onSubmit" v-if="!discounted">
<div class="control-group mt-20" :class="[errors.has('code') ? 'has-error' : '']">
<input v-model="code" type="text" class="control" value="" name="code" placeholder="Enter Coupon Code" v-on:change="codeChange" style="width: 100%">
<span class="control-error" v-if="errors.has('code')">
@{{ errors.first('code') }}
</span>
<span class="coupon-message mt-5" style="display: block; color: #ff5656; margin-bottom: 5px;" v-if="message != 'Success' && message != 'success'">@{{ message }}</span>
<span class="coupon-message mt-5" style="display: block; margin-bottom: 5px;" v-if="message == 'Success' || message == 'success'">@{{ message }}</span>
<button class="btn btn-lg btn-black">{{ __('shop::app.checkout.onepage.apply-coupon') }}</button>
</div>
</form>
</div>
</div>
</script>
<script type="text/x-template" id="checkout-template">
<div id="checkout" class="checkout-process">
<div class="col-main">
<ul class="checkout-steps">
<li class="active" :class="[completedStep >= 0 ? 'active' : '', completedStep > 0 ? 'completed' : '']" @click="navigateToStep(1)">
<div class="decorator address-info"></div>
@ -46,69 +63,50 @@
</ul>
<div class="step-content information" v-show="currentStep == 1" id="address-section">
@include('shop::checkout.onepage.customer-info')
<div class="button-group">
<button type="button" class="btn btn-lg btn-primary" @click="validateForm('address-form')" :disabled="disable_button" id="checkout-address-continue-button">
{{ __('shop::app.checkout.onepage.continue') }}
</button>
</div>
</div>
<div class="step-content shipping" v-show="currentStep == 2" id="shipping-section">
<shipping-section v-if="currentStep == 2" @onShippingMethodSelected="shippingMethodSelected($event)"></shipping-section>
<div class="button-group">
<button type="button" class="btn btn-lg btn-primary" @click="validateForm('shipping-form')" :disabled="disable_button" id="checkout-shipping-continue-button">
{{ __('shop::app.checkout.onepage.continue') }}
</button>
</div>
</div>
<div class="step-content payment" v-show="currentStep == 3" id="payment-section">
<payment-section v-if="currentStep == 3" @onPaymentMethodSelected="paymentMethodSelected($event)"></payment-section>
<div class="button-group">
<button type="button" class="btn btn-lg btn-primary" @click="validateForm('payment-form')" :disabled="disable_button" id="checkout-payment-continue-button">
{{ __('shop::app.checkout.onepage.continue') }}
</button>
</div>
</div>
<div class="step-content review" v-show="currentStep == 4" id="summary-section">
<review-section v-if="currentStep == 4"></review-section>
<div class="button-group">
<button type="button" class="btn btn-lg btn-primary" @click="placeOrder()" :disabled="disable_button" id="checkout-place-order-button">
{{ __('shop::app.checkout.onepage.place-order') }}
</button>
</div>
</div>
</div>
<div class="col-right" v-if="resetSummary" v-show="currentStep != 4">
<summary-section></summary-section>
</div>
</div>
</script>
@ -135,9 +133,7 @@
data: function() {
return {
currentStep: 1,
completedStep: 0,
address: {
billing: {
address1: [''],
@ -149,23 +145,14 @@
address1: ['']
},
},
selected_shipping_method: '',
selected_payment_method: '',
disable_button: false,
new_shipping_address: false,
new_billing_address: false,
allAddress: {},
countryStates: @json(core()->groupedStatesByCountries()),
country: @json(core()->countries()),
resetSummary: true
}
},
@ -483,7 +470,31 @@
Vue.component('review-section', {
data: function() {
return {
templateRender: null,
templateRender: null
}
},
staticRenderFns: reviewTemplateRenderFns,
mounted: function() {
this.templateRender = reviewHtml.render;
for (var i in reviewHtml.staticRenderFns) {
reviewTemplateRenderFns.push(reviewHtml.staticRenderFns[i]);
}
},
render: function(h) {
return h('div', [
(this.templateRender ?
this.templateRender() :
'')
]);
}
});
Vue.component('discount', {
template: '#discount-template',
inject: ['$validator'],
data: function() {
return {
code: null,
message: null,
qtyRevealed: false,
@ -499,22 +510,7 @@
}
},
staticRenderFns: reviewTemplateRenderFns,
mounted: function() {
this.templateRender = reviewHtml.render;
for (var i in reviewHtml.staticRenderFns) {
reviewTemplateRenderFns.push(reviewHtml.staticRenderFns[i]);
}
},
render: function(h) {
return h('div', [
(this.templateRender ?
this.templateRender() :
'')
]);
},
methods: {
@ -560,6 +556,7 @@
}
}
});
</script>
@endpush

View File

@ -3,7 +3,7 @@
<div class="item-detail">
<label>
<span id="total_qty">{{ intval($cart->items_qty) }}</span>
{{ intval($cart->items_qty) }}
{{ __('shop::app.checkout.total.sub-total') }}
{{ __('shop::app.checkout.total.price') }}
</label>
@ -24,72 +24,10 @@
</div>
@endif
<div class="payble-amount">
<div class="payable-amount">
<label>{{ __('shop::app.checkout.total.grand-total') }}</label>
<label class="right">{{ core()->currency($cart->base_grand_total) }}</label>
</div>
<div class="discount">
<div class="discount-group">
@inject('cart_rule', 'Webkul\Discount\Helpers\Discount')
@if (! request()->is('checkout/cart'))
<form class="coupon-form" method="post" @submit.prevent="onSubmit" v-if="!discounted">
<div class="control-group mt-20" :class="[errors.has('code') ? 'has-error' : '']">
<input v-model="code" type="text" class="control" value="" name="code" placeholder="Enter Coupon Code" v-on:change="codeChange" style="width: 100%">
<span class="control-error" v-if="errors.has('code')">
@{{ errors.first('code') }}
</span>
<span class="coupon-message mt-5" style="display: block; color: #ff5656; margin-bottom: 5px;" v-if="message != 'Success' && message != 'success'">@{{ message }}</span>
<span class="coupon-message mt-5" style="display: block; margin-bottom: 5px;" v-if="message == 'Success' || message == 'success'">@{{ message }}</span>
<button class="btn btn-lg btn-black">{{ __('shop::app.checkout.onepage.apply-coupon') }}</button>
</div>
</form>
@if(isset($rule))
<div class="discounted" v-if="!discounted">
<div class="mt-15 mb-10">
{{ $rule['rule']->name }} {{ __('shop::app.checkout.onepage.applied') }}
</div>
<span class="payble-amount row mt-10">
@if ($rule['impact']['amount_given'])
<label style="float: left;">
{{ __('shop::app.checkout.onepage.amt-payable') }}
</label>
<label style="float: right;">
{{ core()->currency($cart->grand_total - $rule['impact']['amount']) }}
</label>
@else
<label style="float: left;">
{{ __('shop::app.checkout.onepage.got') }}
</label>
<label style="float: right;">
{{ $rule['impact']['amount'] }} {{ __('shop::app.checkout.onepage.got') }}
</label>
@endif
</span>
</div>
@endif
<div class="discounted" v-if="discounted">
<div class="mt-15 mb-10">
@{{ message }} <span class="icon cross-icon right" v-on:click="removeCoupon"></span>
</div>
<span class="payble-amount row mt-10">
<label style="float: left;">{{ __('shop::app.checkout.onepage.amt-payable') }}</label>
<label style="float: right;">@{{ discount.amount }}</label>
</span>
</div>
@endif
</div>
</div>
<discount></discount>
</div>