feat(menu): per-item print station (cold bar / kitchen / barista)
CI/CD / CI · API (dotnet build + test) (push) Successful in 41s
CI/CD / CI · Admin API (dotnet build) (push) Successful in 29s
CI/CD / CI · Dashboard (tsc) (push) Successful in 1m6s
CI/CD / CI · Admin Web (tsc) (push) Successful in 38s
CI/CD / CI · Website (tsc) (push) Successful in 45s
CI/CD / CI · Koja (tsc) (push) Successful in 49s
CI/CD / Deploy · all services (push) Successful in 3m28s
CI/CD / CI · API (dotnet build + test) (push) Successful in 41s
CI/CD / CI · Admin API (dotnet build) (push) Successful in 29s
CI/CD / CI · Dashboard (tsc) (push) Successful in 1m6s
CI/CD / CI · Admin Web (tsc) (push) Successful in 38s
CI/CD / CI · Website (tsc) (push) Successful in 45s
CI/CD / CI · Koja (tsc) (push) Successful in 49s
CI/CD / Deploy · all services (push) Successful in 3m28s
Each menu item can now pick its own print station, overriding the category's — so a category can fan out to different printers (e.g. a drink → cold bar, a food → kitchen). Adds MenuItem.KitchenStationId (+ migration, FK SetNull), wires create/update/DTO, and updates kitchen-ticket routing to group by the item's station ?? the category's station ?? the branch kitchen printer. Deleting a station now also clears item assignments. Menu item editor gains a "Print station" dropdown (default = "same as category"). fa/en/ar added. Backend built clean via the Nexus mirror; migration applies on deploy (MigrateAsync). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -55,7 +55,8 @@ public record MenuItemDto(
|
|||||||
string? ImageUrl,
|
string? ImageUrl,
|
||||||
string? VideoUrl,
|
string? VideoUrl,
|
||||||
string? Model3dUrl,
|
string? Model3dUrl,
|
||||||
bool IsAvailable);
|
bool IsAvailable,
|
||||||
|
string? KitchenStationId);
|
||||||
|
|
||||||
public record CreateMenuItemRequest(
|
public record CreateMenuItemRequest(
|
||||||
string CategoryId,
|
string CategoryId,
|
||||||
@@ -68,7 +69,8 @@ public record CreateMenuItemRequest(
|
|||||||
string? ImageUrl = null,
|
string? ImageUrl = null,
|
||||||
string? VideoUrl = null,
|
string? VideoUrl = null,
|
||||||
string? Model3dUrl = null,
|
string? Model3dUrl = null,
|
||||||
bool IsAvailable = true);
|
bool IsAvailable = true,
|
||||||
|
string? KitchenStationId = null);
|
||||||
|
|
||||||
public record UpdateMenuItemRequest(
|
public record UpdateMenuItemRequest(
|
||||||
string? CategoryId,
|
string? CategoryId,
|
||||||
@@ -81,6 +83,7 @@ public record UpdateMenuItemRequest(
|
|||||||
string? ImageUrl,
|
string? ImageUrl,
|
||||||
string? VideoUrl,
|
string? VideoUrl,
|
||||||
string? Model3dUrl,
|
string? Model3dUrl,
|
||||||
bool? IsAvailable);
|
bool? IsAvailable,
|
||||||
|
string? KitchenStationId);
|
||||||
|
|
||||||
public record UpdateMenuItemAvailabilityRequest(bool IsAvailable);
|
public record UpdateMenuItemAvailabilityRequest(bool IsAvailable);
|
||||||
|
|||||||
@@ -114,6 +114,12 @@ public class KitchenStationService : IKitchenStationService
|
|||||||
foreach (var cat in categories)
|
foreach (var cat in categories)
|
||||||
cat.KitchenStationId = null;
|
cat.KitchenStationId = null;
|
||||||
|
|
||||||
|
var items = await _db.MenuItems
|
||||||
|
.Where(i => i.KitchenStationId == id && i.CafeId == cafeId)
|
||||||
|
.ToListAsync(ct);
|
||||||
|
foreach (var item in items)
|
||||||
|
item.KitchenStationId = null;
|
||||||
|
|
||||||
entity.DeletedAt = DateTime.UtcNow;
|
entity.DeletedAt = DateTime.UtcNow;
|
||||||
await _db.SaveChangesAsync(ct);
|
await _db.SaveChangesAsync(ct);
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -139,7 +139,8 @@ public class MenuService : IMenuService
|
|||||||
ImageUrl = imageUrl,
|
ImageUrl = imageUrl,
|
||||||
VideoUrl = request.VideoUrl,
|
VideoUrl = request.VideoUrl,
|
||||||
Model3dUrl = NormalizeOptionalText(request.Model3dUrl),
|
Model3dUrl = NormalizeOptionalText(request.Model3dUrl),
|
||||||
IsAvailable = request.IsAvailable
|
IsAvailable = request.IsAvailable,
|
||||||
|
KitchenStationId = string.IsNullOrWhiteSpace(request.KitchenStationId) ? null : request.KitchenStationId,
|
||||||
};
|
};
|
||||||
|
|
||||||
_db.MenuItems.Add(entity);
|
_db.MenuItems.Add(entity);
|
||||||
@@ -178,6 +179,8 @@ public class MenuService : IMenuService
|
|||||||
if (request.Model3dUrl is not null)
|
if (request.Model3dUrl is not null)
|
||||||
entity.Model3dUrl = string.IsNullOrWhiteSpace(request.Model3dUrl) ? null : request.Model3dUrl.Trim();
|
entity.Model3dUrl = string.IsNullOrWhiteSpace(request.Model3dUrl) ? null : request.Model3dUrl.Trim();
|
||||||
if (request.IsAvailable.HasValue) entity.IsAvailable = request.IsAvailable.Value;
|
if (request.IsAvailable.HasValue) entity.IsAvailable = request.IsAvailable.Value;
|
||||||
|
if (request.KitchenStationId is not null)
|
||||||
|
entity.KitchenStationId = string.IsNullOrWhiteSpace(request.KitchenStationId) ? null : request.KitchenStationId;
|
||||||
|
|
||||||
await _db.SaveChangesAsync(cancellationToken);
|
await _db.SaveChangesAsync(cancellationToken);
|
||||||
return ToItemDto(entity);
|
return ToItemDto(entity);
|
||||||
@@ -236,5 +239,6 @@ public class MenuService : IMenuService
|
|||||||
MenuItemImageDefaults.ResolveDisplayImageUrl(i),
|
MenuItemImageDefaults.ResolveDisplayImageUrl(i),
|
||||||
i.VideoUrl,
|
i.VideoUrl,
|
||||||
i.Model3dUrl,
|
i.Model3dUrl,
|
||||||
i.IsAvailable);
|
i.IsAvailable,
|
||||||
|
i.KitchenStationId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -76,15 +76,16 @@ public class NetworkPrinterService : IPrinterService
|
|||||||
return PrintResult.Ok();
|
return PrintResult.Ok();
|
||||||
|
|
||||||
var menuItemIds = activeItems.Select(i => i.MenuItemId).Distinct().ToList();
|
var menuItemIds = activeItems.Select(i => i.MenuItemId).Distinct().ToList();
|
||||||
var categoryStations = await (
|
// Per-item station overrides the category's station; fall back to category.
|
||||||
|
var itemStations = await (
|
||||||
from m in _db.MenuItems.AsNoTracking()
|
from m in _db.MenuItems.AsNoTracking()
|
||||||
join c in _db.MenuCategories.AsNoTracking() on m.CategoryId equals c.Id
|
join c in _db.MenuCategories.AsNoTracking() on m.CategoryId equals c.Id
|
||||||
where menuItemIds.Contains(m.Id) && m.CafeId == cafeId
|
where menuItemIds.Contains(m.Id) && m.CafeId == cafeId
|
||||||
select new { m.Id, c.KitchenStationId }
|
select new { m.Id, StationId = m.KitchenStationId ?? c.KitchenStationId }
|
||||||
).ToListAsync(ct);
|
).ToListAsync(ct);
|
||||||
|
|
||||||
var stationIds = categoryStations
|
var stationIds = itemStations
|
||||||
.Select(x => x.KitchenStationId)
|
.Select(x => x.StationId)
|
||||||
.Where(id => !string.IsNullOrEmpty(id))
|
.Where(id => !string.IsNullOrEmpty(id))
|
||||||
.Distinct()
|
.Distinct()
|
||||||
.ToList();
|
.ToList();
|
||||||
@@ -99,8 +100,8 @@ public class NetworkPrinterService : IPrinterService
|
|||||||
var groups = activeItems
|
var groups = activeItems
|
||||||
.GroupBy(item =>
|
.GroupBy(item =>
|
||||||
{
|
{
|
||||||
var cat = categoryStations.FirstOrDefault(c => c.Id == item.MenuItemId);
|
var map = itemStations.FirstOrDefault(c => c.Id == item.MenuItemId);
|
||||||
return cat?.KitchenStationId;
|
return map?.StationId;
|
||||||
})
|
})
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
|
|||||||
@@ -12,4 +12,5 @@ public class KitchenStation : TenantEntity
|
|||||||
public Cafe Cafe { get; set; } = null!;
|
public Cafe Cafe { get; set; } = null!;
|
||||||
public Branch? Branch { get; set; }
|
public Branch? Branch { get; set; }
|
||||||
public ICollection<MenuCategory> Categories { get; set; } = [];
|
public ICollection<MenuCategory> Categories { get; set; } = [];
|
||||||
|
public ICollection<MenuItem> MenuItems { get; set; } = [];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,9 +15,13 @@ public class MenuItem : TenantEntity
|
|||||||
/// <summary>GLB/GLTF 3D model for QR menu interactive view (poster = ImageUrl).</summary>
|
/// <summary>GLB/GLTF 3D model for QR menu interactive view (poster = ImageUrl).</summary>
|
||||||
public string? Model3dUrl { get; set; }
|
public string? Model3dUrl { get; set; }
|
||||||
public bool IsAvailable { get; set; } = true;
|
public bool IsAvailable { get; set; } = true;
|
||||||
|
/// <summary>Optional per-item print station (cold bar, kitchen, barista …).
|
||||||
|
/// Overrides the item's category station when set.</summary>
|
||||||
|
public string? KitchenStationId { get; set; }
|
||||||
|
|
||||||
public Cafe Cafe { get; set; } = null!;
|
public Cafe Cafe { get; set; } = null!;
|
||||||
public MenuCategory Category { get; set; } = null!;
|
public MenuCategory Category { get; set; } = null!;
|
||||||
|
public KitchenStation? KitchenStation { get; set; }
|
||||||
public ICollection<OrderItem> OrderItems { get; set; } = [];
|
public ICollection<OrderItem> OrderItems { get; set; } = [];
|
||||||
public ICollection<BranchMenuItemOverride> BranchOverrides { get; set; } = [];
|
public ICollection<BranchMenuItemOverride> BranchOverrides { get; set; } = [];
|
||||||
public ICollection<MenuItemIngredient> RecipeIngredients { get; set; } = [];
|
public ICollection<MenuItemIngredient> RecipeIngredients { get; set; } = [];
|
||||||
|
|||||||
@@ -271,6 +271,7 @@ public class AppDbContext : DbContext
|
|||||||
e.Property(x => x.Price).HasPrecision(18, 2);
|
e.Property(x => x.Price).HasPrecision(18, 2);
|
||||||
e.HasOne(x => x.Cafe).WithMany(c => c.MenuItems).HasForeignKey(x => x.CafeId).OnDelete(DeleteBehavior.Cascade);
|
e.HasOne(x => x.Cafe).WithMany(c => c.MenuItems).HasForeignKey(x => x.CafeId).OnDelete(DeleteBehavior.Cascade);
|
||||||
e.HasOne(x => x.Category).WithMany(c => c.MenuItems).HasForeignKey(x => x.CategoryId).OnDelete(DeleteBehavior.Cascade);
|
e.HasOne(x => x.Category).WithMany(c => c.MenuItems).HasForeignKey(x => x.CategoryId).OnDelete(DeleteBehavior.Cascade);
|
||||||
|
e.HasOne(x => x.KitchenStation).WithMany(s => s.MenuItems).HasForeignKey(x => x.KitchenStationId).OnDelete(DeleteBehavior.SetNull);
|
||||||
e.HasQueryFilter(x => x.DeletedAt == null);
|
e.HasQueryFilter(x => x.DeletedAt == null);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Generated
+3511
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,49 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Meezi.Infrastructure.Data.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class AddMenuItemKitchenStation : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "KitchenStationId",
|
||||||
|
table: "MenuItems",
|
||||||
|
type: "text",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_MenuItems_KitchenStationId",
|
||||||
|
table: "MenuItems",
|
||||||
|
column: "KitchenStationId");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_MenuItems_KitchenStations_KitchenStationId",
|
||||||
|
table: "MenuItems",
|
||||||
|
column: "KitchenStationId",
|
||||||
|
principalTable: "KitchenStations",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.SetNull);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_MenuItems_KitchenStations_KitchenStationId",
|
||||||
|
table: "MenuItems");
|
||||||
|
|
||||||
|
migrationBuilder.DropIndex(
|
||||||
|
name: "IX_MenuItems_KitchenStationId",
|
||||||
|
table: "MenuItems");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "KitchenStationId",
|
||||||
|
table: "MenuItems");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -707,6 +707,46 @@ namespace Meezi.Infrastructure.Data.Migrations
|
|||||||
b.ToTable("Coupons");
|
b.ToTable("Coupons");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Meezi.Core.Entities.CustomRole", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("Id")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("CafeId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Color")
|
||||||
|
.HasMaxLength(20)
|
||||||
|
.HasColumnType("character varying(20)");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DeletedAt")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<string>("Description")
|
||||||
|
.HasMaxLength(500)
|
||||||
|
.HasColumnType("character varying(500)");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(100)
|
||||||
|
.HasColumnType("character varying(100)");
|
||||||
|
|
||||||
|
b.Property<string>("PermissionsJson")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(2000)
|
||||||
|
.HasColumnType("character varying(2000)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("CafeId");
|
||||||
|
|
||||||
|
b.ToTable("CustomRoles");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Meezi.Core.Entities.Customer", b =>
|
modelBuilder.Entity("Meezi.Core.Entities.Customer", b =>
|
||||||
{
|
{
|
||||||
b.Property<string>("Id")
|
b.Property<string>("Id")
|
||||||
@@ -928,46 +968,6 @@ namespace Meezi.Infrastructure.Data.Migrations
|
|||||||
b.ToTable("DemoRequests");
|
b.ToTable("DemoRequests");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Meezi.Core.Entities.CustomRole", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("Id")
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<string>("CafeId")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<string>("Color")
|
|
||||||
.HasMaxLength(20)
|
|
||||||
.HasColumnType("character varying(20)");
|
|
||||||
|
|
||||||
b.Property<DateTime>("CreatedAt")
|
|
||||||
.HasColumnType("timestamp with time zone");
|
|
||||||
|
|
||||||
b.Property<DateTime?>("DeletedAt")
|
|
||||||
.HasColumnType("timestamp with time zone");
|
|
||||||
|
|
||||||
b.Property<string>("Description")
|
|
||||||
.HasMaxLength(500)
|
|
||||||
.HasColumnType("character varying(500)");
|
|
||||||
|
|
||||||
b.Property<string>("Name")
|
|
||||||
.IsRequired()
|
|
||||||
.HasMaxLength(100)
|
|
||||||
.HasColumnType("character varying(100)");
|
|
||||||
|
|
||||||
b.Property<string>("PermissionsJson")
|
|
||||||
.IsRequired()
|
|
||||||
.HasMaxLength(2000)
|
|
||||||
.HasColumnType("character varying(2000)");
|
|
||||||
|
|
||||||
b.HasKey("Id");
|
|
||||||
|
|
||||||
b.HasIndex("CafeId");
|
|
||||||
|
|
||||||
b.ToTable("CustomRoles");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Meezi.Core.Entities.Employee", b =>
|
modelBuilder.Entity("Meezi.Core.Entities.Employee", b =>
|
||||||
{
|
{
|
||||||
b.Property<string>("Id")
|
b.Property<string>("Id")
|
||||||
@@ -1516,6 +1516,9 @@ namespace Meezi.Infrastructure.Data.Migrations
|
|||||||
b.Property<bool>("IsAvailable")
|
b.Property<bool>("IsAvailable")
|
||||||
.HasColumnType("boolean");
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
|
b.Property<string>("KitchenStationId")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
b.Property<string>("Model3dUrl")
|
b.Property<string>("Model3dUrl")
|
||||||
.HasMaxLength(500)
|
.HasMaxLength(500)
|
||||||
.HasColumnType("character varying(500)");
|
.HasColumnType("character varying(500)");
|
||||||
@@ -1543,6 +1546,8 @@ namespace Meezi.Infrastructure.Data.Migrations
|
|||||||
|
|
||||||
b.HasIndex("CategoryId");
|
b.HasIndex("CategoryId");
|
||||||
|
|
||||||
|
b.HasIndex("KitchenStationId");
|
||||||
|
|
||||||
b.ToTable("MenuItems");
|
b.ToTable("MenuItems");
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -2824,6 +2829,17 @@ namespace Meezi.Infrastructure.Data.Migrations
|
|||||||
b.Navigation("Cafe");
|
b.Navigation("Cafe");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Meezi.Core.Entities.CustomRole", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Meezi.Core.Entities.Cafe", "Cafe")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("CafeId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Cafe");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Meezi.Core.Entities.Customer", b =>
|
modelBuilder.Entity("Meezi.Core.Entities.Customer", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("Meezi.Core.Entities.Cafe", "Cafe")
|
b.HasOne("Meezi.Core.Entities.Cafe", "Cafe")
|
||||||
@@ -2857,17 +2873,6 @@ namespace Meezi.Infrastructure.Data.Migrations
|
|||||||
b.Navigation("Cafe");
|
b.Navigation("Cafe");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Meezi.Core.Entities.CustomRole", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("Meezi.Core.Entities.Cafe", "Cafe")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("CafeId")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired();
|
|
||||||
|
|
||||||
b.Navigation("Cafe");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Meezi.Core.Entities.Employee", b =>
|
modelBuilder.Entity("Meezi.Core.Entities.Employee", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("Meezi.Core.Entities.Branch", "Branch")
|
b.HasOne("Meezi.Core.Entities.Branch", "Branch")
|
||||||
@@ -3031,9 +3036,16 @@ namespace Meezi.Infrastructure.Data.Migrations
|
|||||||
.OnDelete(DeleteBehavior.Cascade)
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
.IsRequired();
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("Meezi.Core.Entities.KitchenStation", "KitchenStation")
|
||||||
|
.WithMany("MenuItems")
|
||||||
|
.HasForeignKey("KitchenStationId")
|
||||||
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
|
||||||
b.Navigation("Cafe");
|
b.Navigation("Cafe");
|
||||||
|
|
||||||
b.Navigation("Category");
|
b.Navigation("Category");
|
||||||
|
|
||||||
|
b.Navigation("KitchenStation");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Meezi.Core.Entities.MenuItemIngredient", b =>
|
modelBuilder.Entity("Meezi.Core.Entities.MenuItemIngredient", b =>
|
||||||
@@ -3401,16 +3413,16 @@ namespace Meezi.Infrastructure.Data.Migrations
|
|||||||
b.Navigation("Orders");
|
b.Navigation("Orders");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Meezi.Core.Entities.Customer", b =>
|
|
||||||
{
|
|
||||||
b.Navigation("Orders");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Meezi.Core.Entities.CustomRole", b =>
|
modelBuilder.Entity("Meezi.Core.Entities.CustomRole", b =>
|
||||||
{
|
{
|
||||||
b.Navigation("Employees");
|
b.Navigation("Employees");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Meezi.Core.Entities.Customer", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Orders");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Meezi.Core.Entities.Employee", b =>
|
modelBuilder.Entity("Meezi.Core.Entities.Employee", b =>
|
||||||
{
|
{
|
||||||
b.Navigation("Attendances");
|
b.Navigation("Attendances");
|
||||||
@@ -3436,6 +3448,8 @@ namespace Meezi.Infrastructure.Data.Migrations
|
|||||||
modelBuilder.Entity("Meezi.Core.Entities.KitchenStation", b =>
|
modelBuilder.Entity("Meezi.Core.Entities.KitchenStation", b =>
|
||||||
{
|
{
|
||||||
b.Navigation("Categories");
|
b.Navigation("Categories");
|
||||||
|
|
||||||
|
b.Navigation("MenuItems");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Meezi.Core.Entities.MenuCategory", b =>
|
modelBuilder.Entity("Meezi.Core.Entities.MenuCategory", b =>
|
||||||
|
|||||||
@@ -917,7 +917,8 @@
|
|||||||
"deleteItemSuccess": "تم حذف الصنف",
|
"deleteItemSuccess": "تم حذف الصنف",
|
||||||
"deleteCategoryConfirmTitle": "حذف الفئة",
|
"deleteCategoryConfirmTitle": "حذف الفئة",
|
||||||
"deleteCategoryConfirmDesc": "هل أنت متأكد من حذف الفئة «{name}»؟",
|
"deleteCategoryConfirmDesc": "هل أنت متأكد من حذف الفئة «{name}»؟",
|
||||||
"deleteCategorySuccess": "تم حذف الفئة"
|
"deleteCategorySuccess": "تم حذف الفئة",
|
||||||
|
"printStationInherit": "نفس الفئة"
|
||||||
},
|
},
|
||||||
"branchMenu": {
|
"branchMenu": {
|
||||||
"title": "قائمة الفرع",
|
"title": "قائمة الفرع",
|
||||||
|
|||||||
@@ -951,7 +951,8 @@
|
|||||||
"deleteItemSuccess": "Item deleted",
|
"deleteItemSuccess": "Item deleted",
|
||||||
"deleteCategoryConfirmTitle": "Delete category",
|
"deleteCategoryConfirmTitle": "Delete category",
|
||||||
"deleteCategoryConfirmDesc": "Are you sure you want to delete the “{name}” category?",
|
"deleteCategoryConfirmDesc": "Are you sure you want to delete the “{name}” category?",
|
||||||
"deleteCategorySuccess": "Category deleted"
|
"deleteCategorySuccess": "Category deleted",
|
||||||
|
"printStationInherit": "Same as category"
|
||||||
},
|
},
|
||||||
"branchMenu": {
|
"branchMenu": {
|
||||||
"title": "Branch Menu",
|
"title": "Branch Menu",
|
||||||
|
|||||||
@@ -951,7 +951,8 @@
|
|||||||
"deleteItemSuccess": "آیتم حذف شد",
|
"deleteItemSuccess": "آیتم حذف شد",
|
||||||
"deleteCategoryConfirmTitle": "حذف دستهبندی",
|
"deleteCategoryConfirmTitle": "حذف دستهبندی",
|
||||||
"deleteCategoryConfirmDesc": "آیا از حذف دسته «{name}» مطمئن هستید؟",
|
"deleteCategoryConfirmDesc": "آیا از حذف دسته «{name}» مطمئن هستید؟",
|
||||||
"deleteCategorySuccess": "دسته حذف شد"
|
"deleteCategorySuccess": "دسته حذف شد",
|
||||||
|
"printStationInherit": "مثل دستهٔ منو"
|
||||||
},
|
},
|
||||||
"branchMenu": {
|
"branchMenu": {
|
||||||
"title": "منوی شعبه",
|
"title": "منوی شعبه",
|
||||||
|
|||||||
@@ -73,6 +73,7 @@ interface MenuItem {
|
|||||||
videoUrl?: string;
|
videoUrl?: string;
|
||||||
model3dUrl?: string;
|
model3dUrl?: string;
|
||||||
isAvailable: boolean;
|
isAvailable: boolean;
|
||||||
|
kitchenStationId?: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ItemForm {
|
interface ItemForm {
|
||||||
@@ -84,6 +85,7 @@ interface ItemForm {
|
|||||||
imageUrl: string;
|
imageUrl: string;
|
||||||
videoUrl: string;
|
videoUrl: string;
|
||||||
model3dUrl: string;
|
model3dUrl: string;
|
||||||
|
kitchenStationId: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface CatForm {
|
interface CatForm {
|
||||||
@@ -114,6 +116,7 @@ const defaultItemForm: ItemForm = {
|
|||||||
imageUrl: "",
|
imageUrl: "",
|
||||||
videoUrl: "",
|
videoUrl: "",
|
||||||
model3dUrl: "",
|
model3dUrl: "",
|
||||||
|
kitchenStationId: "",
|
||||||
};
|
};
|
||||||
|
|
||||||
const defaultCatForm: CatForm = {
|
const defaultCatForm: CatForm = {
|
||||||
@@ -296,6 +299,7 @@ export function MenuAdminScreen() {
|
|||||||
imageUrl: itemForm.imageUrl || null,
|
imageUrl: itemForm.imageUrl || null,
|
||||||
videoUrl: itemForm.videoUrl || null,
|
videoUrl: itemForm.videoUrl || null,
|
||||||
model3dUrl: itemForm.model3dUrl || null,
|
model3dUrl: itemForm.model3dUrl || null,
|
||||||
|
kitchenStationId: itemForm.kitchenStationId || null,
|
||||||
}),
|
}),
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
setItemModalOpen(false);
|
setItemModalOpen(false);
|
||||||
@@ -314,6 +318,7 @@ export function MenuAdminScreen() {
|
|||||||
imageUrl: mediaField(itemForm.imageUrl),
|
imageUrl: mediaField(itemForm.imageUrl),
|
||||||
videoUrl: mediaField(itemForm.videoUrl),
|
videoUrl: mediaField(itemForm.videoUrl),
|
||||||
model3dUrl: mediaField(itemForm.model3dUrl),
|
model3dUrl: mediaField(itemForm.model3dUrl),
|
||||||
|
kitchenStationId: itemForm.kitchenStationId || null,
|
||||||
}),
|
}),
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
setItemModalOpen(false);
|
setItemModalOpen(false);
|
||||||
@@ -411,6 +416,7 @@ export function MenuAdminScreen() {
|
|||||||
imageUrl: item.imageUrl ?? "",
|
imageUrl: item.imageUrl ?? "",
|
||||||
videoUrl: item.videoUrl ?? "",
|
videoUrl: item.videoUrl ?? "",
|
||||||
model3dUrl: item.model3dUrl ?? "",
|
model3dUrl: item.model3dUrl ?? "",
|
||||||
|
kitchenStationId: item.kitchenStationId ?? "",
|
||||||
});
|
});
|
||||||
setItemModalOpen(true);
|
setItemModalOpen(true);
|
||||||
};
|
};
|
||||||
@@ -956,6 +962,26 @@ export function MenuAdminScreen() {
|
|||||||
) : null}
|
) : null}
|
||||||
</LabeledField>
|
</LabeledField>
|
||||||
|
|
||||||
|
{stations.length > 0 ? (
|
||||||
|
<LabeledField label={t("printStation")} htmlFor="modal-item-station">
|
||||||
|
<select
|
||||||
|
id="modal-item-station"
|
||||||
|
className="h-10 w-full rounded-md border border-input bg-background px-3 text-sm"
|
||||||
|
value={itemForm.kitchenStationId}
|
||||||
|
onChange={(e) =>
|
||||||
|
setItemForm((f) => ({ ...f, kitchenStationId: e.target.value }))
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<option value="">{t("printStationInherit")}</option>
|
||||||
|
{stations.map((s) => (
|
||||||
|
<option key={s.id} value={s.id}>
|
||||||
|
{s.name}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
</LabeledField>
|
||||||
|
) : null}
|
||||||
|
|
||||||
{/* Actions */}
|
{/* Actions */}
|
||||||
<div className="flex items-center justify-between gap-2 border-t border-border pt-4">
|
<div className="flex items-center justify-between gap-2 border-t border-border pt-4">
|
||||||
{editingItem ? (
|
{editingItem ? (
|
||||||
|
|||||||
Reference in New Issue
Block a user