2

What we have:

di.xml

<type name="Magento\Bundle\Ui\DataProvider\Product\Form\Modifier\BundlePanel">
    <plugin name="bundle_option_sku" type="SY\Configurator\Plugin\Catalog\Ui\DataProvider\Product\Form\Modifier\BundlePanel" sortOrder="1000"/>
</type>

UpgradeSchema.php

<?php
namespace SY\Configurator\Setup;

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

class UpgradeSchema implements UpgradeSchemaInterface {
    public function upgrade(
        SchemaSetupInterface $setup,
        ModuleContextInterface $context
    ){
        $installer = $setup;
        $installer->startSetup();
        if(version_compare($context->getVersion(), '0.0.3', '<')) {
            $installer->getConnection()->addColumn(
                $installer->getTable('catalog_product_bundle_option'),
                'option_sku',
                [
                    'type' => \Magento\Framework\DB\Ddl\Table::TYPE_TEXT,
                    'length' => 255,
                    'nullable' => true,
                    'comment' => 'Sku'
                ]
            );
        }
        $installer->endSetup();
    }
}

Plugin:

class BundlePanel {
    public function afterModifyMeta(
        \Magento\Bundle\Ui\DataProvider\Product\Form\Modifier\BundlePanel $subject,
        $meta
    ){
        $meta['bundle-items']['children']['bundle_options']['children']['record']['children']['product_bundle_container']['children']['option_info']['children']['option_sku'] = $this->getSkuFieldConfig(
            11,
            [
                'arguments' => [
                    'data' => [
                        'config' => [
                            'label' => __('Sku'),
                            'component' => 'Magento_Catalog/component/static-type-input',
                            'valueUpdate' => 'input',
                            'imports' => [
                                'optionId' => '${ $.provider }:${ $.parentScope }.option_id'
                            ]
                        ]
                    ]
                ]
            ]
        );
        return $meta;
    }
    protected function getSkuFieldConfig($sortOrder, array $options = []){
        return array_replace_recursive(
            [
                'arguments' => [
                    'data' => [
                        'config' => [
                            'label' => __('Sku'),
                            'componentType' => \Magento\Ui\Component\Form\Field::NAME,
                            'formElement' => \Magento\Ui\Component\Form\Element\Input::NAME,
                            'dataScope' => 'option_sku',
                            // 'dataScope' => 'title',
                            'dataType' => \Magento\Ui\Component\Form\Element\DataType\Text::NAME,
                            'sortOrder' => $sortOrder,
                            'validation' => [
                                'required-entry' => true,
                                // 'no-whitespace' => true,
                                'validate-alphanum-with-spaces' => true
                            ]
                        ]
                    ]
                ]
            ],
            $options
        );
    }
}

All is ok, showing and saving, but saved values not appends, what is need to do?

1

You need to rewrite class:

\Magento\Bundle\Ui\DataProvider\Product\Form\Modifier\Composite

Look at method name modifyData and find below code:

$data[$modelId][BundlePanel::CODE_BUNDLE_OPTIONS][BundlePanel::CODE_BUNDLE_OPTIONS][]

Please add your custom field key 'option_sku' to above array

Please follow below step

1) crete di.xml file at SY/Configurator/etc/adminhtml/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">
<preference for="Magento\Bundle\Ui\DataProvider\Product\Form\Modifier\Composite" type="SY\Configurator\Ui\DataProvider\Product\Form\Modifier\Composite" />
<type name="Magento\Bundle\Ui\DataProvider\Product\Form\Modifier\BundlePanel">
    <plugin name="bundle_option_sku" type="SY\Configurator\Plugin\Catalog\Ui\DataProvider\Product\Form\Modifier\BundlePanel" sortOrder="1000"/>
</type>
</config>

2) create Composite.php file at

SY/Configurator/Ui/DataProvider/Product/Form/Modifier/Composite.php

<?php

namespace SY\Configurator\Ui\DataProvider\Product\Form\Modifier;

use Magento\Bundle\Model\Product\Type;
use Magento\Bundle\Ui\DataProvider\Product\Form\Modifier\BundlePanel;

class Composite extends \Magento\Bundle\Ui\DataProvider\Product\Form\Modifier\Composite {

