0

I am trying to create afterSetValidationFilter plugin for the Magento Sales Rule collection for implementing multiple coupon code option.

Core file I want to override Magento\SalesRule\Model\ResourceModel\Rule\Collection.php

here is my di.xml

<type name="Magento\SalesRule\Model\ResourceModel\Rule\Collection">
    <plugin name="Myvendor_Coupons::NewRuleCollection" type="Myvendor\Coupons\Plugin\NewRuleCollection" />
</type>

and here is the file NewRuleCollection.php

<?php

namespace Myvendor\Coupons\Plugin;

use Magento\Framework\DB\Select;
use Magento\Framework\Serialize\Serializer\Json;
use Magento\Quote\Model\Quote\Address;

class NewRuleCollection extends \Magento\SalesRule\Model\ResourceModel\Rule\Collection
{

    /**
     * @var string
     */
    private $couponCode;

    /**
     * Store associated with rule entities information map
     *
     * @var array
     */
    protected $_associatedEntitiesMap;

    /**
     * @var \Magento\SalesRule\Model\ResourceModel\Rule\DateApplier
     * @since 100.1.0
     */
    protected $dateApplier;

    /**
     * @var \Magento\Framework\Stdlib\DateTime\TimezoneInterface
     */
    protected $_date;




    /**
     * @var Json $serializer
     */
    protected $serializer;

    public function __construct(
        \Magento\Framework\Data\Collection\EntityFactory $entityFactory,
        \Psr\Log\LoggerInterface $logger,
        \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy,
        \Magento\Framework\Event\ManagerInterface $eventManager,
        \Magento\Framework\Stdlib\DateTime\TimezoneInterface $date,
        \Magento\Framework\DB\Adapter\AdapterInterface $connection = null,
        \Magento\Framework\Model\ResourceModel\Db\AbstractDb $resource = null,
        Json $serializer = null
    ) {
        parent::__construct($entityFactory, $logger, $fetchStrategy, $eventManager, $date, $connection, $resource, $serializer);


        $this->_date = $date;

    }

    /**
     * Filter collection by specified website, customer group, coupon code, date.
     * Filter collection to use only active rules.
     * Involved sorting by sort_order column.
     *
     * @param int $websiteId
     * @param int $customerGroupId
     * @param string $couponCode
     * @param string|null $now
     * @param Address $address allow extensions to further filter out rules based on quote address
     * @use $this->addWebsiteGroupDateFilter()
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
     * @return $this
     */
    public function afterSetValidationFilter(
        $websiteId,
        $customerGroupId,
        $couponCode = '',
        $now = null,
        Address $address = null
    ) {



        if (!$this->getFlag('validation_filter')) {
            /* We need to overwrite joinLeft if coupon is applied */
            $this->getSelect()->reset();
            parent::_initSelect();


            $this->addWebsiteGroupDateFilter(1, 0, null);
            $select = $this->getSelect();

            $connection = $this->getConnection();
            if (strlen($couponCode)) {
                $noCouponWhereCondition = $connection->quoteInto(
                    'main_table.coupon_type = ?',
                    \Magento\SalesRule\Model\Rule::COUPON_TYPE_NO_COUPON
                );


                $relatedRulesIds = $this->getMyCustomCouponRelatedRuleIds($couponCode);

                $select->where(
                    $noCouponWhereCondition . ' OR main_table.rule_id IN (?)',
                    $relatedRulesIds,
                    Select::TYPE_CONDITION
                );
            } else {
                $this->addFieldToFilter(
                    'main_table.coupon_type',
                    \Magento\SalesRule\Model\Rule::COUPON_TYPE_NO_COUPON
                );
            }
            $this->setOrder('sort_order', self::SORT_ORDER_ASC);
            $this->setFlag('validation_filter', true);
        }

        return $this;
    }

