import { Controller, Get, Post, Put, Delete, Patch, Route, Security, Tags, Body, Path, Request, Example, Query, } from "tsoa"; import { AppDataSource } from "../database/data-source"; import { DeepPartial, In, IsNull, Not, Between, MoreThan, Like, Brackets } from "typeorm"; import HttpSuccess from "../interfaces/http-success"; import HttpError from "../interfaces/http-error"; import HttpStatusCode from "../interfaces/http-status"; import { CreateSalaryPeriod, SalaryPeriod, UpdateSalaryPeriod } from "../entities/SalaryPeriod"; import Extension from "../interfaces/extension"; import { SalaryOrg } from "../entities/SalaryOrg"; import { CreateSalaryProfile, SalaryProfile } from "../entities/SalaryProfile"; import { PosType } from "../entities/PosType"; import { PosLevel } from "../entities/PosLevel"; import { Salarys } from "../entities/Salarys"; import { SalaryRanks } from "../entities/SalaryRanks"; import CallAPI from "../interfaces/call-api"; import { Int32 } from "typeorm/browser"; @Route("api/v1/salary/period") @Tags("Salary") @Security("bearerAuth") export class SalaryPeriodController extends Controller { private salaryPeriodRepository = AppDataSource.getRepository(SalaryPeriod); private salaryOrgRepository = AppDataSource.getRepository(SalaryOrg); private salaryProfileRepository = AppDataSource.getRepository(SalaryProfile); private posTypeRepository = AppDataSource.getRepository(PosType); private posLevelRepository = AppDataSource.getRepository(PosLevel); private salaryRepository = AppDataSource.getRepository(Salarys); private salaryRankRepository = AppDataSource.getRepository(SalaryRanks); /** * API รอบล่าสุด * * @summary SLR_030 - รอบล่าสุด #29 * */ @Post("latest") async GetGroupSalaryPeriodLatest( @Body() body: { rootId: string; salaryPeriodId: string; snapshot: string }, ) { const salaryPeriod = await this.salaryPeriodRepository.findOne({ where: { id: body.salaryPeriodId, isActive: true, }, order: { effectiveDate: "DESC" }, relations: ["salaryOrgs"], }); if (!salaryPeriod) { throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบรอบการขึ้นเงินเดือน"); } const data = { group1id: salaryPeriod.salaryOrgs.find( (x) => x.group == "GROUP1" && x.rootId == body.rootId && x.snapshot == body.snapshot.toLocaleUpperCase(), ) == null ? null : salaryPeriod.salaryOrgs.find( (x) => x.group == "GROUP1" && x.rootId == body.rootId && x.snapshot == body.snapshot.toLocaleUpperCase(), )?.id, group2id: salaryPeriod.salaryOrgs.find( (x) => x.group == "GROUP2" && x.rootId == body.rootId && x.snapshot == body.snapshot.toLocaleUpperCase(), ) == null ? null : salaryPeriod.salaryOrgs.find( (x) => x.group == "GROUP2" && x.rootId == body.rootId && x.snapshot == body.snapshot.toLocaleUpperCase(), )?.id, effectiveDate: salaryPeriod.effectiveDate, period: salaryPeriod.period, }; return new HttpSuccess(data); } /** * API จำนวนโควตา * * @summary SLR_029 - จำนวนโควตา #28 * * @param {string} id Guid, *Id กลุ่ม(salaryOrgId/groupId) */ @Get("quota/{id}") async GetSalaryquotaLatest(@Path() id: string) { const salaryOrg = await this.salaryOrgRepository.findOne({ where: { id: id, }, relations: ["salaryProfiles"], }); if (!salaryOrg) { throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบรอบการขึ้นเงินเดือน"); } const data = { total: salaryOrg.total, fifteenPercent: salaryOrg.fifteenPercent, chosen: salaryOrg.salaryProfiles.filter((x) => x.posType == "FULL").length, remaining: salaryOrg.fifteenPercent - salaryOrg.salaryProfiles.filter((x) => x.posType == "FULL").length, }; return new HttpSuccess(data); } /** * API ลบคนเลื่อนเงินเดือนในรอบ * * @summary SLR_024 - ลบคนเลื่อนเงินเดือนในรอบ #23 * * @param {string} id profile Id */ @Delete("profile/{id}") async deleteSalaryProfile(@Path() id: string) { const salaryProfile = await this.salaryProfileRepository.findOne({ relations: ["salaryOrg"], where: { id: id }, }); if (!salaryProfile) { throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลการขอเงินเดือนผู้ใช้งานนี้ในระบบ"); } await this.salaryProfileRepository.remove(salaryProfile); // หาจำนวน Quota คงเหลือ if (salaryProfile.salaryOrg.snapshot == "SNAP1") { const amountFullType = await this.salaryProfileRepository.count({ where: { salaryOrgId: salaryProfile?.salaryOrg.id, type: "FULL", }, }); const calRemainQuota = salaryProfile?.salaryOrg.fifteenPercent - amountFullType; salaryProfile.salaryOrg.quantityUsed = amountFullType; salaryProfile.salaryOrg.remainQuota = calRemainQuota; await this.salaryOrgRepository.save(salaryProfile?.salaryOrg); } return new HttpSuccess(); } /** * API แก้ไขเงินเดือน * * @summary SLR_025 - แก้ไขเงินเดือน #24 * * @param {string} id profile Id * @param {string} amount ฐานเงินเดือน */ @Post("change/amount") async changeAmount(@Body() body: { profileId: string; amount: number }) { const salaryProfile = await this.salaryProfileRepository.findOne({ where: { id: body.profileId }, }); if (!salaryProfile) { throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลการขอเงินเดือนผู้ใช้งานนี้ในระบบ"); } salaryProfile.amount = body.amount; //Type & Level const Type = await this.posTypeRepository.findOne({ where: { posTypeName: salaryProfile.posType, }, }); if (!Type) { throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบประเภทตำแหน่ง"); } const Level = await this.posLevelRepository.findOne({ where: { posTypeId: Type.id, posLevelName: salaryProfile.posLevel, }, }); if (!Level) { throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบระดับตำแหน่ง"); } //Salary const salarys = await this.salaryRepository.findOne({ where: { posTypeId: Level.posTypeId, posLevelId: Level.id, isActive: true, }, }); if (!salarys) { throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบระดับตำแหน่ง"); } //SalaryRank let salaryRanks: any = null; if (salaryProfile.amount != null) { salaryRanks = await this.salaryRankRepository.findOne({ where: { salaryId: salarys.id, salary: salaryProfile.amount, }, }); } if (salaryProfile.type == "NONE") { salaryProfile.amountSpecial = 0; salaryProfile.amountUse = 0; salaryProfile.positionSalaryAmount = salaryProfile.amount; } else if (salaryProfile.type == "PENDING") { salaryProfile.amountSpecial = 0; salaryProfile.amountUse = 0; salaryProfile.positionSalaryAmount = 0; } else if (salaryProfile.type == "HAFT") { salaryProfile.amountSpecial = salaryRanks == null ? 0 : salaryRanks.salaryHalfSpecial; salaryProfile.amountUse = salaryRanks == null || salaryProfile == null || salaryRanks.salaryHalf == null || salaryProfile.amount == null ? 0 : salaryRanks.salaryHalf - salaryProfile.amount; salaryProfile.positionSalaryAmount = salaryRanks == null ? 0 : salaryRanks.salaryHalf; } else if (salaryProfile.type == "FULL") { salaryProfile.amountSpecial = salaryRanks == null ? 0 : salaryRanks.salaryFullSpecial; salaryProfile.amountUse = salaryRanks == null || salaryProfile == null || salaryRanks.salaryFull == null || salaryProfile.amount == null ? 0 : salaryRanks.salaryFull - salaryProfile.amount; salaryProfile.positionSalaryAmount = salaryRanks == null ? 0 : salaryRanks.salaryFull; } else if (salaryProfile.type == "FULLHAFT") { salaryProfile.amountSpecial = salaryRanks == null ? 0 : salaryRanks.salaryFullHalfSpecial; salaryProfile.amountUse = salaryRanks == null || salaryProfile == null || salaryRanks.salaryFullHalf == null || salaryProfile.amount == null ? 0 : salaryRanks.salaryFullHalf - salaryProfile.amount; salaryProfile.positionSalaryAmount = salaryRanks == null ? 0 : salaryRanks.salaryFullHalf; } else { throw new HttpError(HttpStatusCode.NOT_FOUND, "ประเภทการเลื่อนขึ้นเงินเดือนไม่ถูกต้อง"); } await this.salaryProfileRepository.save(salaryProfile); // หาจำนวน Quota คงเหลือ if (salaryProfile?.salaryOrg.snapshot == "SNAP1") { const amountFullType = await this.salaryProfileRepository.count({ where: { salaryOrgId: salaryProfile?.salaryOrg.id, type: "FULL", }, }); const calRemainQuota = salaryProfile?.salaryOrg.fifteenPercent - amountFullType; salaryProfile.salaryOrg.quantityUsed = amountFullType; salaryProfile.salaryOrg.remainQuota = calRemainQuota; await this.salaryOrgRepository.save(salaryProfile?.salaryOrg); } return new HttpSuccess(); } /** * API ย้ายกลุ่ม * * @summary SLR_026 - ย้ายกลุ่ม #25 * * @param {string} id profile Id * @param {string} groupId groupId */ @Post("change/group") async changeGroup(@Body() body: { profileId: string; groupId: string }) { const salaryProfile = await this.salaryProfileRepository.findOne({ where: { id: body.profileId }, }); if (!salaryProfile) { throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลการขอเงินเดือนผู้ใช้งานนี้ในระบบ"); } const salaryOrg = await this.salaryOrgRepository.findOne({ where: { id: body.groupId }, }); if (!salaryOrg) { throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลกลุ่มการขอเลื่อนเงินเดือน"); } salaryProfile.salaryOrgId = salaryOrg.id; await this.salaryProfileRepository.save(salaryProfile); //หาจำนวน Quota คงเหลือ if (salaryOrg.snapshot == "SNAP1") { const amountFullType = await this.salaryProfileRepository.count({ where: { salaryOrgId: salaryOrg.id, type: "FULL", }, }); const calRemainQuota = salaryOrg.fifteenPercent - amountFullType; salaryOrg.quantityUsed = amountFullType; salaryOrg.remainQuota = calRemainQuota; await this.salaryOrgRepository.save(salaryOrg); } return new HttpSuccess(); } /** * API แก้ไขขั้น * * @summary SLR_025 - แก้ไขขั้น #24 * * @param {string} id profile Id * @param {string} type ประเภทการเลื่อน NONE->ไม่ได้เลื่อน HAFT->ครึ่งขั้น FULL->1ขั้น FULLHAFT->1.5ขั้น */ @Post("change/type") async changeType(@Body() body: { profileId: string; type: string }) { const salaryProfile = await this.salaryProfileRepository.findOne({ where: { id: body.profileId }, }); if (!salaryProfile) { throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลการขอเงินเดือนผู้ใช้งานนี้ในระบบ"); } body.type = body.type.toUpperCase(); //Type & Level const Type = await this.posTypeRepository.findOne({ where: { posTypeName: salaryProfile.posType, }, }); if (!Type) { throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบประเภทตำแหน่ง"); } const Level = await this.posLevelRepository.findOne({ where: { posTypeId: Type.id, posLevelName: salaryProfile.posLevel, }, }); if (!Level) { throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบระดับตำแหน่ง"); } //Salary const salarys = await this.salaryRepository.findOne({ where: { posTypeId: Level.posTypeId, posLevelId: Level.id, isActive: true, }, }); if (!salarys) { throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบระดับตำแหน่ง"); } //SalaryRank let salaryRanks: any = null; if (salaryProfile.amount != null) { salaryRanks = await this.salaryRankRepository.findOne({ where: { salaryId: salarys.id, salary: salaryProfile.amount, }, }); } if (body.type == "NONE") { salaryProfile.amountSpecial = 0; salaryProfile.amountUse = 0; salaryProfile.positionSalaryAmount = salaryProfile.amount; } else if (body.type == "PENDING") { salaryProfile.amountSpecial = 0; salaryProfile.amountUse = 0; salaryProfile.positionSalaryAmount = 0; } else if (body.type == "HAFT") { salaryProfile.amountSpecial = salaryRanks == null ? 0 : salaryRanks.salaryHalfSpecial; salaryProfile.amountUse = salaryRanks == null || salaryProfile == null || salaryRanks.salaryHalf == null || salaryProfile.amount == null ? 0 : salaryRanks.salaryHalf - salaryProfile.amount; salaryProfile.positionSalaryAmount = salaryRanks == null ? 0 : salaryRanks.salaryHalf; } else if (body.type == "FULL") { salaryProfile.amountSpecial = salaryRanks == null ? 0 : salaryRanks.salaryFullSpecial; salaryProfile.amountUse = salaryRanks == null || salaryProfile == null || salaryRanks.salaryFull == null || salaryProfile.amount == null ? 0 : salaryRanks.salaryFull - salaryProfile.amount; salaryProfile.positionSalaryAmount = salaryRanks == null ? 0 : salaryRanks.salaryFull; } else if (body.type == "FULLHAFT") { salaryProfile.amountSpecial = salaryRanks == null ? 0 : salaryRanks.salaryFullHalfSpecial; salaryProfile.amountUse = salaryRanks == null || salaryProfile == null || salaryRanks.salaryFullHalf == null || salaryProfile.amount == null ? 0 : salaryRanks.salaryFullHalf - salaryProfile.amount; salaryProfile.positionSalaryAmount = salaryRanks == null ? 0 : salaryRanks.salaryFullHalf; } else { throw new HttpError(HttpStatusCode.NOT_FOUND, "ประเภทการเลื่อนขึ้นเงินเดือนไม่ถูกต้อง"); } salaryProfile.type = body.type; await this.salaryProfileRepository.save(salaryProfile); return new HttpSuccess(); } /** * API รายการอัตราเงินเดือน * * @summary SLR_023 - รายการอัตราเงินเดือน #22 * */ @Put("org/{id}") async GetListsSalaryProfile( @Path() id: string, @Body() body: { page: number; pageSize: number; keyword?: string; type: string }, ) { const salaryOrg = await this.salaryOrgRepository.findOne({ where: { id: id, }, }); if (!salaryOrg) { throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบรอบการขึ้นเงินเดือน"); } const [salaryProfile, total] = await AppDataSource.getRepository(SalaryProfile) .createQueryBuilder("profile") .orWhere( new Brackets((qb) => { qb.andWhere(body.type != null && body.type != "" ? "profile.type LIKE :type" : "1=1", { type: `%${body.type.toUpperCase()}%`, }) .andWhere({ salaryOrgId: salaryOrg.id, }) .andWhere( new Brackets((qb) => { qb.orWhere("profile.posMasterNoPrefix LIKE :keyword", { keyword: `%${body.keyword}%`, }) .orWhere("profile.posMasterNo LIKE :keyword", { keyword: `%${body.keyword}%` }) .orWhere("profile.posMasterNoSuffix LIKE :keyword", { keyword: `%${body.keyword}%`, }) .orWhere("profile.orgShortName LIKE :keyword", { keyword: `%${body.keyword}%` }) .orWhere("profile.prefix LIKE :keyword", { keyword: `%${body.keyword}%` }) .orWhere("profile.firstName LIKE :keyword", { keyword: `%${body.keyword}%` }) .orWhere("profile.lastName LIKE :keyword", { keyword: `%${body.keyword}%` }) // .orWhere("profile.citizenId LIKE :keyword", { keyword: `%${body.keyword}%` }) .orWhere("profile.position LIKE :keyword", { keyword: `%${body.keyword}%` }) // .orWhere("profile.posType LIKE :keyword", { keyword: `%${body.keyword}%` }) // .orWhere("profile.posLevel LIKE :keyword", { keyword: `%${body.keyword}%` }) // .orWhere("profile.posExecutive LIKE :keyword", { keyword: `%${body.keyword}%` }) .orWhere("profile.amount LIKE :keyword", { keyword: `%${body.keyword}%` }) .orWhere("profile.amountSpecial LIKE :keyword", { keyword: `%${body.keyword}%` }) .orWhere("profile.amountUse LIKE :keyword", { keyword: `%${body.keyword}%` }) .orWhere("profile.positionSalaryAmount LIKE :keyword", { keyword: `%${body.keyword}%`, }); }), ); }), ) .orderBy("profile.citizenId", "ASC") .skip((body.page - 1) * body.pageSize) .take(body.pageSize) .getManyAndCount(); return new HttpSuccess({ data: salaryProfile, total }); } /** * API เพิ่มคนเลื่อนเงินเดือนตามรอบ * * @summary SLR_028 - เพิ่มคนเลื่อนเงินเดือนตามรอบ #27 * */ @Post("org/profile") async addSalaryProfile( @Body() requestBody: CreateSalaryProfile, @Request() request: { user: Record }, ) { const salaryOrg = await this.salaryOrgRepository.findOne({ where: { id: requestBody.id, }, }); if (!salaryOrg) { throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบรอบการขึ้นเงินเดือน"); } const salaryOrgAll = await this.salaryOrgRepository.find({ where: { salaryPeriodId: salaryOrg.salaryPeriodId, }, }); if (!salaryOrgAll) { throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบรอบการขึ้นเงินเดือน"); } const salaryProfileAll = await this.salaryProfileRepository.findOne({ where: { salaryOrgId: In(salaryOrgAll.map((x) => x.id)), citizenId: requestBody.citizenId, // prefix: requestBody.prefix, // firstName: requestBody.firstName, // lastName: requestBody.lastName, }, }); if (salaryProfileAll != null) { throw new HttpError( HttpStatusCode.INTERNAL_SERVER_ERROR, "ไม่สามารถเพิ่มรายชื่อนี้ได้ เนื่องจากมีการยื่นของเลื่อนเงินเดือนแล้ว", ); } let salaryProfile: any = Object.assign(new SalaryProfile(), requestBody); delete salaryProfile.id; salaryProfile.type = salaryProfile.type.toUpperCase(); //Type & Level const type = await this.posTypeRepository.findOne({ where: { posTypeName: salaryProfile.posType, }, }); if (!type) { throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบประเภทตำแหน่ง"); } const level = await this.posLevelRepository.findOne({ where: { posTypeId: type.id, posLevelName: salaryProfile.posLevel, }, }); if (!level) { throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบระดับตำแหน่ง"); } //Salary const salarys = await this.salaryRepository.findOne({ where: { posTypeId: level.posTypeId, posLevelId: level.id, isActive: true, }, }); if (!salarys) { throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบระดับตำแหน่ง"); } //SalaryRank let salaryRanks: any = null; if (salaryProfile.amount != null) { salaryRanks = await this.salaryRankRepository.findOne({ where: { salaryId: salarys.id, salary: salaryProfile.amount, }, }); } if (salaryProfile.type == "NONE") { salaryProfile.amountSpecial = 0; salaryProfile.amountUse = 0; salaryProfile.positionSalaryAmount = salaryProfile.amount; } else if (salaryProfile.type == "PENDING") { salaryProfile.amountSpecial = 0; salaryProfile.amountUse = 0; salaryProfile.positionSalaryAmount = 0; } else if (salaryProfile.type == "HAFT") { salaryProfile.amountSpecial = salaryRanks == null ? 0 : salaryRanks.salaryHalfSpecial; salaryProfile.amountUse = salaryRanks == null || salaryProfile == null || salaryRanks.salaryHalf == null || salaryProfile.amount == null ? 0 : salaryRanks.salaryHalf - salaryProfile.amount; salaryProfile.positionSalaryAmount = salaryRanks == null ? 0 : salaryRanks.salaryHalf; } else if (salaryProfile.type == "FULL") { salaryProfile.amountSpecial = salaryRanks == null ? 0 : salaryRanks.salaryFullSpecial; salaryProfile.amountUse = salaryRanks == null || salaryProfile == null || salaryRanks.salaryFull == null || salaryProfile.amount == null ? 0 : salaryRanks.salaryFull - salaryProfile.amount; salaryProfile.positionSalaryAmount = salaryRanks == null ? 0 : salaryRanks.salaryFull; } else if (salaryProfile.type == "FULLHAFT") { salaryProfile.amountSpecial = salaryRanks == null ? 0 : salaryRanks.salaryFullHalfSpecial; salaryProfile.amountUse = salaryRanks == null || salaryProfile == null || salaryRanks.salaryFullHalf == null || salaryProfile.amount == null ? 0 : salaryRanks.salaryFullHalf - salaryProfile.amount; salaryProfile.positionSalaryAmount = salaryRanks == null ? 0 : salaryRanks.salaryFullHalf; } else { salaryProfile.amountSpecial = 0; salaryProfile.amountUse = 0; salaryProfile.positionSalaryAmount = 0; } salaryProfile.salaryOrgId = salaryOrg.id; salaryProfile.createdUserId = request.user.sub; salaryProfile.createdFullName = request.user.name; salaryProfile.lastUpdateUserId = request.user.sub; salaryProfile.lastUpdateFullName = request.user.name; await this.salaryProfileRepository.save(salaryProfile); //หาจำนวน Quota คงเหลือ if (salaryOrg.snapshot == "SNAP1") { const amountFullType = await this.salaryProfileRepository.count({ where: { salaryOrgId: salaryOrg.id, type: "FULL", }, }); const calRemainQuota = salaryOrg.fifteenPercent - amountFullType; salaryOrg.quantityUsed = amountFullType; salaryOrg.remainQuota = calRemainQuota; await this.salaryOrgRepository.save(salaryOrg); } return new HttpSuccess(salaryProfile.id); } /** * API สร้างรอบเงินเดือน * * @summary SLR_016 - สร้างรอบเงินเดือน #16 * */ @Post() async create_salary_period( @Body() requestBody: CreateSalaryPeriod, @Request() request: { user: Record }, ) { const salaryPeriod = Object.assign(new SalaryPeriod(), requestBody); const chk_toUpper = ["SPECIAL", "APR", "OCT"]; if (!chk_toUpper.includes(salaryPeriod.period.toUpperCase())) { throw new HttpError(HttpStatusCode.NOT_FOUND, "ประเภทผัง ไม่ถูกต้อง"); } const chk_period = await this.salaryPeriodRepository.findOne({ where: { period: salaryPeriod.period, year: requestBody.year, }, }); if (chk_period) { throw new HttpError( HttpStatusCode.NOT_FOUND, "ประเภทผังปี " + salaryPeriod.effectiveDate.getFullYear() + " ซ้ำ", ); } salaryPeriod.period = salaryPeriod.period.toUpperCase(); salaryPeriod.createdUserId = request.user.sub; salaryPeriod.createdFullName = request.user.name; salaryPeriod.lastUpdateUserId = request.user.sub; salaryPeriod.lastUpdateFullName = request.user.name; await this.salaryPeriodRepository.save(salaryPeriod); return new HttpSuccess(salaryPeriod.id); } /** * API แก้ไขรอบเงินเดือน * * @summary SLR_017 - แก้ไขรอบเงินเดือน #17 * * @param {string} id Guid, *Id รอบเงินเดือน */ @Put("{id}") async update_salary_period( @Path() id: string, @Body() requestBody: UpdateSalaryPeriod, @Request() request: { user: Record }, ) { const chk_SalaryPeriod = await this.salaryPeriodRepository.findOne({ where: { id: id }, }); if (!chk_SalaryPeriod) { throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลรอบผังเงินเดือนนี้"); } const chk_toUpper = ["SPECIAL", "APR", "OCT"]; if (!chk_toUpper.includes(requestBody.period.toUpperCase())) { throw new HttpError(HttpStatusCode.NOT_FOUND, "ประเภทผัง ไม่ถูกต้อง"); } const chk_period = await this.salaryPeriodRepository.findOne({ where: { period: requestBody.period, id: Not(id), year: requestBody.year, }, }); if (chk_period) { throw new HttpError( HttpStatusCode.NOT_FOUND, "ประเภทผังปี " + (requestBody.effectiveDate.getFullYear() + 543) + " ซ้ำ", ); } chk_SalaryPeriod.period = requestBody.period.toUpperCase(); chk_SalaryPeriod.lastUpdateUserId = request.user.sub; chk_SalaryPeriod.lastUpdateFullName = request.user.name; chk_SalaryPeriod.lastUpdatedAt = new Date(); this.salaryPeriodRepository.merge(chk_SalaryPeriod, requestBody); await this.salaryPeriodRepository.save(chk_SalaryPeriod); return new HttpSuccess(id); } /** * API ลบรอบเงินเดือน * * @summary SLR_018 - ลบรอบเงินเดือน #18 * * @param {string} id Guid, *Id รอบเงินเดือน */ @Delete("{id}") async delete_salary_period(@Path() id: string) { const SalaryPeriod = await this.salaryPeriodRepository.findOne({ where: { id: id }, }); if (!SalaryPeriod) { throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลรอบผังเงินเดือนนี้"); } const SalaryOrg = await this.salaryOrgRepository.findOne({ where: { salaryPeriodId: SalaryPeriod.id }, }); if (SalaryOrg) { throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่สามารถลบได้"); } await this.salaryPeriodRepository.remove(SalaryPeriod); return new HttpSuccess(); } /** * API รายละเอียดรอบเงินเดือน * * @summary SLR_019 - รายละเอียดรอบเงินเดือน #19 * * @param {string} id Guid, *Id รอบเงินเดือน */ @Get("{id}") async GetSalaryPeriod_ById(@Path() id: string) { const salaryPeriod = await this.salaryPeriodRepository.findOne({ where: { id: id }, select: [ "id", "period", "isActive", "effectiveDate", "isActive", "status", "year", "revisionId", ], }); if (!salaryPeriod) { throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลรอบผังเงินเดือนนี้"); } return new HttpSuccess(salaryPeriod); } /** * API รายการรอบเงินเดือน * * @summary SLR_020 - รายการรอบเงินเดือน #20 * */ @Get() async GetListsSalaryPeriod( @Query("page") page: number = 1, @Query("pageSize") pageSize: number = 10, @Query("keyword") keyword?: string, @Query("year") year: number = 2024, ) { const [salaryPeriod, total] = await AppDataSource.getRepository(SalaryPeriod) .createQueryBuilder("salaryPeriod") .andWhere(year != 0 ? "salaryPeriod.year LIKE :year" : "1=1", { year: `%${year}%` }) .orWhere("salaryPeriod.period LIKE :keyword", { keyword: `%${keyword}%` }) .orWhere("salaryPeriod.isActive LIKE :keyword", { keyword: `%${keyword}%` }) .orWhere("salaryPeriod.year LIKE :keyword", { keyword: `%${year}%` }) .select([ "salaryPeriod.id", "salaryPeriod.period", "salaryPeriod.isActive", "salaryPeriod.effectiveDate", "salaryPeriod.status", "salaryPeriod.year", "salaryPeriod.revisionId", ]) .orderBy("salaryPeriod.effectiveDate", "DESC") .skip((page - 1) * pageSize) .take(pageSize) .getManyAndCount(); return new HttpSuccess({ data: salaryPeriod, total }); } /** * API snapshot salary * * @summary snapshot salary * */ @Get("snapshot/{snapshot}/{salaryPeriodId}") async SnapshotSalary( @Path() snapshot: string, salaryPeriodId: string, @Request() request: { user: Record }, ) { snapshot = snapshot.toLocaleUpperCase(); const salaryPeriod = await this.salaryPeriodRepository.findOne({ where: { id: salaryPeriodId }, }); if (!salaryPeriod) { throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบรอบการสร้างเงินเดือน"); } const salaryOrg = await this.salaryOrgRepository.find({ where: { salaryPeriodId: salaryPeriod.id, snapshot: snapshot }, }); const salaryProfile = await this.salaryProfileRepository.find({ where: { salaryOrgId: In(salaryOrg.map((x) => x.id)) }, }); await this.salaryProfileRepository.remove(salaryProfile); await this.salaryOrgRepository.remove(salaryOrg); let orgs = await new CallAPI().GetData(request, "org/unauthorize/active/root/id"); let total = 1000; let _orgProfiles = await new CallAPI().PostData(request, "org/unauthorize/salary/gen", { page: 1, pageSize: 1000, keyword: "", }); let orgProfiles = _orgProfiles.data; total = _orgProfiles.total; if (total > 1000) { const page = Math.ceil(total / 1000); for (let index = 2; index <= page; index++) { await new CallAPI() .PostData(request, "org/unauthorize/profile/salary/gen", { page: index, pageSize: 1000, keyword: "", }) .then((x) => { Array.prototype.push.apply(orgProfiles, x.data); }); } } let revisionId = await new CallAPI().GetData(request, "org/unauthorize/revision/latest"); salaryPeriod.revisionId = revisionId; await this.salaryPeriodRepository.save(salaryPeriod); await Promise.all( orgs.map(async (rootId: string) => { let salaryOrgNew = Object.assign(new SalaryOrg()); delete salaryOrgNew.id; salaryOrgNew.salaryPeriodId = salaryPeriod.id; salaryOrgNew.status = "PENDING"; salaryOrgNew.rootId = rootId; salaryOrgNew.revisionId = salaryPeriod.revisionId; salaryOrgNew.snapshot = snapshot; salaryOrgNew.group = "GROUP1"; salaryOrgNew.createdUserId = request.user.sub; salaryOrgNew.createdFullName = request.user.name; salaryOrgNew.lastUpdateUserId = request.user.sub; salaryOrgNew.lastUpdateFullName = request.user.name; await this.salaryOrgRepository.save(salaryOrgNew); delete salaryOrgNew.id; salaryOrgNew.group = "GROUP2"; await this.salaryOrgRepository.save(salaryOrgNew); }), ); await Promise.all( orgProfiles.map(async (profile: any) => { let group = "GROUP1"; if ( (profile.posType == "ทั่วไป" && profile.posLevel == "ทักษะพิเศษ") || (profile.posType == "วิชาการ" && profile.posLevel == "เชี่ยวชาญ") || (profile.posType == "วิชาการ" && profile.posLevel == "ทรงคุณวุฒิ") || (profile.posType == "อำนวยการ" && profile.posLevel == "สูง") || (profile.posType == "บริหาร" && profile.posLevel == "ต้น") || (profile.posType == "บริหาร" && profile.posLevel == "สูง") ) { group = "GROUP2"; } const salaryOrgNew = await this.salaryOrgRepository.findOne({ where: { salaryPeriodId: salaryPeriod.id, rootId: profile.rootId, snapshot: snapshot, group: group, }, }); if (salaryOrgNew != null) { let salaryProfileNew = Object.assign(new SalaryProfile(), profile); delete profile.id; salaryProfileNew.salaryOrgId = salaryOrgNew.id; salaryProfileNew.revisionId = salaryPeriod.revisionId; salaryProfileNew.createdUserId = request.user.sub; salaryProfileNew.createdFullName = request.user.name; salaryProfileNew.lastUpdateUserId = request.user.sub; salaryProfileNew.lastUpdateFullName = request.user.name; if (snapshot == "SNAP2") { const salaryOrgOld = await this.salaryOrgRepository.find({ where: { salaryPeriodId: salaryPeriod.id, snapshot: "SNAP1" }, }); const salaryOld = await this.salaryProfileRepository.findOne({ where: { citizenId: salaryProfileNew.citizenId, salaryOrgId: In(salaryOrgOld.map((x) => x.id)), }, }); salaryProfileNew.type = salaryOld == null ? "PENDING" : salaryOld.type; salaryProfileNew.amount = salaryOld == null ? 0 : salaryOld.amount; salaryProfileNew.amountSpecial = salaryOld == null ? 0 : salaryOld.amountSpecial; salaryProfileNew.amountUse = salaryOld == null ? 0 : salaryOld.amountUse; salaryProfileNew.positionSalaryAmount = salaryOld == null ? 0 : salaryOld.positionSalaryAmount; } await this.salaryProfileRepository.save(salaryProfileNew); } }), ); const salaryOrgNew = await this.salaryOrgRepository.find({ where: { salaryPeriodId: salaryPeriod.id, snapshot: snapshot }, relations: ["salaryProfiles"], }); if (salaryPeriod.period == "OCT") { const salaryPeriodAPROld = await this.salaryPeriodRepository.findOne({ where: { year: salaryPeriod.year, period: "APR", }, }); await Promise.all( salaryOrgNew.map(async (_salaryOrg: SalaryOrg) => { let totalAmount = 0; if (salaryPeriodAPROld != null) { const salaryOrgSnap2Old: any = await this.salaryOrgRepository.findOne({ where: { salaryPeriodId: salaryPeriodAPROld.id, rootId: _salaryOrg.rootId, group: _salaryOrg.group, snapshot: "SNAP2", }, relations: ["salaryProfiles"], }); totalAmount = salaryOrgSnap2Old == null ? 0 : Extension.sumObjectValues(salaryOrgSnap2Old.salaryProfiles, "amountUse"); } if (snapshot == "SNAP2") { const salaryOrgSnap1 = await this.salaryOrgRepository.findOne({ where: { salaryPeriodId: salaryPeriod.id, rootId: _salaryOrg.rootId, group: _salaryOrg.group, snapshot: "SNAP1", }, }); if (salaryOrgSnap1 == null) { const totalProfile = Extension.sumObjectValues(_salaryOrg.salaryProfiles, "amount"); _salaryOrg.currentAmount = totalProfile; _salaryOrg.sixPercentAmount = totalProfile * 0.06; _salaryOrg.spentAmount = totalAmount; } else { _salaryOrg.currentAmount = salaryOrgSnap1.currentAmount; _salaryOrg.sixPercentAmount = salaryOrgSnap1.sixPercentAmount; _salaryOrg.spentAmount = salaryOrgSnap1.spentAmount; _salaryOrg.useAmount = salaryOrgSnap1.useAmount; _salaryOrg.remainingAmount = salaryOrgSnap1.remainingAmount; } } else { const totalProfile = Extension.sumObjectValues(_salaryOrg.salaryProfiles, "amount"); _salaryOrg.currentAmount = totalProfile; _salaryOrg.sixPercentAmount = totalProfile * 0.06; _salaryOrg.spentAmount = totalAmount; } await this.salaryOrgRepository.save(_salaryOrg); }), ); } else { await Promise.all( salaryOrgNew.map(async (_salaryOrg: SalaryOrg) => { if (snapshot == "SNAP2") { const salaryOrgSnap1 = await this.salaryOrgRepository.findOne({ where: { salaryPeriodId: salaryPeriod.id, rootId: _salaryOrg.rootId, group: _salaryOrg.group, snapshot: "SNAP1", }, }); if (salaryOrgSnap1 == null) { _salaryOrg.total = _salaryOrg.salaryProfiles.length; _salaryOrg.fifteenPercent = Math.floor((_salaryOrg.salaryProfiles.length * 15) / 100); _salaryOrg.fifteenPoint = (_salaryOrg.salaryProfiles.length * 15) % 100; } else { _salaryOrg.total = salaryOrgSnap1.total; _salaryOrg.fifteenPercent = salaryOrgSnap1.fifteenPercent; _salaryOrg.fifteenPoint = salaryOrgSnap1.fifteenPoint; _salaryOrg.quantityUsed = salaryOrgSnap1.quantityUsed; _salaryOrg.remainQuota = salaryOrgSnap1.remainQuota; } } else { _salaryOrg.total = _salaryOrg.salaryProfiles.length; _salaryOrg.fifteenPercent = Math.floor((_salaryOrg.salaryProfiles.length * 15) / 100); _salaryOrg.fifteenPoint = (_salaryOrg.salaryProfiles.length * 15) % 100; } await this.salaryOrgRepository.save(_salaryOrg); }), ); } return new HttpSuccess(); } /** * Cronjob SalaryPeriod */ async CronjobSalaryPeriod() { //bright const current = new Date(); let salaryPeriod: any; let request: any; // request = express.request; // console.log("request: ", request); if (current.getDate() == 1 && current.getMonth() == 2) { salaryPeriod = await this.salaryPeriodRepository.findOne({ where: { year: current.getFullYear(), period: "APR", isActive: true, }, }); if (salaryPeriod) { this.SnapshotSalarys("SNAP1", salaryPeriod.id, request); } } else if (current.getDate() == 1 && current.getMonth() == 3) { salaryPeriod = await this.salaryPeriodRepository.findOne({ where: { year: current.getFullYear(), period: "APR", isActive: true, }, }); if (salaryPeriod) { this.SnapshotSalarys("SNAP2", salaryPeriod.id, request); } } else if (current.getDate() == 1 && current.getMonth() == 8) { salaryPeriod = await this.salaryPeriodRepository.findOne({ where: { year: current.getFullYear(), period: "OCT", isActive: true, }, }); if (salaryPeriod) { this.SnapshotSalarys("SNAP1", salaryPeriod.id, request); } } else if (current.getDate() == 1 && current.getMonth() == 9) { salaryPeriod = await this.salaryPeriodRepository.findOne({ where: { year: current.getFullYear(), period: "OCT", isActive: true, }, }); if (salaryPeriod) { this.SnapshotSalarys("SNAP2", salaryPeriod.id, request); } } } public async SnapshotSalarys(snapshot: string, salaryPeriodId: string, request: any) { snapshot = snapshot.toLocaleUpperCase(); const salaryPeriod = await this.salaryPeriodRepository.findOne({ where: { id: salaryPeriodId }, }); if (!salaryPeriod) { throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบรอบการสร้างเงินเดือน"); } const salaryOrg = await this.salaryOrgRepository.find({ where: { salaryPeriodId: salaryPeriod.id, snapshot: snapshot }, }); const salaryProfile = await this.salaryProfileRepository.find({ where: { salaryOrgId: In(salaryOrg.map((x) => x.id)) }, }); await this.salaryOrgRepository.remove(salaryOrg); await this.salaryProfileRepository.remove(salaryProfile); let orgs = await new CallAPI().GetData(request, "org/unauthorize/active/root/id"); let orgProfiles: any; await new CallAPI() .PostData(request, "org/unauthorize/profile/salary/gen", { page: 1, pageSize: 100, keyword: "", }) .then((x) => { orgProfiles = x.data; }); if (orgProfiles.total > 100) { const page = Math.ceil(orgProfiles.total.length / 100); for (let index = 2; index <= page; index++) { await new CallAPI() .PostData(request, "org/unauthorize/profile/salary/gen", { page: index, pageSize: 100, keyword: "", }) .then((x) => { Array.prototype.push.apply(orgProfiles, x.data); }); } } let revisionId = await new CallAPI().GetData(request, "org/unauthorize/revision/latest"); salaryPeriod.revisionId = revisionId; await this.salaryPeriodRepository.save(salaryPeriod); await Promise.all( orgs.map(async (rootId: string) => { let salaryOrgNew = Object.assign(new SalaryOrg()); salaryOrgNew.salaryPeriodId = salaryPeriod.id; salaryOrgNew.status = "PENDING"; salaryOrgNew.rootId = rootId; salaryOrgNew.revisionId = salaryPeriod.revisionId; salaryOrgNew.snapshot = snapshot; salaryOrgNew.group = "GROUP1"; salaryOrgNew.createdUserId = request.user.sub; salaryOrgNew.createdFullName = request.user.name; salaryOrgNew.lastUpdateUserId = request.user.sub; salaryOrgNew.lastUpdateFullName = request.user.name; await this.salaryOrgRepository.save(salaryOrgNew); delete salaryOrgNew.id; salaryOrgNew.group = "GROUP2"; await this.salaryOrgRepository.save(salaryOrgNew); }), ); await Promise.all( orgProfiles.map(async (profile: any) => { let group = "GROUP1"; if ( (profile.posType == "ทั่วไป" && profile.posLevel == "ทักษะพิเศษ") || (profile.posType == "วิชาการ" && profile.posLevel == "เชี่ยวชาญ") || (profile.posType == "วิชาการ" && profile.posLevel == "ทรงคุณวุฒิ") || (profile.posType == "อำนวยการ" && profile.posLevel == "สูง") || (profile.posType == "บริหาร" && profile.posLevel == "ต้น") || (profile.posType == "บริหาร" && profile.posLevel == "สูง") ) { group = "GROUP2"; } const salaryOrgNew = await this.salaryOrgRepository.findOne({ where: { salaryPeriodId: salaryPeriod.id, rootId: profile.rootId, snapshot: snapshot, group: group, }, }); if (salaryOrgNew != null) { let salaryProfileNew = Object.assign(new SalaryProfile(), profile); salaryProfileNew.salaryOrgId = salaryOrgNew.id; salaryProfileNew.revisionId = salaryPeriod.revisionId; salaryProfileNew.createdUserId = request.user.sub; salaryProfileNew.createdFullName = request.user.name; salaryProfileNew.lastUpdateUserId = request.user.sub; salaryProfileNew.lastUpdateFullName = request.user.name; if (snapshot == "SNAP2") { const salaryOrgOld = await this.salaryOrgRepository.find({ where: { salaryPeriodId: salaryPeriod.id, snapshot: "SNAP1" }, }); const salaryOld = await this.salaryProfileRepository.findOne({ where: { citizenId: salaryProfileNew.citizenId, salaryOrgId: In(salaryOrgOld.map((x) => x.id)), }, }); salaryProfileNew.type = salaryOld == null ? 0 : salaryOld.type; salaryProfileNew.amount = salaryOld == null ? 0 : salaryOld.amount; salaryProfileNew.amountSpecial = salaryOld == null ? 0 : salaryOld.amountSpecial; salaryProfileNew.amountUse = salaryOld == null ? 0 : salaryOld.amountUse; salaryProfileNew.positionSalaryAmount = salaryOld == null ? 0 : salaryOld.positionSalaryAmount; } await this.salaryProfileRepository.save(salaryProfileNew); } }), ); const salaryOrgNew = await this.salaryOrgRepository.find({ where: { salaryPeriodId: salaryPeriod.id, snapshot: snapshot }, relations: ["salaryProfiles"], }); if (salaryPeriod.period == "OCT") { const salaryPeriodAPROld = await this.salaryPeriodRepository.findOne({ where: { year: salaryPeriod.year, period: "APR", }, }); await Promise.all( salaryOrgNew.map(async (_salaryOrg: SalaryOrg) => { let totalAmount = 0; if (salaryPeriodAPROld != null) { const salaryOrgSnap2Old: any = await this.salaryOrgRepository.findOne({ where: { salaryPeriodId: salaryPeriodAPROld.id, rootId: _salaryOrg.rootId, group: _salaryOrg.group, snapshot: "SNAP2", }, relations: ["salaryProfiles"], }); totalAmount = salaryOrgSnap2Old == null ? 0 : Extension.sumObjectValues(salaryOrgSnap2Old.salaryProfiles, "amountUse"); } if (snapshot == "SNAP2") { const salaryOrgSnap1 = await this.salaryOrgRepository.findOne({ where: { salaryPeriodId: salaryPeriod.id, rootId: _salaryOrg.rootId, group: _salaryOrg.group, snapshot: "SNAP1", }, }); if (salaryOrgSnap1 == null) { const totalProfile = Extension.sumObjectValues(_salaryOrg.salaryProfiles, "amount"); _salaryOrg.currentAmount = totalProfile; _salaryOrg.sixPercentAmount = totalProfile * 0.06; _salaryOrg.spentAmount = totalAmount; } else { _salaryOrg.currentAmount = salaryOrgSnap1.currentAmount; _salaryOrg.sixPercentAmount = salaryOrgSnap1.sixPercentAmount; _salaryOrg.spentAmount = salaryOrgSnap1.spentAmount; _salaryOrg.useAmount = salaryOrgSnap1.useAmount; _salaryOrg.remainingAmount = salaryOrgSnap1.remainingAmount; } } else { const totalProfile = Extension.sumObjectValues(_salaryOrg.salaryProfiles, "amount"); _salaryOrg.currentAmount = totalProfile; _salaryOrg.sixPercentAmount = totalProfile * 0.06; _salaryOrg.spentAmount = totalAmount; } await this.salaryOrgRepository.save(_salaryOrg); }), ); } else { await Promise.all( salaryOrgNew.map(async (_salaryOrg: SalaryOrg) => { if (snapshot == "SNAP2") { const salaryOrgSnap1 = await this.salaryOrgRepository.findOne({ where: { salaryPeriodId: salaryPeriod.id, rootId: _salaryOrg.rootId, group: _salaryOrg.group, snapshot: "SNAP1", }, }); if (salaryOrgSnap1 == null) { _salaryOrg.total = _salaryOrg.salaryProfiles.length; _salaryOrg.fifteenPercent = Math.floor((_salaryOrg.salaryProfiles.length * 15) / 100); _salaryOrg.fifteenPoint = (_salaryOrg.salaryProfiles.length * 15) % 100; } else { _salaryOrg.total = salaryOrgSnap1.total; _salaryOrg.fifteenPercent = salaryOrgSnap1.fifteenPercent; _salaryOrg.fifteenPoint = salaryOrgSnap1.fifteenPoint; _salaryOrg.quantityUsed = salaryOrgSnap1.quantityUsed; _salaryOrg.remainQuota = salaryOrgSnap1.remainQuota; } } else { _salaryOrg.total = _salaryOrg.salaryProfiles.length; _salaryOrg.fifteenPercent = Math.floor((_salaryOrg.salaryProfiles.length * 15) / 100); _salaryOrg.fifteenPoint = (_salaryOrg.salaryProfiles.length * 15) % 100; } await this.salaryOrgRepository.save(_salaryOrg); }), ); } } }