Pages - Menu

nopCommerce - Multi Store / Multi Currency / Multi Price for each product

Scope

We have had a few sites went live with nopCommerce. I am in the process to replicate our existing Australia sites to New Zealands sites.
  • Both sites to sell the same products, with stocks coming from the same location.
  • Products dispatch from the same warehouse.
  • Customizable Price, Old Price and Special Price per product per store and not using any currency converter.
  • etc.

What I am trying to achieve is also described here and here by other people. Or as a workitem in codeplex. No viable solution at time of writing this article.

This is base on nopCommerce v3.3.

Business Case

nopCommerce out of the box supports multiple currencies by using a currency converter.



However, this is only practical if your company is 1 entity and want to accept orders from around the world. Currency converter provides an estimate for users on how much they will be spending, but the transaction is still processed in my primary currency - AU dollars in our case.

Example of Currency Converter from my previous project - Bardot

In our business case, we own both of the AU and NZ companies as separate business entities. Our NZ company have their own price and we would like to accept local NZ credit cards in NZ currency. In this scenario, currency converter is not a feasible solution.

Technical Overview

  • Create a new ProductPrices table to store prices for different stores
  • Create an admin screen to handle Product Prices
  • Create a GetCustomPrice() to retrieve price from ProductPrices if store id match
  • Replace any existing controllers or services that use Product.Price to use GetCPrice()

Prerequisite

Code

ProductCustomPrice


We created a new SQL table to store our custom price. 


In our code, we need to create a new domain object for ProductCustomPrice and a mapping file. This is already demonstrated in previous posts in prerequisite.

PriceCalculationService


We need to override the PriceCalculationService.GetFinalPrice() in the Product Price region to use our custom price. We will need a small refactor work in core.

// decimal result = product.Price;
decimal result = GetProductInitPrice(product);

We will write a method to retrieve the custom price from our database.

public virtual ProductCustomPrice GetProductCustomPriceByProductId(int productId)
{
    if (productId == 0)
        return null;
            
    var currentStoreId = _storeContext.CurrentStore.Id;
    var query = _productCustomPriceRepository.Table
                    .Where(p => p.StoreId == currentStoreId 
                            && p.ProductId == productId);

    return query.FirstOrDefault();
}

We will override the method in our new CustomPriceCalculationService class. It will pick up custom price if available, otherwise default.

protected override decimal GetProductInitPrice(Product product)
{
    var customPrice = GetProductCustomPriceByProductId(product.Id);

    if (customPrice != null)
        return customPrice.Price;

    return base.GetProductInitPrice(product);
}

CatalogController


We then need to do the same for OldPrice, SpecialPrice, SpecialPriceStartDateTimeUtc and SpecialPriceEndDateTimeUtc. I will leave this fun exercise for my readers. As a hint, a good starting point is to refactor the CatalogController like what we did for Price.

// decimal oldPriceBase = _taxService.GetProductPrice(product, product.OldPrice, out taxRate);
decimal oldPriceBase = _taxService.GetProductPrice(product, _priceCalculationService.GetProductInitOldPrice(product), out taxRate);

We now able show different Price and SpecialPrice for multi stores.


I built an admin screen base on the TierPrice screen and ProductCustomPrice() CRUD base on Nop.Admin.Controllers.ProductController.TierPriceList().

For example, the Reebok Core Price is $169.99 and Special Price is $118.99.

By introducing Per Store Custom Price, the Reebok NZ Local store would have a customized price of $200, an old price of $180 and a special price of $130.






Other Solutions that didn't work

Tier Price

Initially I was trying to use store specific tier price with 1 unit, and in the hope that the price will be overridden by the tier price. It didn't work in 2 aspects.

Firstly, the way how tier price works is to give a better discount for the customer if they are buying multiples. The logic in nopCommerce will check if the tier price is cheaper than the original and only apply if cheaper. Unfortunately the foreign currency is not always cheaper than the primary.

Secondly, I cannot get store specific for OldPrice or SpecialPrice.

Conclusion

This is not the best solution but the one of the possible solution. If I was a core nopCommerce developer, I would have changed the domain object to work with the prices.

I am very lucky that Australia and New Zealand use the same currency symbol. For wider audience sake, I think the solution needs to be extended to cover other area as well.

No comments:

Post a Comment