1

I have added an extra column 'title' to the catalog_product_entity_tier_price table using Setup/UpdateSchema.php and an extra field to the tier price backend by overwriting Magento\Catalog\Ui\DataProvider\Product\Form\Modifier\AdvancedPricing::getTierPriceStructure:

class InstallSchema implements InstallSchemaInterface
{

    /**
     * {@inheritdoc}
     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
     */
    public function install(SchemaSetupInterface $setup, ModuleContextInterface $context)
    {
        $setup->startSetup();

        /** Tier Price Label **/
        $setup->getConnection()->addColumn(
            $setup->getTable('catalog_product_entity_tier_price'),
            'title',
            [
                'type' => \Magento\Framework\DB\Ddl\Table::TYPE_TEXT,
                'length' => 255,
                'nullable' => true,
                'comment' => 'Tier Price Title'
            ]
        );

        $setup->endSetup();
    }

}

enter image description here

database

product->advanced pricing

I've added the database column by overwriting Magento\Catalog\Model\ResourceModel\Product\Attribute\Backend\Tierprice::_loadPriceDataColumns, so my data from the database is loaded into the corresponding field - as seen above.

class Tierprice extends \Magento\Catalog\Model\ResourceModel\Product\Attribute\Backend\Tierprice
{
    /**
     * Initialize connection and define main table
     *
     * @return void
     */
    protected function _construct()
    {
        $this->_init('catalog_product_entity_tier_price', 'value_id');
    }

    /**
     * Add qty column & title column
     *
     * @param array $columns
     * @return array
     */
    protected function _loadPriceDataColumns($columns)
    {
        $columns = parent::_loadPriceDataColumns($columns);
        $columns['price_qty'] = 'qty';
        $columns['percentage_value'] = 'percentage_value';

        /* Start TierTitle */
        $columns['title'] = 'title';
        /* End TierTitle */

        return $columns;
    }

    /**
     * Order by qty
     *
     * @param \Magento\Framework\DB\Select $select
     * @return \Magento\Framework\DB\Select
     */
    protected function _loadPriceDataSelect($select)
    {
        $select->order('qty');
        return $select;
    }
}

I've added an extension_attribute so that my getters / setters are created:

<extension_attributes for="Magento\Catalog\Api\Data\ProductTierPriceInterface">
    <attribute code="title" type="string">
        <join reference_table="catalog_product_entity_tier_price" reference_field="product_id" join_on_field="entity_id">
            <field>title</field>
        </join>
    </attribute>
</extension_attributes>

These are created in generated/code/Magento/Catalog/Api/Data/ProductTierPriceExtension.php and in generated/code/Magento/Catalog/Api/Data/ProductTierPriceExtensionInterface.php.

As per Jonas Chen's answer below I've overwritten Magento\Catalog\Model\Product\Type\Price::setTierPrices and used $price->getExtensionAttributes()->getTitle():

class Price extends \Magento\Catalog\Model\Product\Type\Price
{
    /**
     * Sets list of product tier prices
     *
     * @param \Magento\Catalog\Model\Product $product
     * @param \Magento\Catalog\Api\Data\ProductTierPriceInterface[] $tierPrices
     * @return $this
     */
    public function setTierPrices($product, array $tierPrices = null)
    {
        // null array means leave everything as is
        if ($tierPrices === null) {
            return $this;
        }

        $allGroupsId = $this->getAllCustomerGroupsId();
        $websiteId = $this->getWebsiteForPriceScope();

        // build the new array of tier prices
        $prices = [];
        foreach ($tierPrices as $price) {
            $extensionAttributes = $price->getExtensionAttributes();
            $priceWebsiteId = $websiteId;
            $priceTitle = "";
            if (isset($extensionAttributes) && is_numeric($extensionAttributes->getWebsiteId())) {
                $priceWebsiteId = (string)$extensionAttributes->getWebsiteId();
            }
            if (isset($extensionAttributes) && $extensionAttributes->getTitle()) {
                $priceTitle = (string)$extensionAttributes->getTitle();
            }
            $prices[] = [
                'website_id' => $priceWebsiteId,
                'cust_group' => $price->getCustomerGroupId(),
                'website_price' => $price->getValue(),
                'price' => $price->getValue(),
                'all_groups' => ($price->getCustomerGroupId() == $allGroupsId),
                'price_qty' => $price->getQty(),
                'percentage_value' => $extensionAttributes ? $extensionAttributes->getPercentageValue() : null,
                'title' => $priceTitle
            ];
        }

        $product->setData('tier_price', $prices);

        return $this;
    }
}

And I've overwritten Model\Product\Attribute\Backend\Tierprice:

class Tierprice extends \Magento\Catalog\Model\Product\Attribute\Backend\Tierprice
{
    protected function getAdditionalFields($objectArray)
    {
        $percentageValue = $this->getPercentage($objectArray);
        $titleValue = $this->getTierTitle($objectArray);
        return [
            'value' => $percentageValue ? null : $objectArray['price'],
            'percentage_value' => $percentageValue ?: null,
            'title' => $titleValue ? $titleValue : null,
        ];
    }

    /**
     * @param array $valuesToUpdate
     * @param array $oldValues
     * @return boolean
     */
    protected function updateValues(array $valuesToUpdate, array $oldValues)
    {
        $isChanged = false;
        foreach ($valuesToUpdate as $key => $value) {

            if ((!empty($value['value']) && $oldValues[$key]['price'] != $value['value'])
                || $this->getPercentage($oldValues[$key]) != $this->getPercentage($value)
                || $this->getTierTitle($oldValues[$key]) != $this->getTierTitle($value)
            ) {
                $price = new \Magento\Framework\DataObject(
                    [
                        'value_id' => $oldValues[$key]['price_id'],
                        'value' => $value['value'],
                        'percentage_value' => $this->getPercentage($value),
                        'title' => $this->getTierTitle($value)
                    ]
                );
                $this->_getResource()->savePriceData($price);

                $isChanged = true;
            }
        }
        return $isChanged;
    }

