Question

We have come across an issue that I'm trying to solve. In order to overcome this bug https://github.com/magento/magento2/issues/10009 where discounted prices are not applied per customer group, I've created a module that will handle this. I have set up a database table which looks like this: enter image description here

And I need to render the price on the product list and product view page. I want to use the built in price renderer but I am unable to figure out how to do this. Currently my code looks like this:

public function getCustomerGroupSpecialPrice($productId)
{

    $collection = $this->customerGroupPricesCollectionFactory->create();
    $collection->getSelect();
    $collection->addFieldToFilter('product_id', array('eq' => $productId))
                       ->addFieldToFilter('customer_group_id', array('eq' => $this->getCustomerGroupId()));
    foreach ($collection as $item) {
        $price = $item->getData('price');
    }
    return $price;
}

This does get the correct price but it looks like this: enter image description here

and what I need is for the price to be rendered like this:

enter image description here

I've tried overriding the price like this:

class CustomerGroupSpecialPrice extends AbstractPrice
{
    /**
     * Price type identifier string
     */
    const PRICE_CODE = 'customer_group_special_price';

    protected $customerGroupPricesCollectionFactory;

    public function __construct(
        \Icansee\CustomerGroupsPrices\Model\ResourceModel\CustomerGroup\CollectionFactory $customerGroupPricesCollectionFactory
    ) {
        $this->customerGroupPricesCollectionFactory = $customerGroupPricesCollectionFactory;
    }
    /**
     * Get Base Price Value
     *
     * @return float|bool
     */
    public function getValue()
    {
        if ($this->value === null) {
            $this->value = false;
            $collection = $this->customerGroupPricesCollectionFactory->create();
            $collection->getSelect();
            $collection->addFieldToFilter('product_id', array('eq' => $productId))
                               ->addFieldToFilter('customer_group_id', array('eq' => $this->getCustomerGroupId()));
            foreach ($collection as $item) {
                $price = $item->getData('price');
            }
            $this->value = $price;
        }
        return $this->value;
    }
}

but I get an error of class not found as the PRICE_CODE 'customer_group_special_price' does not exist within Magento and so I can't do it this way. I don't really want to code in the HTML into the template to render the price correctly, as we need to render this price in multiple places, such as a quickview modal popup, product view etc. so I would need to hard code this in multiple places and that won't do. How can I render the price value correctly from my custom table?

Was it helpful?

Solution 2

I fixed this issue by writing a plugin to get the special price for the customer's group after getPrice is called, which then uses the discount price if there is one and the product's price if there isn't. This renders the price box html with the required price showing in all areas of Magento, from the product list to the checkout and items are ordered with the discounted price as well.

I created etc/di.xml in my module:

<config>
<type name="Magento\Catalog\Model\Product">
    <plugin name="change_product" type="Vendor\Module\Plugin\Product" sortOrder="1" disabled="true" />
</type>

then I moved my getCustomerGroupSpecialPrice function to the plugin and use it there to modify the price with the custom price retrieved from the table of prices I set up. This works perfectly for anyone who needs to set customer group special prices.

EDIT:

A side effect of this is that every call to getPrice() will be overridden by the plugin. To get around displaying incorrect prices in the order view I had to also write an observer as shown below:

<?php

namespace Vendor\Module\Observer;

use \Magento\Framework\Event\ObserverInterface; use \Magento\Framework\Event\Observer as EventObserver;

class OrderSaveAfter implements ObserverInterface { /** * @var \Psr\Log\LoggerInterface */ protected $_logger;

protected $productFactory;

protected $quoteToOrder;

protected $quoteFactory;

protected $taxHelper;

public function __construct(
    \Magento\Catalog\Model\ProductFactory $productFactory,
    \Psr\Log\LoggerInterface $logger,
    \Magento\Quote\Model\Quote\Item\ToOrderItem $quoteToOrder,
    \Magento\Quote\Model\QuoteFactory $quoteFactory,
    \Magento\Catalog\Helper\Data $taxHelper
) {
    $this->productFactory = $productFactory;
    $this->_logger = $logger;
    $this->quoteToOrder = $quoteToOrder;
    $this->quoteFactory = $quoteFactory;
    $this->taxHelper = $taxHelper;
}

/**
 * @param EventObserver $observer
 */
public function execute(\Magento\Framework\Event\Observer $observer)
{
    /** @var \Magento\Sales\Model\Order $order */
    $order = $observer->getEvent()->getOrder();

    if (!$order) {
        return;
    }

    $quote = $this->quoteFactory->create()->load($order->getQuoteId());
    $this->_logger->addInfo("QUOTE ID: " . $quote->getId());

    foreach ($quote->getAllVisibleItems() as $quoteItem) {
        $discountAmount = 0;
        $origOrderItem = $order->getItemByQuoteItemId($quoteItem->getId());
        $orderItemId = $origOrderItem->getItemId();
        $productId = $quoteItem->getProductId();
        $product = $this->productFactory->create()->load($productId);
        $originalPrice = $product->getPriceInfo()->getPrice('regular_price')->getAmount()->getValue();
        $discountAmount = ($originalPrice / 100) * $product->getSaleDiscountPercent();
        $quoteItem->setDiscountAmount($discountAmount);
        $quoteItem->setOriginalPrice($originalPrice);
        $inclTaxPrice = $this->taxHelper->getTaxPrice($product, $originalPrice, true);
        $quoteItem->setRowTotal($inclTaxPrice);
    }
    $quote->save();

    foreach ($quote->getAllVisibleItems() as $quoteItem) {
        $orderItem = $this->quoteToOrder->convert($quoteItem);
        $origOrderItemNew = $order->getItemByQuoteItemId($quoteItem->getId());

        if ($origOrderItemNew) {
            $origOrderItemNew->addData($orderItem->getData());
        } else {
            if ($quoteItem->getParentItem()) {
                $orderItem->setParentItem(
                    $order->getItemByQuoteItemId($orderItem->getParentItem()->getId())
                );
            }
            $order->addItem($orderItem);
        }
    }
    $order->save();

    return $order;
}

}

This uses the following events.xml:

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
<event name="sales_order_save_after">
    <observer name="save_item_discount_amounts" instance="Icansee\CustomerGroupsPrices\Observer\OrderSaveAfter" />
</event>

OTHER TIPS

Use below code to format price in your phtml file.

$this->helper('Magento\Framework\Pricing\Helper\Data')->currency(number_format(50,2),true,false);

Replace 50 by your price in this.

Edit

Add a new module with a phtml to display price in what ever format you want. And you can use this in anywhere you want using layouts.

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