1
0
forked from Yara724/api

Initial commit after migration to gitea

This commit is contained in:
2026-01-18 11:27:43 +03:30
parent a21039410c
commit ea4b8eb543
196 changed files with 45567 additions and 9 deletions

View File

@@ -0,0 +1,483 @@
import { readFile } from "node:fs/promises";
import { extname, parse } from "node:path";
import {
BadRequestException,
Body,
Controller,
Get,
Param,
Patch,
Post,
Put,
Query,
UploadedFile,
UseGuards,
UseInterceptors,
} from "@nestjs/common";
import { FileInterceptor } from "@nestjs/platform-express";
import {
ApiBearerAuth,
ApiBody,
ApiConsumes,
ApiParam,
ApiQuery,
ApiTags,
} from "@nestjs/swagger";
import { diskStorage } from "multer";
import { GlobalGuard } from "src/auth/guards/global.guard";
import { ClaimAccessGuard } from "src/auth/guards/claim-access.guard";
import { RolesGuard } from "src/auth/guards/role.guard";
import { Roles } from "src/decorators/roles.decorator";
import { CurrentUser } from "src/decorators/user.decorator";
import { RoleEnum } from "src/Types&Enums/role.enum";
import { ClaimRequestManagementService } from "./claim-request-management.service";
import { CarDamagePartDto, OtherCarDamagePartDto } from "./dto/car-part.dto";
import { UserCommentDto } from "./dto/user-comment.dto";
import { UserObjectionDto } from "./dto/user-objection.dto";
import { InPersonVisitDto } from "./dto/in-person-visit.dto";
@Controller("claim-request-management")
@ApiTags("claim-request-management")
@Roles(RoleEnum.USER, RoleEnum.EXPERT, RoleEnum.DAMAGE_EXPERT)
@UseGuards(ClaimAccessGuard, RolesGuard)
@ApiBearerAuth()
export class ClaimRequestManagementController {
constructor(
private readonly claimRequestManagementService: ClaimRequestManagementService,
) {}
@ApiParam({ name: "blameId" })
@Post("/:blameId")
async createClaimRequest(
@Param("blameId") requestId: string,
@CurrentUser() user,
) {
return await this.claimRequestManagementService.createClaimRequest(
requestId,
user.role === RoleEnum.USER ? user.sub : undefined,
user,
);
}
@ApiBody({ type: CarDamagePartDto })
@Patch("/car-part-damage/:claimRequestID")
@ApiParam({ name: "claimRequestID" })
async carPartDamage(
@Param("claimRequestID") requestId: string,
@Body() body: CarDamagePartDto,
@CurrentUser() user,
) {
return await this.claimRequestManagementService.selectCarPartDamage(
requestId,
body,
user,
);
}
@Get("/car-other-part")
async getCarOtherParts() {
const carOtherPart = await readFile(
`${process.cwd()}/src/static/car-part.json`,
"utf-8",
);
return carOtherPart;
}
@ApiBody({ type: OtherCarDamagePartDto })
@ApiParam({ name: "claimRequestID" })
@UseInterceptors(
FileInterceptor("file", {
limits: {
fileSize: 10 * 1024 * 1024,
},
storage: diskStorage({
destination: "./files/car-green-cards",
filename: (req, file, callback) => {
const unique = Date.now();
const ex = extname(file.originalname);
const filename = `${file.originalname.split(" ")[0]}-${unique}${ex}`;
callback(null, filename);
},
}),
}),
)
@ApiConsumes("multipart/form-data")
@Patch("/car-other-part-damage/:claimRequestID")
async carOtherPartDamage(
@Param("claimRequestID") requestId: string,
@UploadedFile() file,
@Body() body: OtherCarDamagePartDto,
@CurrentUser() user,
) {
return await this.claimRequestManagementService.selectCarOtherPartDamage(
requestId,
body,
file,
user,
);
}
@Get("required-documents-status/:claimRequestID")
@ApiParam({ name: "claimRequestID" })
async getRequiredDocumentsStatus(
@Param("claimRequestID") requestId: string,
) {
return await this.claimRequestManagementService.getRequiredDocumentsStatus(
requestId,
);
}
@Get("car-part-image-required/:claimRequestID")
@ApiParam({ name: "claimRequestID" })
async getImageRequired(@Param("claimRequestID") requestId) {
return await this.claimRequestManagementService.getImageRequiredList(
requestId,
);
}
@ApiBody({
schema: {
type: "object",
properties: {
file: { type: "string", format: "binary" },
},
},
})
@UseInterceptors(
FileInterceptor("file", {
limits: { fileSize: 10 * 1024 * 1024 },
storage: diskStorage({
destination: "./files/claim-required-documents/",
filename: (req, file, callback) => {
const extension = extname(file.originalname);
const basename = parse(file.originalname).name;
const unique = Date.now();
const sanitizedBasename = basename
.replace(/\s/g, "_")
.replace(/[^\w\-_]/g, "")
.substring(0, 50);
const filename = `${sanitizedBasename}-${unique}${extension}`;
callback(null, filename);
},
}),
}),
)
@ApiConsumes("multipart/form-data")
@ApiParam({ name: "claimRequestID" })
@ApiQuery({
name: "documentType",
enum: [
"damaged_driving_license_back",
"damaged_driving_license_front",
"damaged_chassis_number",
"damaged_engine_photo",
"damaged_car_card_front",
"damaged_car_card_back",
"damaged_metal_plate",
"guilty_driving_license_front",
"guilty_driving_license_back",
"guilty_car_card_front",
"guilty_car_card_back",
"guilty_metal_plate",
],
description: "Type of required document to upload",
})
@Patch("upload-required-document/:claimRequestID")
async uploadRequiredDocument(
@Param("claimRequestID") requestId: string,
@Query("documentType") documentType: string,
@UploadedFile("file") file: Express.Multer.File,
@CurrentUser() user,
) {
if (!file) {
throw new BadRequestException("File is required");
}
return await this.claimRequestManagementService.uploadRequiredDocument(
requestId,
documentType as any,
file,
user,
);
}
@ApiBody({
schema: {
type: "object",
properties: {
file: { type: "string", format: "binary" },
},
},
})
@UseInterceptors(
FileInterceptor("file", {
limits: { fileSize: 10 * 1024 * 1024 },
storage: diskStorage({
destination: "./files/car-parts/",
filename: (req, file, callback) => {
const extension = extname(file.originalname);
const basename = parse(file.originalname).name;
const unique = Date.now();
// Sanitize filename: remove non-ASCII characters and special chars to avoid encoding issues
const sanitizedBasename = basename
.replace(/\s/g, "_")
.replace(/[^\w\-_]/g, "") // Remove all non-word characters except hyphens and underscores
.substring(0, 50); // Limit length
const filename = `${sanitizedBasename}-${unique}${extension}`;
callback(null, filename);
},
}),
}),
)
@ApiConsumes("multipart/form-data")
@ApiParam({ name: "claimRequestID" })
@ApiParam({
name: "partId",
description: "The ID of the specific car part being photographed.",
})
@Patch("capture-car-part-damage/:claimRequestID/:partId")
async captureCarPartDamage(
@Param("partId") partId: string,
@Param("claimRequestID") requestId: string,
@UploadedFile("file") file: Express.Multer.File,
) {
if (!file) {
throw new BadRequestException("Image file is required.");
}
return await this.claimRequestManagementService.setDamageImage(
requestId,
partId,
file,
);
}
@ApiBody({
schema: {
type: "object",
properties: {
file: { type: "string", format: "binary" },
},
},
})
@UseInterceptors(
FileInterceptor("file", {
limits: { fileSize: 50 * 1024 * 1024 },
storage: diskStorage({
destination: "./files/car-capture-videos/",
filename: (req, file, callback) => {
const unique = Date.now();
const ex = extname(file.originalname);
const filename = `claim-video-${unique}${ex}`;
callback(null, filename);
},
}),
}),
)
@ApiConsumes("multipart/form-data")
@ApiParam({ name: "claimRequestID" })
@Patch("car-capture/:claimRequestID")
async captureVideoCapture(
@Param("claimRequestID") requestId: string,
@UploadedFile("file") file: Express.Multer.File,
) {
return await this.claimRequestManagementService.setVideoCapture(
requestId,
file,
);
}
@Get("requests/")
async getRequest(@CurrentUser() currentUser) {
return await this.claimRequestManagementService.myRequests(currentUser);
}
@Get("request/:claimRequestId")
@ApiParam({ name: "claimRequestId" })
myRequests(
@Param("claimRequestId") requestId: string,
@CurrentUser() user,
) {
return this.claimRequestManagementService.requestDetails(requestId, user);
}
@Put("request/reply/:claimRequestId")
@ApiParam({ name: "claimRequestId" })
@UseInterceptors(
FileInterceptor("file", {
limits: {
fileSize: 10 * 1024 * 1024,
},
storage: diskStorage({
destination: "./files/claim-sign",
filename: (req, file, callback) => {
const unique = Date.now();
const ex = extname(file.originalname);
const filename = `${file.originalname.split(" ")[0]}-${unique}${ex}`;
callback(null, filename);
},
}),
}),
)
@ApiBody({
type: UserCommentDto,
description: "if partId null , you can upload video capture",
})
@ApiConsumes("multipart/form-data")
@ApiParam({ name: "claimRequestId" })
async submitReply(
@Param("claimRequestId") requestId,
@Body() body,
@UploadedFile() file: Express.Multer.File,
@CurrentUser() user,
) {
return await this.claimRequestManagementService.submitUserReply(
requestId,
body,
file,
user,
);
}
@Put("request/resend/:claimRequestId/objection")
@ApiParam({ name: "claimRequestId" })
@ApiConsumes("application/json")
@ApiBody({
type: UserObjectionDto,
description: "Objection details with optional new parts",
})
async handleUserObjection(
@Param("claimRequestId") claimRequestId: string,
@Body() userObjectionDto: UserObjectionDto,
) {
return await this.claimRequestManagementService.handleUserObjectionAndParts(
claimRequestId,
userObjectionDto,
);
}
@Patch("request/resend/:claimRequestId")
@ApiConsumes("multipart/form-data")
@ApiParam({ name: "claimRequestId" })
@ApiQuery({ name: "fields", enum: ["resendDocuments", "resendCarParts"] })
@ApiQuery({ name: "partId", required: false })
@ApiQuery({ name: "documentName", required: false })
@ApiQuery({ name: "side", required: false })
@ApiBody({
schema: {
type: "object",
properties: {
file: {
type: "string",
format: "binary",
},
},
},
})
@UseInterceptors(
FileInterceptor("file", {
storage: diskStorage({
destination: "./files/claim-resend-documents",
filename: (req, file, callback) => {
const unique = Date.now();
const ext = extname(file.originalname);
const filename = `${file.originalname.split(" ")[0]}-${unique}${ext}`;
callback(null, filename);
},
}),
limits: { fileSize: 10 * 1024 * 1024 },
}),
)
async uploadDocuments(
@Param("claimRequestId") claimId: string,
@Query() query: string,
@UploadedFile() file: Express.Multer.File,
@CurrentUser() user,
) {
return await this.claimRequestManagementService.resendFiles(
claimId,
file,
query,
user,
);
}
@Patch("request/reply/:claimRequestId/:partId/upload-factor")
@ApiConsumes("multipart/form-data")
@ApiParam({ name: "claimRequestId" })
@ApiParam({ name: "partId" })
@ApiBody({
schema: {
type: "object",
properties: {
file: {
type: "string",
format: "binary",
},
},
},
})
@UseInterceptors(
FileInterceptor("file", {
storage: diskStorage({
destination: "./files/claim-factors",
filename: (req, file, callback) => {
const unique = Date.now();
const filename = `-${unique}-${file.originalname}`;
callback(null, filename);
},
}),
limits: { fileSize: 10 * 1024 * 1024 },
}),
)
async uploadFactorForPart(
@Param("claimRequestId") claimId: string,
@Param("partId") partId: string,
@UploadedFile() file: Express.Multer.File,
@CurrentUser() user,
) {
return await this.claimRequestManagementService.uploadClaimFactor(
claimId,
partId,
file,
user,
);
}
@ApiBody({ type: InPersonVisitDto })
@ApiParam({ name: "id" })
@Patch(":id/visit")
async inPersonVisit(
@Param("id") requestId: string,
@Body() body: InPersonVisitDto,
@CurrentUser() actor,
) {
// Pass the branchId from the body to the service
return await this.claimRequestManagementService.inPersonVisit(
requestId,
body.branchId,
actor,
);
}
@Get("branches/:insuranceId")
async insuranceBranches(@Param("insuranceId") insuranceId: string) {
return await this.claimRequestManagementService.retrieveInsuranceBranches(
insuranceId,
);
}
@Get("fanavaran-submit/:claimRequestId")
@ApiParam({ name: "claimRequestId" })
async fanavaranSubmit(@Param("claimRequestId") claimRequestId: string) {
return await this.claimRequestManagementService.fanavaranSubmit(
claimRequestId,
);
}
@Post("fanavaran-submit/:claimRequestId")
@ApiParam({ name: "claimRequestId" })
async submitToFanavaran(@Param("claimRequestId") claimRequestId: string) {
return await this.claimRequestManagementService.submitToFanavaran(
claimRequestId,
);
}
}

