2

I need to save custom field data in apply_on_weekday column which is located in salesrule DB table. I tried too much but it doesn't save it in DB. I share my code below.

vendor\Module\etc\extension_attributes.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Api/etc/extension_attributes.xsd">
    <extension_attributes for="Magento\SalesRule\Api\Data\RuleInterface">
        <attribute code="apply_on_weekday" type="string[]" />
    </extension_attributes>
</config>

Vendor\Module\view\adminhtml\ui_component\sales_rule_form.xml

<?xml version="1.0" encoding="UTF-8"?>
<form xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd">
    <fieldset name="rule_information" sortOrder="10">
        <field name="apply_on_weekday" formElement="multiselect">
            <argument name="data" xsi:type="array">
                <item name="config" xsi:type="array">
                    <!-- <item name="dataType" xsi:type="string">int</item> -->
                    <item name="source" xsi:type="string">sales_rule</item>
                    <item name="default" xsi:type="string">Mon</item>
                </item>
            </argument>
            <settings>
                <label translate="true">Apply for specific weekdays</label>
                <dataScope>apply_on_weekday</dataScope>
            </settings>
            <formElements>
                <multiselect>
                    <settings>
                        <options class="Vendor\Module\Model\Config\Source\Weekdays"/>
                    </settings>
                </multiselect>
            </formElements>
        </field>
    </fieldset>
</form>

Vendor\Module\Model\Config\Source\Weekdays.php file

<?php

namespace Vendor\Module\Model\Config\Source;

use Magento\Framework\Data\OptionSourceInterface;

class Weekdays implements OptionSourceInterface { /** * Value which equal "Monday" for Weekdays dropdown. */ const MONDAY = "Mon";

/**
 * Value which equal &quot;Tuesday&quot; for Weekdays dropdown.
 */
const TUESDAY = &quot;Tue&quot;;

/**
 * Value which equal &quot;Wednesday&quot; for Weekdays dropdown.
 */
const WEDNESDAY = &quot;Wed&quot;;

/**
 * Value which equal &quot;Thursday&quot; for Weekdays dropdown.
 */
const THURSDAY = &quot;Thu&quot;;

/**
 * Value which equal &quot;Friday&quot; for Weekdays dropdown.
 */
const FRIDAY = &quot;Fri&quot;;

/**
 * Value which equal &quot;Saturday&quot; for Weekdays dropdown.
 */
const SATURDAY = &quot;Sat&quot;;

/**
 * Value which equal &quot;Sunday&quot; for Weekdays dropdown.
 */
const SUNDAY = &quot;Sun&quot;;

/**
 * {@inheritdoc}
 */
public function toOptionArray()
{
    return [
        ['value' =&gt; self::MONDAY, 'label' =&gt; __('Mon')],
        ['value' =&gt; self::TUESDAY, 'label' =&gt; __('Tue')],
        ['value' =&gt; self::WEDNESDAY, 'label' =&gt; __('Wed')],
        ['value' =&gt; self::THURSDAY, 'label' =&gt; __('Thu')],
        ['value' =&gt; self::FRIDAY, 'label' =&gt; __('Fri')],
        ['value' =&gt; self::SATURDAY, 'label' =&gt; __('Sat')],
        ['value' =&gt; self::SUNDAY, 'label' =&gt; __('Sun')],
    ];
}

}

Vendor\Module\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">
    <type name="Magento\SalesRule\Api\RuleRepositoryInterface">
        <plugin name="vendor_module_rule_repository_plugin" type="Vendor\Module\Plugin\Model\Rule\RuleRepositoryPlugin"/>   
    </type>
</config>

Vendor\Module\Plugin\Model\Rule\Rule\RuleRepositoryPlugin.php

<?php

namespace Vendor\Module\Plugin\Model\Rule;

use Magento\SalesRule\Api\Data\RuleExtensionFactory; use Magento\SalesRule\Api\Data\RuleExtensionInterface;

