0

I have created a custom module contain two sections:

The first section contains title(text Field),icon(Uploader) and custom dropdown ,the second section contains conditions rule.

In this module was added new conditions rule named Total Sales (Life Time Sales) for customer.

My Question: How to use this condition and validate it in my module?

/app/Vendor/Modulename/etc/events.xml

<?xml version="1.0" ?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
    <event name="salesrule_rule_condition_combine">
        <observer instance="Vendor\Modulename\Observer\Salesrule\RuleConditionCombine" name="cart_rule_total_sales"/>
    </event>
</config>

/app/Vendor/Modulename/view/adminhtml/ui_component/custom_form.xml

<fieldset name="general">
    <argument name="data" xsi:type="array">
        <item name="config" xsi:type="array">
            <item name="label" xsi:type="string" translate="true">General</item>
            <item name="collapsible" xsi:type="boolean">true</item>
            <item name="sortOrder" xsi:type="number">10</item>
            <item name="opened" xsi:type="boolean">true</item>
        </item>
    </argument>

    <field formElement="input" name="title" sortOrder="20">
        <argument name="data" xsi:type="array">
            <item name="config" xsi:type="array">
                <item name="source" xsi:type="string">Modulename</item>
            </item>
        </argument>
        <settings>
            <dataType>text</dataType>
            <label translate="true">Title</label>
            <dataScope>title</dataScope>
            <validation>
                <rule name="required-entry" xsi:type="boolean">true</rule>
            </validation>
        </settings>
    </field>

    <field name="icon">
        <argument name="data" xsi:type="array">
            <item name="config" xsi:type="array">
                <item name="dataType" xsi:type="string">string</item>
                <item name="source" xsi:type="string">Modulename</item>
                <item name="label" xsi:type="string" translate="true">Icon</item>
                <item name="visible" xsi:type="boolean">true</item>
                <item name="formElement" xsi:type="string">fileUploader</item>
                <item name="elementTmpl" xsi:type="string">ui/form/element/uploader/uploader</item>
                <item name="previewTmpl" xsi:type="string">Magento_Catalog/image-preview</item>
                <item name="required" xsi:type="boolean">true</item>
                <item name="validation" xsi:type="array">
                    <item name="required-entry" xsi:type="boolean">true</item>
                </item>
                <item name="uploaderConfig" xsi:type="array">
                    <item name="url" xsi:type="url" path="route/modulename/upload"/>
                </item>
            </item>
        </argument>
    </field>

    <field name="discount">
        <argument name="data" xsi:type="array">
            <item name="options" xsi:type="object">Vendor\Modulename\Model\Config\Source\Discount</item>
            <item name="config" xsi:type="array">
                <item name="dataType" xsi:type="string">text</item>
                <item name="label" translate="true" xsi:type="string">Discount(%)</item>
                <item name="formElement" xsi:type="string">select</item>
                <item name="source" xsi:type="string">modulename</item>
                <item name="sortOrder" xsi:type="number">40</item>
                <item name="dataScope" xsi:type="string">discount</item>
                <item name="validation" xsi:type="array">
                    <item name="required-entry" xsi:type="boolean">false</item>
                </item>
            </item>
        </argument>
    </field>

    <field name="filter_by">
        <argument name="data" xsi:type="array">
            <item name="options" xsi:type="object">Vendor\Modulename\Model\Config\Source\Filterby</item>
            <item name="config" xsi:type="array">
                <item name="dataType" xsi:type="string">text</item>
                <item name="label" translate="true" xsi:type="string">Filter By</item>
                <item name="formElement" xsi:type="string">select</item>
                <item name="source" xsi:type="string">modulename</item>
                <item name="sortOrder" xsi:type="number">50</item>
                <item name="dataScope" xsi:type="string">filter_by</item>
                <item name="validation" xsi:type="array">
                    <item name="required-entry" xsi:type="boolean">false</item>
                </item>
            </item>
        </argument>
    </field>
</fieldset>

