Repository: fidals/shopelectro

Issue:
Меняем метку в yml
Меняем UTM метку в yml который отдается яндекс маркету https://www.shopelectro.ru/static/yandex.yml
напоминаю, что от этого фаила зависят и другие yml. в них не меняем.

<url>https://www.shopelectro.ru/catalog/products/4023/?utm_source=YM&amp;utm_medium=cpc&amp;utm_content=akkumuliatory-270&amp;utm_term=4023</url>

utm_medium=cpc нужно сменить на utm_medium=cpc-market


Discussion:
i'll fix it in two iterations:
- fast and dirty hack for production
- good code with tests and review
done fast fix at https://github.com/fidals/shopelectro/pull/657

Resolving patch:
diff --git a/shopelectro/management/commands/price.py b/shopelectro/management/commands/price.py
--- a/shopelectro/management/commands/price.py
+++ b/shopelectro/management/commands/price.py
@@ -36,6 +36,8 @@ def run(self, query_set: QuerySet) -> QuerySet:
         return self.FILTERS[self.utm](query_set)
 
 
+# @todo #661:120m Refactor price command.
+#  Create Price class with it's own price processing.
 class Command(BaseCommand):
     """Generate yml file for a given vendor (YM or price.ru)."""
 
@@ -48,10 +50,16 @@ class Command(BaseCommand):
         'Радиоприёмники', 'Фонари', 'Отвертки', 'Весы электронные портативные',
     ]
 
-    IGNORED_CATEGORIES_BY_TARGET = defaultdict(list, {
+    # dict keys are url targets for every service
+    IGNORED_CATEGORIES_MAP = defaultdict(list, {
         'GM': ['Усилители звука для слабослышащих'],
     })
 
+    UTM_MEDIUM_DATA = defaultdict(
+        lambda: 'cpc',
+        {'YM': 'cpc-market'}
+    )
+
     def create_prices(self):
         for target in settings.UTM_PRICE_MAP.items():
             self.generate_yml(*target)
@@ -66,14 +74,14 @@ def put_utm(product):
             """Put UTM attribute to product."""
             utm_marks = [
                 ('utm_source', utm),
-                ('utm_medium', 'cpc' if utm != 'YM' else 'cpc-market'),
+                ('utm_medium', cls.UTM_MEDIUM_DATA[utm]),
                 ('utm_content', product.get_root_category().page.slug),
                 ('utm_term', str(product.vendor_code)),
             ]
 
             url = reverse('product', args=(product.vendor_code,))
-            utm_mark_query = '&'.join('{}={}'.format(k, v) for k, v in utm_marks)
-            product.utm_url = '{}{}?{}'.format(settings.BASE_URL, url, utm_mark_query)
+            utm_mark_query = '&'.join(f'{k}={v}' for k, v in utm_marks)
+            product.utm_url = f'{settings.BASE_URL}{url}?{utm_mark_query}'
 
             product.prepared_params = [
                 (group, tags[0].name)
@@ -101,7 +109,7 @@ def filter_categories(utm):
                 Category.objects
                 .filter(
                     Q(name__in=cls.IGNORED_CATEGORIES)
-                    | Q(name__in=cls.IGNORED_CATEGORIES_BY_TARGET[utm])
+                    | Q(name__in=cls.IGNORED_CATEGORIES_MAP[utm])
                 )
                 .get_descendants(include_self=True)
             )


Test patch:
diff --git a/shopelectro/tests/tests_commands.py b/shopelectro/tests/tests_commands.py
--- a/shopelectro/tests/tests_commands.py
+++ b/shopelectro/tests/tests_commands.py
@@ -10,6 +10,7 @@
 import unittest
 import uuid
 from unittest import mock
+import urllib.parse
 from xml.etree import ElementTree
 
 from django.conf import settings
@@ -164,7 +165,7 @@ def tearDownClass(cls):
     def call_command_patched(cls, name):
         """Patch with test constants and call."""
         with mock.patch(
-            'shopelectro.management.commands.price.Command.IGNORED_CATEGORIES_BY_TARGET',
+            'shopelectro.management.commands.price.Command.IGNORED_CATEGORIES_MAP',
             new_callable=mock.PropertyMock
         ) as target:
             target.return_value = defaultdict(list, {
@@ -172,6 +173,8 @@ def call_command_patched(cls, name):
             })
             call_command(name)
 
+    # @todo #661:30m Refactor huge set of getters in prices test.
+    #  Move every `get_price_...` method to some `PriceNode` class.
     @staticmethod
     def get_price_file_path(filename):
         return os.path.join(settings.ASSETS_DIR, filename)
@@ -267,3 +270,12 @@ def test_brands(self):
                 product.get_brand_name(),
                 offer.find(f'vendor').text,
             )
+
+    def test_utm_yandex(self):
+        """Url tag of every offer should contain valid utm marks."""
+        offer = self.get_price_offers_node(
+            settings.UTM_PRICE_MAP['YM']
+        )[0]
+        url = offer.find('url').text
+        get_attrs = urllib.parse.parse_qs(url)
+        self.assertEqual('cpc-market', get_attrs['utm_medium'][0])