1
0
forked from Yara724/api

Fixed v4/v5 car capture flow

This commit is contained in:
SepehrYahyaee
2026-07-15 15:59:21 +03:30
parent 2fda740171
commit f39c50aeb0
3 changed files with 82 additions and 54 deletions

View File

@@ -8335,36 +8335,17 @@ export class ClaimRequestManagementService {
) { ) {
captureStepCompletedOnThisUpload = true; captureStepCompletedOnThisUpload = true;
if (options?.v3InPersonFlow) { // Advance to walk-around video step (UPLOADING_REQUIRED_DOCUMENTS /
// V4/V5: no further upload steps after capture docs — finalise now. // UPLOAD_REQUIRED_DOCUMENTS). For V4/V5 the claim is finalised in
const finalStatus = options.requiresFileMakerApproval // setVideoCaptureV3 (car-capture), which is the last FileReviewer
? ClaimCaseStatus.WAITING_FOR_FILE_MAKER_APPROVAL // action before handing off to the damage expert.
: ClaimCaseStatus.WAITING_FOR_DAMAGE_EXPERT; $set["status"] = ClaimCaseStatus.UPLOADING_REQUIRED_DOCUMENTS;
$set["status"] = finalStatus; $set["workflow.currentStep"] = ClaimWorkflowStep.UPLOAD_REQUIRED_DOCUMENTS;
$set["claimStatus"] = ClaimStatus.PENDING; $set["workflow.nextStep"] = ClaimWorkflowStep.USER_SUBMISSION_COMPLETE;
$set["workflow.currentStep"] = ClaimWorkflowStep.USER_SUBMISSION_COMPLETE;
$set["workflow.nextStep"] = ClaimWorkflowStep.EXPERT_DAMAGE_ASSESSMENT;
// Mark the linked blame as COMPLETED.
if (claimCase.blameRequestId) {
await this.blameRequestDbService.findByIdAndUpdate(
String(claimCase.blameRequestId),
{ $set: { status: BlameCaseStatus.COMPLETED } },
);
}
} else {
$set["status"] = ClaimCaseStatus.UPLOADING_REQUIRED_DOCUMENTS;
$set["workflow.currentStep"] =
ClaimWorkflowStep.UPLOAD_REQUIRED_DOCUMENTS;
$set["workflow.nextStep"] = ClaimWorkflowStep.USER_SUBMISSION_COMPLETE;
}
completedStepsEntries.push( completedStepsEntries.push(
ClaimWorkflowStep.CAPTURE_PART_DAMAGES, ClaimWorkflowStep.CAPTURE_PART_DAMAGES,
); );
completedStepsEntries.push(
ClaimWorkflowStep.USER_SUBMISSION_COMPLETE,
);
historyEntries.push({ historyEntries.push({
type: "STEP_COMPLETED", type: "STEP_COMPLETED",
actor: { actor: {
@@ -8376,7 +8357,7 @@ export class ClaimRequestManagementService {
metadata: { metadata: {
stepKey: ClaimWorkflowStep.CAPTURE_PART_DAMAGES, stepKey: ClaimWorkflowStep.CAPTURE_PART_DAMAGES,
description: options?.v3InPersonFlow description: options?.v3InPersonFlow
? "V4/V5 capture complete. Claim ready for review." ? "V4/V5 capture docs complete. Upload walk-around video to finalise."
: "Angles, damaged parts, and capture-phase vehicle evidence are complete.", : "Angles, damaged parts, and capture-phase vehicle evidence are complete.",
}, },
}); });
@@ -8540,7 +8521,9 @@ export class ClaimRequestManagementService {
const message = isCapturePhaseDocUpload const message = isCapturePhaseDocUpload
? captureStepCompletedOnThisUpload ? captureStepCompletedOnThisUpload
? "Capture-phase documents and all damage captures are complete. Please proceed to upload the remaining required documents." ? options?.v3InPersonFlow
? "Capture-phase documents and all damage captures are complete. Upload the walk-around video (car-capture) to finalise."
: "Capture-phase documents and all damage captures are complete. Please proceed to upload the remaining required documents."
: remaining > 0 : remaining > 0
? `Document saved. ${remaining} capture-phase document(s) still required (chassis, engine, metal plate).` ? `Document saved. ${remaining} capture-phase document(s) still required (chassis, engine, metal plate).`
: capturePhaseSequenceMessage( : capturePhaseSequenceMessage(
@@ -10584,7 +10567,7 @@ export class ClaimRequestManagementService {
ClaimWorkflowStep.UPLOAD_REQUIRED_DOCUMENTS ClaimWorkflowStep.UPLOAD_REQUIRED_DOCUMENTS
) { ) {
throw new BadRequestException( throw new BadRequestException(
`Complete all part/angle captures first. Expected ${ClaimWorkflowStep.UPLOAD_REQUIRED_DOCUMENTS}, but current step is ${claimCase.workflow?.currentStep}`, `Complete capture-phase documents (chassis/engine) first. Expected ${ClaimWorkflowStep.UPLOAD_REQUIRED_DOCUMENTS}, but current step is ${claimCase.workflow?.currentStep}`,
); );
} }
@@ -10607,12 +10590,53 @@ export class ClaimRequestManagementService {
); );
} }
return this.setVideoCaptureV2( // Store the walk-around video (shared V2 logic).
const result = await this.setVideoCaptureV2(
claimRequestId, claimRequestId,
fileDetail, fileDetail,
currentUserId, currentUserId,
actor, actor,
); );
// V4/V5 (in-person FileReviewer flow): car-capture is the last step.
// Both variants land at WAITING_FOR_DAMAGE_EXPERT here.
// For V5 (requiresFileMakerApproval=true), autoSubmitToFanavaranV2OnClaimCompleted
// intercepts COMPLETED → WAITING_FOR_FILE_MAKER_APPROVAL after expert review.
await this.claimCaseDbService.findByIdAndUpdate(claimRequestId, {
$set: {
status: ClaimCaseStatus.WAITING_FOR_DAMAGE_EXPERT,
claimStatus: ClaimStatus.PENDING,
"workflow.currentStep": ClaimWorkflowStep.USER_SUBMISSION_COMPLETE,
"workflow.nextStep": ClaimWorkflowStep.EXPERT_DAMAGE_ASSESSMENT,
},
$push: {
"workflow.completedSteps": ClaimWorkflowStep.USER_SUBMISSION_COMPLETE,
history: {
type: "STEP_COMPLETED",
actor: {
actorId: new Types.ObjectId(currentUserId),
actorName: claimCase.owner?.fullName || "User",
actorType: actor?.role === RoleEnum.FILE_REVIEWER ? "file_reviewer" : "user",
},
timestamp: new Date(),
metadata: {
stepKey: ClaimWorkflowStep.USER_SUBMISSION_COMPLETE,
description: "V4/V5 walk-around video uploaded. Claim ready for damage expert review.",
v3InPersonFlow: true,
},
},
},
});
// Mark the linked blame file as COMPLETED.
if (claimCase.blameRequestId) {
await this.blameRequestDbService.findByIdAndUpdate(
String(claimCase.blameRequestId),
{ $set: { status: BlameCaseStatus.COMPLETED } },
);
}
return result;
} }
async capturePartV3( async capturePartV3(

View File

@@ -51,8 +51,7 @@ import { GetCaptureRequirementsV2ResponseDto } from "src/claim-request-managemen
* *
* The FileReviewer picks up a sealed file (both signatures collected by the * The FileReviewer picks up a sealed file (both signatures collected by the
* FileMaker) and completes the damage-assessment portion: accident fields, * FileMaker) and completes the damage-assessment portion: accident fields,
* documents, part selection, photo capture, walk-around video, and the final * documents, part selection, photo capture, and walk-around video (final step).
* blame accident video that moves the file to WAITING_FOR_EXPERT.
* *
* Sequence: * Sequence:
* accident-fields * accident-fields
@@ -61,9 +60,11 @@ import { GetCaptureRequirementsV2ResponseDto } from "src/claim-request-managemen
* → select-outer-parts * → select-outer-parts
* → select-other-parts * → select-other-parts
* → capture-part (damaged-part photos + four angles) * → capture-part (damaged-part photos + four angles)
* → upload-document (chassis / engine / metal plate — capture phase) * → upload-document (chassis / engine — capture phase)
* → car-capture (walk-around video) * → car-capture (walk-around video — FINAL FileReviewer step)
* → upload-video (blame accident video — final, moves to WAITING_FOR_EXPERT) * ↳ claim → WAITING_FOR_DAMAGE_EXPERT, blame → COMPLETED
*
* NOTE: upload-video is a no-op for V4 (blame is already COMPLETED by car-capture).
*/ */
@ApiTags("v4 FileReviewer — blame file review & capture") @ApiTags("v4 FileReviewer — blame file review & capture")
@Controller("v4/file-reviewer/blame-request-management") @Controller("v4/file-reviewer/blame-request-management")
@@ -341,9 +342,10 @@ export class FileReviewerBlameV4Controller {
}, },
}) })
@ApiOperation({ @ApiOperation({
summary: "Walk-around video", summary: "Walk-around video (final FileReviewer step — V4)",
description: description:
"Upload after capture-part is complete (parts, angles, capture-phase docs). Required before the final blame accident video.", "Last FileReviewer action. Upload after capture-part is complete (parts, angles, chassis/engine docs). " +
"Finalises the claim → WAITING_FOR_DAMAGE_EXPERT and marks the blame as COMPLETED.",
}) })
async carCapture( async carCapture(
@Param("claimRequestId") claimRequestId: string, @Param("claimRequestId") claimRequestId: string,
@@ -384,10 +386,10 @@ export class FileReviewerBlameV4Controller {
@Post("upload-video/:requestId") @Post("upload-video/:requestId")
@ApiParam({ name: "requestId" }) @ApiParam({ name: "requestId" })
@ApiOperation({ @ApiOperation({
summary: "Blame accident video (FileReviewer final step — optional)", summary: "Blame accident video (no-op for V4 — car-capture is the final step)",
description: description:
"Last step of the V4 flow. Requires claim walk-around video and completed capture. " + "Deprecated for V4. The blame is already COMPLETED by car-capture. " +
"File is optional — omit it to complete the blame without attaching a video.", "Calling this endpoint returns an idempotent success response.",
}) })
async uploadBlameVideo( async uploadBlameVideo(
@Param("requestId") requestId: string, @Param("requestId") requestId: string,

View File

@@ -47,11 +47,9 @@ import {
import { GetCaptureRequirementsV2ResponseDto } from "src/claim-request-management/dto/capture-requirements-v2.dto"; import { GetCaptureRequirementsV2ResponseDto } from "src/claim-request-management/dto/capture-requirements-v2.dto";
/** /**
* V5 FileReviewer flow — same as V4 except the final blame accident video moves * V5 FileReviewer flow — same as V4 except after the damage expert completes
* the file to WAITING_FOR_FINANCIAL_EXPERT instead of WAITING_FOR_EXPERT. * their review, the claim goes to WAITING_FOR_FILE_MAKER_APPROVAL instead of
* * being submitted directly to fanavaran.
* A FinancialExpert must then approve the file (→ WAITING_FOR_EXPERT) or
* reject it back (→ FINANCIAL_EXPERT_REJECTED) for the FileReviewer to correct.
* *
* Sequence: * Sequence:
* accident-fields * accident-fields
@@ -60,9 +58,12 @@ import { GetCaptureRequirementsV2ResponseDto } from "src/claim-request-managemen
* → select-outer-parts * → select-outer-parts
* → select-other-parts * → select-other-parts
* → capture-part (damaged-part photos + four angles) * → capture-part (damaged-part photos + four angles)
* → upload-document (chassis / engine / metal plate — capture phase) * → upload-document (chassis / engine — capture phase)
* → car-capture (walk-around video) * → car-capture (walk-around video — FINAL FileReviewer step)
* → upload-video (blame accident video — final, moves to WAITING_FOR_FINANCIAL_EXPERT) * ↳ claim → WAITING_FOR_DAMAGE_EXPERT, blame → COMPLETED
* ↳ after expert review: claim → WAITING_FOR_FILE_MAKER_APPROVAL
*
* NOTE: upload-video is a no-op for V5 (blame is already COMPLETED by car-capture).
*/ */
@ApiTags("v5 FileReviewer — blame file review & capture (with FinancialExpert approval)") @ApiTags("v5 FileReviewer — blame file review & capture (with FinancialExpert approval)")
@Controller("v5/file-reviewer/blame-request-management") @Controller("v5/file-reviewer/blame-request-management")
@@ -340,9 +341,11 @@ export class FileReviewerBlameV5Controller {
}, },
}) })
@ApiOperation({ @ApiOperation({
summary: "Walk-around video", summary: "Walk-around video (final FileReviewer step — V5)",
description: description:
"Upload after capture-part is complete (parts, angles, capture-phase docs). Required before the final blame accident video.", "Last FileReviewer action. Upload after capture-part is complete (parts, angles, chassis/engine docs). " +
"Finalises the claim → WAITING_FOR_DAMAGE_EXPERT and marks the blame as COMPLETED. " +
"After the damage expert review completes the claim moves to WAITING_FOR_FILE_MAKER_APPROVAL.",
}) })
async carCapture( async carCapture(
@Param("claimRequestId") claimRequestId: string, @Param("claimRequestId") claimRequestId: string,
@@ -360,7 +363,6 @@ export class FileReviewerBlameV5Controller {
// ─── Final blame video ───────────────────────────────────────────────────────── // ─── Final blame video ─────────────────────────────────────────────────────────
// //
// V5 difference: moves file to WAITING_FOR_FINANCIAL_EXPERT, not WAITING_FOR_EXPERT.
@ApiBody({ @ApiBody({
schema: { schema: {
@@ -385,10 +387,10 @@ export class FileReviewerBlameV5Controller {
@Post("upload-video/:requestId") @Post("upload-video/:requestId")
@ApiParam({ name: "requestId" }) @ApiParam({ name: "requestId" })
@ApiOperation({ @ApiOperation({
summary: "Blame accident video (FileReviewer final step — V5, optional)", summary: "Blame accident video (no-op for V5 — car-capture is the final step)",
description: description:
"Last step of the V5 FileReviewer flow. Requires claim walk-around video and completed capture. " + "Deprecated for V5. The blame is already COMPLETED by car-capture. " +
"File is optional — omit it to complete the blame without attaching a video.", "Calling this endpoint returns an idempotent success response.",
}) })
async uploadBlameVideo( async uploadBlameVideo(
@Param("requestId") requestId: string, @Param("requestId") requestId: string,