forked from Yara724/api
update the expert claim dto
This commit is contained in:
@@ -8,6 +8,8 @@ import {
|
|||||||
ValidateNested,
|
ValidateNested,
|
||||||
} from 'class-validator';
|
} from 'class-validator';
|
||||||
import { Type } from 'class-transformer';
|
import { Type } from 'class-transformer';
|
||||||
|
import { ClaimRequiredDocumentType } from 'src/Types&Enums/claim-request-management/required-document-type.enum';
|
||||||
|
import { DamagedPartItem } from 'src/claim-request-management/dto/capture-requirements-v2.dto';
|
||||||
|
|
||||||
export class CarPartDamageV2Dto {
|
export class CarPartDamageV2Dto {
|
||||||
@ApiProperty({ example: 'left' })
|
@ApiProperty({ example: 'left' })
|
||||||
@@ -68,3 +70,14 @@ export class SubmitExpertReplyV2Dto {
|
|||||||
@Type(() => PartPricingV2Dto)
|
@Type(() => PartPricingV2Dto)
|
||||||
parts: PartPricingV2Dto[];
|
parts: PartPricingV2Dto[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class ClaimSubmitResendV2Dto {
|
||||||
|
@ApiProperty({ required: true })
|
||||||
|
resendDescription: string;
|
||||||
|
|
||||||
|
@ApiProperty({ required: true, examples: ClaimRequiredDocumentType })
|
||||||
|
resendDocuments: ClaimRequiredDocumentType[];
|
||||||
|
|
||||||
|
@ApiProperty({ required: true, type: [DamagedPartItem] })
|
||||||
|
resendCarParts: DamagedPartItem[];
|
||||||
|
}
|
||||||
|
|||||||
@@ -42,6 +42,8 @@ import { ClaimRequiredDocumentDbService } from "src/claim-request-management/ent
|
|||||||
import { FactorStatus } from "src/Types&Enums/claim-request-management/factor-status.enum";
|
import { FactorStatus } from "src/Types&Enums/claim-request-management/factor-status.enum";
|
||||||
import { DaghiOption } from "src/Types&Enums/claim-request-management/daghi-option.enum";
|
import { DaghiOption } from "src/Types&Enums/claim-request-management/daghi-option.enum";
|
||||||
import { BranchDbService } from "src/client/entities/db-service/branch.db.service";
|
import { BranchDbService } from "src/client/entities/db-service/branch.db.service";
|
||||||
|
import { ClaimSubmitResendV2Dto } from "./dto/expert-claim-v2.dto";
|
||||||
|
import { BlameRequestDbService } from "src/request-management/entities/db-service/blame-request.db.service";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ExpertClaimService {
|
export class ExpertClaimService {
|
||||||
@@ -154,13 +156,14 @@ export class ExpertClaimService {
|
|||||||
private readonly claimVideoCaptureDbService: VideoCaptureDbService,
|
private readonly claimVideoCaptureDbService: VideoCaptureDbService,
|
||||||
private readonly httpService: HttpService,
|
private readonly httpService: HttpService,
|
||||||
private readonly claimCaseDbService: ClaimCaseDbService,
|
private readonly claimCaseDbService: ClaimCaseDbService,
|
||||||
|
private readonly blameRequestDbService: BlameRequestDbService,
|
||||||
private readonly sandHubService: SandHubService,
|
private readonly sandHubService: SandHubService,
|
||||||
private readonly damageExpertDbService: DamageExpertDbService,
|
private readonly damageExpertDbService: DamageExpertDbService,
|
||||||
private readonly clientDbService: ClientDbService,
|
private readonly clientDbService: ClientDbService,
|
||||||
private readonly claimFactorsImageDbService: ClaimFactorsImageDbService,
|
private readonly claimFactorsImageDbService: ClaimFactorsImageDbService,
|
||||||
private readonly claimRequiredDocumentDbService: ClaimRequiredDocumentDbService,
|
private readonly claimRequiredDocumentDbService: ClaimRequiredDocumentDbService,
|
||||||
private readonly branchDbService: BranchDbService,
|
private readonly branchDbService: BranchDbService,
|
||||||
) {}
|
) { }
|
||||||
|
|
||||||
private isVisibleToClientType(client: any, actor: any): boolean {
|
private isVisibleToClientType(client: any, actor: any): boolean {
|
||||||
if (actor.userType === UserType.GENUINE) {
|
if (actor.userType === UserType.GENUINE) {
|
||||||
@@ -542,9 +545,9 @@ export class ExpertClaimService {
|
|||||||
`[PriceDrop] Request ${requestId}: Fetched ${carPrices.length} car prices. Searching for: "${request.carDetail.carName}"`,
|
`[PriceDrop] Request ${requestId}: Fetched ${carPrices.length} car prices. Searching for: "${request.carDetail.carName}"`,
|
||||||
);
|
);
|
||||||
|
|
||||||
const closestCar = this.findClosestCar(
|
const closestCar = this.findClosestCar(
|
||||||
request.carDetail.carName,
|
request.carDetail.carName,
|
||||||
carPrices,
|
carPrices,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!closestCar) {
|
if (!closestCar) {
|
||||||
@@ -558,11 +561,11 @@ export class ExpertClaimService {
|
|||||||
} else {
|
} else {
|
||||||
this.logger.debug(
|
this.logger.debug(
|
||||||
`[PriceDrop] Request ${requestId}: Found matching car "${closestCar.carName}" with marketPrice: ${closestCar.marketPrice}`,
|
`[PriceDrop] Request ${requestId}: Found matching car "${closestCar.carName}" with marketPrice: ${closestCar.marketPrice}`,
|
||||||
);
|
);
|
||||||
autoCalculatedData = {
|
autoCalculatedData = {
|
||||||
carPrice: closestCar.marketPrice,
|
carPrice: closestCar.marketPrice,
|
||||||
carValue: severityValues,
|
carValue: severityValues,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -600,10 +603,10 @@ export class ExpertClaimService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Step 6: Save to database
|
// Step 6: Save to database
|
||||||
await this.claimRequestManagementDbService.findOneAndUpdate(
|
await this.claimRequestManagementDbService.findOneAndUpdate(
|
||||||
{ _id: new Types.ObjectId(request._id) },
|
{ _id: new Types.ObjectId(request._id) },
|
||||||
{ $set: { priceDrop: finalPriceDropData } },
|
{ $set: { priceDrop: finalPriceDropData } },
|
||||||
);
|
);
|
||||||
|
|
||||||
this.logger.log(
|
this.logger.log(
|
||||||
`[PriceDrop] Request ${requestId}: Price drop calculation completed and saved.`,
|
`[PriceDrop] Request ${requestId}: Price drop calculation completed and saved.`,
|
||||||
@@ -671,7 +674,7 @@ export class ExpertClaimService {
|
|||||||
|
|
||||||
const severityValue =
|
const severityValue =
|
||||||
this.priceDropPart[originalPriceDropKey]?.[
|
this.priceDropPart[originalPriceDropKey]?.[
|
||||||
damagedPartInfo.severity
|
damagedPartInfo.severity
|
||||||
];
|
];
|
||||||
|
|
||||||
if (severityValue !== undefined) {
|
if (severityValue !== undefined) {
|
||||||
@@ -974,7 +977,7 @@ export class ExpertClaimService {
|
|||||||
|
|
||||||
if (!isLockedByCurrentUser) {
|
if (!isLockedByCurrentUser) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Also check if lock has expired (unlockTime has passed)
|
// Also check if lock has expired (unlockTime has passed)
|
||||||
if (request.unlockTime) {
|
if (request.unlockTime) {
|
||||||
@@ -1041,8 +1044,8 @@ export class ExpertClaimService {
|
|||||||
const unlockTime = new Date(request.unlockTime).getTime();
|
const unlockTime = new Date(request.unlockTime).getTime();
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
if (now >= unlockTime) {
|
if (now >= unlockTime) {
|
||||||
throw new ForbiddenException("Your time has expired");
|
throw new ForbiddenException("Your time has expired");
|
||||||
}
|
}
|
||||||
} else if (request?.unlockTime == null && !request?.objection) {
|
} else if (request?.unlockTime == null && !request?.objection) {
|
||||||
throw new ForbiddenException("Your time has expired");
|
throw new ForbiddenException("Your time has expired");
|
||||||
}
|
}
|
||||||
@@ -1255,6 +1258,66 @@ export class ExpertClaimService {
|
|||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async streamServiceV2(requestId, query, res, header) {
|
||||||
|
const request = await this.claimCaseDbService.findById(requestId);
|
||||||
|
console.log(request)
|
||||||
|
// const blameCase = await this.blameCaseDbService
|
||||||
|
return request;
|
||||||
|
// let videoPath: string = "";
|
||||||
|
// switch (query) {
|
||||||
|
// case "accident":
|
||||||
|
// videoPath = await this.getAccidentVideoPath(
|
||||||
|
// String(
|
||||||
|
// request?.blameFile?.firstPartyDetails?.firstPartyFile
|
||||||
|
// ?.firstPartyVideoId,
|
||||||
|
// ),
|
||||||
|
// );
|
||||||
|
// break;
|
||||||
|
// case "car-capture":
|
||||||
|
// videoPath = await this.getCarCapture(requestId);
|
||||||
|
// break;
|
||||||
|
// default:
|
||||||
|
// throw new NotFoundException("Invalid query type");
|
||||||
|
// }
|
||||||
|
// if (!videoPath) throw new NotFoundException("video_not_found");
|
||||||
|
|
||||||
|
// const absolutePath = join(process.cwd(), videoPath.replace(/^\/+/, ""));
|
||||||
|
|
||||||
|
// if (!existsSync(absolutePath)) {
|
||||||
|
// throw new NotFoundException(
|
||||||
|
// `Video file not found at path: ${absolutePath}`,
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
// const { size } = statSync(absolutePath);
|
||||||
|
// const range = header.range;
|
||||||
|
|
||||||
|
// if (range) {
|
||||||
|
// const [startStr, endStr] = range.replace(/bytes=/, "").split("-");
|
||||||
|
// const start = parseInt(startStr, 10);
|
||||||
|
// const end = endStr ? parseInt(endStr, 10) : size - 1;
|
||||||
|
// const chunkSize = end - start + 1;
|
||||||
|
|
||||||
|
// const file = createReadStream(absolutePath, { start, end });
|
||||||
|
|
||||||
|
// res.writeHead(206, {
|
||||||
|
// "Content-Range": `bytes ${start}-${end}/${size}`,
|
||||||
|
// "Accept-Ranges": "bytes",
|
||||||
|
// "Content-Length": chunkSize,
|
||||||
|
// "Content-Type": "video/mp4",
|
||||||
|
// });
|
||||||
|
|
||||||
|
// file.pipe(res);
|
||||||
|
// } else {
|
||||||
|
// res.writeHead(200, {
|
||||||
|
// "Content-Length": size,
|
||||||
|
// "Content-Type": "video/mp4",
|
||||||
|
// });
|
||||||
|
|
||||||
|
// createReadStream(absolutePath).pipe(res);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
async streamService(requestId, query, res, header) {
|
async streamService(requestId, query, res, header) {
|
||||||
const request =
|
const request =
|
||||||
await this.claimRequestManagementDbService.findOne(requestId);
|
await this.claimRequestManagementDbService.findOne(requestId);
|
||||||
@@ -1635,6 +1698,18 @@ export class ExpertClaimService {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async submitResendDocsV2(
|
||||||
|
claimRequestId: string,
|
||||||
|
reply: ClaimSubmitResendV2Dto,
|
||||||
|
actor: any,
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* V2: Submit damage expert reply for a claim.
|
* V2: Submit damage expert reply for a claim.
|
||||||
*
|
*
|
||||||
@@ -1839,16 +1914,16 @@ export class ExpertClaimService {
|
|||||||
locked: c.workflow?.locked || false,
|
locked: c.workflow?.locked || false,
|
||||||
lockedBy: c.workflow?.lockedBy
|
lockedBy: c.workflow?.lockedBy
|
||||||
? {
|
? {
|
||||||
actorId: c.workflow.lockedBy.actorId?.toString(),
|
actorId: c.workflow.lockedBy.actorId?.toString(),
|
||||||
actorName: c.workflow.lockedBy.actorName,
|
actorName: c.workflow.lockedBy.actorName,
|
||||||
}
|
}
|
||||||
: undefined,
|
: undefined,
|
||||||
vehicle: c.vehicle
|
vehicle: c.vehicle
|
||||||
? {
|
? {
|
||||||
carName: c.vehicle.carName,
|
carName: c.vehicle.carName,
|
||||||
carModel: c.vehicle.carModel,
|
carModel: c.vehicle.carModel,
|
||||||
carType: c.vehicle.carType,
|
carType: c.vehicle.carType,
|
||||||
}
|
}
|
||||||
: undefined,
|
: undefined,
|
||||||
createdAt: c.createdAt,
|
createdAt: c.createdAt,
|
||||||
})) as ClaimListItemV2Dto[];
|
})) as ClaimListItemV2Dto[];
|
||||||
@@ -1944,16 +2019,16 @@ export class ExpertClaimService {
|
|||||||
locked: claim.workflow?.locked || false,
|
locked: claim.workflow?.locked || false,
|
||||||
lockedBy: claim.workflow?.lockedBy
|
lockedBy: claim.workflow?.lockedBy
|
||||||
? {
|
? {
|
||||||
actorId: claim.workflow.lockedBy.actorId?.toString(),
|
actorId: claim.workflow.lockedBy.actorId?.toString(),
|
||||||
actorName: claim.workflow.lockedBy.actorName,
|
actorName: claim.workflow.lockedBy.actorName,
|
||||||
lockedAt: (claim.workflow as any).lockedAt?.toISOString(),
|
lockedAt: (claim.workflow as any).lockedAt?.toISOString(),
|
||||||
}
|
}
|
||||||
: undefined,
|
: undefined,
|
||||||
owner: claim.owner
|
owner: claim.owner
|
||||||
? {
|
? {
|
||||||
userId: claim.owner.userId?.toString(),
|
userId: claim.owner.userId?.toString(),
|
||||||
fullName: claim.owner.fullName,
|
fullName: claim.owner.fullName,
|
||||||
}
|
}
|
||||||
: undefined,
|
: undefined,
|
||||||
vehicle: claim.vehicle,
|
vehicle: claim.vehicle,
|
||||||
blameRequestId: claim.blameRequestId?.toString(),
|
blameRequestId: claim.blameRequestId?.toString(),
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
import { Body, Controller, Get, Param, Patch, Put, UseGuards } from "@nestjs/common";
|
import { Body, Controller, Get, Header, Param, Headers, Patch, Put, UseGuards, Query, Res } from "@nestjs/common";
|
||||||
import {
|
import {
|
||||||
ApiBearerAuth,
|
ApiBearerAuth,
|
||||||
ApiBody,
|
ApiBody,
|
||||||
ApiOperation,
|
ApiOperation,
|
||||||
ApiParam,
|
ApiParam,
|
||||||
ApiPropertyOptional,
|
ApiPropertyOptional,
|
||||||
|
ApiQuery,
|
||||||
ApiTags,
|
ApiTags,
|
||||||
} from "@nestjs/swagger";
|
} from "@nestjs/swagger";
|
||||||
import { IsOptional, IsString } from "class-validator";
|
import { IsOptional, IsString } from "class-validator";
|
||||||
@@ -14,7 +15,7 @@ import { Roles } from "src/decorators/roles.decorator";
|
|||||||
import { CurrentUser } from "src/decorators/user.decorator";
|
import { CurrentUser } from "src/decorators/user.decorator";
|
||||||
import { RoleEnum } from "src/Types&Enums/role.enum";
|
import { RoleEnum } from "src/Types&Enums/role.enum";
|
||||||
import { ExpertClaimService } from "./expert-claim.service";
|
import { ExpertClaimService } from "./expert-claim.service";
|
||||||
import { SubmitExpertReplyV2Dto } from "./dto/expert-claim-v2.dto";
|
import { ClaimSubmitResendV2Dto, SubmitExpertReplyV2Dto } from "./dto/expert-claim-v2.dto";
|
||||||
import { UpdateClaimDamagedPartsV2Dto } from "./dto/update-claim-damaged-parts-v2.dto";
|
import { UpdateClaimDamagedPartsV2Dto } from "./dto/update-claim-damaged-parts-v2.dto";
|
||||||
|
|
||||||
class InPersonVisitV2Dto {
|
class InPersonVisitV2Dto {
|
||||||
@@ -30,7 +31,7 @@ class InPersonVisitV2Dto {
|
|||||||
@UseGuards(LocalActorAuthGuard, RolesGuard)
|
@UseGuards(LocalActorAuthGuard, RolesGuard)
|
||||||
@Roles(RoleEnum.DAMAGE_EXPERT)
|
@Roles(RoleEnum.DAMAGE_EXPERT)
|
||||||
export class ExpertClaimV2Controller {
|
export class ExpertClaimV2Controller {
|
||||||
constructor(private readonly expertClaimService: ExpertClaimService) {}
|
constructor(private readonly expertClaimService: ExpertClaimService) { }
|
||||||
|
|
||||||
@Get("requests")
|
@Get("requests")
|
||||||
@ApiOperation({
|
@ApiOperation({
|
||||||
@@ -89,6 +90,22 @@ export class ExpertClaimV2Controller {
|
|||||||
return await this.expertClaimService.submitExpertReplyV2(claimRequestId, body, actor);
|
return await this.expertClaimService.submitExpertReplyV2(claimRequestId, body, actor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Put("reply/resend/:claimRequestId")
|
||||||
|
@ApiOperation({
|
||||||
|
summary: "Submit expert damage resend request. ",
|
||||||
|
description:
|
||||||
|
"Claim must be locked by this expert (status EXPERT_REVIEWING). Submitting unlocks the claim. If any part has factorNeeded=true the claim moves to EXPERT_COST_EVALUATION; otherwise moves to INSURER_REVIEW. Total payment cap is 30,000,000.",
|
||||||
|
})
|
||||||
|
@ApiParam({ name: "claimRequestId" })
|
||||||
|
@ApiBody({ type: ClaimSubmitResendV2Dto })
|
||||||
|
async submitExpertResendV2(
|
||||||
|
@Param("claimRequestId") claimRequestId: string,
|
||||||
|
@Body() body: ClaimSubmitResendV2Dto,
|
||||||
|
@CurrentUser() actor,
|
||||||
|
) {
|
||||||
|
return await this.expertClaimService.submitResendDocsV2(claimRequestId, body, actor);
|
||||||
|
}
|
||||||
|
|
||||||
@Patch(":claimRequestId/visit")
|
@Patch(":claimRequestId/visit")
|
||||||
@ApiOperation({
|
@ApiOperation({
|
||||||
summary: "Request in-person visit for claim",
|
summary: "Request in-person visit for claim",
|
||||||
@@ -128,4 +145,21 @@ export class ExpertClaimV2Controller {
|
|||||||
actor,
|
actor,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ApiQuery({
|
||||||
|
name: "query",
|
||||||
|
enum: ["car-capture", "accident"],
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
@Get("stream/:id/video")
|
||||||
|
@Header("Accept-Ranges", "bytes")
|
||||||
|
@Header("Content-Type", "video/mp4")
|
||||||
|
async claimStream(
|
||||||
|
@Headers() headers,
|
||||||
|
@Param("id") id: string,
|
||||||
|
@Query("query") query: "car-capture" | "accident",
|
||||||
|
@Res() res,
|
||||||
|
) {
|
||||||
|
return this.expertClaimService.streamServiceV2(id, query, res, headers);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user