Magento 2 added custom column in sales order grid but unable to filterable - magento2

I have added a product name column in the sale order grid from XML and it shows correctly on the grid but if I use it in filter form it gives the error as "Something went wrong" and the error log has below error
main.CRITICAL: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'products' in 'where clause', query was: SELECT COUNT(*) FROM `sales_order_grid` AS `main_table` WHERE (((`products` LIKE '%nato%')))
added below code in sales_order_grid file in custom module
<column name="products" class="Custom\Module\Ui\Component\Listing\Columns\ProductName">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="visible" xsi:type="boolean">true</item>
<item name="filter" xsi:type="string">text</item>
<item name="label" xsi:type="string" translate="true">Items Name</item>
<item name="disableAction" xsi:type="boolean">true</item>
<item name="sortable" xsi:type="boolean">false</item>
<item name="sortOrder" xsi:type="number">3</item>
</item>
</argument>
</column>
Then created UI component column at Custom\Module\Ui\Component\Listing\Columns
class ProductName extends Column
{
protected $_orderRepository;
protected $_searchCriteria;
public function __construct(
ContextInterface $context,
UiComponentFactory $uiComponentFactory,
OrderRepositoryInterface $orderRepository,
SearchCriteriaBuilder $criteria,
array $components = [],
array $data = [])
{
$this->_orderRepository = $orderRepository;
$this->_searchCriteria = $criteria;
parent::__construct($context, $uiComponentFactory, $components, $data);
}
public function prepareDataSource(array $dataSource)
{
if (isset($dataSource['data']['items'])) {
foreach ($dataSource['data']['items'] as &$items) {
$productArr = [];
$order = $this->_orderRepository->get($items["entity_id"]);
foreach ($order->getAllVisibleItems() as $item) {
$productArr[] = $item->getName(); //to get product name
}
$items['products'] = implode(" , " , $productArr);
unset($productArr);
}
}
return $dataSource;
}
}

Your Filter will not work with this method.
Use below code for reference -
sales_order_grid.xml
<listing xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd">
<columns name="sales_order_columns">
<column name="column_name">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="filter" xsi:type="string">text</item>
<item name="label" xsi:type="string" translate="true">Colum Test</item>
</item>
</argument>
</column>
</columns>
</listing>
Create di.xml in adminhtml of module
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<!-- Plugins -->
<!-- Adds additional data to the orders grid collection -->
<type name="Magento\Framework\View\Element\UiComponent\DataProvider\CollectionFactory">
<plugin name="mageworx_extended_orders_grid_add_data_to_orders_grid"
type="Vendor\Name\Plugin\AddDataToOrdersGrid"
sortOrder="10"
disabled="false"/>
</type>
<type name="Magento\Framework\View\Element\UiComponent\DataProvider\Reporting">
<plugin name="sales_grid_collection" type="Vendor\Name\Model\Plugin\Sales\Order\Grid"/>
</type>
</config>
AddDataToOrdersGrid.php
<?php
namespace Vendor\Name\Plugin;
class AddDataToOrdersGrid
{
private $logger;
public function __construct(
\Psr\Log\LoggerInterface $customLogger,
array $data = []
) {
$this->logger = $customLogger;
}
public function afterGetReport($subject, $collection, $requestName)
{
if ($requestName !== 'sales_order_grid_data_source') {
return $collection;
}
if ($collection->getMainTable() === $collection->getResource()->getTable('sales_order_grid')) {
try {
$collection->getSelect()
->reset(\Zend_Db_Select::COLUMNS)
->columns(array('main_table.*','main_table.products AS test_product'));
} catch (\Zend_Db_Select_Exception $selectException) {
$this->logger->log(100, $selectException);
}
}
return $collection;
}
}
Grid.php
getMainTable() === $collection->getConnection()->getTableName(self::$table)) {$where = $collection->getSelect()->getPart(\Magento\Framework\DB\Select::WHERE);
foreach($where as $key => $w){
if (str_contains($w, 'test_product')) {
$where[$key] = str_replace("`test_product`","main_table.products",$w);
}
}
$collection->getSelect->setPart(\Magento\Framework\DB\Select::WHERE, $where);
}
return $collection;
}
}
Hope It helps!!
You need to maybe modify the code a bit the get your desired result.

Related

magento 2 admin form ui component

