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 void HandleEvent(ShipmentSentEvent eventMessage)
        {
            var nopOrder = eventMessage.Shipment.Order;

            // Ignore other payment methods.
            if (nopOrder.PaymentMethodSystemName != KlarnaCheckoutProcessor.PaymentMethodSystemName)
            {
                return;
            }

            try
            {
                // Check if the order has been captured manually.
                if (!string.IsNullOrEmpty(nopOrder.CaptureTransactionId))
                {
                    nopOrder.OrderNotes.Add(new OrderNote
                    {
                        Note              = "KlarnaCheckout: Order shipped but the payment has already been captured.",
                        CreatedOnUtc      = DateTime.UtcNow,
                        DisplayToCustomer = false
                    });
                    _orderService.UpdateOrder(nopOrder);
                    return;
                }

                nopOrder.OrderNotes.Add(new OrderNote
                {
                    Note              = "KlarnaCheckout: Order has been shipped, trying to capture payment from Klarna.",
                    CreatedOnUtc      = DateTime.UtcNow,
                    DisplayToCustomer = false
                });
                _orderService.UpdateOrder(nopOrder);

                // Before capture was supported all orders were marked as Paid.
                // Existing paid orders need special treatment since the
                // OrderProcessingService can't capture paid orders but they
                // still need to activate the Klarna order.
                if (nopOrder.PaymentStatus == PaymentStatus.Paid)
                {
                    var klarnaPaymentProvider =
                        _paymentService.LoadPaymentMethodBySystemName(KlarnaCheckoutProcessor.PaymentMethodSystemName);
                    var captureResponse = klarnaPaymentProvider.Capture(new CapturePaymentRequest
                    {
                        Order = nopOrder
                    });

                    nopOrder.CaptureTransactionId = captureResponse.CaptureTransactionId;
                    _orderService.UpdateOrder(nopOrder);
                }
                else if (_orderProcessingService.CanCapture(nopOrder))
                {
                    _orderProcessingService.Capture(nopOrder);
                }
            }
            catch (Exception ex)
            {
                _logger.Error(string.Format(CultureInfo.CurrentCulture, "KlarnaCheckout: Error capturing order when shipped. OrderId: {0}, OrderGuid: {1}",
                                            nopOrder.Id, nopOrder.OrderGuid),
                              exception: ex,
                              customer: nopOrder.Customer);
            }
        }
 /// <summary>
 /// Capture an order (from admin panel)
 /// </summary>
 /// <param name="order">Order</param>
 /// <returns>A list of errors; empty list if no errors</returns>
 public IList <string> Capture(Order order)
 {
     return(_orderProcessingService.Capture(order));
 }
        public IActionResult CaptureOrder([ModelBinder(typeof(JsonModelBinder <OrderCaptureDto>))] Delta <OrderCaptureDto> order)
        {
            if (order.Dto.Id <= 0)
            {
                return(Error(HttpStatusCode.BadRequest, "id", "invalid id"));
            }
            var   orderCaptureRootObject = new OrdersCaptureRootObject();
            Order orderToCapture         = _orderApiService.GetOrderById(order.Dto.Id);

            if (orderToCapture == null)
            {
                return(Error(HttpStatusCode.NotFound, "order", "not found"));
            }
            var orderNote     = LocalizationService.GetResource("Plugins.Api.Orders.Capture");
            var captureStatus = "OK";
            var sb            = new StringBuilder();
            var orderCaptured = false;

            if (order.Dto.Amount < orderToCapture.OrderTotal || order.Dto.Amount < orderToCapture.OrderTotal)
            {
                captureStatus = LocalizationService.GetResource("Plugins.Api.Orders.CaptureStatus.Error");
                var messageText = $"Beløbet ({order.Dto.Amount.ToString()}) i Admind matcher ikke beløbet i webordren. Tryk på Ordredetaljer for at rette totalerne i nopShop";
                orderCaptureRootObject.Messages.Add(new OrdersCaptureRootObject.Message {
                    MessageType = "Error", MessageText = messageText
                });
            }
            else
            {
                orderCaptured = _orderProcessingService.CanCapture(orderToCapture);
                if (orderCaptured)
                {
                    orderToCapture.ShippingStatus = ShippingStatus.Shipped;
                    var errors = _orderProcessingService.Capture(orderToCapture);

                    if (errors.Count > 0)
                    {
                        orderCaptured = false;
                        captureStatus = LocalizationService.GetResource("Plugins.Api.Orders.CaptureStatus.Error");
                        orderCaptureRootObject.Messages.Add(new OrdersCaptureRootObject.Message {
                            MessageType = "Error", MessageText = $"NopCommerce capture errors: {string.Join(";", errors)}"
                        });
                        orderCaptureRootObject.Captured = false;
                        sb.AppendLine(string.Format(orderNote, captureStatus));
                    }
                    else
                    {
                        orderCaptured = true;
                        captureStatus = LocalizationService.GetResource("Plugins.Api.Orders.CaptureStatus.Ok");
                        orderCaptureRootObject.Messages.Add(new OrdersCaptureRootObject.Message {
                            MessageType = "Info", MessageText = $"Capture succesful"
                        });
                        orderCaptureRootObject.Captured = true;
                        sb.AppendLine(string.Format(orderNote, captureStatus));
                    }

                    CustomerActivityService.InsertActivity("EditOrder", LocalizationService.GetResource("ActivityLog.EditOrder"), orderToCapture);
                }
                else
                {
                    captureStatus = LocalizationService.GetResource("Plugins.Api.Orders.CaptureStatus.Error");
                    sb.AppendLine(string.Format(orderNote, captureStatus));
                    orderCaptureRootObject.Messages.Add(new OrdersCaptureRootObject.Message {
                        MessageType = "Error", MessageText = $"NopCommerce capture error. Order not capturable, check order and payment status: "
                    });
                    orderCaptureRootObject.Captured = false;
                    sb.AppendLine(LocalizationService.GetResource("Plugins.Api.Orders.CaptureStatus.CannotCapture"));
                }
            }
            // order note update
            orderToCapture.OrderNotes.Add(
                new OrderNote()
            {
                Note = sb.ToString(),
                DisplayToCustomer = false,
                CreatedOnUtc      = DateTime.UtcNow
            });
            this._orderService.UpdateOrder(orderToCapture);

            _orderProcessingService.CheckOrderStatus(orderToCapture);

            return(Ok(orderCaptureRootObject));
        }