    public function modifyData(array $data) {

        /** @var \Magento\Catalog\Api\Data\ProductInterface $product */
        $product = $this->locator->getProduct();
        $modelId = $product->getId();
        $isBundleProduct = $product->getTypeId() === Type::TYPE_CODE;
        if ($isBundleProduct && $modelId) {
            $data[$modelId][BundlePanel::CODE_BUNDLE_OPTIONS][BundlePanel::CODE_BUNDLE_OPTIONS] = [];
            $extra_options = $this->getEtra_attributes($product);
            /** @var \Magento\Bundle\Api\Data\OptionInterface $option */
            foreach ($this->optionsRepository->getList($product->getSku()) as $option) {
                $selections = [];
                foreach ($option->getProductLinks() as $productLink) {
                    $linkedProduct = $this->productRepository->get($productLink->getSku());
                    $integerQty = 1;
                    if ($linkedProduct->getExtensionAttributes()->getStockItem()) {
                        if ($linkedProduct->getExtensionAttributes()->getStockItem()->getIsQtyDecimal()) {
                            $integerQty = 0;
                        }
                    }
                    $selections[] = [
                        'selection_id' => $productLink->getId(),
                        'option_id' => $productLink->getOptionId(),
                        'product_id' => $linkedProduct->getId(),
                        'name' => $linkedProduct->getName(),
                        'sku' => $linkedProduct->getSku(),
                        'is_default' => ($productLink->getIsDefault()) ? '1' : '0',
                        'selection_price_value' => $productLink->getPrice(),
                        'selection_price_type' => $productLink->getPriceType(),
                        'selection_qty' => (bool) $integerQty ? (int) $productLink->getQty() : $productLink->getQty(),
                        'selection_can_change_qty' => $productLink->getCanChangeQuantity(),
                        'selection_qty_is_integer' => (bool) $integerQty,
                        'position' => $productLink->getPosition(),
                        'delete' => '',
                    ];
                }

                $data[$modelId][BundlePanel::CODE_BUNDLE_OPTIONS][BundlePanel::CODE_BUNDLE_OPTIONS][] = [
                    'position' => $option->getPosition(),
                    'option_id' => $option->getOptionId(),
                    'title' => $option->getTitle(),
                    'option_sku' => $extra_options[$option->getOptionId()]['option_sku'],
                    'default_title' => $option->getDefaultTitle(),
                    'type' => $option->getType(),
                    'required' => ($option->getRequired()) ? '1' : '0',
                    'bundle_selections' => $selections,
                ];
            }
        }

        return $data;
    }

    public function getEtra_attributes($product) {
        $optionArray = array();
        $_objectManager = \Magento\Framework\App\ObjectManager::getInstance();
        $product = $_objectManager->get('\Magento\Catalog\Model\Product')->load($product->getId());
        $optionsCollection = $product->getTypeInstance(true)
                ->getOptionsCollection($product);
        foreach ($optionsCollection as $options) {
            $optionArray[$options->getOptionId()]['option_sku'] = $options->getMaximumQuantity();

        }

        return $optionArray;
    }

}
|improve this answer|||||
  • Code can be little bit improved. Please refer below answer. – Oshan Aug 16 '18 at 12:46
3

1) Create plugin, preferences in app/code/ABC/Product/etc/adminhtml/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\Bundle\Ui\DataProvider\Product\Form\Modifier\BundlePanel">
        <plugin name="bundle_addtional_options" type="ABC\Product\Plugin\Bundle\Ui\DataProvider\Product\Form\Modifier\BundlePanel" sortOrder="1000"/>
    </type>
    <preference for="Magento\Bundle\Ui\DataProvider\Product\Form\Modifier\Composite" type="ABC\Product\Ui\DataProvider\Product\Form\Modifier\Composite"/>
    <preference for="Magento\Bundle\Model\Product\OptionList" type="ABC\Product\Model\Bundle\Product\OptionList"/>
</config>

2) Plugin will be as follows ABC/Product/Plugin/Bundle/Ui/DataProvider/Product/Form/Modifier/BundlePanel.php

<?php

namespace ABC\Product\Plugin\Bundle\Ui\DataProvider\Product\Form\Modifier;

use Magento\Ui\Component\Form;;

