forked from Yara724/api
YARA-732
This commit is contained in:
@@ -41,12 +41,35 @@ export class ExpertInsurerController {
|
||||
constructor(private readonly expertInsurerService: ExpertInsurerService) {}
|
||||
|
||||
@Get("branches")
|
||||
async getInsuranceBranches(@CurrentUser() insurer) {
|
||||
@ApiQuery({ name: "search", required: false, type: String })
|
||||
@ApiQuery({
|
||||
name: "from",
|
||||
required: false,
|
||||
description: "Optional start datetime (ISO string)",
|
||||
})
|
||||
@ApiQuery({
|
||||
name: "to",
|
||||
required: false,
|
||||
description: "Optional end datetime (ISO string)",
|
||||
})
|
||||
@ApiQuery({
|
||||
name: "isActive",
|
||||
required: false,
|
||||
description: "Filter active state (true/false)",
|
||||
})
|
||||
async getInsuranceBranches(
|
||||
@CurrentUser() insurer,
|
||||
@Query("search") search?: string,
|
||||
@Query("from") from?: string,
|
||||
@Query("to") to?: string,
|
||||
@Query("isActive") isActive?: string,
|
||||
) {
|
||||
if (!insurer) {
|
||||
throw new UnauthorizedException("Could not identify the current user.");
|
||||
}
|
||||
return await this.expertInsurerService.retrieveInsuranceBranches(
|
||||
insurer.clientKey,
|
||||
{ search, from, to, isActive },
|
||||
);
|
||||
}
|
||||
|
||||
@@ -66,6 +89,29 @@ export class ExpertInsurerController {
|
||||
);
|
||||
}
|
||||
|
||||
@Put("branches/:branchId/status")
|
||||
@ApiParam({ name: "branchId" })
|
||||
@ApiQuery({ name: "isActive", type: Boolean })
|
||||
async setBranchStatus(
|
||||
@CurrentUser() insurer,
|
||||
@Param("branchId") branchId: string,
|
||||
@Query("isActive") isActive: string,
|
||||
) {
|
||||
if (!insurer) {
|
||||
throw new UnauthorizedException("Could not identify the current user.");
|
||||
}
|
||||
const normalized = String(isActive).trim().toLowerCase();
|
||||
if (!["true", "false", "1", "0", "yes", "no"].includes(normalized)) {
|
||||
throw new BadRequestException("isActive must be true/false");
|
||||
}
|
||||
const active = ["true", "1", "yes"].includes(normalized);
|
||||
return this.expertInsurerService.setBranchActive(
|
||||
insurer.clientKey,
|
||||
branchId,
|
||||
active,
|
||||
);
|
||||
}
|
||||
|
||||
@Post("experts/blame")
|
||||
@ApiBody({ type: CreateBlameExpertByInsurerDto })
|
||||
async addBlameExpert(
|
||||
|
||||
@@ -1207,12 +1207,66 @@ export class ExpertInsurerService {
|
||||
|
||||
const newBranch = await this.branchDbService.create({
|
||||
...branchDto,
|
||||
isActive: branchDto.isActive ?? true,
|
||||
activityStartDate: branchDto.activityStartDate
|
||||
? new Date(branchDto.activityStartDate)
|
||||
: undefined,
|
||||
clientKey: clientId,
|
||||
});
|
||||
|
||||
return newBranch;
|
||||
}
|
||||
|
||||
private parseOptionalBoolean(value?: string): boolean | undefined {
|
||||
if (value == null || value === "") return undefined;
|
||||
const normalized = String(value).trim().toLowerCase();
|
||||
if (["true", "1", "yes"].includes(normalized)) return true;
|
||||
if (["false", "0", "no"].includes(normalized)) return false;
|
||||
throw new BadRequestException("Invalid boolean value for 'isActive'");
|
||||
}
|
||||
|
||||
private buildHandlingBranchStatusSets() {
|
||||
const blameInHandling = new Set<string>([
|
||||
CaseStatus.OPEN,
|
||||
CaseStatus.WAITING_FOR_SECOND_PARTY,
|
||||
CaseStatus.WAITING_FOR_EXPERT,
|
||||
CaseStatus.WAITING_FOR_DOCUMENT_RESEND,
|
||||
CaseStatus.WAITING_FOR_SIGNATURES,
|
||||
]);
|
||||
const claimInHandling = new Set<string>([
|
||||
ClaimCaseStatus.CREATED,
|
||||
ClaimCaseStatus.SELECTING_OUTER_PARTS,
|
||||
ClaimCaseStatus.SELECTING_OTHER_PARTS,
|
||||
ClaimCaseStatus.UPLOADING_REQUIRED_DOCUMENTS,
|
||||
ClaimCaseStatus.CAPTURING_PART_DAMAGES,
|
||||
ClaimCaseStatus.WAITING_FOR_USER_RESEND,
|
||||
ClaimCaseStatus.WAITING_FOR_DAMAGE_EXPERT,
|
||||
ClaimCaseStatus.EXPERT_REVIEWING,
|
||||
ClaimCaseStatus.WAITING_FOR_INSURER_APPROVAL,
|
||||
ClaimCaseStatus.INSURER_REVIEW_AWAITING_OWNER_SIGN,
|
||||
ClaimCaseStatus.INSURER_REVIEW_MIXED_FACTORS_PENDING,
|
||||
ClaimCaseStatus.OWNER_REPAIR_FACTOR_UPLOAD_PENDING,
|
||||
ClaimCaseStatus.EXPERT_VALIDATING_REPAIR_FACTORS,
|
||||
]);
|
||||
return { blameInHandling, claimInHandling };
|
||||
}
|
||||
|
||||
async setBranchActive(
|
||||
clientKey: string,
|
||||
branchId: string,
|
||||
isActive: boolean,
|
||||
) {
|
||||
const clientId = this.getClientId(clientKey);
|
||||
await this.assertBranchBelongsToClient(branchId, clientId);
|
||||
const updated = await this.branchDbService.findByIdAndUpdate(branchId, {
|
||||
$set: { isActive },
|
||||
});
|
||||
if (!updated) {
|
||||
throw new NotFoundException("Branch not found");
|
||||
}
|
||||
return updated;
|
||||
}
|
||||
|
||||
private async assertBranchBelongsToClient(
|
||||
branchId: string,
|
||||
clientId: Types.ObjectId,
|
||||
@@ -1445,8 +1499,108 @@ export class ExpertInsurerService {
|
||||
};
|
||||
}
|
||||
|
||||
async retrieveInsuranceBranches(insuranceId: string) {
|
||||
return this.branchDbService.findAll(insuranceId);
|
||||
async retrieveInsuranceBranches(
|
||||
insuranceId: string,
|
||||
opts?: {
|
||||
search?: string;
|
||||
from?: string;
|
||||
to?: string;
|
||||
isActive?: string;
|
||||
},
|
||||
) {
|
||||
const clientObjectId = this.getClientId(insuranceId);
|
||||
const { fromDate, toDate } = this.parseDateRange(opts?.from, opts?.to);
|
||||
const isActiveFilter = this.parseOptionalBoolean(opts?.isActive);
|
||||
const branches = await this.branchDbService.findAllWithFilters(String(clientObjectId), {
|
||||
search: opts?.search,
|
||||
from: fromDate,
|
||||
to: toDate,
|
||||
isActive: isActiveFilter,
|
||||
});
|
||||
|
||||
const branchIdSet = new Set(branches.map((b: any) => String(b._id)));
|
||||
const ckFilter = this.clientKeyScopeFilter(clientObjectId);
|
||||
const [experts, damageExperts, blameFiles, claimFiles] = await Promise.all([
|
||||
this.expertDbService.findAll(ckFilter as never),
|
||||
this.damageExpertDbService.findAll(ckFilter as never),
|
||||
this.getClientBlameFiles(clientObjectId),
|
||||
this.getClientClaimFiles(clientObjectId),
|
||||
]);
|
||||
|
||||
const activeExpertsByBranch = new Map<string, Set<string>>();
|
||||
const expertBranchById = new Map<string, string>();
|
||||
const claimExpertBranchById = new Map<string, string>();
|
||||
for (const e of experts as any[]) {
|
||||
const bid = e?.branchId ? String(e.branchId) : "";
|
||||
if (!bid || !branchIdSet.has(bid)) continue;
|
||||
const eid = String(e?._id || "");
|
||||
if (!eid) continue;
|
||||
expertBranchById.set(eid, bid);
|
||||
if (!activeExpertsByBranch.has(bid)) activeExpertsByBranch.set(bid, new Set());
|
||||
activeExpertsByBranch.get(bid)!.add(eid);
|
||||
}
|
||||
for (const e of damageExperts as any[]) {
|
||||
const bid = e?.branchId ? String(e.branchId) : "";
|
||||
if (!bid || !branchIdSet.has(bid)) continue;
|
||||
const eid = String(e?._id || "");
|
||||
if (!eid) continue;
|
||||
claimExpertBranchById.set(eid, bid);
|
||||
if (!activeExpertsByBranch.has(bid)) activeExpertsByBranch.set(bid, new Set());
|
||||
activeExpertsByBranch.get(bid)!.add(eid);
|
||||
}
|
||||
|
||||
const completedByBranch = new Map<string, Set<string>>();
|
||||
const handlingByBranch = new Map<string, Set<string>>();
|
||||
const { blameInHandling, claimInHandling } = this.buildHandlingBranchStatusSets();
|
||||
const addPublicId = (map: Map<string, Set<string>>, branchId: string, fileKey: string) => {
|
||||
if (!map.has(branchId)) map.set(branchId, new Set());
|
||||
map.get(branchId)!.add(fileKey);
|
||||
};
|
||||
|
||||
for (const b of blameFiles as any[]) {
|
||||
const expertId = String(b?.expert?.assignedExpertId || "");
|
||||
if (!expertId) continue;
|
||||
const bid = expertBranchById.get(expertId);
|
||||
if (!bid) continue;
|
||||
const fileKey = String(b?.publicId || b?._id || "");
|
||||
if (!fileKey) continue;
|
||||
const status = String(b?.status || "");
|
||||
if (status === CaseStatus.COMPLETED) addPublicId(completedByBranch, bid, fileKey);
|
||||
if (blameInHandling.has(status)) addPublicId(handlingByBranch, bid, fileKey);
|
||||
}
|
||||
|
||||
for (const c of claimFiles as any[]) {
|
||||
const expertId = String(this.claimDamageExpertActorId(c) || "");
|
||||
if (!expertId) continue;
|
||||
const bid = claimExpertBranchById.get(expertId);
|
||||
if (!bid) continue;
|
||||
const fileKey = String(c?.publicId || c?._id || "");
|
||||
if (!fileKey) continue;
|
||||
const status = String(c?.status || "");
|
||||
if (status === ClaimCaseStatus.COMPLETED) addPublicId(completedByBranch, bid, fileKey);
|
||||
if (claimInHandling.has(status)) addPublicId(handlingByBranch, bid, fileKey);
|
||||
}
|
||||
|
||||
const list = branches.map((branch: any) => {
|
||||
const bid = String(branch._id);
|
||||
return {
|
||||
...branch,
|
||||
totalActiveExperts: activeExpertsByBranch.get(bid)?.size ?? 0,
|
||||
totalFinishedFiles: completedByBranch.get(bid)?.size ?? 0,
|
||||
totalFilesInHandling: handlingByBranch.get(bid)?.size ?? 0,
|
||||
};
|
||||
});
|
||||
|
||||
return {
|
||||
total: list.length,
|
||||
filters: {
|
||||
search: opts?.search ?? null,
|
||||
from: fromDate ?? null,
|
||||
to: toDate ?? null,
|
||||
isActive: isActiveFilter ?? null,
|
||||
},
|
||||
branches: list,
|
||||
};
|
||||
}
|
||||
|
||||
private parseDateRange(from?: string, to?: string) {
|
||||
|
||||
Reference in New Issue
Block a user