We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Implement customers section in dashboard


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `saleor/graphql/account/resolvers.py`
Content:
```
1 import graphene_django_optimizer as gql_optimizer
2 from django.db.models import Q
3 from i18naddress import get_validation_rules
4 
5 from ...account import models
6 from ...core.utils import get_client_ip, get_country_by_ip
7 from ..utils import filter_by_query_param
8 from .types import AddressValidationData, ChoiceValue
9 
10 USER_SEARCH_FIELDS = (
11     'email', 'default_shipping_address__first_name',
12     'default_shipping_address__last_name', 'default_shipping_address__city',
13     'default_shipping_address__country')
14 
15 
16 def resolve_customers(info, query):
17     qs = models.User.objects.filter(
18         Q(is_staff=False) | (Q(is_staff=True) & Q(orders__isnull=False)))
19     qs = filter_by_query_param(
20         queryset=qs, query=query, search_fields=USER_SEARCH_FIELDS)
21     qs = qs.distinct()
22     return gql_optimizer.query(qs, info)
23 
24 
25 def resolve_staff_users(info, query):
26     qs = models.User.objects.filter(is_staff=True)
27     qs = filter_by_query_param(
28         queryset=qs, query=query, search_fields=USER_SEARCH_FIELDS)
29     qs = qs.distinct()
30     return gql_optimizer.query(qs, info)
31 
32 
33 def resolve_address_validator(info, input):
34     country_code = input['country_code']
35     if not country_code:
36         client_ip = get_client_ip(info.context)
37         country = get_country_by_ip(client_ip)
38         if country:
39             country_code = country.code
40         else:
41             return None
42     params = {
43         'country_code': country_code,
44         'country_area': input['country_area'],
45         'city_area': input['city_area']}
46     rules = get_validation_rules(params)
47     return AddressValidationData(
48         country_code=rules.country_code,
49         country_name=rules.country_name,
50         address_format=rules.address_format,
51         address_latin_format=rules.address_latin_format,
52         allowed_fields=rules.allowed_fields,
53         required_fields=rules.required_fields,
54         upper_fields=rules.upper_fields,
55         country_area_type=rules.country_area_type,
56         country_area_choices=[
57             ChoiceValue(area[0], area[1])
58             for area in rules.country_area_choices],
59         city_type=rules.city_type,
60         city_area_choices=[
61             ChoiceValue(area[0], area[1]) for area in rules.city_area_choices],
62         postal_code_type=rules.postal_code_type,
63         postal_code_matchers=[
64             compiled.pattern for compiled in rules.postal_code_matchers],
65         postal_code_examples=rules.postal_code_examples,
66         postal_code_prefix=rules.postal_code_prefix)
67
```

