Files
meezi/src/Meezi.Infrastructure/Data/DevelopmentDataSeeder.cs
T
2026-05-29 10:18:47 +03:30

404 lines
14 KiB
C#

using Meezi.Core.Branding;
using Meezi.Core.Discover;
using Meezi.Core.Entities;
using Meezi.Core.Enums;
using Meezi.Infrastructure.Branding;
using Meezi.Infrastructure.Discover;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
namespace Meezi.Infrastructure.Data;
public static class DevelopmentDataSeeder
{
public static async Task SeedAsync(IServiceProvider services)
{
var env = services.GetRequiredService<IHostEnvironment>();
if (!env.IsDevelopment())
return;
var logger = services.GetRequiredService<ILoggerFactory>().CreateLogger("DevelopmentDataSeeder");
await using var scope = services.CreateAsyncScope();
var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
var cafe = await db.Cafes.FirstOrDefaultAsync(c => c.Slug == "demo-cafe");
if (cafe is null)
{
cafe = new Cafe
{
Id = "cafe_demo_001",
Name = "کافه دمو",
NameEn = "Demo Cafe",
Slug = "demo-cafe",
City = "تهران",
Address = "تهران، خیابان ولیعصر",
Description = "کافه دمو میزی — مناسب کار، میهمانی و قهوه تخصصی.",
PlanTier = PlanTier.Pro,
PreferredLanguage = "fa",
IsVerified = true,
SnappfoodVendorId = "demo_vendor"
};
var owner = new Employee
{
Id = "emp_demo_owner",
CafeId = cafe.Id,
BranchId = "branch_demo_main",
Name = "مدیر دمو",
Phone = "09212273138",
Role = EmployeeRole.Owner,
BaseSalary = 0
};
db.Cafes.Add(cafe);
db.Employees.Add(owner);
await db.SaveChangesAsync();
logger.LogInformation("Development seed: cafe slug={Slug}, owner phone={Phone}", cafe.Slug, owner.Phone);
}
else if (string.IsNullOrEmpty(cafe.SnappfoodVendorId))
{
cafe.SnappfoodVendorId = "demo_vendor";
await db.SaveChangesAsync();
}
if (string.IsNullOrEmpty(cafe.ThemeJson))
{
cafe.ThemeJson = CafeThemeSerializer.Serialize(new CafeTheme
{
PaletteId = CafeThemeDefaults.PaletteMeeziGreen,
PanelStyle = CafeThemeDefaults.PanelModern,
MenuStyle = CafeThemeDefaults.MenuCards,
Density = CafeThemeDefaults.DensityComfortable,
Radius = CafeThemeDefaults.RadiusMd
});
await db.SaveChangesAsync();
}
if (string.IsNullOrEmpty(cafe.DiscoverProfileJson))
{
cafe.DiscoverProfileJson = CafeDiscoverProfileSerializer.Serialize(new CafeDiscoverProfile
{
Themes = ["modern", "plants_heavy"],
Size = "cozy",
Vibes = ["quiet", "cozy"],
Occasions = ["date", "friends", "study_work"],
SpaceFeatures = ["indoor", "wifi", "plants"],
NoiseLevel = "quiet",
PriceTier = "mid"
});
await db.SaveChangesAsync();
}
await SeedDemoReviewsAsync(db, cafe.Id, logger);
await SeedDemoBranchAsync(db, cafe.Id, logger);
await SeedDemoOpenShiftsAsync(db, cafe.Id, logger);
var ownerEmp = await db.Employees.FirstOrDefaultAsync(e => e.Id == "emp_demo_owner");
if (ownerEmp is not null)
{
var changed = false;
if (ownerEmp.BranchId is null) { ownerEmp.BranchId = "branch_demo_main"; changed = true; }
if (ownerEmp.Phone != "09212273138") { ownerEmp.Phone = "09212273138"; changed = true; }
if (changed) await db.SaveChangesAsync();
}
await DemoEmployeesSeeder.EnsureEmployeesAsync(db, cafe.Id, logger);
const string taxId = "tax_demo_vat";
await DemoMenuSeeder.EnsureMenuAsync(db, cafe.Id, taxId, logger);
await SeedDemoInventoryAsync(db, cafe.Id, logger);
await DemoCouponSeeder.EnsureCouponsAsync(db, cafe.Id, logger);
await SeedDemoTablesAsync(db, cafe.Id, logger);
if (!await db.EmployeeSchedules.AnyAsync(s => s.EmployeeId == "emp_demo_owner"))
{
for (var day = 0; day <= 6; day++)
{
db.EmployeeSchedules.Add(new EmployeeSchedule
{
EmployeeId = "emp_demo_owner",
DayOfWeek = day,
ShiftType = day is 5 ? ShiftType.DayOff : ShiftType.Morning
});
}
var monthYear = DateTime.UtcNow.ToString("yyyy-MM");
db.EmployeeSalaries.Add(new EmployeeSalary
{
EmployeeId = "emp_demo_owner",
MonthYear = monthYear,
BaseSalary = 25_000_000,
OvertimePay = 0,
Deductions = 0,
NetSalary = 25_000_000,
IsPaid = false
});
await db.SaveChangesAsync();
logger.LogInformation("Development HR seed for cafe {CafeId}", cafe.Id);
}
await SeedDemoOrdersAsync(db, cafe.Id, logger);
await DiscoverShowcaseSeeder.SeedAsync(db, logger);
}
private static async Task SeedDemoBranchAsync(AppDbContext db, string cafeId, ILogger logger)
{
const string branchId = "branch_demo_main";
if (!await db.Branches.AnyAsync(b => b.Id == branchId))
{
var now = DateTime.UtcNow;
db.Branches.Add(new Branch
{
Id = branchId,
CafeId = cafeId,
Name = "شعبه اصلی",
City = "تهران",
Address = "تهران، خیابان ولیعصر",
Phone = "02112345678",
IsActive = true,
CreatedAt = now,
UpdatedAt = now
});
await db.SaveChangesAsync();
logger.LogInformation("Development branch seed: {BranchId}", branchId);
}
}
private static async Task SeedDemoOpenShiftsAsync(AppDbContext db, string cafeId, ILogger logger)
{
const string ownerId = "emp_demo_owner";
var branchIds = await db.Branches
.Where(b => b.CafeId == cafeId && b.IsActive)
.Select(b => b.Id)
.ToListAsync();
var added = false;
foreach (var branchId in branchIds)
{
var hasOpen = await db.RegisterShifts.AnyAsync(
s => s.CafeId == cafeId && s.BranchId == branchId && s.Status == ShiftStatus.Open);
if (hasOpen)
continue;
db.RegisterShifts.Add(new Shift
{
Id = $"shift_open_{branchId}",
CafeId = cafeId,
BranchId = branchId,
OpenedByUserId = ownerId,
OpenedAt = DateTime.UtcNow,
OpeningCash = 0,
ExpectedCash = 0,
Status = ShiftStatus.Open
});
added = true;
}
if (added)
{
await db.SaveChangesAsync();
logger.LogInformation("Development open-shift seed for cafe {CafeId}", cafeId);
}
}
private static async Task SeedDemoInventoryAsync(AppDbContext db, string cafeId, ILogger logger)
{
if (await db.Ingredients.AnyAsync(i => i.CafeId == cafeId))
return;
db.Ingredients.AddRange(
new Ingredient
{
Id = "ing_demo_milk",
CafeId = cafeId,
Name = "شیر",
Unit = "میلی‌لیتر",
QuantityOnHand = 12000,
ReorderLevel = 2000,
ParLevel = 12000,
UnitCost = 80,
LowStockWarningPercent = 20
},
new Ingredient
{
Id = "ing_demo_coffee",
CafeId = cafeId,
Name = "پودر قهوه",
Unit = "گرم",
QuantityOnHand = 500,
ReorderLevel = 100,
ParLevel = 500,
UnitCost = 12,
LowStockWarningPercent = 20
},
new Ingredient
{
Id = "ing_demo_cups",
CafeId = cafeId,
Name = "لیوان یکبارمصرف",
Unit = "عدد",
QuantityOnHand = 80,
ReorderLevel = 20,
ParLevel = 100,
UnitCost = 500,
LowStockWarningPercent = 20
});
await db.SaveChangesAsync();
var espresso = await db.MenuItems
.FirstOrDefaultAsync(m => m.CafeId == cafeId && m.Name.Contains("اسپرسو"));
if (espresso is not null)
{
db.MenuItemIngredients.AddRange(
new MenuItemIngredient
{
Id = "mii_demo_espresso_coffee",
CafeId = cafeId,
MenuItemId = espresso.Id,
IngredientId = "ing_demo_coffee",
QuantityPerUnit = 10
},
new MenuItemIngredient
{
Id = "mii_demo_espresso_cup",
CafeId = cafeId,
MenuItemId = espresso.Id,
IngredientId = "ing_demo_cups",
QuantityPerUnit = 1
});
await db.SaveChangesAsync();
}
logger.LogInformation("Development inventory seed for cafe {CafeId}", cafeId);
}
private static async Task SeedDemoTablesAsync(AppDbContext db, string cafeId, ILogger logger)
{
var specs = new (string Id, string Number, int Capacity, string? Floor, string? QrCode)[]
{
("table_demo_1", "1", 4, "همکف", "demo_table_01"),
("table_demo_2", "2", 2, "همکف", null),
("table_demo_3", "3", 4, "همکف", null),
("table_demo_4", "4", 6, "بالکن", null),
("table_demo_5", "5", 4, "بالکن", null),
("table_demo_6", "6", 2, "بالکن", null),
("table_demo_7", "7", 8, "سالن VIP", null),
("table_demo_8", "8", 4, "سالن VIP", null),
};
foreach (var s in specs)
{
if (await db.Tables.AnyAsync(t => t.Id == s.Id))
continue;
db.Tables.Add(new Table
{
Id = s.Id,
CafeId = cafeId,
BranchId = "branch_demo_main",
Number = s.Number,
Capacity = s.Capacity,
Floor = s.Floor,
QrCode = s.QrCode ?? Guid.NewGuid().ToString("N"),
IsActive = true
});
}
await db.SaveChangesAsync();
logger.LogInformation("Development tables seed (8 tables, QR: demo_table_01) for cafe {CafeId}", cafeId);
}
private static async Task SeedDemoReviewsAsync(AppDbContext db, string cafeId, ILogger logger)
{
if (await db.CafeReviews.AnyAsync(r => r.CafeId == cafeId))
return;
db.CafeReviews.AddRange(
new CafeReview
{
CafeId = cafeId,
AuthorName = "سارا",
Rating = 5,
Comment = "قهوه و فضا عالی بود.",
CreatedAt = DateTime.UtcNow.AddDays(-3)
},
new CafeReview
{
CafeId = cafeId,
AuthorName = "علی",
Rating = 4,
Comment = "سرویس سریع، کیک خوشمزه.",
CreatedAt = DateTime.UtcNow.AddDays(-1)
});
await db.SaveChangesAsync();
logger.LogInformation("Development reviews seed for cafe {CafeId}", cafeId);
}
private static async Task SeedDemoOrdersAsync(AppDbContext db, string cafeId, ILogger logger)
{
if (await db.Orders.AnyAsync(o => o.CafeId == cafeId))
return;
var latte = await db.MenuItems.FirstOrDefaultAsync(m => m.Id == "item_demo_latte");
var cake = await db.MenuItems.FirstOrDefaultAsync(m => m.Id == "item_demo_cake");
if (latte is null || cake is null)
return;
var customer = new Customer
{
Id = "cust_demo_reports",
CafeId = cafeId,
Name = "مشتری گزارش",
Phone = "09120000001",
Group = CustomerGroup.Regular,
CreatedAt = DateTime.UtcNow.AddDays(-10)
};
db.Customers.Add(customer);
for (var i = 0; i < 7; i++)
{
var createdAt = DateTime.UtcNow.AddDays(-i).AddHours(-2);
var subtotal = 215_000m;
var tax = Math.Round(subtotal * 0.09m, 0);
var order = new Order
{
Id = $"order_demo_{i}",
CafeId = cafeId,
CustomerId = i % 2 == 0 ? customer.Id : null,
OrderType = OrderType.DineIn,
Status = OrderStatus.Delivered,
DisplayNumber = i + 1,
Subtotal = subtotal,
TaxTotal = tax,
DiscountAmount = i == 0 ? 15_000m : 0,
Total = subtotal + tax - (i == 0 ? 15_000m : 0),
CreatedAt = createdAt
};
db.Orders.Add(order);
db.OrderItems.AddRange(
new OrderItem
{
OrderId = order.Id,
MenuItemId = latte.Id,
Quantity = 1,
UnitPrice = latte.Price
},
new OrderItem
{
OrderId = order.Id,
MenuItemId = cake.Id,
Quantity = 1,
UnitPrice = cake.Price
});
}
await db.SaveChangesAsync();
logger.LogInformation("Development reports seed: 7 demo orders for cafe {CafeId}", cafeId);
}
}