    /**
     * Get rules ids related to coupon code
     *
     * @param string $couponCode
     * @return array
     */
    public function getMyCustomCouponRelatedRuleIds($couponCode)
    {
        $connection = $this->getConnection();
        $select = $connection->select()->from(
            ['main_table' => $this->getTable('salesrule')],
            'rule_id'
        );
        $select->joinLeft(
            ['rule_coupons' => $this->getTable('salesrule_coupon')],
            $connection->quoteInto(
                'main_table.rule_id = rule_coupons.rule_id AND main_table.coupon_type != ?',
                \Magento\SalesRule\Model\Rule::COUPON_TYPE_NO_COUPON,
                null
            )
        );

        $autoGeneratedCouponCondition = [
            $connection->quoteInto(
                "main_table.coupon_type = ?",
                \Magento\SalesRule\Model\Rule::COUPON_TYPE_AUTO
            ),
            $connection->quoteInto(
                "rule_coupons.type = ?",
                \Magento\SalesRule\Api\Data\CouponInterface::TYPE_GENERATED
            ),
        ];

        $orWhereConditions = [
            "(" . implode($autoGeneratedCouponCondition, " AND ") . ")",
            $connection->quoteInto(
                '(main_table.coupon_type = ? AND main_table.use_auto_generation = 1 AND rule_coupons.type = 1)',
                \Magento\SalesRule\Model\Rule::COUPON_TYPE_SPECIFIC
            ),
            $connection->quoteInto(
                '(main_table.coupon_type = ? AND main_table.use_auto_generation = 0 AND rule_coupons.type = 0)',
                \Magento\SalesRule\Model\Rule::COUPON_TYPE_SPECIFIC
            ),
        ];

        $andWhereConditions = [
                $connection->quoteInto(
                'code IN (?)',
                $couponCode
            ),
            $connection->quoteInto(
                '(rule_coupons.expiration_date IS NULL OR rule_coupons.expiration_date >= ?)',
                $this->_date->date()->format('Y-m-d')
            ),
        ];

        $orWhereCondition = implode(' OR ', $orWhereConditions);
        $andWhereCondition = implode(' AND ', $andWhereConditions);

        $select->where(
            '(' . $orWhereCondition . ') AND ' . $andWhereCondition,
            null,
            Select::TYPE_CONDITION
        );
        $select->group('main_table.rule_id');

        return $connection->fetchCol($select);
    }


}

While applying the coupon code i am getting error like

Fatal error: Uncaught TypeError: Argument 5 passed to Myvendor\Coupons\Plugin\NewRuleCollection\Interceptor::afterSetValidationFilter() must be an instance of Magento\Quote\Model\Quote\Address, string given,

What's wrong with my code ?

1

