OnProviderCallback method
This article explains how to handle the payment provider callback.
When the control is transferred to the payment provider site, the end customer enters the credit card information and confirms the purchase. Then the payment provider will return the control back to Litium by redirecting to the responseUrl (or cancel url if the user cancels the order). These url's are sent to the payment provider in a previous initialization call, or when the HTTP post to the provider site is done.
IPaymentProvider.OnProviderCallback is not always called
The IPaymentProvider.OnProviderCallback method is called only if the control is previously transfered to the payment provider site. In web service mode certain payment providers, such as Klarna and Handelsbanken Ecster, do not transfer control ourside Litium but rely only on web service calls. In such cases this method is not called.
IPaymentProvider.OnProviderCallback method parameters
- queryString: Contains the order reference and payment info references to identify the order and the payment, its status and security hashes. Note that the original query string is being decoded by the Litium API and the order and the PaymentInfo object is already initialized when this method is called. Therefore, the PaymentInfo object that is in the PaymentProviderBase class is already initialized.
- isSuccess: is set to true if the provider redirected to the response url and set to false if the provider redirected to the cancel url. Important: isSuccess=true does not mean that the transaction status is a success. The transaction status is a payment provider dependent parameter which is always communicated through the queryString. Therefore, the transaction can either be a success or a failure even if the isSuccess parameter is true. However, if the parameter is false, the transaction has definitely been cancelled by the user.
- token: This will always be the admin token with highest level of permissions, because the method is being called by the API. The API verifies the hashes from the original call from the payment provider to guarantee that it has not been manupilated.
Implementation
The basic implementation is to check the current payment status. Since this call comes from the payment provider, the payment status in Litium needs to be updated based on the actual transaction status.
The following example sets the payment status and shows how to set the return result.
/// <summary>
/// Called from when payment provider calls back to Litium Studio as part of the checkout flow.
/// </summary>
/// <param name="queryString">The query string.</param>
/// <param name="isSuccess">if set to <c>true</c> [is success].</param>
/// <param name="token">The token.</param>
/// <returns></returns>
/// <exception cref="System.NotImplementedException"></exception>
public ProviderCallbackResult OnProviderCallback(System.Collections.Specialized.NameValueCollection queryString, bool isSuccess, Foundation.Security.SecurityToken token)
{
//initialize the return value to be a failure, and we set this to a success if transaction status is a success.
var result = new ProviderCallbackResult(false, string.Empty);
//information received in query string.
//these information and its keys will be different from provider to provider. Following is a sample.
var transactionRef = queryString["ref"];
var transactionStatus = queryString["status"];
PaymentInfo.SetTransactionReference(transactionRef, token);
if (isSuccess)
{
//provider redirected to response url. We need to check transaction status in the query string.
if (transactionStatus == "Success")
{
//change result to notify a success.
result.Success = true;
if (PaymentInfo.PaymentStatus == PaymentStatus.ExecuteCharge)
{
PaymentInfo.SetPaymentStatus((short)PaymentStatus.Paid, token);
}
else if (PaymentInfo.PaymentStatus == PaymentStatus.ExecuteReserve)
{
PaymentInfo.SetPaymentStatus((short)PaymentStatus.Reserved, token);
}
}
else if (transactionStatus == "Pending")
{
PaymentInfo.SetPaymentStatus((short)PaymentStatus.Pending, token);
//change result to notify a success.
result.Success = true;
//but set the message to notify its still pending.
//Note: display of this message is entirely dependent on how the Checkout flow page template is done.
result.ErrorMessage = "payment is still pending";
}
else
{
if (PaymentInfo.PaymentStatus == PaymentStatus.ExecuteCharge)
{
PaymentInfo.SetPaymentStatus((short)PaymentStatus.ChargeFailed, token);
}
else if (PaymentInfo.PaymentStatus == PaymentStatus.ExecuteReserve)
{
PaymentInfo.SetPaymentStatus((short)PaymentStatus.ReserveFailed, token);
}
//note that this is a failure, change the return result message.
//Note: display of this message is entirely dependent on how the Checkout flow page template is done.
result.ErrorMessage = "payment failed";
}
}
else
{
//provider redirected to the cancel url.
PaymentInfo.SetPaymentStatus((short)PaymentStatus.Cancelled, token);
//record result as a user friendly message in the paymentInfo external message.
//this message is visible when viewing paymentinfo in the LitiumStudio backoffice.
PaymentInfo.AppendExternalMessage(DateTime.Now.ToString(CultureInfo.InvariantCulture) + " user cancelled", token);
//when the return result success is set to false, its message will be displayed to the end user.
//Note: display of this message is entirely dependent on how the Checkout flow page template is done.
result.ErrorMessage = "user cancelled"; //in practice, provide language transactions.
}
return result;
}