"Sign up and login" when using Klarna Checkout

The accelerator has a nifty “sign up and login” feature in the default checkout. What’s the easiest way to recreate this functionality when using Klarna Checkout (KCO)?

I can’t find any code being executed during the checkout flow (strangely) that would ultimately lead to the CheckoutService.RegisterNewUser method.

Litium version: 7.6.2

Klarna supports additional check boxes in their checkout. In UpdateDataSentToKlarna you can configure any custom check box you prefer.

//Set the checkout options here.
klarnaCheckoutOrder.CheckoutOptions = new CheckoutOptions
{
	AllowSeparateShippingAddress = true,
	ColorButton = "#ff69b4",
	DateOfBirthMandatory = true,
	AdditionalCheckboxes = new List<AdditionalCheckboxV2>()
	{
		new AdditionalCheckboxV2
		{
			Id = CheckoutConstants.KcoSignUp,
			Text = "js.checkout.customerinfo.signupandlogin".AsWebSiteString(),
			Checked = false,
			Required = false,
		}
	}
};

The box will appear at the bottom of Klarnas iframe:

You can then access the box in the KCO order, for example in the Confirmation callback:

try
{
	var klarnaCheckout = CreateKlarnaCheckoutApi(accountId);
	var widget = _paymentService.GetPaymentWidget(klarnaCheckout.PaymentProviderName);
	var checkoutOrder = klarnaCheckout.FetchKcoOrder(transactionNumber.Split('/').Last());
	if (checkoutOrder != null)
	{
		_paymentWidgetService.PlaceOrder(new PaymentWidgetOrder(klarnaCheckout, checkoutOrder), true);
		this.Log().Debug("Confirmation completed.");

		var kcoOrder = checkoutOrder as LitiumKcoOrder;
		var signUpCheckBox = kcoOrder?.CheckoutOrder.MerchantRequested.AdditionalCheckboxes.FirstOrDefault(x => x.Id == CheckoutConstants.KcoSignUp);
		if (signUpCheckBox != null && signUpCheckBox.Checked)
		{
			this.Log().Debug("Sign up new user");
			// I made the method public and added it to the abstract class, if you're using 
			// prefixes you might need to create a new method since RouteRequestLookupInfo 
			// could be null in the callback
			_checkoutService.RegisterNewUser(); 
		}
	}
}
2 Likes

_requestModelAccessor.RequestModel is indeed null in GetPersonFromOrder in CheckoutServiceImpl.

I’m not sure what “prefixes” means in this context.

How would I go about resolving this? It seems I would have to get the order from the context somehow, new method or not.

Or could it be because of using Klarna debugging with modified hostnames?

Prefixes are when you’re adding a value before all site URLs, for example you have the domain www.example.com and on the Swedish channel you select that domain and add /se as a prefix. The callback from Klarna might not be able to resolve the channel since it calls a controller directly without the prefix so Litium can’t resolve the correct channel.

In your case it might be because of debugging, if that domain isn’t the primary domain for the channel.

You could implement your own method for registering the user that takes a parameter for the order carrier (this can be found on the checkoutOrder.OrderCarrier).

The _requestModelAccessor.RequestModel problem was indeed hostname related. Everything works fine now using your solution. Thanks!

1 Like

Since the user is created when the order is being confirmed and already placed, the order is not associated with the user. Is there a way to associate the order with the user after creating the user?

A solution could be to create your own RegisterNewUser method that takes the order carrier as a parameter and returns a Person object. Then you can fetch the order after it’s been placed and associate to the correct user.

Functionally it would be very similar to the default implementation. That implementation will result in an exception if the user already exists and in that flow an error message is presented to the user.

In this flow you could first try getting the user via SecurityContextService.GetPersonSystemId(string loginName) (login being their email) before trying to create it.

if (signUpCheckBox != null && signUpCheckBox.Checked)
{
	this.Log().Debug("Sign up new user");

	var person = _checkoutService.RegisterNewUser(kcoOrder.OrderCarrier);

	checkoutOrder = klarnaCheckout.FetchKcoOrder(transactionNumber.Split('/').Last());

	var order = ModuleECommerce.Instance.Orders.GetOrder(checkoutOrder.OrderCarrier.ExternalOrderID, Solution.Instance.SystemToken);
	if (order != null)
	{
		var carrier = order.GetAsCarrier();
		carrier.CustomerInfo.PersonID = person.SystemId;
		carrier.CustomerInfo.CustomerNumber = person.Id;
		order.SetValuesFromCarrier(carrier, Solution.Instance.SystemToken);
	}
}

Thanks.

The only real problem was that RegisterNewUser didn’t persist the carrier changes it makes, apparently since it only runs prior to order placement by default and assumes the carrier carries an unplaced order. So the only fix needed was to actually persist the PersonID and CustomerNumber changes when RegisterNewUser is run for an already-placed order.

The user stuff works as intended already, at least if I understand everything correctly.

1 Like

This topic was automatically closed 28 days after the last reply. New replies are no longer allowed.