forked from Yara724/api
Merge pull request 'main' (#56) from s.hajizadeh/yara724api:main into main
Reviewed-on: Yara724/api#56
This commit is contained in:
@@ -17,8 +17,24 @@ export enum ClaimCaseStatus {
|
|||||||
// Expert flow
|
// Expert flow
|
||||||
WAITING_FOR_DAMAGE_EXPERT = "WAITING_FOR_DAMAGE_EXPERT",
|
WAITING_FOR_DAMAGE_EXPERT = "WAITING_FOR_DAMAGE_EXPERT",
|
||||||
EXPERT_REVIEWING = "EXPERT_REVIEWING",
|
EXPERT_REVIEWING = "EXPERT_REVIEWING",
|
||||||
|
/**
|
||||||
|
* @deprecated Prefer specific post-expert statuses below. Kept for existing DB rows and reads.
|
||||||
|
* Historically used for all owner/insurer steps after expert pricing.
|
||||||
|
*/
|
||||||
WAITING_FOR_INSURER_APPROVAL = "WAITING_FOR_INSURER_APPROVAL",
|
WAITING_FOR_INSURER_APPROVAL = "WAITING_FOR_INSURER_APPROVAL",
|
||||||
|
|
||||||
|
/** Expert reply has only priced lines (`factorNeeded=false` everywhere). Owner final accept/reject at `INSURER_REVIEW`. Also set after expert finishes repair-factor validation when the case returns to final owner sign-off. */
|
||||||
|
INSURER_REVIEW_AWAITING_OWNER_SIGN = "INSURER_REVIEW_AWAITING_OWNER_SIGN",
|
||||||
|
|
||||||
|
/** Expert reply mixes priced lines and factor-needed lines: owner signs priced lines, then uploads factors (status stays through both sub-steps). */
|
||||||
|
INSURER_REVIEW_MIXED_FACTORS_PENDING = "INSURER_REVIEW_MIXED_FACTORS_PENDING",
|
||||||
|
|
||||||
|
/** Expert reply requires a repair-factor file for every line before cost validation. */
|
||||||
|
OWNER_REPAIR_FACTOR_UPLOAD_PENDING = "OWNER_REPAIR_FACTOR_UPLOAD_PENDING",
|
||||||
|
|
||||||
|
/** All required factor files are uploaded; damage expert validates factors (`UNDER_REVIEW` @ `EXPERT_COST_EVALUATION`). */
|
||||||
|
EXPERT_VALIDATING_REPAIR_FACTORS = "EXPERT_VALIDATING_REPAIR_FACTORS",
|
||||||
|
|
||||||
// Final states
|
// Final states
|
||||||
COMPLETED = "COMPLETED",
|
COMPLETED = "COMPLETED",
|
||||||
CANCELLED = "CANCELLED",
|
CANCELLED = "CANCELLED",
|
||||||
|
|||||||
@@ -85,6 +85,8 @@ import {
|
|||||||
partKeyAllowedForExpertResend,
|
partKeyAllowedForExpertResend,
|
||||||
} from "src/helpers/claim-expert-resend";
|
} from "src/helpers/claim-expert-resend";
|
||||||
import {
|
import {
|
||||||
|
claimCaseStatusAllowsOwnerFactorUploadDuringRevision,
|
||||||
|
claimCaseStatusAllowsOwnerInsurerSignStep,
|
||||||
classifyV2ExpertPricingParts,
|
classifyV2ExpertPricingParts,
|
||||||
getActiveV2ExpertReply,
|
getActiveV2ExpertReply,
|
||||||
objectionDisallowedDueToOutstandingFactorWorkflow,
|
objectionDisallowedDueToOutstandingFactorWorkflow,
|
||||||
@@ -2404,9 +2406,9 @@ export class ClaimRequestManagementService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (claim.status !== ClaimCaseStatus.WAITING_FOR_INSURER_APPROVAL) {
|
if (!claimCaseStatusAllowsOwnerFactorUploadDuringRevision(claim.status)) {
|
||||||
throw new BadRequestException(
|
throw new BadRequestException(
|
||||||
"Factors can only be uploaded while the insurer-approval phase is pending.",
|
"Factors can only be uploaded while the claim is in a repair-factor upload phase (see ClaimCaseStatus).",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (claim.claimStatus !== ClaimStatus.NEEDS_REVISION) {
|
if (claim.claimStatus !== ClaimStatus.NEEDS_REVISION) {
|
||||||
@@ -2524,6 +2526,7 @@ export class ClaimRequestManagementService {
|
|||||||
|
|
||||||
await this.claimCaseDbService.findByIdAndUpdate(claimRequestId, {
|
await this.claimCaseDbService.findByIdAndUpdate(claimRequestId, {
|
||||||
$set: {
|
$set: {
|
||||||
|
status: ClaimCaseStatus.EXPERT_VALIDATING_REPAIR_FACTORS,
|
||||||
claimStatus: ClaimStatus.UNDER_REVIEW,
|
claimStatus: ClaimStatus.UNDER_REVIEW,
|
||||||
"workflow.currentStep": ClaimWorkflowStep.EXPERT_COST_EVALUATION,
|
"workflow.currentStep": ClaimWorkflowStep.EXPERT_COST_EVALUATION,
|
||||||
"workflow.nextStep": ClaimWorkflowStep.INSURER_REVIEW,
|
"workflow.nextStep": ClaimWorkflowStep.INSURER_REVIEW,
|
||||||
@@ -5136,7 +5139,7 @@ export class ClaimRequestManagementService {
|
|||||||
/**
|
/**
|
||||||
* V2 API: User objection (ClaimCase + evaluation.objection payload).
|
* V2 API: User objection (ClaimCase + evaluation.objection payload).
|
||||||
*
|
*
|
||||||
* Priced-flow: WAITING_FOR_INSURER_APPROVAL @ INSURER_REVIEW — either NEEDS_REVISION (mixed-priced gate before factor upload)
|
* Priced-flow: insurer-review post-expert statuses (`INSURER_REVIEW_AWAITING_OWNER_SIGN`, `INSURER_REVIEW_MIXED_FACTORS_PENDING`, or legacy `WAITING_FOR_INSURER_APPROVAL`) @ `INSURER_REVIEW` — either NEEDS_REVISION (mixed-priced gate before factor upload)
|
||||||
* or APPROVED (final totals after pricing / factor validation); never while uploading factors or while expert validates.
|
* or APPROVED (final totals after pricing / factor validation); never while uploading factors or while expert validates.
|
||||||
* Legacy: objection during unpaid expert resend (`WAITING_FOR_USER_RESEND` @ `USER_EXPERT_RESEND`).
|
* Legacy: objection during unpaid expert resend (`WAITING_FOR_USER_RESEND` @ `USER_EXPERT_RESEND`).
|
||||||
* Post: resets owner signatures when applicable and returns claim to WAITING_FOR_DAMAGE_EXPERT.
|
* Post: resets owner signatures when applicable and returns claim to WAITING_FOR_DAMAGE_EXPERT.
|
||||||
@@ -5193,7 +5196,7 @@ export class ClaimRequestManagementService {
|
|||||||
|
|
||||||
let pricingObjectionEligible = false;
|
let pricingObjectionEligible = false;
|
||||||
if (
|
if (
|
||||||
claimCase.status === ClaimCaseStatus.WAITING_FOR_INSURER_APPROVAL &&
|
claimCaseStatusAllowsOwnerInsurerSignStep(claimCase.status) &&
|
||||||
claimCase.workflow?.currentStep === ClaimWorkflowStep.INSURER_REVIEW &&
|
claimCase.workflow?.currentStep === ClaimWorkflowStep.INSURER_REVIEW &&
|
||||||
!claimCase.evaluation?.ownerInsurerApproval?.signedAt
|
!claimCase.evaluation?.ownerInsurerApproval?.signedAt
|
||||||
) {
|
) {
|
||||||
@@ -5411,11 +5414,11 @@ export class ClaimRequestManagementService {
|
|||||||
/**
|
/**
|
||||||
* V2: Claim owner signature on expert pricing.
|
* V2: Claim owner signature on expert pricing.
|
||||||
*
|
*
|
||||||
* Phase 1 (mixed priced + factor-needed lines): WAITING_FOR_INSURER_APPROVAL, NEEDS_REVISION, INSURER_REVIEW,
|
* Phase 1 (mixed priced + factor-needed lines): `INSURER_REVIEW_MIXED_FACTORS_PENDING` (or legacy `WAITING_FOR_INSURER_APPROVAL`), NEEDS_REVISION, INSURER_REVIEW,
|
||||||
* owner has not yet accepted priced lines — agreeing records `evaluation.ownerPricedPartsApproval` and moves the
|
* owner has not yet accepted priced lines — agreeing records `evaluation.ownerPricedPartsApproval` and moves the
|
||||||
* workflow to OWNER_UPLOAD_FACTOR_DOCUMENTS. Rejecting rejects the whole case.
|
* workflow to OWNER_UPLOAD_FACTOR_DOCUMENTS. Rejecting rejects the whole case.
|
||||||
*
|
*
|
||||||
* Phase 2 (final): WAITING_FOR_INSURER_APPROVAL, APPROVED, INSURER_REVIEW — full accept/reject completes the case.
|
* Phase 2 (final): INSURER_REVIEW_AWAITING_OWNER_SIGN (or legacy WAITING_FOR_INSURER_APPROVAL), APPROVED, INSURER_REVIEW — full accept/reject completes the case.
|
||||||
*/
|
*/
|
||||||
async submitOwnerInsurerApprovalSignV2(
|
async submitOwnerInsurerApprovalSignV2(
|
||||||
claimRequestId: string,
|
claimRequestId: string,
|
||||||
@@ -5456,7 +5459,7 @@ export class ClaimRequestManagementService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (claimCase.status !== ClaimCaseStatus.WAITING_FOR_INSURER_APPROVAL) {
|
if (!claimCaseStatusAllowsOwnerInsurerSignStep(claimCase.status)) {
|
||||||
throw new BadRequestException(
|
throw new BadRequestException(
|
||||||
`Claim is not waiting for your insurer-approval signature. Current status: ${String(claimCase.status)}`,
|
`Claim is not waiting for your insurer-approval signature. Current status: ${String(claimCase.status)}`,
|
||||||
);
|
);
|
||||||
@@ -5605,7 +5608,7 @@ export class ClaimRequestManagementService {
|
|||||||
message:
|
message:
|
||||||
"Priced repair lines accepted. Upload repair factor files for each factor-needed part; the claim will return to the damage expert for cost validation.",
|
"Priced repair lines accepted. Upload repair factor files for each factor-needed part; the claim will return to the damage expert for cost validation.",
|
||||||
claimRequestId,
|
claimRequestId,
|
||||||
status: ClaimCaseStatus.WAITING_FOR_INSURER_APPROVAL,
|
status: claimCase.status,
|
||||||
claimStatus: ClaimStatus.NEEDS_REVISION,
|
claimStatus: ClaimStatus.NEEDS_REVISION,
|
||||||
currentStep: ClaimWorkflowStep.OWNER_UPLOAD_FACTOR_DOCUMENTS,
|
currentStep: ClaimWorkflowStep.OWNER_UPLOAD_FACTOR_DOCUMENTS,
|
||||||
accepted: true,
|
accepted: true,
|
||||||
|
|||||||
@@ -156,7 +156,7 @@ export class ClaimRequestManagementV2Controller {
|
|||||||
@ApiOperation({
|
@ApiOperation({
|
||||||
summary: "Submit user objection (V2)",
|
summary: "Submit user objection (V2)",
|
||||||
description:
|
description:
|
||||||
"**Windows:** (1) **Insurer-review:** `WAITING_FOR_INSURER_APPROVAL` + `workflow.currentStep=INSURER_REVIEW` without a recorded **final** `evaluation.ownerInsurerApproval` signature — including **mixed** priced+factor gate (`NEEDS_REVISION` before factor upload signature) or **final** totals (`claimStatus=APPROVED`). Not allowed while `OWNER_UPLOAD_FACTOR_DOCUMENTS` or `EXPERT_COST_EVALUATION` (finish factor uploads / validation first).\n" +
|
"**Windows:** (1) **Insurer-review:** `ClaimCaseStatus` in **`INSURER_REVIEW_AWAITING_OWNER_SIGN`**, **`INSURER_REVIEW_MIXED_FACTORS_PENDING`**, or legacy **`WAITING_FOR_INSURER_APPROVAL`**, with `workflow.currentStep=INSURER_REVIEW` and no recorded **final** `evaluation.ownerInsurerApproval` — including **mixed** priced+factor gate (`NEEDS_REVISION` before priced-line signature for factors) or **final** totals (`claimStatus=APPROVED`). Not allowed while uploading factors (`OWNER_UPLOAD_FACTOR_DOCUMENTS`) or expert validation (`EXPERT_COST_EVALUATION`/`EXPERT_VALIDATING_REPAIR_FACTORS`).\n" +
|
||||||
"(2) **Legacy resend:** active expert resend (`WAITING_FOR_USER_RESEND` @ `USER_EXPERT_RESEND`).\n\n" +
|
"(2) **Legacy resend:** active expert resend (`WAITING_FOR_USER_RESEND` @ `USER_EXPERT_RESEND`).\n\n" +
|
||||||
"`objectionParts` may only reference **priced** repair lines (`factorNeeded=false`). Factor-only lines cannot be disputed until they have expert pricing.\n\n" +
|
"`objectionParts` may only reference **priced** repair lines (`factorNeeded=false`). Factor-only lines cannot be disputed until they have expert pricing.\n\n" +
|
||||||
"After **`damageExpertReplyFinal`** exists (final reply following a prior objection), **no second objection** — owner uses **owner-insurer-approval/sign** to accept/reject and close the case.\n\n" +
|
"After **`damageExpertReplyFinal`** exists (final reply following a prior objection), **no second objection** — owner uses **owner-insurer-approval/sign** to accept/reject and close the case.\n\n" +
|
||||||
@@ -247,7 +247,7 @@ export class ClaimRequestManagementV2Controller {
|
|||||||
@ApiOperation({
|
@ApiOperation({
|
||||||
summary: "Sign priced lines or final claim pricing (owner)",
|
summary: "Sign priced lines or final claim pricing (owner)",
|
||||||
description:
|
description:
|
||||||
"Multipart: `sign`, `agree`, `branchId`. Always requires `status=WAITING_FOR_INSURER_APPROVAL` and `workflow.currentStep=INSURER_REVIEW` (never during `EXPERT_COST_EVALUATION`).\n\n" +
|
"Multipart: `sign`, `agree`, `branchId`. Requires `ClaimCaseStatus` **`INSURER_REVIEW_AWAITING_OWNER_SIGN`**, **`INSURER_REVIEW_MIXED_FACTORS_PENDING`**, or legacy **`WAITING_FOR_INSURER_APPROVAL`**, and `workflow.currentStep=INSURER_REVIEW` (not during owner factor upload or `EXPERT_COST_EVALUATION`).\n\n" +
|
||||||
"**Phase A — Mixed reply, priced lines only:** `claimStatus=NEEDS_REVISION`, no `evaluation.ownerPricedPartsApproval` yet. `agree=true` records that signature and moves to `OWNER_UPLOAD_FACTOR_DOCUMENTS` for factor uploads; `agree=false` rejects the whole case (`REJECTED`).\n\n" +
|
"**Phase A — Mixed reply, priced lines only:** `claimStatus=NEEDS_REVISION`, no `evaluation.ownerPricedPartsApproval` yet. `agree=true` records that signature and moves to `OWNER_UPLOAD_FACTOR_DOCUMENTS` for factor uploads; `agree=false` rejects the whole case (`REJECTED`).\n\n" +
|
||||||
"**Phase B — Final:** `claimStatus=APPROVED`, no `evaluation.ownerInsurerApproval` yet. `agree=true` → `COMPLETED`; `agree=false` → `REJECTED`.\n\n" +
|
"**Phase B — Final:** `claimStatus=APPROVED`, no `evaluation.ownerInsurerApproval` yet. `agree=true` → `COMPLETED`; `agree=false` → `REJECTED`.\n\n" +
|
||||||
"Response may include `phase`: `PRICED_PARTS_FOR_FACTORS` or `FINAL_APPROVAL` for UI state.",
|
"Response may include `phase`: `PRICED_PARTS_FOR_FACTORS` or `FINAL_APPROVAL` for UI state.",
|
||||||
@@ -895,9 +895,9 @@ Returns status of each item (uploaded/captured or not).
|
|||||||
summary: "Upload repair factor file for a factor-needed part (V2)",
|
summary: "Upload repair factor file for a factor-needed part (V2)",
|
||||||
description:
|
description:
|
||||||
"Part must have `factorNeeded: true` on the active reply (`evaluation.damageExpertReply` or `evaluation.damageExpertReplyFinal`). One file per part.\n\n" +
|
"Part must have `factorNeeded: true` on the active reply (`evaluation.damageExpertReply` or `evaluation.damageExpertReplyFinal`). One file per part.\n\n" +
|
||||||
"**Requires:** `status=WAITING_FOR_INSURER_APPROVAL`, `claimStatus=NEEDS_REVISION`, `workflow.currentStep=OWNER_UPLOAD_FACTOR_DOCUMENTS`.\n\n" +
|
"**Requires:** `ClaimCaseStatus` **`OWNER_REPAIR_FACTOR_UPLOAD_PENDING`** or **`INSURER_REVIEW_MIXED_FACTORS_PENDING`** (or legacy **`WAITING_FOR_INSURER_APPROVAL`**), `claimStatus=NEEDS_REVISION`, `workflow.currentStep=OWNER_UPLOAD_FACTOR_DOCUMENTS`.\n\n" +
|
||||||
"**Mixed priced+factor replies:** owner must complete **owner-insurer-approval/sign** (priced-line phase) first so `evaluation.ownerPricedPartsApproval` exists.\n\n" +
|
"**Mixed priced+factor replies:** owner must complete **owner-insurer-approval/sign** (priced-line phase) first so `evaluation.ownerPricedPartsApproval` exists.\n\n" +
|
||||||
"When every `factorNeeded` line has `factorLink`, the case moves to `claimStatus=UNDER_REVIEW`, `workflow.currentStep=EXPERT_COST_EVALUATION` for damage expert validation.",
|
"When every `factorNeeded` line has `factorLink`, the case moves to **`EXPERT_VALIDATING_REPAIR_FACTORS`**, `claimStatus=UNDER_REVIEW`, `workflow.currentStep=EXPERT_COST_EVALUATION` for damage expert validation.",
|
||||||
})
|
})
|
||||||
@ApiParam({ name: "claimRequestId", description: "Claim case ID" })
|
@ApiParam({ name: "claimRequestId", description: "Claim case ID" })
|
||||||
@ApiParam({ name: "partId", description: "Part id from expert reply" })
|
@ApiParam({ name: "partId", description: "Part id from expert reply" })
|
||||||
|
|||||||
@@ -84,7 +84,11 @@ export class ClaimDetailsV2ResponseDto {
|
|||||||
@ApiProperty({ description: 'Request number' })
|
@ApiProperty({ description: 'Request number' })
|
||||||
requestNo: string;
|
requestNo: string;
|
||||||
|
|
||||||
@ApiProperty({ description: 'Overall case status' })
|
@ApiProperty({
|
||||||
|
description:
|
||||||
|
"ClaimCaseStatus; see also `ownerGuidance` for UX. Post-expert: INSURER_REVIEW_AWAITING_OWNER_SIGN | INSURER_REVIEW_MIXED_FACTORS_PENDING | OWNER_REPAIR_FACTOR_UPLOAD_PENDING | EXPERT_VALIDATING_REPAIR_FACTORS; legacy WAITING_FOR_INSURER_APPROVAL may still appear.",
|
||||||
|
example: "OWNER_REPAIR_FACTOR_UPLOAD_PENDING",
|
||||||
|
})
|
||||||
status: string;
|
status: string;
|
||||||
|
|
||||||
@ApiProperty({ description: 'Claim damage status' })
|
@ApiProperty({ description: 'Claim damage status' })
|
||||||
|
|||||||
@@ -10,7 +10,11 @@ export class ClaimListItemV2Dto {
|
|||||||
@ApiProperty({ description: 'Claim request number', example: 'CL12345' })
|
@ApiProperty({ description: 'Claim request number', example: 'CL12345' })
|
||||||
requestNo: string;
|
requestNo: string;
|
||||||
|
|
||||||
@ApiProperty({ description: 'Overall case status', example: 'WAITING_FOR_DAMAGE_EXPERT' })
|
@ApiProperty({
|
||||||
|
description:
|
||||||
|
"ClaimCaseStatus. Post-expert owner phase includes: INSURER_REVIEW_AWAITING_OWNER_SIGN (priced lines only → final owner sign); INSURER_REVIEW_MIXED_FACTORS_PENDING (priced + factor lines); OWNER_REPAIR_FACTOR_UPLOAD_PENDING (all lines factor-needed); EXPERT_VALIDATING_REPAIR_FACTORS (all factors uploaded, expert validating). Legacy DB rows may still use WAITING_FOR_INSURER_APPROVAL for those flows.",
|
||||||
|
example: "INSURER_REVIEW_AWAITING_OWNER_SIGN",
|
||||||
|
})
|
||||||
status: string;
|
status: string;
|
||||||
|
|
||||||
@ApiProperty({ description: 'Claim damage determination status', example: 'PENDING' })
|
@ApiProperty({ description: 'Claim damage determination status', example: 'PENDING' })
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ export class ClaimUserComment {
|
|||||||
export const ClaimUserCommentSchema =
|
export const ClaimUserCommentSchema =
|
||||||
SchemaFactory.createForClass(ClaimUserComment);
|
SchemaFactory.createForClass(ClaimUserComment);
|
||||||
|
|
||||||
/** Owner acceptance + signature after expert pricing (WAITING_FOR_INSURER_APPROVAL @ INSURER_REVIEW). */
|
/** Owner acceptance + signature after expert pricing (post-expert insurer `INSURER_REVIEW` — `INSURER_REVIEW_AWAITING_OWNER_SIGN` / `INSURER_REVIEW_MIXED_FACTORS_PENDING` / legacy `WAITING_FOR_INSURER_APPROVAL`). */
|
||||||
@Schema({ _id: false })
|
@Schema({ _id: false })
|
||||||
export class ClaimOwnerInsurerApproval {
|
export class ClaimOwnerInsurerApproval {
|
||||||
@Prop({ type: Boolean, required: true })
|
@Prop({ type: Boolean, required: true })
|
||||||
|
|||||||
@@ -8,7 +8,11 @@ export class ClaimListItemV2Dto {
|
|||||||
@ApiProperty({ description: 'Public ID shared across blame+claim', example: 'A14235' })
|
@ApiProperty({ description: 'Public ID shared across blame+claim', example: 'A14235' })
|
||||||
publicId: string;
|
publicId: string;
|
||||||
|
|
||||||
@ApiProperty({ description: 'Overall case status', example: 'WAITING_FOR_DAMAGE_EXPERT' })
|
@ApiProperty({
|
||||||
|
description:
|
||||||
|
"ClaimCaseStatus (expert list may normalize EXPERT_REVIEWING → WAITING_FOR_DAMAGE_EXPERT). Post-expert owner phase: INSURER_REVIEW_* / OWNER_REPAIR_FACTOR_UPLOAD_PENDING / EXPERT_VALIDATING_REPAIR_FACTORS; see expert reply & validate-factors docs.",
|
||||||
|
example: "WAITING_FOR_DAMAGE_EXPERT",
|
||||||
|
})
|
||||||
status: string;
|
status: string;
|
||||||
|
|
||||||
@ApiProperty({ description: 'Workflow step', example: 'USER_SUBMISSION_COMPLETE' })
|
@ApiProperty({ description: 'Workflow step', example: 'USER_SUBMISSION_COMPLETE' })
|
||||||
@@ -51,7 +55,7 @@ export class ClaimListItemV2Dto {
|
|||||||
|
|
||||||
@ApiPropertyOptional({
|
@ApiPropertyOptional({
|
||||||
description:
|
description:
|
||||||
'True when the claim is in the expert factor validation queue (all factors uploaded).',
|
"True in the expert repair-factor validation queue: `status=EXPERT_VALIDATING_REPAIR_FACTORS` (or legacy `WAITING_FOR_INSURER_APPROVAL`) with `claimStatus=UNDER_REVIEW` and `currentStep=EXPERT_COST_EVALUATION`.",
|
||||||
})
|
})
|
||||||
awaitingFactorValidation?: boolean;
|
awaitingFactorValidation?: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,7 +66,9 @@ import {
|
|||||||
} from "src/helpers/blame-party-agreement-decision";
|
} from "src/helpers/blame-party-agreement-decision";
|
||||||
import { resendRequestHasPayload } from "src/helpers/claim-expert-resend";
|
import { resendRequestHasPayload } from "src/helpers/claim-expert-resend";
|
||||||
import {
|
import {
|
||||||
|
claimCaseStatusAfterExpertReplyV2,
|
||||||
classifyV2ExpertPricingParts,
|
classifyV2ExpertPricingParts,
|
||||||
|
claimIsAwaitingExpertFactorValidationV2,
|
||||||
} from "src/helpers/claim-v2-expert-reply-workflow";
|
} from "src/helpers/claim-v2-expert-reply-workflow";
|
||||||
import {
|
import {
|
||||||
getClaimCarAngleCaptureBlob,
|
getClaimCarAngleCaptureBlob,
|
||||||
@@ -1919,7 +1921,7 @@ export class ExpertClaimService {
|
|||||||
* V2 (ClaimCase): validate user-uploaded repair factors on the active expert reply.
|
* V2 (ClaimCase): validate user-uploaded repair factors on the active expert reply.
|
||||||
* Preconditions: all `factorNeeded` parts have `factorLink`; case is UNDER_REVIEW at EXPERT_COST_EVALUATION.
|
* Preconditions: all `factorNeeded` parts have `factorLink`; case is UNDER_REVIEW at EXPERT_COST_EVALUATION.
|
||||||
* — All approved → claimStatus APPROVED, INSURER_REVIEW: owner accepts/rejects to close.
|
* — All approved → claimStatus APPROVED, INSURER_REVIEW: owner accepts/rejects to close.
|
||||||
* — Any rejected (expert repriced) → WAITING_FOR_INSURER_APPROVAL, APPROVED, INSURER_REVIEW until owner accepts/rejects.
|
* — Any rejected (expert repriced) → INSURER_REVIEW_AWAITING_OWNER_SIGN, APPROVED, INSURER_REVIEW until owner accepts/rejects.
|
||||||
*/
|
*/
|
||||||
async validateClaimFactorsV2(
|
async validateClaimFactorsV2(
|
||||||
claimRequestId: string,
|
claimRequestId: string,
|
||||||
@@ -1935,11 +1937,7 @@ export class ExpertClaimService {
|
|||||||
|
|
||||||
const factorValidationSnapshot = await this.snapshotDamageExpert(actor.sub);
|
const factorValidationSnapshot = await this.snapshotDamageExpert(actor.sub);
|
||||||
|
|
||||||
if (
|
if (!claimIsAwaitingExpertFactorValidationV2(claim)) {
|
||||||
claim.status !== ClaimCaseStatus.WAITING_FOR_INSURER_APPROVAL ||
|
|
||||||
claim.claimStatus !== ClaimStatus.UNDER_REVIEW ||
|
|
||||||
claim.workflow?.currentStep !== ClaimWorkflowStep.EXPERT_COST_EVALUATION
|
|
||||||
) {
|
|
||||||
throw new BadRequestException(
|
throw new BadRequestException(
|
||||||
"Claim is not awaiting expert factor validation (UNDER_REVIEW at EXPERT_COST_EVALUATION).",
|
"Claim is not awaiting expert factor validation (UNDER_REVIEW at EXPERT_COST_EVALUATION).",
|
||||||
);
|
);
|
||||||
@@ -2083,7 +2081,7 @@ export class ExpertClaimService {
|
|||||||
if (anyRejected) {
|
if (anyRejected) {
|
||||||
await this.claimCaseDbService.findByIdAndUpdate(claimRequestId, {
|
await this.claimCaseDbService.findByIdAndUpdate(claimRequestId, {
|
||||||
$set: {
|
$set: {
|
||||||
status: ClaimCaseStatus.WAITING_FOR_INSURER_APPROVAL,
|
status: ClaimCaseStatus.INSURER_REVIEW_AWAITING_OWNER_SIGN,
|
||||||
claimStatus: ClaimStatus.APPROVED,
|
claimStatus: ClaimStatus.APPROVED,
|
||||||
"workflow.currentStep": ClaimWorkflowStep.INSURER_REVIEW,
|
"workflow.currentStep": ClaimWorkflowStep.INSURER_REVIEW,
|
||||||
"workflow.nextStep": ClaimWorkflowStep.CLAIM_COMPLETED,
|
"workflow.nextStep": ClaimWorkflowStep.CLAIM_COMPLETED,
|
||||||
@@ -2116,7 +2114,7 @@ export class ExpertClaimService {
|
|||||||
"Factors reviewed with repricing. Owner must accept or reject via owner-insurer-approval/sign.",
|
"Factors reviewed with repricing. Owner must accept or reject via owner-insurer-approval/sign.",
|
||||||
claimRequestId,
|
claimRequestId,
|
||||||
claimStatus: ClaimStatus.APPROVED,
|
claimStatus: ClaimStatus.APPROVED,
|
||||||
caseStatus: ClaimCaseStatus.WAITING_FOR_INSURER_APPROVAL,
|
caseStatus: ClaimCaseStatus.INSURER_REVIEW_AWAITING_OWNER_SIGN,
|
||||||
outcome: "REJECTED_REPRICED_OWNER_SIGN",
|
outcome: "REJECTED_REPRICED_OWNER_SIGN",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -2163,7 +2161,7 @@ export class ExpertClaimService {
|
|||||||
"All factors approved. The claim proceeds to insurer review (same as non-factor expert reply).",
|
"All factors approved. The claim proceeds to insurer review (same as non-factor expert reply).",
|
||||||
claimRequestId,
|
claimRequestId,
|
||||||
claimStatus: ClaimStatus.APPROVED,
|
claimStatus: ClaimStatus.APPROVED,
|
||||||
caseStatus: ClaimCaseStatus.WAITING_FOR_INSURER_APPROVAL,
|
caseStatus: ClaimCaseStatus.INSURER_REVIEW_AWAITING_OWNER_SIGN,
|
||||||
outcome: "ALL_APPROVED_INSURER_REVIEW",
|
outcome: "ALL_APPROVED_INSURER_REVIEW",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -2490,7 +2488,7 @@ export class ExpertClaimService {
|
|||||||
* On success:
|
* On success:
|
||||||
* - Stores reply; clears owner signature fields (`ownerInsurerApproval`, `ownerPricedPartsApproval`)
|
* - Stores reply; clears owner signature fields (`ownerInsurerApproval`, `ownerPricedPartsApproval`)
|
||||||
* - Unlocks the workflow
|
* - Unlocks the workflow
|
||||||
* - Pricing-only (`factorNeeded=false` everywhere): WAITING_FOR_INSURER_APPROVAL, APPROVED, INSURER_REVIEW → owner final sign/reject.
|
* - Pricing-only (`factorNeeded=false` everywhere): INSURER_REVIEW_AWAITING_OWNER_SIGN, APPROVED, INSURER_REVIEW → owner final sign/reject.
|
||||||
* - All lines `factorNeeded`: NEEDS_REVISION, OWNER_UPLOAD_FACTOR_DOCUMENTS → uploads → UNDER_REVIEW, EXPERT_COST_EVALUATION (validate factors).
|
* - All lines `factorNeeded`: NEEDS_REVISION, OWNER_UPLOAD_FACTOR_DOCUMENTS → uploads → UNDER_REVIEW, EXPERT_COST_EVALUATION (validate factors).
|
||||||
* - Mixed priced + factor: NEEDS_REVISION, INSURER_REVIEW with next OWNER_UPLOAD_FACTOR_DOCUMENTS → owner signs priced lines first → upload factors → expert validates → final sign.
|
* - Mixed priced + factor: NEEDS_REVISION, INSURER_REVIEW with next OWNER_UPLOAD_FACTOR_DOCUMENTS → owner signs priced lines first → upload factors → expert validates → final sign.
|
||||||
*/
|
*/
|
||||||
@@ -2601,7 +2599,7 @@ export class ExpertClaimService {
|
|||||||
let currentStep = ClaimWorkflowStep.INSURER_REVIEW;
|
let currentStep = ClaimWorkflowStep.INSURER_REVIEW;
|
||||||
let nextWorkflowStep = ClaimWorkflowStep.CLAIM_COMPLETED;
|
let nextWorkflowStep = ClaimWorkflowStep.CLAIM_COMPLETED;
|
||||||
|
|
||||||
const nextCaseStatus = ClaimCaseStatus.WAITING_FOR_INSURER_APPROVAL;
|
const nextCaseStatus = claimCaseStatusAfterExpertReplyV2(processedParts);
|
||||||
let nextClaimStatus = ClaimStatus.APPROVED;
|
let nextClaimStatus = ClaimStatus.APPROVED;
|
||||||
|
|
||||||
if (needsFactorUpload) {
|
if (needsFactorUpload) {
|
||||||
@@ -2805,7 +2803,7 @@ export class ExpertClaimService {
|
|||||||
* Returns claims that are (then filtered to the actor's insurer via `claimCaseTouchesClient`):
|
* Returns claims that are (then filtered to the actor's insurer via `claimCaseTouchesClient`):
|
||||||
* 1. WAITING_FOR_DAMAGE_EXPERT and not locked (open queue)
|
* 1. WAITING_FOR_DAMAGE_EXPERT and not locked (open queue)
|
||||||
* 2. Locked by this expert (in-progress)
|
* 2. Locked by this expert (in-progress)
|
||||||
* 3. WAITING_FOR_INSURER_APPROVAL + UNDER_REVIEW at EXPERT_COST_EVALUATION (factor validation queue)
|
* 3. EXPERT_VALIDATING_REPAIR_FACTORS (or legacy WAITING_FOR_INSURER_APPROVAL) + UNDER_REVIEW at EXPERT_COST_EVALUATION (factor validation queue)
|
||||||
*/
|
*/
|
||||||
async getClaimListV2(actor: any): Promise<GetClaimListV2ResponseDto> {
|
async getClaimListV2(actor: any): Promise<GetClaimListV2ResponseDto> {
|
||||||
requireActorClientKey(actor);
|
requireActorClientKey(actor);
|
||||||
@@ -2832,12 +2830,21 @@ export class ExpertClaimService {
|
|||||||
'workflow.lockedBy.actorId': new Types.ObjectId(actorId),
|
'workflow.lockedBy.actorId': new Types.ObjectId(actorId),
|
||||||
},
|
},
|
||||||
// User uploaded all factors; expert must approve/reject (unlocked queue)
|
// User uploaded all factors; expert must approve/reject (unlocked queue)
|
||||||
|
{
|
||||||
|
$or: [
|
||||||
|
{
|
||||||
|
status: ClaimCaseStatus.EXPERT_VALIDATING_REPAIR_FACTORS,
|
||||||
|
claimStatus: ClaimStatus.UNDER_REVIEW,
|
||||||
|
'workflow.currentStep': ClaimWorkflowStep.EXPERT_COST_EVALUATION,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
status: ClaimCaseStatus.WAITING_FOR_INSURER_APPROVAL,
|
status: ClaimCaseStatus.WAITING_FOR_INSURER_APPROVAL,
|
||||||
claimStatus: ClaimStatus.UNDER_REVIEW,
|
claimStatus: ClaimStatus.UNDER_REVIEW,
|
||||||
'workflow.currentStep': ClaimWorkflowStep.EXPERT_COST_EVALUATION,
|
'workflow.currentStep': ClaimWorkflowStep.EXPERT_COST_EVALUATION,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
const filtered = (claims as any[]).filter((c) =>
|
const filtered = (claims as any[]).filter((c) =>
|
||||||
@@ -2892,10 +2899,7 @@ export class ExpertClaimService {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const list = filtered.map((c) => {
|
const list = filtered.map((c) => {
|
||||||
const awaitingFactorValidation =
|
const awaitingFactorValidation = claimIsAwaitingExpertFactorValidationV2(c);
|
||||||
c.status === ClaimCaseStatus.WAITING_FOR_INSURER_APPROVAL &&
|
|
||||||
c.claimStatus === ClaimStatus.UNDER_REVIEW &&
|
|
||||||
c.workflow?.currentStep === ClaimWorkflowStep.EXPERT_COST_EVALUATION;
|
|
||||||
const v = this.vehicleForExpertFromClaimAndBlameMap(c, blameById);
|
const v = this.vehicleForExpertFromClaimAndBlameMap(c, blameById);
|
||||||
const blame = c.blameRequestId
|
const blame = c.blameRequestId
|
||||||
? blameById.get(c.blameRequestId.toString())
|
? blameById.get(c.blameRequestId.toString())
|
||||||
@@ -3262,7 +3266,7 @@ export class ExpertClaimService {
|
|||||||
* Validations:
|
* Validations:
|
||||||
* - Claim must exist and belong to the actor's insurer (`assertClaimCaseForTenant`)
|
* - Claim must exist and belong to the actor's insurer (`assertClaimCaseForTenant`)
|
||||||
* - Allowed when: WAITING_FOR_DAMAGE_EXPERT (queue), or EXPERT_REVIEWING (after lock — same expert must be able to reopen detail),
|
* - Allowed when: WAITING_FOR_DAMAGE_EXPERT (queue), or EXPERT_REVIEWING (after lock — same expert must be able to reopen detail),
|
||||||
* or factor-validation queue (WAITING_FOR_INSURER_APPROVAL + UNDER_REVIEW + EXPERT_COST_EVALUATION)
|
* or factor-validation queue (EXPERT_VALIDATING_REPAIR_FACTORS / legacy WAITING_FOR_INSURER_APPROVAL + UNDER_REVIEW + EXPERT_COST_EVALUATION)
|
||||||
* - If an active workflow lock exists (15 min from lockedAt): only the locking expert; after expiry, any expert (tenant) may view
|
* - If an active workflow lock exists (15 min from lockedAt): only the locking expert; after expiry, any expert (tenant) may view
|
||||||
*/
|
*/
|
||||||
async getClaimDetailV2(
|
async getClaimDetailV2(
|
||||||
@@ -3284,9 +3288,7 @@ export class ExpertClaimService {
|
|||||||
claim.status === ClaimCaseStatus.WAITING_FOR_DAMAGE_EXPERT ||
|
claim.status === ClaimCaseStatus.WAITING_FOR_DAMAGE_EXPERT ||
|
||||||
claim.status === ClaimCaseStatus.EXPERT_REVIEWING;
|
claim.status === ClaimCaseStatus.EXPERT_REVIEWING;
|
||||||
const isFactorValidationPending =
|
const isFactorValidationPending =
|
||||||
claim.status === ClaimCaseStatus.WAITING_FOR_INSURER_APPROVAL &&
|
claimIsAwaitingExpertFactorValidationV2(claim);
|
||||||
claim.claimStatus === ClaimStatus.UNDER_REVIEW &&
|
|
||||||
claim.workflow?.currentStep === ClaimWorkflowStep.EXPERT_COST_EVALUATION;
|
|
||||||
|
|
||||||
if (!isDamageExpertPhase && !isFactorValidationPending) {
|
if (!isDamageExpertPhase && !isFactorValidationPending) {
|
||||||
throw new ForbiddenException(
|
throw new ForbiddenException(
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ export class ExpertClaimV2Controller {
|
|||||||
@ApiOperation({
|
@ApiOperation({
|
||||||
summary: "List available claim requests for damage expert",
|
summary: "List available claim requests for damage expert",
|
||||||
description:
|
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).",
|
"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 (`status=EXPERT_VALIDATING_REPAIR_FACTORS` or legacy `WAITING_FOR_INSURER_APPROVAL` with UNDER_REVIEW at EXPERT_COST_EVALUATION).",
|
||||||
})
|
})
|
||||||
async getClaimListV2(@CurrentUser() actor) {
|
async getClaimListV2(@CurrentUser() actor) {
|
||||||
return await this.expertClaimService.getClaimListV2(actor);
|
return await this.expertClaimService.getClaimListV2(actor);
|
||||||
@@ -87,10 +87,11 @@ export class ExpertClaimV2Controller {
|
|||||||
summary: "Submit expert damage assessment reply",
|
summary: "Submit expert damage assessment reply",
|
||||||
description:
|
description:
|
||||||
"**Preconditions:** claim locked by this expert (`EXPERT_REVIEWING`). **Unlocks** the claim. Each part needs `daghi` (V1 rules) and may set `factorNeeded` (repair factor file required from owner) or priced lines only. **Cap:** sum of `totalPayment` ≤ 30,000,000. Clears any prior `evaluation.ownerInsurerApproval` / `ownerPricedPartsApproval`.\n\n" +
|
"**Preconditions:** claim locked by this expert (`EXPERT_REVIEWING`). **Unlocks** the claim. Each part needs `daghi` (V1 rules) and may set `factorNeeded` (repair factor file required from owner) or priced lines only. **Cap:** sum of `totalPayment` ≤ 30,000,000. Clears any prior `evaluation.ownerInsurerApproval` / `ownerPricedPartsApproval`.\n\n" +
|
||||||
"**Frontend routing by outcome:**\n" +
|
"**Frontend routing by `ClaimCaseStatus` (`status`):**\n" +
|
||||||
"- **All parts `factorNeeded`:** `status=WAITING_FOR_INSURER_APPROVAL`, `claimStatus=NEEDS_REVISION`, `workflow.currentStep=OWNER_UPLOAD_FACTOR_DOCUMENTS`, `workflow.nextStep=EXPERT_COST_EVALUATION` → owner uploads all factors, then `claimStatus` becomes `UNDER_REVIEW` and `currentStep=EXPERT_COST_EVALUATION` for expert validate-factors.\n" +
|
"- **All parts `factorNeeded`:** `OWNER_REPAIR_FACTOR_UPLOAD_PENDING`, `claimStatus=NEEDS_REVISION`, `workflow.currentStep=OWNER_UPLOAD_FACTOR_DOCUMENTS`, `workflow.nextStep=EXPERT_COST_EVALUATION` → owner uploads all factors; then `status` becomes **`EXPERT_VALIDATING_REPAIR_FACTORS`**, `claimStatus=UNDER_REVIEW`, `currentStep=EXPERT_COST_EVALUATION` for expert **validate-factors**.\n" +
|
||||||
"- **Mixed (some priced, some factorNeeded):** same `status`, `claimStatus=NEEDS_REVISION`, `currentStep=INSURER_REVIEW`, `nextStep=OWNER_UPLOAD_FACTOR_DOCUMENTS` → owner must call **owner-insurer-approval/sign** first (priced-line acceptance), then `currentStep` moves to `OWNER_UPLOAD_FACTOR_DOCUMENTS` for factor uploads, then expert validation.\n" +
|
"- **Mixed (some priced, some factorNeeded):** `INSURER_REVIEW_MIXED_FACTORS_PENDING`, `claimStatus=NEEDS_REVISION`, `currentStep=INSURER_REVIEW`, `nextStep=OWNER_UPLOAD_FACTOR_DOCUMENTS` → owner must call **owner-insurer-approval/sign** first (priced-line acceptance); `currentStep` then moves to `OWNER_UPLOAD_FACTOR_DOCUMENTS` (same case `status` until factors are done).\n" +
|
||||||
"- **No factors:** `claimStatus=APPROVED`, `currentStep=INSURER_REVIEW`, `nextStep=CLAIM_COMPLETED` → owner final sign/reject only.\n\n" +
|
"- **No factors:** **`INSURER_REVIEW_AWAITING_OWNER_SIGN`**, `claimStatus=APPROVED`, `currentStep=INSURER_REVIEW`, `nextStep=CLAIM_COMPLETED` → owner final sign/reject only.\n\n" +
|
||||||
|
"**Legacy rows** may still use `WAITING_FOR_INSURER_APPROVAL` instead of the specific values above.\n\n" +
|
||||||
"**After the owner fulfilled an expert resend** (`damageExpertResend.fulfilledAt`), this expert **cannot** initiate **another resend**—use **reply/submit**, in-person visit, or **validate-factors** as appropriate.",
|
"**After the owner fulfilled an expert resend** (`damageExpertResend.fulfilledAt`), this expert **cannot** initiate **another resend**—use **reply/submit**, in-person visit, or **validate-factors** as appropriate.",
|
||||||
})
|
})
|
||||||
@ApiParam({ name: "claimRequestId" })
|
@ApiParam({ name: "claimRequestId" })
|
||||||
@@ -145,11 +146,11 @@ export class ExpertClaimV2Controller {
|
|||||||
@ApiOperation({
|
@ApiOperation({
|
||||||
summary: "Validate uploaded repair factors (V2 ClaimCase)",
|
summary: "Validate uploaded repair factors (V2 ClaimCase)",
|
||||||
description:
|
description:
|
||||||
"**Preconditions:** `status=WAITING_FOR_INSURER_APPROVAL`, `claimStatus=UNDER_REVIEW`, `workflow.currentStep=EXPERT_COST_EVALUATION`, every `factorNeeded` line has `factorLink`.\n\n" +
|
"**Preconditions:** `status=EXPERT_VALIDATING_REPAIR_FACTORS` (or legacy `WAITING_FOR_INSURER_APPROVAL`), `claimStatus=UNDER_REVIEW`, `workflow.currentStep=EXPERT_COST_EVALUATION`, every `factorNeeded` line has `factorLink`.\n\n" +
|
||||||
"**Decisions:** each factor line gets `APPROVED` or `REJECTED`; rejected lines require expert `totalPayment` (or both `price` and `salary`).\n\n" +
|
"**Decisions:** each factor line gets `APPROVED` or `REJECTED`; rejected lines require expert `totalPayment` (or both `price` and `salary`).\n\n" +
|
||||||
"**Outcomes:**\n" +
|
"**Outcomes:**\n" +
|
||||||
"- **All approved:** `claimStatus=APPROVED`, `currentStep=INSURER_REVIEW` → owner must **sign or reject** via `owner-insurer-approval/sign`; agree completes the case.\n" +
|
"- **All approved:** `status=INSURER_REVIEW_AWAITING_OWNER_SIGN`, `claimStatus=APPROVED`, `currentStep=INSURER_REVIEW` → owner must **sign or reject** via `owner-insurer-approval/sign`; agree completes the case.\n" +
|
||||||
"- **Any rejected (repriced):** same waiter + `INSURER_REVIEW` → owner still must **accept or reject** the repriced totals (case is not completed until they sign).\n" +
|
"- **Any rejected (repriced):** same as above (`INSURER_REVIEW_AWAITING_OWNER_SIGN` + `INSURER_REVIEW`) → owner must **accept or reject** the repriced totals.\n" +
|
||||||
"- **Partial batch:** service may return pending until every factor line has a non-pending decision.",
|
"- **Partial batch:** service may return pending until every factor line has a non-pending decision.",
|
||||||
})
|
})
|
||||||
@ApiParam({ name: "claimRequestId" })
|
@ApiParam({ name: "claimRequestId" })
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ import { ClaimStatus } from "src/Types&Enums/claim-request-management/claimStatu
|
|||||||
import { ClaimWorkflowStep } from "src/Types&Enums/claim-request-management/claim-workflow-steps.enum";
|
import { ClaimWorkflowStep } from "src/Types&Enums/claim-request-management/claim-workflow-steps.enum";
|
||||||
import {
|
import {
|
||||||
classifyV2ExpertPricingParts,
|
classifyV2ExpertPricingParts,
|
||||||
|
claimCaseStatusAllowsOwnerInsurerSignStep,
|
||||||
|
claimCaseStatusIsV2OwnerPostExpertPipeline,
|
||||||
getActiveV2ExpertReply,
|
getActiveV2ExpertReply,
|
||||||
objectionDisallowedDueToOutstandingFactorWorkflow,
|
objectionDisallowedDueToOutstandingFactorWorkflow,
|
||||||
} from "src/helpers/claim-v2-expert-reply-workflow";
|
} from "src/helpers/claim-v2-expert-reply-workflow";
|
||||||
@@ -46,7 +48,7 @@ function objectionWindowForOwner(claim: any): {
|
|||||||
|
|
||||||
let pricingEligible = false;
|
let pricingEligible = false;
|
||||||
if (
|
if (
|
||||||
claim.status === ClaimCaseStatus.WAITING_FOR_INSURER_APPROVAL &&
|
claimCaseStatusAllowsOwnerInsurerSignStep(claim.status) &&
|
||||||
claim.workflow?.currentStep === ClaimWorkflowStep.INSURER_REVIEW &&
|
claim.workflow?.currentStep === ClaimWorkflowStep.INSURER_REVIEW &&
|
||||||
!claim.evaluation?.ownerInsurerApproval?.signedAt
|
!claim.evaluation?.ownerInsurerApproval?.signedAt
|
||||||
) {
|
) {
|
||||||
@@ -191,7 +193,7 @@ export function buildClaimDetailsV2OwnerGuidance(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (claim.status !== ClaimCaseStatus.WAITING_FOR_INSURER_APPROVAL) {
|
if (!claimCaseStatusIsV2OwnerPostExpertPipeline(claim.status)) {
|
||||||
return {
|
return {
|
||||||
phaseKey: "USER_FLOW",
|
phaseKey: "USER_FLOW",
|
||||||
headline: "Continue your claim registration",
|
headline: "Continue your claim registration",
|
||||||
|
|||||||
@@ -40,6 +40,72 @@ export function classifyV2ExpertPricingParts(parts: ClaimPricingPartLite[]) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const OWNER_POST_EXPERT_INSURER_SIGNATURE_STATUSES: ReadonlySet<string> = new Set([
|
||||||
|
ClaimCaseStatus.WAITING_FOR_INSURER_APPROVAL,
|
||||||
|
ClaimCaseStatus.INSURER_REVIEW_AWAITING_OWNER_SIGN,
|
||||||
|
ClaimCaseStatus.INSURER_REVIEW_MIXED_FACTORS_PENDING,
|
||||||
|
]);
|
||||||
|
|
||||||
|
const OWNER_FACTOR_UPLOAD_PHASE_STATUSES: ReadonlySet<string> = new Set([
|
||||||
|
ClaimCaseStatus.WAITING_FOR_INSURER_APPROVAL,
|
||||||
|
ClaimCaseStatus.OWNER_REPAIR_FACTOR_UPLOAD_PENDING,
|
||||||
|
ClaimCaseStatus.INSURER_REVIEW_MIXED_FACTORS_PENDING,
|
||||||
|
]);
|
||||||
|
|
||||||
|
const V2_POST_EXPERT_OWNER_PIPELINE_STATUSES: ReadonlySet<string> = new Set([
|
||||||
|
ClaimCaseStatus.WAITING_FOR_INSURER_APPROVAL,
|
||||||
|
ClaimCaseStatus.INSURER_REVIEW_AWAITING_OWNER_SIGN,
|
||||||
|
ClaimCaseStatus.INSURER_REVIEW_MIXED_FACTORS_PENDING,
|
||||||
|
ClaimCaseStatus.OWNER_REPAIR_FACTOR_UPLOAD_PENDING,
|
||||||
|
ClaimCaseStatus.EXPERT_VALIDATING_REPAIR_FACTORS,
|
||||||
|
]);
|
||||||
|
|
||||||
|
/** Owner multipart sign at `INSURER_REVIEW` (priced-line gate or final acceptance). */
|
||||||
|
export function claimCaseStatusAllowsOwnerInsurerSignStep(
|
||||||
|
status: ClaimCaseStatus | string | undefined,
|
||||||
|
): boolean {
|
||||||
|
return OWNER_POST_EXPERT_INSURER_SIGNATURE_STATUSES.has(String(status ?? ""));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Repair-factor upload during `NEEDS_REVISION` @ `OWNER_UPLOAD_FACTOR_DOCUMENTS`. */
|
||||||
|
export function claimCaseStatusAllowsOwnerFactorUploadDuringRevision(
|
||||||
|
status: ClaimCaseStatus | string | undefined,
|
||||||
|
): boolean {
|
||||||
|
return OWNER_FACTOR_UPLOAD_PHASE_STATUSES.has(String(status ?? ""));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Owner-facing post-expert flow: signatures, factor uploads, or waiting on expert factor validation. */
|
||||||
|
export function claimCaseStatusIsV2OwnerPostExpertPipeline(
|
||||||
|
status: ClaimCaseStatus | string | undefined,
|
||||||
|
): boolean {
|
||||||
|
return V2_POST_EXPERT_OWNER_PIPELINE_STATUSES.has(String(status ?? ""));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function claimIsAwaitingExpertFactorValidationV2(claim: {
|
||||||
|
status?: ClaimCaseStatus | string;
|
||||||
|
claimStatus?: ClaimStatus;
|
||||||
|
workflow?: { currentStep?: string };
|
||||||
|
}): boolean {
|
||||||
|
return (
|
||||||
|
claim.claimStatus === ClaimStatus.UNDER_REVIEW &&
|
||||||
|
claim.workflow?.currentStep === ClaimWorkflowStep.EXPERT_COST_EVALUATION &&
|
||||||
|
(claim.status === ClaimCaseStatus.EXPERT_VALIDATING_REPAIR_FACTORS ||
|
||||||
|
claim.status === ClaimCaseStatus.WAITING_FOR_INSURER_APPROVAL)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function claimCaseStatusAfterExpertReplyV2(parts: ClaimPricingPartLite[]): ClaimCaseStatus {
|
||||||
|
const { mixedFactorAndPrice } = classifyV2ExpertPricingParts(parts);
|
||||||
|
const needsFactorUpload = parts.some((p) => p.factorNeeded === true);
|
||||||
|
if (!needsFactorUpload) {
|
||||||
|
return ClaimCaseStatus.INSURER_REVIEW_AWAITING_OWNER_SIGN;
|
||||||
|
}
|
||||||
|
if (mixedFactorAndPrice) {
|
||||||
|
return ClaimCaseStatus.INSURER_REVIEW_MIXED_FACTORS_PENDING;
|
||||||
|
}
|
||||||
|
return ClaimCaseStatus.OWNER_REPAIR_FACTOR_UPLOAD_PENDING;
|
||||||
|
}
|
||||||
|
|
||||||
export function claimIsV2ExpertFactorUploadStep(claim: { workflow?: { currentStep?: string } }) {
|
export function claimIsV2ExpertFactorUploadStep(claim: { workflow?: { currentStep?: string } }) {
|
||||||
return claim.workflow?.currentStep === ClaimWorkflowStep.OWNER_UPLOAD_FACTOR_DOCUMENTS;
|
return claim.workflow?.currentStep === ClaimWorkflowStep.OWNER_UPLOAD_FACTOR_DOCUMENTS;
|
||||||
}
|
}
|
||||||
@@ -49,11 +115,7 @@ export function claimIsV2PendingFactorExpertValidation(claim: {
|
|||||||
claimStatus?: ClaimStatus;
|
claimStatus?: ClaimStatus;
|
||||||
workflow?: { currentStep?: string };
|
workflow?: { currentStep?: string };
|
||||||
}) {
|
}) {
|
||||||
return (
|
return claimIsAwaitingExpertFactorValidationV2(claim);
|
||||||
claim.status === ClaimCaseStatus.WAITING_FOR_INSURER_APPROVAL &&
|
|
||||||
claim.claimStatus === ClaimStatus.UNDER_REVIEW &&
|
|
||||||
claim.workflow?.currentStep === ClaimWorkflowStep.EXPERT_COST_EVALUATION
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function objectionDisallowedDueToOutstandingFactorWorkflow(claim: {
|
export function objectionDisallowedDueToOutstandingFactorWorkflow(claim: {
|
||||||
|
|||||||
Reference in New Issue
Block a user