4

I have a controller that receives custom options for a specific configurable product. For each custom option, I must add the product to the cart with such custom additional option. In the end, I want as many cart items as the number of custom options submitted.

The problem is, because im adding the same configurable product more than once (although with different custom options) in the same script execution, something is messing up when the cart is saved.

At first, I think this is a Magento 2.x bug. I've even opened an issue in Github here: https://github.com/magento/magento2/issues/7488

But maybe its just a simple detail I'm missing, thats why I wonder if anybody could help with this.

Bellow is a test script to illustrate the problem.

$storeId = $this->_objectManager->get('Magento\Store\Model\StoreManagerInterface')->getStore()->getId();
$cart = $this->_objectManager->get('\Magento\Checkout\Model\Cart')->getStore()->getId();

$productId = 115; // Configurable Product

$colorAttributeId = 90;
$color = 10; // white

$sizeAttributeId = 135;
$size = 13; // small

$customOptionValues = [
    'print_style_1', 
    'print_style_2',
];

foreach ($customOptionValues as $customOptionValue) {
    $product = $this->_objectManager->create('Magento\Catalog\Model\Product')->setStoreId($storeId)->load($productId);

    // prepare buyRequest
    $buyRequest = new \Magento\Framework\DataObject();
    $buyRequest->setData([
        'qty' => 1,
        'super_attribute' => [
            $colorAttributeId => $color,
            $sizeAttributeId => $size,
        ],
    ]);

    $additionalOptions = array();
    if ($originalAdditionalOptions = $product->getCustomOption('additional_options'))
    {
        $additionalOptions = (array) unserialize($originalAdditionalOptions->getValue());
    }
    $additionalOptions['print_style'] = [
        'label' => 'Print Style',
        'value' => $customOptionValue,
    ];

    // add the additional options array with the option code additional_options
    $product->addCustomOption('additional_options', serialize($additionalOptions));

    $cart->addProduct($product, $buyRequest);
}
$cart->save();
$cart->getQuote()->setTotalsCollectedFlag(false)->collectTotals()->save();

Expected result

Upon $cart->save() there should be 2 products in the cart, each one with the same configurable attribute options, but with distinct custom additional options (Print style)

expected cart result

Actual result

Whe cart is saved, an exception is thrown regarding the quote_item_option INSERT query.

Notice the insert query for the item option is missing the 'item_id' column

SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails (magento.quote_item_option, CONSTRAINT QUOTE_ITEM_OPTION_ITEM_ID_QUOTE_ITEM_ITEM_ID FOREIGN KEY (item_id) REFERENCES quote_item (item_id) ON DELETE CASCADE), query was: INSERT INTO quote_item_option (product_id, code, value) VALUES (?, ?, ?)

If you add one product with custom option A in one HTTP request, and then do another HTTP request to add the same product with custom option B, there will be no errors. This only happens when products are added to cart in the same HTTP request.

0

Since there's no update or aknowledgement of the issue I've opened in GitHub, here is my workaround to insert more than one product with custom options to the cart:

  1. On the first submit to the custom controller, set up a queue variable in the checkout session (or any other session of your choice). Also save the referer url. Add the first product to the cart and then remove it from the queue var
  2. Redirect to the same controller action url
  3. Upon not receiving any post data, just proccess the queue again and keep redirecting until queue is empty
  4. Finally, redirect back to the cart or to the referer url saved on the first request
0

The easiest fix is to make clone a subproduct instance in _prepareProduct() protected method in vendor\magento\module-configurable-product\Model\Product\Type\Configurable.php.

  1. Override Magento\ConfigurableProduct\Model\Product\Type\Configurable class
  2. Make following changes

From

if ($subProduct) {
    $subProduct = $this->getProductByAttributes($attributes, $product);
}

to

if ($subProduct) {
    $subProduct = clone $this->getProductByAttributes($attributes, $product);
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.