hrms-api-salary/src/controllers/SalaryPeriodController.ts

543 lines
21 KiB
TypeScript

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 } 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";
@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
*
*/
@Get("latest/{id}")
async GetGroupSalaryPeriodLatest(@Path() id: string) {
//xxxx รอบเงินเดือนล่าสุดยังไม่แน่ใจเอาจากรอบไหน
//xxxx หาสังกัดคนนั้น
// const dateNow = new Date();
const salaryPeriod = await this.salaryPeriodRepository.findOne({
where: {
// effectiveDate: MoreThan(dateNow),
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 == id)?.id,
group2id: salaryPeriod.salaryOrgs.find((x) => x.group == "GROUP2" && x.rootId == id)?.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({
where: { id: id },
});
if (!salaryProfile) {
throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลการขอเงินเดือนผู้ใช้งานนี้ในระบบ");
}
await this.salaryProfileRepository.remove(salaryProfile);
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;
// salaryProfile.amountSpecial = xxxx;
// salaryProfile.amountUse = xxxx;
// salaryProfile.positionSalaryAmount = xxxx;
//xxxxxx คำนวนเงินเดือนใหม่
await this.salaryProfileRepository.save(salaryProfile);
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);
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();
//xxxxxx คำนวนเงินเดือนใหม่
if (body.type == "NONE") {
//xxxx เงินไม่เปลืี่ยน
} else if (body.type == "HAFT") {
//xxxx เลื่อน0.5ขั้น
// salaryProfile.amountSpecial = 0;
// salaryProfile.amountUse = 0;
// salaryProfile.positionSalaryAmount = 0;
} else if (body.type == "FULL") {
//xxxx เลื่อน1ขั้น
// salaryProfile.amountSpecial = 0;
// salaryProfile.amountUse = 0;
// salaryProfile.positionSalaryAmount = 0;
} else if (body.type == "FULLHAFT") {
//xxxx เลื่อน1.0ขั้น
// salaryProfile.amountSpecial = 0;
// salaryProfile.amountUse = 0;
// salaryProfile.positionSalaryAmount = 0;
} 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")
.andWhere({
salaryOrgId: salaryOrg.id,
})
.andWhere(body.type != null && body.type != "" ? "profile.type LIKE :type" : "1=1", {
type: `%${body.type}%`,
})
//xxxx รอ fe ว่าแสดงค่าไหนบ่างใหเfilterเฉพาะค่านั้น
.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<string, any> },
) {
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,
"ไม่สามารถเพิ่มรายชื่อนี้ได้ เนื่องจากมีการยื่นของเลื่อนเงินเดือนแล้ว",
);
}
const salaryProfile = Object.assign(new SalaryProfile(), requestBody);
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
}
});
//SalaryRank
const SalaryRanks = await this.salaryRankRepository.findOne({
where: {
salaryId: salarys?.id,
salary: salaryProfile.amount
}
});
//xxxxxx คำนวนเงินเดือนใหม่
if (salaryProfile.type == "NONE") {
//xxxx เงินไม่เปลืี่ยน
} else if (salaryProfile.type == "HAFT") {
//xxxx เลื่อน0.5ขั้น
salaryProfile.amountSpecial = Number(SalaryRanks?.salaryHalfSpecial);
salaryProfile.amountUse = Number(SalaryRanks?.salaryHalf) - salaryProfile.amount;
salaryProfile.positionSalaryAmount = Number(SalaryRanks?.salaryHalf);
} else if (salaryProfile.type == "FULL") {
//xxxx เลื่อน1ขั้น
salaryProfile.amountSpecial = Number(SalaryRanks?.salaryFullSpecial);
salaryProfile.amountUse = Number(SalaryRanks?.salaryFull) - salaryProfile.amount;
salaryProfile.positionSalaryAmount = Number(SalaryRanks?.salaryFull);
} else if (salaryProfile.type == "FULLHAFT") {
//xxxx เลื่อน1.0ขั้น
salaryProfile.amountSpecial = Number(SalaryRanks?.salaryFullHalfSpecial);
salaryProfile.amountUse = Number(SalaryRanks?.salaryFullHalf) - salaryProfile.amount;
salaryProfile.positionSalaryAmount = Number(SalaryRanks?.salaryFullHalf);
} else {
throw new HttpError(HttpStatusCode.NOT_FOUND, "ประเภทการเลื่อนขึ้นเงินเดือนไม่ถูกต้อง");
}
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);
return new HttpSuccess(salaryProfile.id);
}
/**
* API สร้างรอบเงินเดือน
*
* @summary SLR_016 - สร้างรอบเงินเดือน #16
*
*/
@Post()
async create_salary_period(
@Body() requestBody: CreateSalaryPeriod,
@Request() request: { user: Record<string, any> },
) {
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<string, any> },
) {
const chk_SalaryPeriod = await this.salaryPeriodRepository.findOne({
where: { id: id },
});
if (!chk_SalaryPeriod) {
throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลไอดี: " + id);
}
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, "ไม่พบข้อมูลไอดี: " + id);
}
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"],
});
if (!salaryPeriod) {
throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลไอดี: " + id);
}
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",
])
.orderBy("SalaryPeriod.effectiveDate", "DESC")
.skip((page - 1) * pageSize)
.take(pageSize)
.getManyAndCount();
return new HttpSuccess({ data: salaryPeriod, total });
}
}