forked from wangziqi/gongxue-base
feat: improve attendance scheduling and API validation
This commit is contained in:
@@ -59,6 +59,7 @@ const endedSchedule = {
|
||||
subject: '\u6570\u5B66',
|
||||
status: 'active',
|
||||
scheduleType: 'INTERNAL',
|
||||
attendanceAdvanceMinutes: 30,
|
||||
};
|
||||
|
||||
describe('AttendanceService \u2014 DingTalk course attendance', () => {
|
||||
@@ -186,6 +187,40 @@ describe('AttendanceService \u2014 DingTalk course attendance', () => {
|
||||
]);
|
||||
});
|
||||
|
||||
it('counts both OnDuty and OffDuty punches only inside the configured window', async () => {
|
||||
const { service, attendanceRepo, dingRawRepo, scheduleRepo, classStudentRepo, sessionRepo } =
|
||||
createService();
|
||||
scheduleRepo.findOne.mockResolvedValue({ ...endedSchedule, attendanceAdvanceMinutes: 20 });
|
||||
sessionRepo.findOne.mockResolvedValue(null);
|
||||
classStudentRepo.find.mockResolvedValue([
|
||||
{ studentId: 1, student: { id: 1, name: '张三' } },
|
||||
{ studentId: 2, student: { id: 2, name: '李四' } },
|
||||
{ studentId: 3, student: { id: 3, name: '王五' } },
|
||||
]);
|
||||
dingRawRepo.find.mockResolvedValue([
|
||||
{ matchedStudentId: 1, attendanceType: 'OffDuty', checkOutTime: new Date('2026-07-11T08:40:00+08:00') },
|
||||
{ matchedStudentId: 2, attendanceType: 'OffDuty', checkOutTime: new Date('2026-07-11T10:00:00+08:00') },
|
||||
{ matchedStudentId: 3, attendanceType: 'OnDuty', checkInTime: new Date('2026-07-11T08:39:59+08:00') },
|
||||
{ matchedStudentId: 3, attendanceType: 'OffDuty', checkOutTime: new Date('2026-07-11T10:00:01+08:00') },
|
||||
]);
|
||||
|
||||
await service.createLessonAttendanceFromDingTalk(4, '2026-07-11', 21, true);
|
||||
|
||||
expect(attendanceRepo.save).toHaveBeenCalledWith([
|
||||
expect.objectContaining({ studentId: 1, status: 'present' }),
|
||||
expect.objectContaining({ studentId: 2, status: 'present' }),
|
||||
expect.objectContaining({ studentId: 3, status: 'absent' }),
|
||||
]);
|
||||
});
|
||||
|
||||
it('expands import dates when the pre-class window crosses midnight', () => {
|
||||
const { service } = createService();
|
||||
expect(service.getLessonAttendanceImportDateRange(
|
||||
{ startTime: '00:15', endTime: '01:00', attendanceAdvanceMinutes: 30 },
|
||||
'2026-07-11',
|
||||
)).toEqual({ startDate: '2026-07-10', endDate: '2026-07-11' });
|
||||
});
|
||||
|
||||
it('creates local attendance after the lesson starts', async () => {
|
||||
const { service, attendanceRepo, dingRawRepo, scheduleRepo, classStudentRepo, sessionRepo } =
|
||||
createService();
|
||||
|
||||
Reference in New Issue
Block a user