Как «добавить в корзину» товар с настраиваемым полем ввода и сохранить его в базе данных?

9

Я создал собственный модуль, в котором я переопределяю форму добавления в корзину на странице продукта, и я успешно сделал это с catalog_product_view.xmlфайлом. Теперь я могу видеть настраиваемое поле ввода на виде спереди на странице продукта, но мне нужно опубликовать значение этого поля в базе данных с указанием Qty, цены и т. Д. И снова извлечь его в истории заказов.

Я искал некоторое время, а также добился успеха в создании новых пользовательских столбцов в quote_item& sales_orderтаблиц. (Согласно моей информации, добавьте в корзину записи, quote_itemа заказы после оформления заказа перейдите к sales_orderтаблице. Если я ошибаюсь, исправьте меня и в этом, так как я еще учусь.)

Я много пробовал и искал, но не нашел подходящего решения. Мое имя продавца - Cloudways, а имя модуля - Mymodule . Ниже приведены файлы для моего модуля:

Cloudways / MyModule / registration.php

<?php
\Magento\Framework\Component\ComponentRegistrar::register(
    \Magento\Framework\Component\ComponentRegistrar::MODULE,
    'Cloudways_Mymodule',
    __DIR__
);

Cloudways / MyModule / и т.д. / module.xml

<?xml version="1.0"?>
    <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
    <module name="Cloudways_Mymodule" setup_version="1.0.1"></module>
</config>

Cloudways / MyModule / Setup / UpgradeSchema.php

<?php

namespace Cloudways\Mymodule\Setup;

use Magento\Framework\Setup\UpgradeSchemaInterface;
use Magento\Framework\Setup\SchemaSetupInterface;
use Magento\Framework\Setup\ModuleContextInterface;

class UpgradeSchema implements UpgradeSchemaInterface
{
    public function upgrade(SchemaSetupInterface $setup, ModuleContextInterface $context)
    {
        if (version_compare($context->getVersion(), '1.0.1') < 0) {

        $installer = $setup;
        $installer->startSetup();
        $connection = $installer->getConnection();
        //cart table
        $connection->addColumn(
                $installer->getTable('quote_item'),
                'remarks',
                [
                    'type' => \Magento\Framework\DB\Ddl\Table::TYPE_TEXT,
                    'length' => 255,
                    'comment' =>'Remarks'
                ]
            );
        //Order address table
        $connection->addColumn(
                $installer->getTable('sales_order'),
                'remarks',
                [
                    'type' => \Magento\Framework\DB\Ddl\Table::TYPE_TEXT,
                    'length' => 255,
                    'comment' =>'Remarks'

                ]
            );
        $installer->endSetup(); }
    }
}

Cloudways / MyModule / просмотра / интерфейс / расположение / catalog_product_view.xml

<?xml version="1.0"?>
<page layout="1column" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <body>
        <referenceBlock name="product.info.addtocart">
            <action method="setTemplate">
                <argument name="template" xsi:type="string">Cloudways_Mymodule::catalog/product/view/addtocart.phtml</argument>
            </action>
        </referenceBlock>
        <referenceBlock name="product.info.addtocart.additional">
            <action method="setTemplate">
                <argument name="template" xsi:type="string">Cloudways_Mymodule::catalog/product/view/addtocart.phtml</argument>
            </action>
        </referenceBlock>
    </body>
</page>

Cloudways / MyModule / просмотр / интерфейс / шаблоны / Каталог / продукта / вид / addtocart.phtml

<?php
/**
 * Copyright © 2016 Magento. All rights reserved.
 * See COPYING.txt for license details.
 */

// @codingStandardsIgnoreFile

/** @var $block \Magento\Catalog\Block\Product\View */
?>
<?php $_product = $block->getProduct(); ?>
<?php $buttonTitle = __('Add to Cart'); ?>
<?php if ($_product->isSaleable()): ?>
<div class="box-tocart">
    <div class="fieldset">
        <?php if ($block->shouldRenderQuantity()): ?>
        <div class="field qty">
            <label class="label" for="qty"><span><?php /* @escapeNotVerified */ echo __('Qty') ?></span></label>
            <div class="control">
                <input type="number"
                       name="qty"
                       id="qty"
                       maxlength="12"
                       value="<?php /* @escapeNotVerified */ echo $block->getProductDefaultQty() * 1 ?>"
                       title="<?php /* @escapeNotVerified */ echo __('Qty') ?>" class="input-text qty"
                       data-validate="<?php echo $block->escapeHtml(json_encode($block->getQuantityValidators())) ?>"
                       />
            </div>
        </div>
        <!-- Custom Input Field -->
        <div>
            <input
                type="text"
                name="remarks"
                id="remarks"
                maxlength="255"
                placeholder="Remarks"
            />
        </div>
        <!-- Custom Input Field -->
        <br>
        <?php endif; ?>
        <div class="actions">
            <button type="submit"
                    title="<?php /* @escapeNotVerified */ echo $buttonTitle ?>"
                    class="action primary tocart"
                    id="product-addtocart-button">
                <span><?php /* @escapeNotVerified */ echo $buttonTitle ?></span>
            </button>
            <?php echo $block->getChildHtml('', true) ?>
        </div>
    </div>