<fieldset name="conditions_serialized">
    <argument name="data" xsi:type="array">
        <item name="config" xsi:type="array">
            <item name="label" xsi:type="string" translate="true">Conditions</item>
            <item name="collapsible" xsi:type="boolean">true</item>
            <item name="sortOrder" xsi:type="number">20</item>
        </item>
    </argument>
    <container name="conditions_apply_to" >
        <argument name="data" xsi:type="array">
            <item name="config" xsi:type="array">
                <item name="sortOrder" xsi:type="number">10</item>
            </item>
        </argument>
        <htmlContent name="html_content">
            <argument name="block" xsi:type="object">Vendor\Modulename\Block\Adminhtml\Label\Edit\Tab\Conditions</argument>
        </htmlContent>
    </container>
</fieldset>

/app/Vendor\Modulename\Block\Adminhtml\Label\Edit\Tab\Conditions

<?php

namespace Vendor\Modulename\Block\Adminhtml\Label\Edit\Tab;

use Magento\Framework\App\ObjectManager;

class Conditions extends \Magento\Backend\Block\Widget\Form\Generic 
{
    /**
     * Core registry
     *
     * @var \Magento\Backend\Block\Widget\Form\Renderer\Fieldset
     */
    protected $_rendererFieldset;

    /**
     * @var \Magento\Rule\Block\Conditions
     */
    protected $_conditions;

    /**
     * @var string
     */
    protected $_nameInLayout = 'conditions_serialized';

    /**
     * @var \Magento\SalesRule\Model\RuleFactory
     */
    private $ruleFactory;

    /**
     * Initialize dependencies.
     *
     * @param \Magento\Backend\Block\Template\Context $context
     * @param \Magento\Framework\Registry $registry
     * @param \Magento\Framework\Data\FormFactory $formFactory
     * @param \Magento\Rule\Block\Conditions $conditions
     * @param \Magento\Backend\Block\Widget\Form\Renderer\Fieldset $rendererFieldset
     * @param array $data
     */
    public function __construct(
        \Magento\Backend\Block\Template\Context $context,
        \Magento\Framework\Registry $registry,
        \Magento\Framework\Data\FormFactory $formFactory,
        \Magento\Rule\Block\Conditions $conditions,
        \Magento\Backend\Block\Widget\Form\Renderer\Fieldset $rendererFieldset,
        array $data = []
    ) {
        $this->_rendererFieldset = $rendererFieldset;
        $this->_conditions = $conditions;
        parent::__construct($context, $registry, $formFactory, $data);
    }

    /**
     * The getter function to get the new RuleFactory dependency
     *
     * @return \Magento\SalesRule\Model\RuleFactory
     *
     * @deprecated
     */
    private function getRuleFactory()
    {
        if ($this->ruleFactory === null) {
            $this->ruleFactory = ObjectManager::getInstance()->get('Magento\SalesRule\Model\RuleFactory');
        }
        return $this->ruleFactory;
    }

    /**
     * {@inheritdoc}
     * @codeCoverageIgnore
     */
    public function getTabClass()
    {
        return null;
    }

    /**
     * {@inheritdoc}
     * @codeCoverageIgnore
     */
    public function getTabUrl()
    {
        return null;
    }

    /**
     * {@inheritdoc}
     * @codeCoverageIgnore
     */
    public function isAjaxLoaded()
    {
        return false;
    }

    /**
     * {@inheritdoc}
     * @codeCoverageIgnore
     */
    public function getTabLabel()
    {
        return __('Conditions');
    }

    /**
     * {@inheritdoc}
     * @codeCoverageIgnore
     */
    public function getTabTitle()
    {
        return __('Conditions');
    }

    /**
     * {@inheritdoc}
     * @codeCoverageIgnore
     */
    public function canShowTab()
    {
        return true;
    }

    /**
     * {@inheritdoc}
     * @codeCoverageIgnore
     */
    public function isHidden()
    {
        return false;
    }

    /**
     * Prepare form before rendering HTML
     *
     * @return $this
     */
    protected function _prepareForm()
    {
        $model = $this->_coreRegistry->registry(\Magento\SalesRule\Model\RegistryConstants::CURRENT_SALES_RULE);
        $form = $this->addTabToForm($model);
        $this->setForm($form);

        return parent::_prepareForm();
    }