I want to create ui component with tabs.
I want to my base data shows in general tabs and additional in next.
ui component
<?xml version="1.0" encoding="UTF-8"?>
<form xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd">
<argument name="data" xsi:type="array">
<item name="js_config" xsi:type="array">
<item name="provider" xsi:type="string">my_blog_form.my_blog_listing_data_source</item>
<item name="deps" xsi:type="string">my_blog_form.my_blog_listing_data_source</item>
</item>
<item name="label" xsi:type="string" translate="true">General</item>
<item name="layout" xsi:type="array">
<item name="type" xsi:type="string">tabs</item>
<item name="navContainerName" xsi:type="string">left</item>
</item>
<item name="buttons" xsi:type="array">
<item name="save" xsi:type="array">
<item name="name" xsi:type="string">save</item>
<item name="label" xsi:type="string" translate="true">Save</item>
<item name="class" xsi:type="string">primary</item>
<item name="url" xsi:type="string">*/*/save</item>
</item>
</item>
</argument>
<dataSource name="my_blog_form_data_source">
<argument name="dataProvider" xsi:type="configurableObject">
<argument name="class" xsi:type="string">MY\Blog\Ui\DataProvider</argument>
<argument name="name" xsi:type="string">my_blog_form_data_source</argument>
<argument name="primaryFieldName" xsi:type="string">id</argument>
<argument name="requestFieldName" xsi:type="string">id</argument>
<argument name="collectionFactory" xsi:type="object">
\MY\Blog\Model\Post\ResourceModel\Post\CollectionFactory
</argument>
</argument>
</dataSource>
<fieldset name="general">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="label" xsi:type="string" translate="true">Sample Fieldset</item>
</item>
</argument>
<!-- This field has data type 'text' and standard 'input' form element and looks like input -->
<field name="title">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="label" xsi:type="string">Title</item>
<item name="visible" xsi:type="boolean">true</item>
<item name="dataType" xsi:type="string">text</item>
<item name="formElement" xsi:type="string">input</item>
<item name="source" xsi:type="string">title</item>
</item>
</argument>
</field>
</fieldset>
</form>
Corresponding dataSource
<?php
namespace MY\Blog\Ui;
use Magento\Ui\DataProvider\AbstractDataProvider;
use \My\Blog\Model\Post\ResourceModel\Post\CollectionFactory;
class DataProvider extends AbstractDataProvider
{
protected $collection;
public function __construct(
$name,
$primaryFieldName,
$requestFieldName,
CollectionFactory $collectionFactory,
array $meta = [],
array $data = []
) {
parent::__construct($name, $primaryFieldName, $requestFieldName, $meta, $data);
$this->collection = $collectionFactory->create();
}
public function getData()
{
return [];
$results = [];
// var_dump($this->collection->getItems());die();
foreach ($this->collection->getItems() as $item) {
$results[$item->getId()]['general'] = $item->getData();
}
return $results;
}
}
I don't see any tabs and spinner never stops. What am I missing here I got 0 console errors. Model works because I have working data grid that shows my data.
Add this in your form XML
<settings>
<deps>
<dep>my_blog_form.my_blog_listing_data_source</dep>
</deps>
<layout>
<navContainerName>left</navContainerName>
<type>tabs</type>
</layout>
</settings>
set layout 2-column left like this
<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="admin-2columns-left" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
<body>
<referenceContainer name="content">
<uiComponent name="your_form_name" />
</referenceContainer>
</body>
</page>

Magento 2 UiComponent form with tabs has empty fields

I have and issue with empty form fields when I'm using tabs.
If I removing tabs usage, fields contains correct values.
My form uicomponent is large, so I will paste only important parts of configuration:
<argument name="data" xsi:type="array">
<item name="js_config" xsi:type="array">
<item name="provider" xsi:type="string">vendor_modulename_form.vendor_modulename_form_data_source</item>
</item>
<item name="label" xsi:type="string" translate="true">Item</item>
...
</argument>
<settings>
...
<namespace>vendor_modulename_form</namespace>
<dataScope>data</dataScope>
<deps>
<dep>vendor_modulename_form.vendor_modulename_form_data_source</dep>
</deps>
<layout>
<navContainerName>left</navContainerName>
<type>tabs</type>
</layout>
</settings>
<fieldset name="modules">
<settings>
<collapsible>true</collapsible>
<opened>true</opened>
<label translate="true">Details</label>
</settings>
<field name="name" formElement="input">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="source" xsi:type="string">module</item>
</item>
</argument>
<settings>
<dataType>text</dataType>
<label translate="true">Name</label>
<dataType>text</dataType>
<visible>true</visible>
<dataScope>name</dataScope>
</settings>
</field>
...
</fieldset>
Console log and magento logs are empty. I'm working in developer mode.
Any ideas?
In the dataprovider you have to wrap all the content of your fieldset with the key after loading the data.
Eg:
$id = $this->request->getParam('id');
/** #var Collection $items */
$items = $this->collectionFactory->create()->addFieldToFilter('id', $id)->getItems();
foreach ($items as $item) {
$formData['modules'] = $item->getData();
$this->loadedData[$item->getId()] = $formData;
}

How to display shipping country in sales order grid in magento 2

