Skip to content

Commit

Permalink
#769 Ignore price entities with config (#770)
Browse files Browse the repository at this point in the history
* #769  Hide the string with delivery details in price for Ya.Market

* #769  Ignore price products by ids

* #769  Move price ignored entities to settings

* #769  Fix tests for categories

* #769  Fix tests

* #769  Apply linter
  • Loading branch information
duker33 authored Mar 13, 2019
1 parent 212b084 commit 394cb2a
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 33 deletions.
21 changes: 7 additions & 14 deletions shopelectro/management/commands/price.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down Expand Up @@ -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
Expand All @@ -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)
)


Expand Down
18 changes: 18 additions & 0 deletions shopelectro/settings/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"""
import os
import socket
from collections import defaultdict
from datetime import datetime

import sentry_sdk
Expand Down Expand Up @@ -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
Expand Down
50 changes: 32 additions & 18 deletions shopelectro/tests/tests_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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())

Expand All @@ -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
Expand All @@ -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):
Expand All @@ -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())
Expand All @@ -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):
Expand Down
2 changes: 1 addition & 1 deletion templates/prices/price.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
{% endif %}
{% endcomment %}
<description></description>
{% if not utm == 'GM' %}
{% if not utm == 'GM' and not utm == 'YM' %}
<sales_notes>При заказе от {{ shop.local_delivery_cost_threshold }} руб. доставка по СПб бесплатно</sales_notes>
{% endif %}
{% if product.brand %}<vendor>{{ product.brand.name }}</vendor>{% endif %}
Expand Down

0 comments on commit 394cb2a

Please sign in to comment.