0

As per my requirement am creating the cart rule programmatically, for that i am reviewed the following code and implemented in my local

public function createRule()
{
    $price = 100;
    $sku = '24-WG085';
    $discount = ($price - (($price + 1) / 2));
    $shoppingCartPriceRule = $this->ruleFactory->create();

    $shoppingCartPriceRule->setName('Add a second for $1 - ' . $sku)
        ->setDescription('Buy one item at regular price, and receive a second item for just $1.00 more!')
        ->setFromDate('2000-01-01')
        ->setToDate(NULL)
        ->setUsesPerCustomer('0')
        ->setCustomerGroupIds(array('0','1','2','3',))
        ->setIsActive('1')
        ->setStopRulesProcessing('0')
        ->setIsAdvanced('1')
        ->setProductIds(NULL)
        ->setSortOrder('1')
        ->setSimpleAction('by_fixed')
        ->setDiscountAmount($discount)
        ->setDiscountQty(NULL)
        ->setDiscountStep('0')
        ->setSimpleFreeShipping('0')
        ->setApplyToShipping('0')
        ->setTimesUsed('0')
        ->setIsRss('0')
        ->setWebsiteIds(array('1',))
        ->setCouponType('1')
        ->setCouponCode(NULL)
        ->setUsesPerCoupon(NULL);

    $item_found = $this->foundProductRuleFactory->create()
        ->setType('Magento\SalesRule\Model\Rule\Condition\Product\Found')
        ->setValue(1) // 1 == FOUND
        ->setAggregator('all'); // match ALL conditions
    $shoppingCartPriceRule->getConditions()->addCondition($item_found);

    $conditions = $this->productRuleFactory->create()
        ->setType('Magento\SalesRule\Model\Rule\Condition\Product')
        ->setAttribute('sku')
        ->setOperator('==')
        ->setValue($sku);
    $item_found->addCondition($conditions);

    $actions = $this->productRuleFactory->create()
        ->setType('Magento\SalesRule\Model\Rule\Condition\Product')
        ->setAttribute('sku')
        ->setOperator('==')
        ->setValue($sku);
    $shoppingCartPriceRule->getActions()->addCondition($actions);

    $this->ruleResource->save($shoppingCartPriceRule);
}

But, when i execute the code i am getting the 'Uncaught Error: Call to a member function setOperator() on null.

I am not sure what is the exact problem in that setOperator, the following operators are available in core

$this->setOperatorOption(
            [
                '==' => __('is'),
                '!=' => __('is not'),
                '>=' => __('equals or greater than'),
                '<=' => __('equals or less than'),
                '>' => __('greater than'),
                '<' => __('less than'),
                '()' => __('is one of'),
                '!()' => __('is not one of'),
            ]
        );

Thanks in advance for your support and suggestion

1
  • can you provide use statement of "foundProductRuleFactory" and "productRuleFactory" for example use Magento\SalesRule\Model\Rule\Condition\Product\Found; Commented Jun 17, 2021 at 7:45

3 Answers 3

3

I got the answer for my question, instead of setAttribute i tried to setData('attribute','sku') it's working fine.

$conditions = $this->_productRuleFactory->create()
                    ->setType('Magento\SalesRule\Model\Rule\Condition\Product')
                    ->setData('attribute','sku')
                    ->setData('operator','()')
                    ->setValue($requestedParameters['SKU']);
$item_found->addCondition($conditions);
0
1

This solution was the best for me. Just try to create rule in admin pannel and after that find it in salesrule table. There you can see "conditions_serialized" column and there will be different classes. In my case it was something like this

{"type":"Magento\\SalesRule\\Model\\Rule\\Condition\\Combine","attribute":null,"operator":null,"value":"1","is_value_processed":null,"aggregator":"all","conditions":
    [
    {"type":"Magento\\SalesRule\\Model\\Rule\\Condition\\Address","attribute":"base_subtotal_with_discount","operator":">=","value":0,"is_value_processed":false},
    {"type":"Magento\\SalesRule\\Model\\Rule\\Condition\\Address","attribute":"base_subtotal_with_discount","operator":"<=","value":600,"is_value_processed":false}

]}

Take these classes and include them into your code. Watch for the structure nesting.

use Magento\Customer\Model\GroupManagement;
use Magento\SalesRule\Model\Rule\Condition\Address;
use Magento\SalesRule\Model\Rule\Condition\Combine;
use Magento\SalesRule\Model\RuleFactory;
use Magento\Customer\Model\ResourceModel\Group\Collection;

