Make payments dependency injected based on the .env settings

This commit is contained in:
2025-06-20 18:31:18 -07:00
parent c4ad0f2c10
commit fb2a2c6ae9
8 changed files with 111 additions and 83 deletions
@@ -2,107 +2,59 @@
using MistoxWebsite.Server.Controllers.Payment;
using MistoxWebsite.Server.Services.DatabaseService;
using MistoxWebsite.Server.Entities;
using Microsoft.Extensions.Primitives;
namespace MistoxWebsite.Server.Controllers {
[ApiController]
public class PaymentController : ControllerBase {
DatabaseService _databaseService;
IPayment _paymentService;
public PaymentController( DatabaseService databaseService ) {
public PaymentController(DatabaseService databaseService) {
_databaseService = databaseService;
if (IPayment._PaymentType == PaymentType.StripeIntent) {
_paymentService = new StripeIntent(_databaseService);
} else {
// Fallback
_paymentService = new StripeIntent(_databaseService);
}
// Add new payment plugins here
}
// Charges
[Route( "api/getCheckoutToken" )]
[Route("api/getCheckoutToken")]
[HttpPost]
public async Task<string> GetPaymentKey( [FromQuery] string userID ) {
string OrderNumber = Guid.NewGuid().ToString().Substring(0,10);
Account? acc = await _databaseService.GetAccount(userID);
if (acc != null) {
List<Cart> cart = await _databaseService.GetCart(acc);
IPayment PaymentPlugin = new StripeIntent(_databaseService);
(bool, string) PaymentResponse = await PaymentPlugin.Purchase(OrderNumber, acc, cart);
(bool, string) PaymentResponse = await _paymentService.TryGetCheckoutToken(OrderNumber, acc, cart);
if (PaymentResponse.Item1) {
// Returns client secret
return PaymentResponse.Item2;
}
else {
} else {
Console.WriteLine("An error has occured in the payment plugin\n\n");
Console.WriteLine(PaymentResponse.Item2);
Console.WriteLine("\n");
return "0";
return "An error has occured in the payment plugin";
}
} else {
return "Unable to find account";
}
return "0";
}
[Route( "/api/payment/response" )]
[HttpPost]
public async Task<IActionResult> paymentWebhook() {
try {
const string endpointSecret = "whsec_HCO7uv2BPIPmUPOiSg9tfwLZul8usCGG";
string body = await new StreamReader(Request.Body).ReadToEndAsync();
Stripe.Event e = Stripe.EventUtility.ConstructEvent( body, Request.Headers["Stripe-Signature"], endpointSecret );
if( e.Type == "payment_intent.succeeded" ) {
// Extract Data from payment confirm
Stripe.PaymentIntent intent = (Stripe.PaymentIntent)e.Data.Object;
string orderNumber = "";
int userID = 0;
List<int> productIDs = new List<int>();
int subtotal = 0;
int total = 0;
KeyValuePair<string, string>[] y = intent.Metadata.ToArray();
foreach( KeyValuePair<string, string> cur in y ) {
string val = cur.Key;
if( val == "ordernumber" ) {
orderNumber = cur.Value;
} else if( val == "user" ) {
userID = int.Parse( cur.Value );
} else if( val == "products" ) {
string[] products = cur.Value.Split(',');
foreach( string product in products ) {
if ( !string.IsNullOrEmpty(product) ) {
productIDs.Add( Convert.ToInt32( product ) );
}
}
} else if( val == "subtotal" ) {
subtotal = int.Parse( cur.Value );
} else if( val == "total" ) {
total = int.Parse( cur.Value );
}
}
// Clear the cart
Account account = new() {
ID = userID
};
await _databaseService.ClearCart( account );
// Add data to misox receipt
for( int i = 0; i < productIDs.Count; i++ ) {
int product = productIDs[i];
await _databaseService.NewReceipt( new Receipt {
AccountID = userID,
ProductID = product,
ReceiptID = orderNumber,
Time = DateTime.Now,
TaxAmount = total - subtotal,
TotalCost = total,
LineItem = i
} );
}
} else {
Console.WriteLine( "Unhandled event type: {0}", e.Type );
}
await _paymentService.ValidatePurchase(body, Request.Headers["Stripe-Signature"].ToString());
return Ok();
} catch( Exception ex ) {
return Content(ex.ToString());
} catch (Exception ex) {
return NotFound(ex.ToString());
}
}
@@ -4,8 +4,16 @@ namespace MistoxWebsite.Server.Controllers.Payment {
public interface IPayment {
public Task<(bool, string)> Purchase(string OrderNumber, Account user, List<Cart> cart);
public static PaymentType _PaymentType;
public static string _EndpointSecret = "";
public Task<(bool, string)> TryGetCheckoutToken(string OrderNumber, Account user, List<Cart> cart);
public Task ValidatePurchase(string WebHookData, string Headers);
}
public enum PaymentType {
StripeIntent
}
}
@@ -8,11 +8,11 @@ namespace MistoxWebsite.Server.Controllers {
DatabaseService _databaseService;
public StripeIntent( DatabaseService databaseService ) {
public StripeIntent(DatabaseService databaseService) {
_databaseService = databaseService;
}
public async Task<(bool, string)> Purchase(string OrderNumber, Account user, List<Cart> cart) {
public async Task<(bool, string)> TryGetCheckoutToken(string OrderNumber, Account user, List<Cart> cart) {
try {
// build Recipt and calculate Tax
var options = new Stripe.Tax.CalculationCreateOptions {
@@ -72,12 +72,71 @@ namespace MistoxWebsite.Server.Controllers {
Stripe.PaymentIntent x = await intentService.CreateAsync(paymentIntent);
return (true, x.ClientSecret);
} catch(Exception e) {
} catch (Exception e) {
return (false, e.ToString());
}
}
public async Task ValidatePurchase(string WebHookData, string Headers) {
Stripe.Event e = Stripe.EventUtility.ConstructEvent( WebHookData, Headers, IPayment._EndpointSecret );
if (e.Type == "payment_intent.succeeded") {
// Extract Data from payment confirm
Stripe.PaymentIntent intent = (Stripe.PaymentIntent)e.Data.Object;
string orderNumber = "";
int userID = 0;
List<int> productIDs = new List<int>();
int subtotal = 0;
int total = 0;
KeyValuePair<string, string>[] y = intent.Metadata.ToArray();
foreach (KeyValuePair<string, string> cur in y) {
string val = cur.Key;
if (val == "ordernumber") {
orderNumber = cur.Value;
}
else if (val == "user") {
userID = int.Parse(cur.Value);
}
else if (val == "products") {
string[] products = cur.Value.Split(',');
foreach (string product in products) {
if (!string.IsNullOrEmpty(product)) {
productIDs.Add(Convert.ToInt32(product));
}
}
}
else if (val == "subtotal") {
subtotal = int.Parse(cur.Value);
}
else if (val == "total") {
total = int.Parse(cur.Value);
}
}
// Clear the cart
Account account = new() {
ID = userID
};
await _databaseService.ClearCart(account);
// Add data to misox receipt
for (int i = 0; i < productIDs.Count; i++) {
int product = productIDs[i];
await _databaseService.NewReceipt(new Receipt {
AccountID = userID,
ProductID = product,
ReceiptID = orderNumber,
Time = DateTime.Now,
TaxAmount = total - subtotal,
TotalCost = total,
LineItem = i
});
}
} else {
Console.WriteLine("Unhandled event type: {0}", e.Type);
}
}
}
}
+10 -2
View File
@@ -1,5 +1,6 @@
using Microsoft.AspNetCore.Authentication.Cookies;
using MistoxWebsite.Server.Controllers;
using MistoxWebsite.Server.Controllers.Payment;
using MistoxWebsite.Server.Services;
using MistoxWebsite.Server.Services.DatabaseService;
using Stripe;
@@ -37,8 +38,15 @@ EmailService Emailservice = new EmailService( EmailServer, EmailPort, EmailAddre
builder.Services.Add( new ServiceDescriptor( typeof( EmailService ), Emailservice ));
// Payment Service
string? StripeKey = Environment.GetEnvironmentVariable("StripeKey");
StripeConfiguration.ApiKey = StripeKey;
string? PaymentService = Environment.GetEnvironmentVariable("PaymentService");
IPayment._PaymentType = (PaymentType)Enum.Parse(typeof(PaymentType), PaymentService, true);
if (IPayment._PaymentType == PaymentType.StripeIntent) {
string? StripeKey = Environment.GetEnvironmentVariable("StripeKey");
StripeConfiguration.ApiKey = StripeKey;
string? StripeEndpointKey = Environment.GetEnvironmentVariable("StripeEndpointSecret");
IPayment._EndpointSecret = string.IsNullOrEmpty(StripeEndpointKey) ? "" : StripeEndpointKey ;
}
// Authentication Service
builder.Services.AddAuthentication( options => {