company-recent-allocations.integration.test.ts 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509
  1. import { describe, it, expect, beforeEach } from 'vitest';
  2. import { testClient } from 'hono/testing';
  3. import { IntegrationTestDatabase, setupIntegrationDatabaseHooksWithEntities } from '@d8d/shared-test-util';
  4. import { JWTUtil } from '@d8d/shared-utils';
  5. import { JWTPayload } from '@d8d/shared-types';
  6. import { UserEntity, Role } from '@d8d/user-module';
  7. import { File } from '@d8d/file-module';
  8. import { Platform } from '@d8d/allin-platform-module/entities';
  9. import { EmploymentOrder, OrderPerson } from '@d8d/allin-order-module/entities';
  10. import { DisabledPerson, DisabledBankCard, DisabledPhoto, DisabledRemark, DisabledVisit } from '@d8d/allin-disability-module/entities';
  11. import { BankName } from '@d8d/bank-names-module';
  12. import { OrderStatus, WorkStatus } from '@d8d/allin-enums';
  13. import companyRecentAllocationsRoutes from '../../src/routes/company-recent-allocations.route';
  14. import { Company } from '../../src/entities/company.entity';
  15. // 设置集成测试钩子 - 需要包含所有相关实体
  16. setupIntegrationDatabaseHooksWithEntities([
  17. UserEntity, File, Role, Platform, Company,
  18. EmploymentOrder, OrderPerson, DisabledPerson, BankName, DisabledBankCard, DisabledPhoto, DisabledRemark, DisabledVisit
  19. ])
  20. describe('近期分配人才查询API集成测试', () => {
  21. let client: ReturnType<typeof testClient<typeof companyRecentAllocationsRoutes>>;
  22. let testToken: string;
  23. let testUser: UserEntity;
  24. let testCompany: Company;
  25. let testPlatform: Platform;
  26. beforeEach(async () => {
  27. // 创建测试客户端
  28. client = testClient(companyRecentAllocationsRoutes);
  29. // 获取数据源
  30. const dataSource = await IntegrationTestDatabase.getDataSource();
  31. // 创建测试平台
  32. const platformRepository = dataSource.getRepository(Platform);
  33. testPlatform = platformRepository.create({
  34. platformName: `测试平台_${Date.now()}`,
  35. contactPerson: '平台管理员',
  36. contactPhone: '13800138000',
  37. contactEmail: 'admin@example.com',
  38. status: 1
  39. });
  40. await platformRepository.save(testPlatform);
  41. // 创建测试公司
  42. const companyRepository = dataSource.getRepository(Company);
  43. testCompany = companyRepository.create({
  44. companyName: `测试公司_${Date.now()}`,
  45. contactPerson: '公司联系人',
  46. contactPhone: '13900139000',
  47. contactEmail: 'company@example.com',
  48. address: '公司地址',
  49. platformId: testPlatform.id,
  50. status: 1
  51. });
  52. await companyRepository.save(testCompany);
  53. // 创建测试企业用户(有companyId)
  54. const userRepository = dataSource.getRepository(UserEntity);
  55. testUser = userRepository.create({
  56. username: `enterprise_user_${Date.now()}`,
  57. password: 'test_password',
  58. nickname: '企业测试用户',
  59. registrationSource: 'web',
  60. companyId: testCompany.id
  61. });
  62. await userRepository.save(testUser);
  63. // 生成测试用户的token
  64. testToken = JWTUtil.generateToken({
  65. id: testUser.id,
  66. username: testUser.username,
  67. roles: [{ name: 'enterprise_user' }]
  68. }, { companyId: testCompany.id } as Partial<JWTPayload & { companyId: number }>);
  69. });
  70. describe('GET /api/v1/yongren/company/allocations/recent', () => {
  71. it('应该返回近期分配人才列表(最近30天入职的在职人员)', async () => {
  72. // 准备测试数据:创建订单和人员
  73. const dataSource = await IntegrationTestDatabase.getDataSource();
  74. // 创建残疾人
  75. const disabledPersonRepo = dataSource.getRepository(DisabledPerson);
  76. const disabledPerson = disabledPersonRepo.create({
  77. name: '测试残疾人',
  78. idCard: `110101${Date.now() % 100000000}`,
  79. gender: '男',
  80. birthDate: new Date('1990-01-01'),
  81. disabilityType: '视力残疾',
  82. disabilityLevel: '一级',
  83. disabilityId: `DIS${Date.now() % 100000000}`,
  84. idAddress: '身份证地址',
  85. phone: '13800138000',
  86. province: '北京市',
  87. city: '北京市'
  88. });
  89. await disabledPersonRepo.save(disabledPerson);
  90. // 创建订单
  91. const orderRepo = dataSource.getRepository(EmploymentOrder);
  92. const order = orderRepo.create({
  93. orderName: '测试订单',
  94. platformId: testPlatform.id,
  95. companyId: testCompany.id,
  96. orderStatus: OrderStatus.IN_PROGRESS,
  97. workStatus: WorkStatus.WORKING
  98. });
  99. await orderRepo.save(order);
  100. // 创建订单人员关联(近期入职:7天前)
  101. const orderPersonRepo = dataSource.getRepository(OrderPerson);
  102. const recentJoinDate = new Date();
  103. recentJoinDate.setDate(recentJoinDate.getDate() - 7);
  104. recentJoinDate.setHours(0, 0, 0, 0);
  105. const orderPerson = orderPersonRepo.create({
  106. orderId: order.id,
  107. personId: disabledPerson.id,
  108. joinDate: recentJoinDate,
  109. workStatus: WorkStatus.WORKING,
  110. salaryDetail: 5000.00
  111. });
  112. await orderPersonRepo.save(orderPerson);
  113. // 调用API
  114. const response = await client['allocations']['recent'].$get({
  115. query: {}
  116. },{
  117. headers: {
  118. Authorization: `Bearer ${testToken}`
  119. }
  120. });
  121. expect(response.status).toBe(200);
  122. const data = await response.json() as any;
  123. // 验证响应结构
  124. expect(data).toHaveProperty('人才列表');
  125. expect(Array.isArray(data.人才列表)).toBe(true);
  126. expect(data.人才列表.length).toBe(1);
  127. // 验证数据内容
  128. const talent = data.人才列表[0];
  129. expect(talent).toHaveProperty('personId', disabledPerson.id);
  130. expect(talent).toHaveProperty('personName', '测试残疾人');
  131. expect(talent).toHaveProperty('workStatus', 'working');
  132. expect(talent).toHaveProperty('orderName', '测试订单');
  133. expect(new Date(talent.joinDate).toISOString().split('T')[0]).toBe(recentJoinDate.toISOString().split('T')[0]);
  134. });
  135. it('应该支持limit参数控制返回记录数', async () => {
  136. // 准备测试数据:创建多个近期入职人员
  137. const dataSource = await IntegrationTestDatabase.getDataSource();
  138. const orderPersonRepo = dataSource.getRepository(OrderPerson);
  139. const disabledPersonRepo = dataSource.getRepository(DisabledPerson);
  140. const orderRepo = dataSource.getRepository(EmploymentOrder);
  141. // 创建订单
  142. const order = orderRepo.create({
  143. orderName: '测试订单',
  144. platformId: testPlatform.id,
  145. companyId: testCompany.id,
  146. orderStatus: OrderStatus.IN_PROGRESS,
  147. workStatus: WorkStatus.WORKING
  148. });
  149. await orderRepo.save(order);
  150. // 创建5个近期入职的残疾人
  151. for (let i = 0; i < 5; i++) {
  152. const disabledPerson = disabledPersonRepo.create({
  153. name: `测试残疾人${i}`,
  154. idCard: `110101${Date.now() % 100000000 + i}`,
  155. gender: i % 2 === 0 ? '男' : '女',
  156. birthDate: new Date('1990-01-01'),
  157. disabilityType: '视力残疾',
  158. disabilityLevel: '一级',
  159. disabilityId: `DIS${Date.now() % 100000000 + i}`,
  160. idAddress: '身份证地址',
  161. phone: `1380013800${i}`,
  162. province: '北京市',
  163. city: '北京市'
  164. });
  165. await disabledPersonRepo.save(disabledPerson);
  166. const recentJoinDate = new Date();
  167. recentJoinDate.setDate(recentJoinDate.getDate() - i); // 不同的入职日期
  168. recentJoinDate.setHours(0, 0, 0, 0);
  169. const orderPerson = orderPersonRepo.create({
  170. orderId: order.id,
  171. personId: disabledPerson.id,
  172. joinDate: recentJoinDate,
  173. workStatus: WorkStatus.WORKING,
  174. salaryDetail: 5000.00 + i * 1000
  175. });
  176. await orderPersonRepo.save(orderPerson);
  177. }
  178. // 测试默认limit=5
  179. const response1 = await client['allocations']['recent'].$get({
  180. query: {}
  181. },{
  182. headers: {
  183. Authorization: `Bearer ${testToken}`
  184. }
  185. });
  186. expect(response1.status).toBe(200);
  187. const data1 = await response1.json() as any;
  188. expect(data1.人才列表.length).toBe(5);
  189. // 测试limit=2
  190. const response2 = await client['allocations']['recent'].$get({
  191. query: { limit: 2 }
  192. },{
  193. headers: {
  194. Authorization: `Bearer ${testToken}`
  195. }
  196. });
  197. expect(response2.status).toBe(200);
  198. const data2 = await response2.json() as any;
  199. expect(data2.人才列表.length).toBe(2);
  200. // 验证按join_date降序排列(最近入职的在前)
  201. expect(new Date(data2.人才列表[0].joinDate).getTime()).toBeGreaterThanOrEqual(new Date(data2.人才列表[1].joinDate).getTime());
  202. });
  203. it('应该只返回最近30天的数据', async () => {
  204. const dataSource = await IntegrationTestDatabase.getDataSource();
  205. const orderPersonRepo = dataSource.getRepository(OrderPerson);
  206. const disabledPersonRepo = dataSource.getRepository(DisabledPerson);
  207. const orderRepo = dataSource.getRepository(EmploymentOrder);
  208. // 创建订单
  209. const order = orderRepo.create({
  210. orderName: '测试订单',
  211. platformId: testPlatform.id,
  212. companyId: testCompany.id,
  213. orderStatus: OrderStatus.IN_PROGRESS,
  214. workStatus: WorkStatus.WORKING
  215. });
  216. await orderRepo.save(order);
  217. // 创建残疾人
  218. const disabledPerson = disabledPersonRepo.create({
  219. name: '测试残疾人',
  220. idCard: `110101${Date.now() % 100000000}`,
  221. gender: '男',
  222. birthDate: new Date('1990-01-01'),
  223. disabilityType: '视力残疾',
  224. disabilityLevel: '一级',
  225. disabilityId: `DIS${Date.now() % 100000000}`,
  226. idAddress: '身份证地址',
  227. phone: '13800138000',
  228. province: '北京市',
  229. city: '北京市'
  230. });
  231. await disabledPersonRepo.save(disabledPerson);
  232. // 创建近期入职记录(7天前)
  233. const recentJoinDate = new Date();
  234. recentJoinDate.setDate(recentJoinDate.getDate() - 7);
  235. const recentOrderPerson = orderPersonRepo.create({
  236. orderId: order.id,
  237. personId: disabledPerson.id,
  238. joinDate: recentJoinDate,
  239. workStatus: WorkStatus.WORKING,
  240. salaryDetail: 5000.00
  241. });
  242. await orderPersonRepo.save(recentOrderPerson);
  243. // 创建超过30天的入职记录(40天前)
  244. const oldJoinDate = new Date();
  245. oldJoinDate.setDate(oldJoinDate.getDate() - 40);
  246. const oldOrderPerson = orderPersonRepo.create({
  247. orderId: order.id,
  248. personId: disabledPerson.id,
  249. joinDate: oldJoinDate,
  250. workStatus: WorkStatus.WORKING,
  251. salaryDetail: 6000.00
  252. });
  253. await orderPersonRepo.save(oldOrderPerson);
  254. // 调用API
  255. const response = await client['allocations']['recent'].$get({
  256. query: {}
  257. },{
  258. headers: {
  259. Authorization: `Bearer ${testToken}`
  260. }
  261. });
  262. expect(response.status).toBe(200);
  263. const data = await response.json() as any;
  264. // 应该只返回1条记录(近期入职的)
  265. expect(data.人才列表.length).toBe(1);
  266. expect(new Date(data.人才列表[0].joinDate).toISOString().split('T')[0]).toBe(recentJoinDate.toISOString().split('T')[0]);
  267. });
  268. it('应该只返回在职人员(work_status = working)', async () => {
  269. const dataSource = await IntegrationTestDatabase.getDataSource();
  270. const orderPersonRepo = dataSource.getRepository(OrderPerson);
  271. const disabledPersonRepo = dataSource.getRepository(DisabledPerson);
  272. const orderRepo = dataSource.getRepository(EmploymentOrder);
  273. // 创建订单
  274. const order = orderRepo.create({
  275. orderName: '测试订单',
  276. platformId: testPlatform.id,
  277. companyId: testCompany.id,
  278. orderStatus: OrderStatus.IN_PROGRESS,
  279. workStatus: WorkStatus.WORKING
  280. });
  281. await orderRepo.save(order);
  282. // 创建残疾人
  283. const disabledPerson = disabledPersonRepo.create({
  284. name: '测试残疾人',
  285. idCard: `110101${Date.now() % 100000000}`,
  286. gender: '男',
  287. birthDate: new Date('1990-01-01'),
  288. disabilityType: '视力残疾',
  289. disabilityLevel: '一级',
  290. disabilityId: `DIS${Date.now() % 100000000}`,
  291. idAddress: '身份证地址',
  292. phone: '13800138000',
  293. province: '北京市',
  294. city: '北京市'
  295. });
  296. await disabledPersonRepo.save(disabledPerson);
  297. // 创建在职记录
  298. const recentJoinDate = new Date();
  299. recentJoinDate.setDate(recentJoinDate.getDate() - 7);
  300. const workingOrderPerson = orderPersonRepo.create({
  301. orderId: order.id,
  302. personId: disabledPerson.id,
  303. joinDate: recentJoinDate,
  304. workStatus: WorkStatus.WORKING,
  305. salaryDetail: 5000.00
  306. });
  307. await orderPersonRepo.save(workingOrderPerson);
  308. // 创建离职记录
  309. const resignedOrderPerson = orderPersonRepo.create({
  310. orderId: order.id,
  311. personId: disabledPerson.id,
  312. joinDate: recentJoinDate,
  313. workStatus: WorkStatus.RESIGNED,
  314. salaryDetail: 6000.00
  315. });
  316. await orderPersonRepo.save(resignedOrderPerson);
  317. // 调用API
  318. const response = await client['allocations']['recent'].$get({
  319. query: {}
  320. },{
  321. headers: {
  322. Authorization: `Bearer ${testToken}`
  323. }
  324. });
  325. expect(response.status).toBe(200);
  326. const data = await response.json() as any;
  327. // 应该只返回1条记录(在职的)
  328. expect(data.人才列表.length).toBe(1);
  329. expect(data.人才列表[0].workStatus).toBe('working');
  330. });
  331. it('未认证用户应该返回401', async () => {
  332. const response = await client['allocations']['recent'].$get({
  333. query: {}
  334. });
  335. expect(response.status).toBe(401);
  336. });
  337. it('非企业用户应该返回403', async () => {
  338. // 创建非企业用户
  339. const dataSource = await IntegrationTestDatabase.getDataSource();
  340. const userRepository = dataSource.getRepository(UserEntity);
  341. const nonEnterpriseUser = userRepository.create({
  342. username: `non_enterprise_${Date.now()}`,
  343. password: 'test_password',
  344. nickname: '非企业用户',
  345. registrationSource: 'web'
  346. // 没有companyId
  347. });
  348. await userRepository.save(nonEnterpriseUser);
  349. const nonEnterpriseToken = JWTUtil.generateToken({
  350. id: nonEnterpriseUser.id,
  351. username: nonEnterpriseUser.username,
  352. roles: [{ name: 'user' }]
  353. });
  354. const response = await client['allocations']['recent'].$get({
  355. query: {}
  356. },{
  357. headers: {
  358. Authorization: `Bearer ${nonEnterpriseToken}`
  359. }
  360. });
  361. expect(response.status).toBe(403);
  362. });
  363. it('企业用户只能访问自己企业的数据', async () => {
  364. // 创建另一个公司
  365. const dataSource = await IntegrationTestDatabase.getDataSource();
  366. const companyRepository = dataSource.getRepository(Company);
  367. const otherCompany = companyRepository.create({
  368. companyName: `其他公司_${Date.now()}`,
  369. contactPerson: '其他联系人',
  370. contactPhone: '13900139001',
  371. contactEmail: 'other@example.com',
  372. address: '其他地址',
  373. platformId: testPlatform.id,
  374. status: 1
  375. });
  376. await companyRepository.save(otherCompany);
  377. // 在另一个公司创建近期入职人员
  378. const disabledPersonRepo = dataSource.getRepository(DisabledPerson);
  379. const disabledPerson = disabledPersonRepo.create({
  380. name: '其他公司残疾人',
  381. idCard: `110101${Date.now() % 100000000 + 999}`,
  382. gender: '男',
  383. birthDate: new Date('1990-01-01'),
  384. disabilityType: '视力残疾',
  385. disabilityLevel: '一级',
  386. disabilityId: `DIS${Date.now() % 100000000 + 999}`,
  387. idAddress: '身份证地址',
  388. phone: '13800138999',
  389. province: '北京市',
  390. city: '北京市'
  391. });
  392. await disabledPersonRepo.save(disabledPerson);
  393. const orderRepo = dataSource.getRepository(EmploymentOrder);
  394. const otherOrder = orderRepo.create({
  395. orderName: '其他公司订单',
  396. platformId: testPlatform.id,
  397. companyId: otherCompany.id,
  398. orderStatus: OrderStatus.IN_PROGRESS,
  399. workStatus: WorkStatus.WORKING
  400. });
  401. await orderRepo.save(otherOrder);
  402. const orderPersonRepo = dataSource.getRepository(OrderPerson);
  403. const recentJoinDate = new Date();
  404. recentJoinDate.setDate(recentJoinDate.getDate() - 7);
  405. const orderPerson = orderPersonRepo.create({
  406. orderId: otherOrder.id,
  407. personId: disabledPerson.id,
  408. joinDate: recentJoinDate,
  409. workStatus: WorkStatus.WORKING,
  410. salaryDetail: 5000.00
  411. });
  412. await orderPersonRepo.save(orderPerson);
  413. // 调用API - 当前企业用户不应该看到其他公司的数据
  414. const response = await client['allocations']['recent'].$get({
  415. query: {}
  416. },{
  417. headers: {
  418. Authorization: `Bearer ${testToken}`
  419. }
  420. });
  421. expect(response.status).toBe(200);
  422. const data = await response.json() as any;
  423. // 应该返回空数组,因为当前企业没有近期入职人员
  424. expect(data.人才列表.length).toBe(0);
  425. });
  426. it('无效limit参数应该返回400', async () => {
  427. // 测试非数字limit
  428. const response1 = await client['allocations']['recent'].$get({
  429. query: { limit: 'invalid' }
  430. },{
  431. headers: {
  432. Authorization: `Bearer ${testToken}`
  433. }
  434. });
  435. expect(response1.status).toBe(400);
  436. // 测试负数limit
  437. const response2 = await client['allocations']['recent'].$get({
  438. query: { limit: -1 }
  439. },{
  440. headers: {
  441. Authorization: `Bearer ${testToken}`
  442. }
  443. });
  444. expect(response2.status).toBe(400);
  445. // 测试超过最大值的limit
  446. const response3 = await client['allocations']['recent'].$get({
  447. query: { limit: 200 }
  448. },{
  449. headers: {
  450. Authorization: `Bearer ${testToken}`
  451. }
  452. });
  453. expect(response3.status).toBe(400);
  454. });
  455. });
  456. });