One-click purchase
End users who are already logged in to the website can save their credit cards at Dibs when they make the first purchase, and then use the saved credit card for subsequent purchases (if logged in), without having to re-enter the card details. Dibs calls this a "subscription".
Enable subscriptions
To enable subscriptions contact Dibs to enable it for your merchant account. Then enable the saveCreditCardsAtDibs option in the Litium.Studio.AddOns.Dibs.dll.config.
You should then modify your checkout page to allow the users to choose the saved cards on subsequent purchases.
Checkout page modifications
You may use the webcontrols coming with the Dibs plugin to show the user a drop down list to choose from saved cards, or build your own radio buttons.
The following example shows how the Litium Accelerator B2C code is modified to use these webcontrols.
1. Modify web.config
Modify the web.config to include the tag prefix. Add the following in the section system.web > pages > controls.
<add tagPrefix="Dibs" namespace="Litium.Studio.AddOns.Dibs.WebControls" assembly="Litium.Studio.AddOns.Dibs"/>
2. Modify the ascx file
Modify the wwwroot\Site\CMS\Templates\B2C\UserControls\CheckOut\PaymentMethodSelection.ascx as shown below.
<div class="paymentmethodscontainer hide-for-small">
<Ecom:PaymentMethodRepeater runat="server" ID="PaymentMethodRepeater" OnItemDataBound="PaymentMethodRepeaterOnItemDataBound">
<ItemTemplate>
<asp:Panel runat="server" ID="PaymentMethodContainer">
<div class="paymentmethod row">
<div class="large-10 column">
<div class="checkbox">
<asp:RadioButton data-customformname="PaymentMethod" OnCheckedChanged="RadioButtonOnChecked" runat="server" AutoPostBack="True" id="PaymentMethodRadioButton" />
</div>
<div class="name">
<strong>
<asp:Label runat="server" AssociatedControlID="PaymentMethodRadioButton">
<Ecom:PaymentMethodDisplayName runat="server" />
</asp:Label>
</strong>
</div>
<div class="cost">
<Ecom:ShoppingCartPanel runat="server">
<Klarna:IsKlarnaPartPayment runat="server">
<OnTrue>
<Klarna:IsPartialPaymentsAsSeperateMethods runat="server" OnPreRender="KlarnaExistPreRender">
<OnFalse>
<Klarna:PartPaymentOptionsDropDownList ID="PartPaymentOptionsDropDownListKlarna" runat="server"
Visible="true" AutoPostBack="true" DisplayCurrencySymbol="true" OnSelectedIndexChanged="PartPaymentChangedKlarna" />
</OnFalse>
</Klarna:IsPartialPaymentsAsSeperateMethods>
</OnTrue>
<OnFalse>
-
<web:WebSiteString Name="PaymentMethodCost" runat="server" />
<Ecom:PaymentMethodCost DisplayCurrencySymbol="True" runat="server" />
</OnFalse>
</Klarna:IsKlarnaPartPayment>
<Klarna:PartPaymentOptionPanel runat="server">
<table>
<tr>
<td>CampaignCode</td><td><Klarna:PartPaymentOptionCampaignCode runat="server" /></td>
</tr>
<tr>
<td>UseCase</td> <td><Klarna:PartPaymentOptionUseCase runat="server" /></td>
</tr>
</table>
</Klarna:PartPaymentOptionPanel>
<Dibs:CanSaveCardAtDibs runat="server">
<OnTrue>
<Dibs:HasSavedCards runat="server" OnPreRender="DibsExistPreRender">
<OnTrue>
<Dibs:SavedCardsDropDownList ID="SavedCardsDropDownList" runat ="server" ShowPayWithNewCardOption="true" AutoPostBack="true" OnSelectedIndexChanged="PaymentOptionsChanged" />
</br>
<Dibs:SavedCardInfoRepeater runat="server">
<ItemTemplate>
<Dibs:SavedCardInfoCCCategory runat="server" />
<Dibs:SavedCardInfoCCPart runat="server" />
<Dibs:SavedCardInfoCCPrefix runat="server" />
<Dibs:SavedCardInfoCCType runat="server" />
<Dibs:SavedCardInfoExpM runat="server" />
<Dibs:SavedCardInfoExpY runat="server" />
</br>
</ItemTemplate>
</Dibs:SavedCardInfoRepeater>
</OnTrue>
</Dibs:HasSavedCards>
<Dibs:SaveCardAtDibs Text="SaveCard at dibs" runat="server" OnCheckedChanged="PaymentOptionsChanged" />
</OnTrue>
</Dibs:CanSaveCardAtDibs>
</Ecom:ShoppingCartPanel>
</div>
<div class="description">
<Ecom:PaymentMethodDescription runat="server">
</Ecom:PaymentMethodDescription>
</div>
</div>
<div class="large-2 column">
<Ecom:PaymentMethodImage runat="server" RenderSize="False" />
</div>
</div>
</asp:Panel>
</ItemTemplate>
</Ecom:PaymentMethodRepeater>
</div>
3. Modify the code behind
Modify wwwroot\site\cms\templates\b2c\usercontrols\checkout\paymentmethodselection.ascx.cs to allow the drop down box to correctly postback and work inside the update panel.
protected void PaymentOptionsChanged(object sender, EventArgs e)
{
var partPaymentsList = sender as WebControl;
var parent = partPaymentsList.Parent;
while (parent.ID != "PaymentMethodContainer")
{
parent = parent.Parent;
}
var paymentMethodRadioButton = (RadioButton)parent.FindControl("PaymentMethodRadioButton");
var paymentMethodId = paymentMethodRadioButton.Attributes[_paymentMethodId];
ChangePaymentMethod(paymentMethodId);
}
protected void DibsExistPreRender(object sender, EventArgs e)
{
var hasDibsSavedCards = (DibsCtrl.HasSavedCards)sender;
if (hasDibsSavedCards.IsTrue)
{
foreach (Control control in hasDibsSavedCards.Controls)
{
if (control is OnTrueFalseControl.OnTrueFalseTemplateItem)
{
var savedCardsDropDown = (DibsCtrl.SavedCardsDropDownList)control.FindControl("SavedCardsDropDownList");
Control parent = savedCardsDropDown.Parent;
while (!(parent is PaymentMethodRepeaterItem))
{
parent = parent.Parent;
}
if (parent is PaymentMethodRepeaterItem)
{
var paymentMethodId = ((PaymentMethodRepeaterItem)parent).CurrentPaymentMethod.ID;
PaymentInfoCarrier paymentInfoCarrier =
CurrentState.Current.ShoppingCart.OrderCarrier.PaymentInfo.FirstOrDefault();
if (paymentInfoCarrier != null)
{
PaymentMethod selectedPaymentMethod =
ModuleECommerce.Instance.PaymentMethods.Get(paymentInfoCarrier.PaymentMethod,
paymentInfoCarrier.PaymentProvider,
WebControlState.Token);
if (selectedPaymentMethod.ID != paymentMethodId)
{
savedCardsDropDown.Style["display"] = "none";
savedCardsDropDown.Attributes["data-customforms"] = "disabled";
}
var container = (Panel)parent.FindControl("PaymentMethodContainer");
savedCardsDropDown.DataBind();
if (savedCardsDropDown.Items.Count <= 0)
{
container.Style["display"] = "none";
}
else
{
container.Style["display"] = "block";
}
}
}
}
}
}
}
The below is a screenshot generated from sample code above.

