diff --git a/src/controllers/PosLevelController.ts b/src/controllers/PosLevelController.ts new file mode 100644 index 0000000..145786b --- /dev/null +++ b/src/controllers/PosLevelController.ts @@ -0,0 +1,274 @@ +import { + Controller, + Get, + Post, + Put, + Delete, + Patch, + Route, + Security, + Tags, + Body, + Path, + Request, + Example, + SuccessResponse, + Response, + Query, +} from "tsoa"; +import { AppDataSource } from "../database/data-source"; +import HttpSuccess from "../interfaces/http-success"; +import HttpStatusCode from "../interfaces/http-status"; +import { PosType } from "../entities/PosType"; +import { PosLevel, CreatePosLevel, UpdatePosLevel } from "../entities/PosLevel"; +import HttpError from "../interfaces/http-error"; +import { Not } from "typeorm"; + +@Route("api/v1/salary/pos/level") +@Tags("PosLevel") +@Security("bearerAuth") +@Response( + HttpStatusCode.INTERNAL_SERVER_ERROR, + "เกิดข้อผิดพลาด ไม่สามารถแสดงรายการได้ กรุณาลองใหม่ในภายหลัง", +) +@SuccessResponse(HttpStatusCode.OK, "สำเร็จ") + +export class PosLevelController extends Controller { + + private posTypeRepository = AppDataSource.getRepository(PosType); + private posLevelRepository = AppDataSource.getRepository(PosLevel); + + /** + * API เพิ่มระดับตำแหน่ง + * + * @summary เพิ่มระดับตำแหน่ง (ADMIN) + * + */ + @Post() + @Example( + { + posLevelName: "นักบริหาร", + posLevelRank: 1, + posLevelAuthority: "HEAD", + posTypeId: "08db9e81-fc46-4e95-8b33-be4ca0016abf" + }, + ) + async createLevel( + @Body() + requestBody: CreatePosLevel, + @Request() request: { user: Record }, + ) { + const posLevel = Object.assign(new PosLevel(), requestBody); + if (!posLevel) { + throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูล"); + } + const chkPosTypeId = await this.posTypeRepository.findOne({ where: { + id: requestBody.posTypeId } + }) + if(!chkPosTypeId){ + throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูล posTypeId ไอดีนี้ : " + requestBody.posTypeId); + } + + const chkPosLevelName = await this.posLevelRepository.findOne({ where: { + posTypeId: requestBody.posTypeId, //ระดับประเภทเดียวกัน ชื่อระดับตำแหน่ง ห้ามซ้ำ + posLevelName: requestBody.posLevelName } + }) + if(chkPosLevelName){ + throw new HttpError(HttpStatusCode.NOT_FOUND, "ชื่อระดับตำแหน่ง: " + requestBody.posLevelName + " มีอยู่ในระบบแล้ว"); + } + + const validPosLevelAuthority = ["HEAD", "DEPUTY", "GOVERNOR"]; + if ( + requestBody.posLevelAuthority == null || + !validPosLevelAuthority.includes(requestBody.posLevelAuthority.toUpperCase()) + ) { + throw new HttpError(HttpStatusCode.NOT_FOUND, "not found. posLevelAuthority"); + } + + try { + posLevel.createdUserId = request.user.sub; + posLevel.createdFullName = request.user.name; + posLevel.lastUpdateUserId = request.user.sub; + posLevel.lastUpdateFullName = request.user.name; + await this.posLevelRepository.save(posLevel); + return new HttpSuccess(posLevel); + } catch (error) { + return error; + } + } + + /** + * API แก้ไขระดับตำแหน่ง + * + * @summary แก้ไขระดับตำแหน่ง (ADMIN) + * + * @param {string} id Id ระดับตำแหน่ง + */ + @Put("{id}") + @Example( + { + positionName: "นักบริหาร", + posTypeRank: 1, + }, + ) + async editLevel( + @Path() id: string, + @Body() requestBody: UpdatePosLevel, + @Request() request: { user: Record }, + ) { + const posLevel = await this.posLevelRepository.findOne({ where: { id } }); + if (!posLevel) { + throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลไอดีนี้ : " + id); + } + + const chkPosTypeId = await this.posTypeRepository.findOne({ where: { + id: requestBody.posTypeId } + }) + if(!chkPosTypeId){ + throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูล posTypeId ไอดีนี้ : " + requestBody.posTypeId); + } + + const chkPosLevelName = await this.posLevelRepository.findOne({ where: { + id: Not(id), + posTypeId: requestBody.posTypeId, + posLevelName: requestBody.posLevelName } + }) + if(chkPosLevelName){ + throw new HttpError(HttpStatusCode.NOT_FOUND, "ชื่อระดับตำแหน่ง: " + requestBody.posLevelName + " มีอยู่ในระบบแล้ว"); + } + const validPosLevelAuthority = ["HEAD", "DEPUTY", "GOVERNOR"]; + if ( + requestBody.posLevelAuthority == null || + !validPosLevelAuthority.includes(requestBody.posLevelAuthority.toUpperCase()) + ) { + throw new HttpError(HttpStatusCode.NOT_FOUND, "not found. posLevelAuthority"); + } + + try { + posLevel.lastUpdateUserId = request.user.sub; + posLevel.lastUpdateFullName = request.user.name; + this.posLevelRepository.merge(posLevel, requestBody); + await this.posLevelRepository.save(posLevel); + return new HttpSuccess(posLevel.id); + } catch (error) { + return error; + } + } + + /** + * API ลบระดับตำแหน่ง + * + * @summary ลบระดับตำแหน่ง (ADMIN) + * + * @param {string} id Id ระดับตำแหน่ง + */ + @Delete("{id}") + async deleteLevel(@Path() id: string) { + const delPosLevel = await this.posLevelRepository.findOne({ where: { id } }); + if (!delPosLevel) { + throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลไอดีนี้ : " + id); + } + try { + await this.posLevelRepository.remove(delPosLevel); + return new HttpSuccess(); + } catch (error) { + return error; + } + } + + /** + * API รายละเอียดระดับตำแหน่ง + * + * @summary รายละเอียดระดับตำแหน่ง (ADMIN) + * + * @param {string} id Id ระดับตำแหน่ง + */ + @Get("{id}") + @Example( + { + id: "00000000-0000-0000-0000-000000000000", + posLevelName: "นักบริหาร", + posLevelRank: 1, + posLevelAuthority: "HEAD", + posTypes: { + id: "00000000-0000-0000-0000-000000000000", + posTypeName: "นักบริหาร", + posTypeRank: 1, + }, + }, + ) + async GetLevelDetail(@Path() id: string) { + try { + const getPosType = await this.posLevelRepository.findOne({ + select: ["id", "posLevelName", "posLevelRank", "posLevelAuthority"], + relations: ["posType"], + where: { id: id } + }); + if (!getPosType) { + throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลไอดีนี้ : " + id); + } + + const mapPosLevel = { + id: getPosType.id, + posLevelName: getPosType.posLevelName, + posLevelRank: getPosType.posLevelRank, + posLevelAuthority: getPosType.posLevelAuthority, + posTypes:{ + id: getPosType.posType.id, + posTypeName: getPosType.posType.posTypeName, + posTypeRank: getPosType.posType.posTypeRank + } + } + + return new HttpSuccess(mapPosLevel); + } catch (error) { + return error; + } + } + + /** + * API รายการระดับตำแหน่ง + * + * @summary SLR_007 - รายการระดับตำแหน่ง #7 + * + */ + @Get() + @Example([ + { + id: "00000000-0000-0000-0000-000000000000", + posLevelName: "นักบริหาร", + posLevelRank: 1, + posLevelAuthority: "HEAD", + posTypes: { + id: "00000000-0000-0000-0000-000000000000", + posTypeName: "นักบริหาร", + posTypeRank: 1, + }, + }, + ]) + async GetPosLevel() { + try { + const posLevel = await this.posLevelRepository.find({ + select: ["id", "posLevelName", "posLevelRank", "posLevelAuthority", "posTypeId"], + relations: ["posType"], + }); + if (!posLevel) { + return new HttpSuccess([]); + } + const mapPosLevel = posLevel.map((item) => ({ + id: item.id, + posLevelName: item.posLevelName, + posLevelRank: item.posLevelRank, + posLevelAuthority: item.posLevelAuthority, + posTypes: { + id: item.posType.id, + posTypeName: item.posType.posTypeName, + posTypeRank: item.posType.posTypeRank, + } + })); + return new HttpSuccess(mapPosLevel); + } catch (error) { + return error; + } + } +} diff --git a/src/controllers/PosTypeController.ts b/src/controllers/PosTypeController.ts new file mode 100644 index 0000000..7a8fce4 --- /dev/null +++ b/src/controllers/PosTypeController.ts @@ -0,0 +1,249 @@ +import { + Controller, + Get, + Post, + Put, + Delete, + Patch, + Route, + Security, + Tags, + Body, + Path, + Request, + Example, + SuccessResponse, + Response, + Query, +} from "tsoa"; +import { AppDataSource } from "../database/data-source"; +import HttpSuccess from "../interfaces/http-success"; +import HttpStatusCode from "../interfaces/http-status"; +import { PosType, CreatePosType, UpdatePosType } from "../entities/PosType"; +import { PosLevel } from "../entities/PosLevel"; +import HttpError from "../interfaces/http-error"; +import { Not } from "typeorm"; + +@Route("api/v1/salary/pos/type") +@Tags("PosType") +@Security("bearerAuth") +@Response( + HttpStatusCode.INTERNAL_SERVER_ERROR, + "เกิดข้อผิดพลาด ไม่สามารถแสดงรายการได้ กรุณาลองใหม่ในภายหลัง", +) +@SuccessResponse(HttpStatusCode.OK, "สำเร็จ") + +export class PosTypeController extends Controller { + + private posTypeRepository = AppDataSource.getRepository(PosType); + private posLevelRepository = AppDataSource.getRepository(PosLevel); + + /** + * API เพิ่มประเภทตำแหน่ง + * + * @summary เพิ่มประเภทตำแหน่ง (ADMIN) + * + */ + @Post() + @Example( + { + positionName: "นักบริหาร", + posTypeRank: 1, + }, + ) + async createType( + @Body() + requestBody: CreatePosType, + @Request() request: { user: Record }, + ) { + const posType = Object.assign(new PosType(), requestBody); + if (!posType) { + throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูล"); + } + const chkPosTypeName = await this.posTypeRepository.findOne({ where: { + posTypeName: requestBody.posTypeName } + }) + if(chkPosTypeName){ + throw new HttpError(HttpStatusCode.NOT_FOUND, "ชื่อประเภทตำแหน่ง: " + requestBody.posTypeName + " มีอยู่ในระบบแล้ว"); + } + try { + posType.createdUserId = request.user.sub; + posType.createdFullName = request.user.name; + posType.lastUpdateUserId = request.user.sub; + posType.lastUpdateFullName = request.user.name; + await this.posTypeRepository.save(posType); + return new HttpSuccess(posType); + } catch (error) { + return error; + } + } + + /** + * API แก้ไขประเภทตำแหน่ง + * + * @summary แก้ไขประเภทตำแหน่ง (ADMIN) + * + * @param {string} id Id ประเภทตำแหน่ง + */ + @Put("{id}") + @Example( + { + positionName: "นักบริหาร", + posTypeRank: 1, + }, + ) + async editType( + @Path() id: string, + @Body() requestBody: UpdatePosType, + @Request() request: { user: Record }, + ) { + const posType = await this.posTypeRepository.findOne({ where: { id } }); + if (!posType) { + throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลไอดีนี้ : " + id); + } + const chkPosTypeName = await this.posTypeRepository.findOne({ where: { + id: Not(id), + posTypeName: requestBody.posTypeName } + }) + if(chkPosTypeName){ + throw new HttpError(HttpStatusCode.NOT_FOUND, "ชื่อประเภทตำแหน่ง: " + requestBody.posTypeName + " มีอยู่ในระบบแล้ว"); + } + try { + posType.lastUpdateUserId = request.user.sub; + posType.lastUpdateFullName = request.user.name; + this.posTypeRepository.merge(posType, requestBody); + await this.posTypeRepository.save(posType); + return new HttpSuccess(posType.id); + } catch (error) { + return error; + } + } + + /** + * API ลบประเภทตำแหน่ง + * + * @summary ลบประเภทตำแหน่ง (ADMIN) + * + * @param {string} id Id ตำแหน่ง + */ + @Delete("{id}") + async deleteType(@Path() id: string) { + const delPosType = await this.posTypeRepository.findOne({ where: { id } }); + if (!delPosType) { + throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลไอดีนี้ : " + id); + } + const IdExitsInLevel = await this.posLevelRepository.find({ + where: { posTypeId: id } + }) + if(IdExitsInLevel.length > 0){ + throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่สามารถลบได้ เนื่องจาก id ผูกกับ posLevel",); + } + + try { + await this.posTypeRepository.remove(delPosType); + return new HttpSuccess(); + } catch (error) { + return error; + } + } + + /** + * API รายละเอียดประเภทตำแหน่ง + * + * @summary รายละเอียดประเภทตำแหน่ง (ADMIN) + * + * @param {string} id Id ประเภทตำแหน่ง + */ + @Get("{id}") + @Example([ + { + id: "00000000-0000-0000-0000-000000000000", + posTypeName: "นักบริหาร", + posLevelposTypeRanks: 1, + posLevels: [ + { + id: "00000000-0000-0000-0000-000000000000", + posLevelName: "นักบริหาร", + posLevelRank: 1, + posLevelAuthority: "HEAD" + } + ] + }, + ]) + async GetTypeDetail(@Path() id: string) { + try { + const getPosType = await this.posTypeRepository.findOne({ + select: ["id", "posTypeName", "posTypeRank"], + relations: ["posLevels"], + where: { id: id } + }); + if (!getPosType) { + throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลไอดีนี้ : " + id); + } + + const mapGetPosType = { + id : getPosType.id, + posTypeName : getPosType.posTypeName, + posTypeRank : getPosType.posTypeRank, + posLevels : getPosType.posLevels.map((posLevel) => ({ + id: posLevel.id, + posLevelName: posLevel.posLevelName, + posLevelRank: posLevel.posLevelRank, + posLevelAuthority: posLevel.posLevelAuthority, + })), + } + + return new HttpSuccess(mapGetPosType); + } catch (error) { + return error; + } + } + + /** + * API รายการประเภทตำแหน่ง + * + * @summary SLR_006 - รายการประเภทตำแหน่ง #6 + * + */ + @Get() + @Example([ + { + id: "00000000-0000-0000-0000-000000000000", + posTypeName: "นักบริหาร", + posTypeRank: 1, + posLevels: [ + { + id: "00000000-0000-0000-0000-000000000000", + posLevelName: "นักบริหาร", + posLevelRank: 1, + posLevelAuthority: "HEAD", + }, + ], + }, + ]) + async GetPosType() { + try { + const posType = await this.posTypeRepository.find({ + select: ["id", "posTypeName", "posTypeRank"], + relations: ["posLevels"], + }); + if (!posType) { + return new HttpSuccess([]); + } + const mapPosType = posType.map((item) => ({ + id: item.id, + posTypeName: item.posTypeName, + posTypeRank: item.posTypeRank, + posLevels: item.posLevels.map((posLevel) => ({ + id: posLevel.id, + posLevelName: posLevel.posLevelName, + posLevelRank: posLevel.posLevelRank, + posLevelAuthority: posLevel.posLevelAuthority, + })), + })); + return new HttpSuccess(mapPosType); + } catch (error) { + return error; + } + } +} diff --git a/src/controllers/SalaryRankController.ts b/src/controllers/SalaryRankController.ts new file mode 100644 index 0000000..0050ef3 --- /dev/null +++ b/src/controllers/SalaryRankController.ts @@ -0,0 +1,203 @@ +import { + Controller, + Post, + Put, + Delete, + Route, + Security, + Tags, + Body, + Path, + Request, + SuccessResponse, + Response, + Get, + Query + } from "tsoa"; + import { AppDataSource } from "../database/data-source"; + import HttpSuccess from "../interfaces/http-success"; + import HttpStatusCode from "../interfaces/http-status"; + import HttpError from "../interfaces/http-error"; + import { CreateSalaryRank, SalaryRanks, UpdateSalaryRank } from "../entities/SalaryRanks"; + import { Not } from "typeorm"; + import { Salarys } from "../entities/Salarys"; + @Route("api/v1/salary/rate") + @Tags("SalaryRank") +// @Security("bearerAuth") + @Response( + HttpStatusCode.INTERNAL_SERVER_ERROR, + "เกิดข้อผิดพลาด ไม่สามารถแสดงรายการได้ กรุณาลองใหม่ในภายหลัง", + ) + @SuccessResponse(HttpStatusCode.OK, "สำเร็จ") + export class SalaryRanksController extends Controller { + private salaryRankRepository = AppDataSource.getRepository(SalaryRanks); + private salaryRepository = AppDataSource.getRepository(Salarys); + + /** + * API สร้างอัตราเงินเดือน + * + * @summary SLR_009 - สร้างอัตราเงินเดือน #9 + * + */ + @Post() + async CreateSalaryRank( + @Body() + requestBody: CreateSalaryRank, + @Request() request: { user: Record }, + ) { + const checkSalary = await this.salaryRepository.findOne({ + where: {id:requestBody.salaryId} + }) + if (!checkSalary) { + throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลไอดีนี้ : " + requestBody.salaryId) + } + try { + const salaryRank = Object.assign(new SalaryRanks(), requestBody); + salaryRank.createdUserId = request.user.sub; + salaryRank.createdFullName = request.user.name; + salaryRank.lastUpdateUserId = request.user.sub; + salaryRank.lastUpdateFullName = request.user.name; + await this.salaryRankRepository.save(salaryRank); + return new HttpSuccess(); + } catch (error) { + return error; + } + } + + /** + * API แก้ไขอัตราเงินเดือน + * + * @summary SLR_010 - แก้ไขอัตราเงินเดือน #10 + * + * @param {string} id Id อัตราเงินเดือน + */ + @Put("{id}") + async updateSalaryRanks( + @Path() id: string, + @Body() + requestBody: UpdateSalaryRank, + @Request() request: { user: Record }, + ) { + const salaryRank = await this.salaryRankRepository.findOne({ where: { id: id } }); + if (!salaryRank) { + throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลไอดีนี้ : " + id); + } + + try { + salaryRank.lastUpdateUserId = request.user.sub; + salaryRank.lastUpdateFullName = request.user.name; + this.salaryRankRepository.merge(salaryRank, requestBody); + await this.salaryRankRepository.save(salaryRank); + return new HttpSuccess(); + } catch (error) { + return error; + } + } + + /** + * API ลบอัตราเงินเดือน + * + * @summary SLR_011 - ลบอัตราเงินเดือน #11 + * + * @param {string} id Id อัตราเงินเดือน + */ + @Delete("{id}") + async deleteSalaryRanks(@Path() id: string) { + const delSalaryRanks = await this.salaryRankRepository.findOne({ + where: { id }, + }); + if (!delSalaryRanks) { + throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลตำแหน่งตามไอดีนี้ : " + id); + } + try { + await this.salaryRankRepository.delete({ id: id }); + return new HttpSuccess(); + } catch (error) { + return error; + } + } + + // /** + // * API รายละเอียดรายการอัตราเงินเดือน + // * + // * @summary ORG_059 - รายละเอียดรายการอัตราเงินเดือน (ADMIN) #65 + // * + // * @param {string} id Id อัตราเงินเดือน + // */ + // @Get("{id}") + // async detailSalaryRanks(@Path() id: string) { + // const salaryRank = await this.salaryRankRepository.findOne({ + // where: { id }, + // select: ["id"], + // }); + // if (!salaryRank) { + // throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูล"); + // } + // try { + // return new HttpSuccess(salaryRank); + // } catch (error) { + // return error; + // } + // } + + /** + * API รายการอัตราเงินเดือน + * + * @summary SLR_012 - รายการอัตราเงินเดือน #12 + * + * @param {string} id Id ผังเงินเดือน + */ + @Get("rate/{id}") + async listSalaryRanks( + @Path() id: string, + @Query('page') page: number = 1, + @Query('pageSize') pageSize: number = 10, + @Query('keyword') keyword?: string, + ) { + const [salaryRank,total] = await this.salaryRankRepository.findAndCount({ + where:{ + salaryId:id + }, + select: [ + "id", + "salary", + "salaryHalf", + "salaryHalfSpecial", + "salaryFull", + "salaryFullSpecial", + "salaryFullHalf", + "salaryFullHalfSpecial", + "isNext", + ], + order: { + salary: "DESC", + salaryHalf: "DESC" + }, + skip: (page - 1) * pageSize, + take: pageSize, + }); + if (keyword != undefined && keyword !== "") { + const filteredSalaryRank = salaryRank.filter( + (x) => + (x.salary?.toString().includes(keyword)) || + (x.salaryHalf?.toString().includes(keyword)) || + (x.salaryHalfSpecial?.toString().includes(keyword)) || + (x.salaryFull?.toString().includes(keyword)) || + (x.salaryFullSpecial?.toString().includes(keyword)) || + (x.salaryFullHalf?.toString().includes(keyword)) || + (x.salaryFullHalfSpecial?.toString().includes(keyword)), + ); + return new HttpSuccess({ data: filteredSalaryRank, total: filteredSalaryRank.length }); + } + + if (!salaryRank) { + return new HttpSuccess([]); + } + try { + return new HttpSuccess({ data:salaryRank , total }); + } catch (error) { + return error; + } + } + } + \ No newline at end of file diff --git a/src/entities/SalaryRanks.ts b/src/entities/SalaryRanks.ts index 62f16c0..b26d9d4 100644 --- a/src/entities/SalaryRanks.ts +++ b/src/entities/SalaryRanks.ts @@ -111,4 +111,4 @@ export class CreateSalaryRank { rank: number; } -export type UpdateSalaryRank = Partial; +export type UpdateSalaryRank = Partial>>;