prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN 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.
  
  --- 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/order/types.py`
  Content:
  ```
  1 import graphene
  2 from graphene import relay
  3 
  4 from ...order import OrderEvents, models
  5 from ..account.types import User
  6 from ..core.types.common import CountableDjangoObjectType
  7 from ..core.types.money import Money, TaxedMoney
  8 from decimal import Decimal
  9 
  10 OrderEventsEnum = graphene.Enum.from_enum(OrderEvents)
  11 
  12 
  13 class OrderEvent(CountableDjangoObjectType):
  14     date = graphene.types.datetime.DateTime(
  15         description='Date when event happened at in ISO 8601 format.')
  16     type = OrderEventsEnum(description='Order event type')
  17     user = graphene.Field(
  18         User, id=graphene.Argument(graphene.ID),
  19         description='User who performed the action.')
  20     message = graphene.String(
  21         description='Content of a note added to the order.')
  22     email = graphene.String(description='Email of the customer')
  23     email_type = graphene.String(
  24         description='Type of an email sent to the customer')
  25     amount = graphene.Float(description='Amount of money.')
  26     quantity = graphene.Int(description='Number of items.')
  27     composed_id = graphene.String(
  28         description='Composed id of the Fulfillment.')
  29 
  30     class Meta:
  31         description = 'History log of the order.'
  32         model = models.OrderEvent
  33         interfaces = [relay.Node]
  34         exclude_fields = ['order', 'parameters']
  35 
  36     def resolve_email(self, info):
  37         return self.parameters.get('email', None)
  38 
  39     def resolve_email_type(self, info):
  40         return self.parameters.get('email_type', None)
  41 
  42     def resolve_amount(self, info):
  43         amount = self.parameters.get('amount', None)
  44         return Decimal(amount) if amount else None
  45 
  46     def resolve_quantity(self, info):
  47         quantity = self.parameters.get('quantity', None)
  48         return int(quantity) if quantity else None
  49 
  50     def resolve_message(self, info):
  51         return self.parameters.get('message', None)
  52 
  53     def resolve_composed_id(self, info):
  54         return self.parameters.get('composed_id', None)
  55 
  56 
  57 class Fulfillment(CountableDjangoObjectType):
  58     status_display = graphene.String(
  59         description='User-friendly fulfillment status.')
  60 
  61     class Meta:
  62         description = 'Represents order fulfillment.'
  63         interfaces = [relay.Node]
  64         model = models.Fulfillment
  65         exclude_fields = ['order']
  66 
  67     def resolve_status_display(self, info):
  68         return self.get_status_display()
  69 
  70 
  71 class FulfillmentLine(CountableDjangoObjectType):
  72     class Meta:
  73         description = 'Represents line of the fulfillment.'
  74         interfaces = [relay.Node]
  75         model = models.FulfillmentLine
  76         exclude_fields = ['fulfillment']
  77 
  78 
  79 class Order(CountableDjangoObjectType):
  80     fulfillments = graphene.List(
  81         Fulfillment,
  82         required=True,
  83         description='List of shipments for the order.')
  84     is_paid = graphene.Boolean(
  85         description='Informs if an order is fully paid.')
  86     number = graphene.String(description='User-friendly number of an order.')
  87     payment_status = graphene.String(description='Internal payment status.')
  88     payment_status_display = graphene.String(
  89         description='User-friendly payment status.')
  90     subtotal = graphene.Field(
  91         TaxedMoney,
  92         description='The sum of line prices not including shipping.')
  93     status_display = graphene.String(description='User-friendly order status.')
  94     total_authorized = graphene.Field(
  95         Money, description='Amount authorized for the order.')
  96     total_captured = graphene.Field(
  97         Money, description='Amount captured by payment.')
  98     events = graphene.List(
  99         OrderEvent,
  100         description='List of events associated with the order.')
  101     user_email = graphene.String(
  102         required=False, description='Email address of the customer.')
  103 
  104     class Meta:
  105         description = 'Represents an order in the shop.'
  106         interfaces = [relay.Node]
  107         model = models.Order
  108         exclude_fields = [
  109             'shipping_price_gross', 'shipping_price_net', 'total_gross',
  110             'total_net']
  111 
  112     @staticmethod
  113     def resolve_subtotal(obj, info):
  114         return obj.get_subtotal()
  115 
  116     @staticmethod
  117     def resolve_total_authorized(obj, info):
  118         payment = obj.get_last_payment()
  119         if payment:
  120             return payment.get_total_price().gross
  121 
  122     @staticmethod
  123     def resolve_total_captured(obj, info):
  124         payment = obj.get_last_payment()
  125         if payment:
  126             return payment.get_captured_price()
  127 
  128     @staticmethod
  129     def resolve_fulfillments(obj, info):
  130         return obj.fulfillments.all()
  131 
  132     @staticmethod
  133     def resolve_events(obj, info):
  134         return obj.events.all()
  135 
  136     @staticmethod
  137     def resolve_is_paid(obj, info):
  138         return obj.is_fully_paid()
  139 
  140     @staticmethod
  141     def resolve_number(obj, info):
  142         return str(obj.pk)
  143 
  144     @staticmethod
  145     def resolve_payment_status(obj, info):
  146         return obj.get_last_payment_status()
  147 
  148     @staticmethod
  149     def resolve_payment_status_display(obj, info):
  150         return obj.get_last_payment_status_display()
  151 
  152     @staticmethod
  153     def resolve_status_display(obj, info):
  154         return obj.get_status_display()
  155 
  156     @staticmethod
  157     def resolve_user_email(obj, info):
  158         if obj.user_email:
  159             return obj.user_email
  160         if obj.user_id:
  161             return obj.user.email
  162         return None
  163 
  164 
  165 class OrderLine(CountableDjangoObjectType):
  166     class Meta:
  167         description = 'Represents order line of particular order.'
  168         model = models.OrderLine
  169         interfaces = [relay.Node]
  170         exclude_fields = [
  171             'order', 'unit_price_gross', 'unit_price_net', 'variant']
  172
  ```
  --- 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()
  
  ```
  
