forked from wangziqi/gongxue-base
feat: DingTalk attendance import + integration config + expense types + UI polish
Server: - Add DingTalk attendance import service with SSE progress streaming - Add IntegrationConfig entity & module for multi-tenant DingTalk setup - Add ExpenseType entity & ExpenseTypesModule - Add SeedModule for DB initialization - Add UserDingMapping entity for DingTalk user linkage - Attendance service: import flow with dedup & student auto-mapping - Rooms service: time-range overlap queries - Sync controller/service: DingTalk integration wiring - Permission guard: refactor to pure re-export - Campus scope middleware: tenant-aware filtering Admin UI: - Attendance page: import UI with progress & result summary - All pages: tableStyle/tablePagination standardization - Login page: responsive styling - Sensitive data: useViewSensitive hook for masked viewing - Vite config: path aliases, build optimization - Test infra: vitest config, test utilities Docs: PRD DingTalk batch 1 & 2 design docs
This commit is contained in:
@@ -7,6 +7,9 @@ import { AttendanceRecord } from '../entities/attendance-record.entity';
|
||||
import { DingAttendanceRaw } from '../entities/ding-attendance-raw.entity';
|
||||
import { Class } from '../entities/class.entity';
|
||||
import { Student } from '../entities/student.entity';
|
||||
import { ClassSchedule } from '../entities/class-schedule.entity';
|
||||
import { ClassStudent } from '../entities/class-student.entity';
|
||||
import { UserDingMapping } from '../entities/user-ding-mapping.entity';
|
||||
import { CampusScope } from '../common/campus-scope';
|
||||
import { BatchCreateAttendanceDto } from './dto/attendance.dto';
|
||||
|
||||
@@ -34,6 +37,10 @@ describe('AttendanceService — batchCreate', () => {
|
||||
const mockDingRepo = {};
|
||||
const mockClassRepo = { find: jest.fn().mockResolvedValue([]) };
|
||||
const mockStudentRepo = { find: jest.fn().mockResolvedValue([]) };
|
||||
// Reserved for future tests (auto-match, schedule-based attendance, etc.)
|
||||
const mockScheduleRepo = { find: jest.fn().mockResolvedValue([]) };
|
||||
const mockClassStudentRepo = { find: jest.fn().mockResolvedValue([]) };
|
||||
const mockUserDingMappingRepo = { find: jest.fn().mockResolvedValue([]) };
|
||||
const mockCampusScope = { getScopeDepartmentIds: jest.fn().mockResolvedValue(null), filter: jest.fn((w: any) => w) };
|
||||
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
@@ -43,6 +50,9 @@ describe('AttendanceService — batchCreate', () => {
|
||||
{ provide: getRepositoryToken(DingAttendanceRaw), useValue: mockDingRepo },
|
||||
{ provide: getRepositoryToken(Class), useValue: mockClassRepo },
|
||||
{ provide: getRepositoryToken(Student), useValue: mockStudentRepo },
|
||||
{ provide: getRepositoryToken(ClassSchedule), useValue: mockScheduleRepo },
|
||||
{ provide: getRepositoryToken(UserDingMapping), useValue: mockUserDingMappingRepo },
|
||||
{ provide: getRepositoryToken(ClassStudent), useValue: mockClassStudentRepo },
|
||||
{ provide: CampusScope, useValue: mockCampusScope },
|
||||
],
|
||||
}).compile();
|
||||
@@ -91,4 +101,10 @@ describe('AttendanceService — batchCreate', () => {
|
||||
|
||||
await expect(service.batchCreate(dto)).rejects.toThrow(BadRequestException);
|
||||
});
|
||||
|
||||
it.skip('autoMatchDingRecords with UserDingMapping chain', async () => {
|
||||
// TODO: match dingtalk raw records to students via UserDingMapping lookup,
|
||||
// then to class schedules → ClassStudent association, producing attendance records.
|
||||
// Requires mock setup for UserDingMapping, ClassSchedule, ClassStudent, and DingAttendanceRaw repos.
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user