diff --git a/src/abnormal/abnormal.service.spec.ts b/src/abnormal/abnormal.service.spec.ts index 75e81ac..a9133bd 100644 --- a/src/abnormal/abnormal.service.spec.ts +++ b/src/abnormal/abnormal.service.spec.ts @@ -1,6 +1,7 @@ import { describe, expect, it, vi } from 'vitest'; import { AbnormalService } from './abnormal.service.js'; import type { PrismaService } from '../prisma/prisma.service.js'; +import { ErrorCodes } from '../common/error-codes.js'; import { runWithRequestContext } from '../common/context/request-context.js'; import type { RequestContext } from '../common/context/request-context.js'; @@ -20,12 +21,14 @@ function makeService( recordAbnormalFindMany?: ReturnType; recordAbnormalCount?: ReturnType; orderUpdate?: ReturnType; + orderFindUnique?: ReturnType; } = {}, ) { const recordAbnormalCreate = overrides.recordAbnormalCreate ?? vi.fn().mockResolvedValue({ id: 'a1' }); const recordAbnormalFindMany = overrides.recordAbnormalFindMany ?? vi.fn().mockResolvedValue([]); const recordAbnormalCount = overrides.recordAbnormalCount ?? vi.fn().mockResolvedValue(0); const orderUpdate = overrides.orderUpdate ?? vi.fn().mockResolvedValue({ id: 'o1', orderStatus: 'not_met' }); + const orderFindUnique = overrides.orderFindUnique ?? vi.fn().mockResolvedValue({ id: 'o1', orderStatus: 'assigned' }); const prisma = { client: { @@ -34,11 +37,11 @@ function makeService( findMany: recordAbnormalFindMany, count: recordAbnormalCount, }, - order: { update: orderUpdate }, + order: { update: orderUpdate, findUnique: orderFindUnique }, }, }; const service = new AbnormalService(prisma as unknown as PrismaService); - return { service, recordAbnormalCreate, recordAbnormalFindMany, recordAbnormalCount, orderUpdate }; + return { service, recordAbnormalCreate, recordAbnormalFindMany, recordAbnormalCount, orderUpdate, orderFindUnique }; } describe('AbnormalService', () => { @@ -149,6 +152,29 @@ describe('AbnormalService', () => { expect(recordAbnormalCreate).not.toHaveBeenCalled(); }); + it('report 扑空 order 不存在 → ORDER_NOT_FOUND(44003),不写工单/异常', async () => { + const orderFindUnique = vi.fn().mockResolvedValue(null); + const { service, recordAbnormalCreate, orderUpdate } = makeService({ orderFindUnique }); + + await expect( + runWithRequestContext(ctx, () => + service.report({ + abnormalType: 'not_met', + elderId: 'e1', + orderId: 'o-missing', + abnormalDesc: '老人不在家', + visitTime: '2026-10-15T09:30:00', + visitLat: 25.01, + visitLng: 102.7, + }), + ), + ).rejects.toMatchObject({ response: { code: ErrorCodes.ORDER_NOT_FOUND } }); + + expect(orderFindUnique).toHaveBeenCalledWith({ where: { id: 'o-missing' } }); + expect(orderUpdate).not.toHaveBeenCalled(); + expect(recordAbnormalCreate).not.toHaveBeenCalled(); + }); + it('list 按 abnormal_type/notify_status/handle_status/老人 筛选', async () => { const recordAbnormalFindMany = vi.fn().mockResolvedValue([{ id: 'a1' }]); const recordAbnormalCount = vi.fn().mockResolvedValue(1); diff --git a/src/abnormal/abnormal.service.ts b/src/abnormal/abnormal.service.ts index cae6960..7bc30c5 100644 --- a/src/abnormal/abnormal.service.ts +++ b/src/abnormal/abnormal.service.ts @@ -1,6 +1,8 @@ -import { BadRequestException, Injectable } from '@nestjs/common'; +import { BadRequestException, HttpStatus, Injectable } from '@nestjs/common'; import { PrismaService } from '../prisma/prisma.service.js'; import { getRequestContext } from '../common/context/request-context.js'; +import { BusinessException } from '../common/business-exception.js'; +import { ErrorCodes } from '../common/error-codes.js'; import { ListAbnormalQuery, NOT_MET, ReportAbnormalDto } from './dto.js'; /** ISO datetime 字符串 → Date。业务时区为北京时间(UTC+8),与 order.service 口径一致。 */ @@ -35,7 +37,8 @@ export class AbnormalService { if (dto.abnormalType === NOT_MET) { this.assertNotMetEvidence(dto); - // 扑空:工单转 not_met(原因 + 到访时间)。 + // 扑空:工单须存在,再转 not_met(原因 + 到访时间)。 + await this.requireOrder(dto.orderId!); await this.prisma.client.order.update({ where: { id: dto.orderId! }, data: { @@ -93,4 +96,13 @@ export class AbnormalService { throw new BadRequestException('扑空须填写到访时间、定位、原因与关联工单(3003)'); } } + + /** 工单须存在(扑空转 not_met 前校验,44003),循 order.service 的 requireOrder。 */ + private async requireOrder(id: string): Promise> { + const order = await this.prisma.client.order.findUnique({ where: { id } }); + if (!order) { + throw new BusinessException(ErrorCodes.ORDER_NOT_FOUND, '工单不存在', HttpStatus.NOT_FOUND); + } + return order; + } }