public function createRules()
{    
     /*$this->customerGroupColl is instance of 
       Magento\Customer\Model\ResourceModel\Group\Collection*/
    $customerGroups = $this->customerGroupColl->toOptionArray();
    
    /*"$this->ruleFactory" is 
      Magento\SalesRule\Model\RuleFactory instance;*/
    $salesRule = $this->ruleFactory->create();

    // General rule data
    $salesRule->setData(
        [
            'name' => 'some rule name',
            'description' => 'some rule description',
            'is_active' => 1,
            'customer_group_ids' => array_keys($customerGroups), //[0,1,2...]
            'coupon_type' => Magento\SalesRule\Model\Rule::COUPON_TYPE_NO_COUPON,
            'simple_action' => Magento\SalesRule\Model\Rule::BY_PERCENT_ACTION,
            'discount_amount' => 50,
            'discount_step' => 0,
            'stop_rules_processing' => 0,
            'website_ids' => [
                1, 2
            ],
            'store_labels' => [
                0 => 'Label for store with Id=0',
                1 => 'Label for store with Id=1'
            ]
    ]);

    /*including conditions. The required classes for type keys can be found in 
       "conditions_serialized" column*/
    $salesRule->getConditions()->loadArray(
        [
            'type' => Combine::class,
            'attribute' => null,
            'operator' => null,
            'value' => '1',
            'is_value_processed' => null,
            'aggregator' => 'all',
            'conditions' => [
                    [
                        'type' => Address::class,
                        'attribute' => 'base_subtotal_with_discount',
                        'operator' => '>=',
                        'value' => 0,
                        'is_value_processed' => false,
                    ],
                    [
                        'type' => Address::class,
                        'attribute' => 'base_subtotal_with_discount',
                        'operator' => '<=',
                        'value' => 600,
                        'is_value_processed' => false,
                    ]
            ],
        ]
    );

    $salesRule->save();
}
0

I have written this code and it working fine.


    /**
     * Create a cart rule.
     *
     * @param $customerId
     * @param $subscriptionCode
     * @param $amount
     * @param string $description
     * @throws InputException
     * @throws LocalizedException
     * @throws NoSuchEntityException
     */
    public function createCartRule($customerId, $subscriptionCode, $amount, $description = '')
    {
        $customer = $this->customerFactory->create()->load($customerId);
        $newRule = $this->rule->create();
        $newRule->setName(__('discount for subscription: %1', $subscriptionCode))
            ->setDescription($description)
            ->setIsAdvanced(true)
            ->setStopRulesProcessing(true)
            ->setDiscountQty(1)
            ->setCustomerGroupIds([$customer->getGroupId()])
            ->setWebsiteIds([$customer->getWebsiteId()])
            ->setIsRss(false)
            ->setUsesPerCoupon(1)
            ->setUsesPerCustomer(1)
            ->setDiscountStep(1)
            ->setCouponType(RuleInterface::COUPON_TYPE_SPECIFIC_COUPON)
            ->setSimpleAction(RuleInterface::DISCOUNT_ACTION_FIXED_AMOUNT_FOR_CART)
            ->setDiscountAmount($amount)
            ->setIsActive(true)
            ->setCondition($this->condition->create()
                ->setConditionType(Combine::class)
                ->setAggregatorType('all')
                ->setValue('1')
                ->setConditions([
                    0 => $this->condition->create()
                        ->setConditionType(CustomerAttributes::class)
                        ->setAttributeName('id')
                        ->setOperator('==')
                        ->setValue($customerId)
                ])
            );
        try {
            $ruleCreate = $this->ruleRepository->save($newRule);
            //If rule generated, Create new Coupon by rule id
            if ($ruleCreate->getRuleId()) {
                $this->createCoupon($ruleCreate->getRuleId(), $subscriptionCode."-".$this->helperData->generateCode());
            }
        } catch (Exception $exception) {
            $this->logger->error($exception->getMessage());
        }
    }

Used classes.

use Magento\SalesRule\Api\Data\ConditionInterface;
use Magento\SalesRule\Api\Data\CouponInterface;
use Magento\SalesRule\Api\Data\RuleInterface;
use Magento\SalesRule\Api\Data\RuleInterfaceFactory;
use Magento\SalesRule\Api\Data\ConditionInterfaceFactory;
use Magento\SalesRule\Model\Rule\Condition\Combine;
use Amasty\Conditions\Model\Rule\Condition\CustomerAttributes;
use Magento\SalesRule\Api\RuleRepositoryInterface;

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.