diff --git a/src/command/unit/inspection/inspectionCommandHandler.ts b/src/command/unit/inspection/inspectionCommandHandler.ts index 5f4a61d..34b7bf5 100644 --- a/src/command/unit/inspection/inspectionCommandHandler.ts +++ b/src/command/unit/inspection/inspectionCommandHandler.ts @@ -1,6 +1,8 @@ +import { Not } from "typeorm"; import { dataSource } from "../../../data-source"; import { inspection } from "../../../entity/unit/inspection/inspection"; import DatabaseActionException from "../../../exceptions/databaseActionException"; +import InspectionService from "../../../service/unit/inspection/inspectionService"; import InspectionVersionedPlanService from "../../../service/unit/inspection/inspectionVersionedPlanService"; import { CreateInspectionCommand, UpdateInspectionCommand, DeleteInspectionCommand } from "./inspectionCommand"; @@ -8,27 +10,42 @@ export default abstract class InspectionCommandHandler { /** * @description create inspection * @param {CreateInspectionCommand} createInspection - * @returns {Promise} + * @returns {Promise} */ - static async create(createInspection: CreateInspectionCommand): Promise { + static async create(createInspection: CreateInspectionCommand): Promise { let latestVersionedPlan = await InspectionVersionedPlanService.getLatestForInspectionPlan( createInspection.inspectionPlanId ); + let insertId = ""; return await dataSource - .createQueryBuilder() - .insert() - .into(inspection) - .values({ - context: createInspection.context, - nextInspection: createInspection.nextInspection, - inspectionPlanId: createInspection.inspectionPlanId, - inspectionVersionedPlanId: latestVersionedPlan.id, - equipmentId: createInspection.assigned == "equipment" ? createInspection.relatedId : null, - vehicleId: createInspection.assigned == "vehicle" ? createInspection.relatedId : null, + .transaction(async (manager) => { + await manager + .createQueryBuilder() + .update(inspection) + .set({ + hasNewer: true, + }) + .execute(); + + await manager + .createQueryBuilder() + .insert() + .into(inspection) + .values({ + context: createInspection.context, + nextInspection: createInspection.nextInspection, + inspectionPlanId: createInspection.inspectionPlanId, + inspectionVersionedPlanId: latestVersionedPlan.id, + equipmentId: createInspection.assigned == "equipment" ? createInspection.relatedId : null, + vehicleId: createInspection.assigned == "vehicle" ? createInspection.relatedId : null, + }) + .execute() + .then((result) => { + insertId = result.identifiers[0].id; + }); }) - .execute() - .then((result) => { - return result.identifiers[0].id; + .then(() => { + return insertId; }) .catch((err) => { throw new DatabaseActionException("CREATE", "inspection", err); @@ -62,12 +79,42 @@ export default abstract class InspectionCommandHandler { * @returns {Promise} */ static async delete(deleteInspection: DeleteInspectionCommand): Promise { + let deleteInspectionData = await InspectionService.getById(deleteInspection.id); return await dataSource - .createQueryBuilder() - .delete() - .from(inspection) - .where("id = :id", { id: deleteInspection.id }) - .execute() + .transaction(async (manager) => { + await manager + .createQueryBuilder() + .update(inspection) + .set({ + hasNewer: false, + }) + .where((qb) => { + const subQuery = qb + .createQueryBuilder() + .select("id") + .from(inspection, "sub") + .where({ + inspectionPlanId: deleteInspectionData.inspectionPlanId, + inspectionVersionedPlanId: deleteInspectionData.inspectionVersionedPlanId, + equipmentId: deleteInspectionData.equipmentId, + vehicleId: deleteInspectionData.vehicleId, + wearableId: deleteInspectionData.wearableId, + }) + .andWhere({ id: Not(deleteInspection.id) }) + .orderBy("sub.createdAt", "DESC") + .limit(1) + .getQuery(); + return "id = " + subQuery; + }) + .execute(); + + await manager + .createQueryBuilder() + .delete() + .from(inspection) + .where("id = :id", { id: deleteInspection.id }) + .execute(); + }) .then(() => {}) .catch((err) => { throw new DatabaseActionException("DELETE", "inspection", err); diff --git a/src/controller/admin/unit/inspectionController.ts b/src/controller/admin/unit/inspectionController.ts index e7d3dce..f98f4c5 100644 --- a/src/controller/admin/unit/inspectionController.ts +++ b/src/controller/admin/unit/inspectionController.ts @@ -8,6 +8,49 @@ import { } from "../../../command/unit/inspection/inspectionCommand"; import InspectionCommandHandler from "../../../command/unit/inspection/inspectionCommandHandler"; import BadRequestException from "../../../exceptions/badRequestException"; +import ForbiddenRequestException from "../../../exceptions/forbiddenRequestException"; + +/** + * @description get all inspections sorted by id not having newer inspection + * @param req {Request} Express req object + * @param res {Response} Express res object + * @returns {Promise<*>} + */ +export async function getAllInspectionsSortedNotHavingNewer(req: Request, res: Response): Promise { + 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 [inspections, total] = await InspectionService.getAllSortedNotHavingNewer({ offset, count, noLimit }); + + res.json({ + inspections: InspectionFactory.mapToBase(inspections), + total: total, + offset: offset, + count: count, + }); +} + +/** + * @description get all inspections running + * @param req {Request} Express req object + * @param res {Response} Express res object + * @returns {Promise<*>} + */ +export async function getAllInspectionsRunning(req: Request, res: Response): Promise { + 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 [inspections, total] = await InspectionService.getAllRunning({ offset, count, noLimit }); + + res.json({ + inspections: InspectionFactory.mapToBase(inspections), + total: total, + offset: offset, + count: count, + }); +} /** * @description get all inspections for related id @@ -111,7 +154,10 @@ export async function updateInspectionById(req: Request, res: Response): Promise export async function deleteInspectionById(req: Request, res: Response): Promise { const inspectionId = req.params.id; - // TODO finished inspection cannot be deleted + let deleteInspectionData = await InspectionService.getById(inspectionId); + if (deleteInspectionData.finishedAt != null) { + throw new ForbiddenRequestException("Cannot delete as inspection is already finished"); + } let deleteInspection: DeleteInspectionCommand = { id: inspectionId, diff --git a/src/entity/unit/inspection/inspection.ts b/src/entity/unit/inspection/inspection.ts index 16aae27..f49b92d 100644 --- a/src/entity/unit/inspection/inspection.ts +++ b/src/entity/unit/inspection/inspection.ts @@ -24,6 +24,9 @@ export class inspection { @Column({ type: getTypeByORM("date").type as ColumnType, nullable: true, default: null }) nextInspection?: Date; + @Column({ type: "boolean", default: false }) + hasNewer: boolean; + @Column() inspectionPlanId: string; diff --git a/src/migrations/baseSchemaTables/inspection.ts b/src/migrations/baseSchemaTables/inspection.ts index 2b827fc..87af919 100644 --- a/src/migrations/baseSchemaTables/inspection.ts +++ b/src/migrations/baseSchemaTables/inspection.ts @@ -94,6 +94,7 @@ export const inspection_table = new Table({ { name: "createdAt", ...getTypeByORM("datetime"), default: getDefaultByORM("currentTimestamp") }, { name: "finishedAt", ...getTypeByORM("date", true) }, { name: "nextInspection", ...getTypeByORM("date", true) }, + { name: "hasNewer", ...getTypeByORM("boolean"), default: getDefaultByORM("boolean", false) }, { name: "inspectionPlanId", ...getTypeByORM("uuid") }, { name: "inspectionVersionedPlanId", ...getTypeByORM("uuid") }, { name: "equipmentId", ...getTypeByORM("uuid", true) }, diff --git a/src/routes/admin/unit/inspection.ts b/src/routes/admin/unit/inspection.ts index 41694ea..57f6883 100644 --- a/src/routes/admin/unit/inspection.ts +++ b/src/routes/admin/unit/inspection.ts @@ -3,13 +3,23 @@ import PermissionHelper from "../../../helpers/permissionHelper"; import { createInspection, deleteInspectionById, + getAllInspectionsSortedNotHavingNewer, getAllInspectionsForRelated, getInspectionById, updateInspectionById, + getAllInspectionsRunning, } from "../../../controller/admin/unit/inspectionController"; var router = express.Router({ mergeParams: true }); +router.get("/next", async (req: Request, res: Response) => { + await getAllInspectionsSortedNotHavingNewer(req, res); +}); + +router.get("/running", async (req: Request, res: Response) => { + await getAllInspectionsRunning(req, res); +}); + router.get( ["/vehicle/:relatedId", "/equipment/:relatedId", "/wearable/:relatedId"], async (req: Request, res: Response) => { diff --git a/src/service/unit/inspection/inspectionService.ts b/src/service/unit/inspection/inspectionService.ts index c4c8b1d..7de9af8 100644 --- a/src/service/unit/inspection/inspectionService.ts +++ b/src/service/unit/inspection/inspectionService.ts @@ -1,3 +1,4 @@ +import { IsNull } from "typeorm"; import { dataSource } from "../../../data-source"; import { inspection } from "../../../entity/unit/inspection/inspection"; import DatabaseActionException from "../../../exceptions/databaseActionException"; @@ -16,6 +17,66 @@ export default abstract class InspectionService { .leftJoinAndSelect("inspection.vehicle", "vehicle") .leftJoinAndSelect("inspection.wearable", "wearable"); + /** + * @description get all inspections sorted by next inspection not having newer + * @returns {Promise>} + */ + static async getAllSortedNotHavingNewer({ + offset = 0, + count = 25, + noLimit = false, + }: { + offset?: number; + count?: number; + noLimit?: boolean; + }): Promise<[Array, number]> { + let query = this.query().where({ hasNewer: false }); + + if (!noLimit) { + query = query.offset(offset).limit(count); + } + + return await query + .orderBy("inspection.nextInspection", "ASC", "NULLS LAST") + .getManyAndCount() + .then((res) => { + return res; + }) + .catch((err) => { + throw new DatabaseActionException("SELECT", "inspection", err); + }); + } + + /** + * @description get all inspections running + * @returns {Promise>} + */ + static async getAllRunning({ + offset = 0, + count = 25, + noLimit = false, + }: { + offset?: number; + count?: number; + noLimit?: boolean; + }): Promise<[Array, number]> { + let query = this.query().where({ finishedAt: IsNull() }); + + if (!noLimit) { + query = query.offset(offset).limit(count); + } + + return await query + .orderBy("inspection.createdAt", "ASC") + .getManyAndCount() + .then((res) => { + return res; + }) + .catch((err) => { + throw new DatabaseActionException("SELECT", "inspection", err); + }); + } + /** * @description get all inspections for related * @returns {Promise>}