public virtual Task <Overture.ServiceModel.Orders.Order> CompleteCheckoutAsync(CompleteCheckoutParam param) { if (param == null) { throw new ArgumentNullException("param", "param"); } if (string.IsNullOrWhiteSpace(param.CartName)) { throw new ArgumentException(ArgumentNullMessageFormatter.FormatErrorMessage("param.CartName"), "param"); } if (param.CultureInfo == null) { throw new ArgumentException(ArgumentNullMessageFormatter.FormatErrorMessage("CultureInfo"), "param"); } if (param.CustomerId == Guid.Empty) { throw new ArgumentException(ArgumentNullMessageFormatter.FormatErrorMessage("CustomerId"), "param"); } if (string.IsNullOrWhiteSpace(param.Scope)) { throw new ArgumentException(ArgumentNullMessageFormatter.FormatErrorMessage("Scope"), "param"); } var request = new CompleteCheckoutRequest { CartName = param.CartName, CultureName = param.CultureInfo.Name, CustomerId = param.CustomerId, ScopeId = param.Scope }; return(OvertureClient.SendAsync(request)); }
public virtual Task <Overture.ServiceModel.Orders.Order> CompleteCheckoutAsync(CompleteCheckoutParam param) { if (param == null) { throw new ArgumentNullException(nameof(param)); } if (string.IsNullOrWhiteSpace(param.CartName)) { throw new ArgumentException(GetMessageOfNullWhiteSpace(nameof(param.CartName)), nameof(param)); } if (param.CultureInfo == null) { throw new ArgumentException(GetMessageOfNull(nameof(param.CultureInfo)), nameof(param)); } if (param.CustomerId == Guid.Empty) { throw new ArgumentException(GetMessageOfEmpty(nameof(param.CustomerId)), nameof(param)); } if (string.IsNullOrWhiteSpace(param.Scope)) { throw new ArgumentException(GetMessageOfNullWhiteSpace(nameof(param.Scope)), nameof(param)); } var request = new CompleteCheckoutRequest { CartName = param.CartName, CultureName = param.CultureInfo.Name, CustomerId = param.CustomerId, ScopeId = param.Scope }; return(OvertureClient.SendAsync(request)); }
public virtual async Task <IHttpActionResult> CompleteCheckout(CompleteCheckoutRequest request) { if (request == null) { return(BadRequest("No request body found.")); } var nextStepUrl = CartUrlProvider.GetCheckoutStepUrl(new GetCheckoutStepUrlParam { CultureInfo = ComposerContext.CultureInfo, StepNumber = request.CurrentStep + 1 }); var checkoutViewModel = await CheckoutService.CompleteCheckoutAsync(new CompleteCheckoutParam { CartName = CartConfiguration.ShoppingCartName, CustomerId = ComposerContext.CustomerId, CultureInfo = ComposerContext.CultureInfo, Scope = ComposerContext.Scope, BaseUrl = RequestUtils.GetBaseUrl(Request).ToString(), }); checkoutViewModel.NextStepUrl = nextStepUrl; return(Ok(checkoutViewModel)); }
/// <summary> /// If you pass 'true’ to 'merchant_completes’ in our Create CreateCheckoutRequest flow, then you must call our Complete CreateCheckoutRequest endpoint. /// For some checkouts, a merchant may need to have the user return to their site for additional steps before completing the purchase. /// If this is the case, the order completion endpoint is used to complete the CreateCheckoutRequest with Sezzle. /// From the time the user is redirected back to the Merchant’s site, you must make the request to complete the createCheckoutRequest within 30 minutes, or the createCheckoutRequest will be /// cancelled by Sezzle. If the createCheckoutRequest has expired, we will return the rejection response on the right, with a Status 409 /// There are two non-error responses expected. Either an HTTP 200 (currently no response body) or a rejection message. /// </summary> /// <param name="completeCheckoutRequest"></param> /// <remarks> /// https://gateway.sezzle.com/v1/checkouts/{order_reference_id}/complete /// </remarks> /// <returns></returns> public async Task <CompleteCheckoutResponse> CompleteAsync(CompleteCheckoutRequest completeCheckoutRequest) { var tokenTask = _authenticationEndpoint.CreateTokenAsync(); //create url and request object var requestUrl = UrlStringExtensions.FormatRequestUrl(GetCheckoutsBaseUrl(), $"{completeCheckoutRequest.LocalOrderId}/complete"); var token = await tokenTask; var response = await _sezzleHttpClient.PostAsync <CompleteCheckoutRequest, CompleteCheckoutResponse>(token.Token, requestUrl, null); return(response); }
public void CanCompleteACheckoutWithMerchantCompletes() { // TODO: Mark this test as ignored and require a parameter to send the order reference id into it var request = new CompleteCheckoutRequest() { LocalOrderId = "636773928435687781" }; var checkouts = CreateCheckoutClient(); // Now let's try completing it var completeResponse = checkouts.CompleteAsync(request); // Per Sezzle, an empty response body is success Assert.IsNotNull(completeResponse); }
public async Task FullWorkflowWithMerchantCompletesEqualsTrue_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); }
public async Task FullWorkflowWithMerchantCompletesEqualsTrue_AttemptToCompleteCheckoutWithoutCustomerCompleting_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); // ** 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); Func <Task> act = async() => { //merchant completes the checkout/order. (we had used merchantcompletes=true) var completeCheckoutRequest = new CompleteCheckoutRequest() { LocalOrderId = orderReferenceId }; var response = await checkouts.CompleteAsync(completeCheckoutRequest); }; //exception is thrown from sezzle because you cannot complete a checkout that has not been completed by user. act.Should().Throw <SezzleErrorResponseException>(); }
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); }
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); }
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>(); }