feat(P15B-1,P15B-6): 完成请假V1闭环
这个提交包含在:
@@ -0,0 +1,107 @@
|
||||
const {
|
||||
calculateRequestedDays,
|
||||
leaveRangesOverlap,
|
||||
summarizeLeaveLedgerEntries,
|
||||
} = require("../../../src/services/leave");
|
||||
|
||||
describe("Leave Service", () => {
|
||||
describe("calculateRequestedDays", () => {
|
||||
it("supports same-day half-day requests", () => {
|
||||
expect(
|
||||
calculateRequestedDays({
|
||||
startDate: "2026-03-10",
|
||||
endDate: "2026-03-10",
|
||||
startSession: "am",
|
||||
endSession: "am",
|
||||
}),
|
||||
).toBe(0.5);
|
||||
|
||||
expect(
|
||||
calculateRequestedDays({
|
||||
startDate: "2026-03-10",
|
||||
endDate: "2026-03-10",
|
||||
startSession: "pm",
|
||||
endSession: "pm",
|
||||
}),
|
||||
).toBe(0.5);
|
||||
});
|
||||
|
||||
it("supports cross-day half-day boundaries", () => {
|
||||
expect(
|
||||
calculateRequestedDays({
|
||||
startDate: "2026-03-10",
|
||||
endDate: "2026-03-12",
|
||||
startSession: "pm",
|
||||
endSession: "am",
|
||||
}),
|
||||
).toBe(2);
|
||||
});
|
||||
|
||||
it("rejects invalid session ranges", () => {
|
||||
expect(() =>
|
||||
calculateRequestedDays({
|
||||
startDate: "2026-03-10",
|
||||
endDate: "2026-03-10",
|
||||
startSession: "pm",
|
||||
endSession: "am",
|
||||
}),
|
||||
).toThrow(/参数校验失败/);
|
||||
});
|
||||
});
|
||||
|
||||
describe("leaveRangesOverlap", () => {
|
||||
it("detects overlapping half-day ranges", () => {
|
||||
expect(
|
||||
leaveRangesOverlap(
|
||||
{
|
||||
startDate: "2026-03-10",
|
||||
endDate: "2026-03-11",
|
||||
startSession: "pm",
|
||||
endSession: "pm",
|
||||
},
|
||||
{
|
||||
startDate: "2026-03-11",
|
||||
endDate: "2026-03-12",
|
||||
startSession: "am",
|
||||
endSession: "am",
|
||||
},
|
||||
),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it("does not flag non-overlapping adjacent ranges", () => {
|
||||
expect(
|
||||
leaveRangesOverlap(
|
||||
{
|
||||
startDate: "2026-03-10",
|
||||
endDate: "2026-03-10",
|
||||
startSession: "am",
|
||||
endSession: "am",
|
||||
},
|
||||
{
|
||||
startDate: "2026-03-10",
|
||||
endDate: "2026-03-10",
|
||||
startSession: "pm",
|
||||
endSession: "pm",
|
||||
},
|
||||
),
|
||||
).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("summarizeLeaveLedgerEntries", () => {
|
||||
it("calculates reserve / consume / release balances correctly", () => {
|
||||
const summary = summarizeLeaveLedgerEntries([
|
||||
{ entry_type: "grant", days: 10 },
|
||||
{ entry_type: "reserve", days: 2.5 },
|
||||
{ entry_type: "release", days: 1 },
|
||||
{ entry_type: "consume", days: 1.5 },
|
||||
]);
|
||||
|
||||
expect(summary.granted).toBe(10);
|
||||
expect(summary.reserved).toBe(1.5);
|
||||
expect(summary.used).toBe(1.5);
|
||||
expect(summary.available).toBe(7);
|
||||
});
|
||||
});
|
||||
});
|
||||
在新工单中引用
屏蔽一个用户