We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
models.py:85: Explore and doc what is vendor_code.
The puzzle `910-f547fee5` from #910 has to be resolved: 

https://github.com/fidals/shopelectro/blob/e7de650f01b749f584f374923d7863083cc83b3c/shopelectro/models.py#L85-L85

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

Estimate: 30 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). 


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `shopelectro/models.py`
Content:
```
1 import enum
2 import random
3 import string
4 import typing
5 from uuid import uuid4
6 
7 from django.conf import settings
8 from django.db import models
9 from django.urls import reverse
10 from django.utils.translation import ugettext_lazy as _
11 
12 from catalog import models as catalog_models
13 from ecommerce import models as ecommerce_models
14 from pages import models as pages_models
15 
16 
17 def randomize_slug(slug: str) -> str:
18     slug_hash = ''.join(
19         random.choices(string.ascii_lowercase, k=settings.SLUG_HASH_SIZE)
20     )
21     return f'{slug}_{slug_hash}'
22 
23 
24 class SECategoryQuerySet(catalog_models.CategoryQuerySet):
25     def get_categories_tree_with_pictures(self) -> 'SECategoryQuerySet':
26         categories_with_pictures = (
27             self
28             .filter(products__page__images__isnull=False)
29             .distinct()
30         )
31 
32         return categories_with_pictures.get_ancestors(include_self=True)
33 
34 
35 class SECategoryManager(
36     catalog_models.CategoryManager.from_queryset(SECategoryQuerySet)
37 ):
38     pass
39 
40 
41 class Category(catalog_models.AbstractCategory, pages_models.SyncPageMixin):
42 
43     objects = SECategoryManager()
44     uuid = models.UUIDField(default=uuid4, editable=False)
45 
46     @classmethod
47     def get_default_parent(cls):
48         return pages_models.CustomPage.objects.filter(slug='catalog').first()
49 
50     @property
51     def image(self):
52         products = self.products.all()
53         return products[0].image if products else None
54 
55     def get_absolute_url(self):
56         return reverse('category', args=(self.page.slug,))
57 
58 
59 class Product(
60     catalog_models.AbstractProduct,
61     catalog_models.AbstractPosition,
62     pages_models.SyncPageMixin
63 ):
64 
65     # That's why we are needed to explicitly add objects manager here
66     # because of Django special managers behaviour.
67     # Se se#480 for details.
68     objects = catalog_models.ProductManager()
69 
70     category = models.ForeignKey(
71         Category,
72         on_delete=models.CASCADE,
73         null=True,
74         related_name='products',
75         verbose_name=_('category'),
76     )
77 
78     tags = models.ManyToManyField(
79         'Tag',
80         related_name='products',
81         blank=True,
82         verbose_name=_('tags'),
83     )
84 
85     # @todo #910:30m  Explore and doc what is vendor_code.
86     vendor_code = models.SmallIntegerField(verbose_name=_('vendor_code'))
87     uuid = models.UUIDField(default=uuid4, editable=False)
88     purchase_price = models.FloatField(
89         default=0, verbose_name=_('purchase_price'))
90     wholesale_small = models.FloatField(
91         default=0, verbose_name=_('wholesale_small'))
92     wholesale_medium = models.FloatField(
93         default=0, verbose_name=_('wholesale_medium'))
94     wholesale_large = models.FloatField(
95         default=0, verbose_name=_('wholesale_large'))
96 
97     in_pack = models.PositiveSmallIntegerField(
98         default=1,
99         verbose_name=_('in pack'),
100     )
101 
102     def get_absolute_url(self):
103         return reverse('product', args=(self.vendor_code,))
104 
105     @property
106     def average_rate(self):
107         """Return rounded to first decimal averaged rating."""
108         rating = self.product_feedbacks.aggregate(
109             avg=models.Avg('rating')).get('avg', 0)
110         return round(rating, 1)
111 
112     @property
113     def feedback_count(self):
114         return self.product_feedbacks.count()
115 
116     @property
117     def feedback(self):
118         return self.product_feedbacks.all().order_by('-date')
119 
120     def get_params(self):
121         return Tag.objects.filter_by_products([self]).group_tags()
122 
123     def get_brand_name(self) -> str:
124         brand: typing.Optional['Tag'] = Tag.objects.get_brands([self]).get(self)
125         return brand.name if brand else ''
126 
127 
128 class ProductFeedback(models.Model):
129     product = models.ForeignKey(
130         Product, on_delete=models.CASCADE, null=True,
131         related_name='product_feedbacks'
132     )
133 
134     date = models.DateTimeField(
135         auto_now=True, db_index=True, verbose_name=_('date'))
136     name = models.CharField(
137         max_length=255, db_index=True, verbose_name=_('name'))
138     rating = models.PositiveSmallIntegerField(
139         default=1, db_index=True, verbose_name=_('rating'))
140     dignities = models.TextField(
141         default='', blank=True, verbose_name=_('dignities'))
142     limitations = models.TextField(
143         default='', blank=True, verbose_name=_('limitations'))
144     general = models.TextField(
145         default='', blank=True, verbose_name=_('limitations'))
146 
147 
148 class ItemsEnum(enum.EnumMeta):
149     """
150     Provide dict-like `items` method.
151 
152     https://docs.python.org/3/library/enum.html#enum-classes
153     """
154 
155     def items(self):
156         return [(i.name, i.value) for i in self]
157 
158     def __repr__(self):
159         fields = ', '.join(i.name for i in self)
160         return f"<enum '{self.__name__}: {fields}'>"
161 
162 
163 class PaymentOptions(enum.Enum, metaclass=ItemsEnum):
164     cash = 'Наличные'
165     cashless = 'Безналичные и денежные переводы'
166     AC = 'Банковская карта'
167     PC = 'Яндекс.Деньги'
168     GP = 'Связной (терминал)'
169     AB = 'Альфа-Клик'
170 
171     @staticmethod
172     def default():
173         return PaymentOptions.cash
174 
175 
176 class Order(ecommerce_models.Order):
177     address = models.TextField(blank=True, default='')
178     payment_type = models.CharField(
179         max_length=255,
180         choices=PaymentOptions.items(),
181         default=PaymentOptions.default().name,
182     )
183     comment = models.TextField(blank=True, default='')
184     # total price - total purchase price
185     revenue = models.FloatField(default=0, null=True, verbose_name=_('revenue'))
186 
187     @property
188     def payment_type_label(self):
189         """Return label for an order's payment option."""
190         return PaymentOptions[self.payment_type].value
191 
192     def set_positions(self, cart):
193         """
194         Save cart's state into Order instance.
195 
196         @todo #589:60m Create Cart model.
197          See details here: https://github.com/fidals/shopelectro/pull/590#discussion_r222544672
198         """
199         self.revenue = cart.total_revenue()
200         self.save()
201         for id_, position in cart:
202             self.positions.create(
203                 order=self,
204                 product_id=id_,
205                 vendor_code=position['vendor_code'],
206                 name=position['name'],
207                 price=position['price'],
208                 quantity=position['quantity'],
209             )
210         return self
211 
212 
213 class CategoryPage(pages_models.ModelPage):
214     """Create proxy model for Admin."""
215 
216     class Meta(pages_models.ModelPage.Meta):  # Ignore PycodestyleBear (E303)
217         proxy = True
218 
219     # noinspection PyTypeChecker
220     objects = pages_models.ModelPage.create_model_page_managers(Category)
221 
222 
223 class ProductPage(pages_models.ModelPage):
224     """Create proxy model for Admin."""
225 
226     class Meta(pages_models.ModelPage.Meta):  # Ignore PycodestyleBear (E303)
227         proxy = True
228 
229     # noinspection PyTypeChecker
230     objects = (
231         pages_models.ModelPage
232         .create_model_page_managers(Product)
233     )
234 
235 
236 class TagGroupManager(models.Manager):
237 
238     def get_pack(self):
239         return self.get_queryset().get(uuid=settings.PACK_GROUP_UUID)
240 
241 
242 class TagGroup(catalog_models.TagGroup):
243 
244     objects = TagGroupManager()
245 
246 
247 class TagQuerySet(catalog_models.TagQuerySet):
248 
249     def products(self):
250         ids = self.values_list('products__id', flat=True)
251         return Product.objects.filter(id__in=ids).distinct()
252 
253 
254 class TagManager(catalog_models.TagManager.from_queryset(TagQuerySet)):
255 
256     def get_packs(self):
257         return TagGroup.objects.get_pack().tags.all()
258 
259 
260 class Tag(catalog_models.Tag):
261     group = models.ForeignKey(
262         TagGroup, on_delete=models.CASCADE, null=True, related_name='tags',
263     )
264 
265     objects = TagManager()
266
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/shopelectro/models.py b/shopelectro/models.py
--- a/shopelectro/models.py
+++ b/shopelectro/models.py
@@ -82,7 +82,13 @@
         verbose_name=_('tags'),
     )
 
-    # @todo #910:30m  Explore and doc what is vendor_code.
+    # `vendor_code` is a code that refers to the particular stock keeping unit (SKU).
+    # You can treat it as public unique id. Use it to publicly identify a product.
+
+    # We bring codes from 1C database and sync with products.
+    # We doesn't use the id field instead, because it is auto-increment sequence,
+    # that can't be changed easily. We decided to avoid that complexity.
+    # https://www.postgresql.org/docs/current/functions-sequence.html
     vendor_code = models.SmallIntegerField(verbose_name=_('vendor_code'))
     uuid = models.UUIDField(default=uuid4, editable=False)
     purchase_price = models.FloatField(

{"golden_diff": "diff --git a/shopelectro/models.py b/shopelectro/models.py\n--- a/shopelectro/models.py\n+++ b/shopelectro/models.py\n@@ -82,7 +82,13 @@\n         verbose_name=_('tags'),\n     )\n \n-    # @todo #910:30m  Explore and doc what is vendor_code.\n+    # `vendor_code` is a code that refers to the particular stock keeping unit (SKU).\n+    # You can treat it as public unique id. Use it to publicly identify a product.\n+\n+    # We bring codes from 1C database and sync with products.\n+    # We doesn't use the id field instead, because it is auto-increment sequence,\n+    # that can't be changed easily. We decided to avoid that complexity.\n+    # https://www.postgresql.org/docs/current/functions-sequence.html\n     vendor_code = models.SmallIntegerField(verbose_name=_('vendor_code'))\n     uuid = models.UUIDField(default=uuid4, editable=False)\n     purchase_price = models.FloatField(\n", "issue": "models.py:85: Explore and doc what is vendor_code.\nThe puzzle `910-f547fee5` from #910 has to be resolved: \n\nhttps://github.com/fidals/shopelectro/blob/e7de650f01b749f584f374923d7863083cc83b3c/shopelectro/models.py#L85-L85\n\nThe puzzle was created by duker33 on 28-Jun-19. \n\nEstimate: 30 minutes,  role: DEV. \n\nIf 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). \n\n", "before_files": [{"content": "import enum\nimport random\nimport string\nimport typing\nfrom uuid import uuid4\n\nfrom django.conf import settings\nfrom django.db import models\nfrom django.urls import reverse\nfrom django.utils.translation import ugettext_lazy as _\n\nfrom catalog import models as catalog_models\nfrom ecommerce import models as ecommerce_models\nfrom pages import models as pages_models\n\n\ndef randomize_slug(slug: str) -> str:\n    slug_hash = ''.join(\n        random.choices(string.ascii_lowercase, k=settings.SLUG_HASH_SIZE)\n    )\n    return f'{slug}_{slug_hash}'\n\n\nclass SECategoryQuerySet(catalog_models.CategoryQuerySet):\n    def get_categories_tree_with_pictures(self) -> 'SECategoryQuerySet':\n        categories_with_pictures = (\n            self\n            .filter(products__page__images__isnull=False)\n            .distinct()\n        )\n\n        return categories_with_pictures.get_ancestors(include_self=True)\n\n\nclass SECategoryManager(\n    catalog_models.CategoryManager.from_queryset(SECategoryQuerySet)\n):\n    pass\n\n\nclass Category(catalog_models.AbstractCategory, pages_models.SyncPageMixin):\n\n    objects = SECategoryManager()\n    uuid = models.UUIDField(default=uuid4, editable=False)\n\n    @classmethod\n    def get_default_parent(cls):\n        return pages_models.CustomPage.objects.filter(slug='catalog').first()\n\n    @property\n    def image(self):\n        products = self.products.all()\n        return products[0].image if products else None\n\n    def get_absolute_url(self):\n        return reverse('category', args=(self.page.slug,))\n\n\nclass Product(\n    catalog_models.AbstractProduct,\n    catalog_models.AbstractPosition,\n    pages_models.SyncPageMixin\n):\n\n    # That's why we are needed to explicitly add objects manager here\n    # because of Django special managers behaviour.\n    # Se se#480 for details.\n    objects = catalog_models.ProductManager()\n\n    category = models.ForeignKey(\n        Category,\n        on_delete=models.CASCADE,\n        null=True,\n        related_name='products',\n        verbose_name=_('category'),\n    )\n\n    tags = models.ManyToManyField(\n        'Tag',\n        related_name='products',\n        blank=True,\n        verbose_name=_('tags'),\n    )\n\n    # @todo #910:30m  Explore and doc what is vendor_code.\n    vendor_code = models.SmallIntegerField(verbose_name=_('vendor_code'))\n    uuid = models.UUIDField(default=uuid4, editable=False)\n    purchase_price = models.FloatField(\n        default=0, verbose_name=_('purchase_price'))\n    wholesale_small = models.FloatField(\n        default=0, verbose_name=_('wholesale_small'))\n    wholesale_medium = models.FloatField(\n        default=0, verbose_name=_('wholesale_medium'))\n    wholesale_large = models.FloatField(\n        default=0, verbose_name=_('wholesale_large'))\n\n    in_pack = models.PositiveSmallIntegerField(\n        default=1,\n        verbose_name=_('in pack'),\n    )\n\n    def get_absolute_url(self):\n        return reverse('product', args=(self.vendor_code,))\n\n    @property\n    def average_rate(self):\n        \"\"\"Return rounded to first decimal averaged rating.\"\"\"\n        rating = self.product_feedbacks.aggregate(\n            avg=models.Avg('rating')).get('avg', 0)\n        return round(rating, 1)\n\n    @property\n    def feedback_count(self):\n        return self.product_feedbacks.count()\n\n    @property\n    def feedback(self):\n        return self.product_feedbacks.all().order_by('-date')\n\n    def get_params(self):\n        return Tag.objects.filter_by_products([self]).group_tags()\n\n    def get_brand_name(self) -> str:\n        brand: typing.Optional['Tag'] = Tag.objects.get_brands([self]).get(self)\n        return brand.name if brand else ''\n\n\nclass ProductFeedback(models.Model):\n    product = models.ForeignKey(\n        Product, on_delete=models.CASCADE, null=True,\n        related_name='product_feedbacks'\n    )\n\n    date = models.DateTimeField(\n        auto_now=True, db_index=True, verbose_name=_('date'))\n    name = models.CharField(\n        max_length=255, db_index=True, verbose_name=_('name'))\n    rating = models.PositiveSmallIntegerField(\n        default=1, db_index=True, verbose_name=_('rating'))\n    dignities = models.TextField(\n        default='', blank=True, verbose_name=_('dignities'))\n    limitations = models.TextField(\n        default='', blank=True, verbose_name=_('limitations'))\n    general = models.TextField(\n        default='', blank=True, verbose_name=_('limitations'))\n\n\nclass ItemsEnum(enum.EnumMeta):\n    \"\"\"\n    Provide dict-like `items` method.\n\n    https://docs.python.org/3/library/enum.html#enum-classes\n    \"\"\"\n\n    def items(self):\n        return [(i.name, i.value) for i in self]\n\n    def __repr__(self):\n        fields = ', '.join(i.name for i in self)\n        return f\"<enum '{self.__name__}: {fields}'>\"\n\n\nclass PaymentOptions(enum.Enum, metaclass=ItemsEnum):\n    cash = '\u041d\u0430\u043b\u0438\u0447\u043d\u044b\u0435'\n    cashless = '\u0411\u0435\u0437\u043d\u0430\u043b\u0438\u0447\u043d\u044b\u0435 \u0438 \u0434\u0435\u043d\u0435\u0436\u043d\u044b\u0435 \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u044b'\n    AC = '\u0411\u0430\u043d\u043a\u043e\u0432\u0441\u043a\u0430\u044f \u043a\u0430\u0440\u0442\u0430'\n    PC = '\u042f\u043d\u0434\u0435\u043a\u0441.\u0414\u0435\u043d\u044c\u0433\u0438'\n    GP = '\u0421\u0432\u044f\u0437\u043d\u043e\u0439 (\u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b)'\n    AB = '\u0410\u043b\u044c\u0444\u0430-\u041a\u043b\u0438\u043a'\n\n    @staticmethod\n    def default():\n        return PaymentOptions.cash\n\n\nclass Order(ecommerce_models.Order):\n    address = models.TextField(blank=True, default='')\n    payment_type = models.CharField(\n        max_length=255,\n        choices=PaymentOptions.items(),\n        default=PaymentOptions.default().name,\n    )\n    comment = models.TextField(blank=True, default='')\n    # total price - total purchase price\n    revenue = models.FloatField(default=0, null=True, verbose_name=_('revenue'))\n\n    @property\n    def payment_type_label(self):\n        \"\"\"Return label for an order's payment option.\"\"\"\n        return PaymentOptions[self.payment_type].value\n\n    def set_positions(self, cart):\n        \"\"\"\n        Save cart's state into Order instance.\n\n        @todo #589:60m Create Cart model.\n         See details here: https://github.com/fidals/shopelectro/pull/590#discussion_r222544672\n        \"\"\"\n        self.revenue = cart.total_revenue()\n        self.save()\n        for id_, position in cart:\n            self.positions.create(\n                order=self,\n                product_id=id_,\n                vendor_code=position['vendor_code'],\n                name=position['name'],\n                price=position['price'],\n                quantity=position['quantity'],\n            )\n        return self\n\n\nclass CategoryPage(pages_models.ModelPage):\n    \"\"\"Create proxy model for Admin.\"\"\"\n\n    class Meta(pages_models.ModelPage.Meta):  # Ignore PycodestyleBear (E303)\n        proxy = True\n\n    # noinspection PyTypeChecker\n    objects = pages_models.ModelPage.create_model_page_managers(Category)\n\n\nclass ProductPage(pages_models.ModelPage):\n    \"\"\"Create proxy model for Admin.\"\"\"\n\n    class Meta(pages_models.ModelPage.Meta):  # Ignore PycodestyleBear (E303)\n        proxy = True\n\n    # noinspection PyTypeChecker\n    objects = (\n        pages_models.ModelPage\n        .create_model_page_managers(Product)\n    )\n\n\nclass TagGroupManager(models.Manager):\n\n    def get_pack(self):\n        return self.get_queryset().get(uuid=settings.PACK_GROUP_UUID)\n\n\nclass TagGroup(catalog_models.TagGroup):\n\n    objects = TagGroupManager()\n\n\nclass TagQuerySet(catalog_models.TagQuerySet):\n\n    def products(self):\n        ids = self.values_list('products__id', flat=True)\n        return Product.objects.filter(id__in=ids).distinct()\n\n\nclass TagManager(catalog_models.TagManager.from_queryset(TagQuerySet)):\n\n    def get_packs(self):\n        return TagGroup.objects.get_pack().tags.all()\n\n\nclass Tag(catalog_models.Tag):\n    group = models.ForeignKey(\n        TagGroup, on_delete=models.CASCADE, null=True, related_name='tags',\n    )\n\n    objects = TagManager()\n", "path": "shopelectro/models.py"}], "after_files": [{"content": "import enum\nimport random\nimport string\nimport typing\nfrom uuid import uuid4\n\nfrom django.conf import settings\nfrom django.db import models\nfrom django.urls import reverse\nfrom django.utils.translation import ugettext_lazy as _\n\nfrom catalog import models as catalog_models\nfrom ecommerce import models as ecommerce_models\nfrom pages import models as pages_models\n\n\ndef randomize_slug(slug: str) -> str:\n    slug_hash = ''.join(\n        random.choices(string.ascii_lowercase, k=settings.SLUG_HASH_SIZE)\n    )\n    return f'{slug}_{slug_hash}'\n\n\nclass SECategoryQuerySet(catalog_models.CategoryQuerySet):\n    def get_categories_tree_with_pictures(self) -> 'SECategoryQuerySet':\n        categories_with_pictures = (\n            self\n            .filter(products__page__images__isnull=False)\n            .distinct()\n        )\n\n        return categories_with_pictures.get_ancestors(include_self=True)\n\n\nclass SECategoryManager(\n    catalog_models.CategoryManager.from_queryset(SECategoryQuerySet)\n):\n    pass\n\n\nclass Category(catalog_models.AbstractCategory, pages_models.SyncPageMixin):\n\n    objects = SECategoryManager()\n    uuid = models.UUIDField(default=uuid4, editable=False)\n\n    @classmethod\n    def get_default_parent(cls):\n        return pages_models.CustomPage.objects.filter(slug='catalog').first()\n\n    @property\n    def image(self):\n        products = self.products.all()\n        return products[0].image if products else None\n\n    def get_absolute_url(self):\n        return reverse('category', args=(self.page.slug,))\n\n\nclass Product(\n    catalog_models.AbstractProduct,\n    catalog_models.AbstractPosition,\n    pages_models.SyncPageMixin\n):\n\n    # That's why we are needed to explicitly add objects manager here\n    # because of Django special managers behaviour.\n    # Se se#480 for details.\n    objects = catalog_models.ProductManager()\n\n    category = models.ForeignKey(\n        Category,\n        on_delete=models.CASCADE,\n        null=True,\n        related_name='products',\n        verbose_name=_('category'),\n    )\n\n    tags = models.ManyToManyField(\n        'Tag',\n        related_name='products',\n        blank=True,\n        verbose_name=_('tags'),\n    )\n\n    # `vendor_code` is a code that refers to the particular stock keeping unit (SKU).\n    # You can treat it as public unique id. Use it to publicly identify a product.\n\n    # We bring codes from 1C database and sync with products.\n    # We doesn't use the id field instead, because it is auto-increment sequence,\n    # that can't be changed easily. We decided to avoid that complexity.\n    # https://www.postgresql.org/docs/current/functions-sequence.html\n    vendor_code = models.SmallIntegerField(verbose_name=_('vendor_code'))\n    uuid = models.UUIDField(default=uuid4, editable=False)\n    purchase_price = models.FloatField(\n        default=0, verbose_name=_('purchase_price'))\n    wholesale_small = models.FloatField(\n        default=0, verbose_name=_('wholesale_small'))\n    wholesale_medium = models.FloatField(\n        default=0, verbose_name=_('wholesale_medium'))\n    wholesale_large = models.FloatField(\n        default=0, verbose_name=_('wholesale_large'))\n\n    in_pack = models.PositiveSmallIntegerField(\n        default=1,\n        verbose_name=_('in pack'),\n    )\n\n    def get_absolute_url(self):\n        return reverse('product', args=(self.vendor_code,))\n\n    @property\n    def average_rate(self):\n        \"\"\"Return rounded to first decimal averaged rating.\"\"\"\n        rating = self.product_feedbacks.aggregate(\n            avg=models.Avg('rating')).get('avg', 0)\n        return round(rating, 1)\n\n    @property\n    def feedback_count(self):\n        return self.product_feedbacks.count()\n\n    @property\n    def feedback(self):\n        return self.product_feedbacks.all().order_by('-date')\n\n    def get_params(self):\n        return Tag.objects.filter_by_products([self]).group_tags()\n\n    def get_brand_name(self) -> str:\n        brand: typing.Optional['Tag'] = Tag.objects.get_brands([self]).get(self)\n        return brand.name if brand else ''\n\n\nclass ProductFeedback(models.Model):\n    product = models.ForeignKey(\n        Product, on_delete=models.CASCADE, null=True,\n        related_name='product_feedbacks'\n    )\n\n    date = models.DateTimeField(\n        auto_now=True, db_index=True, verbose_name=_('date'))\n    name = models.CharField(\n        max_length=255, db_index=True, verbose_name=_('name'))\n    rating = models.PositiveSmallIntegerField(\n        default=1, db_index=True, verbose_name=_('rating'))\n    dignities = models.TextField(\n        default='', blank=True, verbose_name=_('dignities'))\n    limitations = models.TextField(\n        default='', blank=True, verbose_name=_('limitations'))\n    general = models.TextField(\n        default='', blank=True, verbose_name=_('limitations'))\n\n\nclass ItemsEnum(enum.EnumMeta):\n    \"\"\"\n    Provide dict-like `items` method.\n\n    https://docs.python.org/3/library/enum.html#enum-classes\n    \"\"\"\n\n    def items(self):\n        return [(i.name, i.value) for i in self]\n\n    def __repr__(self):\n        fields = ', '.join(i.name for i in self)\n        return f\"<enum '{self.__name__}: {fields}'>\"\n\n\nclass PaymentOptions(enum.Enum, metaclass=ItemsEnum):\n    cash = '\u041d\u0430\u043b\u0438\u0447\u043d\u044b\u0435'\n    cashless = '\u0411\u0435\u0437\u043d\u0430\u043b\u0438\u0447\u043d\u044b\u0435 \u0438 \u0434\u0435\u043d\u0435\u0436\u043d\u044b\u0435 \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u044b'\n    AC = '\u0411\u0430\u043d\u043a\u043e\u0432\u0441\u043a\u0430\u044f \u043a\u0430\u0440\u0442\u0430'\n    PC = '\u042f\u043d\u0434\u0435\u043a\u0441.\u0414\u0435\u043d\u044c\u0433\u0438'\n    GP = '\u0421\u0432\u044f\u0437\u043d\u043e\u0439 (\u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b)'\n    AB = '\u0410\u043b\u044c\u0444\u0430-\u041a\u043b\u0438\u043a'\n\n    @staticmethod\n    def default():\n        return PaymentOptions.cash\n\n\nclass Order(ecommerce_models.Order):\n    address = models.TextField(blank=True, default='')\n    payment_type = models.CharField(\n        max_length=255,\n        choices=PaymentOptions.items(),\n        default=PaymentOptions.default().name,\n    )\n    comment = models.TextField(blank=True, default='')\n    # total price - total purchase price\n    revenue = models.FloatField(default=0, null=True, verbose_name=_('revenue'))\n\n    @property\n    def payment_type_label(self):\n        \"\"\"Return label for an order's payment option.\"\"\"\n        return PaymentOptions[self.payment_type].value\n\n    def set_positions(self, cart):\n        \"\"\"\n        Save cart's state into Order instance.\n\n        @todo #589:60m Create Cart model.\n         See details here: https://github.com/fidals/shopelectro/pull/590#discussion_r222544672\n        \"\"\"\n        self.revenue = cart.total_revenue()\n        self.save()\n        for id_, position in cart:\n            self.positions.create(\n                order=self,\n                product_id=id_,\n                vendor_code=position['vendor_code'],\n                name=position['name'],\n                price=position['price'],\n                quantity=position['quantity'],\n            )\n        return self\n\n\nclass CategoryPage(pages_models.ModelPage):\n    \"\"\"Create proxy model for Admin.\"\"\"\n\n    class Meta(pages_models.ModelPage.Meta):  # Ignore PycodestyleBear (E303)\n        proxy = True\n\n    # noinspection PyTypeChecker\n    objects = pages_models.ModelPage.create_model_page_managers(Category)\n\n\nclass ProductPage(pages_models.ModelPage):\n    \"\"\"Create proxy model for Admin.\"\"\"\n\n    class Meta(pages_models.ModelPage.Meta):  # Ignore PycodestyleBear (E303)\n        proxy = True\n\n    # noinspection PyTypeChecker\n    objects = (\n        pages_models.ModelPage\n        .create_model_page_managers(Product)\n    )\n\n\nclass TagGroupManager(models.Manager):\n\n    def get_pack(self):\n        return self.get_queryset().get(uuid=settings.PACK_GROUP_UUID)\n\n\nclass TagGroup(catalog_models.TagGroup):\n\n    objects = TagGroupManager()\n\n\nclass TagQuerySet(catalog_models.TagQuerySet):\n\n    def products(self):\n        ids = self.values_list('products__id', flat=True)\n        return Product.objects.filter(id__in=ids).distinct()\n\n\nclass TagManager(catalog_models.TagManager.from_queryset(TagQuerySet)):\n\n    def get_packs(self):\n        return TagGroup.objects.get_pack().tags.all()\n\n\nclass Tag(catalog_models.Tag):\n    group = models.ForeignKey(\n        TagGroup, on_delete=models.CASCADE, null=True, related_name='tags',\n    )\n\n    objects = TagManager()\n", "path": "shopelectro/models.py"}]}