Added order item comment

This commit is contained in:
2025-11-30 16:05:31 +01:00
parent 7098530cf4
commit 90306e8944
8 changed files with 492 additions and 21 deletions

View File

@@ -102,7 +102,7 @@ public class OrderController : Controller
// POST: Order/AddItem
[HttpPost]
public async Task<IActionResult> AddItem(int orderId, int menuItemId, int quantity)
public async Task<IActionResult> 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);

View File

@@ -0,0 +1,417 @@
// <auto-generated />
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
{
/// <inheritdoc />
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<string>("Id")
.HasColumnType("TEXT");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("TEXT");
b.Property<string>("Name")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.Property<string>("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<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("ClaimType")
.HasColumnType("TEXT");
b.Property<string>("ClaimValue")
.HasColumnType("TEXT");
b.Property<string>("RoleId")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("RoleId");
b.ToTable("AspNetRoleClaims", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b =>
{
b.Property<string>("Id")
.HasColumnType("TEXT");
b.Property<int>("AccessFailedCount")
.HasColumnType("INTEGER");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("TEXT");
b.Property<string>("Email")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.Property<bool>("EmailConfirmed")
.HasColumnType("INTEGER");
b.Property<bool>("LockoutEnabled")
.HasColumnType("INTEGER");
b.Property<DateTimeOffset?>("LockoutEnd")
.HasColumnType("TEXT");
b.Property<string>("NormalizedEmail")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.Property<string>("NormalizedUserName")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.Property<string>("PasswordHash")
.HasColumnType("TEXT");
b.Property<string>("PhoneNumber")
.HasColumnType("TEXT");
b.Property<bool>("PhoneNumberConfirmed")
.HasColumnType("INTEGER");
b.Property<string>("SecurityStamp")
.HasColumnType("TEXT");
b.Property<bool>("TwoFactorEnabled")
.HasColumnType("INTEGER");
b.Property<string>("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<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("ClaimType")
.HasColumnType("TEXT");
b.Property<string>("ClaimValue")
.HasColumnType("TEXT");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("AspNetUserClaims", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.Property<string>("LoginProvider")
.HasColumnType("TEXT");
b.Property<string>("ProviderKey")
.HasColumnType("TEXT");
b.Property<string>("ProviderDisplayName")
.HasColumnType("TEXT");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("LoginProvider", "ProviderKey");
b.HasIndex("UserId");
b.ToTable("AspNetUserLogins", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("TEXT");
b.Property<string>("RoleId")
.HasColumnType("TEXT");
b.HasKey("UserId", "RoleId");
b.HasIndex("RoleId");
b.ToTable("AspNetUserRoles", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("TEXT");
b.Property<string>("LoginProvider")
.HasColumnType("TEXT");
b.Property<string>("Name")
.HasColumnType("TEXT");
b.Property<string>("Value")
.HasColumnType("TEXT");
b.HasKey("UserId", "LoginProvider", "Name");
b.ToTable("AspNetUserTokens", (string)null);
});
modelBuilder.Entity("OneForMe.Models.MenuItem", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("TEXT");
b.Property<int>("OrderId")
.HasColumnType("INTEGER");
b.Property<decimal>("Price")
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("OrderId");
b.ToTable("MenuItems");
});
modelBuilder.Entity("OneForMe.Models.Order", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("AdditionalInfo")
.HasColumnType("TEXT");
b.Property<DateTime?>("ClosedAt")
.HasColumnType("TEXT");
b.Property<DateTime?>("CompletedAt")
.HasColumnType("TEXT");
b.Property<DateTime>("CreatedAt")
.HasColumnType("TEXT");
b.Property<string>("CreatorName")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("ImagePath")
.HasColumnType("TEXT");
b.Property<bool>("IsClosed")
.HasColumnType("INTEGER");
b.Property<bool>("IsCompleted")
.HasColumnType("INTEGER");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("OrderCode")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("OrderCode")
.IsUnique();
b.ToTable("Orders");
});
modelBuilder.Entity("OneForMe.Models.OrderItem", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("Comments")
.HasColumnType("TEXT");
b.Property<int>("MenuItemId")
.HasColumnType("INTEGER");
b.Property<int>("OrderId")
.HasColumnType("INTEGER");
b.Property<DateTime>("OrderedAt")
.HasColumnType("TEXT");
b.Property<string>("ParticipantEmail")
.HasColumnType("TEXT");
b.Property<string>("ParticipantName")
.IsRequired()
.HasColumnType("TEXT");
b.Property<int>("Quantity")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.HasIndex("MenuItemId");
b.HasIndex("OrderId");
b.ToTable("OrderItems");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", 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<string>", 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
}
}
}

View File

@@ -0,0 +1,28 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace OneForMe.Migrations
{
/// <inheritdoc />
public partial class AddDescriptionToMenuOrder : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "Comments",
table: "OrderItems",
type: "TEXT",
nullable: true);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "Comments",
table: "OrderItems");
}
}
}