Your plugin code should be like this:

                    <?php

                    namespace Myvendor\Coupons\Plugin;

                    use Magento\Framework\DB\Select;
                    use Magento\Framework\Serialize\Serializer\Json;
                    use Magento\Quote\Model\Quote\Address;

                    class NewRuleCollection extends \Magento\SalesRule\Model\ResourceModel\Rule\Collection
                    {

                        public function afterSetValidationFilter(
                            \Magento\SalesRule\Model\ResourceModel\Rule\Collection $subject,
                            $websiteId,
                            $customerGroupId,
                            $couponCode = '',
                            $now = null,
                            Address $address = null
                        ) {



                            if (!$this->getFlag('validation_filter')) {
                                /* We need to overwrite joinLeft if coupon is applied */
                                $this->getSelect()->reset();
                                parent::_initSelect();


                                $this->addWebsiteGroupDateFilter(1, 0, null);
                                $select = $this->getSelect();

                                $connection = $this->getConnection();
                                if (strlen($couponCode)) {
                                    $noCouponWhereCondition = $connection->quoteInto(
                                        'main_table.coupon_type = ?',
                                        \Magento\SalesRule\Model\Rule::COUPON_TYPE_NO_COUPON
                                    );


                                    $relatedRulesIds = $this->getMyCustomCouponRelatedRuleIds($couponCode);

                                    $select->where(
                                        $noCouponWhereCondition . ' OR main_table.rule_id IN (?)',
                                        $relatedRulesIds,
                                        Select::TYPE_CONDITION
                                    );
                                } else {
                                    $this->addFieldToFilter(
                                        'main_table.coupon_type',
                                        \Magento\SalesRule\Model\Rule::COUPON_TYPE_NO_COUPON
                                    );
                                }
                                $this->setOrder('sort_order', self::SORT_ORDER_ASC);
                                $this->setFlag('validation_filter', true);
                            }

                            return $this;
                        }

                        /**
                         * Get rules ids related to coupon code
                         *
                         * @param string $couponCode
                         * @return array
                         */
                        public function getMyCustomCouponRelatedRuleIds($couponCode)
                        {
                            $connection = $this->getConnection();
                            $select = $connection->select()->from(
                                ['main_table' => $this->getTable('salesrule')],
                                'rule_id'
                            );
                            $select->joinLeft(
                                ['rule_coupons' => $this->getTable('salesrule_coupon')],
                                $connection->quoteInto(
                                    'main_table.rule_id = rule_coupons.rule_id AND main_table.coupon_type != ?',
                                    \Magento\SalesRule\Model\Rule::COUPON_TYPE_NO_COUPON,
                                    null
                                )
                            );

                            $autoGeneratedCouponCondition = [
                                $connection->quoteInto(
                                    "main_table.coupon_type = ?",
                                    \Magento\SalesRule\Model\Rule::COUPON_TYPE_AUTO
                                ),
                                $connection->quoteInto(
                                    "rule_coupons.type = ?",
                                    \Magento\SalesRule\Api\Data\CouponInterface::TYPE_GENERATED
                                ),
                            ];

                            $orWhereConditions = [
                                "(" . implode($autoGeneratedCouponCondition, " AND ") . ")",
                                $connection->quoteInto(
                                    '(main_table.coupon_type = ? AND main_table.use_auto_generation = 1 AND rule_coupons.type = 1)',
                                    \Magento\SalesRule\Model\Rule::COUPON_TYPE_SPECIFIC
                                ),
                                $connection->quoteInto(
                                    '(main_table.coupon_type = ? AND main_table.use_auto_generation = 0 AND rule_coupons.type = 0)',
                                    \Magento\SalesRule\Model\Rule::COUPON_TYPE_SPECIFIC
                                ),
                            ];

                            $andWhereConditions = [
                                    $connection->quoteInto(
                                    'code IN (?)',
                                    $couponCode
                                ),
                                $connection->quoteInto(
                                    '(rule_coupons.expiration_date IS NULL OR rule_coupons.expiration_date >= ?)',
                                    $this->_date->date()->format('Y-m-d')
                                ),
                            ];

                            $orWhereCondition = implode(' OR ', $orWhereConditions);
                            $andWhereCondition = implode(' AND ', $andWhereConditions);

                            $select->where(
                                '(' . $orWhereCondition . ') AND ' . $andWhereCondition,
                                null,
                                Select::TYPE_CONDITION
                            );
                            $select->group('main_table.rule_id');

                            return $connection->fetchCol($select);
                        }


                    }
1

First of all from your code it looks like you are mixing the concept of class overwrite and plugin concept but in reality both concepts are totally different.

If you want to overwrite the code then you should use

<preference for="Magento\SalesRule\Model\ResourceModel\Rule\Collection" type="Vendor\Some\Some\Some" />

And If you want to write plugin then can use

<config>
    <type name="{ObservedType}">
      <plugin name="{pluginName}" type="{PluginClassName}"/>
    </type>
</config>

According to your requirements you have to take decision.

Now, As per the after plugin First argument should be the class object so in your case first argument of afterSetValidationFilter should be Magento\SalesRule\Model\ResourceModel\Rule\Collection as $subject then you can use the arguments of method If you need otherwise you cans just pass $result in the method.

So, in your code it should looks like this,

public function afterSetValidationFilter(
Magento\SalesRule\Model\ResourceModel\Rule\Collection $subject,
        $result,
        $websiteId,
        $customerGroupId,
        $couponCode = '',
        $now = null,
        Address $address = null
    ) {

...................

`

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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