Repository: saleor/saleor

Issue:
Dashboard 2.0: Order API does not expose a way to get a product thumbnail for an order line
We get access to `productName` and `productSku` but not a thumbnail. It's ok to return `null` if the product no longer exists so we don't need to denormalize this field but I'd like to avoid having the client query the `product` directly and then have to manually figure out which image to show.


Discussion:
I propose that we add a `thumbnail()` resolver that matches the one found on product images.

Resolving patch:
diff --git a/saleor/graphql/order/types.py b/saleor/graphql/order/types.py
--- a/saleor/graphql/order/types.py
+++ b/saleor/graphql/order/types.py
@@ -1,11 +1,13 @@
+from decimal import Decimal
+
 import graphene
 from graphene import relay
 
 from ...order import OrderEvents, models
+from ...product.templatetags.product_images import get_thumbnail
 from ..account.types import User
 from ..core.types.common import CountableDjangoObjectType
 from ..core.types.money import Money, TaxedMoney
-from decimal import Decimal
 
 OrderEventsEnum = graphene.Enum.from_enum(OrderEvents)
 
@@ -163,9 +165,21 @@ def resolve_user_email(obj, info):
 
 
 class OrderLine(CountableDjangoObjectType):
+    thumbnail_url = graphene.String(
+        description='The URL of a main thumbnail for the ordered product.',
+        size=graphene.Int(description='Size of the image'))
+
     class Meta:
         description = 'Represents order line of particular order.'
         model = models.OrderLine
         interfaces = [relay.Node]
         exclude_fields = [
             'order', 'unit_price_gross', 'unit_price_net', 'variant']
+
+    def resolve_thumbnail_url(self, info, size=None):
+        if not self.variant_id:
+            return None
+        if not size:
+            size = 255
+        return get_thumbnail(
+            self.variant.get_first_image(), size, method='thumbnail')


Test patch:
diff --git a/tests/api/test_order.py b/tests/api/test_order.py
--- a/tests/api/test_order.py
+++ b/tests/api/test_order.py
@@ -15,6 +15,41 @@
 from tests.utils import get_graphql_content
 
 
+def test_orderline_query(admin_api_client, fulfilled_order):
+    order = fulfilled_order
+    query = """
+        query OrdersQuery {
+            orders(first: 1) {
+                edges {
+                    node {
+                        lines {
+                            edges {
+                                node {
+                                    thumbnailUrl(size: 540)
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    """
+    line = order.lines.first()
+    line.variant = None
+    line.save()
+
+    response = admin_api_client.post(
+        reverse('api'), {'query': query})
+    content = get_graphql_content(response)
+    assert 'errors' not in content
+    order_data = content['data']['orders']['edges'][0]['node']
+    lines_data = order_data['lines']['edges']
+    thumbnails = [l['node']['thumbnailUrl'] for l in lines_data]
+    assert len(thumbnails) == 2
+    assert None in thumbnails
+    assert '/static/images/placeholder540x540.png' in thumbnails
+
+
 def test_order_query(admin_api_client, fulfilled_order):
     order = fulfilled_order
     query = """