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.
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();
}
}
}
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).
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);
}
}
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.