diff --git a/shopelectro/management/commands/price.py b/shopelectro/management/commands/price.py index 7b34b437..46cd7da9 100644 --- a/shopelectro/management/commands/price.py +++ b/shopelectro/management/commands/price.py @@ -67,23 +67,11 @@ def context(self) -> dict: class CategoriesFilter: """Categories list for particular market place.""" - # dict keys are url targets for every service - IGNORED_CATEGORIES_MAP = defaultdict(list, { - 'GM': ['Усилители звука для слабослышащих'], - 'YM': ['Пиротехника'], - # will be ignored by every category - 'default': [ - 'Измерительные приборы', 'Новогодние вращающиеся светодиодные лампы', - 'Новогодние лазерные проекторы', 'MP3- колонки', 'Беспроводные звонки', - 'Радиоприёмники', 'Фонари', 'Отвертки', 'Весы электронные портативные', - ] - }) - @property def ignored(self) -> typing.List[str]: return ( - self.IGNORED_CATEGORIES_MAP['default'] - + self.IGNORED_CATEGORIES_MAP[self.target] + settings.PRICE_IGNORED_CATEGORIES_MAP['default'] + + settings.PRICE_IGNORED_CATEGORIES_MAP[self.target] ) def __init__(self, target: str): @@ -121,6 +109,10 @@ def qs(self) -> models.SECategoryQuerySet: class ProductsFilter: """Filter offers with individual price requirements.""" + @property + def ignored(self) -> typing.List[str]: + return settings.PRICE_IGNORED_PRODUCTS_MAP[self.target] + FILTERS = defaultdict( lambda: (lambda qs: qs), # Yandex Market feed requires picture for every offer @@ -145,6 +137,7 @@ def qs(self) -> QuerySet: return self.FILTERS[self.target]( models.Product.objects.active() .filter(category__in=self.categories, price__gt=0) + .exclude(id__in=self.ignored) ) diff --git a/shopelectro/settings/base.py b/shopelectro/settings/base.py index 70ea64a5..df9fbfea 100644 --- a/shopelectro/settings/base.py +++ b/shopelectro/settings/base.py @@ -11,6 +11,7 @@ """ import os import socket +from collections import defaultdict from datetime import datetime import sentry_sdk @@ -499,6 +500,23 @@ def get_robots_content(): 'SE78': 'se78.yml', } +PRICE_IGNORED_CATEGORIES_MAP = defaultdict(list, { + 'GM': ['Усилители звука для слабослышащих'], + 'YM': ['Пиротехника'], + # will be ignored by every category + 'default': [ + 'Измерительные приборы', 'Новогодние вращающиеся светодиодные лампы', + 'Новогодние лазерные проекторы', 'MP3- колонки', 'Беспроводные звонки', + 'Радиоприёмники', 'Фонари', 'Отвертки', 'Весы электронные портативные', + ] +}) + + +# contains some values for example. Local.py will contain the real values +PRICE_IGNORED_PRODUCTS_MAP = defaultdict(list, { + 'YM': [1, 2, 3], +}) + # Number of pagination neighbors shown for page. # If PAGINATION_NEIGHBORS = 4 and number of a page = 5, # then will be shown neighbors by number: 3, 4, 6, 7 diff --git a/shopelectro/tests/tests_commands.py b/shopelectro/tests/tests_commands.py index 296c4133..a5a33cca 100644 --- a/shopelectro/tests/tests_commands.py +++ b/shopelectro/tests/tests_commands.py @@ -11,12 +11,11 @@ import urllib.parse import uuid from collections import defaultdict -from unittest import mock from xml.etree import ElementTree from django.conf import settings from django.core.management import call_command -from django.test import TestCase, tag +from django.test import TestCase, override_settings, tag from shopelectro.management.commands._update_catalog import ( update_products, update_tags @@ -213,10 +212,21 @@ class GeneratePrices(TestCase): fixtures = ['dump.json'] CATEGORY_TO_EXCLUDE = 'Category #1 of #Category #0 of #Category #1' + PRICE_IGNORED_CATEGORIES_MAP = defaultdict( + list, {'GM': [CATEGORY_TO_EXCLUDE]} + ) + ignore_categories = override_settings( + PRICE_IGNORED_CATEGORIES_MAP=PRICE_IGNORED_CATEGORIES_MAP + ) + PRODUCTS_TO_EXCLUDE = [1, 2, 3] + ignore_products = override_settings( + PRICE_IGNORED_PRODUCTS_MAP=defaultdict(list, {'YM': PRODUCTS_TO_EXCLUDE}) + ) @classmethod def setUpTestData(cls): - cls.call_command_patched('price') + with cls.ignore_categories, cls.ignore_products: + call_command('price') super(GeneratePrices, cls).setUpTestData() cls.prices = Prices(settings.UTM_PRICE_MAP.keys()) @@ -225,18 +235,6 @@ def tearDownClass(cls): cls.prices.remove() super(GeneratePrices, cls).tearDownClass() - @classmethod - def call_command_patched(cls, name): - """Patch with test constants and call.""" - with mock.patch( - 'shopelectro.management.commands.price.CategoriesFilter.IGNORED_CATEGORIES_MAP', - new_callable=mock.PropertyMock - ) as target: - target.return_value = defaultdict(list, { - 'GM': [cls.CATEGORY_TO_EXCLUDE] - }) - call_command(name) - def test_prices_exists(self): """Price command should generate various price-list files.""" price_file_min_size = 10 ** 3 # ~1kb @@ -257,6 +255,7 @@ def test_categories_in_yandex_price(self): Category.objects.get_categories_tree_with_pictures().count() ) + @ignore_categories def test_categories_excluded_by_utm(self): """Price file should not contain it's excluded category.""" def find_category(categories, name): @@ -282,6 +281,15 @@ def find_category(categories, name): ) ) + @ignore_products + def test_products_excluded_by_id(self): + to_ignore = set(settings.PRICE_IGNORED_PRODUCTS_MAP['YM']) + ignored = set( + offer.attrib['id'] + for offer in self.prices['YM'].offers_node.findall('offer') + ) + self.assertFalse(to_ignore.intersection(ignored)) + def test_products_in_price(self): products = self.prices['priceru'].offers_node self.assertEqual(len(products), Product.objects.count()) @@ -296,10 +304,16 @@ def test_products_in_gm_price_bounds(self): self.assertTrue(prices_are_in_bounds) def test_products_in_yandex_price(self): - products = self.prices['YM'].offers_node + origin = ( + Product.objects + .exclude(id__in=self.PRODUCTS_TO_EXCLUDE) + .filter(page__images__isnull=False) + .distinct() + ) + result = self.prices['YM'].offers_node self.assertEqual( - len(products), - Product.objects.filter(page__images__isnull=False).distinct().count() + len(result), + origin.count() ) def test_brands(self): diff --git a/templates/prices/price.yml b/templates/prices/price.yml index f84ab8d0..028ee2c3 100644 --- a/templates/prices/price.yml +++ b/templates/prices/price.yml @@ -41,7 +41,7 @@ {% endif %} {% endcomment %} - {% if not utm == 'GM' %} + {% if not utm == 'GM' and not utm == 'YM' %} При заказе от {{ shop.local_delivery_cost_threshold }} руб. доставка по СПб бесплатно {% endif %} {% if product.brand %}{{ product.brand.name }}{% endif %}