Example #1
0
        /// <summary>
        /// Sezzle allows refunds for orders either through our Merchant Dashboard or through the API. If the refund is processed through the dashboard, a webhook will be sent to your system. In either case, Sezzle allows for either partial or complete refunds. RefundAsync amounts are relative to the order total, not the amount that has been paid by the shopper.
        /// </summary>
        /// <remarks>
        ///     https://gateway.sezzle.com/v1/orders/{order_reference_id}/refund
        /// </remarks>
        /// <param name="orderRefundRequest"></param>
        /// <returns></returns>
        public async Task <OrderRefundResponse> RefundAsync(OrderRefundRequest orderRefundRequest)
        {
            var tokenTask = _authenticationEndpoint.CreateTokenAsync();

            //build in the shipping information to true for all requests.  doesn't hurt to have it.
            var requestUrl = UrlStringExtensions.FormatRequestUrl(_baseConfiguration.ApiUrl, $"/orders/{orderRefundRequest.OrderReferenceId}/refund");

            var token = await tokenTask;
            //send null into the client; we have manually added the necessary request data to parameters and url.
            var response = await _sezzleHttpClient.PostAsync <OrderRefundRequestBody, OrderRefundResponse>(token.Token, requestUrl, orderRefundRequest, null);

            return(response);
        }
Example #2
0
        /// <summary>
        /// Refund. This method allows you make a refund.
        /// In this case a Refund button will be visible on the order details page in admin area.
        /// Note that an order should be paid, and SupportRefund or SupportPartiallyRefund property should return true.
        /// </summary>
        /// <param name="refundPaymentRequest"></param>
        /// <returns></returns>
        public RefundPaymentResult Refund(RefundPaymentRequest refundPaymentRequest)
        {
            ListResponse <OrderResponse> listResponse = _mollieOrderClient.GetOrderListAsync().Result;

            var mollieOrderId = "";

            foreach (var orderItem in listResponse.Items)
            {
                if (orderItem.OrderNumber == refundPaymentRequest.Order.CustomOrderNumber)
                {
                    mollieOrderId = orderItem.Id;
                }
            }

            if (string.IsNullOrEmpty(mollieOrderId))
            {
                return new RefundPaymentResult {
                           Errors = new[] { "Mollie OrderID is Null or Empty" }
                }
            }
            ;

            OrderResponse retrieveOrder = _mollieOrderClient.GetOrderAsync(mollieOrderId).Result;

            var orderlineList = new List <OrderLineDetails>();

            foreach (var item in _orderService.GetOrderItems(refundPaymentRequest.Order.Id))
            {
                foreach (var line in retrieveOrder.Lines)
                {
                    orderlineList.Add(new OrderLineDetails()
                    {
                        Id       = line.Id,
                        Quantity = item.Quantity,
                        Amount   = new Amount(SelectCurrency().CurrencyCode, line.TotalAmount)
                    });
                }
            }

            OrderRefundRequest refundRequest = new OrderRefundRequest()
            {
                Lines = orderlineList
            };

            OrderRefundResponse result = _mollieOrderClient.CreateOrderRefundAsync(mollieOrderId, refundRequest).Result;

            return(new RefundPaymentResult
            {
                NewPaymentStatus = refundPaymentRequest.IsPartialRefund ? PaymentStatus.PartiallyRefunded : PaymentStatus.Refunded
            });
        }
Example #3
0
 public Task CreateOrderRefundAsync(string orderId, OrderRefundRequest createOrderRefundRequest) =>
 ClientService.DeleteAsync($"orders/{orderId}/refunds", createOrderRefundRequest);
Example #4
0
 public async Task CreateOrderRefundAsync(string orderId, OrderRefundRequest createOrderRefundRequest)
 {
     await this.DeleteAsync($"orders/{orderId}/refunds", createOrderRefundRequest);
 }
Example #5
0
 public async Task <OrderRefundResponse> CreateOrderRefundAsync(string orderId, OrderRefundRequest createOrderRefundRequest)
 {
     return(await this.PostAsync <OrderRefundResponse>($"orders/{orderId}/refunds", createOrderRefundRequest));
 }