Path: `saleor/graphql/product/resolvers.py`
Content:
```
1 import graphene
2 import graphene_django_optimizer as gql_optimizer
3 from django.db.models import Sum, Q
4 
5 from ...order import OrderStatus
6 from ...product import models
7 from ..utils import (
8     filter_by_query_param, filter_by_period, get_database_id, get_nodes)
9 from .filters import (
10     filter_products_by_attributes, filter_products_by_categories,
11     filter_products_by_collections, filter_products_by_price, sort_qs)
12 from .types import Category, Collection, ProductVariant, StockAvailability
13 
14 PRODUCT_SEARCH_FIELDS = ('name', 'description', 'category__name')
15 CATEGORY_SEARCH_FIELDS = ('name', 'slug', 'description', 'parent__name')
16 COLLECTION_SEARCH_FIELDS = ('name', 'slug')
17 ATTRIBUTES_SEARCH_FIELDS = ('name', 'slug')
18 
19 
20 def resolve_attributes(info, category_id, query):
21     qs = models.Attribute.objects.all()
22     qs = filter_by_query_param(qs, query, ATTRIBUTES_SEARCH_FIELDS)
23     if category_id:
24         # Get attributes that are used with product types
25         # within the given category.
26         category = graphene.Node.get_node_from_global_id(
27             info, category_id, Category)
28         if category is None:
29             return qs.none()
30         tree = category.get_descendants(include_self=True)
31         product_types = {
32             obj[0]
33             for obj in models.Product.objects.filter(
34                 category__in=tree).values_list('product_type_id')}
35         qs = qs.filter(
36             Q(product_type__in=product_types)
37             | Q(product_variant_type__in=product_types))
38     qs = qs.distinct()
39     return gql_optimizer.query(qs, info)
40 
41 
42 def resolve_categories(info, query, level=None):
43     qs = models.Category.objects.prefetch_related('children')
44     if level is not None:
45         qs = qs.filter(level=level)
46     qs = filter_by_query_param(qs, query, CATEGORY_SEARCH_FIELDS)
47     return gql_optimizer.query(qs, info)
48 
49 
50 def resolve_collections(info, query):
51     user = info.context.user
52     qs = models.Collection.objects.visible_to_user(user)
53     qs = filter_by_query_param(qs, query, COLLECTION_SEARCH_FIELDS)
54     return gql_optimizer.query(qs, info)
55 
56 
57 def resolve_products(
58         info, attributes=None, categories=None, collections=None,
59         price_lte=None, price_gte=None, sort_by=None, stock_availability=None,
60         query=None, **kwargs):
61 
62     user = info.context.user
63     qs = models.Product.objects.visible_to_user(user)
64     qs = filter_by_query_param(qs, query, PRODUCT_SEARCH_FIELDS)
65 
66     if attributes:
67         qs = filter_products_by_attributes(qs, attributes)
68 
69     if categories:
70         categories = get_nodes(categories, Category)
71         qs = filter_products_by_categories(qs, categories)
72 
73     if collections:
74         collections = get_nodes(collections, Collection)
75         qs = filter_products_by_collections(qs, collections)
76 
77     if stock_availability:
78         qs = qs.annotate(total_quantity=Sum('variants__quantity'))
79         if stock_availability == StockAvailability.IN_STOCK:
80             qs = qs.filter(total_quantity__gt=0)
81         elif stock_availability == StockAvailability.OUT_OF_STOCK:
82             qs = qs.filter(total_quantity__lte=0)
83 
84     qs = filter_products_by_price(qs, price_lte, price_gte)
85     qs = sort_qs(qs, sort_by)
86     qs = qs.distinct()
87     return gql_optimizer.query(qs, info)
88 
89 
90 def resolve_product_types(info):
91     qs = models.ProductType.objects.all()
92     return gql_optimizer.query(qs, info)
93 
94 
95 def resolve_product_variants(info, ids=None):
96     qs = models.ProductVariant.objects.all()
97     if ids:
98         db_ids = [
99             get_database_id(info, node_id, only_type=ProductVariant)
100             for node_id in ids]
101         qs = qs.filter(pk__in=db_ids)
102     return gql_optimizer.query(qs, info)
103 
104 
105 def resolve_report_product_sales(info, period):
106     qs = models.ProductVariant.objects.prefetch_related(
107         'product', 'product__images', 'order_lines__order').all()
108 
109     # exclude draft and canceled orders
110     exclude_status = [OrderStatus.DRAFT, OrderStatus.CANCELED]
111     qs = qs.exclude(order_lines__order__status__in=exclude_status)
112 
113     # filter by period
114     qs = filter_by_period(qs, period, 'order_lines__order__created')
115 
116     qs = qs.annotate(quantity_ordered=Sum('order_lines__quantity'))
117     qs = qs.filter(quantity_ordered__isnull=False)
118     return qs.order_by('-quantity_ordered')
119
```
--- 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/saleor/graphql/account/resolvers.py b/saleor/graphql/account/resolvers.py
--- a/saleor/graphql/account/resolvers.py
+++ b/saleor/graphql/account/resolvers.py
@@ -18,6 +18,7 @@
         Q(is_staff=False) | (Q(is_staff=True) & Q(orders__isnull=False)))
     qs = filter_by_query_param(
         queryset=qs, query=query, search_fields=USER_SEARCH_FIELDS)
