From 6f120b006681ac0ddfc17fe49b32a4d2ba886b59 Mon Sep 17 00:00:00 2001 From: "s.yahyaee" Date: Fri, 1 May 2026 11:25:10 +0330 Subject: [PATCH] YARA-868 --- .../claim-request-management.service.ts | 55 ++++++++++++++++++- .../claim-request-management.v2.controller.ts | 14 ++++- .../schema/claim-case.evaluation.schema.ts | 4 ++ 3 files changed, 68 insertions(+), 5 deletions(-) diff --git a/src/claim-request-management/claim-request-management.service.ts b/src/claim-request-management/claim-request-management.service.ts index ea6a7a2..228c722 100644 --- a/src/claim-request-management/claim-request-management.service.ts +++ b/src/claim-request-management/claim-request-management.service.ts @@ -2805,6 +2805,27 @@ export class ClaimRequestManagementService { }, 0); } + /** Branch ids referenced on expert-priced parts (`daghi` object with `branchId`). */ + private collectBranchIdsFromClaimExpertReply(reply: { + parts?: unknown[]; + }): Set { + const ids = new Set(); + const parts = reply?.parts; + if (!Array.isArray(parts)) { + return ids; + } + for (const p of parts) { + const d = (p as { daghi?: unknown })?.daghi; + if (d && typeof d === "object" && d !== null && "branchId" in d) { + const bid = (d as { branchId?: unknown }).branchId; + if (bid != null && Types.ObjectId.isValid(String(bid))) { + ids.add(String(bid)); + } + } + } + return ids; + } + /** * Fanavaran Submit - Map data from claim-request-management and request-management to third-party-car-financial-claims format */ @@ -5139,6 +5160,7 @@ export class ClaimRequestManagementService { async submitOwnerInsurerApprovalSignV2( claimRequestId: string, agree: boolean, + branchId: string, signFile: Express.Multer.File, currentUserId: string, actor?: { sub: string; role?: string; fullName?: string }, @@ -5200,6 +5222,34 @@ export class ClaimRequestManagementService { throw new BadRequestException("No expert reply is available to sign off on yet."); } + const rawBranchId = (branchId ?? "").trim(); + if (!rawBranchId || !Types.ObjectId.isValid(rawBranchId)) { + throw new BadRequestException( + "branchId is required and must be a valid MongoDB ObjectId.", + ); + } + const branchDoc = await this.branchDbService.findById(rawBranchId); + if (!branchDoc) { + throw new NotFoundException(`Branch with ID ${rawBranchId} not found.`); + } + const ownerClientId = claimCase.owner?.clientId; + if (!ownerClientId || String(branchDoc.clientKey) !== String(ownerClientId)) { + throw new ForbiddenException( + "This branch does not belong to the insurer for this claim.", + ); + } + const branchIdsOnPricing = this.collectBranchIdsFromClaimExpertReply( + activeReply as { parts?: unknown[] }, + ); + if ( + branchIdsOnPricing.size > 0 && + !branchIdsOnPricing.has(String(rawBranchId)) + ) { + throw new BadRequestException( + "branchId must match a branch used in the expert pricing for this claim.", + ); + } + const signDoc = await this.claimSignDbService.create({ fileName: signFile.filename, userId: effectiveUserId, @@ -5210,6 +5260,7 @@ export class ClaimRequestManagementService { const signedAt = new Date(); const approvalPayload = { agree, + branchId: new Types.ObjectId(rawBranchId), signDetailId: signId, signedAt, }; @@ -5233,7 +5284,7 @@ export class ClaimRequestManagementService { type: "OWNER_REJECTED_INSURER_APPROVAL_PRICING", actor: historyActor, timestamp: signedAt, - metadata: {}, + metadata: { branchId: rawBranchId }, }, }, }); @@ -5262,7 +5313,7 @@ export class ClaimRequestManagementService { type: "OWNER_SIGNED_INSURER_APPROVAL", actor: historyActor, timestamp: signedAt, - metadata: {}, + metadata: { branchId: rawBranchId }, }, }, }); diff --git a/src/claim-request-management/claim-request-management.v2.controller.ts b/src/claim-request-management/claim-request-management.v2.controller.ts index 718ca76..78b650a 100644 --- a/src/claim-request-management/claim-request-management.v2.controller.ts +++ b/src/claim-request-management/claim-request-management.v2.controller.ts @@ -245,21 +245,27 @@ export class ClaimRequestManagementV2Controller { @ApiOperation({ summary: "Sign final claim pricing (owner)", description: - "Multipart: `sign` (signature image) and `agree` (boolean). Allowed only when `status` is WAITING_FOR_INSURER_APPROVAL, " + + "Multipart: `sign` (signature image), `agree` (boolean), and `branchId` (Mongo ObjectId of the insurer branch the file is reviewed under). " + + "Allowed only when `status` is WAITING_FOR_INSURER_APPROVAL, " + "`workflow.currentStep` is INSURER_REVIEW (not EXPERT_COST_EVALUATION), and `claimStatus` is APPROVED. " + "If `agree` is true, the case moves to COMPLETED; if false, to REJECTED.", }) @ApiBody({ - description: "Signature file and agreement", + description: "Signature file, agreement, and branch", schema: { type: "object", - required: ["sign", "agree"], + required: ["sign", "agree", "branchId"], properties: { sign: { type: "string", format: "binary", description: "Signature image" }, agree: { type: "boolean", description: "true to accept expert pricing and complete the claim", }, + branchId: { + type: "string", + description: "Insurer branch id (must belong to the claim owner's insurer; if pricing lists branch options, must match one of them)", + example: "507f1f77bcf86cd799439011", + }, }, }, }) @@ -285,6 +291,7 @@ export class ClaimRequestManagementV2Controller { async submitOwnerInsurerApprovalSignV2( @Param("claimRequestId") claimRequestId: string, @Body("agree") agree: string | boolean, + @Body("branchId") branchId: string, @CurrentUser() user: any, @UploadedFile() sign: Express.Multer.File, ) { @@ -297,6 +304,7 @@ export class ClaimRequestManagementV2Controller { return await this.claimRequestManagementService.submitOwnerInsurerApprovalSignV2( claimRequestId, agreed, + typeof branchId === "string" ? branchId : "", sign, user.sub, user, diff --git a/src/claim-request-management/entites/schema/claim-case.evaluation.schema.ts b/src/claim-request-management/entites/schema/claim-case.evaluation.schema.ts index 770aea6..5e58798 100644 --- a/src/claim-request-management/entites/schema/claim-case.evaluation.schema.ts +++ b/src/claim-request-management/entites/schema/claim-case.evaluation.schema.ts @@ -82,6 +82,10 @@ export class ClaimOwnerInsurerApproval { @Prop({ type: Boolean, required: true }) agree: boolean; + /** Branch the owner is signing for (must belong to their insurer; aligned with expert daghi options when present). */ + @Prop({ type: Types.ObjectId }) + branchId?: Types.ObjectId; + @Prop({ type: Types.ObjectId }) signDetailId?: Types.ObjectId;