This commit is contained in:
Damien Ostler 2024-01-27 20:12:52 -05:00
parent 1fd4a3160a
commit d3afd7948b
19 changed files with 848 additions and 66 deletions

View File

@ -1,5 +1,6 @@
using ArtPlatform.API.Extensions; using ArtPlatform.API.Extensions;
using ArtPlatform.API.Models.Order; using ArtPlatform.API.Models.Order;
using ArtPlatform.API.Services.Payment;
using ArtPlatform.API.Services.Storage; using ArtPlatform.API.Services.Storage;
using ArtPlatform.Database; using ArtPlatform.Database;
using ArtPlatform.Database.Entities; using ArtPlatform.Database.Entities;
@ -7,6 +8,8 @@ using ArtPlatform.Database.Enums;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Stripe;
using Stripe.Checkout;
namespace ArtPlatform.API.Controllers; namespace ArtPlatform.API.Controllers;
@ -16,11 +19,52 @@ public class OrderController : Controller
{ {
private readonly ApplicationDbContext _dbContext; private readonly ApplicationDbContext _dbContext;
private readonly IStorageService _storageService; private readonly IStorageService _storageService;
private readonly IPaymentService _paymentService;
private readonly IConfiguration _configuration;
private readonly string _webHookSecret;
public OrderController(ApplicationDbContext dbContext, IStorageService storageService) public OrderController(ApplicationDbContext dbContext, IConfiguration configuration, IStorageService storageService, IPaymentService paymentService)
{ {
_configuration = configuration;
_paymentService = paymentService;
_storageService = storageService; _storageService = storageService;
_dbContext = dbContext; _dbContext = dbContext;
_webHookSecret = _configuration.GetValue<string>("Stripe:WebHookSecret");
}
[HttpPost("PaymentWebhook")]
public async Task<IActionResult> ProcessWebhookEvent()
{
var json = await new StreamReader(HttpContext.Request.Body).ReadToEndAsync();
// If you are testing your webhook locally with the Stripe CLI you
// can find the endpoint's secret by running `stripe listen`
// Otherwise, find your endpoint's secret in your webhook settings
// in the Developer Dashboard
var stripeEvent = EventUtility.ConstructEvent(json, Request.Headers["Stripe-Signature"], _webHookSecret);
if (stripeEvent.Type == Events.CheckoutSessionAsyncPaymentSucceeded)
{
var session = stripeEvent.Data.Object as Session;
var connectedAccountId = stripeEvent.Account;
}
else if (stripeEvent.Type == Events.CheckoutSessionAsyncPaymentFailed)
{
var session = stripeEvent.Data.Object as Session;
var connectedAccountId = stripeEvent.Account;
}
else if (stripeEvent.Type == Events.CheckoutSessionCompleted)
{
}
else if (stripeEvent.Type == Events.CheckoutSessionExpired)
{
}
// ... handle other event types
else
{
Console.WriteLine("Unhandled event type: {0}", stripeEvent.Type);
}
return Ok();
} }
[HttpGet] [HttpGet]
@ -104,6 +148,7 @@ public class OrderController : Controller
var userId = User.GetUserId(); var userId = User.GetUserId();
var order = await _dbContext.SellerServiceOrders var order = await _dbContext.SellerServiceOrders
.Include(x=>x.SellerService) .Include(x=>x.SellerService)
.Include(x=>x.Buyer)
.Include(x=>x.Seller) .Include(x=>x.Seller)
.FirstOrDefaultAsync(x=>x.Id==orderId && x.BuyerId==userId); .FirstOrDefaultAsync(x=>x.Id==orderId && x.BuyerId==userId);
if(order==null) if(order==null)
@ -114,8 +159,61 @@ public class OrderController : Controller
return BadRequest("Order is already complete."); return BadRequest("Order is already complete.");
if(order.Status<EnumOrderStatus.DiscussingRequirements) if(order.Status<EnumOrderStatus.DiscussingRequirements)
return BadRequest("Order has not been started yet."); return BadRequest("Order has not been started yet.");
order.Status = EnumOrderStatus.InProgress;
if(string.IsNullOrEmpty(order.PaymentUrl)==false)
return BadRequest("Order has price already been agreed on.");
order.TermsAcceptedDate = DateTime.UtcNow; order.TermsAcceptedDate = DateTime.UtcNow;
if (order.Seller.PrepaymentRequired)
{
order.Status = EnumOrderStatus.WaitingForPayment;
var url = _paymentService.ChargeForService(order.SellerServiceId, order.Buyer.StripeCustomerId, order.Seller.StripeAccountId, order.Price);
order.PaymentUrl = url;
}
else
{
order.Status = EnumOrderStatus.InProgress;
}
order = _dbContext.SellerServiceOrders.Update(order).Entity;
await _dbContext.SaveChangesAsync();
var result = order.ToModel();
return Ok(result);
}
[HttpPut]
[Authorize("write:orders")]
[Route("Orders/{orderId:int}/Payment")]
public async Task<IActionResult> Payment(int orderId)
{
var userId = User.GetUserId();
var order = await _dbContext.SellerServiceOrders
.Include(x=>x.SellerService)
.Include(x=>x.Buyer)
.Include(x=>x.Seller)
.FirstOrDefaultAsync(x=>x.Id==orderId && x.BuyerId==userId);
if(order==null)
return NotFound("Order not found.");
if(order.Seller.UserId!=userId)
return BadRequest("You are not the seller of this order.");
if(order.Status==EnumOrderStatus.Completed)
return BadRequest("Order is already complete.");
if(order.Status!=EnumOrderStatus.WaitingForPayment)
return BadRequest("Order does not need to be paid for.");
order.TermsAcceptedDate = DateTime.UtcNow;
if (order.Seller.PrepaymentRequired)
{
order.Status = EnumOrderStatus.InProgress;
var url = _paymentService.ChargeForService(order.SellerServiceId, order.Buyer.StripeCustomerId, order.Seller.StripeAccountId, order.Price);
order.PaymentUrl = url;
}
else
{
order.Status = EnumOrderStatus.Completed;
var url = _paymentService.ChargeForService(order.SellerServiceId, order.Buyer.StripeCustomerId, order.Seller.StripeAccountId, order.Price);
order.PaymentUrl = url;
}
order = _dbContext.SellerServiceOrders.Update(order).Entity; order = _dbContext.SellerServiceOrders.Update(order).Entity;
await _dbContext.SaveChangesAsync(); await _dbContext.SaveChangesAsync();
var result = order.ToModel(); var result = order.ToModel();
@ -142,7 +240,16 @@ public class OrderController : Controller
return BadRequest("Order has not been started yet."); return BadRequest("Order has not been started yet.");
if(order.Status<EnumOrderStatus.PendingReview) if(order.Status<EnumOrderStatus.PendingReview)
return BadRequest("Order is in progress and not pending review."); return BadRequest("Order is in progress and not pending review.");
order.Status = EnumOrderStatus.Completed;
if(order.Seller.PrepaymentRequired)
order.Status = EnumOrderStatus.Completed;
else
{
order.Status = EnumOrderStatus.WaitingForPayment;
var url = _paymentService.ChargeForService(order.SellerServiceId, order.Buyer.StripeCustomerId, order.Seller.StripeAccountId, order.Price);
order.PaymentUrl = url;
}
order.TermsAcceptedDate = DateTime.UtcNow; order.TermsAcceptedDate = DateTime.UtcNow;
order = _dbContext.SellerServiceOrders.Update(order).Entity; order = _dbContext.SellerServiceOrders.Update(order).Entity;
await _dbContext.SaveChangesAsync(); await _dbContext.SaveChangesAsync();

View File

@ -196,8 +196,10 @@ public class SellerProfileController : Controller
return BadRequest("Account has requested to be a seller and not been approved yet."); return BadRequest("Account has requested to be a seller and not been approved yet.");
return Unauthorized("Account is not a seller."); return Unauthorized("Account is not a seller.");
} }
if(existingSellerProfile.StripeAccountId!=null) if(existingSellerProfile.StripeAccountId!=null)
return BadRequest("Account already has a payment account."); return BadRequest("Account already have a payment account.");
var accountId = _paymentService.CreateSellerAccount(); var accountId = _paymentService.CreateSellerAccount();
existingSellerProfile.StripeAccountId = accountId; existingSellerProfile.StripeAccountId = accountId;
existingSellerProfile = _dbContext.UserSellerProfiles.Update(existingSellerProfile).Entity; existingSellerProfile = _dbContext.UserSellerProfiles.Update(existingSellerProfile).Entity;
@ -223,10 +225,8 @@ public class SellerProfileController : Controller
if(existingSellerProfile.StripeAccountId==null) if(existingSellerProfile.StripeAccountId==null)
return BadRequest("Account does not have a payment account."); return BadRequest("Account does not have a payment account.");
if (_paymentService.SellerAccountIsOnboarded(existingSellerProfile.StripeAccountId) == false)
return BadRequest("Account has not finished onboarding.");
var result = _paymentService.CreateSellerAccountOnboardingUrl(existingSellerProfile.StripeAccountId); var result = _paymentService.CreateSellerAccountOnboardingUrl(existingSellerProfile.StripeAccountId);
return Ok(result); return Ok(result);
} }
} }

