diff --git a/Directory.Packages.props b/Directory.Packages.props
index 74620e0..90a35bf 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -37,7 +37,7 @@
-
+
\ No newline at end of file
diff --git a/src/Application/Application.csproj b/src/Application/Application.csproj
index 8544947..e01512a 100644
--- a/src/Application/Application.csproj
+++ b/src/Application/Application.csproj
@@ -10,6 +10,7 @@
+
diff --git a/src/Application/Common/Interfaces/IStripeService.cs b/src/Application/Common/Interfaces/IStripeService.cs
index 75edbe9..ca32184 100644
--- a/src/Application/Common/Interfaces/IStripeService.cs
+++ b/src/Application/Common/Interfaces/IStripeService.cs
@@ -1,7 +1,11 @@
+using Hutopy.Application.Common.Models;
+using Hutopy.Application.Stripe.Commands;
+
namespace Hutopy.Application.Common.Interfaces;
public interface IStripeService
{
public Task CreateCheckoutSession(int amount, string currency);
+ public Result ValidateTransaction(ConfirmStripeTransactionCommand request);
}
diff --git a/src/Application/Stripe/Commands/ConfirmStripeTransaction.cs b/src/Application/Stripe/Commands/ConfirmStripeTransaction.cs
index 7aa8a3e..ea5a61c 100644
--- a/src/Application/Stripe/Commands/ConfirmStripeTransaction.cs
+++ b/src/Application/Stripe/Commands/ConfirmStripeTransaction.cs
@@ -1,24 +1,75 @@
using Hutopy.Application.Common.Interfaces;
+using Stripe;
+
namespace Hutopy.Application.Stripe.Commands;
-public record ConfirmStripeTransactionCommand : IRequest
+public class ConfirmStripeTransactionCommand : IRequest
{
- public required Guid UserTransactionId { get; init; }
- public required bool IsConfirmed { get; init; }
+ public string Id { get; set; }
+ public string Object { get; set; }
+ public int Created { get; set; }
+ public Data Data { get; set; }
+ public Request Request { get; set; }
+}
+
+public class Data
+{
+ public Object Object { get; set; }
+}
+
+public class Object
+{
+ public string Id { get; set; } = String.Empty;
+ public int Amount { get; set; }
+ public BillingDetails Billing_details { get; set; } = new();
+ public string Calculated_statement_descriptor { get; set; } = String.Empty;
+ public string Currency { get; set; } = String.Empty;
+ public bool Paid { get; set; }
+ public string Payment_intent { get; set; } = String.Empty;
+ public string Payment_method { get; set; } = String.Empty;
+ public string Receipt_url { get; set; } = String.Empty;
+ public string Status { get; set; } = String.Empty;
+ public string Failure_message { get; set; } = String.Empty;
+}
+
+public class BillingDetails
+{
+ public string Email { get; set; } = String.Empty;
+ public string Name { get; set; } = String.Empty;
+ public string Phone { get; set; } = String.Empty;
+}
+
+public class Request
+{
+ public string Id { get; set; } = String.Empty;
}
public class ConfirmStripeTransactionCommandHandler(
- IApplicationDbContext dbContext
+ IApplicationDbContext dbContext,
+ IStripeService stripeService
)
: IRequestHandler
{
public async Task Handle(ConfirmStripeTransactionCommand request, CancellationToken cancellationToken)
{
- var transaction = await dbContext.UserTransactions.FirstOrDefaultAsync(x => x.Id == request.UserTransactionId, cancellationToken);
- if (transaction is null) return "";
- transaction.IsConfirmed = request.IsConfirmed;
- dbContext.UserTransactions.Update(transaction);
+ var lastTransaction = await dbContext.UserTransactions.OrderBy(x => x.Created).LastAsync(cancellationToken);
+ var stripeConfirmation = stripeService.ValidateTransaction(request);
- return transaction.Id.ToString();
+ if (stripeConfirmation.Succeeded)
+ {
+ lastTransaction.IsConfirmed = true;
+ lastTransaction.Paid = request.Data.Object.Paid;
+ lastTransaction.StripeChargeId = request.Data.Object.Id;
+ lastTransaction.StripeEventId = request.Id;
+ lastTransaction.StripeReceiptUrl = request.Data.Object.Receipt_url;
+ lastTransaction.StripePaymentIntent = request.Data.Object.Payment_intent;
+ lastTransaction.StripePaymentMethod = request.Data.Object.Payment_method;
+ lastTransaction.StripeBillingDetailEmail = request.Data.Object.Billing_details.Email;
+ lastTransaction.StripeBillingDetailName = request.Data.Object.Billing_details.Name;
+ }
+
+ await dbContext.SaveChangesAsync(cancellationToken);
+
+ return "";
}
}
diff --git a/src/Application/Stripe/Commands/CreateSessionCheckoutCommand.cs b/src/Application/Stripe/Commands/CreateSessionCheckoutCommand.cs
index b428733..28e9d72 100644
--- a/src/Application/Stripe/Commands/CreateSessionCheckoutCommand.cs
+++ b/src/Application/Stripe/Commands/CreateSessionCheckoutCommand.cs
@@ -22,9 +22,7 @@ public class CreateSessionCheckoutCommandHandler(
// ReSharper disable once PossibleLossOfFraction
decimal priceInDollars = (request.Amount / 100);
-
- //todo: Need to add this transaction after the confirmation from stripe in the frontEnd ( redirect, re-call backend )
var userTransaction = new UserTransaction
{
Currency = request.Currency, Amount = priceInDollars, TipMessage = request.TipMessage, ApplicationUserId = request.CreatorId
diff --git a/src/Domain/Entities/UserTransaction.cs b/src/Domain/Entities/UserTransaction.cs
index b879fd2..5ab7314 100644
--- a/src/Domain/Entities/UserTransaction.cs
+++ b/src/Domain/Entities/UserTransaction.cs
@@ -8,5 +8,13 @@ public class UserTransaction : BaseAuditableEntity
// Foreign key to ApplicationUser
public string ApplicationUserId { get; set; } = string.Empty;
- public bool IsConfirmed { get; set; } = false;
+ public bool IsConfirmed { get; set; }
+ public string StripeEventId { get; set; } = string.Empty;
+ public string StripeChargeId { get; set; } = string.Empty;
+ public string StripePaymentIntent { get; set; } = string.Empty;
+ public string StripePaymentMethod { get; set; } = string.Empty;
+ public string StripeReceiptUrl { get; set; } = string.Empty;
+ public string StripeBillingDetailEmail { get; set; } = string.Empty;
+ public string StripeBillingDetailName { get; set; } = string.Empty;
+ public bool Paid { get; set; }
}
diff --git a/src/Infrastructure/Migrations/20240509215538_AddMoreInformationToTransaction.Designer.cs b/src/Infrastructure/Migrations/20240509215538_AddMoreInformationToTransaction.Designer.cs
new file mode 100644
index 0000000..f8c9e81
--- /dev/null
+++ b/src/Infrastructure/Migrations/20240509215538_AddMoreInformationToTransaction.Designer.cs
@@ -0,0 +1,418 @@
+//
+using System;
+using Hutopy.Infrastructure.Data;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Metadata;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+
+#nullable disable
+
+namespace Hutopy.Infrastructure.Migrations
+{
+ [DbContext(typeof(ApplicationDbContext))]
+ [Migration("20240509215538_AddMoreInformationToTransaction")]
+ partial class AddMoreInformationToTransaction
+ {
+ ///
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "8.0.3")
+ .HasAnnotation("Relational:MaxIdentifierLength", 128);
+
+ SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
+
+ modelBuilder.Entity("Hutopy.Domain.Entities.FutureCreator", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uniqueidentifier");
+
+ b.Property("Created")
+ .HasColumnType("datetimeoffset");
+
+ b.Property("CreatedBy")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("EmailAddress")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("FirstName")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("LastModified")
+ .HasColumnType("datetimeoffset");
+
+ b.Property("LastModifiedBy")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("LastName")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("PhoneNumber")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("ReasonToJoin")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("SocialNetworkAccount")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.HasKey("Id");
+
+ b.ToTable("FutureCreators");
+ });
+
+ modelBuilder.Entity("Hutopy.Domain.Entities.UserTransaction", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uniqueidentifier");
+
+ b.Property("Amount")
+ .HasPrecision(18, 2)
+ .HasColumnType("decimal(18,2)");
+
+ b.Property("ApplicationUserId")
+ .IsRequired()
+ .HasColumnType("nvarchar(450)");
+
+ b.Property("Created")
+ .HasColumnType("datetimeoffset");
+
+ b.Property("CreatedBy")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("Currency")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("IsConfirmed")
+ .HasColumnType("bit");
+
+ b.Property("LastModified")
+ .HasColumnType("datetimeoffset");
+
+ b.Property("LastModifiedBy")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("Paid")
+ .HasColumnType("bit");
+
+ b.Property("StripeBillingDetailEmail")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("StripeBillingDetailName")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("StripeChargeId")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("StripeEventId")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("StripePaymentIntent")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("StripePaymentMethod")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("StripeReceiptUrl")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("TipMessage")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("ApplicationUserId");
+
+ b.ToTable("UserTransactions");
+ });
+
+ modelBuilder.Entity("Hutopy.Infrastructure.Identity.ApplicationUser", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("nvarchar(450)");
+
+ b.Property("AccessFailedCount")
+ .HasColumnType("int");
+
+ b.Property("ConcurrencyStamp")
+ .IsConcurrencyToken()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("Email")
+ .HasMaxLength(256)
+ .HasColumnType("nvarchar(256)");
+
+ b.Property("EmailConfirmed")
+ .HasColumnType("bit");
+
+ b.Property("FirstName")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("LastName")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("LockoutEnabled")
+ .HasColumnType("bit");
+
+ b.Property("LockoutEnd")
+ .HasColumnType("datetimeoffset");
+
+ b.Property("NormalizedEmail")
+ .HasMaxLength(256)
+ .HasColumnType("nvarchar(256)");
+
+ b.Property("NormalizedUserName")
+ .HasMaxLength(256)
+ .HasColumnType("nvarchar(256)");
+
+ b.Property("PasswordHash")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("PhoneNumber")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("PhoneNumberConfirmed")
+ .HasColumnType("bit");
+
+ b.Property("SecurityStamp")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("TwoFactorEnabled")
+ .HasColumnType("bit");
+
+ b.Property("UserName")
+ .HasMaxLength(256)
+ .HasColumnType("nvarchar(256)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("NormalizedEmail")
+ .HasDatabaseName("EmailIndex");
+
+ b.HasIndex("NormalizedUserName")
+ .IsUnique()
+ .HasDatabaseName("UserNameIndex")
+ .HasFilter("[NormalizedUserName] IS NOT NULL");
+
+ b.ToTable("AspNetUsers", (string)null);
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("nvarchar(450)");
+
+ b.Property("ConcurrencyStamp")
+ .IsConcurrencyToken()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("Name")
+ .HasMaxLength(256)
+ .HasColumnType("nvarchar(256)");
+
+ b.Property("NormalizedName")
+ .HasMaxLength(256)
+ .HasColumnType("nvarchar(256)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("NormalizedName")
+ .IsUnique()
+ .HasDatabaseName("RoleNameIndex")
+ .HasFilter("[NormalizedName] IS NOT NULL");
+
+ b.ToTable("AspNetRoles", (string)null);
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
+
+ b.Property("ClaimType")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("ClaimValue")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("RoleId")
+ .IsRequired()
+ .HasColumnType("nvarchar(450)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("RoleId");
+
+ b.ToTable("AspNetRoleClaims", (string)null);
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
+
+ b.Property("ClaimType")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("ClaimValue")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("UserId")
+ .IsRequired()
+ .HasColumnType("nvarchar(450)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("AspNetUserClaims", (string)null);
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b =>
+ {
+ b.Property("LoginProvider")
+ .HasColumnType("nvarchar(450)");
+
+ b.Property("ProviderKey")
+ .HasColumnType("nvarchar(450)");
+
+ b.Property("ProviderDisplayName")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("UserId")
+ .IsRequired()
+ .HasColumnType("nvarchar(450)");
+
+ b.HasKey("LoginProvider", "ProviderKey");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("AspNetUserLogins", (string)null);
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b =>
+ {
+ b.Property("UserId")
+ .HasColumnType("nvarchar(450)");
+
+ b.Property("RoleId")
+ .HasColumnType("nvarchar(450)");
+
+ b.HasKey("UserId", "RoleId");
+
+ b.HasIndex("RoleId");
+
+ b.ToTable("AspNetUserRoles", (string)null);
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b =>
+ {
+ b.Property("UserId")
+ .HasColumnType("nvarchar(450)");
+
+ b.Property("LoginProvider")
+ .HasColumnType("nvarchar(450)");
+
+ b.Property("Name")
+ .HasColumnType("nvarchar(450)");
+
+ b.Property("Value")
+ .HasColumnType("nvarchar(max)");
+
+ b.HasKey("UserId", "LoginProvider", "Name");
+
+ b.ToTable("AspNetUserTokens", (string)null);
+ });
+
+ modelBuilder.Entity("Hutopy.Domain.Entities.UserTransaction", b =>
+ {
+ b.HasOne("Hutopy.Infrastructure.Identity.ApplicationUser", null)
+ .WithMany()
+ .HasForeignKey("ApplicationUserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b =>
+ {
+ b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
+ .WithMany()
+ .HasForeignKey("RoleId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b =>
+ {
+ b.HasOne("Hutopy.Infrastructure.Identity.ApplicationUser", null)
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b =>
+ {
+ b.HasOne("Hutopy.Infrastructure.Identity.ApplicationUser", null)
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b =>
+ {
+ b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
+ .WithMany()
+ .HasForeignKey("RoleId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("Hutopy.Infrastructure.Identity.ApplicationUser", null)
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b =>
+ {
+ b.HasOne("Hutopy.Infrastructure.Identity.ApplicationUser", null)
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/src/Infrastructure/Migrations/20240509215538_AddMoreInformationToTransaction.cs b/src/Infrastructure/Migrations/20240509215538_AddMoreInformationToTransaction.cs
new file mode 100644
index 0000000..d91d3cf
--- /dev/null
+++ b/src/Infrastructure/Migrations/20240509215538_AddMoreInformationToTransaction.cs
@@ -0,0 +1,106 @@
+using Microsoft.EntityFrameworkCore.Migrations;
+
+#nullable disable
+
+namespace Hutopy.Infrastructure.Migrations
+{
+ ///
+ public partial class AddMoreInformationToTransaction : Migration
+ {
+ ///
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.AddColumn(
+ name: "Paid",
+ table: "UserTransactions",
+ type: "bit",
+ nullable: false,
+ defaultValue: false);
+
+ migrationBuilder.AddColumn(
+ name: "StripeBillingDetailEmail",
+ table: "UserTransactions",
+ type: "nvarchar(max)",
+ nullable: false,
+ defaultValue: "");
+
+ migrationBuilder.AddColumn(
+ name: "StripeBillingDetailName",
+ table: "UserTransactions",
+ type: "nvarchar(max)",
+ nullable: false,
+ defaultValue: "");
+
+ migrationBuilder.AddColumn(
+ name: "StripeChargeId",
+ table: "UserTransactions",
+ type: "nvarchar(max)",
+ nullable: false,
+ defaultValue: "");
+
+ migrationBuilder.AddColumn(
+ name: "StripeEventId",
+ table: "UserTransactions",
+ type: "nvarchar(max)",
+ nullable: false,
+ defaultValue: "");
+
+ migrationBuilder.AddColumn(
+ name: "StripePaymentIntent",
+ table: "UserTransactions",
+ type: "nvarchar(max)",
+ nullable: false,
+ defaultValue: "");
+
+ migrationBuilder.AddColumn(
+ name: "StripePaymentMethod",
+ table: "UserTransactions",
+ type: "nvarchar(max)",
+ nullable: false,
+ defaultValue: "");
+
+ migrationBuilder.AddColumn(
+ name: "StripeReceiptUrl",
+ table: "UserTransactions",
+ type: "nvarchar(max)",
+ nullable: false,
+ defaultValue: "");
+ }
+
+ ///
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropColumn(
+ name: "Paid",
+ table: "UserTransactions");
+
+ migrationBuilder.DropColumn(
+ name: "StripeBillingDetailEmail",
+ table: "UserTransactions");
+
+ migrationBuilder.DropColumn(
+ name: "StripeBillingDetailName",
+ table: "UserTransactions");
+
+ migrationBuilder.DropColumn(
+ name: "StripeChargeId",
+ table: "UserTransactions");
+
+ migrationBuilder.DropColumn(
+ name: "StripeEventId",
+ table: "UserTransactions");
+
+ migrationBuilder.DropColumn(
+ name: "StripePaymentIntent",
+ table: "UserTransactions");
+
+ migrationBuilder.DropColumn(
+ name: "StripePaymentMethod",
+ table: "UserTransactions");
+
+ migrationBuilder.DropColumn(
+ name: "StripeReceiptUrl",
+ table: "UserTransactions");
+ }
+ }
+}
diff --git a/src/Infrastructure/Migrations/ApplicationDbContextModelSnapshot.cs b/src/Infrastructure/Migrations/ApplicationDbContextModelSnapshot.cs
index dedb234..cb3b55f 100644
--- a/src/Infrastructure/Migrations/ApplicationDbContextModelSnapshot.cs
+++ b/src/Infrastructure/Migrations/ApplicationDbContextModelSnapshot.cs
@@ -102,6 +102,37 @@ namespace Hutopy.Infrastructure.Migrations
b.Property("LastModifiedBy")
.HasColumnType("nvarchar(max)");
+ b.Property("Paid")
+ .HasColumnType("bit");
+
+ b.Property("StripeBillingDetailEmail")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("StripeBillingDetailName")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("StripeChargeId")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("StripeEventId")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("StripePaymentIntent")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("StripePaymentMethod")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("StripeReceiptUrl")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
b.Property("TipMessage")
.IsRequired()
.HasColumnType("nvarchar(max)");
diff --git a/src/Infrastructure/Stripe/StripeService.cs b/src/Infrastructure/Stripe/StripeService.cs
index 881b6c4..dc84e34 100644
--- a/src/Infrastructure/Stripe/StripeService.cs
+++ b/src/Infrastructure/Stripe/StripeService.cs
@@ -1,13 +1,20 @@
using Stripe;
using Stripe.Checkout;
using Hutopy.Application.Common.Interfaces;
+using Microsoft.AspNetCore.Http;
+using Hutopy.Application.Common.Models;
+using Hutopy.Application.Stripe.Commands;
namespace Hutopy.Infrastructure.Stripe;
public class StripeService : IStripeService
{
- public StripeService()
+ const string EndpointSecret = "";
+ private readonly IHttpContextAccessor _httpContextAccessor;
+
+ public StripeService(IHttpContextAccessor httpContextAccessor)
{
+ _httpContextAccessor = httpContextAccessor;
StripeConfiguration.ApiKey = "";
}
@@ -31,7 +38,7 @@ public class StripeService : IStripeService
],
Mode = "payment",
UiMode = "embedded",
- ReturnUrl = "https://zealous-bay-08204590f.5.azurestaticapps.net/paymentcompleted",
+ ReturnUrl = "https://hutopy.ca/paymentcompleted",
};
var service = new SessionService();
@@ -39,4 +46,27 @@ public class StripeService : IStripeService
return session.ClientSecret;
}
+
+ public Result ValidateTransaction(ConfirmStripeTransactionCommand request)
+ {
+ try
+ {
+ if (request.Data.Object.Status is "succeeded")
+ {
+ return new Result(true, new List());
+ }
+
+ return new Result(false, new List());
+
+ }
+ catch (StripeException e)
+ {
+ Console.WriteLine("Error: {0}", e.Message);
+ return new Result(false, new List{e.Message});
+ }
+ catch (Exception e)
+ {
+ return new Result(false, new List{e.Message});
+ }
+ }
}
diff --git a/src/Web/Endpoints/Stripe.cs b/src/Web/Endpoints/Stripe.cs
index b944419..264f4c8 100644
--- a/src/Web/Endpoints/Stripe.cs
+++ b/src/Web/Endpoints/Stripe.cs
@@ -16,8 +16,8 @@ public class Stripe : EndpointGroupBase
return sender.Send(command);
}
- private static Task ConfirmTransaction(ISender sender, ConfirmStripeTransactionCommand command)
+ private async static Task ConfirmTransaction(ISender sender, ConfirmStripeTransactionCommand command)
{
- return sender.Send(command);
+ return await sender.Send(command);
}
}
diff --git a/src/Web/appsettings.Development.json b/src/Web/appsettings.Development.json
index 84308c9..b98033c 100644
--- a/src/Web/appsettings.Development.json
+++ b/src/Web/appsettings.Development.json
@@ -2,9 +2,28 @@
"Logging": {
"LogLevel": {
"Default": "Information",
- "Microsoft": "Warning",
+ "Microsoft": "Information",
"Microsoft.AspNetCore.SpaProxy": "Information",
"Microsoft.Hosting.Lifetime": "Information"
}
+ },
+ "Google": {
+ "ClientId": "468391910875-78sfopq1t12ulrv4f5vj227j45guuj66.apps.googleusercontent.com",
+ "ClientSecret": "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",
+ "ProjectId": "hutopy-420016",
+ "AuthUri": "https://accounts.google.com/o/oauth2/auth",
+ "TokenUri": "https://oauth2.googleapis.com/token",
+ "AuthProviderX509CertUrl": "https://www.googleapis.com/oauth2/v1/certs",
+ "RedirectUris": [
+ "https://hutopy.ca",
+ "https://hutopy.com",
+ "http://localhost"
+ ],
+ "JavascriptOrigins": [
+ "https://hutopy.ca",
+ "https://hutopy.com",
+ "http://localhost"
+ ]
}
}
+
diff --git a/src/Web/wwwroot/api/specification.json b/src/Web/wwwroot/api/specification.json
index 5a1838c..9c7a80c 100644
--- a/src/Web/wwwroot/api/specification.json
+++ b/src/Web/wwwroot/api/specification.json
@@ -723,12 +723,94 @@
"type": "object",
"additionalProperties": false,
"properties": {
- "userTransactionId": {
- "type": "string",
- "format": "guid"
+ "id": {
+ "type": "string"
},
- "isConfirmed": {
+ "object": {
+ "type": "string"
+ },
+ "created": {
+ "type": "integer",
+ "format": "int32"
+ },
+ "data": {
+ "$ref": "#/components/schemas/Data"
+ },
+ "request": {
+ "$ref": "#/components/schemas/Request"
+ }
+ }
+ },
+ "Data": {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "object": {
+ "$ref": "#/components/schemas/Object"
+ }
+ }
+ },
+ "Object": {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "id": {
+ "type": "string"
+ },
+ "amount": {
+ "type": "integer",
+ "format": "int32"
+ },
+ "billing_details": {
+ "$ref": "#/components/schemas/BillingDetails"
+ },
+ "calculated_statement_descriptor": {
+ "type": "string"
+ },
+ "currency": {
+ "type": "string"
+ },
+ "paid": {
"type": "boolean"
+ },
+ "payment_intent": {
+ "type": "string"
+ },
+ "payment_method": {
+ "type": "string"
+ },
+ "receipt_url": {
+ "type": "string"
+ },
+ "status": {
+ "type": "string"
+ },
+ "failure_message": {
+ "type": "string"
+ }
+ }
+ },
+ "BillingDetails": {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "email": {
+ "type": "string"
+ },
+ "name": {
+ "type": "string"
+ },
+ "phone": {
+ "type": "string"
+ }
+ }
+ },
+ "Request": {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "id": {
+ "type": "string"
}
}
},