+    qs = qs.order_by('email')
     qs = qs.distinct()
     return gql_optimizer.query(qs, info)
 
@@ -26,6 +27,7 @@
     qs = models.User.objects.filter(is_staff=True)
     qs = filter_by_query_param(
         queryset=qs, query=query, search_fields=USER_SEARCH_FIELDS)
+    qs = qs.order_by('email')
     qs = qs.distinct()
     return gql_optimizer.query(qs, info)
 
diff --git a/saleor/graphql/product/resolvers.py b/saleor/graphql/product/resolvers.py
--- a/saleor/graphql/product/resolvers.py
+++ b/saleor/graphql/product/resolvers.py
@@ -35,6 +35,7 @@
         qs = qs.filter(
             Q(product_type__in=product_types)
             | Q(product_variant_type__in=product_types))
+    qs = qs.order_by('name')
     qs = qs.distinct()
     return gql_optimizer.query(qs, info)
 
@@ -44,6 +45,8 @@
     if level is not None:
         qs = qs.filter(level=level)
     qs = filter_by_query_param(qs, query, CATEGORY_SEARCH_FIELDS)
+    qs = qs.order_by('name')
+    qs = qs.distinct()
     return gql_optimizer.query(qs, info)
 
 
@@ -51,6 +54,7 @@
     user = info.context.user
     qs = models.Collection.objects.visible_to_user(user)
     qs = filter_by_query_param(qs, query, COLLECTION_SEARCH_FIELDS)
+    qs = qs.order_by('name')
     return gql_optimizer.query(qs, info)
 
 
@@ -89,6 +93,7 @@
 
 def resolve_product_types(info):
     qs = models.ProductType.objects.all()
+    qs = qs.order_by('name')
     return gql_optimizer.query(qs, info)