golden_diff: 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 @@
   
   
   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')
  
verification_info: {"golden_diff": "diff --git a/saleor/graphql/order/types.py b/saleor/graphql/order/types.py\n--- a/saleor/graphql/order/types.py\n+++ b/saleor/graphql/order/types.py\n@@ -1,11 +1,13 @@\n+from decimal import Decimal\n+\n import graphene\n from graphene import relay\n \n from ...order import OrderEvents, models\n+from ...product.templatetags.product_images import get_thumbnail\n from ..account.types import User\n from ..core.types.common import CountableDjangoObjectType\n from ..core.types.money import Money, TaxedMoney\n-from decimal import Decimal\n \n OrderEventsEnum = graphene.Enum.from_enum(OrderEvents)\n \n@@ -163,9 +165,21 @@\n \n \n class OrderLine(CountableDjangoObjectType):\n+    thumbnail_url = graphene.String(\n+        description='The URL of a main thumbnail for the ordered product.',\n+        size=graphene.Int(description='Size of the image'))\n+\n     class Meta:\n         description = 'Represents order line of particular order.'\n         model = models.OrderLine\n         interfaces = [relay.Node]\n         exclude_fields = [\n             'order', 'unit_price_gross', 'unit_price_net', 'variant']\n+\n+    def resolve_thumbnail_url(self, info, size=None):\n+        if not self.variant_id:\n+            return None\n+        if not size:\n+            size = 255\n+        return get_thumbnail(\n+            self.variant.get_first_image(), size, method='thumbnail')\n", "issue": "Dashboard 2.0: Order API does not expose a way to get a product thumbnail for an order line\nWe 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.\n", "before_files": [{"content": "import graphene\nfrom graphene import relay\n\nfrom ...order import OrderEvents, models\nfrom ..account.types import User\nfrom ..core.types.common import CountableDjangoObjectType\nfrom ..core.types.money import Money, TaxedMoney\nfrom decimal import Decimal\n\nOrderEventsEnum = graphene.Enum.from_enum(OrderEvents)\n\n\nclass OrderEvent(CountableDjangoObjectType):\n    date = graphene.types.datetime.DateTime(\n        description='Date when event happened at in ISO 8601 format.')\n    type = OrderEventsEnum(description='Order event type')\n    user = graphene.Field(\n        User, id=graphene.Argument(graphene.ID),\n        description='User who performed the action.')\n    message = graphene.String(\n        description='Content of a note added to the order.')\n    email = graphene.String(description='Email of the customer')\n    email_type = graphene.String(\n        description='Type of an email sent to the customer')\n    amount = graphene.Float(description='Amount of money.')\n    quantity = graphene.Int(description='Number of items.')\n    composed_id = graphene.String(\n        description='Composed id of the Fulfillment.')\n\n    class Meta:\n        description = 'History log of the order.'\n        model = models.OrderEvent\n        interfaces = [relay.Node]\n        exclude_fields = ['order', 'parameters']\n\n    def resolve_email(self, info):\n        return self.parameters.get('email', None)\n\n    def resolve_email_type(self, info):\n        return self.parameters.get('email_type', None)\n\n    def resolve_amount(self, info):\n        amount = self.parameters.get('amount', None)\n        return Decimal(amount) if amount else None\n\n    def resolve_quantity(self, info):\n        quantity = self.parameters.get('quantity', None)\n        return int(quantity) if quantity else None\n\n    def resolve_message(self, info):\n        return self.parameters.get('message', None)\n\n    def resolve_composed_id(self, info):\n        return self.parameters.get('composed_id', None)\n\n\nclass Fulfillment(CountableDjangoObjectType):\n    status_display = graphene.String(\n        description='User-friendly fulfillment status.')\n\n    class Meta:\n        description = 'Represents order fulfillment.'\n        interfaces = [relay.Node]\n        model = models.Fulfillment\n        exclude_fields = ['order']\n\n    def resolve_status_display(self, info):\n        return self.get_status_display()\n\n\nclass FulfillmentLine(CountableDjangoObjectType):\n    class Meta:\n        description = 'Represents line of the fulfillment.'\n        interfaces = [relay.Node]\n        model = models.FulfillmentLine\n        exclude_fields = ['fulfillment']\n\n\nclass Order(CountableDjangoObjectType):\n    fulfillments = graphene.List(\n        Fulfillment,\n        required=True,\n        description='List of shipments for the order.')\n    is_paid = graphene.Boolean(\n        description='Informs if an order is fully paid.')\n    number = graphene.String(description='User-friendly number of an order.')\n    payment_status = graphene.String(description='Internal payment status.')\n    payment_status_display = graphene.String(\n        description='User-friendly payment status.')\n    subtotal = graphene.Field(\n        TaxedMoney,\n        description='The sum of line prices not including shipping.')\n    status_display = graphene.String(description='User-friendly order status.')\n    total_authorized = graphene.Field(\n        Money, description='Amount authorized for the order.')\n    total_captured = graphene.Field(\n        Money, description='Amount captured by payment.')\n    events = graphene.List(\n        OrderEvent,\n        description='List of events associated with the order.')\n    user_email = graphene.String(\n        required=False, description='Email address of the customer.')\n\n    class Meta:\n        description = 'Represents an order in the shop.'\n        interfaces = [relay.Node]\n        model = models.Order\n        exclude_fields = [\n            'shipping_price_gross', 'shipping_price_net', 'total_gross',\n            'total_net']\n\n    @staticmethod\n    def resolve_subtotal(obj, info):\n        return obj.get_subtotal()\n\n    @staticmethod\n    def resolve_total_authorized(obj, info):\n        payment = obj.get_last_payment()\n        if payment:\n            return payment.get_total_price().gross\n\n    @staticmethod\n    def resolve_total_captured(obj, info):\n        payment = obj.get_last_payment()\n        if payment:\n            return payment.get_captured_price()\n\n    @staticmethod\n    def resolve_fulfillments(obj, info):\n        return obj.fulfillments.all()\n\n    @staticmethod\n    def resolve_events(obj, info):\n        return obj.events.all()\n\n    @staticmethod\n    def resolve_is_paid(obj, info):\n        return obj.is_fully_paid()\n\n    @staticmethod\n    def resolve_number(obj, info):\n        return str(obj.pk)\n\n    @staticmethod\n    def resolve_payment_status(obj, info):\n        return obj.get_last_payment_status()\n\n    @staticmethod\n    def resolve_payment_status_display(obj, info):\n        return obj.get_last_payment_status_display()\n\n    @staticmethod\n    def resolve_status_display(obj, info):\n        return obj.get_status_display()\n\n    @staticmethod\n    def resolve_user_email(obj, info):\n        if obj.user_email:\n            return obj.user_email\n        if obj.user_id:\n            return obj.user.email\n        return None\n\n\nclass OrderLine(CountableDjangoObjectType):\n    class Meta:\n        description = 'Represents order line of particular order.'\n        model = models.OrderLine\n        interfaces = [relay.Node]\n        exclude_fields = [\n            'order', 'unit_price_gross', 'unit_price_net', 'variant']\n", "path": "saleor/graphql/order/types.py"}], "after_files": [{"content": "from decimal import Decimal\n\nimport graphene\nfrom graphene import relay\n\nfrom ...order import OrderEvents, models\nfrom ...product.templatetags.product_images import get_thumbnail\nfrom ..account.types import User\nfrom ..core.types.common import CountableDjangoObjectType\nfrom ..core.types.money import Money, TaxedMoney\n\nOrderEventsEnum = graphene.Enum.from_enum(OrderEvents)\n\n\nclass OrderEvent(CountableDjangoObjectType):\n    date = graphene.types.datetime.DateTime(\n        description='Date when event happened at in ISO 8601 format.')\n    type = OrderEventsEnum(description='Order event type')\n    user = graphene.Field(\n        User, id=graphene.Argument(graphene.ID),\n        description='User who performed the action.')\n    message = graphene.String(\n        description='Content of a note added to the order.')\n    email = graphene.String(description='Email of the customer')\n    email_type = graphene.String(\n        description='Type of an email sent to the customer')\n    amount = graphene.Float(description='Amount of money.')\n    quantity = graphene.Int(description='Number of items.')\n    composed_id = graphene.String(\n        description='Composed id of the Fulfillment.')\n\n    class Meta:\n        description = 'History log of the order.'\n        model = models.OrderEvent\n        interfaces = [relay.Node]\n        exclude_fields = ['order', 'parameters']\n\n    def resolve_email(self, info):\n        return self.parameters.get('email', None)\n\n    def resolve_email_type(self, info):\n        return self.parameters.get('email_type', None)\n\n    def resolve_amount(self, info):\n        amount = self.parameters.get('amount', None)\n        return Decimal(amount) if amount else None\n\n    def resolve_quantity(self, info):\n        quantity = self.parameters.get('quantity', None)\n        return int(quantity) if quantity else None\n\n    def resolve_message(self, info):\n        return self.parameters.get('message', None)\n\n    def resolve_composed_id(self, info):\n        return self.parameters.get('composed_id', None)\n\n\nclass Fulfillment(CountableDjangoObjectType):\n    status_display = graphene.String(\n        description='User-friendly fulfillment status.')\n\n    class Meta:\n        description = 'Represents order fulfillment.'\n        interfaces = [relay.Node]\n        model = models.Fulfillment\n        exclude_fields = ['order']\n\n    def resolve_status_display(self, info):\n        return self.get_status_display()\n\n\nclass FulfillmentLine(CountableDjangoObjectType):\n    class Meta:\n        description = 'Represents line of the fulfillment.'\n        interfaces = [relay.Node]\n        model = models.FulfillmentLine\n        exclude_fields = ['fulfillment']\n\n\nclass Order(CountableDjangoObjectType):\n    fulfillments = graphene.List(\n        Fulfillment,\n        required=True,\n        description='List of shipments for the order.')\n    is_paid = graphene.Boolean(\n        description='Informs if an order is fully paid.')\n    number = graphene.String(description='User-friendly number of an order.')\n    payment_status = graphene.String(description='Internal payment status.')\n    payment_status_display = graphene.String(\n        description='User-friendly payment status.')\n    subtotal = graphene.Field(\n        TaxedMoney,\n        description='The sum of line prices not including shipping.')\n    status_display = graphene.String(description='User-friendly order status.')\n    total_authorized = graphene.Field(\n        Money, description='Amount authorized for the order.')\n    total_captured = graphene.Field(\n        Money, description='Amount captured by payment.')\n    events = graphene.List(\n        OrderEvent,\n        description='List of events associated with the order.')\n    user_email = graphene.String(\n        required=False, description='Email address of the customer.')\n\n    class Meta:\n        description = 'Represents an order in the shop.'\n        interfaces = [relay.Node]\n        model = models.Order\n        exclude_fields = [\n            'shipping_price_gross', 'shipping_price_net', 'total_gross',\n            'total_net']\n\n    @staticmethod\n    def resolve_subtotal(obj, info):\n        return obj.get_subtotal()\n\n    @staticmethod\n    def resolve_total_authorized(obj, info):\n        payment = obj.get_last_payment()\n        if payment:\n            return payment.get_total_price().gross\n\n    @staticmethod\n    def resolve_total_captured(obj, info):\n        payment = obj.get_last_payment()\n        if payment:\n            return payment.get_captured_price()\n\n    @staticmethod\n    def resolve_fulfillments(obj, info):\n        return obj.fulfillments.all()\n\n    @staticmethod\n    def resolve_events(obj, info):\n        return obj.events.all()\n\n    @staticmethod\n    def resolve_is_paid(obj, info):\n        return obj.is_fully_paid()\n\n    @staticmethod\n    def resolve_number(obj, info):\n        return str(obj.pk)\n\n    @staticmethod\n    def resolve_payment_status(obj, info):\n        return obj.get_last_payment_status()\n\n    @staticmethod\n    def resolve_payment_status_display(obj, info):\n        return obj.get_last_payment_status_display()\n\n    @staticmethod\n    def resolve_status_display(obj, info):\n        return obj.get_status_display()\n\n    @staticmethod\n    def resolve_user_email(obj, info):\n        if obj.user_email:\n            return obj.user_email\n        if obj.user_id:\n            return obj.user.email\n        return None\n\n\nclass OrderLine(CountableDjangoObjectType):\n    thumbnail_url = graphene.String(\n        description='The URL of a main thumbnail for the ordered product.',\n        size=graphene.Int(description='Size of the image'))\n\n    class Meta:\n        description = 'Represents order line of particular order.'\n        model = models.OrderLine\n        interfaces = [relay.Node]\n        exclude_fields = [\n            'order', 'unit_price_gross', 'unit_price_net', 'variant']\n\n    def resolve_thumbnail_url(self, info, size=None):\n        if not self.variant_id:\n            return None\n        if not size:\n            size = 255\n        return get_thumbnail(\n            self.variant.get_first_image(), size, method='thumbnail')\n", "path": "saleor/graphql/order/types.py"}]}