Made Catalog Rules made compatible with new product types and updated issue templates

This commit is contained in:
Prashant Singh 2019-10-23 19:00:13 +05:30
parent 02f0d004b0
commit 23237f9921
18 changed files with 263 additions and 198 deletions

View File

@ -6,29 +6,31 @@ about: 'Report a general library issue.'
# Bug report
### Title
**Just a quick sentence to brief your trouble with Bagisto or something associated with it.**
Please be calm, short and emaphasize on points.
**Just a quick sentence to brief your trouble with Bagisto or something associated with it.**
**Please be calm, short and emaphasize on points.**
### Issue Description
**Description helps the developers to understand the bug. It describes the problem encountered or some after effect of some kind.**
**Description helps the developers to understand the bug. It describes the problem encountered or some after effect of some kind.**
### Preconditions
**Please provide as detailed information about your environment as possible.**
**Please provide as detailed information about your environment as possible.**
1. framework Version.
2. Commit id.
### Steps to reproduce
**It is important to provide a set of clear steps to reproduce this bug.If relevant please include code samples.**
**It is important to provide a set of clear steps to reproduce this bug.If relevant please include code samples.**
1. step1
2. step2
### Expected result
**Tell us what should happen.**
* [Screenshots, logs or description]
**Tell us what should happen.**
* [Screenshots, logs or description]
### Actual result
**Tell us what happens instead.**
* [Tell us what happens instead]
> **Tell us what happens instead.**
* [points....]

View File

