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 { dataSource } from "../../data-source";
import { damageReport } from "../../entity/unit/damageReport"; import { damageReport } from "../../entity/unit/damageReport";
import DatabaseActionException from "../../exceptions/databaseActionException"; 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 * @description delete damageReport
* @param {DeleteDamageReportCommand} deleteDamageReport * @param {DeleteDamageReportCommand} deleteDamageReport

View file

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

View file

@ -1,31 +1,46 @@
import { dataSource } from "../../data-source"; import { dataSource } from "../../data-source";
import { repair } from "../../entity/unit/repair"; import { repair } from "../../entity/unit/repair";
import DatabaseActionException from "../../exceptions/databaseActionException"; import DatabaseActionException from "../../exceptions/databaseActionException";
import DamageReportCommandHandler from "./damageReportCommandHandler";
import { CreateRepairCommand, UpdateRepairCommand, DeleteRepairCommand } from "./repairCommand"; import { CreateRepairCommand, UpdateRepairCommand, DeleteRepairCommand } from "./repairCommand";
export default abstract class RepairCommandHandler { export default abstract class RepairCommandHandler {
/** /**
* @description create repair * @description create repair
* @param {CreateRepairCommand} createRepair * @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 return await dataSource
.createQueryBuilder() .transaction(async (manager) => {
.insert() await manager
.into(repair) .createQueryBuilder()
.values({ .insert()
status: "in Arbeit", .into(repair)
description: createRepair.description, .values({
reports: createRepair.reports.map((r) => ({ id: r })), status: "in Arbeit",
responsible: createRepair.responsible, title: createRepair.title,
equipmentId: createRepair.affected == "equipment" ? createRepair.affectedId : null, description: createRepair.description,
vehicleId: createRepair.affected == "vehicle" ? createRepair.affectedId : null, responsible: createRepair.responsible,
wearableId: createRepair.affected == "wearable" ? createRepair.affectedId : null, 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(() => {
.then((result) => { return resultId;
return result.identifiers[0].id;
}) })
.catch((err) => { .catch((err) => {
throw new DatabaseActionException("CREATE", "repair", err); throw new DatabaseActionException("CREATE", "repair", err);
@ -43,6 +58,7 @@ export default abstract class RepairCommandHandler {
.update(repair) .update(repair)
.set({ .set({
status: updateRepair.status, status: updateRepair.status,
title: updateRepair.title,
description: updateRepair.description, description: updateRepair.description,
reports: updateRepair.reports.map((r) => ({ id: r })), reports: updateRepair.reports.map((r) => ({ id: r })),
responsible: updateRepair.responsible, 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 count = parseInt((req.query.count as string) ?? "25");
let noLimit = req.query.noLimit === "true"; 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({ res.json({
damageReports: DamageReportFactory.mapToBase(damageReports), damageReports: DamageReportFactory.mapToBase(damageReports),
@ -72,6 +72,25 @@ export async function getDamageReportById(req: Request, res: Response): Promise<
res.json(DamageReportFactory.mapToSingle(damageReport)); 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 * @description provide uploaded image for damage report
* @param req {Request} Express req object * @param req {Request} Express req object

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,3 +1,4 @@
import { In } from "typeorm";
import { dataSource } from "../../data-source"; import { dataSource } from "../../data-source";
import { damageReport } from "../../entity/unit/damageReport"; import { damageReport } from "../../entity/unit/damageReport";
import DatabaseActionException from "../../exceptions/databaseActionException"; import DatabaseActionException from "../../exceptions/databaseActionException";
@ -11,12 +12,47 @@ export default abstract class DamageReportService {
.leftJoinAndSelect("damageReport.vehicle", "vehicle") .leftJoinAndSelect("damageReport.vehicle", "vehicle")
.leftJoinAndSelect("damageReport.wearable", "wearable") .leftJoinAndSelect("damageReport.wearable", "wearable")
.leftJoinAndSelect("damageReport.repair", "repair"); .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 * @description get all damageReports By done
* @returns {Promise<[Array<damageReport>, number]>} * @returns {Promise<[Array<damageReport>, number]>}
*/ */
static async getAll( static async getAllByStatus(
done = false, done = false,
{ {
offset = 0, offset = 0,

View file

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