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.56k stars 9.32k forks source link

Quote/totals return incorrect information after deleting items. #27139

Open Jasper-ketelaar opened 4 years ago

Jasper-ketelaar commented 4 years ago

Preconditions (*)

  1. Magento version 2.3.3
  2. Using REST API calls

Steps to reproduce (*)

  1. Create a quote for a user if they do not have one.
  2. Add a few items item to the shopping cart using POST carts/{quoteId}/items
  3. Delete all items in quick succession using DELETE carts/{quoteId}/items
  4. Get the cart using GET carts/{quoteId}

Expected result (*)

  1. The cart should be empty and items_qty should be 0
  2. The cart should be empty and items_count should be 0

Actual result (*)

  1. image
  2. items is an empty array but items_qty is 2.
  3. items is an empty array but items_count is 2.
m2-assistant[bot] commented 4 years ago

Hi @Jasper-ketelaar. Thank you for your report. To help us process this issue please make sure that you provided the following information:

Please make sure that the issue is reproducible on the vanilla Magento instance following Steps to reproduce. To deploy vanilla Magento instance on our environment, please, add a comment to the issue:

@magento give me 2.4-develop instance - upcoming 2.4.x release

For more details, please, review the Magento Contributor Assistant documentation.

@Jasper-ketelaar do you confirm that you were able to reproduce the issue on vanilla Magento instance following steps to reproduce?


m2-assistant[bot] commented 4 years ago

Hi @engcom-Echo. 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:

magento-engcom-team commented 4 years ago

:white_check_mark: Confirmed by @engcom-Echo Thank you for verifying the issue. Based on the provided information internal tickets MC-32311 were created

Issue Available: @engcom-Echo, You will be automatically unassigned. Contributors/Maintainers can claim this issue to continue. To reclaim and continue work, reassign the ticket to yourself.

m2-assistant[bot] commented 4 years ago

Hi @engcom-Charlie. Thank you for working on this issue. Looks like this issue is already verified and confirmed. But if you want to validate it one more time, please, go though the following instruction:


sudheernayak31 commented 4 years ago

@Jasper-ketelaar I am unable to re-produce the same, just to rewind

This leads to "items_count": 0, "items_qty": 0 so Please share exact steps to re-produce.

ProkopovVitaliy commented 4 years ago

@Jasper-ketelaar i was trying to reproduce this issue on 2.3.3 and 2.4 version many times but I did not succeed. For work with api i was using Postman.

My reproduce flow:

  1. Created new quote: POST /V1/carts/mine
  2. Added couple of items to quote (with configurable products) POST /V1/carts/{quoteId}/items 2.1 My request body example:

    
    {
    "cartItem": {
    "sku": "WS12",
    "qty": 1,
    "quote_id": "{quoteId}",
    "product_option": {
        "extension_attributes": {
            "configurable_item_options":
            [
                {
                    "option_id": "152",
                    "option_value": 166
    
                },
                {
                    "option_id": "93",
                    "option_value": 57
                }
            ]
        }
    }
    }
    }

3. Checked state of quote and made sure everything with quote is ok (item_qty  is right). `GET /V1/carts/{quoteId`
4. Deleted all items one by one `DELETE /V1/{quoteId}/5/items/{itemId}`
5. Checked state of quote again and made sure that item_qty  is correct
<img width="342" alt="Screenshot 2020-03-16 at 12 22 46" src="https://user-images.githubusercontent.com/29776509/76746945-01641600-6781-11ea-97e6-e7c7040e5ee9.png">

**After that i also wrote some script that do this many times and very fast, and i never got the wrong result.**

**So could you give more detailed information ? For example php version, work environment configs or maybe you use some extension which has side effects related to quote?**
MageRakesh commented 4 years ago

@magento I am working on it

m2-assistant[bot] commented 4 years ago

Hi @MageRakesh! :wave: Thank you for joining. Please accept team invitation :point_right: here :point_left: and self-assign the issue.

JKetelaar commented 4 years ago

After a lot of debugging this can be achieved by requesting the delete calls asynchronous. Here's some test code you can use (proof of concept code, nothing with standards 😂). Do note, this uses the async PHP package spatie/async.

<?php
/**
 * @author JKetelaar
 * @noinspection PhpComposerExtensionStubsInspection
 */

require_once('vendor/autoload.php');

const url = 'http://your.mage.instance/';
const bearer = 'your_bearer_key';
const skus = [
    'AALT-17003',
    'PAVI-12021',
    '660022',
];

$seconds = time();

$curl = curl_init();

