From 0f6401953f1d4ea60d8500fe265c06a01859bb95 Mon Sep 17 00:00:00 2001 From: Julian Krauser Date: Wed, 28 May 2025 22:51:17 +0200 Subject: [PATCH] add maintenance model, factory and service --- src/data-source.ts | 2 + src/entity/unit/damageReport.ts | 13 ++++- src/entity/unit/maintenance.ts | 56 +++++++++++++++++++ src/factory/admin/unit/damageReport.ts | 4 +- src/factory/admin/unit/maintenance.ts | 55 ++++++++++++++++++ src/migrations/1748261477410-unitBase.ts | 4 +- .../baseSchemaTables/unit_extend.ts | 45 +++++++++++++++ src/service/unit/damageReport.ts | 5 ++ src/service/unit/maintenance.ts | 49 ++++++++++++++++ .../admin/unit/damageReport.models.ts | 4 +- .../admin/unit/maintenance.models.ts | 43 ++++++++++++++ 11 files changed, 276 insertions(+), 4 deletions(-) create mode 100644 src/entity/unit/maintenance.ts create mode 100644 src/factory/admin/unit/maintenance.ts create mode 100644 src/service/unit/maintenance.ts create mode 100644 src/viewmodel/admin/unit/maintenance.models.ts diff --git a/src/data-source.ts b/src/data-source.ts index 85fe595..42e035a 100644 --- a/src/data-source.ts +++ b/src/data-source.ts @@ -69,6 +69,7 @@ import { inspectionPoint } from "./entity/unit/inspection/inspectionPoint"; import { inspection } from "./entity/unit/inspection/inspection"; import { inspectionPointResult } from "./entity/unit/inspection/inspectionPointResult"; import { UnitBase1748261477410 } from "./migrations/1748261477410-unitBase"; +import { maintenance } from "./entity/unit/maintenance"; configCheck(); @@ -131,6 +132,7 @@ const dataSource = new DataSource({ wearableType, wearable, damageReport, + maintenance, inspectionPlan, inspectionVersionedPlan, inspectionPoint, diff --git a/src/entity/unit/damageReport.ts b/src/entity/unit/damageReport.ts index dd0955e..20a78c2 100644 --- a/src/entity/unit/damageReport.ts +++ b/src/entity/unit/damageReport.ts @@ -1,7 +1,8 @@ -import { Check, Column, CreateDateColumn, Entity, ManyToOne, PrimaryGeneratedColumn } from "typeorm"; +import { Column, CreateDateColumn, Entity, ManyToOne, PrimaryGeneratedColumn } from "typeorm"; import { equipment } from "./equipment/equipment"; import { wearable } from "./wearable/wearable"; import { vehicle } from "./vehicle/vehicle"; +import { maintenance } from "./maintenance"; @Entity() export class damageReport { @@ -29,6 +30,9 @@ export class damageReport { @Column({ nullable: true, default: null }) equipmentId?: string; + @Column({ nullable: true, default: null }) + maintenanceId: string; + @Column({ nullable: true, default: null }) vehicleId?: string; @@ -55,4 +59,11 @@ export class damageReport { onUpdate: "RESTRICT", }) wearable?: wearable; + + @ManyToOne(() => maintenance, { + nullable: true, + onDelete: "SET NULL", + onUpdate: "RESTRICT", + }) + maintenance?: maintenance; } diff --git a/src/entity/unit/maintenance.ts b/src/entity/unit/maintenance.ts new file mode 100644 index 0000000..f3c9669 --- /dev/null +++ b/src/entity/unit/maintenance.ts @@ -0,0 +1,56 @@ +import { Column, CreateDateColumn, Entity, ManyToOne, OneToMany, PrimaryGeneratedColumn } from "typeorm"; +import { equipment } from "./equipment/equipment"; +import { wearable } from "./wearable/wearable"; +import { vehicle } from "./vehicle/vehicle"; +import { damageReport } from "./damageReport"; + +@Entity() +export class maintenance { + @PrimaryGeneratedColumn("uuid") + id: string; + + @CreateDateColumn() + createdAt: Date; + + @Column({ type: "varchar", length: 255 }) + status: string; + + @Column({ type: "boolean", default: false }) + done: boolean; + + @Column({ type: "text" }) + description: string; + + @Column({ nullable: true, default: null }) + equipmentId?: string; + + @Column({ nullable: true, default: null }) + vehicleId?: string; + + @Column({ nullable: true, default: null }) + wearableId?: string; + + @ManyToOne(() => equipment, { + nullable: true, + onDelete: "CASCADE", + onUpdate: "RESTRICT", + }) + equipment?: equipment; + + @ManyToOne(() => vehicle, { + nullable: true, + onDelete: "CASCADE", + onUpdate: "RESTRICT", + }) + vehicle?: vehicle; + + @ManyToOne(() => wearable, { + nullable: true, + onDelete: "CASCADE", + onUpdate: "RESTRICT", + }) + wearable?: wearable; + + @OneToMany(() => damageReport, (dr) => dr.maintenance) + reports: damageReport[]; +} diff --git a/src/factory/admin/unit/damageReport.ts b/src/factory/admin/unit/damageReport.ts index 908c0fe..fb9115e 100644 --- a/src/factory/admin/unit/damageReport.ts +++ b/src/factory/admin/unit/damageReport.ts @@ -1,6 +1,7 @@ import { damageReport } from "../../../entity/unit/damageReport"; import { DamageReportAssigned, DamageReportViewModel } from "../../../viewmodel/admin/unit/damageReport.models"; import EquipmentFactory from "./equipment/equipment"; +import MaintenanceFactory from "./maintenance"; import VehicleFactory from "./vehicle/vehicle"; import WearableFactory from "./wearable/wearable"; @@ -34,13 +35,14 @@ export default abstract class DamageReportFactory { return { id: record.id, - reported: record.reportedAt, + reportedAt: record.reportedAt, status: record.status, done: record.done, description: record.description, imageCount: record.imageCount, reportedBy: record?.reportedBy, ...assigned, + maintenance: record.maintenance ? MaintenanceFactory.mapToSingle(record.maintenance) : null, }; } diff --git a/src/factory/admin/unit/maintenance.ts b/src/factory/admin/unit/maintenance.ts new file mode 100644 index 0000000..69f4c78 --- /dev/null +++ b/src/factory/admin/unit/maintenance.ts @@ -0,0 +1,55 @@ +import { maintenance } from "../../../entity/unit/maintenance"; +import { MaintenanceAssigned, MaintenanceViewModel } from "../../../viewmodel/admin/unit/maintenance.models"; +import DamageReportFactory from "./damageReport"; +import EquipmentFactory from "./equipment/equipment"; +import VehicleFactory from "./vehicle/vehicle"; +import WearableFactory from "./wearable/wearable"; + +export default abstract class MaintenanceFactory { + /** + * @description map record to maintenance + * @param {maintenance} record + * @returns {MaintenanceViewModel} + */ + public static mapToSingle(record: maintenance): MaintenanceViewModel { + let assigned: MaintenanceAssigned; + if (record?.equipmentId) { + assigned = { + relatedId: record.equipmentId, + assigned: "equipment", + related: EquipmentFactory.mapToSingle(record.equipment), + }; + } else if (record?.vehicleId) { + assigned = { + relatedId: record.vehicleId, + assigned: "vehicle", + related: VehicleFactory.mapToSingle(record.vehicle), + }; + } else { + assigned = { + relatedId: record.wearableId, + assigned: "wearable", + related: WearableFactory.mapToSingle(record.wearable), + }; + } + + return { + id: record.id, + createdAt: record.createdAt, + status: record.status, + done: record.done, + description: record.description, + ...assigned, + reports: record.reports ? DamageReportFactory.mapToBase(record.reports) : [], + }; + } + + /** + * @description map records to maintenance + * @param {Array} records + * @returns {Array} + */ + public static mapToBase(records: Array): Array { + return records.map((r) => this.mapToSingle(r)); + } +} diff --git a/src/migrations/1748261477410-unitBase.ts b/src/migrations/1748261477410-unitBase.ts index d4951c6..cc6e201 100644 --- a/src/migrations/1748261477410-unitBase.ts +++ b/src/migrations/1748261477410-unitBase.ts @@ -7,7 +7,7 @@ import { wearable_table, wearable_type_table, } from "./baseSchemaTables/unit"; -import { damage_report_table } from "./baseSchemaTables/unit_extend"; +import { damage_report_table, maintenance_table } from "./baseSchemaTables/unit_extend"; import { inspection_plan_table, inspection_point_result_table, @@ -27,6 +27,7 @@ export class UnitBase1748261477410 implements MigrationInterface { await queryRunner.createTable(wearable_type_table, true, true, true); await queryRunner.createTable(wearable_table, true, true, true); + await queryRunner.createTable(maintenance_table, true, true, true); await queryRunner.createTable(damage_report_table, true, true, true); await queryRunner.createTable(inspection_plan_table, true, true, true); @@ -46,6 +47,7 @@ export class UnitBase1748261477410 implements MigrationInterface { await queryRunner.dropTable(inspection_plan_table, true, true, true); await queryRunner.dropTable(damage_report_table, true, true, true); + await queryRunner.dropTable(maintenance_table, true, true, true); await queryRunner.dropTable(wearable_table, true, true, true); await queryRunner.dropTable(wearable_type_table, true, true, true); diff --git a/src/migrations/baseSchemaTables/unit_extend.ts b/src/migrations/baseSchemaTables/unit_extend.ts index 9115540..3f78910 100644 --- a/src/migrations/baseSchemaTables/unit_extend.ts +++ b/src/migrations/baseSchemaTables/unit_extend.ts @@ -14,6 +14,51 @@ export const damage_report_table = new Table({ { name: "equipmentId", ...getTypeByORM("uuid", true), default: getDefaultByORM("null") }, { name: "vehicleId", ...getTypeByORM("uuid", true), default: getDefaultByORM("null") }, { name: "wearableId", ...getTypeByORM("uuid", true), default: getDefaultByORM("null") }, + { name: "maintenanceId", ...getTypeByORM("uuid", true), default: getDefaultByORM("null") }, + ], + foreignKeys: [ + new TableForeignKey({ + columnNames: ["equipmentId"], + referencedColumnNames: ["id"], + referencedTableName: "equipment", + onDelete: "CASCADE", + onUpdate: "RESTRICT", + }), + new TableForeignKey({ + columnNames: ["vehicleId"], + referencedColumnNames: ["id"], + referencedTableName: "vehicle", + onDelete: "CASCADE", + onUpdate: "RESTRICT", + }), + new TableForeignKey({ + columnNames: ["wearableId"], + referencedColumnNames: ["id"], + referencedTableName: "wearable", + onDelete: "CASCADE", + onUpdate: "RESTRICT", + }), + new TableForeignKey({ + columnNames: ["maintenanceId"], + referencedColumnNames: ["id"], + referencedTableName: "maintenance", + onDelete: "SET NULL", + onUpdate: "RESTRICT", + }), + ], +}); + +export const maintenance_table = new Table({ + name: "maintenance", + columns: [ + { name: "id", ...getTypeByORM("uuid"), ...isUUIDPrimary }, + { name: "createdAt", ...getTypeByORM("date"), default: getDefaultByORM("currentTimestamp") }, + { name: "status", ...getTypeByORM("varchar") }, + { name: "done", ...getTypeByORM("boolean"), default: getDefaultByORM("boolean", false) }, + { name: "description", ...getTypeByORM("text") }, + { name: "equipmentId", ...getTypeByORM("uuid", true), default: getDefaultByORM("null") }, + { name: "vehicleId", ...getTypeByORM("uuid", true), default: getDefaultByORM("null") }, + { name: "wearableId", ...getTypeByORM("uuid", true), default: getDefaultByORM("null") }, ], foreignKeys: [ new TableForeignKey({ diff --git a/src/service/unit/damageReport.ts b/src/service/unit/damageReport.ts index ef8b999..7821ea1 100644 --- a/src/service/unit/damageReport.ts +++ b/src/service/unit/damageReport.ts @@ -14,6 +14,7 @@ export default abstract class DamageReportService { .leftJoinAndSelect("damageReport.equipment", "equipment") .leftJoinAndSelect("damageReport.vehicle", "vehicle") .leftJoinAndSelect("damageReport.wearable", "wearable") + .leftJoinAndSelect("damageReport.maintenance", "maintenance") .orderBy("type", "ASC") .getMany() .then((res) => { @@ -32,6 +33,10 @@ export default abstract class DamageReportService { return await dataSource .getRepository(damageReport) .createQueryBuilder("damageReport") + .leftJoinAndSelect("damageReport.equipment", "equipment") + .leftJoinAndSelect("damageReport.vehicle", "vehicle") + .leftJoinAndSelect("damageReport.wearable", "wearable") + .leftJoinAndSelect("damageReport.maintenance", "maintenance") .where({ id }) .getOneOrFail() .then((res) => { diff --git a/src/service/unit/maintenance.ts b/src/service/unit/maintenance.ts new file mode 100644 index 0000000..d9e8519 --- /dev/null +++ b/src/service/unit/maintenance.ts @@ -0,0 +1,49 @@ +import { dataSource } from "../../data-source"; +import { maintenance } from "../../entity/unit/maintenance"; +import DatabaseActionException from "../../exceptions/databaseActionException"; + +export default abstract class MaintenanceService { + /** + * @description get all maintenances + * @returns {Promise>} + */ + static async getAll(): Promise> { + return await dataSource + .getRepository(maintenance) + .createQueryBuilder("maintenance") + .leftJoinAndSelect("maintenance.equipment", "equipment") + .leftJoinAndSelect("maintenance.vehicle", "vehicle") + .leftJoinAndSelect("maintenance.wearable", "wearable") + .leftJoinAndSelect("maintenance.reports", "reports") + .orderBy("type", "ASC") + .getMany() + .then((res) => { + return res; + }) + .catch((err) => { + throw new DatabaseActionException("SELECT", "maintenance", err); + }); + } + + /** + * @description get maintenance by id + * @returns {Promise} + */ + static async getById(id: string): Promise { + return await dataSource + .getRepository(maintenance) + .createQueryBuilder("maintenance") + .leftJoinAndSelect("maintenance.equipment", "equipment") + .leftJoinAndSelect("maintenance.vehicle", "vehicle") + .leftJoinAndSelect("maintenance.wearable", "wearable") + .leftJoinAndSelect("maintenance.reports", "reports") + .where({ id }) + .getOneOrFail() + .then((res) => { + return res; + }) + .catch((err) => { + throw new DatabaseActionException("SELECT", "maintenance", err); + }); + } +} diff --git a/src/viewmodel/admin/unit/damageReport.models.ts b/src/viewmodel/admin/unit/damageReport.models.ts index b0f5c20..e675c9c 100644 --- a/src/viewmodel/admin/unit/damageReport.models.ts +++ b/src/viewmodel/admin/unit/damageReport.models.ts @@ -1,4 +1,5 @@ import { EquipmentViewModel } from "./equipment/equipment.models"; +import { MaintenanceViewModel } from "./maintenance.models"; import { VehicleViewModel } from "./vehicle/vehicle.models"; import { WearableViewModel } from "./wearable/wearable.models"; @@ -21,12 +22,13 @@ export type DamageReportAssigned = { export type DamageReportViewModel = { id: string; - reported: Date; + reportedAt: Date; status: string; done: boolean; description: string; imageCount: number; reportedBy: string; + maintenance?: MaintenanceViewModel; } & DamageReportAssigned; export interface CreateDamageReportViewModel { diff --git a/src/viewmodel/admin/unit/maintenance.models.ts b/src/viewmodel/admin/unit/maintenance.models.ts new file mode 100644 index 0000000..ce5c0b9 --- /dev/null +++ b/src/viewmodel/admin/unit/maintenance.models.ts @@ -0,0 +1,43 @@ +import { DamageReportViewModel } from "./damageReport.models"; +import { EquipmentViewModel } from "./equipment/equipment.models"; +import { VehicleViewModel } from "./vehicle/vehicle.models"; +import { WearableViewModel } from "./wearable/wearable.models"; + +export type MaintenanceAssigned = { + relatedId: string; +} & ( + | { + assigned: "equipment"; + related: EquipmentViewModel; + } + | { + assigned: "vehicle"; + related: VehicleViewModel; + } + | { + assigned: "wearable"; + related: WearableViewModel; + } +); + +export type MaintenanceViewModel = { + id: string; + createdAt: Date; + status: string; + done: boolean; + description: string; + reports: DamageReportViewModel[]; +} & MaintenanceAssigned; + +export interface CreateMaintenanceViewModel { + description: string; + reportedBy: string; + affectedId: string; + affected: "equipment" | "vehicle" | "wearable"; +} + +export interface UpdateMaintenanceViewModel { + id: string; + status: string; + done: boolean; +}