namespace Admin.NET.Plugin.AiDOP.Infrastructure.S8;
///
/// S8-CFG-NOTIFY-NONDEFAULT-ROLE-OPTIONS-FIX-1:S8 业务角色的 **canonical 定义(唯一来源)**。
///
/// 身份模型(本批锁定):
/// SysRole.Code = **逻辑身份**,跨租户稳定;
/// SysRole.Id = **租户本地物理身份**,同一个 Code 在每个租户都有各自不同的 Id。
/// 因此任何「按角色找行」的逻辑都必须**按 Code 在可信租户作用域内查**,
/// 绝不能按写死的物理 Id 去找——那等于假设所有租户共用默认租户那一份角色行。
///
/// 为什么需要这个文件:这 7 个角色此前在仓内被**逐字复制了两份**
/// (S8SysRoleSeedData 种默认租户、AidopTenantInitService 按租户复制),
/// 内容恰好一致纯属人工同步。再在第三处(role-options)复制一份必然分叉,
/// 所以本文件把两份合并为一份,两个既有定义改为引用它。
///
/// ⚠️ 不含 sys_admin:那是平台系统管理员角色(默认租户 `系统管理员`),
/// 既不在上述任一 S8 角色定义里,也不被任何一条生效通知层引用
/// (14 条 GLOBAL 层只引用下列 Code 中的 5 个)。仓内唯一出现 sys_admin 的通知层
/// 属于另一个租户的 legacy demo 行,且其 scene 是已被禁止新建的非规范场景。
/// 故它**不是** S8 业务角色,不应出现在租户的 CFG_NOTIFY 角色候选里。
///
public static class S8CanonicalRole
{
///
/// S8 七个业务角色(异常协同承接)。
/// OrderNo 同时是**产品展示顺序**——产品顺序不得由数据库物理 Id 决定,
/// 否则同一份配置在不同租户会呈现不同排序。
///
public static readonly (string Code, string Name, int OrderNo)[] BusinessRoles =
{
("ROLE_ORDER_PLANNER", "订单计划员", 800),
("ROLE_PRODUCTION_PLANNER", "生产计划员", 801),
("ROLE_PURCHASER", "采购员", 802),
("ROLE_WH_INBOUND", "仓库收货员", 803),
("ROLE_WH_OUTBOUND", "仓库发货员", 804),
("ROLE_QC", "质检员", 805),
("ROLE_EQUIP_MAINT", "设备维修员", 806),
};
/// canonical 业务角色 Code 白名单(候选集合的**唯一**筛选依据)。
public static readonly string[] BusinessRoleCodes = Array.ConvertAll(BusinessRoles, x => x.Code);
///
/// canonical 展示序。未知 Code 排到末尾而不是抛错——
/// 排序不是校验入口,不该因为出现一个陌生 Code 就让整个下拉挂掉。
///
public static int OrderOf(string? code)
{
foreach (var r in BusinessRoles)
if (string.Equals(r.Code, code, StringComparison.Ordinal)) return r.OrderNo;
return int.MaxValue;
}
}