View File

@ -1,6 +1,7 @@
using ArtPlatform.API.Extensions; using ArtPlatform.API.Extensions;
using ArtPlatform.API.Models.PortfolioModel; using ArtPlatform.API.Models.PortfolioModel;
using ArtPlatform.API.Models.SellerService; using ArtPlatform.API.Models.SellerService;
using ArtPlatform.API.Services.Payment;
using ArtPlatform.API.Services.Storage; using ArtPlatform.API.Services.Storage;
using ArtPlatform.Database; using ArtPlatform.Database;
using ArtPlatform.Database.Entities; using ArtPlatform.Database.Entities;
@ -16,9 +17,11 @@ public class SellerServiceController : Controller
{ {
private readonly ApplicationDbContext _dbContext; private readonly ApplicationDbContext _dbContext;
private readonly IStorageService _storageService; private readonly IStorageService _storageService;
private readonly IPaymentService _paymentService;
public SellerServiceController(ApplicationDbContext dbContext, IStorageService storageService) public SellerServiceController(ApplicationDbContext dbContext, IPaymentService paymentService, IStorageService storageService)
{ {
_paymentService = paymentService;
_storageService = storageService; _storageService = storageService;
_dbContext = dbContext; _dbContext = dbContext;
} }
@ -65,6 +68,12 @@ public class SellerServiceController : Controller
if(seller==null) if(seller==null)
return BadRequest("Account is not a seller."); return BadRequest("Account is not a seller.");
if(seller.StripeAccountId==null)
return BadRequest("Account does not have a payment account.");
if (_paymentService.SellerAccountIsOnboarded(seller.StripeAccountId) == false)
return BadRequest("Account has not finished onboarding.");
var sellerService = new Database.Entities.SellerService() var sellerService = new Database.Entities.SellerService()
{ {
Name = model.Name, Name = model.Name,

View File

@ -1,4 +1,5 @@
using System.Security.Claims; using System.Security.Claims;
using ArtPlatform.API.Services.Payment;
using ArtPlatform.Database; using ArtPlatform.Database;
using ArtPlatform.Database.Entities; using ArtPlatform.Database.Entities;
@ -14,7 +15,7 @@ public class UserMiddleware
_next = next; _next = next;
} }
public async Task InvokeAsync(HttpContext context, ApplicationDbContext dbContext) public async Task InvokeAsync(HttpContext context, ApplicationDbContext dbContext, IPaymentService paymentService)
{ {
if (context.User.Identity.IsAuthenticated) if (context.User.Identity.IsAuthenticated)
{ {
@ -24,20 +25,14 @@ public class UserMiddleware
if (user == null) if (user == null)
{ {
var customer = paymentService.CreateCustomer();
user = new User user = new User
{ {
Id = userId, Id = userId,
DisplayName = context.User.Identity.Name ?? "Anonymous", DisplayName = context.User.Identity.Name ?? "Anonymous",
Biography = string.Empty, Biography = string.Empty,
Email = context.User.Claims.FirstOrDefault(x=>x.Type=="email")?.Value ?? string.Empty, Email = context.User.Claims.FirstOrDefault(x=>x.Type=="email")?.Value ?? string.Empty,
FirstName = string.Empty, StripeCustomerId = customer
LastName = string.Empty,
AddressCountry = string.Empty,
AddressCity = string.Empty,
AddressStreet = string.Empty,
AddressHouseNumber = string.Empty,
AddressPostalCode = string.Empty,
AddressRegion = string.Empty
}; };
dbContext.Users.Add(user); dbContext.Users.Add(user);
await dbContext.SaveChangesAsync(); await dbContext.SaveChangesAsync();

View File

@ -5,4 +5,5 @@ public class DiscoverySellerModel
public int Id { get; set; } public int Id { get; set; }
public List<string> SocialMediaLinks { get; set; } public List<string> SocialMediaLinks { get; set; }
public string Biography { get; set; } public string Biography { get; set; }
public bool PrepaymentRequired { get; set; }
} }

View File

@ -12,4 +12,5 @@ public class OrderModel
public string StatusLabel => Status.ToString(); public string StatusLabel => Status.ToString();
public double Price { get; set; } public double Price { get; set; }
public string? PaymentUrl { get; set; }
} }

View File

@ -1,4 +1,4 @@
using ArtPlatform.Database.Entities; using ArtPlatform.Database.Entities;
namespace ArtPlatform.API.Models.Order; namespace ArtPlatform.API.Models.Order;
@ -14,7 +14,8 @@ public static class OrderModelExtensions
SellerServiceId = sellerProfile.SellerServiceId, SellerServiceId = sellerProfile.SellerServiceId,
SellerId = sellerProfile.SellerId, SellerId = sellerProfile.SellerId,
Status = sellerProfile.Status, Status = sellerProfile.Status,
Price = sellerProfile.Price Price = sellerProfile.Price,
PaymentUrl = sellerProfile.PaymentUrl
}; };
} }
} }