View File

@@ -0,0 +1,88 @@
import { Module } from "@nestjs/common";
import { MongooseModule } from "@nestjs/mongoose";
import { AiModule } from "src/ai/ai.module";
import { SandHubModule } from "src/sand-hub/sand-hub.module";
import { RequestManagementModule } from "src/request-management/request-management.module";
import { UsersModule } from "src/users/users.module";
import { ClaimRequestManagementController } from "./claim-request-management.controller";
import { ClaimRequestManagementService } from "./claim-request-management.service";
import { CarGreenCardDbService } from "./entites/db-service/car-green-card.db.service";
import { ClaimRequestManagementDbService } from "./entites/db-service/claim-request-management.db.service";
import { ClaimSignDbService } from "./entites/db-service/claim-sign.db.service";
import { DamageImageDbService } from "./entites/db-service/damage-image.db.service";
import { ClaimFactorsImageDbService } from "./entites/db-service/factor-image.db.service";
import { VideoCaptureDbService } from "./entites/db-service/video-capture.db.service";
import { ClaimRequiredDocumentDbService } from "./entites/db-service/claim-required-document.db.service";
import {
CarGreenCardModel,
CarGreenCardSchema,
} from "./entites/schema/car-green-card.schema";
import {
ClaimRequiredDocument,
ClaimRequiredDocumentSchema,
} from "./entites/schema/claim-required-document.schema";
import {
ClaimRequestManagementModel,
ClaimRequestManagementSchema,
} from "./entites/schema/claim-request-management.schema";
import { ClaimSignModel, ClaimSignSchema } from "./entites/schema/claim-sign";
import {
DamageImageModelSchema,
DamagePartImageModel,
} from "./entites/schema/damage-image-part.schema";
import {
ClaimFactorsImage,
ClaimFactorsImageSchema,
} from "./entites/schema/factor-image.schema";
import {
VideoCaptureModel,
VideoCaptureSchema,
} from "./entites/schema/video-capture.schema";
import { ClientModule } from "src/client/client.module";
import { ClaimAccessGuard } from "src/auth/guards/claim-access.guard";
import { JwtModule } from "@nestjs/jwt";
@Module({
imports: [
UsersModule,
RequestManagementModule,
AiModule,
SandHubModule,
ClientModule,
JwtModule.register({}),
MongooseModule.forFeature([
{
name: ClaimRequestManagementModel.name,
schema: ClaimRequestManagementSchema,
},
{ name: CarGreenCardModel.name, schema: CarGreenCardSchema },
{ name: DamagePartImageModel.name, schema: DamageImageModelSchema },
{ name: ClaimSignModel.name, schema: ClaimSignSchema },
{ name: ClaimFactorsImage.name, schema: ClaimFactorsImageSchema },
{ name: VideoCaptureModel.name, schema: VideoCaptureSchema },
{
name: ClaimRequiredDocument.name,
schema: ClaimRequiredDocumentSchema,
},
]),
],
providers: [
ClaimRequestManagementService,
ClaimRequestManagementDbService,
CarGreenCardDbService,
DamageImageDbService,
ClaimSignDbService,
ClaimFactorsImageDbService,
VideoCaptureDbService,
ClaimRequiredDocumentDbService,
ClaimAccessGuard,
],
controllers: [ClaimRequestManagementController],
exports: [
ClaimRequestManagementDbService,
DamageImageDbService,
VideoCaptureDbService,
ClaimRequiredDocumentDbService,
],
})
export class ClaimRequestManagementModule {}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,108 @@
import { ApiProperty } from "@nestjs/swagger";
export class MainParts {
@ApiProperty({ default: false })
backFender: boolean;
@ApiProperty({ default: false })
backWheel: boolean;
@ApiProperty({ default: false })
backDoor: boolean;
@ApiProperty({ default: false })
frontDoor: boolean;
@ApiProperty({ default: false })
mirror: boolean;
@ApiProperty({ default: false })
frontWheel: boolean;
@ApiProperty({ default: false })
frontFender: boolean;
@ApiProperty({ default: false })
backWindow: boolean;
@ApiProperty({ default: false })
frontWindow: boolean;
}
export class FrontParts {
@ApiProperty({ default: false })
frontBumper: boolean;
@ApiProperty({ default: false })
frontCarWindshield: boolean;
@ApiProperty({ default: false })
carHood: boolean;
@ApiProperty({ default: false })
leftLight: boolean;
@ApiProperty({ default: false })
rightLight: boolean;
@ApiProperty({ default: false, description: "جلو پنجره " })
frontGrille: boolean;
}
export class BackParts {
@ApiProperty({ default: false })
backBumper: boolean;
@ApiProperty({ default: false })
carTrunk: boolean;
@ApiProperty({ default: false })
backCarWindshield: boolean;
@ApiProperty({ default: false })
leftLight: boolean;
@ApiProperty({ default: false })
rightLight: boolean;
}
export class TopParts {
@ApiProperty({ default: false })
roof: boolean;
}
export class CarDamagePartDto {
@ApiProperty({ type: MainParts })
left: MainParts[];
@ApiProperty({ type: MainParts })
right: MainParts[];
@ApiProperty({ type: FrontParts })
front: FrontParts[];
@ApiProperty({ type: BackParts })
back: BackParts[];
@ApiProperty({ type: TopParts })
top: TopParts[];
}
export class OtherCarDamagePartDto {
@ApiProperty({
format: "array",
description: "please add items of json into array",
example: [{ "حسگر درها": true }],
})
otherParts: [];
@ApiProperty({ format: "string" })
sheba: string;
@ApiProperty({ format: "string" })
nationalCodeOfInsurer: string;
@ApiProperty({ type: "string", format: "binary", required: true })
file: Express.Multer.File;
}
export class CaptureCarPartDto {
@ApiProperty({ type: "string", format: "binary", required: true })
file: Express.Multer.File;
}

