Chapters Close

How to Add a Column to the Tier Price in Magento 2 Admin?

Here, in this blog, I’ll guide you to add columns in the tier price grid of the product. Sometimes it’s essential to understand the client’s Magento web development requirements by overriding the core modules. Here, I am sharing a use case in which we’ve to override the tier price functionality.

Use Case: Our client has a few products that can be sold separately or in bulk. Let’s take the example of soap. Users can purchase the soap single or in a pack of 8 to which they call family package, and there is also one more option: Users can purchase a pack of 24 to which they call a box.

To fulfill the client’s requirement, we’ve decided to override the tier price functionality and divide the solution into two parts. 

  • Add a secondary unit column in the tier price
  • Display units on the frontend by using the dropdown.

This blog consists of a first solution, which is to add a column in the tier price grid. To do so, you have to do the following things in your extension.

  1. Add a required field in the tier price table
  2. Add a field in the grid
  3. Override save & update handlers

Let’s follow the above steps and customize the tier price.

1. Add a required field in the tier price table:

Here, we’ll add the field in the tier price table using the database schema. To do so, create the db_schema.xml in the etc folder and add the code below to it.

 
 
 
Copy Code

<schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   
xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">
   <table name="catalog_product_entity_tier_price" resource="default" engine="innodb" comment="Tier Pricing Table">
       <column xsi:type="varchar" name="{KEY}" nullable="true" length="255" comment="comment" />
   </table>
</schema>

2. Add a field in the grid:

We’ll add a field in a tier price grid using the modifiers in the following way. First, we’ll create a di.xml in the etc/adminhtml and add a modifier pool in it.

 
 
 
Copy Code
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
   <virtualType name="Magento\Catalog\Ui\DataProvider\Product\Form\Modifier\Pool" type="Magento\Ui\DataProvider\Modifier\Pool">
       <arguments>
           <argument name="modifiers" xsi:type="array">
               <item name="{identifier}" xsi:type="array">
                   <item name="class" xsi:type="string">{vendor}\{module}\Ui\DataProvider\Product\Form\Modifier\UpdateTierPricing</item>
                   <item name="sortOrder" xsi:type="number">200</item>
               </item>
           </argument>
       </arguments>
   </virtualType>
   <type name="{vendor}\{module}\Ui\DataProvider\Product\Form\Modifier\UpdateTierPricing">
       <arguments>
           <argument name="scopeName" xsi:type="string">product_form.product_form</argument>
       </arguments>
   </type>
</config>

Now, create an UpdateTierPricing.php at the Ui\DataProvider\Product\Form\Modifier and add the below code.

 
 
 
Copy Code
class UpdateTierPricing extends AbstractModifier
{
   /**
    * @var ArrayManager
    * @since 101.0.0
    */
   protected $arrayManager;

   /**
    * @var string
    * @since 101.0.0
    */
   protected $scopeName;

   /**
    * @var array
    * @since 101.0.0
    */
   protected $meta = [];

   /**
    * UpdateTierPricing constructor.
    * @param ArrayManager $arrayManager
    */
   public function __construct(
       ArrayManager $arrayManager
   ) {
       $this->arrayManager = $arrayManager;
   }

   /**
    * @param array $data
    * @return array
    * @since 100.1.0
    */
   public function modifyData(array $data)
   {
       // TODO: Implement modifyData() method.
       return $data;
   }

   /**
    * @param array $meta
    * @return array
    * @since 100.1.0
    */
   public function modifyMeta(array $meta)
   {
       // TODO: Implement modifyMeta() method.
       $this->meta = $meta;

       $this->customizeTierPrice();

       return $this->meta;
   }

   /**
    * @return $this
    */
   private function customizeTierPrice()
   {
       $tierPricePath = $this->arrayManager->findPath(
           ProductAttributeInterface::CODE_TIER_PRICE,
           $this->meta,
           null,
           'children'
       );

       if ($tierPricePath) {
           $this->meta = $this->arrayManager->merge(
               $tierPricePath,
               $this->meta,
               $this->getTierPriceStructure()
           );
       }

       return $this;
   }

   /**
    * @return array
    */
   private function getTierPriceStructure()
   {
       return [
           'children' => [
               'record' => [
                   'children' => [
                       {KEY} => [
                           'arguments' => [
                               'data' => [
                                   'config' => [
                                       'formElement' => Input::NAME,
                                       'componentType' => Field::NAME,
                                       'dataType' => Number::NAME,
                                       'label' => __('Label'),
                                       'dataScope' => '{KEY},
                                       'sortOrder' => 25,
                                   ],
                               ],
                           ],
                       ],
                   ],
               ],
           ],
       ];
   }
}

3. Override save & update handlers:

After performing the above steps, we’ve added the field to the grid and the database. Now, we have to override the handlers using the preference.

To do so, we’ve to create the SaveHandler.php in the Model directory. This file overrides the save functionality of the tier price, which will execute during the save of the new product.

 
 
 
Copy Code
use Magento\Catalog\Model\Product\Attribute\Backend\TierPrice\SaveHandler;

class SavePriceHandler extends SaveHandler
{

