| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107 |
- using Admin.NET.Plugin.AiDOP.DataPlatform;
- using Xunit;
- namespace Admin.NET.Plugin.AiDOP.Tests.DataPlatform;
- public class EmployeePositionRulesTests
- {
- [Theory]
- [InlineData("计划", "PLANNER")]
- [InlineData("仓管", "WAREHOUSE")]
- [InlineData("生产", "PRODUCTION")]
- [InlineData("成品仓", "WAREHOUSE")]
- [InlineData("库管员", "WAREHOUSE")]
- [InlineData("物料员", "WAREHOUSE")]
- [InlineData("WMS专员", "WAREHOUSE")]
- [InlineData("装配工", "PRODUCTION")]
- [InlineData("车间班长", "PRODUCTION")]
- [InlineData("PMC", "PLANNER")]
- [InlineData("调度员", "PLANNER")]
- [InlineData("财务", "UNKNOWN")]
- [InlineData("", "UNKNOWN")]
- [InlineData(null, "UNKNOWN")]
- // 165 的 EmployeeMaster.JobTitle 填的是小写英文,中文关键字一个都匹配不上。
- [InlineData("warehouse", "WAREHOUSE")]
- [InlineData("warehouse1", "WAREHOUSE")]
- [InlineData("Warehouse Clerk", "WAREHOUSE")]
- [InlineData("wms专员", "WAREHOUSE")]
- [InlineData("production", "PRODUCTION")]
- [InlineData("Assembly Operator", "PRODUCTION")]
- [InlineData("planner", "PLANNER")]
- // 已人工确认不属于三类业务岗,归 OTHER 而非 UNKNOWN,不再记 POSITION_UNMAPPED。
- [InlineData("quality", "OTHER")]
- [InlineData("QC检验员", "OTHER")]
- [InlineData("数据员", "OTHER")]
- [InlineData("研发工程师", "OTHER")]
- // OTHER 判定在三类业务岗之后,含「仓」仍归 WAREHOUSE。
- [InlineData("质量仓管", "WAREHOUSE")]
- public void Classify_ExactBeforeKeyword(string? raw, string expected)
- {
- Assert.Equal(expected, EmployeePositionRules.Classify(raw));
- }
- [Theory]
- [InlineData("WAREHOUSE", "WAREHOUSE")]
- [InlineData(" PLANNER ", "PLANNER")]
- // MySQL 默认排序规则不区分大小写,小写值不挡住就会绕过校验混进库里,故统一归一化为大写标准值。
- [InlineData("warehouse", "WAREHOUSE")]
- [InlineData("Other", "OTHER")]
- [InlineData("WAREHOUSE1", null)]
- [InlineData("WAREHOUS", null)]
- [InlineData("QUALITY", null)]
- [InlineData("", null)]
- [InlineData(null, null)]
- public void Normalize_OnlyAcceptsAllowedCodes(string? input, string? expected)
- {
- Assert.Equal(expected, EmployeePositionRules.Normalize(input));
- }
- /// <summary>岗位码白名单只有这五个:Classify 的全部返回值 + 人工可选值,与 KPI 的等值过滤口径对齐。</summary>
- [Fact]
- public void AllowedCodes_AreExactlyTheFiveNeutralCodes()
- {
- Assert.Equal(
- new[] { "WAREHOUSE", "PRODUCTION", "PLANNER", "OTHER", "UNKNOWN" },
- EmployeePositionRules.AllowedCodes);
- }
- /// <summary>人工保存必须经过白名单,否则写错的岗位码会变成永远匹配不上 KPI 过滤的死值。</summary>
- [Fact]
- public void SavePositions_ValidatesAgainstWhitelist()
- {
- var service = File.ReadAllText(FindFile(
- "server", "Plugins", "Admin.NET.Plugin.AiDOP", "DataPlatform", "MdpSourceMappingService.cs"));
- Assert.Contains("EmployeePositionRules.Normalize(row.PositionCode)", service);
- Assert.Contains("EmployeePositionRules.AllowedCodes", service);
- // 旧写法直接把前端传入值落库,不得复活。
- Assert.DoesNotContain("code = row.PositionCode.Trim()", service);
- }
- /// <summary>前端下拉选项与后端白名单必须一致,否则页面能选出后端拒收的值。</summary>
- [Fact]
- public void FrontendPositionCodeOptions_MatchAllowedCodes()
- {
- var vue = File.ReadAllText(FindFile(
- "Web", "src", "views", "aidop", "data-platform", "sourceMappings.vue"));
- var expected = "const positionCodes = ["
- + string.Join(", ", EmployeePositionRules.AllowedCodes.Select(code => $"'{code}'"))
- + "];";
- Assert.Contains(expected, vue);
- // 岗位码不得退回自由文本输入。
- Assert.DoesNotContain("<el-input v-model=\"row.positionCode\" />", vue);
- }
- private static string FindFile(params string[] parts)
- {
- var dir = new DirectoryInfo(AppContext.BaseDirectory);
- while (dir != null)
- {
- var candidate = Path.Combine(new[] { dir.FullName }.Concat(parts).ToArray());
- if (File.Exists(candidate)) return candidate;
- dir = dir.Parent;
- }
- throw new FileNotFoundException(string.Join('/', parts));
- }
- }
|