</div>
<?php endif; ?>
<?php if ($block->isRedirectToCartEnabled()) : ?>
<script type="text/x-magento-init">
    {
        "#product_addtocart_form": {
            "Magento_Catalog/product/view/validation": {
                "radioCheckboxClosest": ".nested"
            }
        }
    }
</script>
<?php else : ?>
<script>
    require([
        'jquery',
        'mage/mage',
        'Magento_Catalog/product/view/validation',
        'Magento_Catalog/js/catalog-add-to-cart'
    ], function ($) {
        'use strict';

        $('#product_addtocart_form').mage('validation', {
            radioCheckboxClosest: '.nested',
            submitHandler: function (form) {
                var widget = $(form).catalogAddToCart({
                    bindSubmit: false
                });

                widget.catalogAddToCart('submitForm', $(form));

                return false;
            }
        });
    });
</script>
<?php endif; ?>

Вот скриншот вид спереди:

введите описание изображения здесь

Все, что мне нужно, это опубликовать значение пользовательского поля ввода и сохранить его в базе данных вместе с заказом. Заранее спасибо!

РЕДАКТИРОВАТЬ: Я сделал соответствующие изменения в ответ на RS, и вот проблема, с которой я сталкиваюсь: (PS Я использую MAGENTO 2.0.9)

введите описание изображения здесь

Я проверил файл журнала и вот что я нашел:

[2016-08-26 07:29:38] main.CRITICAL: exception 'Exception' with message 'Report ID: webapi-57bfefe2d8272; Message: Warning: Invalid argument supplied for foreach() in /home/41209-54048.cloudwaysapps.com/yyzmyegjdk/public_html/app/code/Cloudways/Mymodule/Observer/SalesModelServiceQuoteSubmitBeforeObserver.php on line 67' in /home/41209-54048.cloudwaysapps.com/yyzmyegjdk/public_html/vendor/magento/framework/Webapi/ErrorProcessor.php:194
Stack trace:
#0 /home/41209-54048.cloudwaysapps.com/yyzmyegjdk/public_html/vendor/magento/framework/Webapi/ErrorProcessor.php(139): Magento\Framework\Webapi\ErrorProcessor->_critical(Object(Exception))
#1 /home/41209-54048.cloudwaysapps.com/yyzmyegjdk/public_html/vendor/magento/module-webapi/Controller/Rest.php(163): Magento\Framework\Webapi\ErrorProcessor->maskException(Object(Exception))
#2 /home/41209-54048.cloudwaysapps.com/yyzmyegjdk/public_html/var/generation/Magento/Webapi/Controller/Rest/Interceptor.php(24): Magento\Webapi\Controller\Rest->dispatch(Object(Magento\Framework\App\Request\Http))
#3 /home/41209-54048.cloudwaysapps.com/yyzmyegjdk/public_html/vendor/magento/framework/App/Http.php(115): Magento\Webapi\Controller\Rest\Interceptor->dispatch(Object(Magento\Framework\App\Request\Http))
#4 /home/41209-54048.cloudwaysapps.com/yyzmyegjdk/public_html/vendor/magento/framework/App/Bootstrap.php(258): Magento\Framework\App\Http->launch()
#5 /home/41209-54048.cloudwaysapps.com/yyzmyegjdk/public_html/index.php(39): Magento\Framework\App\Bootstrap->run(Object(Magento\Framework\App\Http))
#6 {main} [] []

Любые предложения, пожалуйста?

Файяз Хаттак
источник
Взгляните на этот пример magento 1 stackoverflow.com/questions/9412074/… ... вы должны быть в состоянии использовать «дополнительные_опции» для хранения этой информации, используя наблюдатель github.com/magento/magento2/… ... используя дополнительные_опции автоматически покажет эту информацию в админке, электронной почте заказа на продажу и т. д.
Ренон Стюарт,
Есть ли причина, по которой вы не используете простой продукт с пользовательскими настройками для этого?
Ренон Стюарт
@RS Мне нужно сделать это программно, потому что мы будем расширять эту пользовательскую корзину с помощью других пользовательских параметров, которые, я думаю, могут быть сделаны только с помощью пользовательского модуля.
Файяз Хаттак
Можете ли вы добавить (github) ссылку на ваш код, чтобы я мог скачать и попробовать реализовать дополнительные_опции
Ренон Стюарт
@RS Да, конечно, пожалуйста, дайте мне несколько минут.
Файяз Хаттак

