unit/#126-repairs #128

Merged
jkeffects merged 5 commits from unit/#126-repairs into milestone/ff-admin-unit 2025-07-23 07:30:08 +00:00
14 changed files with 138 additions and 31 deletions
Showing only changes of commit 2363933f5a - Show all commits

View file

@ -1,3 +1,4 @@
import { EntityManager, UpdateResult } from "typeorm";
import { dataSource } from "../../data-source";
import { damageReport } from "../../entity/unit/damageReport";
import DatabaseActionException from "../../exceptions/databaseActionException";
@ -82,6 +83,25 @@ export default abstract class DamageReportCommandHandler {
});
}
/**
* @description update damageReport related maintenance in transaction
* @param {UpdateDamageReportCommand} updateDamageReport
* @returns {Promise<void>}
*/
static async updateRelatedMaintenanceTransaction(
manager: EntityManager,
updateDamageReport: UpdateDamageReportRelatedRepairCommand
): Promise<UpdateResult> {
return await manager
.createQueryBuilder()
.update(damageReport)
.set({
repairId: updateDamageReport.repairId,
})
.where("id = :id", { id: updateDamageReport.id })
.execute();
}
/**
* @description delete damageReport
* @param {DeleteDamageReportCommand} deleteDamageReport

View file

@ -1,4 +1,5 @@
export interface CreateRepairCommand {
title: string;
description: string;
responsible: string;
affectedId: string;
@ -9,6 +10,7 @@ export interface CreateRepairCommand {
export interface UpdateRepairCommand {
id: string;
status: string;
title: string;
description: string;
responsible: string;
reports: string[];

View file

@ -1,31 +1,46 @@
import { dataSource } from "../../data-source";
import { repair } from "../../entity/unit/repair";
import DatabaseActionException from "../../exceptions/databaseActionException";
import DamageReportCommandHandler from "./damageReportCommandHandler";
import { CreateRepairCommand, UpdateRepairCommand, DeleteRepairCommand } from "./repairCommand";
export default abstract class RepairCommandHandler {
/**
* @description create repair
* @param {CreateRepairCommand} createRepair
* @returns {Promise<number>}
* @returns {Promise<string>}
*/
static async create(createRepair: CreateRepairCommand): Promise<number> {
static async create(createRepair: CreateRepairCommand): Promise<string> {
let resultId = "";
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,
.transaction(async (manager) => {
await manager
.createQueryBuilder()
.insert()
.into(repair)
.values({
status: "in Arbeit",
title: createRepair.title,
description: createRepair.description,
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) => {
resultId = result.identifiers[0].id;
});
for (const report of createRepair.reports) {
await DamageReportCommandHandler.updateRelatedMaintenanceTransaction(manager, {
id: report,
repairId: resultId,
});
}
})
.execute()
.then((result) => {
return result.identifiers[0].id;
.then(() => {
return resultId;
})
.catch((err) => {
throw new DatabaseActionException("CREATE", "repair", err);
@ -43,6 +58,7 @@ export default abstract class RepairCommandHandler {
.update(repair)
.set({
status: updateRepair.status,
title: updateRepair.title,
description: updateRepair.description,
reports: updateRepair.reports.map((r) => ({ id: r })),
responsible: updateRepair.responsible,

View file

@ -18,7 +18,7 @@ export async function getAllDamageReportsByStatus(req: Request, res: Response):
let count = parseInt((req.query.count as string) ?? "25");
let noLimit = req.query.noLimit === "true";
let [damageReports, total] = await DamageReportService.getAll(done, { offset, count, noLimit });
let [damageReports, total] = await DamageReportService.getAllByStatus(done, { offset, count, noLimit });
res.json({
damageReports: DamageReportFactory.mapToBase(damageReports),
@ -72,6 +72,25 @@ export async function getDamageReportById(req: Request, res: Response): Promise<
res.json(DamageReportFactory.mapToSingle(damageReport));
}
/**
* @description get reports by Ids
* @param req {Request} Express req object
* @param res {Response} Express res object
* @returns {Promise<*>}
*/
export async function getDamageReportsByIds(req: Request, res: Response): Promise<any> {
let ids = req.body.ids as Array<string>;
let [damageReports, total] = await DamageReportService.getAll({ noLimit: true, ids });
res.json({
damageReports: DamageReportFactory.mapToBase(damageReports),
total: total,
offset: 0,
count: total,
});
}
/**
* @description provide uploaded image for damage report
* @param req {Request} Express req object

View file

@ -79,6 +79,7 @@ export async function getRepairById(req: Request, res: Response): Promise<any> {
* @returns {Promise<*>}
*/
export async function createRepair(req: Request, res: Response): Promise<any> {
const title = req.body.title;
const description = req.body.description;
const responsible = req.body.responsible;
const reports = req.body.reports;
@ -89,6 +90,7 @@ export async function createRepair(req: Request, res: Response): Promise<any> {
throw new BadRequestException("set assigned to equipment or vehicle or wearable");
let createRepair: CreateRepairCommand = {
title,
description,
affectedId,
affected,
@ -109,6 +111,7 @@ export async function createRepair(req: Request, res: Response): Promise<any> {
export async function updateRepairById(req: Request, res: Response): Promise<any> {
const repairId = req.params.id;
const status = req.body.status;
const title = req.body.title;
const description = req.body.description;
const responsible = req.body.responsible;
const reports = req.body.reports;
@ -116,6 +119,7 @@ export async function updateRepairById(req: Request, res: Response): Promise<any
let updateRepair: UpdateRepairCommand = {
id: repairId,
status,
title,
description,
responsible,
reports,

View file

@ -39,7 +39,7 @@ export class damageReport {
from(value: string): Array<string> {
return (value ?? "").split(",").filter((i) => !!i);
},
to(value: Array<string>): string {
to(value: Array<string> = []): string {
return value.join(",");
},
},

View file

@ -22,6 +22,9 @@ export class repair {
@Column({ type: "varchar", length: 255 })
responsible: string;
@Column({ type: "varchar", length: 255 })
title: string;
@Column({ type: "text" })
description: string;
@ -31,15 +34,15 @@ export class repair {
from(value: string): Array<string> {
return (value ?? "").split(",").filter((i) => !!i);
},
to(value: Array<string>): string {
to(value: Array<string> = []): string {
return value.join(",");
},
},
})
images: string[];
@Column({ type: "varchar", length: 255 })
reportDocument: string;
@Column({ type: "varchar", length: 255, nullable: true, default: null })
reportDocument?: string;
@Column({ nullable: true, default: null })
equipmentId?: string;

View file

@ -18,19 +18,19 @@ export default abstract class DamageReportFactory {
assigned = {
relatedId: record.equipmentId,
assigned: "equipment",
related: EquipmentFactory.mapToSingle(record.equipment),
related: record.equipment ? EquipmentFactory.mapToSingle(record.equipment) : undefined,
};
} else if (record?.vehicleId) {
assigned = {
relatedId: record.vehicleId,
assigned: "vehicle",
related: VehicleFactory.mapToSingle(record.vehicle),
related: record.vehicle ? VehicleFactory.mapToSingle(record.vehicle) : undefined,
};
} else if (record?.wearableId) {
assigned = {
relatedId: record.wearableId,
assigned: "wearable",
related: WearableFactory.mapToSingle(record.wearable),
related: record.wearable ? WearableFactory.mapToSingle(record.wearable) : undefined,
};
} else {
assigned = {

View file

@ -17,19 +17,19 @@ export default abstract class RepairFactory {
assigned = {
relatedId: record.equipmentId,
assigned: "equipment",
related: EquipmentFactory.mapToSingle(record.equipment),
related: record.equipment ? EquipmentFactory.mapToSingle(record.equipment) : undefined,
};
} else if (record?.vehicleId) {
assigned = {
relatedId: record.vehicleId,
assigned: "vehicle",
related: VehicleFactory.mapToSingle(record.vehicle),
related: record.vehicle ? VehicleFactory.mapToSingle(record.vehicle) : undefined,
};
} else if (record?.wearableId) {
assigned = {
relatedId: record.wearableId,
assigned: "wearable",
related: WearableFactory.mapToSingle(record.wearable),
related: record.wearable ? WearableFactory.mapToSingle(record.wearable) : undefined,
};
} else {
assigned = {
@ -45,6 +45,7 @@ export default abstract class RepairFactory {
finishedAt: record.finishedAt,
status: record.status,
responsible: record.responsible,
title: record.title,
description: record.description,
images: record.images,
reportDocument: record.reportDocument,

View file

@ -99,7 +99,7 @@ export const repair_table = new Table({
{ name: "responsible", ...getTypeByORM("varchar") },
{ name: "description", ...getTypeByORM("text") },
{ name: "images", ...getTypeByORM("text") },
{ name: "reportDocument", ...getTypeByORM("varchar") },
{ name: "reportDocument", ...getTypeByORM("varchar", true) },
{ name: "equipmentId", ...getTypeByORM("uuid", true) },
{ name: "vehicleId", ...getTypeByORM("uuid", true) },
{ name: "wearableId", ...getTypeByORM("uuid", true) },

View file

@ -11,6 +11,7 @@ import {
getAllDamageReportsByStatus,
getAllDamageReportsForRelated,
getDamageReportById,
getDamageReportsByIds,
provideDamageReportImageUpload,
updateDamageReportById,
} from "../../../controller/admin/unit/damageReportController";
@ -40,6 +41,10 @@ router.get("/:id", async (req: Request, res: Response) => {
await getDamageReportById(req, res);
});
router.post("/ids", async (req: Request, res: Response) => {
await getDamageReportsByIds(req, res);
});
router.get("/:id/:filename", async (req: Request, res: Response) => {
await provideDamageReportImageUpload(req, res);
});

View file

@ -34,7 +34,7 @@ router.get("/:id", async (req: Request, res: Response) => {
});
router.post(
"/:id",
"/",
PermissionHelper.passCheckMiddleware("update", "unit", "inspection"),
async (req: Request, res: Response) => {
await createRepair(req, res);

View file

@ -1,3 +1,4 @@
import { In } from "typeorm";
import { dataSource } from "../../data-source";
import { damageReport } from "../../entity/unit/damageReport";
import DatabaseActionException from "../../exceptions/databaseActionException";
@ -11,12 +12,47 @@ export default abstract class DamageReportService {
.leftJoinAndSelect("damageReport.vehicle", "vehicle")
.leftJoinAndSelect("damageReport.wearable", "wearable")
.leftJoinAndSelect("damageReport.repair", "repair");
/**
* @description get all damageReports By done
* @returns {Promise<[Array<damageReport>, number]>}
*/
static async getAll({
offset = 0,
count = 25,
noLimit = false,
ids = [],
}: {
offset?: number;
count?: number;
noLimit?: boolean;
ids?: Array<string>;
}): Promise<[Array<damageReport>, number]> {
let query = this.query();
if (ids.length != 0) {
query = query.where({ id: In(ids) });
}
if (!noLimit) {
query = query.offset(offset).limit(count);
}
return await query
.orderBy("damageReport.reportedAt", "ASC")
.getManyAndCount()
.then((res) => {
return res;
})
.catch((err) => {
throw new DatabaseActionException("SELECT", "damageReport", err);
});
}
/**
* @description get all damageReports By done
* @returns {Promise<[Array<damageReport>, number]>}
*/
static async getAll(
static async getAllByStatus(
done = false,
{
offset = 0,

View file

@ -26,8 +26,9 @@ export type RepairViewModel = {
finishedAt?: Date;
status: string;
responsible: string;
title: string;
description: string;
images: string[];
reportDocument: string;
reportDocument?: string;
reports: DamageReportViewModel[];
} & RepairAssigned;