diff --git a/Lutra/Lutra.API/Controllers/VerspakkettenController.cs b/Lutra/Lutra.API/Controllers/VerspakkettenController.cs
index e0d39a5..37a2a52 100644
--- a/Lutra/Lutra.API/Controllers/VerspakkettenController.cs
+++ b/Lutra/Lutra.API/Controllers/VerspakkettenController.cs
@@ -5,7 +5,7 @@ using Microsoft.AspNetCore.Mvc;
namespace Lutra.API.Controllers
{
///
- /// Provides read-only access to verspakket resources.
+ /// Provides access to verspakket resources.
///
[ApiController]
[Route("api/verspakketten")]
@@ -50,5 +50,27 @@ namespace Lutra.API.Controllers
return Ok(result);
}
+
+ ///
+ /// Creates a new verspakket.
+ ///
+ /// The verspakket values to create.
+ /// Returns 201 Created with the created verspakket identifier.
+ [HttpPost]
+ [ProducesResponseType(typeof(CreateVerspakket.Response), StatusCodes.Status201Created)]
+ [ProducesResponseType(StatusCodes.Status400BadRequest)]
+ public async Task> Post([FromBody] CreateVerspakket.Command command)
+ {
+ try
+ {
+ var result = await mediator.SendCommandAsync(command);
+
+ return CreatedAtAction(nameof(GetById), new { id = result.Id }, result);
+ }
+ catch (InvalidOperationException ex)
+ {
+ return BadRequest(ex.Message);
+ }
+ }
}
}
\ No newline at end of file
diff --git a/Lutra/Lutra.API/Lutra.API.csproj b/Lutra/Lutra.API/Lutra.API.csproj
index bf52713..4441b7e 100644
--- a/Lutra/Lutra.API/Lutra.API.csproj
+++ b/Lutra/Lutra.API/Lutra.API.csproj
@@ -1,4 +1,4 @@
-
+
net10.0
@@ -12,13 +12,13 @@
-
-
+
+
runtime; build; native; contentfiles; analyzers; buildtransitive
all
-
+
diff --git a/Lutra/Lutra.Application/Lutra.Application.csproj b/Lutra/Lutra.Application/Lutra.Application.csproj
index c836440..109f6fd 100644
--- a/Lutra/Lutra.Application/Lutra.Application.csproj
+++ b/Lutra/Lutra.Application/Lutra.Application.csproj
@@ -8,7 +8,7 @@
-
+
diff --git a/Lutra/Lutra.Application/Models/Supermarkten/Supermarkt.cs b/Lutra/Lutra.Application/Models/Supermarkten/Supermarkt.cs
index 6f6ad50..31c2398 100644
--- a/Lutra/Lutra.Application/Models/Supermarkten/Supermarkt.cs
+++ b/Lutra/Lutra.Application/Models/Supermarkten/Supermarkt.cs
@@ -2,6 +2,8 @@
{
public record Supermarkt
{
+ public required Guid Id { get; init; }
+
public required string Naam { get; init; }
}
}
diff --git a/Lutra/Lutra.Application/Models/Verspakketten/Beoordeling.cs b/Lutra/Lutra.Application/Models/Verspakketten/Beoordeling.cs
index cb3bc0d..45fb971 100644
--- a/Lutra/Lutra.Application/Models/Verspakketten/Beoordeling.cs
+++ b/Lutra/Lutra.Application/Models/Verspakketten/Beoordeling.cs
@@ -3,7 +3,10 @@
public class Beoordeling
{
public required int CijferSmaak { get; init; }
+
public required int CijferBereiden { get; init; }
+
public required bool Aanbevolen { get; init; }
+
public string? Tekst { get; init; }
}
diff --git a/Lutra/Lutra.Application/Models/Verspakketten/Verspakket.cs b/Lutra/Lutra.Application/Models/Verspakketten/Verspakket.cs
index ea86fd8..46a7d78 100644
--- a/Lutra/Lutra.Application/Models/Verspakketten/Verspakket.cs
+++ b/Lutra/Lutra.Application/Models/Verspakketten/Verspakket.cs
@@ -4,9 +4,14 @@ namespace Lutra.Application.Models.Verspakketten
{
public record Verspakket
{
+ public required Guid Id { get; init; }
+
public required string Naam { get; init; }
+
public int? PrijsInCenten { get; init; }
+
public Beoordeling[]? Beoordelingen { get; init; }
+
public Supermarkt? Supermarkt { get; init; }
}
}
diff --git a/Lutra/Lutra.Application/Supermarkten/GetSupermarkten.Handler.cs b/Lutra/Lutra.Application/Supermarkten/GetSupermarkten.Handler.cs
index 303c02e..756e766 100644
--- a/Lutra/Lutra.Application/Supermarkten/GetSupermarkten.Handler.cs
+++ b/Lutra/Lutra.Application/Supermarkten/GetSupermarkten.Handler.cs
@@ -13,10 +13,15 @@ namespace Lutra.Application.Supermarkten
{
var supermarkten = await context.Supermarkten
.AsNoTracking()
+ .Where(w => w.DeletedAt == null)
.OrderBy(s => s.Naam)
.Skip(request.Skip)
.Take(request.Take)
- .Select(s => new Supermarkt { Naam = s.Naam })
+ .Select(s => new Supermarkt
+ {
+ Id = s.Id,
+ Naam = s.Naam
+ })
.ToListAsync(cancellationToken);
return new Response { Supermarkten = supermarkten };
diff --git a/Lutra/Lutra.Application/Verspakketten/CreateVerspakket.Command.cs b/Lutra/Lutra.Application/Verspakketten/CreateVerspakket.Command.cs
new file mode 100644
index 0000000..9a35b7c
--- /dev/null
+++ b/Lutra/Lutra.Application/Verspakketten/CreateVerspakket.Command.cs
@@ -0,0 +1,12 @@
+using Cortex.Mediator.Commands;
+
+namespace Lutra.Application.Verspakketten;
+
+public sealed partial class CreateVerspakket
+{
+ public sealed record Command(
+ string Naam,
+ int? PrijsInCenten,
+ int AantalPersonen,
+ Guid SupermarktId) : ICommand;
+}
diff --git a/Lutra/Lutra.Application/Verspakketten/CreateVerspakket.Handler.cs b/Lutra/Lutra.Application/Verspakketten/CreateVerspakket.Handler.cs
new file mode 100644
index 0000000..271f3b1
--- /dev/null
+++ b/Lutra/Lutra.Application/Verspakketten/CreateVerspakket.Handler.cs
@@ -0,0 +1,40 @@
+using Cortex.Mediator.Commands;
+using Lutra.Application.Interfaces;
+using Microsoft.EntityFrameworkCore;
+
+namespace Lutra.Application.Verspakketten;
+
+public sealed partial class CreateVerspakket
+{
+ public sealed class Handler(ILutraDbContext context) : ICommandHandler
+ {
+ public async Task Handle(Command request, CancellationToken cancellationToken)
+ {
+ var supermarktExists = await context.Supermarkten
+ .AsNoTracking()
+ .AnyAsync(s => s.Id == request.SupermarktId, cancellationToken);
+
+ if (!supermarktExists)
+ {
+ throw new InvalidOperationException($"Supermarkt with id '{request.SupermarktId}' was not found.");
+ }
+
+ var now = DateTime.UtcNow;
+ var verspakket = new Domain.Entities.Verspakket
+ {
+ Id = Guid.NewGuid(),
+ Naam = request.Naam,
+ PrijsInCenten = request.PrijsInCenten,
+ AantalPersonen = request.AantalPersonen,
+ SupermarktId = request.SupermarktId,
+ CreatedAt = now,
+ ModifiedAt = now
+ };
+
+ await context.Verspaketten.AddAsync(verspakket, cancellationToken);
+ await context.SaveChangesAsync(cancellationToken);
+
+ return new Response { Id = verspakket.Id };
+ }
+ }
+}
diff --git a/Lutra/Lutra.Application/Verspakketten/CreateVerspakket.Response.cs b/Lutra/Lutra.Application/Verspakketten/CreateVerspakket.Response.cs
new file mode 100644
index 0000000..e2c3f91
--- /dev/null
+++ b/Lutra/Lutra.Application/Verspakketten/CreateVerspakket.Response.cs
@@ -0,0 +1,9 @@
+namespace Lutra.Application.Verspakketten;
+
+public sealed partial class CreateVerspakket
+{
+ public sealed class Response
+ {
+ public required Guid Id { get; set; }
+ }
+}
diff --git a/Lutra/Lutra.Application/Verspakketten/CreateVerspakket.cs b/Lutra/Lutra.Application/Verspakketten/CreateVerspakket.cs
new file mode 100644
index 0000000..9be41ca
--- /dev/null
+++ b/Lutra/Lutra.Application/Verspakketten/CreateVerspakket.cs
@@ -0,0 +1,3 @@
+namespace Lutra.Application.Verspakketten;
+
+public sealed partial class CreateVerspakket { }
diff --git a/Lutra/Lutra.Application/Verspakketten/GetVerspakket.Handler.cs b/Lutra/Lutra.Application/Verspakketten/GetVerspakket.Handler.cs
index fb0f059..2e0b010 100644
--- a/Lutra/Lutra.Application/Verspakketten/GetVerspakket.Handler.cs
+++ b/Lutra/Lutra.Application/Verspakketten/GetVerspakket.Handler.cs
@@ -17,6 +17,7 @@ namespace Lutra.Application.Verspakketten
.Where(v => v.Id == request.Id)
.Select(v => new Verspakket
{
+ Id = v.Id,
Naam = v.Naam,
PrijsInCenten = v.PrijsInCenten,
Beoordelingen = v.Beoordelingen
@@ -30,6 +31,7 @@ namespace Lutra.Application.Verspakketten
.ToArray(),
Supermarkt = new Supermarkt
{
+ Id = v.Supermarkt.Id,
Naam = v.Supermarkt.Naam
}
})
diff --git a/Lutra/Lutra.Application/Verspakketten/GetVerspakketten.Handler.cs b/Lutra/Lutra.Application/Verspakketten/GetVerspakketten.Handler.cs
index d04ded3..1f073f9 100644
--- a/Lutra/Lutra.Application/Verspakketten/GetVerspakketten.Handler.cs
+++ b/Lutra/Lutra.Application/Verspakketten/GetVerspakketten.Handler.cs
@@ -12,7 +12,9 @@ namespace Lutra.Application.Verspakketten
{
public async Task Handle(Query request, CancellationToken cancellationToken)
{
- var query = context.Verspaketten.AsNoTracking();
+ var query = context.Verspaketten
+ .Where(w => w.DeletedAt == null)
+ .AsNoTracking();
// Apply sort before pagination so the database handles ordering efficiently.
IOrderedQueryable sorted = request.SortField switch
@@ -40,6 +42,7 @@ namespace Lutra.Application.Verspakketten
.Take(request.Take)
.Select(v => new Verspakket
{
+ Id = v.Id,
Naam = v.Naam,
PrijsInCenten = v.PrijsInCenten,
Beoordelingen = v.Beoordelingen
@@ -53,6 +56,7 @@ namespace Lutra.Application.Verspakketten
.ToArray(),
Supermarkt = new Supermarkt
{
+ Id = v.Supermarkt.Id,
Naam = v.Supermarkt.Naam
}
})
diff --git a/Lutra/Lutra.Domain/Entities/BaseEntity.cs b/Lutra/Lutra.Domain/Entities/BaseEntity.cs
index 222e25c..60a7d0d 100644
--- a/Lutra/Lutra.Domain/Entities/BaseEntity.cs
+++ b/Lutra/Lutra.Domain/Entities/BaseEntity.cs
@@ -9,6 +9,4 @@ public abstract class BaseEntity
public DateTime ModifiedAt { get; set; }
public DateTime? DeletedAt { get; set; }
-
- public bool IsDeleted => DeletedAt.HasValue;
}
diff --git a/Lutra/Lutra.Domain/Entities/Verspakket.cs b/Lutra/Lutra.Domain/Entities/Verspakket.cs
index 2d6bb95..d31a98e 100644
--- a/Lutra/Lutra.Domain/Entities/Verspakket.cs
+++ b/Lutra/Lutra.Domain/Entities/Verspakket.cs
@@ -16,7 +16,7 @@ public class Verspakket : BaseEntity
public required Guid SupermarktId { get; set; }
- public required virtual Supermarkt Supermarkt { get; set; }
+ public virtual Supermarkt Supermarkt { get; set; } = null!;
public IReadOnlyCollection Beoordelingen => _beoordelingen.AsReadOnly();
diff --git a/Lutra/Lutra.Infrastructure.Migrator/Lutra.Infrastructure.Migrator.csproj b/Lutra/Lutra.Infrastructure.Migrator/Lutra.Infrastructure.Migrator.csproj
index 44bd8d9..7c181e2 100644
--- a/Lutra/Lutra.Infrastructure.Migrator/Lutra.Infrastructure.Migrator.csproj
+++ b/Lutra/Lutra.Infrastructure.Migrator/Lutra.Infrastructure.Migrator.csproj
@@ -8,8 +8,8 @@
-
-
+
+
diff --git a/Lutra/Lutra.Infrastructure/Lutra.Infrastructure.Sql.csproj b/Lutra/Lutra.Infrastructure/Lutra.Infrastructure.Sql.csproj
index eb0075d..c1bfb82 100644
--- a/Lutra/Lutra.Infrastructure/Lutra.Infrastructure.Sql.csproj
+++ b/Lutra/Lutra.Infrastructure/Lutra.Infrastructure.Sql.csproj
@@ -7,12 +7,12 @@
-
-
+
+
runtime; build; native; contentfiles; analyzers; buildtransitive
all
-
+