class BundlePanel
{
    /**
     * @param \Magento\Bundle\Ui\DataProvider\Product\Form\Modifier\BundlePanel $subject
     * @param $meta
     * @return mixed
     */
    public function afterModifyMeta(\Magento\Bundle\Ui\DataProvider\Product\Form\Modifier\BundlePanel $subject, $meta)
    {
        $fieldSet = [
            'min_qty' => [
                'dataType' => Form\Element\DataType\Number::NAME,
                'formElement'   => Form\Element\Input::NAME,
                'label' => 'Min Qty',
                'dataScope' => 'min_qty',
                'sortOrder' => 40
            ],
            'max_qty' => [
                'dataType' => Form\Element\DataType\Number::NAME,
                'formElement'   => Form\Element\Input::NAME,
                'label' => 'Max Qty',
                'dataScope' => 'max_qty',
                'sortOrder' => 45
            ],
            'is_lease_machine' => [
                'dataType' => Form\Element\DataType\Boolean::NAME,
                'formElement'   => Form\Element\Select::NAME,
                'label' => 'Is Lease Machine',
                'dataScope' => 'is_lease_machine',
                'sortOrder' => 50,
                'options' => [
                    [
                        'label' => __('No'),
                        'value' => 0
                    ],
                    [
                        'label' => __('Yes'),
                        'value' => 1
                    ],
                ],
            ],
        ];

        foreach ($fieldSet as $filed => $fieldOptions)
        {
            $meta['bundle-items']['children']['bundle_options']['children']
            ['record']['children']['product_bundle_container']['children']['option_info']['children'][$filed] = $this->getSelectionCustomText($fieldOptions);
        }

        return $meta;
    }

    /**
     * @param $fieldOptions
     * @return array
     */
    protected function getSelectionCustomText($fieldOptions)
    {
        return [
            'arguments' => [
                'data' => [
                    'config' => [
                        'componentType' => Form\Field::NAME,
                        'dataType'      => $fieldOptions['dataType'],
                        'formElement'   => $fieldOptions['formElement'],
                        'label'         => __($fieldOptions['label']),
                        'dataScope'     => $fieldOptions['dataScope'],
                        'sortOrder'     => $fieldOptions['sortOrder'],
                        'options'       => array_key_exists('options', $fieldOptions) ? $fieldOptions['options']: "",
                    ]
                ]
            ]
        ];
    }
}

3) Preference 1 as follows (to save data):

<?php

namespace ABC\Product\Ui\DataProvider\Product\Form\Modifier;

use Magento\Bundle\Model\Product\Type;
use Magento\Bundle\Ui\DataProvider\Product\Form\Modifier\BundlePanel;

class Composite extends \Magento\Bundle\Ui\DataProvider\Product\Form\Modifier\Composite
{
    public function modifyData(array $data)
    {

        /** @var \Magento\Catalog\Api\Data\ProductInterface $product */
        $product = $this->locator->getProduct();
        $modelId = $product->getId();
        $isBundleProduct = $product->getTypeId() === Type::TYPE_CODE;
        if ($isBundleProduct && $modelId) {
            $data[$modelId][BundlePanel::CODE_BUNDLE_OPTIONS][BundlePanel::CODE_BUNDLE_OPTIONS] = [];

            /** @var \Magento\Bundle\Api\Data\OptionInterface $option */
            foreach ($this->optionsRepository->getList($product->getSku()) as $option) {
                $selections = [];
                foreach ($option->getProductLinks() as $productLink) {
                    $linkedProduct = $this->productRepository->get($productLink->getSku());
                    $integerQty = 1;
                    if ($linkedProduct->getExtensionAttributes()->getStockItem()) {
                        if ($linkedProduct->getExtensionAttributes()->getStockItem()->getIsQtyDecimal()) {
                            $integerQty = 0;
                        }
                    }
                    $selections[] = [
                        'selection_id' => $productLink->getId(),
                        'option_id' => $productLink->getOptionId(),
                        'product_id' => $linkedProduct->getId(),
                        'name' => $linkedProduct->getName(),
                        'sku' => $linkedProduct->getSku(),
                        'is_default' => ($productLink->getIsDefault()) ? '1' : '0',
                        'selection_price_value' => $productLink->getPrice(),
                        'selection_price_type' => $productLink->getPriceType(),
                        'selection_qty' => (bool)$integerQty ? (int)$productLink->getQty() : $productLink->getQty(),
                        'selection_can_change_qty' => $productLink->getCanChangeQuantity(),
                        'selection_qty_is_integer' => (bool)$integerQty,
                        'position' => $productLink->getPosition(),
                        'delete' => '',
                    ];
                }

                $data[$modelId][BundlePanel::CODE_BUNDLE_OPTIONS][BundlePanel::CODE_BUNDLE_OPTIONS][] = [
                    'position' => $option->getPosition(),
                    'option_id' => $option->getOptionId(),
                    'title' => $option->getTitle(),
                    'min_qty' => $option->getMinQty(), //new field
                    'max_qty' => $option->getMaxQty(), //new field
                    'is_lease_machine' => $option->getIsLeaseMachine(), //new field
                    'default_title' => $option->getDefaultTitle(),
                    'type' => $option->getType(),
                    'required' => ($option->getRequired()) ? '1' : '0',
                    'bundle_selections' => $selections,
                ];
            }
        }

        return $data;
    }
}