Deleting saved cards
You can remove the saved cards from the user by calling the DibsProvider.RemoveDibsCardInfo() method.
/// <summary>
/// Removes the dibs card information.
/// </summary>
/// <param name="personId">The person identifier.</param>
/// <param name="cardInfo">The card information.</param>
public static void RemoveDibsCardInfo(Guid personId, CardInfo cardInfo)
The CardInfo parameter passed is the databound items of the SavedCardInfoRepeater web control.
Obtaining a list of saved cards for a logged in user
You may get this list of saved cards by calling the api method DibsProvider.GetDibsSavedCreditCardInfo.
/// <summary>
/// Gets the dibs saved credit card information.
/// </summary>
/// <param name="personId">The person identifier.</param>
/// <returns></returns>
public static List<CardInfo> GetDibsSavedCreditCardInfo(Guid personId)
Usage:
var savedCards = DibsProvider.GetDibsSavedCreditCardInfo(CurrentState.Current.Token.UserID);
The following code is the SavedCardInfoRepeater control source for reference.
using Litium.Foundation;
using Litium.Foundation.Modules.WebControls;
using System;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace Litium.Studio.AddOns.Dibs.WebControls
{
/// <summary>
/// Repeater for Dibs saved credit card info.
/// If datasource is not set, will attempt to databind if the current logged in user can be found.
/// </summary>
public class SavedCardInfoRepeater : TypedRepeater<CardInfo, SavedCardInfoRepeaterItem>
{
//to check whether control is already databound.
private bool _dataBound;
/// <summary>
/// Renders the control to the specified HTML writer.
/// </summary>
/// <param name="writer">The <see cref="T:System.Web.UI.HtmlTextWriter"/> object that receives the control content.</param>
protected override void Render(HtmlTextWriter writer)
{
if (!_dataBound)
DataBind();
base.Render(writer);
}
/// <summary>
/// Databind. If datasource is not set, will attempt to databind for the saved cards of current logged in user..
/// </summary>
public override void DataBind()
{
_dataBound = true;
if (DataSource == null)
{
//obtain the part payment options for current order carrier., if available.
try
{
if (!WebControlState.CMS.CurrentState.Token.IsAnonymousUser)
{
DataSource = DibsProvider.GetDibsSavedCreditCardInfo(WebControlState.CMS.CurrentState.Token.UserID);
}
}
catch (Exception ex)
{
Solution.Instance.Log.CreateLogEntry("Dibs: could not obtain saved card info", ex, Foundation.Log.LogLevels.ERROR);
}
}
base.DataBind();
}
}
/// <summary>
/// Saved Card information repeater item.
/// </summary>
public class SavedCardInfoRepeaterItem : System.Web.UI.WebControls.RepeaterItem, ICardInfoIntroducer
{
/// <summary>
/// Initializes a new instance of the <see cref="SavedCardInfoRepeaterItem"/> class.
/// </summary>
/// <param name="itemIndex">The index of the item in the <see cref="T:System.Web.UI.WebControls.Repeater" /> control from the <see cref="P:System.Web.UI.WebControls.Repeater.Items" /> collection of the control.</param>
/// <param name="itemType">One of the <see cref="T:System.Web.UI.WebControls.ListItemType" /> values.</param>
public SavedCardInfoRepeaterItem(int itemIndex, ListItemType itemType)
: base(itemIndex, itemType)
{
}
/// <summary>
/// Gets the Current CardInfo
/// </summary>
public CardInfo CurrentCardInfo
{
get
{
return (CardInfo)DataItem;
}
}
}
}
Paying with a saved card using the API (without using the SavedCardsDropDownList web control)
If you wish to use the API directly to pay with a saved card, follow the steps below.
- Obtain a list of saved cards using the DibsProvider.GetDibsSavedCreditCardInfo() method, display the list to the user, and allow the user to select a saved card.
- When the user has selected a card, add the DibsProvider.DibsVerifyId CheckoutflowInfo value as shown below. For example, the following code shows a typical selected index changed event that will be fired when a user selects an option, and what should be done in that event.
/// <summary>
/// When selected index changed.
/// </summary>
/// <param name="e">A <see cref="T:System.EventArgs"/> that contains the event data.</param>
protected override void OnSelectedIndexChanged(EventArgs e)
{
base.OnSelectedIndexChanged(e);
if (SelectedIndex >= 0)
{
CurrentState.Current.ShoppingCart.CheckoutFlowInfo.SetValue(DibsProvider.DibsVerifyId, SelectedItem.Value);
}
}
- If you have a "Pay using a new card" option, the value of DibsProvider.DibsVerifyId should be zero. Below is an example.
//if paying by new card option is selected.
CurrentState.Current.ShoppingCart.CheckoutFlowInfo.SetValue(DibsProvider.DibsVerifyId, "0");
- You should aslo notify before you call the ExecutePayment method, whether the user has authorized to save the card by setting the DibsProvider.SaveCard checkout flow info key to true. Typically, you would display a checkbox for the user to decide whether to save the card or not. A typical CheckedChanged event would look as follows:
/// <summary>
/// Raises the <see cref="E:System.Web.UI.WebControls.CheckBox.CheckedChanged" /> event of the <see cref="T:System.Web.UI.WebControls.CheckBox" /> control. This allows you to handle the event directly.
/// </summary>
/// <param name="e">A <see cref="T:System.EventArgs" /> that contains the event data.</param>
protected override void OnCheckedChanged(EventArgs e)
{
CurrentState.Current.ShoppingCart.CheckoutFlowInfo.SetValue(DibsProvider.SaveCard, Checked.ToString(CultureInfo.InvariantCulture));
base.OnCheckedChanged(e);
}
- You can call the PaymentInfo.ExecutePayment method as usual after the above changes. A typical ExecutePayment method in the checkout page code would look as follows.
private void ExecutePayment(PaymentInfo paymentInfo)
{
try
{
//Flow 1: if you are using an existing saved card, following call is made in your users saved card selection event.
//CurrentState.Current.ShoppingCart.CheckoutFlowInfo.SetValue(DibsProvider.DibsVerifyId, CardInfo.VerifyID);
//Flow 2: if you want a new card saved., following two calls are made in your event handlers.
//CurrentState.Current.ShoppingCart.CheckoutFlowInfo.SetValue(DibsProvider.DibsVerifyId, 0);
//CurrentState.Current.ShoppingCart.CheckoutFlowInfo.SetValue(DibsProvider.SaveCard, true);
ExecutePaymentResult result = paymentInfo.ExecutePayment(CurrentState.Current.ShoppingCart.CheckoutFlowInfo, CurrentState.Current.Token);
//paymentInfo.ExecutePayment() returns here only if it is Flow 1 above.
//if it is flow2, then it will redirect to Dibs site and will come back to Success url or Cancel Url.
if (result != null)
{
if(result is Litium.Studio.AddOns.Dibs.DibsPaymentResult)
{
var dibsResult = (Litium.Studio.AddOns.Dibs.DibsPaymentResult)result;
HandlePaymentResult(result.Success, result.ErrorMessage + ": " + dibsResult.DibsResultCode + " " + dibsResult.DibsReplyText);
}
else
{
HandlePaymentResult(result.Success, result.ErrorMessage);
}
}
}
catch (ShoppingCartItemInvalidException cartInvalid)
{
ErrorPanel.AddAndShowErrorMessages(String.Format("{0}: {1}",
CurrentState.Current.WebSite.Strings[CheckOutStringConstants.StringPaymentUnsuccessful],
Server.HtmlEncode(cartInvalid.Message)));
}
catch (PaymentProviderException ex)
{
ErrorPanel.AddAndShowErrorMessages(String.Format("{0}, {1}: {2}",
CurrentState.Current.WebSite.Strings[CheckOutStringConstants.StringPaymentUnsuccessful],
CurrentState.Current.WebSite.Strings[CheckOutStringConstants.StringExternalMessage],
Server.HtmlEncode(ex.Message)));
ShoppingCartPanel.RebindShoppingCart();
}
catch (ArgumentOutOfRangeException)
{
ErrorPanel.AddAndShowErrorMessages(CurrentState.Current.WebSite.Strings[CheckOutStringConstants.StringPaymentUnsuccessful]);
ShoppingCartPanel.RebindShoppingCart();
}
}