View File

@@ -0,0 +1,16 @@
import { ClaimRequestManagementModel } from "src/claim-request-management/entites/schema/claim-request-management.schema";
export class ClaimPartUploadDetail {
list: any;
constructor(claimFile: ClaimRequestManagementModel[]) {
this.list = claimFile
.map((c) => {
return {
carPartDamage: c.carPartDamage,
carOtherPartDamage: c.otherParts,
greenCardUpload: !!c.carGreenCard.path,
};
})
.flat(2);
}
}

View File

@@ -0,0 +1,17 @@
import { ClaimRequestManagementModel } from "src/claim-request-management/entites/schema/claim-request-management.schema";
import { ReqClaimStatus } from "src/Types&Enums/claim-request-management/status.enum";
export class ClaimRequestDtoRs {
requestDetail: any;
messsage: string;
status: ReqClaimStatus;
constructor(
req: ClaimRequestManagementModel,
message: string,
status: ReqClaimStatus,
) {
this.requestDetail = req;
this.messsage = message;
this.status = status;
}
}

View File

@@ -0,0 +1,8 @@
export class CreateClaimRequestDtoRs {
message: string;
requestId: string;
constructor(requestId: string, message: string) {
this.requestId = requestId;
this.message = message;
}
}

View File

@@ -0,0 +1,8 @@
import { ClaimRequestManagementModel } from "src/claim-request-management/entites/schema/claim-request-management.schema";
export class ImageRequiredDto {
public list: {} = {};
constructor(imageModel: ClaimRequestManagementModel) {
this.list = imageModel.imageRequired;
}
}

