Repository: fidals/shopelectro

Issue:
update_pack.py:20: Implement update_pack and render...
The puzzle `859-ae8cb052` from #859 has to be resolved: 

https://github.com/fidals/shopelectro/blob/029838cd8440741a382790fa6da0d8a790d3e423/shopelectro/management/commands/_update_catalog/update_pack.py#L20-L20

The puzzle was created by @artemiy312 on 31-May-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.
I have increased the estimate, because I made here little bit more then required 

Resolving patch:
diff --git a/shopelectro/management/commands/_update_catalog/update_pack.py b/shopelectro/management/commands/_update_catalog/update_pack.py
--- a/shopelectro/management/commands/_update_catalog/update_pack.py
+++ b/shopelectro/management/commands/_update_catalog/update_pack.py
@@ -6,18 +6,57 @@
 2. Multiply product prices by in_pack value and save.
 """
 import logging
+import typing
 
+from django.conf import settings
 from django.db import models, transaction
 
+from catalog.models_expressions import Substring
+
 from shopelectro.models import TagQuerySet, TagGroup
 
 logger = logging.getLogger(__name__)
 PRICES = ['price', 'purchase_price', 'wholesale_small', 'wholesale_medium', 'wholesale_large']
 
 
+def find_pack_group() -> typing.Optional[TagGroup]:
+    pack_group = TagGroup.objects.filter(uuid=settings.PACK_GROUP_UUID).first()
+
+    # @todo #864:60m Raise errors in find_pack_group.
+    #  Remove Optional type as returning value and test find_pack_group.
+    if not pack_group:
+        logger.error(
+            f'Couldn\'t find "{settings.PACK_GROUP_NAME}" tag group by'
+            f'UUID="{settings.PACK_GROUP_UUID}".\n'
+            'Update the PACK_GROUP_UUID django settings variable to set the new relevant UUID.'
+        )
+        pack_group = None
+    if not settings.PACK_GROUP_NAME.lower() not in pack_group.name.lower():
+        logger.error(
+            'The pack group name isn\'t matched with the set name:'
+            f' Pack group name: {pack_group.name}\n'
+            f' Set name: {settings.PACK_GROUP_NAME}\n'
+            'Update the PACK_GROUP_NAME django settings variable to set the new relevant name.'
+        )
+        pack_group = None
+
+    return pack_group
+
+
 def update_in_packs(packs: TagQuerySet):
     """Parse and save in pack quantity values."""
-    # @todo #859:60m Implement update_pack and render prices properly.
+    packs = (
+        packs
+        .annotate(
+            in_pack_str=Substring(
+                models.F('name'),
+                models.Value('[0-9]+\+?[0-9]*')))
+        .exclude(in_pack_str__exact='')
+    )
+
+    for pack in packs:
+        in_pack = sum(map(int, pack.in_pack_str.split('+')))
+        pack.products.all().update(in_pack=max(in_pack, 1))
 
 
 def update_prices(packs: TagQuerySet):
@@ -31,10 +70,8 @@ def update_prices(packs: TagQuerySet):
 
 
 def main(*args, **kwargs):
-    uuid = 'ae30f766-0bb8-11e6-80ea-02d2cc20e118'
-    pack_group = TagGroup.objects.filter(uuid=uuid).first()
+    pack_group = find_pack_group()
     if not pack_group:
-        logger.error(f'Couldn\'t find "Упаковка" tag group with uuid = "{uuid}".')
         return
 
     return
diff --git a/shopelectro/models.py b/shopelectro/models.py
--- a/shopelectro/models.py
+++ b/shopelectro/models.py
@@ -239,7 +239,7 @@ class TagGroup(catalog_models.TagGroup):
 class TagQuerySet(catalog_models.TagQuerySet):
 
     def products(self):
-        ids = Tag.objects.all().values_list('products__id', flat=True)
+        ids = self.values_list('products__id', flat=True)
         return Product.objects.filter(id__in=ids).distinct()
 
 
diff --git a/shopelectro/settings/base.py b/shopelectro/settings/base.py
--- a/shopelectro/settings/base.py
+++ b/shopelectro/settings/base.py
@@ -542,3 +542,7 @@ def get_robots_content():
             CeleryIntegration(),
         ]
     )
+
+# At 17.05.2019 it's relevant pack group data
+PACK_GROUP_UUID = 'ae30f766-0bb8-11e6-80ea-02d2cc20e118'
+PACK_GROUP_NAME = 'Упаковка'


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
@@ -43,12 +43,41 @@ class UpdatePack(TestCase):
 
     fixtures = ['dump.json']
 
+    def test_command(self):
+        """The command updates only packed products."""
+        # @todo #864:30m Test update_pack command.
+
+    def test_update_in_packs(self):
+        name_in_pack_map = {
+            'в пакете': 1,
+            '6+2 в блистере': 8,
+            '2 в блистере': 2,
+            '10 в стяжке': 10,
+        }
+
+        for pack, name in zip(TagGroup.objects.first().tags.all(), name_in_pack_map):
+            pack.name = name
+            pack.save()
+
+        def get_packs():
+            return Tag.objects.filter(name__in=name_in_pack_map)
+
+        update_pack.update_in_packs(get_packs())
+
+        for pack in get_packs():
+            for product in pack.products.all():
+                self.assertEqual(
+                    product.in_pack,
+                    name_in_pack_map[pack.name],
+                    f'Product: {product}, Pack: {pack}'
+                )
+
     def test_update_prices(self):
         # @todo #859:60m Create fixture products with in_pack = 2
         #  Resuse the fixture in related tests.
 
         mul = 2
-        tags = Tag.objects.all()
+        tags = TagGroup.objects.first().tags.all()
         tags.products().update(in_pack=mul)
         products = list(tags.products())