forked from Yara724/api
195 lines
7.6 KiB
TypeScript
195 lines
7.6 KiB
TypeScript
import { Body, Controller, Get, Header, Param, Headers, Patch, Put, UseGuards, Query, Res } from "@nestjs/common";
|
|
import {
|
|
ApiBearerAuth,
|
|
ApiBody,
|
|
ApiOperation,
|
|
ApiParam,
|
|
ApiPropertyOptional,
|
|
ApiQuery,
|
|
ApiTags,
|
|
} from "@nestjs/swagger";
|
|
import { IsOptional, IsString } from "class-validator";
|
|
import { LocalActorAuthGuard } from "src/auth/guards/actor-local.guard";
|
|
import { RolesGuard } from "src/auth/guards/role.guard";
|
|
import { Roles } from "src/decorators/roles.decorator";
|
|
import { CurrentUser } from "src/decorators/user.decorator";
|
|
import { RoleEnum } from "src/Types&Enums/role.enum";
|
|
import { ExpertClaimService } from "./expert-claim.service";
|
|
import { ClaimSubmitResendV2Dto, SubmitExpertReplyV2Dto } from "./dto/expert-claim-v2.dto";
|
|
import { UpdateClaimDamagedPartsV2Dto } from "./dto/update-claim-damaged-parts-v2.dto";
|
|
import { FactorValidationV2Dto } from "./dto/factor-validation.dto";
|
|
|
|
class InPersonVisitV2Dto {
|
|
@ApiPropertyOptional({ example: 'Paint damage requires physical inspection' })
|
|
@IsOptional()
|
|
@IsString()
|
|
note?: string;
|
|
}
|
|
|
|
@ApiTags("expert-claim-panel (v2)")
|
|
@Controller("v2/expert-claim")
|
|
@ApiBearerAuth()
|
|
@UseGuards(LocalActorAuthGuard, RolesGuard)
|
|
@Roles(RoleEnum.DAMAGE_EXPERT)
|
|
export class ExpertClaimV2Controller {
|
|
constructor(private readonly expertClaimService: ExpertClaimService) { }
|
|
|
|
@Get("report/status-counts")
|
|
@ApiOperation({
|
|
summary: "Count claim cases by grouped status bucket (tenant)",
|
|
description:
|
|
"IN_PROGRESS groups user-phase statuses before submission is complete (CREATED through CAPTURING_PART_DAMAGES). Other keys match ClaimCaseStatus. Scoped to the insurer in the JWT.",
|
|
})
|
|
async getStatusReportBucketsV2(@CurrentUser() actor: any) {
|
|
return await this.expertClaimService.getStatusReportBucketsV2(actor);
|
|
}
|
|
|
|
@Get("requests")
|
|
@ApiOperation({
|
|
summary: "List available claim requests for damage expert",
|
|
description:
|
|
"Returns claims that are WAITING_FOR_DAMAGE_EXPERT and not locked by another expert, this expert's locked/in-progress claims, and claims awaiting factor validation (UNDER_REVIEW at EXPERT_COST_EVALUATION).",
|
|
})
|
|
async getClaimListV2(@CurrentUser() actor) {
|
|
return await this.expertClaimService.getClaimListV2(actor);
|
|
}
|
|
|
|
@Get("request/:claimRequestId")
|
|
@ApiOperation({
|
|
summary: "Get claim request detail for damage expert",
|
|
description:
|
|
"Returns full claim details including captured images, required documents, damage selections, `videoCapture` (from claim-video-capture via media.videoCaptureId), and `blameCase` (linked blameCases document with party video/voice URLs like expert-blame detail). Allowed when status is WAITING_FOR_DAMAGE_EXPERT (if locked, only the locking expert) or when awaiting factor validation.",
|
|
})
|
|
@ApiParam({ name: "claimRequestId" })
|
|
async getClaimDetailV2(
|
|
@Param("claimRequestId") claimRequestId: string,
|
|
@CurrentUser() actor,
|
|
) {
|
|
return await this.expertClaimService.getClaimDetailV2(claimRequestId, actor);
|
|
}
|
|
|
|
@Put("lock/:claimRequestId")
|
|
@ApiOperation({
|
|
summary: "Lock a claim request for review",
|
|
description:
|
|
"Claim must have status WAITING_FOR_DAMAGE_EXPERT. Locking sets status to EXPERT_REVIEWING and claimStatus to UNDER_REVIEW. Only one expert can lock a claim at a time.",
|
|
})
|
|
@ApiParam({ name: "claimRequestId" })
|
|
async lockClaimRequestV2(
|
|
@Param("claimRequestId") claimRequestId: string,
|
|
@CurrentUser() actor,
|
|
) {
|
|
return await this.expertClaimService.lockClaimRequestV2(claimRequestId, actor);
|
|
}
|
|
|
|
@Put("reply/submit/:claimRequestId")
|
|
@ApiOperation({
|
|
summary: "Submit expert damage assessment reply",
|
|
description:
|
|
"Claim must be locked by this expert (status EXPERT_REVIEWING). Submitting unlocks the claim. Each part requires `daghi` with the same rules as V1 (DaghiOption, price for recycled value, branchId for deliver damaged part). If any part has factorNeeded=true the claim moves to EXPERT_COST_EVALUATION; otherwise moves to INSURER_REVIEW. Total payment cap is 30,000,000.",
|
|
})
|
|
@ApiParam({ name: "claimRequestId" })
|
|
@ApiBody({ type: SubmitExpertReplyV2Dto })
|
|
async submitExpertReplyV2(
|
|
@Param("claimRequestId") claimRequestId: string,
|
|
@Body() body: SubmitExpertReplyV2Dto,
|
|
@CurrentUser() actor,
|
|
) {
|
|
return await this.expertClaimService.submitExpertReplyV2(claimRequestId, body, actor);
|
|
}
|
|
|
|
@Put("reply/resend/:claimRequestId")
|
|
@ApiOperation({
|
|
summary: "Submit expert damage resend request",
|
|
description:
|
|
"Claim must be locked by this expert (`EXPERT_REVIEWING`). Sets `WAITING_FOR_USER_RESEND`, `USER_EXPERT_RESEND`, `NEEDS_REVISION`, clears the lock, and stores `evaluation.damageExpertResend`. " +
|
|
"The owner uploads via the same document/capture endpoints or `POST .../expert-resend/acknowledge` when only instructions were given.",
|
|
})
|
|
@ApiParam({ name: "claimRequestId" })
|
|
@ApiBody({ type: ClaimSubmitResendV2Dto })
|
|
async submitExpertResendV2(
|
|
@Param("claimRequestId") claimRequestId: string,
|
|
@Body() body: ClaimSubmitResendV2Dto,
|
|
@CurrentUser() actor,
|
|
) {
|
|
return await this.expertClaimService.submitResendDocsV2(claimRequestId, body, actor);
|
|
}
|
|
|
|
@Patch(":claimRequestId/visit")
|
|
@ApiOperation({
|
|
summary: "Request in-person visit for claim",
|
|
description:
|
|
"Expert decides the user must come in person. Claim must be locked by this expert. Sets claimStatus to NEEDS_REVISION and unlocks the claim so the user is informed.",
|
|
})
|
|
@ApiParam({ name: "claimRequestId" })
|
|
@ApiBody({ type: InPersonVisitV2Dto, required: false })
|
|
async requestInPersonVisitV2(
|
|
@Param("claimRequestId") claimRequestId: string,
|
|
@Body() body: InPersonVisitV2Dto,
|
|
@CurrentUser() actor,
|
|
) {
|
|
return await this.expertClaimService.requestInPersonVisitV2(
|
|
claimRequestId,
|
|
actor,
|
|
body?.note,
|
|
);
|
|
}
|
|
|
|
@Patch("validate-factors/:claimRequestId")
|
|
@ApiOperation({
|
|
summary: "Validate uploaded repair factors (V2 ClaimCase)",
|
|
description:
|
|
"After all required factors are uploaded, expert approves or rejects each part. Rejected parts must include expert totalPayment (or price and salary). All approved → insurer review. Any rejected → expert repricing and case COMPLETED.",
|
|
})
|
|
@ApiParam({ name: "claimRequestId" })
|
|
@ApiBody({ type: FactorValidationV2Dto })
|
|
async validateClaimFactorsV2(
|
|
@Param("claimRequestId") claimRequestId: string,
|
|
@Body() body: FactorValidationV2Dto,
|
|
@CurrentUser() actor,
|
|
) {
|
|
return await this.expertClaimService.validateClaimFactorsV2(
|
|
claimRequestId,
|
|
body,
|
|
actor,
|
|
);
|
|
}
|
|
|
|
@Patch("request/:claimRequestId/damaged-parts")
|
|
@ApiOperation({
|
|
summary: "Edit selected damaged parts (V2)",
|
|
description:
|
|
"Damage expert can modify selected damaged parts while claim is in EXPERT_REVIEWING and locked by the same expert.",
|
|
})
|
|
@ApiParam({ name: "claimRequestId" })
|
|
@ApiBody({ type: UpdateClaimDamagedPartsV2Dto })
|
|
async updateClaimDamagedPartsV2(
|
|
@Param("claimRequestId") claimRequestId: string,
|
|
@Body() body: UpdateClaimDamagedPartsV2Dto,
|
|
@CurrentUser() actor,
|
|
) {
|
|
return await this.expertClaimService.updateClaimDamagedPartsV2(
|
|
claimRequestId,
|
|
body,
|
|
actor,
|
|
);
|
|
}
|
|
|
|
@ApiQuery({
|
|
name: "query",
|
|
enum: ["car-capture", "accident"],
|
|
required: true,
|
|
})
|
|
@Get("stream/:id/video")
|
|
@Header("Accept-Ranges", "bytes")
|
|
@Header("Content-Type", "video/mp4")
|
|
async claimStream(
|
|
@Headers() headers,
|
|
@Param("id") id: string,
|
|
@Query("query") query: "car-capture" | "accident",
|
|
@Res() res,
|
|
) {
|
|
return this.expertClaimService.streamServiceV2(id, query, res, headers);
|
|
}
|
|
}
|