Wie kann ich ein Produkt mit einem benutzerdefinierten Eingabefeld in den Warenkorb legen und in der Datenbank speichern?

9

Ich habe ein benutzerdefiniertes Modul erstellt, in dem ich das Formular zum Hinzufügen zum Warenkorb auf der Produktseite überschreibe , und ich habe es erfolgreich mit der catalog_product_view.xmlDatei ausgeführt. Jetzt kann ich ein benutzerdefiniertes Eingabefeld in der Vorderansicht der Produktseite sehen, aber ich muss den Wert dieses Felds in der Datenbank mit Menge, Preis usw. veröffentlichen und im Bestellverlauf erneut abrufen.

Ich habe eine Weile gesucht und auch erfolgreich neue benutzerdefinierte Spalten in quote_item& sales_orderTabellen erstellt. (Gemäß meinen Informationen gehen Sie zu den Warenkorbeinträgen quote_itemund Bestellungen nach dem Auschecken gehen zur sales_orderTabelle. Wenn ich mich irre, korrigieren Sie mich bitte auch darin, da ich noch ein Lernender bin.)

Ich habe viel versucht und danach gesucht, aber keine relevante Lösung gefunden. Mein Herstellername ist Cloudways und der Modulname ist Mymodule . Unten sind die Dateien für mein Modul:

Cloudways / Mymodule / registration.php

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

Cloudways / Mymodule / etc / 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 / view / frontend / layout / 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 / view / frontend / templates / catalog / product / view / 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; ?>

Hier ist der Screenshot der Vorderansicht:

Geben Sie hier die Bildbeschreibung ein

Ich muss lediglich den Wert des benutzerdefinierten Eingabefelds veröffentlichen und zusammen mit der Bestellung in der Datenbank speichern. Danke im Voraus!

EDIT: Ich habe entsprechende Änderungen gemäß der Antwort von RS vorgenommen und hier ist das Problem, mit dem ich konfrontiert bin: (PS Ich verwende MAGENTO 2.0.9)

Geben Sie hier die Bildbeschreibung ein

Ich habe die Protokolldatei überprüft und Folgendes gefunden:

[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} [] []

Irgendwelche Vorschläge bitte?

Fayyaz Khattak
quelle
Schauen Sie sich dieses Beispiel für magento 1 an stackoverflow.com/questions/9412074/… ... Sie sollten in der Lage sein, "zusätzliche_Optionen" zu verwenden, um diese Informationen mithilfe eines Beobachters zu speichern. Github.com/magento/magento2/… ... Verwenden Sie zusätzliche_Optionen wird diese Informationen automatisch in Admin, Kundenauftrag E-Mail usw.
anzeigen
Gibt es einen Grund, warum Sie kein einfaches Produkt mit benutzerdefinierten Optionen verwenden, um dies zu erreichen?
Renon Stewart
@RS Ich muss es programmgesteuert tun, da wir diesen benutzerdefinierten Warenkorb um verschiedene benutzerdefinierte Optionen erweitern werden, die meiner Meinung nach nur mit benutzerdefinierten Modulen möglich sind.
Fayyaz Khattak
Können Sie Ihrem Code einen (Github-) Link hinzufügen, damit ich zusätzliche Optionen herunterladen und implementieren kann
Renon Stewart
@RS Ja sicher, bitte gib mir ein paar Minuten.
Fayyaz Khattak

Antworten:

14

Um dies zu erreichen, können Sie die in Magento integrierte Funktion "Zusätzliche_Optionen" verwenden, sodass Sie nicht die E-Mail-Vorlage, die Ansicht der Administratorbestellung, die Ansicht der Kundenbestellung (usw.) bearbeiten müssen, um Ihre benutzerdefinierten Optionen anzuzeigen.

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>

Option zum Angebot hinzufügen

/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

    }
}

Methode 1 - Kopieren der Option von quote_item nach order_item mithilfe von Observer Siehe Magento 2 fieldset.xml; Kopieren Sie die Felder vom Angebot in die Bestellung

/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;
    }
}

Methode 2 - Kopieren der Option von quote_item nach order_item mithilfe des Plugins

/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;
    }
}

Warenkorb und Admin-Bestellsicht

Basis von Magento1 - Produktartikelattribut für Angebot / Bestellung basierend auf Benutzereingaben

Renon Stewart
quelle
@renon Ich habe oben die Funktionalität für ein einfaches Produkt ausprobiert und es hat super geklappt, danke! Ich benötige jedoch dasselbe für konfigurierbare Produkte, erhalte jedoch die folgende Fehlermeldung auf der Warenkorbseite "Ausgewählte Option (en) oder deren Kombination ist derzeit nicht verfügbar." Ich weiß, warum dieses Problem auftritt, aber gibt es eine Möglichkeit, es zu überwinden. Ich meine, bestimmte Optionen herauszufiltern?
Nausif
Ich habe es gerade benutzt und es funktioniert wie ein Zauber. Vielen Dank! Kennen Sie Funktionen in Magento, die wirklich Eigenschaften pro Artikel (nicht pro Produkt) zulassen? Zum Beispiel ein benutzerdefinierter Text auf einem Shirt, der jedoch mehrere gleiche Shirts mit unterschiedlichen Texten enthält. Magento kombiniert jetzt diese Produkte im Warenkorb und somit verliere ich diese wirklich spezifischen Einstellungen pro Artikel.
Jürgen
@Nausif, ich hatte das gleiche Problem, aber jetzt wurde es behoben. Verweisen Sie auf diese URL - magento.stackexchange.com/questions/177133/…
Kishor Hase
@renon Ich benutze dies und die Werte werden in Mini-Cart, Cart und Checkout angezeigt. Ich habe ein konfigurierbares Produkt, um dies zu tun. Ich habe beide Angebotskonvertierungsmethoden ausprobiert, aber Werte, die nicht in der Bestellmail und im Bestellabschnitt in admin angezeigt werden.
Rishabh Rk Rai
Wenn jemand [invalidargumentexception] unable to unserialize value.json_encode und json_decode anstelle von serialize und unserialize verwendet
Ebin Manuval
0

So beheben Sie dieses Problem: // Wenn Sie eine neue Warenkorbposition mit identischen Optionswerten erstellen, wird eine neue Werbebuchung hinzugefügt, anstatt die vorherige Artikelmenge zu erhöhen

Ich habe nach dem Plugin für die Methode RepresentProduct in Magento \ Quote \ Model \ Quote \ Item hinzugefügt. Im Plugin überprüfe ich, ob es mein benötigter zusätzlicher Parameter ist und ob es das benötigte Ergebnis (true) zurückgibt.

Alex Kozyr
quelle