View File

@ -4,4 +4,5 @@ public class SellerProfileModel
{ {
public List<string> SocialMediaLinks { get; set; } public List<string> SocialMediaLinks { get; set; }
public string Biography { get; set; } public string Biography { get; set; }
public bool PrepaymentRequired { get; set; }
} }

View File

@ -10,7 +10,8 @@ public static class SellerProfileModelExtensions
return new SellerProfileModel() return new SellerProfileModel()
{ {
SocialMediaLinks = sellerProfile.SocialMediaLinks, SocialMediaLinks = sellerProfile.SocialMediaLinks,
Biography = sellerProfile.Biography Biography = sellerProfile.Biography,
PrepaymentRequired = sellerProfile.PrepaymentRequired
}; };
} }
public static DiscoverySellerModel ToDiscoveryModel(this UserSellerProfile sellerProfile) public static DiscoverySellerModel ToDiscoveryModel(this UserSellerProfile sellerProfile)
@ -19,13 +20,15 @@ public static class SellerProfileModelExtensions
{ {
Id = sellerProfile.Id, Id = sellerProfile.Id,
SocialMediaLinks = sellerProfile.SocialMediaLinks, SocialMediaLinks = sellerProfile.SocialMediaLinks,
Biography = sellerProfile.Biography Biography = sellerProfile.Biography,
PrepaymentRequired = sellerProfile.PrepaymentRequired
}; };
} }
public static UserSellerProfile ToModel(this SellerProfileModel sellerProfile, UserSellerProfile existingSellerProfile) public static UserSellerProfile ToModel(this SellerProfileModel sellerProfile, UserSellerProfile existingSellerProfile)
{ {
existingSellerProfile.SocialMediaLinks = sellerProfile.SocialMediaLinks; existingSellerProfile.SocialMediaLinks = sellerProfile.SocialMediaLinks;
existingSellerProfile.Biography = sellerProfile.Biography; existingSellerProfile.Biography = sellerProfile.Biography;
existingSellerProfile.PrepaymentRequired = sellerProfile.PrepaymentRequired;
return existingSellerProfile; return existingSellerProfile;
} }
} }

