forked from Yara724/api
Fixed 3 upload documents for capture part
This commit is contained in:
@@ -106,6 +106,9 @@
|
||||
"**/*.(t|j)s"
|
||||
],
|
||||
"coverageDirectory": "../coverage",
|
||||
"testEnvironment": "node"
|
||||
"testEnvironment": "node",
|
||||
"moduleNameMapper": {
|
||||
"^src/(.*)$": "<rootDir>/$1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,16 +120,13 @@ import {
|
||||
resolvePartCaptureIndex,
|
||||
} from "src/helpers/outer-damage-parts";
|
||||
|
||||
/** Same `requiredDocuments` keys as in getCaptureRequirementsV2; upload allowed during CAPTURE_PART_DAMAGES. */
|
||||
const CAPTURE_PHASE_DAMAGED_PARTY_DOC_KEYS = [
|
||||
"damaged_chassis_number",
|
||||
"damaged_engine_photo",
|
||||
"damaged_metal_plate",
|
||||
] as const;
|
||||
|
||||
function isCapturePhaseDamagedPartyDocKey(key: string): boolean {
|
||||
return (CAPTURE_PHASE_DAMAGED_PARTY_DOC_KEYS as readonly string[]).includes(key);
|
||||
}
|
||||
import {
|
||||
CAPTURE_PHASE_DAMAGED_PARTY_DOC_KEYS,
|
||||
capturePhaseSequenceMessage,
|
||||
getClaimCaptureProgress,
|
||||
isCapturePhaseDamagedPartyDocKey,
|
||||
isClaimCaptureStepComplete,
|
||||
} from "src/helpers/claim-capture-phase";
|
||||
|
||||
@Injectable()
|
||||
export class ClaimRequestManagementService {
|
||||
@@ -203,12 +200,6 @@ export class ClaimRequestManagementService {
|
||||
return !!doc?.uploaded;
|
||||
}
|
||||
|
||||
private capturePhaseDamagedPartyDocsComplete(claimCase: any): boolean {
|
||||
return CAPTURE_PHASE_DAMAGED_PARTY_DOC_KEYS.every((k) =>
|
||||
this.isRequiredDocumentUploadedOnClaim(claimCase, k),
|
||||
);
|
||||
}
|
||||
|
||||
private allV2OwnerDocumentsComplete(
|
||||
claimCase: any,
|
||||
isCarBody: boolean,
|
||||
@@ -4633,15 +4624,31 @@ export class ClaimRequestManagementService {
|
||||
const anglesCaptured = carAngles.filter(a => a.captured).length;
|
||||
const partsCaptured = damagedParts.filter(p => p.captured).length;
|
||||
|
||||
const totalRemaining =
|
||||
(requiredDocuments.length - documentsUploaded) +
|
||||
(carAngles.length - anglesCaptured) +
|
||||
(damagedParts.length - partsCaptured);
|
||||
const captureProgress = getClaimCaptureProgress(claimCase);
|
||||
const capturePhaseDocsRemaining = captureProgress.capturePhaseDocsRemaining;
|
||||
const partsRemaining = Math.max(
|
||||
0,
|
||||
captureProgress.partsTotal - captureProgress.partsCaptured,
|
||||
);
|
||||
const anglesRemaining = Math.max(
|
||||
0,
|
||||
captureProgress.anglesTotal - captureProgress.anglesCaptured,
|
||||
);
|
||||
const postCaptureDocsRemaining = requiredDocuments.filter(
|
||||
(d) => !d.preferUploadDuringCapture && !d.uploaded,
|
||||
).length;
|
||||
|
||||
const totalRemaining =
|
||||
partsRemaining + anglesRemaining + capturePhaseDocsRemaining;
|
||||
|
||||
return {
|
||||
claimRequestId: claimCase._id.toString(),
|
||||
publicId: claimCase.publicId,
|
||||
currentStep: claimCase.workflow?.currentStep || '',
|
||||
captureSequencePhase: captureProgress.sequencePhase,
|
||||
captureSequenceHint: capturePhaseSequenceMessage(
|
||||
captureProgress.sequencePhase,
|
||||
),
|
||||
requiredDocuments,
|
||||
carAngles,
|
||||
damagedParts,
|
||||
@@ -4653,6 +4660,8 @@ export class ClaimRequestManagementService {
|
||||
anglesTotal: carAngles.length,
|
||||
partsCaptured,
|
||||
partsTotal: damagedParts.length,
|
||||
capturePhaseDocsRemaining,
|
||||
postCaptureDocumentsRemaining: postCaptureDocsRemaining,
|
||||
},
|
||||
};
|
||||
} catch (error) {
|
||||
@@ -4796,9 +4805,22 @@ export class ClaimRequestManagementService {
|
||||
if (!isResendUpload) {
|
||||
if (step === ClaimWorkflowStep.CAPTURE_PART_DAMAGES && !isCapturePhaseDocUpload) {
|
||||
throw new BadRequestException(
|
||||
`During ${ClaimWorkflowStep.CAPTURE_PART_DAMAGES} only chassis, engine, and damaged metal plate photos may be uploaded here (${CAPTURE_PHASE_DAMAGED_PARTY_DOC_KEYS.join(", ")}).`,
|
||||
`During ${ClaimWorkflowStep.CAPTURE_PART_DAMAGES} only chassis, engine, and damaged metal plate photos may be uploaded here (${CAPTURE_PHASE_DAMAGED_PARTY_DOC_KEYS.join(", ")}), and only after all damaged parts and car angles are captured.`,
|
||||
);
|
||||
}
|
||||
if (isCapturePhaseDocUpload) {
|
||||
const captureProgress = getClaimCaptureProgress(claimCase);
|
||||
if (!captureProgress.partsComplete) {
|
||||
throw new BadRequestException(
|
||||
"Upload photos for all selected damaged parts before uploading chassis, engine, or metal plate photos.",
|
||||
);
|
||||
}
|
||||
if (!captureProgress.anglesComplete) {
|
||||
throw new BadRequestException(
|
||||
"Capture all four car angles (front, back, left, right) before uploading chassis, engine, or metal plate photos.",
|
||||
);
|
||||
}
|
||||
}
|
||||
const allowedInitialUploadStep =
|
||||
step === ClaimWorkflowStep.UPLOAD_REQUIRED_DOCUMENTS || isCapturePhaseDocUpload;
|
||||
if (!allowedInitialUploadStep) {
|
||||
@@ -4896,31 +4918,14 @@ export class ClaimRequestManagementService {
|
||||
allDocumentsUploaded = false;
|
||||
|
||||
if (remaining === 0) {
|
||||
// After this upload all 3 capture-phase docs will be on the claim.
|
||||
// Check angles + parts captures using the in-memory claim media.
|
||||
const carAnglesData = (claimCase.media as any)?.carAngles;
|
||||
const damagedPartsData = (claimCase.media as any)?.damagedParts;
|
||||
const selectedNorm = normalizeDamageSelectedParts(
|
||||
claimCase.damage?.selectedParts,
|
||||
claimCase.vehicle?.carType as ClaimVehicleTypeV2,
|
||||
(claimCase.damage as any)?.selectedOuterParts,
|
||||
);
|
||||
const anglesKeys = ["front", "back", "left", "right"];
|
||||
const anglesCaptured = anglesKeys.filter((k) =>
|
||||
hasClaimCarAngleCapture(
|
||||
carAnglesData,
|
||||
damagedPartsData,
|
||||
k as ClaimCarAngleKey,
|
||||
),
|
||||
).length;
|
||||
const partsCaptured = selectedNorm.filter((sp) => {
|
||||
const ck = sp.catalogKey ?? catalogLikeKeyFromPart(sp);
|
||||
return hasDamagedPartCapture(damagedPartsData, ck, selectedNorm);
|
||||
}).length;
|
||||
const progressAfterDoc = getClaimCaptureProgress(claimCase, {
|
||||
assumeCapturePhaseDocKey: body.documentKey,
|
||||
});
|
||||
|
||||
if (
|
||||
anglesCaptured >= 4 &&
|
||||
partsCaptured >= selectedNorm.length
|
||||
progressAfterDoc.partsComplete &&
|
||||
progressAfterDoc.anglesComplete &&
|
||||
progressAfterDoc.capturePhaseDocsComplete
|
||||
) {
|
||||
captureStepCompletedOnThisUpload = true;
|
||||
updateData["status"] = ClaimCaseStatus.UPLOADING_REQUIRED_DOCUMENTS;
|
||||
@@ -5031,8 +5036,12 @@ export class ClaimRequestManagementService {
|
||||
? captureStepCompletedOnThisUpload
|
||||
? "Capture-phase documents and all damage captures are complete. Please proceed to upload the remaining required documents."
|
||||
: remaining > 0
|
||||
? `Document saved. ${remaining} capture-phase document(s) still required (chassis, engine, metal plate) before you can finish damage capture.`
|
||||
: "Document saved. All capture-phase documents are uploaded; finish car angles and part photos to proceed."
|
||||
? `Document saved. ${remaining} capture-phase document(s) still required (chassis, engine, metal plate).`
|
||||
: capturePhaseSequenceMessage(
|
||||
getClaimCaptureProgress(claimCase, {
|
||||
assumeCapturePhaseDocKey: body.documentKey,
|
||||
}).sequencePhase,
|
||||
)
|
||||
: allDocumentsUploaded
|
||||
? "All documents uploaded successfully. Your claim is now ready for damage expert review."
|
||||
: `Document uploaded successfully. ${remaining} documents remaining.`;
|
||||
@@ -5114,6 +5123,19 @@ export class ClaimRequestManagementService {
|
||||
}
|
||||
}
|
||||
|
||||
if (!isResendCapture) {
|
||||
const captureProgressBefore = getClaimCaptureProgress(claimCase);
|
||||
const willBeAngle =
|
||||
body.captureType === "angle" ||
|
||||
(body.captureType === "part" &&
|
||||
canonicalizeClaimCarAngleKey(body.captureKey) !== null);
|
||||
if (willBeAngle && !captureProgressBefore.partsComplete) {
|
||||
throw new BadRequestException(
|
||||
"Upload photos for all selected damaged parts before capturing car angles.",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const angleCanon = canonicalizeClaimCarAngleKey(body.captureKey);
|
||||
if (body.captureType === "angle" && !angleCanon) {
|
||||
throw new BadRequestException(
|
||||
@@ -5269,40 +5291,8 @@ export class ClaimRequestManagementService {
|
||||
};
|
||||
}
|
||||
|
||||
const hasCapture = (data: any, key: string) =>
|
||||
data && (data instanceof Map ? data.get(key) : data[key]);
|
||||
|
||||
// Use same logic as getCaptureRequirementsV2 to determine completion
|
||||
const anglesKeys = ["front", "back", "left", "right"];
|
||||
const carAnglesData = updatedClaim?.media?.carAngles as any;
|
||||
const damagedPartsData = updatedClaim?.media?.damagedParts as any;
|
||||
const selectedNormAfter = normalizeDamageSelectedParts(
|
||||
updatedClaim?.damage?.selectedParts,
|
||||
updatedClaim?.vehicle?.carType as ClaimVehicleTypeV2,
|
||||
(updatedClaim?.damage as any)?.selectedOuterParts,
|
||||
);
|
||||
|
||||
const anglesCaptured = anglesKeys.filter((k) =>
|
||||
hasClaimCarAngleCapture(
|
||||
carAnglesData,
|
||||
damagedPartsData,
|
||||
k as ClaimCarAngleKey,
|
||||
),
|
||||
).length;
|
||||
const partsCaptured = selectedNormAfter.filter((sp) => {
|
||||
const ck = sp.catalogKey ?? catalogLikeKeyFromPart(sp);
|
||||
return hasDamagedPartCapture(
|
||||
damagedPartsData,
|
||||
ck,
|
||||
selectedNormAfter,
|
||||
);
|
||||
}).length;
|
||||
|
||||
const capturePhaseDocsDone = this.capturePhaseDamagedPartyDocsComplete(updatedClaim);
|
||||
const allCapturesComplete =
|
||||
anglesCaptured >= 4 &&
|
||||
partsCaptured >= selectedNormAfter.length &&
|
||||
capturePhaseDocsDone;
|
||||
const captureProgress = getClaimCaptureProgress(updatedClaim);
|
||||
const allCapturesComplete = isClaimCaptureStepComplete(updatedClaim);
|
||||
|
||||
if (allCapturesComplete) {
|
||||
await this.claimCaseDbService.findByIdAndUpdate(claimRequestId, {
|
||||
@@ -5329,16 +5319,21 @@ export class ClaimRequestManagementService {
|
||||
});
|
||||
}
|
||||
|
||||
const captureDocsRemaining = CAPTURE_PHASE_DAMAGED_PARTY_DOC_KEYS.filter(
|
||||
(k) => !this.isRequiredDocumentUploadedOnClaim(updatedClaim, k),
|
||||
).length;
|
||||
const partsRemaining = Math.max(
|
||||
0,
|
||||
captureProgress.partsTotal - captureProgress.partsCaptured,
|
||||
);
|
||||
const anglesRemaining = Math.max(
|
||||
0,
|
||||
captureProgress.anglesTotal - captureProgress.anglesCaptured,
|
||||
);
|
||||
const remaining =
|
||||
(4 - anglesCaptured) +
|
||||
(selectedNormAfter.length - partsCaptured) +
|
||||
captureDocsRemaining;
|
||||
partsRemaining +
|
||||
anglesRemaining +
|
||||
captureProgress.capturePhaseDocsRemaining;
|
||||
const message = allCapturesComplete
|
||||
? 'All captures complete. Please proceed to upload required documents.'
|
||||
: `${body.captureType === 'angle' ? 'Angle' : 'Part'} captured successfully. ${remaining} items remaining (angles, parts, and capture-phase documents).`;
|
||||
? "All captures complete. Please proceed to upload the remaining required documents."
|
||||
: `${body.captureType === "angle" ? "Angle" : "Part"} captured successfully. ${capturePhaseSequenceMessage(captureProgress.sequencePhase)} (${remaining} item(s) left in this step).`;
|
||||
|
||||
return {
|
||||
claimRequestId: claimCase._id.toString(),
|
||||
@@ -5393,6 +5388,18 @@ export class ClaimRequestManagementService {
|
||||
);
|
||||
}
|
||||
|
||||
const captureProgress = getClaimCaptureProgress(claimCase);
|
||||
if (!captureProgress.partsComplete) {
|
||||
throw new BadRequestException(
|
||||
"Upload photos for all selected damaged parts before uploading the walk-around video.",
|
||||
);
|
||||
}
|
||||
if (!captureProgress.anglesComplete) {
|
||||
throw new BadRequestException(
|
||||
"Capture all four car angles (front, back, left, right) before uploading the walk-around video.",
|
||||
);
|
||||
}
|
||||
|
||||
if (claimCase.media?.videoCaptureId) {
|
||||
throw new ConflictException('A video has already been uploaded for this claim.');
|
||||
}
|
||||
|
||||
@@ -649,7 +649,7 @@ Optional: upload car green card file in the same step.
|
||||
|
||||
Returns status of each item (uploaded/captured or not).
|
||||
|
||||
**V2 order:** During \`CAPTURE_PART_DAMAGES\`, complete angles, part photos, walk-around video, and the three \`preferUploadDuringCapture\` documents (same upload-document API). Then complete the remaining documents in \`UPLOAD_REQUIRED_DOCUMENTS\`.
|
||||
**V2 order (enforced by API):** During \`CAPTURE_PART_DAMAGES\`, (1) all damaged-part photos, (2) four car angles, (3) chassis/engine/metal-plate via upload-document, then walk-around video. Remaining documents in \`UPLOAD_REQUIRED_DOCUMENTS\`. Use \`captureSequencePhase\` / \`captureSequenceHint\` in the response.
|
||||
`,
|
||||
})
|
||||
@ApiParam({
|
||||
@@ -828,7 +828,7 @@ Returns status of each item (uploaded/captured or not).
|
||||
1. **angle**: Car angles (front, back, left, right) - 4 required
|
||||
2. **part**: Damaged parts based on selectedParts from Step 2
|
||||
|
||||
**When all captures are complete:** Workflow moves to UPLOAD_REQUIRED_DOCUMENTS (Step 5).
|
||||
**When all captures are complete (parts, angles, capture-phase docs):** Workflow moves to UPLOAD_REQUIRED_DOCUMENTS (Step 5). Angles are blocked until all parts are captured; capture-phase documents are blocked until all angles are captured.
|
||||
|
||||
**Field expert IN_PERSON:** Same endpoint; use with claim created from expert-initiated IN_PERSON blame to capture photos on behalf of the damaged party.
|
||||
`,
|
||||
|
||||
@@ -144,6 +144,20 @@ export class GetCaptureRequirementsV2ResponseDto {
|
||||
})
|
||||
currentStep: string;
|
||||
|
||||
@ApiProperty({
|
||||
description:
|
||||
'Ordered capture phase during CAPTURE_PART_DAMAGES: parts → angles → capture_phase_documents',
|
||||
example: 'angles',
|
||||
enum: ['parts', 'angles', 'capture_phase_documents', 'complete'],
|
||||
})
|
||||
captureSequencePhase: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Human-readable hint for what the user should do next in the capture step',
|
||||
example: 'Capture all four car angles (front, back, left, right) next.',
|
||||
})
|
||||
captureSequenceHint: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'List of required documents to upload',
|
||||
type: [RequiredDocumentItem],
|
||||
@@ -186,5 +200,7 @@ export class GetCaptureRequirementsV2ResponseDto {
|
||||
anglesTotal: number;
|
||||
partsCaptured: number;
|
||||
partsTotal: number;
|
||||
capturePhaseDocsRemaining: number;
|
||||
postCaptureDocumentsRemaining: number;
|
||||
};
|
||||
}
|
||||
|
||||
95
src/helpers/claim-capture-phase.spec.ts
Normal file
95
src/helpers/claim-capture-phase.spec.ts
Normal file
@@ -0,0 +1,95 @@
|
||||
import {
|
||||
getClaimCaptureProgress,
|
||||
isClaimCaptureStepComplete,
|
||||
} from "./claim-capture-phase";
|
||||
|
||||
describe("claim-capture-phase", () => {
|
||||
const baseClaim = {
|
||||
vehicle: { carType: "sedan" },
|
||||
damage: {
|
||||
selectedParts: [{ name: "hood", side: "front", label_fa: "کاپوت" }],
|
||||
},
|
||||
media: { carAngles: {}, damagedParts: [] },
|
||||
requiredDocuments: {},
|
||||
};
|
||||
|
||||
it("starts in parts phase", () => {
|
||||
const p = getClaimCaptureProgress(baseClaim);
|
||||
expect(p.sequencePhase).toBe("parts");
|
||||
expect(p.partsComplete).toBe(false);
|
||||
});
|
||||
|
||||
it("moves to angles after all parts", () => {
|
||||
const claim = {
|
||||
...baseClaim,
|
||||
media: {
|
||||
carAngles: {},
|
||||
damagedParts: [
|
||||
{
|
||||
name: "hood",
|
||||
side: "front",
|
||||
label_fa: "کاپوت",
|
||||
path: "/x.jpg",
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
const p = getClaimCaptureProgress(claim);
|
||||
expect(p.sequencePhase).toBe("angles");
|
||||
expect(p.partsComplete).toBe(true);
|
||||
expect(p.anglesComplete).toBe(false);
|
||||
});
|
||||
|
||||
it("does not complete capture step with only capture-phase docs uploaded", () => {
|
||||
const claim = {
|
||||
...baseClaim,
|
||||
media: {
|
||||
carAngles: {},
|
||||
damagedParts: [
|
||||
{
|
||||
name: "hood",
|
||||
side: "front",
|
||||
label_fa: "کاپوت",
|
||||
path: "/x.jpg",
|
||||
},
|
||||
],
|
||||
},
|
||||
requiredDocuments: {
|
||||
damaged_chassis_number: { uploaded: true },
|
||||
damaged_engine_photo: { uploaded: true },
|
||||
damaged_metal_plate: { uploaded: true },
|
||||
},
|
||||
};
|
||||
expect(isClaimCaptureStepComplete(claim)).toBe(false);
|
||||
expect(getClaimCaptureProgress(claim).sequencePhase).toBe("angles");
|
||||
});
|
||||
|
||||
it("is complete only when parts, angles, and capture-phase docs are done", () => {
|
||||
const claim = {
|
||||
...baseClaim,
|
||||
media: {
|
||||
carAngles: {
|
||||
front: { path: "/f.jpg" },
|
||||
back: { path: "/b.jpg" },
|
||||
left: { path: "/l.jpg" },
|
||||
right: { path: "/r.jpg" },
|
||||
},
|
||||
damagedParts: [
|
||||
{
|
||||
name: "hood",
|
||||
side: "front",
|
||||
label_fa: "کاپوت",
|
||||
path: "/x.jpg",
|
||||
},
|
||||
],
|
||||
},
|
||||
requiredDocuments: {
|
||||
damaged_chassis_number: { uploaded: true },
|
||||
damaged_engine_photo: { uploaded: true },
|
||||
damaged_metal_plate: { uploaded: true },
|
||||
},
|
||||
};
|
||||
expect(isClaimCaptureStepComplete(claim)).toBe(true);
|
||||
expect(getClaimCaptureProgress(claim).sequencePhase).toBe("complete");
|
||||
});
|
||||
});
|
||||
127
src/helpers/claim-capture-phase.ts
Normal file
127
src/helpers/claim-capture-phase.ts
Normal file
@@ -0,0 +1,127 @@
|
||||
import {
|
||||
CLAIM_CAR_ANGLE_KEYS,
|
||||
hasClaimCarAngleCapture,
|
||||
hasDamagedPartCapture,
|
||||
} from "src/helpers/claim-car-angle-media";
|
||||
import {
|
||||
catalogLikeKeyFromPart,
|
||||
normalizeDamageSelectedParts,
|
||||
} from "src/helpers/outer-damage-parts";
|
||||
import type { ClaimVehicleTypeV2 } from "src/static/outer-car-parts-catalog";
|
||||
|
||||
/** Upload during CAPTURE_PART_DAMAGES (after parts + angles). */
|
||||
export const CAPTURE_PHASE_DAMAGED_PARTY_DOC_KEYS = [
|
||||
"damaged_chassis_number",
|
||||
"damaged_engine_photo",
|
||||
"damaged_metal_plate",
|
||||
] as const;
|
||||
|
||||
export type CapturePhaseSequence =
|
||||
| "parts"
|
||||
| "angles"
|
||||
| "capture_phase_documents"
|
||||
| "complete";
|
||||
|
||||
export interface ClaimCaptureProgress {
|
||||
partsCaptured: number;
|
||||
partsTotal: number;
|
||||
partsComplete: boolean;
|
||||
anglesCaptured: number;
|
||||
anglesTotal: number;
|
||||
anglesComplete: boolean;
|
||||
capturePhaseDocsComplete: boolean;
|
||||
capturePhaseDocsRemaining: number;
|
||||
sequencePhase: CapturePhaseSequence;
|
||||
}
|
||||
|
||||
export function isCapturePhaseDamagedPartyDocKey(key: string): boolean {
|
||||
return (CAPTURE_PHASE_DAMAGED_PARTY_DOC_KEYS as readonly string[]).includes(
|
||||
key,
|
||||
);
|
||||
}
|
||||
|
||||
function isRequiredDocumentUploadedOnClaim(
|
||||
claimCase: any,
|
||||
key: string,
|
||||
): boolean {
|
||||
const doc =
|
||||
(claimCase?.requiredDocuments as any)?.get?.(key) ??
|
||||
claimCase?.requiredDocuments?.[key];
|
||||
return !!doc?.uploaded;
|
||||
}
|
||||
|
||||
export function getClaimCaptureProgress(
|
||||
claimCase: any,
|
||||
options?: { assumeCapturePhaseDocKey?: string },
|
||||
): ClaimCaptureProgress {
|
||||
const carType = claimCase?.vehicle?.carType as ClaimVehicleTypeV2 | undefined;
|
||||
const selectedNorm = normalizeDamageSelectedParts(
|
||||
claimCase?.damage?.selectedParts,
|
||||
carType,
|
||||
claimCase?.damage?.selectedOuterParts,
|
||||
);
|
||||
const carAnglesData = claimCase?.media?.carAngles;
|
||||
const damagedPartsData = claimCase?.media?.damagedParts;
|
||||
|
||||
const anglesCaptured = CLAIM_CAR_ANGLE_KEYS.filter((k) =>
|
||||
hasClaimCarAngleCapture(carAnglesData, damagedPartsData, k),
|
||||
).length;
|
||||
const partsCaptured = selectedNorm.filter((sp) => {
|
||||
const ck = sp.catalogKey ?? catalogLikeKeyFromPart(sp);
|
||||
return hasDamagedPartCapture(damagedPartsData, ck, selectedNorm);
|
||||
}).length;
|
||||
|
||||
const partsTotal = selectedNorm.length;
|
||||
const partsComplete = partsTotal === 0 || partsCaptured >= partsTotal;
|
||||
const anglesTotal = CLAIM_CAR_ANGLE_KEYS.length;
|
||||
const anglesComplete = anglesCaptured >= anglesTotal;
|
||||
|
||||
const capturePhaseDocsRemaining = CAPTURE_PHASE_DAMAGED_PARTY_DOC_KEYS.filter(
|
||||
(k) => {
|
||||
if (k === options?.assumeCapturePhaseDocKey) return false;
|
||||
return !isRequiredDocumentUploadedOnClaim(claimCase, k);
|
||||
},
|
||||
).length;
|
||||
const capturePhaseDocsComplete = capturePhaseDocsRemaining === 0;
|
||||
|
||||
let sequencePhase: CapturePhaseSequence = "parts";
|
||||
if (partsComplete && !anglesComplete) {
|
||||
sequencePhase = "angles";
|
||||
} else if (partsComplete && anglesComplete && !capturePhaseDocsComplete) {
|
||||
sequencePhase = "capture_phase_documents";
|
||||
} else if (partsComplete && anglesComplete && capturePhaseDocsComplete) {
|
||||
sequencePhase = "complete";
|
||||
}
|
||||
|
||||
return {
|
||||
partsCaptured,
|
||||
partsTotal,
|
||||
partsComplete,
|
||||
anglesCaptured,
|
||||
anglesTotal,
|
||||
anglesComplete,
|
||||
capturePhaseDocsComplete,
|
||||
capturePhaseDocsRemaining,
|
||||
sequencePhase,
|
||||
};
|
||||
}
|
||||
|
||||
export function isClaimCaptureStepComplete(claimCase: any): boolean {
|
||||
const p = getClaimCaptureProgress(claimCase);
|
||||
return (
|
||||
p.partsComplete && p.anglesComplete && p.capturePhaseDocsComplete
|
||||
);
|
||||
}
|
||||
|
||||
export function capturePhaseSequenceMessage(phase: CapturePhaseSequence): string {
|
||||
switch (phase) {
|
||||
case "parts":
|
||||
return "Upload photos for all selected damaged parts first.";
|
||||
case "angles":
|
||||
return "Capture all four car angles (front, back, left, right) next.";
|
||||
case "capture_phase_documents":
|
||||
return "Upload chassis number, engine photo, and damaged metal plate photos last.";
|
||||
default:
|
||||
return "Damage capture is complete.";
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user