magento / magento2

Prior to making any Submission(s), you must sign an Adobe Contributor License Agreement, available here at: https://opensource.adobe.com/cla.html. All Submissions you make to Adobe Inc. and its affiliates, assigns and subsidiaries (collectively “Adobe”) are subject to the terms of the Adobe Contributor License Agreement.
http://www.magento.com
Open Software License 3.0
11.55k stars 9.32k forks source link

GraphQl customer orders query failed if try to retreive order item with deleted product #38900

Open zakdma opened 4 months ago

zakdma commented 4 months ago

Preconditions and environment

Steps to reproduce

  1. Install vanilla Magento instance
  2. Go to admin and create new simple product with SKU: simple-deleted
  3. Fill in all necessary product data to display it on front (stock, price, category etc.) and save it
  4. Reindex all
  5. Go to front and create new customer
  6. Find and add simple-deleted product to cart
  7. Go to checkout and place an order using some address data and default shipping and billing methods
  8. Go to admin and see the order is in Sales/Orders grid
  9. Open any GraphQl client and generate token using generateCustomerToken GraphQl mutation using previously created customer credentials https://developer.adobe.com/commerce/webapi/graphql/schema/customer/mutations/generate-token/
  10. Use the generated token in the following requests by adding it to Authorization header according to Magento GraphQl documentation
  11. perform query
    query {
    customer {
    orders(currentPage: 1, pageSize: 999) {
      items {
        number
        items {
          product {
            sku
            name
          }
        }
      }
    }
    }
    }
  12. See the correct response like this
    {
    "data": {
    "customer": {
      "orders": {
        "items": [
          {
            "number": "000000001",
            "items": [
              {
                "product": {
                  "sku": "simple-deleted",
                  "name": "simple-deleted"
                }
              }
            ]
          }
        ]
      }
    }
    }
    }
  13. Go to admin and delete product simple-deleted
  14. Perform the query again
    query {
    customer {
    orders(currentPage: 1, pageSize: 999) {
      items {
        number
        items {
          product {
            sku
            name
          }
        }
      }
    }
    }
    }

Expected result

There is a correct response with the data requested without any error

Actual result

There is error response like this

{
  "errors": [
    {
      "message": "Internal server error",
      "locations": [
        {
          "line": 7,
          "column": 11
        }
      ],
      "path": [
        "customer",
        "orders",
        "items",
        0,
        "items",
        0,
        "product"
      ]
    }
  ],
  "data": {
    "customer": {
      "orders": {
        "items": [
          {
            "number": "000000001",
            "items": [
              {
                "product": null
              }
            ]
          }
        ]
      }
    }
  }
}

Additional information

Check exception.log and see error like this

[2024-07-03T15:09:43.938496+00:00] main.ERROR: Missing key "associatedProduct" in Order Item value data