    /**
     * Check whether price has percentage value.
     *
     * @param array $priceRow
     * @return null
     */
    private function getPercentage($priceRow)
    {
        return isset($priceRow['percentage_value']) && is_numeric($priceRow['percentage_value'])
            ? $priceRow['percentage_value']
            : null;
    }

    /**
     * Check whether price has title value.
     *
     * @param $priceRow
     * @return null
     */
    private function getTierTitle($priceRow)
    {
        return isset($priceRow['title'])
            ? $priceRow['title']
            : null;
    }

}

Following this the backend values are saved into the database, however now the the tierprice object does not contain the title.

I've tried overwriting Magento\Catalog\Model\Product\Type\Price::getTierPrices, but calling $tierPrices = $this->getExistingPrices($product, 'tier_price'); is already missing the title.

Answer

I had to also use a plugin on Magento\Catalog\Model\ResourceModel\Product\Attribute\Backend\GroupPrice\AbstractGroupPrice and had to add my custom database column on top of setting my title in my overwrite of Magento\Catalog\Model\Product\Type\Price::getTierPrices:

class AbstractGroupPricePlugin
{
    public function afterGetSelect(
        \Magento\Catalog\Model\ResourceModel\Product\Attribute\Backend\GroupPrice\AbstractGroupPrice $subject,
        $result
    )
    {
        //add title column to select
        $result->columns('title');

        return $result;
    }
}

I hope this helps someone else also.

2
+100

for Magento\Catalog\Model\Product\Type\Price::setTierPrices get value from $extensionAttributes->getTitle()

public function setTierPrices($product, array $tierPrices = null)
{
    // null array means leave everything as is
    if ($tierPrices === null) {
        return $this;
    }

    $allGroupsId = $this->getAllCustomerGroupsId();
    $websiteId = $this->getWebsiteForPriceScope();

    // build the new array of tier prices
    $prices = [];
    foreach ($tierPrices as $price) {
        $extensionAttributes = $price->getExtensionAttributes();
        $priceWebsiteId = $websiteId;
        $priceTitle = "";
        if (isset($extensionAttributes) && is_numeric($extensionAttributes->getWebsiteId())) {
            $priceWebsiteId = (string)$extensionAttributes->getWebsiteId();
        }
        if (isset($extensionAttributes) && $extensionAttributes->getTitle()) {
            $priceTitle = (string)$extensionAttributes->getTitle();
        }
        $prices[] = [
            'website_id' => $priceWebsiteId,
            'cust_group' => $price->getCustomerGroupId(),
            'website_price' => $price->getValue(),
            'price' => $price->getValue(),
            'all_groups' => ($price->getCustomerGroupId() == $allGroupsId),
            'price_qty' => $price->getQty(),
            'percentage_value' => $extensionAttributes ? $extensionAttributes->getPercentageValue() : null,

            'price_title' => $priceTitle
        ];
    }

    $product->setData('tier_price', $prices);

    return $this;
}

when save value in backend, try overwrite \Magento\Catalog\Model\Product\Attribute\Backend\Tierprice updateValues and getAdditionalFields functions

protected function getAdditionalFields($objectArray)
{
    $percentageValue = $this->getPercentage($objectArray);
    $titleValue = $objectArray['title'];
    return [
        'value' => $percentageValue ? null : $objectArray['price'],
        'percentage_value' => $percentageValue ?: null,
        'title' => $titleValue ? $titleValue : "",
    ];
}

/**
 * @param array $valuesToUpdate
 * @param array $oldValues
 * @return boolean
 */
protected function updateValues(array $valuesToUpdate, array $oldValues)
{
    $isChanged = false;
    foreach ($valuesToUpdate as $key => $value) {
        //check if "title" changed
        if ((!empty($value['value']) && $oldValues[$key]['price'] != $value['value'])
            || (!empty($value['title']) && $oldValues[$key]['title'] != $value['title'])
            || $this->getPercentage($oldValues[$key]) != $this->getPercentage($value)
        ) {
            $price = new \Magento\Framework\DataObject(
                [
                    'value_id' => $oldValues[$key]['price_id'],
                    'value' => $value['value'],
                    'percentage_value' => $this->getPercentage($value),
                    'title' => $value['title']
                ]
            );
            $this->_getResource()->savePriceData($price);

            $isChanged = true;
        }
    }
    return $isChanged;
}
  • Thank you! This was the missing piece of the puzzle. Now there is no need for the observer. – tecjam May 23 '18 at 8:03
  • The only problem I now have is that getTierPrices does not contain the title field. Even using getExtensionAttributes()->getTitle() on the Tierprice object does not return it. – tecjam May 23 '18 at 9:44
  • I had to overwrite the getTierPrices() and also use setTitle(). On top of that I had to use a plugin on Magento\Catalog\Model\ResourceModel\Product\Attribute\Backend\GroupPrice\AbstractGroupPrice and use afterGetSelect and set the extra column title. Thanks for your help, I'll award you the bounty once it lets me =) – tecjam May 23 '18 at 14:31
  • I am doing the same, but I cannot figure out how to add the new filed. Can you have a look: magento.stackexchange.com/questions/261313/… – Adarsh Khatri Feb 12 at 4:25

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.