forked from wangziqi/gongxue-base
feat: streamline occupancy check-in and imports
This commit is contained in:
@@ -8,7 +8,7 @@ import { Bed } from '../entities/bed.entity';
|
||||
import { Locker } from '../entities/locker.entity';
|
||||
|
||||
describe('OccupanciesService — responsible organization', () => {
|
||||
it('defaults the responsible organization to the student organization', async () => {
|
||||
it('always takes the responsible organization from the student', async () => {
|
||||
const occupancyRepo = {
|
||||
findOne: jest.fn().mockResolvedValue(null),
|
||||
count: jest.fn().mockResolvedValue(0),
|
||||
@@ -42,7 +42,8 @@ describe('OccupanciesService — responsible organization', () => {
|
||||
roomId: 2,
|
||||
checkInDate: '2026-07-10',
|
||||
bedId: 4,
|
||||
});
|
||||
responsibleOrganizationId: 99,
|
||||
} as any);
|
||||
|
||||
expect(occupancyRepo.create).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ responsibleOrganizationId: 7 }),
|
||||
@@ -50,6 +51,89 @@ describe('OccupanciesService — responsible organization', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('OccupanciesService — manual check-in deposit', () => {
|
||||
const createService = (existingDeposit: Deposit | null = null) => {
|
||||
const occupancyRepo = {
|
||||
findOne: jest.fn().mockResolvedValue(null),
|
||||
count: jest.fn().mockResolvedValue(0),
|
||||
create: jest.fn((value) => value),
|
||||
save: jest.fn(async (value) => ({ ...value, id: 10 })),
|
||||
} as any as Repository<Occupancy>;
|
||||
const roomRepo = {
|
||||
findOne: jest.fn().mockResolvedValue({ id: 2, capacity: 4 }),
|
||||
update: jest.fn(),
|
||||
} as any as Repository<Room>;
|
||||
const studentRepo = {
|
||||
findOne: jest.fn().mockResolvedValue({ id: 3, organizationId: 7 }),
|
||||
} as any as Repository<Student>;
|
||||
const depositRepo = {
|
||||
findOne: jest.fn().mockResolvedValue(existingDeposit),
|
||||
create: jest.fn((value) => value),
|
||||
save: jest.fn(async (value) => ({ ...value, id: 20 })),
|
||||
} as any as Repository<Deposit>;
|
||||
const bedRepo = {
|
||||
findOne: jest.fn().mockResolvedValue({ id: 4, roomId: 2, status: 'available' }),
|
||||
update: jest.fn(),
|
||||
} as any as Repository<Bed>;
|
||||
|
||||
return {
|
||||
service: new OccupanciesService(
|
||||
occupancyRepo,
|
||||
roomRepo,
|
||||
studentRepo,
|
||||
depositRepo,
|
||||
bedRepo,
|
||||
{} as Repository<Locker>,
|
||||
{} as Repository<any>,
|
||||
{} as DataSource,
|
||||
),
|
||||
depositRepo,
|
||||
};
|
||||
};
|
||||
|
||||
it('creates a paid deposit together with manual check-in', async () => {
|
||||
const { service, depositRepo } = createService();
|
||||
|
||||
await service.checkIn(
|
||||
{
|
||||
studentId: 3,
|
||||
roomId: 2,
|
||||
checkInDate: '2026-07-14',
|
||||
bedId: 4,
|
||||
collectDeposit: true,
|
||||
depositAmount: 800,
|
||||
},
|
||||
11,
|
||||
);
|
||||
|
||||
expect(depositRepo.create).toHaveBeenCalledWith({
|
||||
studentId: 3,
|
||||
amount: 800,
|
||||
paidDate: '2026-07-14',
|
||||
status: 'paid',
|
||||
recordedBy: 11,
|
||||
notes: '入住登记自动收取',
|
||||
});
|
||||
expect(depositRepo.save).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('does not create another paid deposit when one already exists', async () => {
|
||||
const { service, depositRepo } = createService({ id: 99 } as Deposit);
|
||||
|
||||
await service.checkIn({
|
||||
studentId: 3,
|
||||
roomId: 2,
|
||||
checkInDate: '2026-07-14',
|
||||
bedId: 4,
|
||||
collectDeposit: true,
|
||||
depositAmount: 800,
|
||||
});
|
||||
|
||||
expect(depositRepo.create).not.toHaveBeenCalled();
|
||||
expect(depositRepo.save).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('OccupanciesService — import bed capacity', () => {
|
||||
it('rejects creating a new bed when the room already has its capacity in beds', async () => {
|
||||
const occupancyRepo = {
|
||||
@@ -97,6 +181,7 @@ describe('OccupanciesService — import bed capacity', () => {
|
||||
const result = await service.batchImportCheckIn([
|
||||
{
|
||||
name: '张三',
|
||||
phone: '13800138000',
|
||||
roomNumber: '4-102',
|
||||
bedNumber: '5号床',
|
||||
checkInDate: '2026-07-14',
|
||||
@@ -114,3 +199,78 @@ describe('OccupanciesService — import bed capacity', () => {
|
||||
expect(occupancyRepo.save).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('OccupanciesService — import student matching', () => {
|
||||
it('associates an existing student by phone and keeps the student organization', async () => {
|
||||
const existingStudent = {
|
||||
id: 3,
|
||||
name: '学生档案姓名',
|
||||
phone: '13800138000',
|
||||
organizationId: 7,
|
||||
};
|
||||
const occupancyRepo = {
|
||||
findOne: jest.fn().mockResolvedValue(null),
|
||||
count: jest.fn().mockResolvedValue(0),
|
||||
create: jest.fn((value) => value),
|
||||
save: jest.fn(async (value) => ({ ...value, id: 10 })),
|
||||
} as any as Repository<Occupancy>;
|
||||
const roomRepo = {
|
||||
findOne: jest.fn().mockResolvedValue({ id: 2, roomNumber: '4-102', capacity: 4 }),
|
||||
create: jest.fn((value) => value),
|
||||
save: jest.fn(),
|
||||
update: jest.fn(),
|
||||
} as any as Repository<Room>;
|
||||
const studentRepo = {
|
||||
findOne: jest.fn().mockResolvedValue(existingStudent),
|
||||
create: jest.fn((value) => value),
|
||||
save: jest.fn(),
|
||||
update: jest.fn(),
|
||||
} as any as Repository<Student>;
|
||||
const bedRepo = {
|
||||
findOne: jest.fn().mockResolvedValue({
|
||||
id: 4,
|
||||
roomId: 2,
|
||||
bedNumber: '1号床',
|
||||
status: 'available',
|
||||
}),
|
||||
count: jest.fn(),
|
||||
create: jest.fn((value) => value),
|
||||
save: jest.fn(),
|
||||
update: jest.fn(),
|
||||
} as any as Repository<Bed>;
|
||||
const organizationRepo = {
|
||||
findOne: jest.fn(),
|
||||
create: jest.fn((value) => value),
|
||||
save: jest.fn(),
|
||||
} as any as Repository<any>;
|
||||
|
||||
const service = new OccupanciesService(
|
||||
occupancyRepo,
|
||||
roomRepo,
|
||||
studentRepo,
|
||||
{ findOne: jest.fn() } as any as Repository<Deposit>,
|
||||
bedRepo,
|
||||
{ findOne: jest.fn() } as any as Repository<Locker>,
|
||||
organizationRepo,
|
||||
{} as DataSource,
|
||||
);
|
||||
|
||||
const result = await service.batchImportCheckIn([
|
||||
{
|
||||
name: 'Excel姓名',
|
||||
phone: '13800138000',
|
||||
roomNumber: '4-102',
|
||||
bedNumber: '1号床',
|
||||
checkInDate: '2026-07-14',
|
||||
},
|
||||
]);
|
||||
|
||||
expect(studentRepo.findOne).toHaveBeenCalledWith({ where: { phone: '13800138000' } });
|
||||
expect(studentRepo.save).not.toHaveBeenCalled();
|
||||
expect(organizationRepo.findOne).not.toHaveBeenCalled();
|
||||
expect(occupancyRepo.create).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ studentId: 3, responsibleOrganizationId: 7 }),
|
||||
);
|
||||
expect(result).toEqual(expect.objectContaining({ imported: 1, skipped: 0 }));
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user