I tried to show the shipping country in the Admin Sales Order Grid but nothing works.
I did check the customer address configuration twice and there I can see that the country variable exists and should be shown. But in the grid you can not see the shipping country.
Any workarounds?
I found a solution. Creating a Module and Rewrite Class.
app/code/Vendor/ExtendedAdminGrid/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\Framework\View\Element\UiComponent\DataProvider\CollectionFactory">
<arguments>
<argument name="collections" xsi:type="array">
<item name="sales_order_grid_data_source" xsi:type="string">Vendor\ExtendedAdminGrid\Model\ResourceModel\Order\Grid\Collection</item>
</argument>
</arguments>
</type>
</config>
app/code/Vendor/ExtendedAdminGrid/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="Vendor_ExtendedAdminGrid" setup_version="2.0.0">
<sequence>
<module name="Magento_Sales"/>
<module name="Magento_Backend"/>
</sequence>
</module>
</config>
app/code/Vendor/ExtendedAdminGrid/Model/ResourceModel/Order/Grid/Collection.php
<?php
namespace Vendor\ExtendedAdminGrid\Model\ResourceModel\Order\Grid;
class Collection extends \Magento\Sales\Model\ResourceModel\Order\Grid\Collection
{
protected function _renderFiltersBefore()
{
$this->getSelect()->joinLeft(
["soa" => "sales_order_address"],
"main_table.entity_id = soa.parent_id and soa.address_type = 'shipping'",
array('country_id')
)
->distinct();
parent::_renderFiltersBefore();
}
protected function _initSelect()
{
$this->addFilterToMap('created_at', 'main_table.created_at');
$this->addFilterToMap('base_grand_total', 'main_table.base_grand_total');
$this->addFilterToMap('grand_total', 'main_table.grand_total');
$this->addFilterToMap('store_id', 'main_table.store_id');
$this->addFilterToMap('store_name', 'main_table.store_name');
$this->addFilterToMap('order_id', 'main_table.order_id');
$this->addFilterToMap('order_increment_id', 'main_table.order_increment_id');
$this->addFilterToMap('billing_name', 'main_table.billing_name');
$this->addFilterToMap('billing_name', 'main_table.shipping_name');
$this->addFilterToMap('status', 'main_table.status');
parent::_initSelect();
}
}
app/code/Vendor/ExtendedAdminGrid/view/adminhtml/ui_component/sales_order_grid.xml
<?xml version="1.0" encoding="UTF-8"?>
<listing xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd">
<columns name="sales_order_columns">
<column name="country_id">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="filter" xsi:type="string">text</item>
<item name="label" xsi:type="string" translate="true">Shipping Country ID</item>
</item>
</argument>
</column>
</columns>
</listing>
app/code/Vendor/ExtendedAdminGrid/registration.php
<?php
\Magento\Framework\Component\ComponentRegistrar::register(
\Magento\Framework\Component\ComponentRegistrar::MODULE,
'Vendor_ExtendedAdminGrid',
__DIR__
);
Thanks to Sergey for this great blogpost Modifying the default magento2 sales order grid — adding a coupon code column.

In Magento2 (2.2.5) uicomponent form in frontend, SAVE button not appearing with form

