Skip to content

Commit

Permalink
feat: migrate to dotnet server sdk (#163)
Browse files Browse the repository at this point in the history
Co-authored-by: Sourav Sarkar <[email protected]>
  • Loading branch information
amsourav and Sourav Sarkar authored Oct 16, 2024
1 parent faf8b4d commit 2cdd5d3
Show file tree
Hide file tree
Showing 4 changed files with 129 additions and 193 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="7.0.9" />
<PackageReference Include="PayPalServerSDK" Version="0.5.3" />
</ItemGroup>
</Project>
159 changes: 63 additions & 96 deletions advanced-integration/v2/server/dotnet/Server.cs
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
using System;
using System.IO;
using System.Net.Http;
using System.Text;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Newtonsoft.Json;
using Microsoft.Extensions.Logging;
using PaypalServerSDK.Standard;
using PaypalServerSDK.Standard.Authentication;
using PaypalServerSDK.Standard.Controllers;
using PaypalServerSDK.Standard.Http.Response;
using PaypalServerSDK.Standard.Models;
using IConfiguration = Microsoft.Extensions.Configuration.IConfiguration;

namespace PayPalAdvancedIntegration;

Expand Down Expand Up @@ -56,22 +58,42 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
[ApiController]
public class CheckoutController : Controller
{
private readonly IHttpClientFactory _httpClientFactory;
private readonly OrdersController _ordersController;
private readonly PaymentsController _paymentsController;

private IConfiguration _configuration { get; }
private string _paypalClientId
{
get { return Environment.GetEnvironmentVariable("PAYPAL_CLIENT_ID"); }
get { return System.Environment.GetEnvironmentVariable("PAYPAL_CLIENT_ID"); }
}
private string _paypalClientSecret
{
get { return Environment.GetEnvironmentVariable("PAYPAL_CLIENT_SECRET"); }
get { return System.Environment.GetEnvironmentVariable("PAYPAL_CLIENT_SECRET"); }
}
private readonly string _base = "https://api-m.sandbox.paypal.com";

public CheckoutController(IHttpClientFactory httpClientFactory, IConfiguration configuration)
private readonly ILogger<CheckoutController> _logger;

public CheckoutController(IConfiguration configuration, ILogger<CheckoutController> logger)
{
_httpClientFactory = httpClientFactory;
_configuration = configuration;
_logger = logger;

// Initialize the PayPal SDK client
PaypalServerSDKClient client = new PaypalServerSDKClient.Builder()
.Environment(PaypalServerSDK.Standard.Environment.Sandbox)
.ClientCredentialsAuth(
new ClientCredentialsAuthModel.Builder(_paypalClientId, _paypalClientSecret).Build()
)
.LoggingConfig(config =>
config
.LogLevel(LogLevel.Information)
.RequestConfig(reqConfig => reqConfig.Body(true))
.ResponseConfig(respConfig => respConfig.Headers(true))
)
.Build();

_ordersController = client.OrdersController;
_paymentsController = client.PaymentsController;
}

[HttpPost("api/orders")]
Expand All @@ -80,7 +102,7 @@ public async Task<IActionResult> CreateOrder([FromBody] dynamic cart)
try
{
var result = await _CreateOrder(cart);
return StatusCode((int)result.httpStatusCode, result.jsonResponse);
return StatusCode((int)result.StatusCode, result.Data);
}
catch (Exception ex)
{
Expand All @@ -89,13 +111,37 @@ public async Task<IActionResult> CreateOrder([FromBody] dynamic cart)
}
}

private async Task<dynamic> _CreateOrder(dynamic cart)
{
CheckoutPaymentIntent intent = (CheckoutPaymentIntent)
Enum.Parse(typeof(CheckoutPaymentIntent), "CAPTURE", true);

OrdersCreateInput ordersCreateInput = new OrdersCreateInput
{
Body = new OrderRequest
{
Intent = intent,
PurchaseUnits = new List<PurchaseUnitRequest>
{
new PurchaseUnitRequest
{
Amount = new AmountWithBreakdown { CurrencyCode = "USD", MValue = "100", },
},
},
},
};

ApiResponse<Order> result = await _ordersController.OrdersCreateAsync(ordersCreateInput);
return result;
}

[HttpPost("api/orders/{orderID}/capture")]
public async Task<IActionResult> CaptureOrder(string orderID)
{
try
{
var result = await _CaptureOrder(orderID);
return StatusCode((int)result.httpStatusCode, result.jsonResponse);
return StatusCode((int)result.StatusCode, result.Data);
}
catch (Exception ex)
{
Expand All @@ -104,91 +150,12 @@ public async Task<IActionResult> CaptureOrder(string orderID)
}
}

private async Task<string> GenerateAccessToken()
{
if (string.IsNullOrEmpty(_paypalClientId) || string.IsNullOrEmpty(_paypalClientSecret))
{
throw new Exception("MISSING_API_CREDENTIALS");
}

var auth = Convert.ToBase64String(
Encoding.UTF8.GetBytes($"{_paypalClientId}:{_paypalClientSecret}")
);
var client = _httpClientFactory.CreateClient();
var request = new HttpRequestMessage(HttpMethod.Post, $"{_base}/v1/oauth2/token")
{
Content = new StringContent(
"grant_type=client_credentials",
Encoding.UTF8,
"application/x-www-form-urlencoded"
)
};
request.Headers.Add("Authorization", $"Basic {auth}");

var response = await client.SendAsync(request);
var data = JsonConvert.DeserializeObject<dynamic>(
await response.Content.ReadAsStringAsync()
);
return data.access_token;
}

private async Task<dynamic> _CreateOrder(dynamic cart)
{
var accessToken = await GenerateAccessToken();
var url = $"{_base}/v2/checkout/orders";
var payload = new
{
intent = "CAPTURE",
purchase_units = new[]
{
new { amount = new { currency_code = "USD", value = "100.00" } }
}
};

var client = _httpClientFactory.CreateClient();
var request = new HttpRequestMessage(HttpMethod.Post, url)
{
Content = new StringContent(
JsonConvert.SerializeObject(payload),
Encoding.UTF8,
"application/json"
)
};
request.Headers.Add("Authorization", $"Bearer {accessToken}");

var response = await client.SendAsync(request);
return await HandleResponse(response);
}

private async Task<dynamic> _CaptureOrder(string orderID)
{
var accessToken = await GenerateAccessToken();
var url = $"{_base}/v2/checkout/orders/{orderID}/capture";

var client = _httpClientFactory.CreateClient();
var request = new HttpRequestMessage(HttpMethod.Post, url)
{
Content = new StringContent("", Encoding.UTF8, "application/json")
};
request.Headers.Add("Authorization", $"Bearer {accessToken}");
OrdersCaptureInput ordersCaptureInput = new OrdersCaptureInput { Id = orderID, };

var response = await client.SendAsync(request);
return await HandleResponse(response);
}
ApiResponse<Order> result = await _ordersController.OrdersCaptureAsync(ordersCaptureInput);

private async Task<dynamic> HandleResponse(HttpResponseMessage response)
{
try
{
var jsonResponse = JsonConvert.DeserializeObject<dynamic>(
await response.Content.ReadAsStringAsync()
);
return new { jsonResponse, httpStatusCode = response.StatusCode };
}
catch (Exception)
{
var errorMessage = await response.Content.ReadAsStringAsync();
throw new Exception(errorMessage);
}
return result;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="7.0.9" />
<PackageReference Include="PayPalServerSDK" Version="0.5.3" />
</ItemGroup>
</Project>
Loading

0 comments on commit 2cdd5d3

Please sign in to comment.