From b99c42b88c3fc23ab4ca43355947b8f22dc0f5c4 Mon Sep 17 00:00:00 2001 From: kTrzcinskii Date: Sun, 15 Jun 2025 00:08:32 +0200 Subject: [PATCH 1/3] Add option to send mail about multiple new tickets --- .../Common/Mail/Abstractions/IMailService.cs | 5 +- .../Common/Mail/Services/MailService.cs | 50 ++++++++++++++----- .../Tickets/Models/TicketWithScanUrl.cs | 13 +++++ 3 files changed, 53 insertions(+), 15 deletions(-) create mode 100644 TickAPI/TickAPI/Tickets/Models/TicketWithScanUrl.cs diff --git a/TickAPI/TickAPI/Common/Mail/Abstractions/IMailService.cs b/TickAPI/TickAPI/Common/Mail/Abstractions/IMailService.cs index f4b3444..ad0cfe1 100644 --- a/TickAPI/TickAPI/Common/Mail/Abstractions/IMailService.cs +++ b/TickAPI/TickAPI/Common/Mail/Abstractions/IMailService.cs @@ -1,11 +1,12 @@ using TickAPI.Common.Mail.Models; using TickAPI.Common.Results; +using TickAPI.Customers.Models; +using TickAPI.Tickets.Models; namespace TickAPI.Common.Mail.Abstractions; public interface IMailService { - public Task SendTicketAsync(MailRecipient recipient, string eventName, byte[] pdfData); - + public Task SendTicketsAsync(Customer customer, List tickets); public Task SendMailAsync(IEnumerable recipients, string subject, string content, List? attachments); } \ No newline at end of file diff --git a/TickAPI/TickAPI/Common/Mail/Services/MailService.cs b/TickAPI/TickAPI/Common/Mail/Services/MailService.cs index b35b5c4..21923b4 100644 --- a/TickAPI/TickAPI/Common/Mail/Services/MailService.cs +++ b/TickAPI/TickAPI/Common/Mail/Services/MailService.cs @@ -1,8 +1,12 @@ -using SendGrid; +using System.Text; +using SendGrid; using SendGrid.Helpers.Mail; using TickAPI.Common.Mail.Abstractions; using TickAPI.Common.Mail.Models; +using TickAPI.Common.QR.Abstractions; using TickAPI.Common.Results; +using TickAPI.Customers.Models; +using TickAPI.Tickets.Models; namespace TickAPI.Common.Mail.Services; @@ -10,28 +14,48 @@ public class MailService : IMailService { private readonly SendGridClient _client; private readonly EmailAddress _fromEmailAddress; + private readonly IQRCodeService _qrCodeService; - public MailService(IConfiguration configuration) + public MailService(IConfiguration configuration, IQRCodeService qrCodeService) { + _qrCodeService = qrCodeService; var apiKey = configuration["SendGrid:ApiKey"]; _client = new SendGridClient(apiKey); var fromEmail = configuration["SendGrid:FromEmail"]; var fromName = configuration["SendGrid:FromName"]; _fromEmailAddress = new EmailAddress(fromEmail, fromName); } - - public async Task SendTicketAsync(MailRecipient recipient, string eventName, byte[] pdfData) + + public async Task SendTicketsAsync(Customer customer, List tickets) { - var subject = $"Ticket for {eventName}"; - var htmlContent = "Download your ticket from attachments"; - var base64Content = Convert.ToBase64String(pdfData); - List attachments = [ - new MailAttachment("ticket.pdf", base64Content, "application/pdf") - ]; - var res = await SendMailAsync([recipient], subject, htmlContent, attachments); - return res; - } + var subject = "Your New Tickets"; + var htmlContent = new StringBuilder(); + htmlContent.AppendLine("Here are your tickets:
    "); + + var attachments = new List(); + + foreach (var tWithScanUrl in tickets) + { + var ticket = tWithScanUrl.Ticket; + var eventName = ticket.Type.Event.Name; + var eventDate = ticket.Type.Event.StartDate.ToString("yyyy-MM-dd"); + + htmlContent.AppendLine( + $"
  • Ticket for event {eventName} on {eventDate} " + ); + + var pdfData = _qrCodeService.GenerateQrCode(tWithScanUrl.ScanUrl); + + var base64Content = Convert.ToBase64String(pdfData); + attachments.Add(new MailAttachment($"ticket_{ticket.Id}.pdf", base64Content, "application/pdf")); + } + + htmlContent.AppendLine("
"); + var recipient = new MailRecipient(customer.Email, customer.FirstName); + return await SendMailAsync([recipient], subject, htmlContent.ToString(), attachments); + } + public async Task SendMailAsync(IEnumerable recipients, string subject, string content, List? attachments = null) { diff --git a/TickAPI/TickAPI/Tickets/Models/TicketWithScanUrl.cs b/TickAPI/TickAPI/Tickets/Models/TicketWithScanUrl.cs new file mode 100644 index 0000000..97ca0ab --- /dev/null +++ b/TickAPI/TickAPI/Tickets/Models/TicketWithScanUrl.cs @@ -0,0 +1,13 @@ +namespace TickAPI.Tickets.Models; + +public class TicketWithScanUrl +{ + public TicketWithScanUrl(Ticket ticket, string scanUrl) + { + Ticket = ticket; + ScanUrl = scanUrl; + } + + public Ticket Ticket { get; set; } + public string ScanUrl { get; set; } +} From 17b81fa02f210de2176f5887a1e333e9a42b27e0 Mon Sep 17 00:00:00 2001 From: kTrzcinskii Date: Sun, 15 Jun 2025 00:09:39 +0200 Subject: [PATCH 2/3] Update checkout flow to send mail with info about bought tickets --- .../Abstractions/IShoppingCartService.cs | 3 +- .../Controllers/ShoppingCartsController.cs | 32 ++++++++++- .../ShoppingCarts/Models/CheckoutResult.cs | 9 ++++ .../Services/ShoppingCartService.cs | 54 ++++++++++++------- .../Tickets/Abstractions/ITicketRepository.cs | 2 +- .../Tickets/Abstractions/ITicketService.cs | 2 +- .../Tickets/Controllers/TicketsController.cs | 1 - .../Tickets/Repositories/TicketRepository.cs | 6 +-- .../TickAPI/Tickets/Services/TicketService.cs | 2 +- 9 files changed, 81 insertions(+), 30 deletions(-) create mode 100644 TickAPI/TickAPI/ShoppingCarts/Models/CheckoutResult.cs diff --git a/TickAPI/TickAPI/ShoppingCarts/Abstractions/IShoppingCartService.cs b/TickAPI/TickAPI/ShoppingCarts/Abstractions/IShoppingCartService.cs index 609ff79..9bd10a3 100644 --- a/TickAPI/TickAPI/ShoppingCarts/Abstractions/IShoppingCartService.cs +++ b/TickAPI/TickAPI/ShoppingCarts/Abstractions/IShoppingCartService.cs @@ -2,6 +2,7 @@ using TickAPI.Common.Results; using TickAPI.Common.Results.Generic; using TickAPI.ShoppingCarts.DTOs.Response; +using TickAPI.ShoppingCarts.Models; namespace TickAPI.ShoppingCarts.Abstractions; @@ -13,6 +14,6 @@ public interface IShoppingCartService public Task RemoveNewTicketsFromCartAsync(Guid ticketTypeId, uint amount, string customerEmail); public Task RemoveResellTicketFromCartAsync(Guid ticketId, string customerEmail); public Task>> GetDueAmountAsync(string customerEmail); - public Task> CheckoutAsync(string customerEmail, decimal amount, string currency, + public Task> CheckoutAsync(string customerEmail, decimal amount, string currency, string cardNumber, string cardExpiry, string cvv); } \ No newline at end of file diff --git a/TickAPI/TickAPI/ShoppingCarts/Controllers/ShoppingCartsController.cs b/TickAPI/TickAPI/ShoppingCarts/Controllers/ShoppingCartsController.cs index 88542c5..94d0f9b 100644 --- a/TickAPI/TickAPI/ShoppingCarts/Controllers/ShoppingCartsController.cs +++ b/TickAPI/TickAPI/ShoppingCarts/Controllers/ShoppingCartsController.cs @@ -2,10 +2,13 @@ using TickAPI.Common.Auth.Attributes; using TickAPI.Common.Auth.Enums; using TickAPI.Common.Claims.Abstractions; +using TickAPI.Common.Mail.Abstractions; using TickAPI.Common.Payment.Models; +using TickAPI.Customers.Abstractions; using TickAPI.ShoppingCarts.Abstractions; using TickAPI.ShoppingCarts.DTOs.Request; using TickAPI.ShoppingCarts.DTOs.Response; +using TickAPI.Tickets.Models; namespace TickAPI.ShoppingCarts.Controllers; @@ -15,11 +18,15 @@ public class ShoppingCartsController : ControllerBase { private readonly IShoppingCartService _shoppingCartService; private readonly IClaimsService _claimsService; + private readonly IMailService _mailService; + private readonly ICustomerService _customerService; - public ShoppingCartsController(IShoppingCartService shoppingCartService, IClaimsService claimsService) + public ShoppingCartsController(IShoppingCartService shoppingCartService, IClaimsService claimsService, IMailService mailService, ICustomerService customerService) { _shoppingCartService = shoppingCartService; _claimsService = claimsService; + _mailService = mailService; + _customerService = customerService; } [AuthorizeWithPolicy(AuthPolicies.CustomerPolicy)] @@ -136,6 +143,27 @@ public async Task> Checkout([FromBody] CheckoutD var checkoutResult = await _shoppingCartService.CheckoutAsync(email, checkoutDto.Amount, checkoutDto.Currency, checkoutDto.CardNumber, checkoutDto.CardExpiry, checkoutDto.Cvv); - return checkoutResult.ToObjectResult(); + if (checkoutResult.IsError) + { + return checkoutResult.ToObjectResult(); + } + + var checkout = checkoutResult.Value!; + + var customerResult = await _customerService.GetCustomerByEmailAsync(email); + if (customerResult.IsError) + { + return customerResult.ToObjectResult(); + } + + var customer = customerResult.Value!; + + await _mailService.SendTicketsAsync(customer, checkout.BoughtTickets.Select(t => + { + var scanUrl = Url.Action("ScanTicket", "Tickets", new { id = t.Id }, Request.Scheme)!; + return new TicketWithScanUrl(t, scanUrl); + }).ToList()); + + return checkout.PaymentResponse; } } \ No newline at end of file diff --git a/TickAPI/TickAPI/ShoppingCarts/Models/CheckoutResult.cs b/TickAPI/TickAPI/ShoppingCarts/Models/CheckoutResult.cs new file mode 100644 index 0000000..cb4870f --- /dev/null +++ b/TickAPI/TickAPI/ShoppingCarts/Models/CheckoutResult.cs @@ -0,0 +1,9 @@ +using TickAPI.Common.Payment.Models; +using TickAPI.Tickets.Models; + +namespace TickAPI.ShoppingCarts.Models; + +public record CheckoutResult( + List BoughtTickets, + PaymentResponsePG PaymentResponse +); diff --git a/TickAPI/TickAPI/ShoppingCarts/Services/ShoppingCartService.cs b/TickAPI/TickAPI/ShoppingCarts/Services/ShoppingCartService.cs index 2f01bc6..2a00ca2 100644 --- a/TickAPI/TickAPI/ShoppingCarts/Services/ShoppingCartService.cs +++ b/TickAPI/TickAPI/ShoppingCarts/Services/ShoppingCartService.cs @@ -246,27 +246,27 @@ public async Task>> GetDueAmountAsync(string return Result>.Success(dueAmount); } - public async Task> CheckoutAsync(string customerEmail, decimal amount, string currency, + public async Task> CheckoutAsync(string customerEmail, decimal amount, string currency, string cardNumber, string cardExpiry, string cvv) { var dueAmountResult = await GetDueAmountAsync(customerEmail); if (dueAmountResult.IsError) { - return Result.PropagateError(dueAmountResult); + return Result.PropagateError(dueAmountResult); } var currencyExists = dueAmountResult.Value!.TryGetValue(currency, out var dueAmount); if (!currencyExists) { - return Result.Failure(StatusCodes.Status400BadRequest, + return Result.Failure(StatusCodes.Status400BadRequest, $"no tickets paid in {currency} found in cart"); } if (dueAmount != amount) { - return Result.Failure(StatusCodes.Status400BadRequest, + return Result.Failure(StatusCodes.Status400BadRequest, $"the given amount {amount} {currency} is different than the expected amount of {dueAmount} {currency}"); } @@ -276,14 +276,14 @@ await _paymentGatewayService.ProcessPayment(new PaymentRequestPG(amount, currenc if (paymentResult.IsError) { - return Result.PropagateError(paymentResult); + return Result.PropagateError(paymentResult); } var getShoppingCartResult = await _shoppingCartRepository.GetShoppingCartByEmailAsync(customerEmail); if (getShoppingCartResult.IsError) { - return Result.PropagateError(getShoppingCartResult); + return Result.PropagateError(getShoppingCartResult); } var cart = getShoppingCartResult.Value!; @@ -292,7 +292,7 @@ await _paymentGatewayService.ProcessPayment(new PaymentRequestPG(amount, currenc if (getCustomerResult.IsError) { - return Result.PropagateError(getCustomerResult); + return Result.PropagateError(getCustomerResult); } var owner = getCustomerResult.Value!; @@ -301,32 +301,40 @@ await _paymentGatewayService.ProcessPayment(new PaymentRequestPG(amount, currenc if (generateTicketsResult.IsError) { - return Result.PropagateError(generateTicketsResult); + return Result.PropagateError(generateTicketsResult); } + var boughtTickets = generateTicketsResult.Value!; + var passOwnershipResult = await PassTicketOwnershipAsync(cart, owner, currency); if (passOwnershipResult.IsError) { - return Result.PropagateError(passOwnershipResult); + return Result.PropagateError(passOwnershipResult); } + + var resoldTickets = passOwnershipResult.Value!; + + List allTickets = [..boughtTickets, ..resoldTickets]; var payment = paymentResult.Value!; - return Result.Success(payment); + return Result.Success(new CheckoutResult(allTickets, payment)); } - private async Task GenerateBoughtTicketsAsync(ShoppingCart cart, Customer owner, string currency) + private async Task>> GenerateBoughtTicketsAsync(ShoppingCart cart, Customer owner, string currency) { var removals = new List<(Guid id, uint amount)>(); + var newTickets = new List(); + foreach (var ticket in cart.NewTickets) { var ticketTypeResult = await _ticketService.GetTicketTypeByIdAsync(ticket.TicketTypeId); if (ticketTypeResult.IsError) { - return Result.PropagateError(ticketTypeResult); + return Result>.PropagateError(ticketTypeResult); } var type = ticketTypeResult.Value!; @@ -341,8 +349,10 @@ private async Task GenerateBoughtTicketsAsync(ShoppingCart cart, Custome if (createTicketResult.IsError) { - return Result.PropagateError(createTicketResult); + return Result>.PropagateError(createTicketResult); } + + newTickets.Add(createTicketResult.Value!); } } } @@ -353,24 +363,26 @@ private async Task GenerateBoughtTicketsAsync(ShoppingCart cart, Custome if (removalResult.IsError) { - return Result.PropagateError(removalResult); + return Result>.PropagateError(removalResult); } } - return Result.Success(); + return Result>.Success(newTickets); } - private async Task PassTicketOwnershipAsync(ShoppingCart cart, Customer newOwner, string currency) + private async Task>> PassTicketOwnershipAsync(ShoppingCart cart, Customer newOwner, string currency) { var removals = new List(); + var resoldTickets = new List(); + foreach (var resellTicket in cart.ResellTickets) { var ticketResult = await _ticketService.GetTicketByIdAsync(resellTicket.TicketId); if (ticketResult.IsError) { - return Result.PropagateError(ticketResult); + return Result>.PropagateError(ticketResult); } var ticket = ticketResult.Value!; @@ -383,8 +395,10 @@ private async Task PassTicketOwnershipAsync(ShoppingCart cart, Customer if (createTicketResult.IsError) { - return Result.PropagateError(createTicketResult); + return Result>.PropagateError(createTicketResult); } + + resoldTickets.Add(ticket); } } @@ -394,10 +408,10 @@ private async Task PassTicketOwnershipAsync(ShoppingCart cart, Customer if (removalResult.IsError) { - return Result.PropagateError(removalResult); + return Result>.PropagateError(removalResult); } } - return Result.Success(); + return Result>.Success(resoldTickets); } } \ No newline at end of file diff --git a/TickAPI/TickAPI/Tickets/Abstractions/ITicketRepository.cs b/TickAPI/TickAPI/Tickets/Abstractions/ITicketRepository.cs index e441b09..9536346 100644 --- a/TickAPI/TickAPI/Tickets/Abstractions/ITicketRepository.cs +++ b/TickAPI/TickAPI/Tickets/Abstractions/ITicketRepository.cs @@ -14,7 +14,7 @@ public interface ITicketRepository public IQueryable GetTicketsByCustomerEmail(string email); public Task MarkTicketAsUsed(Guid id); public Task SetTicketForResell(Guid ticketId, decimal newPrice, string currency); - public Task AddTicketAsync(Ticket ticket); + public Task> AddTicketAsync(Ticket ticket); public Task> GetTicketWithDetailsByIdAsync(Guid id); public Task ChangeTicketOwnershipAsync(Ticket ticket, Customer newOwner, string? nameOnTicket = null); } \ No newline at end of file diff --git a/TickAPI/TickAPI/Tickets/Abstractions/ITicketService.cs b/TickAPI/TickAPI/Tickets/Abstractions/ITicketService.cs index 30c46a2..15a2123 100644 --- a/TickAPI/TickAPI/Tickets/Abstractions/ITicketService.cs +++ b/TickAPI/TickAPI/Tickets/Abstractions/ITicketService.cs @@ -24,7 +24,7 @@ public Task> GetTicketDetailsAsync(Guid tick public Task SetTicketForResellAsync(Guid ticketId, string email, decimal resellPrice, string resellCurrency); public Task> GetTicketByIdAsync(Guid ticketId); public Task> GetTicketTypeByIdAsync(Guid ticketTypeId); - public Task CreateTicketAsync(TicketType type, Customer owner, string? nameOnTicket = null, + public Task> CreateTicketAsync(TicketType type, Customer owner, string? nameOnTicket = null, string? seats = null); public Task ChangeTicketOwnershipViaResellAsync(Ticket ticket, Customer newOwner, string? nameOnTicket = null); } \ No newline at end of file diff --git a/TickAPI/TickAPI/Tickets/Controllers/TicketsController.cs b/TickAPI/TickAPI/Tickets/Controllers/TicketsController.cs index 54209b7..4de33ef 100644 --- a/TickAPI/TickAPI/Tickets/Controllers/TicketsController.cs +++ b/TickAPI/TickAPI/Tickets/Controllers/TicketsController.cs @@ -5,7 +5,6 @@ using TickAPI.Tickets.Abstractions; using TickAPI.Tickets.DTOs.Response; using TickAPI.Common.Pagination.Responses; -using TickAPI.Common.Results; using TickAPI.Tickets.DTOs.Request; namespace TickAPI.Tickets.Controllers; diff --git a/TickAPI/TickAPI/Tickets/Repositories/TicketRepository.cs b/TickAPI/TickAPI/Tickets/Repositories/TicketRepository.cs index 90d3244..f32917f 100644 --- a/TickAPI/TickAPI/Tickets/Repositories/TicketRepository.cs +++ b/TickAPI/TickAPI/Tickets/Repositories/TicketRepository.cs @@ -72,20 +72,20 @@ public async Task MarkTicketAsUsed(Guid id) return Result.Success(); } - public async Task AddTicketAsync(Ticket ticket) + public async Task> AddTicketAsync(Ticket ticket) { var maxCount = ticket.Type.MaxCount; if (maxCount <= _tickApiDbContext.Tickets.Count(t => t.Type.Id == ticket.Type.Id)) { - return Result.Failure(StatusCodes.Status400BadRequest, + return Result.Failure(StatusCodes.Status400BadRequest, "The ticket you are trying to buy has already reached its max count"); } _tickApiDbContext.Tickets.Add(ticket); await _tickApiDbContext.SaveChangesAsync(); - return Result.Success(); + return Result.Success(ticket); } public async Task> GetTicketWithDetailsByIdAsync(Guid id) diff --git a/TickAPI/TickAPI/Tickets/Services/TicketService.cs b/TickAPI/TickAPI/Tickets/Services/TicketService.cs index c9de357..96f2a76 100644 --- a/TickAPI/TickAPI/Tickets/Services/TicketService.cs +++ b/TickAPI/TickAPI/Tickets/Services/TicketService.cs @@ -188,7 +188,7 @@ public async Task> GetTicketTypeByIdAsync(Guid ticketTypeId) return Result.Success(ticketTypeResult.Value!); } - public async Task CreateTicketAsync(TicketType type, Customer owner, string? nameOnTicket = null, + public async Task> CreateTicketAsync(TicketType type, Customer owner, string? nameOnTicket = null, string? seats = null) { var ticket = new Ticket From c92aaa991cd9da449ef0926bc0a0a8ca51f55754 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stanis=C5=82aw?= <62651497+staszkiet@users.noreply.github.com> Date: Sun, 15 Jun 2025 09:27:12 +0200 Subject: [PATCH 3/3] Add nullable resellprice --- .../TickApiDbContext/TickApiDbContext.cs | 2 +- ...615072633_nullable resellprice.Designer.cs | 400 ++++++++++++++++++ .../20250615072633_nullable resellprice.cs | 28 ++ 3 files changed, 429 insertions(+), 1 deletion(-) create mode 100644 TickAPI/TickAPI/Migrations/20250615072633_nullable resellprice.Designer.cs create mode 100644 TickAPI/TickAPI/Migrations/20250615072633_nullable resellprice.cs diff --git a/TickAPI/TickAPI/Common/TickApiDbContext/TickApiDbContext.cs b/TickAPI/TickAPI/Common/TickApiDbContext/TickApiDbContext.cs index 6490325..a5b2732 100644 --- a/TickAPI/TickAPI/Common/TickApiDbContext/TickApiDbContext.cs +++ b/TickAPI/TickAPI/Common/TickApiDbContext/TickApiDbContext.cs @@ -28,7 +28,7 @@ public TickApiDbContext(DbContextOptions options) : base(optio protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); - modelBuilder.Entity().Property(t => t.ResellPrice).HasColumnType("decimal(18,2)"); + modelBuilder.Entity().Property(t => t.ResellPrice).IsRequired(false); modelBuilder.Entity().Property(t => t.Price).HasColumnType("decimal(18,2)"); modelBuilder.Entity().HasData( new Category diff --git a/TickAPI/TickAPI/Migrations/20250615072633_nullable resellprice.Designer.cs b/TickAPI/TickAPI/Migrations/20250615072633_nullable resellprice.Designer.cs new file mode 100644 index 0000000..dd356f8 --- /dev/null +++ b/TickAPI/TickAPI/Migrations/20250615072633_nullable resellprice.Designer.cs @@ -0,0 +1,400 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using TickAPI.Common.TickApiDbContext; + +#nullable disable + +namespace TickAPI.Migrations +{ + [DbContext(typeof(TickApiDbContext))] + [Migration("20250615072633_nullable resellprice")] + partial class nullableresellprice + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "9.0.2") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("CategoryEvent", b => + { + b.Property("CategoriesId") + .HasColumnType("uniqueidentifier"); + + b.Property("EventsId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("CategoriesId", "EventsId"); + + b.HasIndex("EventsId"); + + b.ToTable("CategoryEvent"); + }); + + modelBuilder.Entity("TickAPI.Addresses.Models.Address", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("City") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Country") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("FlatNumber") + .HasColumnType("bigint"); + + b.Property("HouseNumber") + .HasColumnType("bigint"); + + b.Property("PostalCode") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Street") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("Addresses"); + }); + + modelBuilder.Entity("TickAPI.Admins.Models.Admin", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Email") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Login") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("Admins"); + }); + + modelBuilder.Entity("TickAPI.Categories.Models.Category", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("Categories"); + + b.HasData( + new + { + Id = new Guid("ec3daf69-baa9-4fcd-a674-c09884a57272"), + Name = "Music" + }, + new + { + Id = new Guid("de89dd76-3b29-43e1-8f4b-5278b1b8bde2"), + Name = "Sports" + }, + new + { + Id = new Guid("ea58370b-2a17-4770-abea-66399ad69fb8"), + Name = "Conferences" + }, + new + { + Id = new Guid("4a086d9e-59de-4fd1-a1b2-bd9b5eec797c"), + Name = "Theatre" + }, + new + { + Id = new Guid("5f8dbe65-30be-453f-8f22-191a11b2977b"), + Name = "Comedy" + }, + new + { + Id = new Guid("4421327a-4bc8-4706-bec0-666f78ed0c69"), + Name = "Workshops" + }); + }); + + modelBuilder.Entity("TickAPI.Customers.Models.Customer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Email") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("FirstName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("LastName") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("Customers"); + }); + + modelBuilder.Entity("TickAPI.Events.Models.Event", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("AddressId") + .HasColumnType("uniqueidentifier"); + + b.Property("Description") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("EndDate") + .HasColumnType("datetime2"); + + b.Property("EventStatus") + .HasColumnType("int"); + + b.Property("ImageUrl") + .HasColumnType("nvarchar(max)"); + + b.Property("MinimumAge") + .HasColumnType("bigint"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("OrganizerId") + .HasColumnType("uniqueidentifier"); + + b.Property("StartDate") + .HasColumnType("datetime2"); + + b.HasKey("Id"); + + b.HasIndex("AddressId"); + + b.HasIndex("OrganizerId"); + + b.ToTable("Events"); + }); + + modelBuilder.Entity("TickAPI.Organizers.Models.Organizer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("DisplayName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Email") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("FirstName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("IsVerified") + .HasColumnType("bit"); + + b.Property("LastName") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("Organizers"); + }); + + modelBuilder.Entity("TickAPI.TicketTypes.Models.TicketType", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("AvailableFrom") + .HasColumnType("datetime2"); + + b.Property("Currency") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("EventId") + .HasColumnType("uniqueidentifier"); + + b.Property("MaxCount") + .HasColumnType("bigint"); + + b.Property("Price") + .HasColumnType("decimal(18,2)"); + + b.HasKey("Id"); + + b.HasIndex("EventId"); + + b.ToTable("TicketTypes"); + }); + + modelBuilder.Entity("TickAPI.Tickets.Models.Ticket", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ForResell") + .HasColumnType("bit"); + + b.Property("NameOnTicket") + .HasColumnType("nvarchar(max)"); + + b.Property("OwnerId") + .HasColumnType("uniqueidentifier"); + + b.Property("ResellCurrency") + .HasColumnType("nvarchar(max)"); + + b.Property("ResellPrice") + .HasColumnType("decimal(18,2)"); + + b.Property("Seats") + .HasColumnType("nvarchar(max)"); + + b.Property("TypeId") + .HasColumnType("uniqueidentifier"); + + b.Property("Used") + .HasColumnType("bit"); + + b.HasKey("Id"); + + b.HasIndex("OwnerId"); + + b.HasIndex("TypeId"); + + b.ToTable("Tickets"); + }); + + modelBuilder.Entity("CategoryEvent", b => + { + b.HasOne("TickAPI.Categories.Models.Category", null) + .WithMany() + .HasForeignKey("CategoriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("TickAPI.Events.Models.Event", null) + .WithMany() + .HasForeignKey("EventsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("TickAPI.Events.Models.Event", b => + { + b.HasOne("TickAPI.Addresses.Models.Address", "Address") + .WithMany() + .HasForeignKey("AddressId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("TickAPI.Organizers.Models.Organizer", "Organizer") + .WithMany("Events") + .HasForeignKey("OrganizerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Address"); + + b.Navigation("Organizer"); + }); + + modelBuilder.Entity("TickAPI.TicketTypes.Models.TicketType", b => + { + b.HasOne("TickAPI.Events.Models.Event", "Event") + .WithMany("TicketTypes") + .HasForeignKey("EventId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Event"); + }); + + modelBuilder.Entity("TickAPI.Tickets.Models.Ticket", b => + { + b.HasOne("TickAPI.Customers.Models.Customer", "Owner") + .WithMany("Tickets") + .HasForeignKey("OwnerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("TickAPI.TicketTypes.Models.TicketType", "Type") + .WithMany("Tickets") + .HasForeignKey("TypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + + b.Navigation("Type"); + }); + + modelBuilder.Entity("TickAPI.Customers.Models.Customer", b => + { + b.Navigation("Tickets"); + }); + + modelBuilder.Entity("TickAPI.Events.Models.Event", b => + { + b.Navigation("TicketTypes"); + }); + + modelBuilder.Entity("TickAPI.Organizers.Models.Organizer", b => + { + b.Navigation("Events"); + }); + + modelBuilder.Entity("TickAPI.TicketTypes.Models.TicketType", b => + { + b.Navigation("Tickets"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/TickAPI/TickAPI/Migrations/20250615072633_nullable resellprice.cs b/TickAPI/TickAPI/Migrations/20250615072633_nullable resellprice.cs new file mode 100644 index 0000000..d1de12b --- /dev/null +++ b/TickAPI/TickAPI/Migrations/20250615072633_nullable resellprice.cs @@ -0,0 +1,28 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace TickAPI.Migrations +{ + /// + public partial class nullableresellprice : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "ResellPrice", + table: "Tickets", + type: "decimal(18,2)", + nullable: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "ResellPrice", + table: "Tickets"); + } + } +}