import { Controller, Get, Post, Put, Delete, Route, Security, Tags, Body, Path, Request, Query, } from "tsoa"; import { AppDataSource } from "../database/data-source"; import { In, Not, MoreThan, Brackets, Like, MoreThanOrEqual } 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 CallAPI from "../interfaces/call-api"; import { SalaryOrgEmployee } from "../entities/SalaryOrgEmployee"; import { EmployeePosType } from "../entities/EmployeePosType"; import { SalaryProfileEmployee, CreateSalaryProfileEmployee, } from "../entities/SalaryProfileEmployee"; import { EmployeePosLevel } from "../entities/EmployeePosLevel"; import { SalaryEmployee } from "../entities/SalaryEmployee"; import { SalaryRankEmployee } from "../entities/SalaryRankEmployee"; import { SalaryFormulaEmployee } from "../entities/SalaryFormulaEmployee"; import { RequestWithUser } from "../middlewares/user"; import permission from "../interfaces/permission"; import { setLogDataDiff } from "../interfaces/utils"; @Route("api/v1/salary/period-employee") @Tags("SalaryEmployee") @Security("bearerAuth") export class SalaryPeriodEmployeeController extends Controller { private salaryPeriodRepository = AppDataSource.getRepository(SalaryPeriod); private salaryOrgRepository = AppDataSource.getRepository(SalaryOrgEmployee); private salaryProfileRepository = AppDataSource.getRepository(SalaryProfileEmployee); private posTypeRepository = AppDataSource.getRepository(EmployeePosType); private posLevelRepository = AppDataSource.getRepository(EmployeePosLevel); private salaryRankRepository = AppDataSource.getRepository(SalaryRankEmployee); private salaryFormulaEmployeeRepository = AppDataSource.getRepository(SalaryFormulaEmployee); /** * 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: ["salaryOrgEmployees"], }); if (!salaryPeriod) { throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบรอบการขึ้นเงินเดือน"); } const data = { group1id: salaryPeriod.salaryOrgEmployees && salaryPeriod.salaryOrgEmployees.find( (x) => x.group == "GROUP1" && x.rootId == body.rootId && x.snapshot == body.snapshot.toLocaleUpperCase(), ) == null ? null : salaryPeriod.salaryOrgEmployees && salaryPeriod.salaryOrgEmployees.find( (x) => x.group == "GROUP1" && x.rootId == body.rootId && x.snapshot == body.snapshot.toLocaleUpperCase(), )?.id, group1IsClose: salaryPeriod.salaryOrgEmployees && salaryPeriod.salaryOrgEmployees.find( (x) => x.group == "GROUP1" && x.rootId == body.rootId && x.snapshot == body.snapshot.toLocaleUpperCase(), ) == null ? null : salaryPeriod.salaryOrgEmployees && salaryPeriod.salaryOrgEmployees.find( (x) => x.group == "GROUP1" && x.rootId == body.rootId && x.snapshot == body.snapshot.toLocaleUpperCase(), )?.isClose, group2id: salaryPeriod.salaryOrgEmployees && salaryPeriod.salaryOrgEmployees.find( (x) => x.group == "GROUP2" && x.rootId == body.rootId && x.snapshot == body.snapshot.toLocaleUpperCase(), ) == null ? null : salaryPeriod.salaryOrgEmployees && salaryPeriod.salaryOrgEmployees.find( (x) => x.group == "GROUP2" && x.rootId == body.rootId && x.snapshot == body.snapshot.toLocaleUpperCase(), )?.id, group2IsClose: salaryPeriod.salaryOrgEmployees && salaryPeriod.salaryOrgEmployees.find( (x) => x.group == "GROUP2" && x.rootId == body.rootId && x.snapshot == body.snapshot.toLocaleUpperCase(), ) == null ? null : salaryPeriod.salaryOrgEmployees && salaryPeriod.salaryOrgEmployees.find( (x) => x.group == "GROUP2" && x.rootId == body.rootId && x.snapshot == body.snapshot.toLocaleUpperCase(), )?.isClose, effectiveDate: salaryPeriod.effectiveDate, period: salaryPeriod.period, }; return new HttpSuccess(data); } /** * API ยอดใช้งานทั้งหมด * * @summary ยอดใช้งานทั้งหมด * * @param {string} id * @param {string} group * @param {string} period * @param {string} snapshot */ @Post("summary/all") async summaryUseSalary( @Body() body: { year: number; group: string; period: string; snapshot: string; }, ) { const _salaryOrg = await this.salaryOrgRepository.find({ relations: ["salaryPeriod", "salaryProfiles"], where: { group: Like( `%${body.group.trim().toUpperCase() == "GROUP1" ? "GROUP1" : body.group.trim().toUpperCase() == "GROUP2" ? "GROUP2" : "GROUP1"}%`, ), snapshot: body.snapshot.trim().toUpperCase(), salaryPeriod: { id: body.period }, }, }); const salaryOrg: any[] = []; await Promise.all( _salaryOrg.map(async (item) => { const sum = item.salaryProfiles.reduce((accumulator, object) => { return accumulator + object.amountSpecial; }, 0); const data = { org: item.root, total: item.total, fifteenPercent: item.fifteenPercent + item.fifteenPoint / 100, chosen: item.quantityUsed, remaining: item.remainQuota, currentAmount: item.currentAmount, sixPercentAmount: item.sixPercentAmount, spentAmount: item.spentAmount, sixPercentSpentAmount: item.sixPercentAmount - item.spentAmount, useAmount: item.useAmount, remainingAmount: item.remainingAmount, totalAmountSpecial: sum, totalBackup: item.salaryProfiles.filter((x) => x.isReserve == true).length, }; salaryOrg.push(data); }), ); return new HttpSuccess({ salaryOrg, dashboard: { total: salaryOrg.reduce((accumulator, object) => { return accumulator + object.total; }, 0), fifteenPercent: salaryOrg.reduce((accumulator, object) => { return accumulator + object.fifteenPercent; }, 0), chosen: salaryOrg.reduce((accumulator, object) => { return accumulator + object.chosen; }, 0), remaining: salaryOrg.reduce((accumulator, object) => { return accumulator + object.remaining; }, 0), currentAmount: salaryOrg.reduce((accumulator, object) => { return accumulator + object.currentAmount; }, 0), sixPercentAmount: salaryOrg.reduce((accumulator, object) => { return accumulator + object.sixPercentAmount; }, 0), spentAmount: salaryOrg.reduce((accumulator, object) => { return accumulator + object.spentAmount; }, 0), sixPercentSpentAmount: salaryOrg.reduce((accumulator, object) => { return accumulator + object.sixPercentSpentAmount; }, 0), useAmount: salaryOrg.reduce((accumulator, object) => { return accumulator + object.useAmount; }, 0), remainingAmount: salaryOrg.reduce((accumulator, object) => { return accumulator + object.remainingAmount; }, 0), totalAmountSpecial: salaryOrg.reduce((accumulator, object) => { return accumulator + object.totalAmountSpecial; }, 0), totalBackup: salaryOrg.reduce((accumulator, object) => { return accumulator + object.totalBackup; }, 0), }, }); } /** * 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 sum = salaryOrg.salaryProfiles.reduce((accumulator, object) => { return accumulator + object.amountSpecial; }, 0); const data = { total: salaryOrg.total, fifteenPercent: salaryOrg.fifteenPercent + salaryOrg.fifteenPoint / 100, chosen: salaryOrg.quantityUsed, remaining: salaryOrg.remainQuota, currentAmount: salaryOrg.currentAmount, sixPercentAmount: salaryOrg.sixPercentAmount, spentAmount: salaryOrg.spentAmount, sixPercentSpentAmount: salaryOrg.sixPercentAmount - salaryOrg.spentAmount, useAmount: salaryOrg.useAmount, remainingAmount: salaryOrg.remainingAmount, totalAmountSpecial: sum, totalBackup: salaryOrg.salaryProfiles.filter((x) => x.isReserve == true).length, status: salaryOrg.status, }; return new HttpSuccess(data); } /** * API ลบคนเลื่อนเงินเดือนในรอบ * * @summary SLR_024 - ลบคนเลื่อนเงินเดือนในรอบ #23 * * @param {string} id profile Id */ @Delete("profile/{id}") async deleteSalaryProfile(@Path() id: string, @Request() request: RequestWithUser) { await new permission().PermissionDelete(request, "SYS_WAGE"); const salaryProfile = await this.salaryProfileRepository.findOne({ relations: ["salaryOrg", "salaryOrg.salaryPeriod"], where: { id: id }, }); if (!salaryProfile) { throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลการขอเงินเดือนผู้ใช้งานนี้ในระบบ"); } await this.salaryProfileRepository.remove(salaryProfile, { data: request }); const _salaryProfile = await this.salaryProfileRepository.findOne({ relations: ["salaryOrg", "salaryOrg.salaryPeriod"], where: { id: salaryProfile.id }, }); // หาจำนวน Quota คงเหลือ if (_salaryProfile != null) { if (_salaryProfile.salaryOrg.snapshot == "SNAP1") { if (_salaryProfile.salaryOrg.salaryPeriod.period == "APR") { if (_salaryProfile != null) { const salaryOrg = await this.salaryOrgRepository.findOne({ where: { id: _salaryProfile.salaryOrg.id, }, relations: { salaryProfiles: true }, }); if (salaryOrg != null) { const amountFullType = await this.salaryProfileRepository.count({ where: { salaryOrgId: salaryOrg.id, type: "FULL", }, }); salaryOrg.total = salaryOrg.salaryProfiles.length; salaryOrg.fifteenPercent = Math.floor((salaryOrg.salaryProfiles.length * 15) / 100); salaryOrg.fifteenPoint = (salaryOrg.salaryProfiles.length * 15) % 100; salaryOrg.quantityUsed = amountFullType; const calRemainQuota = salaryOrg.fifteenPercent - amountFullType; salaryOrg.remainQuota = calRemainQuota; salaryOrg.lastUpdateUserId = request.user.sub; salaryOrg.lastUpdateFullName = request.user.name; salaryOrg.lastUpdatedAt = new Date(); await this.salaryOrgRepository.save(salaryOrg, { data: request }); } } } else if (_salaryProfile.salaryOrg.salaryPeriod.period == "OCT") { if (_salaryProfile != null) { const salaryOrg = await this.salaryOrgRepository.findOne({ where: { id: _salaryProfile.salaryOrg.id, }, relations: { salaryProfiles: true }, }); if (salaryOrg != null) { const totalProfile = Extension.sumObjectValues(salaryOrg.salaryProfiles, "amount"); salaryOrg.currentAmount = totalProfile; salaryOrg.total = salaryOrg.salaryProfiles.length; salaryOrg.sixPercentAmount = totalProfile * 0.06; let totalAmount = 0; const salaryPeriodAPROld = await this.salaryPeriodRepository.findOne({ where: { year: _salaryProfile.salaryOrg.salaryPeriod.year, period: "APR", }, }); 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"); } salaryOrg.spentAmount = totalAmount; const sumAmountUse = await AppDataSource.getRepository(SalaryProfileEmployee) .createQueryBuilder("salaryProfileEmployee") .select("SUM(salaryProfileEmployee.amountUse)", "totalAmount") .where({ salaryOrgId: salaryOrg.id, type: In(["HAFT", "FULL", "FULLHAFT"]), }) .getRawOne(); const calRemainAmount = salaryOrg.sixPercentAmount - sumAmountUse.totalAmount - salaryOrg.spentAmount; salaryOrg.useAmount = sumAmountUse == null || sumAmountUse.totalAmount == null ? 0 : sumAmountUse.totalAmount; salaryOrg.remainingAmount = calRemainAmount; salaryOrg.lastUpdateUserId = request.user.sub; salaryOrg.lastUpdateFullName = request.user.name; salaryOrg.lastUpdatedAt = new Date(); await this.salaryOrgRepository.save(salaryOrg, { data: request }); } } } } return new HttpSuccess(); } 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 }, @Request() req: RequestWithUser, ) { await new permission().PermissionCreate(req, "SYS_WAGE"); let salaryProfile = await this.salaryProfileRepository.findOne({ relations: ["salaryOrg", "salaryOrg.salaryPeriod"], 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, "ไม่พบระดับตำแหน่ง"); } let type = salaryProfile.type; salaryProfile = await this.calSalaryNew(type, salaryProfile); salaryProfile.lastUpdateUserId = req.user.sub; salaryProfile.lastUpdateFullName = req.user.name; salaryProfile.lastUpdatedAt = new Date(); const before = structuredClone(salaryProfile); await this.salaryProfileRepository.save(salaryProfile, { data: req }); setLogDataDiff(req, { before, after: salaryProfile }); const _salaryProfile = await this.salaryProfileRepository.findOne({ relations: ["salaryOrg", "salaryOrg.salaryPeriod"], where: { id: salaryProfile.id }, }); // หาจำนวน Quota คงเหลือ if (_salaryProfile != null) { if (_salaryProfile.salaryOrg.snapshot == "SNAP1") { if (_salaryProfile.salaryOrg.salaryPeriod.period == "APR") { if (_salaryProfile != null) { const salaryOrg = await this.salaryOrgRepository.findOne({ where: { id: _salaryProfile.salaryOrg.id, }, relations: { salaryProfiles: true }, }); if (salaryOrg != null) { const amountFullType = await this.salaryProfileRepository.count({ where: { salaryOrgId: salaryOrg.id, type: "FULL", }, }); salaryOrg.total = salaryOrg.salaryProfiles.length; salaryOrg.fifteenPercent = Math.floor((salaryOrg.salaryProfiles.length * 15) / 100); salaryOrg.fifteenPoint = (salaryOrg.salaryProfiles.length * 15) % 100; salaryOrg.quantityUsed = amountFullType; const calRemainQuota = salaryOrg.fifteenPercent - amountFullType; salaryOrg.remainQuota = calRemainQuota; salaryOrg.lastUpdateUserId = req.user.sub; salaryOrg.lastUpdateFullName = req.user.name; salaryOrg.lastUpdatedAt = new Date(); await this.salaryOrgRepository.save(salaryOrg, { data: req }); setLogDataDiff(req, { before, after: salaryOrg }); } } } else if (_salaryProfile.salaryOrg.salaryPeriod.period == "OCT") { if (_salaryProfile != null) { const salaryOrg = await this.salaryOrgRepository.findOne({ where: { id: _salaryProfile.salaryOrg.id, }, relations: { salaryProfiles: true }, }); if (salaryOrg != null) { const totalProfile = Extension.sumObjectValues(salaryOrg.salaryProfiles, "amount"); salaryOrg.currentAmount = totalProfile; salaryOrg.total = salaryOrg.salaryProfiles.length; salaryOrg.sixPercentAmount = totalProfile * 0.06; let totalAmount = 0; const salaryPeriodAPROld = await this.salaryPeriodRepository.findOne({ where: { year: _salaryProfile.salaryOrg.salaryPeriod.year, period: "APR", }, }); 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"); } salaryOrg.spentAmount = totalAmount; const sumAmountUse = await AppDataSource.getRepository(SalaryProfileEmployee) .createQueryBuilder("salaryProfileEmployee") .select("SUM(salaryProfileEmployee.amountUse)", "totalAmount") .where({ salaryOrgId: salaryOrg.id, type: In(["HAFT", "FULL", "FULLHAFT"]), }) .getRawOne(); const calRemainAmount = salaryOrg.sixPercentAmount - sumAmountUse.totalAmount - salaryOrg.spentAmount; salaryOrg.useAmount = sumAmountUse == null || sumAmountUse.totalAmount == null ? 0 : sumAmountUse.totalAmount; salaryOrg.remainingAmount = calRemainAmount; salaryOrg.lastUpdateUserId = req.user.sub; salaryOrg.lastUpdateFullName = req.user.name; salaryOrg.lastUpdatedAt = new Date(); await this.salaryOrgRepository.save(salaryOrg, { data: req }); setLogDataDiff(req, { before, after: salaryOrg }); } } } } return new HttpSuccess(); } 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 }, @Request() req: RequestWithUser, ) { await new permission().PermissionCreate(req, "SYS_WAGE"); const salaryProfile = await this.salaryProfileRepository.findOne({ // relations: ["salaryOrg", "salaryOrg.salaryPeriod"], where: { id: body.profileId }, }); if (!salaryProfile) { throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลการขอเงินเดือนผู้ใช้งานนี้ในระบบ"); } const salaryOrg = await this.salaryOrgRepository.findOne({ relations: ["salaryPeriod"], where: { id: body.groupId }, }); if (!salaryOrg) { throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลกลุ่มการขอเลื่อนเงินเดือน"); } const before = null; salaryProfile.salaryOrgId = salaryOrg.id; salaryProfile.lastUpdateUserId = req.user.sub; salaryProfile.lastUpdateFullName = req.user.name; salaryProfile.lastUpdatedAt = new Date(); await this.salaryProfileRepository.save(salaryProfile, { data: req }); setLogDataDiff(req, { before, after: salaryProfile }); const _salaryProfile = await this.salaryProfileRepository.findOne({ relations: ["salaryOrg", "salaryOrg.salaryPeriod"], where: { id: salaryProfile.id }, }); // หาจำนวน Quota คงเหลือ if (_salaryProfile != null) { if (_salaryProfile.salaryOrg.snapshot == "SNAP1") { if (_salaryProfile.salaryOrg.salaryPeriod.period == "APR") { if (_salaryProfile != null) { const salaryOrg = await this.salaryOrgRepository.findOne({ where: { id: _salaryProfile.salaryOrg.id, }, relations: { salaryProfiles: true }, }); if (salaryOrg != null) { const amountFullType = await this.salaryProfileRepository.count({ where: { salaryOrgId: salaryOrg.id, type: "FULL", }, }); salaryOrg.total = salaryOrg.salaryProfiles.length; salaryOrg.fifteenPercent = Math.floor((salaryOrg.salaryProfiles.length * 15) / 100); salaryOrg.fifteenPoint = (salaryOrg.salaryProfiles.length * 15) % 100; salaryOrg.quantityUsed = amountFullType; const calRemainQuota = salaryOrg.fifteenPercent - amountFullType; salaryOrg.remainQuota = calRemainQuota; salaryOrg.lastUpdateUserId = req.user.sub; salaryOrg.lastUpdateFullName = req.user.name; salaryOrg.lastUpdatedAt = new Date(); await this.salaryOrgRepository.save(salaryOrg, { data: req }); setLogDataDiff(req, { before, after: salaryOrg }); } } } else if (_salaryProfile.salaryOrg.salaryPeriod.period == "OCT") { if (_salaryProfile != null) { const salaryOrg = await this.salaryOrgRepository.findOne({ where: { id: _salaryProfile.salaryOrg.id, }, relations: { salaryProfiles: true }, }); if (salaryOrg != null) { const totalProfile = Extension.sumObjectValues(salaryOrg.salaryProfiles, "amount"); salaryOrg.currentAmount = totalProfile; salaryOrg.total = salaryOrg.salaryProfiles.length; salaryOrg.sixPercentAmount = totalProfile * 0.06; let totalAmount = 0; const salaryPeriodAPROld = await this.salaryPeriodRepository.findOne({ where: { year: _salaryProfile.salaryOrg.salaryPeriod.year, period: "APR", }, }); 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"); } salaryOrg.spentAmount = totalAmount; const sumAmountUse = await AppDataSource.getRepository(SalaryProfileEmployee) .createQueryBuilder("salaryProfileEmployee") .select("SUM(salaryProfileEmployee.amountUse)", "totalAmount") .where({ salaryOrgId: salaryOrg.id, type: In(["HAFT", "FULL", "FULLHAFT"]), }) .getRawOne(); const calRemainAmount = salaryOrg.sixPercentAmount - sumAmountUse.totalAmount - salaryOrg.spentAmount; salaryOrg.useAmount = sumAmountUse == null || sumAmountUse.totalAmount == null ? 0 : sumAmountUse.totalAmount; salaryOrg.remainingAmount = calRemainAmount; salaryOrg.lastUpdateUserId = req.user.sub; salaryOrg.lastUpdateFullName = req.user.name; salaryOrg.lastUpdatedAt = new Date(); await this.salaryOrgRepository.save(salaryOrg, { data: req }); setLogDataDiff(req, { before, after: salaryOrg }); } } } } return new HttpSuccess(); } 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; isReserve: boolean; remark?: string | null }, @Request() req: RequestWithUser, ) { await new permission().PermissionCreate(req, "SYS_WAGE"); let salaryProfile = await this.salaryProfileRepository.findOne({ relations: ["salaryOrg", "salaryOrg.salaryPeriod"], where: { id: body.profileId }, }); if (!salaryProfile) { throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลการขอเงินเดือนผู้ใช้งานนี้ในระบบ"); } body.type = body.type.toUpperCase(); //ตรวจสอบงวดเมษาว่าเลื่อนกี่ขั้น if (body.type == "FULLHAFT") { if (salaryProfile?.salaryOrg?.salaryPeriod?.period === "OCT") { const checkPreviousType = await this.salaryProfileRepository.findOne({ relations: ["salaryOrg", "salaryOrg.salaryPeriod"], where: { citizenId: salaryProfile?.citizenId, salaryOrg: { salaryPeriod: { period: "APR", year: salaryProfile?.salaryOrg?.salaryPeriod?.year, //ปีที่ตรงกันด้วย }, snapshot: "SNAP2", }, type: "FULL", }, }); if (checkPreviousType) { throw new HttpError( HttpStatusCode.NOT_FOUND, "ไม่สามารถเลื่อนขั้นบุคลากรเกิน 2 ขั้นต่อปีได้", ); } } } if (body.type == "FULL") { salaryProfile.isReserve = body.isReserve; } else { salaryProfile.isReserve = false; } //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, "ไม่พบระดับตำแหน่ง"); } salaryProfile.type = body.type; let _null: any = null; salaryProfile.remark = body.remark == null ? _null : body.remark; let type = salaryProfile.type; salaryProfile = await this.calSalaryNew(type, salaryProfile); salaryProfile.lastUpdateUserId = req.user.sub; salaryProfile.lastUpdateFullName = req.user.name; salaryProfile.lastUpdatedAt = new Date(); const before = structuredClone(salaryProfile); await this.salaryProfileRepository.save(salaryProfile, { data: req }); setLogDataDiff(req, { before, after: salaryProfile }); const _salaryProfile = await this.salaryProfileRepository.findOne({ relations: ["salaryOrg", "salaryOrg.salaryPeriod"], where: { id: salaryProfile.id }, }); // หาจำนวน Quota คงเหลือ if (_salaryProfile != null) { if (_salaryProfile.salaryOrg.snapshot == "SNAP1") { if (_salaryProfile.salaryOrg.salaryPeriod.period == "APR") { if (_salaryProfile != null) { const salaryOrg = await this.salaryOrgRepository.findOne({ where: { id: _salaryProfile.salaryOrg.id, }, relations: { salaryProfiles: true }, }); if (salaryOrg != null) { const amountFullType = await this.salaryProfileRepository.count({ where: { salaryOrgId: salaryOrg.id, type: "FULL", }, }); salaryOrg.total = salaryOrg.salaryProfiles.length; salaryOrg.fifteenPercent = Math.floor((salaryOrg.salaryProfiles.length * 15) / 100); salaryOrg.fifteenPoint = (salaryOrg.salaryProfiles.length * 15) % 100; salaryOrg.quantityUsed = amountFullType; const calRemainQuota = salaryOrg.fifteenPercent - amountFullType; salaryOrg.remainQuota = calRemainQuota; salaryOrg.lastUpdateUserId = req.user.sub; salaryOrg.lastUpdateFullName = req.user.name; salaryOrg.lastUpdatedAt = new Date(); await this.salaryOrgRepository.save(salaryOrg, { data: req }); setLogDataDiff(req, { before, after: salaryOrg }); } } } else if (_salaryProfile.salaryOrg.salaryPeriod.period == "OCT") { if (_salaryProfile != null) { const salaryOrg = await this.salaryOrgRepository.findOne({ where: { id: _salaryProfile.salaryOrg.id, }, relations: { salaryProfiles: true }, }); if (salaryOrg != null) { const totalProfile = Extension.sumObjectValues(salaryOrg.salaryProfiles, "amount"); salaryOrg.currentAmount = totalProfile; salaryOrg.total = salaryOrg.salaryProfiles.length; salaryOrg.sixPercentAmount = totalProfile * 0.06; let totalAmount = 0; const salaryPeriodAPROld = await this.salaryPeriodRepository.findOne({ where: { year: _salaryProfile.salaryOrg.salaryPeriod.year, period: "APR", }, }); 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"); } salaryOrg.spentAmount = totalAmount; const sumAmountUse = await AppDataSource.getRepository(SalaryProfileEmployee) .createQueryBuilder("salaryProfileEmployee") .select("SUM(salaryProfileEmployee.amountUse)", "totalAmount") .where({ salaryOrgId: salaryOrg.id, type: In(["HAFT", "FULL", "FULLHAFT"]), }) .getRawOne(); const calRemainAmount = salaryOrg.sixPercentAmount - sumAmountUse.totalAmount - salaryOrg.spentAmount; salaryOrg.useAmount = sumAmountUse == null || sumAmountUse.totalAmount == null ? 0 : sumAmountUse.totalAmount; salaryOrg.remainingAmount = calRemainAmount; salaryOrg.lastUpdateUserId = req.user.sub; salaryOrg.lastUpdateFullName = req.user.name; salaryOrg.lastUpdatedAt = new Date(); await this.salaryOrgRepository.save(salaryOrg, { data: req }); setLogDataDiff(req, { before, after: salaryOrg }); } } } } return new HttpSuccess(); } 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-multi") async changeTypeMulti( @Body() body: { profileId: string[]; type: string; isReserve: boolean; remark?: string | null }, @Request() req: RequestWithUser, ) { await new permission().PermissionCreate(req, "SYS_WAGE"); for await (const profile of body.profileId) { let salaryProfile = await this.salaryProfileRepository.findOne({ relations: ["salaryOrg", "salaryOrg.salaryPeriod"], where: { id: profile }, }); if (!salaryProfile) { throw new HttpError( HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลการขอเงินเดือนผู้ใช้งานนี้ในระบบ", ); } body.type = body.type.toUpperCase(); //ตรวจสอบงวดเมษาว่าเลื่อนกี่ขั้น if (body.type == "FULLHAFT") { if (salaryProfile?.salaryOrg?.salaryPeriod?.period === "OCT") { const checkPreviousType = await this.salaryProfileRepository.findOne({ relations: ["salaryOrg", "salaryOrg.salaryPeriod"], where: { citizenId: salaryProfile?.citizenId, salaryOrg: { salaryPeriod: { period: "APR", year: salaryProfile?.salaryOrg?.salaryPeriod?.year, //ปีที่ตรงกันด้วย }, snapshot: "SNAP2", }, type: "FULL", }, }); if (checkPreviousType) { throw new HttpError( HttpStatusCode.NOT_FOUND, "ไม่สามารถเลื่อนขั้นบุคลากรเกิน 2 ขั้นต่อปีได้", ); } } } if (body.type == "FULL") { salaryProfile.isReserve = body.isReserve; } else { salaryProfile.isReserve = false; } //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, "ไม่พบระดับตำแหน่ง"); } salaryProfile.type = body.type; let _null: any = null; salaryProfile.remark = body.remark == null ? _null : body.remark; let type = salaryProfile.type; salaryProfile = await this.calSalary(type, salaryProfile); salaryProfile.lastUpdateUserId = req.user.sub; salaryProfile.lastUpdateFullName = req.user.name; salaryProfile.lastUpdatedAt = new Date(); const before = structuredClone(salaryProfile); await this.salaryProfileRepository.save(salaryProfile, { data: req }); setLogDataDiff(req, { before, after: salaryProfile }); const _salaryProfile = await this.salaryProfileRepository.findOne({ relations: ["salaryOrg", "salaryOrg.salaryPeriod"], where: { id: salaryProfile.id }, }); // หาจำนวน Quota คงเหลือ if (_salaryProfile != null) { if (_salaryProfile.salaryOrg.snapshot == "SNAP1") { if (_salaryProfile.salaryOrg.salaryPeriod.period == "APR") { if (_salaryProfile != null) { const salaryOrg = await this.salaryOrgRepository.findOne({ where: { id: _salaryProfile.salaryOrg.id, }, relations: { salaryProfiles: true }, }); if (salaryOrg != null) { const amountFullType = await this.salaryProfileRepository.count({ where: { salaryOrgId: salaryOrg.id, type: "FULL", }, }); salaryOrg.total = salaryOrg.salaryProfiles.length; salaryOrg.fifteenPercent = Math.floor((salaryOrg.salaryProfiles.length * 15) / 100); salaryOrg.fifteenPoint = (salaryOrg.salaryProfiles.length * 15) % 100; salaryOrg.quantityUsed = amountFullType; const calRemainQuota = salaryOrg.fifteenPercent - amountFullType; salaryOrg.remainQuota = calRemainQuota; salaryOrg.lastUpdateUserId = req.user.sub; salaryOrg.lastUpdateFullName = req.user.name; salaryOrg.lastUpdatedAt = new Date(); await this.salaryOrgRepository.save(salaryOrg, { data: req }); setLogDataDiff(req, { before, after: salaryOrg }); } } } else if (_salaryProfile.salaryOrg.salaryPeriod.period == "OCT") { if (_salaryProfile != null) { const salaryOrg = await this.salaryOrgRepository.findOne({ where: { id: _salaryProfile.salaryOrg.id, }, relations: { salaryProfiles: true }, }); if (salaryOrg != null) { const totalProfile = Extension.sumObjectValues(salaryOrg.salaryProfiles, "amount"); salaryOrg.currentAmount = totalProfile; salaryOrg.total = salaryOrg.salaryProfiles.length; salaryOrg.sixPercentAmount = totalProfile * 0.06; let totalAmount = 0; const salaryPeriodAPROld = await this.salaryPeriodRepository.findOne({ where: { year: _salaryProfile.salaryOrg.salaryPeriod.year, period: "APR", }, }); 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"); } salaryOrg.spentAmount = totalAmount; const sumAmountUse = await AppDataSource.getRepository(SalaryProfileEmployee) .createQueryBuilder("salaryProfileEmployee") .select("SUM(salaryProfileEmployee.amountUse)", "totalAmount") .where({ salaryOrgId: salaryOrg.id, type: In(["HAFT", "FULL", "FULLHAFT"]), }) .getRawOne(); const calRemainAmount = salaryOrg.sixPercentAmount - sumAmountUse.totalAmount - salaryOrg.spentAmount; salaryOrg.useAmount = sumAmountUse == null || sumAmountUse.totalAmount == null ? 0 : sumAmountUse.totalAmount; salaryOrg.remainingAmount = calRemainAmount; salaryOrg.lastUpdateUserId = req.user.sub; salaryOrg.lastUpdateFullName = req.user.name; salaryOrg.lastUpdatedAt = new Date(); await this.salaryOrgRepository.save(salaryOrg, { data: req }); setLogDataDiff(req, { before, after: salaryOrg }); } } } } // return new HttpSuccess(); } } return new HttpSuccess(); } /** * API รายการอัตราเงินเดือน * * @summary SLR_023 - รายการอัตราเงินเดือน #22 * */ @Put("org/{id}") async GetListsSalaryProfile( @Request() request: RequestWithUser, @Path() id: string, @Body() body: { page: number; pageSize: number; keyword?: string; type?: any; isRetire?: string | null; sortBy?: string, descending?: boolean, }, ) { await new permission().PermissionList(request, "SYS_WAGE"); const salaryOrg = await this.salaryOrgRepository.findOne({ where: { id: id, }, }); if (!salaryOrg) { throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบรอบการขึ้นเงินเดือน"); } let query = await AppDataSource.getRepository(SalaryProfileEmployee) .createQueryBuilder("profile") .andWhere( new Brackets((qb) => { qb.andWhere(body.type != null && body.type != "" ? `profile.type LIKE :type` : "1=1", { type: body.type == null ? "" : `${body.type.toUpperCase()}`, }) .andWhere( // body.isRetire != null // ? body.isRetire == "1" // ? `profile.isRetired = true` // : `profile.isRetired = false` // : "1=1", body.isRetire == null ? "1=1" : body.isRetire == "1" ? `profile.isRetired = true` : body.isRetire == "0" ? `profile.isRetired = false` : "1=1", ) .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("CONCAT(profile.posTypeShort,' ',profile.posLevel) LIKE :keyword", { keyword: `%${body.keyword}%`, }) .orWhere( "CONCAT(profile.prefix,profile.firstName,' ',profile.lastName) LIKE :keyword", { keyword: `%${body.keyword}%` }, ) .orWhere("CONCAT(profile.orgShortName,' ',profile.posMasterNo) LIKE :keyword", { keyword: `%${body.keyword}%`, }) .orWhere("CONCAT(profile.orgShortName,' ',profile.posMasterNo) 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}%`, }); }), ); }), ) if (body.sortBy) { if(body.sortBy === "posLevel"){ query = query .orderBy( `profile.posTypeShort`,body.descending ? "DESC" : "ASC") .addOrderBy( `profile.posLevel`,body.descending ? "DESC" : "ASC"); }else{ query = query.orderBy( `profile.${body.sortBy}`, body.descending ? "DESC" : "ASC" ); } }else{ query = query.orderBy("profile.citizenId", "ASC") .addOrderBy("profile.isReserve", "ASC") } const [salaryProfile, total] = await query .skip((body.page - 1) * body.pageSize) .take(body.pageSize) .getManyAndCount(); const mapSalaryProfile = salaryProfile.map((item) => ({ id: item.id, profileId: item.profileId, salaryOrgId: item.salaryOrgId, salaryLevel: item.salaryLevel, salaryLevelNew: item.salaryLevelNew, prefix: item.prefix, firstName: item.firstName, lastName: item.lastName, citizenId: item.citizenId, posMasterNoPrefix: item.posMasterNoPrefix, posMasterNo: item.posMasterNo, posMasterNoSuffix: item.posMasterNoSuffix, orgShortName: item.orgShortName, position: item.position, posType: item.posType, posTypeShort: item.posTypeShort, posLevel: item.posTypeShort != null && item.posLevel != null ? `${item.posTypeShort} ${item.posLevel}` : null, group: item.group, groupNew: item.groupNew, amount: item.amount, amountSpecial: item.amountSpecial, amountUse: item.amountUse, positionSalaryAmount: item.positionSalaryAmount, positionSalaryAmountPer: item.positionSalaryAmountPer, positionSalaryDayAmount: item.positionSalaryDayAmount, type: item.type, status: item.status, revisionId: item.revisionId, rootId: item.rootId, root: item.root, child1Id: item.child1Id, child1: item.child1, child2Id: item.child2Id, child2: item.child2, child3Id: item.child3Id, child3: item.child3, child4Id: item.child4Id, child4: item.child4, result: item.result, duration: item.duration, isPunish: item.isPunish, isSuspension: item.isSuspension, isAbsent: item.isAbsent, isLeave: item.isLeave, isRetired: item.isRetired, isReserve: item.isReserve, isNext: item.isNext, remark: item.remark, })); return new HttpSuccess({ data: mapSalaryProfile, total }); } /** * API แก้คุณสมบัติ * * @summary SLR_031 - แก้คุณสมบัติ #30 * */ @Put("org/property/{id}") async editProperty( @Path() id: string, @Body() body: { isPunish: any; isSuspension: any; isAbsent: any; isLeave: any; }, @Request() request: RequestWithUser, ) { await new permission().PermissionUpdate(request, "SYS_WAGE"); const salaryProfile = await this.salaryProfileRepository.findOne({ where: { id: id, }, }); if (!salaryProfile) { throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลการเพิ่มเงินเดือนของบุคคลนี้"); } const before = structuredClone(salaryProfile); salaryProfile.isPunish = body.isPunish; salaryProfile.isSuspension = body.isSuspension; salaryProfile.isAbsent = body.isAbsent; salaryProfile.isLeave = body.isLeave; salaryProfile.lastUpdateUserId = request.user.sub; salaryProfile.lastUpdateFullName = request.user.name; salaryProfile.lastUpdatedAt = new Date(); await this.salaryProfileRepository.save(salaryProfile, { data: request }); setLogDataDiff(request, { before, after: salaryProfile }); return new HttpSuccess(); } /** * API เพิ่มคนเลื่อนเงินเดือนตามรอบ * * @summary SLR_028 - เพิ่มคนเลื่อนเงินเดือนตามรอบ #27 * */ @Post("org/profile") async addSalaryProfile( @Body() requestBody: CreateSalaryProfileEmployee, @Request() request: RequestWithUser, ) { await new permission().PermissionCreate(request, "SYS_WAGE"); const salaryOrg = await this.salaryOrgRepository.findOne({ relations: ["salaryPeriod", "salaryProfiles"], where: { id: requestBody.id, }, }); if (!salaryOrg) { throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบรอบการขึ้นเงินเดือน"); } const salaryOrgAll = await this.salaryOrgRepository.find({ where: { salaryPeriodId: salaryOrg.salaryPeriodId, snapshot: salaryOrg.snapshot, }, }); 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 SalaryProfileEmployee(), requestBody); delete salaryProfile.id; salaryProfile.type = salaryProfile.type.toUpperCase(); //Type & Level const posType = await this.posTypeRepository.findOne({ where: { posTypeName: salaryProfile.posType, }, }); if (!posType) { throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบประเภทตำแหน่ง"); } const posLevel = await this.posLevelRepository.findOne({ where: { posTypeId: posType.id, posLevelName: salaryProfile.posLevel, }, }); if (!posLevel) { throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบระดับตำแหน่ง"); } let type = salaryProfile.type; salaryProfile = await this.calSalary(type, salaryProfile); const before = null; salaryProfile.salaryOrgId = salaryOrg.id; salaryProfile.createdUserId = request.user.sub; salaryProfile.createdFullName = request.user.name; salaryProfile.lastUpdateUserId = request.user.sub; salaryProfile.lastUpdateFullName = request.user.name; salaryProfile.createdAt = new Date(); salaryProfile.lastUpdatedAt = new Date(); await this.salaryProfileRepository.save(salaryProfile, { data: request }); setLogDataDiff(request, { before, after: salaryProfile }); const _salaryProfile = await this.salaryProfileRepository.findOne({ relations: ["salaryOrg", "salaryOrg.salaryPeriod"], where: { id: salaryProfile.id }, }); // หาจำนวน Quota คงเหลือ if (_salaryProfile != null) { if (_salaryProfile.salaryOrg.snapshot == "SNAP1") { if (_salaryProfile.salaryOrg.salaryPeriod.period == "APR") { if (_salaryProfile != null) { const salaryOrg = await this.salaryOrgRepository.findOne({ where: { id: _salaryProfile.salaryOrg.id, }, relations: { salaryProfiles: true }, }); if (salaryOrg != null) { const amountFullType = await this.salaryProfileRepository.count({ where: { salaryOrgId: salaryOrg.id, type: "FULL", }, }); salaryOrg.total = salaryOrg.salaryProfiles.length; salaryOrg.fifteenPercent = Math.floor((salaryOrg.salaryProfiles.length * 15) / 100); salaryOrg.fifteenPoint = (salaryOrg.salaryProfiles.length * 15) % 100; salaryOrg.quantityUsed = amountFullType; const calRemainQuota = salaryOrg.fifteenPercent - amountFullType; salaryOrg.remainQuota = calRemainQuota; salaryOrg.lastUpdateUserId = request.user.sub; salaryOrg.lastUpdateFullName = request.user.name; salaryOrg.lastUpdatedAt = new Date(); await this.salaryOrgRepository.save(salaryOrg, { data: request }); setLogDataDiff(request, { before, after: salaryOrg }); } } } else if (_salaryProfile.salaryOrg.salaryPeriod.period == "OCT") { if (_salaryProfile != null) { const salaryOrg = await this.salaryOrgRepository.findOne({ where: { id: _salaryProfile.salaryOrg.id, }, relations: { salaryProfiles: true }, }); if (salaryOrg != null) { const totalProfile = Extension.sumObjectValues(salaryOrg.salaryProfiles, "amount"); salaryOrg.currentAmount = totalProfile; salaryOrg.total = salaryOrg.salaryProfiles.length; salaryOrg.sixPercentAmount = totalProfile * 0.06; let totalAmount = 0; const salaryPeriodAPROld = await this.salaryPeriodRepository.findOne({ where: { year: _salaryProfile.salaryOrg.salaryPeriod.year, period: "APR", }, }); 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"); } salaryOrg.spentAmount = totalAmount; const sumAmountUse = await AppDataSource.getRepository(SalaryProfileEmployee) .createQueryBuilder("salaryProfileEmployee") .select("SUM(salaryProfileEmployee.amountUse)", "totalAmount") .where({ salaryOrgId: salaryOrg.id, type: In(["HAFT", "FULL", "FULLHAFT"]), }) .getRawOne(); const calRemainAmount = salaryOrg.sixPercentAmount - sumAmountUse.totalAmount - salaryOrg.spentAmount; salaryOrg.useAmount = sumAmountUse == null || sumAmountUse.totalAmount == null ? 0 : sumAmountUse.totalAmount; salaryOrg.remainingAmount = calRemainAmount; salaryOrg.lastUpdateUserId = request.user.sub; salaryOrg.lastUpdateFullName = request.user.name; salaryOrg.lastUpdatedAt = new Date(); await this.salaryOrgRepository.save(salaryOrg, { data: request }); setLogDataDiff(request, { before, after: salaryOrg }); } } } } return new HttpSuccess(); } return new HttpSuccess(salaryProfile.id); } /** * API ปิดรอบเงินเดือน * * @summary SLR_032 - ปิดรอบเงินเดือน #31 * * @param {string} id Guid, *Id รอบเงินเดือน */ @Get("close/{id}") async closeSalaryPeriod_ById(@Path() id: string, @Request() request: RequestWithUser) { const salaryPeriod = await this.salaryPeriodRepository.findOne({ where: { id: id }, }); if (!salaryPeriod) { throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลรอบผังเงินเดือนนี้"); } const before = structuredClone(salaryPeriod); salaryPeriod.isClose = !salaryPeriod.isClose; salaryPeriod.lastUpdateUserId = request.user.sub; salaryPeriod.lastUpdateFullName = request.user.name; salaryPeriod.lastUpdatedAt = new Date(); await this.salaryPeriodRepository.save(salaryPeriod, { data: request }); setLogDataDiff(request, { before, after: salaryPeriod }); return new HttpSuccess(); } /** * API สร้างรอบเงินเดือน * * @summary SLR_016 - สร้างรอบเงินเดือน #16 * */ @Post() async create_salary_period( @Body() requestBody: CreateSalaryPeriod, @Request() request: RequestWithUser, ) { await new permission().PermissionCreate(request, "SYS_WAGE"); 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, "ประเภทผังปี " + Extension.ToThaiYear(salaryPeriod.year) + " ซ้ำ", ); } const before = null; 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; salaryPeriod.createdAt = new Date(); salaryPeriod.lastUpdatedAt = new Date(); await this.salaryPeriodRepository.save(salaryPeriod, { data: request }); setLogDataDiff(request, { before, after: salaryPeriod }); if (salaryPeriod.period == "SPECIAL") { const snapshot = "SNAP1"; 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, { data: request }); await this.salaryProfileRepository.remove(salaryProfile, { data: request }); let orgs = await new CallAPI().GetData(request, "/org/unauthorize/active/root/id"); let revisionId = await new CallAPI().GetData(request, "/org/unauthorize/revision/latest"); salaryPeriod.revisionId = revisionId; salaryPeriod.lastUpdateUserId = request.user.sub; salaryPeriod.lastUpdateFullName = request.user.name; salaryPeriod.lastUpdatedAt = new Date(); await this.salaryPeriodRepository.save(salaryPeriod, { data: request }); setLogDataDiff(request, { before, after: salaryPeriod }); await Promise.all( orgs.map(async (rootId: string) => { let salaryOrgNew = Object.assign(new SalaryOrgEmployee()); salaryOrgNew.salaryPeriodId = salaryPeriod.id; salaryOrgNew.status = "PENDING"; salaryOrgNew.rootId = rootId; salaryOrgNew.revisionId = salaryPeriod.revisionId; salaryOrgNew.snapshot = snapshot; salaryOrgNew.createdUserId = request.user.sub; salaryOrgNew.createdFullName = request.user.name; salaryOrgNew.lastUpdateUserId = request.user.sub; salaryOrgNew.lastUpdateFullName = request.user.name; salaryOrgNew.createdAt = new Date(); salaryOrgNew.lastUpdatedAt = new Date(); salaryOrgNew.group = "GROUP1"; await this.salaryOrgRepository.save(salaryOrgNew, { data: request }); setLogDataDiff(request, { before, after: salaryOrgNew }); }), ); } 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: RequestWithUser, ) { await new permission().PermissionUpdate(request, "SYS_WAGE"); 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) + " ซ้ำ", ); } const beforechk_SalaryPeriod = structuredClone(chk_SalaryPeriod); 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, { data: request }); setLogDataDiff(request, { before: beforechk_SalaryPeriod, after: chk_SalaryPeriod }); if (chk_SalaryPeriod.period == "SPECIAL") { const snapshot = "SNAP1"; const salaryOrg = await this.salaryOrgRepository.find({ where: { salaryPeriodId: chk_SalaryPeriod.id, snapshot: snapshot }, }); const salaryProfile = await this.salaryProfileRepository.find({ where: { salaryOrgId: In(salaryOrg.map((x) => x.id)) }, }); await this.salaryOrgRepository.remove(salaryOrg, { data: request }); await this.salaryProfileRepository.remove(salaryProfile, { data: request }); let orgs = await new CallAPI().GetData(request, "/org/unauthorize/active/root/id"); let revisionId = await new CallAPI().GetData(request, "/org/unauthorize/revision/latest"); chk_SalaryPeriod.revisionId = revisionId; chk_SalaryPeriod.lastUpdateUserId = request.user.sub; chk_SalaryPeriod.lastUpdateFullName = request.user.name; chk_SalaryPeriod.lastUpdatedAt = new Date(); await this.salaryPeriodRepository.save(chk_SalaryPeriod, { data: request }); setLogDataDiff(request, { before: beforechk_SalaryPeriod, after: chk_SalaryPeriod }); await Promise.all( orgs.map(async (rootId: string) => { let salaryOrgNew = Object.assign(new SalaryOrgEmployee()); const before = structuredClone(salaryOrgNew); salaryOrgNew.salaryPeriodId = chk_SalaryPeriod.id; salaryOrgNew.status = "PENDING"; salaryOrgNew.rootId = rootId; salaryOrgNew.revisionId = chk_SalaryPeriod.revisionId; salaryOrgNew.snapshot = snapshot; salaryOrgNew.createdUserId = request.user.sub; salaryOrgNew.createdFullName = request.user.name; salaryOrgNew.lastUpdateUserId = request.user.sub; salaryOrgNew.lastUpdateFullName = request.user.name; salaryOrgNew.createdAt = new Date(); salaryOrgNew.lastUpdatedAt = new Date(); salaryOrgNew.group = "GROUP1"; await this.salaryOrgRepository.save(salaryOrgNew, { data: request }); setLogDataDiff(request, { before, after: salaryOrgNew }); }), ); } return new HttpSuccess(id); } /** * API ลบรอบเงินเดือน * * @summary SLR_018 - ลบรอบเงินเดือน #18 * * @param {string} id Guid, *Id รอบเงินเดือน */ @Delete("{id}") async delete_salary_period(@Path() id: string, @Request() request: RequestWithUser) { await new permission().PermissionDelete(request, "SYS_WAGE"); const SalaryPeriod = await this.salaryPeriodRepository.findOne({ where: { id: id }, }); if (!SalaryPeriod) throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลรอบผังเงินเดือนนี้"); if (SalaryPeriod?.period == "SPECIAL") { const SalaryOrg = await this.salaryOrgRepository.find({ where: { salaryPeriodId: SalaryPeriod.id }, relations: ["salaryProfiles"], }); const salaryProfile = SalaryOrg.find((x) => x.salaryProfiles.length > 0); if (salaryProfile) throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่สามารถลบได้"); await this.salaryOrgRepository.remove(SalaryOrg, { data: request }); await this.salaryPeriodRepository.remove(SalaryPeriod, { data: request }); return new HttpSuccess(); } else { const SalaryOrg = await this.salaryOrgRepository.findOne({ where: { salaryPeriodId: SalaryPeriod.id }, }); if (SalaryOrg) throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่สามารถลบได้"); await this.salaryPeriodRepository.remove(SalaryPeriod, { data: request }); return new HttpSuccess(); } } /** * API รายการรอบเงินเดือน(active) * * */ @Get("active") async GetListsSalaryPeriodActive( @Query("page") page: number = 1, @Query("pageSize") pageSize: number = 10, @Query("keyword") keyword?: string, ) { const [salaryPeriod, total] = await AppDataSource.getRepository(SalaryPeriod) .createQueryBuilder("salaryPeriod") .where({ isActive: true }) .select([ "salaryPeriod.id", "salaryPeriod.period", "salaryPeriod.isActive", "salaryPeriod.isClose", "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 รายละเอียดรอบเงินเดือน * * @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", "isClose", "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}` }) .select([ "salaryPeriod.id", "salaryPeriod.period", "salaryPeriod.isActive", "salaryPeriod.isClose", "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 เจ้าหน้าที่ส่ง ผอ * * * @param {string} periodId Guid, *Id รอบเงินเดือน * @param {string} rootId Guid, *Id สำนัก */ @Get("officer/approve/{periodId}/{rootId}") async OfficerApprove( @Path() periodId: string, rootId: string, @Request() request: RequestWithUser, ) { const salaryPeriod = await this.salaryPeriodRepository.findOne({ where: { id: periodId }, relations: ["salaryOrgEmployees"], }); if (!salaryPeriod) throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลรอบผังเงินเดือนนี้"); await Promise.all( salaryPeriod.salaryOrgEmployees .filter((x) => x.rootId == rootId) .map(async (x: any) => { const before = structuredClone(x); x.status = "WAITHEAD1"; x.lastUpdateUserId = request.user.sub; x.lastUpdateFullName = request.user.name; x.lastUpdatedAt = new Date(); await this.salaryOrgRepository.save(x, { data: request }); setLogDataDiff(request, { before, after: x }); }), ); return new HttpSuccess(); } /** * API ผอ ส่ง สกจ * * * @param {string} orgId Guid, *Id รอบเงินเดือน * @param {string} rootId Guid, *Id สำนัก */ @Get("head/approve/{periodId}/{rootId}") async HeadApprove(@Path() periodId: string, rootId: string, @Request() request: RequestWithUser) { const salaryPeriod = await this.salaryPeriodRepository.findOne({ where: { id: periodId }, relations: ["salaryOrgEmployees"], }); if (!salaryPeriod) throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลรอบผังเงินเดือนนี้"); await Promise.all( salaryPeriod.salaryOrgEmployees .filter((x) => x.rootId == rootId) .map(async (x: any) => { const before = structuredClone(x); x.status = "WAITOWNER1"; x.lastUpdateUserId = request.user.sub; x.lastUpdateFullName = request.user.name; x.lastUpdatedAt = new Date(); await this.salaryOrgRepository.save(x, { data: request }); setLogDataDiff(request, { before, after: x }); }), ); return new HttpSuccess(); } /** * API สกจ อนุมัติ * * * @param {string} orgId Guid, *Id รอบเงินเดือน * @param {string} rootId Guid, *Id สำนัก */ @Get("owner/approve/{periodId}/{rootId}") async OwnerApprove( @Path() periodId: string, rootId: string, @Request() request: RequestWithUser, ) { const salaryPeriod = await this.salaryPeriodRepository.findOne({ where: { id: periodId }, relations: ["salaryOrgEmployees"], }); if (!salaryPeriod) throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลรอบผังเงินเดือนนี้"); await Promise.all( salaryPeriod.salaryOrgEmployees .filter((x) => x.rootId == rootId) .map(async (x: any) => { const before = structuredClone(x); x.status = "REPORT"; x.lastUpdateUserId = request.user.sub; x.lastUpdateFullName = request.user.name; x.lastUpdatedAt = new Date(); await this.salaryOrgRepository.save(x, { data: request }); setLogDataDiff(request, { before, after: x }); }), ); return new HttpSuccess(); } /** * API สกจ ส่ง ผอ * * * @param {string} orgId Guid, *Id รอบเงินเดือน * @param {string} rootId Guid, *Id สำนัก */ @Put("owner/comment/{periodId}/{rootId}") async WaitOwnerApprove( @Path() periodId: string, rootId: string, @Body() body: { titleRecommend: string; }, @Request() request: RequestWithUser, ) { await new permission().PermissionUpdate(request, "SYS_WAGE"); const salaryPeriod = await this.salaryPeriodRepository.findOne({ where: { id: periodId }, relations: ["salaryOrgEmployees"], }); if (!salaryPeriod) throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลรอบผังเงินเดือนนี้"); await Promise.all( salaryPeriod.salaryOrgEmployees .filter((x) => x.rootId == rootId) .map(async (x: any) => { const before = structuredClone(x); x.status = "WAITHEAD2"; x.ownerRecommend = body.titleRecommend; x.lastUpdateUserId = request.user.sub; x.lastUpdateFullName = request.user.name; x.lastUpdatedAt = new Date(); await this.salaryOrgRepository.save(x, { data: request }); setLogDataDiff(request, { before, after: x }); }), ); return new HttpSuccess(); } /** * API ผอ ส่ง เจ้าหน้าที่ * * * @param {string} orgId Guid, *Id รอบเงินเดือน * @param {string} rootId Guid, *Id สำนัก */ @Put("head/comment/{periodId}/{rootId}") async WaitHeadApprove( @Path() periodId: string, rootId: string, @Body() body: { titleRecommend: string; }, @Request() request: RequestWithUser, ) { await new permission().PermissionUpdate(request, "SYS_WAGE"); const salaryPeriod = await this.salaryPeriodRepository.findOne({ where: { id: periodId }, relations: ["salaryOrgEmployees"], }); if (!salaryPeriod) throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลรอบผังเงินเดือนนี้"); await Promise.all( salaryPeriod.salaryOrgEmployees .filter((x) => x.rootId == rootId) .map(async (x: any) => { const before = structuredClone(x); x.status = "REPORT"; x.ownerRecommend = body.titleRecommend; x.lastUpdateUserId = request.user.sub; x.lastUpdateFullName = request.user.name; x.lastUpdatedAt = new Date(); await this.salaryOrgRepository.save(x, { data: request }); setLogDataDiff(request, { before, after: x }); }), ); return new HttpSuccess(); } async calSalary( type: string, salaryProfile: SalaryProfileEmployee, ): Promise { if (type == "NONE") { salaryProfile.isNext = false; salaryProfile.amountSpecial = 0; salaryProfile.amountUse = 0; salaryProfile.positionSalaryAmount = salaryProfile.amount == null ? 0 : salaryProfile.amount; salaryProfile.positionSalaryDayAmount = 0; salaryProfile.groupNew = 0; salaryProfile.salaryLevelNew = 0; salaryProfile.positionSalaryAmountPer = 0; } else if (type == "PENDING") { salaryProfile.isNext = false; salaryProfile.amountSpecial = 0; salaryProfile.amountUse = 0; salaryProfile.positionSalaryAmount = 0; salaryProfile.positionSalaryDayAmount = 0; salaryProfile.groupNew = 0; salaryProfile.salaryLevelNew = 0; salaryProfile.positionSalaryAmountPer = 0; } else if (type == "HAFT" || type == "FULL" || type == "FULLHAFT") { const salaryFormula = await this.salaryFormulaEmployeeRepository.findOne({ where: { position: salaryProfile.position, posType: { posTypeName: salaryProfile.posType }, posLevel: { posLevelName: salaryProfile.posLevel }, }, relations: ["salaryEmployeeMins", "salaryEmployee"], }); //ขั้นเก่าที่เลื่อนมา let group = salaryProfile.group == null ? 0 : salaryProfile.group; let step = salaryProfile.salaryLevel == null ? 0 : salaryProfile.salaryLevel; if (group == null || group == 0) { if (salaryFormula != null) { //หากลุ่มต่ำสุดตามเกณฑ์ group = salaryFormula.salaryEmployeeMins.sort((a, b) => a.group - b.group)[0].group; } else { group = 1; } } if (step == null || step == 0) { if (salaryFormula != null) { // //หาเงินตำ่สุดที่คำนวนเงิน // let salary = 0; // let _step = 0; // if ( // salaryProfile.amount != null && // salaryProfile.amount > 0 && // salaryFormula.salaryMin != null && // salaryFormula.salaryMin > 0 // ) { // if (salaryProfile.amount >= salaryFormula.salaryMin) { // salary = salaryProfile.amount; // } else { // salary = salaryFormula.salaryMin; // _step = 0.5; // } // } else { // // if (salaryProfile.amount != null && salaryProfile.amount > 0) // // salary = salaryProfile.amount; // // if (salaryFormula.salaryMin != null && salaryFormula.salaryMin > 0) { // salary = salaryFormula.salaryMin == null ? 0 : salaryFormula.salaryMin; // _step = 0.5; // // } // } let salary = salaryProfile.amount == null ? 0 : salaryProfile.amount; //หาขั้นต่ำสุดตามเกณฑ์ let salaryRankMin = await this.salaryRankRepository.findOne({ where: { salaryMonth: salary, salaryEmployee_: { isActive: true, group: group, }, }, // order: { salaryMonth: "ASC" }, }); if (salaryRankMin == null) { salaryRankMin = await this.salaryRankRepository.findOne({ where: { salaryMonth: MoreThan(salary), salaryEmployee_: { isActive: true, group: group, }, }, order: { salaryMonth: "ASC" }, }); if (salaryRankMin == null) { salaryRankMin = await this.salaryRankRepository.findOne({ where: { salaryMonth: salary, salaryEmployee_: { isActive: true, group: salaryFormula.salaryEmployee.group, }, }, order: { salaryMonth: "ASC" }, }); if (salaryRankMin == null) { salaryRankMin = await this.salaryRankRepository.findOne({ where: { salaryMonth: MoreThan(salary), salaryEmployee_: { isActive: true, group: salaryFormula.salaryEmployee.group, }, }, order: { salaryMonth: "ASC" }, }); let _salaryRankAmountMax = await this.salaryRankRepository.findOne({ where: { salaryMonth: salaryFormula.salaryMax == null ? 0 : salaryFormula.salaryMax, salaryEmployee_: { id: salaryFormula.salaryEmployee.id, }, }, }); step = salaryRankMin == null ? _salaryRankAmountMax == null ? 0.5 : _salaryRankAmountMax.step : salaryRankMin.step - 0.5; group = salaryFormula.salaryEmployee.group; } else { step = salaryRankMin.step; group = salaryFormula.salaryEmployee.group; } } else { step = salaryRankMin.step - 0.5; } } else { step = salaryRankMin.step; } } else { step = 0.5; } } if (type == "HAFT") { step = step + 0.5; } else if (type == "FULL") { step = step + 1; } else if (type == "FULLHAFT") { step = step + 1.5; } //หาขั้นสูงสุดในกลุ่มนั้น let salaryRankMax = await this.salaryRankRepository.findOne({ where: { salaryEmployee_: { isActive: true, group: group, }, }, order: { step: "DESC" }, }); //เงินเดือนเกินตาราง if ( salaryRankMax != null && step > salaryRankMax.step && (salaryFormula == null || (salaryFormula != null && salaryProfile.amount != null && salaryFormula.salaryMax != null && salaryFormula.salaryMax > salaryProfile.amount)) ) { group = group + 1; //เงินเดือนในกลุ่มต่อไป let salaryRankAmount = await this.salaryRankRepository.findOne({ where: { salaryMonth: salaryRankMax.salaryMonth != null && salaryRankMax.salaryMonth > 0 ? MoreThan(salaryRankMax.salaryMonth) : 0, salaryEmployee_: { isActive: true, group: group, }, }, order: { salaryMonth: "ASC" }, }); step = (salaryRankAmount == null ? 1 : salaryRankAmount.step) + (step - (salaryRankMax == null ? 0 : salaryRankMax.step) - 0.5); } let salaryRanks = await this.salaryRankRepository.findOne({ where: { step: step, salaryEmployee_: { isActive: true, group: group, }, }, }); if (salaryRanks != null && salaryRanks.salaryMonth != null) { if ( salaryFormula != null && salaryFormula.salaryMax != null && salaryRanks.salaryMonth > salaryFormula.salaryMax ) { let salaryRankAmountMax = await this.salaryRankRepository.findOne({ where: { salaryMonth: salaryFormula.salaryMax, salaryEmployee_: { id: salaryFormula.salaryEmployee.id, }, }, }); salaryProfile.isNext = true; salaryProfile.amountUse = salaryFormula.salaryMax - (salaryProfile.amount == null ? 0 : salaryProfile.amount); salaryProfile.positionSalaryAmount = salaryRankAmountMax == null || salaryRankAmountMax.salaryMonth == null ? 0 : salaryRankAmountMax.salaryMonth; salaryProfile.positionSalaryDayAmount = salaryRankAmountMax == null ? 0 : salaryRankAmountMax.salaryDay; salaryProfile.groupNew = salaryFormula.salaryEmployee.group; salaryProfile.salaryLevelNew = salaryRankAmountMax == null ? 0 : salaryRankAmountMax.step; salaryRankAmountMax == null ? 0 : salaryRankAmountMax.step; if (salaryRankAmountMax != null) { if (step - salaryRankAmountMax.step <= 0.5) { salaryProfile.positionSalaryAmountPer = 0.02; salaryProfile.amountSpecial = salaryRankAmountMax == null || salaryRankAmountMax.salaryMonth == null ? 0 : Math.floor(salaryRankAmountMax.salaryMonth * 0.02); } else if (step - salaryRankAmountMax.step <= 1) { salaryProfile.positionSalaryAmountPer = 0.04; salaryProfile.amountSpecial = salaryRankAmountMax == null || salaryRankAmountMax.salaryMonth == null ? 0 : Math.floor(salaryRankAmountMax.salaryMonth * 0.04); } else { salaryProfile.positionSalaryAmountPer = 0.06; salaryProfile.amountSpecial = salaryRankAmountMax == null || salaryRankAmountMax.salaryMonth == null ? 0 : Math.floor(salaryRankAmountMax.salaryMonth * 0.06); } } else { salaryProfile.positionSalaryAmountPer = 0; salaryProfile.amountSpecial = 0; } } else { salaryProfile.isNext = false; salaryProfile.amountUse = salaryRanks.salaryMonth - (salaryProfile.amount == null ? 0 : salaryProfile.amount); salaryProfile.positionSalaryAmount = salaryRanks.salaryMonth; salaryProfile.positionSalaryDayAmount = salaryRanks.salaryDay; salaryProfile.groupNew = group; salaryProfile.salaryLevelNew = step; salaryProfile.positionSalaryAmountPer = 0; salaryProfile.amountSpecial = 0; } } else { if ( salaryFormula != null && salaryFormula.salaryMax != null && salaryProfile.amount != null && salaryFormula.salaryMax <= salaryProfile.amount ) { let salaryRankAmountMax = await this.salaryRankRepository.findOne({ where: { salaryMonth: salaryFormula.salaryMax, salaryEmployee_: { id: salaryFormula.salaryEmployee.id, }, }, }); salaryProfile.isNext = true; salaryProfile.amountUse = salaryFormula.salaryMax - salaryProfile.amount; salaryProfile.positionSalaryAmount = salaryRankAmountMax == null || salaryRankAmountMax.salaryMonth == null ? 0 : salaryRankAmountMax.salaryMonth; salaryProfile.positionSalaryDayAmount = salaryRankAmountMax == null ? 0 : salaryRankAmountMax.salaryDay; salaryProfile.groupNew = salaryFormula.salaryEmployee.group; salaryProfile.salaryLevelNew = salaryRankAmountMax == null ? 0 : salaryRankAmountMax.step; salaryRankAmountMax == null ? 0 : salaryRankAmountMax.step; if (salaryRankAmountMax != null) { if (step - salaryRankAmountMax.step <= 0.5) { salaryProfile.positionSalaryAmountPer = 0.02; salaryProfile.amountSpecial = salaryRankAmountMax == null || salaryRankAmountMax.salaryMonth == null ? 0 : Math.floor(salaryRankAmountMax.salaryMonth * 0.02); } else if (step - salaryRankAmountMax.step <= 1) { salaryProfile.positionSalaryAmountPer = 0.04; salaryProfile.amountSpecial = salaryRankAmountMax == null || salaryRankAmountMax.salaryMonth == null ? 0 : Math.floor(salaryRankAmountMax.salaryMonth * 0.04); } else { salaryProfile.positionSalaryAmountPer = 0.06; salaryProfile.amountSpecial = salaryRankAmountMax == null || salaryRankAmountMax.salaryMonth == null ? 0 : Math.floor(salaryRankAmountMax.salaryMonth * 0.06); } } else { salaryProfile.positionSalaryAmountPer = 0; salaryProfile.amountSpecial = 0; } } else { salaryProfile.isNext = false; salaryProfile.amountUse = 0; salaryProfile.positionSalaryAmount = salaryProfile.amount == null ? 0 : salaryProfile.amount; salaryProfile.positionSalaryDayAmount = 0; salaryProfile.positionSalaryAmountPer = 0; salaryProfile.amountSpecial = 0; } } } else { throw "ประเภทการเลื่อนขึ้นเงินเดือนไม่ถูกต้อง"; } return salaryProfile; } async calSalaryNew( type: string, salaryProfile: SalaryProfileEmployee, ): Promise { if (type == "NONE") { salaryProfile.isNext = false; salaryProfile.amountSpecial = 0; salaryProfile.amountUse = 0; salaryProfile.positionSalaryAmount = salaryProfile.amount == null ? 0 : salaryProfile.amount; salaryProfile.positionSalaryDayAmount = 0; salaryProfile.groupNew = 0; salaryProfile.salaryLevelNew = 0; salaryProfile.positionSalaryAmountPer = 0; } else if (type == "PENDING") { salaryProfile.isNext = false; salaryProfile.amountSpecial = 0; salaryProfile.amountUse = 0; salaryProfile.positionSalaryAmount = 0; salaryProfile.positionSalaryDayAmount = 0; salaryProfile.groupNew = 0; salaryProfile.salaryLevelNew = 0; salaryProfile.positionSalaryAmountPer = 0; } else if (type == "HAFT" || type == "FULL" || type == "FULLHAFT") { const salaryFormula = await this.salaryFormulaEmployeeRepository.findOne({ where: { position: salaryProfile.position, posType: { posTypeName: salaryProfile.posType }, posLevel: { posLevelName: salaryProfile.posLevel }, }, relations: ["salaryEmployeeMins", "salaryEmployee"], }); //ขั้นเก่าที่เลื่อนมา // let group = salaryProfile.group == null ? 0 : salaryProfile.group; // let step = salaryProfile.salaryLevel == null ? 0 : salaryProfile.salaryLevel; // if (group == null || group == 0) { // if (salaryFormula != null) { // //หากลุ่มต่ำสุดตามเกณฑ์ // group = salaryFormula.salaryEmployeeMins.sort((a, b) => a.group - b.group)[0].group; // } else { // group = 1; // } // } // if (step == null || step == 0) { // if (salaryFormula != null) { // let salary = salaryProfile.amount == null ? 0 : salaryProfile.amount; // //หาขั้นต่ำสุดตามเกณฑ์ // let salaryRankMin = await this.salaryRankRepository.findOne({ // where: { // salaryMonth: salary, // salaryEmployee_: { // isActive: true, // group: group, // }, // }, // // order: { salaryMonth: "ASC" }, // }); // if (salaryRankMin == null) { // salaryRankMin = await this.salaryRankRepository.findOne({ // where: { // salaryMonth: MoreThan(salary), // salaryEmployee_: { // isActive: true, // group: group, // }, // }, // order: { salaryMonth: "ASC" }, // }); // if (salaryRankMin == null) { // salaryRankMin = await this.salaryRankRepository.findOne({ // where: { // salaryMonth: salary, // salaryEmployee_: { // isActive: true, // group: salaryFormula.salaryEmployee.group, // }, // }, // order: { salaryMonth: "ASC" }, // }); // if (salaryRankMin == null) { // salaryRankMin = await this.salaryRankRepository.findOne({ // where: { // salaryMonth: MoreThan(salary), // salaryEmployee_: { // isActive: true, // group: salaryFormula.salaryEmployee.group, // }, // }, // order: { salaryMonth: "ASC" }, // }); // let _salaryRankAmountMax = await this.salaryRankRepository.findOne({ // where: { // salaryMonth: salaryFormula.salaryMax == null ? 0 : salaryFormula.salaryMax, // salaryEmployee_: { // id: salaryFormula.salaryEmployee.id, // }, // }, // }); // step = // salaryRankMin == null // ? _salaryRankAmountMax == null // ? 0.5 // : _salaryRankAmountMax.step // : salaryRankMin.step - 0.5; // group = salaryFormula.salaryEmployee.group; // } else { // step = salaryRankMin.step; // group = salaryFormula.salaryEmployee.group; // } // } else { // step = salaryRankMin.step - 0.5; // } // } else { // step = salaryRankMin.step; // } // } else { // step = 0.5; // } // } let group = 0; let step = 0; let stepUp = 0; //****หา group และ step จาก amount MoreThanOrEqual if (salaryProfile.amount != null) { let salaryCurrentRanks = await this.salaryRankRepository.findOne({ where: { salaryMonth: salaryProfile.amount, }, relations: ["salaryEmployee_"], }); if (!salaryCurrentRanks) { salaryCurrentRanks = await this.salaryRankRepository.findOne({ where: { salaryMonth: MoreThanOrEqual(salaryProfile.amount), }, order: { salaryMonth: "ASC", }, relations: ["salaryEmployee_"], }); } if (salaryCurrentRanks) { group = salaryCurrentRanks.salaryEmployee_.group; step = salaryCurrentRanks.step; } } //console.log("group", group); //console.log("step", step); if (type == "HAFT") { step = step + 0.5; stepUp = 0.5; } else if (type == "FULL") { step = step + 1; stepUp = 1; } else if (type == "FULLHAFT") { step = step + 1.5; stepUp = 1.5; } //console.log("step+type", step); //หาขั้นสูงสุดในกลุ่มนั้น let salaryRankMax = await this.salaryRankRepository.findOne({ where: { salaryEmployee_: { isActive: true, group: group, }, }, order: { step: "DESC" }, }); //console.log("salaryRankMax.step", salaryRankMax?.step); //console.log("salaryProfile.amount", salaryProfile.amount); //console.log("salaryFormula.salaryMax", salaryFormula?.salaryMax); //เงินเดือนเกินตาราง //****หา shot ที่ +ขั้น แล้วแก้เป็นหาเงินเดือนที่ใกล้เคียงกับขั้นผังเก่าก่อนแล้วค่อย +ขั้นที่เลื่อนเข้าไป ex.เงินตันที่ 20000 ไปหาผังใหม่ได้ใกล้เคียง 20100 ยึดตัวเลขนี้ไว้แล้วค่อย +ขั้นในผังใหม่ขึ้นไป if ( salaryRankMax != null && step > salaryRankMax.step && (salaryFormula == null || (salaryFormula != null && salaryProfile.amount != null && salaryFormula.salaryMax != null && salaryFormula.salaryMax > salaryProfile.amount)) ) { //console.log("in function เกินตาราง"); group = group + 1; //เงินเดือนในกลุ่มต่อไป let salaryRankAmount = await this.salaryRankRepository.findOne({ where: { salaryMonth: salaryRankMax.salaryMonth != null && salaryRankMax.salaryMonth > 0 ? MoreThan(salaryRankMax.salaryMonth) : 0, salaryEmployee_: { isActive: true, group: group, }, }, order: { salaryMonth: "ASC" }, }); //console.log("salaryRankAmount", salaryRankAmount?.salaryMonth); // step = // (salaryRankAmount == null ? 1 : salaryRankAmount.step) + // (step - (salaryRankMax == null ? 0 : salaryRankMax.step) - 0.5); step = (salaryRankAmount == null ? 1 : salaryRankAmount.step) + stepUp; //****หาขั้นของผังใหม่แล้ว + ด้วยขั้นที่ได้เลื่อน //console.log("step in if", step); } let whereCondition: any = { step: step, salaryEmployee_: { isActive: true, group: group, }, }; let salaryRanks = await this.salaryRankRepository.findOne({ where: whereCondition, }); //console.log("salaryRanks.salaryMonth", salaryRanks?.salaryMonth); if (salaryRanks != null && salaryRanks.salaryMonth != null) { if ( salaryFormula != null && salaryFormula.salaryMax != null && salaryRanks.salaryMonth > salaryFormula.salaryMax ) { let salaryRankAmountMax = await this.salaryRankRepository.findOne({ where: { salaryMonth: salaryFormula.salaryMax, salaryEmployee_: { id: salaryFormula.salaryEmployee.id, }, }, }); salaryProfile.isNext = true; salaryProfile.amountUse = salaryFormula.salaryMax - (salaryProfile.amount == null ? 0 : salaryProfile.amount); salaryProfile.positionSalaryAmount = salaryRankAmountMax == null || salaryRankAmountMax.salaryMonth == null ? 0 : salaryRankAmountMax.salaryMonth; salaryProfile.positionSalaryDayAmount = salaryRankAmountMax == null ? 0 : salaryRankAmountMax.salaryDay; salaryProfile.groupNew = salaryFormula.salaryEmployee.group; salaryProfile.salaryLevelNew = salaryRankAmountMax == null ? 0 : salaryRankAmountMax.step;; salaryRankAmountMax == null ? 0 : salaryRankAmountMax.step; if (salaryRankAmountMax != null) { if (step - salaryRankAmountMax.step <= 0.5) { //console.log("in case 0.5 * 0.02"); //console.log("salaryRankAmountMax.salaryMont>>>" ,salaryRankAmountMax == null || salaryRankAmountMax.salaryMonth == null? 0 : salaryRankAmountMax.salaryMonth); salaryProfile.positionSalaryAmountPer = 0.02; salaryProfile.amountSpecial = salaryRankAmountMax == null || salaryRankAmountMax.salaryMonth == null ? 0 : Math.floor(salaryRankAmountMax.salaryMonth * 0.02); } else if (step - salaryRankAmountMax.step <= 1) { //console.log("in case 1 * 0.04"); salaryProfile.positionSalaryAmountPer = 0.04; salaryProfile.amountSpecial = salaryRankAmountMax == null || salaryRankAmountMax.salaryMonth == null ? 0 : Math.floor(salaryRankAmountMax.salaryMonth * 0.04); } else { //console.log("in case 1.5 * 0.06"); salaryProfile.positionSalaryAmountPer = 0.06; salaryProfile.amountSpecial = salaryRankAmountMax == null || salaryRankAmountMax.salaryMonth == null ? 0 : Math.floor(salaryRankAmountMax.salaryMonth * 0.06); } } else { salaryProfile.positionSalaryAmountPer = 0; salaryProfile.amountSpecial = 0; } //console.log("in case เงินเดือน max ตำแหน่งแต่ไม่เกินผัง"); //console.log(" salaryProfile.amountSpecial", salaryProfile.amountSpecial); //console.log("salaryRanks.salaryMonth",salaryRanks.salaryMonth); //console.log("salaryProfile.amount",(salaryProfile.amount == null ? 0 : salaryProfile.amount)); } else { //console.log("in case normal"); //console.log("salaryRanks.salaryMonth",salaryRanks.salaryMonth); //console.log("salaryProfile.amount",(salaryProfile.amount == null ? 0 : salaryProfile.amount)); //console.log("salaryRanks.salaryMonth - salaryProfile.amount",salaryRanks.salaryMonth - (salaryProfile.amount == null ? 0 : salaryProfile.amount)); salaryProfile.isNext = false; salaryProfile.amountUse = salaryRanks.salaryMonth - (salaryProfile.amount == null ? 0 : salaryProfile.amount); salaryProfile.positionSalaryAmount = salaryRanks.salaryMonth; salaryProfile.positionSalaryDayAmount = salaryRanks.salaryDay; salaryProfile.groupNew = group; salaryProfile.salaryLevelNew = step; salaryProfile.positionSalaryAmountPer = 0; salaryProfile.amountSpecial = 0; } } else { if ( salaryFormula != null && salaryFormula.salaryMax != null && salaryProfile.amount != null && salaryFormula.salaryMax <= salaryProfile.amount ) { let salaryRankAmountMax = await this.salaryRankRepository.findOne({ where: { salaryMonth: salaryFormula.salaryMax, salaryEmployee_: { id: salaryFormula.salaryEmployee.id, }, }, }); salaryProfile.isNext = true; salaryProfile.amountUse = salaryFormula.salaryMax - salaryProfile.amount; salaryProfile.positionSalaryAmount = salaryRankAmountMax == null || salaryRankAmountMax.salaryMonth == null ? 0 : salaryRankAmountMax.salaryMonth; salaryProfile.positionSalaryDayAmount = salaryRankAmountMax == null ? 0 : salaryRankAmountMax.salaryDay; salaryProfile.groupNew = salaryFormula.salaryEmployee.group; salaryProfile.salaryLevelNew = salaryRankAmountMax == null ? 0 : salaryRankAmountMax.step; salaryRankAmountMax == null ? 0 : salaryRankAmountMax.step; if (salaryRankAmountMax != null) { if (step - salaryRankAmountMax.step <= 0.5) { salaryProfile.positionSalaryAmountPer = 0.02; salaryProfile.amountSpecial = salaryRankAmountMax == null || salaryRankAmountMax.salaryMonth == null ? 0 : Math.floor(salaryRankAmountMax.salaryMonth * 0.02); } else if (step - salaryRankAmountMax.step <= 1) { salaryProfile.positionSalaryAmountPer = 0.04; salaryProfile.amountSpecial = salaryRankAmountMax == null || salaryRankAmountMax.salaryMonth == null ? 0 : Math.floor(salaryRankAmountMax.salaryMonth * 0.04); } else { salaryProfile.positionSalaryAmountPer = 0.06; salaryProfile.amountSpecial = salaryRankAmountMax == null || salaryRankAmountMax.salaryMonth == null ? 0 : Math.floor(salaryRankAmountMax.salaryMonth * 0.06); } } else { salaryProfile.positionSalaryAmountPer = 0; salaryProfile.amountSpecial = 0; } } else { salaryProfile.isNext = false; salaryProfile.amountUse = 0; salaryProfile.positionSalaryAmount = salaryProfile.amount == null ? 0 : salaryProfile.amount; salaryProfile.positionSalaryDayAmount = 0; salaryProfile.positionSalaryAmountPer = 0; salaryProfile.amountSpecial = 0; } } } else { throw "ประเภทการเลื่อนขึ้นเงินเดือนไม่ถูกต้อง"; } return salaryProfile; } /** * API แก้ไขรอบเงินเดือน * * */ @Put("change/isclose/{snapShot}/{salaryPeriodId}") async ChangeIsClose( @Request() request: RequestWithUser, @Path() snapShot: string, salaryPeriodId: string, @Body() body: { isClose: boolean; }, ) { await new permission().PermissionUpdate(request, "SYS_SALARY_ROUND"); const salaryPeriod = await this.salaryOrgRepository.find({ where: { salaryPeriodId: salaryPeriodId, snapshot: snapShot }, }); for await (const item of salaryPeriod) { item.isClose = body.isClose; await this.salaryOrgRepository.save(item); } return new HttpSuccess(); } }