   /**
    * Get additional tier price fields.
    *
    * @param array $objectArray
    * @return array
    */
   public function getAdditionalFields(array $objectArray): array
   {
       $percentageValue = $this->getPercentage($objectArray);

       return [
           'value' => $percentageValue ? null : $objectArray['price'],
           'percentage_value' => $percentageValue ?: null,
           {KEY} => $this->getSecondaryUnit($objectArray),
       ];
   }

   /**
    * @param array $priceRow
    * @return mixed|null
    */
   public function getSecondaryUnit(array  $priceRow)
   {
       return isset($priceRow[{KEY}]) && !empty($priceRow[{KEY}])
           ? $priceRow[{KEY}]
           : null;
   }
}

To update the tier price data while updating the product need to create the UpdateHandler.php in the Model directory and copy the code from vendor/magento/module-catalog/Model/Product/Attribute/Backend/TierPrice/UpdateHandler.php and remove the updateValues function from the code and add code in the file.

Note: Here, don’t forget to extend the UpdateHandler.

 
 
 
Copy Code
/**
* Update existing tier prices for processed product
*
* @param array $valuesToUpdate
* @param array $oldValues
* @return bool
*/
public function updateValues(array $valuesToUpdate, array $oldValues): bool
{

   $isChanged = false;
   foreach ($valuesToUpdate as $key => $value) {
       if ((!empty($value['value']) && (float)$oldValues[$key]['price'] !== (float)$value['value'])
           || $this->getPercentage($oldValues[$key]) !== $this->getPercentage($value)
           || $this->getSecondaryUnit($oldValues[$key]) !== $this->getSecondaryUnit($value)
       ) {
           $price = new \Magento\Framework\DataObject(
               [
                   'value_id' => $oldValues[$key]['price_id'],
                   'value' => $value['value'],
                   'percentage_value' => $this->getPercentage($value),
                   {KEY} => $this->getSecondaryUnit($value),
               ]
           );
           $this->tierPriceResource->savePriceData($price);
           $isChanged = true;
       }
   }

   return $isChanged;
}

/**
* Get additional tier price fields.
*
* @param array $objectArray
* @return array
*/
public function getAdditionalFields(array $objectArray): array
{
   $percentageValue = $this->getPercentage($objectArray);

   return [
       'value' => $percentageValue ? null : $objectArray['price'],
       'percentage_value' => $percentageValue ?: null,
       {KEY} => $this->getSecondaryUnit($objectArray),
   ];
}

/**
* @param array $priceRow
* @return mixed|null
*/
public function getSecondaryUnit(array  $priceRow)
{
   return isset($priceRow[{KEY}]) && !empty($priceRow[{KEY}])
       ? $priceRow[{KEY}]
       : null;
}

Create DataColumnUpdate.php in the Model directory. This file will load the saved data into the database.

 
 
 
Copy Code
class DataColumnUpdate extends Tierprice
{
   /**
    * @param array $columns
    * @return array
    */
   protected function _loadPriceDataColumns($columns)
   {
       $columns = parent::_loadPriceDataColumns($columns);
       $columns[{KEY}] = {KEY};
       return $columns;
   }
}

Now, you have to add the di.xml in the etc directory and add code below.

 
 
 
Copy Code
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
   <preference for="Magento\Catalog\Model\Product\Attribute\Backend\TierPrice\UpdateHandler"
               type="{vendor}\{module}\Model\UpdatePriceHandler" />
   <preference for="Magento\Catalog\Model\Product\Attribute\Backend\TierPrice\SaveHandler"
               type="{vendor}\{module}\Model\Product\Attribute\Backend\TierPrice\SavePriceHandler" />
   <preference for="Magento\Catalog\Model\ResourceModel\Product\Attribute\Backend\Tierprice"
               type="{vendor}\{module}\Model\ResourceModel\Product\Attribute\Backend\DataColumnUpdate" />
</config>

Here, we’ve added all the necessary code to override the tier pricing functionality. Now, just execute the command below from the Magento root directory and verify your implementation.

php bin/magento setup:upgrade
php bin/magento setup:di:compile

I hope this solution will resolve your problem. Let me know your thoughts in the comment section. And if you have any queries with this blog, I will be happy to solve that. Thanks and cheers … 🙂

Also read: Convert the price from one current to another in Magento 2

Speak your Mind

Post a Comment

Got a question? Have a feedback? Please feel free to leave your ideas, opinions, and questions in the comments section of our post! ❤️

* This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

Thank you for your feedback

Comments (4)

  1. Hi I am getting following error when saving the tier price

    Type Error occurred when creating object: Vendor\Module\Model\Product\Attribute\Backend\Tierprice\UpdatePriceHandler

    Reply
  2. Nice tutorial. I tried to follow and add column in M2 but I get following error after I run
    php bin/magento setup:upgrade

    PHP Fatal error: Class ‘AbstractModifier’ not found in /var/www/vhosts/{site}/httpdocs/app/code/{MOD}/TierPriceMod/Ui/DataProvider/Product/Form/Modifier/UpdateTierPricing.php on line 2

    Reply
  3. I have followed this tutorial but I’m getting an error while updating the value:

    Fatal error: Uncaught Error: Call to a member function getAllCustomersGroup() on null in

    Reply
  4. Great tutorial!
    How retrive the custom value programmatically (in phtml page, controller… for example)?
    Thanks!

    Reply

Grow your online business like 3,596 subscribers

    * This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.
    envelope

    Thank You!

    We are reviewing your submission, and will be in touch shortly.