diff --git a/LiteCharms.Entities/Configuration/NotificationConfiguration.cs b/LiteCharms.Entities/Configuration/NotificationConfiguration.cs new file mode 100644 index 0000000..7d118f5 --- /dev/null +++ b/LiteCharms.Entities/Configuration/NotificationConfiguration.cs @@ -0,0 +1,21 @@ +namespace LiteCharms.Entities.Configuration; + +public class NotificationConfiguration : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.ToTable(nameof(Notification)); + + builder.HasKey(f => f.Id); + builder.Property(f => f.CreatedAt).IsRequired().ValueGeneratedOnAdd(); + builder.Property(f => f.Direction).IsRequired(); + builder.Property(f => f.Author).IsRequired(); + builder.Property(f => f.Title).IsRequired(); + builder.Property(f => f.Description).IsRequired(); + builder.Property(f => f.Platform).IsRequired(); + builder.Property(f => f.PlatformAddress).IsRequired(); + builder.Property(f => f.CorrelationId).IsRequired(); + builder.Property(f => f.CorrelationIdType).IsRequired(); + builder.Property(f => f.IsInternal).IsRequired(); + } +} \ No newline at end of file diff --git a/LiteCharms.Entities/Notification.cs b/LiteCharms.Entities/Notification.cs new file mode 100644 index 0000000..2f3bf11 --- /dev/null +++ b/LiteCharms.Entities/Notification.cs @@ -0,0 +1,6 @@ +using LiteCharms.Entities.Configuration; + +namespace LiteCharms.Entities; + +[EntityTypeConfiguration] +public class Notification : Models.Notification; diff --git a/LiteCharms.Extensions/EntityModeMappers.cs b/LiteCharms.Extensions/EntityModeMappers.cs index 217dd4a..28230ba 100644 --- a/LiteCharms.Extensions/EntityModeMappers.cs +++ b/LiteCharms.Extensions/EntityModeMappers.cs @@ -4,6 +4,22 @@ namespace LiteCharms.Extensions; public static class EntityModeMappers { + public static Notification ToModel(this Entities.Notification entity) => + new() + { + Id = entity.Id, + CreatedAt = entity.CreatedAt, + Description = entity.Description, + Direction = entity.Direction, + CorrelationId = entity.CorrelationId, + CorrelationIdType = entity.CorrelationIdType, + IsInternal = entity.IsInternal, + Author = entity.Author, + Platform = entity.Platform, + PlatformAddress = entity.PlatformAddress, + Title = entity.Title + }; + public static Customer ToModel(this Entities.Customer entity) => new() { diff --git a/LiteCharms.Features/Customers/Queries/GetCustomersQuery.cs b/LiteCharms.Features/Customers/Queries/GetCustomersQuery.cs index 76bab43..3f271b3 100644 --- a/LiteCharms.Features/Customers/Queries/GetCustomersQuery.cs +++ b/LiteCharms.Features/Customers/Queries/GetCustomersQuery.cs @@ -8,17 +8,23 @@ public class GetCustomersQuery : IRequest> public DateOnly To { get; set; } - private GetCustomersQuery(DateOnly from, DateOnly to) + public int MaxRecords { get; set; } + + private GetCustomersQuery(DateOnly from, DateOnly to, int maxRecords = 1000) { From = from; To = to; + MaxRecords = maxRecords; } - public static GetCustomersQuery Create(DateOnly from, DateOnly to) + public static GetCustomersQuery Create(DateOnly from, DateOnly to, int maxRecords = 1000) { if (from > to) throw new ArgumentException("From date cannot be greater than To date."); - return new(from, to); + if(maxRecords <= 0) + throw new ArgumentException("MaxRecords must be a positive integer."); + + return new(from, to, maxRecords); } } diff --git a/LiteCharms.Features/Customers/Queries/Handlers/GetCustomersQueryHandler.cs b/LiteCharms.Features/Customers/Queries/Handlers/GetCustomersQueryHandler.cs index dd5d753..e3e3d73 100644 --- a/LiteCharms.Features/Customers/Queries/Handlers/GetCustomersQueryHandler.cs +++ b/LiteCharms.Features/Customers/Queries/Handlers/GetCustomersQueryHandler.cs @@ -18,6 +18,7 @@ public class GetCustomersQueryHandler(IDbContextFactory var customers = await context.Customers.AsNoTracking() .OrderByDescending(o => o.CreatedAt) .Where(c => c.CreatedAt >= fromDate && c.CreatedAt <= toDate) + .Take(request.MaxRecords) .ToArrayAsync(cancellationToken); return customers?.Length > 0 diff --git a/LiteCharms.Features/Leads/Queries/GetLeadsQuery.cs b/LiteCharms.Features/Leads/Queries/GetLeadsQuery.cs index d0c0714..3278bf7 100644 --- a/LiteCharms.Features/Leads/Queries/GetLeadsQuery.cs +++ b/LiteCharms.Features/Leads/Queries/GetLeadsQuery.cs @@ -8,17 +8,23 @@ public class GetLeadsQuery : IRequest> public DateOnly To { get; set; } - private GetLeadsQuery(DateOnly from, DateOnly to) + public int MaxRecords { get; set; } + + private GetLeadsQuery(DateOnly from, DateOnly to, int maxRecords = 1000) { From = from; To = to; + MaxRecords = maxRecords; } - public static GetLeadsQuery Create(DateOnly from, DateOnly to) + public static GetLeadsQuery Create(DateOnly from, DateOnly to, int maxRecords = 1000) { if (from > to) throw new ArgumentException("From date cannot be greater than To date."); - return new(from, to); + if(maxRecords <= 0) + throw new ArgumentException("MaxRecords must be a positive integer."); + + return new(from, to, maxRecords); } } diff --git a/LiteCharms.Features/Leads/Queries/Handlers/GetLeadsQueryHandler.cs b/LiteCharms.Features/Leads/Queries/Handlers/GetLeadsQueryHandler.cs index 497a292..2496116 100644 --- a/LiteCharms.Features/Leads/Queries/Handlers/GetLeadsQueryHandler.cs +++ b/LiteCharms.Features/Leads/Queries/Handlers/GetLeadsQueryHandler.cs @@ -18,6 +18,7 @@ public class GetLeadsQueryHandler(IDbContextFactory cont var leads = await context.Leads.AsNoTracking() .OrderByDescending(o => o.CreatedAt) .Where(l => l.CreatedAt.Date >= fromDate && l.CreatedAt.Date <= toDate) + .Take(request.MaxRecords) .ToArrayAsync(cancellationToken); return leads?.Length > 0 diff --git a/LiteCharms.Features/LiteCharms.Features.csproj b/LiteCharms.Features/LiteCharms.Features.csproj index 97e26cb..3eee68a 100644 --- a/LiteCharms.Features/LiteCharms.Features.csproj +++ b/LiteCharms.Features/LiteCharms.Features.csproj @@ -34,8 +34,8 @@ - - + + diff --git a/LiteCharms.Features/Notifications/Queries/GetNotificationsQuery.cs b/LiteCharms.Features/Notifications/Queries/GetNotificationsQuery.cs new file mode 100644 index 0000000..6eef589 --- /dev/null +++ b/LiteCharms.Features/Notifications/Queries/GetNotificationsQuery.cs @@ -0,0 +1,30 @@ +using LiteCharms.Models; + +namespace LiteCharms.Features.Notifications.Queries; + +public class GetNotificationsQuery : IRequest> +{ + public DateOnly From { get; set; } + + public DateOnly To { get; set; } + + public int MaxRecords { get; set; } + + private GetNotificationsQuery(DateOnly from, DateOnly to, int maxRecords = 1000) + { + From = from; + To = to; + MaxRecords = maxRecords; + } + + public static GetNotificationsQuery Create(DateOnly from, DateOnly to, int maxRecords = 1000) + { + if (from > to) + throw new ArgumentException("From date cannot be greater than To date."); + + if(maxRecords <= 0) + throw new ArgumentException("MaxRecords must be a positive integer.", nameof(maxRecords)); + + return new(from, to, maxRecords); + } +} diff --git a/LiteCharms.Features/Notifications/Queries/Handlers/GetNotificationsQueryHandler.cs b/LiteCharms.Features/Notifications/Queries/Handlers/GetNotificationsQueryHandler.cs new file mode 100644 index 0000000..2d1a6a2 --- /dev/null +++ b/LiteCharms.Features/Notifications/Queries/Handlers/GetNotificationsQueryHandler.cs @@ -0,0 +1,33 @@ +using LiteCharms.Extensions; +using LiteCharms.Infrastructure.Database; +using LiteCharms.Models; + +namespace LiteCharms.Features.Notifications.Queries.Handlers; + +public class GetNotificationsQueryHandler(IDbContextFactory contextFactory) : IRequestHandler> +{ + public async ValueTask> Handle(GetNotificationsQuery request, CancellationToken cancellationToken) + { + try + { + var fromDate = request.From.ToDateTime(TimeOnly.MinValue); + var toDate = request.To.ToDateTime(TimeOnly.MaxValue); + + using var context = await contextFactory.CreateDbContextAsync(cancellationToken); + + var notifications = await context.Notifications + .Where(n => n.CreatedAt >= fromDate && n.CreatedAt <= toDate) + .OrderByDescending(n => n.CreatedAt) + .Take(request.MaxRecords) + .ToArrayAsync(cancellationToken); + + return notifications?.Length > 0 + ? Result.Ok(notifications.Select(n => n.ToModel()).ToArray()) + : Result.Fail(new Error($"No notifications found for the specified date range {request.From} to {request.To}.")); + } + catch (Exception ex) + { + return Result.Fail(new Error(ex.Message).CausedBy(ex)); + } + } +} diff --git a/LiteCharms.Features/Orders/Queries/GetOrdersQuery.cs b/LiteCharms.Features/Orders/Queries/GetOrdersQuery.cs index 3e1fb8f..c0c2c3b 100644 --- a/LiteCharms.Features/Orders/Queries/GetOrdersQuery.cs +++ b/LiteCharms.Features/Orders/Queries/GetOrdersQuery.cs @@ -8,17 +8,23 @@ public class GetOrdersQuery : IRequest> public DateOnly To { get; set; } - private GetOrdersQuery(DateOnly from, DateOnly to) + public int MaxRecords { get; set; } + + private GetOrdersQuery(DateOnly from, DateOnly to, int maxRecords = 1000) { From = from; To = to; + MaxRecords = maxRecords; } - public static GetOrdersQuery Create(DateOnly from, DateOnly to) + public static GetOrdersQuery Create(DateOnly from, DateOnly to, int maxRecords = 1000) { if (from > to) throw new ArgumentException("From date cannot be greater than To date."); - return new(from, to); + if(maxRecords <= 0) + throw new ArgumentException("MaxRecords must be a positive integer."); + + return new(from, to, maxRecords); } } \ No newline at end of file diff --git a/LiteCharms.Features/Orders/Queries/Handlers/GetOrdersQueryHandler.cs b/LiteCharms.Features/Orders/Queries/Handlers/GetOrdersQueryHandler.cs index 719d26b..29b25a3 100644 --- a/LiteCharms.Features/Orders/Queries/Handlers/GetOrdersQueryHandler.cs +++ b/LiteCharms.Features/Orders/Queries/Handlers/GetOrdersQueryHandler.cs @@ -18,6 +18,7 @@ public class GetOrdersQueryHandler(IDbContextFactory con var orders = await context.Orders .OrderByDescending(o => o.CreatedAt) .Where(o => o.CreatedAt >= fromDate && o.CreatedAt <= toDate) + .Take(request.MaxRecords) .ToArrayAsync(cancellationToken); return orders?.Length > 0 diff --git a/LiteCharms.Features/Products/Queries/GetProductPricesQuery.cs b/LiteCharms.Features/Products/Queries/GetProductPricesQuery.cs new file mode 100644 index 0000000..6e9cf66 --- /dev/null +++ b/LiteCharms.Features/Products/Queries/GetProductPricesQuery.cs @@ -0,0 +1,18 @@ +using LiteCharms.Models; + +namespace LiteCharms.Features.Products.Queries; + +public class GetProductPricesQuery : IRequest> +{ + public int MaxRecords { get; set; } + + private GetProductPricesQuery(int maxRecords = 1000) => MaxRecords = maxRecords; + + public static GetProductPricesQuery Create(int maxRecords = 1000) + { + if (maxRecords <= 0) + throw new ArgumentOutOfRangeException(nameof(maxRecords), "MaxRecords must be greater than zero."); + + return new(maxRecords); + } +} diff --git a/LiteCharms.Features/Products/Queries/GetProductsQuery.cs b/LiteCharms.Features/Products/Queries/GetProductsQuery.cs index b8cdc8b..1c7082d 100644 --- a/LiteCharms.Features/Products/Queries/GetProductsQuery.cs +++ b/LiteCharms.Features/Products/Queries/GetProductsQuery.cs @@ -4,5 +4,15 @@ namespace LiteCharms.Features.Products.Queries; public class GetProductsQuery : IRequest> { - public static GetProductsQuery Create() => new(); + public int MaxRecords { get; set; } + + private GetProductsQuery(int maxRecords = 1000) => MaxRecords = maxRecords; + + public static GetProductsQuery Create(int maxRecords = 1000) + { + if (maxRecords <= 0) + throw new ArgumentException("MaxRecords must be a positive integer."); + + return new(maxRecords); + } } diff --git a/LiteCharms.Features/Products/Queries/Handlers/GetProductPricesQueryHandler.cs b/LiteCharms.Features/Products/Queries/Handlers/GetProductPricesQueryHandler.cs new file mode 100644 index 0000000..0f1f5af --- /dev/null +++ b/LiteCharms.Features/Products/Queries/Handlers/GetProductPricesQueryHandler.cs @@ -0,0 +1,27 @@ +using LiteCharms.Extensions; +using LiteCharms.Infrastructure.Database; +using LiteCharms.Models; + +namespace LiteCharms.Features.Products.Queries.Handlers; + +public class GetProductPricesQueryHandler(IDbContextFactory contextFactory) : IRequestHandler> +{ + public async ValueTask> Handle(GetProductPricesQuery request, CancellationToken cancellationToken) + { + try + { + using var context = await contextFactory.CreateDbContextAsync(cancellationToken); + + var products = await context.ProductPrices.AsNoTracking() + .OrderByDescending(o => o.Id) + .Take(request.MaxRecords) + .ToArrayAsync(cancellationToken); + + return Result.Ok(products.Select(p => p.ToModel()).ToArray()); + } + catch (Exception ex) + { + return Result.Fail(new Error(ex.Message).CausedBy(ex)); + } + } +} diff --git a/LiteCharms.Features/Products/Queries/Handlers/GetProductsQueryHandler.cs b/LiteCharms.Features/Products/Queries/Handlers/GetProductsQueryHandler.cs index 54be7b3..1b99b16 100644 --- a/LiteCharms.Features/Products/Queries/Handlers/GetProductsQueryHandler.cs +++ b/LiteCharms.Features/Products/Queries/Handlers/GetProductsQueryHandler.cs @@ -14,6 +14,7 @@ public class GetProductsQueryHandler(IDbContextFactory c var products = await context.Products.AsNoTracking() .OrderByDescending(o => o.Id) + .Take(request.MaxRecords) .ToArrayAsync(cancellationToken); return Result.Ok(products.Select(p => p.ToModel()).ToArray()); diff --git a/LiteCharms.Infrastructure/Database/LeadGeneratorDbContext.cs b/LiteCharms.Infrastructure/Database/LeadGeneratorDbContext.cs index 7daef35..59447d8 100644 --- a/LiteCharms.Infrastructure/Database/LeadGeneratorDbContext.cs +++ b/LiteCharms.Infrastructure/Database/LeadGeneratorDbContext.cs @@ -15,4 +15,6 @@ public class LeadGeneratorDbContext(DbContextOptions opt public DbSet Products { get; set; } public DbSet ProductPrices { get; set; } + + public DbSet Notifications { get; set; } } diff --git a/LiteCharms.Models/Enums.cs b/LiteCharms.Models/Enums.cs index deb97b0..3b26c0f 100644 --- a/LiteCharms.Models/Enums.cs +++ b/LiteCharms.Models/Enums.cs @@ -19,3 +19,10 @@ public enum LeadStatus : int Converted = 4, Lost = 5 } + +public enum NotificationDirection : int +{ + Incoming = 0, + Outgoing = 1, + Neutral = 2 +} diff --git a/LiteCharms.Models/Notification.cs b/LiteCharms.Models/Notification.cs new file mode 100644 index 0000000..23c0596 --- /dev/null +++ b/LiteCharms.Models/Notification.cs @@ -0,0 +1,26 @@ +namespace LiteCharms.Models; + +public class Notification +{ + public Guid Id { get; set; } + + public DateTimeOffset CreatedAt { get; set; } + + public NotificationDirection Direction { get; set; } + + public string? Author { get; set; } + + public string? Title { get; set; } + + public string? Description { get; set; } + + public string? Platform { get; set; } + + public string? PlatformAddress { get; set; } + + public string? CorrelationId { get; set; } + + public string? CorrelationIdType { get; set; } + + public bool IsInternal { get; set; } +}