diff --git a/Controllers/OrderController.cs b/Controllers/OrderController.cs index 316f89c..88da2a3 100644 --- a/Controllers/OrderController.cs +++ b/Controllers/OrderController.cs @@ -102,7 +102,7 @@ public class OrderController : Controller // POST: Order/AddItem [HttpPost] - public async Task AddItem(int orderId, int menuItemId, int quantity) + public async Task AddItem(int orderId, int menuItemId, int quantity, string comments) { var order = await _context.Orders.FindAsync(orderId); if (order == null || order.IsClosed) @@ -118,7 +118,8 @@ public class OrderController : Controller MenuItemId = menuItemId, Quantity = quantity, ParticipantName = User.Identity?.Name ?? "", - ParticipantEmail = User.Identity?.Name + ParticipantEmail = User.Identity?.Name, + Comments = comments }; _context.OrderItems.Add(orderItem); diff --git a/Migrations/20251130144638_AddDescriptionToMenuOrder.Designer.cs b/Migrations/20251130144638_AddDescriptionToMenuOrder.Designer.cs new file mode 100644 index 0000000..1f8cf8a --- /dev/null +++ b/Migrations/20251130144638_AddDescriptionToMenuOrder.Designer.cs @@ -0,0 +1,417 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using OneForMe.Data; + +#nullable disable + +namespace OneForMe.Migrations +{ + [DbContext(typeof(ApplicationDbContext))] + [Migration("20251130144638_AddDescriptionToMenuOrder")] + partial class AddDescriptionToMenuOrder + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "10.0.0-rc.2.25502.107"); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex"); + + b.ToTable("AspNetRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("RoleId") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("AccessFailedCount") + .HasColumnType("INTEGER"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("EmailConfirmed") + .HasColumnType("INTEGER"); + + b.Property("LockoutEnabled") + .HasColumnType("INTEGER"); + + b.Property("LockoutEnd") + .HasColumnType("TEXT"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("PasswordHash") + .HasColumnType("TEXT"); + + b.Property("PhoneNumber") + .HasColumnType("TEXT"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("INTEGER"); + + b.Property("SecurityStamp") + .HasColumnType("TEXT"); + + b.Property("TwoFactorEnabled") + .HasColumnType("INTEGER"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.ToTable("AspNetUsers", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("TEXT"); + + b.Property("ProviderKey") + .HasColumnType("TEXT"); + + b.Property("ProviderDisplayName") + .HasColumnType("TEXT"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("RoleId") + .HasColumnType("TEXT"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("LoginProvider") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("OneForMe.Models.MenuItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("OrderId") + .HasColumnType("INTEGER"); + + b.Property("Price") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("OrderId"); + + b.ToTable("MenuItems"); + }); + + modelBuilder.Entity("OneForMe.Models.Order", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AdditionalInfo") + .HasColumnType("TEXT"); + + b.Property("ClosedAt") + .HasColumnType("TEXT"); + + b.Property("CompletedAt") + .HasColumnType("TEXT"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("CreatorName") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ImagePath") + .HasColumnType("TEXT"); + + b.Property("IsClosed") + .HasColumnType("INTEGER"); + + b.Property("IsCompleted") + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("OrderCode") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("OrderCode") + .IsUnique(); + + b.ToTable("Orders"); + }); + + modelBuilder.Entity("OneForMe.Models.OrderItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Comments") + .HasColumnType("TEXT"); + + b.Property("MenuItemId") + .HasColumnType("INTEGER"); + + b.Property("OrderId") + .HasColumnType("INTEGER"); + + b.Property("OrderedAt") + .HasColumnType("TEXT"); + + b.Property("ParticipantEmail") + .HasColumnType("TEXT"); + + b.Property("ParticipantName") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Quantity") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("MenuItemId"); + + b.HasIndex("OrderId"); + + b.ToTable("OrderItems"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("OneForMe.Models.MenuItem", b => + { + b.HasOne("OneForMe.Models.Order", "Order") + .WithMany("MenuItems") + .HasForeignKey("OrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Order"); + }); + + modelBuilder.Entity("OneForMe.Models.OrderItem", b => + { + b.HasOne("OneForMe.Models.MenuItem", "MenuItem") + .WithMany("OrderItems") + .HasForeignKey("MenuItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("OneForMe.Models.Order", "Order") + .WithMany("OrderItems") + .HasForeignKey("OrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("MenuItem"); + + b.Navigation("Order"); + }); + + modelBuilder.Entity("OneForMe.Models.MenuItem", b => + { + b.Navigation("OrderItems"); + }); + + modelBuilder.Entity("OneForMe.Models.Order", b => + { + b.Navigation("MenuItems"); + + b.Navigation("OrderItems"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Migrations/20251130144638_AddDescriptionToMenuOrder.cs b/Migrations/20251130144638_AddDescriptionToMenuOrder.cs new file mode 100644 index 0000000..05c7f9d --- /dev/null +++ b/Migrations/20251130144638_AddDescriptionToMenuOrder.cs @@ -0,0 +1,28 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace OneForMe.Migrations +{ + /// + public partial class AddDescriptionToMenuOrder : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "Comments", + table: "OrderItems", + type: "TEXT", + nullable: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "Comments", + table: "OrderItems"); + } + } +} diff --git a/Migrations/ApplicationDbContextModelSnapshot.cs b/Migrations/ApplicationDbContextModelSnapshot.cs index 8ddfd39..9204b32 100644 --- a/Migrations/ApplicationDbContextModelSnapshot.cs +++ b/Migrations/ApplicationDbContextModelSnapshot.cs @@ -285,6 +285,9 @@ namespace OneForMe.Migrations .ValueGeneratedOnAdd() .HasColumnType("INTEGER"); + b.Property("Comments") + .HasColumnType("TEXT"); + b.Property("MenuItemId") .HasColumnType("INTEGER"); diff --git a/Models/OrderItem.cs b/Models/OrderItem.cs index b47705d..ba9a164 100644 --- a/Models/OrderItem.cs +++ b/Models/OrderItem.cs @@ -8,6 +8,7 @@ public class OrderItem public string ParticipantName { get; set; } = string.Empty; public string? ParticipantEmail { get; set; } public int Quantity { get; set; } = 1; + public string? Comments { get; set; } public DateTime OrderedAt { get; set; } = DateTime.UtcNow; public Order? Order { get; set; } diff --git a/Resources/SharedResources.de.resx b/Resources/SharedResources.de.resx index 8ad3357..2d8972c 100644 --- a/Resources/SharedResources.de.resx +++ b/Resources/SharedResources.de.resx @@ -306,4 +306,7 @@ Erfüllt + + Anmerkungen + \ No newline at end of file diff --git a/Resources/SharedResources.en.resx b/Resources/SharedResources.en.resx index 11adba4..2bcc912 100644 --- a/Resources/SharedResources.en.resx +++ b/Resources/SharedResources.en.resx @@ -303,4 +303,7 @@ Fulfilled + + Comments + \ No newline at end of file diff --git a/Views/Order/Join.cshtml b/Views/Order/Join.cshtml index 4c1e0d6..6888335 100644 --- a/Views/Order/Join.cshtml +++ b/Views/Order/Join.cshtml @@ -54,6 +54,11 @@ +
+ + +
+
@Localizer["Total"]: @Html.Raw(Localizer["Currency", "0.00"])
@@ -78,27 +83,37 @@
@if (Model.OrderItems.Any()) { - - - - - - - - - - - @foreach (var orderItem in Model.OrderItems) - { +
+
@Localizer["Participant"]@Localizer["Item"]@Localizer["Qty"]@Localizer["Total"]
+ - - - - + + + + @if (Model.OrderItems.Any(oi => !string.IsNullOrEmpty(oi.Comments))) + { + + } + - } - -
@orderItem.ParticipantName@orderItem.MenuItem?.Name@orderItem.Quantity@Localizer["Currency", (orderItem.MenuItem?.Price * orderItem.Quantity ?? 0).ToString("F2")]@Localizer["Person"]@Localizer["Item"]@Localizer["Qty"]@Localizer["Comments"]@Localizer["Total"]
+ + + @foreach (var orderItem in Model.OrderItems) + { + + @orderItem.ParticipantName + @orderItem.MenuItem?.Name + @orderItem.Quantity + @if (Model.OrderItems.Any(oi => !string.IsNullOrEmpty(oi.Comments))) + { + @orderItem.Comments + } + @Localizer["Currency", (orderItem.MenuItem?.Price * orderItem.Quantity ?? 0).ToString("F2")] + + } + + +