View File

@ -4,7 +4,9 @@ namespace ArtPlatform.API.Services.Payment;
public interface IPaymentService public interface IPaymentService
{ {
public string CreateCustomer();
string CreateSellerAccount(); string CreateSellerAccount();
string CreateSellerAccountOnboardingUrl(string accountId); string CreateSellerAccountOnboardingUrl(string accountId);
bool SellerAccountIsOnboarded(string accountId); bool SellerAccountIsOnboarded(string accountId);
string ChargeForService(int orderSellerServiceId, string buyerStripeCustomerId, string? sellerStripeAccountId, double orderPrice);
} }

View File

@ -16,9 +16,50 @@ public class StripePaymentServiceProvider:IPaymentService
StripeConfiguration.ApiKey = _apiKey; StripeConfiguration.ApiKey = _apiKey;
} }
public string CreateCustomer()
{
var options = new CustomerCreateOptions
{
Name = "Jenny Rosen",
Email = "jennyrosen@example.com",
};
var service = new CustomerService();
var customer = service.Create(options);
return customer.Id;
}
// public string ChargeCustomer(string customerId, int amount)
// {
// var options = new PaymentIntentCreateOptions
// {
// Amount = amount,
// Currency = "usd",
// AutomaticPaymentMethods = new PaymentIntentAutomaticPaymentMethodsOptions
// {
// Enabled = true,
// },
// };
// var requestOptions = new RequestOptions
// {
// StripeAccount = "{{CONNECTED_ACCOUNT_ID}}",
// };
// var service = new PaymentIntentService();
// var intent = service.Create(options, requestOptions);
// throw new NotImplementedException();
// }
public string CreateSellerAccount() public string CreateSellerAccount()
{ {
var accountCreateOptions = new AccountCreateOptions { Type = "express" }; var accountCreateOptions = new AccountCreateOptions { Type = "express",
Capabilities
= new AccountCapabilitiesOptions
{
CardPayments
= new AccountCapabilitiesCardPaymentsOptions { Requested
= true },
Transfers
= new AccountCapabilitiesTransfersOptions { Requested
= true },
} };
var accountService = new AccountService(); var accountService = new AccountService();
var account = accountService.Create(accountCreateOptions); var account = accountService.Create(accountCreateOptions);
return account.Id; return account.Id;
@ -44,4 +85,42 @@ public class StripePaymentServiceProvider:IPaymentService
var account = service.Get(accountId); var account = service.Get(accountId);
return account.Requirements.CurrentlyDue.Count == 0 && account.ChargesEnabled==true && account.DetailsSubmitted==true; return account.Requirements.CurrentlyDue.Count == 0 && account.ChargesEnabled==true && account.DetailsSubmitted==true;
} }
public string ChargeForService(int orderSellerServiceId, string buyerStripeCustomerId, string? sellerStripeAccountId,
double orderPrice)
{
var feeAmount = (long)Math.Round((orderPrice*0.05) * 100);
var options = new Stripe.Checkout.SessionCreateOptions
{
LineItems = new List<Stripe.Checkout.SessionLineItemOptions> {
new Stripe.Checkout.SessionLineItemOptions
{
PriceData = new Stripe.Checkout.SessionLineItemPriceDataOptions
{
UnitAmount = (long)Math.Round(orderPrice * 100),
Currency = "usd",
ProductData = new Stripe.Checkout.SessionLineItemPriceDataProductDataOptions
{
Name = orderSellerServiceId.ToString()
},
},
Quantity = 1,
},
},
PaymentIntentData = new Stripe.Checkout.SessionPaymentIntentDataOptions
{
ApplicationFeeAmount = feeAmount,
},
Mode = "payment",
SuccessUrl = "https://example.com/success",
CancelUrl = "https://example.com/failure",
};
var requestOptions = new RequestOptions
{
StripeAccount = sellerStripeAccountId
};
var service = new Stripe.Checkout.SessionService();
var session = service.Create(options, requestOptions);
return session.Url;
}
} }

