From a1df4a08f92b34b9dcb052b8035f5648f0a83f51 Mon Sep 17 00:00:00 2001 From: wayanrivan Date: Wed, 25 Mar 2026 14:04:29 +0700 Subject: [PATCH 1/2] update: faretype done --- src/controllers/faretype.ts | 340 ++++++++++++++++++++++++++++++++ src/controllers/service_fare.ts | 1 + src/helpers/orm.ts | 5 +- src/model/faretype.ts | 23 +++ src/routes/private.ts | 8 + src/swagger/builder.js | 3 + 6 files changed, 378 insertions(+), 2 deletions(-) create mode 100644 src/controllers/faretype.ts create mode 100644 src/model/faretype.ts diff --git a/src/controllers/faretype.ts b/src/controllers/faretype.ts new file mode 100644 index 0000000..29cf807 --- /dev/null +++ b/src/controllers/faretype.ts @@ -0,0 +1,340 @@ +import { Response, NextFunction, Application } from "express"; +import { Request } from "express-jwt"; +import { ReturnHelper } from "../helpers/express/return"; +import { OrmHelper } from "../helpers/orm"; +import Joi from "joi"; +import { ILogObj, Logger } from "tslog"; +import { Language } from "../langs/lang"; +import { Paging } from "entity"; +import CommonHelper from "../helpers/common"; +import * as fastcsv from 'fast-csv'; +import dayjs from "dayjs"; +import { FareType } from "entity"; + +const log: Logger = new Logger({ name: '[FareTypeController]', type: 'pretty' }); + +export class FareTypeController { + static async list(req: Request, res: Response, next: NextFunction): Promise { + /* + #swagger.tags = ['Fare Type'] + #swagger.security = [{ + "bearerAuth": [] + }] + #swagger.parameters['filter'] = { + description: '', + 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').required().label('Order Direction'), + }); + + const param: Paging = await schema.validateAsync(req.query); + + const repo = OrmHelper.DB.getRepository(FareType); + + const offset = (param.page - 1) * param.limit + + const filterObj = param.filter ? JSON.parse(param.filter) : {}; + // Remove foreign key from filter for CommonHelper.handleFilter + const filterWithoutFK = { ...filterObj }; + delete filterWithoutFK.munisipo_id; + const filterStrWithoutFK = JSON.stringify(filterWithoutFK); + + // const { whereAttr, whereVal } = CommonHelper.handleFilter({ + // filter: filterStrWithoutFK, + // col_any_eq: ['code'], + // col_any_like: ['name'] + // }); + + const res_count = repo.createQueryBuilder("FareType") + // .leftJoin("Administrativu.munisipo", "munisipo") + // .where(whereAttr || "1=1", whereVal); + + // Handle foreign key filter with relation + // if (filterObj.munisipo_id) { + // res_count.andWhere("munisipo.id = :munisipoId", { munisipoId: filterObj.munisipo_id }); + // } + + const res_list = repo.createQueryBuilder("FareType") + // .leftJoin("Administrativu.munisipo", "munisipo") + // .where(whereAttr || "1=1", whereVal) + .orderBy("FareType." + param.order_field, param.order_direction) + .offset(offset) + .limit(param.limit); + + // Handle foreign key filter with relation + // if (filterObj.munisipo_id) { + // res_list.andWhere("munisipo.id = :munisipoId", { munisipoId: filterObj.munisipo_id }); + // } + + 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 option(req: Request, res: Response, next: NextFunction): Promise { + /* + #swagger.tags = ['Fare Type'] + #swagger.security = [{ + "bearerAuth": [] + }] + */ + + try { + const repo = OrmHelper.DB.getRepository(FareType); + const res_count = repo.createQueryBuilder("FareType") + // .leftJoin("Administrativu.munisipo", "munisipo") + // .where(whereAttr || "1=1", whereVal); + + // Handle foreign key filter with relation + // if (filterObj.munisipo_id) { + // res_count.andWhere("munisipo.id = :munisipoId", { munisipoId: filterObj.munisipo_id }); + // } + + const res_list = repo.createQueryBuilder("FareType"); + + // Handle foreign key filter with relation + // if (filterObj.munisipo_id) { + // res_list.andWhere("munisipo.id = :munisipoId", { munisipoId: filterObj.munisipo_id }); + // } + + const current_page = 1; + 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 create(req: Request, res: Response, next: NextFunction): Promise { + /* + #swagger.tags = ['Fare Type'] + #swagger.security = [{ + "bearerAuth": [] + }] + + #swagger.requestBody = { + required: true, + content: { + "application/json": { + schema: { + $ref: "#/components/schemas/faretype" + } + } + } + } + */ + + try { + const schema = Joi.object().keys({ + name: Joi.string().required().label('Name'), + }); + + const param: any = await schema.validateAsync(req.body); + + const data = new FareType() + data.name = param.name + await OrmHelper.DB.manager.save(data); + + return ReturnHelper.successResponseAny(res, 200, Language.lang.success_insert, data); + } catch (e: unknown) { + log.error(e); + const err = e as Error; + + return ReturnHelper.errorResponse(res, 500, 401, Language.lang.failed_insert, err.message); + } + } + + static async update(req: Request, res: Response, next: NextFunction): Promise { + /* + #swagger.tags = ['Fare Type'] + #swagger.security = [{ + "bearerAuth": [] + }] + #swagger.parameters['id'] = { + in: 'path', + description: 'Fare Type ID.', + required: true, + type: 'string' + } + + #swagger.requestBody = { + required: true, + content: { + "application/json": { + schema: { + $ref: "#/components/schemas/faretype" + } + } + } + } + */ + + try { + const schema = Joi.object().keys({ + id: Joi.string().uuid().required().label('ID'), + name: Joi.string().required().label('Name'), + }); + + req.body.id = req.params['id']; + + const param: any = await schema.validateAsync(req.body); + + const repo = OrmHelper.DB.getRepository(FareType); + + const data = await repo.findOneBy({ id: param.id }); + + if (data != null) { + data.name = param.name + await repo.save(data); + + return ReturnHelper.successResponseAny(res, 200, Language.lang.success_update, data); + } else { + return ReturnHelper.errorResponse(res, 404, 401, Language.lang.failed_not_found, ""); + } + } catch (e: unknown) { + log.error(e); + const err = e as Error; + + return ReturnHelper.errorResponse(res, 500, 402, Language.lang.failed_update, err.message); + } + } + + static async delete(req: Request, res: Response, next: NextFunction): Promise { + /* + #swagger.tags = ['Fare Type'] + #swagger.security = [{ + "bearerAuth": [] + }] + #swagger.parameters['id'] = { + in: 'path', + description: 'Fare Type ID.', + required: true, + type: 'string' + } + #swagger.parameters['hard'] = { + in: 'path', + description: 'Is Hard Delete', + required: false, + type: 'boolean' + } + */ + try { + const schema = Joi.object().keys({ + id: Joi.string().uuid().required().label('ID'), + hard: Joi.bool().optional().allow('').label('Is hard delete?') + }); + + const param: { id: string, hard: boolean } = await schema.validateAsync(req.params); + + const repo = OrmHelper.DB.getRepository(FareType); + + const affected = (!param.hard ? await repo.softDelete({ id: param.id }) : await repo.delete({ id: param.id })).affected; + + if (affected > 0) { + return ReturnHelper.successResponseAny(res, 200, Language.lang.success_delete, {}); + } else { + return ReturnHelper.errorResponse(res, 404, 401, Language.lang.failed_not_found, ""); + } + } catch (e: unknown) { + log.error(e); + const err = e as Error; + + return ReturnHelper.errorResponse(res, 500, 402, Language.lang.failed_delete, err.message); + } + } + + static async restore(req: Request, res: Response, next: NextFunction): Promise { + /* + #swagger.tags = ['Fare Type'] + #swagger.security = [{ + "bearerAuth": [] + }] + + #swagger.parameters['id'] = { + in: 'path', + description: 'Fare Type ID.', + required: true, + type: 'string' + } + */ + try { + const schema = Joi.object().keys({ + id: Joi.string().uuid().required().label('ID') + }); + + const param: FareType = await schema.validateAsync(req.params); + + const repo = OrmHelper.DB.getRepository(FareType); + + const affected = (await repo.restore({ id: param.id })).affected; + + if (affected > 0) { + return ReturnHelper.successResponseAny(res, 200, Language.lang.success_restore, {}); + } else { + return ReturnHelper.errorResponse(res, 404, 401, Language.lang.failed_not_found, ""); + } + } catch (e: unknown) { + log.error(e); + const err = e as Error; + + return ReturnHelper.errorResponse(res, 500, 402, Language.lang.failed_restore, err.message); + } + } +} \ No newline at end of file diff --git a/src/controllers/service_fare.ts b/src/controllers/service_fare.ts index 552ce06..d854318 100644 --- a/src/controllers/service_fare.ts +++ b/src/controllers/service_fare.ts @@ -52,6 +52,7 @@ export class ServiceFareController { const res_list = query .leftJoinAndSelect("ServiceFare.serviceClass", "serviceClass") .leftJoinAndSelect("ServiceFare.service", "service") + .leftJoinAndSelect('ServiceFare.faretype', 'faretype') .orderBy("ServiceFare." + param.order_field, param.order_direction) .offset(offset) .limit(limit); diff --git a/src/helpers/orm.ts b/src/helpers/orm.ts index cfebf88..da6289a 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 { RoomStock,Administrativu, Aldeia, District, Menu, Munisipo, Suco, Application, Nationality, Diagnosis, DiagnosticProcedure, Room, ServiceType, ServiceClass, Service, ServiceFare, ServicePackage, Department, DoctorSchedule, MeasurementUnit, ReferenceRange, QueueMonitoring, 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, PatientGuarantor, InitialStock, DoctorItem, DoctorItemPackage, UserToRoom, RoomToPharmacy, PlanningVerificator, ScheduleSeries, ScheduleException } from 'entity' +import { FareType,RoomStock,Administrativu, Aldeia, District, Menu, Munisipo, Suco, Application, Nationality, Diagnosis, DiagnosticProcedure, Room, ServiceType, ServiceClass, Service, ServiceFare, ServicePackage, Department, DoctorSchedule, MeasurementUnit, ReferenceRange, QueueMonitoring, 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, PatientGuarantor, InitialStock, DoctorItem, DoctorItemPackage, UserToRoom, RoomToPharmacy, PlanningVerificator, ScheduleSeries, ScheduleException } from 'entity' export class OrmHelper { static DB: DataSource = null @@ -49,7 +49,8 @@ export class OrmHelper { PlanningVerificator, RoomStock, ScheduleSeries, - ScheduleException + ScheduleException, + FareType ], subscribers: [], migrations: [], diff --git a/src/model/faretype.ts b/src/model/faretype.ts new file mode 100644 index 0000000..dfc3bed --- /dev/null +++ b/src/model/faretype.ts @@ -0,0 +1,23 @@ +import { FareType } from "entity"; +import { SelectQueryBuilder } from "typeorm"; +import CommonHelper from "../helpers/common"; +import { OrmHelper } from "../helpers/orm"; + +export class FareTypeModel { + static async list(filter = {}): Promise> { + const repo = OrmHelper.DB.getRepository(FareType); + let whereAttr: string[] = []; + let whereVal: any = {}; + if (filter && Object.keys(filter).length > 0) { + whereAttr = [...whereAttr, ...CommonHelper.handleQueryFilter(filter).whereAttr]; + whereVal = { ...whereVal, ...CommonHelper.handleQueryFilter(filter).whereVal }; + } + + var query = repo.createQueryBuilder("FareType"); + 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 88cd73f..614656e 100644 --- a/src/routes/private.ts +++ b/src/routes/private.ts @@ -59,6 +59,7 @@ import { UserToRoomController } from '../controllers/user_to_room'; import { RoomToPharmacyController } from '../controllers/room_to_pharmacy'; import { PlanningVerificatorController } from '../controllers/pharmacy/planning_verificator'; import { ScheduleController } from '../controllers/schedule'; +import { FareTypeController } from '../controllers/faretype'; export class RoutePrivate { static setup(app: express.Application) { @@ -449,5 +450,12 @@ export class RoutePrivate { app.post('/api/pharmacy/planning-verificator/create', PlanningVerificatorController.create) app.delete('/api/pharmacy/planning-verificator/delete/:id/:hard', PlanningVerificatorController.delete) app.put('/api/pharmacy/planning-verificator/restore/:id', PlanningVerificatorController.restore) + + app.get('/api/fare-type/list', FareTypeController.list) + app.get('/api/fare-type/option', FareTypeController.option) + app.post('/api/fare-type/create', FareTypeController.create) + app.put('/api/fare-type/update/:id', FareTypeController.update) + app.delete('/api/fare-type/delete/:id/:hard', FareTypeController.delete) + app.put('/api/fare-type/restore/:id', FareTypeController.restore) } } diff --git a/src/swagger/builder.js b/src/swagger/builder.js index c9167ef..a9b7b04 100644 --- a/src/swagger/builder.js +++ b/src/swagger/builder.js @@ -436,6 +436,9 @@ const doc = { $page: 1, $limit: 20 }, + faretype: { + $name: 'Name (string)', + }, }, parameters: { From 4f3074f8f81bfb43ac745031a796b57cfd5270a4 Mon Sep 17 00:00:00 2001 From: wayanrivan Date: Wed, 25 Mar 2026 14:06:50 +0700 Subject: [PATCH 2/2] new param for service fare, fare type id --- src/controllers/service_fare.ts | 10 ++++++++++ src/swagger/builder.js | 1 + 2 files changed, 11 insertions(+) diff --git a/src/controllers/service_fare.ts b/src/controllers/service_fare.ts index d854318..e6dc424 100644 --- a/src/controllers/service_fare.ts +++ b/src/controllers/service_fare.ts @@ -88,6 +88,7 @@ export class ServiceFareController { service_class_id: Joi.string().uuid().required().label("Service Class ID"), service_id: Joi.string().uuid().required().label("Service ID"), fare: Joi.number().min(0).required().label("Fare"), + faretype: Joi.string().uuid().required().label("Fare Type ID"), }); let param: any = await schema.validateAsync(req.body); @@ -98,6 +99,9 @@ export class ServiceFareController { let service = await ServiceModel.list({ "Service.id": param.service_id }).then((q) => q.getOne()); if (!service) throw { message: "Service not found" }; + let fareType = await OrmHelper.DB.getRepository("FareType").createQueryBuilder("FareType").where("FareType.id = :id", { id: param.faretype }).getOne(); + if (!fareType) throw { message: "Fare Type not found" }; + // let filter = { // serviceClassId: param.service_class_id, // serviceId: param.service_id, @@ -109,6 +113,7 @@ export class ServiceFareController { serviceFare.serviceClass = serviceClass; serviceFare.service = service; serviceFare.fare = String(param.fare); + serviceFare.faretype = param.faretype; serviceFare.created_by = req.auth.data.name; serviceFare.updated_by = req.auth.data.name; await queryRunner.manager.save(serviceFare); @@ -172,6 +177,7 @@ export class ServiceFareController { service_class_id: Joi.string().uuid().required().label("Service Class ID"), service_id: Joi.string().uuid().required().label("Service ID"), fare: Joi.number().min(0).required().label("Fare"), + faretype: Joi.string().uuid().required().label("Fare Type ID"), }); let param: any = await schema.validateAsync(req.body); @@ -185,6 +191,9 @@ export class ServiceFareController { let serviceFare = await ServiceFareModel.list({ "ServiceFare.id": param.id }).then((q) => q.getOne()); if (!serviceFare) throw { message: "Service Fare " + Language.lang.failed_not_found }; + let fareType = await OrmHelper.DB.getRepository("FareType").createQueryBuilder("FareType").where("FareType.id = :id", { id: param.faretype }).getOne(); + if (!fareType) throw { message: "Fare Type not found" }; + // let filter = { // serviceClassId: param.service_class_id, // serviceId: param.service_id, @@ -195,6 +204,7 @@ export class ServiceFareController { serviceFare.serviceClass = serviceClass; serviceFare.service = service; serviceFare.fare = String(param.fare); + serviceFare.faretype = param.faretype; serviceFare.updated_by = req.auth.data.name; await queryRunner.manager.save(serviceFare); diff --git a/src/swagger/builder.js b/src/swagger/builder.js index a9b7b04..bec67f3 100644 --- a/src/swagger/builder.js +++ b/src/swagger/builder.js @@ -147,6 +147,7 @@ const doc = { serviceFare: { $service_class_id: "uuid-string", $service_id: "uuid-string", + $faretype: "uuid-string", $fare: 100000 }, servicePackage: {