HR 类库把部分休假规则放入 LeavePolicySchedule,比把所有数字写死在方法里更进一步;但 Schedule 只表达六类字段,无法覆盖地方条件、法源版本、适用人群和完整生效历史。
1. LeavePolicySchedule 字段
| 字段 | 当前含义 |
|---|---|
| AnnualLeaveTiers | (MinWorkYears, Days) 列表 |
| MarriageDays | 婚假天数 |
| MaternityDays | 基础 + 地方延长后的总天数 |
| PaternityDays | 陪产/护理假天数 |
| BereavementDays | 丧假天数 |
| Region | 自由字符串 |
| EffectiveFrom | 生效日,缺省为 DateTime.Today |
没有 EffectiveTo、PolicyId/Version、Source URI/hash、PublishedAt、ApprovedBy、Employee category、birth order、difficult-labor increment、miscarriage rules 或 historical supersession。
2. 创建校验
Create 拒绝空 tiers、非严格升序的 MinWorkYears,以及四类假天数为负。它会复制 tier 数组,避免调用方后续修改原集合;ValueObject 原子值包含所有字段与 tiers。
// 显式传入生效日,避免使用随进程启动日期变化的默认值。var schedule = LeavePolicySchedule.Create( annualLeaveTiers: [(1, 5), (10, 10), (20, 15)], marriageDays: 3, maternityDays: 158, paternityDays: 15, bereavementDays: 3, region: "ExampleProvince", effectiveFrom: new DateOnly(2026, 1, 1));
// Create 只验证结构;调用方仍需证明这些数字来自已审核法源。if (schedule.IsFailure) return schedule.Error;return schedule.Value;MinWorkYears 和 tier Days 本身可以为负;Region 不 Trim,只在全空白时替换 National。没有最大 tier 数或天数上限。
3. 四个预置政策
LeavePolicies 暴露 National、Guangdong、Shanghai、Beijing,Default=National。静态初始化未传 EffectiveFrom,因此每个进程在启动当天创建快照。
这让相同程序集在不同日期生成不相等的值对象,而且日期不是法规生效日。预置注释称“截至 2024 年参考值”,不能在 2026 产品中被默认为当前有效。
4. 法定年假档位
National tiers 为满1年5天、满10年10天、满20年15天,与《职工带薪年休假条例》第三条一致。算法从低档遍历到高档,命中则覆盖 days;不足1年返回 0。
源码方法 XML 却写成“工龄小于 1 年:5 天;1~10 年:10 天;大于 10 年:15 天”,与 tiers 和法条不一致。说明书以可执行代码和官方法源为准,并将 XML 修正列为待办。
5. 年假折算不是官方日历公式
CalcAnnualLeaveProrated 接收 workedMonths 0–12,以 fullDays × months / 12 向下取整。官方企业职工办法对新入职按“当年度在本单位剩余日历天数÷365”,解除/终止按“已过日历天数÷365−已安排天数”。
var approximate = LeaveCalculator.CalcAnnualLeaveProrated( totalWorkYears: 12m, workedMonths: 7, schedule: LeavePolicies.National);
// 当前为 floor(10×7/12)=5;它没有入职日、年度天数或已休天数。if (approximate.IsFailure) return approximate.Error;
// 正式结算必须走日历日规则引擎,并保存入离职日期证据。return new AdvisoryLeaveEstimate(approximate.Value);方法 XML 引用官方公式后明确说“按月简化”,所以不能用于精确工资补偿或争议处理。
6. 婚假、陪产假与丧假
三个 getter 直接返回 Schedule 数字,没有资格、婚姻登记日期、是否晚婚、亲属关系、路程假、地方/单位更优规则或生效日期选择。
业务 wrapper 必须先解析雇佣地/参保地/单位政策和事件日期,再选择政策。若合同或规章提供更优待遇,还要执行法定下限与企业政策的组合,而不是只替换一个 static Schedule。
7. 产假算法
总天数从 policy.MaternityDays 开始;难产固定 +15;多胞胎每多一胎 +15。国家特别规定支持这两个 15 天基线。
地方实现可能对难产或奖励假有不同增量与条件。例如 2026 可查的广东实施办法对难产增加天数与当前固定值不一致;Schedule 只保存最终 MaternityDays,无法表达地区专属 difficult-labor rule。
8. 多胞胎与输入上限
multipleBirthCount 小于 1 返回 Validation;没有最大值。极大 int 参与 (count-1)*15 可溢出并产生错误天数。Production wrapper 应设置合理上限并使用 checked arithmetic。
政策还未表达流产假(国家规定按孕周 15/42 天)、哺乳时间、奖励假是否与难产/多胞胎叠加、配偶护理假资格等。
9. 医疗期矩阵
CalcMedicalPeriodMonths 根据 totalWorkYears 和 currentCompanyYears 返回 3/6/9/12/18/24。负值失败;未校验本单位工龄≤总工龄,因此逻辑不一致输入仍可得到结果。
算法只返回上限月份,不处理累计病休期间、医疗期计算周期、地区规则、工资待遇或工伤边界。
10. 政策选择缺失
调用者必须手动传 Schedule;不传就用 National。没有按 Region + event date 自动选择,也没有拒绝过期/未来政策。一个上海事件如果忘传参数,就悄悄按国家基线计算。
失败关闭的目标 Resolver 应要求明确 jurisdiction,找到发生日覆盖的唯一 Published policy;缺失/重叠都返回稳定 Error,不默认为看似安全但业务错误的 National。
11. 目标政策模型
var policy = await policies.ResolveAsync(new LeavePolicyQuery( JurisdictionCode: employment.JurisdictionCode, LeaveType: LeaveType.Maternity, OccurredOn: birthDate, EmployeeCategory: employment.Category), cancellationToken);
// Published policy 必须携带版本、法源 hash、生效区间和结构化规则。if (policy.IsFailure) return policy.Error;
// 计算结果保存选择原因和逐项加成,不能只保存最终天数。return leaveEngine.Calculate(facts, policy.Value) .WithEvidence(policy.Value.Version, policy.Value.SourceHash);这是 GA 目标,不是当前 API。
12. 法规变更工作流
法务/HR 发现变更 → 保存官方原文与 hash → 结构化规则草稿 → 双人复核 → 黄金用例 → 指定 EffectiveFrom/To → 发布 → 旧版本 Superseded 但可重放 → 受影响计算重评估报告。
不能在应用启动时从网页抓法条直接生效;外部文本需要可信来源、人工解释和审批。
13. 测试矩阵
| 场景 | 必须证明 |
|---|---|
| tier | 1/10/20 边界、负 tier、乱序、重复 |
| prorate | 闰年、入职/离职日、已休天数、月度近似差异 |
| maternity | National/地方、难产、多胞胎、溢出、叠加 |
| region | 缺失、未知、过期、重叠、未来 policy |
| medical | 每个矩阵边界、本单位工龄>总工龄 |
| value object | 同一发布版本跨进程/日期相等 |
| source | hash 变化触发审核,不自动生效 |
| history | 旧事件始终命中旧 policy |
当前没有任何自动化测试。
14. 检查命令
# Schedule 字段、默认日期、预置政策与算法固定增量。rg -n "DateTime.Today|LeavePolicies|MaternityDays|days \+= 15|workedMonths / 12m" \ src/Platform/IndustryExtensions/BitzOrcas.Platform.IndustryExtensions.Hr -g '*.cs'
# 版本、结束日、法源和测试当前预期无命中。rg -n "PolicyVersion|EffectiveTo|SourceHash|ApprovedBy|\[Fact\]" \ src/Platform/IndustryExtensions/BitzOrcas.Platform.IndustryExtensions.Hr tests -g '*.cs'