From e8e9a85c57f2de17c47a6299d296773464ec3590 Mon Sep 17 00:00:00 2001 From: Khwezi Mngoma Date: Sun, 10 May 2026 15:27:26 +0200 Subject: [PATCH] Migrated database changes after refactoring the Notification model --- .../NotificationConfiguration.cs | 14 +- .../Configuration/QuoteConfiguration.cs | 2 +- LiteCharms.Extensions/EntityModeMappers.cs | 4 +- .../Handlers/SendEmailCommandHandler.cs | 5 +- .../Commands/SendEmailCommand.cs | 2 +- .../Handlers/CreateLeadCommandHandler.cs | 2 +- .../LiteCharms.Features.csproj | 4 + .../UpdateNotificationCommandHandler.cs | 6 + .../Commands/UpdateNotificationCommand.cs | 10 +- .../Orders/Commands/CreateOrderCommand.cs | 18 +- .../Handlers/CreateOrderCommandHandler.cs | 10 +- .../{ => Hash}/Commands/ComputeHashCommand.cs | 2 +- .../Handlers/ComputeHashCommandHandler.cs | 4 +- .../20260510090446_Init.Designer.cs | 631 ------------------ .../20260510091540_AddedPackages.cs | 114 ---- ...ner.cs => 20260510132008_Init.Designer.cs} | 31 +- ...0090446_Init.cs => 20260510132008_Init.cs} | 112 +++- .../Migrations/ShopDbContextModelSnapshot.cs | 27 +- LiteCharms.Models/Enums.cs | 15 + LiteCharms.Models/Notification.cs | 8 +- 20 files changed, 244 insertions(+), 777 deletions(-) rename LiteCharms.Features/{Utilities => Email}/Commands/Handlers/SendEmailCommandHandler.cs (94%) rename LiteCharms.Features/{Utilities => Email}/Commands/SendEmailCommand.cs (98%) rename LiteCharms.Features/Utilities/{ => Hash}/Commands/ComputeHashCommand.cs (86%) rename LiteCharms.Features/Utilities/{ => Hash}/Commands/Handlers/ComputeHashCommandHandler.cs (80%) delete mode 100644 LiteCharms.Infrastructure/Database/Migrations/20260510090446_Init.Designer.cs delete mode 100644 LiteCharms.Infrastructure/Database/Migrations/20260510091540_AddedPackages.cs rename LiteCharms.Infrastructure/Database/Migrations/{20260510091540_AddedPackages.Designer.cs => 20260510132008_Init.Designer.cs} (96%) rename LiteCharms.Infrastructure/Database/Migrations/{20260510090446_Init.cs => 20260510132008_Init.cs} (78%) diff --git a/LiteCharms.Entities/Configuration/NotificationConfiguration.cs b/LiteCharms.Entities/Configuration/NotificationConfiguration.cs index bd103f7..45319a4 100644 --- a/LiteCharms.Entities/Configuration/NotificationConfiguration.cs +++ b/LiteCharms.Entities/Configuration/NotificationConfiguration.cs @@ -1,4 +1,6 @@ -namespace LiteCharms.Entities.Configuration; +using LiteCharms.Models; + +namespace LiteCharms.Entities.Configuration; public class NotificationConfiguration : IEntityTypeConfiguration { @@ -9,18 +11,20 @@ public class NotificationConfiguration : IEntityTypeConfiguration builder.HasKey(f => f.Id); builder.Property(f => f.CreatedAt).IsRequired().ValueGeneratedOnAdd(); builder.Property(f => f.UpdatedAt).IsRequired(false).ValueGeneratedOnUpdate(); - builder.Property(f => f.Direction).IsRequired(); - builder.Property(f => f.Platform).IsRequired(); - builder.Property(f => f.Priority).IsRequired(); + builder.Property(f => f.Direction).IsRequired().HasConversion(); + builder.Property(f => f.Platform).IsRequired().HasConversion(); + builder.Property(f => f.Priority).IsRequired().HasConversion(); + builder.Property(f => f.CorrelationIdType).IsRequired().HasConversion(); builder.Property(f => f.Sender).IsRequired(); builder.Property(f => f.Subject).IsRequired(); builder.Property(f => f.Message).IsRequired(); builder.Property(f => f.Recipient).IsRequired(); builder.Property(f => f.RecipientAddress).IsRequired(); builder.Property(f => f.CorrelationId).IsRequired(); - builder.Property(f => f.CorrelationIdType).IsRequired(); builder.Property(f => f.IsHtml).HasDefaultValue(false); builder.Property(f => f.IsInternal).HasDefaultValue(true); builder.Property(f => f.Processed).HasDefaultValue(false); + builder.Property(f => f.HasError).HasDefaultValue(false); + builder.Property(f => f.Errors).HasColumnType("jsonb").IsRequired(false); } } \ No newline at end of file diff --git a/LiteCharms.Entities/Configuration/QuoteConfiguration.cs b/LiteCharms.Entities/Configuration/QuoteConfiguration.cs index de5240a..d48a768 100644 --- a/LiteCharms.Entities/Configuration/QuoteConfiguration.cs +++ b/LiteCharms.Entities/Configuration/QuoteConfiguration.cs @@ -11,7 +11,7 @@ public class QuoteConfiguration : IEntityTypeConfiguration builder.Property(f => f.UpdatedAt).IsRequired(false).ValueGeneratedOnUpdate(); builder.Property(f => f.ExpiredAt).IsRequired(false); builder.Property(f => f.CustomerId).IsRequired(); - builder.Property(f => f.Status).IsRequired(); + builder.Property(f => f.Status).IsRequired().HasConversion(); builder.Property(f => f.ShoppingCartId).IsRequired(); builder.Property(f => f.Reason).IsRequired(false); diff --git a/LiteCharms.Extensions/EntityModeMappers.cs b/LiteCharms.Extensions/EntityModeMappers.cs index 37ad38e..9a1d97a 100644 --- a/LiteCharms.Extensions/EntityModeMappers.cs +++ b/LiteCharms.Extensions/EntityModeMappers.cs @@ -88,7 +88,9 @@ public static class EntityModeMappers RecipientAddress = entity.RecipientAddress, Priority = entity.Priority, UpdatedAt = entity?.UpdatedAt, - IsHtml = entity!.IsHtml + IsHtml = entity!.IsHtml, + HasError = entity.HasError, + Errors = entity.Errors }; public static Customer ToModel(this Entities.Customer entity) => diff --git a/LiteCharms.Features/Utilities/Commands/Handlers/SendEmailCommandHandler.cs b/LiteCharms.Features/Email/Commands/Handlers/SendEmailCommandHandler.cs similarity index 94% rename from LiteCharms.Features/Utilities/Commands/Handlers/SendEmailCommandHandler.cs rename to LiteCharms.Features/Email/Commands/Handlers/SendEmailCommandHandler.cs index e3fcdf7..30f86dc 100644 --- a/LiteCharms.Features/Utilities/Commands/Handlers/SendEmailCommandHandler.cs +++ b/LiteCharms.Features/Email/Commands/Handlers/SendEmailCommandHandler.cs @@ -1,6 +1,7 @@ -using LiteCharms.Models.Configuraton.Email; +using LiteCharms.Features.Email.Commands; +using LiteCharms.Models.Configuraton.Email; -namespace LiteCharms.Features.Utilities.Commands.Handlers; +namespace LiteCharms.Features.Email.Commands.Handlers; public class SendEmailCommandHandler(IOptions smtpOptions) : IRequestHandler { diff --git a/LiteCharms.Features/Utilities/Commands/SendEmailCommand.cs b/LiteCharms.Features/Email/Commands/SendEmailCommand.cs similarity index 98% rename from LiteCharms.Features/Utilities/Commands/SendEmailCommand.cs rename to LiteCharms.Features/Email/Commands/SendEmailCommand.cs index 4393edd..972e496 100644 --- a/LiteCharms.Features/Utilities/Commands/SendEmailCommand.cs +++ b/LiteCharms.Features/Email/Commands/SendEmailCommand.cs @@ -1,4 +1,4 @@ -namespace LiteCharms.Features.Utilities.Commands; +namespace LiteCharms.Features.Email.Commands; public class SendEmailCommand : IRequest { diff --git a/LiteCharms.Features/Leads/Commands/Handlers/CreateLeadCommandHandler.cs b/LiteCharms.Features/Leads/Commands/Handlers/CreateLeadCommandHandler.cs index bc8295b..256bc22 100644 --- a/LiteCharms.Features/Leads/Commands/Handlers/CreateLeadCommandHandler.cs +++ b/LiteCharms.Features/Leads/Commands/Handlers/CreateLeadCommandHandler.cs @@ -1,4 +1,4 @@ -using LiteCharms.Features.Utilities.Commands; +using LiteCharms.Features.Utilities.Hash.Commands; using LiteCharms.Infrastructure.Database; namespace LiteCharms.Features.Leads.Commands.Handlers; diff --git a/LiteCharms.Features/LiteCharms.Features.csproj b/LiteCharms.Features/LiteCharms.Features.csproj index 9a2a0ac..6f9f146 100644 --- a/LiteCharms.Features/LiteCharms.Features.csproj +++ b/LiteCharms.Features/LiteCharms.Features.csproj @@ -61,4 +61,8 @@ + + + + diff --git a/LiteCharms.Features/Notifications/Commands/Handlers/UpdateNotificationCommandHandler.cs b/LiteCharms.Features/Notifications/Commands/Handlers/UpdateNotificationCommandHandler.cs index 066638a..5ce4e81 100644 --- a/LiteCharms.Features/Notifications/Commands/Handlers/UpdateNotificationCommandHandler.cs +++ b/LiteCharms.Features/Notifications/Commands/Handlers/UpdateNotificationCommandHandler.cs @@ -17,6 +17,12 @@ public class UpdateNotificationCommandHandler(IDbContextFactory c notification.Processed = request.Processed; + if (request.HasError) + { + notification.HasError = request.HasError; + notification.Errors = request.Errors; + } + return await context.SaveChangesAsync(cancellationToken) > 0 ? Result.Ok() : Result.Fail(new Error($"Failed to update notification with id {request.NotificationId}.")); diff --git a/LiteCharms.Features/Notifications/Commands/UpdateNotificationCommand.cs b/LiteCharms.Features/Notifications/Commands/UpdateNotificationCommand.cs index d5961f2..950442d 100644 --- a/LiteCharms.Features/Notifications/Commands/UpdateNotificationCommand.cs +++ b/LiteCharms.Features/Notifications/Commands/UpdateNotificationCommand.cs @@ -6,13 +6,19 @@ public class UpdateNotificationCommand : IRequest public bool Processed { get; set; } - private UpdateNotificationCommand(Guid notificationId, bool processed) + public bool HasError { get; set; } + + public string[]? Errors { get; set; } + + private UpdateNotificationCommand(Guid notificationId, bool processed, bool hasError = false, string[]? errors = null) { NotificationId = notificationId; Processed = processed; + HasError = hasError; + Errors = errors; } - public static UpdateNotificationCommand Create(Guid notificationId, bool processed) + public static UpdateNotificationCommand Create(Guid notificationId, bool processed, bool hasError = false, string[]? errors = null) { if(notificationId == Guid.Empty) throw new ArgumentException("Notification ID cannot be empty.", nameof(notificationId)); diff --git a/LiteCharms.Features/Orders/Commands/CreateOrderCommand.cs b/LiteCharms.Features/Orders/Commands/CreateOrderCommand.cs index e18258e..8baf7e1 100644 --- a/LiteCharms.Features/Orders/Commands/CreateOrderCommand.cs +++ b/LiteCharms.Features/Orders/Commands/CreateOrderCommand.cs @@ -8,14 +8,26 @@ public class CreateOrderCommand : IRequest> public Guid? QuoteId { get; set; } - private CreateOrderCommand(Guid customerId, Guid shoppingCartId, Guid? quoteId = null) + public string[]? Requirements { get; set; } + + public string[]? Notes { get; set; } + + public string[]? Terms { get; set; } + + public bool DepositRequired { get; set; } + + private CreateOrderCommand(Guid customerId, Guid shoppingCartId, bool depositRequired, Guid? quoteId = null, string[]? requirements = null, string[]? notes = null, string[]? terms = null) { CustomerId = customerId; ShoppingCartId = shoppingCartId; + DepositRequired = depositRequired; QuoteId = quoteId; + Requirements = requirements; + Notes = notes; + Terms = terms; } - public static CreateOrderCommand Create(Guid customerId, Guid shoppingCartId, Guid? quoteId = null) + public static CreateOrderCommand Create(Guid customerId, Guid shoppingCartId, bool depositRequired, Guid? quoteId = null, string[]? requirements = null, string[]? notes = null, string[]? terms = null) { if (customerId == Guid.Empty) throw new ArgumentException("CustomerId is required.", nameof(customerId)); @@ -23,6 +35,6 @@ public class CreateOrderCommand : IRequest> if (shoppingCartId == Guid.Empty) throw new ArgumentException("ShoppingCartId is required.", nameof(shoppingCartId)); - return new(customerId, shoppingCartId, quoteId); + return new(customerId, shoppingCartId, depositRequired, quoteId, requirements, notes, terms); } } diff --git a/LiteCharms.Features/Orders/Commands/Handlers/CreateOrderCommandHandler.cs b/LiteCharms.Features/Orders/Commands/Handlers/CreateOrderCommandHandler.cs index f06e53b..b97f83e 100644 --- a/LiteCharms.Features/Orders/Commands/Handlers/CreateOrderCommandHandler.cs +++ b/LiteCharms.Features/Orders/Commands/Handlers/CreateOrderCommandHandler.cs @@ -1,4 +1,5 @@ using LiteCharms.Infrastructure.Database; +using LiteCharms.Models; namespace LiteCharms.Features.Orders.Commands.Handlers; @@ -21,10 +22,15 @@ public class CreateOrderCommandHandler(IDbContextFactory contextF var newOrder = context.Orders.Add(new Entities.Order { + CreatedAt = DateTime.UtcNow, + Status = OrderStatus.Pending, CustomerId = request.CustomerId, - ShoppingCartId = request.ShoppingCartId, QuoteId = request.QuoteId, - CreatedAt = DateTime.UtcNow + ShoppingCartId = request.ShoppingCartId, + DepositRequired = request.DepositRequired, + Requirements = request.Requirements, + Notes = request.Notes, + Terms = request.Terms }); return await context.SaveChangesAsync(cancellationToken) > 0 diff --git a/LiteCharms.Features/Utilities/Commands/ComputeHashCommand.cs b/LiteCharms.Features/Utilities/Hash/Commands/ComputeHashCommand.cs similarity index 86% rename from LiteCharms.Features/Utilities/Commands/ComputeHashCommand.cs rename to LiteCharms.Features/Utilities/Hash/Commands/ComputeHashCommand.cs index ef235fc..252a9e7 100644 --- a/LiteCharms.Features/Utilities/Commands/ComputeHashCommand.cs +++ b/LiteCharms.Features/Utilities/Hash/Commands/ComputeHashCommand.cs @@ -1,4 +1,4 @@ -namespace LiteCharms.Features.Utilities.Commands; +namespace LiteCharms.Features.Utilities.Hash.Commands; public class ComputeHashCommand : IRequest> { diff --git a/LiteCharms.Features/Utilities/Commands/Handlers/ComputeHashCommandHandler.cs b/LiteCharms.Features/Utilities/Hash/Commands/Handlers/ComputeHashCommandHandler.cs similarity index 80% rename from LiteCharms.Features/Utilities/Commands/Handlers/ComputeHashCommandHandler.cs rename to LiteCharms.Features/Utilities/Hash/Commands/Handlers/ComputeHashCommandHandler.cs index d4ef5b4..013ab03 100644 --- a/LiteCharms.Features/Utilities/Commands/Handlers/ComputeHashCommandHandler.cs +++ b/LiteCharms.Features/Utilities/Hash/Commands/Handlers/ComputeHashCommandHandler.cs @@ -1,4 +1,6 @@ -namespace LiteCharms.Features.Utilities.Commands.Handlers; +using LiteCharms.Features.Utilities.Hash.Commands; + +namespace LiteCharms.Features.Utilities.Hash.Commands.Handlers; public class ComputeHashCommandHandler : IRequestHandler> { diff --git a/LiteCharms.Infrastructure/Database/Migrations/20260510090446_Init.Designer.cs b/LiteCharms.Infrastructure/Database/Migrations/20260510090446_Init.Designer.cs deleted file mode 100644 index 6ae5382..0000000 --- a/LiteCharms.Infrastructure/Database/Migrations/20260510090446_Init.Designer.cs +++ /dev/null @@ -1,631 +0,0 @@ -// -using System; -using LiteCharms.Infrastructure.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 LiteCharms.Infrastructure.Database.Migrations -{ - [DbContext(typeof(ShopDbContext))] - [Migration("20260510090446_Init")] - partial class Init - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "10.0.7") - .HasAnnotation("Relational:MaxIdentifierLength", 63); - - NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - - modelBuilder.Entity("LiteCharms.Entities.Customer", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("Active") - .ValueGeneratedOnAdd() - .HasColumnType("boolean") - .HasDefaultValue(true); - - b.Property("Address") - .HasColumnType("text"); - - b.Property("City") - .HasColumnType("text"); - - b.Property("Company") - .HasColumnType("text"); - - b.Property("Country") - .HasColumnType("text"); - - b.Property("CreatedAt") - .ValueGeneratedOnAdd() - .HasColumnType("timestamp with time zone"); - - b.Property("Discord") - .HasColumnType("text"); - - b.Property("Email") - .IsRequired() - .HasColumnType("text"); - - b.Property("LastName") - .IsRequired() - .HasColumnType("text"); - - b.Property("LinkedIn") - .HasColumnType("text"); - - b.Property("Name") - .IsRequired() - .HasColumnType("text"); - - b.Property("Phone") - .HasColumnType("text"); - - b.Property("PostalCode") - .HasColumnType("text"); - - b.Property("Region") - .HasColumnType("text"); - - b.Property("Slack") - .HasColumnType("text"); - - b.Property("Tax") - .HasColumnType("text"); - - b.Property("UpdatedAt") - .ValueGeneratedOnUpdate() - .HasColumnType("timestamp with time zone"); - - b.Property("Website") - .HasColumnType("text"); - - b.Property("Whatsapp") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.ToTable("Customer", (string)null); - }); - - modelBuilder.Entity("LiteCharms.Entities.Lead", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("AdGroupId") - .HasColumnType("bigint"); - - b.Property("AdName") - .HasColumnType("bigint"); - - b.Property("AppClickId") - .HasColumnType("text"); - - b.Property("AttributionHash") - .IsRequired() - .HasColumnType("text"); - - b.Property("CampaignId") - .HasColumnType("bigint"); - - b.Property("ClickId") - .HasColumnType("text"); - - b.Property("ClickLocation") - .HasColumnType("text"); - - b.Property("CreatedAt") - .ValueGeneratedOnAdd() - .HasColumnType("timestamp with time zone"); - - b.Property("CustomerId") - .HasColumnType("uuid"); - - b.Property("FeedItemId") - .HasColumnType("bigint"); - - b.Property("Source") - .HasColumnType("text"); - - b.Property("Status") - .HasColumnType("integer"); - - b.Property("TargetId") - .HasColumnType("bigint"); - - b.Property("UpdatedAt") - .ValueGeneratedOnUpdate() - .HasColumnType("timestamp with time zone"); - - b.Property("WebClickId") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.HasIndex("CustomerId"); - - b.ToTable("Lead", (string)null); - }); - - modelBuilder.Entity("LiteCharms.Entities.Notification", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("CorrelationId") - .IsRequired() - .HasColumnType("text"); - - b.Property("CorrelationIdType") - .IsRequired() - .HasColumnType("text"); - - b.Property("CreatedAt") - .ValueGeneratedOnAdd() - .HasColumnType("timestamp with time zone"); - - b.Property("Direction") - .HasColumnType("integer"); - - b.Property("IsHtml") - .ValueGeneratedOnAdd() - .HasColumnType("boolean") - .HasDefaultValue(false); - - b.Property("IsInternal") - .ValueGeneratedOnAdd() - .HasColumnType("boolean") - .HasDefaultValue(true); - - b.Property("Message") - .IsRequired() - .HasColumnType("text"); - - b.Property("Platform") - .HasColumnType("integer"); - - b.Property("Priority") - .HasColumnType("integer"); - - b.Property("Processed") - .ValueGeneratedOnAdd() - .HasColumnType("boolean") - .HasDefaultValue(false); - - b.Property("Recipient") - .IsRequired() - .HasColumnType("text"); - - b.Property("RecipientAddress") - .IsRequired() - .HasColumnType("text"); - - b.Property("Sender") - .IsRequired() - .HasColumnType("text"); - - b.Property("SenderName") - .HasColumnType("text"); - - b.Property("Subject") - .IsRequired() - .HasColumnType("text"); - - b.Property("UpdatedAt") - .ValueGeneratedOnUpdate() - .HasColumnType("timestamp with time zone"); - - b.HasKey("Id"); - - b.ToTable("Notification", (string)null); - }); - - modelBuilder.Entity("LiteCharms.Entities.Order", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("CreatedAt") - .ValueGeneratedOnAdd() - .HasColumnType("timestamp with time zone"); - - b.Property("CustomerId") - .HasColumnType("uuid"); - - b.Property("DepositRequired") - .HasColumnType("boolean"); - - b.PrimitiveCollection("Notes") - .HasColumnType("jsonb"); - - b.Property("QuoteId") - .HasColumnType("uuid"); - - b.Property("RefundId") - .HasColumnType("uuid"); - - b.PrimitiveCollection("Requirements") - .HasColumnType("jsonb"); - - b.Property("ShoppingCartId") - .HasColumnType("uuid"); - - b.Property("Status") - .HasColumnType("integer"); - - b.PrimitiveCollection("Terms") - .HasColumnType("jsonb"); - - b.Property("UpdatedAt") - .ValueGeneratedOnUpdate() - .HasColumnType("timestamp with time zone"); - - b.HasKey("Id"); - - b.HasIndex("CustomerId"); - - b.HasIndex("QuoteId") - .IsUnique(); - - b.HasIndex("ShoppingCartId") - .IsUnique(); - - b.ToTable("Order", (string)null); - }); - - modelBuilder.Entity("LiteCharms.Entities.OrderRefund", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("Amount") - .HasPrecision(18, 2) - .HasColumnType("numeric(18,2)"); - - b.Property("CreatedAt") - .ValueGeneratedOnAdd() - .HasColumnType("timestamp with time zone"); - - b.Property("OrderId") - .HasColumnType("uuid"); - - b.Property("Reason") - .IsRequired() - .HasColumnType("text"); - - b.HasKey("Id"); - - b.HasIndex("OrderId") - .IsUnique(); - - b.ToTable("OrderRefund", (string)null); - }); - - modelBuilder.Entity("LiteCharms.Entities.Product", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("Active") - .ValueGeneratedOnAdd() - .HasColumnType("boolean") - .HasDefaultValue(true); - - b.Property("Description") - .IsRequired() - .HasColumnType("text"); - - b.Property("Name") - .IsRequired() - .HasColumnType("text"); - - b.HasKey("Id"); - - b.ToTable("Product", (string)null); - }); - - modelBuilder.Entity("LiteCharms.Entities.ProductPrice", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("Active") - .HasColumnType("boolean"); - - b.Property("CreatedAt") - .ValueGeneratedOnAdd() - .HasColumnType("timestamp with time zone"); - - b.Property("Discount") - .HasPrecision(18, 2) - .HasColumnType("numeric(18,2)"); - - b.Property("Price") - .HasPrecision(18, 2) - .HasColumnType("numeric(18,2)"); - - b.Property("ProductId") - .HasColumnType("uuid"); - - b.Property("UpdatedAt") - .ValueGeneratedOnUpdate() - .HasColumnType("timestamp with time zone"); - - b.HasKey("Id"); - - b.HasIndex("ProductId"); - - b.ToTable("ProductPrice", (string)null); - }); - - modelBuilder.Entity("LiteCharms.Entities.Quote", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("CreatedAt") - .ValueGeneratedOnAdd() - .HasColumnType("timestamp with time zone"); - - b.Property("CustomerId") - .HasColumnType("uuid"); - - b.Property("CustomerId1") - .HasColumnType("uuid"); - - b.Property("ExpiredAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Reason") - .HasColumnType("text"); - - b.Property("ShoppingCartId") - .HasColumnType("uuid"); - - b.Property("Status") - .HasColumnType("integer"); - - b.Property("UpdatedAt") - .ValueGeneratedOnUpdate() - .HasColumnType("timestamp with time zone"); - - b.HasKey("Id"); - - b.HasIndex("CustomerId"); - - b.HasIndex("CustomerId1"); - - b.HasIndex("ShoppingCartId") - .IsUnique(); - - b.ToTable("Quote", (string)null); - }); - - modelBuilder.Entity("LiteCharms.Entities.ShoppingCart", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("CreatedAt") - .ValueGeneratedOnAdd() - .HasColumnType("timestamp with time zone"); - - b.Property("CustomerId") - .HasColumnType("uuid"); - - b.Property("OrderId") - .HasColumnType("uuid"); - - b.Property("QuoteId") - .HasColumnType("uuid"); - - b.Property("UpdatedAt") - .ValueGeneratedOnUpdate() - .HasColumnType("timestamp with time zone"); - - b.HasKey("Id"); - - b.HasIndex("CustomerId"); - - b.ToTable("ShoppingCart", (string)null); - }); - - modelBuilder.Entity("LiteCharms.Entities.ShoppingCartItem", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("ProductPriceId") - .HasColumnType("uuid"); - - b.Property("Quantity") - .HasColumnType("integer"); - - b.Property("ShoppingCartId") - .HasColumnType("uuid"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.HasKey("Id"); - - b.HasIndex("ProductPriceId"); - - b.HasIndex("ShoppingCartId"); - - b.ToTable("ShoppingCartItems"); - }); - - modelBuilder.Entity("LiteCharms.Entities.Lead", b => - { - b.HasOne("LiteCharms.Entities.Customer", "Customer") - .WithMany("Leads") - .HasForeignKey("CustomerId") - .OnDelete(DeleteBehavior.NoAction); - - b.Navigation("Customer"); - }); - - modelBuilder.Entity("LiteCharms.Entities.Order", b => - { - b.HasOne("LiteCharms.Entities.Customer", "Customer") - .WithMany("Orders") - .HasForeignKey("CustomerId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("LiteCharms.Entities.Quote", "Quote") - .WithOne("Order") - .HasForeignKey("LiteCharms.Entities.Order", "QuoteId") - .OnDelete(DeleteBehavior.Restrict); - - b.HasOne("LiteCharms.Entities.ShoppingCart", "ShoppingCart") - .WithOne("Order") - .HasForeignKey("LiteCharms.Entities.Order", "ShoppingCartId") - .OnDelete(DeleteBehavior.NoAction) - .IsRequired(); - - b.Navigation("Customer"); - - b.Navigation("Quote"); - - b.Navigation("ShoppingCart"); - }); - - modelBuilder.Entity("LiteCharms.Entities.OrderRefund", b => - { - b.HasOne("LiteCharms.Entities.Order", "Order") - .WithOne("Refund") - .HasForeignKey("LiteCharms.Entities.OrderRefund", "OrderId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Order"); - }); - - modelBuilder.Entity("LiteCharms.Entities.ProductPrice", b => - { - b.HasOne("LiteCharms.Entities.Product", "Product") - .WithMany("ProductPrices") - .HasForeignKey("ProductId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("Product"); - }); - - modelBuilder.Entity("LiteCharms.Entities.Quote", b => - { - b.HasOne("LiteCharms.Entities.Customer", "Customer") - .WithMany() - .HasForeignKey("CustomerId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("LiteCharms.Entities.Customer", null) - .WithMany("Quotes") - .HasForeignKey("CustomerId1"); - - b.HasOne("LiteCharms.Entities.ShoppingCart", "ShoppingCart") - .WithOne("Quote") - .HasForeignKey("LiteCharms.Entities.Quote", "ShoppingCartId") - .OnDelete(DeleteBehavior.NoAction) - .IsRequired(); - - b.Navigation("Customer"); - - b.Navigation("ShoppingCart"); - }); - - modelBuilder.Entity("LiteCharms.Entities.ShoppingCart", b => - { - b.HasOne("LiteCharms.Entities.Customer", "Customer") - .WithMany("ShoppingCarts") - .HasForeignKey("CustomerId") - .OnDelete(DeleteBehavior.NoAction); - - b.Navigation("Customer"); - }); - - modelBuilder.Entity("LiteCharms.Entities.ShoppingCartItem", b => - { - b.HasOne("LiteCharms.Entities.ProductPrice", "ProductPrice") - .WithMany() - .HasForeignKey("ProductPriceId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("LiteCharms.Entities.ShoppingCart", "ShoppingCart") - .WithMany("ShoppingCartItems") - .HasForeignKey("ShoppingCartId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("ProductPrice"); - - b.Navigation("ShoppingCart"); - }); - - modelBuilder.Entity("LiteCharms.Entities.Customer", b => - { - b.Navigation("Leads"); - - b.Navigation("Orders"); - - b.Navigation("Quotes"); - - b.Navigation("ShoppingCarts"); - }); - - modelBuilder.Entity("LiteCharms.Entities.Order", b => - { - b.Navigation("Refund"); - }); - - modelBuilder.Entity("LiteCharms.Entities.Product", b => - { - b.Navigation("ProductPrices"); - }); - - modelBuilder.Entity("LiteCharms.Entities.Quote", b => - { - b.Navigation("Order"); - }); - - modelBuilder.Entity("LiteCharms.Entities.ShoppingCart", b => - { - b.Navigation("Order"); - - b.Navigation("Quote"); - - b.Navigation("ShoppingCartItems"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/LiteCharms.Infrastructure/Database/Migrations/20260510091540_AddedPackages.cs b/LiteCharms.Infrastructure/Database/Migrations/20260510091540_AddedPackages.cs deleted file mode 100644 index 351ac6b..0000000 --- a/LiteCharms.Infrastructure/Database/Migrations/20260510091540_AddedPackages.cs +++ /dev/null @@ -1,114 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace LiteCharms.Infrastructure.Database.Migrations -{ - /// - public partial class AddedPackages : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: "Package", - columns: table => new - { - Id = table.Column(type: "uuid", nullable: false), - CreatedAt = table.Column(type: "timestamp with time zone", nullable: false), - UpdatedAt = table.Column(type: "timestamp with time zone", nullable: true), - Name = table.Column(type: "text", nullable: false), - Description = table.Column(type: "text", nullable: false), - Active = table.Column(type: "boolean", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_Package", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "PackageItem", - columns: table => new - { - Id = table.Column(type: "uuid", nullable: false), - PackageId1 = table.Column(type: "uuid", nullable: true), - PackageId = table.Column(type: "uuid", nullable: false), - ProductPriceId = table.Column(type: "uuid", nullable: false), - CreatedAt = table.Column(type: "timestamp with time zone", nullable: false), - Active = table.Column(type: "boolean", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_PackageItem", x => x.Id); - table.ForeignKey( - name: "FK_PackageItem_Package_PackageId", - column: x => x.PackageId, - principalTable: "Package", - principalColumn: "Id"); - table.ForeignKey( - name: "FK_PackageItem_Package_PackageId1", - column: x => x.PackageId1, - principalTable: "Package", - principalColumn: "Id"); - }); - - migrationBuilder.CreateTable( - name: "ShoppingCartPackage", - columns: table => new - { - Id = table.Column(type: "uuid", nullable: false), - CreatedAt = table.Column(type: "timestamp with time zone", nullable: false), - ShoppingCartId = table.Column(type: "uuid", nullable: false), - PackageId = table.Column(type: "uuid", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_ShoppingCartPackage", x => x.Id); - table.ForeignKey( - name: "FK_ShoppingCartPackage_Package_PackageId", - column: x => x.PackageId, - principalTable: "Package", - principalColumn: "Id"); - table.ForeignKey( - name: "FK_ShoppingCartPackage_ShoppingCart_ShoppingCartId", - column: x => x.ShoppingCartId, - principalTable: "ShoppingCart", - principalColumn: "Id"); - }); - - migrationBuilder.CreateIndex( - name: "IX_PackageItem_PackageId", - table: "PackageItem", - column: "PackageId"); - - migrationBuilder.CreateIndex( - name: "IX_PackageItem_PackageId1", - table: "PackageItem", - column: "PackageId1"); - - migrationBuilder.CreateIndex( - name: "IX_ShoppingCartPackage_PackageId", - table: "ShoppingCartPackage", - column: "PackageId"); - - migrationBuilder.CreateIndex( - name: "IX_ShoppingCartPackage_ShoppingCartId", - table: "ShoppingCartPackage", - column: "ShoppingCartId"); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "PackageItem"); - - migrationBuilder.DropTable( - name: "ShoppingCartPackage"); - - migrationBuilder.DropTable( - name: "Package"); - } - } -} diff --git a/LiteCharms.Infrastructure/Database/Migrations/20260510091540_AddedPackages.Designer.cs b/LiteCharms.Infrastructure/Database/Migrations/20260510132008_Init.Designer.cs similarity index 96% rename from LiteCharms.Infrastructure/Database/Migrations/20260510091540_AddedPackages.Designer.cs rename to LiteCharms.Infrastructure/Database/Migrations/20260510132008_Init.Designer.cs index f83fabb..4624007 100644 --- a/LiteCharms.Infrastructure/Database/Migrations/20260510091540_AddedPackages.Designer.cs +++ b/LiteCharms.Infrastructure/Database/Migrations/20260510132008_Init.Designer.cs @@ -12,8 +12,8 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; namespace LiteCharms.Infrastructure.Database.Migrations { [DbContext(typeof(ShopDbContext))] - [Migration("20260510091540_AddedPackages")] - partial class AddedPackages + [Migration("20260510132008_Init")] + partial class Init { /// protected override void BuildTargetModel(ModelBuilder modelBuilder) @@ -171,9 +171,8 @@ namespace LiteCharms.Infrastructure.Database.Migrations .IsRequired() .HasColumnType("text"); - b.Property("CorrelationIdType") - .IsRequired() - .HasColumnType("text"); + b.Property("CorrelationIdType") + .HasColumnType("integer"); b.Property("CreatedAt") .ValueGeneratedOnAdd() @@ -182,6 +181,14 @@ namespace LiteCharms.Infrastructure.Database.Migrations b.Property("Direction") .HasColumnType("integer"); + b.PrimitiveCollection("Errors") + .HasColumnType("jsonb"); + + b.Property("HasError") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false); + b.Property("IsHtml") .ValueGeneratedOnAdd() .HasColumnType("boolean") @@ -339,12 +346,17 @@ namespace LiteCharms.Infrastructure.Database.Migrations .IsRequired() .HasColumnType("text"); + b.Property("ShoppingCartId") + .HasColumnType("uuid"); + b.Property("UpdatedAt") .ValueGeneratedOnUpdate() .HasColumnType("timestamp with time zone"); b.HasKey("Id"); + b.HasIndex("ShoppingCartId"); + b.ToTable("Package", (string)null); }); @@ -614,6 +626,13 @@ namespace LiteCharms.Infrastructure.Database.Migrations b.Navigation("Order"); }); + modelBuilder.Entity("LiteCharms.Entities.Package", b => + { + b.HasOne("LiteCharms.Entities.ShoppingCart", null) + .WithMany("Packages") + .HasForeignKey("ShoppingCartId"); + }); + modelBuilder.Entity("LiteCharms.Entities.PackageItem", b => { b.HasOne("LiteCharms.Entities.Package", "Package") @@ -746,6 +765,8 @@ namespace LiteCharms.Infrastructure.Database.Migrations { b.Navigation("Order"); + b.Navigation("Packages"); + b.Navigation("Quote"); b.Navigation("ShoppingCartItems"); diff --git a/LiteCharms.Infrastructure/Database/Migrations/20260510090446_Init.cs b/LiteCharms.Infrastructure/Database/Migrations/20260510132008_Init.cs similarity index 78% rename from LiteCharms.Infrastructure/Database/Migrations/20260510090446_Init.cs rename to LiteCharms.Infrastructure/Database/Migrations/20260510132008_Init.cs index 3bc9554..773f0d6 100644 --- a/LiteCharms.Infrastructure/Database/Migrations/20260510090446_Init.cs +++ b/LiteCharms.Infrastructure/Database/Migrations/20260510132008_Init.cs @@ -51,6 +51,7 @@ namespace LiteCharms.Infrastructure.Database.Migrations Direction = table.Column(type: "integer", nullable: false), Platform = table.Column(type: "integer", nullable: false), Priority = table.Column(type: "integer", nullable: false), + CorrelationIdType = table.Column(type: "integer", nullable: false), Sender = table.Column(type: "text", nullable: false), SenderName = table.Column(type: "text", nullable: true), Subject = table.Column(type: "text", nullable: false), @@ -58,10 +59,11 @@ namespace LiteCharms.Infrastructure.Database.Migrations Recipient = table.Column(type: "text", nullable: false), RecipientAddress = table.Column(type: "text", nullable: false), CorrelationId = table.Column(type: "text", nullable: false), - CorrelationIdType = table.Column(type: "text", nullable: false), IsHtml = table.Column(type: "boolean", nullable: false, defaultValue: false), IsInternal = table.Column(type: "boolean", nullable: false, defaultValue: true), - Processed = table.Column(type: "boolean", nullable: false, defaultValue: false) + Processed = table.Column(type: "boolean", nullable: false, defaultValue: false), + HasError = table.Column(type: "boolean", nullable: false, defaultValue: false), + Errors = table.Column(type: "jsonb", nullable: true) }, constraints: table => { @@ -157,6 +159,28 @@ namespace LiteCharms.Infrastructure.Database.Migrations onDelete: ReferentialAction.Restrict); }); + migrationBuilder.CreateTable( + name: "Package", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + ShoppingCartId = table.Column(type: "uuid", nullable: true), + CreatedAt = table.Column(type: "timestamp with time zone", nullable: false), + UpdatedAt = table.Column(type: "timestamp with time zone", nullable: true), + Name = table.Column(type: "text", nullable: false), + Description = table.Column(type: "text", nullable: false), + Active = table.Column(type: "boolean", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Package", x => x.Id); + table.ForeignKey( + name: "FK_Package_ShoppingCart_ShoppingCartId", + column: x => x.ShoppingCartId, + principalTable: "ShoppingCart", + principalColumn: "Id"); + }); + migrationBuilder.CreateTable( name: "Quote", columns: table => new @@ -220,6 +244,56 @@ namespace LiteCharms.Infrastructure.Database.Migrations onDelete: ReferentialAction.Cascade); }); + migrationBuilder.CreateTable( + name: "PackageItem", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + PackageId1 = table.Column(type: "uuid", nullable: true), + PackageId = table.Column(type: "uuid", nullable: false), + ProductPriceId = table.Column(type: "uuid", nullable: false), + CreatedAt = table.Column(type: "timestamp with time zone", nullable: false), + Active = table.Column(type: "boolean", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_PackageItem", x => x.Id); + table.ForeignKey( + name: "FK_PackageItem_Package_PackageId", + column: x => x.PackageId, + principalTable: "Package", + principalColumn: "Id"); + table.ForeignKey( + name: "FK_PackageItem_Package_PackageId1", + column: x => x.PackageId1, + principalTable: "Package", + principalColumn: "Id"); + }); + + migrationBuilder.CreateTable( + name: "ShoppingCartPackage", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + CreatedAt = table.Column(type: "timestamp with time zone", nullable: false), + ShoppingCartId = table.Column(type: "uuid", nullable: false), + PackageId = table.Column(type: "uuid", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ShoppingCartPackage", x => x.Id); + table.ForeignKey( + name: "FK_ShoppingCartPackage_Package_PackageId", + column: x => x.PackageId, + principalTable: "Package", + principalColumn: "Id"); + table.ForeignKey( + name: "FK_ShoppingCartPackage_ShoppingCart_ShoppingCartId", + column: x => x.ShoppingCartId, + principalTable: "ShoppingCart", + principalColumn: "Id"); + }); + migrationBuilder.CreateTable( name: "Order", columns: table => new @@ -308,6 +382,21 @@ namespace LiteCharms.Infrastructure.Database.Migrations column: "OrderId", unique: true); + migrationBuilder.CreateIndex( + name: "IX_Package_ShoppingCartId", + table: "Package", + column: "ShoppingCartId"); + + migrationBuilder.CreateIndex( + name: "IX_PackageItem_PackageId", + table: "PackageItem", + column: "PackageId"); + + migrationBuilder.CreateIndex( + name: "IX_PackageItem_PackageId1", + table: "PackageItem", + column: "PackageId1"); + migrationBuilder.CreateIndex( name: "IX_ProductPrice_ProductId", table: "ProductPrice", @@ -343,6 +432,16 @@ namespace LiteCharms.Infrastructure.Database.Migrations name: "IX_ShoppingCartItems_ShoppingCartId", table: "ShoppingCartItems", column: "ShoppingCartId"); + + migrationBuilder.CreateIndex( + name: "IX_ShoppingCartPackage_PackageId", + table: "ShoppingCartPackage", + column: "PackageId"); + + migrationBuilder.CreateIndex( + name: "IX_ShoppingCartPackage_ShoppingCartId", + table: "ShoppingCartPackage", + column: "ShoppingCartId"); } /// @@ -357,15 +456,24 @@ namespace LiteCharms.Infrastructure.Database.Migrations migrationBuilder.DropTable( name: "OrderRefund"); + migrationBuilder.DropTable( + name: "PackageItem"); + migrationBuilder.DropTable( name: "ShoppingCartItems"); + migrationBuilder.DropTable( + name: "ShoppingCartPackage"); + migrationBuilder.DropTable( name: "Order"); migrationBuilder.DropTable( name: "ProductPrice"); + migrationBuilder.DropTable( + name: "Package"); + migrationBuilder.DropTable( name: "Quote"); diff --git a/LiteCharms.Infrastructure/Database/Migrations/ShopDbContextModelSnapshot.cs b/LiteCharms.Infrastructure/Database/Migrations/ShopDbContextModelSnapshot.cs index 8a32836..6708099 100644 --- a/LiteCharms.Infrastructure/Database/Migrations/ShopDbContextModelSnapshot.cs +++ b/LiteCharms.Infrastructure/Database/Migrations/ShopDbContextModelSnapshot.cs @@ -168,9 +168,8 @@ namespace LiteCharms.Infrastructure.Database.Migrations .IsRequired() .HasColumnType("text"); - b.Property("CorrelationIdType") - .IsRequired() - .HasColumnType("text"); + b.Property("CorrelationIdType") + .HasColumnType("integer"); b.Property("CreatedAt") .ValueGeneratedOnAdd() @@ -179,6 +178,14 @@ namespace LiteCharms.Infrastructure.Database.Migrations b.Property("Direction") .HasColumnType("integer"); + b.PrimitiveCollection("Errors") + .HasColumnType("jsonb"); + + b.Property("HasError") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false); + b.Property("IsHtml") .ValueGeneratedOnAdd() .HasColumnType("boolean") @@ -336,12 +343,17 @@ namespace LiteCharms.Infrastructure.Database.Migrations .IsRequired() .HasColumnType("text"); + b.Property("ShoppingCartId") + .HasColumnType("uuid"); + b.Property("UpdatedAt") .ValueGeneratedOnUpdate() .HasColumnType("timestamp with time zone"); b.HasKey("Id"); + b.HasIndex("ShoppingCartId"); + b.ToTable("Package", (string)null); }); @@ -611,6 +623,13 @@ namespace LiteCharms.Infrastructure.Database.Migrations b.Navigation("Order"); }); + modelBuilder.Entity("LiteCharms.Entities.Package", b => + { + b.HasOne("LiteCharms.Entities.ShoppingCart", null) + .WithMany("Packages") + .HasForeignKey("ShoppingCartId"); + }); + modelBuilder.Entity("LiteCharms.Entities.PackageItem", b => { b.HasOne("LiteCharms.Entities.Package", "Package") @@ -743,6 +762,8 @@ namespace LiteCharms.Infrastructure.Database.Migrations { b.Navigation("Order"); + b.Navigation("Packages"); + b.Navigation("Quote"); b.Navigation("ShoppingCartItems"); diff --git a/LiteCharms.Models/Enums.cs b/LiteCharms.Models/Enums.cs index 385a5b5..b672e25 100644 --- a/LiteCharms.Models/Enums.cs +++ b/LiteCharms.Models/Enums.cs @@ -1,5 +1,20 @@ namespace LiteCharms.Models; +public enum CorrelationIdTypes : int +{ + None = 0, + Email = 1, + Discord = 2, + Slack = 3, + Whatsapp = 4, + Customer = 5, + Order = 6, + Refund = 7, + Lead = 8, + Quote = 9, + LinkedIn = 10 +} + public enum Priorities : int { Low = 0, diff --git a/LiteCharms.Models/Notification.cs b/LiteCharms.Models/Notification.cs index 90ac390..6108cbb 100644 --- a/LiteCharms.Models/Notification.cs +++ b/LiteCharms.Models/Notification.cs @@ -14,6 +14,8 @@ public class Notification public Priorities Priority { get; set; } + public CorrelationIdTypes CorrelationIdType { get; set; } + public string? Sender { get; set; } public string? SenderName { get; set; } @@ -28,11 +30,13 @@ public class Notification public string? CorrelationId { get; set; } - public string? CorrelationIdType { get; set; } - public bool IsHtml { get; set; } public bool IsInternal { get; set; } public bool Processed { get; set; } + + public bool HasError { get; set; } + + public string[]? Errors { get; set; } }