Ответы:

14

Для этого вы можете использовать встроенную в magento функцию «дополнительные_опции», чтобы вам не приходилось редактировать шаблон электронной почты, представление заказа администратора, представление заказа клиента (и т. Д.) Для отображения пользовательских настроек.

Github: https://github.com/srenon/Cloudways_Mymodule

/app/code/Cloudways/Mymodule/etc/events.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
    <event name="checkout_cart_product_add_after">
        <observer name="cloudways_mymodule_checkout_cart_product_add_after" instance="Cloudways\Mymodule\Observer\CheckoutCartProductAddAfterObserver" />
    </event>
    <event name="sales_model_service_quote_submit_before">
        <observer name="cloudways_mymodule_sales_model_service_quote_submit_before" instance="Cloudways\Mymodule\Observer\SalesModelServiceQuoteSubmitBeforeObserver" />
    </event>
</config>

Добавить опцию для цитаты

/app/code/Cloudways/Mymodule/Observer/CheckoutCartProductAddAfterObserver.php

<?php

namespace Cloudways\Mymodule\Observer;

use Magento\Framework\Event\Observer as EventObserver;
use Magento\Framework\Event\ObserverInterface;
use Magento\Framework\App\RequestInterface;

class CheckoutCartProductAddAfterObserver implements ObserverInterface
{

    protected $_request;

    /**
     * @param RequestInterface $request
     */
    public function __construct(RequestInterface $request){
            $this->_request = $request;
    }

    /**
     * @param EventObserver $observer
     * @return void
     */
    public function execute(EventObserver $observer)
    {
        /* @var \Magento\Quote\Model\Quote\Item $item */
        $item = $observer->getQuoteItem();

        $additionalOptions = array();

        if ($additionalOption = $item->getOptionByCode('additional_options')){
            $additionalOptions = (array) unserialize($additionalOption->getValue());
        }

        $post = $this->_request->getParam('cloudways');

        if(is_array($post)){
            foreach($post as $key => $value){
                if($key == '' || $value == ''){
                    continue;
                }

                $additionalOptions[] = [
                    'label' => $key,
                    'value' => $value
                ];
            }
        }

        if(count($additionalOptions) > 0){
            $item->addOption(array(
                'code' => 'additional_options',
                'value' => serialize($additionalOptions)
            ));
        }


        /* To Do */

        // Edit Cart - May need to remove option and readd them
        // Pre-fill remarks on product edit pages


        /* Issues */

        // Create new cart item with identical option values will add a new line item, instead of increment previous item qty

    }
}

Метод № 1 - Копирование Option из quote_item в order_item с использованием Observer См. Magento 2 fieldset.xml; скопировать поля из цитаты в заказ

/app/code/Cloudways/Mymodule/Observer/SalesModelServiceQuoteSubmitBeforeObserver.php

<?php

namespace Cloudways\Mymodule\Observer;

use Magento\Framework\Event\Observer as EventObserver;
use Magento\Framework\Event\ObserverInterface;


class SalesModelServiceQuoteSubmitBeforeObserver implements ObserverInterface
{

    private $quoteItems = [];

    private $quote = null;
    private $order = null;

    /**
     * Add order information into GA block to render on checkout success pages
     *
     * @param EventObserver $observer
     * @return void
     */
    public function execute(EventObserver $observer)
    {

        $this->quote = $observer->getQuote();
        $this->order = $observer->getOrder();

        // can not find an equivalent event for sales_convert_quote_item_to_order_item


        /* @var  \Magento\Sales\Model\Order\Item $orderItem */
        foreach($this->order->getItems() as $orderItem){
            if(!$orderItem->getParentItemId() && $orderItem->getProductType() == \Magento\Catalog\Model\Product\Type::TYPE_SIMPLE){

                if($quoteItem = $this->getQuoteItemById($orderItem->getQuoteItemId())){
                    if ($additionalOptionsQuote = $quoteItem->getOptionByCode('additional_options')) {

                        //To do
                        // - check to make sure element are not added twice
                        // - $additionalOptionsQuote - may not be an array
                        if($additionalOptionsOrder = $orderItem->getProductOptionByCode('additional_options')){
                            $additionalOptions = array_merge($additionalOptionsQuote, $additionalOptionsOrder);
                        }
                        else{
                            $additionalOptions = $additionalOptionsQuote;
                        }


                        if(count($additionalOptions) > 0){
                            $options = $orderItem->getProductOptions();
                            $options['additional_options'] = unserialize($additionalOptions->getValue());
                            $orderItem->setProductOptions($options);
                        }

                    }
                }
            }
        }

    }


