forked from Yara724/api
YARA-763
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
import { ApiProperty } from "@nestjs/swagger";
|
||||
import { AddPlateDto } from "src/profile/dto/user/AddPlateDto";
|
||||
import { LocationDto } from "./create-request-management.dto";
|
||||
import { DescriptionDto } from "./create-request-management.dto";
|
||||
import { InitialFormDto, CarBodyFormDto } from "./create-request-management.dto";
|
||||
|
||||
@@ -24,9 +23,6 @@ export class ExpertCompleteCarBodyFormDto {
|
||||
@ApiProperty({ type: AddPlateDto })
|
||||
firstPartyPlate: AddPlateDto;
|
||||
|
||||
@ApiProperty({ type: LocationDto })
|
||||
firstPartyLocation: LocationDto;
|
||||
|
||||
@ApiProperty({ type: DescriptionDto })
|
||||
firstPartyDescription: DescriptionDto;
|
||||
}
|
||||
|
||||
11
src/request-management/dto/expert-complete-locations.dto.ts
Normal file
11
src/request-management/dto/expert-complete-locations.dto.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { ApiProperty, ApiPropertyOptional } from "@nestjs/swagger";
|
||||
import { LocationDto } from "./create-request-management.dto";
|
||||
|
||||
export class ExpertCompleteLocationsDto {
|
||||
@ApiProperty({ type: LocationDto })
|
||||
firstPartyLocation: LocationDto;
|
||||
|
||||
@ApiPropertyOptional({ type: LocationDto })
|
||||
secondPartyLocation?: LocationDto;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { ApiProperty } from "@nestjs/swagger";
|
||||
import { AddPlateDto } from "src/profile/dto/user/AddPlateDto";
|
||||
import { LocationDto } from "./create-request-management.dto";
|
||||
import { DescriptionDto } from "./create-request-management.dto";
|
||||
import { InitialFormDto } from "./create-request-management.dto";
|
||||
|
||||
@@ -20,9 +19,6 @@ export class ExpertSecondPartyInfoDto {
|
||||
@ApiProperty({ type: AddPlateDto })
|
||||
plate: AddPlateDto;
|
||||
|
||||
@ApiProperty({ type: LocationDto })
|
||||
location: LocationDto;
|
||||
|
||||
@ApiProperty({ type: DescriptionDto })
|
||||
description: DescriptionDto;
|
||||
}
|
||||
@@ -44,9 +40,6 @@ export class ExpertCompleteThirdPartyFormDto {
|
||||
@ApiProperty({ type: AddPlateDto })
|
||||
firstPartyPlate: AddPlateDto;
|
||||
|
||||
@ApiProperty({ type: LocationDto })
|
||||
firstPartyLocation: LocationDto;
|
||||
|
||||
@ApiProperty({ type: DescriptionDto })
|
||||
firstPartyDescription: DescriptionDto;
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@ import { ExpertCompleteClaimDataDto } from "./dto/expert-complete-claim-data.dto
|
||||
import { ExpertUploadPartySignatureDto } from "./dto/expert-upload-party-signature.dto";
|
||||
import { VerifyPartyOtpsDto } from "./dto/verify-party-otps.dto";
|
||||
import { SendPartyOtpsDto } from "./dto/send-party-otps.dto";
|
||||
import { ExpertCompleteLocationsDto } from "./dto/expert-complete-locations.dto";
|
||||
import { ClaimRequestManagementService } from "src/claim-request-management/claim-request-management.service";
|
||||
import { PartyRole } from "./entities/schema/partyRole.enum";
|
||||
|
||||
@@ -224,7 +225,7 @@ export class ExpertInitiatedV2Controller {
|
||||
@ApiOperation({
|
||||
summary: "[V2] Submit all blame data (IN_PERSON)",
|
||||
description:
|
||||
"For IN_PERSON files only. Send THIRD_PARTY or CAR_BODY form. After this, status becomes WAITING_FOR_SIGNATURES; use upload-party-signature to collect party signatures.",
|
||||
"For IN_PERSON files only. Send THIRD_PARTY or CAR_BODY form EXCEPT locations. After this, call add-locations to submit lat/lon and move workflow to WAITING_FOR_SIGNATURES.",
|
||||
})
|
||||
@ApiParam({ name: "requestId", description: "Blame request ID" })
|
||||
@ApiBody({
|
||||
@@ -252,7 +253,6 @@ export class ExpertInitiatedV2Controller {
|
||||
insurerBirthday: 13770624,
|
||||
driverBirthday: "1370-01-01",
|
||||
},
|
||||
firstPartyLocation: { lat: 35.6892, lon: 51.389 },
|
||||
firstPartyDescription: { desc: "توضیح حادثه طرف اول" },
|
||||
secondParty: {
|
||||
phoneNumber: "09187654321",
|
||||
@@ -273,7 +273,6 @@ export class ExpertInitiatedV2Controller {
|
||||
insurerBirthday: 13700720,
|
||||
driverBirthday: "1370-01-01",
|
||||
},
|
||||
location: { lat: 35.6892, lon: 51.389 },
|
||||
description: { desc: "توضیح حادثه طرف دوم" },
|
||||
},
|
||||
guiltyPartyPhoneNumber: "09123456789",
|
||||
@@ -303,7 +302,6 @@ export class ExpertInitiatedV2Controller {
|
||||
insurerBirthday: 1370,
|
||||
driverBirthday: "1370-01-01",
|
||||
},
|
||||
firstPartyLocation: { lat: 35.6892, lon: 51.389 },
|
||||
firstPartyDescription: {
|
||||
desc: "توضیح حادثه",
|
||||
accidentDate: "2025-01-15",
|
||||
@@ -317,7 +315,7 @@ export class ExpertInitiatedV2Controller {
|
||||
},
|
||||
schema: { type: "object" },
|
||||
})
|
||||
@ApiResponse({ status: 200, description: "Blame form completed; next: upload party signature(s)" })
|
||||
@ApiResponse({ status: 200, description: "Blame form completed; next: add-locations" })
|
||||
async completeBlameDataV2(
|
||||
@CurrentUser() expert: any,
|
||||
@Param("requestId") requestId: string,
|
||||
@@ -330,6 +328,44 @@ export class ExpertInitiatedV2Controller {
|
||||
);
|
||||
}
|
||||
|
||||
@Post("add-locations/:requestId")
|
||||
@ApiOperation({
|
||||
summary: "[V2] Submit location(s) for expert-initiated IN_PERSON blame",
|
||||
description:
|
||||
"Submit first party (and second party for THIRD_PARTY) location after complete-blame-data. This transitions workflow to WAITING_FOR_SIGNATURES.",
|
||||
})
|
||||
@ApiParam({ name: "requestId", description: "Blame request ID" })
|
||||
@ApiBody({
|
||||
type: ExpertCompleteLocationsDto,
|
||||
examples: {
|
||||
THIRD_PARTY: {
|
||||
summary: "THIRD_PARTY locations",
|
||||
value: {
|
||||
firstPartyLocation: { lat: 35.6892, lon: 51.389 },
|
||||
secondPartyLocation: { lat: 35.7001, lon: 51.4102 },
|
||||
},
|
||||
},
|
||||
CAR_BODY: {
|
||||
summary: "CAR_BODY location",
|
||||
value: {
|
||||
firstPartyLocation: { lat: 35.6892, lon: 51.389 },
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
@ApiResponse({ status: 200, description: "Locations saved; next: upload party signature(s)" })
|
||||
async addLocationsV2(
|
||||
@CurrentUser() expert: any,
|
||||
@Param("requestId") requestId: string,
|
||||
@Body() dto: ExpertCompleteLocationsDto,
|
||||
) {
|
||||
return this.requestManagementService.expertAddLocationsForBlameV2(
|
||||
expert,
|
||||
requestId,
|
||||
dto,
|
||||
);
|
||||
}
|
||||
|
||||
@Post("upload-video/:requestId")
|
||||
@ApiOperation({
|
||||
summary: "[V2] Expert uploads video for expert-initiated BlameRequest",
|
||||
|
||||
@@ -4100,7 +4100,7 @@ export class RequestManagementService {
|
||||
roadCondition: formData.firstPartyDescription?.roadCondition,
|
||||
lightCondition: formData.firstPartyDescription?.lightCondition,
|
||||
},
|
||||
location: formData.firstPartyLocation,
|
||||
location: req.parties?.[0]?.location,
|
||||
carBodyFirstForm: {
|
||||
car: !!formData.carBodyForm.car,
|
||||
object: !!formData.carBodyForm.object,
|
||||
@@ -4110,20 +4110,19 @@ export class RequestManagementService {
|
||||
|
||||
req.parties = [firstParty];
|
||||
req.workflow = {
|
||||
currentStep: WorkflowStep.WAITING_FOR_SIGNATURES as any,
|
||||
nextStep: undefined,
|
||||
currentStep: WorkflowStep.FIRST_LOCATION as any,
|
||||
nextStep: WorkflowStep.WAITING_FOR_SIGNATURES as any,
|
||||
completedSteps: [
|
||||
WorkflowStep.CREATED,
|
||||
WorkflowStep.CAR_BODY_ACCIDENT_TYPE,
|
||||
WorkflowStep.FIRST_VIDEO,
|
||||
WorkflowStep.FIRST_INITIAL_FORM,
|
||||
WorkflowStep.FIRST_LOCATION,
|
||||
WorkflowStep.FIRST_VOICE,
|
||||
WorkflowStep.FIRST_DESCRIPTION,
|
||||
].filter((s) => s),
|
||||
locked: false,
|
||||
};
|
||||
req.status = CaseStatus.WAITING_FOR_SIGNATURES;
|
||||
req.status = CaseStatus.OPEN;
|
||||
req.blameStatus = BlameStatus.AGREED;
|
||||
(req as any).filledBy = FilledBy.EXPERT;
|
||||
|
||||
@@ -4181,7 +4180,6 @@ export class RequestManagementService {
|
||||
userId: Types.ObjectId,
|
||||
initialForm: any,
|
||||
plateDto: any,
|
||||
locationDto: any,
|
||||
desc: string,
|
||||
role: PartyRole,
|
||||
) => {
|
||||
@@ -4229,7 +4227,7 @@ export class RequestManagementService {
|
||||
financialCeiling: sandHubReport?.FinancialCvrCptl || sandHubReport?.FinancialCommitment,
|
||||
},
|
||||
statement: { description: desc },
|
||||
location: locationDto,
|
||||
location: undefined,
|
||||
evidence: {},
|
||||
};
|
||||
};
|
||||
@@ -4239,7 +4237,6 @@ export class RequestManagementService {
|
||||
firstPartyUserId,
|
||||
formData.firstPartyInitialForm,
|
||||
formData.firstPartyPlate,
|
||||
formData.firstPartyLocation,
|
||||
formData.firstPartyDescription?.desc || "",
|
||||
PartyRole.FIRST,
|
||||
);
|
||||
@@ -4248,7 +4245,6 @@ export class RequestManagementService {
|
||||
secondPartyUserId,
|
||||
formData.secondParty.initialForm,
|
||||
formData.secondParty.plate,
|
||||
formData.secondParty.location,
|
||||
formData.secondParty.description?.desc || "",
|
||||
PartyRole.SECOND,
|
||||
);
|
||||
@@ -4261,24 +4257,22 @@ export class RequestManagementService {
|
||||
if (!req.expert) req.expert = {} as any;
|
||||
req.expert.decision = { guiltyPartyId: new Types.ObjectId(guiltyPartyId) } as any;
|
||||
req.workflow = {
|
||||
currentStep: WorkflowStep.WAITING_FOR_SIGNATURES as any,
|
||||
nextStep: undefined,
|
||||
currentStep: WorkflowStep.FIRST_LOCATION as any,
|
||||
nextStep: WorkflowStep.SECOND_LOCATION as any,
|
||||
completedSteps: [
|
||||
WorkflowStep.CREATED,
|
||||
WorkflowStep.FIRST_BLAME_CONFESSION,
|
||||
WorkflowStep.FIRST_VIDEO,
|
||||
WorkflowStep.FIRST_INITIAL_FORM,
|
||||
WorkflowStep.FIRST_LOCATION,
|
||||
WorkflowStep.FIRST_VOICE,
|
||||
WorkflowStep.FIRST_DESCRIPTION,
|
||||
WorkflowStep.SECOND_INITIAL_FORM,
|
||||
WorkflowStep.SECOND_LOCATION,
|
||||
WorkflowStep.SECOND_VOICE,
|
||||
WorkflowStep.SECOND_DESCRIPTION,
|
||||
].filter((s) => s),
|
||||
locked: false,
|
||||
};
|
||||
req.status = CaseStatus.WAITING_FOR_SIGNATURES;
|
||||
req.status = CaseStatus.OPEN;
|
||||
req.blameStatus = BlameStatus.AGREED;
|
||||
(req as any).filledBy = FilledBy.EXPERT;
|
||||
|
||||
@@ -4302,6 +4296,90 @@ export class RequestManagementService {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* V2: Expert submits location(s) for expert-initiated IN_PERSON blame.
|
||||
* This is separated from complete-blame-data to support dedicated location UI step.
|
||||
*/
|
||||
async expertAddLocationsForBlameV2(
|
||||
expert: any,
|
||||
requestId: string,
|
||||
dto: { firstPartyLocation: LocationDto; secondPartyLocation?: LocationDto },
|
||||
): Promise<any> {
|
||||
const req = await this.blameRequestDbService.findById(requestId);
|
||||
if (!req) throw new NotFoundException("Request not found");
|
||||
if (
|
||||
(!req.expertInitiated && !req.registrarInitiated) ||
|
||||
req.creationMethod !== CreationMethod.IN_PERSON
|
||||
) {
|
||||
throw new BadRequestException(
|
||||
"This endpoint is only for expert-initiated IN_PERSON blame files.",
|
||||
);
|
||||
}
|
||||
this.verifyExpertAccessForBlameV2(req, expert);
|
||||
|
||||
const firstIdx = this.getPartyIndex(req, PartyRole.FIRST);
|
||||
if (firstIdx === -1) throw new BadRequestException("First party not found");
|
||||
if (!dto?.firstPartyLocation) {
|
||||
throw new BadRequestException("firstPartyLocation is required");
|
||||
}
|
||||
req.parties[firstIdx].location = dto.firstPartyLocation as any;
|
||||
|
||||
if (req.type === BlameRequestType.THIRD_PARTY) {
|
||||
const secondIdx = this.getPartyIndex(req, PartyRole.SECOND);
|
||||
if (secondIdx === -1) throw new BadRequestException("Second party not found");
|
||||
if (!dto?.secondPartyLocation) {
|
||||
throw new BadRequestException(
|
||||
"secondPartyLocation is required for THIRD_PARTY",
|
||||
);
|
||||
}
|
||||
req.parties[secondIdx].location = dto.secondPartyLocation as any;
|
||||
}
|
||||
|
||||
const completed = Array.isArray(req.workflow?.completedSteps)
|
||||
? req.workflow.completedSteps
|
||||
: [];
|
||||
if (!completed.includes(WorkflowStep.FIRST_LOCATION as any)) {
|
||||
completed.push(WorkflowStep.FIRST_LOCATION as any);
|
||||
}
|
||||
if (
|
||||
req.type === BlameRequestType.THIRD_PARTY &&
|
||||
!completed.includes(WorkflowStep.SECOND_LOCATION as any)
|
||||
) {
|
||||
completed.push(WorkflowStep.SECOND_LOCATION as any);
|
||||
}
|
||||
|
||||
req.workflow = {
|
||||
...(req.workflow || {}),
|
||||
currentStep: WorkflowStep.WAITING_FOR_SIGNATURES as any,
|
||||
nextStep: undefined,
|
||||
completedSteps: completed,
|
||||
locked: false,
|
||||
} as any;
|
||||
req.status = CaseStatus.WAITING_FOR_SIGNATURES;
|
||||
|
||||
if (!Array.isArray(req.history)) req.history = [];
|
||||
req.history.push({
|
||||
type: "EXPERT_ADDED_LOCATIONS_V2",
|
||||
actor: {
|
||||
actorId: new Types.ObjectId(expert.sub),
|
||||
actorName: `${expert.firstName || ""} ${expert.lastName || ""}`.trim(),
|
||||
actorType: expert?.role === RoleEnum.REGISTRAR ? "registrar" : "field_expert",
|
||||
},
|
||||
metadata: {
|
||||
hasFirstLocation: true,
|
||||
hasSecondLocation: req.type === BlameRequestType.THIRD_PARTY,
|
||||
},
|
||||
} as any);
|
||||
|
||||
await (req as any).save();
|
||||
return {
|
||||
requestId: req._id,
|
||||
publicId: req.publicId,
|
||||
workflow: req.workflow,
|
||||
status: req.status,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* V2: Expert uploads video for expert-initiated BlameRequest (first party).
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user