Example #6
0
        public async Task CanCreateOrder_CustomerCompletes_MerchantCompletes_RefundPartial()
        {
            //arrange
            var orderReferenceId = DateTime.UtcNow.Ticks.ToString();

            var checkoutEndpoint      = new CheckoutEndpoint(_baseConfiguration, _authenticationClient, GetDefaultSezzleHttpClient());
            var createCheckoutRequest = GenerateValidCreateCheckoutRequest(orderReferenceId);

            createCheckoutRequest.MerchantCompletes = true;
            //makes it easier to script completion of checkout by a user.
            createCheckoutRequest.RequiresShippingInfo = false;

            var completeCheckoutRequest = new CompleteCheckoutRequest()
            {
                LocalOrderId = createCheckoutRequest.OrderReferenceId
            };

            var ordersEndpoint = new OrdersEndpoint(_baseConfiguration, _authenticationClient, GetDefaultSezzleHttpClient());

            var request = new OrderDetailsRequest()
            {
                IncludeShippingInfo = true,
                OrderReferenceId    = orderReferenceId
            };

            //create refund request
            var refundAmount         = 123;
            var partialRefundRequest = new OrderRefundRequest()
            {
                Amount = new Price()
                {
                    AmountInCents = refundAmount,
                    Currency      = Enums.CheckoutCurrencyCodeEnum.USD
                },
                IsFullRefund     = false,
                OrderReferenceId = orderReferenceId,
                RefundId         = $"gh_refund_{DateTime.UtcNow.Ticks.ToString()}",
                RefundReason     = "some reason here"
            };

            //act
            //10 create order
            var order = await checkoutEndpoint.CreateAsync(createCheckoutRequest);

            Console.WriteLine(JsonConvert.SerializeObject(order, Formatting.Indented));

            //20 get order details
            var orderDetails = await ordersEndpoint.GetDetailsAsync(request);

            Console.WriteLine(JsonConvert.SerializeObject(orderDetails, Formatting.Indented));

            //30 (user completes checkout - use selenium) complete the checkout
            //todo: use selenium to complete the checkout through user workflow.

            //40 merchant completes the checkout.
            var completedCheckout = await checkoutEndpoint.CompleteAsync(completeCheckoutRequest);

            //partial refund
            var refundResponse = await ordersEndpoint.RefundAsync(partialRefundRequest);

            //test #1, verify order refund is processed and returns data as sent in.
            Assert.AreEqual(refundAmount, refundResponse.Amount.AmountInCents);
            Assert.AreEqual(partialRefundRequest.RefundId, refundResponse.RefundId);

            //get order details again.  the order value should have changed by the amount refunded.
            var orderDetails2 = await ordersEndpoint.GetDetailsAsync(request);

            //test #2, verify order amount has changed after refund
            //todo: this ammount does not actually change like I expected it to.  Perhaps there is a missing endpoint where we can see what modified the order (refunds).
            //long expectedOrderAmountAfterRefund = orderDetails.AmountInCents - refundAmount;
            //Assert.AreEqual(expectedOrderAmountAfterRefund, orderDetails2.AmountInCents);
        }
Example #7
0
        public async Task FullWorkflowWithMerchantCompletesEqualsTrue_ThenRefundFullAmount_Positive()
        {
            //** Create the Checkout/Order
            var checkouts             = CreateCheckoutClient();
            var orderReferenceId      = DateTime.UtcNow.Ticks.ToString();
            var createCheckoutRequest = GenerateValidCreateCheckoutRequest(orderReferenceId, false);

            createCheckoutRequest.MerchantCompletes = true;
            var checkoutResponse = await checkouts.CreateAsync(createCheckoutRequest);

            Console.WriteLine(checkoutResponse.CheckoutUrl);

            // ** get order details.
            //verify that order is in customer NotPaid status.
            var orders = new OrdersEndpoint(_baseConfiguration, _authenticationClient, GetDefaultSezzleHttpClient());
            var orderDetailsRequest = new OrderDetailsRequest()
            {
                IncludeShippingInfo = true,
                OrderReferenceId    = orderReferenceId
            };

            // ** check order status. get order details before user has been redirected to the checkout URL
            var orderDetailsBeforeUserChecksOut = await orders.GetDetailsAsync(orderDetailsRequest);

            Assert.AreEqual(orderDetailsBeforeUserChecksOut.OrderStatus, Enums.OrderStatusEnum.S0010OrderCreated);

            //***********Existing Customer goes to checkout And completes checkout
            _sezzleCheckoutAutomationHelper.CompleteCheckoutClientSide(checkoutResponse.CheckoutUrl, base.GetCustomerLoginCredentials(), createCheckoutRequest.CheckoutCompleteUrl);

            // verify order status is now in the checked out status
            var orderDetailsBeforeMerchantCompletesCheckout = await orders.GetDetailsAsync(orderDetailsRequest);

            Assert.AreEqual(orderDetailsBeforeMerchantCompletesCheckout.OrderStatus, Enums.OrderStatusEnum.S0020UserHasCheckedOut);

            //merchant completes the checkout/order. (we had used merchantcompletes=true)
            var completeCheckoutRequest = new CompleteCheckoutRequest()
            {
                LocalOrderId = orderReferenceId
            };
            await checkouts.CompleteAsync(completeCheckoutRequest);

            //get order details.  order should now be complete, meaning sezzle has captured the funds and we are guaranteed the full amount.
            var orderDetailsAfterMerchantCompletesCheckout = await orders.GetDetailsAsync(orderDetailsRequest);

            Assert.AreEqual(Enums.OrderStatusEnum.S0030FundsCapturedAllDoneBoomshakalakaYippiekiyay, orderDetailsAfterMerchantCompletesCheckout.OrderStatus);

            //**********************up to now, that is just a standard order.
            //now we refund

            var refundAmount = createCheckoutRequest.AmountInCents;

            var refundRequest = new OrderRefundRequest()
            {
                Amount = new Price()
                {
                    AmountInCents = refundAmount,
                    Currency      = Enums.CheckoutCurrencyCodeEnum.USD
                },
                OrderReferenceId = orderReferenceId,
                IsFullRefund     = false,
                RefundId         = Guid.NewGuid().ToString(),
                RefundReason     = "unit test reason"
            };

            var refundResponse = await orders.RefundAsync(refundRequest);

            //verifies amount was refunded
            Assert.AreEqual(refundAmount, refundResponse.Amount.AmountInCents);

            //get order status and verify that it is equal to the full original amount.  there are no endpoints that get the history of the refunds at this time.
            var orderStatusAfterPartialRefund = await orders.GetDetailsAsync(orderDetailsRequest);

            Assert.AreEqual(createCheckoutRequest.AmountInCents, orderStatusAfterPartialRefund.AmountInCents);
        }