I added uiform in frontend. Form is loading but save button is not appearing. Code details:
1. employee_form.xml code:
<argument name="data" xsi:type="array">
<item name="js_config" xsi:type="array">
<item name="provider" xsi:type="string">employee_form.employee_form_data_source</item>
</item>
<item name="label" xsi:type="string" translate="true">Assign Product Form</item>
<item name="template" xsi:type="string">templates/form/collapsible</item>
<item name="spinner" xsi:type="string">uiform_index_columns2</item>
</argument>
<settings>
<buttons>
<button name="save" class="Cn\Uiform\Block\Employee\Form\SaveButton"/>
<button name="back">
<url path="*/*/"/>
<class>back</class>
<label translate="true">Back</label>
</button>
</buttons>
<namespace>employee_form</namespace>
<dataScope>data</dataScope>
<deps>
<dep>employee_form.employee_form_data_source</dep>
</deps>
</settings>
<dataSource name="employee_form_data_source">
<argument name="data" xsi:type="array">
<item name="js_config" xsi:type="array">
<item name="component" xsi:type="string">Magento_Ui/js/form/provider</item>
</item>
</argument>
<settings>
<submitUrl path="*/*/save"/>
</settings>
<dataProvider class="Cn\Uiform\Model\DataProvider" name="employee_form_data_source">
<settings>
<primaryFieldName>id</primaryFieldName>
<requestFieldName>id</requestFieldName>
</settings>
</dataProvider>
</dataSource>
2. DataProvide.php methods code
public function prepareMeta(array $meta) {
return $meta;
}
public function getData() {
return [];
}
3. SaveButton.php class code
use Magento\Framework\View\Element\UiComponent\Control\ButtonProviderInterface;
class SaveButton extends GenericButton implements ButtonProviderInterface {
public function getButtonData() {
return [
'label' => __('Save Slide'),
'class' => 'save primary',
'data_attribute' => [
'mage-init' => ['button' => ['event' => 'save']],
'form-role' => 'save',
],
'sort_order' => 90,
];
}
}
4. di.xml
<!--for edit uiform-->
<type name="Magento\Framework\View\Element\UiComponent\DataProvider\CollectionFactory">
<arguments>
<argument name="collections" xsi:type="array">
<item name="employee_form_data_source" xsi:type="string">Cn\Uiform\Model\ResourceModel\Employee\Collection</item>
</argument>
</arguments>
</type>
=> But, the ui form is loading without SAVE button.
For displaying buttons on frontend UI component form. You have to add a Container reference in your layout.
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
<body>
<referenceContainer name="page.main.actions">
<block class="Magento\Framework\View\Element\Template" name="page.actions.toolbar" template="Magento_Backend::pageactions.phtml"/>
</referenceContainer>
<referenceContainer name="admin.scope.col.wrap" htmlClass="admin__old" />
<referenceContainer name="content">
<uiComponent name="employee_form"/>
</referenceContainer>
</body>
</page>
I've never implemented IU components on the frontend, but as far as the backend goes, my own forms have the buttons included inside the 'data' argument. E.g.
<argument name="data" xsi:type="array">
<item name="buttons" xsi:type="array”>
<item name="save" xsi:type="string">Cn\Uiform\Block\Employee\Form\SaveButton</item>
</item>
</argument>

Magento2 : Custom Image Attribute in Category Not Saving?

I have create an custom image attribute in category and image uploaded successfully but it's saving Database. Can anyone guide me what is the issue in below code.
path:- /app/code/Catattribute/Catthumbnail/Setup/InstallData.php
namespace Catattribute\Catthumbnail\Setup;
use Magento\Eav\Setup\EavSetup;
use Magento\Eav\Setup\EavSetupFactory;
use Magento\Framework\Module\Setup\Migration;
use Magento\Framework\Setup\InstallDataInterface;
use Magento\Framework\Setup\ModuleContextInterface;
use Magento\Framework\Setup\ModuleDataSetupInterface;
use Magento\Catalog\Setup\CategorySetupFactory;
class InstallData implements InstallDataInterface
{
private $eavSetupFactory;
public function __construct(CategorySetupFactory $categorySetupFactory)
{
$this->categorySetupFactory = $categorySetupFactory;
}
public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context)
{
$installer = $setup;
$setup->startSetup();
$categorySetup = $this->categorySetupFactory->create(['setup' => $setup]);
$entityTypeId = $categorySetup->getEntityTypeId(\Magento\Catalog\Model\Category::ENTITY);
$attributeSetId = $categorySetup->getDefaultAttributeSetId($entityTypeId);
$categorySetup->removeAttribute(
\Magento\Catalog\Model\Category::ENTITY, 'image_thumb' );
$categorySetup->addAttribute(
\Magento\Catalog\Model\Category::ENTITY, 'image_thumb', [
'type' => 'varchar',
'label' => 'Thumbnail Image',
'input' => 'image',
'backend' => 'Magento\Catalog\Model\Category\Attribute\Backend\Image',
'required' => false,
'sort_order' => 5,
'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_STORE,
'group' => 'General Information',
]
);
$setup->endSetup();
}
}
path:- /app/code/Catattribute/Catthumbnail/view/adminhtml/ui_component/category_form.xml
<?xml version="1.0" encoding="UTF-8"?>
<form xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd">
<fieldset name="content">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="label" xsi:type="string" translate="true">Content</item>
<item name="collapsible" xsi:type="boolean">true</item>
<item name="sortOrder" xsi:type="number">10</item>
</item>
</argument>
<field name="image_thumb">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="dataType" xsi:type="string">string</item>
<item name="source" xsi:type="string">category</item>
<item name="label" xsi:type="string" translate="true">Thumbnail Image</item>
<item name="visible" xsi:type="boolean">true</item>
<item name="formElement" xsi:type="string">fileUploader</item>
<item name="elementTmpl" xsi:type="string">ui/form/element/uploader/uploader</item>
<item name="previewTmpl" xsi:type="string">Magento_Catalog/image-preview</item>
<item name="required" xsi:type="boolean">false</item>
<item name="sortOrder" xsi:type="number">40</item>
<item name="uploaderConfig" xsi:type="array">
<item name="url" xsi:type="url" path="catthumbnail/category_thumb/upload"/>
</item>
</item>
</argument>
</field>
</fieldset>
</form>