1
0
forked from Yara724/api
This commit is contained in:
2026-05-01 11:25:10 +03:30
parent 8419ec06ae
commit 6f120b0066
3 changed files with 68 additions and 5 deletions

View File

@@ -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<string> {
const ids = new Set<string>();
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 },
},
},
});

View File

@@ -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,

View File

@@ -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;