Repository: fidals/shopelectro

Issue:
Catalog import from xml
Add management command to get catalog data from xml file.



Discussion:

Resolving patch:
diff --git a/shopelectro/models.py b/shopelectro/models.py
--- a/shopelectro/models.py
+++ b/shopelectro/models.py
@@ -6,6 +6,7 @@
 from django.db import models
 from django.db.models import Avg, Q
 from django.conf import settings
+from django.utils.translation import ugettext_lazy as _
 from django.urls import reverse
 
 from catalog.models import (
@@ -73,18 +74,25 @@ class Product(AbstractProduct, SyncPageMixin):
     objects = SEProductManager()
 
     category = models.ForeignKey(
-        Category, on_delete=models.CASCADE, null=True, related_name='products'
+        Category,
+        on_delete=models.CASCADE,
+        null=True,
+        related_name='products',
+        verbose_name=_('category'),
     )
 
     tags = models.ManyToManyField(
-        'Tag', related_name='products', blank=True
+        'Tag',
+        related_name='products',
+        blank=True,
+        verbose_name=_('tags'),
     )
 
     uuid = models.UUIDField(default=uuid4, editable=False)
-    purchase_price = models.FloatField(default=0)
-    wholesale_small = models.FloatField(default=0)
-    wholesale_medium = models.FloatField(default=0)
-    wholesale_large = models.FloatField(default=0)
+    purchase_price = models.FloatField(default=0, verbose_name=_('purchase_price'))
+    wholesale_small = models.FloatField(default=0, verbose_name=_('wholesale_small'))
+    wholesale_medium = models.FloatField(default=0, verbose_name=_('wholesale_medium'))
+    wholesale_large = models.FloatField(default=0, verbose_name=_('wholesale_large'))
 
     def get_absolute_url(self):
         return reverse('product', args=(self.id,))
@@ -109,12 +117,12 @@ class ProductFeedback(models.Model):
         related_name='product_feedbacks'
     )
 
-    date = models.DateTimeField(auto_now=True, db_index=True)
-    name = models.CharField(max_length=255, db_index=True)
-    rating = models.PositiveSmallIntegerField(default=1, db_index=True)
-    dignities = models.TextField(default='', blank=True)
-    limitations = models.TextField(default='', blank=True)
-    general = models.TextField(default='', blank=True)
+    date = models.DateTimeField(auto_now=True, db_index=True, verbose_name=_('date'))
+    name = models.CharField(max_length=255, db_index=True, verbose_name=_('name'))
+    rating = models.PositiveSmallIntegerField(default=1, db_index=True, verbose_name=_('rating'))
+    dignities = models.TextField(default='', blank=True, verbose_name=_('dignities'))
+    limitations = models.TextField(default='', blank=True, verbose_name=_('limitations'))
+    general = models.TextField(default='', blank=True, verbose_name=_('limitations'))
 
 
 def _default_payment():
@@ -158,8 +166,10 @@ class Meta(ModelPage.Meta):
 
 class TagGroup(models.Model):
 
-    name = models.CharField(max_length=100, db_index=True)
-    position = models.PositiveSmallIntegerField(default=0, blank=True, db_index=True)
+    name = models.CharField(max_length=100, db_index=True, verbose_name=_('name'))
+    position = models.PositiveSmallIntegerField(
+        default=0, blank=True, db_index=True, verbose_name=_('position'),
+    )
     uuid = models.UUIDField(default=uuid4, editable=False)
 
     def __str__(self):
@@ -195,8 +205,10 @@ def get_group_tags_pairs(self, tags=None):
 
 class Tag(models.Model):
 
-    name = models.CharField(max_length=100, db_index=True)
-    position = models.PositiveSmallIntegerField(default=0, blank=True, db_index=True)
+    name = models.CharField(max_length=100, db_index=True, verbose_name=_('name'))
+    position = models.PositiveSmallIntegerField(
+        default=0, blank=True, db_index=True, verbose_name=_('position'),
+    )
     uuid = models.UUIDField(default=uuid4, editable=False)
 
     objects = TagManager()
