1
0
forked from Yara724/api

YARA-1072

This commit is contained in:
SepehrYahyaee
2026-06-28 15:04:18 +03:30
parent d3249e9854
commit 220b39ea5a

View File

@@ -378,7 +378,10 @@ export class ExpertClaimService {
return this.blameRequestDbService.findById(id); return this.blameRequestDbService.findById(id);
} }
private async assertExpertActorOnClaim(claim: any, actor: any): Promise<void> { private async assertExpertActorOnClaim(
claim: any,
actor: any,
): Promise<void> {
const blame = await this.loadBlameForClaim(claim); const blame = await this.loadBlameForClaim(claim);
assertClaimCaseForExpertActor(claim, actor, blame); assertClaimCaseForExpertActor(claim, actor, blame);
} }
@@ -2462,9 +2465,15 @@ export class ExpertClaimService {
*/ */
async assignClaimForReviewV2( async assignClaimForReviewV2(
claimRequestId: string, claimRequestId: string,
actor: { sub: string; fullName?: string; clientKey?: string; role?: string }, actor: {
sub: string;
fullName?: string;
clientKey?: string;
role?: string;
},
): Promise<ExpertFileAssignResultDto> { ): Promise<ExpertFileAssignResultDto> {
if ((actor as any).role !== RoleEnum.FIELD_EXPERT) requireActorClientKey(actor); if ((actor as any).role !== RoleEnum.FIELD_EXPERT)
requireActorClientKey(actor);
await this.expireClaimWorkflowLockV2IfStale(claimRequestId); await this.expireClaimWorkflowLockV2IfStale(claimRequestId);
const claim = await this.claimCaseDbService.findById(claimRequestId); const claim = await this.claimCaseDbService.findById(claimRequestId);
@@ -3003,7 +3012,9 @@ export class ExpertClaimService {
if (priceCap !== null) { if (priceCap !== null) {
let totalPrice = 0; let totalPrice = 0;
for (const part of reply.parts || []) { for (const part of reply.parts || []) {
const parsed = this.parsePersianNumber(String(part.totalPayment ?? "0")); const parsed = this.parsePersianNumber(
String(part.totalPayment ?? "0"),
);
if (!isNaN(parsed)) totalPrice += parsed; if (!isNaN(parsed)) totalPrice += parsed;
} }
if (totalPrice > priceCap) { if (totalPrice > priceCap) {
@@ -3492,10 +3503,11 @@ export class ExpertClaimService {
const clientKey = requireActorClientKey(actor); const clientKey = requireActorClientKey(actor);
const expertId = String(actor.sub); const expertId = String(actor.sub);
const expertOid = new Types.ObjectId(expertId); const expertOid = new Types.ObjectId(expertId);
const activityEvents = await this.expertFileActivityDbService.findByExpert( const activityEvents =
expertId, await this.expertFileActivityDbService.findByExpert(
ExpertFileKind.CLAIM, expertId,
); ExpertFileKind.CLAIM,
);
const activityFileIds = const activityFileIds =
expertPortfolioFileIdsFromActivityEvents(activityEvents); expertPortfolioFileIdsFromActivityEvents(activityEvents);
const orClauses: Record<string, unknown>[] = [ const orClauses: Record<string, unknown>[] = [
@@ -3511,7 +3523,10 @@ export class ExpertClaimService {
const rows = const rows =
orClauses.length === 0 orClauses.length === 0
? [] ? []
: await this.claimCaseDbService.find({ $or: orClauses }, { lean: true }); : await this.claimCaseDbService.find(
{ $or: orClauses },
{ lean: true },
);
const seen = new Set<string>(); const seen = new Set<string>();
for (const doc of rows as Record<string, unknown>[]) { for (const doc of rows as Record<string, unknown>[]) {
const id = String(doc._id ?? ""); const id = String(doc._id ?? "");
@@ -4234,54 +4249,54 @@ export class ExpertClaimService {
} }
// Fall through to the detail build below (skip the damage-expert gate) // Fall through to the detail build below (skip the damage-expert gate)
} else { } else {
const isResendPending = const isResendPending =
claim.status === ClaimCaseStatus.WAITING_FOR_USER_RESEND; claim.status === ClaimCaseStatus.WAITING_FOR_USER_RESEND;
const assignedForReviewById = String( const assignedForReviewById = String(
(claim.workflow as any)?.assignedForReviewBy?.actorId ?? "", (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 &&
!isAssignedToMe
) {
throw new ForbiddenException(
`This claim is not available for expert review. Current status: ${claim.status}`,
); );
} const lockEnforced = this.isClaimV2WorkflowLockCurrentlyEnforced(claim);
const lockedById = String(claim.workflow?.lockedBy?.actorId ?? "");
const isAssignedToMe =
!!assignedForReviewById && assignedForReviewById === actorId;
const isAvailable = // Gate: must satisfy at least one bucket
isDamageExpertPhase && !assignedForReviewById && !lockEnforced; if (
const isLockedByMe = lockEnforced && lockedById === actorId; !isDamageExpertPhase &&
const isFactorValidationOpen = isFactorValidationPending; !isFactorValidationPending &&
!isResendPending &&
if ( !isAssignedToMe
!isAvailable && ) {
!isAssignedToMe &&
!isLockedByMe &&
!isFactorValidationOpen
) {
if (lockEnforced && lockedById && lockedById !== actorId) {
throw new ForbiddenException( throw new ForbiddenException(
`This claim is locked by another expert: ${claim.workflow?.lockedBy?.actorName}`, `This claim is not available for expert review. Current status: ${claim.status}`,
); );
} }
if (assignedForReviewById && assignedForReviewById !== actorId) {
const isAvailable =
isDamageExpertPhase && !assignedForReviewById && !lockEnforced;
const isLockedByMe = lockEnforced && lockedById === actorId;
const isFactorValidationOpen = isFactorValidationPending;
if (
!isAvailable &&
!isAssignedToMe &&
!isLockedByMe &&
!isFactorValidationOpen
) {
if (lockEnforced && lockedById && lockedById !== actorId) {
throw new ForbiddenException(
`This claim is locked by another expert: ${claim.workflow?.lockedBy?.actorName}`,
);
}
if (assignedForReviewById && assignedForReviewById !== actorId) {
throw new ForbiddenException(
"This claim has been assigned to another expert.",
);
}
throw new ForbiddenException( throw new ForbiddenException(
"This claim has been assigned to another expert.", "You do not have permission to view this claim.",
); );
} }
throw new ForbiddenException(
"You do not have permission to view this claim.",
);
}
} // end damage-expert gate (else block) } // end damage-expert gate (else block)
// Build requiredDocuments map // Build requiredDocuments map
@@ -4513,9 +4528,10 @@ export class ExpertClaimService {
carAngles, carAngles,
damagedParts, damagedParts,
awaitingFactorValidation: isFactorValidationPending, awaitingFactorValidation: isFactorValidationPending,
evaluation: evaluationForApi as evaluation:
| ClaimDetailV2ResponseDto["evaluation"] (evaluationForApi as
| undefined, | ClaimDetailV2ResponseDto["evaluation"]
| undefined) || (enrichedEvaluation as any),
videoCapture, videoCapture,
blameCase: blameCaseForApi, blameCase: blameCaseForApi,
blameExpertDecision, blameExpertDecision,