View File

@@ -0,0 +1,12 @@
import { ApiProperty } from "@nestjs/swagger";
import { IsMongoId, IsNotEmpty } from "class-validator";
export class InPersonVisitDto {
@ApiProperty({
example: "60d5ec49e7b2f8001c8e4d2a",
description: "The unique ID of the branch the user is being sent to.",
})
@IsNotEmpty()
@IsMongoId()
branchId: string;
}

View File

@@ -0,0 +1,23 @@
import { Types } from "mongoose";
import { ClaimRequestManagementModel } from "src/claim-request-management/entites/schema/claim-request-management.schema";
import { ReqClaimStatus } from "src/Types&Enums/claim-request-management/status.enum";
export class MyRequestsDtoList {
status: ReqClaimStatus;
submitDate: string;
numberOfRequest: number;
_id: Types.ObjectId;
constructor(request: ClaimRequestManagementModel) {
this._id = request["_id"];
this.status = request.claimStatus;
this.submitDate = new Date(request.createdAt).toLocaleString("fa-IR");
this.numberOfRequest = request.requestNumber;
}
}
export class MyRequestsDto {
public list = [];
constructor(requests: ClaimRequestManagementModel[]) {
this.list = requests.map((r) => new MyRequestsDtoList(r));
}
}

View File

@@ -0,0 +1,19 @@
import { ClaimRequestManagementModel } from "src/claim-request-management/entites/schema/claim-request-management.schema";
import { UserCommentDto } from "src/claim-request-management/dto/user-comment.dto";
export class SubmitUserReplyDtoRs {
requestId: string;
partsNeedFactorDetail: object;
partsNeedFactor: boolean;
userComment: UserCommentDto;
constructor(
claim: ClaimRequestManagementModel,
partsFactorDetail?,
partsNeedFactor?,
) {
this.requestId = claim["_id"];
this.partsNeedFactorDetail = partsFactorDetail;
this.partsNeedFactor = partsNeedFactor;
this.userComment = claim.damageExpertReply.userComment;
}
}

View File

@@ -0,0 +1,12 @@
import { ApiProperty } from "@nestjs/swagger";
export class UserCommentDto {
@ApiProperty({ type: Boolean })
isAccept: boolean;
@ApiProperty({ type: "string", format: "binary", required: false })
file?: Express.Multer.File;
@ApiProperty({ type: String })
branch?: string;
}

View File

@@ -0,0 +1,47 @@
import { ApiProperty } from "@nestjs/swagger";
import { Type } from "class-transformer";
import { TypeOfDamage } from "src/Types&Enums/claim-request-management/type-of-damage.enum";
export class UserObjectionPartDto {
@ApiProperty()
partId: string;
@ApiProperty({ required: false })
reason?: string;
@ApiProperty({ required: false })
partPrice?: string;
@ApiProperty({ required: false })
partSalary?: string;
@ApiProperty({ required: false })
typeOfDamage?: TypeOfDamage;
@ApiProperty({ required: false })
carPartDamage?: string;
@ApiProperty({ required: false })
side?: string;
}
export class NewPartDto {
@ApiProperty({ required: false, nullable: true })
partId: string | null;
@ApiProperty()
partName: string;
@ApiProperty({ required: false })
side?: string;
}
export class UserObjectionDto {
@ApiProperty({ type: [UserObjectionPartDto], required: false })
@Type(() => UserObjectionPartDto)
objectionParts?: UserObjectionPartDto[];
@ApiProperty({ type: [NewPartDto], required: false })
@Type(() => NewPartDto)
newParts?: NewPartDto[];
}

View File

@@ -0,0 +1,4 @@
export class UserReplyDtoRs {
requestId: string;
isAccept: string;
}

View File

@@ -0,0 +1,19 @@
import { InjectModel } from "@nestjs/mongoose";
import { FilterQuery, Model } from "mongoose";
import { CarGreenCardModel } from "src/claim-request-management/entites/schema/car-green-card.schema";
export class CarGreenCardDbService {
constructor(
@InjectModel(CarGreenCardModel.name)
private readonly model: Model<CarGreenCardModel>,
) {}
async create(greenCard): Promise<CarGreenCardModel> {
return await this.model.create(greenCard);
}
async findOne(
filter: FilterQuery<CarGreenCardModel>,
): Promise<CarGreenCardModel> {
return await this.model.findOne({ filter });
}
}

View File

@@ -0,0 +1,121 @@
import { Injectable } from "@nestjs/common";
import { InjectModel } from "@nestjs/mongoose";
import { FilterQuery, Model, Types, UpdateQuery } from "mongoose";
import { ClaimRequestManagementModel } from "src/claim-request-management/entites/schema/claim-request-management.schema";
const crypto = require("node:crypto");
@Injectable()
export class ClaimRequestManagementDbService {
constructor(
@InjectModel(ClaimRequestManagementModel.name)
private readonly model: Model<ClaimRequestManagementModel>,
) {}
async create(
claimRequest: ClaimRequestManagementModel,
): Promise<ClaimRequestManagementModel> {
const uniqueRequestNumber = await this.generateUniqueNumbers();
return this.model.create({
...claimRequest,
requestNumber: uniqueRequestNumber,
});
}
async findOne(
id?: string,
filter?: FilterQuery<ClaimRequestManagementModel>,
) {
if (filter) return await this.model.findOne(filter);
return await this.model.findOne({ _id: new Types.ObjectId(id) });
}
async findOneDocument(
id: string,
filter?: FilterQuery<ClaimRequestManagementModel>,
) {
if (filter) return await this.model.findOne(filter);
return await this.model.findOne({ _id: new Types.ObjectId(id) }).lean();
}
async findOneAndUpdate(
filter: FilterQuery<ClaimRequestManagementModel>,
update: UpdateQuery<ClaimRequestManagementModel>,
option?,
) {
return await this.model.findOneAndUpdate(filter, update, option);
}
async findAllByStatus(filter: FilterQuery<ClaimRequestManagementModel>) {
return await this.model.find(filter);
}
async findAndDelete(
filter: FilterQuery<ClaimRequestManagementModel>,
option,
) {
return await this.model.deleteMany(filter, option);
}
async findAllAndPagination(
filter: FilterQuery<ClaimRequestManagementModel>,
currentPage: number,
countPerPage: number,
) {
const responsePerPage = countPerPage | 1;
const skipPge = responsePerPage * (Number(currentPage) - 1);
return await this.model.find(filter).limit(responsePerPage).skip(skipPge);
}
async aggregate(filter?) {
return await this.model.aggregate(filter);
}
async findAndUpdate(
id: string,
update: UpdateQuery<ClaimRequestManagementModel>,
option?: FilterQuery<ClaimRequestManagementModel>,
) {
return await this.model.findByIdAndUpdate(
{ _id: new Types.ObjectId(id) },
update,
option,
);
}
async findAllByAnyFilter(
filter: FilterQuery<ClaimRequestManagementModel>,
): Promise<ClaimRequestManagementModel[]> {
return await this.model.find(filter);
}
async countByFilter(
filter: FilterQuery<ClaimRequestManagementModel>,
): Promise<number> {
return await this.model.countDocuments(filter);
}
async findAll(): Promise<ClaimRequestManagementModel[]> {
return await this.model.find();
}
async generateUniqueNumbers(digits = 5) {
try {
const max = Math.pow(10, digits);
const randomBytes = crypto.randomBytes(Math.ceil(digits / 2));
const randomNumber = parseInt(randomBytes.toString("hex"), 16) % max;
return randomNumber.toString().padStart(digits, "0");
} catch (error) {
console.error("Error generating unique numbers:", error);
throw error;
}
}
async findAllWithFilter(filter?: FilterQuery<ClaimRequestManagementModel>) {
return await this.model.find(filter);
}
async findByIdAndUpdate(
id: string,
updateDto: UpdateQuery<ClaimRequestManagementModel>,
): Promise<ClaimRequestManagementModel | null> {
return this.model.findByIdAndUpdate(id, updateDto, { new: true }).lean();
}
}

View File

@@ -0,0 +1,41 @@
import { Injectable } from "@nestjs/common";
import { InjectModel } from "@nestjs/mongoose";
import { FilterQuery, Model, Types } from "mongoose";
import { ClaimRequiredDocument } from "src/claim-request-management/entites/schema/claim-required-document.schema";
@Injectable()
export class ClaimRequiredDocumentDbService {
constructor(
@InjectModel(ClaimRequiredDocument.name)
private readonly model: Model<ClaimRequiredDocument>,
) {}
async create(document: Partial<ClaimRequiredDocument>): Promise<ClaimRequiredDocument> {
return await this.model.create(document);
}
async findOne(
filter: FilterQuery<ClaimRequiredDocument>,
): Promise<ClaimRequiredDocument | null> {
return await this.model.findOne(filter);
}
async findAll(
filter: FilterQuery<ClaimRequiredDocument>,
): Promise<ClaimRequiredDocument[]> {
return await this.model.find(filter);
}
async findById(id: string): Promise<ClaimRequiredDocument | null> {
return this.model.findById(id).lean();
}
async findByClaimId(claimId: string): Promise<ClaimRequiredDocument[]> {
return this.model.find({ claimId: new Types.ObjectId(claimId) });
}
async delete(id: string): Promise<void> {
await this.model.findByIdAndDelete(id);
}
}

View File

@@ -0,0 +1,20 @@
import { Injectable } from "@nestjs/common";
import { InjectModel } from "@nestjs/mongoose";
import { FilterQuery, Model } from "mongoose";
import { ClaimSignModel } from "src/claim-request-management/entites/schema/claim-sign";
@Injectable()
export class ClaimSignDbService {
constructor(
@InjectModel(ClaimSignModel.name)
private readonly claimSignService: Model<ClaimSignModel>,
) {}
async create(claimSign: ClaimSignModel): Promise<ClaimSignModel> {
return await this.claimSignService.create(claimSign);
}
async findOne(filter: FilterQuery<ClaimSignModel>): Promise<ClaimSignModel> {
return await this.claimSignService.findOne(filter);
}
}

View File

@@ -0,0 +1,18 @@
import { InjectModel } from "@nestjs/mongoose";
import { Model, Types } from "mongoose";
import { DamagePartImageModel } from "src/claim-request-management/entites/schema/damage-image-part.schema";
export class DamageImageDbService {
constructor(
@InjectModel(DamagePartImageModel.name)
private readonly model: Model<DamagePartImageModel>,
) {}
async create(image): Promise<DamagePartImageModel> {
return await this.model.create(image);
}
async findOne(id: string): Promise<DamagePartImageModel> {
return await this.model.findById(new Types.ObjectId(id));
}
}

View File

@@ -0,0 +1,25 @@
import { Injectable } from "@nestjs/common";
import { InjectModel } from "@nestjs/mongoose";
import { FilterQuery, Model } from "mongoose";
import { ClaimFactorsImage } from "src/claim-request-management/entites/schema/factor-image.schema";
@Injectable()
export class ClaimFactorsImageDbService {
constructor(
@InjectModel(ClaimFactorsImage.name)
private readonly model: Model<ClaimFactorsImage>,
) {}
async create(image): Promise<ClaimFactorsImage> {
return await this.model.create(image);
}
async findOne(
filter: FilterQuery<ClaimFactorsImage>,
): Promise<ClaimFactorsImage> {
return await this.model.findOne({ filter });
}
async findById(id: string): Promise<ClaimFactorsImage | null> {
return this.model.findById(id).lean();
}
}

View File

@@ -0,0 +1,25 @@
import { Injectable } from "@nestjs/common";
import { InjectModel } from "@nestjs/mongoose";
import { FilterQuery, Model } from "mongoose";
import { VideoCaptureModel } from "src/claim-request-management/entites/schema/video-capture.schema";
@Injectable()
export class VideoCaptureDbService {
constructor(
@InjectModel(VideoCaptureModel.name)
private readonly videoCapture: Model<VideoCaptureModel>,
) {}
async create(video): Promise<VideoCaptureModel> {
return await this.videoCapture.create(video);
}
async findOne(
filter: FilterQuery<VideoCaptureModel>,
): Promise<VideoCaptureModel> {
return await this.videoCapture.findOne(filter);
}
async findById(id: string): Promise<VideoCaptureModel | null> {
return this.videoCapture.findById(id).lean();
}
}

View File

@@ -0,0 +1,13 @@
import { Prop, Schema, SchemaFactory } from "@nestjs/mongoose";
import mongoose, { Types } from "mongoose";
@Schema({ versionKey: false })
export class ActionUserModel extends mongoose.Document {
@Prop({ required: true, type: Types.ObjectId })
userId: Types.ObjectId;
@Prop({ required: true, type: Date })
date: Date;
}
export const ActionActorSchema = SchemaFactory.createForClass(ActionUserModel);

View File

@@ -0,0 +1,7 @@
import { Prop, Schema } from "@nestjs/mongoose";
@Schema({ versionKey: false, _id: true })
export class AiImagesModel {
@Prop({ type: "array" })
imagesAddress: string[];
}

View File

@@ -0,0 +1,17 @@
import { Prop, Schema, SchemaFactory } from "@nestjs/mongoose";
import mongoose, { Types } from "mongoose";
@Schema({ versionKey: false, collection: "car-green-cards" })
export class CarGreenCardModel extends mongoose.Document {
@Prop({ required: false, type: String })
path?: string;
@Prop({ required: false, type: String })
fileName?: string;
@Prop({ required: false, type: Types.ObjectId })
claimId?: Types.ObjectId;
}
export const CarGreenCardSchema =
SchemaFactory.createForClass(CarGreenCardModel);

View File

@@ -0,0 +1,18 @@
import { Prop } from "@nestjs/mongoose";
export class CarDamagePartOtherModel {
@Prop({
format: "array",
description: "please add items of json into array",
example: [{ "حسگر درها": true }],
})
otherParts?: [];
}
export class CarDamagePartModel {
@Prop({ type: String })
side: string;
@Prop({ type: String })
part: string;
}

View File

@@ -0,0 +1,29 @@
import { Prop } from "@nestjs/mongoose";
import mongoose, { Types } from "mongoose";
import { ActionUserModel } from "./action-user.schema";
export class ClaimBaseModel extends mongoose.Document {
@Prop()
readonly _id: Types.ObjectId;
@Prop()
readonly created: Date;
@Prop({
required: false,
type: ActionUserModel,
})
createdBy: ActionUserModel;
@Prop({ required: false })
readonly updated: Date;
@Prop({
required: false,
type: [ActionUserModel],
})
updatedBy: ActionUserModel[];
@Prop()
readonly deleted: boolean;
}

View File

@@ -0,0 +1,330 @@
import { Prop, Schema, SchemaFactory } from "@nestjs/mongoose";
import { Types } from "mongoose";
import {
CarDetail,
RequestManagementModel,
} from "src/request-management/entities/schema/request-management.schema";
import { UserSignModel } from "src/request-management/entities/schema/sign.schema";
import { ReqClaimStatus } from "src/Types&Enums/claim-request-management/status.enum";
import { ClaimStepsEnum } from "src/Types&Enums/claim-request-management/steps.enum";
import { UserReplyEnum } from "src/Types&Enums/claim-request-management/userReply.enum";
import { AiImagesModel } from "./ai-image.schema";
import { CarGreenCardModel } from "./car-green-card.schema";
import {
CarDamagePartModel,
CarDamagePartOtherModel,
} from "./car-parts.schema";
import { ImageRequiredModel } from "./image-required.schema";
import { Plates } from "src/Types&Enums/plate.interface";
import { AddPlateDto } from "src/profile/dto/user/AddPlateDto";
import { FactorStatus } from "src/Types&Enums/claim-request-management/factor-status.enum";
import { DaghiOption } from "src/Types&Enums/claim-request-management/daghi-option.enum";
// main schema
export type ClaimRequestManagementDoc = ClaimRequestManagementModel & Document;
export class EffectedUserReply {
@Prop({ required: true, type: String })
reply?: UserReplyEnum;
@Prop({ required: true })
signDetail?: UserSignModel;
}
export class UserComment {
@Prop({ type: Boolean })
isAccept: boolean;
@Prop({ required: false })
signDetail?: Types.ObjectId;
}
export class DaghiDetails {
@Prop({ required: true, type: String, enum: DaghiOption })
option: DaghiOption;
@Prop({ required: false, type: String })
price?: string;
@Prop({ required: false, type: Types.ObjectId })
branchId?: Types.ObjectId;
}
export class PartsList {
@Prop({ required: true, type: String })
partId: string;
@Prop({ required: true, type: String })
carPartDamage: string;
@Prop({ required: true, type: String })
typeOfDamage: string;
@Prop({ required: true, type: String })
price: string;
@Prop({ required: true, type: String })
salary: string;
@Prop({ required: true, type: String })
totalPayment: string;
@Prop({ required: true, type: DaghiDetails })
daghi: DaghiDetails;
@Prop({ required: true, type: Boolean })
factorNeeded: boolean;
@Prop({ type: Types.ObjectId })
factorLink?: Types.ObjectId;
@Prop({ type: String, enum: FactorStatus, default: null })
factorStatus?: FactorStatus;
@Prop({ type: String, default: null })
rejectionReason?: string;
}
export class ActorDetail {
@Prop()
actorName: string;
@Prop()
actorId: string;
}
export class InPersonDocuments {
@Prop()
NationalCertificate: string;
@Prop()
CarCertificate: string;
@Prop()
DrivingLicense: string;
@Prop()
CarGreenCard: string;
}
export class SubmitReply {
@Prop({ required: true })
description: string;
@Prop({ required: true })
actorDetail: ActorDetail;
@Prop({ required: true, type: [PartsList] })
parts: PartsList[];
@Prop({ required: true, default: () => new Date() })
submitTime: Date;
@Prop()
userComment?: UserComment;
}
export class ActorLockDetails {
@Prop({ type: String })
fullName?: string;
@Prop({ type: Types.ObjectId })
actorId?: Types.ObjectId;
}
export class ResendCarPartsDto {
@Prop({ required: true })
partId: string;
@Prop({ required: true })
partName: string;
}
export class ClaimSubmitResend {
@Prop({ required: true })
resendDescription: string;
@Prop({ required: true, type: [InPersonDocuments] })
resendDocuments: InPersonDocuments[];
@Prop({ required: true })
resendCarParts: ResendCarPartsDto[];
}
export class UserResendDocuments {
@Prop({ required: false })
documents: [];
@Prop({ required: false })
carParts: [];
}
export class UserObjection {
@Prop({ type: String, required: true })
partId: string;
@Prop({ type: String })
reason: string;
@Prop({ type: String })
partPrice: string;
@Prop({ type: String })
partSalary: string;
@Prop({ type: String })
typeOfDamage: string;
}
@Schema({ _id: false })
export class FileRating {
@Prop({ type: Number, min: 0, max: 5 })
collisionMethodAccuracy: number;
@Prop({ type: Number, min: 0, max: 5 })
evaluationTimeliness: number;
@Prop({ type: Number, min: 0, max: 5 })
accidentCauseAccuracy: number;
@Prop({ type: Number, min: 0, max: 5 })
guiltyVehicleIdentification: number;
}
export class PriceDrop {
@Prop({ type: Number })
total: number;
@Prop({ type: Number })
carPrice: number;
@Prop({ type: Number })
carModel: number;
@Prop({ type: [Number] })
carValue: number[];
@Prop({ type: Number })
sumOfSeverity: number;
}
@Schema({
collection: "claim-requests-management",
versionKey: false,
timestamps: true,
autoIndex: false,
})
export class ClaimRequestManagementModel {
readonly aiImage?: any;
constructor() {}
@Prop({ type: RequestManagementModel, unique: true })
blameFile: RequestManagementModel;
@Prop({ type: Number, default: 100 })
requestNumber?: number;
@Prop({ type: Types.ObjectId })
userClientKey?: Types.ObjectId;
@Prop({ type: Types.ObjectId })
userId: Types.ObjectId;
@Prop()
fullName: string;
@Prop()
carDetail: CarDetail;
@Prop({ type: AddPlateDto })
carPlate: Plates;
@Prop({})
claimStatus: ReqClaimStatus;
@Prop({})
steps: ClaimStepsEnum[];
@Prop({})
currentStep: ClaimStepsEnum;
@Prop({})
nextStep?: ClaimStepsEnum;
@Prop({ type: CarDamagePartModel })
carPartDamage?: CarDamagePartModel[];
@Prop({ type: CarDamagePartOtherModel })
otherParts?: CarDamagePartOtherModel[];
@Prop({ format: "string" })
sheba?: string;
@Prop({ format: "string" })
nationalCodeOfInsurer?: string;
@Prop({ type: CarGreenCardModel, required: false })
carGreenCard?: CarGreenCardModel;
@Prop({ type: ImageRequiredModel })
imageRequired?: ImageRequiredModel;
@Prop({ type: AiImagesModel })
aiImages?: AiImagesModel;
@Prop({ type: EffectedUserReply })
effectedUserReply?: EffectedUserReply;
@Prop()
lockFile?: boolean;
@Prop({ type: Date })
lockTime?: Date | string | number;
@Prop({ type: Date })
unlockTime?: Date | number;
@Prop()
actorLocked?: ActorLockDetails | null;
@Prop()
actorsChecker?: [];
@Prop({ required: false })
videoCaptureId?: Types.ObjectId;
@Prop({ required: false })
damageExpertReply?: SubmitReply | null;
@Prop({ required: false })
damageExpertReplyFinal?: SubmitReply | null;
@Prop({ required: false, type: ClaimSubmitResend })
damageExpertResend?: ClaimSubmitResend | null;
@Prop({ type: UserObjection, required: false })
objection?: UserObjection;
@Prop({ type: UserResendDocuments })
userResendDocuments?: UserResendDocuments;
@Prop({ type: PriceDrop, required: false })
priceDrop?: PriceDrop;
@Prop({ type: Map, of: Types.ObjectId, required: false })
requiredDocuments?: { [key: string]: Types.ObjectId };
createdAt: any;
updatedAt: any;
@Prop({ type: FileRating, required: false })
rating?: FileRating;
@Prop({ type: String, required: false })
visitLocation?: string;
@Prop({ type: Number, required: false })
claimNo?: number;
@Prop({ type: Number, required: false })
claimId?: number;
}
export const ClaimRequestManagementSchema = SchemaFactory.createForClass(
ClaimRequestManagementModel,
);

View File

@@ -0,0 +1,27 @@
import { Prop, Schema, SchemaFactory } from "@nestjs/mongoose";
import { Types } from "mongoose";
import { ClaimRequiredDocumentType } from "src/Types&Enums/claim-request-management/required-document-type.enum";
@Schema({ versionKey: false, collection: "claim-required-documents" })
export class ClaimRequiredDocument {
@Prop({ required: true, type: String })
path: string;
@Prop({ required: true, type: String })
fileName: string;
@Prop({ required: true, type: Types.ObjectId })
claimId: Types.ObjectId;
@Prop({ required: true, enum: ClaimRequiredDocumentType })
documentType: ClaimRequiredDocumentType;
@Prop({ default: () => new Date() })
uploadedAt: Date;
_id?: Types.ObjectId;
}
export const ClaimRequiredDocumentSchema =
SchemaFactory.createForClass(ClaimRequiredDocument);

View File

@@ -0,0 +1,6 @@
import { Schema, SchemaFactory } from "@nestjs/mongoose";
import { UserSignModel } from "src/request-management/entities/schema/sign.schema";
@Schema({ collection: "claim-sign", versionKey: false })
export class ClaimSignModel extends UserSignModel {}
export const ClaimSignSchema = SchemaFactory.createForClass(ClaimSignModel);

View File

@@ -0,0 +1,18 @@
import { Prop, Schema, SchemaFactory } from "@nestjs/mongoose";
export type DamagePartImage = DamagePartImageModel & Document;
@Schema({ versionKey: false, collection: "damage-part-image" })
export class DamagePartImageModel {
@Prop({ default: null })
path: string | null = null;
@Prop({ default: null })
fileName: string | null = null;
@Prop({ default: null })
claimId: string = null;
}
export const DamageImageModelSchema =
SchemaFactory.createForClass(DamagePartImageModel);

View File

@@ -0,0 +1,28 @@
import { Prop, Schema, SchemaFactory } from "@nestjs/mongoose";
import { Types } from "mongoose";
@Schema({ versionKey: false, collection: "claim-factors-image" })
export class ClaimFactorsImage {
@Prop({ required: true, type: String })
path: string;
@Prop({ required: true, type: String })
fileName: string;
@Prop({ required: true, type: Types.ObjectId })
claimId: Types.ObjectId;
@Prop({ required: true, type: String })
partId: string;
@Prop({ required: true, type: Object })
partName: any;
@Prop({ default: () => new Date() })
uploadedAt: Date;
_id?: Types.ObjectId;
}
export const ClaimFactorsImageSchema =
SchemaFactory.createForClass(ClaimFactorsImage);

View File

@@ -0,0 +1,38 @@
import { Prop, Schema } from "@nestjs/mongoose";
import { v4 as uuidv4 } from "uuid";
@Schema({ versionKey: false, _id: false })
export class ImageRequiredModel {
@Prop({ type: "array" })
public aroundTheCar = [
{ side: "left" },
{ side: "back" },
{ side: "front" },
{ side: "right" },
];
@Prop({ type: "array" })
public selectPartOfCar = [];
@Prop({ type: "string" })
public aiReportText: string;
constructor(claimFile: any[]) {
this.aroundTheCar.forEach((a) => {
Object.assign(a, {
partId: uuidv4(),
imageId: null,
aiReport: {},
upload: false,
});
});
this.selectPartOfCar = claimFile.map((c, idx) =>
Object.assign(c, {
partId: uuidv4(),
aiReport: {},
imageId: null,
upload: false,
}),
);
}
}

View File

@@ -0,0 +1,17 @@
import { Prop, Schema, SchemaFactory } from "@nestjs/mongoose";
import mongoose, { Types } from "mongoose";
@Schema({ versionKey: false, collection: "claim-video-capture" })
export class VideoCaptureModel extends mongoose.Document {
@Prop({ required: false, type: String })
path?: string;
@Prop({ required: false, type: String })
fileName?: string;
@Prop({ required: false, type: Types.ObjectId })
claimId?: Types.ObjectId;
}
export const VideoCaptureSchema =
SchemaFactory.createForClass(VideoCaptureModel);

View File

@@ -0,0 +1,181 @@
{
"قاب موتور": true,
"گلگیرهاتایرها": true,
"دیسک ترمز": true,
"لنت ترمز": true,
"روغن ترمز": true,
"ترمز دستی": true,
"پیچ چرخ‌ها": true,
"پیستون ترمز": true,
"پدال ترمز": true,
"شلنگ‌های ترمز": true,
"سوزن هواگیر": true,
"سامانه ABS": true,
"پمپ ترمز": true,
"کالیپر": true,
"بوستر": true,
"انواع سوپاپ‌های ترمز": true,
"فنرهای نگهدارنده": true,
"لنگر": true,
"کفشک ترمز": true,
"مخزن روغن ترمز": true,
"واحد تقویت‌کننده هیدرولیکی": true,
"پایه باتری": true,
"کابل باتری": true,
"سینی باتری": true,
"سامانه مدیریت باتری": true,
"دینام": true,
"ترمینال سیم‌کشی باتری": true,
"چراغ‌های جلو و عقب": true,
"چراغ‌های مه‌شکن": true,
"چراغ‌هایی داخل داشبورد": true,
"چراغ سقفی داخل کابین": true,
"حسگر دنده اتوماتیک": true,
"حسگر سرعت": true,
"حسگر دمای مایع خنک‌کننده": true,
"حسگر ترمز ABS": true,
"حسگر اکسیژن": true,
"حسگر جریان هوا": true,
"حسگر کیسه هوا": true,
"حسگر روغن": true,
"حسگر سوخت": true,
"حسگر میل‌لنگ": true,
"حسگر میل بادامک": true,
"حسگر کمربند ایمنی": true,
"حسگر نور": true,
"حسگر درها": true,
"جعبه احتراق": true,
"شمع": true,
"دلکو": true,
"کنترل‌گر زمان": true,
"سیم‌های اتصال": true,
"سوپاپ مغناطیسی": true,
"سیم‌پیچ احتراق": true,
"وایر شمع": true,
"رله فن": true,
"سوئیچ درها": true,
"سوئیچ استارت": true,
"کلید شیشه بالابر": true,
"سوئیچ قفل فرمان": true,
"ترموستات": true,
"تهویه": true,
"موتور": true,
"کف کابین": true,
"ادوات داخل کابین": true,
"اصلی": true,
"دوربین دنده عقب": true,
"دوربین‌های 360 درجه": true,
"صال به زمین": true,
"سامانه قفل مرکزی": true,
"اتصالات برقی درها": true,
"ماژول کنترل ایربگ": true,
"سامانه کنترل سرعت": true,
"سامانه مدیریت موتور": true,
"کروز کنترل": true,
"سامانه ناوبری": true,
"سوکت‌ها": true,
"سیستم قفل از راه دور": true,
"رایانه جعبه‌دنده": true,
"فیوزها": true,
"بلوک سیلندر": true,
"پوشش میل‌لنگ": true,
"پولی میل‌لنگ": true,
"میل‌لنگ": true,
"پولی پمپ آب": true,
"تسمه پروانه": true,
"پیستون": true,
"تسمه دینام": true,
"تسمه تایم": true,
"توربو شارژ": true,
"درپوش سوپاپ": true,
"دسته موتور": true,
"سرسیلندر": true,
"سوپاپ پایت": true,
"سوپاپ تهویه": true,
"شاتون": true,
"پین انگشتی": true,
"بخاری": true,
"میل بادامک": true,
"لرزش‌گیر موتور": true,
"فیلر": true,
"جعبه‌دنده": true,
"پوسته گیربکس": true,
"چرخ‌دنده‌های انتقال قدرت، جناحی، هرزگرد، سرعت‌سنج، چرخ لنگر، فرمان": true,
"پمپ دنده": true,
"دنده": true,
"اهرم تعویض دنده": true,
"دوشاخ دنده": true,
"کوپلینگ دنده": true,
"دیفرانسیل": true,
"سیلندر": true,
"فنر جعبه‌دنده": true,
"محور جعبه‌دنده": true,
"میل‌گاردان": true,
"شفت خروجی": true,
"پولوس‌ها": true,
"سامانه کلاچ": true,
"کابل تعویض دنده": true,
"فیلتر بنزین": true,
"فیلتر هوا": true,
"کاربراتور": true,
"باک سوخت": true,
"سیستم LPG": true,
"کابل ساسات": true,
"منیفولد ورودی": true,
"جداکننده آب از سوخت": true,
"پیل سوختی": true,
"سیستم CNG": true,
"پمپ‌بنزین": true,
"انژکتور": true,
"بدنه دریچه گاز": true,
"خنک‌کننده سوخت": true,
"رگلاتور": true,
"ریل": true,
"غربیلک فرمان": true,
"بازوی فرمان": true,
"جعبه فرمان": true,
"دوک": true,
"شفت فرمان": true,
"سامانه فرمان خودکار": true,
"اتصال جانبی": true,
"اتصال میل موج‌گیر": true,
"بازوی خمیده": true,
"بازوی آزاد": true,
"بازوی پیت من": true,
"بست و اتصالات": true,
"سیبک فرمان": true,
"کمک‌فنرها": true,
"اتصالات تعادلی": true,
"فنر": true,
"محور خودرو": true,
"عایق حرارتی": true,
"گیره‌ها": true,
"لوله اگزوز": true,
"سپر حرارتی": true,
"صداخفه‌کن": true,
"رزیناتور": true,
"کاتالیست": true,
"حلقه فاصله": true,
"انواع واشرها": true,
"لوله‌های روغن": true,
"کارتل روغن": true,
"پمپ روغن": true,
"واشر پمپ روغن": true,
"صافی روغن": true,
"فیلتر روغن": true,
"تسمه فن": true,
"تیغه فن": true,
"واتر پمپ": true,
"واشر پمپ آب": true,
"دمنده هوا": true,
"بوش فن": true,
"مخزن": true,
"درپوش فشار": true,
"ترموستات": true,
"پوشش فن": true,
"کلاچ فن": true,
"پروانه یا فن": true,
"لوله‌های ورودی و خروجی آب": true,
"زانویی آب": true,
"شلنگ مایع خنک‌کننده": true
}