Make payments dependency injected based on the .env settings
This commit is contained in:
@@ -13,3 +13,4 @@ trim_trailing_whitespace = false
|
|||||||
csharp_new_line_before_open_brace = none
|
csharp_new_line_before_open_brace = none
|
||||||
csharp_new_line_before_catch = false
|
csharp_new_line_before_catch = false
|
||||||
csharp_new_line_before_finally = false
|
csharp_new_line_before_finally = false
|
||||||
|
csharp_new_line_after_else = false
|
||||||
@@ -1,4 +1,7 @@
|
|||||||
|
Payment_Service=StripeIntent # Options are [ StripeIntent ]
|
||||||
|
|
||||||
Stripe_Key=
|
Stripe_Key=
|
||||||
|
Stripe_Endpoint_Secret=
|
||||||
|
|
||||||
MySQL_Server=mistox-database
|
MySQL_Server=mistox-database
|
||||||
MySQL_User=root
|
MySQL_User=root
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
Fix stripe payments *Updated API*
|
Stripe payments aren't currently tested
|
||||||
Havent Tested
|
|
||||||
|
|
||||||
After a new account is created notify a user that they need to verify their email before logging in
|
After a new account is created notify a user that they need to verify their email before logging in
|
||||||
|
|
||||||
@@ -30,9 +29,5 @@ DTO
|
|||||||
Cannot send dotnet List -> must be arrays
|
Cannot send dotnet List -> must be arrays
|
||||||
Need to update local server to use www-formdata instead of json
|
Need to update local server to use www-formdata instead of json
|
||||||
|
|
||||||
PaymentController
|
|
||||||
PaymentResponse is still tied to Stripe.
|
|
||||||
Need to change to Interface so different services can be interchanged
|
|
||||||
|
|
||||||
ProductController
|
ProductController
|
||||||
Need to figure out new way to download purchased items as there is currently no way
|
Need to figure out new way to download purchased items as there is currently no way
|
||||||
@@ -5,7 +5,9 @@ services:
|
|||||||
image: mistox-website:latest
|
image: mistox-website:latest
|
||||||
restart: always
|
restart: always
|
||||||
environment:
|
environment:
|
||||||
|
- PaymentService=${Payment_Service}
|
||||||
- StripeKey=${Stripe_Key}
|
- StripeKey=${Stripe_Key}
|
||||||
|
- StripeEndpointSecret=&{Stripe_Endpoint_Secret}
|
||||||
- MySQLServer=${MySQL_Server}
|
- MySQLServer=${MySQL_Server}
|
||||||
- MySQLUser=${MySQL_User}
|
- MySQLUser=${MySQL_User}
|
||||||
- MySQLPass=${MySQL_Pass}
|
- MySQLPass=${MySQL_Pass}
|
||||||
|
|||||||
@@ -2,107 +2,59 @@
|
|||||||
using MistoxWebsite.Server.Controllers.Payment;
|
using MistoxWebsite.Server.Controllers.Payment;
|
||||||
using MistoxWebsite.Server.Services.DatabaseService;
|
using MistoxWebsite.Server.Services.DatabaseService;
|
||||||
using MistoxWebsite.Server.Entities;
|
using MistoxWebsite.Server.Entities;
|
||||||
|
using Microsoft.Extensions.Primitives;
|
||||||
|
|
||||||
namespace MistoxWebsite.Server.Controllers {
|
namespace MistoxWebsite.Server.Controllers {
|
||||||
[ApiController]
|
[ApiController]
|
||||||
public class PaymentController : ControllerBase {
|
public class PaymentController : ControllerBase {
|
||||||
|
|
||||||
DatabaseService _databaseService;
|
DatabaseService _databaseService;
|
||||||
|
IPayment _paymentService;
|
||||||
|
|
||||||
public PaymentController( DatabaseService databaseService ) {
|
public PaymentController(DatabaseService databaseService) {
|
||||||
_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]
|
[HttpPost]
|
||||||
public async Task<string> GetPaymentKey( [FromQuery] string userID ) {
|
public async Task<string> GetPaymentKey( [FromQuery] string userID ) {
|
||||||
|
|
||||||
string OrderNumber = Guid.NewGuid().ToString().Substring(0,10);
|
string OrderNumber = Guid.NewGuid().ToString().Substring(0,10);
|
||||||
Account? acc = await _databaseService.GetAccount(userID);
|
Account? acc = await _databaseService.GetAccount(userID);
|
||||||
if (acc != null) {
|
if (acc != null) {
|
||||||
List<Cart> cart = await _databaseService.GetCart(acc);
|
List<Cart> cart = await _databaseService.GetCart(acc);
|
||||||
|
(bool, string) PaymentResponse = await _paymentService.TryGetCheckoutToken(OrderNumber, acc, cart);
|
||||||
IPayment PaymentPlugin = new StripeIntent(_databaseService);
|
|
||||||
|
|
||||||
(bool, string) PaymentResponse = await PaymentPlugin.Purchase(OrderNumber, acc, cart);
|
|
||||||
if (PaymentResponse.Item1) {
|
if (PaymentResponse.Item1) {
|
||||||
|
// Returns client secret
|
||||||
return PaymentResponse.Item2;
|
return PaymentResponse.Item2;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
Console.WriteLine("An error has occured in the payment plugin\n\n");
|
Console.WriteLine("An error has occured in the payment plugin\n\n");
|
||||||
Console.WriteLine(PaymentResponse.Item2);
|
Console.WriteLine(PaymentResponse.Item2);
|
||||||
Console.WriteLine("\n");
|
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" )]
|
[Route( "/api/payment/response" )]
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
public async Task<IActionResult> paymentWebhook() {
|
public async Task<IActionResult> paymentWebhook() {
|
||||||
try {
|
try {
|
||||||
const string endpointSecret = "whsec_HCO7uv2BPIPmUPOiSg9tfwLZul8usCGG";
|
|
||||||
string body = await new StreamReader(Request.Body).ReadToEndAsync();
|
string body = await new StreamReader(Request.Body).ReadToEndAsync();
|
||||||
Stripe.Event e = Stripe.EventUtility.ConstructEvent( body, Request.Headers["Stripe-Signature"], endpointSecret );
|
await _paymentService.ValidatePurchase(body, Request.Headers["Stripe-Signature"].ToString());
|
||||||
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 );
|
|
||||||
}
|
|
||||||
return Ok();
|
return Ok();
|
||||||
} catch( Exception ex ) {
|
} catch (Exception ex) {
|
||||||
return Content(ex.ToString());
|
return NotFound(ex.ToString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,8 +4,16 @@ namespace MistoxWebsite.Server.Controllers.Payment {
|
|||||||
|
|
||||||
public interface IPayment {
|
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;
|
DatabaseService _databaseService;
|
||||||
|
|
||||||
public StripeIntent( DatabaseService databaseService ) {
|
public StripeIntent(DatabaseService databaseService) {
|
||||||
_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 {
|
try {
|
||||||
// build Recipt and calculate Tax
|
// build Recipt and calculate Tax
|
||||||
var options = new Stripe.Tax.CalculationCreateOptions {
|
var options = new Stripe.Tax.CalculationCreateOptions {
|
||||||
@@ -72,12 +72,71 @@ namespace MistoxWebsite.Server.Controllers {
|
|||||||
Stripe.PaymentIntent x = await intentService.CreateAsync(paymentIntent);
|
Stripe.PaymentIntent x = await intentService.CreateAsync(paymentIntent);
|
||||||
|
|
||||||
return (true, x.ClientSecret);
|
return (true, x.ClientSecret);
|
||||||
} catch(Exception e) {
|
} catch (Exception e) {
|
||||||
return (false, e.ToString());
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||||
using MistoxWebsite.Server.Controllers;
|
using MistoxWebsite.Server.Controllers;
|
||||||
|
using MistoxWebsite.Server.Controllers.Payment;
|
||||||
using MistoxWebsite.Server.Services;
|
using MistoxWebsite.Server.Services;
|
||||||
using MistoxWebsite.Server.Services.DatabaseService;
|
using MistoxWebsite.Server.Services.DatabaseService;
|
||||||
using Stripe;
|
using Stripe;
|
||||||
@@ -37,8 +38,15 @@ EmailService Emailservice = new EmailService( EmailServer, EmailPort, EmailAddre
|
|||||||
builder.Services.Add( new ServiceDescriptor( typeof( EmailService ), Emailservice ));
|
builder.Services.Add( new ServiceDescriptor( typeof( EmailService ), Emailservice ));
|
||||||
|
|
||||||
// Payment Service
|
// Payment Service
|
||||||
string? StripeKey = Environment.GetEnvironmentVariable("StripeKey");
|
string? PaymentService = Environment.GetEnvironmentVariable("PaymentService");
|
||||||
StripeConfiguration.ApiKey = StripeKey;
|
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
|
// Authentication Service
|
||||||
builder.Services.AddAuthentication( options => {
|
builder.Services.AddAuthentication( options => {
|
||||||
|
|||||||
Reference in New Issue
Block a user