cancel
Showing results for 
Search instead for 
Did you mean: 

Magento 2 Error while canceling the order

Magento 2 Error while canceling the order

I'm facing the below error while canceling the order

SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails (`magentodb`.`salesrule_customer`, CONSTRAINT `SALESRULE_CUSTOMER_RULE_ID_SALESRULE_RULE_ID` FOREIGN KEY (`rule_id`) REFERENCES `salesrule` (`rule_id`) ON DELETE CASCADE), query was: INSERT INTO `salesrule_customer` () VALUES ()

I found this solution https://github.com/magento/magento2/issues/16779 According to this reference I made direct changes in vendor/magento/module-sales-rule/Model/Coupon/Usage/Processor.php file of this updateCustomerRuleUsages() then an error is gone

I tried the same thing by overriding the class Magento\SalesRule\Model\Coupon\Usage\Processor it shows the error

You have not canceled the item.

Myvendor\Mymodule\Model\Coupon\Usage\Processor.php

<?php
/**
 * Copyright © Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */
declare(strict_types=1);

namespace Myvendor\Mymodule\Model\Coupon\Usage;

use Magento\SalesRule\Model\Coupon;
use Magento\SalesRule\Model\ResourceModel\Coupon\Usage;
use Magento\SalesRule\Model\Rule\CustomerFactory;
use Magento\SalesRule\Model\RuleFactory;

/**
 * Processor to update coupon usage
 */
class Processor extends \Magento\SalesRule\Model\Coupon\Usage\Processor
{
    /**
     * @var RuleFactory
     */
    private $ruleFactory;

    /**
     * @var RuleFactory
     */
    private $ruleCustomerFactory;

    /**
     * @var Coupon
     */
    private $coupon;

    /**
     * @var Usage
     */
    private $couponUsage;

    /**
     * @param RuleFactory $ruleFactory
     * @param CustomerFactory $ruleCustomerFactory
     * @param Coupon $coupon
     * @param Usage $couponUsage
     */
    public function __construct(        RuleFactory $ruleFactory,
        CustomerFactory $ruleCustomerFactory,
        Coupon $coupon,
        Usage $couponUsage
    ) {
        $this->ruleFactory = $ruleFactory;
        $this->ruleCustomerFactory = $ruleCustomerFactory;
        $this->coupon = $coupon;
        $this->couponUsage = $couponUsage;
        parent::__construct($ruleFactory,$ruleCustomerFactory, $coupon, $couponUsage);
    }

    /**
     * Update the number of rule usages per customer
     *
     * @param bool $isIncrement
     * @param int $ruleId
     * @param int $customerId
     */
    private function updateCustomerRuleUsages(bool $increment, int $ruleId, int $customerId)
    {
        /** @var \Magento\SalesRule\Model\Rule\Customer $ruleCustomer */
        $ruleCustomer = $this->ruleCustomerFactory->create();
        $ruleCustomer->loadByCustomerRule($customerId, $ruleId);
        
        if ($ruleCustomer->getId()) {
            if ($increment || $ruleCustomer->getTimesUsed() > 0) {
                $ruleCustomer->setTimesUsed($ruleCustomer->getTimesUsed() + ($increment ? 1 : -1));
                $ruleCustomer->save(); //ADD SAVE METHOD WITHIN THE CONDITION
            }
        } elseif ($increment) {
            $ruleCustomer->setCustomerId($customerId)->setRuleId($ruleId)->setTimesUsed(1);
            $ruleCustomer->save(); //ADD SAVE METHOD WITHIN THE CONDITION
        }
        //$ruleCustomer->save(); //REMOVE SAVE METHOD
    }
}

In that reference, there is a comment quoting

"I just made the change in the base code(I know, bad), but you could potentially use a plugin to jump into the $ruleCustomer->save() and prevent the save from happening. This is a bit clunky though because save() is on the AbstractModel class used by all kinds of things."

I'm wondering if we can write a plugin for $ruleCustomer->save(). Please Let me know if anyone has any ideas.