In Magento 1 you could have Cart Sales Rules with no start and/or end date, i.e. codes with unlimited validity. In Magento 2, saving a rule with an empty start and/or end date will automatically fill the current date as value.
Magento 2.1.0
Create new "Cart Price Rule"
Save & continue editing
"From" and "To" fields should be empty
The rule should be saved without date and be always valid
Todays date is filled into "From" and "To"
the post fields from_date and to_date are filtered in \Magento\SalesRule\Controller\Adminhtml\Promo\Quote\Save::execute()
:
$data = $this->getRequest()->getPostValue();
$inputFilter = new \Zend_Filter_Input(
['from_date' => $this->_dateFilter, 'to_date' => $this->_dateFilter],
[],
$data
);
$data = $inputFilter->getUnescaped();
unfortunately \Magento\Framework\Stdlib\DateTime\Filter\Date
does not handle empty strings:
public function filter($value)
{
try {
$value = new \DateTime($value);
return $value->format('Y-m-d');
} catch (\Exception $e) {
throw new \Exception("Invalid input date format '$value'");
}
}
initializing a \DateTime
object with an empty string will automatically use todays date.
here's a quick (and dirty) workaround: in Magento\SalesRule\Controller\Adminhtml\Promo\Quote\Save::execute()
replace
$data = $this->getRequest()->getPostValue();
$inputFilter = new \Zend_Filter_Input(
['from_date' => $this->_dateFilter, 'to_date' => $this->_dateFilter],
[],
$data
);
$data = $inputFilter->getUnescaped();
$id = $this->getRequest()->getParam('rule_id');
with
$data = $this->getRequest()->getPostValue();
$inputFilter = new \Zend_Filter_Input(
['from_date' => $this->_dateFilter, 'to_date' => $this->_dateFilter],
[],
$data
);
if (array_key_exists('from_date', $data)) {
$data['from_date'] = trim($data['from_date']) ? $inputFilter->getUnescaped('from_date') : '';
}
if (array_key_exists('to_date', $data)) {
$data['to_date'] = trim($data['to_date']) ? $inputFilter->getUnescaped('to_date') : '';
}
$id = $this->getRequest()->getParam('rule_id');
still present in 2.1.1
Can't reproduce on clean install of 2.1.1. Have you upgraded from previous versions?
yes, 2.0.4 was our starting point. our 2.1.1 store still shows this behaviour and the above mentioned patch fixes the problem. will retry on a clean 2.1.1 and report back.
sorry for the delay, the post shop launches prevented me from retesting. will be done ASAP.
it seems that your team was able to reproduce it after all: #6762 - MAGETWO-59047
Hi @heldchen , thank for report, yes we've created internal ticket MAGETWO-59047
This issue causes further problems when you have content staging on a site. As it seems content staging is removing the from_date & to_date from the cart rules form.
Fields are marked as invisible in vendor/magento/module-sales-rule-staging/view/adminhtml/ui_component/sales_rule_form.xml
.
The underlying problem here seems to be that Magento\Framework\Stdlib\DateTime\Filter\Date
is always returning a DateTime instance, without first validating if the value has any data. This could be expected functionality, but I can imagine causes other problems throughout the admin.
It seems there are a number of issues in conjunction with content staging. Content staging is forcing the to_date for rules to always be the current date when a coupon is updated causing all coupon codes to have their expiration_date set to the current date. Resulting in them expiring daily and requires to be saved each day.
I can confirm that this issue is still occurring in Magento 2.1.3. As these fields are currently not flagged as mandatory and are optional, this definitely appears to be a bug.
the issue is still present in 2.1.4, the commit https://github.com/magento/magento2/commit/e200425c1ecec910d50660fed8c422caa8d0971b did not yet land in 2.1.4
This issue is still happening in 2.1.5
I found that MagentoSalesRuleStagingModelPluginDateResolverPlugin::beforeGetToDate() is forcing toDate on the cart rule when the rule save. The coupon picks it up as expiration date. Hence the coupon code breaks each day.
I wrote a plugin to reset the coupon expiration date to null.
What is Date Resolver suppose to do?
This plugin is indeed what cause the to_date to be updated with today's date
instead of null
It looks like any time after 03:14:07 UTC on Tuesday, 19 January 2038 is converted to null in the database. This is because Unix timestamp runs out of int to convert to.
Im not sure if my solution is correct. I force the expiration_date to null
Modified file: vendor/magento/module-sales-rule/Model/Rule.php
public function afterSave()
...
)->setExpirationDate(
$this->getToDate()
)->save();
public function afterSave()
...
)->setExpirationDate(
null
)->save();
The commit referenced above on Oct 27 does not appear to fix this issue, at least on M2.1.5 EE.
I'm going ahead with the workaround from @nphp101 on Apr 25, which appears to be effective.
I'm not sure if forcing to null in all cases is really the best for everyone. But on EE, if the content staging system is supposed to handle rule expiration, it seems safe to me.
Hello Magento-Team,
We still can reproduce this issue in 2.1.7. I had a look at Release 2.1.8, and in Branch 2.1-Dev. Its still not merged there.
Could you please merge it in 2.1-Dev? In 2.2 this fix is already avaible, but 2.2 is not released yet.
Greetings
Elias
Additional Info:
There is another issue which have the same effect, with a the EE-Sales-Rule-Staging-Module.
It can be found here:
File: magento/vendor/magento/module-sales-rule-staging/Model/Plugin/DateResolverPlugin.php
Method: beforeGetToDate
This Plugin create the same behaviour (sets the date incorrect if its "null"). I am aware that this issue is EE-only and here is not a support area for such issues. But i hope it will help someone, who is searching for a solution.
Greetings
Elias
@heldchen, thank you for your report.
The issue is already fixed in 2.2.0
This issue is still open in 2.1.12
Most helpful comment
This issue causes further problems when you have content staging on a site. As it seems content staging is removing the from_date & to_date from the cart rules form.
Fields are marked as invisible in
vendor/magento/module-sales-rule-staging/view/adminhtml/ui_component/sales_rule_form.xml
.The underlying problem here seems to be that
Magento\Framework\Stdlib\DateTime\Filter\Date
is always returning a DateTime instance, without first validating if the value has any data. This could be expected functionality, but I can imagine causes other problems throughout the admin.It seems there are a number of issues in conjunction with content staging. Content staging is forcing the to_date for rules to always be the current date when a coupon is updated causing all coupon codes to have their expiration_date set to the current date. Resulting in them expiring daily and requires to be saved each day.