forked from Yara724/api
YARA-855
This commit is contained in:
@@ -242,24 +242,19 @@ export class ExpertInsurerController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ApiParam({ name: "expertId" })
|
@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")
|
@Get("/:expertId")
|
||||||
async requestDetail(
|
async requestDetail(@CurrentUser() insurer, @Param("expertId") id: string) {
|
||||||
@CurrentUser() insurer,
|
if (!Types.ObjectId.isValid(id)) {
|
||||||
@Param("expertId") id: string,
|
|
||||||
@Query("role") role: "claim" | "blame",
|
|
||||||
) {
|
|
||||||
if (!Types.ObjectId.isValid(new Types.ObjectId(id))) {
|
|
||||||
throw new BadRequestException("Invalid expert ID");
|
throw new BadRequestException("Invalid expert ID");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!["claim", "blame"].includes(role)) {
|
return await this.expertInsurerService.getAllFilesForInsurerExpert(
|
||||||
throw new BadRequestException("Invalid role");
|
|
||||||
}
|
|
||||||
|
|
||||||
return await this.expertInsurerService.getAllFilesByExpertAndRole(
|
|
||||||
id,
|
id,
|
||||||
role,
|
|
||||||
insurer.clientKey,
|
insurer.clientKey,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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) {
|
private buildPartiesPreview(parties: any[] | undefined) {
|
||||||
if (!Array.isArray(parties) || !parties.length) return undefined;
|
if (!Array.isArray(parties) || !parties.length) return undefined;
|
||||||
return parties.map((p: any) => ({
|
return parties.map((p: any) => ({
|
||||||
@@ -365,10 +414,8 @@ export class ExpertInsurerService {
|
|||||||
return scored.sort((a, b) => b.combinedScore - a.combinedScore).slice(0, 10);
|
return scored.sort((a, b) => b.combinedScore - a.combinedScore).slice(0, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async assertExpertBelongsToInsurer(
|
async getAllFilesForInsurerExpert(expertId: string, insurerClientKey: string) {
|
||||||
expertObjectId: Types.ObjectId,
|
const expertObjectId = this.parseObjectId(expertId, "expert id");
|
||||||
insurerClientKey: string,
|
|
||||||
) {
|
|
||||||
const clientOid = this.getClientId(insurerClientKey);
|
const clientOid = this.getClientId(insurerClientKey);
|
||||||
const ckFilter = this.clientKeyScopeFilter(clientOid);
|
const ckFilter = this.clientKeyScopeFilter(clientOid);
|
||||||
const [experts, damageExperts] = await Promise.all([
|
const [experts, damageExperts] = await Promise.all([
|
||||||
@@ -376,42 +423,36 @@ export class ExpertInsurerService {
|
|||||||
this.damageExpertDbService.findAll(ckFilter as never),
|
this.damageExpertDbService.findAll(ckFilter as never),
|
||||||
]);
|
]);
|
||||||
const id = String(expertObjectId);
|
const id = String(expertObjectId);
|
||||||
const ok = [...experts, ...damageExperts].some((e) => String(e._id) === id);
|
const onBlameRoster = experts.some((e) => String(e._id) === id);
|
||||||
if (!ok) {
|
const onClaimRoster = damageExperts.some((e) => String(e._id) === id);
|
||||||
|
if (!onBlameRoster && !onClaimRoster) {
|
||||||
throw new ForbiddenException(
|
throw new ForbiddenException(
|
||||||
"This expert is not registered under your insurance company.",
|
"This expert is not registered under your insurance company.",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
async getAllFilesByExpertAndRole(
|
const clientKeyStr = String(clientOid);
|
||||||
expertId: string,
|
if (onBlameRoster) {
|
||||||
role: "claim" | "blame",
|
const blames = (await this.blameRequestDbService.find({}, { lean: true })) as any[];
|
||||||
insurerClientKey: string,
|
return blames
|
||||||
) {
|
.filter(
|
||||||
const expertObjectId = this.parseObjectId(expertId, "expert id");
|
(b) =>
|
||||||
await this.assertExpertBelongsToInsurer(expertObjectId, insurerClientKey);
|
blameCaseTouchesClient(b, clientKeyStr) &&
|
||||||
const clientKeyStr = String(this.getClientId(insurerClientKey));
|
this.blameFieldExpertIdCandidates(b).includes(id),
|
||||||
|
)
|
||||||
if (role === "claim") {
|
.map((b) => this.mapBlameFileSummaryForInsurerExpert(b));
|
||||||
|
}
|
||||||
|
if (onClaimRoster) {
|
||||||
const claims = (await this.claimCaseDbService.find({}, { lean: true })) as any[];
|
const claims = (await this.claimCaseDbService.find({}, { lean: true })) as any[];
|
||||||
return claims
|
return claims
|
||||||
.filter(
|
.filter(
|
||||||
(c) =>
|
(c) =>
|
||||||
claimCaseTouchesClient(c, clientKeyStr) &&
|
claimCaseTouchesClient(c, clientKeyStr) &&
|
||||||
c?.evaluation?.damageExpertReply?.actorDetail?.actorId ===
|
this.claimDamageExpertActorId(c) === id,
|
||||||
String(expertObjectId),
|
|
||||||
)
|
)
|
||||||
.map((c) => this.normalizeClaimCase(c));
|
.map((c) => this.mapClaimFileSummaryForInsurerExpert(c));
|
||||||
}
|
}
|
||||||
const blames = (await this.blameRequestDbService.find({}, { lean: true })) as any[];
|
return [];
|
||||||
return blames
|
|
||||||
.filter(
|
|
||||||
(b) =>
|
|
||||||
blameCaseTouchesClient(b, clientKeyStr) &&
|
|
||||||
String(b?.expert?.assignedExpertId ?? "") === String(expertObjectId),
|
|
||||||
)
|
|
||||||
.map((b) => this.normalizeBlameCase(b));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private validateInsurerFileRating(rating: FileRating) {
|
private validateInsurerFileRating(rating: FileRating) {
|
||||||
|
|||||||
Reference in New Issue
Block a user