UCommerce Extensions

Over the course of my first Sitecore 8 and UCommerce integration project I’ve created some extension methods that might be useful in other projects. Most of these are straight forward so let’s dive into it.

Basket

the culture difference

In case you have different stores for different you need to keep your baskets separated. You cannot have a basket with product X with Euro as currency and product Y with Dollars as currency. So what we decided to do is delete the existing basket when the visitor browses a different Country website. Our site had a country/language selector which allowed the visitor to do that.

The following code does just that. It checks if the basket culture corresponds with the SiteContext culture.

1
2
3
4
5
6
7
8
9
public static void EnsureBasketCulture(this Basket basket)
{

if (!basket.PurchaseOrder.CultureCode.Equals(SiteContext.Current.CurrentCulture.Name))
{
SiteContext.Current.OrderContext.ClearBasketInformation();
basket = SiteContext.Current.OrderContext.GetBasket();
basket.PurchaseOrder.Save();
}
}

Now in case you may not want to loose any basket data, so we want to save that. The following code adds a summary of the existing basket in an audit trail in the new one. Now you might be thinking you want to add the order lines to the new basket and you can do that. However it was out of scope for our project and it could lead you down the rabbit hole since you would have to check if the product is sold in the new country, the prices might be different between countries, not to mention taxes and so on.

This code is just example and you might want to be more defensive in your coding, it’s merely for reference.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public static void EnsureBasketCulture(this Basket basket)
{

if (!basket.PurchaseOrder.CultureCode.Equals(SiteContext.Current.CurrentCulture.Name))
{
string summary = string.Empty;
if (basket.PurchaseOrder != null && basket.PurchaseOrder.OrderLines.Any())
{
summary = string.Join(" | ", basket.PurchaseOrder.OrderLines.Select(
l => string.Format("{0} - #{1}", l.ProductName, l.Quantity)));
}
SiteContext.Current.OrderContext.ClearBasketInformation();
basket = SiteContext.Current.OrderContext.GetBasket();
basket.PurchaseOrder.Save();

var auditline = new OrderStatusAudit();
var order = basket.PurchaseOrder;
auditline.CreatedOn = DateTime.Now;
auditline.Message = string.Format("Country changed, new basket created: {0}", summary);
auditline.PurchaseOrder = order;
auditline.NewOrderStatus = basket.PurchaseOrder.OrderStatus;
auditline.Save();
order.AddOrderStatusAudit(auditline);
}
}

Payment method

the delivery date modification

In the Adyen payment method properties you can set standard shipping time. To be able to show the estimated delivery date of the order, we added the following extension method. It simply retrieves the properties from the payment method and corrects the date (adding only business days).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
private static DateTime GetDateAdjustment(PaymentMethod paymentMethod)
{

AdyenPaymentMethodProperties properties = new AdyenPaymentMethodProperties(paymentMethod.PaymentMethodProperties);
string shipDays = properties.ShipDays;
string shipHours = properties.ShipHours;
string shipMinutes = properties.ShipMinutes;

DateTime shipBefore = DateTime.Now;
if (!string.IsNullOrEmpty(shipDays))
{
shipBefore = shipBefore.AddBusinessDays(int.Parse(shipDays));
}

if (!string.IsNullOrEmpty(shipHours))
{
shipBefore = shipBefore.AddHours(int.Parse(shipHours));
}

if (!string.IsNullOrEmpty(shipMinutes))
{
shipBefore = shipBefore.AddMinutes(int.Parse(shipMinutes));
}

return shipBefore;
}

the property enquiry

The following extension method avoids duplicating the same code each time you need to access a payment method property. I also saves a lot of time trying to figure out how to do that again.

1
2
3
4
public static string GetPaymentMethodPropertiesValue(this ICollection<PaymentMethodProperty> properties, string key)
{

return properties.FirstOrDefault(p => p.DefinitionField != null && p.DefinitionField.Name.Equals(key)).Value;
}

PuchaseOrder

the American way As we had quite a lot of divergent logic for the US, I added this extension method that inspects the culture to find out if the order is in place in/for the US.

1
2
3
4
public static bool IsAmerican(this PurchaseOrder order)
{

return order.CultureCode.Equals("en-US");
}

the pipeline verification

Sometimes something happens, some times it’s bad. let’s leave it at that. I needed to check if the Checkout pipeline was executed or not, so here’s the code.

1
2
3
4
5
6
7
8
9
10
public static bool CheckoutPipelineHasAlreadyBeenExecutedForPayment(this PurchaseOrder order)
{

if (order.OrderStatus.OrderStatusId == (int)OrderStatusCode.Basket ||
order.OrderStatus.OrderStatusId == (int)OrderStatusCode.Processing)
{
return false;
}

return true;
}

the order number assignment

In case you want to assign an order number at some random point in the order process, this extension method will let you do that. We used it to assign the order number when the customer reaches the confirmation page and the payment was authorised.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public static void AssignOrdernumberIfEmpty(this PurchaseOrder order,string source = "PurchaseOrderExtension")
{
if (string.IsNullOrEmpty(order.OrderNumber))
{
try
{
var numberSeriesService = ObjectFactory.Instance.Resolve<INumberSeriesService>();
order.OrderNumber =
numberSeriesService.GetNumber(order.ProductCatalogGroup.OrderNumberSerie.OrderNumberName);
Log.Info(string.Format("Assigning order number to order. id:
{0}, number {1}", order.OrderId, order.OrderNumber),source);
order.Save();
}
catch (Exception ex)
{
Log.Error(string.Format("An error occured assingning the order ordernumber to order (ID): {0}"
,order.OrderId) ,ex);
}
}
}

Custom Model

the currency format issue

The UCommerce version we were using 6.x had a fixed currency format. So I wrote this class so I could make my own money. You can provide a currency format to the ToString method or use the default one. In our project we only displayed decimals when they’re not zero.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public class MyMoney : Money
{
public MyMoney(decimal value, CultureInfo culture, Currency currency)
: base(value, culture, currency)
{

}

public MyMoney(decimal value, Currency currency) : base(value, currency)
{

}

public MyMoney(Money money) : base(money.Value, money.Culture, money.Currency)
{


}

//uCommerce ToString method has a fixed currency format
public string ToString(string format)
{

if (format.IsNullOrEmpty())
{
format = "C0";
}
string cultureSpecificStringValue = Value.ToString(format, Culture);
return cultureSpecificStringValue;
}


//should return the value with 2 decimals if it is not a whole number
public override string ToString()
{

string format = "C0";
if (Value - Math.Truncate(Value) > 0)
{
format = "c2";
}
return ToString(format);
}
}

the money maker

Here’s how you would use that. Let’s say you’re displaying the cost of a product in an orderline. Since the ultimate goal of e-commerce it to turn the product value into cash, we can do that in code. Let’s convert the product cost to MyMoney.

1
2
string displayValue = new MyMoney(orderline.Total.GetValueOrDefault(), 
orderline.PurchaseOrder.BillingCurrency).ToString();