4) Preference 2 as follows (to retrieve data):

<?php

namespace ABC\Product\Model\Bundle\Product;

class OptionList extends \Magento\Bundle\Model\Product\OptionList
{
    /**
     * @param \Magento\Catalog\Api\Data\ProductInterface $product
     * @return \Magento\Bundle\Api\Data\OptionInterface[]
     */
    public function getItems(\Magento\Catalog\Api\Data\ProductInterface $product)
    {
        $optionCollection = $this->type->getOptionsCollection($product);
        $this->extensionAttributesJoinProcessor->process($optionCollection);
        $optionList = [];
        /** @var \Magento\Bundle\Model\Option $option */
        foreach ($optionCollection as $option) {
            $productLinks = $this->linkList->getItems($product, $option->getOptionId());
            /** @var \Magento\Bundle\Api\Data\OptionInterface $optionDataObject */
            $optionDataObject = $this->optionFactory->create();
            $this->dataObjectHelper->populateWithArray(
                $optionDataObject,
                $option->getData(),
                \Magento\Bundle\Api\Data\OptionInterface::class
            );
            $optionDataObject->setOptionId($option->getOptionId())
                ->setTitle($option->getTitle() === null ? $option->getDefaultTitle() : $option->getTitle())
                ->setDefaultTitle($option->getDefaultTitle())
                ->setSku($product->getSku())
                ->setMinQty($option->getMinQty()) // retrieve "min_qty" from db
                ->setMaxQty($option->getMaxQty()) // retrieve "max_qty" from db
                ->setIsLeaseMachine($option->getIsLeaseMachine()) // retrieve "is_lease_machine" from db
                ->setProductLinks($productLinks);
            $optionList[] = $optionDataObject;
        }
        return $optionList;
    }
}

5) To create columns named "min_qty, max_qty, is_machine_lease" can use UpgradeSchema as follows.

<?php

namespace ABC\Product\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)
    {
        $installer = $setup;

        $installer->startSetup();

        if (version_compare($context->getVersion(), '1.0.4', '<')) {
            $installer->getConnection()->addColumn(
                $installer->getTable('catalog_product_bundle_option'),
                'min_qty',
                [
                    'type' => \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER,
                    'length'    => null,
                    'unsigned' => true,
                    'nullable' => true,
                    'default' => null,
                    'comment' => 'Minimum Qty'
                ]
            );

            $installer->getConnection()->addColumn(
                $installer->getTable('catalog_product_bundle_option'),
                'max_qty',
                [
                    'type' => \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER,
                    'length'    => null,
                    'unsigned' => true,
                    'nullable' => true,
                    'default' => null,
                    'comment' => 'Maximum Qty'
                ]
            );

            $installer->getConnection()->addColumn(
                $installer->getTable('catalog_product_bundle_option'),
                'is_lease_machine',
                [
                    'type' => \Magento\Framework\DB\Ddl\Table::TYPE_SMALLINT,
                    'length'    => 1,
                    'unsigned' => true,
                    'nullable' => true,
                    'default' => 0,
                    'comment' => 'Is Lease Machine'
                ]
            );
        }

        $installer->endSetup();
    }
}

Output will be shown as follows. enter image description here

|improve this answer|||||
  • For me save in db and display in backend this custom value were not working. after lot of research i found that in setup script you have mentioned wrong table instead of this 'catalog_product_bundle_selection' need to use this table 'catalog_product_bundle_option' and all worked fine. Thanks for help. – Dhaval Solanki Feb 20 '19 at 6:11
  • 1
    @DhavalSolanki: Thank you for pointing this out. Answer updated. – Oshan Feb 22 '19 at 0:49

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.