Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: migrate to dotnet server sdk #163

Merged
merged 1 commit into from
Oct 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading