diff --git a/.env.example b/.env.example index a31186e..1809dc7 100644 --- a/.env.example +++ b/.env.example @@ -3,6 +3,8 @@ # --------------------------------------------- NODE_ENV = PORT = +CLIENT_ID = +CLIENT_NAME = # --------------------------------------------- # 🌐 Application URLs # --------------------------------------------- diff --git a/src/app.module.ts b/src/app.module.ts index 3ab2b03..1c9c6a7 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -1,7 +1,7 @@ import { join } from "node:path"; import { APP_INTERCEPTOR, APP_PIPE } from "@nestjs/core"; -import { Module, ValidationPipe } from "@nestjs/common"; -import { ConfigModule, ConfigService } from "@nestjs/config"; +import { Module } from "@nestjs/common"; +import { ConfigService } from "@nestjs/config"; import { UnicodeDigitsNormalizeInterceptor } from "./common/interceptors/unicode-digits-normalize.interceptor"; import { MongooseModule } from "@nestjs/mongoose"; import { ServeStaticModule } from "@nestjs/serve-static"; @@ -24,79 +24,18 @@ import { applyIranFaTimestampPlugin } from "./helpers/mongoose-fa-timestamps.plu import { CronModule } from "./utils/cron/cron.module"; import { WorkflowStepManagementModule } from "./workflow-step-management/workflow-step-management.module"; import { ExpertInitiatedModule } from "./expert-initiated/expert-initiated.module"; -import * as Joi from "joi"; +import { DatabaseModule } from "./core/database/database.module"; +import { AppConfigModule } from "./core/config/config.module"; @Module({ imports: [ - ConfigModule.forRoot({ - isGlobal: true, - validationSchema: Joi.object({ - NODE_ENV: Joi.string() - .valid("development", "production") - .default("development"), - PORT: Joi.number().port().default(9001), - URL: Joi.string().uri().required(), - BASE_URL_DEV: Joi.string() - .uri() - .when("NODE_ENV", { - is: Joi.string().valid("development"), - then: Joi.required(), - otherwise: Joi.optional(), - }), - SWAGGER_USER_DEV: Joi.string().when("NODE_ENV", { - is: Joi.string().valid("development"), - then: Joi.required(), - otherwise: Joi.optional(), - }), - SWAGGER_PASSWORD_DEV: Joi.string().when("NODE_ENV", { - is: Joi.string().valid("development"), - then: Joi.required(), - otherwise: Joi.optional(), - }), - MONGO_HOST: Joi.string().required(), - MONGO_PORT: Joi.number().port().required(), - MONGO_USER: Joi.string().required(), - MONGO_PASS: Joi.string().required(), - MONGO_DB_NAME: Joi.string().required(), - JWT_SECRET: Joi.string().required(), - SANHUB_BASE_URL: Joi.string().uri(), - SANHUB_URL_LOGIN: Joi.string().uri(), - SANHUB_USERNAME: Joi.string(), - SANHUB_PASSWORD: Joi.string(), - AI_URL: Joi.string().uri(), - AI_URL_V2: Joi.string().uri(), - AI_USERNAME: Joi.string(), - AI_PASSWORD: Joi.string(), - SMS_PROVIDER: Joi.string() - .valid("kavenegar", "parsian") - .default("kavenegar"), - SMS_API_KEY: Joi.string(), - AUTH_SMS_TEMPLATE: Joi.string(), - EXP_OTP_TIME: Joi.number(), - }), - }), + AppConfigModule, + DatabaseModule, CronModule, ServeStaticModule.forRoot({ rootPath: join(__dirname, "..", "files"), serveRoot: "/files", }), - MongooseModule.forRootAsync({ - inject: [ConfigService], - useFactory: (configService: ConfigService) => { - return { - uri: `mongodb://${configService.get("MONGO_USER")}:${configService.get("MONGO_PASS")}@${configService.get("MONGO_HOST")}:${configService.get("MONGO_PORT")}/${configService.get("MONGO_DB_NAME")}?authSource=admin&${configService.get("MONGO_OPTIONS")}`, - tls: configService.get("MONGO_TLS") === "true", - tlsAllowInvalidCertificates: - configService.get("MONGO_TLS_ALLOW_INVALID_CERTS") === - "true", - autoIndex: configService.get("NODE_ENV") !== "production", - connectionFactory: (connection) => { - applyIranFaTimestampPlugin(connection); - return connection; - }, - }; - }, - }), UsersModule, AuthModule, ClientModule, diff --git a/src/client/client.controller.ts b/src/client/client.controller.ts index 7f0b443..13ff777 100644 --- a/src/client/client.controller.ts +++ b/src/client/client.controller.ts @@ -1,17 +1,24 @@ -import { Body, Controller, Get, Post, UseGuards } from "@nestjs/common"; -import { ApiBearerAuth, ApiTags } from "@nestjs/swagger"; -import { GlobalGuard } from "src/auth/guards/global.guard"; -import { RolesGuard } from "src/auth/guards/role.guard"; -import { Roles } from "src/decorators/roles.decorator"; +import { Body, Controller, Get, Patch, Post } from "@nestjs/common"; +import { + ApiBody, + ApiOperation, + ApiResponse, + ApiTags, +} from "@nestjs/swagger"; import { CurrentUser } from "src/decorators/user.decorator"; -import { RoleEnum } from "src/Types&Enums/role.enum"; +import { SystemSettingsResponseDto } from "src/system-settings/dto/system-settings.dto"; +import { SystemSettingsService } from "src/system-settings/system-settings.service"; import { ClientService } from "./client.service"; import { ClientDto } from "./dto/create-client.dto"; +import { SetExternalInquiriesLiveDto } from "./dto/external-inquiries-live.dto"; @Controller("client") @ApiTags("client-management") export class ClientController { - constructor(private readonly clientService: ClientService) {} + constructor( + private readonly clientService: ClientService, + private readonly systemSettingsService: SystemSettingsService, + ) {} @Post() async addClient(@Body() client: ClientDto) { @@ -27,4 +34,33 @@ export class ClientController { async getClientList(@CurrentUser() user) { return await this.clientService.getClientList(); } + + /** Toggle SandHub/Tejarat live HTTP vs mock inquiries (`system_settings.externalApis.sandHubUseLiveApi`). */ + @Patch("external-inquiries-live") + @ApiOperation({ + summary: "Enable or disable live external inquiries", + description: + "Updates `system_settings.externalApis.sandHubUseLiveApi`. No auth required. Use the request examples below to switch between live Tejarat/SandHub HTTP and offline mock mode.", + }) + @ApiBody({ + type: SetExternalInquiriesLiveDto, + examples: { + enableLive: { + summary: "Enable live inquiries", + description: "Call real SandHub/Tejarat HTTP APIs.", + value: { enabled: true }, + }, + disableLive: { + summary: "Disable live inquiries (mock mode)", + description: "Use mocked inquiry responses; flows continue without external connectivity.", + value: { enabled: false }, + }, + }, + }) + @ApiResponse({ status: 200, type: SystemSettingsResponseDto }) + async setExternalInquiriesLive(@Body() body?: SetExternalInquiriesLiveDto) { + return this.systemSettingsService.updateSettings({ + externalApis: { sandHubUseLiveApi: body?.enabled === true }, + }); + } } diff --git a/src/client/client.module.ts b/src/client/client.module.ts index 7f7b863..02a62f0 100644 --- a/src/client/client.module.ts +++ b/src/client/client.module.ts @@ -1,5 +1,6 @@ import { Module } from "@nestjs/common"; import { MongooseModule } from "@nestjs/mongoose"; +import { SystemSettingsModule } from "src/system-settings/system-settings.module"; import { ClientController } from "./client.controller"; import { ClientPanelController } from "./client-panel.controller"; import { ClientService } from "./client.service"; @@ -10,6 +11,7 @@ import { ClientDbSchema, ClientModel } from "./entities/schema/client.schema"; @Module({ imports: [ + SystemSettingsModule, MongooseModule.forFeature([ { name: ClientModel.name, schema: ClientDbSchema }, { diff --git a/src/client/client.service.ts b/src/client/client.service.ts index edccfa8..5faaaeb 100644 --- a/src/client/client.service.ts +++ b/src/client/client.service.ts @@ -142,6 +142,38 @@ export class ClientService { return await this.clientDbService.find({ clientCode: companyCode }); } + /** + * Resolve a client by insurer company code from an external inquiry. + * Creates the client when missing so inquiry flows don't fail on unknown codes. + */ + async findOrCreateClientByCompanyCode( + companyCode: number | string | null | undefined, + companyName: string | null | undefined, + ) { + const name = typeof companyName === "string" ? companyName.trim() : ""; + const code = Number(companyCode); + if (!name || !Number.isFinite(code)) { + return null; + } + + let client = await this.clientDbService.find({ clientCode: code }); + if (client) return client; + + try { + await this.addClient({ + clientName: { persian: name, english: null }, + clientCode: code, + useExpertMode: "legal", + }); + } catch (err) { + client = await this.clientDbService.find({ clientCode: code }); + if (client) return client; + throw err; + } + + return this.clientDbService.find({ clientCode: code }); + } + async getClients(): Promise { const clients = await this.clientDbService.findAll(); const show = clients.map((c) => new ClientDtoRs(c)); diff --git a/src/client/dto/external-inquiries-live.dto.ts b/src/client/dto/external-inquiries-live.dto.ts new file mode 100644 index 0000000..9f4199b --- /dev/null +++ b/src/client/dto/external-inquiries-live.dto.ts @@ -0,0 +1,10 @@ +import { ApiProperty } from "@nestjs/swagger"; + +export class SetExternalInquiriesLiveDto { + @ApiProperty({ + description: + "When true, SandHub/Tejarat live HTTP inquiries run. When false, mocked inquiry data is used.", + example: true, + }) + enabled: boolean; +} diff --git a/src/core/config/config.module.ts b/src/core/config/config.module.ts new file mode 100644 index 0000000..82e65bf --- /dev/null +++ b/src/core/config/config.module.ts @@ -0,0 +1,14 @@ +import { Module } from "@nestjs/common"; +import { ConfigModule } from "@nestjs/config"; +import { validate } from "./config.validation"; + +@Module({ + imports: [ + ConfigModule.forRoot({ + isGlobal: true, + expandVariables: true, + validate, + }), + ], +}) +export class AppConfigModule {} diff --git a/src/core/config/config.schema.ts b/src/core/config/config.schema.ts new file mode 100644 index 0000000..60caa61 --- /dev/null +++ b/src/core/config/config.schema.ts @@ -0,0 +1,75 @@ +import { + IsBooleanString, + IsEnum, + IsNumber, + IsPositive, + IsString, + IsUrl, + Matches, + Max, + Min, + MinLength, +} from "class-validator"; +import { StringValue } from "ms"; + +export enum Environment { + Development = "development", + Production = "production", +} + +export class EnvironmentVariables { + @IsEnum(Environment, { + message: "NODE_ENV should be development or production", + }) + NODE_ENV: Environment; + // --------------------------------------------------------- // + @IsNumber( + { + allowNaN: false, + allowInfinity: false, + }, + { + message: "PORT must be a valid number", + }, + ) + @IsPositive({ message: "PORT must be positive" }) + @Min(0, { message: "PORT must be between 0 and 65535" }) + @Max(65535, { message: "PORT must be between 0 and 65535" }) + PORT: number; + // --------------------------------------------------------- // + @IsString({ message: "MONGO_URI must be string" }) + @IsUrl( + { + require_tld: false, + protocols: ["mongodb", "mongodb+srv"], + }, + { + message: "MONGO_URI must be in the correct format (mongodb://...)", + }, + ) + MONGO_URI: string; + // --------------------------------------------------------- // + @IsBooleanString({ message: "MONGO_TLS must be boolean" }) + MONGO_TLS: string; + // --------------------------------------------------------- // + @IsBooleanString({ message: "MONGO_TLS_ALLOW_INVALID_CERTS must be boolean" }) + MONGO_TLS_ALLOW_INVALID_CERTS: string; + // --------------------------------------------------------- // + @IsString({ message: "JWT_SECRET must be string" }) + @MinLength(32, { + message: "JWT_SECRET must be at least 32 characters", + }) + JWT_SECRET: string; + // --------------------------------------------------------- // + @Matches(/^\d+(ms|s|m|h|d|w|y)$/, { + message: "JWT_EXPIRY must be in the correct format", + }) + JWT_EXPIRY: StringValue; + // --------------------------------------------------------- // + // @IsString({ message: "HASH_PEPPER must be string" }) + // @MinLength(32, { + // message: "HASH_PEPPER must be at least 32 characters", + // }) + // HASH_PEPPER: string; + // --------------------------------------------------------- // +} diff --git a/src/core/config/config.validation.ts b/src/core/config/config.validation.ts new file mode 100644 index 0000000..a24de6c --- /dev/null +++ b/src/core/config/config.validation.ts @@ -0,0 +1,23 @@ +import { plainToInstance } from "class-transformer"; +import { validateSync } from "class-validator"; +import { EnvironmentVariables } from "./config.schema"; + +export function validate(config: Record) { + const validatedConfig = plainToInstance(EnvironmentVariables, config, { + enableImplicitConversion: true, + }); + + const errors = validateSync(validatedConfig, { + skipMissingProperties: false, + }); + + if (errors.length > 0) { + const messages = errors + .flatMap((error) => Object.values(error.constraints ?? {})) + .join("\n"); + + throw new Error(`Environment validation failed:\n${messages}`); + } + + return validatedConfig; +} diff --git a/src/core/database/database.module.ts b/src/core/database/database.module.ts new file mode 100644 index 0000000..095600c --- /dev/null +++ b/src/core/database/database.module.ts @@ -0,0 +1,19 @@ +import { Module } from "@nestjs/common"; +import { ConfigService } from "@nestjs/config"; +import { MongooseModule } from "@nestjs/mongoose"; + +@Module({ + imports: [ + MongooseModule.forRootAsync({ + inject: [ConfigService], + useFactory: (configService: ConfigService) => ({ + uri: configService.get("MONGO_URI"), + tls: configService.get("MONGO_TLS") === "true", + tlsAllowInvalidCertificates: + configService.get("MONGO_TLS_ALLOW_INVALID_CERTS") === "true", + autoIndex: configService.get("NODE_ENV") !== "production", + }), + }), + ], +}) +export class DatabaseModule {} diff --git a/src/core/database/plugins/iran-timestamp.plugin.ts b/src/core/database/plugins/iran-timestamp.plugin.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/request-management/request-management.service.ts b/src/request-management/request-management.service.ts index 5fa1be0..09b4fb1 100644 --- a/src/request-management/request-management.service.ts +++ b/src/request-management/request-management.service.ts @@ -1160,24 +1160,16 @@ export class RequestManagementService { ); } const companyCode = inquiryMapped?.CompanyCode; - let client = - await this.clientService.findClientWithCompanyCode(+companyCode); - + const client = await this.clientService.findOrCreateClientByCompanyCode( + companyCode, + clientName, + ); if (!client) { - await this.clientService.addClient({ - clientName: { - persian: clientName, - english: null, - }, - clientCode: Number(companyCode), - useExpertMode: "legal", - }); + throw new BadRequestException( + `CompanyCode missing or invalid in inquiry response`, + ); } - // if (!client) { - // throw new HttpException("Client not found", HttpStatus.CONFLICT); - // } - // Persist inquiry/body data into new model if (!party.person) party.person = {} as any; const resolvedClientId = @@ -1286,27 +1278,13 @@ export class RequestManagementService { const carBodyCompanyCode = m.companyId ?? m.CompanyCode; const carBodyCompanyName = m.CompanyName ?? m.companyPersianName; - if (carBodyCompanyCode) { - let carBodyClient: any = - await this.clientService.findClientWithCompanyCode( - Number(carBodyCompanyCode), + if (carBodyCompanyCode && carBodyCompanyName) { + const carBodyClient = + await this.clientService.findOrCreateClientByCompanyCode( + carBodyCompanyCode, + carBodyCompanyName, ); - if (!carBodyClient && carBodyCompanyName) { - await this.clientService.addClient({ - clientName: { - persian: carBodyCompanyName, - english: null, - }, - clientCode: Number(carBodyCompanyCode), - useExpertMode: "legal", - }); - // Re-fetch after creation so we get the actual document with _id - carBodyClient = await this.clientService.findClientWithCompanyCode( - Number(carBodyCompanyCode), - ); - } - const carBodyClientId = (carBodyClient as any)?._id ?? (carBodyClient as any)?._doc?._id; @@ -2075,8 +2053,10 @@ export class RequestManagementService { const clientName = sandHubReport?.CompanyName; const companyCode = sandHubReport?.CompanyCode; - const client = - await this.clientService.findClientWithCompanyCode(+companyCode); + const client = await this.clientService.findOrCreateClientByCompanyCode( + companyCode, + clientName, + ); if (!client) { throw new HttpException("Client not found", HttpStatus.CONFLICT); @@ -5021,7 +5001,10 @@ export class RequestManagementService { sandHubReport?.CompanyName || sandHubReport?.LastCompanyName; const companyCode = sandHubReport?.CompanyCode; const client = companyCode - ? await this.clientService.findClientWithCompanyCode(+companyCode) + ? await this.clientService.findOrCreateClientByCompanyCode( + companyCode, + clientName, + ) : await this.clientService.findOne({ clientName }); if (!client) { throw new NotFoundException( @@ -5228,7 +5211,10 @@ export class RequestManagementService { sandHubReport?.CompanyName || sandHubReport?.LastCompanyName; const companyCode = sandHubReport?.CompanyCode; const client = companyCode - ? await this.clientService.findClientWithCompanyCode(+companyCode) + ? await this.clientService.findOrCreateClientByCompanyCode( + companyCode, + clientName, + ) : await this.clientService.findOne({ clientName }); if (!client) { throw new NotFoundException( @@ -5834,7 +5820,10 @@ export class RequestManagementService { // Try to find client by company code first (more reliable) const client = companyCode - ? await this.clientService.findClientWithCompanyCode(+companyCode) + ? await this.clientService.findOrCreateClientByCompanyCode( + companyCode, + clientName, + ) : await this.clientService.findOne({ clientName: clientName }); if (!client) { @@ -5898,7 +5887,10 @@ export class RequestManagementService { // Try to find client by company code first (more reliable) const client = companyCode - ? await this.clientService.findClientWithCompanyCode(+companyCode) + ? await this.clientService.findOrCreateClientByCompanyCode( + companyCode, + clientName, + ) : await this.clientService.findOne({ clientName: clientName }); if (!client) { @@ -6168,7 +6160,10 @@ export class RequestManagementService { // Try to find client by company code first (more reliable) const client = companyCode - ? await this.clientService.findClientWithCompanyCode(+companyCode) + ? await this.clientService.findOrCreateClientByCompanyCode( + companyCode, + clientName, + ) : await this.clientService.findOne({ clientName: clientName }); if (!client) { diff --git a/src/sand-hub/sand-hub.service.ts b/src/sand-hub/sand-hub.service.ts index a8122b6..1e72169 100644 --- a/src/sand-hub/sand-hub.service.ts +++ b/src/sand-hub/sand-hub.service.ts @@ -40,40 +40,49 @@ export class SandHubService { return this.systemSettingsService.isSandHubLiveEnabled(); } + /** Tenant-specific company fields for mocked external inquiries (MOCK_INQUIRY_COMPANY_*). */ + private getMockInquiryCompanyId(): string { + return process.env.CLIENT_ID ?? "15"; + } + + private getMockInquiryCompanyName(): string { + return process.env.CLIENT_NAME ?? "بیمه سامان"; + } + /** Fixed plate/insurance inquiry payload used everywhere we mock block-inquiry style APIs. */ private getDefaultMockPlateInquiryRaw(): Record { return { - PrntPlcyCmpDocNo: "1403/1143-70591/200/35", - MapTypNam: "پرايد هاچ بک -111", - MtrNum: "5215907", - ShsNum: "NAS431100E5798656", - DisFnYrNum: "0", - DisLfYrNum: "0", - DisPrsnYrNum: "0", - DisPrsnYrPrcnt: "0", - DisFnYrPrcnt: "0", - DisLfYrPrcnt: "0", - vin: "IRPC941V2BD798656", + PrntPlcyCmpDocNo: "1404/1143-70591/200/123", + MapTypNam: "فائو ( FAW )", + MtrNum: "TZ196XYAP223A210074", + ShsNum: "LFP8C7PC3R1K12157", + DisFnYrNum: null, + DisLfYrNum: null, + DisPrsnYrNum: null, + DisPrsnYrPrcnt: null, + DisFnYrPrcnt: "5", + DisLfYrPrcnt: "5", + vin: "LFP8C7PC3R1K12157", MapVehicleSystemName: "ثبت نشده", LfCvrCptl: 0, FnCvrCptl: 0, PrsnCvrCptl: 0, VehicleSystemCode: 1, - EdrsJson: '[{"id":1,"Dsc":" الحاقيه توضيحات ندارد"}]', + EdrsJson: "", PersonCvrCptl: 12000000000, LifeCvrCptl: 16000000000, FinancialCvrCptl: 4000000000, CarGroupCode: 3, CylCnt: 4, - LastCompanyDocumentNumber: "03/1031/2835/1001/662", + LastCompanyDocumentNumber: "31/3100/03/18350", UsageCode: "8", MapUsageCode: 1, MapUsageName: "شخصي", - Plk1: 59, - Plk2: 16, - Plk3: 419, - PlkSrl: 78, - PrintEndorsCompanyDocumentNumber: "بيمه نامه الحاقيه ندارد.", + Plk1: 16, + Plk2: 12, + Plk3: 498, + PlkSrl: 60, + PrintEndorsCompanyDocumentNumber: "", EndorseDate: null, InsuranceFullName: null, SystemField: "سايپا", @@ -81,12 +90,12 @@ export class SandHubService { UsageField: "سواري", MainColorField: "سفيد", SecondColorField: "سفيد شيري", - ModelField: "1394", + ModelField: "2024", CapacityField: "جمعا 4 نفر", CylinderNumberField: "4", EngineNumberField: "5215907", - ChassisNumberField: "NAS431100E5798656", - VinNumberField: "IRPC941V2BD798656", + ChassisNumberField: "LFP8C7PC3R1K12157", + VinNumberField: "LFP8C7PC3R1K12157", InstallDateField: "1403/03/01", AxelNumberField: "2", WheelNumberField: "4", @@ -107,7 +116,7 @@ export class SandHubService { SystemCodeCii: 0, SystemNameCii: "ثبت نشده", TypeCodeCii: 12189, - TypeNameCii: "پرايد هاچ بک -111", + TypeNameCii: "فائو ( FAW )", UsageNameCii: "سواري", UsageCodeCii: 1, ModelCii: 1394, @@ -116,6 +125,47 @@ export class SandHubService { }; } + private getDefaultMockCarBodyInquiryRaw( + userDetail: SandHubDetailDto, + ): Record { + const companyId = Number(this.getMockInquiryCompanyId()); + + return { + data: { + id: 70016075946, + printNumber: "1405/1143-70591/220/1/0", + companyId: Number.isNaN(companyId) ? 15 : companyId, + companyName: this.getMockInquiryCompanyName(), + beginDate: "1405/01/17", + endDate: "1406/01/17", + issueDate: "1405/01/16", + hasEndorsement: null, + motorNumber: "TZ196XYAP223A210074", + chassisNumber: "LFP8C7PC3R1K12157", + vin: "LFP8C7PC3R1K12157", + plateTypeId: 9, + plateTypeTitle: "پلاک قدیمی", + platePartOne: 16, + plateSerialNumber: 60, + plateLetterid: 12, + plateLetterTitle: "م ", + vehicleSystemTitle: "فائو ( FAW )", + vehicleGroupId: 2, + vehicleGroupTitle: "سواری چهار سیلندر", + insurerNationalCode: userDetail.nationalCodeOfInsurer, + insurerName: "هانيه کارخانهء", + ownerNationalCode: userDetail.nationalCodeOfInsurer, + previousId: 70006331822, + noLossYearsCount: 4, + platePartThree: 498, + lossDocuments: [], + }, + isSuccess: true, + statusCode: 200, + message: "عملیات با موفقیت انجام شد", + }; + } + /** * Bodies returned from `makeSandHubRequest` in mock mode (same shape callers expect from real API). */ @@ -401,30 +451,7 @@ export class SandHubService { this.logger.debug( `[MOCK] getTejaratCarBodyInquiry plate=${JSON.stringify(requestPayload)}`, ); - raw = { - data: { - printNumber: "MOCK-BADANE-001", - companyId: 34, - companyName: "بیمه تجارت نو", - beginDate: "1404/06/15", - endDate: "1405/06/15", - issueDate: "1404/06/13", - hasEndorsement: null, - motorNumber: "MOCK-ENGINE", - chassisNumber: "MOCK-CHASSIS", - vin: "MOCK-VIN", - vehicleSystemTitle: "سایپا", - vehicleGroupTitle: "سواری چهار سیلندر", - insurerNationalCode: userDetail.nationalCodeOfInsurer, - insurerName: "نام آزمایشی", - ownerNationalCode: userDetail.nationalCodeOfInsurer, - noLossYearsCount: 0, - lossDocuments: [], - }, - isSuccess: true, - statusCode: 200, - message: "mock-ok", - }; + raw = this.getDefaultMockCarBodyInquiryRaw(userDetail); } const mapped = this.mapCarBodyInquiryResponse(raw);