diff --git a/src/command/unit/damageReportCommand.ts b/src/command/unit/damageReportCommand.ts index 9d7a631..1b397c2 100644 --- a/src/command/unit/damageReportCommand.ts +++ b/src/command/unit/damageReportCommand.ts @@ -15,9 +15,9 @@ export interface UpdateDamageReportCommand { done: boolean; } -export interface UpdateDamageReportRelatedMaintenanceCommand { +export interface UpdateDamageReportRelatedRepairCommand { id: string; - maintenanceId: string; + repairId: string; } export interface DeleteDamageReportCommand { diff --git a/src/command/unit/damageReportCommandHandler.ts b/src/command/unit/damageReportCommandHandler.ts index e5357d6..d7d8485 100644 --- a/src/command/unit/damageReportCommandHandler.ts +++ b/src/command/unit/damageReportCommandHandler.ts @@ -5,7 +5,7 @@ import { CreateDamageReportCommand, UpdateDamageReportCommand, DeleteDamageReportCommand, - UpdateDamageReportRelatedMaintenanceCommand, + UpdateDamageReportRelatedRepairCommand, } from "./damageReportCommand"; export default abstract class DamageReportCommandHandler { @@ -66,14 +66,12 @@ export default abstract class DamageReportCommandHandler { * @param {UpdateDamageReportCommand} updateDamageReport * @returns {Promise} */ - static async updateRelatedMaintenance( - updateDamageReport: UpdateDamageReportRelatedMaintenanceCommand - ): Promise { + static async updateRelatedMaintenance(updateDamageReport: UpdateDamageReportRelatedRepairCommand): Promise { return await dataSource .createQueryBuilder() .update(damageReport) .set({ - maintenanceId: updateDamageReport.maintenanceId, + repairId: updateDamageReport.repairId, }) .where("id = :id", { id: updateDamageReport.id }) .execute() diff --git a/src/command/unit/repairCommand.ts b/src/command/unit/repairCommand.ts new file mode 100644 index 0000000..bd7af10 --- /dev/null +++ b/src/command/unit/repairCommand.ts @@ -0,0 +1,19 @@ +export interface CreateRepairCommand { + description: string; + responsible: string; + affectedId: string; + affected: "equipment" | "vehicle" | "wearable"; + reports: string[]; +} + +export interface UpdateRepairCommand { + id: string; + status: string; + description: string; + responsible: string; + reports: string[]; +} + +export interface DeleteRepairCommand { + id: string; +} diff --git a/src/command/unit/repairCommandHandler.ts b/src/command/unit/repairCommandHandler.ts new file mode 100644 index 0000000..b2713f5 --- /dev/null +++ b/src/command/unit/repairCommandHandler.ts @@ -0,0 +1,75 @@ +import { dataSource } from "../../data-source"; +import { repair } from "../../entity/unit/repair"; +import DatabaseActionException from "../../exceptions/databaseActionException"; +import { CreateRepairCommand, UpdateRepairCommand, DeleteRepairCommand } from "./repairCommand"; + +export default abstract class RepairCommandHandler { + /** + * @description create repair + * @param {CreateRepairCommand} createRepair + * @returns {Promise} + */ + static async create(createRepair: CreateRepairCommand): Promise { + return await dataSource + .createQueryBuilder() + .insert() + .into(repair) + .values({ + status: "in Arbeit", + description: createRepair.description, + reports: createRepair.reports.map((r) => ({ id: r })), + responsible: createRepair.responsible, + equipmentId: createRepair.affected == "equipment" ? createRepair.affectedId : null, + vehicleId: createRepair.affected == "vehicle" ? createRepair.affectedId : null, + wearableId: createRepair.affected == "wearable" ? createRepair.affectedId : null, + }) + .execute() + .then((result) => { + return result.identifiers[0].id; + }) + .catch((err) => { + throw new DatabaseActionException("CREATE", "repair", err); + }); + } + + /** + * @description update repair + * @param {UpdateRepairCommand} updateRepair + * @returns {Promise} + */ + static async update(updateRepair: UpdateRepairCommand): Promise { + return await dataSource + .createQueryBuilder() + .update(repair) + .set({ + status: updateRepair.status, + description: updateRepair.description, + reports: updateRepair.reports.map((r) => ({ id: r })), + responsible: updateRepair.responsible, + }) + .where("id = :id", { id: updateRepair.id }) + .execute() + .then(() => {}) + .catch((err) => { + throw new DatabaseActionException("UPDATE", "repair", err); + }); + } + + /** + * @description delete repair + * @param {DeleteRepairCommand} deleteRepair + * @returns {Promise} + */ + static async delete(deleteRepair: DeleteRepairCommand): Promise { + return await dataSource + .createQueryBuilder() + .delete() + .from(repair) + .where("id = :id", { id: deleteRepair.id }) + .execute() + .then(() => {}) + .catch((err) => { + throw new DatabaseActionException("DELETE", "repair", err); + }); + } +} diff --git a/src/controller/admin/unit/repairController.ts b/src/controller/admin/unit/repairController.ts new file mode 100644 index 0000000..9e6a25e --- /dev/null +++ b/src/controller/admin/unit/repairController.ts @@ -0,0 +1,126 @@ +import { Request, Response } from "express"; +import RepairService from "../../../service/unit/repairService"; +import RepairFactory from "../../../factory/admin/unit/repair"; +import { CreateRepairCommand, UpdateRepairCommand } from "../../../command/unit/repairCommand"; +import RepairCommandHandler from "../../../command/unit/repairCommandHandler"; +import BadRequestException from "../../../exceptions/badRequestException"; +import { FileSystemHelper } from "../../../helpers/fileSystemHelper"; + +/** + * @description get all repairs by status + * @param req {Request} Express req object + * @param res {Response} Express res object + * @returns {Promise<*>} + */ +export async function getAllRepairsByStatus(req: Request, res: Response): Promise { + let done = req.query.done === "true"; + let offset = parseInt((req.query.offset as string) ?? "0"); + let count = parseInt((req.query.count as string) ?? "25"); + let noLimit = req.query.noLimit === "true"; + + let [repairs, total] = await RepairService.getAll(done, { offset, count, noLimit }); + + res.json({ + repairs: RepairFactory.mapToBase(repairs), + total: total, + offset: offset, + count: count, + }); +} + +/** + * @description get all repairs for related id + * @param req {Request} Express req object + * @param res {Response} Express res object + * @returns {Promise<*>} + */ +export async function getAllRepairsForRelated(req: Request, res: Response): Promise { + let relation = req.params.related as "vehicle" | "equipment" | "wearable"; + let relationId = req.params.relatedId as string; + let offset = parseInt((req.query.offset as string) ?? "0"); + let count = parseInt((req.query.count as string) ?? "25"); + let noLimit = req.query.noLimit === "true"; + + let where; + if (relation == "equipment") { + where = { equipmentId: relationId }; + } else if (relation == "vehicle") { + where = { vehicleId: relationId }; + } else { + where = { wearableId: relationId }; + } + let [repairs, total] = await RepairService.getAllForRelated(where, { offset, count, noLimit }); + + res.json({ + repairs: RepairFactory.mapToBase(repairs), + total: total, + offset: offset, + count: count, + }); +} + +/** + * @description get repair by id + * @param req {Request} Express req object + * @param res {Response} Express res object + * @returns {Promise<*>} + */ +export async function getRepairById(req: Request, res: Response): Promise { + const repairId = req.params.id; + let repair = await RepairService.getById(repairId); + + res.json(RepairFactory.mapToSingle(repair)); +} + +/** + * @description create repair + * @param req {Request} Express req object + * @param res {Response} Express res object + * @returns {Promise<*>} + */ +export async function createRepair(req: Request, res: Response): Promise { + const description = req.body.description; + const responsible = req.body.responsible; + const reports = req.body.reports; + const affectedId = req.body.affectedId; + const affected = req.body.affected; + + if (affected != "equipment" && affected != "vehicle" && affected != "wearable") + throw new BadRequestException("set assigned to equipment or vehicle or wearable"); + + let createRepair: CreateRepairCommand = { + description, + affectedId, + affected, + responsible, + reports, + }; + let repairId = await RepairCommandHandler.create(createRepair); + + res.status(200).send(repairId); +} + +/** + * @description update repair by id + * @param req {Request} Express req object + * @param res {Response} Express res object + * @returns {Promise<*>} + */ +export async function updateRepairById(req: Request, res: Response): Promise { + const repairId = req.params.id; + const status = req.body.status; + const description = req.body.description; + const responsible = req.body.responsible; + const reports = req.body.reports; + + let updateRepair: UpdateRepairCommand = { + id: repairId, + status, + description, + responsible, + reports, + }; + await RepairCommandHandler.update(updateRepair); + + res.sendStatus(204); +} diff --git a/src/data-source.ts b/src/data-source.ts index b54707a..3f337f1 100644 --- a/src/data-source.ts +++ b/src/data-source.ts @@ -65,7 +65,8 @@ import { maintenance } from "./entity/unit/maintenance"; import { BackupAndResetDatabase1749296262915 } from "./migrations/1749296262915-BackupAndResetDatabase"; import { CreateSchema1749296280721 } from "./migrations/1749296280721-CreateSchema"; import { UpdateNewsletterQueryRelation1752502069178 } from "./migrations/1752502069178-updateNewsletterQueryRelation"; -import { UnitBase1749361405703 } from "./migrations/1749361405703-UnitBase"; +import { UnitBase1752914551204 } from "./migrations/1752914551204-UnitBase"; +import { repair } from "./entity/unit/repair"; configCheck(); @@ -131,6 +132,7 @@ const dataSource = new DataSource({ wearable, damageReport, maintenance, + repair, inspectionPlan, inspectionVersionedPlan, inspectionPoint, @@ -140,8 +142,8 @@ const dataSource = new DataSource({ migrations: [ BackupAndResetDatabase1749296262915, CreateSchema1749296280721, + UnitBase1752914551204, UpdateNewsletterQueryRelation1752502069178, - UnitBase1749361405703, ], migrationsRun: true, migrationsTransactionMode: "each", diff --git a/src/entity/unit/damageReport.ts b/src/entity/unit/damageReport.ts index bfb45ae..59ed8c2 100644 --- a/src/entity/unit/damageReport.ts +++ b/src/entity/unit/damageReport.ts @@ -2,7 +2,7 @@ import { Column, CreateDateColumn, Entity, ManyToOne, PrimaryGeneratedColumn } f import { equipment } from "./equipment/equipment"; import { wearable } from "./wearable/wearable"; import { vehicle } from "./vehicle/vehicle"; -import { maintenance } from "./maintenance"; +import { repair } from "./repair"; @Entity() export class damageReport { @@ -34,7 +34,7 @@ export class damageReport { type: "text", transformer: { from(value: string): Array { - return value.split(",").filter((i) => !!i); + return (value ?? "").split(",").filter((i) => !!i); }, to(value: Array): string { return value.join(","); @@ -56,7 +56,7 @@ export class damageReport { wearableId?: string; @Column({ nullable: true, default: null }) - maintenanceId?: string; + repairId?: string; @ManyToOne(() => equipment, (e) => e.reports, { nullable: true, @@ -79,10 +79,10 @@ export class damageReport { }) wearable?: wearable; - @ManyToOne(() => maintenance, (m) => m.reports, { + @ManyToOne(() => repair, (m) => m.reports, { nullable: true, onDelete: "SET NULL", onUpdate: "RESTRICT", }) - maintenance?: maintenance; + repair?: repair; } diff --git a/src/entity/unit/equipment/equipment.ts b/src/entity/unit/equipment/equipment.ts index 2d3b022..21f5022 100644 --- a/src/entity/unit/equipment/equipment.ts +++ b/src/entity/unit/equipment/equipment.ts @@ -4,6 +4,7 @@ import { equipmentType } from "./equipmentType"; import { damageReport } from "../damageReport"; import { inspection } from "../inspection/inspection"; import { maintenance } from "../maintenance"; +import { repair } from "../repair"; @Entity() export class equipment { @@ -38,6 +39,9 @@ export class equipment { @OneToMany(() => damageReport, (d) => d.equipment, { cascade: ["insert"] }) reports: damageReport[]; + @OneToMany(() => repair, (d) => d.equipment, { cascade: ["insert"] }) + repairs: repair[]; + @OneToMany(() => maintenance, (m) => m.equipment, { cascade: ["insert"] }) maintenances: maintenance[]; diff --git a/src/entity/unit/maintenance.ts b/src/entity/unit/maintenance.ts index 3c9b7c0..15ce3c2 100644 --- a/src/entity/unit/maintenance.ts +++ b/src/entity/unit/maintenance.ts @@ -1,8 +1,9 @@ -import { Column, CreateDateColumn, Entity, ManyToOne, OneToMany, PrimaryGeneratedColumn } from "typeorm"; +import { Column, ColumnType, 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"; +import { getTypeByORM } from "../../migrations/ormHelper"; @Entity() export class maintenance { @@ -12,12 +13,12 @@ export class maintenance { @CreateDateColumn() createdAt: Date; + @Column({ type: getTypeByORM("datetime").type as ColumnType, nullable: true, default: null }) + finishedAt?: Date; + @Column({ type: "varchar", length: 255 }) status: string; - @Column({ type: "boolean", default: false }) - done: boolean; - @Column({ type: "text" }) description: string; @@ -50,7 +51,4 @@ export class maintenance { onUpdate: "RESTRICT", }) wearable?: wearable; - - @OneToMany(() => damageReport, (dr) => dr.maintenance) - reports: damageReport[]; } diff --git a/src/entity/unit/repair.ts b/src/entity/unit/repair.ts new file mode 100644 index 0000000..0eac000 --- /dev/null +++ b/src/entity/unit/repair.ts @@ -0,0 +1,76 @@ +import { Column, ColumnType, 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"; +import { getTypeByORM } from "../../migrations/ormHelper"; + +@Entity() +export class repair { + @PrimaryGeneratedColumn("uuid") + id: string; + + @CreateDateColumn() + createdAt: Date; + + @Column({ type: getTypeByORM("datetime").type as ColumnType, nullable: true, default: null }) + finishedAt?: Date; + + @Column({ type: "varchar", length: 255 }) + status: string; + + @Column({ type: "varchar", length: 255 }) + responsible: string; + + @Column({ type: "text" }) + description: string; + + @Column({ + type: "text", + transformer: { + from(value: string): Array { + return (value ?? "").split(",").filter((i) => !!i); + }, + to(value: Array): string { + return value.join(","); + }, + }, + }) + images: string[]; + + @Column({ type: "varchar", length: 255 }) + reportDocument: string; + + @Column({ nullable: true, default: null }) + equipmentId?: string; + + @Column({ nullable: true, default: null }) + vehicleId?: string; + + @Column({ nullable: true, default: null }) + wearableId?: string; + + @ManyToOne(() => equipment, (e) => e.maintenances, { + nullable: true, + onDelete: "CASCADE", + onUpdate: "RESTRICT", + }) + equipment?: equipment; + + @ManyToOne(() => vehicle, (v) => v.maintenances, { + nullable: true, + onDelete: "CASCADE", + onUpdate: "RESTRICT", + }) + vehicle?: vehicle; + + @ManyToOne(() => wearable, (w) => w.maintenances, { + nullable: true, + onDelete: "CASCADE", + onUpdate: "RESTRICT", + }) + wearable?: wearable; + + @OneToMany(() => damageReport, (dr) => dr.repair) + reports: damageReport[]; +} diff --git a/src/entity/unit/vehicle/vehicle.ts b/src/entity/unit/vehicle/vehicle.ts index 3f75651..8102bf0 100644 --- a/src/entity/unit/vehicle/vehicle.ts +++ b/src/entity/unit/vehicle/vehicle.ts @@ -4,6 +4,7 @@ import { vehicleType } from "./vehicleType"; import { damageReport } from "../damageReport"; import { inspection } from "../inspection/inspection"; import { maintenance } from "../maintenance"; +import { repair } from "../repair"; @Entity() export class vehicle { @@ -38,6 +39,9 @@ export class vehicle { @OneToMany(() => damageReport, (d) => d.vehicle, { cascade: ["insert"] }) reports: damageReport[]; + @OneToMany(() => repair, (d) => d.vehicle, { cascade: ["insert"] }) + repairs: repair[]; + @OneToMany(() => maintenance, (m) => m.vehicle, { cascade: ["insert"] }) maintenances: maintenance[]; diff --git a/src/entity/unit/wearable/wearable.ts b/src/entity/unit/wearable/wearable.ts index 2c5ce44..e4ecf22 100644 --- a/src/entity/unit/wearable/wearable.ts +++ b/src/entity/unit/wearable/wearable.ts @@ -5,6 +5,7 @@ import { damageReport } from "../damageReport"; import { member } from "../../club/member/member"; import { inspection } from "../inspection/inspection"; import { maintenance } from "../maintenance"; +import { repair } from "../repair"; @Entity() export class wearable { @@ -49,6 +50,9 @@ export class wearable { @OneToMany(() => damageReport, (d) => d.wearable, { cascade: ["insert"] }) reports: damageReport[]; + @OneToMany(() => repair, (d) => d.wearable, { cascade: ["insert"] }) + repairs: repair[]; + @OneToMany(() => maintenance, (m) => m.wearable, { cascade: ["insert"] }) maintenances: maintenance[]; diff --git a/src/factory/admin/unit/damageReport.ts b/src/factory/admin/unit/damageReport.ts index fe6ff61..969593b 100644 --- a/src/factory/admin/unit/damageReport.ts +++ b/src/factory/admin/unit/damageReport.ts @@ -2,6 +2,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 RepairFactory from "./repair"; import VehicleFactory from "./vehicle/vehicle"; import WearableFactory from "./wearable/wearable"; @@ -51,7 +52,7 @@ export default abstract class DamageReportFactory { images: record.images, reportedBy: record?.reportedBy, ...assigned, - maintenance: record.maintenance ? MaintenanceFactory.mapToSingle(record.maintenance) : null, + repair: record.repair ? RepairFactory.mapToSingle(record.repair) : null, }; } diff --git a/src/factory/admin/unit/maintenance.ts b/src/factory/admin/unit/maintenance.ts index 69f4c78..fb5a464 100644 --- a/src/factory/admin/unit/maintenance.ts +++ b/src/factory/admin/unit/maintenance.ts @@ -37,10 +37,8 @@ export default abstract class MaintenanceFactory { id: record.id, createdAt: record.createdAt, status: record.status, - done: record.done, description: record.description, ...assigned, - reports: record.reports ? DamageReportFactory.mapToBase(record.reports) : [], }; } diff --git a/src/factory/admin/unit/repair.ts b/src/factory/admin/unit/repair.ts new file mode 100644 index 0000000..2ff8206 --- /dev/null +++ b/src/factory/admin/unit/repair.ts @@ -0,0 +1,64 @@ +import { repair } from "../../../entity/unit/repair"; +import { RepairAssigned, RepairViewModel } from "../../../viewmodel/admin/unit/repair.models"; +import DamageReportFactory from "./damageReport"; +import EquipmentFactory from "./equipment/equipment"; +import VehicleFactory from "./vehicle/vehicle"; +import WearableFactory from "./wearable/wearable"; + +export default abstract class RepairFactory { + /** + * @description map record to repair + * @param {repair} record + * @returns {RepairViewModel} + */ + public static mapToSingle(record: repair): RepairViewModel { + let assigned: RepairAssigned; + 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 if (record?.wearableId) { + assigned = { + relatedId: record.wearableId, + assigned: "wearable", + related: WearableFactory.mapToSingle(record.wearable), + }; + } else { + assigned = { + relatedId: undefined, + assigned: undefined, + related: undefined, + }; + } + + return { + id: record.id, + createdAt: record.createdAt, + finishedAt: record.finishedAt, + status: record.status, + responsible: record.responsible, + description: record.description, + images: record.images, + reportDocument: record.reportDocument, + reports: record.reports ? DamageReportFactory.mapToBase(record.reports) : [], + ...assigned, + }; + } + + /** + * @description map records to repair + * @param {Array} records + * @returns {Array} + */ + public static mapToBase(records: Array): Array { + return records.map((r) => this.mapToSingle(r)); + } +} diff --git a/src/helpers/backupHelper.ts b/src/helpers/backupHelper.ts index d510f8d..b986cea 100644 --- a/src/helpers/backupHelper.ts +++ b/src/helpers/backupHelper.ts @@ -516,6 +516,7 @@ export default abstract class BackupHelper { wearable: await dataSource.getRepository("wearable").find(), maintenance: await dataSource.getRepository("maintenance").find(), damage_report: await dataSource.getRepository("damage_report").find(), + repair: await dataSource.getRepository("repair").find(), inspection: await dataSource.getRepository("inspection").find(), inspection_point_result: await dataSource.getRepository("inspection_point_result").find(), }; @@ -903,23 +904,26 @@ export default abstract class BackupHelper { await this.transactionManager.getRepository("setting").save(data); } private static async setUnitBase(data: { [key: string]: Array }): Promise { - await this.transactionManager.getRepository("equipment_type").save(data["equipment_type"]); - await this.transactionManager.getRepository("vehicle_type").save(data["vehicle_type"]); - await this.transactionManager.getRepository("wearable_type").save(data["wearable_type"]); + await this.transactionManager.getRepository("equipment_type").save(data["equipment_type"] ?? []); + await this.transactionManager.getRepository("vehicle_type").save(data["vehicle_type"] ?? []); + await this.transactionManager.getRepository("wearable_type").save(data["wearable_type"] ?? []); - await this.transactionManager.getRepository("inspection_plan").save(data["inspection_plan"]); - await this.transactionManager.getRepository("inspection_versioned_plan").save(data["inspection_versioned_plan"]); - await this.transactionManager.getRepository("inspection_point").save(data["inspection_point"]); + await this.transactionManager.getRepository("inspection_plan").save(data["inspection_plan"] ?? []); + await this.transactionManager + .getRepository("inspection_versioned_plan") + .save(data["inspection_versioned_plan"] ?? []); + await this.transactionManager.getRepository("inspection_point").save(data["inspection_point"] ?? []); } private static async setUnitInstances(data: { [key: string]: Array }): Promise { - await this.transactionManager.getRepository("equipment").save(data["equipment"]); - await this.transactionManager.getRepository("vehicle").save(data["vehicle"]); - await this.transactionManager.getRepository("wearable").save(data["wearable"]); + await this.transactionManager.getRepository("equipment").save(data["equipment"] ?? []); + await this.transactionManager.getRepository("vehicle").save(data["vehicle"] ?? []); + await this.transactionManager.getRepository("wearable").save(data["wearable"] ?? []); - await this.transactionManager.getRepository("damage_report").save(data["damage_report"]); - await this.transactionManager.getRepository("maintenance").save(data["maintenance"]); + await this.transactionManager.getRepository("repair").save(data["repair"] ?? []); + await this.transactionManager.getRepository("damage_report").save(data["damage_report"] ?? []); + await this.transactionManager.getRepository("maintenance").save(data["maintenance"] ?? []); - await this.transactionManager.getRepository("inspection").save(data["inspection"]); - await this.transactionManager.getRepository("inspection_point_result").save(data["inspection_point_result"]); + await this.transactionManager.getRepository("inspection").save(data["inspection"] ?? []); + await this.transactionManager.getRepository("inspection_point_result").save(data["inspection_point_result"] ?? []); } } diff --git a/src/migrations/1749361405703-UnitBase.ts b/src/migrations/1752914551204-UnitBase.ts similarity index 90% rename from src/migrations/1749361405703-UnitBase.ts rename to src/migrations/1752914551204-UnitBase.ts index 97c657f..685bf42 100644 --- a/src/migrations/1749361405703-UnitBase.ts +++ b/src/migrations/1752914551204-UnitBase.ts @@ -14,12 +14,12 @@ import { wearable_type_table, wearable_table, } from "./baseSchemaTables/unit"; -import { maintenance_table, damage_report_table } from "./baseSchemaTables/unit_extend"; +import { maintenance_table, damage_report_table, repair_table } from "./baseSchemaTables/unit_extend"; import { availableTemplates } from "../type/templateTypes"; import { template_usage_table } from "./baseSchemaTables/query_template"; -export class UnitBase1749361405703 implements MigrationInterface { - name = "UnitBase1749361405703"; +export class UnitBase1752914551204 implements MigrationInterface { + name = "UnitBase1752914551204"; public async up(queryRunner: QueryRunner): Promise { await queryRunner.createTable(equipment_type_table, true, true, true); @@ -30,6 +30,7 @@ export class UnitBase1749361405703 implements MigrationInterface { await queryRunner.createTable(wearable_table, true, true, true); await queryRunner.createTable(maintenance_table, true, true, true); + await queryRunner.createTable(repair_table, true, true, true); await queryRunner.createTable(damage_report_table, true, true, true); await queryRunner.createTable(inspection_plan_table, true, true, true); @@ -61,6 +62,7 @@ export class UnitBase1749361405703 implements MigrationInterface { await queryRunner.dropTable(inspection_plan_table, true, true, true); await queryRunner.dropTable(damage_report_table, true, true, true); + await queryRunner.dropTable(repair_table, true, true, true); await queryRunner.dropTable(maintenance_table, true, true, true); await queryRunner.dropTable(wearable_table, true, true, true); diff --git a/src/migrations/baseSchemaTables/unit_extend.ts b/src/migrations/baseSchemaTables/unit_extend.ts index 171c808..82eff28 100644 --- a/src/migrations/baseSchemaTables/unit_extend.ts +++ b/src/migrations/baseSchemaTables/unit_extend.ts @@ -17,7 +17,7 @@ export const damage_report_table = new Table({ { name: "equipmentId", ...getTypeByORM("uuid", true) }, { name: "vehicleId", ...getTypeByORM("uuid", true) }, { name: "wearableId", ...getTypeByORM("uuid", true) }, - { name: "maintenanceId", ...getTypeByORM("uuid", true) }, + { name: "repairId", ...getTypeByORM("uuid", true) }, ], foreignKeys: [ new TableForeignKey({ @@ -42,9 +42,9 @@ export const damage_report_table = new Table({ onUpdate: "RESTRICT", }), new TableForeignKey({ - columnNames: ["maintenanceId"], + columnNames: ["repairId"], referencedColumnNames: ["id"], - referencedTableName: "maintenance", + referencedTableName: "repair", onDelete: "SET NULL", onUpdate: "RESTRICT", }), @@ -56,8 +56,8 @@ export const maintenance_table = new Table({ columns: [ { name: "id", ...getTypeByORM("uuid"), ...isUUIDPrimary }, { name: "createdAt", ...getTypeByORM("datetime"), default: getDefaultByORM("currentTimestamp") }, + { name: "finishedAt", ...getTypeByORM("datetime", true) }, { name: "status", ...getTypeByORM("varchar") }, - { name: "done", ...getTypeByORM("boolean"), default: getDefaultByORM("boolean", false) }, { name: "description", ...getTypeByORM("text") }, { name: "equipmentId", ...getTypeByORM("uuid", true) }, { name: "vehicleId", ...getTypeByORM("uuid", true) }, @@ -87,3 +87,43 @@ export const maintenance_table = new Table({ }), ], }); + +export const repair_table = new Table({ + name: "repair", + columns: [ + { name: "id", ...getTypeByORM("uuid"), ...isUUIDPrimary }, + { name: "createdAt", ...getTypeByORM("datetime"), default: getDefaultByORM("currentTimestamp") }, + { name: "finishedAt", ...getTypeByORM("datetime", true) }, + { name: "status", ...getTypeByORM("varchar") }, + { name: "responsible", ...getTypeByORM("varchar") }, + { name: "description", ...getTypeByORM("text") }, + { name: "images", ...getTypeByORM("text") }, + { name: "reportDocument", ...getTypeByORM("varchar") }, + { name: "equipmentId", ...getTypeByORM("uuid", true) }, + { name: "vehicleId", ...getTypeByORM("uuid", true) }, + { name: "wearableId", ...getTypeByORM("uuid", true) }, + ], + 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", + }), + ], +}); diff --git a/src/routes/admin/index.ts b/src/routes/admin/index.ts index 3a6edf2..a3e8b33 100644 --- a/src/routes/admin/index.ts +++ b/src/routes/admin/index.ts @@ -43,6 +43,7 @@ import inspection from "./unit/inspection"; import inspectionPlan from "./unit/inspectionPlan"; import damageReport from "./unit/damageReport"; import maintenance from "./unit/maintenance"; +import repair from "./unit/repair"; var router = express.Router({ mergeParams: true }); @@ -283,5 +284,15 @@ router.use( ]), maintenance ); +router.use( + "/repair", + PermissionHelper.passCheckSomeMiddleware([ + { requiredPermission: "read", section: "unit", module: "repair" }, + { requiredPermission: "read", section: "unit", module: "equipment" }, + { requiredPermission: "read", section: "unit", module: "vehicle" }, + { requiredPermission: "read", section: "unit", module: "wearable" }, + ]), + repair +); export default router; diff --git a/src/routes/admin/unit/repair.ts b/src/routes/admin/unit/repair.ts new file mode 100644 index 0000000..68bd58a --- /dev/null +++ b/src/routes/admin/unit/repair.ts @@ -0,0 +1,52 @@ +import express, { Request, Response } from "express"; +import PermissionHelper from "../../../helpers/permissionHelper"; +import { + createRepair, + getAllRepairsByStatus, + getAllRepairsForRelated, + getRepairById, + updateRepairById, +} from "../../../controller/admin/unit/repairController"; + +var router = express.Router({ mergeParams: true }); + +router.get("/", async (req: Request, res: Response) => { + await getAllRepairsByStatus(req, res); +}); + +router.get( + ["/vehicle/:relatedId", "/equipment/:relatedId", "/wearable/:relatedId"], + async (req: Request, res: Response) => { + if (req.path.startsWith("/vehicle")) { + req.params.related = "vehicle"; + } else if (req.path.startsWith("/equipment")) { + req.params.related = "equipment"; + } else { + req.params.related = "wearable"; + } + + await getAllRepairsForRelated(req, res); + } +); + +router.get("/:id", async (req: Request, res: Response) => { + await getRepairById(req, res); +}); + +router.post( + "/:id", + PermissionHelper.passCheckMiddleware("update", "unit", "inspection"), + async (req: Request, res: Response) => { + await createRepair(req, res); + } +); + +router.patch( + "/:id", + PermissionHelper.passCheckMiddleware("update", "unit", "inspection"), + async (req: Request, res: Response) => { + await updateRepairById(req, res); + } +); + +export default router; diff --git a/src/service/unit/damageReportService.ts b/src/service/unit/damageReportService.ts index 21072c7..85b5e1d 100644 --- a/src/service/unit/damageReportService.ts +++ b/src/service/unit/damageReportService.ts @@ -10,7 +10,7 @@ export default abstract class DamageReportService { .leftJoinAndSelect("damageReport.equipment", "equipment") .leftJoinAndSelect("damageReport.vehicle", "vehicle") .leftJoinAndSelect("damageReport.wearable", "wearable") - .leftJoinAndSelect("damageReport.maintenance", "maintenance"); + .leftJoinAndSelect("damageReport.repair", "repair"); /** * @description get all damageReports By done diff --git a/src/service/unit/maintenanceService.ts b/src/service/unit/maintenanceService.ts index d9d997d..d2917e2 100644 --- a/src/service/unit/maintenanceService.ts +++ b/src/service/unit/maintenanceService.ts @@ -1,3 +1,4 @@ +import { Not, IsNull } from "typeorm"; import { dataSource } from "../../data-source"; import { maintenance } from "../../entity/unit/maintenance"; import DatabaseActionException from "../../exceptions/databaseActionException"; @@ -9,8 +10,7 @@ export default abstract class MaintenanceService { .createQueryBuilder("maintenance") .leftJoinAndSelect("maintenance.equipment", "equipment") .leftJoinAndSelect("maintenance.vehicle", "vehicle") - .leftJoinAndSelect("maintenance.wearable", "wearable") - .leftJoinAndSelect("maintenance.reports", "reports"); + .leftJoinAndSelect("maintenance.wearable", "wearable"); /** * @description get all maintenances @@ -28,7 +28,7 @@ export default abstract class MaintenanceService { noLimit?: boolean; } ): Promise<[Array, number]> { - let query = this.query().where({ done }); + let query = this.query().where({ finishedAt: done ? Not(IsNull()) : IsNull() }); if (!noLimit) { query = query.offset(offset).limit(count); } diff --git a/src/service/unit/repairService.ts b/src/service/unit/repairService.ts new file mode 100644 index 0000000..731b8ad --- /dev/null +++ b/src/service/unit/repairService.ts @@ -0,0 +1,96 @@ +import { IsNull, Not } from "typeorm"; +import { dataSource } from "../../data-source"; +import { repair } from "../../entity/unit/repair"; +import DatabaseActionException from "../../exceptions/databaseActionException"; + +export default abstract class RepairService { + private static query = () => + dataSource + .getRepository(repair) + .createQueryBuilder("repair") + .leftJoinAndSelect("repair.equipment", "equipment") + .leftJoinAndSelect("repair.vehicle", "vehicle") + .leftJoinAndSelect("repair.wearable", "wearable") + .leftJoinAndSelect("repair.reports", "reports"); + + /** + * @description get all repairs + * @returns {Promise<[Array, number]>} + */ + static async getAll( + done = false, + { + offset = 0, + count = 25, + noLimit = false, + }: { + offset?: number; + count?: number; + noLimit?: boolean; + } + ): Promise<[Array, number]> { + let query = this.query().where({ finishedAt: done ? Not(IsNull()) : IsNull() }); + if (!noLimit) { + query = query.offset(offset).limit(count); + } + + return await query + .orderBy("repair.createdAt", "ASC") + .getManyAndCount() + .then((res) => { + return res; + }) + .catch((err) => { + throw new DatabaseActionException("SELECT", "repair", err); + }); + } + + /** + * @description get all repairs By related + * @returns {Promise<[Array, number]>} + */ + static async getAllForRelated( + where: { equipmentId: string } | { vehicleId: string } | { wearableId: string }, + { + offset = 0, + count = 25, + noLimit = false, + }: { + offset?: number; + count?: number; + noLimit?: boolean; + } + ): Promise<[Array, number]> { + let query = this.query().where(where); + + if (!noLimit) { + query = query.offset(offset).limit(count); + } + + return await query + .orderBy("repair.createdAt", "ASC") + .getManyAndCount() + .then((res) => { + return res; + }) + .catch((err) => { + throw new DatabaseActionException("SELECT", "repair", err); + }); + } + + /** + * @description get repair by id + * @returns {Promise} + */ + static async getById(id: string): Promise { + return await this.query() + .where({ id }) + .getOneOrFail() + .then((res) => { + return res; + }) + .catch((err) => { + throw new DatabaseActionException("SELECT", "repair", err); + }); + } +} diff --git a/src/type/permissionTypes.ts b/src/type/permissionTypes.ts index 2442d9f..091c0c3 100644 --- a/src/type/permissionTypes.ts +++ b/src/type/permissionTypes.ts @@ -22,6 +22,7 @@ export type PermissionModule = | "respiratory_mission" | "damage_report" | "maintenance" + | "repair" // configuration | "qualification" | "award" @@ -97,6 +98,7 @@ export const permissionModules: Array = [ "respiratory_mission", "damage_report", "maintenance", + "repair", // configuration "qualification", "award", @@ -134,6 +136,7 @@ export const sectionsAndModules: SectionsAndModulesObject = { "respiratory_mission", "damage_report", "maintenance", + "repair", ], configuration: [ "qualification", diff --git a/src/viewmodel/admin/unit/damageReport.models.ts b/src/viewmodel/admin/unit/damageReport.models.ts index 15b03f2..fc510cf 100644 --- a/src/viewmodel/admin/unit/damageReport.models.ts +++ b/src/viewmodel/admin/unit/damageReport.models.ts @@ -1,5 +1,6 @@ import { EquipmentViewModel } from "./equipment/equipment.models"; import { MaintenanceViewModel } from "./maintenance.models"; +import { RepairViewModel } from "./repair.models"; import { VehicleViewModel } from "./vehicle/vehicle.models"; import { WearableViewModel } from "./wearable/wearable.models"; @@ -31,5 +32,5 @@ export type DamageReportViewModel = { noteByWorker: string; images: string[]; reportedBy: string; - maintenance?: MaintenanceViewModel; + repair?: RepairViewModel; } & DamageReportAssigned; diff --git a/src/viewmodel/admin/unit/maintenance.models.ts b/src/viewmodel/admin/unit/maintenance.models.ts index 98f22f2..7f85029 100644 --- a/src/viewmodel/admin/unit/maintenance.models.ts +++ b/src/viewmodel/admin/unit/maintenance.models.ts @@ -1,4 +1,3 @@ -import { DamageReportViewModel } from "./damageReport.models"; import { EquipmentViewModel } from "./equipment/equipment.models"; import { VehicleViewModel } from "./vehicle/vehicle.models"; import { WearableViewModel } from "./wearable/wearable.models"; @@ -24,7 +23,5 @@ export type MaintenanceViewModel = { id: string; createdAt: Date; status: string; - done: boolean; description: string; - reports: DamageReportViewModel[]; } & MaintenanceAssigned; diff --git a/src/viewmodel/admin/unit/repair.models.ts b/src/viewmodel/admin/unit/repair.models.ts new file mode 100644 index 0000000..044b650 --- /dev/null +++ b/src/viewmodel/admin/unit/repair.models.ts @@ -0,0 +1,33 @@ +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 RepairAssigned = { + relatedId: string; +} & ( + | { + assigned: "equipment"; + related: EquipmentViewModel; + } + | { + assigned: "vehicle"; + related: VehicleViewModel; + } + | { + assigned: "wearable"; + related: WearableViewModel; + } +); + +export type RepairViewModel = { + id: string; + createdAt: Date; + finishedAt?: Date; + status: string; + responsible: string; + description: string; + images: string[]; + reportDocument: string; + reports: DamageReportViewModel[]; +} & RepairAssigned;