7

We have simple catalog price rule which is valid indefinitely.

In our Google Shopping feed which is generated at midnight, the price rule does not apply.

My theory is, that there is a small time frame, where the calculated prices are not available.

I have checked catalogrule_product_price - there seem to be only prices calculated until today (2013-04-22), so they would expire at midnight:

mysql> select distinct rule_date from catalogrule_product_price;
+------------+
| rule_date  |
+------------+
| 2013-04-20 |
| 2013-04-21 |
| 2013-04-22 |
+------------+
3 rows in set (0.05 sec)

Is this normal? cron_schedule has recent entries so I think the cron system is generally running.

I was having in mind, that price rules are always generated several days in advance, just to avoid such time spans with wrong prices - was I wrong with this assumption? What is going on here?

EDIT: checked it again today (2013-04-25) - same problem. I wish I checked it yesterday to see if also 23.,24. and 25. where existing and so the prices are generated always in bunches or tree of if the prices are always generated until today and three days back.

mysql> select distinct rule_date from catalogrule_product_price;
+------------+
| rule_date  |
+------------+
| 2013-04-23 |
| 2013-04-24 |
| 2013-04-25 |
+------------+
3 rows in set (0.00 sec)
4
  • I've the same problem in the same Google Shopping-related context. Did you find a solution? For me it would be enough to have the price calculated for today and tomorrow. Apr 19, 2019 at 13:36
  • 1
    Yeah I spend sometime to understand this and The script calculate prices for the current day, the previous day and the next day. In Which, Updates include interval 3 days - current day - 1 days before + 1 days after Apr 25, 2019 at 5:29
  • Which Generate data for interval -1 day ... +1 day Apr 25, 2019 at 5:29

2 Answers 2

6

No.

The cron job calls the observer method Mage_CatalogRule_Model_Observer::dailyCatalogUpdate(). This one calls Mage_CatalogRule_Model_Resource_Rule::applyAllRulesForDateRange() without arguments.

If applyAllRulesForDateRange() is called without arguments, one day +/- the current date is assumed.

So you can create newer or older dates but the nightly cron job does not.

3
  • So I guess when the nightly cron job is called it is still 2013-04-24 in UTC and it generates 23. and 25. ? This is a mess.
    – Alex
    Apr 25, 2013 at 10:35
  • I mean I am quite sure, that there is a small timespan in which the prices are wrong...
    – Alex
    Apr 25, 2013 at 12:33
  • Why not just move catalog price rule calculation cron job to 11p.m.? You can use Aoe_Scheduler module for this. In this case your Google Shopping feed generation cron will always pick up right price. Apr 25, 2013 at 23:13
6
+100

I spend sometime to understand this :)

And The script calculate prices for the current day, the previous day and the next day.

In Which, Updates include interval 3 days [in Magento 2.2.X]

  • current day - 1 days before + 1 days after

Daily update catalog price rule by cron

/vendor/magento/module-catalog-rule/Cron/DailyCatalogUpdate.php

  • Update include interval 3 days - current day - 1 days before + 1 days after
  • This method is called from cron process, cron is working in UTC time and
  • we should generate data for interval -1 day ... +1 day

Reindex product prices according rule settings.

/vendor/magento/module-catalog-rule/Model/Indexer/ReindexRuleProductPrice.php

public function execute(
    $batchCount,
    \Magento\Catalog\Model\Product $product = null,
    $useAdditionalTable = false
) {
    $fromDate = mktime(0, 0, 0, date('m'), date('d') - 1);
    $toDate = mktime(0, 0, 0, date('m'), date('d') + 1);

    /**
     * Update products rules prices per each website separately
     * because of max join limit in mysql
     */

    -
    -
    -

$ruleData['from_time'] = $this->roundTime($ruleData['from_time']);
$ruleData['to_time'] = $this->roundTime($ruleData['to_time']);
/**
 * Build prices for each day
 */
for ($time = $fromDate; $time <= $toDate; $time += IndexBuilder::SECONDS_IN_DAY) {
    if (($ruleData['from_time'] == 0 ||
            $time >= $ruleData['from_time']) && ($ruleData['to_time'] == 0 ||
            $time <= $ruleData['to_time'])
    ) {
        $priceKey = $time . '_' . $productKey;

        if (isset($stopFlags[$priceKey])) {
            continue;
        }

        if (!isset($dayPrices[$priceKey])) {
            $dayPrices[$priceKey] = [
                'rule_date' => $time,
                'website_id' => $ruleData['website_id'],
                'customer_group_id' => $ruleData['customer_group_id'],
                'product_id' => $ruleProductId,
                'rule_price' => $this->productPriceCalculator->calculate($ruleData),
                'latest_start_date' => $ruleData['from_time'],
                'earliest_end_date' => $ruleData['to_time'],
            ];
        } else {
            $dayPrices[$priceKey]['rule_price'] = $this->productPriceCalculator->calculate(
                $ruleData,
                $dayPrices[$priceKey]
            );
            $dayPrices[$priceKey]['latest_start_date'] = max(
                $dayPrices[$priceKey]['latest_start_date'],
                $ruleData['from_time']
            );
            $dayPrices[$priceKey]['earliest_end_date'] = min(
                $dayPrices[$priceKey]['earliest_end_date'],
                $ruleData['to_time']
            );
        }

        if ($ruleData['action_stop']) {
            $stopFlags[$priceKey] = true;
        }
    }
}

So the calculation duration

$fromDate = mktime(0, 0, 0, date('m'), date('d') - 1);
$toDate = mktime(0, 0, 0, date('m'), date('d') + 1);

In Magento 1.X this bug occurs if you are living in a timezone which is more than +01:00 from GMT. The default cronjob is running at 01:00 and is using GMT time to set the rule_date. In said case the date will be "yesterday" so there would be no price rule for the current day.

Example:

Current Datetime: 2017-07-19 01:00:00 (at current timezone)
Current Datetime at GMT: 2017-07-18 23:00:00
At 01:00 cronjob runs to write price rules with "$coreDate->gmtTimestamp('Today');"
Function will return "2017-07-18" which in this example is "yesterday"

Solution in 2.2.X

/vendor/magento/module-catalog-rule/Model/Indexer/IndexBuilder.php

$fromTime = strtotime($rule->getFromDate());
$toTime = strtotime($rule->getToDate());
$toTime = $toTime ? $toTime + self::SECONDS_IN_DAY - 1 : 0;

References

  1. http://www.divisionlab.com/solvingmagento/magento-catalog-price-rules/
  2. https://github.com/magento/magento2/issues/6610
  3. https://ipfs-sec.stackexchange.cloudflare-ipfs.com/magento/A/question/3161.html
  4. https://support.google.com/merchants/answer/6069284?hl=en
4
  • 1
    This looks like it! I'm indeed at GMT+2 now (I'm normally at GMT+1, but now daylight saving is in effect). I'm on holiday now, but tomorrow I'll be back at the office and try this out. Apr 25, 2019 at 14:05
  • Yeah please check your server timezone and application time zone, although Magento manages it internally. Apr 25, 2019 at 15:13
  • 1
    I can confirm that this is indeed the issue. I fixed it with this github.com/Chuvisco88/Chuvisco_CatalogRuleFix Thanks for your help, enjoy your bounty :-) Apr 26, 2019 at 15:11
  • 1
    Awesome! I knew there is a timezone issue there :)
    – Alex
    Apr 26, 2019 at 16:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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