Repository: saleor/saleor

Issue:
Improve promotion rule - variants recalculation
Call variant recalculations only for PromotionRule with `reward_value` set and above 0, to reduce the number of rules to proceed. Update `update_products_discounted_prices_for_promotion_task` from `saleor/saleor/product/tasks.py`


Discussion:

Resolving patch:
diff --git a/saleor/product/tasks.py b/saleor/product/tasks.py
--- a/saleor/product/tasks.py
+++ b/saleor/product/tasks.py
@@ -176,12 +176,15 @@ def update_products_discounted_prices_for_promotion_task(
     rules = (
         PromotionRule.objects.order_by("id")
         .using(settings.DATABASE_CONNECTION_REPLICA_NAME)
-        .filter(Exists(promotions.filter(id=OuterRef("promotion_id"))), **kwargs)[
+        .filter(Exists(promotions.filter(id=OuterRef("promotion_id"))), **kwargs)
+        .exclude(Q(reward_value__isnull=True) | Q(reward_value=0))[
             :PROMOTION_RULE_BATCH_SIZE
         ]
     )
     if ids := list(rules.values_list("pk", flat=True)):
-        qs = PromotionRule.objects.filter(pk__in=ids)
+        qs = PromotionRule.objects.filter(pk__in=ids).exclude(
+            Q(reward_value__isnull=True) | Q(reward_value=0)
+        )
         fetch_variants_for_promotion_rules(rules=qs)
         update_products_discounted_prices_for_promotion_task.delay(
             product_ids, ids[-1], rule_ids=rule_ids


Test patch:
diff --git a/saleor/product/tests/test_tasks.py b/saleor/product/tests/test_tasks.py
--- a/saleor/product/tests/test_tasks.py
+++ b/saleor/product/tests/test_tasks.py
@@ -5,6 +5,7 @@
 from unittest.mock import patch
 
 import graphene
+import pytest
 from django.utils import timezone
 
 from ...discount import RewardValueType
@@ -128,6 +129,44 @@ def test_update_products_discounted_prices_for_promotion_task_with_rules_id(
     ) == {rule_id}
 
 
+@pytest.mark.parametrize("reward_value", [None, 0])
+@patch("saleor.product.tasks.PROMOTION_RULE_BATCH_SIZE", 1)
+@patch("saleor.product.tasks.update_discounted_prices_task.delay")
+@patch("saleor.product.utils.variants.fetch_variants_for_promotion_rules")
+def test_update_products_discounted_prices_for_promotion_task_with_empty_reward_value(
+    fetch_variants_for_promotion_rules_mock,
+    update_discounted_prices_task_mock,
+    reward_value,
+    promotion_list,
+    collection,
+    product_list,
+):
+    # given
+    Promotion.objects.update(start_date=timezone.now() - timedelta(days=1))
+    PromotionRuleVariant = PromotionRule.variants.through
+    PromotionRuleVariant.objects.all().delete()
+
+    collection.products.add(*product_list[1:])
+
+    rule = PromotionRule.objects.first()
+    rule.reward_value = reward_value
+    rule.save(update_fields=["reward_value"])
+    rule_id = PromotionRule.objects.first().id
+    product_ids = [product.id for product in product_list]
+
+    # when
+    update_products_discounted_prices_for_promotion_task(
+        product_ids, rule_ids=[rule_id]
+    )
+
+    # then
+    update_discounted_prices_task_mock.assert_called_once_with(product_ids)
+    assert (
+        set(PromotionRuleVariant.objects.values_list("promotionrule_id", flat=True))
+        == set()
+    )
+
+
 @patch("saleor.product.tasks.DISCOUNTED_PRODUCT_BATCH", 1)
 def test_update_discounted_prices_task(
     product_list,