We're working on a couple of Commerce Server projects right now and common for both of them is the fact that we need to support multiple currencies and languages. "That's easy", you might think, "you just add additional languages to the catalog and you're done". Indeed that is the case for multiple languages but it turns out that supporting multiple currencies is a little more involved.
Of course I need to support multiple currencies and languages but also multiple price groups so I can have different prices in countries using the same currency, say Spain and Holland where both use euro. Also I need to support pretty prices, i.e. the business user can specify the price like $9,99 or kr 5,95. I don't want to link a single currency to a particular country, e.g. I want Danish customers to be able see prices in Danish kroner as well as euro (the Danish euro price and not the Spanish one as they may differ).
Finally I need to support BizTalk integration with an ERP system with an internal category structure which makes sense to the business users and an external category structure for retail customers as defined by marketing. Of course I want all this to fit well in the Commerce Server way of doing this without compromising architecture and maintainability.
Requirements summed up:
- Multiple languages
- Multiple currencies
- Price groups
- Don't link currency to country
- Internal hierarchy and completely different external hierarchy
- Fit into CS way of doing things
Commerce Server Support
There are a number of features in Commerce Server which can help me support my requirements it's just a matter of using them in the right fashion to achieve the desired end result. Multiple languages are supported right out the box simply by specifying on each catalog which language to support. From there on in you can switch language when you're viewing any item in the catalog and edit text in whichever language you want. The catalog schema is fully extendable so you can use that to add a new field for each currency or price group you wan to support. We have virtual catalogs which allow you to move a product from another catalog into the virtual one and override values there. Finally we have catalogsets which is a way to bundle catalogs together and associate them users or groups.
In summary we have the following tools to work with:
- Multiple language support on catalogs
- Extendable catalog schema
- Virtual catalog for overriding field values
- Catalogsets to associate catalogs to users
What Not To Do
Now you could go ahead and use the multiple language feature to support multiple currencies but there are two problems with that: 1) Numbers are not overridable like text so you can only specify a single value across languages, you can remedy this by creating a text field and override that but then we'd be working with text values instead of decimal values and you would need to make modifications to the standard pipeline components which are looking for the ListPrice field on the products. Additionally you'd have to come up with a naming scheme for languages if you want to support multiple currencies in the same country essentially creating redundant text data because of it.
As a better alternative we could create new fields for each currency but it would break our requirement of maintainability as we'd have to create a new field each time we want to support a new currency. Even worse we'd have to come up with a naming scheme to support the same currency but in different countries, e.g. Spain_EUR_ListPrice, Holland_EUR_ListPrice, and come up with code which can support it in our pipelines. Interestingly this is one of the scenarios Microsoft is pushing needless to say that I don't agree in the least with this recommendation. Also each catalog in Commerce Server has a base currency specified which would be rendered useless or even worse would confuse the business users.
Using multiple fields would however make the integration story very easy because we simply map the fixed fields coming from the external source to Commerce Server.
What To Do
This is how I propose we solve the problem using virtual catalogs. Everything needs to be imported into a single base catalog which won't hold any price information, optionally you could use the base catalog for the currency which the company operates in internally but for our purposes I'll leave it blank as to only have a single model for multiple currencies.
Virtual Catalogs for Currency and Price Groups
Remember that each catalog in Commerce Server has a currency configured we'll leverage that by creating a virtual catalog for each currency we wish to support additionally we'll need to go one step further to support our price groups. In order to do that we'll extend the catalog schema with a field called price group which along with the currency will identify the correct catalog to look for when displaying products to the retail customers and when BizTalk is updating. To make the solution more maintainable we do a single "include all"-rule for each of the price group catalogs which will allow the BizTalk developers to assume that the product will always be present in all currencies, of course you can elect not to this but it will need a higher level support either manually or in the integration piece.
Now I mentioned include rules in passing above so allow me to elaborate on them here a bit: To include products, variants, or categories from another catalog in a virtual catalog we do it by creating virtual catalog rules. We have four types to choose from: Include everything, include category, include product family, and include variant; for each of those you can specify that we're excluding instead of including. There's a fifth rule type which I'll mention for the sake of completeness though I won't use them in here: pricing rules which is a way of adjusting prices in the catalogs. In summary I chose an "include all"-rule to support my price group catalogs above which will bring in all categories, products, and variants which are imported by BizTalk.
Support for BizTalk Integration
Whenever BizTalk imports a new product it needs to lookup the correct price group catalog for each price group on the product and update accordingly while this makes the integration piece a little more complicated it allows the Commerce Server developers to use the product in the intended way.
Virtual Catalog Considerations
For maintainability it's important to only update price information in the virtual catalogs we've created. Updating anything else will break the override chain which means that future updates to say product description will not populate to the virtual catalogs in which we overrode the value. It may be what you want but you need to be aware of this behavior.
Custom Hierarchy for Retail Customers
Remember that we want to provide the business with the opportunity to completely customize the category hierarchy for the retail customers while maintaining an internal hierarchy which makes sense from a business point of view. Now we have the business view of things in our Import catalog which is reflected in our price group catalogs as well due to the "include all"-rule we've added to the catalogs but we need a way to do a different hierarchy for our retail customers.
Unfortunately we can't do an "include all"-rule because that effectively includes categories as well and once you've included a category you're effectively stuck with it in your virtual catalog, there's no way to remove it without removing the products within as well. This means that we need to do include rules for every product family we want to include which provides the ultimate flexibility but also requires more from the Catalog Manager tool. Basically you can do with Catalog Manager but that doesn't mean that you should :) The workflow for adding an include rule basically involves opening the virtual catalog, clicking rules, then add new rule, search for the product you want, select the product, click next a couple of times, and then you need to add it to your new category in the virtual catalog which is another couple of steps. Imagine doing that for 4000 products :) Obviously some work need to be done on the Catalog Manager to make the workflow more smooth, maybe drag and drop within the catalog hierarchies or some kind of two-pane UI with the two catalogs on either side. In any event something needs to be put into place to handle the workflow but that's for a different post.
With that done we have something like this:
Finally we do a catalogset for each required user segment to line up the catalogs for the correct users programmatically. Once that's done we should have all our requirements covered.
Working with Commerce Server to support our requirements is essential even though it might involve a bit extra work to get there. We could've added an extra field for each currency we needed to support but that would have cornered us and ultimately created a less flexible system which might not support us in the future. We want to work within the restraints of Commerce Server without jeopardizing our systems design which in the end would render the decision to go with Commerce Server useless.
With an integrated solution it's important to keep in mind the opportunity which we have to keep some of the ugliness found in the systems we're integrating with at our system boundary enabling us to stay with a nice and clean design.
As with any standardized product it's important to know the tools available to us and how to use them in the correct fashion. Our little exercise above shows some of the capabilities of the catalog system and how you could leverage them to achieve a flexible solution while not compromising the design.