Question

While exporting customers by going to Customer->All Customers-> Export CSV from grid, billing & shipping addresses are shown as full address. Instead of full address, I need to have separate columns like billing_address_street,billing_address_city,shipping_address_street,shipping_address_city etc..,

I understandard these are coming from listing file module-customer\view\adminhtml\ui_component\customer_listing.xml and mapped to a table.

Is there a way to split the full billing & shipping address during the export operation instead of adding new columns to the listing or how to add address columns to customer_grid_flat table and populate the data in csv file

Your ideas will be appreciated.

Was it helpful?

Solution

Part one: Understanding Magento

Let me first explain what's going on, and why you're getting the result you're getting:

If you look at the columns defined in module-customer\view\adminhtml\ui_component\customer_listing.xml you'll see that stuff like billing_postcode and billing_city are already available / exported, only they're labeled als ZIP and City:

<column name="billing_postcode" sortOrder="70">
    <settings>
        <filter>text</filter>
        <editor>
            <editorType>text</editorType>
        </editor>
        <label translate="true">ZIP</label>
    </settings>
</column>
<column name="billing_city" sortOrder="210">
    <settings>
        <filter>text</filter>
        <editor>
            <editorType>text</editorType>
        </editor>
        <label translate="true">City</label>
        <visible>false</visible>
    </settings>
</column>

The addresses that are exported in as Billing Address and Shipping Address are billing_full and shipping_full:

<column name="billing_full" sortOrder="150">
    <settings>
        <label translate="true">Billing Address</label>
        <visible>false</visible>
    </settings>
</column>
<column name="shipping_full" sortOrder="160">
    <settings>
        <label translate="true">Shipping Address</label>
        <visible>false</visible>
    </settings>
</column>

These values are not as-is stored in the default database, but are generated for convenience purposes (like listing in a grid, or exporting in your case) in the flat table. See indexer.xml:

<fieldset name="billing" source="Magento\Customer\Model\ResourceModel\Address\Collection"
          provider="Magento\Customer\Model\Indexer\Address\AttributeProvider">
    <reference fieldset="customer" from="entity_id" to="default_billing"/>
    <field name="full" xsi:type="searchable" dataType="text" handler="BillingAddressHandler"/>
    ...

And BillingAddressHandler is a virtual type:

<virtualType name="BillingAddressHandler" type="Magento\Framework\Indexer\Handler\ConcatHandler">
    <arguments>
        <argument name="concatExpression" xsi:type="object">BillingAddressExpression</argument>
    </arguments>
</virtualType>

Which has an expression that builds the space concatenated data you have in your column:

<virtualType name="BillingAddressExpression" type="Magento\Framework\DB\Sql\ConcatExpression">
    <arguments>
        <argument name="columns" xsi:type="array">
            <item name="prefix" xsi:type="array">
                <item name="tableAlias" xsi:type="string">billing</item>
                <item name="columnName" xsi:type="string">street</item>
            </item>
            <item name="firstname" xsi:type="array">
                <item name="tableAlias" xsi:type="string">billing</item>
                <item name="columnName" xsi:type="string">city</item>
            </item>
            <item name="middlename" xsi:type="array">
                <item name="tableAlias" xsi:type="string">billing</item>
                <item name="columnName" xsi:type="string">region</item>
            </item>
            <item name="lastname" xsi:type="array">
                <item name="tableAlias" xsi:type="string">billing</item>
                <item name="columnName" xsi:type="string">postcode</item>
            </item>
        </argument>
    </arguments>
</virtualType>

Part two: Implementing

Now, as you can see, the export is done from the flat grid (=indexed) table, so if you want to export additional columns, you have to make sure that these are available.

As you can see in module-customer/etc/indexer.xml, there are actually already a lot of fields for the billing information, like postcode, city, street, etc. However, for shipping there is only the full-field (which maps to shipping_full):

<fieldset name="shipping" source="Magento\Customer\Model\ResourceModel\Address\Collection">
    <reference fieldset="customer" from="entity_id" to="default_shipping"/>
    <field name="full" xsi:type="searchable" dataType="text" handler="ShippingAddressHandler"/>
</fieldset>

<fieldset name="billing" source="Magento\Customer\Model\ResourceModel\Address\Collection"
          provider="Magento\Customer\Model\Indexer\Address\AttributeProvider">
    <reference fieldset="customer" from="entity_id" to="default_billing"/>
    <field name="full" xsi:type="searchable" dataType="text" handler="BillingAddressHandler"/>
    <field name="firstname" xsi:type="searchable" dataType="varchar"/>
    <field name="lastname" xsi:type="searchable" dataType="varchar"/>
    <field name="telephone" xsi:type="searchable" dataType="varchar"/>
    <field name="postcode" xsi:type="searchable" dataType="varchar"/>
    <field name="country_id" xsi:type="filterable" dataType="varchar"/>
    <field name="region" xsi:type="searchable" dataType="varchar"/>
    <field name="street" xsi:type="searchable" dataType="varchar"/>
    <field name="city" xsi:type="searchable" dataType="varchar"/>
    <field name="fax" xsi:type="searchable" dataType="varchar"/>
    <field name="vat_id" xsi:type="searchable" dataType="varchar"/>
    <field name="company" xsi:type="searchable" dataType="varchar"/>
</fieldset>

Now if you also want to have more shipping details indexed, just create your own module that hooks with it's own indexer.xml into this one (XML files are merged together after all), and add you desired fields:

<fieldset name="shipping" source="Magento\Customer\Model\ResourceModel\Address\Collection">
    <field name="postcode" xsi:type="filterable" dataType="varchar"/>
    <field name="street" xsi:type="filterable" dataType="varchar"/>
    <field name="city" xsi:type="filterable" dataType="varchar"/>
</fieldset>

Please note that at this point if you mark too much fields as xsi:type="searchable" you might get a SQL error: Syntax error or access violation: 1070 Too many key parts specified; max 16 parts allowed. This is because if a field is searchable it gets added to the index, and (depending on the configuration of your database) MySQL might not allow too big indexes. The xsi:type="filterable" is required for \Magento\Framework\Indexer\SaveHandler\Grid to populate the tables during indexing.

Flush the cache and run the reindex command to populate the table now:

php bin/magento cache:flush
php bin/magento indexer:reindex customer_grid

Now that the indexer is setup and the table is indexed, you can see in the database the extra columns present in customer_grid_flat with the proper data.

Part 3: Presenting

Now the last thing to do is add the columns to our module-customer/view/adminhtml/ui_component/customer_listing.xml. For example:

<column name="shipping_postcode" sortOrder="1000">
    <settings>
        <filter>text</filter>
        <editor>
            <editorType>text</editorType>
        </editor>
        <label translate="true">Shipping ZIP</label>
    </settings>
</column>
<column name="shipping_street" sortOrder="1001">
    <settings>
        <label translate="true">Shipping Street Address</label>
        <visible>false</visible>
    </settings>
</column>
<column name="shipping_city" sortOrder="1002">
    <settings>
        <filter>text</filter>
        <editor>
            <editorType>text</editorType>
        </editor>
        <label translate="true">Shipping City</label>
        <visible>false</visible>
    </settings>
</column>

And the result:

screenshot magento

csv

So as you can see, it's not a matter of manipulating the existing columns, but rather understanding where the data comes from and to add your own columns to it.

Hopefully this answer helps you.

Licensed under: CC-BY-SA with attribution
Not affiliated with magento.stackexchange
scroll top