Merge pull request 'Added required documents for blame, added 2 sms' (#37) from s.yahyaee/yara724-api:main into main

Reviewed-on: Yara724/api#37
This commit is contained in:
2026-04-25 15:15:11 +03:30
6 changed files with 102 additions and 5 deletions

View File

@@ -5,7 +5,8 @@ export enum ResendItemType {
CAR_CERTIFICATE = "carCertificate", CAR_CERTIFICATE = "carCertificate",
DRIVING_LICENSE = "drivingLicense", DRIVING_LICENSE = "drivingLicense",
CAR_GREEN_CARD = "carGreenCard", CAR_GREEN_CARD = "carGreenCard",
PLATE = "plate",
CAR_PLATE = "carPlate",
// Media evidence // Media evidence
VOICE = "voice", VOICE = "voice",
VIDEO = "video", VIDEO = "video",

View File

@@ -4345,8 +4345,8 @@ export class ClaimRequestManagementService {
let remaining = 0; let remaining = 0;
if (!isResendUpload) { if (!isResendUpload) {
// Check if all documents are uploaded (7 for CAR_BODY, 13 for THIRD_PARTY) // Check if all documents are uploaded (8 for CAR_BODY, 13 for THIRD_PARTY)
const totalDocsRequired = isCarBodyUpload ? 7 : 13; const totalDocsRequired = isCarBodyUpload ? 8 : 13;
const currentDocs = claimCase.requiredDocuments || new Map(); const currentDocs = claimCase.requiredDocuments || new Map();
const uploadedCount = const uploadedCount =
(currentDocs instanceof Map ? currentDocs.size : Object.keys(currentDocs).length) + 1; (currentDocs instanceof Map ? currentDocs.size : Object.keys(currentDocs).length) + 1;

View File

@@ -6,9 +6,16 @@ import { ExpertBlameController } from "./expert-blame.controller";
import { ExpertBlameV2Controller } from "./expert-blame.v2.controller"; import { ExpertBlameV2Controller } from "./expert-blame.v2.controller";
import { ExpertBlameService } from "./expert-blame.service"; import { ExpertBlameService } from "./expert-blame.service";
import { RequestManagementModule } from "src/request-management/request-management.module"; import { RequestManagementModule } from "src/request-management/request-management.module";
import { SmsOrchestrationModule } from "src/sms-orchestration/sms-orchestration.module";
@Module({ @Module({
imports: [UsersModule, ClientModule, RequestManagementModule, PlatesModule], imports: [
UsersModule,
ClientModule,
RequestManagementModule,
PlatesModule,
SmsOrchestrationModule,
],
controllers: [ExpertBlameController, ExpertBlameV2Controller], controllers: [ExpertBlameController, ExpertBlameV2Controller],
providers: [ExpertBlameService], providers: [ExpertBlameService],
exports: [ExpertBlameService], exports: [ExpertBlameService],

View File

@@ -45,6 +45,7 @@ import { UserSignDbService } from "src/request-management/entities/db-service/si
import { RequestManagementService } from "src/request-management/request-management.service"; import { RequestManagementService } from "src/request-management/request-management.service";
import { snapshotFromFieldExpert } from "src/helpers/expert-profile-snapshot"; import { snapshotFromFieldExpert } from "src/helpers/expert-profile-snapshot";
import { ExpertModel } from "src/users/entities/schema/expert.schema"; import { ExpertModel } from "src/users/entities/schema/expert.schema";
import { SmsOrchestrationService } from "src/sms-orchestration/sms-orchestration.service";
interface CheckedRequestEntry { interface CheckedRequestEntry {
CheckedRequest?: { CheckedRequest?: {
@@ -85,6 +86,7 @@ export class ExpertBlameService {
private readonly blameDocumentDbService: BlameDocumentDbService, private readonly blameDocumentDbService: BlameDocumentDbService,
private readonly userSignDbService: UserSignDbService, private readonly userSignDbService: UserSignDbService,
private readonly requestManagementService: RequestManagementService, private readonly requestManagementService: RequestManagementService,
private readonly smsOrchestrationService: SmsOrchestrationService,
) { } ) { }
/** Load immutable profile fields from `expert` for the acting field expert. */ /** Load immutable profile fields from `expert` for the acting field expert. */
@@ -946,6 +948,23 @@ export class ExpertBlameService {
// Update expert stats (reusing existing helper) // Update expert stats (reusing existing helper)
await this.updateDamageExpertStats(actorDetail.sub, requestId, "checked"); await this.updateDamageExpertStats(actorDetail.sub, requestId, "checked");
if (request.type === BlameRequestType.THIRD_PARTY) {
const phones = (request.parties || [])
.map((p: any) => p?.person?.phoneNumber)
.filter((p: unknown): p is string => typeof p === "string" && p.length > 0);
const expertLastName =
actorDetail?.fullName?.trim()?.split(/\s+/).pop() || "کارشناس";
for (const phone of phones) {
await this.smsOrchestrationService.sendThirdPartyExpertStartedReviewNotice(
{
receptor: phone,
publicId: request.publicId,
expertLastName,
},
);
}
}
return { _id: requestId, lock: true }; return { _id: requestId, lock: true };
} catch (error) { } catch (error) {
if (error instanceof HttpException) throw error; if (error instanceof HttpException) throw error;

View File

@@ -1182,6 +1182,46 @@ export class RequestManagementService {
req.workflow.nextStep = undefined; req.workflow.nextStep = undefined;
req.status = CaseStatus.WAITING_FOR_SIGNATURES; req.status = CaseStatus.WAITING_FOR_SIGNATURES;
closedByMutualAgreement = true; closedByMutualAgreement = true;
if (
isSecondThirdParty &&
closedByMutualAgreement &&
req.status === CaseStatus.WAITING_FOR_SIGNATURES &&
req.blameStatus === BlameStatus.AGREED
) {
const firstIdx = this.getPartyIndex(req, PartyRole.FIRST);
const secondIdx = this.getPartyIndex(req, PartyRole.SECOND);
const firstPhone = (req.parties?.[firstIdx]?.person as any)?.phoneNumber;
const secondPhone = (req.parties?.[secondIdx]?.person as any)?.phoneNumber;
const baseUrl = process.env.URL;
const token = String(req._id);
const targets = [
firstPhone
? {
receptor: firstPhone,
link: `${baseUrl}/user?token=${token}`,
}
: null,
secondPhone
? {
receptor: secondPhone,
link: `${baseUrl}/user2?token=${token}`,
}
: null,
].filter(
(t): t is { receptor: string; link: string } => !!t?.receptor && !!t?.link,
);
for (const target of targets) {
await this.smsOrchestrationService.sendThirdPartyAgreementSignNotice(
{
receptor: target.receptor,
publicId: req.publicId,
link: target.link,
},
);
}
}
} }
} }

View File

@@ -94,6 +94,36 @@ export class SmsOrchestrationService implements OnModuleInit {
} }
} }
async sendThirdPartyAgreementSignNotice(params: {
receptor: string;
publicId: string;
link: string;
}): Promise<boolean> {
return this.sendTemplate({
template: "yara-blame-agreement",
receptor: params.receptor,
token: params.publicId,
token2: params.link,
});
}
async sendThirdPartyExpertStartedReviewNotice(
params: {
receptor: string;
publicId: string;
expertLastName: string;
},
): Promise<boolean> {
return this.sendTemplate({
template:
process.env.SMS_TEMPLATE_THIRD_PARTY_EXPERT_LOCK ||
"yara-blame-expert-lock",
receptor: params.receptor,
token: params.publicId,
token2: params.expertLastName || "کارشناس",
});
}
private async sendTemplate(args: TemplateArgs): Promise<boolean> { private async sendTemplate(args: TemplateArgs): Promise<boolean> {
try { try {
await this.smsGatewayService.verifyLookUp(args); await this.smsGatewayService.verifyLookUp(args);