1
0
forked from Yara724/api
This commit is contained in:
2026-04-30 10:32:53 +03:30
parent 715a9f2467
commit bffb8a3b97
2 changed files with 77 additions and 41 deletions

View File

@@ -242,24 +242,19 @@ export class ExpertInsurerController {
}
@ApiParam({ name: "expertId" })
@ApiQuery({ name: "role", enum: ["claim", "blame"] })
@ApiOperation({
summary: "Files handled by one roster expert (summary rows)",
description:
"Resolves id against this insurer's `expert` then `damage-expert` roster. Blame branch runs when the id is on the expert roster (field experts). Each item is a small summary (`kind`, ids, statuses, dates)—not full file payloads. Claim matches use final or draft damage-expert reply.",
})
@Get("/:expertId")
async requestDetail(
@CurrentUser() insurer,
@Param("expertId") id: string,
@Query("role") role: "claim" | "blame",
) {
if (!Types.ObjectId.isValid(new Types.ObjectId(id))) {
async requestDetail(@CurrentUser() insurer, @Param("expertId") id: string) {
if (!Types.ObjectId.isValid(id)) {
throw new BadRequestException("Invalid expert ID");
}
if (!["claim", "blame"].includes(role)) {
throw new BadRequestException("Invalid role");
}
return await this.expertInsurerService.getAllFilesByExpertAndRole(
return await this.expertInsurerService.getAllFilesForInsurerExpert(
id,
role,
insurer.clientKey,
);
}

View File

@@ -144,6 +144,55 @@ export class ExpertInsurerService {
};
}
/** BlameCases may tie the field expert via assignment, expert-initiated id, or decision author. */
private blameFieldExpertIdCandidates(b: any): string[] {
const raw: unknown[] = [
b?.expert?.assignedExpertId,
b?.initiatedByFieldExpertId,
b?.expert?.decision?.decidedByExpertId,
];
const out = new Set<string>();
for (const x of raw) {
if (x != null && x !== "") out.add(String(x));
}
return [...out];
}
private claimDamageExpertActorId(c: any): string | null {
const reply =
c?.evaluation?.damageExpertReplyFinal || c?.evaluation?.damageExpertReply;
const aid = reply?.actorDetail?.actorId;
if (aid == null || aid === "") return null;
return String(aid);
}
private mapBlameFileSummaryForInsurerExpert(b: any) {
return {
kind: "blame" as const,
requestId: String(b._id),
publicId: b.publicId,
requestNo: b.requestNo,
type: b.type,
status: b.status,
blameStatus: b.blameStatus,
createdAt: b.createdAt,
updatedAt: b.updatedAt,
};
}
private mapClaimFileSummaryForInsurerExpert(c: any) {
return {
kind: "claim" as const,
requestId: String(c._id),
publicId: c.publicId,
requestNo: c.requestNo ?? c.requestNumber,
status: c.status,
claimStatus: c.claimStatus,
createdAt: c.createdAt,
updatedAt: c.updatedAt,
};
}
private buildPartiesPreview(parties: any[] | undefined) {
if (!Array.isArray(parties) || !parties.length) return undefined;
return parties.map((p: any) => ({
@@ -365,10 +414,8 @@ export class ExpertInsurerService {
return scored.sort((a, b) => b.combinedScore - a.combinedScore).slice(0, 10);
}
private async assertExpertBelongsToInsurer(
expertObjectId: Types.ObjectId,
insurerClientKey: string,
) {
async getAllFilesForInsurerExpert(expertId: string, insurerClientKey: string) {
const expertObjectId = this.parseObjectId(expertId, "expert id");
const clientOid = this.getClientId(insurerClientKey);
const ckFilter = this.clientKeyScopeFilter(clientOid);
const [experts, damageExperts] = await Promise.all([
@@ -376,42 +423,36 @@ export class ExpertInsurerService {
this.damageExpertDbService.findAll(ckFilter as never),
]);
const id = String(expertObjectId);
const ok = [...experts, ...damageExperts].some((e) => String(e._id) === id);
if (!ok) {
const onBlameRoster = experts.some((e) => String(e._id) === id);
const onClaimRoster = damageExperts.some((e) => String(e._id) === id);
if (!onBlameRoster && !onClaimRoster) {
throw new ForbiddenException(
"This expert is not registered under your insurance company.",
);
}
}
async getAllFilesByExpertAndRole(
expertId: string,
role: "claim" | "blame",
insurerClientKey: string,
) {
const expertObjectId = this.parseObjectId(expertId, "expert id");
await this.assertExpertBelongsToInsurer(expertObjectId, insurerClientKey);
const clientKeyStr = String(this.getClientId(insurerClientKey));
if (role === "claim") {
const claims = (await this.claimCaseDbService.find({}, { lean: true })) as any[];
return claims
.filter(
(c) =>
claimCaseTouchesClient(c, clientKeyStr) &&
c?.evaluation?.damageExpertReply?.actorDetail?.actorId ===
String(expertObjectId),
)
.map((c) => this.normalizeClaimCase(c));
}
const clientKeyStr = String(clientOid);
if (onBlameRoster) {
const blames = (await this.blameRequestDbService.find({}, { lean: true })) as any[];
return blames
.filter(
(b) =>
blameCaseTouchesClient(b, clientKeyStr) &&
String(b?.expert?.assignedExpertId ?? "") === String(expertObjectId),
this.blameFieldExpertIdCandidates(b).includes(id),
)
.map((b) => this.normalizeBlameCase(b));
.map((b) => this.mapBlameFileSummaryForInsurerExpert(b));
}
if (onClaimRoster) {
const claims = (await this.claimCaseDbService.find({}, { lean: true })) as any[];
return claims
.filter(
(c) =>
claimCaseTouchesClient(c, clientKeyStr) &&
this.claimDamageExpertActorId(c) === id,
)
.map((c) => this.mapClaimFileSummaryForInsurerExpert(c));
}
return [];
}
private validateInsurerFileRating(rating: FileRating) {