1
0
forked from Yara724/api

Merge pull request 'update the blame service' (#9) from s.hajizadeh/yara724api:main into main

Reviewed-on: Yara724/api#9
This commit is contained in:
2026-03-18 15:53:40 +03:30
2 changed files with 67 additions and 42 deletions

View File

@@ -269,8 +269,7 @@ export class RequestManagementService {
const step = stepByNumber ?? stepByKey;
if (!step) {
throw new InternalServerErrorException(
`Workflow step not found (${stepNumber ? `stepNumber=${stepNumber}` : ""}${
stepNumber && stepKey ? ", " : ""
`Workflow step not found (${stepNumber ? `stepNumber=${stepNumber}` : ""}${stepNumber && stepKey ? ", " : ""
}${stepKey ? `stepKey=${stepKey}` : ""})`,
);
}
@@ -304,7 +303,7 @@ export class RequestManagementService {
private readonly workflowStepDbService: WorkflowStepDbService,
private readonly hashService: HashService,
private readonly userAuthService: UserAuthService,
) {}
) { }
async createRequestV2(user: any, type: BlameRequestType) {
const firstStep = await this.getWorkflowStep({ stepNumber: 1 });
@@ -768,8 +767,7 @@ export class RequestManagementService {
);
if (err?.response) {
this.logger.error(
`[TEJARAT] block inquiry response for request=${req._id}: status=${
err.response.status
`[TEJARAT] block inquiry response for request=${req._id}: status=${err.response.status
}, data=${JSON.stringify(err.response.data)}`,
);
}
@@ -1310,10 +1308,10 @@ export class RequestManagementService {
if (foundRequest.expertInitiated && foundRequest.creationMethod === CreationMethod.LINK) {
// User should already be set in firstPartyDetails or secondPartyDetails
const isFirstParty = foundRequest.firstPartyDetails?.firstPartyId?.toString() === user.sub ||
foundRequest.firstPartyDetails?.firstPartyPhoneNumber === user.username;
foundRequest.firstPartyDetails?.firstPartyPhoneNumber === user.username;
const isSecondParty = foundRequest.secondPartyDetails?.secondPartyId?.toString() === user.sub ||
foundRequest.secondPartyDetails?.secondPartyPhoneNumber === user.username;
foundRequest.secondPartyDetails?.secondPartyPhoneNumber === user.username;
if (!isFirstParty && !isSecondParty) {
throw new ForbiddenException(
"You are not authorized to complete this file. This file was created by an expert for specific parties.",
@@ -1357,9 +1355,9 @@ export class RequestManagementService {
);
} else if (
foundRequest?.firstPartyDetails?.firstPartyPhoneNumber == user.username ||
(foundRequest.expertInitiated &&
foundRequest.creationMethod === CreationMethod.LINK &&
foundRequest.firstPartyDetails?.firstPartyId?.toString() === user.sub)
(foundRequest.expertInitiated &&
foundRequest.creationMethod === CreationMethod.LINK &&
foundRequest.firstPartyDetails?.firstPartyId?.toString() === user.sub)
) {
// Normal flow or link-based - set full firstPartyDetails
const updatePayload: any = {
@@ -1373,7 +1371,7 @@ export class RequestManagementService {
nextStep: StepsEnum.F_videoUpload,
$push: { steps: StepsEnum.F_InitialForm },
};
// For link-based expert-initiated files, ensure filledBy is set
if (foundRequest.expertInitiated && foundRequest.creationMethod === CreationMethod.LINK) {
updatePayload.$set = { filledBy: FilledBy.CUSTOMER };
@@ -1492,7 +1490,7 @@ export class RequestManagementService {
partyType === "firstParty" ? StepsEnum.F_addPlate : StepsEnum.S_addPlate;
const currentStep =
partyType === "firstParty" ? StepsEnum.F_addPlate : StepsEnum.S_addPlate;
// Determine next step based on request type
let nextStep: StepsEnum;
if (request.type === "CAR_BODY") {
@@ -1635,8 +1633,8 @@ export class RequestManagementService {
// Determine if the current user is the first party
// Check if nextStep is firstParty-addPlate OR if user is the first party phone number
const isFirstParty =
(request.nextStep === StepsEnum.F_addPlate ||
request.currentStep === StepsEnum.F_addPlate) &&
(request.nextStep === StepsEnum.F_addPlate ||
request.currentStep === StepsEnum.F_addPlate) &&
request.firstPartyDetails.firstPartyPhoneNumber === user.username;
if (!isFirstParty) {
@@ -1787,7 +1785,7 @@ export class RequestManagementService {
const findRequest =
await this.requestManagementDbService.findOne(requestId);
if (!findRequest) throw new NotFoundException("requestId not found");
// Allow first party only
if (findRequest.firstPartyDetails.firstPartyId == new Types.ObjectId(userId)) {
await this.requestManagementDbService.findAndUpdate(
@@ -1799,7 +1797,7 @@ export class RequestManagementService {
$push: { steps: StepsEnum.F_addLocation }, // Ensure step is saved
},
);
return new RequestManagementDtoRs(
findRequest.firstPartyDetails.firstPartyId,
findRequest?.secondPartyDetails?.secondPartyId || null,
@@ -1840,7 +1838,7 @@ export class RequestManagementService {
if (!request) {
throw new NotFoundException("request is not found");
}
const voiceDoc = await this.blameVoiceDbService.create({
fileName: voice.filename,
path: voice.path,
@@ -1990,7 +1988,7 @@ export class RequestManagementService {
);
}
const nextStepMessage = request.type === "CAR_BODY"
const nextStepMessage = request.type === "CAR_BODY"
? "Please sign the document to complete your request"
: "add secondParty to request";
@@ -2798,7 +2796,7 @@ export class RequestManagementService {
const replyField = isObjection
? "expertSubmitReplyFinal"
: "expertSubmitReply";
// Handle cases where firstPartyId might be undefined (e.g., IN_PERSON expert-filled files)
const firstPartyId = request.firstPartyDetails?.firstPartyId;
if (!firstPartyId) {
@@ -2806,7 +2804,7 @@ export class RequestManagementService {
"First party ID is missing. Please ensure the file has been properly initialized.",
);
}
const isFirstParty = userId === firstPartyId.toString();
const currentPartyKey = isFirstParty
@@ -2859,13 +2857,13 @@ export class RequestManagementService {
// (CAR_BODY requests might not have actorLocked set)
if (request.actorLocked?.actorId) {
// Convert ObjectIds to strings safely
const actorIdStr = request.actorLocked.actorId.toString ?
request.actorLocked.actorId.toString() :
const actorIdStr = request.actorLocked.actorId.toString ?
request.actorLocked.actorId.toString() :
String(request.actorLocked.actorId);
const requestIdStr = request._id.toString ?
request._id.toString() :
const requestIdStr = request._id.toString ?
request._id.toString() :
String(request._id);
await this.updateDamageExpertStats(
actorIdStr,
requestIdStr,
@@ -3777,6 +3775,25 @@ export class RequestManagementService {
}));
}
async getAllBlameRequestsV2(user: any): Promise<any> {
console.log(user)
try {
const requests = await this.blameRequestDbService.find({
parties: {
$elemMatch: {
'person.userId': new Types.ObjectId(user.sub)
}
}
}, { select: "requestNo type status blameStatus createdAt updatedAt" });
return requests;
} catch (err) {
this.logger.error("Error: ", err);
throw new InternalServerErrorException(
"Something Went Wrong",
);
}
}
/**
* V2: Get one blame request by id. Access allowed if current user is a party (by userId or phone)
* or the initiating field expert. For expert-initiated LINK, party access by phone is sufficient.
@@ -4562,7 +4579,7 @@ export class RequestManagementService {
const clientName = sandHubReport?.CompanyName || sandHubReport?.LastCompanyName;
const companyCode = sandHubReport?.CompanyCode;
// Try to find client by company code first (more reliable)
const client = companyCode
? await this.clientService.findClientWithCompanyCode(+companyCode)
@@ -4619,7 +4636,7 @@ export class RequestManagementService {
const clientName = sandHubReport?.CompanyName || sandHubReport?.LastCompanyName;
const companyCode = sandHubReport?.CompanyCode;
// Try to find client by company code first (more reliable)
const client = companyCode
? await this.clientService.findClientWithCompanyCode(+companyCode)
@@ -4877,7 +4894,7 @@ export class RequestManagementService {
const clientName = sandHubReport?.CompanyName || sandHubReport?.LastCompanyName;
const companyCode = sandHubReport?.CompanyCode;
// Try to find client by company code first (more reliable)
const client = companyCode
? await this.clientService.findClientWithCompanyCode(+companyCode)
@@ -4941,7 +4958,7 @@ export class RequestManagementService {
// For CAR_BODY: Create expertSubmitReply
// First party is guilty by default if accident was with another car
const guiltyUserId = firstPartyUserId;
// Accident fields can be added separately via add-accident-fields endpoint
updatePayload.$set.expertSubmitReply = {
description: "Expert completed all information on-site. Awaiting signature.",
@@ -5170,11 +5187,11 @@ export class RequestManagementService {
// If description is already added, next step is different
const hasDescription = request.steps?.includes(StepsEnum.F_addDescription) ||
request.steps?.includes(StepsEnum.S_addDescription);
const currentStep = request.type === "THIRD_PARTY"
? StepsEnum.F_addVoice
const currentStep = request.type === "THIRD_PARTY"
? StepsEnum.F_addVoice
: StepsEnum.F_addVoice;
const nextStep = hasDescription
? (request.type === "THIRD_PARTY" ? StepsEnum.AddSignatures : StepsEnum.AddSignatures)
: (request.type === "THIRD_PARTY" ? StepsEnum.F_addDescription : StepsEnum.F_addDescription);
@@ -5277,25 +5294,25 @@ export class RequestManagementService {
} else {
newReplyObject.description = "Expert on-site assessment";
}
if ('guiltyUserId' in existingReply) {
newReplyObject.guiltyUserId = existingReply.guiltyUserId;
} else {
newReplyObject.guiltyUserId = request.firstPartyDetails?.firstPartyId;
}
if ('submitTime' in existingReply) {
newReplyObject.submitTime = existingReply.submitTime;
} else {
newReplyObject.submitTime = new Date();
}
if ('firstPartyComment' in existingReply) {
newReplyObject.firstPartyComment = existingReply.firstPartyComment;
} else {
newReplyObject.firstPartyComment = null;
}
if ('secondPartyComment' in existingReply) {
newReplyObject.secondPartyComment = existingReply.secondPartyComment;
} else {

View File

@@ -51,7 +51,7 @@ import { RequestManagementService } from "./request-management.service";
export class RequestManagementV2Controller {
constructor(
private readonly requestManagementService: RequestManagementService,
) {}
) { }
@Post()
@UseGuards(GlobalGuard)
@@ -65,6 +65,14 @@ export class RequestManagementV2Controller {
);
}
@Get()
@Roles(RoleEnum.USER, RoleEnum.FIELD_EXPERT)
async getAllBlameRequestsV2(
@CurrentUser() user: any,
) {
return this.requestManagementService.getAllBlameRequestsV2(user);
}
/**
* Get one blame request by id. Allowed for the request owner (party) or the initiating field expert.
*/
@@ -324,10 +332,10 @@ export class RequestManagementV2Controller {
@UploadedFile() sign: Express.Multer.File,
) {
// Convert string "true"/"false" to boolean
const acceptDecision = typeof isAccept === "string"
? isAccept === "true"
const acceptDecision = typeof isAccept === "string"
? isAccept === "true"
: Boolean(isAccept);
return this.requestManagementService.userSignDecisionV2(
requestId,
user.sub,