404 lines
14 KiB
C#
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);
|
|
}
|
|
}
|