    private function getQuoteItemById($id){
        if(empty($this->quoteItems)){
            /* @var  \Magento\Quote\Model\Quote\Item $item */
            foreach($this->quote->getItems() as $item){

                //filter out config/bundle etc product
                if(!$item->getParentItemId() && $item->getProductType() == \Magento\Catalog\Model\Product\Type::TYPE_SIMPLE){
                    $this->quoteItems[$item->getId()] = $item;
                }
            }
        }


        if(array_key_exists($id, $this->quoteItems)){
            return $this->quoteItems[$id];
        }

        return null;
    }
}

Метод № 2 - Копирование опции из quote_item в order_item с помощью плагина

/app/code/Cloudways/Mymodule/etc/di.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <type name="Magento\Quote\Model\Quote\Item\ToOrderItem">
        <plugin name="cloudways_mymodule\_Sales_Quote_Item_ToOrderItem" type="Cloudways\Mymodule\Plugin\QuoteItemToOrderItemPlugin" />
    </type>
</config>

/app/code/Cloudways/Mymodule/Plugin/QuoteItemToOrderItemPlugin.php

<?php

namespace Cloudways\Mymodule\Plugin;

class QuoteItemToOrderItemPlugin
{

    public function aroundConvert(\Magento\Quote\Model\Quote\Item\ToOrderItem $subject, callable $proceed, $quoteItem, $data)
    {

        // get order item
        $orderItem = $proceed($quoteItem, $data);


        if(!$orderItem->getParentItemId() && $orderItem->getProductType() == \Magento\Catalog\Model\Product\Type::TYPE_SIMPLE){
            if ($additionalOptionsQuote = $quoteItem->getOptionByCode('additional_options')) {
                //To do
                // - check to make sure element are not added twice
                // - $additionalOptionsQuote - may not be an array
                if($additionalOptionsOrder = $orderItem->getProductOptionByCode('additional_options')){
                    $additionalOptions = array_merge($additionalOptionsQuote, $additionalOptionsOrder);
                }
                else{
                    $additionalOptions = $additionalOptionsQuote;
                }
                if(count($additionalOptions) > 0){
                    $options = $orderItem->getProductOptions();
                    $options['additional_options'] = unserialize($additionalOptions->getValue());
                    $orderItem->setProductOptions($options);
                }
            }
        }

        return $orderItem;
    }
}

Корзина покупок и страница просмотра заказа администратора

Base off of Magento1 - Цитировать / заказывать товарный атрибут на основе пользовательского ввода

Ренон Стюарт
источник
@renon Я попробовал описанную выше функциональность для простого продукта, и все получилось отлично, спасибо! но мне нужно то же самое для настраиваемого продукта, но я получаю следующую ошибку на странице корзины «Выбранные опции или их комбинация в настоящее время недоступны». Я знаю, почему возникает эта проблема, но есть ли способ ее преодолеть, я имею в виду отфильтровать конкретные варианты?
Nausif
Просто использовал это, и это работает как шарм. Спасибо! Знаете ли вы о какой-либо функциональности в Magento, которая действительно позволяет свойства для элемента (не для продукта)? Например, нестандартный текст на рубашке, но с несколькими одинаковыми рубашками с разными надписями. Magento теперь комбинирует эти продукты в корзине, и поэтому я теряю эти действительно специфические настройки для каждого товара.
Юрген
@Nausif, я столкнулся с той же проблемой, но теперь она решена. Ссылка на
Кишор Хасе
@renon Я использую это, и значения отображаются в мини-корзине, корзине и оформлении заказа. У меня есть настраиваемый продукт для этого. Я попробовал оба метода преобразования котировок, но значения не отображаются в разделе «Заказ по почте» и «Заказ в разделе» в админке.
Rishabh Rk Rai
Если кто-то [invalidargumentexception] unable to unserialize value.использует json_encode и json_decode вместо сериализации и
десериализации
0

Чтобы решить эту проблему: // Создать новый элемент корзины с одинаковыми значениями параметров добавит новую позицию вместо увеличения предыдущего элемента Кол-во

Я добавил после плагина для метода представления продукта в Magento \ Quote \ Model \ Quote \ Item. В плагине я проверяю, является ли это моим необходимым дополнительным параметром, и если он возвращает необходимый результат (true).

Алекс Козырь
источник