{"golden_diff": "diff --git a/saleor/graphql/account/resolvers.py b/saleor/graphql/account/resolvers.py\n--- a/saleor/graphql/account/resolvers.py\n+++ b/saleor/graphql/account/resolvers.py\n@@ -18,6 +18,7 @@\n         Q(is_staff=False) | (Q(is_staff=True) & Q(orders__isnull=False)))\n     qs = filter_by_query_param(\n         queryset=qs, query=query, search_fields=USER_SEARCH_FIELDS)\n+    qs = qs.order_by('email')\n     qs = qs.distinct()\n     return gql_optimizer.query(qs, info)\n \n@@ -26,6 +27,7 @@\n     qs = models.User.objects.filter(is_staff=True)\n     qs = filter_by_query_param(\n         queryset=qs, query=query, search_fields=USER_SEARCH_FIELDS)\n+    qs = qs.order_by('email')\n     qs = qs.distinct()\n     return gql_optimizer.query(qs, info)\n \ndiff --git a/saleor/graphql/product/resolvers.py b/saleor/graphql/product/resolvers.py\n--- a/saleor/graphql/product/resolvers.py\n+++ b/saleor/graphql/product/resolvers.py\n@@ -35,6 +35,7 @@\n         qs = qs.filter(\n             Q(product_type__in=product_types)\n             | Q(product_variant_type__in=product_types))\n+    qs = qs.order_by('name')\n     qs = qs.distinct()\n     return gql_optimizer.query(qs, info)\n \n@@ -44,6 +45,8 @@\n     if level is not None:\n         qs = qs.filter(level=level)\n     qs = filter_by_query_param(qs, query, CATEGORY_SEARCH_FIELDS)\n+    qs = qs.order_by('name')\n+    qs = qs.distinct()\n     return gql_optimizer.query(qs, info)\n \n \n@@ -51,6 +54,7 @@\n     user = info.context.user\n     qs = models.Collection.objects.visible_to_user(user)\n     qs = filter_by_query_param(qs, query, COLLECTION_SEARCH_FIELDS)\n+    qs = qs.order_by('name')\n     return gql_optimizer.query(qs, info)\n \n \n@@ -89,6 +93,7 @@\n \n def resolve_product_types(info):\n     qs = models.ProductType.objects.all()\n+    qs = qs.order_by('name')\n     return gql_optimizer.query(qs, info)\n", "issue": "Implement customers section in dashboard\n\n", "before_files": [{"content": "import graphene_django_optimizer as gql_optimizer\nfrom django.db.models import Q\nfrom i18naddress import get_validation_rules\n\nfrom ...account import models\nfrom ...core.utils import get_client_ip, get_country_by_ip\nfrom ..utils import filter_by_query_param\nfrom .types import AddressValidationData, ChoiceValue\n\nUSER_SEARCH_FIELDS = (\n    'email', 'default_shipping_address__first_name',\n    'default_shipping_address__last_name', 'default_shipping_address__city',\n    'default_shipping_address__country')\n\n\ndef resolve_customers(info, query):\n    qs = models.User.objects.filter(\n        Q(is_staff=False) | (Q(is_staff=True) & Q(orders__isnull=False)))\n    qs = filter_by_query_param(\n        queryset=qs, query=query, search_fields=USER_SEARCH_FIELDS)\n    qs = qs.distinct()\n    return gql_optimizer.query(qs, info)\n\n\ndef resolve_staff_users(info, query):\n    qs = models.User.objects.filter(is_staff=True)\n    qs = filter_by_query_param(\n        queryset=qs, query=query, search_fields=USER_SEARCH_FIELDS)\n    qs = qs.distinct()\n    return gql_optimizer.query(qs, info)\n\n\ndef resolve_address_validator(info, input):\n    country_code = input['country_code']\n    if not country_code:\n        client_ip = get_client_ip(info.context)\n        country = get_country_by_ip(client_ip)\n        if country:\n            country_code = country.code\n        else:\n            return None\n    params = {\n        'country_code': country_code,\n        'country_area': input['country_area'],\n        'city_area': input['city_area']}\n    rules = get_validation_rules(params)\n    return AddressValidationData(\n        country_code=rules.country_code,\n        country_name=rules.country_name,\n        address_format=rules.address_format,\n        address_latin_format=rules.address_latin_format,\n        allowed_fields=rules.allowed_fields,\n        required_fields=rules.required_fields,\n        upper_fields=rules.upper_fields,\n        country_area_type=rules.country_area_type,\n        country_area_choices=[\n            ChoiceValue(area[0], area[1])\n            for area in rules.country_area_choices],\n        city_type=rules.city_type,\n        city_area_choices=[\n            ChoiceValue(area[0], area[1]) for area in rules.city_area_choices],\n        postal_code_type=rules.postal_code_type,\n        postal_code_matchers=[\n            compiled.pattern for compiled in rules.postal_code_matchers],\n        postal_code_examples=rules.postal_code_examples,\n        postal_code_prefix=rules.postal_code_prefix)\n", "path": "saleor/graphql/account/resolvers.py"}, {"content": "import graphene\nimport graphene_django_optimizer as gql_optimizer\nfrom django.db.models import Sum, Q\n\nfrom ...order import OrderStatus\nfrom ...product import models\nfrom ..utils import (\n    filter_by_query_param, filter_by_period, get_database_id, get_nodes)\nfrom .filters import (\n    filter_products_by_attributes, filter_products_by_categories,\n    filter_products_by_collections, filter_products_by_price, sort_qs)\nfrom .types import Category, Collection, ProductVariant, StockAvailability\n\nPRODUCT_SEARCH_FIELDS = ('name', 'description', 'category__name')\nCATEGORY_SEARCH_FIELDS = ('name', 'slug', 'description', 'parent__name')\nCOLLECTION_SEARCH_FIELDS = ('name', 'slug')\nATTRIBUTES_SEARCH_FIELDS = ('name', 'slug')\n\n\ndef resolve_attributes(info, category_id, query):\n    qs = models.Attribute.objects.all()\n    qs = filter_by_query_param(qs, query, ATTRIBUTES_SEARCH_FIELDS)\n    if category_id:\n        # Get attributes that are used with product types\n        # within the given category.\n        category = graphene.Node.get_node_from_global_id(\n            info, category_id, Category)\n        if category is None:\n            return qs.none()\n        tree = category.get_descendants(include_self=True)\n        product_types = {\n            obj[0]\n            for obj in models.Product.objects.filter(\n                category__in=tree).values_list('product_type_id')}\n        qs = qs.filter(\n            Q(product_type__in=product_types)\n            | Q(product_variant_type__in=product_types))\n    qs = qs.distinct()\n    return gql_optimizer.query(qs, info)\n\n\ndef resolve_categories(info, query, level=None):\n    qs = models.Category.objects.prefetch_related('children')\n    if level is not None:\n        qs = qs.filter(level=level)\n    qs = filter_by_query_param(qs, query, CATEGORY_SEARCH_FIELDS)\n    return gql_optimizer.query(qs, info)\n\n\ndef resolve_collections(info, query):\n    user = info.context.user\n    qs = models.Collection.objects.visible_to_user(user)\n    qs = filter_by_query_param(qs, query, COLLECTION_SEARCH_FIELDS)\n    return gql_optimizer.query(qs, info)\n\n\ndef resolve_products(\n        info, attributes=None, categories=None, collections=None,\n        price_lte=None, price_gte=None, sort_by=None, stock_availability=None,\n        query=None, **kwargs):\n\n    user = info.context.user\n    qs = models.Product.objects.visible_to_user(user)\n    qs = filter_by_query_param(qs, query, PRODUCT_SEARCH_FIELDS)\n\n    if attributes:\n        qs = filter_products_by_attributes(qs, attributes)\n\n    if categories:\n        categories = get_nodes(categories, Category)\n        qs = filter_products_by_categories(qs, categories)\n\n    if collections:\n        collections = get_nodes(collections, Collection)\n        qs = filter_products_by_collections(qs, collections)\n\n    if stock_availability:\n        qs = qs.annotate(total_quantity=Sum('variants__quantity'))\n        if stock_availability == StockAvailability.IN_STOCK:\n            qs = qs.filter(total_quantity__gt=0)\n        elif stock_availability == StockAvailability.OUT_OF_STOCK:\n            qs = qs.filter(total_quantity__lte=0)\n\n    qs = filter_products_by_price(qs, price_lte, price_gte)\n    qs = sort_qs(qs, sort_by)\n    qs = qs.distinct()\n    return gql_optimizer.query(qs, info)\n\n\ndef resolve_product_types(info):\n    qs = models.ProductType.objects.all()\n    return gql_optimizer.query(qs, info)\n\n\ndef resolve_product_variants(info, ids=None):\n    qs = models.ProductVariant.objects.all()\n    if ids:\n        db_ids = [\n            get_database_id(info, node_id, only_type=ProductVariant)\n            for node_id in ids]\n        qs = qs.filter(pk__in=db_ids)\n    return gql_optimizer.query(qs, info)\n\n\ndef resolve_report_product_sales(info, period):\n    qs = models.ProductVariant.objects.prefetch_related(\n        'product', 'product__images', 'order_lines__order').all()\n\n    # exclude draft and canceled orders\n    exclude_status = [OrderStatus.DRAFT, OrderStatus.CANCELED]\n    qs = qs.exclude(order_lines__order__status__in=exclude_status)\n\n    # filter by period\n    qs = filter_by_period(qs, period, 'order_lines__order__created')\n\n    qs = qs.annotate(quantity_ordered=Sum('order_lines__quantity'))\n    qs = qs.filter(quantity_ordered__isnull=False)\n    return qs.order_by('-quantity_ordered')\n", "path": "saleor/graphql/product/resolvers.py"}], "after_files": [{"content": "import graphene_django_optimizer as gql_optimizer\nfrom django.db.models import Q\nfrom i18naddress import get_validation_rules\n\nfrom ...account import models\nfrom ...core.utils import get_client_ip, get_country_by_ip\nfrom ..utils import filter_by_query_param\nfrom .types import AddressValidationData, ChoiceValue\n\nUSER_SEARCH_FIELDS = (\n    'email', 'default_shipping_address__first_name',\n    'default_shipping_address__last_name', 'default_shipping_address__city',\n    'default_shipping_address__country')\n\n\ndef resolve_customers(info, query):\n    qs = models.User.objects.filter(\n        Q(is_staff=False) | (Q(is_staff=True) & Q(orders__isnull=False)))\n    qs = filter_by_query_param(\n        queryset=qs, query=query, search_fields=USER_SEARCH_FIELDS)\n    qs = qs.order_by('email')\n    qs = qs.distinct()\n    return gql_optimizer.query(qs, info)\n\n\ndef resolve_staff_users(info, query):\n    qs = models.User.objects.filter(is_staff=True)\n    qs = filter_by_query_param(\n        queryset=qs, query=query, search_fields=USER_SEARCH_FIELDS)\n    qs = qs.order_by('email')\n    qs = qs.distinct()\n    return gql_optimizer.query(qs, info)\n\n\ndef resolve_address_validator(info, input):\n    country_code = input['country_code']\n    if not country_code:\n        client_ip = get_client_ip(info.context)\n        country = get_country_by_ip(client_ip)\n        if country:\n            country_code = country.code\n        else:\n            return None\n    params = {\n        'country_code': country_code,\n        'country_area': input['country_area'],\n        'city_area': input['city_area']}\n    rules = get_validation_rules(params)\n    return AddressValidationData(\n        country_code=rules.country_code,\n        country_name=rules.country_name,\n        address_format=rules.address_format,\n        address_latin_format=rules.address_latin_format,\n        allowed_fields=rules.allowed_fields,\n        required_fields=rules.required_fields,\n        upper_fields=rules.upper_fields,\n        country_area_type=rules.country_area_type,\n        country_area_choices=[\n            ChoiceValue(area[0], area[1])\n            for area in rules.country_area_choices],\n        city_type=rules.city_type,\n        city_area_choices=[\n            ChoiceValue(area[0], area[1]) for area in rules.city_area_choices],\n        postal_code_type=rules.postal_code_type,\n        postal_code_matchers=[\n            compiled.pattern for compiled in rules.postal_code_matchers],\n        postal_code_examples=rules.postal_code_examples,\n        postal_code_prefix=rules.postal_code_prefix)\n", "path": "saleor/graphql/account/resolvers.py"}, {"content": "import graphene\nimport graphene_django_optimizer as gql_optimizer\nfrom django.db.models import Sum, Q\n\nfrom ...order import OrderStatus\nfrom ...product import models\nfrom ..utils import (\n    filter_by_query_param, filter_by_period, get_database_id, get_nodes)\nfrom .filters import (\n    filter_products_by_attributes, filter_products_by_categories,\n    filter_products_by_collections, filter_products_by_price, sort_qs)\nfrom .types import Category, Collection, ProductVariant, StockAvailability\n\nPRODUCT_SEARCH_FIELDS = ('name', 'description', 'category__name')\nCATEGORY_SEARCH_FIELDS = ('name', 'slug', 'description', 'parent__name')\nCOLLECTION_SEARCH_FIELDS = ('name', 'slug')\nATTRIBUTES_SEARCH_FIELDS = ('name', 'slug')\n\n\ndef resolve_attributes(info, category_id, query):\n    qs = models.Attribute.objects.all()\n    qs = filter_by_query_param(qs, query, ATTRIBUTES_SEARCH_FIELDS)\n    if category_id:\n        # Get attributes that are used with product types\n        # within the given category.\n        category = graphene.Node.get_node_from_global_id(\n            info, category_id, Category)\n        if category is None:\n            return qs.none()\n        tree = category.get_descendants(include_self=True)\n        product_types = {\n            obj[0]\n            for obj in models.Product.objects.filter(\n                category__in=tree).values_list('product_type_id')}\n        qs = qs.filter(\n            Q(product_type__in=product_types)\n            | Q(product_variant_type__in=product_types))\n    qs = qs.order_by('name')\n    qs = qs.distinct()\n    return gql_optimizer.query(qs, info)\n\n\ndef resolve_categories(info, query, level=None):\n    qs = models.Category.objects.prefetch_related('children')\n    if level is not None:\n        qs = qs.filter(level=level)\n    qs = filter_by_query_param(qs, query, CATEGORY_SEARCH_FIELDS)\n    qs = qs.order_by('name')\n    qs = qs.distinct()\n    return gql_optimizer.query(qs, info)\n\n\ndef resolve_collections(info, query):\n    user = info.context.user\n    qs = models.Collection.objects.visible_to_user(user)\n    qs = filter_by_query_param(qs, query, COLLECTION_SEARCH_FIELDS)\n    qs = qs.order_by('name')\n    return gql_optimizer.query(qs, info)\n\n\ndef resolve_products(\n        info, attributes=None, categories=None, collections=None,\n        price_lte=None, price_gte=None, sort_by=None, stock_availability=None,\n        query=None, **kwargs):\n\n    user = info.context.user\n    qs = models.Product.objects.visible_to_user(user)\n    qs = filter_by_query_param(qs, query, PRODUCT_SEARCH_FIELDS)\n\n    if attributes:\n        qs = filter_products_by_attributes(qs, attributes)\n\n    if categories:\n        categories = get_nodes(categories, Category)\n        qs = filter_products_by_categories(qs, categories)\n\n    if collections:\n        collections = get_nodes(collections, Collection)\n        qs = filter_products_by_collections(qs, collections)\n\n    if stock_availability:\n        qs = qs.annotate(total_quantity=Sum('variants__quantity'))\n        if stock_availability == StockAvailability.IN_STOCK:\n            qs = qs.filter(total_quantity__gt=0)\n        elif stock_availability == StockAvailability.OUT_OF_STOCK:\n            qs = qs.filter(total_quantity__lte=0)\n\n    qs = filter_products_by_price(qs, price_lte, price_gte)\n    qs = sort_qs(qs, sort_by)\n    qs = qs.distinct()\n    return gql_optimizer.query(qs, info)\n\n\ndef resolve_product_types(info):\n    qs = models.ProductType.objects.all()\n    qs = qs.order_by('name')\n    return gql_optimizer.query(qs, info)\n\n\ndef resolve_product_variants(info, ids=None):\n    qs = models.ProductVariant.objects.all()\n    if ids:\n        db_ids = [\n            get_database_id(info, node_id, only_type=ProductVariant)\n            for node_id in ids]\n        qs = qs.filter(pk__in=db_ids)\n    return gql_optimizer.query(qs, info)\n\n\ndef resolve_report_product_sales(info, period):\n    qs = models.ProductVariant.objects.prefetch_related(\n        'product', 'product__images', 'order_lines__order').all()\n\n    # exclude draft and canceled orders\n    exclude_status = [OrderStatus.DRAFT, OrderStatus.CANCELED]\n    qs = qs.exclude(order_lines__order__status__in=exclude_status)\n\n    # filter by period\n    qs = filter_by_period(qs, period, 'order_lines__order__created')\n\n    qs = qs.annotate(quantity_ordered=Sum('order_lines__quantity'))\n    qs = qs.filter(quantity_ordered__isnull=False)\n    return qs.order_by('-quantity_ordered')\n", "path": "saleor/graphql/product/resolvers.py"}]}