diff --git a/src/controllers/inpatient_room_bed.ts b/src/controllers/inpatient_room_bed.ts new file mode 100644 index 0000000..ee96174 --- /dev/null +++ b/src/controllers/inpatient_room_bed.ts @@ -0,0 +1,304 @@ +import { Paging, InpatientRoom, InpatientRoomBed, InpatientRoomBedDetail } from "entity"; +import { NextFunction, Response } from "express"; +import { Request } from "express-jwt"; +import Joi from "joi"; +import { ILogObj, Logger } from "tslog"; +import CommonHelper from "../helpers/common"; +import { ReturnHelper } from "../helpers/express/return"; +import { OrmHelper } from "../helpers/orm"; +import { Language } from "../langs/lang"; +import { InpatientRoomModel } from "../model/inpatient_room"; +import { InpatientRoomBedModel } from "../model/inpatient_room_beds"; + +const log: Logger = new Logger({ + name: "[InpatientRoomBedController]", + type: "pretty", +}); + +export class InpatientRoomBedController { + static async list(req: Request, res: Response, next: NextFunction): Promise { + /* + #swagger.tags = ['Inpatient Room - Bed'] + #swagger.security = [{ + "bearerAuth": [] + }] + #swagger.parameters['filter'] = { + descriptionk:'', + in: 'query', + type: 'string' + } + #swagger.parameters['limit'] = { + in: 'query', + required: true, + type: 'number' + } + #swagger.parameters['page'] = { + in: 'query', + required: true, + type: 'number' + } + #swagger.parameters['with_deleted'] = { + in: 'query', + required: true, + type: 'boolean' + } + #swagger.parameters['order_field'] = { + in: 'query', + required: true, + type: 'string' + } + #swagger.parameters['order_direction'] = { + in: 'query', + required: true, + schema: { + '@enum': ['ASC', 'DESC'] + } + } + */ + + try { + const schema = Joi.object().keys({ + filter: Joi.string().allow("").optional().label("Filter"), + page: Joi.number().required().min(1).label("Page"), + limit: Joi.number().required().min(1).label("Limit"), + with_deleted: Joi.bool().required().label("With Deleted"), + order_field: Joi.string().required().label("Order Field"), + order_direction: Joi.string().allow("asc", "desc", "ASC", "DESC").required().label("Order Direction"), + }); + + const param: Paging = await schema.validateAsync(req.query); + const offset = (param.page - 1) * param.limit; + const filter = param.filter && param.filter !== "" ? JSON.parse(param.filter) : {}; + const query = await InpatientRoomBedModel.list(filter); + const limit = param.limit; + + const res_count = query; + const res_list = query + .leftJoinAndSelect("InpatientRoomBed.inpatient_room", "inpatient_room") + .leftJoinAndSelect("inpatient_room.room", "room") + .leftJoinAndSelect("room.serviceclass", "service_class") + .leftJoinAndMapOne( + "InpatientRoomBed.bed_detail", + InpatientRoomBedDetail, + "bed_detail", + "bed_detail.inpatientRoomBedId = InpatientRoomBed.id", + ) + .orderBy("InpatientRoomBed." + param.order_field, param.order_direction as "ASC" | "DESC") + .offset(offset) + .limit(limit); + + if (param.with_deleted) { + res_count.withDeleted(); + res_list.withDeleted(); + } + + const current_page = param.page; + const total_count_data = await res_count.getCount(); + const list_data = await res_list.getMany(); + const count_data = CommonHelper.countObject(list_data); + + return ReturnHelper.successResponselist(res, 200, Language.lang.success_view, count_data, current_page, total_count_data, list_data); + } catch (e: unknown) { + log.error(e); + const err = e as Error; + + return ReturnHelper.errorResponse(res, 400, 401, Language.lang.failed_view, err.message); + } + } + + static async detail(req: Request, res: Response, next: NextFunction): Promise { + /* + #swagger.tags = ['Inpatient Room - Bed'] + #swagger.security = [{ + "bearerAuth": [] + }] + #swagger.parameters['id'] = { + in: 'path', + description: 'Inpatient Room Bed ID.', + required: true, + type: 'string' + } + */ + + try { + const schema = Joi.object().keys({ + id: Joi.string().uuid().required().label("ID"), + }); + + let param: any = await schema.validateAsync(req.params); + + let data = await InpatientRoomBedModel.list({ "InpatientRoomBed.id": param.id }).then((q) => + q // + .leftJoinAndSelect("InpatientRoomBed.inpatient_room", "inpatient_room") + .leftJoinAndSelect("inpatient_room.room", "room") + .leftJoinAndSelect("room.serviceclass", "service_class") + .leftJoinAndMapOne( + "InpatientRoomBed.bed_detail", + InpatientRoomBedDetail, + "bed_detail", + "bed_detail.inpatientRoomBedId = InpatientRoomBed.id", + ) + .getOne(), + ); + + if (!data) throw { message: "Inpatient Room Bed " + Language.lang.failed_not_found }; + + return ReturnHelper.successResponseAny(res, 200, Language.lang.success_view, data); + } catch (e: unknown) { + log.error(e); + const err = e as Error; + + return ReturnHelper.errorResponse(res, 500, 402, Language.lang.failed_view, err.message); + } + } + + static async update(req: Request, res: Response, next: NextFunction): Promise { + /* + #swagger.tags = ['Inpatient Room - Bed'] + #swagger.security = [{ + "bearerAuth": [] + }] + #swagger.parameters['id'] = { + description:'', + in: 'path', + type: 'string' + } + #swagger.requestBody = { + required: true, + content: { + "application/json": { + schema: { + $ref: "#/components/schemas/inpatient_room_bed" + } + } + } + } + */ + + const queryRunner = OrmHelper.DB.createQueryRunner(); + await queryRunner.startTransaction(); + + try { + req.body.id = req.params["id"]; + + const schema = Joi.object().keys({ + id: Joi.string().uuid().required().label("Inpatient Room Bed ID"), + inpatient_room_id: Joi.string().uuid().required().label("Inpatient Room ID"), + number: Joi.number().integer().min(1).optional().label("Number"), + status: Joi.string().required().valid("booked", "empty", "progress", "occupied").label("Status"), + bed_detail: Joi.object({ + photo_before: Joi.string().allow("", null).optional().label("Photo Before"), + photo_after: Joi.string().allow("", null).optional().label("Photo After"), + electrical: Joi.boolean().optional().label("Electrical"), + telephone: Joi.boolean().optional().label("Telephone"), + lighting: Joi.boolean().optional().label("Lighting"), + wall: Joi.boolean().optional().label("Wall"), + ceiling: Joi.boolean().optional().label("Ceiling"), + floor: Joi.boolean().optional().label("Floor"), + leakage: Joi.boolean().optional().label("Leakage"), + temperature: Joi.boolean().optional().label("Temperature"), + electromedical_equipment: Joi.boolean().optional().label("Electromedical Equipment"), + available: Joi.boolean().optional().label("Available"), + online_inpatient_referral: Joi.boolean().optional().label("Online Inpatient Referral"), + cohort: Joi.boolean().optional().label("Cohort"), + }), + }); + + let param: any = await schema.validateAsync(req.body); + + let inpatientRoomBed: InpatientRoomBed = await InpatientRoomBedModel.list({ id: param.id }).then((q) => q.getOne()); + if (!inpatientRoomBed) throw { message: "Inpatient Room Bed " + Language.lang.failed_not_found }; + + let inpatient_room: InpatientRoom = await InpatientRoomModel.list({ id: param.inpatient_room_id }).then((q) => q.getOne()); + if (!inpatient_room) throw { message: "Inpatient Room " + Language.lang.failed_not_found }; + + if (param.number !== undefined && param.number !== null) { + const number: number = param.number; + if (number > inpatient_room.number_of_bed) { + throw { message: "Order Number exceeds number of bed" }; + } + + const inpatientRoomBeds = await InpatientRoomBedModel.list({ "inpatient_room.id": param.inpatient_room_id }).then((q) => + q // + .leftJoin("InpatientRoomBed.inpatient_room", "inpatient_room") + .getMany(), + ); + const usedOrderNumbers = inpatientRoomBeds.filter((b) => b.id !== inpatientRoomBed.id).map((b) => b.number); + if (usedOrderNumbers.includes(number)) { + throw { message: "Order Number already used" }; + } + + inpatientRoomBed.number = number; + } + + inpatientRoomBed.inpatient_room = inpatient_room; + inpatientRoomBed.status = param.status; + inpatientRoomBed.updated_by = req.auth?.data.name; + + await queryRunner.manager.save(inpatientRoomBed); + + if (param.bed_detail) { + let bedDetail = await queryRunner.manager.findOne(InpatientRoomBedDetail, { + where: { inpatient_room_bed: { id: param.id } }, + }); + + if (!bedDetail) { + bedDetail = new InpatientRoomBedDetail(); + bedDetail.inpatient_room_bed = inpatientRoomBed; + bedDetail.created_by = req.auth?.data.name; + } + + const detailFields = [ + "photo_before", + "photo_after", + "electrical", + "telephone", + "lighting", + "wall", + "ceiling", + "floor", + "leakage", + "temperature", + "electromedical_equipment", + "available", + "online_inpatient_referral", + "cohort", + ] as const; + + for (const field of detailFields) { + if (param.bed_detail[field] !== undefined) { + (bedDetail as any)[field] = param.bed_detail[field]; + } + } + + bedDetail.updated_by = req.auth?.data.name; + await queryRunner.manager.save(bedDetail); + } + + await queryRunner.commitTransaction(); + + const data = await InpatientRoomBedModel.list({ "InpatientRoomBed.id": param.id }).then((q) => + q // + .leftJoinAndSelect("InpatientRoomBed.inpatient_room", "inpatient_room") + .leftJoinAndSelect("inpatient_room.room", "room") + .leftJoinAndSelect("room.serviceclass", "service_class") + .leftJoinAndMapOne( + "InpatientRoomBed.bed_detail", + InpatientRoomBedDetail, + "bed_detail", + "bed_detail.inpatientRoomBedId = InpatientRoomBed.id", + ) + .getOne(), + ); + + return ReturnHelper.successResponseAny(res, 200, Language.lang.success_update, data); + } catch (e: unknown) { + await queryRunner.rollbackTransaction(); + log.error(e); + const err = e as Error; + return ReturnHelper.errorResponse(res, 400, 401, Language.lang.failed_update, err.message); + } finally { + await queryRunner.release(); + } + } +} diff --git a/src/helpers/orm.ts b/src/helpers/orm.ts index c5834ee..b5b5dd6 100644 --- a/src/helpers/orm.ts +++ b/src/helpers/orm.ts @@ -1,7 +1,7 @@ import config from "config"; import { DataSource } from "typeorm"; import { ILogObj, Logger } from "tslog"; -import { ResponsiblePartyConsent, Province, City, Subdistrict, Ward, RefferalHospital, RegistrationFee, FareType, RoomStock, Administrativu, Aldeia, District, Menu, Munisipo, Suco, Application, Nationality, Diagnosis, DiagnosticProcedure, Room, ServiceType, ServiceClass, Service, ServiceFare, ServicePackage, Department, DoctorSchedule, MeasurementUnit, ReferenceRange, QueueMonitoring, QueueMonitoringRooms, ExaminationDetail, ExaminationType, User, UserRole, HrmsEmployee, HrmsDepartment, HrmsPosition, HrmsShift, HospitalInformation, ItemOrigin, ItemType, ItemTypeDetail, Unit, ItemCategory, ItemStatus, UsageInstructions, UsageTime, ItemClass, ItemClassDetail, GenericName, Factory, Supplier, FactoryToSupplier, ItemMaster, ItemGroup, PharmacyInfo, ItemPrice, SellingPricePercentage, PatientGroup, Currency, InpatientRoom, SurgeryRoom, SurgeryType, PatientGuarantor, InitialStock, DoctorItem, DoctorItemPackage, UserToRoom, RoomToPharmacy, PlanningVerificator, ScheduleSeries, ScheduleException, CardType, PaymentMethod, FosterCareHistory } from "entity"; +import { ResponsiblePartyConsent, Province, City, Subdistrict, Ward, RefferalHospital, RegistrationFee, FareType, RoomStock, Administrativu, Aldeia, District, Menu, Munisipo, Suco, Application, Nationality, Diagnosis, DiagnosticProcedure, Room, ServiceType, ServiceClass, Service, ServiceFare, ServicePackage, Department, DoctorSchedule, MeasurementUnit, ReferenceRange, QueueMonitoring, QueueMonitoringRooms, ExaminationDetail, ExaminationType, User, UserRole, HrmsEmployee, HrmsDepartment, HrmsPosition, HrmsShift, HospitalInformation, ItemOrigin, ItemType, ItemTypeDetail, Unit, ItemCategory, ItemStatus, UsageInstructions, UsageTime, ItemClass, ItemClassDetail, GenericName, Factory, Supplier, FactoryToSupplier, ItemMaster, ItemGroup, PharmacyInfo, ItemPrice, SellingPricePercentage, PatientGroup, Currency, InpatientRoom, InpatientRoomBed, InpatientRoomBedDetail, SurgeryRoom, SurgeryType, PatientGuarantor, InitialStock, DoctorItem, DoctorItemPackage, UserToRoom, RoomToPharmacy, PlanningVerificator, ScheduleSeries, ScheduleException, CardType, PaymentMethod, FosterCareHistory } from "entity"; export class OrmHelper { static DB: DataSource = null; @@ -60,6 +60,8 @@ export class OrmHelper { Unit, Currency, InpatientRoom, + InpatientRoomBed, + InpatientRoomBedDetail, SurgeryRoom, SurgeryType, ItemCategory, diff --git a/src/model/inpatient_room_beds.ts b/src/model/inpatient_room_beds.ts new file mode 100644 index 0000000..177252d --- /dev/null +++ b/src/model/inpatient_room_beds.ts @@ -0,0 +1,28 @@ +import { InpatientRoomBed } from "entity"; +import { SelectQueryBuilder } from "typeorm"; +import CommonHelper from "../helpers/common"; +import { OrmHelper } from "../helpers/orm"; + +export class InpatientRoomBedModel { + static async list(filter = {}): Promise> { + const repo = OrmHelper.DB.getRepository(InpatientRoomBed); + let whereAttr = []; + let whereVal: any = {}; + if (filter) { + whereAttr = [...whereAttr, ...CommonHelper.handleQueryFilter(filter).whereAttr]; + whereVal = { + ...whereVal, + ...CommonHelper.handleQueryFilter(filter).whereVal, + }; + } + + var query = null; + query = repo.createQueryBuilder(); + if (whereAttr.length != 0) { + query = query.where(whereAttr.join(" and "), whereVal); + } + + return query; + } +} + diff --git a/src/routes/private.ts b/src/routes/private.ts index 6d8de72..35f457d 100644 --- a/src/routes/private.ts +++ b/src/routes/private.ts @@ -67,6 +67,7 @@ import { RegionController } from "../controllers/region"; import { ResponsiblePartyConsentController } from "../controllers/responsiblepartyconsent"; import { CurrencyController } from "../controllers/currency"; import { InpatientRoomController } from "../controllers/inpatient_room"; +import { InpatientRoomBedController } from "../controllers/inpatient_room_bed"; import { SurgeryRoomController } from "../controllers/surgery_room"; import { SurgeryTypeController } from "../controllers/surgery_type"; import { FosterCareHistoryController } from "../controllers/fostercarehistory"; @@ -330,6 +331,10 @@ export class RoutePrivate { app.put("/api/inpatient-room/update/:id", InpatientRoomController.update); app.delete("/api/inpatient-room/delete/:id/:hard", InpatientRoomController.delete); + app.get("/api/inpatient-room-bed/list", InpatientRoomBedController.list); + app.get("/api/inpatient-room-bed/detail/:id", InpatientRoomBedController.detail); + app.put("/api/inpatient-room-bed/update/:id", InpatientRoomBedController.update); + app.get("/api/surgery-room/list", SurgeryRoomController.list); app.post("/api/surgery-room/create", SurgeryRoomController.create); app.get("/api/surgery-room/detail/:id", SurgeryRoomController.detail); diff --git a/src/swagger/builder.js b/src/swagger/builder.js index 358e58d..46a8018 100644 --- a/src/swagger/builder.js +++ b/src/swagger/builder.js @@ -140,6 +140,29 @@ const doc = { $department_id: "uuid-string", $status: "Y", }, + inpatient_room_bed: { + $inpatient_room_id: "34fdda87-9b42-44d3-8cab-2f2032481d42", + $number: 1, + $status: { + "@enum": ["booked", "empty", "progress", "occupied"], + }, + $bed_detail: { + $photo_before: "base64 or url string", + $photo_after: "base64 or url string", + $electrical: true, + $telephone: false, + $lighting: true, + $wall: false, + $ceiling: false, + $floor: false, + $leakage: false, + $temperature: false, + $electromedical_equipment: false, + $available: true, + $online_inpatient_referral: false, + $cohort: false, + }, + }, // pharmacy: { // $room: "Room name", // $code: "R001",