class RuleRepositoryPlugin { /** * Rule Extension Attributes Factory * * @var RuleExtensionFactory */ protected $extensionFactory;

/**
 * RuleExtensionFactory constructor
 *
 * @param RuleExtensionFactory $extensionFactory
 */
public function __construct(RuleExtensionFactory $extensionFactory)
{
    $this-&gt;extensionFactory = $extensionFactory;
}

public function afterSave(
    \Magento\SalesRule\Api\RuleRepositoryInterface $subject,
    \Magento\SalesRule\Api\Data\RuleInterface $entity
) {
    $rule = $entity;
    /** Get Current Extension Attributes from Rule 
     * @var \Magento\SalesRule\Api\Data\RuleExtensionInterface|null
     */
    $extensionAttributes = $rule-&gt;getExtensionAttributes();
    $extensionAttributes = $extensionAttributes ? $extensionAttributes : $this-&gt;extensionFactory-&gt;create();
    $applyOnWeekday = $extensionAttributes-&gt;getApplyOnWeekday();

    var_dump($applyOnWeekday);
    if($applyOnWeekday != null) {
        if(is_array($applyOnWeekday)) {
            $applyOnWeekday = implode(',', $applyOnWeekday);
        }

        $rule-&gt;setData('apply_on_weekday', $applyOnWeekday);
    }

    return $rule;
}

}

Now we call API for create salesrule

Endpoint :- rest/default/V1/salesRules

Method :- POST

payload:-

{
    "rule": {
        "name": "testing the string",
        "store_labels": [],
        "description": "",
        "website_ids": [
            1
        ],
        "customer_group_ids": [
            1
        ],
        "from_date": "2022-10-31",
        "uses_per_customer": 0,
        "is_active": true,
        "condition": {
            "condition_type": "Magento\\SalesRule\\Model\\Rule\\Condition\\Combine",
            "aggregator_type": "all",
            "operator": null,
            "value": true
        },
        "action_condition": {
            "condition_type": "Magento\\SalesRule\\Model\\Rule\\Condition\\Product\\Combine",
            "aggregator_type": "all",
            "operator": null,
            "value": true
        },
        "stop_rules_processing": true,
        "is_advanced": true,
        "sort_order": 0,
        "simple_action": "by_percent",
        "discount_amount": 0,
        "discount_step": 0,
        "apply_to_shipping": false,
        "times_used": 0,
        "is_rss": true,
        "coupon_type": "NO_COUPON",
        "use_auto_generation": false,
        "uses_per_coupon": 0,
        "simple_free_shipping": "0",
        "extension_attributes": {
            "apply_on_weekday": [
                "Fri",
                "Sat",
                "Sun"
            ]
        }
    }
}
Tu Van
  • 6,868
  • 2
  • 11
  • 22
Harsh Patel
  • 219
  • 1
  • 10
  • When you save from admin, is it working ? – Pawan Nov 06 '22 at 05:15
  • @pawan when I tried apply_on_weekday field using select elemnet then it saved in DB, but I need to use MultiSelect element. So, I tried Plugin method but it doesn't works. then I tried adminhtml_controller_salesrule_prepare_save event observer but it also doesn't working. then when I debugging adminhtml_controller_salesrule_prepare_save observer event then I see that data array to comma seperated string successfull saved. but https://github.com/magento/magento2/blob/2.4-develop/app/code/Magento/SalesRule/Controller/Adminhtml/Promo/Quote/Save.php see this – Harsh Patel Nov 07 '22 at 05:26
  • after Magento firing adminhtml_controller_salesrule_prepare_save event when I check request data, it shows old data. magento doesn't take updated data from request. which one we modified using observer event – Harsh Patel Nov 07 '22 at 05:29

1 Answers1

1

Due to Magento\SalesRule\Model\Data\Rule can't set custom data, you should use the resource model to save the Rule.

To do that, replace your RuleRepositoryPlugin with the following code:

<?php

namespace Vendor\Module\Plugin\Model\Rule; use Magento\SalesRule\Api\Data\RuleExtensionFactory; use Magento\SalesRule\Api\Data\RuleExtensionInterface; use Magento\SalesRule\Api\Data\RuleInterface; use Magento\SalesRule\Api\RuleRepositoryInterface; use Magento\SalesRule\Model\ResourceModel\Rule as ResourceModel; use Magento\SalesRule\Model\RuleFactory;

