Merged PR 46: #27 added more info to transaction + callback from stripe

#27 added more info to transaction + callback from stripe

Related work items: #27
This commit is contained in:
Dominic Villemure
2024-05-10 02:04:12 +00:00
14 changed files with 781 additions and 31 deletions

5
.gitignore vendored
View File

@@ -485,3 +485,8 @@ $RECYCLE.BIN/
# Other IDE files # Other IDE files
.vscode/ .vscode/
.idea/ .idea/
#AppSettings dev
*/appsettings.Development.json
/src/Web/appsettings.Development.json

View File

@@ -37,7 +37,7 @@
<PackageVersion Include="NUnit.Analyzers" Version="3.9.0" /> <PackageVersion Include="NUnit.Analyzers" Version="3.9.0" />
<PackageVersion Include="NUnit3TestAdapter" Version="4.5.0" /> <PackageVersion Include="NUnit3TestAdapter" Version="4.5.0" />
<PackageVersion Include="Respawn" Version="6.1.0" /> <PackageVersion Include="Respawn" Version="6.1.0" />
<PackageVersion Include="Stripe.net" Version="43.19.0" /> <PackageVersion Include="Stripe.net" Version="44.5.0" />
<PackageVersion Include="Testcontainers.MsSql" Version="3.6.0" /> <PackageVersion Include="Testcontainers.MsSql" Version="3.6.0" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@@ -1,7 +1,11 @@
using Hutopy.Application.Common.Models;
using Hutopy.Application.Stripe.Commands;
namespace Hutopy.Application.Common.Interfaces; namespace Hutopy.Application.Common.Interfaces;
public interface IStripeService public interface IStripeService
{ {
public Task<string> CreateCheckoutSession(int amount, string currency); public Task<string> CreateCheckoutSession(int amount, string currency);
public Result ValidateTransaction(ConfirmStripeTransactionCommand request);
} }

View File