    /**
     * Handles addition of conditions tab to supplied form.
     *
     * @param \Magento\SalesRule\Model\Rule $model
     * @param string $fieldsetId
     * @param string $formName
     * @return \Magento\Framework\Data\Form
     * @throws \Magento\Framework\Exception\LocalizedException
     */
    protected function addTabToForm($model, $fieldsetId = 'conditions_serialized', $formName = 'custom_form')
    {
        if (!$model) {
            $id = $this->getRequest()->getParam('id');
            $model = $this->getRuleFactory()->create();
            $model->load($id);
        }
        $conditionsFieldSetId = $model->getConditionsFieldSetId($formName);
        $newChildUrl = $this->getUrl(
            'sales_rule/promo_quote/newConditionHtml/form/' . $conditionsFieldSetId,
            ['form_namespace' => $formName]
        );

        /** @var \Magento\Framework\Data\Form $form */
        $form = $this->_formFactory->create();
        $form->setHtmlIdPrefix('rule_');
        $renderer = $this->_rendererFieldset->setTemplate(
            'Magento_CatalogRule::promo/fieldset.phtml'
        )->setNewChildUrl(
            $newChildUrl
        )->setFieldSetId(
            $conditionsFieldSetId
        );

        $fieldset = $form->addFieldset(
            $fieldsetId,
            [
                'legend' => __(
                    'Apply the rule only if the following conditions are met (leave blank for all products).'
                )
            ]
        )->setRenderer(
            $renderer
        );
        $fieldset->addField(
            'conditions',
            'text',
            [
                'name'           => 'conditions',
                'label'          => __('Conditions'),
                'title'          => __('Conditions'),
                'required'       => true,
                'data-form-part' => $formName
            ]
        )->setRule(
            $model
        )->setRenderer(
            $this->_conditions
        );

        $form->setValues($model->getData());
        $this->setConditionFormName($model->getConditions(), $formName);
        return $form;
    }

    /**
     * Handles addition of form name to condition and its conditions.
     *
     * @param \Magento\Rule\Model\Condition\AbstractCondition $conditions
     * @param string $formName
     * @return void
     */
    private function setConditionFormName(\Magento\Rule\Model\Condition\AbstractCondition $conditions, $formName)
    {
        $conditions->setFormName($formName);
        if ($conditions->getConditions() && is_array($conditions->getConditions())) {
            foreach ($conditions->getConditions() as $condition) {
                $this->setConditionFormName($condition, $formName);
            }
        }
    }
}

/app/Vendor/Modulename/Observer/Salesrule/RuleConditionCombine.php

<?php

namespace Vendor\Modulename\Observer\Salesrule;

class RuleConditionCombine implements \Magento\Framework\Event\ObserverInterface
{

    /**
     * Execute observer
     *
     * @param \Magento\Framework\Event\Observer $observer
     * @return void
     */
    public function execute(
        \Magento\Framework\Event\Observer $observer
    ) {
        $additional = $observer->getAdditional();
        $conditions = (array) $additional->getConditions();

        $conditions = array_merge_recursive($conditions, [
            $this->getTotalSalesRuleCondition()
        ]);

        $additional->setConditions($conditions);
        return $this;
    }

    /**
     * Get total sales rule conditions.
     * @return array
     */
    private function getTotalSalesRuleCondition()
    {
        return [
            'label'=> __('Total Sales'),
            'value'=> \Vendor\Modulename\Model\Rule\Condition\Totalsales::class
        ];
    }
}

/app/Vendor/Modulename/Model/Rule/Condition/Totalsales

<?php

namespace Vendor\Modulename\Model\Rule\Condition;

/**
 * Class Totalsales
 */
class Totalsales extends \Magento\Rule\Model\Condition\AbstractCondition
{

    /**
     * @var \Magento\Sales\Model\ResourceModel\Order\CollectionFactory
     */
    protected $orderFactory;

    /**
     * Constructor
     * @param \Magento\Rule\Model\Condition\Context $context
     * @param \Magento\Sales\Model\ResourceModel\Order\CollectionFactory $orderFactory
     * @param array $data
     */
    public function __construct(
        \Magento\Rule\Model\Condition\Context $context,
        \Magento\Sales\Model\ResourceModel\Order\CollectionFactory $orderFactory,
        array $data = []
    ) {
        $this->orderFactory = $orderFactory;
        parent::__construct($context, $data);
    }

