person-extension.integration.test.ts 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382
  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, parseWithAwait } 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, OrderPersonAsset } from '@d8d/allin-order-module/entities';
  10. import { BankName } from '@d8d/bank-names-module';
  11. import { DisabledPerson, DisabledBankCard, DisabledPhoto, DisabledRemark, DisabledVisit } from '../../src/entities';
  12. import personExtensionRoutes from '../../src/routes/person-extension.route';
  13. import {
  14. WorkHistoryResponseSchema,
  15. SalaryHistoryResponseSchema,
  16. CreditInfoResponseSchema,
  17. PersonVideosResponseSchema
  18. } from '../../src/schemas/person-extension.schema';
  19. import { Company } from '@d8d/allin-company-module/entities';
  20. // 设置集成测试钩子 - 需要包含所有相关实体
  21. setupIntegrationDatabaseHooksWithEntities([
  22. UserEntity, File, Role, Platform, Company,
  23. EmploymentOrder, OrderPerson, OrderPersonAsset,
  24. DisabledPerson, BankName, DisabledBankCard, DisabledPhoto, DisabledRemark, DisabledVisit
  25. ])
  26. describe('人才扩展API集成测试', () => {
  27. let client: ReturnType<typeof testClient<typeof personExtensionRoutes>>;
  28. let testToken: string;
  29. let testUser: UserEntity;
  30. let testCompany: Company;
  31. let testPlatform: Platform;
  32. let testDisabledPerson: DisabledPerson;
  33. let testOrder: EmploymentOrder;
  34. beforeEach(async () => {
  35. // 创建测试客户端
  36. client = testClient(personExtensionRoutes);
  37. // 获取数据源
  38. const dataSource = await IntegrationTestDatabase.getDataSource();
  39. // 创建测试平台
  40. const platformRepository = dataSource.getRepository(Platform);
  41. testPlatform = platformRepository.create({
  42. platformName: `测试平台_${Date.now()}`,
  43. contactPerson: '平台管理员',
  44. contactPhone: '13800138000',
  45. contactEmail: 'admin@example.com',
  46. status: 1
  47. });
  48. await platformRepository.save(testPlatform);
  49. // 创建测试公司
  50. const companyRepository = dataSource.getRepository(Company);
  51. testCompany = companyRepository.create({
  52. companyName: `测试公司_${Date.now()}`,
  53. contactPerson: '公司联系人',
  54. contactPhone: '13900139000',
  55. contactEmail: 'company@example.com',
  56. address: '公司地址',
  57. platformId: testPlatform.id,
  58. status: 1
  59. });
  60. await companyRepository.save(testCompany);
  61. // 创建测试企业用户
  62. const userRepository = dataSource.getRepository(UserEntity);
  63. testUser = userRepository.create({
  64. username: `enterprise_user_${Date.now()}`,
  65. password: 'test_password',
  66. nickname: '企业测试用户',
  67. registrationSource: 'web',
  68. companyId: testCompany.id
  69. });
  70. await userRepository.save(testUser);
  71. // 生成测试用户的token
  72. testToken = JWTUtil.generateToken({
  73. id: testUser.id,
  74. username: testUser.username,
  75. roles: [{ name: 'enterprise_user' }]
  76. }, { companyId: testCompany.id } as Partial<JWTPayload & { companyId: number }>);
  77. // 创建测试残疾人
  78. const disabledPersonRepo = dataSource.getRepository(DisabledPerson);
  79. testDisabledPerson = disabledPersonRepo.create({
  80. name: '测试残疾人',
  81. idCard: `110101${Date.now() % 100000000}`,
  82. gender: '男',
  83. birthDate: new Date('1990-01-01'),
  84. disabilityType: '视力残疾',
  85. disabilityLevel: '一级',
  86. disabilityId: `DIS${Date.now() % 100000000}`,
  87. idAddress: '身份证地址',
  88. phone: '13800138000',
  89. province: '北京市',
  90. city: '北京市',
  91. address: '测试地址'
  92. } as any);
  93. await disabledPersonRepo.save(testDisabledPerson);
  94. // 创建测试订单
  95. const orderRepo = dataSource.getRepository(EmploymentOrder);
  96. testOrder = orderRepo.create({
  97. orderName: '测试订单',
  98. platformId: testPlatform.id,
  99. companyId: testCompany.id,
  100. orderStatus: 'confirmed',
  101. workStatus: 'working'
  102. } as any);
  103. await orderRepo.save(testOrder);
  104. // 创建订单人员关联,使人员属于该企业
  105. const orderPersonRepo = dataSource.getRepository(OrderPerson);
  106. const orderPerson = orderPersonRepo.create({
  107. orderId: testOrder.id,
  108. personId: testDisabledPerson.id,
  109. joinDate: new Date('2024-01-01'),
  110. workStatus: 'working',
  111. salaryDetail: 5000.00
  112. } as any);
  113. await orderPersonRepo.save(orderPerson);
  114. });
  115. describe('GET /api/v1/yongren/disability-person/{id}/work-history', () => {
  116. it('应该返回人员工作历史', async () => {
  117. // 准备测试数据:多个订单关联
  118. const dataSource = await IntegrationTestDatabase.getDataSource();
  119. const orderPersonRepo = dataSource.getRepository(OrderPerson);
  120. // 创建另一个订单关联
  121. const orderRepo = dataSource.getRepository(EmploymentOrder);
  122. const anotherOrder = orderRepo.create({
  123. orderName: '另一个测试订单',
  124. platformId: testPlatform.id,
  125. companyId: testCompany.id,
  126. orderStatus: 'completed',
  127. workStatus: 'working'
  128. } as any);
  129. await orderRepo.save(anotherOrder);
  130. const anotherOrderPerson = orderPersonRepo.create({
  131. orderId: anotherOrder.id,
  132. personId: testDisabledPerson.id,
  133. joinDate: new Date('2024-06-01'),
  134. actualStartDate: new Date('2024-06-02'),
  135. leaveDate: new Date('2024-12-31'),
  136. workStatus: 'resigned',
  137. salaryDetail: 6000.00
  138. } as any);
  139. await orderPersonRepo.save(anotherOrderPerson);
  140. // 调用API
  141. const response = await client[':id']['work-history'].$get({
  142. param: { id: testDisabledPerson.id }
  143. },{
  144. headers: {
  145. Authorization: `Bearer ${testToken}`
  146. }
  147. });
  148. console.debug('响应状态:', response.status);
  149. // 类型保护:如果状态不是200,抛出错误
  150. if (response.status !== 200) {
  151. try {
  152. const errorData = await response.json();
  153. console.debug('错误响应:', errorData);
  154. throw new Error(`API returned ${response.status}: ${errorData.message}`);
  155. } catch (e) {
  156. console.debug('无法解析错误响应:', e);
  157. throw new Error(`API returned ${response.status} and response could not be parsed`);
  158. }
  159. }
  160. const data = await response.json();
  161. // 验证响应结构
  162. expect(data).toHaveProperty('工作历史');
  163. expect(Array.isArray(data.工作历史)).toBe(true);
  164. // 验证数据
  165. expect(data.工作历史.length).toBeGreaterThanOrEqual(1);
  166. const workHistory = data.工作历史[0];
  167. expect(workHistory).toHaveProperty('订单ID');
  168. expect(workHistory).toHaveProperty('订单名称');
  169. expect(workHistory).toHaveProperty('入职日期');
  170. expect(workHistory).toHaveProperty('工作状态');
  171. expect(workHistory).toHaveProperty('个人薪资');
  172. });
  173. it('访问其他企业人员应该返回403', async () => {
  174. // 创建另一个公司的残疾人
  175. const dataSource = await IntegrationTestDatabase.getDataSource();
  176. // 创建另一个公司
  177. const companyRepository = dataSource.getRepository(Company);
  178. const otherCompany = companyRepository.create({
  179. companyName: `其他公司_${Date.now()}`,
  180. contactPerson: '其他联系人',
  181. contactPhone: '13900139001',
  182. contactEmail: 'other@example.com',
  183. address: '其他地址',
  184. platformId: testPlatform.id,
  185. status: 1
  186. });
  187. await companyRepository.save(otherCompany);
  188. // 创建另一个公司的残疾人
  189. const disabledPersonRepo = dataSource.getRepository(DisabledPerson);
  190. const otherDisabledPerson = disabledPersonRepo.create({
  191. name: '其他公司残疾人',
  192. idCard: `110101${Date.now() % 100000000 + 1000}`,
  193. gender: '女',
  194. birthDate: new Date('1995-01-01'),
  195. disabilityType: '听力残疾',
  196. disabilityLevel: '二级',
  197. disabilityId: `DIS${Date.now() % 100000000 + 1000}`,
  198. idAddress: '其他地址',
  199. phone: '13900139000',
  200. province: '上海市',
  201. city: '上海市',
  202. address: '其他地址'
  203. } as any);
  204. await disabledPersonRepo.save(otherDisabledPerson);
  205. // 尝试访问其他公司人员数据
  206. const response = await client[':id']['work-history'].$get({
  207. param: { id: otherDisabledPerson.id }
  208. },{
  209. headers: {
  210. Authorization: `Bearer ${testToken}`
  211. }
  212. });
  213. expect(response.status).toBe(403);
  214. });
  215. });
  216. describe('GET /api/v1/yongren/disability-person/{id}/salary-history', () => {
  217. it('应该返回人员薪资历史', async () => {
  218. // 注意:薪资历史可能需要从薪资模块获取,这里暂时返回空数组
  219. const response = await client[':id']['salary-history'].$get({
  220. param: { id: testDisabledPerson.id }
  221. },{
  222. headers: {
  223. Authorization: `Bearer ${testToken}`
  224. }
  225. });
  226. expect(response.status).toBe(200);
  227. const data = await response.json();
  228. // 验证响应结构
  229. expect(data).toHaveProperty('薪资历史');
  230. expect(Array.isArray(data.薪资历史)).toBe(true);
  231. });
  232. });
  233. describe('GET /api/v1/yongren/disability-person/{id}/credit-info', () => {
  234. it('应该返回人员征信信息', async () => {
  235. // 准备测试数据:银行卡信息
  236. const dataSource = await IntegrationTestDatabase.getDataSource();
  237. // 创建文件
  238. const fileRepository = dataSource.getRepository(File);
  239. const testFile = fileRepository.create({
  240. name: '银行卡照片.jpg',
  241. type: 'image/jpeg',
  242. size: 1024,
  243. path: 'uploads/bank-card.jpg',
  244. description: '银行卡照片',
  245. uploadUserId: testUser.id,
  246. uploadTime: new Date()
  247. });
  248. await fileRepository.save(testFile);
  249. // 创建银行名称记录
  250. const bankNameRepo = dataSource.getRepository(BankName);
  251. const bankName = bankNameRepo.create({
  252. name: '测试银行',
  253. code: 'TESTBANK',
  254. status: 1
  255. } as any);
  256. await bankNameRepo.save(bankName);
  257. // 创建银行卡记录
  258. const bankCardRepo = dataSource.getRepository(DisabledBankCard);
  259. const bankCard = bankCardRepo.create({
  260. personId: testDisabledPerson.id,
  261. subBankName: '测试支行',
  262. bankNameId: bankName.id, // 使用实际创建的银行ID
  263. cardNumber: '6228481234567890123',
  264. cardholderName: '测试持卡人',
  265. cardType: '一类卡',
  266. fileId: testFile.id,
  267. isDefault: 1
  268. });
  269. await bankCardRepo.save(bankCard);
  270. // 调用API
  271. const response = await client[':id']['credit-info'].$get({
  272. param: { id: testDisabledPerson.id }
  273. },{
  274. headers: {
  275. Authorization: `Bearer ${testToken}`
  276. }
  277. });
  278. expect(response.status).toBe(200);
  279. const data = await response.json();
  280. // 验证响应结构
  281. expect(data).toHaveProperty('征信信息');
  282. expect(Array.isArray(data.征信信息)).toBe(true);
  283. if (data.征信信息.length > 0) {
  284. const creditInfo = data.征信信息[0];
  285. expect(creditInfo).toHaveProperty('文件ID');
  286. expect(creditInfo).toHaveProperty('银行卡号');
  287. expect(creditInfo).toHaveProperty('持卡人姓名');
  288. }
  289. });
  290. });
  291. describe('GET /api/v1/yongren/disability-person/{id}/videos', () => {
  292. it('应该返回人员视频关联', async () => {
  293. // 准备测试数据:订单人员资产(视频)
  294. const dataSource = await IntegrationTestDatabase.getDataSource();
  295. // 创建文件
  296. const fileRepository = dataSource.getRepository(File);
  297. const testFile = fileRepository.create({
  298. name: '工作视频.mp4',
  299. type: 'video/mp4',
  300. size: 1024000,
  301. path: 'uploads/work-video.mp4',
  302. description: '工作视频',
  303. uploadUserId: testUser.id,
  304. uploadTime: new Date()
  305. });
  306. await fileRepository.save(testFile);
  307. // 创建订单人员资产记录
  308. const assetRepo = dataSource.getRepository(OrderPersonAsset);
  309. const asset = assetRepo.create({
  310. orderId: testOrder.id,
  311. personId: testDisabledPerson.id,
  312. assetType: 'work_video',
  313. assetFileType: 'video',
  314. fileId: testFile.id,
  315. relatedTime: new Date()
  316. } as any);
  317. await assetRepo.save(asset);
  318. // 调用API
  319. const response = await client[':id'].videos.$get({
  320. param: { id: testDisabledPerson.id }
  321. },{
  322. headers: {
  323. Authorization: `Bearer ${testToken}`
  324. }
  325. });
  326. expect(response.status).toBe(200);
  327. const data = await response.json();
  328. // 验证响应结构
  329. expect(data).toHaveProperty('视频列表');
  330. expect(Array.isArray(data.视频列表)).toBe(true);
  331. if (data.视频列表.length > 0) {
  332. const video = data.视频列表[0];
  333. expect(video).toHaveProperty('视频类型');
  334. expect(video).toHaveProperty('文件ID');
  335. expect(video).toHaveProperty('关联订单ID');
  336. }
  337. });
  338. });
  339. });