From fb02eb58a3aeb3b78d36462080090fe84ca8088d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stanis=C5=82aw?= <62651497+staszkiet@users.noreply.github.com> Date: Fri, 9 May 2025 07:03:25 +0200 Subject: [PATCH 1/3] Working feature --- .../Tickets/Services/TicketServiceTests.cs | 6 +- .../20250508114210_UsedTicket.Designer.cs | 392 ++++++++++++++++++ .../Migrations/20250508114210_UsedTicket.cs | 29 ++ .../TickApiDbContextModelSnapshot.cs | 3 + .../Tickets/Abstractions/ITicketFilter.cs | 13 + .../Abstractions/ITicketFilterApplier.cs | 9 + .../Tickets/Abstractions/ITicketService.cs | 3 +- .../Tickets/Controllers/TicketsController.cs | 6 +- .../Tickets/DTOs/Request/TicketFiltersDto.cs | 10 + .../DTOs/Response/GetTicketForCustomerDto.cs | 1 + .../TickAPI/Tickets/Filters/TicketFilter.cs | 44 ++ .../Tickets/Filters/TicketFilterApplier.cs | 37 ++ TickAPI/TickAPI/Tickets/Models/Ticket.cs | 1 + .../TickAPI/Tickets/Services/TicketService.cs | 12 +- 14 files changed, 559 insertions(+), 7 deletions(-) create mode 100644 TickAPI/TickAPI/Migrations/20250508114210_UsedTicket.Designer.cs create mode 100644 TickAPI/TickAPI/Migrations/20250508114210_UsedTicket.cs create mode 100644 TickAPI/TickAPI/Tickets/Abstractions/ITicketFilter.cs create mode 100644 TickAPI/TickAPI/Tickets/Abstractions/ITicketFilterApplier.cs create mode 100644 TickAPI/TickAPI/Tickets/DTOs/Request/TicketFiltersDto.cs create mode 100644 TickAPI/TickAPI/Tickets/Filters/TicketFilter.cs create mode 100644 TickAPI/TickAPI/Tickets/Filters/TicketFilterApplier.cs diff --git a/TickAPI/TickAPI.Tests/Tickets/Services/TicketServiceTests.cs b/TickAPI/TickAPI.Tests/Tickets/Services/TicketServiceTests.cs index 479c287..6ff2147 100644 --- a/TickAPI/TickAPI.Tests/Tickets/Services/TicketServiceTests.cs +++ b/TickAPI/TickAPI.Tests/Tickets/Services/TicketServiceTests.cs @@ -447,6 +447,7 @@ public async Task GetTicketsForCustomerAsync_WithValidInput_ReturnsSuccessResult { new Ticket { + Id = new Guid(), Type = new TicketType { Event = new Event @@ -459,6 +460,7 @@ public async Task GetTicketsForCustomerAsync_WithValidInput_ReturnsSuccessResult }, new Ticket { + Id = new Guid(), Type = new TicketType { Event = new Event @@ -480,8 +482,8 @@ public async Task GetTicketsForCustomerAsync_WithValidInput_ReturnsSuccessResult false, new PaginationDetails(0, 2) ); - var mappedData1 = new GetTicketForCustomerDto("EventName", new DateTime(2025, 10, 10), new DateTime(2025, 10, 20)); - var mappedData2 = new GetTicketForCustomerDto("EventName2", new DateTime(2025, 11, 10), new DateTime(2025, 11, 20)); + var mappedData1 = new GetTicketForCustomerDto(tickets[0].Id, "EventName", new DateTime(2025, 10, 10), new DateTime(2025, 10, 20)); + var mappedData2 = new GetTicketForCustomerDto(tickets[1].Id, "EventName2", new DateTime(2025, 11, 10), new DateTime(2025, 11, 20)); var mappedPaginatedData = new PaginatedData ( new List{mappedData1, mappedData2}, diff --git a/TickAPI/TickAPI/Migrations/20250508114210_UsedTicket.Designer.cs b/TickAPI/TickAPI/Migrations/20250508114210_UsedTicket.Designer.cs new file mode 100644 index 0000000..f2dca06 --- /dev/null +++ b/TickAPI/TickAPI/Migrations/20250508114210_UsedTicket.Designer.cs @@ -0,0 +1,392 @@ +// +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("20250508114210_UsedTicket")] + partial class UsedTicket + { + /// + 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("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") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("OwnerId") + .HasColumnType("uniqueidentifier"); + + 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/20250508114210_UsedTicket.cs b/TickAPI/TickAPI/Migrations/20250508114210_UsedTicket.cs new file mode 100644 index 0000000..852c68f --- /dev/null +++ b/TickAPI/TickAPI/Migrations/20250508114210_UsedTicket.cs @@ -0,0 +1,29 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace TickAPI.Migrations +{ + /// + public partial class UsedTicket : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "Used", + table: "Tickets", + type: "bit", + nullable: false, + defaultValue: false); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "Used", + table: "Tickets"); + } + } +} diff --git a/TickAPI/TickAPI/Migrations/TickApiDbContextModelSnapshot.cs b/TickAPI/TickAPI/Migrations/TickApiDbContextModelSnapshot.cs index 8866990..50fd0cc 100644 --- a/TickAPI/TickAPI/Migrations/TickApiDbContextModelSnapshot.cs +++ b/TickAPI/TickAPI/Migrations/TickApiDbContextModelSnapshot.cs @@ -288,6 +288,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("TypeId") .HasColumnType("uniqueidentifier"); + b.Property("Used") + .HasColumnType("bit"); + b.HasKey("Id"); b.HasIndex("OwnerId"); diff --git a/TickAPI/TickAPI/Tickets/Abstractions/ITicketFilter.cs b/TickAPI/TickAPI/Tickets/Abstractions/ITicketFilter.cs new file mode 100644 index 0000000..56dc48e --- /dev/null +++ b/TickAPI/TickAPI/Tickets/Abstractions/ITicketFilter.cs @@ -0,0 +1,13 @@ +using TickAPI.Tickets.Models; + +namespace TickAPI.Tickets.Abstractions; + +public interface ITicketFilter +{ + public IQueryable GetTickets(); + public void FilterUsedTickets(); + public void FilterUnusedTickets(); + public void FilterTicketsForResell(); + public void FilterTicketsNotForResell(); + public void FilterTicketsByEventName(string name); +} \ No newline at end of file diff --git a/TickAPI/TickAPI/Tickets/Abstractions/ITicketFilterApplier.cs b/TickAPI/TickAPI/Tickets/Abstractions/ITicketFilterApplier.cs new file mode 100644 index 0000000..1c76a38 --- /dev/null +++ b/TickAPI/TickAPI/Tickets/Abstractions/ITicketFilterApplier.cs @@ -0,0 +1,9 @@ +using TickAPI.Tickets.DTOs.Request; +using TickAPI.Tickets.Models; + +namespace TickAPI.Tickets.Abstractions; + +public interface ITicketFilterApplier +{ + public IQueryable ApplyFilters(TicketFiltersDto filters); +} \ No newline at end of file diff --git a/TickAPI/TickAPI/Tickets/Abstractions/ITicketService.cs b/TickAPI/TickAPI/Tickets/Abstractions/ITicketService.cs index 37b6384..028353b 100644 --- a/TickAPI/TickAPI/Tickets/Abstractions/ITicketService.cs +++ b/TickAPI/TickAPI/Tickets/Abstractions/ITicketService.cs @@ -1,5 +1,6 @@ using TickAPI.Common.Pagination.Responses; using TickAPI.Common.Results.Generic; +using TickAPI.Tickets.DTOs.Request; using TickAPI.Tickets.DTOs.Response; using TickAPI.TicketTypes.Models; @@ -12,5 +13,5 @@ public interface ITicketService public Task>> GetTicketsForResellAsync(Guid eventId, int page, int pageSize); public Task>> GetTicketsForCustomerAsync(string email, int page, - int pageSize); + int pageSize, TicketFiltersDto ? ticketFilters = null); } \ No newline at end of file diff --git a/TickAPI/TickAPI/Tickets/Controllers/TicketsController.cs b/TickAPI/TickAPI/Tickets/Controllers/TicketsController.cs index 78979fb..c6838e6 100644 --- a/TickAPI/TickAPI/Tickets/Controllers/TicketsController.cs +++ b/TickAPI/TickAPI/Tickets/Controllers/TicketsController.cs @@ -5,6 +5,8 @@ using TickAPI.Tickets.Abstractions; using TickAPI.Tickets.DTOs.Response; using TickAPI.Common.Pagination.Responses; +using TickAPI.Events.DTOs.Request; +using TickAPI.Tickets.DTOs.Request; namespace TickAPI.Tickets.Controllers; @@ -51,14 +53,14 @@ public async Task>> Ge [AuthorizeWithPolicy(AuthPolicies.CustomerPolicy)] [HttpGet] - public async Task>> GetTicketsForCustomer([FromQuery] int pageSize, [FromQuery] int page) + public async Task>> GetTicketsForCustomer([FromQuery] int pageSize, [FromQuery] int page, [FromQuery] TicketFiltersDto filters) { var emailResult = _claimsService.GetEmailFromClaims(User.Claims); if (emailResult.IsError) { return StatusCode(emailResult.StatusCode, emailResult.ErrorMsg); } - var tickets = await _ticketService.GetTicketsForCustomerAsync(emailResult.Value!, page, pageSize); + var tickets = await _ticketService.GetTicketsForCustomerAsync(emailResult.Value!, page, pageSize, filters); if (tickets.IsError) { return StatusCode(tickets.StatusCode, tickets.ErrorMsg); diff --git a/TickAPI/TickAPI/Tickets/DTOs/Request/TicketFiltersDto.cs b/TickAPI/TickAPI/Tickets/DTOs/Request/TicketFiltersDto.cs new file mode 100644 index 0000000..b6204f4 --- /dev/null +++ b/TickAPI/TickAPI/Tickets/DTOs/Request/TicketFiltersDto.cs @@ -0,0 +1,10 @@ +namespace TickAPI.Tickets.DTOs.Request; + +public record TicketFiltersDto +{ + public bool usedOnly { get; set; } + public bool unusedOnly { get; set; } + public bool forResellOnly { get; set; } + public bool notForResellOnly { get; set; } + public string ? EventName { get; set; } +} \ No newline at end of file diff --git a/TickAPI/TickAPI/Tickets/DTOs/Response/GetTicketForCustomerDto.cs b/TickAPI/TickAPI/Tickets/DTOs/Response/GetTicketForCustomerDto.cs index ca94458..db50365 100644 --- a/TickAPI/TickAPI/Tickets/DTOs/Response/GetTicketForCustomerDto.cs +++ b/TickAPI/TickAPI/Tickets/DTOs/Response/GetTicketForCustomerDto.cs @@ -2,6 +2,7 @@ public record GetTicketForCustomerDto ( + Guid TicketId, string EventName, DateTime EventStartDate, DateTime EventEndDate diff --git a/TickAPI/TickAPI/Tickets/Filters/TicketFilter.cs b/TickAPI/TickAPI/Tickets/Filters/TicketFilter.cs new file mode 100644 index 0000000..3e08cd9 --- /dev/null +++ b/TickAPI/TickAPI/Tickets/Filters/TicketFilter.cs @@ -0,0 +1,44 @@ +using TickAPI.Tickets.Abstractions; +using TickAPI.Tickets.Models; + +namespace TickAPI.Tickets.Filters; + +public class TicketFilter : ITicketFilter +{ + IQueryable _tickets; + + public TicketFilter(IQueryable tickets) + { + _tickets = tickets; + } + + public IQueryable GetTickets() + { + return _tickets; + } + + public void FilterUsedTickets() + { + _tickets = _tickets.Where(t => t.Used); + } + + public void FilterUnusedTickets() + { + _tickets = _tickets.Where(t => !t.Used); + } + + public void FilterTicketsForResell() + { + _tickets = _tickets.Where(t => t.ForResell); + } + + public void FilterTicketsNotForResell() + { + _tickets = _tickets.Where(t => !t.ForResell); + } + + public void FilterTicketsByEventName(string name) + { + _tickets = _tickets.Where(t => t.Type.Event.Name.ToLower().Contains(name.ToLower())); + } +} \ No newline at end of file diff --git a/TickAPI/TickAPI/Tickets/Filters/TicketFilterApplier.cs b/TickAPI/TickAPI/Tickets/Filters/TicketFilterApplier.cs new file mode 100644 index 0000000..b7154b3 --- /dev/null +++ b/TickAPI/TickAPI/Tickets/Filters/TicketFilterApplier.cs @@ -0,0 +1,37 @@ +using TickAPI.Tickets.Abstractions; +using TickAPI.Tickets.DTOs.Request; +using TickAPI.Tickets.Models; + +namespace TickAPI.Tickets.Filters; + +public class TicketFilterApplier +{ + private readonly ITicketFilter _ticketFilter; + private readonly Dictionary, Action> _filterActions; + + public TicketFilterApplier(ITicketFilter ticketFilter) + { + _ticketFilter = ticketFilter; + _filterActions = new Dictionary, Action> + { + { f => !string.IsNullOrEmpty(f.EventName), f => _ticketFilter.FilterTicketsByEventName(f.EventName!) }, + { f => f.usedOnly, f => _ticketFilter.FilterUsedTickets() }, + { f => f.unusedOnly, f => _ticketFilter.FilterUnusedTickets() }, + { f => f.forResellOnly, f => _ticketFilter.FilterTicketsForResell() }, + { f => f.notForResellOnly, f => _ticketFilter.FilterTicketsNotForResell() }, + }; + } + + public IQueryable ApplyFilters(TicketFiltersDto filters) + { + foreach (var (condition, apply) in _filterActions) + { + if (condition(filters)) + { + apply(filters); + } + } + + return _ticketFilter.GetTickets(); + } +} \ No newline at end of file diff --git a/TickAPI/TickAPI/Tickets/Models/Ticket.cs b/TickAPI/TickAPI/Tickets/Models/Ticket.cs index 21f765f..49a68ac 100644 --- a/TickAPI/TickAPI/Tickets/Models/Ticket.cs +++ b/TickAPI/TickAPI/Tickets/Models/Ticket.cs @@ -11,4 +11,5 @@ public class Ticket public string NameOnTicket { get; set; } public string? Seats { get; set; } public bool ForResell { get; set; } + public bool Used { get; set; } } \ No newline at end of file diff --git a/TickAPI/TickAPI/Tickets/Services/TicketService.cs b/TickAPI/TickAPI/Tickets/Services/TicketService.cs index d003a6e..7b7fa2e 100644 --- a/TickAPI/TickAPI/Tickets/Services/TicketService.cs +++ b/TickAPI/TickAPI/Tickets/Services/TicketService.cs @@ -2,7 +2,9 @@ using TickAPI.Common.Pagination.Responses; using TickAPI.Common.Results.Generic; using TickAPI.Tickets.Abstractions; +using TickAPI.Tickets.DTOs.Request; using TickAPI.Tickets.DTOs.Response; +using TickAPI.Tickets.Filters; using TickAPI.TicketTypes.Models; namespace TickAPI.Tickets.Services; @@ -48,9 +50,15 @@ public async Task>> GetTicke return Result>.Success(paginatedResult); } //TODO: Maybe apply some filtering over here? - public async Task>> GetTicketsForCustomerAsync(string email, int page, int pageSize) + public async Task>> GetTicketsForCustomerAsync(string email, int page, int pageSize, TicketFiltersDto ? ticketFilters = null) { var customerTickets = _ticketRepository.GetTicketsByCustomerEmail(email); + if (ticketFilters != null) + { + var filter = new TicketFilter(customerTickets); + var applier = new TicketFilterApplier(filter); + customerTickets = applier.ApplyFilters(ticketFilters); + } var paginatedCustomerTickets = await _paginationService.PaginateAsync(customerTickets, pageSize, page); if (paginatedCustomerTickets.IsError) { @@ -58,7 +66,7 @@ public async Task>> GetTicketsForC } var paginatedResult = _paginationService.MapData(paginatedCustomerTickets.Value!, - t => new GetTicketForCustomerDto(t.Type.Event.Name, t.Type.Event.StartDate, t.Type.Event.EndDate)); + t => new GetTicketForCustomerDto(t.Id, t.Type.Event.Name, t.Type.Event.StartDate, t.Type.Event.EndDate)); return Result>.Success(paginatedResult); } From 715b5262004363f739b5f6189348b26c74da388f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stanis=C5=82aw?= <62651497+staszkiet@users.noreply.github.com> Date: Fri, 9 May 2025 07:31:20 +0200 Subject: [PATCH 2/3] tests --- .../Filters/TicketFilterApplierTests.cs | 183 ++++++++++++++++ .../Tickets/Filters/TicketFilterTests.cs | 201 ++++++++++++++++++ 2 files changed, 384 insertions(+) create mode 100644 TickAPI/TickAPI.Tests/Tickets/Filters/TicketFilterApplierTests.cs create mode 100644 TickAPI/TickAPI.Tests/Tickets/Filters/TicketFilterTests.cs diff --git a/TickAPI/TickAPI.Tests/Tickets/Filters/TicketFilterApplierTests.cs b/TickAPI/TickAPI.Tests/Tickets/Filters/TicketFilterApplierTests.cs new file mode 100644 index 0000000..0a81f6a --- /dev/null +++ b/TickAPI/TickAPI.Tests/Tickets/Filters/TicketFilterApplierTests.cs @@ -0,0 +1,183 @@ +using Moq; +using TickAPI.Tickets.Abstractions; +using TickAPI.Tickets.DTOs.Request; +using TickAPI.Tickets.Filters; +using TickAPI.Tickets.Models; + +namespace TickAPI.Tests.Tickets.Filters; + +public class TicketFilterApplierTests +{ + private readonly Mock _mockTicketFilter; + private readonly TicketFilterApplier _ticketFilterApplier; + private readonly IQueryable _emptyQueryable = new List().AsQueryable(); + + public TicketFilterApplierTests() + { + _mockTicketFilter = new Mock(); + _mockTicketFilter.Setup(tf => tf.GetTickets()).Returns(_emptyQueryable); + _ticketFilterApplier = new TicketFilterApplier(_mockTicketFilter.Object); + } + + [Fact] + public void ApplyFilters_WithEventName_ShouldCallFilterTicketsByEventName() + { + // Arrange + var filters = new TicketFiltersDto + { + EventName = "concert", + usedOnly = false, + unusedOnly = false, + forResellOnly = false, + notForResellOnly = false + }; + + // Act + _ticketFilterApplier.ApplyFilters(filters); + + // Assert + _mockTicketFilter.Verify(tf => tf.FilterTicketsByEventName(filters.EventName!), Times.Once); + _mockTicketFilter.Verify(tf => tf.GetTickets(), Times.Once); + } + + [Fact] + public void ApplyFilters_WithUsedOnly_ShouldCallFilterUsedTickets() + { + // Arrange + var filters = new TicketFiltersDto + { + EventName = null, + usedOnly = true, + unusedOnly = false, + forResellOnly = false, + notForResellOnly = false + }; + + // Act + _ticketFilterApplier.ApplyFilters(filters); + + // Assert + _mockTicketFilter.Verify(tf => tf.FilterUsedTickets(), Times.Once); + _mockTicketFilter.Verify(tf => tf.GetTickets(), Times.Once); + } + + [Fact] + public void ApplyFilters_WithUnusedOnly_ShouldCallFilterUnusedTickets() + { + // Arrange + var filters = new TicketFiltersDto + { + EventName = null, + usedOnly = false, + unusedOnly = true, + forResellOnly = false, + notForResellOnly = false + }; + + // Act + _ticketFilterApplier.ApplyFilters(filters); + + // Assert + _mockTicketFilter.Verify(tf => tf.FilterUnusedTickets(), Times.Once); + _mockTicketFilter.Verify(tf => tf.GetTickets(), Times.Once); + } + + [Fact] + public void ApplyFilters_WithForResellOnly_ShouldCallFilterTicketsForResell() + { + // Arrange + var filters = new TicketFiltersDto + { + EventName = null, + usedOnly = false, + unusedOnly = false, + forResellOnly = true, + notForResellOnly = false + }; + + // Act + _ticketFilterApplier.ApplyFilters(filters); + + // Assert + _mockTicketFilter.Verify(tf => tf.FilterTicketsForResell(), Times.Once); + _mockTicketFilter.Verify(tf => tf.GetTickets(), Times.Once); + } + + [Fact] + public void ApplyFilters_WithNotForResellOnly_ShouldCallFilterTicketsNotForResell() + { + // Arrange + var filters = new TicketFiltersDto + { + EventName = null, + usedOnly = false, + unusedOnly = false, + forResellOnly = false, + notForResellOnly = true + }; + + // Act + _ticketFilterApplier.ApplyFilters(filters); + + // Assert + _mockTicketFilter.Verify(tf => tf.FilterTicketsNotForResell(), Times.Once); + _mockTicketFilter.Verify(tf => tf.GetTickets(), Times.Once); + } + + [Fact] + public void ApplyFilters_WithMultipleFilters_ShouldCallAllRelevantFilters() + { + // Arrange + var filters = new TicketFiltersDto + { + EventName = "concert", + usedOnly = true, + unusedOnly = false, + forResellOnly = true, + notForResellOnly = false + }; + + // Act + _ticketFilterApplier.ApplyFilters(filters); + + // Assert + _mockTicketFilter.Verify(tf => tf.FilterTicketsByEventName(filters.EventName!), Times.Once); + _mockTicketFilter.Verify(tf => tf.FilterUsedTickets(), Times.Once); + _mockTicketFilter.Verify(tf => tf.FilterTicketsForResell(), Times.Once); + _mockTicketFilter.Verify(tf => tf.FilterUnusedTickets(), Times.Never); + _mockTicketFilter.Verify(tf => tf.FilterTicketsNotForResell(), Times.Never); + _mockTicketFilter.Verify(tf => tf.GetTickets(), Times.Once); + } + + [Fact] + public void ApplyFilters_WithNoFilters_ShouldOnlyCallGetTickets() + { + // Arrange + var expectedResult = new List + { + new Ticket { NameOnTicket = "Test Ticket" } + }.AsQueryable(); + _mockTicketFilter.Setup(tf => tf.GetTickets()).Returns(expectedResult); + var filters = new TicketFiltersDto + { + EventName = null, + usedOnly = false, + unusedOnly = false, + forResellOnly = false, + notForResellOnly = false + }; + + // Act + var result = _ticketFilterApplier.ApplyFilters(filters); + + // Assert + _mockTicketFilter.Verify(tf => tf.FilterTicketsByEventName(It.IsAny()), Times.Never); + _mockTicketFilter.Verify(tf => tf.FilterUsedTickets(), Times.Never); + _mockTicketFilter.Verify(tf => tf.FilterUnusedTickets(), Times.Never); + _mockTicketFilter.Verify(tf => tf.FilterTicketsForResell(), Times.Never); + _mockTicketFilter.Verify(tf => tf.FilterTicketsNotForResell(), Times.Never); + _mockTicketFilter.Verify(tf => tf.GetTickets(), Times.Once); + Assert.Same(expectedResult, result); + } + +} \ No newline at end of file diff --git a/TickAPI/TickAPI.Tests/Tickets/Filters/TicketFilterTests.cs b/TickAPI/TickAPI.Tests/Tickets/Filters/TicketFilterTests.cs new file mode 100644 index 0000000..10031b4 --- /dev/null +++ b/TickAPI/TickAPI.Tests/Tickets/Filters/TicketFilterTests.cs @@ -0,0 +1,201 @@ +using TickAPI.Customers.Models; +using TickAPI.Events.Models; +using TickAPI.Tickets.Filters; +using TickAPI.Tickets.Models; +using TickAPI.TicketTypes.Models; + +namespace TickAPI.Tests.Tickets.Filters; + +public class TicketFilterTests +{ + private static List GetTestTickets() => + [ + new Ticket + { + Id = Guid.NewGuid(), + Type = new TicketType + { + Price = 100, + Event = new Event + { + Name = "Concert A", + Description = "An amazing rock concert" + } + }, + Owner = new Customer { FirstName = "John", LastName = "Doe" }, + NameOnTicket = "John Doe", + Seats = "A12", + ForResell = true, + Used = false + }, + + new Ticket + { + Id = Guid.NewGuid(), + Type = new TicketType + { + Price = 50, + Event = new Event + { + Name = "Concert B", + Description = "Chill jazz night" + } + }, + Owner = new Customer { FirstName = "Jane", LastName = "Smith" }, + NameOnTicket = "Jane Smith", + Seats = "B5", + ForResell = false, + Used = true + }, + + new Ticket + { + Id = Guid.NewGuid(), + Type = new TicketType + { + Price = 200, + Event = new Event + { + Name = "Conference", + Description = "Tech event for developers" + } + }, + Owner = new Customer { FirstName = "Mike", LastName = "Johnson" }, + NameOnTicket = "Mike Johnson", + Seats = "C8", + ForResell = false, + Used = false + } + ]; + + [Fact] + public void FilterUsedTickets_ShouldReturnOnlyUsedTickets() + { + // Arrange + var tickets = GetTestTickets(); + var sut = new TicketFilter(tickets.AsQueryable()); + + //Act + sut.FilterUsedTickets(); + var result = sut.GetTickets().ToList(); + + // Assert + Assert.Single(result); + Assert.Contains(tickets[1], result); + } + + [Fact] + public void FilterUnusedTickets_ShouldReturnOnlyUnusedTickets() + { + // Arrange + var tickets = GetTestTickets(); + var sut = new TicketFilter(tickets.AsQueryable()); + + // Act + sut.FilterUnusedTickets(); + var result = sut.GetTickets().ToList(); + + // Assert + Assert.Equal(2, result.Count); + Assert.Contains(tickets[0], result); + Assert.Contains(tickets[2], result); + } + + [Fact] + public void FilterTicketsForResell_ShouldReturnOnlyTicketsForResell() + { + // Arrange + var tickets = GetTestTickets(); + var sut = new TicketFilter(tickets.AsQueryable()); + + //Act + sut.FilterTicketsForResell(); + var result = sut.GetTickets().ToList(); + + // Assert + Assert.Single(result); + Assert.Contains(tickets[0], result); + } + + [Fact] + public void FilterTicketsNotForResell_ShouldReturnOnlyTicketsNotForResell() + { + // Arrange + var tickets = GetTestTickets(); + var sut = new TicketFilter(tickets.AsQueryable()); + + // Act + sut.FilterTicketsNotForResell(); + var result = sut.GetTickets().ToList(); + + // Assert + Assert.Equal(2, result.Count); + Assert.Contains(tickets[1], result); + Assert.Contains(tickets[2], result); + } + + [Fact] + public void FilterTicketsByEventName_ShouldReturnTicketsWithMatchingEventName() + { + // Arrange + var tickets = GetTestTickets(); + + // Act + var ticketFilter = new TicketFilter(tickets.AsQueryable()); + ticketFilter.FilterTicketsByEventName("concert"); + var result = ticketFilter.GetTickets().ToList(); + + // Assert + Assert.Equal(2, result.Count); + Assert.Contains(tickets[0], result); + Assert.Contains(tickets[1], result); + } + + [Fact] + public void FilterTicketsByEventName_CaseInsensitive_ShouldReturnMatchingTickets() + { + // Arrange + var tickets = GetTestTickets(); + + // Act + var ticketFilter = new TicketFilter(tickets.AsQueryable()); + ticketFilter.FilterTicketsByEventName("cONcErt a"); + var result = ticketFilter.GetTickets().ToList(); + + // Assert + Assert.Single(result); + Assert.Contains(tickets[0], result); + } + + [Fact] + public void FilterTicketsByEventName_WithNoMatches_ShouldReturnEmptyList() + { + // Arrange + var tickets = GetTestTickets(); + + // Act + var ticketFilter = new TicketFilter(tickets.AsQueryable()); + ticketFilter.FilterTicketsByEventName("nonexistent event"); + var result = ticketFilter.GetTickets().ToList(); + + // Assert + Assert.Empty(result); + } + + [Fact] + public void GetTickets_WithNoFilters_ShouldReturnAllTickets() + { + // Arrange + var tickets = GetTestTickets(); + + // Act + var ticketFilter = new TicketFilter(tickets.AsQueryable()); + var result = ticketFilter.GetTickets().ToList(); + + // Assert + Assert.Equal(3, result.Count); + Assert.Contains(tickets[0], result); + Assert.Contains(tickets[1], result); + Assert.Contains(tickets[2], result); + } +} \ No newline at end of file From 0bbfe5ba60cb97ef8c64d8e787d9998a9e8f9f07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stanis=C5=82aw?= <62651497+staszkiet@users.noreply.github.com> Date: Sat, 10 May 2025 12:19:56 +0200 Subject: [PATCH 3/3] trzcinskik comments --- .../Filters/TicketFilterApplierTests.cs | 92 ++++++++----------- .../Tickets/Services/TicketServiceTests.cs | 6 +- .../Tickets/DTOs/Request/TicketFiltersDto.cs | 24 +++-- .../DTOs/Response/GetTicketForCustomerDto.cs | 3 +- .../Tickets/Filters/TicketFilterApplier.cs | 8 +- .../TickAPI/Tickets/Services/TicketService.cs | 3 +- 6 files changed, 67 insertions(+), 69 deletions(-) diff --git a/TickAPI/TickAPI.Tests/Tickets/Filters/TicketFilterApplierTests.cs b/TickAPI/TickAPI.Tests/Tickets/Filters/TicketFilterApplierTests.cs index 0a81f6a..1bf1ecf 100644 --- a/TickAPI/TickAPI.Tests/Tickets/Filters/TicketFilterApplierTests.cs +++ b/TickAPI/TickAPI.Tests/Tickets/Filters/TicketFilterApplierTests.cs @@ -24,13 +24,11 @@ public void ApplyFilters_WithEventName_ShouldCallFilterTicketsByEventName() { // Arrange var filters = new TicketFiltersDto - { - EventName = "concert", - usedOnly = false, - unusedOnly = false, - forResellOnly = false, - notForResellOnly = false - }; + ( + null, + null, + "concert" + ); // Act _ticketFilterApplier.ApplyFilters(filters); @@ -45,13 +43,11 @@ public void ApplyFilters_WithUsedOnly_ShouldCallFilterUsedTickets() { // Arrange var filters = new TicketFiltersDto - { - EventName = null, - usedOnly = true, - unusedOnly = false, - forResellOnly = false, - notForResellOnly = false - }; + ( + UsageFilter.OnlyUsed, + null, + null + ); // Act _ticketFilterApplier.ApplyFilters(filters); @@ -66,13 +62,11 @@ public void ApplyFilters_WithUnusedOnly_ShouldCallFilterUnusedTickets() { // Arrange var filters = new TicketFiltersDto - { - EventName = null, - usedOnly = false, - unusedOnly = true, - forResellOnly = false, - notForResellOnly = false - }; + ( + UsageFilter.OnlyNotUsed, + null, + null + ); // Act _ticketFilterApplier.ApplyFilters(filters); @@ -87,13 +81,11 @@ public void ApplyFilters_WithForResellOnly_ShouldCallFilterTicketsForResell() { // Arrange var filters = new TicketFiltersDto - { - EventName = null, - usedOnly = false, - unusedOnly = false, - forResellOnly = true, - notForResellOnly = false - }; + ( + null, + ResellFilter.OnlyForResell, + null + ); // Act _ticketFilterApplier.ApplyFilters(filters); @@ -108,13 +100,11 @@ public void ApplyFilters_WithNotForResellOnly_ShouldCallFilterTicketsNotForResel { // Arrange var filters = new TicketFiltersDto - { - EventName = null, - usedOnly = false, - unusedOnly = false, - forResellOnly = false, - notForResellOnly = true - }; + ( + null, + ResellFilter.OnlyNotForResell, + null + ); // Act _ticketFilterApplier.ApplyFilters(filters); @@ -129,23 +119,21 @@ public void ApplyFilters_WithMultipleFilters_ShouldCallAllRelevantFilters() { // Arrange var filters = new TicketFiltersDto - { - EventName = "concert", - usedOnly = true, - unusedOnly = false, - forResellOnly = true, - notForResellOnly = false - }; + ( + UsageFilter.OnlyNotUsed, + ResellFilter.OnlyNotForResell, + "concert" + ); // Act _ticketFilterApplier.ApplyFilters(filters); // Assert _mockTicketFilter.Verify(tf => tf.FilterTicketsByEventName(filters.EventName!), Times.Once); - _mockTicketFilter.Verify(tf => tf.FilterUsedTickets(), Times.Once); - _mockTicketFilter.Verify(tf => tf.FilterTicketsForResell(), Times.Once); - _mockTicketFilter.Verify(tf => tf.FilterUnusedTickets(), Times.Never); - _mockTicketFilter.Verify(tf => tf.FilterTicketsNotForResell(), Times.Never); + _mockTicketFilter.Verify(tf => tf.FilterUsedTickets(), Times.Never); + _mockTicketFilter.Verify(tf => tf.FilterTicketsForResell(), Times.Never); + _mockTicketFilter.Verify(tf => tf.FilterUnusedTickets(), Times.Once); + _mockTicketFilter.Verify(tf => tf.FilterTicketsNotForResell(), Times.Once); _mockTicketFilter.Verify(tf => tf.GetTickets(), Times.Once); } @@ -159,13 +147,11 @@ public void ApplyFilters_WithNoFilters_ShouldOnlyCallGetTickets() }.AsQueryable(); _mockTicketFilter.Setup(tf => tf.GetTickets()).Returns(expectedResult); var filters = new TicketFiltersDto - { - EventName = null, - usedOnly = false, - unusedOnly = false, - forResellOnly = false, - notForResellOnly = false - }; + ( + null, + null, + null + ); // Act var result = _ticketFilterApplier.ApplyFilters(filters); diff --git a/TickAPI/TickAPI.Tests/Tickets/Services/TicketServiceTests.cs b/TickAPI/TickAPI.Tests/Tickets/Services/TicketServiceTests.cs index 6ff2147..389f7a4 100644 --- a/TickAPI/TickAPI.Tests/Tickets/Services/TicketServiceTests.cs +++ b/TickAPI/TickAPI.Tests/Tickets/Services/TicketServiceTests.cs @@ -448,6 +448,7 @@ public async Task GetTicketsForCustomerAsync_WithValidInput_ReturnsSuccessResult new Ticket { Id = new Guid(), + Used = false, Type = new TicketType { Event = new Event @@ -461,6 +462,7 @@ public async Task GetTicketsForCustomerAsync_WithValidInput_ReturnsSuccessResult new Ticket { Id = new Guid(), + Used = false, Type = new TicketType { Event = new Event @@ -482,8 +484,8 @@ public async Task GetTicketsForCustomerAsync_WithValidInput_ReturnsSuccessResult false, new PaginationDetails(0, 2) ); - var mappedData1 = new GetTicketForCustomerDto(tickets[0].Id, "EventName", new DateTime(2025, 10, 10), new DateTime(2025, 10, 20)); - var mappedData2 = new GetTicketForCustomerDto(tickets[1].Id, "EventName2", new DateTime(2025, 11, 10), new DateTime(2025, 11, 20)); + var mappedData1 = new GetTicketForCustomerDto(tickets[0].Id, "EventName", new DateTime(2025, 10, 10), new DateTime(2025, 10, 20), false); + var mappedData2 = new GetTicketForCustomerDto(tickets[1].Id, "EventName2", new DateTime(2025, 11, 10), new DateTime(2025, 11, 20), false); var mappedPaginatedData = new PaginatedData ( new List{mappedData1, mappedData2}, diff --git a/TickAPI/TickAPI/Tickets/DTOs/Request/TicketFiltersDto.cs b/TickAPI/TickAPI/Tickets/DTOs/Request/TicketFiltersDto.cs index b6204f4..19cbf47 100644 --- a/TickAPI/TickAPI/Tickets/DTOs/Request/TicketFiltersDto.cs +++ b/TickAPI/TickAPI/Tickets/DTOs/Request/TicketFiltersDto.cs @@ -1,10 +1,20 @@ namespace TickAPI.Tickets.DTOs.Request; -public record TicketFiltersDto +public enum UsageFilter +{ + OnlyUsed, + OnlyNotUsed +} + +public enum ResellFilter { - public bool usedOnly { get; set; } - public bool unusedOnly { get; set; } - public bool forResellOnly { get; set; } - public bool notForResellOnly { get; set; } - public string ? EventName { get; set; } -} \ No newline at end of file + OnlyForResell, + OnlyNotForResell +} + +public record TicketFiltersDto +( + UsageFilter? Usage, + ResellFilter? Resell, + string? EventName +); \ No newline at end of file diff --git a/TickAPI/TickAPI/Tickets/DTOs/Response/GetTicketForCustomerDto.cs b/TickAPI/TickAPI/Tickets/DTOs/Response/GetTicketForCustomerDto.cs index db50365..4584d76 100644 --- a/TickAPI/TickAPI/Tickets/DTOs/Response/GetTicketForCustomerDto.cs +++ b/TickAPI/TickAPI/Tickets/DTOs/Response/GetTicketForCustomerDto.cs @@ -5,5 +5,6 @@ public record GetTicketForCustomerDto Guid TicketId, string EventName, DateTime EventStartDate, - DateTime EventEndDate + DateTime EventEndDate, + bool Used ); \ No newline at end of file diff --git a/TickAPI/TickAPI/Tickets/Filters/TicketFilterApplier.cs b/TickAPI/TickAPI/Tickets/Filters/TicketFilterApplier.cs index b7154b3..2b9bf6e 100644 --- a/TickAPI/TickAPI/Tickets/Filters/TicketFilterApplier.cs +++ b/TickAPI/TickAPI/Tickets/Filters/TicketFilterApplier.cs @@ -15,10 +15,10 @@ public TicketFilterApplier(ITicketFilter ticketFilter) _filterActions = new Dictionary, Action> { { f => !string.IsNullOrEmpty(f.EventName), f => _ticketFilter.FilterTicketsByEventName(f.EventName!) }, - { f => f.usedOnly, f => _ticketFilter.FilterUsedTickets() }, - { f => f.unusedOnly, f => _ticketFilter.FilterUnusedTickets() }, - { f => f.forResellOnly, f => _ticketFilter.FilterTicketsForResell() }, - { f => f.notForResellOnly, f => _ticketFilter.FilterTicketsNotForResell() }, + { f => f.Usage == UsageFilter.OnlyUsed, f => _ticketFilter.FilterUsedTickets() }, + { f => f.Usage == UsageFilter.OnlyNotUsed, f => _ticketFilter.FilterUnusedTickets() }, + { f => f.Resell == ResellFilter.OnlyForResell, f => _ticketFilter.FilterTicketsForResell() }, + { f => f.Resell == ResellFilter.OnlyNotForResell, f => _ticketFilter.FilterTicketsNotForResell() }, }; } diff --git a/TickAPI/TickAPI/Tickets/Services/TicketService.cs b/TickAPI/TickAPI/Tickets/Services/TicketService.cs index 7b7fa2e..36c7c4c 100644 --- a/TickAPI/TickAPI/Tickets/Services/TicketService.cs +++ b/TickAPI/TickAPI/Tickets/Services/TicketService.cs @@ -49,7 +49,6 @@ public async Task>> GetTicke t => new GetTicketForResellResponseDto(t.Id, t.Type.Price, t.Type.Currency, t.Type.Description, t.Seats)); return Result>.Success(paginatedResult); } - //TODO: Maybe apply some filtering over here? public async Task>> GetTicketsForCustomerAsync(string email, int page, int pageSize, TicketFiltersDto ? ticketFilters = null) { var customerTickets = _ticketRepository.GetTicketsByCustomerEmail(email); @@ -66,7 +65,7 @@ public async Task>> GetTicketsForC } var paginatedResult = _paginationService.MapData(paginatedCustomerTickets.Value!, - t => new GetTicketForCustomerDto(t.Id, t.Type.Event.Name, t.Type.Event.StartDate, t.Type.Event.EndDate)); + t => new GetTicketForCustomerDto(t.Id, t.Type.Event.Name, t.Type.Event.StartDate, t.Type.Event.EndDate, t.Used)); return Result>.Success(paginatedResult); }