View File

@@ -285,6 +285,9 @@ namespace OneForMe.Migrations
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("Comments")
.HasColumnType("TEXT");
b.Property<int>("MenuItemId")
.HasColumnType("INTEGER");

View File

@@ -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; }

View File

@@ -306,4 +306,7 @@
<data name="Fulfilled" xml:space="preserve">
<value>Erfüllt</value>
</data>
<data name="Comments" xml:space="preserve">
<value>Anmerkungen</value>
</data>
</root>

View File

@@ -303,4 +303,7 @@
<data name="Fulfilled" xml:space="preserve">
<value>Fulfilled</value>
</data>
<data name="Comments" xml:space="preserve">
<value>Comments</value>
</data>
</root>

View File

@@ -54,6 +54,11 @@
<input type="number" class="form-control" id="quantity" name="quantity" value="1" min="1" required>
</div>
<div class="mb-3">
<label for="comments" class="form-label">@Localizer["Comments"]</label>
<input class="form-control" id="comments" name="comments"></input>
</div>
<div class="alert alert-info">
<strong>@Localizer["Total"]:</strong> @Html.Raw(Localizer["Currency", "<span id=\"totalPrice\">0.00</span>"])
</div>
@@ -78,27 +83,37 @@
<div class="card-body">
@if (Model.OrderItems.Any())
{
<table class="table table-sm table-hover">
<thead>
<tr>
<th>@Localizer["Participant"]</th>
<th>@Localizer["Item"]</th>
<th>@Localizer["Qty"]</th>
<th>@Localizer["Total"]</th>
</tr>
</thead>
<tbody>
@foreach (var orderItem in Model.OrderItems)
{
<div class="table-responsive">
<table class="table table-sm table-hover">
<thead>
<tr>
<td>@orderItem.ParticipantName</td>
<td>@orderItem.MenuItem?.Name</td>
<td>@orderItem.Quantity</td>
<td>@Localizer["Currency", (orderItem.MenuItem?.Price * orderItem.Quantity ?? 0).ToString("F2")]</td>
<th>@Localizer["Person"]</th>
<th>@Localizer["Item"]</th>
<th>@Localizer["Qty"]</th>
@if (Model.OrderItems.Any(oi => !string.IsNullOrEmpty(oi.Comments)))
{
<th>@Localizer["Comments"]</th>
}
<th>@Localizer["Total"]</th>
</tr>
}
</tbody>
</table>
</thead>
<tbody>
@foreach (var orderItem in Model.OrderItems)
{
<tr>
<td>@orderItem.ParticipantName</td>
<td>@orderItem.MenuItem?.Name</td>
<td>@orderItem.Quantity</td>
@if (Model.OrderItems.Any(oi => !string.IsNullOrEmpty(oi.Comments)))
{
<td style="word-break: break-word;">@orderItem.Comments</td>
}
<td>@Localizer["Currency", (orderItem.MenuItem?.Price * orderItem.Quantity ?? 0).ToString("F2")]</td>
</tr>
}
</tbody>
</table>
</div>
<hr>