feat: 结算时同步钉钉已审批请假并标记为请假

This commit is contained in:
2026-08-05 18:43:02 +08:00
parent 32343b271b
commit c8316e9e8e
19 changed files with 746 additions and 58 deletions

View File

@@ -14,6 +14,7 @@ const createService = () => {
count: jest.fn(),
};
const dingRawRepo = { find: jest.fn() };
const dingLeaveRawRepo = { find: jest.fn().mockResolvedValue([]) };
const scheduleRepo = { findOne: jest.fn() };
const classStudentRepo = { find: jest.fn() };
const sessionRepo = {
@@ -37,6 +38,7 @@ const createService = () => {
const service = new AttendanceService(
attendanceRepo as never,
dingRawRepo as never,
dingLeaveRawRepo as never,
{} as never,
{} as never,
scheduleRepo as never,
@@ -52,6 +54,7 @@ const createService = () => {
service,
attendanceRepo,
dingRawRepo,
dingLeaveRawRepo,
scheduleRepo,
classStudentRepo,
sessionRepo,
@@ -151,6 +154,58 @@ describe('AttendanceService \u2014 DingTalk course attendance', () => {
expect(result.session.status).toBe('completed');
});
it('finalizes a missing punch as leave when an approved DingTalk leave overlaps the lesson', async () => {
const { service, attendanceRepo, dingRawRepo, dingLeaveRawRepo, scheduleRepo, classStudentRepo, sessionRepo } =
createService();
scheduleRepo.findOne.mockResolvedValue(endedSchedule);
sessionRepo.findOne.mockResolvedValue(null);
classStudentRepo.find.mockResolvedValue([{ studentId: 1, student: { id: 1, name: '张三' } }]);
dingRawRepo.find.mockResolvedValue([]);
dingLeaveRawRepo.find.mockResolvedValue([
{
startTime: new Date('2026-07-11T08:00:00+08:00'),
endTime: new Date('2026-07-11T12:00:00+08:00'),
approvedAt: new Date('2026-07-10T15:00:00+08:00'),
leaveType: '事假',
tagName: '请假',
},
]);
await service.createLessonAttendanceFromDingTalk(4, '2026-07-11', 21, true);
expect(attendanceRepo.save).toHaveBeenCalledWith([
expect.objectContaining({
studentId: 1,
status: 'leave',
remark: '钉钉请假已通过(事假)',
}),
]);
});
it('keeps a leave student pending before the lesson is finalized', async () => {
const { service, attendanceRepo, dingRawRepo, dingLeaveRawRepo, scheduleRepo, classStudentRepo, sessionRepo } =
createService();
scheduleRepo.findOne.mockResolvedValue(endedSchedule);
sessionRepo.findOne.mockResolvedValue(null);
classStudentRepo.find.mockResolvedValue([{ studentId: 1, student: { id: 1, name: '张三' } }]);
dingRawRepo.find.mockResolvedValue([]);
dingLeaveRawRepo.find.mockResolvedValue([
{
startTime: new Date('2026-07-11T08:00:00+08:00'),
endTime: new Date('2026-07-11T12:00:00+08:00'),
approvedAt: new Date('2026-07-10T15:00:00+08:00'),
leaveType: '事假',
tagName: '请假',
},
]);
await service.createLessonAttendanceFromDingTalk(4, '2026-07-11', 21);
expect(attendanceRepo.save).toHaveBeenCalledWith([
expect.objectContaining({ studentId: 1, status: 'pending' }),
]);
});
it('returns student relations after the first pull', async () => {
const { service, attendanceRepo, dingRawRepo, scheduleRepo, classStudentRepo, sessionRepo } =
createService();