From e4a5e84fb658276d0593cac409d5cafe4b027b3d Mon Sep 17 00:00:00 2001 From: Prashant Singh Date: Sat, 3 Aug 2019 19:54:02 +0530 Subject: [PATCH] Refactoring cart rules --- .../Admin/src/Resources/assets/sass/app.scss | 2 +- .../CMS/src/Http/Controllers/Controller.php | 2 +- .../Webkul/Discount/src/Actions/Action.php | 4 +- .../src/Actions/Cart/PercentOfProduct.php | 130 ++++++++++++++---- .../src/Actions/Cart/WholeCartToPercent.php | 46 ++++--- .../Webkul/Discount/src/Helpers/Discount.php | 109 ++++++++++++--- .../src/Helpers/NonCouponAbleRule.php | 2 +- .../Http/Controllers/OnepageController.php | 9 +- 8 files changed, 227 insertions(+), 77 deletions(-) diff --git a/packages/Webkul/Admin/src/Resources/assets/sass/app.scss b/packages/Webkul/Admin/src/Resources/assets/sass/app.scss index a2dc1af89..6b63d8c8f 100755 --- a/packages/Webkul/Admin/src/Resources/assets/sass/app.scss +++ b/packages/Webkul/Admin/src/Resources/assets/sass/app.scss @@ -269,7 +269,7 @@ body { .control-container { display: flex; flex-direction: row; - align-items: center; + align-items: flex-start; width: 750px; .control { diff --git a/packages/Webkul/CMS/src/Http/Controllers/Controller.php b/packages/Webkul/CMS/src/Http/Controllers/Controller.php index 971cb744c..1abdaf472 100644 --- a/packages/Webkul/CMS/src/Http/Controllers/Controller.php +++ b/packages/Webkul/CMS/src/Http/Controllers/Controller.php @@ -9,4 +9,4 @@ use Illuminate\Foundation\Validation\ValidatesRequests; class Controller extends BaseController { use DispatchesJobs, ValidatesRequests; -} +} \ No newline at end of file diff --git a/packages/Webkul/Discount/src/Actions/Action.php b/packages/Webkul/Discount/src/Actions/Action.php index 62268aa18..b5db12e74 100644 --- a/packages/Webkul/Discount/src/Actions/Action.php +++ b/packages/Webkul/Discount/src/Actions/Action.php @@ -4,7 +4,7 @@ namespace Webkul\Discount\Actions; abstract class Action { - abstract public function calculate($rule, $item, $cart); + abstract public function calculate($rule); - abstract public function calculateOnShipping($cart); + abstract public function calculateOnShipping(); } \ No newline at end of file diff --git a/packages/Webkul/Discount/src/Actions/Cart/PercentOfProduct.php b/packages/Webkul/Discount/src/Actions/Cart/PercentOfProduct.php index 700e2f780..de66c416f 100644 --- a/packages/Webkul/Discount/src/Actions/Cart/PercentOfProduct.php +++ b/packages/Webkul/Discount/src/Actions/Cart/PercentOfProduct.php @@ -6,60 +6,132 @@ use Webkul\Discount\Actions\Action; class PercentOfProduct extends Action { - public function calculate($rule, $items, $cart) + public function calculate($rule) { - $report = collect(); + $cart = \Cart::getCart(); + $items = $cart->items; + + $impact = collect(); $totalDiscount = 0; - foreach ($items as $item) { - $amountDiscounted = 0; - $itemReport = array(); + if ($rule->uses_attribute_conditions) { + $productIds = $rule->product_ids; - $disc_threshold = $rule->disc_threshold; - $disc_amount = $rule->disc_amount; - $disc_quantity = $rule->disc_quantity; + $productIds = explode(',', $productIds); - $realQty = $item['quantity']; + foreach ($items as $item) { + $product = $item->product; - if ($cart->items_qty >= $disc_threshold) { - $amountDiscounted = $item['base_price'] * ($disc_amount / 100); - - if ($realQty > $disc_quantity) { - $amountDiscounted = $amountDiscounted * $disc_quantity; - } else { - $amountDiscounted = $amountDiscounted * $realQty; + if ($product->type == 'configurable') { + $product = $item->child->product; } - if ($amountDiscounted > $item['base_price'] && $realQty == 1) { - $amountDiscounted = $item['base_price']; + foreach ($productIds as $productId) { + $disc_threshold = $rule->disc_threshold; + $disc_amount = $rule->disc_amount; + $disc_quantity = $rule->disc_quantity; + $amountDiscounted = 0; + $report = array(); + + $realQty = $item->quantity; + + if ($productId == $product->id && $cart->items_qty >= $disc_threshold) { + // distribute the discount according to ratios in case when rule is getting applied on multiple items + + $amountDiscounted = $item->base_price * ($disc_amount / 100); + + if ($realQty > $disc_quantity) { + $amountDiscounted = $amountDiscounted * $disc_quantity; + } else { + $amountDiscounted = $amountDiscounted * $realQty; + } + + if ($amountDiscounted > $item->base_price && $realQty == 1) { + $amountDiscounted = $item->base_price; + } + + $totalDiscount = $totalDiscount + $amountDiscounted; + + $report['item_id'] = $item->id; + $report['product_id'] = $productId; + $report['discount'] = $amountDiscounted; + $report['formatted_discount'] = core()->currency($amountDiscounted); + + $impact->push($report); + + unset($report); + } } } + } else { + $productIds = null; - $totalDiscount = $totalDiscount + $amountDiscounted; + foreach ($items as $item) { + $product = $item->product; - $itemReport['item_id'] = $item->id; - $itemReport['product_id'] = $item->product_id; - $itemReport['discount'] = $amountDiscounted; - $itemReport['formatted_discount'] = core()->currency($amountDiscounted); + if ($product->type == 'configurable') { + $product = $item->child->product; + } - $report->push($itemReport); + $disc_threshold = $rule->disc_threshold; + $disc_amount = $rule->disc_amount; + $disc_quantity = $rule->disc_quantity; + $amountDiscounted = 0; + $report = array(); - unset($itemReport); + $realQty = $item->quantity; + + if ($productId == $product->id && $cart->items_qty >= $disc_threshold) { + // distribute the discount according to ratios in case when rule is getting applied on multiple items + + $amountDiscounted = $item->base_price * ($disc_amount / 100); + + if ($realQty > $disc_quantity) { + $amountDiscounted = $amountDiscounted * $disc_quantity; + } else { + $amountDiscounted = $amountDiscounted * $realQty; + } + + if ($amountDiscounted > $item->base_price && $realQty == 1) { + $amountDiscounted = $item->base_price; + } + + $totalDiscount = $totalDiscount + $amountDiscounted; + + $report['item_id'] = $item->id; + $report['product_id'] = $productId; + $report['discount'] = $amountDiscounted; + $report['formatted_discount'] = core()->currency($amountDiscounted); + + $impact->push($report); + + unset($report); + } + } } - $report->discount = $totalDiscount; - $report->formatted_discount = core()->currency($totalDiscount); + // if (isset($rule->apply_on_shipping) && ! $rule->free_shipping) { + // $impact->discount_on_shipping = $this->calculateOnShipping(); + // } else { + // $rule->discount_on_shipping = 0; + // $rule->base_discount_on_shipping = 0; + // } - return $report; + $impact->discount = $totalDiscount; + $impact->formatted_discount = core()->currency($totalDiscount); + + return $impact; } /** * Calculates the impact on the shipping amount if the rule is apply_to_shipping enabled */ - public function calculateOnShipping($cart) + public function calculateOnShipping() { $cart = \Cart::getCart(); + $shippingRate = $cart->selected_shipping_rate; + $percentOfDiscount = ($cart->base_discount_amount * 100) / $cart->base_grand_total; return $percentOfDiscount; diff --git a/packages/Webkul/Discount/src/Actions/Cart/WholeCartToPercent.php b/packages/Webkul/Discount/src/Actions/Cart/WholeCartToPercent.php index 62fd54137..92169c0f2 100644 --- a/packages/Webkul/Discount/src/Actions/Cart/WholeCartToPercent.php +++ b/packages/Webkul/Discount/src/Actions/Cart/WholeCartToPercent.php @@ -15,19 +15,21 @@ class WholeCartToPercent extends Action * * @return boolean */ - public function calculate($rule, $items, $cart) + public function calculate($rule) { - $report = collect(); + $cart = \Cart::getCart(); + $items = $cart->items; + $impact = collect(); $totalDiscount = 0; if ($rule->discount_amount >= 100) { - $report->discount = $cart->base_grand_total; + $impact->discount = $cart->base_grand_total; } else { - $report->discount = ($rule->disc_amount / 100) * $cart->base_grand_total; + $impact->discount = ($rule->disc_amount / 100) * $cart->base_grand_total; } - $report->formatted_discount = core()->currency($report->discount); + $impact->formatted_discount = core()->currency($impact->discount); if ($rule->uses_attribute_conditions) { $productIDs = $rule->product_ids; @@ -45,22 +47,22 @@ class WholeCartToPercent extends Action } if ($matchCount > 0) { - $discountPerItem = $report->discount / $matchCount; + $discountPerItem = $impact->discount / $matchCount; } foreach ($productIDs as $productID) { foreach ($items as $item) { if ($item->product_id == $productID) { - $itemReport = array(); + $report = array(); - $itemReport['item_id'] = $item->id; - $itemReport['product_id'] = $item->product_id; - $itemReport['discount'] = $discountPerItem; - $itemReport['formatted_discount'] = core()->currency(0); + $report['item_id'] = $item->id; + $report['product_id'] = $item->product_id; + $report['discount'] = $discountPerItem; + $report['formatted_discount'] = core()->currency(0); - $report->push($itemReport); + $impact->push($report); - unset($itemReport); + unset($report); } } } @@ -68,26 +70,26 @@ class WholeCartToPercent extends Action $discountPerItem = $report->discount / $cart->items_qty; foreach ($items as $item) { - $itemReport = array(); + $report = array(); - $itemReport['item_id'] = $item->id; - $itemReport['product_id'] = $item->product_id; - $itemReport['discount'] = $discountPerItem; - $itemReport['formatted_discount'] = core()->currency(0); + $report['item_id'] = $item->id; + $report['product_id'] = $item->product_id; + $report['discount'] = $discountPerItem; + $report['formatted_discount'] = core()->currency(0); - $report->push($itemReport); + $impact->push($report); - unset($itemReport); + unset($report); } } - return $report; + return $impact; } /** * Calculates the impact on the shipping amount if the rule is apply_to_shipping enabled */ - public function calculateOnShipping($cart) + public function calculateOnShipping() { $percentOfDiscount = ($cart->base_discount_amount * 100) / $cart->base_grand_total; diff --git a/packages/Webkul/Discount/src/Helpers/Discount.php b/packages/Webkul/Discount/src/Helpers/Discount.php index 64acd70fb..474e52bea 100644 --- a/packages/Webkul/Discount/src/Helpers/Discount.php +++ b/packages/Webkul/Discount/src/Helpers/Discount.php @@ -43,6 +43,81 @@ abstract class Discount */ abstract public function apply($code); + /** + * To find all the suitable rules that can be applied on the current cart + * + * @return collection $rules + */ + public function getApplicableRules($usecoupon = false) + { + $channel = core()->getCurrentChannel()->id; + + $rules = $this->cartRule->findWhere([ + 'use_coupon' => 0, + 'status' => 1 + ]); + + $filteredRules = collect(); + + // time based constraints + foreach ($rules as $rule) { + if ($rule->starts_from != null && $rule->ends_till == null) { + if (Carbon::parse($rule->starts_from) < now()) { + $rule->impact = $this->calculateImpact($rule); + + $filteredRules->push($rule); + } + } else if ($rule->starts_from == null && $rule->ends_till != null) { + if (Carbon::parse($rule->ends_till) > now()) { + $rule->impact = $this->calculateImpact($rule); + + $filteredRules->push($rule); + } + } else if ($rule->starts_from != null && $rule->ends_till != null) { + if (Carbon::parse($rule->starts_from) < now() && now() < Carbon::parse($rule->ends_till)) { + $rule->impact = $this->calculateImpact($rule); + + $filteredRules->push($rule); + } + } else { + $rule->impact = $this->calculateImpact($rule); + + $filteredRules->push($rule); + } + } + + dd($filteredRules, 'called by this'); + + return $filteredRules; + } + + /** + * To calculate the impact of the rule + * + * @return collection + */ + public function calculateImpact($rule) + { + $impact = $this->getActionInstance($rule); + + return $impact; + } + + /** + * Return the instance of the related rule's action type + * + * @return object + */ + public function getActionInstance($rule) + { + $actionType = new $this->rules['cart'][$rule->action_type]; + + $outcome = $actionType->calculate($rule); + + return $outcome; + } + + /** * Checks whether coupon is getting applied on current cart instance or not * @@ -54,22 +129,22 @@ abstract class Discount $timeBased = false; - // time based constraints - if ($rule->starts_from != null && $rule->ends_till == null) { - if (Carbon::parse($rule->starts_from) < now()) { - $timeBased = true; - } - } else if ($rule->starts_from == null && $rule->ends_till != null) { - if (Carbon::parse($rule->ends_till) > now()) { - $timeBased = true; - } - } else if ($rule->starts_from != null && $rule->ends_till != null) { - if (Carbon::parse($rule->starts_from) < now() && now() < Carbon::parse($rule->ends_till)) { - $timeBased = true; - } - } else { - $timeBased = true; - } + // // time based constraints + // if ($rule->starts_from != null && $rule->ends_till == null) { + // if (Carbon::parse($rule->starts_from) < now()) { + // $timeBased = true; + // } + // } else if ($rule->starts_from == null && $rule->ends_till != null) { + // if (Carbon::parse($rule->ends_till) > now()) { + // $timeBased = true; + // } + // } else if ($rule->starts_from != null && $rule->ends_till != null) { + // if (Carbon::parse($rule->starts_from) < now() && now() < Carbon::parse($rule->ends_till)) { + // $timeBased = true; + // } + // } else { + // $timeBased = true; + // } $channelBased = false; @@ -130,7 +205,7 @@ abstract class Discount } } - if ($timeBased && $channelBased && $customerGroupBased && $conditionsBased) { + if ($channelBased && $customerGroupBased && $conditionsBased) { if ($rule->uses_attribute_conditions == 1 && $partialMatch) { return true; } else if ($rule->uses_attribute_conditions == 0) { diff --git a/packages/Webkul/Discount/src/Helpers/NonCouponAbleRule.php b/packages/Webkul/Discount/src/Helpers/NonCouponAbleRule.php index 96fd9a69c..89445bbcf 100644 --- a/packages/Webkul/Discount/src/Helpers/NonCouponAbleRule.php +++ b/packages/Webkul/Discount/src/Helpers/NonCouponAbleRule.php @@ -51,7 +51,7 @@ class NonCouponAbleRule extends Discount } // time based filter - foreach($rules as $rule) { + foreach ($rules as $rule) { $applicability = $this->checkApplicability($rule); if ($applicability) { diff --git a/packages/Webkul/Shop/src/Http/Controllers/OnepageController.php b/packages/Webkul/Shop/src/Http/Controllers/OnepageController.php index bfe3abe71..abd7d3281 100755 --- a/packages/Webkul/Shop/src/Http/Controllers/OnepageController.php +++ b/packages/Webkul/Shop/src/Http/Controllers/OnepageController.php @@ -89,7 +89,8 @@ class OnepageController extends Controller if (Cart::hasError()) return redirect()->route('shop.checkout.cart.index'); - $this->nonCoupon->apply(); + // $this->nonCoupon->apply(); + $this->nonCoupon->getApplicableRules(); Cart::collectTotals(); @@ -126,7 +127,7 @@ class OnepageController extends Controller if (Cart::hasError() || !Cart::saveCustomerAddress($data) || ! $rates = Shipping::collectRates()) return response()->json(['redirect_url' => route('shop.checkout.cart.index')], 403); - $this->nonCoupon->apply(); + $this->nonCoupon->getApplicableRules(); Cart::collectTotals(); @@ -145,7 +146,7 @@ class OnepageController extends Controller if (Cart::hasError() || !$shippingMethod || !Cart::saveShippingMethod($shippingMethod)) return response()->json(['redirect_url' => route('shop.checkout.cart.index')], 403); - $this->nonCoupon->apply(); + $this->nonCoupon->getApplicableRules(); Cart::collectTotals(); @@ -164,7 +165,7 @@ class OnepageController extends Controller if (Cart::hasError() || !$payment || !Cart::savePaymentMethod($payment)) return response()->json(['redirect_url' => route('shop.checkout.cart.index')], 403); - $this->nonCoupon->apply(); + $this->nonCoupon->getApplicableRules(); $this->nonCoupon->checkOnShipping(Cart::getCart());