curl_setopt_array(
    $curl,
    [
        CURLOPT_URL => url."/rest/V1/carts/",
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_ENCODING => "",
        CURLOPT_MAXREDIRS => 10,
        CURLOPT_TIMEOUT => 0,
        CURLOPT_FOLLOWLOCATION => true,
        CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
        CURLOPT_CUSTOMREQUEST => "POST",
        CURLOPT_HTTPHEADER => [
            "Authorization: Bearer ".bearer,
        ],
    ]
);

$response = curl_exec($curl);

curl_close($curl);
$cartId = json_decode($response);

$items = [];
foreach (skus as $sku) {
    $items[] = addToCart($cartId, $sku);
}

$pool = \Spatie\Async\Pool::create();

foreach ($items as $item) {
    $url = url;
    $bearer = bearer;
    $pool->add(
        function () use ($bearer, $url, $cartId, $item) {
            $curl = curl_init();

            curl_setopt_array(
                $curl,
                [
                    CURLOPT_URL => $url."/rest/V1/carts/".$cartId."/items/".$item,
                    CURLOPT_RETURNTRANSFER => true,
                    CURLOPT_ENCODING => "",
                    CURLOPT_MAXREDIRS => 10,
                    CURLOPT_TIMEOUT => 0,
                    CURLOPT_FOLLOWLOCATION => true,
                    CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
                    CURLOPT_CUSTOMREQUEST => "DELETE",
                    CURLOPT_HTTPHEADER => [
                        "Authorization: Bearer ".$bearer,
                    ],
                ]
            );

            curl_exec($curl);

            curl_close($curl);
        }
    )->then(
        function ($output) {
            echo "Deleted item\n";
        }
    );
}
$pool->wait();

$cartInfo = getCart($cartId);
echo 'cart ID: '.$cartId."\n";
echo 'items_count: '.$cartInfo['items_count']."\n";
echo 'items count(): '.count($cartInfo['items'])."\n";
echo 'time: '.(time() - $seconds)." seconds\n";

function getCart($cartId)
{
    $curl = curl_init();

    curl_setopt_array(
        $curl,
        [
            CURLOPT_URL => url."/rest/V1/carts/".$cartId,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_ENCODING => "",
            CURLOPT_MAXREDIRS => 10,
            CURLOPT_TIMEOUT => 0,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
            CURLOPT_CUSTOMREQUEST => "GET",
            CURLOPT_HTTPHEADER => [
                "Authorization: Bearer ".bearer,
            ],
        ]
    );

    $response = curl_exec($curl);

    curl_close($curl);

    return json_decode($response, true);
}

function addToCart($cart, $sku)
{
    $curl = curl_init();

    curl_setopt_array(
        $curl,
        [
            CURLOPT_URL => url."/rest/V1/carts/".$cart."/items",
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_ENCODING => "",
            CURLOPT_MAXREDIRS => 10,
            CURLOPT_TIMEOUT => 0,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
            CURLOPT_CUSTOMREQUEST => "POST",
            CURLOPT_POSTFIELDS => "{\n  \"cartItem\": {\n    \"sku\": \"".$sku."\",\n    \"qty\": 1,\n    \"quote_id\": \"".$cart."\"\n  }\n}",
            CURLOPT_HTTPHEADER => [
                "Authorization: Bearer ".bearer,
                "Content-Type: application/json",
            ],
        ]
    );

    $response = curl_exec($curl);

    curl_close($curl);

    return json_decode($response, true)['item_id'];
}
stale[bot] commented 3 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed after 14 days if no further activity occurs. Is this issue still relevant? If so, what is blocking it? Is there anything you can do to help move it forward? Thank you for your contributions!

JKetelaar commented 3 years ago

Still the case

stale[bot] commented 3 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed after 14 days if no further activity occurs. Is this issue still relevant? If so, what is blocking it? Is there anything you can do to help move it forward? Thank you for your contributions!

dverkade commented 3 years ago

Posting a comment. Issues should not be automatically closed.

Jasper-ketelaar commented 3 years ago

I think the 'problem runs a bit deeper than I originally thought. Simply put, Magento will not handle synchronous requests that are sent after each other as you would hope to expect. They have (as far as I am aware) no queue for stalling requests that come in when other requests are still being processed.

So if you send two quote-related requests in quick success Magento will somehow process them at the time of each request's arrival and does not have any checks on whether or not any other request is currently altering the state of the quote.

The way I ended up solving this was by just sending the request synchronously so that Magento never has to deal with the multiple requests on the same object being present at the same time.

stale[bot] commented 3 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed after 28 days if no further activity occurs. Is this issue still relevant? If so, what is blocking it? Is there anything you can do to help move it forward? Thank you for your contributions!