1
0
forked from Yara724/api

Fix v3 mirror flow

This commit is contained in:
SepehrYahyaee
2026-06-22 17:30:58 +03:30
parent 83e82ea68e
commit db569db9d1
15 changed files with 1004 additions and 248 deletions

View File

@@ -309,6 +309,44 @@ export class ClaimRequestManagementService {
return true;
}
/** V3 initial document step — excludes capture-phase vehicle evidence. */
private v3PreCaptureDocumentKeys(isCarBody: boolean): string[] {
return this.requiredDocumentKeysV2(isCarBody).filter(
(k) => !isCapturePhaseDamagedPartyDocKey(k),
);
}
private allV3PreCaptureDocumentsComplete(
claimCase: any,
isCarBody: boolean,
assumeUploadedKey?: string,
): boolean {
for (const k of this.v3PreCaptureDocumentKeys(isCarBody)) {
const ok =
k === assumeUploadedKey
? true
: this.isRequiredDocumentUploadedOnClaim(claimCase, k);
if (!ok) return false;
}
return true;
}
private countRemainingV3PreCaptureDocuments(
claimCase: any,
isCarBody: boolean,
assumeUploadedKey?: string,
): number {
let n = 0;
for (const k of this.v3PreCaptureDocumentKeys(isCarBody)) {
const ok =
k === assumeUploadedKey
? true
: this.isRequiredDocumentUploadedOnClaim(claimCase, k);
if (!ok) n++;
}
return n;
}
private countRemainingV2OwnerDocuments(
claimCase: any,
isCarBody: boolean,
@@ -5985,6 +6023,7 @@ export class ClaimRequestManagementService {
file: Express.Multer.File,
currentUserId: string,
actor?: { sub: string; role?: string },
options?: { v3InPersonFlow?: boolean },
): Promise<UploadRequiredDocumentV2ResponseDto> {
try {
const claimCase = await this.claimCaseDbService.findById(claimRequestId);
@@ -6042,6 +6081,21 @@ export class ClaimRequestManagementService {
`Invalid workflow step. Expected ${ClaimWorkflowStep.UPLOAD_REQUIRED_DOCUMENTS}, ${ClaimWorkflowStep.CAPTURE_PART_DAMAGES} (capture-phase documents only), or ${ClaimWorkflowStep.USER_EXPERT_RESEND}, but current step is ${claimCase.workflow?.currentStep}`,
);
}
if (options?.v3InPersonFlow) {
if (body.documentKey === ClaimRequiredDocumentType.CAR_GREEN_CARD) {
throw new BadRequestException(
"Car green card must be uploaded during other-parts selection, not in the documents step.",
);
}
if (
step === ClaimWorkflowStep.UPLOAD_REQUIRED_DOCUMENTS &&
isCapturePhaseDamagedPartyDocKey(body.documentKey)
) {
throw new BadRequestException(
`Chassis, engine, and metal plate photos must be uploaded during capture (after parts and angles), not in the initial documents step (${CAPTURE_PHASE_DAMAGED_PARTY_DOC_KEYS.join(", ")}).`,
);
}
}
}
if (isResendUpload) {
@@ -6160,8 +6214,9 @@ export class ClaimRequestManagementService {
$set["status"] = ClaimCaseStatus.UPLOADING_REQUIRED_DOCUMENTS;
$set["workflow.currentStep"] =
ClaimWorkflowStep.UPLOAD_REQUIRED_DOCUMENTS;
$set["workflow.nextStep"] =
ClaimWorkflowStep.USER_SUBMISSION_COMPLETE;
$set["workflow.nextStep"] = options?.v3InPersonFlow
? ClaimWorkflowStep.UPLOAD_REQUIRED_DOCUMENTS
: ClaimWorkflowStep.USER_SUBMISSION_COMPLETE;
completedStepsEntries.push(
ClaimWorkflowStep.CAPTURE_PART_DAMAGES,
@@ -6183,30 +6238,46 @@ export class ClaimRequestManagementService {
}
}
} else {
allDocumentsUploaded = this.allV2OwnerDocumentsComplete(
claimCase,
isCarBodyUpload,
body.documentKey,
);
remaining = this.countRemainingV2OwnerDocuments(
claimCase,
isCarBodyUpload,
body.documentKey,
);
const v3InitialDocsComplete =
!!options?.v3InPersonFlow &&
step === ClaimWorkflowStep.UPLOAD_REQUIRED_DOCUMENTS &&
this.allV3PreCaptureDocumentsComplete(
claimCase,
isCarBodyUpload,
body.documentKey,
);
allDocumentsUploaded = options?.v3InPersonFlow
? v3InitialDocsComplete
: this.allV2OwnerDocumentsComplete(
claimCase,
isCarBodyUpload,
body.documentKey,
);
remaining = options?.v3InPersonFlow
? this.countRemainingV3PreCaptureDocuments(
claimCase,
isCarBodyUpload,
body.documentKey,
)
: this.countRemainingV2OwnerDocuments(
claimCase,
isCarBodyUpload,
body.documentKey,
);
if (allDocumentsUploaded) {
$set["status"] = ClaimCaseStatus.WAITING_FOR_DAMAGE_EXPERT;
$set["claimStatus"] = ClaimStatus.PENDING;
$set["workflow.currentStep"] =
ClaimWorkflowStep.USER_SUBMISSION_COMPLETE;
$set["workflow.nextStep"] =
ClaimWorkflowStep.EXPERT_DAMAGE_ASSESSMENT;
if (options?.v3InPersonFlow) {
$set["status"] = ClaimCaseStatus.SELECTING_OUTER_PARTS;
$set["workflow.currentStep"] =
ClaimWorkflowStep.SELECT_OUTER_PARTS;
$set["workflow.nextStep"] =
ClaimWorkflowStep.SELECT_OTHER_PARTS;
completedStepsEntries.push(
ClaimWorkflowStep.UPLOAD_REQUIRED_DOCUMENTS,
);
historyEntries.push(
{
completedStepsEntries.push(
ClaimWorkflowStep.UPLOAD_REQUIRED_DOCUMENTS,
);
historyEntries.push({
type: "STEP_COMPLETED",
actor: {
actorId: new Types.ObjectId(currentUserId),
@@ -6216,24 +6287,52 @@ export class ClaimRequestManagementService {
timestamp: new Date(),
metadata: {
stepKey: ClaimWorkflowStep.UPLOAD_REQUIRED_DOCUMENTS,
description: "All required documents uploaded",
},
},
{
type: "STEP_COMPLETED",
actor: {
actorId: new Types.ObjectId(currentUserId),
actorName: claimCase.owner?.fullName || "User",
actorType: "user",
},
timestamp: new Date(),
metadata: {
stepKey: ClaimWorkflowStep.USER_SUBMISSION_COMPLETE,
description:
"User submission complete. Claim ready for damage expert review.",
"Initial required documents uploaded. Proceed to outer part selection.",
v3InPersonFlow: true,
},
},
);
});
} else {
$set["status"] = ClaimCaseStatus.WAITING_FOR_DAMAGE_EXPERT;
$set["claimStatus"] = ClaimStatus.PENDING;
$set["workflow.currentStep"] =
ClaimWorkflowStep.USER_SUBMISSION_COMPLETE;
$set["workflow.nextStep"] =
ClaimWorkflowStep.EXPERT_DAMAGE_ASSESSMENT;
completedStepsEntries.push(
ClaimWorkflowStep.UPLOAD_REQUIRED_DOCUMENTS,
);
historyEntries.push(
{
type: "STEP_COMPLETED",
actor: {
actorId: new Types.ObjectId(currentUserId),
actorName: claimCase.owner?.fullName || "User",
actorType: "user",
},
timestamp: new Date(),
metadata: {
stepKey: ClaimWorkflowStep.UPLOAD_REQUIRED_DOCUMENTS,
description: "All required documents uploaded",
},
},
{
type: "STEP_COMPLETED",
actor: {
actorId: new Types.ObjectId(currentUserId),
actorName: claimCase.owner?.fullName || "User",
actorType: "user",
},
timestamp: new Date(),
metadata: {
stepKey: ClaimWorkflowStep.USER_SUBMISSION_COMPLETE,
description:
"User submission complete. Claim ready for damage expert review.",
},
},
);
}
}
}
}
@@ -6295,7 +6394,9 @@ export class ClaimRequestManagementService {
}).sequencePhase,
)
: allDocumentsUploaded
? "All documents uploaded successfully. Your claim is now ready for damage expert review."
? options?.v3InPersonFlow
? "Initial required documents uploaded. Proceed to outer part selection."
: "All documents uploaded successfully. Your claim is now ready for damage expert review."
: `Document uploaded successfully. ${remaining} documents remaining.`;
return {
@@ -6308,7 +6409,9 @@ export class ClaimRequestManagementService {
? ClaimWorkflowStep.UPLOAD_REQUIRED_DOCUMENTS
: ClaimWorkflowStep.CAPTURE_PART_DAMAGES
: allDocumentsUploaded
? ClaimWorkflowStep.USER_SUBMISSION_COMPLETE
? options?.v3InPersonFlow
? ClaimWorkflowStep.SELECT_OUTER_PARTS
: ClaimWorkflowStep.USER_SUBMISSION_COMPLETE
: ClaimWorkflowStep.UPLOAD_REQUIRED_DOCUMENTS,
message,
};
@@ -7852,6 +7955,11 @@ export class ClaimRequestManagementService {
}
}
private v3PartsFlowNotStarted(claimCase: any): boolean {
const parts = claimCase.damage?.selectedParts;
return !Array.isArray(parts) || parts.length === 0;
}
private async advanceV3ClaimToOuterPartsIfReady(
claimCase: any,
blame: any,
@@ -7859,9 +7967,18 @@ export class ClaimRequestManagementService {
if (claimCase.workflow?.currentStep === ClaimWorkflowStep.SELECT_OUTER_PARTS) {
return;
}
if (claimCase.workflow?.currentStep !== ClaimWorkflowStep.UPLOAD_REQUIRED_DOCUMENTS) {
const step = claimCase.workflow?.currentStep;
const partsNotStarted = this.v3PartsFlowNotStarted(claimCase);
const prematurelyCompleted =
step === ClaimWorkflowStep.USER_SUBMISSION_COMPLETE && partsNotStarted;
const canAdvance =
step === ClaimWorkflowStep.UPLOAD_REQUIRED_DOCUMENTS ||
prematurelyCompleted;
if (!canAdvance) {
throw new BadRequestException(
`Complete required documents before selecting outer parts. Current step: ${claimCase.workflow?.currentStep}`,
`Complete required documents before selecting outer parts. Current step: ${step}`,
);
}
if (!(blame.expert?.decision as any)?.fields?.accidentWay) {
@@ -7869,9 +7986,11 @@ export class ClaimRequestManagementService {
"Submit accident fields before selecting outer parts.",
);
}
await this.claimCaseDbService.findByIdAndUpdate(String(claimCase._id), {
$set: {
status: ClaimCaseStatus.SELECTING_OUTER_PARTS,
claimStatus: ClaimStatus.PENDING,
"workflow.currentStep": ClaimWorkflowStep.SELECT_OUTER_PARTS,
"workflow.nextStep": ClaimWorkflowStep.SELECT_OTHER_PARTS,
},
@@ -7906,22 +8025,13 @@ export class ClaimRequestManagementService {
const blame = await this.assertV3InPersonClaim(claimCase);
this.assertV3ClaimDocumentsPhase(blame);
const step = claimCase.workflow?.currentStep;
if (step !== ClaimWorkflowStep.UPLOAD_REQUIRED_DOCUMENTS) {
await this.claimCaseDbService.findByIdAndUpdate(claimRequestId, {
$set: {
status: ClaimCaseStatus.UPLOADING_REQUIRED_DOCUMENTS,
"workflow.currentStep": ClaimWorkflowStep.UPLOAD_REQUIRED_DOCUMENTS,
},
});
}
return this.uploadRequiredDocumentV2(
claimRequestId,
body,
file,
currentUserId,
actor,
{ v3InPersonFlow: true },
);
}