diff --git a/shopelectro/settings/base.py b/shopelectro/settings/base.py
--- a/shopelectro/settings/base.py
+++ b/shopelectro/settings/base.py
@@ -78,6 +78,7 @@
     'django.contrib.messages.middleware.MessageMiddleware',
     'django.middleware.clickjacking.XFrameOptionsMiddleware',
     'django.contrib.redirects.middleware.RedirectFallbackMiddleware',
+    'django.middleware.locale.LocaleMiddleware',
     'shopelectro.middleware.PatchedUserAgentMiddleware',
     'debug_toolbar.middleware.DebugToolbarMiddleware',
 ]
@@ -134,6 +135,7 @@
 USE_L10N = True
 USE_TZ = True
 
+LOCALE_PATHS = [os.path.join(BASE_DIR, 'shopelectro/locale')]
 FORMAT_MODULE_PATH = [
     'shopelectro.formats',
 ]
@@ -144,6 +146,8 @@
 STATIC_ROOT = os.path.join(BASE_DIR, 'static')
 ASSETS_DIR = os.path.join(BASE_DIR, 'assets')
 
+STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.ManifestStaticFilesStorage'
+
 STATICFILES_DIRS = [
     os.path.join(BASE_DIR, 'front/build'),
     ASSETS_DIR,


Test patch:
diff --git a/shopelectro/tests/helpers.py b/shopelectro/tests/helpers.py
new file mode 100644
--- /dev/null
+++ b/shopelectro/tests/helpers.py
@@ -0,0 +1,7 @@
+from django.test import override_settings
+
+set_default_staticfiles_storage = override_settings(
+    STATICFILES_STORAGE='django.contrib.staticfiles.storage.StaticFilesStorage',
+)
+
+disable_celery = override_settings(USE_CELERY=False)
diff --git a/shopelectro/tests/tests_selenium.py b/shopelectro/tests/tests_selenium.py
--- a/shopelectro/tests/tests_selenium.py
+++ b/shopelectro/tests/tests_selenium.py
@@ -18,6 +18,7 @@
 from pages.models import FlatPage, CustomPage, Page
 
 from shopelectro.models import Category, Product
+from shopelectro.tests.helpers import set_default_staticfiles_storage, disable_celery
 
 
 def wait(seconds=1):
@@ -79,7 +80,8 @@ def tearDownClass(cls):
         super(SeleniumTestCase, cls).tearDownClass()
 
 
-@override_settings(DEBUG=True, INTERNAL_IPS=tuple(), USE_CELERY=False)
+@disable_celery
+@override_settings(DEBUG=True, INTERNAL_IPS=tuple())
 class Header(SeleniumTestCase):
 
     def setUp(self):
@@ -135,6 +137,7 @@ def test_product_total_price_in_dropdown(self):
         self.assertTrue(product_price == product_total_price_price_in_cart)
 
 
+@set_default_staticfiles_storage
 class CategoryPage(SeleniumTestCase):
 
     PRODUCTS_TO_LOAD = 48
@@ -370,6 +373,7 @@ def test_load_more_after_filtering(self):
         self.assertEqual(new_product_cards, 50)
 
 
+@set_default_staticfiles_storage
 class ProductPage(SeleniumTestCase):
 
     PRODUCT_ID = 1
@@ -439,7 +443,7 @@ def test_one_click_buy_disabled_with_empty_phone(self):
 
         self.assertTrue(self.one_click.get_attribute('disabled'))
 
-    @override_settings(USE_CELERY=False)
+    @disable_celery
     def test_one_click_buy_action(self):
         """We can order product via one-click buy button."""
         self.browser.find_element_by_id(
@@ -511,7 +515,8 @@ def test_feedback_filter(self):
         self.assertTrue(all(not element.is_displayed() for element in feedbacks))
 
 
-@override_settings(USE_CELERY=False)
+@disable_celery
+@set_default_staticfiles_storage
 class OrderPage(SeleniumTestCase):
 
     @staticmethod
@@ -693,7 +698,8 @@ def test_accordion_minimize_by_double_click(self):
         self.assertFalse(accordion_content.is_displayed())
 
 
-@override_settings(DEBUG=True, INTERNAL_IPS=tuple(), USE_CELERY=False)
+@disable_celery
+@override_settings(DEBUG=True, INTERNAL_IPS=tuple())
 class YandexMetrika(SeleniumTestCase):
 
     def setUp(self):
diff --git a/shopelectro/tests/tests_selenium_admin.py b/shopelectro/tests/tests_selenium_admin.py
--- a/shopelectro/tests/tests_selenium_admin.py
+++ b/shopelectro/tests/tests_selenium_admin.py
@@ -16,6 +16,7 @@
 from django.urls import reverse
 
 from shopelectro.models import Category, Product
+from shopelectro.tests.helpers import disable_celery
 
 
 def wait(seconds=1):
@@ -146,7 +147,7 @@ def test_product_price_filter(self):
         self.browser.find_element_by_xpath(self.price_filter).click()
         wait()
         product = self.browser.find_element_by_xpath('//*[@id="result_list"]/tbody/tr[1]/td[4]')
-        product_price = int(float(product.text))
+        product_price = int(float(product.text.replace(',', '.')))
 
         self.assertTrue(product_price >= 1000)
 
@@ -260,7 +261,7 @@ def test_tree_redirect_to_table_editor_page(self):
         wait()
 
         test_h1 = self.browser.find_elements_by_tag_name('h1')[1].text
-        self.assertEqual(test_h1, 'Table editor')
+        self.assertEqual(test_h1, 'Табличный редактор')
 
         test_search_value = self.browser.find_element_by_id('search-field').get_attribute('value')
         self.assertTrue(len(test_search_value) > 0)
@@ -296,7 +297,7 @@ def test_sidebar_toggle(self):
 
         self.assertTrue('collapsed' in body_classes)
 
-    @override_settings(USE_CELERY=False)
+    @disable_celery
     def test_yandex_feedback_request(self):
         """Send mail with request for leaving feedback on Ya.Market."""
         self.browser.find_element_by_class_name('js-toggle-sidebar').click()
@@ -307,6 +308,7 @@ def test_yandex_feedback_request(self):
         self.assertTrue('Письмо с отзывом успешно отправлено' in self.browser.page_source)
 
 
+@override_settings(LANGUAGE_CODE='ru-ru', LANGUAGES=(('ru', 'Russian'),))
 class TableEditor(SeleniumTestCase):
     """Selenium-based tests for Table Editor [TE]."""
 
@@ -420,10 +422,10 @@ def test_products_loaded(self):
 
     def test_edit_product_name(self):
         """We could change Product name from TE."""
-        self.get_cell(1).click()
-        self.update_input_value(0, self.new_product_name)
+        self.get_cell(2).click()
+        self.update_input_value(1, self.new_product_name)
         self.refresh_table_editor_page()
-        updated_name = self.get_cell(1).text
+        updated_name = self.get_cell(2).text
 
         self.assertEqual(updated_name, self.new_product_name)
 
@@ -479,10 +481,10 @@ def test_sort_table_by_id(self):
     def test_sort_table_by_price(self):
         """We could sort products in TE by price."""
         first_product_price_before = self.get_cell(1).text
-        name_header = self.browser.find_elements_by_class_name('ui-jqgrid-sortable')[1]
+        name_header = self.browser.find_elements_by_class_name('ui-jqgrid-sortable')[3]
         name_header.click()
         name_header.click()
-        first_product_price_after = self.get_cell(1).text
+        first_product_price_after = self.get_cell(3).text
 
         self.assertNotEqual(first_product_price_before, first_product_price_after)
 
@@ -569,7 +571,7 @@ def test_new_entity_creation(self):
         self.browser.find_element_by_class_name('js-modal-close').click()
         wait()
         first_row = self.browser.find_element_by_id('jqGrid').find_element_by_class_name('jqgrow')
-        name_cell = first_row.find_elements_by_tag_name('td')[1]
+        name_cell = first_row.find_elements_by_tag_name('td')[2]
         self.assertEqual(name_cell.get_attribute('title'), new_entity_text)
 
         # We are able to change newly created entity: