HowTo - Create personalized prices

Edit on GitHub

This article describes the steps you need to consider when implementing personalized prices for customer groups.

There are several steps to consider when implementing special prices based on which customer group the customer belongs to.

MODULE DESCRIPTION
Customer The customer entity needs to be extended to include the group id. Also, the customer module should be extended so that we have also the group id information for the customer.
Price The group id should be included in the price entity also. For an SKU, we should have one or more prices. The Price module should be extended so that we can query the price based on the SKU of the product and the group id.
Importer The set of prices should be imported for each product.
Collector The set of prices should be exported to the client side data storage.
Catalog The price that corresponds to the logged in customer group should be displayed.
PriceCartConnector The price that corresponds to the group the logged in customer is part of should be used in the cart.

1. Extend Customer module

The spy_customer table should be extended on the project side to include the group id. You can read more on how to extend the database schema in Extending the database schema article.

The spy_customer table should be extended on the project side to include the group ID. You can read more here on how to extend the database schema.

2. Extend Price module

The spy_price table should be extended on the project side to include the group id. The new added column should not be mandatory.

Extend price module

The Price module should be extended so that we can query prices by SKU and group id and retrieve the default price.

3. Import prices

The Importer module takes care of importing data to the SQL database.

Prices are imported by the ProductPriceImporter. If you are using the Importer module to load initial data to the SQL database, you need to update the ProductPriceImporter:importOne(array $data) to include the group ID for each price entry.

4. Adjust prices for cart

For the products in the cart, prices must be displayed according to the group the logged-in user belongs to (in case the current user is a guest, the default price should be displayed).

The prices for the products in the cart are added by the CartItemPricePlugin.

These values are used by the cart calculators.

It is recommended that you implement a new plugin that replaces the one from Core rather than extending it on the project side. This ensures backward compatibility.

You can implement a new plugin to retrieve the price based on the group id and register it under the CartDependencyProvider:getExpanderPlugins(Container $container).

<?php
   /**
     * @param \Spryker\Zed\Kernel\Container $container
     *
     * @return \Spryker\Zed\Cart\Dependency\ItemExpanderPluginInterface[]
     */
    protected function getExpanderPlugins(Container $container)
    {
        return [
            new CartItemSpecialPricePlugin(),
            /..
        ];
    }

From the QuoteTransfer that is included in the CartChangeTransfer you can get the customer data and the group id:

<?php
namespace Pyz\Zed\PriceCartConnector\Communication\Plugin;

use Generated\Shared\Transfer\CartChangeTransfer;
use Spryker\Zed\Cart\Dependency\ItemExpanderPluginInterface;
use Spryker\Zed\Kernel\Communication\AbstractPlugin;

/**
 * @method \Pyz\Zed\PriceCartConnector\Business\PriceCartConnectorFacade getFacade()
 * @method \Pyz\Zed\PriceCartConnector\Communication\PriceCartConnectorCommunicationFactory getFactory()
 */
class CartItemSpecialPricePlugin extends AbstractPlugin implements ItemExpanderPluginInterface
{

    /**
     * @param \Generated\Shared\Transfer\CartChangeTransfer $cartChangeTransfer
     *
     * @return \Generated\Shared\Transfer\CartChangeTransfer
     */
    public function expandItems(CartChangeTransfer $cartChangeTransfer)
    {
        return $this->getFacade()->addGrossSpecialPriceToItems($cartChangeTransfer);
    }

}

5. Export prices

The special prices must also be exported to the client-side data storage so that the corresponding price can be displayed to the customer. Data aggregation and export to client-side data storage is handled by the Collector module.

The product data is collected by the ProductCollector. The ProductCollector:collectItem($touchKey, array $collectItemData) should be modified to collect the prices for the current SKU.

<?php
 /**
     * @param string $touchKey
     * @param array $collectItemData
     *
     * @return array
     */
    protected function collectItem($touchKey, array $collectItemData)
    {
      $collectedItem= [
            'abstract_product_id' =>
            'abstract_attributes' => $this->getAbstractAttributes($collectItemData),
            'abstract_name' => $collectItemData[static::ABSTRACT_NAME],
            'abstract_sku' => $collectItemData[static::SKU], // FIXME
            'url' => $collectItemData[static::ABSTRACT_URL],
            'quantity' =>  (int)$collectItemData[static::QUANTITY],
            'available' => (int)$collectItemData[static::QUANTITY] > 0,
            'category' => $this->generateCategories($collectItemData[CollectorConfig::COLLECTOR_RESOURCE_ID]),
        ];
      $specialPrices = $this->getSpecialPricesBySku($collectItemData[static::ABSTRACT_SKU]),

      $collectedItem=$specialPrices;    

      return $collectedItem;
    }

6. Display price to customer

The ProductResourceCreator transforms the JSON containing product details stored in Redis into a more understandable format.

The price needs to be set according to the group that the customer belongs to when building the product using the data from Redis.

A controller action that’s called when a request on a product detail page is submitted allows you to retrieve logged in customer information by calling the getUser() method. Now that you know the id of the group that the customer is a member of, you can set the price of the product according to the group.