GraphQL (40:11)
39:           }
40:           product {
              ^
41:             id
 {"exception":"[object] (GraphQL\\Error\\Error(code: 0): Missing key \"associatedProduct\" in Order Item value data at /var/www/app/vendor/webonyx/graphql-php/src/Error/Error.php:155)
[previous exception] [object] (Magento\\Framework\\Exception\\LocalizedException(code: 0): Missing key \"associatedProduct\" in Order Item value data at /var/www/app/vendor/magento/module-sales-graph-ql/Model/Resolver/ProductResolver.php:46)"} []

Release note

No response

Triage and priority

m2-assistant[bot] commented 4 months ago

Hi @zakdma. Thank you for your report. To speed up processing of this issue, make sure that the issue is reproducible on the vanilla Magento instance following Steps to reproduce. To deploy vanilla Magento instance on our environment, Add a comment to the issue:

m2-assistant[bot] commented 4 months ago

Hi @engcom-Bravo. Thank you for working on this issue. In order to make sure that issue has enough information and ready for development, please read and check the following instruction: :point_down:

engcom-Bravo commented 4 months ago

@magento give me 2.4-develop instance

magento-deployment-service[bot] commented 4 months ago

Hi @engcom-Bravo. Thank you for your request. I'm working on Magento instance for you.

magento-deployment-service[bot] commented 4 months ago

Hi @engcom-Bravo, here is your Magento Instance: https://11bfd466f8c258a1113feb50fd641584.instances-prod.magento-community.engineering Admin access: https://11bfd466f8c258a1113feb50fd641584.instances-prod.magento-community.engineering/admin_b096 Login: 0094132b Password: 5f24f247854d

engcom-Bravo commented 4 months ago

Hi @zakdma,

Thanks for your reporting and collaboration.

We have verified the issue in Latest 2.4-develop instance and the issue is reproducible.Kindly refer the screenshots.

Screenshot 2024-07-04 at 13 11 06

Error in Exception Logs:

GraphQL (11:11)
10:         items {
11:           product {
              ^
12:             sku
 {"exception":"[object] (GraphQL\\Error\\Error(code: 0): Missing key \"associatedProduct\" in Order Item value data at /usr/local/var/www/magentok/magento2/vendor/webonyx/graphql-php/src/Error/Error.php:155)
[previous exception] [object] (Magento\\Framework\\Exception\\LocalizedException(code: 0): Missing key \"associatedProduct\" in Order Item value data at /usr/local/var/www/magentok/magento2/app/code/Magento/SalesGraphQl/Model/Resolver/ProductResolver.php:46)"} []

Hence Confirming the issue.

Thanks.

github-jira-sync-bot commented 4 months ago

:white_check_mark: Jira issue https://jira.corp.adobe.com/browse/AC-12332 is successfully created for this GitHub issue.

m2-assistant[bot] commented 4 months ago

:white_check_mark: Confirmed by @engcom-Bravo. Thank you for verifying the issue.
Issue Available: @engcom-Bravo, You will be automatically unassigned. Contributors/Maintainers can claim this issue to continue. To reclaim and continue work, reassign the ticket to yourself.

quterorta commented 3 months ago

@magento I'm working on this

quterorta commented 3 months ago

I guess it's a normal behavior. If you delete the product and try to get the customer's order list via GraphQl, you get the next response: image As you can see, the order list is still available, you just can't get product data (obviously, because you deleted it). So, hypothetically, it's possible to add order item data to product data, and the rest of it provided as null, but I think it's redundant.

quterorta commented 3 months ago

Also, this issue doesn't look like an accidental bug, this behavior was developed to throw exceptions, if an order item doesn't have associated product data (for example, in our case, when the product was deleted) image

pmzandbergen commented 3 months ago

I think the exception is redundant and shouldn't be throwed. It's a nullable field, and besides the error message thrown isn't really clear to frontend / the GraphQL API user.

Simply returning null is correct. The type hint in the Order Item resolver is also wrong: https://github.com/magento/magento2/blob/2.4-develop/app/code/Magento/SalesGraphQl/Model/OrderItem/DataProvider.php#L137

/** @var ProductInterface $associatedProduct */

Should be:

/** @var ProductInterface|null $associatedProduct */

Or even better, add a private function with a correct return type.

@quterorta since I've already created a patch for this issue: Are you working on the code or do you want me to create a PR?

quterorta commented 3 months ago

@pmzandbergen Hm, I agree with you. Yeah, if you have already created a patch for it, you could create PR, no problems

pmzandbergen commented 3 months ago

@magento give me 2.4-develop instance

magento-deployment-service[bot] commented 3 months ago

Hi @pmzandbergen. Thank you for your request. I'm working on Magento instance for you.

magento-deployment-service[bot] commented 3 months ago

Hi @pmzandbergen, here is your Magento Instance: https://11bfd466f8c258a1113feb50fd641584.instances-prod.magento-community.engineering Admin access: https://11bfd466f8c258a1113feb50fd641584.instances-prod.magento-community.engineering/admin_a69f Login: 62be90e3 Password: 2bf33469180f

dimitriBouteille commented 2 weeks ago

Hi @zakdma Any news for this issue ?

Maybe someone has already made a patch? Because I have this problem too :(

pmzandbergen commented 2 weeks ago

@dimitriBouteille depends on what you want to see as a fix (nullable product, product ignoring the state and scope). Simple fix could be:

--- Model/OrderItem/DataProvider.php.org    2024-07-17 10:59:31
+++ Model/OrderItem/DataProvider.php    2024-07-17 11:01:09
@@ -10,6 +10,7 @@
 use Magento\Catalog\Api\Data\ProductInterface;
 use Magento\Catalog\Api\ProductRepositoryInterface;
 use Magento\Framework\Api\SearchCriteriaBuilder;
+use Magento\Framework\Exception\NoSuchEntityException;
 use Magento\Sales\Api\Data\OrderInterface;
 use Magento\Sales\Api\Data\OrderItemInterface;
 use Magento\Sales\Api\OrderItemRepositoryInterface;
@@ -184,15 +185,13 @@
             $orderItems
         );

-        $searchCriteria = $this->searchCriteriaBuilder
-            ->addFilter('entity_id', $productIds, 'in')
-            ->create();
-        $products = $this->productRepository->getList($searchCriteria)->getItems();
-        $productList = [];
-        foreach ($products as $product) {
-            $productList[$product->getId()] = $product;
-        }
-        return $productList;
+        return array_combine($productIds, array_map(function (mixed $productId): ?ProductInterface {
+            try {
+                return $this->productRepository->getById($productId);
+            } catch (NoSuchEntityException $e) {
+                return null;
+            }
+        }, $productIds));
     }

     /**
pmzandbergen commented 2 weeks ago

@dimitriBouteille note that this fix is not as efficient, since we’re (trying to) load(ing) each product independently.

Using the deferred data provider would be a more efficient solution. However the existing one also has a few bugs.

Planning to fix those and this one when I’ve got some spare time.