next and running inspections

This commit is contained in:
Julian Krauser 2025-07-10 13:22:29 +02:00
parent 8747baaf2e
commit 705297ba50
6 changed files with 142 additions and 7 deletions

View file

@ -3,7 +3,7 @@ export interface CreateInspectionCommand {
nextInspection?: Date; nextInspection?: Date;
inspectionPlanId: string; inspectionPlanId: string;
relatedId: string; relatedId: string;
assigned: "vehicle" | "equipment"; assigned: "vehicle" | "equipment" | "wearable";
} }
export interface UpdateInspectionCommand { export interface UpdateInspectionCommand {

View file

@ -1,4 +1,4 @@
import { Not } from "typeorm"; import { IsNull, Not } from "typeorm";
import { dataSource } from "../../../data-source"; import { dataSource } from "../../../data-source";
import { inspection } from "../../../entity/unit/inspection/inspection"; import { inspection } from "../../../entity/unit/inspection/inspection";
import DatabaseActionException from "../../../exceptions/databaseActionException"; import DatabaseActionException from "../../../exceptions/databaseActionException";
@ -25,6 +25,12 @@ export default abstract class InspectionCommandHandler {
.set({ .set({
hasNewer: true, hasNewer: true,
}) })
.where({
inspectionPlanId: createInspection.inspectionPlanId,
equipmentId: createInspection.assigned == "equipment" ? createInspection.relatedId : IsNull(),
vehicleId: createInspection.assigned == "vehicle" ? createInspection.relatedId : IsNull(),
wearableId: createInspection.assigned == "wearable" ? createInspection.relatedId : IsNull(),
})
.execute(); .execute();
await manager await manager
@ -38,6 +44,7 @@ export default abstract class InspectionCommandHandler {
inspectionVersionedPlanId: latestVersionedPlan.id, inspectionVersionedPlanId: latestVersionedPlan.id,
equipmentId: createInspection.assigned == "equipment" ? createInspection.relatedId : null, equipmentId: createInspection.assigned == "equipment" ? createInspection.relatedId : null,
vehicleId: createInspection.assigned == "vehicle" ? createInspection.relatedId : null, vehicleId: createInspection.assigned == "vehicle" ? createInspection.relatedId : null,
wearableId: createInspection.assigned == "wearable" ? createInspection.relatedId : null,
}) })
.execute() .execute()
.then((result) => { .then((result) => {

View file

@ -24,7 +24,7 @@ export async function getAllInspectionsSortedNotHavingNewer(req: Request, res: R
let [inspections, total] = await InspectionService.getAllSortedNotHavingNewer({ offset, count, noLimit }); let [inspections, total] = await InspectionService.getAllSortedNotHavingNewer({ offset, count, noLimit });
res.json({ res.json({
inspections: InspectionFactory.mapToBase(inspections), inspections: InspectionFactory.mapToBaseNext(inspections),
total: total, total: total,
offset: offset, offset: offset,
count: count, count: count,
@ -45,7 +45,7 @@ export async function getAllInspectionsRunning(req: Request, res: Response): Pro
let [inspections, total] = await InspectionService.getAllRunning({ offset, count, noLimit }); let [inspections, total] = await InspectionService.getAllRunning({ offset, count, noLimit });
res.json({ res.json({
inspections: InspectionFactory.mapToBase(inspections), inspections: InspectionFactory.mapToBaseMinified(inspections),
total: total, total: total,
offset: offset, offset: offset,
count: count, count: count,
@ -112,6 +112,13 @@ export async function createInspection(req: Request, res: Response): Promise<any
if (assigned != "equipment" && assigned != "vehicle" && assigned != "wearable") if (assigned != "equipment" && assigned != "vehicle" && assigned != "wearable")
throw new BadRequestException("set assigned to equipment or vehicle or wearable"); throw new BadRequestException("set assigned to equipment or vehicle or wearable");
let existsUnfinished = await InspectionService.existsUnfinishedInspectionToPlan(
inspectionPlanId,
assigned,
relatedId
);
if (existsUnfinished) throw new ForbiddenRequestException("there is already an unfinished inspection existing");
let createInspection: CreateInspectionCommand = { let createInspection: CreateInspectionCommand = {
context, context,
nextInspection, nextInspection,

View file

@ -1,5 +1,10 @@
import { inspection } from "../../../../entity/unit/inspection/inspection"; import { inspection } from "../../../../entity/unit/inspection/inspection";
import { InspectionRelated, InspectionViewModel } from "../../../../viewmodel/admin/unit/inspection/inspection.models"; import {
InspectionNextViewModel,
InspectionRelated,
InspectionViewModel,
MinifiedInspectionViewModel,
} from "../../../../viewmodel/admin/unit/inspection/inspection.models";
import EquipmentFactory from "../equipment/equipment"; import EquipmentFactory from "../equipment/equipment";
import VehicleFactory from "../vehicle/vehicle"; import VehicleFactory from "../vehicle/vehicle";
import WearableFactory from "../wearable/wearable"; import WearableFactory from "../wearable/wearable";
@ -13,7 +18,7 @@ export default abstract class InspectionFactory {
* @param {inspection} record * @param {inspection} record
* @returns {InspectionViewModel} * @returns {InspectionViewModel}
*/ */
public static mapToSingle(record: inspection): InspectionViewModel { public static mapRelated(record: inspection): InspectionRelated {
let related: InspectionRelated; let related: InspectionRelated;
if (record?.equipmentId) { if (record?.equipmentId) {
related = { related = {
@ -34,6 +39,16 @@ export default abstract class InspectionFactory {
related: WearableFactory.mapToSingle(record.wearable), related: WearableFactory.mapToSingle(record.wearable),
}; };
} }
return related;
}
/**
* @description map record to inspection
* @param {inspection} record
* @returns {InspectionViewModel}
*/
public static mapToSingle(record: inspection): InspectionViewModel {
let related = this.mapRelated(record);
return { return {
id: record.id, id: record.id,
@ -59,4 +74,60 @@ export default abstract class InspectionFactory {
public static mapToBase(records: Array<inspection>): Array<InspectionViewModel> { public static mapToBase(records: Array<inspection>): Array<InspectionViewModel> {
return records.map((r) => this.mapToSingle(r)); return records.map((r) => this.mapToSingle(r));
} }
/**
* @description map record to minified inspection
* @param {inspection} record
* @returns {MinifiedInspectionViewModel}
*/
public static mapToSingleMinified(record: inspection): MinifiedInspectionViewModel {
let related = this.mapRelated(record);
return {
id: record.id,
inspectionPlanId: record.inspectionPlanId,
inspectionPlan: InspectionPlanFactory.mapToSingle(record.inspectionPlan),
context: record.context,
created: record.createdAt,
finished: record?.finishedAt,
isOpen: record?.finishedAt == undefined,
nextInspection: record?.nextInspection,
...related,
};
}
/**
* @description map records to minified inspection
* @param {Array<inspection>} records
* @returns {Array<MinifiedInspectionViewModel>}
*/
public static mapToBaseMinified(records: Array<inspection>): Array<MinifiedInspectionViewModel> {
return records.map((r) => this.mapToSingleMinified(r));
}
/**
* @description map record to next inspection
* @param {inspection} record
* @returns {InspectionNextViewModel}
*/
public static mapToSingleNext(record: inspection): InspectionNextViewModel {
let related = this.mapRelated(record);
return {
id: record.id,
inspectionPlanId: record.inspectionPlanId,
inspectionPlan: InspectionPlanFactory.mapToSingle(record.inspectionPlan),
dueDate: record?.nextInspection,
...related,
};
}
/**
* @description map records to next inspection
* @param {Array<inspection>} records
* @returns {Array<InspectionNextViewModel>}
*/
public static mapToBaseNext(records: Array<inspection>): Array<InspectionNextViewModel> {
return records.map((r) => this.mapToSingleNext(r));
}
} }

View file

@ -1,4 +1,4 @@
import { IsNull } from "typeorm"; import { IsNull, Not } from "typeorm";
import { dataSource } from "../../../data-source"; import { dataSource } from "../../../data-source";
import { inspection } from "../../../entity/unit/inspection/inspection"; import { inspection } from "../../../entity/unit/inspection/inspection";
import DatabaseActionException from "../../../exceptions/databaseActionException"; import DatabaseActionException from "../../../exceptions/databaseActionException";
@ -129,6 +129,36 @@ export default abstract class InspectionService {
}); });
} }
/**
* @description uses versionedPlan
* @returns {Promise<boolean>}
*/
static async existsUnfinishedInspectionToPlan(
inspectionPlanId: string,
relation: "vehicle" | "equipment" | "wearable",
relationId: string
): Promise<boolean> {
let where: { equipmentId: string } | { vehicleId: string } | { wearableId: string };
if (relation == "equipment") {
where = { equipmentId: relationId };
} else if (relation == "vehicle") {
where = { vehicleId: relationId };
} else {
where = { wearableId: relationId };
}
return await dataSource
.getRepository(inspection)
.createQueryBuilder("inspection")
.where({ inspectionPlanId, finishedAt: IsNull(), ...where })
.getExists()
.then((res) => {
return res;
})
.catch((err) => {
throw new DatabaseActionException("SELECT", "used inspection", err);
});
}
/** /**
* @description uses versionedPlan * @description uses versionedPlan
* @returns {Promise<boolean>} * @returns {Promise<boolean>}

View file

@ -38,6 +38,26 @@ export type InspectionViewModel = {
checks: Array<InspectionPointResultViewModel>; checks: Array<InspectionPointResultViewModel>;
} & InspectionRelated; } & InspectionRelated;
export type MinifiedInspectionViewModel = {
id: string;
inspectionPlanId: string;
inspectionPlan: InspectionPlanViewModel;
context: string;
created: Date;
finished?: Date;
isOpen: boolean;
nextInspection?: Date;
relatedId: string;
} & InspectionRelated;
export type InspectionNextViewModel = {
id: string;
inspectionPlanId: string;
inspectionPlan: InspectionPlanViewModel;
dueDate: Date;
relatedId: string;
} & InspectionRelated;
export interface InspectionPointResultViewModel { export interface InspectionPointResultViewModel {
inspectionId: string; inspectionId: string;
inspectionPointId: string; inspectionPointId: string;