Example #8
0
        public async Task FullWorkflowWithMerchantCompletesEqualsTrue_ThenRefundInvalidAmount_Negative()
        {
            //** Create the Checkout/Order
            var checkouts             = CreateCheckoutClient();
            var orderReferenceId      = DateTime.UtcNow.Ticks.ToString();
            var createCheckoutRequest = GenerateValidCreateCheckoutRequest(orderReferenceId, false);

            createCheckoutRequest.MerchantCompletes = true;
            var checkoutResponse = await checkouts.CreateAsync(createCheckoutRequest);

            Console.WriteLine(checkoutResponse.CheckoutUrl);

            // ** get order details.
            //verify that order is in customer NotPaid status.
            var orders = new OrdersEndpoint(_baseConfiguration, _authenticationClient, GetDefaultSezzleHttpClient());
            var orderDetailsRequest = new OrderDetailsRequest()
            {
                IncludeShippingInfo = true,
                OrderReferenceId    = orderReferenceId
            };

            // ** check order status. get order details before user has been redirected to the checkout URL
            var orderDetailsBeforeUserChecksOut = await orders.GetDetailsAsync(orderDetailsRequest);

            Assert.AreEqual(orderDetailsBeforeUserChecksOut.OrderStatus, Enums.OrderStatusEnum.S0010OrderCreated);

            //***********Existing Customer goes to checkout And completes checkout
            _sezzleCheckoutAutomationHelper.CompleteCheckoutClientSide(checkoutResponse.CheckoutUrl, base.GetCustomerLoginCredentials(), createCheckoutRequest.CheckoutCompleteUrl);

            // verify order status is now in the checked out status
            var orderDetailsBeforeMerchantCompletesCheckout = await orders.GetDetailsAsync(orderDetailsRequest);

            Assert.AreEqual(orderDetailsBeforeMerchantCompletesCheckout.OrderStatus, Enums.OrderStatusEnum.S0020UserHasCheckedOut);

            //merchant completes the checkout/order. (we had used merchantcompletes=true)
            var completeCheckoutRequest = new CompleteCheckoutRequest()
            {
                LocalOrderId = orderReferenceId
            };
            await checkouts.CompleteAsync(completeCheckoutRequest);

            //get order details.  order should now be complete, meaning sezzle has captured the funds and we are guaranteed the full amount.
            var orderDetailsAfterMerchantCompletesCheckout = await orders.GetDetailsAsync(orderDetailsRequest);

            Assert.AreEqual(Enums.OrderStatusEnum.S0030FundsCapturedAllDoneBoomshakalakaYippiekiyay, orderDetailsAfterMerchantCompletesCheckout.OrderStatus);

            //**********************up to now, that is just a standard order.

            // try to refund an amount greater than the initial checkout amount.  Verify our framework throws an exception.
            Func <Task> act = async() =>
            {
                //set the refund amount to 1 cent over the entire order.
                var refundAmount = createCheckoutRequest.AmountInCents + 1;

                var refundRequest = new OrderRefundRequest()
                {
                    Amount = new Price()
                    {
                        AmountInCents = refundAmount,
                        Currency      = Enums.CheckoutCurrencyCodeEnum.USD
                    },
                    OrderReferenceId = orderReferenceId,
                    IsFullRefund     = false,
                    RefundId         = Guid.NewGuid().ToString(),
                    RefundReason     = "unit test reason"
                };

                var refundResponse = await orders.RefundAsync(refundRequest);
            };

            //exception is thrown from sezzle because you cannot complete a checkout that has not been completed by user.
            act.Should().Throw <SezzleErrorResponseException>();
        }