Repository: fidals/shopelectro

Issue:
header.html:157: Sort top menu subcategories by name #}
The puzzle `971-f15c5594` from #971 has to be resolved: 

https://github.com/fidals/shopelectro/blob/77991fd4612ae6a434e23aef3fd4d0ed83507740/templates/layout/header.html#L157-L157

The puzzle was created by duker33 on 28-Sep-19. 

Estimate: 60 minutes,  role: DEV. 

If you have any technical questions, don't ask me, submit new tickets instead. The task will be \"done\" when the problem is fixed and the text of the puzzle is _removed_ from the source code. Here is more about [PDD](http://www.yegor256.com/2009/03/04/pdd.html) and [about me](http://www.yegor256.com/2017/04/05/pdd-in-action.html). 



Discussion:
@artemiyds2 @duker33 please pay attention to this new issue.

Resolving patch:
diff --git a/shopelectro/logic/__init__.py b/shopelectro/logic/__init__.py
new file mode 100644
--- /dev/null
+++ b/shopelectro/logic/__init__.py
@@ -0,0 +1,3 @@
+from . import header
+
+__all__ = ['header']
diff --git a/shopelectro/logic/header.py b/shopelectro/logic/header.py
new file mode 100644
--- /dev/null
+++ b/shopelectro/logic/header.py
@@ -0,0 +1,24 @@
+from django.conf import settings
+from django.db.models import Q
+
+from pages import models as pages_models
+from shopelectro import models
+
+
+def menu_qs() -> pages_models.PageQuerySet:
+    return (
+        pages_models.Page.objects.active()
+        .filter(
+            Q(slug__in=settings.HEADER_LINKS['add'])
+            & ~Q(slug__in=settings.HEADER_LINKS['exclude'])
+            | (
+                # @todo #974:30m  Optimize the header menu query.
+                #  Fetch catalog page for the header menu at the same query.
+                #  root category pages.
+                Q(parent=pages_models.CustomPage.objects.filter(slug='catalog'))
+                & Q(related_model_name=models.Category._meta.db_table)
+                & Q(parent=pages_models.CustomPage.objects.filter(slug='catalog'))
+            )
+        )
+        .order_by('position')
+    )
diff --git a/shopelectro/templatetags/se_extras.py b/shopelectro/templatetags/se_extras.py
--- a/shopelectro/templatetags/se_extras.py
+++ b/shopelectro/templatetags/se_extras.py
@@ -10,7 +10,6 @@
 
 from images.models import ImageMixin
 from pages.models import Page
-
 from shopelectro.models import CategoryPage
 
 register = template.Library()
@@ -18,6 +17,8 @@
 
 @register.simple_tag
 def roots():
+    # @todo #974:60m  Reuse the logic.header.menu_qs menu menu query.
+    #  And test HEADER_LINKS "exclude/add" settings option.
     return sorted(
         chain(
             Page.objects.filter(slug__in=settings.HEADER_LINKS['add']),


Test patch:
diff --git a/shopelectro/tests/tests_logic.py b/shopelectro/tests/tests_logic.py
new file mode 100644
--- /dev/null
+++ b/shopelectro/tests/tests_logic.py
@@ -0,0 +1,14 @@
+from django.test import TestCase, override_settings, tag
+
+from shopelectro import models, logic
+
+
+@tag('fast')
+@override_settings(HEADER_LINKS={'exclude': [], 'add': []})
+class HeaderMenu(TestCase):
+    fixtures = ['dump.json']
+
+    def test_roots_are_presented(self):
+        from_db = set(models.CategoryPage.objects.get_cached_trees())
+        from_logic = set(logic.header.menu_qs())
+        self.assertEqual(from_db, from_logic)