View File

@ -1,5 +1,6 @@
{ {
"Stripe": { "Stripe": {
"WebhookKey": "whsec_9fe0ed9b64090eb1a4eaabb9e5ed2c99818daa083c2dd8d06581910f54692f3b",
"ApiKey": "sk_test_51OdJ1SLooS0IZqYkx2IdNoLcscm6BisgaUyYVIc5jM1RMmarww2e9hLLQS3Atn6TQi00p9YQkCLGQPhAI2gf9ZSY00HmbQYCvP" "ApiKey": "sk_test_51OdJ1SLooS0IZqYkx2IdNoLcscm6BisgaUyYVIc5jM1RMmarww2e9hLLQS3Atn6TQi00p9YQkCLGQPhAI2gf9ZSY00HmbQYCvP"
}, },
"Auth0": { "Auth0": {

View File

@ -20,4 +20,5 @@ public class SellerServiceOrder
public virtual ICollection<SellerServiceOrderReview> Reviews { get; set; } = new List<SellerServiceOrderReview>(); public virtual ICollection<SellerServiceOrderReview> Reviews { get; set; } = new List<SellerServiceOrderReview>();
public virtual ICollection<SellerServiceOrderMessage> Messages { get; set; } = new List<SellerServiceOrderMessage>(); public virtual ICollection<SellerServiceOrderMessage> Messages { get; set; } = new List<SellerServiceOrderMessage>();
public string? PaymentUrl { get; set; }
} }

View File

@ -11,17 +11,7 @@ public record User
public string Biography { get; set; } = null!; public string Biography { get; set; } = null!;
public string Email { get; set; } = null!; public string Email { get; set; } = null!;
public int? UserSellerProfileId { get; set; } public int? UserSellerProfileId { get; set; }
public string StripeCustomerId { get; set; } = null!;
#region Billing Information
public string FirstName { get; set; } = null!;
public string LastName { get; set; } = null!;
public string AddressCountry { get; set; } = null!;
public string AddressCity { get; set; } = null!;
public string AddressStreet { get; set; } = null!;
public string AddressHouseNumber { get; set; } = null!;
public string AddressPostalCode { get; set; } = null!;
public string AddressRegion { get; set; } = null!;
#endregion
[JsonIgnore] public virtual UserSellerProfile? UserSellerProfile { get; set; } [JsonIgnore] public virtual UserSellerProfile? UserSellerProfile { get; set; }
[JsonIgnore] public virtual ICollection<SellerServiceOrder> Orders { get; set; } [JsonIgnore] public virtual ICollection<SellerServiceOrder> Orders { get; set; }

View File

@ -11,6 +11,7 @@ public record UserSellerProfile
public List<string> SocialMediaLinks { get; set; } = new(); public List<string> SocialMediaLinks { get; set; } = new();
public bool AgeRestricted { get; set; } public bool AgeRestricted { get; set; }
public string? StripeAccountId { get; set; } public string? StripeAccountId { get; set; }
public bool PrepaymentRequired { get; set; } = false;
public virtual User User { get; set; } = null!; public virtual User User { get; set; } = null!;
public virtual ICollection<SellerService> SellerServices { get; set; } = new List<SellerService>(); public virtual ICollection<SellerService> SellerServices { get; set; } = new List<SellerService>();

View File

@ -8,5 +8,6 @@ public enum EnumOrderStatus
InProgress, InProgress,
PendingReview, PendingReview,
Completed, Completed,
Cancelled Cancelled,
WaitingForPayment
} }