@@ -1,24 +1,73 @@
using Hutopy.Application.Common.Interfaces; using Hutopy.Application.Common.Interfaces;
namespace Hutopy.Application.Stripe.Commands; namespace Hutopy.Application.Stripe.Commands;
public record ConfirmStripeTransactionCommand : IRequest<string> public class ConfirmStripeTransactionCommand : IRequest<string>
{ {
public required Guid UserTransactionId { get; init; } public string Id { get; set; }
public required bool IsConfirmed { get; init; } 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( public class ConfirmStripeTransactionCommandHandler(
IApplicationDbContext dbContext IApplicationDbContext dbContext,
IStripeService stripeService
) )
: IRequestHandler<ConfirmStripeTransactionCommand, string> : IRequestHandler<ConfirmStripeTransactionCommand, string>
{ {
public async Task<string> Handle(ConfirmStripeTransactionCommand request, CancellationToken cancellationToken) public async Task<string> Handle(ConfirmStripeTransactionCommand request, CancellationToken cancellationToken)
{ {
var transaction = await dbContext.UserTransactions.FirstOrDefaultAsync(x => x.Id == request.UserTransactionId, cancellationToken); var lastTransaction = await dbContext.UserTransactions.OrderBy(x => x.Created).LastAsync(cancellationToken);
if (transaction is null) return ""; var stripeConfirmation = stripeService.ValidateTransaction(request);
transaction.IsConfirmed = request.IsConfirmed;
dbContext.UserTransactions.Update(transaction);
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 "";
} }
} }

View File

@@ -22,9 +22,7 @@ public class CreateSessionCheckoutCommandHandler(
// ReSharper disable once PossibleLossOfFraction // ReSharper disable once PossibleLossOfFraction
decimal priceInDollars = (request.Amount / 100); 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 var userTransaction = new UserTransaction
{ {
Currency = request.Currency, Amount = priceInDollars, TipMessage = request.TipMessage, ApplicationUserId = request.CreatorId Currency = request.Currency, Amount = priceInDollars, TipMessage = request.TipMessage, ApplicationUserId = request.CreatorId

View File

@@ -8,5 +8,13 @@ public class UserTransaction : BaseAuditableEntity
// Foreign key to ApplicationUser // Foreign key to ApplicationUser
public string ApplicationUserId { get; set; } = string.Empty; 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; }
} }

View File

@@ -0,0 +1,418 @@
// <auto-generated />
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
{
/// <inheritdoc />
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<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier");
b.Property<DateTimeOffset>("Created")
.HasColumnType("datetimeoffset");
b.Property<string>("CreatedBy")
.HasColumnType("nvarchar(max)");
b.Property<string>("EmailAddress")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("FirstName")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<DateTimeOffset>("LastModified")
.HasColumnType("datetimeoffset");
b.Property<string>("LastModifiedBy")
.HasColumnType("nvarchar(max)");
b.Property<string>("LastName")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("PhoneNumber")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("ReasonToJoin")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("SocialNetworkAccount")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.HasKey("Id");
b.ToTable("FutureCreators");
});
modelBuilder.Entity("Hutopy.Domain.Entities.UserTransaction", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier");
b.Property<decimal>("Amount")
.HasPrecision(18, 2)
.HasColumnType("decimal(18,2)");
b.Property<string>("ApplicationUserId")
.IsRequired()
.HasColumnType("nvarchar(450)");
b.Property<DateTimeOffset>("Created")
.HasColumnType("datetimeoffset");
b.Property<string>("CreatedBy")
.HasColumnType("nvarchar(max)");
b.Property<string>("Currency")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<bool>("IsConfirmed")
.HasColumnType("bit");
b.Property<DateTimeOffset>("LastModified")
.HasColumnType("datetimeoffset");
b.Property<string>("LastModifiedBy")
.HasColumnType("nvarchar(max)");
b.Property<bool>("Paid")
.HasColumnType("bit");
b.Property<string>("StripeBillingDetailEmail")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("StripeBillingDetailName")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("StripeChargeId")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("StripeEventId")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("StripePaymentIntent")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("StripePaymentMethod")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("StripeReceiptUrl")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("TipMessage")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.HasKey("Id");
b.HasIndex("ApplicationUserId");
b.ToTable("UserTransactions");
});
modelBuilder.Entity("Hutopy.Infrastructure.Identity.ApplicationUser", b =>
{
b.Property<string>("Id")
.HasColumnType("nvarchar(450)");
b.Property<int>("AccessFailedCount")
.HasColumnType("int");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("nvarchar(max)");
b.Property<string>("Email")
.HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.Property<bool>("EmailConfirmed")
.HasColumnType("bit");
b.Property<string>("FirstName")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("LastName")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<bool>("LockoutEnabled")
.HasColumnType("bit");
b.Property<DateTimeOffset?>("LockoutEnd")
.HasColumnType("datetimeoffset");
b.Property<string>("NormalizedEmail")
.HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.Property<string>("NormalizedUserName")
.HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.Property<string>("PasswordHash")
.HasColumnType("nvarchar(max)");
b.Property<string>("PhoneNumber")
.HasColumnType("nvarchar(max)");
b.Property<bool>("PhoneNumberConfirmed")
.HasColumnType("bit");
b.Property<string>("SecurityStamp")
.HasColumnType("nvarchar(max)");
b.Property<bool>("TwoFactorEnabled")
.HasColumnType("bit");
b.Property<string>("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<string>("Id")
.HasColumnType("nvarchar(450)");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("nvarchar(max)");
b.Property<string>("Name")
.HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.Property<string>("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<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("ClaimType")
.HasColumnType("nvarchar(max)");
b.Property<string>("ClaimValue")
.HasColumnType("nvarchar(max)");
b.Property<string>("RoleId")
.IsRequired()
.HasColumnType("nvarchar(450)");
b.HasKey("Id");
b.HasIndex("RoleId");
b.ToTable("AspNetRoleClaims", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("ClaimType")
.HasColumnType("nvarchar(max)");
b.Property<string>("ClaimValue")
.HasColumnType("nvarchar(max)");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("nvarchar(450)");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("AspNetUserClaims", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.Property<string>("LoginProvider")
.HasColumnType("nvarchar(450)");
b.Property<string>("ProviderKey")
.HasColumnType("nvarchar(450)");
b.Property<string>("ProviderDisplayName")
.HasColumnType("nvarchar(max)");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("nvarchar(450)");
b.HasKey("LoginProvider", "ProviderKey");
b.HasIndex("UserId");
b.ToTable("AspNetUserLogins", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("nvarchar(450)");
b.Property<string>("RoleId")
.HasColumnType("nvarchar(450)");
b.HasKey("UserId", "RoleId");
b.HasIndex("RoleId");
b.ToTable("AspNetUserRoles", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("nvarchar(450)");
b.Property<string>("LoginProvider")
.HasColumnType("nvarchar(450)");
b.Property<string>("Name")
.HasColumnType("nvarchar(450)");
b.Property<string>("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<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.HasOne("Hutopy.Infrastructure.Identity.ApplicationUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.HasOne("Hutopy.Infrastructure.Identity.ApplicationUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", 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<string>", b =>
{
b.HasOne("Hutopy.Infrastructure.Identity.ApplicationUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
#pragma warning restore 612, 618
}
}
}

View File

@@ -0,0 +1,106 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Hutopy.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class AddMoreInformationToTransaction : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<bool>(
name: "Paid",
table: "UserTransactions",
type: "bit",
nullable: false,
defaultValue: false);
migrationBuilder.AddColumn<string>(
name: "StripeBillingDetailEmail",
table: "UserTransactions",
type: "nvarchar(max)",
nullable: false,
defaultValue: "");
migrationBuilder.AddColumn<string>(
name: "StripeBillingDetailName",
table: "UserTransactions",
type: "nvarchar(max)",
nullable: false,
defaultValue: "");
migrationBuilder.AddColumn<string>(
name: "StripeChargeId",
table: "UserTransactions",
type: "nvarchar(max)",
nullable: false,
defaultValue: "");
migrationBuilder.AddColumn<string>(
name: "StripeEventId",
table: "UserTransactions",
type: "nvarchar(max)",
nullable: false,
defaultValue: "");
migrationBuilder.AddColumn<string>(
name: "StripePaymentIntent",
table: "UserTransactions",
type: "nvarchar(max)",
nullable: false,
defaultValue: "");
migrationBuilder.AddColumn<string>(
name: "StripePaymentMethod",
table: "UserTransactions",
type: "nvarchar(max)",
nullable: false,
defaultValue: "");
migrationBuilder.AddColumn<string>(
name: "StripeReceiptUrl",
table: "UserTransactions",
type: "nvarchar(max)",
nullable: false,
defaultValue: "");
}
/// <inheritdoc />
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");
}
}
}

View File

@@ -102,6 +102,37 @@ namespace Hutopy.Infrastructure.Migrations
b.Property<string>("LastModifiedBy") b.Property<string>("LastModifiedBy")
.HasColumnType("nvarchar(max)"); .HasColumnType("nvarchar(max)");
b.Property<bool>("Paid")
.HasColumnType("bit");
b.Property<string>("StripeBillingDetailEmail")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("StripeBillingDetailName")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("StripeChargeId")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("StripeEventId")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("StripePaymentIntent")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("StripePaymentMethod")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("StripeReceiptUrl")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("TipMessage") b.Property<string>("TipMessage")
.IsRequired() .IsRequired()
.HasColumnType("nvarchar(max)"); .HasColumnType("nvarchar(max)");

View File

@@ -1,13 +1,20 @@
using Stripe; using Stripe;
using Stripe.Checkout; using Stripe.Checkout;
using Hutopy.Application.Common.Interfaces; using Hutopy.Application.Common.Interfaces;
using Microsoft.AspNetCore.Http;
using Hutopy.Application.Common.Models;
using Hutopy.Application.Stripe.Commands;
namespace Hutopy.Infrastructure.Stripe; namespace Hutopy.Infrastructure.Stripe;
public class StripeService : IStripeService public class StripeService : IStripeService
{ {
public StripeService() const string EndpointSecret = "";
private readonly IHttpContextAccessor _httpContextAccessor;
public StripeService(IHttpContextAccessor httpContextAccessor)
{ {
_httpContextAccessor = httpContextAccessor;
StripeConfiguration.ApiKey = ""; StripeConfiguration.ApiKey = "";
} }
@@ -31,7 +38,7 @@ public class StripeService : IStripeService
], ],
Mode = "payment", Mode = "payment",
UiMode = "embedded", UiMode = "embedded",
ReturnUrl = "https://zealous-bay-08204590f.5.azurestaticapps.net/paymentcompleted", ReturnUrl = "https://hutopy.ca/paymentcompleted",
}; };
var service = new SessionService(); var service = new SessionService();
@@ -39,4 +46,27 @@ public class StripeService : IStripeService
return session.ClientSecret; return session.ClientSecret;
} }
public Result ValidateTransaction(ConfirmStripeTransactionCommand request)
{
try
{
if (request.Data.Object.Status is "succeeded")
{
return new Result(true, new List<string>());
}
return new Result(false, new List<string>());
}
catch (StripeException e)
{
Console.WriteLine("Error: {0}", e.Message);
return new Result(false, new List<string>{e.Message});
}
catch (Exception e)
{
return new Result(false, new List<string>{e.Message});
}
}
} }

