Merge remote-tracking branch 'upstream/main' | Merge upstream into main and reapply local changes

This commit is contained in:
2026-04-18 12:30:32 +03:30
19 changed files with 1317 additions and 1323 deletions

View File

@@ -3938,10 +3938,19 @@ export class RequestManagementService {
async getAllBlameRequestsV2(user: any): Promise<any> {
try {
const userIdFilter =
user?.sub && Types.ObjectId.isValid(user.sub)
? { "parties.person.userId": new Types.ObjectId(user.sub) }
: null;
const phoneFilter = user?.username
? { "parties.person.phoneNumber": user.username }
: null;
const filters = [userIdFilter, phoneFilter].filter(Boolean);
if (filters.length === 0) return [];
const requests = await this.blameRequestDbService.find(
{
"parties.person.userId": new Types.ObjectId(user.sub),
},
filters.length === 1 ? (filters[0] as any) : ({ $or: filters } as any),
{
select: "requestNo type status blameStatus createdAt updatedAt parties",
}
@@ -3949,7 +3958,9 @@ export class RequestManagementService {
const enriched = requests.map((req: any) => {
const party = req.parties.find(
(p: any) => String(p.person.userId) === String(user.sub)
(p: any) =>
(p?.person?.userId && String(p.person.userId) === String(user.sub)) ||
(p?.person?.phoneNumber && p.person.phoneNumber === user?.username),
);
const obj = req.toObject();
@@ -4105,6 +4116,9 @@ export class RequestManagementService {
if (!formData.carBodyForm) {
throw new BadRequestException("carBodyForm is required.");
}
if (!formData?.expertDescription?.desc) {
throw new BadRequestException("expertDescription.desc is required.");
}
const firstPartyUserId = await this.getOrCreateUserByPhoneNumber(
formData.firstPartyPhoneNumber,
@@ -4176,12 +4190,12 @@ export class RequestManagementService {
},
},
statement: {
description: formData.firstPartyDescription?.desc,
accidentDate: formData.firstPartyDescription?.accidentDate,
accidentTime: formData.firstPartyDescription?.accidentTime,
weatherCondition: formData.firstPartyDescription?.weatherCondition,
roadCondition: formData.firstPartyDescription?.roadCondition,
lightCondition: formData.firstPartyDescription?.lightCondition,
description: formData.expertDescription?.desc,
accidentDate: formData.expertDescription?.accidentDate,
accidentTime: formData.expertDescription?.accidentTime,
weatherCondition: formData.expertDescription?.weatherCondition,
roadCondition: formData.expertDescription?.roadCondition,
lightCondition: formData.expertDescription?.lightCondition,
},
location: req.parties?.[0]?.location,
carBodyFirstForm: {
@@ -4250,6 +4264,9 @@ export class RequestManagementService {
if (!formData.secondParty || !formData.guiltyPartyPhoneNumber) {
throw new BadRequestException("secondParty and guiltyPartyPhoneNumber are required.");
}
if (!formData?.expertDescription?.desc) {
throw new BadRequestException("expertDescription.desc is required.");
}
const firstPartyUserId = await this.getOrCreateUserByPhoneNumber(
formData.firstPartyPhoneNumber,
@@ -4320,7 +4337,7 @@ export class RequestManagementService {
firstPartyUserId,
formData.firstPartyInitialForm,
formData.firstPartyPlate,
formData.firstPartyDescription?.desc || "",
formData.expertDescription?.desc || "",
PartyRole.FIRST,
);
const secondParty = await buildPartyFromForm(
@@ -4328,7 +4345,7 @@ export class RequestManagementService {
secondPartyUserId,
formData.secondParty.initialForm,
formData.secondParty.plate,
formData.secondParty.description?.desc || "",
formData.expertDescription?.desc || "",
PartyRole.SECOND,
);
@@ -4386,7 +4403,7 @@ export class RequestManagementService {
async expertAddLocationsForBlameV2(
expert: any,
requestId: string,
dto: { firstPartyLocation: LocationDto; secondPartyLocation?: LocationDto },
dto: { location: LocationDto },
): Promise<any> {
const req = await this.blameRequestDbService.findById(requestId);
if (!req) throw new NotFoundException("Request not found");
@@ -4402,21 +4419,10 @@ export class RequestManagementService {
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;
if (!dto?.location) {
throw new BadRequestException("location is required");
}
req.parties[firstIdx].location = dto.location as any;
const completed = Array.isArray(req.workflow?.completedSteps)
? req.workflow.completedSteps
@@ -4424,12 +4430,6 @@ export class RequestManagementService {
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 || {}),
@@ -4449,8 +4449,7 @@ export class RequestManagementService {
actorType: expert?.role === RoleEnum.REGISTRAR ? "registrar" : "field_expert",
},
metadata: {
hasFirstLocation: true,
hasSecondLocation: req.type === BlameRequestType.THIRD_PARTY,
hasLocation: true,
},
} as any);
@@ -4533,6 +4532,12 @@ export class RequestManagementService {
const firstPartyIndex = this.getPartyIndex(req, PartyRole.FIRST);
if (firstPartyIndex === -1) throw new BadRequestException("First party not found");
const firstParty = req.parties[firstPartyIndex];
if (
Array.isArray(firstParty?.evidence?.voices) &&
firstParty.evidence.voices.length > 0
) {
throw new ConflictException("Voice already uploaded for this file");
}
const voiceDocument = await this.blameVoiceDbService.create({
fileName: voiceFile.filename,