View File

@ -0,0 +1,485 @@
// <auto-generated />
using System;
using System.Collections.Generic;
using ArtPlatform.Database;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace ArtPlatform.Database.Migrations
{
[DbContext(typeof(ApplicationDbContext))]
[Migration("20240128002310_stoff")]
partial class stoff
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "8.0.1")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("ArtPlatform.Database.Entities.SellerProfilePortfolioPiece", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("FileReference")
.HasColumnType("text");
b.Property<int>("SellerProfileId")
.HasColumnType("integer");
b.Property<int?>("SellerServiceId")
.HasColumnType("integer");
b.HasKey("Id");
b.HasIndex("SellerProfileId");
b.HasIndex("SellerServiceId");
b.ToTable("SellerProfilePortfolioPieces");
});
modelBuilder.Entity("ArtPlatform.Database.Entities.SellerProfileRequest", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<bool>("Accepted")
.HasColumnType("boolean");
b.Property<DateTime?>("AcceptedDate")
.HasColumnType("timestamp with time zone");
b.Property<DateTime>("RequestDate")
.HasColumnType("timestamp with time zone");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("SellerProfileRequests");
});
modelBuilder.Entity("ArtPlatform.Database.Entities.SellerService", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("Description")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.Property<double>("Price")
.HasColumnType("double precision");
b.Property<int>("SellerProfileId")
.HasColumnType("integer");
b.HasKey("Id");
b.HasIndex("SellerProfileId");
b.ToTable("SellerServices");
});
modelBuilder.Entity("ArtPlatform.Database.Entities.SellerServiceOrder", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("BuyerId")
.IsRequired()
.HasColumnType("text");
b.Property<DateTime>("CreatedDate")
.HasColumnType("timestamp with time zone");
b.Property<DateTime?>("EndDate")
.HasColumnType("timestamp with time zone");
b.Property<string>("PaymentUrl")
.HasColumnType("text");
b.Property<double>("Price")
.HasColumnType("double precision");
b.Property<int>("SellerId")
.HasColumnType("integer");
b.Property<int>("SellerServiceId")
.HasColumnType("integer");
b.Property<int>("Status")
.HasColumnType("integer");
b.Property<DateTime?>("TermsAcceptedDate")
.HasColumnType("timestamp with time zone");
b.HasKey("Id");
b.HasIndex("BuyerId");
b.HasIndex("SellerId");
b.HasIndex("SellerServiceId");
b.ToTable("SellerServiceOrders");
});
modelBuilder.Entity("ArtPlatform.Database.Entities.SellerServiceOrderMessage", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("Message")
.IsRequired()
.HasColumnType("text");
b.Property<int>("SellerServiceOrderId")
.HasColumnType("integer");
b.Property<string>("SenderId")
.IsRequired()
.HasColumnType("text");
b.Property<DateTime>("SentAt")
.HasColumnType("timestamp with time zone");
b.HasKey("Id");
b.HasIndex("SellerServiceOrderId");
b.HasIndex("SenderId");
b.ToTable("SellerServiceOrderMessages");
});
modelBuilder.Entity("ArtPlatform.Database.Entities.SellerServiceOrderMessageAttachment", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("FileReference")
.IsRequired()
.HasColumnType("text");
b.Property<int>("SellerServiceOrderMessageId")
.HasColumnType("integer");
b.HasKey("Id");
b.HasIndex("SellerServiceOrderMessageId");
b.ToTable("SellerServiceOrderMessageAttachments");
});
modelBuilder.Entity("ArtPlatform.Database.Entities.SellerServiceOrderReview", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<int>("Rating")
.HasColumnType("integer");
b.Property<string>("Review")
.HasColumnType("text");
b.Property<DateTime>("ReviewDate")
.HasColumnType("timestamp with time zone");
b.Property<string>("ReviewerId")
.IsRequired()
.HasColumnType("text");
b.Property<int>("SellerServiceId")
.HasColumnType("integer");
b.Property<int>("SellerServiceOrderId")
.HasColumnType("integer");
b.HasKey("Id");
b.HasIndex("ReviewerId");
b.HasIndex("SellerServiceId");
b.HasIndex("SellerServiceOrderId");
b.ToTable("SellerServiceOrderReviews");
});
modelBuilder.Entity("ArtPlatform.Database.Entities.User", b =>
{
b.Property<string>("Id")
.HasColumnType("text");
b.Property<string>("Biography")
.IsRequired()
.HasColumnType("text");
b.Property<string>("DisplayName")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Email")
.IsRequired()
.HasColumnType("text");
b.Property<string>("StripeCustomerId")
.IsRequired()
.HasColumnType("text");
b.Property<int?>("UserSellerProfileId")
.HasColumnType("integer");
b.HasKey("Id");
b.ToTable("Users");
});
modelBuilder.Entity("ArtPlatform.Database.Entities.UserSellerProfile", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<bool>("AgeRestricted")
.HasColumnType("boolean");
b.Property<string>("Biography")
.IsRequired()
.HasColumnType("text");
b.Property<bool>("PrepaymentRequired")
.HasColumnType("boolean");
b.Property<List<string>>("SocialMediaLinks")
.IsRequired()
.HasColumnType("text[]");
b.Property<string>("StripeAccountId")
.HasColumnType("text");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("UserId")
.IsUnique();
b.ToTable("UserSellerProfiles");
});
modelBuilder.Entity("ArtPlatform.Database.Entities.SellerProfilePortfolioPiece", b =>
{
b.HasOne("ArtPlatform.Database.Entities.UserSellerProfile", "SellerProfile")
.WithMany("PortfolioPieces")
.HasForeignKey("SellerProfileId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("ArtPlatform.Database.Entities.SellerService", "SellerService")
.WithMany("PortfolioPieces")
.HasForeignKey("SellerServiceId");
b.Navigation("SellerProfile");
b.Navigation("SellerService");
});
modelBuilder.Entity("ArtPlatform.Database.Entities.SellerProfileRequest", b =>
{
b.HasOne("ArtPlatform.Database.Entities.User", "User")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("User");
});
modelBuilder.Entity("ArtPlatform.Database.Entities.SellerService", b =>
{
b.HasOne("ArtPlatform.Database.Entities.UserSellerProfile", "SellerProfile")
.WithMany("SellerServices")
.HasForeignKey("SellerProfileId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("SellerProfile");
});
modelBuilder.Entity("ArtPlatform.Database.Entities.SellerServiceOrder", b =>
{
b.HasOne("ArtPlatform.Database.Entities.User", "Buyer")
.WithMany("Orders")
.HasForeignKey("BuyerId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("ArtPlatform.Database.Entities.UserSellerProfile", "Seller")
.WithMany()
.HasForeignKey("SellerId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("ArtPlatform.Database.Entities.SellerService", "SellerService")
.WithMany()
.HasForeignKey("SellerServiceId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Buyer");
b.Navigation("Seller");
b.Navigation("SellerService");
});
modelBuilder.Entity("ArtPlatform.Database.Entities.SellerServiceOrderMessage", b =>
{
b.HasOne("ArtPlatform.Database.Entities.SellerServiceOrder", "SellerServiceOrder")
.WithMany("Messages")
.HasForeignKey("SellerServiceOrderId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("ArtPlatform.Database.Entities.User", "Sender")
.WithMany()
.HasForeignKey("SenderId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("SellerServiceOrder");
b.Navigation("Sender");
});
modelBuilder.Entity("ArtPlatform.Database.Entities.SellerServiceOrderMessageAttachment", b =>
{
b.HasOne("ArtPlatform.Database.Entities.SellerServiceOrderMessage", "SellerServiceOrderMessage")
.WithMany("Attachments")
.HasForeignKey("SellerServiceOrderMessageId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("SellerServiceOrderMessage");
});
modelBuilder.Entity("ArtPlatform.Database.Entities.SellerServiceOrderReview", b =>
{
b.HasOne("ArtPlatform.Database.Entities.User", "Reviewer")
.WithMany()
.HasForeignKey("ReviewerId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("ArtPlatform.Database.Entities.SellerService", "SellerService")
.WithMany("Reviews")
.HasForeignKey("SellerServiceId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("ArtPlatform.Database.Entities.SellerServiceOrder", "SellerServiceOrder")
.WithMany("Reviews")
.HasForeignKey("SellerServiceOrderId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Reviewer");
b.Navigation("SellerService");
b.Navigation("SellerServiceOrder");
});
modelBuilder.Entity("ArtPlatform.Database.Entities.UserSellerProfile", b =>
{
b.HasOne("ArtPlatform.Database.Entities.User", "User")
.WithOne("UserSellerProfile")
.HasForeignKey("ArtPlatform.Database.Entities.UserSellerProfile", "UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("User");
});
modelBuilder.Entity("ArtPlatform.Database.Entities.SellerService", b =>
{
b.Navigation("PortfolioPieces");
b.Navigation("Reviews");
});
modelBuilder.Entity("ArtPlatform.Database.Entities.SellerServiceOrder", b =>
{
b.Navigation("Messages");
b.Navigation("Reviews");
});
modelBuilder.Entity("ArtPlatform.Database.Entities.SellerServiceOrderMessage", b =>
{
b.Navigation("Attachments");
});
modelBuilder.Entity("ArtPlatform.Database.Entities.User", b =>
{
b.Navigation("Orders");
b.Navigation("UserSellerProfile");
});
modelBuilder.Entity("ArtPlatform.Database.Entities.UserSellerProfile", b =>
{
b.Navigation("PortfolioPieces");
b.Navigation("SellerServices");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,126 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace ArtPlatform.Database.Migrations
{
/// <inheritdoc />
public partial class stoff : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "AddressCity",
table: "Users");
migrationBuilder.DropColumn(
name: "AddressCountry",
table: "Users");
migrationBuilder.DropColumn(
name: "AddressHouseNumber",
table: "Users");
migrationBuilder.DropColumn(
name: "AddressPostalCode",
table: "Users");
migrationBuilder.DropColumn(
name: "AddressRegion",
table: "Users");
migrationBuilder.DropColumn(
name: "AddressStreet",
table: "Users");
migrationBuilder.DropColumn(
name: "FirstName",
table: "Users");
migrationBuilder.RenameColumn(
name: "LastName",
table: "Users",
newName: "StripeCustomerId");
migrationBuilder.AddColumn<bool>(
name: "PrepaymentRequired",
table: "UserSellerProfiles",
type: "boolean",
nullable: false,
defaultValue: false);
migrationBuilder.AddColumn<string>(
name: "PaymentUrl",
table: "SellerServiceOrders",
type: "text",
nullable: true);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "PrepaymentRequired",
table: "UserSellerProfiles");
migrationBuilder.DropColumn(
name: "PaymentUrl",
table: "SellerServiceOrders");
migrationBuilder.RenameColumn(
name: "StripeCustomerId",
table: "Users",
newName: "LastName");
migrationBuilder.AddColumn<string>(
name: "AddressCity",
table: "Users",
type: "text",
nullable: false,
defaultValue: "");
migrationBuilder.AddColumn<string>(
name: "AddressCountry",
table: "Users",
type: "text",
nullable: false,
defaultValue: "");
migrationBuilder.AddColumn<string>(
name: "AddressHouseNumber",
table: "Users",
type: "text",
nullable: false,
defaultValue: "");
migrationBuilder.AddColumn<string>(
name: "AddressPostalCode",
table: "Users",
type: "text",
nullable: false,
defaultValue: "");
migrationBuilder.AddColumn<string>(
name: "AddressRegion",
table: "Users",
type: "text",
nullable: false,
defaultValue: "");
migrationBuilder.AddColumn<string>(
name: "AddressStreet",
table: "Users",
type: "text",
nullable: false,
defaultValue: "");
migrationBuilder.AddColumn<string>(
name: "FirstName",
table: "Users",
type: "text",
nullable: false,
defaultValue: "");
}
}
}

View File

@ -124,6 +124,9 @@ namespace ArtPlatform.Database.Migrations
b.Property<DateTime?>("EndDate") b.Property<DateTime?>("EndDate")
.HasColumnType("timestamp with time zone"); .HasColumnType("timestamp with time zone");
b.Property<string>("PaymentUrl")
.HasColumnType("text");
b.Property<double>("Price") b.Property<double>("Price")
.HasColumnType("double precision"); .HasColumnType("double precision");
@ -246,30 +249,6 @@ namespace ArtPlatform.Database.Migrations
b.Property<string>("Id") b.Property<string>("Id")
.HasColumnType("text"); .HasColumnType("text");
b.Property<string>("AddressCity")
.IsRequired()
.HasColumnType("text");
b.Property<string>("AddressCountry")
.IsRequired()
.HasColumnType("text");
b.Property<string>("AddressHouseNumber")
.IsRequired()
.HasColumnType("text");
b.Property<string>("AddressPostalCode")
.IsRequired()
.HasColumnType("text");
b.Property<string>("AddressRegion")
.IsRequired()
.HasColumnType("text");
b.Property<string>("AddressStreet")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Biography") b.Property<string>("Biography")
.IsRequired() .IsRequired()
.HasColumnType("text"); .HasColumnType("text");
@ -282,11 +261,7 @@ namespace ArtPlatform.Database.Migrations
.IsRequired() .IsRequired()
.HasColumnType("text"); .HasColumnType("text");
b.Property<string>("FirstName") b.Property<string>("StripeCustomerId")
.IsRequired()
.HasColumnType("text");
b.Property<string>("LastName")
.IsRequired() .IsRequired()
.HasColumnType("text"); .HasColumnType("text");
@ -313,6 +288,9 @@ namespace ArtPlatform.Database.Migrations
.IsRequired() .IsRequired()
.HasColumnType("text"); .HasColumnType("text");
b.Property<bool>("PrepaymentRequired")
.HasColumnType("boolean");
b.Property<List<string>>("SocialMediaLinks") b.Property<List<string>>("SocialMediaLinks")
.IsRequired() .IsRequired()
.HasColumnType("text[]"); .HasColumnType("text[]");