    /**
     * Load attribute options
     * @return $this
     */
    public function loadAttributeOptions()
    {
        $this->setAttributeOption([
            'total_sales' => __('Total Sales')
        ]);
        return $this;
    }

    /**
     * Get input type
     * @return string
     */
    public function getInputType()
    {
        return 'string';
    }

    /**
     * Get value element type
     * @return string
     */
    public function getValueElementType()
    {
        return 'text';
    }

    /**
     * Get value select options
     * @return array|mixed
     */
    public function getValueSelectOptions()
    {
        $opt = [];
        if ($this->hasValueOption()) {
            foreach ((array)$this->getValueOption() as $key => $value) {
                $opt[] = ['value' => $key, 'label' => $value];
            }
        }
        return $opt;
    }

    /**
     * Validate Total Sales Rule Condition
     * @param \Magento\Framework\Model\AbstractModel $model
     * @return bool
     */
    public function validate(\Magento\Framework\Model\AbstractModel $model)
    {
        $customerId = $model->getCustomerId();
        $lifetimesales = $this->getLifetimeSalesByCustomer($customerId);
        $model->setData('total_sales', $lifetimesales);
        return parent::validate($model);
    }

    /**
     * getLifetimeSalesByCustomer
     * @param integer $customer_id
     * @return float            
     */
    protected function getLifetimeSalesByCustomer($customer_id)
    {   
        //Get Object Manager Instance
        $objectManager = \Magento\Framework\App\ObjectManager::getInstance();
        $_collection = $objectManager->create('\Magento\Sales\Model\ResourceModel\Sale\Collection');
        $_collection->addFieldToFilter('status', array('in' => array(\Magento\Sales\Model\Order::STATE_COMPLETE)));
        $_collection->setOrderStateFilter(\Magento\Sales\Model\Order::STATE_CANCELED, true)
        ->setCustomerIdFilter($customer_id)
        ->load();
        $customerLifetimeSales = $_collection->getTotals();
        $lifetime = $customerLifetimeSales['lifetime'];
        return $lifetime;
    }
}

/app/Vendor/Modulename/etc/di.xml

<?xml version="1.0" ?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <!-- Start Total Sales Custom Rule Condition -->
    <type name="Vendor\Modulename\Model\Rule\Condition\Totalsales">
        <arguments>
            <argument name="data" xsi:type="array">
                <item name="form_name" xsi:type="string">sales_rule_form</item>
            </argument>
        </arguments>
    </type>
    <!-- End Total Sales Custom Rule Condition -->
</config>

Conditions Rule:

[rule] => Array
        (
            [conditions] => Array
                (
                    [1] => Array
                        (
                            [type] => Magento\SalesRule\Model\Rule\Condition\Combine
                            [aggregator] => all
                            [value] => 1
                            [new_child] => 
                        )

                    [1--1] => Array
                        (
                            [type] => Vendor\Modulename\Model\Rule\Condition\Totalsales
                            [attribute] => total_sales
                            [operator] => >=
                            [value] => 1200
                        )

                    [1--2] => Array
                        (
                            [type] => vendor\Modulename\Model\Rule\Condition\Totalsales
                            [attribute] => total_sales
                            [operator] => <
                            [value] => 2400
                        )

                )

        )

Conditions Rule Serialized:

a:3:{i:1;a:4:{s:4:"type";s:46:"Magento\SalesRule\Model\Rule\Condition\Combine";s:10:"aggregator";s:3:"all";s:5:"value";s:1:"1";s:9:"new_child";s:0:"";}s:4:"1--1";a:4:{s:4:"type";s:51:"Vendor\Modulename\Model\Rule\Condition\Totalsales";s:9:"attribute";s:11:"total_sales";s:8:"operator";s:2:">=";s:5:"value";s:4:"1200";}s:4:"1--2";a:4:{s:4:"type";s:51:"Vendor\Modulename\Model\Rule\Condition\Totalsales";s:9:"attribute";s:11:"total_sales";s:8:"operator";s:1:"<";s:5:"value";s:4:"2400";}}

enter image description here

Your Answer

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

Browse other questions tagged or ask your own question.