View File

@@ -16,8 +16,8 @@ public class Stripe : EndpointGroupBase
return sender.Send(command); return sender.Send(command);
} }
private static Task<string> ConfirmTransaction(ISender sender, ConfirmStripeTransactionCommand command) private async static Task<string> ConfirmTransaction(ISender sender, ConfirmStripeTransactionCommand command)
{ {
return sender.Send(command); return await sender.Send(command);
} }
} }

View File

@@ -0,0 +1,29 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Information",
"Microsoft.AspNetCore.SpaProxy": "Information",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"Google": {
"ClientId": "",
"ClientSecret": "",
"ProjectId": "",
"AuthUri": "",
"TokenUri": "",
"AuthProviderX509CertUrl": "",
"RedirectUris": [
"https://hutopy.ca",
"https://hutopy.com",
"http://localhost"
],
"JavascriptOrigins": [
"https://hutopy.ca",
"https://hutopy.com",
"http://localhost"
]
}
}

View File

@@ -1,10 +0,0 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.AspNetCore.SpaProxy": "Information",
"Microsoft.Hosting.Lifetime": "Information"
}
}
}

View File

@@ -723,12 +723,94 @@
"type": "object", "type": "object",
"additionalProperties": false, "additionalProperties": false,
"properties": { "properties": {
"userTransactionId": { "id": {
"type": "string", "type": "string"
"format": "guid"
}, },
"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" "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"
} }
} }
}, },