custom Adyen skin

When creating my first skin for Adyen I ran into the problem of translations. Adyen has got it’s language files which you can modify and update as much as you want. But here’s the kicker, once uploaded you cannot reach those files from your skin. This means that if you created a nice header with some text that needs translating, you’ll have to do it yourself.

So that’s what I did. I added some custom JSON files containing the required translations. They are stored as text files with the locale in the file name. I kept the name resources for convenience. example: resources_it_IT.txt Note that the hyphen is replaced with an underscore.

Shortcuts

Because I had trouble uploading these files in separate folders, I keep them in my javascript folder for now. I took another shortcut in the JSON (again as a proof of concept). The JSON structure is super simple and contains key/value pairs. The keys are actually the CSS selectors I will use to find the location of the text that needs to be translated This results in a somewhat dirty file, but keeps everything nice and simple.

1
2
3
4
{
".contact": "Questions? Call us .... ",
"h2" : "CHECKOUT",
}

Script with jQuery

The javascript itself is also quite simple. I get the shopperLocale from the form that gets rendered inside the skin and default it to en-GB. Next I set the link on the logo on my skin to homepage in the correct language. Before getting the file, you need to construct a url which points to the correct directory. This has the following format: /sf/[SKINCODE]/js/[RESOURCE_FILE_NAME]

Finally I get the file with the needed translations via an AJAX call, loop through the data and use the key/value pairs to set my translation on the page. All of which gets executed when the page has finished loading. Since I already had jquery loaded for other parts, I used it for this code as well.

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
// determine correct locale
var locale = $('[name="shopperLocale"]').val();
if (locale == null || locale === "") {
locale = "en_GB";
}

// set logo url to correct language, example: http://www.YOURDOMAIN.com/en-gb/
$(".logo").attr("href", "http://www.YOURDOMAIN.com/" + locale.replace("_", "-") + "/");

// construct resource url
var resourceUrl = "/sf/kTcgNKNd/js/resources_" + locale + ".txt";

$.ajax({
url: resourceUrl,
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function(data) {
// loop through data and set translation text
$.each(data, function (key, val) {
$(key).html(val);
});
},
error: function(xhr, ajaxOptions, thrownError) {
console.log(xhr.status);
console.log(thrownError);
}
});

As a final note to this, make sure all links to files in your skin have the same structure as the resource url. I haven’t had much luck with relative url’s using ../ in them. For instance here’s what the part of my skin footer that loads jquery and my script.

1
2
<script src="/sf/kTcgNKNd/js/jquery.min.js"></script>
<script src="/sf/kTcgNKNd/js/checkout.js></script>

Display custom data

Besides the need to display a large amount of data on the HPP (Hosted Payment Page), the customer wanted to display an overview of the order. The problem is that all data you submit to the HPP should be a encoded in the Merchant Signature and the more fields you add the more complicated everything gets. The solution is to make a dictionary of strings and serialize the object as json. This way you can pass it all as the orderdata field.

another way to do it is to build the html using some sort of string builder and pass that, perhaps url encode it before serializing just to be sure.

To decode it on the Adyen skin I used the following script. Since I used a dictionary of type dictionary, I get name / value pairs after de-serialization so I added span tags to the skin which used the same names for their ID attribute.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var orderDataString = decodeURIComponent($("[name='orderData']").val());
var orderJson = $.parseJSON(orderDataString);

var cost = $("[name='paymentAmount']").val();
if (cost !== "" &amp;&amp; cost !== 0) {
cost = cost / 100;
}
$("#totalCost").html(cost + " " + $("[name='currencyCode']").val());

$.each(orderJson, function (index, obj) {
if ($("#" + obj.Name) != undefined && obj.Value != undefined
&& obj.Value !== "") {
var val = obj.Value.split("+").join(" ");
if (obj.Name === "billingPhone") {
val = "+" + val.substring(1, val.length - 1);
}
if (obj.Name === "backLink") {
$("#" + obj.Name).attr("href", val);
} else {
$("#" + obj.Name).html(val);
}
}
});

In our case we were integrating with Sitecore and uCommerce. When submitting our first tests to the HPP’s we quickly realized it was a bust. As it turned out uCommerce was still using the SHA1 hashing to calculate the HMAC for the merchant signature. We requested the code they used and adapted it to use the SHA256 hashing. We gave our code back, so in case you need it before the next release, just ask your uCommerce buddy and he can hook you up.

In case you have some other .NET implementation, I made a pull request to the Adyen github, which was since added to their examples. Here you can find the new HPP example.

3D security

If you want to add extra security, Adyen can activate the 3D secure option. For the shopper this means another form to fill out after the completion of the HPP. This extra page is provided by the card issues (aka the bank) so you don’t have any control over it. This includes the layout if you were wondering.

Our customer wanted to be extra safe, so we had Adyen enabe the 3D secure option. And that’s when it all blew up in my face. When you clicked on the pay button on the HPP page it started flashing. I soon realized this was the javascript that tried to add in the translations. It didn’t have the correct data however since it was the HPP and not our generated payment page that was being submitted.

To make matters worse there wasn’t any obvious indication why this was happening as everything worked fine without the 3D secure. After inspecting the skin closely I noticed a few issues. The first being we had some elements with the ID’s that Adyen’s was using for their elements on the HPP.

The biggest issue was that we added a form element in our skin which had the “pageform” as ID. So you can probably guess what happened. Adyen inserts a form element of it’s own with the same id. In fact the form they add, was inserted inside our form element. They’re using javascript to submit the form with id “pageform” and so it all came tumbling down.

In hindsight we didn’t need the form, so we could easily solve the problem by removing the form from our skin and using different id’s.

Another issue that can occur is that the payment is authorised but the issuer has some sort of issue. this results in a correct payment, without 3D secure. In that case it’s up to your customer to decide what to do. Adyen can set up rules to support two scenario’s.

Either the payment is accepted and the shopper is redirected to your confirmation/success page or the fraud score can be raised for those cases and the shopper is redirected to your cancel page.