class RuleRepositoryPlugin { /** * @var RuleExtensionFactory */ protected $ruleExtensionFactory;

/**
 * @var RuleFactory
 */
protected $ruleFactory;

/**
 * @var ResourceModel
 */
private $resourceModel;

/**
 * RuleExtensionFactory constructor
 *
 * @param RuleExtensionFactory $ruleExtensionFactory
 */
public function __construct(
    RuleExtensionFactory $ruleExtensionFactory,
    ResourceModel $resourceModel,
    RuleFactory $ruleFactory
) {
    $this-&gt;ruleExtensionFactory = $ruleExtensionFactory;
    $this-&gt;resourceModel = $resourceModel;
    $this-&gt;ruleFactory = $ruleFactory;
}

public function afterSave(
    RuleRepositoryInterface $subject,
    RuleInterface $rule
) {
    /** @var RuleExtensionInterface|null $extensionAttributes */
    $extensionAttributes = $rule-&gt;getExtensionAttributes();// get original extension attributes from entity

    if (null !== $extensionAttributes &amp;&amp;
        null !== $extensionAttributes-&gt;getApplyOnWeekday()
    ) {
        $applyOnWeekday = $extensionAttributes-&gt;getApplyOnWeekday();

        if (is_array($applyOnWeekday)) {
            $applyOnWeekday = implode(',', $applyOnWeekday);
        }

        /** @var RuleFactory $ruleFactory */
        $ruleFactory = $this-&gt;ruleFactory-&gt;create();
        $this-&gt;resourceModel-&gt;load($ruleFactory, $rule-&gt;getRuleId());
        $ruleFactory-&gt;setApplyOnWeekday($applyOnWeekday);
        $this-&gt;resourceModel-&gt;save($ruleFactory);
    }

    return $rule;
}

}

Then re-compile code and clear the cache.


multiselect custom field does not save in sales rule admin form in magento 2.4

How to validate a custom field in sales rule before the discount applying to cart in magento 2.4

Harsh Patel
  • 219
  • 1
  • 10
Tu Van
  • 6,868
  • 2
  • 11
  • 22
  • hi, thank you for answering. but it not works. it returns error Error: Call to undefined method Magento\SalesRule\Model\Data\Rule::setApplyOnWeekday() . .. means it throw error on $rule->setApplyOnWeekday($applyOnWeekday); line . ... then i tried with replace that line with $rule->setData('apply_on_weekday', $applyOnWeekday); . then it returns result, but apply_on_weekday data doesn't saved in DB. – Harsh Patel Nov 07 '22 at 05:17
  • 1
    hey @HarshPatel, I've fixed your issue and update the solution, please check. – Tu Van Nov 07 '22 at 07:57
  • yeahhh, now it works perfectly. but I have one more dout. in admin salesrule form single select dropdown perfectly save apply_on_weekday field. but I need to use multiselect. So, I convert array to comma seprate value for apply_on_weekday using adminhtml_controller_salesrule_prepare_save observer event. but it doesn't save value in apply_on_weekday column. – Harsh Patel Nov 07 '22 at 08:48
  • when i debugging, I found that comma seperated value saved in request. but after that event magento use old data array for store it in Db. see this controller https://github.com/magento/magento2/blob/2.4-develop/app/code/Magento/SalesRule/Controller/Adminhtml/Promo/Quote/Save.php here i found that magento doesn't take updated data to store it. So what can I do? – Harsh Patel Nov 07 '22 at 08:48
  • That is out of the scope of this topic. Are you happy with a new question for that? – Tu Van Nov 07 '22 at 09:28
  • Creating a new question also help other who had the same issue find the solution easier. – Tu Van Nov 07 '22 at 10:22
  • see here I open seperate question https://magento.stackexchange.com/q/361526/93504 – Harsh Patel Nov 07 '22 at 10:56
  • Great, I'll take a look. – Tu Van Nov 07 '22 at 11:03