I think the best approach to multi-currency will differ depending on how you are going to handle the data. The two most prevalent ways people have approached it thus far both use a "base" currency in the back office and then either have a static rate conversion table they update or call out to an API service to get the new price based on current exchange rate to display the equivalent on the front end albeit it is possible to actually bill in different currencies, that's more of a matter with the payment providers.
Adjusting the price (for sales too) and currency code as the product goes into the basket is a matter of adjusting the extended data values and the line item price. You do this through by using the one of the overloaded AddItem methods to the basket and passing in your own ExtendedDataCollection or finding the line item that you had added and using the SetValue extension method on the collection that was created.
Finally, you'll need to validate the items added to the basket are all in the same currency so that someone does not try to buy 3 in Euros and 1 and dollars for example. It would be a lot more coding to get that to work.
Thanks for the advice as i am on customers offering a full price and some customers get a discount.
Is there any issues using the main Merchello product prices for my GB currency so price would be normally full price and sale price i would use as my price for my customers that get the additional discount.
In the other product data type that has product images/content I could store the other two prices for the other two currencies.
Then as you said i could overload the AddItem Method and set the price and currency as suggested. Could you send me that link again as its been truncated.
Overloading the method would i have to use the extended data or can i just set the price for the item inside the methods.
I would assume if i had to use extended data I would have to modify the invoicing methods of when looking at the individual line items.
You should not need to modify any invoicing methods as they already use the line item data and ExtendedData values. Once an item is in a collection there is only a loose association with the original product. This is designed so that you can add items from outside Merchello's product catalog.
Adjusting the price, sale price and currency code, shippable, taxable ... etc. values are independent of the product itself so your essentially overriding the product values. It should work just fine.
If you add the product to the basket without designating the currency code, it will assume the global setting set in the back office.
If you want to set the currency code, you would need to set the extended data value with the 3 character ISO currency code.
Depending on your setup, you may have to check the ship rate quotes and taxation calculations too so that the resulting invoice is all generated in the same currency. In the invoice builder, there is a task to assert the currency code. If it does not find one, it will add the default currency (from memory so you need to check me on that).
If you are converting everything to the base currency (back office setting) and only displaying prices in various currencies then you would not need to worry about it.
CustomHelper.GetCurrency() returns an ICurrency which takes in context the current logged in member and their preference for there currency and CustomHelper.GetProductPrice() takes the products guid, and based on the members currency and if they have the discounted price returns the products price in that currency (eg. apply the currency calculation so if an item was £400 would return $520 )
This I have amended the AddToBasket to this, however viewing the basket i can see the product totals tally with my overridden price however it is still showing the currency symbol £ rather than $
[HttpPost]
public ActionResult AddToBasket(AddItemModel model)
{
var extendedData = new ExtendedDataCollection();
extendedData.SetValue("umbracoContentId", model.ContentId.ToString(CultureInfo.InvariantCulture));
extendedData.SetValue(Constants.ExtendedDataKeys.CurrencyCode, CustomHelper.GetCurrency().CurrencyCode);
var product = this.MerchelloServices.ProductService.GetByKey(model.Product.Key);
if (!this.Basket.Items.Contains(product.Sku))
{
this.Basket.AddItem(product.Name, product.Sku, 1, CustomHelper.GetProductPrice(model.Product.Key), extendedData);
}
this.Basket.Save();
return this.RedirectToUmbracoPage(model.BasketPageId);
}
Thanks Rusty, I am using that service to get to get the symbols etc, I will modify the basket markup to get this. Will the back office use the extended data for currency or will I need to make adjustments there?
On checkout now i now get an "Invoice is being created with line items costed in different currencies." exception when it produces the invoice which i guess is to be expected as the stores default currency is different to the currency of the product i added to the basket.
Delving into the code i can see there is a tax item which is set to GBP but all the products in the basket are USD. The products in question is not taxable.
My guess is the product currency code is not present in the ExtendedDataCollection (or with an incorrect key) and the task above is adding the store default currency code.
That being said an exception should be thrown at some point because of multiple currency codes. I probably missed handling that case in the Bazaar starter since I was only ever doing a single currency.
I have just tried to debug PerformTask in ValidateCommonCurrency.
So in my example i have added 2 products, however in PerFormTask value.Items that it selects the currencies from has 3 items my two products which are both USD in the extended data. I was also using the constant for the currency code key "Constants.ExtendedDataKeys.CurrencyCode" to ensure i didn't make a typo on them.
The third item is Tax which is defaulting to the stores base currency.
I was under the impression i can just add an item to the basket and call save, should i be doing anything about the tax situation? I was assuming there be any need for a Tax line item as the store is not applying tax.
Ok, that makes sense. The tax provider is calculating taxes as 0 and it looks like I still mistakenly have the switch ApplyTaxesToInvoice as internal in the SalePreparationBase class. I'll change that for version 1.9.1 so that it can be set in your controller.
/// <summary>
/// Gets or sets a value indicating whether to apply taxes to invoice.
/// </summary>
internal bool ApplyTaxesToInvoice { get; set; }
For the time being so that you are not stuck, comment out the apply taxes task in the merchello.config file. That will skip that step and you should not get a tax line item.
Additional pricing editing in the back office
Hi,
I am looking at having two pricing options but based on multi currencies that are fixed.
I understand i can use extended data on a product.
eg. FullPriceEuro, DiscountedEuro, FullPriceDollar, DiscountedDollar ...
Is there any advice on how to extend the product edit in the back-office so i can edit these properties directly.
I was under the impression i would need to look at modifying productvariant.mainproperties.tpl.html
Thanks
Paul
Hey Paul,
I think the best approach to multi-currency will differ depending on how you are going to handle the data. The two most prevalent ways people have approached it thus far both use a "base" currency in the back office and then either have a static rate conversion table they update or call out to an API service to get the new price based on current exchange rate to display the equivalent on the front end albeit it is possible to actually bill in different currencies, that's more of a matter with the payment providers.
Adjusting the price (for sales too) and currency code as the product goes into the basket is a matter of adjusting the extended data values and the line item price. You do this through by using the one of the overloaded AddItem methods to the basket and passing in your own ExtendedDataCollection or finding the line item that you had added and using the SetValue extension method on the collection that was created.
On line 193 you'll see how it's done in the Core. https://github.com/Merchello/M...
Finally, you'll need to validate the items added to the basket are all in the same currency so that someone does not try to buy 3 in Euros and 1 and dollars for example. It would be a lot more coding to get that to work.
Rusty
Hi Rusty,
Thanks for the advice as i am on customers offering a full price and some customers get a discount.
Is there any issues using the main Merchello product prices for my GB currency so price would be normally full price and sale price i would use as my price for my customers that get the additional discount.
In the other product data type that has product images/content I could store the other two prices for the other two currencies.
Then as you said i could overload the AddItem Method and set the price and currency as suggested. Could you send me that link again as its been truncated.
Overloading the method would i have to use the extended data or can i just set the price for the item inside the methods.
I would assume if i had to use extended data I would have to modify the invoicing methods of when looking at the individual line items.
Thanks
Paul
Hi Paul,
Here's the link again:
https://github.com/Merchello/Merchello/blob/1.9.0/src/Merchello.Core/Models/ExtendedDataExtensions.cs
You should not need to modify any invoicing methods as they already use the line item data and ExtendedData values. Once an item is in a collection there is only a loose association with the original product. This is designed so that you can add items from outside Merchello's product catalog.
Adjusting the price, sale price and currency code, shippable, taxable ... etc. values are independent of the product itself so your essentially overriding the product values. It should work just fine.
You can see the Basket.AddItem methods here:
https://github.com/Merchello/Merchello/blob/1.9.0/src/Merchello.Web/Workflow/Basket.cs
Thanks Rusty,
Do I need to apply the currency to the Basket, as I know if I added by the product directly i would guess it would get this from the product.
As in all my use cases I can see that I can use this version of the AddItem
"public void AddItem(string name, string sku, int quantity, decimal price)"
Will provide exactly what I need, as I can work out what price I would require.
Thanks,
Paul
If you add the product to the basket without designating the currency code, it will assume the global setting set in the back office.
If you want to set the currency code, you would need to set the extended data value with the 3 character ISO currency code.
Depending on your setup, you may have to check the ship rate quotes and taxation calculations too so that the resulting invoice is all generated in the same currency. In the invoice builder, there is a task to assert the currency code. If it does not find one, it will add the default currency (from memory so you need to check me on that).
If you are converting everything to the base currency (back office setting) and only displaying prices in various currencies then you would not need to worry about it.
Hi Rusty,
Is there a particular key name on extended data i would need to assign the currency code for?
In AddToBasket i have the following code to add an item:
extendedData.SetValue("Currency", CustomHelper.GetCurrency().CurrencyCode); this.Basket.AddItem(product.Name, product.Sku, 1, CustomHelper.GetProductPrice(model.Product.Key), extendedData);
CustomHelper.GetCurrency() returns an ICurrency which takes in context the current logged in member and their preference for there currency and CustomHelper.GetProductPrice() takes the products guid, and based on the members currency and if they have the discounted price returns the products price in that currency (eg. apply the currency calculation so if an item was £400 would return $520 )
Thanks,
Paul
@Paul - yes sorry. Checkout out the reserved ExtendedData constants:
https://github.com/Merchello/Merchello/blob/1.9.0/src/Merchello.Core/Constants-ExtendedDataKeys.cs
Hi Rusty,
This I have amended the AddToBasket to this, however viewing the basket i can see the product totals tally with my overridden price however it is still showing the currency symbol £ rather than $
Thanks,
Paul
In the Bazaar, I am just using the back office setting to display the currency symbol and have a bunch of extension methods
https://github.com/Merchello/Merchello/blob/1.9.0/src/Merchello.Bazaar/ModelExtensions.cs
that write out the format in the views.
The StoreSettingService has a method
Which can be used to retrieve the current symbol.
The symbol can then be accessed like
You should be able to use the Bazaar extensions from there. Just select the one that is applicable to whatever object you are working with.
Thanks Rusty, I am using that service to get to get the symbols etc, I will modify the basket markup to get this. Will the back office use the extended data for currency or will I need to make adjustments there?
Hi Rusty,
On checkout now i now get an "Invoice is being created with line items costed in different currencies." exception when it produces the invoice which i guess is to be expected as the stores default currency is different to the currency of the product i added to the basket.
Delving into the code i can see there is a tax item which is set to GBP but all the products in the basket are USD. The products in question is not taxable.
Is there anything that i have missed here?
Paul
Hi Paul,
The invoice should fail to build if the validating task finds more than one currency.
You can see how that works here: https://github.com/Merchello/Merchello/blob/1.9.0/src/Merchello.Core/Chains/InvoiceCreation/ValidateCommonCurrency.cs
My guess is the product currency code is not present in the ExtendedDataCollection (or with an incorrect key) and the task above is adding the store default currency code.
That being said an exception should be thrown at some point because of multiple currency codes. I probably missed handling that case in the Bazaar starter since I was only ever doing a single currency.
Hi Rusty,
I have just tried to debug PerformTask in ValidateCommonCurrency.
So in my example i have added 2 products, however in PerFormTask value.Items that it selects the currencies from has 3 items my two products which are both USD in the extended data. I was also using the constant for the currency code key "Constants.ExtendedDataKeys.CurrencyCode" to ensure i didn't make a typo on them.
The third item is Tax which is defaulting to the stores base currency.
I was under the impression i can just add an item to the basket and call save, should i be doing anything about the tax situation? I was assuming there be any need for a Tax line item as the store is not applying tax.
Paul
Ok, that makes sense. The tax provider is calculating taxes as 0 and it looks like I still mistakenly have the switch ApplyTaxesToInvoice as internal in the SalePreparationBase class. I'll change that for version 1.9.1 so that it can be set in your controller.
I created an issue here for that: http://issues.merchello.com/youtrack/issue/M-743
For the time being so that you are not stuck, comment out the apply taxes task in the merchello.config file. That will skip that step and you should not get a tax line item.
is working on a reply...