@ -3,10 +3,15 @@ name: "💡 Feature Request"
about: 'For ideas or feature requests, please make a pull request, or open an issue'
---
This repository is only for reporting bugs or issues. If you need support, please use the forums:
This repository is only for reporting bugs or issues. If you need support, please use
other channels:
- https://forums.bagisto.com/
1. Write an email - mailto:support@bagisto.com
2. Create support ticket on https://bagisto.uvdesk.com
3. Visit forums to get support from our community (https://forums.bagisto.com)
Alternatively, you may use Facebook (https://www.facebook.com/groups/bagisto/).
We promise that more channels are coming soon!!!
We promise that more channels are coming soon!!!

View File

@ -6,10 +6,6 @@ about: 'This repository is only for reporting bugs or problems. If you need help
This repository is only for reporting bugs or issues. If you need support, please use:
1. Write an email - mailto:support@bagisto.com
2. Create support ticket on https://bagisto.uvdesk.com
3. Visit forums to get support from our community (https://forums.bagisto.com)
1. Create support ticket on https://bagisto.uvdesk.com
Thanks!

View File

@ -1,13 +1,11 @@
**BUGS:**
Please describe the issue that you solved if its not filed. Otherwise please mention issue #id and use comma
if your PR is having multiple fixes.
>Please describe the issue that you solved if its not filed.
**Core development ideas or discussion:**
>Otherwise please mention issue #id and use comma if your PR
>solves multiple issues.
Describe the feature in very short lines word usage limit is 200. Otherwise use **issue #id** if the issue was
filed as **feature** request.
**For things other than bugs:**
**Which branch you should target?**
You should fork the Bagisto repository and push your local changes to your own **development** branch. And after you are done then generate from your **development** branch to Bagisto's **master** branch. Use branches other than **master** if you are fixing any backward compatible issue.
> Describe that thing in very short line, word limit is 200.
> Otherwise use **issue #id** if the issue was filed as **feature** request.

View File

@ -193,13 +193,15 @@ return [
'route' => 'admin.cart-rule.index',
'sort' => 1,
'icon-class' => ''
], [
'key' => 'promotions.catalog-rule',
'name' => 'admin::app.promotion.catalog-rule',
'route' => 'admin.catalog-rule.index',
'sort' => 1,
'icon-class' => '',
], [
],
// , [
// 'key' => 'promotions.catalog-rule',
// 'name' => 'admin::app.promotion.catalog-rule',
// 'route' => 'admin.catalog-rule.index',
// 'sort' => 1,
// 'icon-class' => '',
// ],
[
'key' => 'cms',
'name' => 'admin::app.layouts.cms',
'route' => 'admin.cms.index',

View File

@ -57,7 +57,7 @@ class CartItem extends Model implements CartItemContract
}
/**
* Get the children items.
* Get the item childrens.
*/
public function children()
{

View File

@ -1,38 +0,0 @@
<?php
namespace Webkul\Discount\Actions;
abstract class Action
{
abstract public function calculate($rule);
public function getEligibleItems($rule)
{
$cart = \Cart::getCart();
$items = $cart->items;
$matchedItems = collect();
$productIDs = $rule->product_ids;
$productIDs = explode(',', $productIDs);
$matchCriteria = $rule->uses_attribute_conditions ? $rule->product_ids : '*';
if ($matchCriteria == '*') {
return $items;
} else {
$matchingIDs = explode(',', $matchCriteria);
foreach ($items as $item) {
foreach ($matchingIDs as $matchingID) {
if ($matchingID == ($item->child ? $item->child->product_id : $item->product_id)) {
$matchedItems->push($item);
}
}
}
return $matchedItems;
}
}
}

View File

@ -0,0 +1,112 @@
<?php
namespace Webkul\Discount\Actions\Cart;
abstract class Action
{
/**
* To hold the current rule
*/
protected $rule;
abstract public function calculate($rule);
/**
* Empty collection instance for keeping final list of items
*/
protected $matchedItems;
public function __construct()
{
/**
* Making $matchedItems property empty collection instance.
*/
$this->matchedItems = collect();
}
/**
* To find the eligble items for the current rule,
*
* @param CartRule $rule
*
* @return Collection $matchedItems
*/
public function getEligibleItems($rule)
{
$cart = \Cart::getCart();
$items = $cart->items()->get();
$productIDs = $rule->product_ids;
$productIDs = explode(',', $productIDs);
$matchCriteria = $rule->uses_attribute_conditions ? $rule->product_ids : '*';
if ($matchCriteria == '*') {
$this->matchedItems = $items;
return $this->matchedItems;
} else {
$matchingIDs = explode(',', $matchCriteria);
foreach ($items as $item) {
foreach ($matchingIDs as $matchingID) {
$childrens = collect();
$childrens = $item->children;
foreach ($childrens as $children) {
if ($children->product_id == $matchingID) {
$this->pushItem($children);
}
}
if ($item->product_id == $matchingID) {
$this->pushItem($item);
}
}
}
return $this->matchedItems;
}
}
/**
* To check the items applicability
*/
public function checkApplicability()
{
$rule = $this->rule;
$eligibleItems = $this->getEligibleItems($rule);
$apply = function () use($rule, $eligibleItems) {
if ($rule->action_type == 'percent_of_product') {
return true;
} else {
if ($rule->action_type == 'whole_cart_to_percent' && $rule->uses_attribute_condition) {
$matchIDs = explode(',', $rule->product_ids);
foreach ($matchIDs as $matchID) {
foreach ($eligibleItems as $item) {
if (($item->child ? $item->child->product_id : $item->product_id) == $matchID) {
return true;
}
}
}
return false;
} else {
return true;
}
}
};
return $apply();
}
private function pushItem($item) {
$this->matchedItems->push($item);
}
}

View File

@ -2,47 +2,36 @@
namespace Webkul\Discount\Actions\Cart;
use Webkul\Discount\Actions\Action;
use Webkul\Discount\Actions\Cart\Action;
class FixedAmount extends Action
{
public function calculate($rule)
{
/**
* Setting the rule getting applied
*/
$this->rule = $rule;
$impact = collect();
$totalDiscount = 0;
$eligibleItems = $this->getEligibleItems($rule);
$applicability = $this->checkApplicability();
$apply = function () use ($rule, $eligibleItems) {
if ($rule->action_type == 'fixed_amount') {
return true;
} else {
if ($rule->action_type == 'whole_cart_to_fixed' && $rule->uses_attribute_condition) {
$matchIDs = explode(',', $rule->product_ids);
if ($applicability) {
// if ($rule->action_type == 'whole_cart_to_fixed') {
// $eligibleItems = \Cart::getCart()->items;
// }
foreach ($matchIDs as $matchID) {
foreach ($eligibleItems as $item) {
if (($item->child ? $item->child->product_id : $item->product_id) == $matchID) {
return true;
}
}
}
return false;
} else {
return true;
}
}
};
if ($apply()) {
if ($rule->action_type == 'whole_cart_to_fixed')
{
$eligibleItems = \Cart::getCart()->items;
}
$eligibleItems = \Cart::getCart()->items;
foreach ($eligibleItems as $item) {
$report = array();
$report['item_id'] = $item->id;
$report['child_items'] = collect();
$itemPrice = $item->base_price;
$itemQuantity = $item->quantity;
@ -51,10 +40,6 @@ class FixedAmount extends Action
$discQuantity = $itemQuantity <= $discQuantity ? $itemQuantity : $discQuantity;
$report = array();
$report['item_id'] = $item->id;
if ($item->product->getTypeInstance()->isComposite()) {
$isQtyZero = true;
@ -65,24 +50,26 @@ class FixedAmount extends Action
}
if ($isQtyZero) {
// case for configurable products
$report['product_id'] = $item->children->first()->product_id;
$report['child_items'] = collect();
} else {
// composites other than configurable
$report['product_id'] = $item->product_id;
$report['child_items'] = collect();
foreach ($item->children as $children) {
$children->discount = $rule->disc_amount;
$childBaseTotal = $children->base_total;
$itemDiscount = $childBaseTotal / (\Cart::getCart()->base_sub_total / 100);
$children->discount = ($itemDiscount / 100) * $rule->disc_amount;
$children->discount = $children->base_total > $children->discount ? $children->discount : $children->base_total;
$report['child_items']->push($children);
}
}
} else {
$report['product_id'] = $item->product_id;
$report['child_items'] = collect();
}
$discount = round($rule->disc_amount, 4) * $discQuantity;

View File

@ -2,7 +2,7 @@
namespace Webkul\Discount\Actions\Cart;
use Webkul\Discount\Actions\Action;
use Webkul\Discount\Actions\Cart\Action;
class PercentOfProduct extends Action
{
@ -15,51 +15,49 @@ class PercentOfProduct extends Action
*/
public function calculate($rule)
{
/**
* Setting the rule getting applied
*/
$this->rule = $rule;
$impact = collect();
$totalDiscount = 0;
$eligibleItems = $this->getEligibleItems($rule);
$applicability = $this->checkApplicability();
$apply = function () use($rule, $eligibleItems) {
if ($rule->action_type == 'percent_of_product') {
return true;
} else {
if ($rule->action_type == 'whole_cart_to_percent' && $rule->uses_attribute_condition) {
$matchIDs = explode(',', $rule->product_ids);
foreach ($matchIDs as $matchID) {
foreach ($eligibleItems as $item) {
if (($item->child ? $item->child->product_id : $item->product_id) == $matchID) {
return true;
}
}
}
return false;
} else {
return true;
}
}
};
if ($apply()) {
if ($rule->action_type == 'whole_cart_to_percent') {
if ($applicability) {
if ($this->rule->action_type == 'whole_cart_to_percent') {
$eligibleItems = \Cart::getCart()->items;
}
$cart = \Cart::getCart();
$eligibleItems = $cart->items;
foreach ($eligibleItems as $item) {
$report = array();
$report['item_id'] = $item->id;
$report['child_items'] = collect();
$itemPrice = $item->base_price;
$itemQuantity = $item->quantity;
$discQuantity = $rule->disc_quantity;
$discQuantity = $this->rule->disc_quantity;
$discQuantity = $itemQuantity <= $discQuantity ? $itemQuantity : $discQuantity;
$report = array();
if ($this->rule->disc_amount > 100) {
$discount_amount = 100;
} else {
$discount_amount = $this->rule->disc_amount;
}
$report['item_id'] = $item->id;
$discount = $itemPrice * ($discount_amount / 100) * $discQuantity;
$discount = $discount <= $itemPrice * $discQuantity ? $discount : $itemPrice * $discQuantity;
if ($item->product->getTypeInstance()->isComposite()) {
$isQtyZero = true;
@ -71,16 +69,18 @@ class PercentOfProduct extends Action
}
if ($isQtyZero) {
// case for configurable products
$report['product_id'] = $item->children->first()->product_id;
$report['child_items'] = collect();
} else {
// composites other than configurable
$report['product_id'] = $item->product_id;
$report['child_items'] = collect();
foreach ($item->children as $children) {
$children->discount = $children->base_total * ($rule->disc_amount / 100);
$childBaseTotal = $children->base_total;
$itemDiscount = $childBaseTotal / (\Cart::getCart()->base_sub_total / 100);
$children->discount = ($itemDiscount / 100) * ($cart->base_sub_total * ($this->rule->disc_amount / 100));
$children->discount = $children->base_total > $children->discount ? $children->discount : $children->base_total;
@ -89,20 +89,8 @@ class PercentOfProduct extends Action
}
} else {
$report['product_id'] = $item->product_id;
$report['child_items'] = collect();
}
if ($rule->disc_amount > 100) {
$discount_amount = 100;
} else {
$discount_amount = $rule->disc_amount;
}
$discount = $itemPrice * ($discount_amount / 100) * $discQuantity;
$discount = $discount <= $itemPrice * $discQuantity ? $discount : $itemPrice * $discQuantity;
$report['discount'] = $discount;
$report['formatted_discount'] = core()->currency($discount);

View File

@ -2,7 +2,7 @@
namespace Webkul\Discount\Actions\Cart;
use Webkul\Discount\Actions\Cart\FixedAmount;
use Webkul\Discount\Actions\Cart\Cart\FixedAmount;
class WholeCartToFixed
{

View File

@ -2,7 +2,7 @@
namespace Webkul\Discount\Actions\Cart;
use Webkul\Discount\Actions\Cart\PercentOfProduct;
use Webkul\Discount\Actions\Cart\Cart\PercentOfProduct;
class WholeCartToPercent
{

View File

@ -3,11 +3,11 @@
namespace Webkul\Discount\Helpers\Cart;
use Webkul\Discount\Repositories\CartRuleRepository as CartRule;
use Webkul\Attribute\Repositories\AttributeRepository as Attribute;
use Webkul\Attribute\Repositories\AttributeOptionRepository as AttributeOption;
use Webkul\Attribute\Repositories\AttributeRepository;
use Webkul\Attribute\Repositories\AttributeOptionRepository;
use Webkul\Category\Repositories\CategoryRepository as Category;
use Webkul\Product\Repositories\ProductRepository as Product;
use Webkul\Product\Models\ProductAttributeValue as ProductAttributeValue;
use Webkul\Product\Models\ProductAttributeValue;
class ConvertXToProductId
{
@ -29,7 +29,7 @@ class ConvertXToProductId
/**
* AttributeOptionRepository instance
*/
protected $attributeOption;
protected $attributeOptionRepository;
/**
* CartRuleRepository instance
@ -41,11 +41,6 @@ class ConvertXToProductId
*/
protected $pav;
/**
* Ignorable type from convertX
*/
protected $ignorables;
/**
* Condition symbols for matching the criteria with attributes selected
*/
@ -53,27 +48,25 @@ class ConvertXToProductId
public function __construct(
Category $category,
Attribute $attribute,
AttributeRepository $attributeRepository,
Product $product,
AttributeOption $attributeOption,
AttributeOptionRepository $attributeOptionRepository,
CartRule $cartRule,
ProductAttributeValue $pav
)
{
$this->category = $category;
$this->attribute = $attribute;
$this->attribute = $attributeRepository;
$this->product = $product;
$this->attributeOption = $attributeOption;
$this->attributeOptionRepository = $attributeOptionRepository;
$this->cartRule = $cartRule;
$this->pav = $pav;
$this->ignorable = ['configurable', 'group'];
$this->conditionSymbols = config('pricerules.cart.conditions.symbols');
}
@ -133,7 +126,7 @@ class ConvertXToProductId
foreach ($attributeOptions as $attributeOption) {
$selectedOptions = $attributeOption->value;
if (isset($attributeOption->type) && ($attributeOption->type == 'select' || $attributeOption->type == 'multiselect')) {
if ($attributeOption->type == 'select' || $attributeOption->type == 'multiselect') {
$attribute = $this->attribute->findWhere([
'code' => $attributeOption->attribute
]);
@ -180,19 +173,14 @@ class ConvertXToProductId
if ($testCondition == '{}') {
$foundProducts = $this->product->findWhere([
['sku', 'like', '%'.$testValue.'%'],
['type', '!=', 'configurable'],
['type', '!=', 'group']
])->flatten()->all();
} else if ($testCondition == '!{}') {
$foundProducts = $this->product->findWhere([
['sku', 'not like', '%'.$testValue.'%'],
['type', '!=', 'configurable'],
['type', '!=', 'group']
])->flatten()->all();
} else if ($testCondition == '=') {
$foundProducts = $this->product->findWhere([
['sku', '=', $testValue],
['type', '!=', 'configurable']
])->flatten()->all();
}
}
@ -284,33 +272,34 @@ class ConvertXToProductId
*/
public function getAll($categoryId = null)
{
$results = app('Webkul\Product\Repositories\ProductFlatRepository')->scopeQuery(function($query) use ($categoryId) {
$results = app('Webkul\Product\Repositories\ProductFlatRepository')->scopeQuery(function($query) use($categoryId) {
$channel = request()->get('channel') ?: (core()->getCurrentChannelCode() ?: core()->getDefaultChannelCode());
$locale = request()->get('locale') ?: app()->getLocale();
$qb = $query->distinct()
->select('products.id')
->addSelect('product_flat.*')
->leftJoin('products', 'product_flat.product_id', '=', 'products.id')
->leftJoin('product_categories', 'products.id', '=', 'product_categories.product_id')
->where('products.type', '!=', 'configurable')
->where('products.type', '!=', 'group')
->where('product_flat.channel', $channel)
->where('product_flat.locale', $locale)
->whereNotNull('product_flat.url_key');
if ($categoryId) {
if ($categoryId)
$qb->where('product_categories.category_id', $categoryId);
}
$qb->where('product_flat.status', 1);
$qb->where('product_flat.status', 1);
$qb->where('product_flat.visible_individually', 1);
$qb->where('product_flat.visible_individually', 1);
$queryBuilder = $qb->leftJoin('product_flat as flat_variants', function($qb) use($channel, $locale) {
$qb->on('product_flat.id', '=', 'flat_variants.parent_id');
$qb->on('product_flat.id', '=', 'flat_variants.parent_id')
->where('flat_variants.channel', $channel)
->where('flat_variants.locale', $locale);
});
$qb = $qb->leftJoin('products as variants', 'products.id', '=', 'variants.parent_id');
return $qb->groupBy('product_flat.id');
})->get();

View File

@ -35,6 +35,11 @@ abstract class Discount
*/
protected $cartItem;
/**
* To set the percentage columns or not
*/
protected $setPercentages;
public function __construct(CartRule $cartRule, CartRuleCart $cartRuleCart, CartItem $cartItem)
{
$this->cartRule = $cartRule;
@ -588,9 +593,13 @@ abstract class Discount
$item = $this->cartItem->findOneWhere(['id' => $itemImpact['item_id']]);
if (isset($itemImpact['child_items']) && $itemImpact['child_items']->count()) {
$totalItemDiscount = 0.0000;
foreach ($itemImpact['child_items'] as $child) {
$discount = $child->discount;
$totalItemDiscount = $totalItemDiscount + $discount;
unset($child->discount);
$child->update([
@ -611,6 +620,8 @@ abstract class Discount
'coupon_code' => $coupon
]);
}
$this->updateParent($child, $totalItemDiscount, $cartCurrencyCode = $cart->cart_currency_code);
}
} else {
$item->update([
@ -649,6 +660,19 @@ abstract class Discount
return true;
}
/**
* To update the discount on parent CartItem
*/
private function updateParent($item, $discount, $currencyCode)
{
$parentItem = $this->cartItem->findOneWhere(['id' => $item->parent_id]);
$parentItem->update([
'base_discount_amount' => $discount,
'discount_amount' => core()->convertPrice($discount, $currencyCode)
]);
}
/**
* Removes any cart rule from the current cart instance
*

View File

@ -24,8 +24,8 @@ class NonCouponAbleRule extends Discount
$canApply = $this->canApply($rule);
if ($canApply) {
$this->save($rule);
if ($canApply && isset($rule->impact)) {
$result = $this->save($rule);
$this->updateCartItemAndCart($rule);
}

View File

@ -166,7 +166,7 @@ class ProductRepository extends Repository
];
foreach($aliases as $table => $alias) {
$query1 = $query1->orWhere(function($query2) use($qb, $table, $alias) {
$query1 = $query1->orWhere(function($query2) use ($qb, $table, $alias) {
foreach ($this->attributeRepository->getProductDefaultAttributes(array_keys(request()->input())) as $code => $attribute) {
$aliasTemp = $alias . $attribute->code;

View File

@ -91,7 +91,7 @@ class OnepageController extends Controller
if (! auth()->guard('customer')->check() && $cart->haveDownloadableItems())
return redirect()->route('customer.session.index');
//$this->nonCoupon->apply();
$this->nonCoupon->apply();
Cart::collectTotals();

View File

@ -448,11 +448,11 @@ h5 {
vertical-align: top;
&.actions {
.action {
display: inline-flex;
}
.icon {
cursor: pointer;
vertical-align: middle;
@ -986,7 +986,7 @@ modal {
animation: fade-in-white 0.3s ease-in-out;
animation: jelly 0.5s ease-in-out;
@include border-radius(5px);
overflow-y: scroll;
overflow-y: auto;
max-height: 80%;
.modal-header {