forked from Yara724/api
Fixed insurer
This commit is contained in:
@@ -92,7 +92,10 @@ import {
|
||||
buildMutualAgreementExpertDecision,
|
||||
enrichBlamePartiesForAgreementView,
|
||||
} from "src/helpers/blame-party-agreement-decision";
|
||||
import { resendRequestHasPayload } from "src/helpers/claim-expert-resend";
|
||||
import {
|
||||
normalizeResendDocumentKeys,
|
||||
resendRequestHasPayload,
|
||||
} from "src/helpers/claim-expert-resend";
|
||||
import {
|
||||
claimCaseStatusAfterExpertReplyV2,
|
||||
classifyV2ExpertPricingParts,
|
||||
@@ -133,6 +136,7 @@ import { CLAIM_V2_TOTAL_PAYMENT_CAP_TOMAN } from "src/constants/repair-amount-li
|
||||
import { ListQueryV2Dto } from "src/common/dto/list-query-v2.dto";
|
||||
import { applyListQueryV2 } from "src/helpers/list-query-v2";
|
||||
import { buildEnrichedDamagedParts } from "./dto/claim-damaged-part.enricher";
|
||||
import { canonicalizeResendDocumentKey } from "src/helpers/claim-resend-document-keys";
|
||||
|
||||
const CLAIM_V2_TOTAL_PAYMENT_CAP = CLAIM_V2_TOTAL_PAYMENT_CAP_TOMAN;
|
||||
|
||||
@@ -3842,29 +3846,29 @@ export class ExpertClaimService {
|
||||
const isResendPending =
|
||||
claim.status === ClaimCaseStatus.WAITING_FOR_USER_RESEND;
|
||||
|
||||
const assignedForReviewById = String(
|
||||
(claim.workflow as any)?.assignedForReviewBy?.actorId ?? "",
|
||||
);
|
||||
const lockEnforced = this.isClaimV2WorkflowLockCurrentlyEnforced(claim);
|
||||
const lockedById = String(claim.workflow?.lockedBy?.actorId ?? "");
|
||||
const isAssignedToMe =
|
||||
!!assignedForReviewById && assignedForReviewById === actorId;
|
||||
|
||||
// Gate: must satisfy at least one bucket
|
||||
if (
|
||||
!isDamageExpertPhase &&
|
||||
!isFactorValidationPending &&
|
||||
!isResendPending
|
||||
!isResendPending &&
|
||||
!isAssignedToMe
|
||||
) {
|
||||
throw new ForbiddenException(
|
||||
`This claim is not available for expert review. Current status: ${claim.status}`,
|
||||
);
|
||||
}
|
||||
|
||||
// Ownership access control — same 4-bucket logic as list
|
||||
const assignedForReviewById = String(
|
||||
(claim.workflow as any)?.assignedForReviewBy?.actorId ?? "",
|
||||
);
|
||||
const lockEnforced = this.isClaimV2WorkflowLockCurrentlyEnforced(claim);
|
||||
const lockedById = String(claim.workflow?.lockedBy?.actorId ?? "");
|
||||
|
||||
const isAvailable =
|
||||
isDamageExpertPhase && !assignedForReviewById && !lockEnforced;
|
||||
const isAssignedToMe =
|
||||
!!assignedForReviewById && assignedForReviewById === actorId;
|
||||
const isLockedByMe = lockEnforced && lockedById === actorId;
|
||||
// Factor validation is open to all tenant experts (no individual ownership)
|
||||
const isFactorValidationOpen = isFactorValidationPending;
|
||||
|
||||
if (
|
||||
@@ -3888,12 +3892,19 @@ export class ExpertClaimService {
|
||||
);
|
||||
}
|
||||
|
||||
const hasCapture = (data: any, key: string) =>
|
||||
data && (data instanceof Map ? data.get(key) : data[key]);
|
||||
|
||||
// Build requiredDocuments map
|
||||
const requiredDocs = claim.requiredDocuments as any;
|
||||
const requiredDocumentsStatus: Record<string, any> = {};
|
||||
|
||||
// Resend documents requested by expert — normalize to canonical keys for comparison
|
||||
const resendDocumentKeys = new Set(
|
||||
normalizeResendDocumentKeys(
|
||||
(claim as any).evaluation?.damageExpertResend?.resendDocuments,
|
||||
),
|
||||
);
|
||||
const resendFulfilled = !!(claim as any).evaluation?.damageExpertResend
|
||||
?.fulfilledAt;
|
||||
|
||||
if (requiredDocs) {
|
||||
const keys =
|
||||
requiredDocs instanceof Map
|
||||
@@ -3902,11 +3913,18 @@ export class ExpertClaimService {
|
||||
for (const k of keys as string[]) {
|
||||
const doc =
|
||||
requiredDocs instanceof Map ? requiredDocs.get(k) : requiredDocs[k];
|
||||
const canonicalKey = canonicalizeResendDocumentKey(k) ?? k;
|
||||
const wasResendRequested = resendDocumentKeys.has(canonicalKey);
|
||||
|
||||
requiredDocumentsStatus[k] = {
|
||||
uploaded: !!doc?.uploaded,
|
||||
fileId: doc?.fileId?.toString(),
|
||||
fileName: doc?.fileName,
|
||||
filePath: doc?.filePath ? buildFileLink(doc.filePath) : undefined,
|
||||
resend: {
|
||||
wasRequested: wasResendRequested,
|
||||
isFulfilled: wasResendRequested && resendFulfilled,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -3927,7 +3945,7 @@ export class ExpertClaimService {
|
||||
};
|
||||
}
|
||||
|
||||
// Build damaged parts list (aligned with normalized selected parts and enriched with evaluation context)
|
||||
// Build enriched damaged parts
|
||||
const carTypeExpert = claim.vehicle?.carType as
|
||||
| ClaimVehicleTypeV2
|
||||
| undefined;
|
||||
@@ -3938,18 +3956,10 @@ export class ExpertClaimService {
|
||||
);
|
||||
const damagedPartsDataExpert = claim.media?.damagedParts as any;
|
||||
|
||||
// Extract optimization lookups from the DB document safely
|
||||
const evaluationBlock = (claim as any).evaluation;
|
||||
const priceDropLines = evaluationBlock?.priceDrop?.partLines || [];
|
||||
const objectionParts = evaluationBlock?.objection?.objectionParts || [];
|
||||
const newObjectionParts = evaluationBlock?.objection?.newParts || [];
|
||||
|
||||
// Inside getClaimDetailV2, replace the damagedParts block:
|
||||
|
||||
const damagedParts = buildEnrichedDamagedParts({
|
||||
selectedParts: selectedNormExpert,
|
||||
damagedPartsData: damagedPartsDataExpert,
|
||||
evaluationBlock: (claim as any).evaluation, // damageExpertResend lives here already
|
||||
evaluationBlock: (claim as any).evaluation,
|
||||
expertAddedParts: (claim.damage as any)?.expertAddedParts ?? [],
|
||||
getDamagedPartCaptureBlob,
|
||||
hasDamagedPartCapture,
|
||||
@@ -3957,7 +3967,7 @@ export class ExpertClaimService {
|
||||
buildFileLink,
|
||||
});
|
||||
|
||||
// 1. Vehicle payload logic from "upstream"
|
||||
// Vehicle payload — fall back to blame inquiry if claim vehicle is sparse
|
||||
let vehiclePayload = claim.vehicle as any;
|
||||
const hasClaimVehicle =
|
||||
vehiclePayload &&
|
||||
@@ -3968,7 +3978,6 @@ export class ExpertClaimService {
|
||||
|
||||
let blameLean: any = null;
|
||||
|
||||
// 2. Video capture and blame case db queries from "stashed"
|
||||
const videoCaptureIdRaw = (claim.media as any)?.videoCaptureId;
|
||||
const blameRequestIdStr = claim.blameRequestId?.toString();
|
||||
|
||||
@@ -3991,18 +4000,15 @@ export class ExpertClaimService {
|
||||
blameLean = blameLeanRows[0] ?? null;
|
||||
}
|
||||
|
||||
// If claim vehicle not found and blameLean exists, replace vehiclePayload
|
||||
if (!hasClaimVehicle && blameLean) {
|
||||
const fromBlame = this.damagedPartyVehicleFromBlame(blameLean, claim);
|
||||
if (fromBlame) vehiclePayload = fromBlame;
|
||||
}
|
||||
|
||||
// 3. Blame file context logic from "upstream"
|
||||
const blameFileContext = blameLean
|
||||
? this.blameFileContextForExpert(blameLean)
|
||||
: {};
|
||||
|
||||
// 4. videoCapture logic from "stashed"
|
||||
let videoCapture: ClaimDetailV2ResponseDto["videoCapture"] = undefined;
|
||||
if (videoCaptureRow) {
|
||||
const vc = videoCaptureRow as any;
|
||||
@@ -4036,28 +4042,12 @@ export class ExpertClaimService {
|
||||
? ClaimCaseStatus.WAITING_FOR_DAMAGE_EXPERT
|
||||
: claim.status;
|
||||
|
||||
const objection = (claim as any).evaluation?.objection
|
||||
? {
|
||||
objectionParts:
|
||||
(claim as any).evaluation.objection.objectionParts ?? [],
|
||||
newParts: (claim as any).evaluation.objection.newParts ?? [],
|
||||
submittedAt: (claim as any).evaluation.objection.submittedAt,
|
||||
}
|
||||
: undefined;
|
||||
|
||||
const blameCaseForApi = blameCase
|
||||
? this.sanitizeBlameCaseForClaimDetailApi(
|
||||
blameCase as Record<string, unknown>,
|
||||
)
|
||||
: undefined;
|
||||
|
||||
// Enrich the full evaluation block with `signLink`s for every place a user
|
||||
// signature is referenced, then assemble the response slice.
|
||||
//
|
||||
// We always expose owner approval blocks (when present in the DB) because
|
||||
// the signature URL is needed across all phases of the claim. The expert
|
||||
// reply payloads are still gated on `isFactorValidationPending` to match
|
||||
// the historical contract of this endpoint.
|
||||
const claimEvaluationRaw = (claim as any).evaluation as
|
||||
| Record<string, unknown>
|
||||
| undefined;
|
||||
@@ -4122,7 +4112,6 @@ export class ExpertClaimService {
|
||||
blameRequestId: claim.blameRequestId?.toString(),
|
||||
blameRequestNo: claim.blameRequestNo,
|
||||
money: moneyPayload,
|
||||
// selectedParts: selectedNormExpert,
|
||||
otherParts: claim.damage?.otherParts,
|
||||
requiredDocuments:
|
||||
Object.keys(requiredDocumentsStatus).length > 0
|
||||
@@ -4131,10 +4120,9 @@ export class ExpertClaimService {
|
||||
carAngles,
|
||||
damagedParts,
|
||||
awaitingFactorValidation: isFactorValidationPending,
|
||||
evaluation: enrichedEvaluation as
|
||||
evaluation: evaluationForApi as
|
||||
| ClaimDetailV2ResponseDto["evaluation"]
|
||||
| undefined,
|
||||
// objection,
|
||||
videoCapture,
|
||||
blameCase: blameCaseForApi,
|
||||
blameExpertDecision,
|
||||
|
||||
Reference in New Issue
Block a user