From a2a628c1a184021e77062c590e7677375073a69f Mon Sep 17 00:00:00 2001 From: Muhammad Rayhan Ardiansyah Date: Thu, 26 Feb 2026 16:30:08 +0700 Subject: [PATCH] init pharmacy master data --- package.json | 6 +- src/controllers/pharmacy/item_category.ts | 339 ++++++++++++++++++ src/controllers/pharmacy/item_group.ts | 339 ++++++++++++++++++ src/controllers/pharmacy/item_origin.ts | 352 +++++++++++++++++++ src/controllers/pharmacy/item_status.ts | 339 ++++++++++++++++++ src/controllers/pharmacy/item_type.ts | 343 ++++++++++++++++++ src/controllers/pharmacy/item_type_detail.ts | 343 ++++++++++++++++++ src/controllers/pharmacy/unit.ts | 339 ++++++++++++++++++ src/helpers/orm.ts | 19 +- src/model/item_category.ts | 23 ++ src/model/item_group.ts | 23 ++ src/model/item_origin.ts | 23 ++ src/model/item_status.ts | 23 ++ src/model/item_type.ts | 23 ++ src/model/item_type_detail.ts | 23 ++ src/model/unit.ts | 23 ++ src/routes/private.ts | 56 +++ src/swagger/builder.js | 26 ++ 18 files changed, 2659 insertions(+), 3 deletions(-) create mode 100644 src/controllers/pharmacy/item_category.ts create mode 100644 src/controllers/pharmacy/item_group.ts create mode 100644 src/controllers/pharmacy/item_origin.ts create mode 100644 src/controllers/pharmacy/item_status.ts create mode 100644 src/controllers/pharmacy/item_type.ts create mode 100644 src/controllers/pharmacy/item_type_detail.ts create mode 100644 src/controllers/pharmacy/unit.ts create mode 100644 src/model/item_category.ts create mode 100644 src/model/item_group.ts create mode 100644 src/model/item_origin.ts create mode 100644 src/model/item_status.ts create mode 100644 src/model/item_type.ts create mode 100644 src/model/item_type_detail.ts create mode 100644 src/model/unit.ts diff --git a/package.json b/package.json index 36fb0ce..e8448b2 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "cors": "^2.8.5", "entity": "file:../entity", "express": "^4.21.1", + "express-fileupload": "^1.5.2", "express-jwt": "^8.4.1", "fast-csv": "^5.0.2", "helmet": "^8.0.0", @@ -42,8 +43,11 @@ "@types/config": "^3.3.5", "@types/cors": "^2.8.17", "@types/express": "^4.17.21", + "@types/express-fileupload": "^1.5.1", "@types/morgan": "^1.9.9", "@types/swagger-ui-express": "^4.1.7", - "@types/uuid": "^10.0.0" + "@types/uuid": "^10.0.0", + "ts-node": "^10.9.2", + "typescript": "^5.9.3" } } diff --git a/src/controllers/pharmacy/item_category.ts b/src/controllers/pharmacy/item_category.ts new file mode 100644 index 0000000..4dec970 --- /dev/null +++ b/src/controllers/pharmacy/item_category.ts @@ -0,0 +1,339 @@ +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 { ItemCategory, Paging } from "entity"; +import CommonHelper from "../../helpers/common"; +import * as fastcsv from 'fast-csv'; +import dayjs from "dayjs"; +import { ItemCategoryModel } from "../../model/item_category"; + +const log: Logger = new Logger({ name: '[ItemCategoryController]', type: 'pretty' }); + +export class ItemCategoryController { + static async list(req: Request, res: Response, next: NextFunction): Promise { + /* + #swagger.tags = ['Pharmacy - ItemCategory'] + #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"), + }); + + let param: Paging = await schema.validateAsync(req.query); + + let filter = param.filter && param.filter !== "" ? JSON.parse(param.filter) : {}; + + var query = await ItemCategoryModel.list(filter); + + const offset = (param.page - 1) * param.limit; + let limit = param.limit; + + const res_count = query; + const res_list = query + .orderBy("item_category." + param.order_field, param.order_direction) + .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 export(req: Request, res: Response, next: NextFunction): Promise { + /* + #swagger.tags = ['Pharmacy - ItemCategory'] + #swagger.security = [{ + "bearerAuth": [] + }] + #swagger.parameters['filter'] = { + description: 'Filter with 2 format :
  • Simple format use text plaint will filter eq:code or like %name%
  • Advance format using field existing {status:\'Y\', any:\'SAME AS PLAINT LOGIC\', etc...}
', + in: 'query', + type: 'string' + } + #swagger.parameters['filter'] = { + in: 'query', + type: 'string' + } + #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'), + 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); + + let filter = param.filter && param.filter !== "" ? JSON.parse(param.filter) : {}; + + var query = await ItemCategoryModel.list(filter); + const data = await query.getMany(); + + const filename = "item_category.csv"; + + res.setHeader('Content-Type', 'text/csv'); + res.setHeader('Content-Disposition', 'attachment; filename=' + filename); + + const csvStream = fastcsv.format({ + headers: true, + writeHeaders: true, + transform: (row: ItemCategory): any => ({ + ...row, + created_at: dayjs(row.created_at).format('DD-MM-YYYY HH:MM:ss'), + }) + }); + csvStream.pipe(res); + + const limit = 50; + + const fetchAndWrite = async (page: any) => { + + if (CommonHelper.countObject(data) === 0) { + csvStream.end(); + } else { + data.forEach((item: any) => csvStream.write(item)); + + if (CommonHelper.countObject(data) == limit) { + fetchAndWrite(page + 1); + } else { + csvStream.end(); + } + } + }; + + fetchAndWrite(1); + } 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 = ['Pharmacy - ItemCategory'] + #swagger.security = [{ + "bearerAuth": [] + }] + + #swagger.requestBody = { + required: true, + content: { + "application/json": { + schema: { + $ref: "#/components/schemas/item_category" + } + } + } + } + */ + try { + const schema = Joi.object().keys({ + category_name: Joi.string().max(256).required().label('Name'), + }); + + const param: any = await schema.validateAsync(req.body); + + const data = new ItemCategory() + data.category_name = param.category_name + data.created_by = req.auth.data.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 = ['Pharmacy - ItemCategory'] + #swagger.security = [{ + "bearerAuth": [] + }] + #swagger.parameters['id'] = { + in: 'path', + description: 'ItemCategory ID.', + required: true, + type: 'string' + } + + #swagger.requestBody = { + required: true, + content: { + "application/json": { + schema: { + $ref: "#/components/schemas/item_category" + } + } + } + } + */ + + try { + const schema = Joi.object().keys({ + id: Joi.string().uuid().required().label('ID'), + category_name: Joi.string().max(256).required().label('Name'), + }); + + req.body.id = req.params['id']; + + const param: any = await schema.validateAsync(req.body); + + const repo = OrmHelper.DB.getRepository(ItemCategory); + + const data = await repo.findOneBy({ id: param.id }); + + if (data != null) { + data.category_name = param.category_name + data.updated_by = req.auth.data.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 = ['Pharmacy - ItemCategory'] + #swagger.security = [{ + "bearerAuth": [] + }] + #swagger.parameters['id'] = { + in: 'path', + description: 'ItemCategory 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(ItemCategory); + + const existData = await repo.findOne({ where: { id: param.id } }); + if (existData && !param.hard) { + existData.deleted_by = req.auth.data.name; + await OrmHelper.DB.manager.save(existData); + } + + 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 = ['Pharmacy - ItemCategory'] + #swagger.security = [{ + "bearerAuth": [] + }] + + #swagger.parameters['id'] = { + in: 'path', + description: 'ItemCategory ID.', + required: true, + type: 'string' + } + */ + try { + const schema = Joi.object().keys({ + id: Joi.string().uuid().required().label('ID') + }); + + const param: ItemCategory = await schema.validateAsync(req.params); + + const repo = OrmHelper.DB.getRepository(ItemCategory); + + 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/pharmacy/item_group.ts b/src/controllers/pharmacy/item_group.ts new file mode 100644 index 0000000..d2a9c8e --- /dev/null +++ b/src/controllers/pharmacy/item_group.ts @@ -0,0 +1,339 @@ +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 { ItemGroup, Paging } from "entity"; +import CommonHelper from "../../helpers/common"; +import * as fastcsv from 'fast-csv'; +import dayjs from "dayjs"; +import { ItemGroupModel } from "../../model/item_group"; + +const log: Logger = new Logger({ name: '[ItemGroupController]', type: 'pretty' }); + +export class ItemGroupController { + static async list(req: Request, res: Response, next: NextFunction): Promise { + /* + #swagger.tags = ['Pharmacy - ItemGroup'] + #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"), + }); + + let param: Paging = await schema.validateAsync(req.query); + + let filter = param.filter && param.filter !== "" ? JSON.parse(param.filter) : {}; + + var query = await ItemGroupModel.list(filter); + + const offset = (param.page - 1) * param.limit; + let limit = param.limit; + + const res_count = query; + const res_list = query + .orderBy("item_group." + param.order_field, param.order_direction) + .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 export(req: Request, res: Response, next: NextFunction): Promise { + /* + #swagger.tags = ['Pharmacy - ItemGroup'] + #swagger.security = [{ + "bearerAuth": [] + }] + #swagger.parameters['filter'] = { + description: 'Filter with 2 format :
  • Simple format use text plaint will filter eq:code or like %name%
  • Advance format using field existing {status:\'Y\', any:\'SAME AS PLAINT LOGIC\', etc...}
', + in: 'query', + type: 'string' + } + #swagger.parameters['filter'] = { + in: 'query', + type: 'string' + } + #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'), + 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); + + let filter = param.filter && param.filter !== "" ? JSON.parse(param.filter) : {}; + + var query = await ItemGroupModel.list(filter); + const data = await query.getMany(); + + const filename = "item_group.csv"; + + res.setHeader('Content-Type', 'text/csv'); + res.setHeader('Content-Disposition', 'attachment; filename=' + filename); + + const csvStream = fastcsv.format({ + headers: true, + writeHeaders: true, + transform: (row: ItemGroup): any => ({ + ...row, + created_at: dayjs(row.created_at).format('DD-MM-YYYY HH:MM:ss'), + }) + }); + csvStream.pipe(res); + + const limit = 50; + + const fetchAndWrite = async (page: any) => { + + if (CommonHelper.countObject(data) === 0) { + csvStream.end(); + } else { + data.forEach((item: any) => csvStream.write(item)); + + if (CommonHelper.countObject(data) == limit) { + fetchAndWrite(page + 1); + } else { + csvStream.end(); + } + } + }; + + fetchAndWrite(1); + } 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 = ['Pharmacy - ItemGroup'] + #swagger.security = [{ + "bearerAuth": [] + }] + + #swagger.requestBody = { + required: true, + content: { + "application/json": { + schema: { + $ref: "#/components/schemas/item_group" + } + } + } + } + */ + try { + const schema = Joi.object().keys({ + group_name: Joi.string().max(256).required().label('Name'), + }); + + const param: any = await schema.validateAsync(req.body); + + const data = new ItemGroup() + data.group_name = param.group_name + data.created_by = req.auth.data.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 = ['Pharmacy - ItemGroup'] + #swagger.security = [{ + "bearerAuth": [] + }] + #swagger.parameters['id'] = { + in: 'path', + description: 'ItemGroup ID.', + required: true, + type: 'string' + } + + #swagger.requestBody = { + required: true, + content: { + "application/json": { + schema: { + $ref: "#/components/schemas/item_group" + } + } + } + } + */ + + try { + const schema = Joi.object().keys({ + id: Joi.string().uuid().required().label('ID'), + group_name: Joi.string().max(256).required().label('Name'), + }); + + req.body.id = req.params['id']; + + const param: any = await schema.validateAsync(req.body); + + const repo = OrmHelper.DB.getRepository(ItemGroup); + + const data = await repo.findOneBy({ id: param.id }); + + if (data != null) { + data.group_name = param.group_name + data.updated_by = req.auth.data.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 = ['Pharmacy - ItemGroup'] + #swagger.security = [{ + "bearerAuth": [] + }] + #swagger.parameters['id'] = { + in: 'path', + description: 'Item Group 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(ItemGroup); + + const existData = await repo.findOne({ where: { id: param.id } }); + if (existData && !param.hard) { + existData.deleted_by = req.auth.data.name; + await OrmHelper.DB.manager.save(existData); + } + + 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 = ['Pharmacy - ItemGroup'] + #swagger.security = [{ + "bearerAuth": [] + }] + + #swagger.parameters['id'] = { + in: 'path', + description: 'ItemGroup ID.', + required: true, + type: 'string' + } + */ + try { + const schema = Joi.object().keys({ + id: Joi.string().uuid().required().label('ID') + }); + + const param: ItemGroup = await schema.validateAsync(req.params); + + const repo = OrmHelper.DB.getRepository(ItemGroup); + + 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/pharmacy/item_origin.ts b/src/controllers/pharmacy/item_origin.ts new file mode 100644 index 0000000..cfddcca --- /dev/null +++ b/src/controllers/pharmacy/item_origin.ts @@ -0,0 +1,352 @@ +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 { ItemOrigin, Paging } from "entity"; +import CommonHelper from "../../helpers/common"; +import * as fastcsv from 'fast-csv'; +import dayjs from "dayjs"; +import { ItemOriginModel } from "../../model/item_origin"; + +const log: Logger = new Logger({ name: '[ItemOriginController]', type: 'pretty' }); + +export class ItemOriginController { + static async list(req: Request, res: Response, next: NextFunction): Promise { + /* + #swagger.tags = ['Pharmacy - ItemOrigin'] + #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"), + }); + + let param: Paging = await schema.validateAsync(req.query); + + let filter = param.filter && param.filter !== "" ? JSON.parse(param.filter) : {}; + + var query = await ItemOriginModel.list(filter); + + const offset = (param.page - 1) * param.limit; + let limit = param.limit; + + const res_count = query; + const res_list = query + .orderBy("item_origin." + param.order_field, param.order_direction) + .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 export(req: Request, res: Response, next: NextFunction): Promise { + /* + #swagger.tags = ['Pharmacy - ItemOrigin'] + #swagger.security = [{ + "bearerAuth": [] + }] + #swagger.parameters['filter'] = { + description: 'Filter with 2 format :
  • Simple format use text plaint will filter eq:code or like %name%
  • Advance format using field existing {status:\'Y\', any:\'SAME AS PLAINT LOGIC\', etc...}
', + in: 'query', + type: 'string' + } + #swagger.parameters['filter'] = { + in: 'query', + type: 'string' + } + #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'), + 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); + + let filter = param.filter && param.filter !== "" ? JSON.parse(param.filter) : {}; + + var query = await ItemOriginModel.list(filter); + const data = await query.getMany(); + + const filename = "item_origin.csv"; + + res.setHeader('Content-Type', 'text/csv'); + res.setHeader('Content-Disposition', 'attachment; filename=' + filename); + + const csvStream = fastcsv.format({ + headers: true, + writeHeaders: true, + transform: (row: ItemOrigin): any => ({ + ...row, + created_at: dayjs(row.created_at).format('DD-MM-YYYY HH:MM:ss'), + }) + }); + csvStream.pipe(res); + + const limit = 50; + + const fetchAndWrite = async (page: any) => { + + if (CommonHelper.countObject(data) === 0) { + csvStream.end(); + } else { + data.forEach((item: any) => csvStream.write(item)); + + if (CommonHelper.countObject(data) == limit) { + fetchAndWrite(page + 1); + } else { + csvStream.end(); + } + } + }; + + fetchAndWrite(1); + } 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 = ['Pharmacy - ItemOrigin'] + #swagger.security = [{ + "bearerAuth": [] + }] + + #swagger.requestBody = { + required: true, + content: { + "application/json": { + schema: { + $ref: "#/components/schemas/item_origin" + } + } + } + } + */ + try { + const schema = Joi.object().keys({ + origin_name: Joi.string().max(256).required().label('Name'), + origin_description: Joi.string().max(256).required().label('Desc'), + department: Joi.string().max(256).optional().label('Department'), + account: Joi.string().max(256).optional().label('Account'), + + }); + + const param: any = await schema.validateAsync(req.body); + + const data = new ItemOrigin() + data.origin_name = param.origin_name + data.origin_description = param.origin_description + data.department = param.department + data.account = param.account + data.created_by = req.auth.data.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 = ['Pharmacy - ItemOrigin'] + #swagger.security = [{ + "bearerAuth": [] + }] + #swagger.parameters['id'] = { + in: 'path', + description: 'ItemOrigin ID.', + required: true, + type: 'string' + } + + #swagger.requestBody = { + required: true, + content: { + "application/json": { + schema: { + $ref: "#/components/schemas/item_origin" + } + } + } + } + */ + + try { + const schema = Joi.object().keys({ + id: Joi.string().uuid().required().label('ID'), + origin_name: Joi.string().max(256).required().label('Name'), + origin_description: Joi.string().max(256).required().label('Desc'), + department: Joi.string().max(256).required().label('Department'), + account: Joi.string().max(256).required().label('Account'), + }); + + req.body.id = req.params['id']; + + const param: any = await schema.validateAsync(req.body); + + const repo = OrmHelper.DB.getRepository(ItemOrigin); + + const data = await repo.findOneBy({ id: param.id }); + + if (data != null) { + data.origin_name = param.origin_name + data.origin_description = param.origin_description + data.department = param.department + data.account = param.account + data.updated_by = req.auth.data.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 = ['Pharmacy - ItemOrigin'] + #swagger.security = [{ + "bearerAuth": [] + }] + #swagger.parameters['id'] = { + in: 'path', + description: 'Item Origin 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(ItemOrigin); + + const existData = await repo.findOne({ where: { id: param.id } }); + if (existData && !param.hard) { + existData.deleted_by = req.auth.data.name; + await OrmHelper.DB.manager.save(existData); + } + + 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 = ['Pharmacy - ItemOrigin'] + #swagger.security = [{ + "bearerAuth": [] + }] + + #swagger.parameters['id'] = { + in: 'path', + description: 'ItemOrigin ID.', + required: true, + type: 'string' + } + */ + try { + const schema = Joi.object().keys({ + id: Joi.string().uuid().required().label('ID') + }); + + const param: ItemOrigin = await schema.validateAsync(req.params); + + const repo = OrmHelper.DB.getRepository(ItemOrigin); + + 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/pharmacy/item_status.ts b/src/controllers/pharmacy/item_status.ts new file mode 100644 index 0000000..ccfe101 --- /dev/null +++ b/src/controllers/pharmacy/item_status.ts @@ -0,0 +1,339 @@ +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 { ItemStatus, Paging } from "entity"; +import CommonHelper from "../../helpers/common"; +import * as fastcsv from 'fast-csv'; +import dayjs from "dayjs"; +import { ItemStatusModel } from "../../model/item_status"; + +const log: Logger = new Logger({ name: '[ItemStatusController]', type: 'pretty' }); + +export class ItemStatusController { + static async list(req: Request, res: Response, next: NextFunction): Promise { + /* + #swagger.tags = ['Pharmacy - ItemStatus'] + #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"), + }); + + let param: Paging = await schema.validateAsync(req.query); + + let filter = param.filter && param.filter !== "" ? JSON.parse(param.filter) : {}; + + var query = await ItemStatusModel.list(filter); + + const offset = (param.page - 1) * param.limit; + let limit = param.limit; + + const res_count = query; + const res_list = query + .orderBy("item_status." + param.order_field, param.order_direction) + .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 export(req: Request, res: Response, next: NextFunction): Promise { + /* + #swagger.tags = ['Pharmacy - ItemStatus'] + #swagger.security = [{ + "bearerAuth": [] + }] + #swagger.parameters['filter'] = { + description: 'Filter with 2 format :
  • Simple format use text plaint will filter eq:code or like %name%
  • Advance format using field existing {status:\'Y\', any:\'SAME AS PLAINT LOGIC\', etc...}
', + in: 'query', + type: 'string' + } + #swagger.parameters['filter'] = { + in: 'query', + type: 'string' + } + #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'), + 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); + + let filter = param.filter && param.filter !== "" ? JSON.parse(param.filter) : {}; + + var query = await ItemStatusModel.list(filter); + const data = await query.getMany(); + + const filename = "item_status.csv"; + + res.setHeader('Content-Type', 'text/csv'); + res.setHeader('Content-Disposition', 'attachment; filename=' + filename); + + const csvStream = fastcsv.format({ + headers: true, + writeHeaders: true, + transform: (row: ItemStatus): any => ({ + ...row, + created_at: dayjs(row.created_at).format('DD-MM-YYYY HH:MM:ss'), + }) + }); + csvStream.pipe(res); + + const limit = 50; + + const fetchAndWrite = async (page: any) => { + + if (CommonHelper.countObject(data) === 0) { + csvStream.end(); + } else { + data.forEach((item: any) => csvStream.write(item)); + + if (CommonHelper.countObject(data) == limit) { + fetchAndWrite(page + 1); + } else { + csvStream.end(); + } + } + }; + + fetchAndWrite(1); + } 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 = ['Pharmacy - ItemStatus'] + #swagger.security = [{ + "bearerAuth": [] + }] + + #swagger.requestBody = { + required: true, + content: { + "application/json": { + schema: { + $ref: "#/components/schemas/item_status" + } + } + } + } + */ + try { + const schema = Joi.object().keys({ + status_name: Joi.string().max(256).required().label('Name'), + }); + + const param: any = await schema.validateAsync(req.body); + + const data = new ItemStatus() + data.status_name = param.status_name + data.created_by = req.auth.data.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 = ['Pharmacy - ItemStatus'] + #swagger.security = [{ + "bearerAuth": [] + }] + #swagger.parameters['id'] = { + in: 'path', + description: 'ItemStatus ID.', + required: true, + type: 'string' + } + + #swagger.requestBody = { + required: true, + content: { + "application/json": { + schema: { + $ref: "#/components/schemas/item_status" + } + } + } + } + */ + + try { + const schema = Joi.object().keys({ + id: Joi.string().uuid().required().label('ID'), + status_name: Joi.string().max(256).required().label('Name'), + }); + + req.body.id = req.params['id']; + + const param: any = await schema.validateAsync(req.body); + + const repo = OrmHelper.DB.getRepository(ItemStatus); + + const data = await repo.findOneBy({ id: param.id }); + + if (data != null) { + data.status_name = param.status_name + data.updated_by = req.auth.data.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 = ['Pharmacy - ItemStatus'] + #swagger.security = [{ + "bearerAuth": [] + }] + #swagger.parameters['id'] = { + in: 'path', + description: 'ItemStatus 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(ItemStatus); + + const existData = await repo.findOne({ where: { id: param.id } }); + if (existData && !param.hard) { + existData.deleted_by = req.auth.data.name; + await OrmHelper.DB.manager.save(existData); + } + + 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 = ['Pharmacy - ItemStatus'] + #swagger.security = [{ + "bearerAuth": [] + }] + + #swagger.parameters['id'] = { + in: 'path', + description: 'ItemStatus ID.', + required: true, + type: 'string' + } + */ + try { + const schema = Joi.object().keys({ + id: Joi.string().uuid().required().label('ID') + }); + + const param: ItemStatus = await schema.validateAsync(req.params); + + const repo = OrmHelper.DB.getRepository(ItemStatus); + + 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/pharmacy/item_type.ts b/src/controllers/pharmacy/item_type.ts new file mode 100644 index 0000000..caff889 --- /dev/null +++ b/src/controllers/pharmacy/item_type.ts @@ -0,0 +1,343 @@ +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 { ItemType, Paging } from "entity"; +import CommonHelper from "../../helpers/common"; +import * as fastcsv from 'fast-csv'; +import dayjs from "dayjs"; +import { ItemTypeModel } from "../../model/item_type"; + +const log: Logger = new Logger({ name: '[ItemTypeController]', type: 'pretty' }); + +export class ItemTypeController { + static async list(req: Request, res: Response, next: NextFunction): Promise { + /* + #swagger.tags = ['Pharmacy - ItemType'] + #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"), + }); + + let param: Paging = await schema.validateAsync(req.query); + + let filter = param.filter && param.filter !== "" ? JSON.parse(param.filter) : {}; + + var query = await ItemTypeModel.list(filter); + + const offset = (param.page - 1) * param.limit; + let limit = param.limit; + + const res_count = query; + const res_list = query + .orderBy("item_type." + param.order_field, param.order_direction) + .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 export(req: Request, res: Response, next: NextFunction): Promise { + /* + #swagger.tags = ['Pharmacy - ItemType'] + #swagger.security = [{ + "bearerAuth": [] + }] + #swagger.parameters['filter'] = { + description: 'Filter with 2 format :
  • Simple format use text plaint will filter eq:code or like %name%
  • Advance format using field existing {status:\'Y\', any:\'SAME AS PLAINT LOGIC\', etc...}
', + in: 'query', + type: 'string' + } + #swagger.parameters['filter'] = { + in: 'query', + type: 'string' + } + #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'), + 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); + + let filter = param.filter && param.filter !== "" ? JSON.parse(param.filter) : {}; + + var query = await ItemTypeModel.list(filter); + const data = await query.getMany(); + + const filename = "item_type.csv"; + + res.setHeader('Content-Type', 'text/csv'); + res.setHeader('Content-Disposition', 'attachment; filename=' + filename); + + const csvStream = fastcsv.format({ + headers: true, + writeHeaders: true, + transform: (row: ItemType): any => ({ + ...row, + created_at: dayjs(row.created_at).format('DD-MM-YYYY HH:MM:ss'), + }) + }); + csvStream.pipe(res); + + const limit = 50; + + const fetchAndWrite = async (page: any) => { + + if (CommonHelper.countObject(data) === 0) { + csvStream.end(); + } else { + data.forEach((item: any) => csvStream.write(item)); + + if (CommonHelper.countObject(data) == limit) { + fetchAndWrite(page + 1); + } else { + csvStream.end(); + } + } + }; + + fetchAndWrite(1); + } 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 = ['Pharmacy - ItemType'] + #swagger.security = [{ + "bearerAuth": [] + }] + + #swagger.requestBody = { + required: true, + content: { + "application/json": { + schema: { + $ref: "#/components/schemas/item_type" + } + } + } + } + */ + try { + const schema = Joi.object().keys({ + type_name: Joi.string().max(256).required().label('Name'), + item_group_id: Joi.string().uuid().required().label('Item Group ID'), + }); + + const param: any = await schema.validateAsync(req.body); + + const data = new ItemType() + data.type_name = param.type_name + data.item_group = param.item_group_id + data.created_by = req.auth.data.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 = ['Pharmacy - ItemType'] + #swagger.security = [{ + "bearerAuth": [] + }] + #swagger.parameters['id'] = { + in: 'path', + description: 'ItemType ID.', + required: true, + type: 'string' + } + + #swagger.requestBody = { + required: true, + content: { + "application/json": { + schema: { + $ref: "#/components/schemas/item_type" + } + } + } + } + */ + + try { + const schema = Joi.object().keys({ + id: Joi.string().uuid().required().label('ID'), + type_name: Joi.string().max(256).required().label('Name'), + item_group_id: Joi.string().uuid().required().label('Item Group ID'), + }); + + req.body.id = req.params['id']; + + const param: any = await schema.validateAsync(req.body); + + const repo = OrmHelper.DB.getRepository(ItemType); + + const data = await repo.findOneBy({ id: param.id }); + + if (data != null) { + data.type_name = param.type_name + data.item_group = param.item_group_id + data.updated_by = req.auth.data.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 = ['Pharmacy - ItemType'] + #swagger.security = [{ + "bearerAuth": [] + }] + #swagger.parameters['id'] = { + in: 'path', + description: 'Item 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(ItemType); + + const existData = await repo.findOne({ where: { id: param.id } }); + if (existData && !param.hard) { + existData.deleted_by = req.auth.data.name; + await OrmHelper.DB.manager.save(existData); + } + + 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 = ['Pharmacy - ItemType'] + #swagger.security = [{ + "bearerAuth": [] + }] + + #swagger.parameters['id'] = { + in: 'path', + description: 'ItemType ID.', + required: true, + type: 'string' + } + */ + try { + const schema = Joi.object().keys({ + id: Joi.string().uuid().required().label('ID') + }); + + const param: ItemType = await schema.validateAsync(req.params); + + const repo = OrmHelper.DB.getRepository(ItemType); + + 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/pharmacy/item_type_detail.ts b/src/controllers/pharmacy/item_type_detail.ts new file mode 100644 index 0000000..9c8e247 --- /dev/null +++ b/src/controllers/pharmacy/item_type_detail.ts @@ -0,0 +1,343 @@ +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 { ItemTypeDetail, Paging } from "entity"; +import CommonHelper from "../../helpers/common"; +import * as fastcsv from 'fast-csv'; +import dayjs from "dayjs"; +import { ItemTypeDetailModel } from "../../model/item_type_detail"; + +const log: Logger = new Logger({ name: '[ItemTypeDetailController]', type: 'pretty' }); + +export class ItemTypeDetailController { + static async list(req: Request, res: Response, next: NextFunction): Promise { + /* + #swagger.tags = ['Pharmacy - ItemTypeDetail'] + #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"), + }); + + let param: Paging = await schema.validateAsync(req.query); + + let filter = param.filter && param.filter !== "" ? JSON.parse(param.filter) : {}; + + var query = await ItemTypeDetailModel.list(filter); + + const offset = (param.page - 1) * param.limit; + let limit = param.limit; + + const res_count = query; + const res_list = query + .orderBy("item_type_detail." + param.order_field, param.order_direction) + .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 export(req: Request, res: Response, next: NextFunction): Promise { + /* + #swagger.tags = ['Pharmacy - ItemTypeDetail'] + #swagger.security = [{ + "bearerAuth": [] + }] + #swagger.parameters['filter'] = { + description: 'Filter with 2 format :
  • Simple format use text plaint will filter eq:code or like %name%
  • Advance format using field existing {status:\'Y\', any:\'SAME AS PLAINT LOGIC\', etc...}
', + in: 'query', + type: 'string' + } + #swagger.parameters['filter'] = { + in: 'query', + type: 'string' + } + #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'), + 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); + + let filter = param.filter && param.filter !== "" ? JSON.parse(param.filter) : {}; + + var query = await ItemTypeDetailModel.list(filter); + const data = await query.getMany(); + + const filename = "item_type_detail.csv"; + + res.setHeader('Content-Type', 'text/csv'); + res.setHeader('Content-Disposition', 'attachment; filename=' + filename); + + const csvStream = fastcsv.format({ + headers: true, + writeHeaders: true, + transform: (row: ItemTypeDetail): any => ({ + ...row, + created_at: dayjs(row.created_at).format('DD-MM-YYYY HH:MM:ss'), + }) + }); + csvStream.pipe(res); + + const limit = 50; + + const fetchAndWrite = async (page: any) => { + + if (CommonHelper.countObject(data) === 0) { + csvStream.end(); + } else { + data.forEach((item: any) => csvStream.write(item)); + + if (CommonHelper.countObject(data) == limit) { + fetchAndWrite(page + 1); + } else { + csvStream.end(); + } + } + }; + + fetchAndWrite(1); + } 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 = ['Pharmacy - ItemTypeDetail'] + #swagger.security = [{ + "bearerAuth": [] + }] + + #swagger.requestBody = { + required: true, + content: { + "application/json": { + schema: { + $ref: "#/components/schemas/item_type_detail" + } + } + } + } + */ + try { + const schema = Joi.object().keys({ + type_detail_name: Joi.string().max(256).required().label('Name'), + item_type_id: Joi.string().uuid().required().label('Item Group ID'), + }); + + const param: any = await schema.validateAsync(req.body); + + const data = new ItemTypeDetail() + data.type_detail_name = param.type_detail_name + data.item_type = param.item_type_id + data.created_by = req.auth.data.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 = ['Pharmacy - ItemTypeDetail'] + #swagger.security = [{ + "bearerAuth": [] + }] + #swagger.parameters['id'] = { + in: 'path', + description: 'ItemTypeDetail ID.', + required: true, + type: 'string' + } + + #swagger.requestBody = { + required: true, + content: { + "application/json": { + schema: { + $ref: "#/components/schemas/item_type_detail" + } + } + } + } + */ + + try { + const schema = Joi.object().keys({ + id: Joi.string().uuid().required().label('ID'), + type_detail_name: Joi.string().max(256).required().label('Name'), + item_type_id: Joi.string().uuid().required().label('Item Group ID'), + }); + + req.body.id = req.params['id']; + + const param: any = await schema.validateAsync(req.body); + + const repo = OrmHelper.DB.getRepository(ItemTypeDetail); + + const data = await repo.findOneBy({ id: param.id }); + + if (data != null) { + data.type_detail_name = param.type_detail_name + data.item_type = param.item_type_id + data.updated_by = req.auth.data.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 = ['Pharmacy - ItemTypeDetail'] + #swagger.security = [{ + "bearerAuth": [] + }] + #swagger.parameters['id'] = { + in: 'path', + description: 'Item Type Detail 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(ItemTypeDetail); + + const existData = await repo.findOne({ where: { id: param.id } }); + if (existData && !param.hard) { + existData.deleted_by = req.auth.data.name; + await OrmHelper.DB.manager.save(existData); + } + + 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 = ['Pharmacy - ItemTypeDetail'] + #swagger.security = [{ + "bearerAuth": [] + }] + + #swagger.parameters['id'] = { + in: 'path', + description: 'ItemTypeDetail ID.', + required: true, + type: 'string' + } + */ + try { + const schema = Joi.object().keys({ + id: Joi.string().uuid().required().label('ID') + }); + + const param: ItemTypeDetail = await schema.validateAsync(req.params); + + const repo = OrmHelper.DB.getRepository(ItemTypeDetail); + + 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/pharmacy/unit.ts b/src/controllers/pharmacy/unit.ts new file mode 100644 index 0000000..e48b2cd --- /dev/null +++ b/src/controllers/pharmacy/unit.ts @@ -0,0 +1,339 @@ +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 { Unit, Paging } from "entity"; +import CommonHelper from "../../helpers/common"; +import * as fastcsv from 'fast-csv'; +import dayjs from "dayjs"; +import { UnitModel } from "../../model/unit"; + +const log: Logger = new Logger({ name: '[UnitController]', type: 'pretty' }); + +export class UnitController { + static async list(req: Request, res: Response, next: NextFunction): Promise { + /* + #swagger.tags = ['Pharmacy - Unit'] + #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"), + }); + + let param: Paging = await schema.validateAsync(req.query); + + let filter = param.filter && param.filter !== "" ? JSON.parse(param.filter) : {}; + + var query = await UnitModel.list(filter); + + const offset = (param.page - 1) * param.limit; + let limit = param.limit; + + const res_count = query; + const res_list = query + .orderBy("unit." + param.order_field, param.order_direction) + .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 export(req: Request, res: Response, next: NextFunction): Promise { + /* + #swagger.tags = ['Pharmacy - Unit'] + #swagger.security = [{ + "bearerAuth": [] + }] + #swagger.parameters['filter'] = { + description: 'Filter with 2 format :
  • Simple format use text plaint will filter eq:code or like %name%
  • Advance format using field existing {status:\'Y\', any:\'SAME AS PLAINT LOGIC\', etc...}
', + in: 'query', + type: 'string' + } + #swagger.parameters['filter'] = { + in: 'query', + type: 'string' + } + #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'), + 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); + + let filter = param.filter && param.filter !== "" ? JSON.parse(param.filter) : {}; + + var query = await UnitModel.list(filter); + const data = await query.getMany(); + + const filename = "unit.csv"; + + res.setHeader('Content-Type', 'text/csv'); + res.setHeader('Content-Disposition', 'attachment; filename=' + filename); + + const csvStream = fastcsv.format({ + headers: true, + writeHeaders: true, + transform: (row: Unit): any => ({ + ...row, + created_at: dayjs(row.created_at).format('DD-MM-YYYY HH:MM:ss'), + }) + }); + csvStream.pipe(res); + + const limit = 50; + + const fetchAndWrite = async (page: any) => { + + if (CommonHelper.countObject(data) === 0) { + csvStream.end(); + } else { + data.forEach((item: any) => csvStream.write(item)); + + if (CommonHelper.countObject(data) == limit) { + fetchAndWrite(page + 1); + } else { + csvStream.end(); + } + } + }; + + fetchAndWrite(1); + } 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 = ['Pharmacy - Unit'] + #swagger.security = [{ + "bearerAuth": [] + }] + + #swagger.requestBody = { + required: true, + content: { + "application/json": { + schema: { + $ref: "#/components/schemas/unit" + } + } + } + } + */ + try { + const schema = Joi.object().keys({ + unit_name: Joi.string().max(256).required().label('Name'), + }); + + const param: any = await schema.validateAsync(req.body); + + const data = new Unit() + data.unit_name = param.unit_name + data.created_by = req.auth.data.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 = ['Pharmacy - Unit'] + #swagger.security = [{ + "bearerAuth": [] + }] + #swagger.parameters['id'] = { + in: 'path', + description: 'Unit ID.', + required: true, + type: 'string' + } + + #swagger.requestBody = { + required: true, + content: { + "application/json": { + schema: { + $ref: "#/components/schemas/unit" + } + } + } + } + */ + + try { + const schema = Joi.object().keys({ + id: Joi.string().uuid().required().label('ID'), + unit_name: Joi.string().max(256).required().label('Name'), + }); + + req.body.id = req.params['id']; + + const param: any = await schema.validateAsync(req.body); + + const repo = OrmHelper.DB.getRepository(Unit); + + const data = await repo.findOneBy({ id: param.id }); + + if (data != null) { + data.unit_name = param.unit_name + data.updated_by = req.auth.data.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 = ['Pharmacy - Unit'] + #swagger.security = [{ + "bearerAuth": [] + }] + #swagger.parameters['id'] = { + in: 'path', + description: 'Unit 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(Unit); + + const existData = await repo.findOne({ where: { id: param.id } }); + if (existData && !param.hard) { + existData.deleted_by = req.auth.data.name; + await OrmHelper.DB.manager.save(existData); + } + + 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 = ['Pharmacy - Unit'] + #swagger.security = [{ + "bearerAuth": [] + }] + + #swagger.parameters['id'] = { + in: 'path', + description: 'Unit ID.', + required: true, + type: 'string' + } + */ + try { + const schema = Joi.object().keys({ + id: Joi.string().uuid().required().label('ID') + }); + + const param: Unit = await schema.validateAsync(req.params); + + const repo = OrmHelper.DB.getRepository(Unit); + + 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/helpers/orm.ts b/src/helpers/orm.ts index 5a47346..88979f9 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 { 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 } from 'entity' +import { 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 } from 'entity' export class OrmHelper { static DB: DataSource = null @@ -20,7 +20,22 @@ export class OrmHelper { database: String(config.get("database.database")), synchronize: true, logging: config.get('database.logging'), - entities: [Menu, Administrativu, Aldeia, District, 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], + entities: [Menu, Administrativu, Aldeia, District, 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, ItemGroup, + ItemOrigin, + ItemType, + ItemTypeDetail, + Unit, + ItemCategory, + ItemStatus, + UsageInstructions, + UsageTime, + ItemClass, + ItemClassDetail, + GenericName, + Factory, + Supplier, + FactoryToSupplier, + ItemMaster], subscribers: [], migrations: [], }) diff --git a/src/model/item_category.ts b/src/model/item_category.ts new file mode 100644 index 0000000..26b6e4a --- /dev/null +++ b/src/model/item_category.ts @@ -0,0 +1,23 @@ +import { ItemCategory } from "entity"; +import { SelectQueryBuilder } from "typeorm"; +import CommonHelper from "../helpers/common"; +import { OrmHelper } from "../helpers/orm"; + +export class ItemCategoryModel { + static async list(filter = {}): Promise> { + const repo = OrmHelper.DB.getRepository(ItemCategory); + let whereAttr: string[] = []; + let whereVal: any = {}; + if (filter && Object.keys(filter).length > 0) { + whereAttr = [...whereAttr, ...CommonHelper.handleQueryFilter(filter, "item_category").whereAttr]; + whereVal = { ...whereVal, ...CommonHelper.handleQueryFilter(filter, "item_category").whereVal }; + } + + var query = repo.createQueryBuilder("item_category"); + if (whereAttr.length != 0) { + query = query.where(whereAttr.join(" and "), whereVal); + } + + return query; + } +} \ No newline at end of file diff --git a/src/model/item_group.ts b/src/model/item_group.ts new file mode 100644 index 0000000..7eb189a --- /dev/null +++ b/src/model/item_group.ts @@ -0,0 +1,23 @@ +import { ItemGroup } from "entity"; +import { SelectQueryBuilder } from "typeorm"; +import CommonHelper from "../helpers/common"; +import { OrmHelper } from "../helpers/orm"; + +export class ItemGroupModel { + static async list(filter = {}): Promise> { + const repo = OrmHelper.DB.getRepository(ItemGroup); + let whereAttr: string[] = []; + let whereVal: any = {}; + if (filter && Object.keys(filter).length > 0) { + whereAttr = [...whereAttr, ...CommonHelper.handleQueryFilter(filter, "item_group").whereAttr]; + whereVal = { ...whereVal, ...CommonHelper.handleQueryFilter(filter, "item_group").whereVal }; + } + + var query = repo.createQueryBuilder("item_group"); + if (whereAttr.length != 0) { + query = query.where(whereAttr.join(" and "), whereVal); + } + + return query; + } +} \ No newline at end of file diff --git a/src/model/item_origin.ts b/src/model/item_origin.ts new file mode 100644 index 0000000..3f93eb5 --- /dev/null +++ b/src/model/item_origin.ts @@ -0,0 +1,23 @@ +import { SelectQueryBuilder } from "typeorm"; +import CommonHelper from "../helpers/common"; +import { OrmHelper } from "../helpers/orm"; +import { ItemOrigin } from "entity"; + +export class ItemOriginModel { + static async list(filter = {}): Promise> { + const repo = OrmHelper.DB.getRepository(ItemOrigin); + let whereAttr: string[] = []; + let whereVal: any = {}; + if (filter && Object.keys(filter).length > 0) { + whereAttr = [...whereAttr, ...CommonHelper.handleQueryFilter(filter, "item_origin").whereAttr]; + whereVal = { ...whereVal, ...CommonHelper.handleQueryFilter(filter, "item_origin").whereVal }; + } + + var query = repo.createQueryBuilder("item_origin"); + if (whereAttr.length != 0) { + query = query.where(whereAttr.join(" and "), whereVal); + } + + return query; + } +} \ No newline at end of file diff --git a/src/model/item_status.ts b/src/model/item_status.ts new file mode 100644 index 0000000..c5cb9a5 --- /dev/null +++ b/src/model/item_status.ts @@ -0,0 +1,23 @@ +import { ItemStatus } from "entity"; +import { SelectQueryBuilder } from "typeorm"; +import CommonHelper from "../helpers/common"; +import { OrmHelper } from "../helpers/orm"; + +export class ItemStatusModel { + static async list(filter = {}): Promise> { + const repo = OrmHelper.DB.getRepository(ItemStatus); + let whereAttr: string[] = []; + let whereVal: any = {}; + if (filter && Object.keys(filter).length > 0) { + whereAttr = [...whereAttr, ...CommonHelper.handleQueryFilter(filter, "item_status").whereAttr]; + whereVal = { ...whereVal, ...CommonHelper.handleQueryFilter(filter, "item_status").whereVal }; + } + + var query = repo.createQueryBuilder("item_status"); + if (whereAttr.length != 0) { + query = query.where(whereAttr.join(" and "), whereVal); + } + + return query; + } +} \ No newline at end of file diff --git a/src/model/item_type.ts b/src/model/item_type.ts new file mode 100644 index 0000000..570af5e --- /dev/null +++ b/src/model/item_type.ts @@ -0,0 +1,23 @@ +import { SelectQueryBuilder } from "typeorm"; +import CommonHelper from "../helpers/common"; +import { OrmHelper } from "../helpers/orm"; +import { ItemType } from "entity"; + +export class ItemTypeModel { + static async list(filter = {}): Promise> { + const repo = OrmHelper.DB.getRepository(ItemType); + let whereAttr: string[] = []; + let whereVal: any = {}; + if (filter && Object.keys(filter).length > 0) { + whereAttr = [...whereAttr, ...CommonHelper.handleQueryFilter(filter, "item_type").whereAttr]; + whereVal = { ...whereVal, ...CommonHelper.handleQueryFilter(filter, "item_type").whereVal }; + } + + var query = repo.createQueryBuilder("item_type").leftJoinAndSelect("item_type.item_group", "item_group"); + if (whereAttr.length != 0) { + query = query.where(whereAttr.join(" and "), whereVal); + } + + return query; + } +} \ No newline at end of file diff --git a/src/model/item_type_detail.ts b/src/model/item_type_detail.ts new file mode 100644 index 0000000..b740ba3 --- /dev/null +++ b/src/model/item_type_detail.ts @@ -0,0 +1,23 @@ +import { SelectQueryBuilder } from "typeorm"; +import CommonHelper from "../helpers/common"; +import { OrmHelper } from "../helpers/orm"; +import { ItemTypeDetail } from "entity"; + +export class ItemTypeDetailModel { + static async list(filter = {}): Promise> { + const repo = OrmHelper.DB.getRepository(ItemTypeDetail); + let whereAttr: string[] = []; + let whereVal: any = {}; + if (filter && Object.keys(filter).length > 0) { + whereAttr = [...whereAttr, ...CommonHelper.handleQueryFilter(filter, "item_type_detail").whereAttr]; + whereVal = { ...whereVal, ...CommonHelper.handleQueryFilter(filter, "item_type_detail").whereVal }; + } + + var query = repo.createQueryBuilder("item_type_detail").leftJoinAndSelect("item_type_detail.item_type", "item_type"); + if (whereAttr.length != 0) { + query = query.where(whereAttr.join(" and "), whereVal); + } + + return query; + } +} \ No newline at end of file diff --git a/src/model/unit.ts b/src/model/unit.ts new file mode 100644 index 0000000..8bbe643 --- /dev/null +++ b/src/model/unit.ts @@ -0,0 +1,23 @@ +import { Unit } from "entity"; +import { SelectQueryBuilder } from "typeorm"; +import CommonHelper from "../helpers/common"; +import { OrmHelper } from "../helpers/orm"; + +export class UnitModel { + static async list(filter = {}): Promise> { + const repo = OrmHelper.DB.getRepository(Unit); + let whereAttr: string[] = []; + let whereVal: any = {}; + if (filter && Object.keys(filter).length > 0) { + whereAttr = [...whereAttr, ...CommonHelper.handleQueryFilter(filter, "unit").whereAttr]; + whereVal = { ...whereVal, ...CommonHelper.handleQueryFilter(filter, "unit").whereVal }; + } + + var query = repo.createQueryBuilder("unit"); + if (whereAttr.length != 0) { + query = query.where(whereAttr.join(" and "), whereVal); + } + + return query; + } +} \ No newline at end of file diff --git a/src/routes/private.ts b/src/routes/private.ts index 5a823fb..a140f6e 100644 --- a/src/routes/private.ts +++ b/src/routes/private.ts @@ -28,6 +28,13 @@ import { ExaminationTypeController } from '../controllers/examination_type'; import { ServiceExaminationController } from '../controllers/service_examination'; import { LaboratoryController } from '../controllers/laboratory'; import { HospitalInformationController } from '../controllers/hospital_information'; +import { ItemCategoryController } from '../controllers/pharmacy/item_category'; +import { ItemStatusController } from '../controllers/pharmacy/item_status'; +import { UnitController } from '../controllers/pharmacy/unit'; +import { ItemTypeDetailController } from '../controllers/pharmacy/item_type_detail'; +import { ItemTypeController } from '../controllers/pharmacy/item_type'; +import { ItemOriginController } from '../controllers/pharmacy/item_origin'; +import { ItemGroupController } from '../controllers/pharmacy/item_group'; export class RoutePrivate { static setup(app: express.Application) { @@ -214,5 +221,54 @@ export class RoutePrivate { app.post('/api/hospital-information/upload-logo', HospitalInformationController.uploadlogo) app.delete('/api/hospital-information/delete-logo', HospitalInformationController.deletelogo) + app.get('/api/item-group/list', ItemGroupController.list) + app.get('/api/item-group/export', ItemGroupController.export) + app.post('/api/item-group/create', ItemGroupController.create) + app.put('/api/item-group/update/:id', ItemGroupController.update) + app.delete('/api/item-group/delete/:id/:hard', ItemGroupController.delete) + app.put('/api/item-group/restore/:id', ItemGroupController.restore) + + app.get('/api/item-origin/list', ItemOriginController.list) + app.get('/api/item-origin/export', ItemOriginController.export) + app.post('/api/item-origin/create', ItemOriginController.create) + app.put('/api/item-origin/update/:id', ItemOriginController.update) + app.delete('/api/item-origin/delete/:id/:hard', ItemOriginController.delete) + app.put('/api/item-origin/restore/:id', ItemOriginController.restore) + + app.get('/api/item-type/list', ItemTypeController.list) + app.get('/api/item-type/export', ItemTypeController.export) + app.post('/api/item-type/create', ItemTypeController.create) + app.put('/api/item-type/update/:id', ItemTypeController.update) + app.delete('/api/item-type/delete/:id/:hard', ItemTypeController.delete) + app.put('/api/item-type/restore/:id', ItemTypeController.restore) + + app.get('/api/item-type-detail/list', ItemTypeDetailController.list) + app.get('/api/item-type-detail/export', ItemTypeDetailController.export) + app.post('/api/item-type-detail/create', ItemTypeDetailController.create) + app.put('/api/item-type-detail/update/:id', ItemTypeDetailController.update) + app.delete('/api/item-type-detail/delete/:id/:hard', ItemTypeDetailController.delete) + app.put('/api/item-type-detail/restore/:id', ItemTypeDetailController.restore) + + app.get('/api/unit/list', UnitController.list) + app.get('/api/unit/export', UnitController.export) + app.post('/api/unit/create', UnitController.create) + app.put('/api/unit/update/:id', UnitController.update) + app.delete('/api/unit/delete/:id/:hard', UnitController.delete) + app.put('/api/unit/restore/:id', UnitController.restore) + + app.get('/api/item-category/list', ItemCategoryController.list) + app.get('/api/item-category/export', ItemCategoryController.export) + app.post('/api/item-category/create', ItemCategoryController.create) + app.put('/api/item-category/update/:id', ItemCategoryController.update) + app.delete('/api/item-category/delete/:id/:hard', ItemCategoryController.delete) + app.put('/api/item-category/restore/:id', ItemCategoryController.restore) + + app.get('/api/item-status/list', ItemStatusController.list) + app.get('/api/item-status/export', ItemStatusController.export) + app.post('/api/item-status/create', ItemStatusController.create) + app.put('/api/item-status/update/:id', ItemStatusController.update) + app.delete('/api/item-status/delete/:id/:hard', ItemStatusController.delete) + app.put('/api/item-status/restore/:id', ItemStatusController.restore) + } } \ No newline at end of file diff --git a/src/swagger/builder.js b/src/swagger/builder.js index 386e87c..3d29682 100644 --- a/src/swagger/builder.js +++ b/src/swagger/builder.js @@ -201,6 +201,32 @@ const doc = { files: { $file_name: "File Name", }, + item_group: { + $group_name: 'ItemGroup name', + }, + item_origin: { + $origin_name: 'ItemOrigin name', + $origin_description: 'ItemOrigin Desc', + $department: 'Department name', + $account: 'Account name', + }, + item_type: { + $type_name: 'ItemType name', + $item_group_id: 'ItemGroup Id' + }, + item_type_detail: { + $type_detail_name: 'ItemTypeDetail name', + $item_type_id: 'ItemType Id' + }, + unit: { + $unit_name: 'Unit name', + }, + item_category: { + $category_name: 'ItemCategory name', + }, + item_status: { + $status_name: 'Itemstatus name', + }, }, parameters: {