public Uri Create() { var cart = _klarnaCheckoutUtils.GetCart(); var merchant = _klarnaCheckoutUtils.GetMerchant(); var supportedLocale = _klarnaCheckoutUtils.GetSupportedLocale(); var gui = _klarnaCheckoutUtils.GetGui(); var options = _klarnaCheckoutUtils.GetOptions(); var shippingAddress = _klarnaCheckoutUtils.GetShippingAddress(); var klarnaOrder = new KlarnaCheckoutOrder { Cart = cart, Merchant = merchant, Gui = gui, Options = options, ShippingAddress = shippingAddress, Locale = supportedLocale.Locale, PurchaseCountry = supportedLocale.PurchaseCountry, PurchaseCurrency = supportedLocale.PurchaseCurrency }; var dictData = klarnaOrder.ToDictionary(); var connector = Connector.Create(_klarnaSettings.SharedSecret, BaseUri); var order = new Klarna.Checkout.Order(connector); order.Create(dictData); var location = order.Location; var kcoOrderRequest = GetKcoOrderRequest(_workContext.CurrentCustomer, location); _klarnaRepository.Insert(kcoOrderRequest); return(location); }
private void SyncKlarnaAndNopOrder(KlarnaCheckoutEntity klarnaRequest, Customer customer, out Order nopOrder, out KlarnaCheckoutOrder klarnaCheckoutOrder) { nopOrder = _orderService.GetOrderByGuid(klarnaRequest.OrderGuid); var resourceUri = new Uri(klarnaRequest.KlarnaResourceUri); var apiOrder = _klarnaCheckoutPaymentService.Fetch(resourceUri); klarnaCheckoutOrder = KlarnaCheckoutOrder.FromApiOrder(apiOrder); // Create the order if it doesn't exist in nop. According to the Klarna Checkout // developer guidelines, one should only create the order if the status is // 'checkout_complete'. // https://developers.klarna.com/en/klarna-checkout/acknowledge-an-order if (nopOrder == null && klarnaCheckoutOrder.Status == KlarnaCheckoutOrder.StatusCheckoutComplete) { if (klarnaCheckoutOrder.Status == KlarnaCheckoutOrder.StatusCheckoutComplete) { klarnaRequest.Status = KlarnaCheckoutStatus.Complete; _repository.Update(klarnaRequest); } _klarnaCheckoutPaymentService.SyncBillingAndShippingAddress(customer, klarnaCheckoutOrder); nopOrder = CreateOrderAndSyncWithKlarna(klarnaRequest, customer, klarnaCheckoutOrder, resourceUri); } }
public void Acknowledge(global::Nop.Core.Domain.Orders.Order order) { try { var entity = _klarnaRepository.Table.First(x => x.OrderGuid == order.OrderGuid); var resourceUri = new Uri(entity.KlarnaResourceUri); var apiOrder = Fetch(resourceUri); var klarnaOrder = KlarnaCheckoutOrder.FromApiOrder(apiOrder); if (klarnaOrder.Status == KlarnaCheckoutOrder.StatusCheckoutComplete) { var updateData = new KlarnaCheckoutOrder { Status = KlarnaCheckoutOrder.StatusCreated, MerchantReference = new MerchantReference { OrderId1 = order.Id.ToString(CultureInfo.InvariantCulture), OrderId2 = order.OrderGuid.ToString() } }; var dictData = updateData.ToDictionary(); apiOrder.Update(dictData); order.AuthorizationTransactionId = klarnaOrder.Reservation; _orderService.UpdateOrder(order); } } catch (Exception ex) { throw new KlarnaCheckoutException("Error acknowledging Klarna order. Order Id: " + order.Id, ex); } }
public ActionResult ConfirmationSnippet(int orderId) { var order = _orderService.GetOrderById(orderId); if (order == null || order.PaymentMethodSystemName != KlarnaCheckoutProcessor.PaymentMethodSystemName) { return(Content(string.Empty)); } var klarnaRequest = _repository.Table.FirstOrDefault(x => x.OrderGuid == order.OrderGuid); if (klarnaRequest == null) { _logger.Warning(string.Format(CultureInfo.CurrentCulture, "KlarnaCheckout: Didn't find entity for order payed with Klarna. Order Id: {0}", orderId)); return(Content(string.Empty)); } try { var apiOrder = _klarnaCheckoutPaymentService.Fetch(new Uri(klarnaRequest.KlarnaResourceUri)); var klarnaOrder = KlarnaCheckoutOrder.FromApiOrder(apiOrder); if (klarnaOrder.Status != KlarnaCheckoutOrder.StatusCheckoutComplete && klarnaOrder.Status != KlarnaCheckoutOrder.StatusCreated) { _logger.Warning(string.Format(CultureInfo.CurrentCulture, "KlarnaCheckout: Cannot show confirmation snippet for Klarna order that is not marked as complete or created. Order Id: {0}; Status: {1}; Resource URI: {2}", orderId, klarnaOrder.Status, klarnaRequest.KlarnaResourceUri)); return(Content(string.Empty)); } return(Content(klarnaOrder.Gui.Snippet)); } catch (KlarnaCheckoutException kce) { _logger.Error(string.Format(CultureInfo.CurrentCulture, "KlarnaCheckout: Error when fetching and getting Klarna confirmation snippet. Order Id: {0}; Resource URI: {1}", orderId, klarnaRequest.KlarnaResourceUri), exception: kce, customer: order.Customer); } return(Content(string.Empty)); }
public bool Update(Uri resourceUri) { try { var klarnaOrderId = _klarnaCheckoutUtils.GetOrderIdFromUri(resourceUri); var cart = _klarnaCheckoutUtils.GetCart(); var options = _klarnaCheckoutUtils.GetOptions(); var connector = Connector.Create(_klarnaSettings.SharedSecret, BaseUri); var supportedLocale = _klarnaCheckoutUtils.GetSupportedLocale(); var klarnaOrder = new KlarnaCheckoutOrder { Cart = cart, Options = options, Locale = supportedLocale.Locale, PurchaseCountry = supportedLocale.PurchaseCountry, PurchaseCurrency = supportedLocale.PurchaseCurrency }; var order = new Order(connector, klarnaOrderId); var dictData = klarnaOrder.ToDictionary(); order.Update(dictData); return(true); } catch (Exception ex) { var exceptionJson = JsonConvert.SerializeObject(ex.Data); _logger.Warning(string.Format(CultureInfo.CurrentCulture, "KlarnaCheckout: Error updating Klarna order. Will try to create a new one. ResourceURI: {0}, Data: {1}", resourceUri, exceptionJson), exception: ex); } return(false); }
private void SyncCartWithKlarnaOrder(Customer customer, KlarnaCheckoutOrder klarnaCheckoutOrder) { var currentStoreId = _storeContext.CurrentStore.Id; var orderCurrency = _currencyService.GetCurrencyByCode(klarnaCheckoutOrder.PurchaseCurrency); if (orderCurrency != null) { _workContext.WorkingCurrency = orderCurrency; } ClearItemsInCart(customer, currentStoreId); ClearDiscountsAndShippingSelection(customer, currentStoreId); var physicalItems = klarnaCheckoutOrder.Cart.Items.Where(x => x.Type == CartItem.TypePhysical); var appliedCoupons = klarnaCheckoutOrder.Cart.Items.Where(x => x.Type == CartItem.TypeDiscount && x.HasOrderLevelDiscountCouponCode()); var appliedGiftCards = klarnaCheckoutOrder.Cart.Items.Where(x => x.Type == CartItem.TypeDiscount && x.IsDiscountGiftCardCartItem()); var appliedRewardPoints = klarnaCheckoutOrder.Cart.Items.Where(x => x.Type == CartItem.TypeDiscount && x.IsRewardPointsCartItem()); var checkoutAttributes = klarnaCheckoutOrder.Cart.Items.Where(x => x.Type == CartItem.TypeDiscount && x.IsCheckoutAttribtue()); var shippingItems = klarnaCheckoutOrder.Cart.Items.Where(x => x.Type == CartItem.TypeShippingFee); foreach (var physicalItem in physicalItems) { AddPhysicalItemToCart(customer, physicalItem, currentStoreId); var couponCodes = physicalItem.GetCouponCodesFromPhysicalCartItem(); foreach (var couponCode in couponCodes) { UseCouponCode(customer, couponCode); } } foreach (var coupon in appliedCoupons) { var couponCode = coupon.GetCouponCodeFromDiscountCouponCartItem(); UseCouponCode(customer, couponCode); } foreach (var giftCardCartItem in appliedGiftCards) { var giftCardId = giftCardCartItem.GetGiftCardIdFromDiscountGiftCardCartItem(); var giftCard = _giftCardService.GetGiftCardById(giftCardId); customer.ApplyGiftCardCouponCode(giftCard.GiftCardCouponCode); } if (appliedRewardPoints.Any()) { _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.UseRewardPointsDuringCheckout, true, currentStoreId); } var checkoutAttributesXml = GetSelectedCheckoutAttributesThatHasNotBeenSentToKlarna(customer, currentStoreId); foreach (var item in checkoutAttributes) { var ca = _checkoutAttributeService.GetCheckoutAttributeById(item.GetCheckoutAttributeId()); checkoutAttributesXml = _checkoutAttributeParser.AddCheckoutAttribute(checkoutAttributesXml, ca, item.GetCheckoutAttributeValue()); } _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.CheckoutAttributes, checkoutAttributesXml, currentStoreId); foreach (var shippingItem in shippingItems) { AddShippingItemToCart(customer, shippingItem, currentStoreId); var couponCodes = shippingItem.GetCouponCodesFromShippingItem(); foreach (var couponCode in couponCodes) { UseCouponCode(customer, couponCode); } } }
private Order CreateOrderAndSyncWithKlarna(KlarnaCheckoutEntity klarnaRequest, Customer customer, KlarnaCheckoutOrder klarnaCheckoutOrder, Uri resourceUri) { SyncCartWithKlarnaOrder(customer, klarnaCheckoutOrder); var processPaymentRequest = new ProcessPaymentRequest { OrderGuid = klarnaRequest.OrderGuid, CustomerId = customer.Id, StoreId = _storeContext.CurrentStore.Id, PaymentMethodSystemName = KlarnaCheckoutProcessor.PaymentMethodSystemName }; var placeOrderResult = _orderProcessingService.PlaceOrder(processPaymentRequest); // If you tamper with the cart after the klarna widget is rendered nop fails to create the order. if (!placeOrderResult.Success) { var errors = string.Join("; ", placeOrderResult.Errors); _logger.Error(string.Format(CultureInfo.CurrentCulture, "KlarnaCheckout: Klarna has been processed but order could not be created in Nop! Klarna ID={0}, ResourceURI={1}. Errors: {2}", klarnaCheckoutOrder.Id, klarnaRequest.KlarnaResourceUri, errors), customer: customer); _klarnaCheckoutPaymentService.CancelPayment(klarnaCheckoutOrder.Reservation, customer); throw new KlarnaCheckoutException("Error creating order: " + errors); } // Order was successfully created. var orderId = placeOrderResult.PlacedOrder.Id; var nopOrder = _orderService.GetOrderById(orderId); var klarnaPayment = _paymentService.LoadPaymentMethodBySystemName(KlarnaCheckoutProcessor.PaymentMethodSystemName); klarnaPayment.PostProcessPayment(new PostProcessPaymentRequest { Order = nopOrder }); var orderTotalInCurrentCurrency = _currencyService.ConvertFromPrimaryStoreCurrency(nopOrder.OrderTotal, _workContext.WorkingCurrency); // Due to rounding when using prices contains more than 2 decimals (e.g. currency conversion), we allow // a slight diff in paid price and nop's reported price. // For example nop rounds the prices after _all_ cart item prices have been summed but when sending // items to Klarna, each price needs to be rounded separately (Klarna uses 2 decimals). // Assume a cart with two items. // 1.114 + 2.114 = 3.228 which nop rounds to 3.23. // 1.11 + 2.11 is sent to Klarna, which totals 3.22. var allowedPriceDiff = orderTotalInCurrentCurrency * 0.01m; var diff = Math.Abs(orderTotalInCurrentCurrency - (klarnaCheckoutOrder.Cart.TotalPriceIncludingTax.Value / 100m)); if (diff >= allowedPriceDiff) { var orderTotalInCents = _klarnaCheckoutHelper.ConvertToCents(orderTotalInCurrentCurrency); nopOrder.OrderNotes.Add(new OrderNote { Note = string.Format(CultureInfo.CurrentCulture, "KlarnaCheckout: Order total differs from Klarna order. OrderTotal: {0}, OrderTotalInCents: {1}, KlarnaTotal: {2}, AllowedDiff: {3}, Diff: {4}, Uri: {5}", orderTotalInCurrentCurrency, orderTotalInCents, klarnaCheckoutOrder.Cart.TotalPriceIncludingTax, allowedPriceDiff, diff, resourceUri), DisplayToCustomer = false, CreatedOnUtc = DateTime.UtcNow }); } nopOrder.OrderNotes.Add(new OrderNote { Note = "KlarnaCheckout: Order acknowledged. Uri: " + resourceUri, DisplayToCustomer = false, CreatedOnUtc = DateTime.UtcNow }); _orderService.UpdateOrder(nopOrder); if (_orderProcessingService.CanMarkOrderAsAuthorized(nopOrder)) { _orderProcessingService.MarkAsAuthorized(nopOrder); // Sometimes shipping isn't required, e.g. if only ordering virtual gift cards. // In those cases, make sure the Klarna order is activated. if (nopOrder.OrderStatus == OrderStatus.Complete || nopOrder.ShippingStatus == ShippingStatus.ShippingNotRequired) { nopOrder.OrderNotes.Add(new OrderNote { Note = "KlarnaCheckout: Order complete after payment, will try to capture payment.", CreatedOnUtc = DateTime.UtcNow, DisplayToCustomer = false }); _orderService.UpdateOrder(nopOrder); if (_orderProcessingService.CanCapture(nopOrder)) { _orderProcessingService.Capture(nopOrder); } } } return(nopOrder); }
public ActionResult PaymentInfo() { Uri resourceUri; var customer = _workContext.CurrentCustomer; var storeId = _storeContext.CurrentStore.Id; var payment = _repository.Table .OrderByDescending(x => x.CreatedOnUtc) .FirstOrDefault(x => x.CustomerId == customer.Id && x.StoreId == storeId && x.Status == KlarnaCheckoutStatus.Pending); if (payment == null) { try { resourceUri = _klarnaCheckoutPaymentService.Create(); } catch (Exception ex) { var exceptionJson = JsonConvert.SerializeObject(ex.Data); _logger.Error(string.Format(CultureInfo.CurrentCulture, "KlarnaCheckout: Error creating Klarna order. Data: {0}", exceptionJson), exception: ex, customer: customer); ViewBag.StatusCode = ex.Data["http_status_code"]; return(View("~/Plugins/Motillo.KlarnaCheckout/Views/KlarnaCheckout/PaymentInfoError.cshtml")); } } else { try { resourceUri = new Uri(payment.KlarnaResourceUri); // If update of old Klarna order failed, try creating a new one. // Failure can occur for old orders or when toggling between live/test mode. if (!_klarnaCheckoutPaymentService.Update(resourceUri)) { payment.Status = KlarnaCheckoutStatus.Failed; _repository.Update(payment); resourceUri = _klarnaCheckoutPaymentService.Create(); } } catch (Exception ex) { var exceptionJson = JsonConvert.SerializeObject(ex.Data); _logger.Error(string.Format(CultureInfo.CurrentCulture, "KlarnaCheckout: Error updating Klarna order. ResourceURI: {0}, Data: {1}", payment.KlarnaResourceUri, exceptionJson), exception: ex, customer: customer); ViewBag.StatusCode = ex.Data["http_status_code"]; return(View("~/Plugins/Motillo.KlarnaCheckout/Views/KlarnaCheckout/PaymentInfoError.cshtml")); } } var apiOrder = _klarnaCheckoutPaymentService.Fetch(resourceUri); var klarnaOrder = KlarnaCheckoutOrder.FromApiOrder(apiOrder); var model = new PaymentInfoModel { SnippetHtml = klarnaOrder.Gui.Snippet }; return(View("~/Plugins/Motillo.KlarnaCheckout/Views/KlarnaCheckout/PaymentInfo.cshtml", model)); }
public void SyncBillingAndShippingAddress(global::Nop.Core.Domain.Customers.Customer customer, KlarnaCheckoutOrder klarnaCheckoutOrder) { try { var billingAddress = klarnaCheckoutOrder.BillingAddress; var shippingAddress = klarnaCheckoutOrder.ShippingAddress; var nopBillingAddress = customer.Addresses.FirstOrDefault(billingAddress.RepresentsAddress); if (nopBillingAddress == null) { nopBillingAddress = new global::Nop.Core.Domain.Common.Address { CreatedOnUtc = DateTime.UtcNow }; customer.Addresses.Add(nopBillingAddress); } customer.BillingAddress = nopBillingAddress; billingAddress.CopyTo(nopBillingAddress); var nopShippingAddress = customer.Addresses.FirstOrDefault(shippingAddress.RepresentsAddress); if (nopShippingAddress == null) { nopShippingAddress = new global::Nop.Core.Domain.Common.Address { CreatedOnUtc = DateTime.UtcNow }; customer.Addresses.Add(nopShippingAddress); } customer.ShippingAddress = nopShippingAddress; shippingAddress.CopyTo(nopShippingAddress); _customerService.UpdateCustomer(customer); } catch (Exception ex) { var billing = JsonConvert.SerializeObject(klarnaCheckoutOrder.BillingAddress); var shipping = JsonConvert.SerializeObject(klarnaCheckoutOrder.ShippingAddress); throw new KlarnaCheckoutException(string.Format(CultureInfo.CurrentCulture, "Error syncing addresses. Billing: {0}, Shipping: {1}", billing, shipping), ex); } }