Added Bestellzustände
This commit is contained in:
@@ -94,15 +94,15 @@ public class OrderController : Controller
|
|||||||
if (order == null)
|
if (order == null)
|
||||||
return NotFound("Order not found");
|
return NotFound("Order not found");
|
||||||
|
|
||||||
if (order.IsClosed)
|
if (order.IsClosed || order.IsCompleted)
|
||||||
return BadRequest("This order is closed");
|
return BadRequest("This order cannot be joined");
|
||||||
|
|
||||||
return View(order);
|
return View(order);
|
||||||
}
|
}
|
||||||
|
|
||||||
// POST: Order/AddItem
|
// POST: Order/AddItem
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
public async Task<IActionResult> AddItem(int orderId, int menuItemId, int quantity, string participantName, string? participantEmail)
|
public async Task<IActionResult> AddItem(int orderId, int menuItemId, int quantity)
|
||||||
{
|
{
|
||||||
var order = await _context.Orders.FindAsync(orderId);
|
var order = await _context.Orders.FindAsync(orderId);
|
||||||
if (order == null || order.IsClosed)
|
if (order == null || order.IsClosed)
|
||||||
@@ -117,8 +117,8 @@ public class OrderController : Controller
|
|||||||
OrderId = orderId,
|
OrderId = orderId,
|
||||||
MenuItemId = menuItemId,
|
MenuItemId = menuItemId,
|
||||||
Quantity = quantity,
|
Quantity = quantity,
|
||||||
ParticipantName = participantName,
|
ParticipantName = User.Identity?.Name ?? "",
|
||||||
ParticipantEmail = participantEmail
|
ParticipantEmail = User.Identity?.Name
|
||||||
};
|
};
|
||||||
|
|
||||||
_context.OrderItems.Add(orderItem);
|
_context.OrderItems.Add(orderItem);
|
||||||
@@ -152,6 +152,9 @@ public class OrderController : Controller
|
|||||||
if (order.IsClosed)
|
if (order.IsClosed)
|
||||||
return BadRequest("Order is already closed");
|
return BadRequest("Order is already closed");
|
||||||
|
|
||||||
|
if (order.CreatorName != User.Identity?.Name)
|
||||||
|
return Forbid("Only the order creator can close this order");
|
||||||
|
|
||||||
order.IsClosed = true;
|
order.IsClosed = true;
|
||||||
order.ClosedAt = DateTime.UtcNow;
|
order.ClosedAt = DateTime.UtcNow;
|
||||||
|
|
||||||
@@ -161,6 +164,33 @@ public class OrderController : Controller
|
|||||||
return RedirectToAction("Details", new { code = order.OrderCode });
|
return RedirectToAction("Details", new { code = order.OrderCode });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GET: Order/Complete/{code}
|
||||||
|
public async Task<IActionResult> Complete(string code)
|
||||||
|
{
|
||||||
|
var order = await _context.Orders.FirstOrDefaultAsync(o => o.OrderCode == code);
|
||||||
|
|
||||||
|
if (order == null)
|
||||||
|
return NotFound("Order not found");
|
||||||
|
|
||||||
|
// Only the creator can complete an order
|
||||||
|
if (order.CreatorName != User.Identity?.Name)
|
||||||
|
return Forbid("Only the order creator can mark this as completed");
|
||||||
|
|
||||||
|
if (!order.IsClosed)
|
||||||
|
return BadRequest("Order must be closed before marking as completed");
|
||||||
|
|
||||||
|
if (order.IsCompleted)
|
||||||
|
return BadRequest("Order is already marked as completed");
|
||||||
|
|
||||||
|
order.IsCompleted = true;
|
||||||
|
order.CompletedAt = DateTime.UtcNow;
|
||||||
|
|
||||||
|
_context.Orders.Update(order);
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
|
||||||
|
return RedirectToAction("Details", new { code = order.OrderCode });
|
||||||
|
}
|
||||||
|
|
||||||
private string GenerateOrderCode()
|
private string GenerateOrderCode()
|
||||||
{
|
{
|
||||||
return Guid.NewGuid().ToString().Substring(0, 8).ToUpper();
|
return Guid.NewGuid().ToString().Substring(0, 8).ToUpper();
|
||||||
|
|||||||
@@ -10,13 +10,50 @@ namespace OneForMe.Migrations
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
{
|
{
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "AdditionalInfo",
|
||||||
|
table: "Orders",
|
||||||
|
type: "TEXT",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "ImagePath",
|
||||||
|
table: "Orders",
|
||||||
|
type: "TEXT",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<bool>(
|
||||||
|
name: "IsCompleted",
|
||||||
|
table: "Orders",
|
||||||
|
type: "INTEGER",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: false);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "CompletedAt",
|
||||||
|
table: "Orders",
|
||||||
|
type: "TEXT",
|
||||||
|
nullable: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void Down(MigrationBuilder migrationBuilder)
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
{
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "AdditionalInfo",
|
||||||
|
table: "Orders");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "ImagePath",
|
||||||
|
table: "Orders");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "IsCompleted",
|
||||||
|
table: "Orders");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "CompletedAt",
|
||||||
|
table: "Orders");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
414
Migrations/20251130110018_AddCompletedStateToOrder.Designer.cs
generated
Normal file
414
Migrations/20251130110018_AddCompletedStateToOrder.Designer.cs
generated
Normal file
@@ -0,0 +1,414 @@
|
|||||||
|
// <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("20251130110018_AddCompletedStateToOrder")]
|
||||||
|
partial class AddCompletedStateToOrder
|
||||||
|
{
|
||||||
|
/// <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<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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
40
Migrations/20251130120000_AddCompletedStateToOrder.cs
Normal file
40
Migrations/20251130120000_AddCompletedStateToOrder.cs
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace OneForMe.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class AddCompletedStateToOrder : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<bool>(
|
||||||
|
name: "IsCompleted",
|
||||||
|
table: "Orders",
|
||||||
|
type: "INTEGER",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: false);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "CompletedAt",
|
||||||
|
table: "Orders",
|
||||||
|
type: "TEXT",
|
||||||
|
nullable: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "IsCompleted",
|
||||||
|
table: "Orders");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "CompletedAt",
|
||||||
|
table: "Orders");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -244,6 +244,9 @@ namespace OneForMe.Migrations
|
|||||||
b.Property<DateTime?>("ClosedAt")
|
b.Property<DateTime?>("ClosedAt")
|
||||||
.HasColumnType("TEXT");
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("CompletedAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
b.Property<DateTime>("CreatedAt")
|
b.Property<DateTime>("CreatedAt")
|
||||||
.HasColumnType("TEXT");
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
@@ -257,6 +260,9 @@ namespace OneForMe.Migrations
|
|||||||
b.Property<bool>("IsClosed")
|
b.Property<bool>("IsClosed")
|
||||||
.HasColumnType("INTEGER");
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("IsCompleted")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
b.Property<string>("Name")
|
b.Property<string>("Name")
|
||||||
.IsRequired()
|
.IsRequired()
|
||||||
.HasColumnType("TEXT");
|
.HasColumnType("TEXT");
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ public class Order
|
|||||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||||
public DateTime? ClosedAt { get; set; }
|
public DateTime? ClosedAt { get; set; }
|
||||||
public bool IsClosed { get; set; } = false;
|
public bool IsClosed { get; set; } = false;
|
||||||
|
public DateTime? CompletedAt { get; set; }
|
||||||
|
public bool IsCompleted { get; set; } = false;
|
||||||
|
|
||||||
public ICollection<MenuItem> MenuItems { get; set; } = new List<MenuItem>();
|
public ICollection<MenuItem> MenuItems { get; set; } = new List<MenuItem>();
|
||||||
public ICollection<OrderItem> OrderItems { get; set; } = new List<OrderItem>();
|
public ICollection<OrderItem> OrderItems { get; set; } = new List<OrderItem>();
|
||||||
|
|||||||
@@ -99,6 +99,9 @@
|
|||||||
<data name="Total" xml:space="preserve">
|
<data name="Total" xml:space="preserve">
|
||||||
<value>Gesamt</value>
|
<value>Gesamt</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="RecordedAmount" xml:space="preserve">
|
||||||
|
<value>Erfasster Betrag</value>
|
||||||
|
</data>
|
||||||
<data name="IOwe" xml:space="preserve">
|
<data name="IOwe" xml:space="preserve">
|
||||||
<value>Offener Betrag</value>
|
<value>Offener Betrag</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -294,4 +297,13 @@
|
|||||||
<data name="CreatedOn" xml:space="preserve">
|
<data name="CreatedOn" xml:space="preserve">
|
||||||
<value>Erstellt am</value>
|
<value>Erstellt am</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Completed" xml:space="preserve">
|
||||||
|
<value>Geliefert</value>
|
||||||
|
</data>
|
||||||
|
<data name="MarkCompleted" xml:space="preserve">
|
||||||
|
<value>Als geliefert markieren</value>
|
||||||
|
</data>
|
||||||
|
<data name="Fulfilled" xml:space="preserve">
|
||||||
|
<value>Erfüllt</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
@@ -99,6 +99,9 @@
|
|||||||
<data name="Total" xml:space="preserve">
|
<data name="Total" xml:space="preserve">
|
||||||
<value>Total</value>
|
<value>Total</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="RecordedAmount" xml:space="preserve">
|
||||||
|
<value>Recorded Amount</value>
|
||||||
|
</data>
|
||||||
<data name="IOwe" xml:space="preserve">
|
<data name="IOwe" xml:space="preserve">
|
||||||
<value>Outstanding amount</value>
|
<value>Outstanding amount</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -291,4 +294,13 @@
|
|||||||
<data name="CreatedOn" xml:space="preserve">
|
<data name="CreatedOn" xml:space="preserve">
|
||||||
<value>Created on</value>
|
<value>Created on</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Completed" xml:space="preserve">
|
||||||
|
<value>Completed</value>
|
||||||
|
</data>
|
||||||
|
<data name="MarkCompleted" xml:space="preserve">
|
||||||
|
<value>Mark as Completed</value>
|
||||||
|
</data>
|
||||||
|
<data name="Fulfilled" xml:space="preserve">
|
||||||
|
<value>Fulfilled</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
@@ -55,7 +55,7 @@
|
|||||||
<div class="col-md-6 mb-3">
|
<div class="col-md-6 mb-3">
|
||||||
<div class="card shadow">
|
<div class="card shadow">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h5 class="card-title">@order.Name</h5>
|
<h5 class="card-title">@order.Name <span class="badge @(order.IsCompleted ? "bg-success" : "bg-warning text-dark")" style="float: right">@Localizer.Get(order.IsClosed ? (order.IsCompleted ? "Completed" : "Closed") : "Open")</span></h5>
|
||||||
<p class="card-text">
|
<p class="card-text">
|
||||||
<small class="text-muted">@Localizer.Get("Code"): <strong>@order.OrderCode</strong></small><br>
|
<small class="text-muted">@Localizer.Get("Code"): <strong>@order.OrderCode</strong></small><br>
|
||||||
<small class="text-muted">@Localizer.Get("Created"): @order.CreatedAt.ToString("MMM dd, yyyy HH:mm")</small><br>
|
<small class="text-muted">@Localizer.Get("Created"): @order.CreatedAt.ToString("MMM dd, yyyy HH:mm")</small><br>
|
||||||
@@ -64,14 +64,6 @@
|
|||||||
<p class="text-success"><strong>@Localizer.Get("Total"): @Localizer["Currency", order.OrderItems.Sum(oi => oi.MenuItem.Price * oi.Quantity).ToString("F2")]</strong></p>
|
<p class="text-success"><strong>@Localizer.Get("Total"): @Localizer["Currency", order.OrderItems.Sum(oi => oi.MenuItem.Price * oi.Quantity).ToString("F2")]</strong></p>
|
||||||
<div class="d-flex gap-2">
|
<div class="d-flex gap-2">
|
||||||
<a href="/order/details?code=@order.OrderCode" class="btn btn-sm btn-primary">@Localizer.Get("View")</a>
|
<a href="/order/details?code=@order.OrderCode" class="btn btn-sm btn-primary">@Localizer.Get("View")</a>
|
||||||
@if (!order.IsClosed)
|
|
||||||
{
|
|
||||||
<a href="/order/close?code=@order.OrderCode" class="btn btn-sm btn-danger">@Localizer.Get("CloseOrder")</a>
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
<span class="badge bg-secondary align-content-center">@Localizer.Get("Closed")</span>
|
|
||||||
}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -24,7 +24,40 @@
|
|||||||
{
|
{
|
||||||
<p class="border rounded p-3" style="white-space: pre-wrap;">@Model.AdditionalInfo</p>
|
<p class="border rounded p-3" style="white-space: pre-wrap;">@Model.AdditionalInfo</p>
|
||||||
}
|
}
|
||||||
<p>@Localizer.Get("Status"): <span class="badge @(Model.IsClosed ? "bg-danger" : "bg-success")">@(Model.IsClosed ? Localizer.Get("Closed") : Localizer.Get("Open"))</span></p>
|
<p>@Localizer.Get("Status"):
|
||||||
|
<div class="d-flex align-items-center gap-3">
|
||||||
|
|
||||||
|
<div class="text-center">
|
||||||
|
<div class="badge bg-success")">Offen</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex-grow-1 border-top" style="border-width:3px !important;"></div>
|
||||||
|
|
||||||
|
<div class="text-center">
|
||||||
|
<div class="badge @(Model.IsClosed ? "bg-success" : "bg-danger")">Abgeschlossen</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex-grow-1 border-top" style="border-width:3px !important;"></div>
|
||||||
|
|
||||||
|
<div class="text-center">
|
||||||
|
<div class="badge @(Model.IsCompleted ? "bg-success" : "bg-danger")">Geliefert</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</p>
|
||||||
|
<div class="d-grid gap-2 mt-4">
|
||||||
|
@if (!Model.IsClosed && Model.CreatorName == User.Identity?.Name)
|
||||||
|
{
|
||||||
|
<a href="/order/close?code=@Model.OrderCode" class="btn btn-warning">@Localizer.Get("CloseOrder")</a>
|
||||||
|
}
|
||||||
|
@if (Model.IsClosed && !Model.IsCompleted && Model.CreatorName == User.Identity?.Name)
|
||||||
|
{
|
||||||
|
<a href="/order/complete?code=@Model.OrderCode" class="btn btn-success">@Localizer.Get("MarkCompleted")</a>
|
||||||
|
}
|
||||||
|
@if (Model.IsCompleted)
|
||||||
|
{
|
||||||
|
<button class="btn btn-success" disabled>@Localizer.Get("Completed")</button>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -117,15 +150,6 @@
|
|||||||
<p>@Localizer.Get("TotalRevenue"): <strong>@Localizer["Currency", Model.OrderItems.Sum(oi => oi.MenuItem.Price * oi.Quantity).ToString("F2")]</strong></p>
|
<p>@Localizer.Get("TotalRevenue"): <strong>@Localizer["Currency", Model.OrderItems.Sum(oi => oi.MenuItem.Price * oi.Quantity).ToString("F2")]</strong></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@if (!Model.IsClosed)
|
|
||||||
{
|
|
||||||
<a href="/order/close?code=@Model.OrderCode" class="btn btn-danger w-100">@Localizer.Get("CloseOrder")</a>
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
<div class="alert alert-danger w-100">@Localizer.Get("Closed")</div>
|
|
||||||
}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -38,16 +38,6 @@
|
|||||||
<form method="post" action="/order/additem">
|
<form method="post" action="/order/additem">
|
||||||
<input type="hidden" name="orderId" value="@Model.Id">
|
<input type="hidden" name="orderId" value="@Model.Id">
|
||||||
|
|
||||||
<div class="mb-3">
|
|
||||||
<label for="participantName" class="form-label">@Localizer["YourName"]</label>
|
|
||||||
<input type="text" class="form-control" id="participantName" name="participantName" placeholder="@Localizer["EnterYourName"]" required>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mb-3">
|
|
||||||
<label for="participantEmail" class="form-label">@Localizer["YourEmail"]</label>
|
|
||||||
<input type="email" class="form-control" id="participantEmail" name="participantEmail" placeholder="@Localizer["EnterYourEmail"]">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="menuItemId" class="form-label">@Localizer["SelectItem"]</label>
|
<label for="menuItemId" class="form-label">@Localizer["SelectItem"]</label>
|
||||||
<select class="form-select" id="menuItemId" name="menuItemId" required onchange="updatePrice()">
|
<select class="form-select" id="menuItemId" name="menuItemId" required onchange="updatePrice()">
|
||||||
|
|||||||
Reference in New Issue
Block a user