You could just use Mage::app()->getStore()->isAdmin()
within the logic where the coupon validity is checked.
You could do it in
Checkout/controllers/CartController.php couponPostAction()
SalesRule/Model/Validator.php _canProcessRule()
The latter would probably be preferred, you could just extend the class and add a conditional statement and return false.
Then add an attribute to the coupon model for whether it can be used in the frontend or not.
Eg.
protected function _canProcessRule($rule, $address)
{
...
if ( Mage::app()->getStore()->isAdmin() && $rule->hasAdminOnly() ) {
return false;
}
The above is just pseudo(ish) code, correct to suit your needs.
Thanks @R.S. . I found the solution by referring repo created by @R.S. here: https://github.com/magepal/stackexchange/tree/develop/104112 after some minor modifications.
sales.xml
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Sales:etc/sales.xsd">
<section name="quote">
<group name="totals">
<item name="testdiscount" instance="MagePal\TestDiscount\Model\Quote\Discount" sort_order="500"/>
</group>
</section>
</config>
Model file
public function collect(
\Magento\Quote\Model\Quote $quote,
\Magento\Quote\Api\Data\ShippingAssignmentInterface $shippingAssignment,
\Magento\Quote\Model\Quote\Address\Total $total
) {
//Fix for discount applied twice
$items = $shippingAssignment->getItems();
if (!count($items)) {
return $this;
}
parent::collect($quote, $shippingAssignment, $total);
//$address = $shippingAssignment->getShipping()->getAddress();
$label = 'My Custom Discount';
$discountAmount = -10;
$appliedCartDiscount = 0;
if($total->getDiscountDescription()) {
// If a discount exists in cart and another discount is applied, the add both discounts.
$appliedCartDiscount = $total->getDiscountAmount();
$discountAmount = $total->getDiscountAmount()+$discountAmount;
$label = $total->getDiscountDescription().', '.$label;
}
$total->setDiscountDescription($label);
$total->setDiscountAmount($discountAmount);
$total->setBaseDiscountAmount($discountAmount);
$total->setSubtotalWithDiscount($total->getSubtotal() + $discountAmount);
$total->setBaseSubtotalWithDiscount($total->getBaseSubtotal() + $discountAmount);
if(isset($appliedCartDiscount)) {
$total->addTotalAmount($this->getCode(), $discountAmount - $appliedCartDiscount);
$total->addBaseTotalAmount($this->getCode(), $discountAmount - $appliedCartDiscount);
} else {
$total->addTotalAmount($this->getCode(), $discountAmount);
$total->addBaseTotalAmount($this->getCode(), $discountAmount);
}
return $this;
}
checkout_cart_index.xml
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
<body>
<referenceBlock name="checkout.cart.totals">
<arguments>
<argument name="jsLayout" xsi:type="array">
<item name="components" xsi:type="array">
<item name="block-totals" xsi:type="array">
<item name="children" xsi:type="array">
<item name="before_grandtotal" xsi:type="array">
<item name="children" xsi:type="array">
<item name="testdiscount" xsi:type="array">
<item name="config" xsi:type="array">
<item name="title" xsi:type="string" translate="true">My Discount</item>
</item>
</item>
</item>
</item>
</item>
</item>
</item>
</argument>
</arguments>
</referenceBlock>
</body>
</page>
checkout_index_index.xml
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="1column" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
<body>
<referenceBlock name="checkout.root">
<arguments>
<argument name="jsLayout" xsi:type="array">
<item name="components" xsi:type="array">
<item name="checkout" xsi:type="array">
<item name="children" xsi:type="array">
<item name="sidebar" xsi:type="array">
<item name="children" xsi:type="array">
<item name="summary" xsi:type="array">
<item name="children" xsi:type="array">
<item name="totals" xsi:type="array">
<item name="children" xsi:type="array">
<item name="testdiscount" xsi:type="array">
<item name="config" xsi:type="array">
<item name="title" xsi:type="string" translate="true">My Discount</item>
</item>
</item>
</item>
</item>
</item>
</item>
</item>
</item>
</item>
</item>
</item>
</argument>
</arguments>
</referenceBlock>
</body>
</page>
Fetch is not showing the custom discount description. I have opened its ticket here: https://github.com/magento/magento2/issues/3594
Best Answer
Admin panel -> Marketing -> Cart Sales Rules.
When you expand the “Conditions” tab, you’ll be able to set when a given discount applies. For example, you can select the cart value option and this way specify that: If the cart value is greater than 50 – the discount should be applied.
However, the default options don’t cover all possible situations. Let’s imagine that we want to reward our client for the dedication he put in creating an account in our store. We have the following scenario: If this is a first order of a given client – the discount should be applied.
Unfortunately, Magento doesn’t offer this option out-of-the-box
Custom Cart Sales Rule Conditions
we will focus on extending the available discount conditions. To understand how the available conditions are collected, you need to look into the Magento\SalesRule\Model\Rule\Condition\Combine class, more specifically into the getNewChildSelectOptions() method. You’ll notice that after the default conditions, the salesrule_rule_condition_combine event is dispatched and then the collected conditions are combined.
As usual, we will start with creating the foundations of our module:
Next, we will create an observer that will add our condition:
What happens in the observer? We’re fetching other conditions, for example the ones added in other observers, and merge them with ours. As you can see, one condition consists of a name and a value which means that it includes our class that will handle the condition.
Now, we can move on to the logic responsible for our condition:
We load the Yesno model in the constructor of our logic that is mainly used as a source_model in the backend. We’ll fetch from it the available values for our select fields. Moreover, we load the factory of order collection that we will use for validating the condition correctness. We need to set the name and label of our condition in the loadAttributeOptions() method. getInputType() defines what will be displayed as an operator for comparing our attribute – the returned select field will allow us to choose “is” or “is not”. Returning a numeric value here would allow you to select available operators for comparing numbers, such as “greater than” or “less than”. getValueElementType() defines the type of the value with which we will compare our values. The returned select will render the field with available options, which we will define in getValueSelectOptions().
In case we don’t want to define imposed values, we can return text – an input with the option to write a given value will then be displayed (using numeric value and text would allow you to create a condition “if the number of customer’s orders is greater than X – apply the discount”).
The last method is validate() that we use to check whether the customer has other orders placed with his account, and then we can set the value that will be compared with the one we previously defined.
Now, we only need to create a discount with our condition
Originally posted on Magently: https://magently.com/blog/magento-2-custom-sales-rule-condition/