This commit is contained in:
parent
5ea111a3c5
commit
6c5356ca46
2 changed files with 379 additions and 127 deletions
|
|
@ -24,11 +24,20 @@ import { In, IsNull, LessThan, MoreThan, Not } from "typeorm";
|
|||
import permission from "../interfaces/permission";
|
||||
import { setLogDataDiff } from "../interfaces/utils";
|
||||
import { normalizeDurationSumSimple } from "../utils/tenure";
|
||||
import { TenurePositionOfficer } from "../entities/TenurePositionOfficer";
|
||||
import { TenureLevelOfficer } from "../entities/TenureLevelOfficer";
|
||||
import { TenurePositionEmployee } from "../entities/TenurePositionEmployee";
|
||||
import { TenureLevelEmployee } from "../entities/TenureLevelEmployee";
|
||||
import { TenurePositionExecutiveOfficer } from "../entities/TenurePositionExecutiveOfficer";
|
||||
import {
|
||||
TenurePositionOfficer,
|
||||
CreateTenurePositionOfficer,
|
||||
} from "../entities/TenurePositionOfficer";
|
||||
import { TenureLevelOfficer, CreateTenureLevelOfficer } from "../entities/TenureLevelOfficer";
|
||||
import {
|
||||
TenurePositionEmployee,
|
||||
CreateTenurePositionEmployee,
|
||||
} from "../entities/TenurePositionEmployee";
|
||||
import { TenureLevelEmployee, CreateTenureLevelEmployee } from "../entities/TenureLevelEmployee";
|
||||
import {
|
||||
TenurePositionExecutiveOfficer,
|
||||
CreateTenurePositionExecutiveOfficer,
|
||||
} from "../entities/TenurePositionExecutiveOfficer";
|
||||
import { Command } from "../entities/Command";
|
||||
import { OrgRoot } from "../entities/OrgRoot";
|
||||
import { OrgRevision } from "../entities/OrgRevision";
|
||||
|
|
@ -46,44 +55,84 @@ export class ProfileSalaryController extends Controller {
|
|||
private profileEmployeeRepo = AppDataSource.getRepository(ProfileEmployee);
|
||||
private salaryRepo = AppDataSource.getRepository(ProfileSalary);
|
||||
private salaryHistoryRepo = AppDataSource.getRepository(ProfileSalaryHistory);
|
||||
private positionOfficerRepo = AppDataSource.getRepository(TenurePositionOfficer);
|
||||
private positionEmployeeRepo = AppDataSource.getRepository(TenurePositionEmployee);
|
||||
private levelOfficerRepo = AppDataSource.getRepository(TenureLevelOfficer);
|
||||
private levelEmployeeRepo = AppDataSource.getRepository(TenureLevelEmployee);
|
||||
private positionExecutiveOfficerRepo = AppDataSource.getRepository(
|
||||
TenurePositionExecutiveOfficer,
|
||||
);
|
||||
private commandRepository = AppDataSource.getRepository(Command);
|
||||
private orgRootRepository = AppDataSource.getRepository(OrgRoot);
|
||||
private orgRevisionRepository = AppDataSource.getRepository(OrgRevision);
|
||||
private positionRepo = AppDataSource.getRepository(Position);
|
||||
private registryRepo = AppDataSource.getRepository(Registry);
|
||||
private registryEmployeeRepo = AppDataSource.getRepository(RegistryEmployee);
|
||||
|
||||
@Get("TenurePositionOfficer")
|
||||
public async cronjobTenurePositionOfficer() {
|
||||
let data: any = [];
|
||||
await this.positionOfficerRepo.clear();
|
||||
const profile = await this.profileRepo.find();
|
||||
const CURRENT_DATE = await AppDataSource.query("SELECT CURRENT_DATE() as today");
|
||||
const baseCurrentDate = CURRENT_DATE[0].today;
|
||||
for await (const x of profile) {
|
||||
// Use leave date if available and valid, otherwise use current date
|
||||
let _currentDate = baseCurrentDate;
|
||||
if (x.isLeave && x.leaveDate) {
|
||||
_currentDate = Extension.toDateOnlyString(x.leaveDate);
|
||||
|
||||
const profiles = await this.profileRepo.find({
|
||||
select: ["id", "position", "isLeave", "leaveDate"],
|
||||
where: { position: Not(IsNull()) },
|
||||
});
|
||||
|
||||
const BATCH_SIZE = 100;
|
||||
let successCount = 0;
|
||||
let failCount = 0;
|
||||
const allData: CreateTenurePositionOfficer[] = [];
|
||||
|
||||
for (let i = 0; i < profiles.length; i += BATCH_SIZE) {
|
||||
const batch = profiles.slice(i, Math.min(i + BATCH_SIZE, profiles.length));
|
||||
const results = await Promise.allSettled(
|
||||
batch.map((profile) =>
|
||||
this.processSingleProfileForTenurePositionOfficer(profile, baseCurrentDate),
|
||||
),
|
||||
);
|
||||
|
||||
results.forEach((result) => {
|
||||
if (result.status === "fulfilled" && result.value) {
|
||||
allData.push(result.value);
|
||||
successCount++;
|
||||
} else {
|
||||
failCount++;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
await AppDataSource.transaction(async (transactionalEntityManager) => {
|
||||
await transactionalEntityManager.delete(TenurePositionOfficer, {});
|
||||
if (allData.length > 0) {
|
||||
const entities = allData.map((data) => {
|
||||
const entity = new TenurePositionOfficer();
|
||||
Object.assign(entity, data);
|
||||
return entity;
|
||||
});
|
||||
await transactionalEntityManager.save(TenurePositionOfficer, entities);
|
||||
}
|
||||
});
|
||||
|
||||
return new HttpSuccess({
|
||||
message: `อัปเดต tenure position officer สำเร็จ`,
|
||||
total: profiles.length,
|
||||
success: successCount,
|
||||
failed: failCount,
|
||||
});
|
||||
}
|
||||
|
||||
private async processSingleProfileForTenurePositionOfficer(
|
||||
profile: Pick<Profile, "id" | "position" | "isLeave" | "leaveDate">,
|
||||
baseCurrentDate: string,
|
||||
): Promise<CreateTenurePositionOfficer | null> {
|
||||
try {
|
||||
let _currentDate = baseCurrentDate;
|
||||
if (profile.isLeave && profile.leaveDate) {
|
||||
_currentDate = Extension.toDateOnlyString(profile.leaveDate);
|
||||
}
|
||||
|
||||
const position = await AppDataSource.query("CALL GetProfileSalaryPosition(?, ?)", [
|
||||
x.id,
|
||||
profile.id,
|
||||
_currentDate,
|
||||
]);
|
||||
const _position = position.length > 0 ? position[0] : [];
|
||||
// Filter for current position and use SP's calculated values (calendar arithmetic)
|
||||
|
||||
const mapPosition =
|
||||
_position.length > 1
|
||||
? _position.slice(1).map((curr: any, index: number) => ({
|
||||
positionName: _position[index]?.positionName,
|
||||
// Use stored procedure's calculated values (calendar arithmetic)
|
||||
year:
|
||||
curr.Years !== null && curr.Years !== undefined
|
||||
? Math.floor(Number(curr.Years))
|
||||
|
|
@ -96,51 +145,102 @@ export class ProfileSalaryController extends Controller {
|
|||
curr.Days !== null && curr.Days !== undefined ? Math.floor(Number(curr.Days)) : 0,
|
||||
}))
|
||||
: [];
|
||||
const currentTenure = mapPosition.find((curr: any) => curr.positionName == x.position);
|
||||
|
||||
const currentTenure = mapPosition.find((curr: any) => curr.positionName === profile.position);
|
||||
|
||||
if (currentTenure) {
|
||||
const normalized = normalizeDurationSumSimple(
|
||||
currentTenure.year,
|
||||
currentTenure.month,
|
||||
currentTenure.day,
|
||||
);
|
||||
const mapData: any = {
|
||||
profileId: x.id,
|
||||
return {
|
||||
profileId: profile.id,
|
||||
positionName: currentTenure.positionName,
|
||||
days_diff: null,
|
||||
Years: normalized.years,
|
||||
Months: normalized.months,
|
||||
Days: normalized.days,
|
||||
};
|
||||
data.push(mapData);
|
||||
}
|
||||
return null;
|
||||
} catch (error) {
|
||||
return null;
|
||||
}
|
||||
await this.positionOfficerRepo.save(data);
|
||||
|
||||
return new HttpSuccess();
|
||||
}
|
||||
@Get("TenurePositionEmployee")
|
||||
public async cronjobTenurePositionEmployee() {
|
||||
let data: any = [];
|
||||
await this.positionEmployeeRepo.clear();
|
||||
const CURRENT_DATE = await AppDataSource.query("SELECT CURRENT_DATE() as today");
|
||||
const baseCurrentDate = CURRENT_DATE[0].today;
|
||||
const profile = await this.profileEmployeeRepo.find();
|
||||
for await (const x of profile) {
|
||||
// Use leave date if available and valid, otherwise use current date
|
||||
let _currentDate = baseCurrentDate;
|
||||
if (x?.isLeave && x.leaveDate) {
|
||||
_currentDate = Extension.toDateOnlyString(x.leaveDate);
|
||||
|
||||
const profiles = await this.profileEmployeeRepo.find({
|
||||
select: ["id", "position", "isLeave", "leaveDate"],
|
||||
where: { position: Not(IsNull()) },
|
||||
});
|
||||
|
||||
const BATCH_SIZE = 100;
|
||||
let successCount = 0;
|
||||
let failCount = 0;
|
||||
const allData: CreateTenurePositionEmployee[] = [];
|
||||
|
||||
for (let i = 0; i < profiles.length; i += BATCH_SIZE) {
|
||||
const batch = profiles.slice(i, Math.min(i + BATCH_SIZE, profiles.length));
|
||||
const results = await Promise.allSettled(
|
||||
batch.map((profile) =>
|
||||
this.processSingleProfileForTenurePositionEmployee(profile, baseCurrentDate),
|
||||
),
|
||||
);
|
||||
|
||||
results.forEach((result) => {
|
||||
if (result.status === "fulfilled" && result.value) {
|
||||
allData.push(result.value);
|
||||
successCount++;
|
||||
} else {
|
||||
failCount++;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
await AppDataSource.transaction(async (transactionalEntityManager) => {
|
||||
await transactionalEntityManager.delete(TenurePositionEmployee, {});
|
||||
if (allData.length > 0) {
|
||||
const entities = allData.map((data) => {
|
||||
const entity = new TenurePositionEmployee();
|
||||
Object.assign(entity, data);
|
||||
return entity;
|
||||
});
|
||||
await transactionalEntityManager.save(TenurePositionEmployee, entities);
|
||||
}
|
||||
});
|
||||
|
||||
return new HttpSuccess({
|
||||
message: `อัปเดต tenure position employee สำเร็จ`,
|
||||
total: profiles.length,
|
||||
success: successCount,
|
||||
failed: failCount,
|
||||
});
|
||||
}
|
||||
|
||||
private async processSingleProfileForTenurePositionEmployee(
|
||||
profile: Pick<ProfileEmployee, "id" | "position" | "isLeave" | "leaveDate">,
|
||||
baseCurrentDate: string,
|
||||
): Promise<CreateTenurePositionEmployee | null> {
|
||||
try {
|
||||
let _currentDate = baseCurrentDate;
|
||||
if (profile.isLeave && profile.leaveDate) {
|
||||
_currentDate = Extension.toDateOnlyString(profile.leaveDate);
|
||||
}
|
||||
|
||||
const position = await AppDataSource.query("CALL GetProfileEmployeeSalaryPosition(?, ?)", [
|
||||
x.id,
|
||||
profile.id,
|
||||
_currentDate,
|
||||
]);
|
||||
const _position = position.length > 0 ? position[0] : [];
|
||||
// Filter for current position and use SP's calculated values (calendar arithmetic)
|
||||
|
||||
const mapPosition =
|
||||
_position.length > 1
|
||||
? _position.slice(1).map((curr: any, index: number) => ({
|
||||
positionName: _position[index]?.positionName,
|
||||
// Use stored procedure's calculated values (calendar arithmetic)
|
||||
year:
|
||||
curr.Years !== null && curr.Years !== undefined
|
||||
? Math.floor(Number(curr.Years))
|
||||
|
|
@ -153,45 +253,105 @@ export class ProfileSalaryController extends Controller {
|
|||
curr.Days !== null && curr.Days !== undefined ? Math.floor(Number(curr.Days)) : 0,
|
||||
}))
|
||||
: [];
|
||||
const currentTenure = mapPosition.find((curr: any) => curr.positionName == x.position);
|
||||
|
||||
const currentTenure = mapPosition.find((curr: any) => curr.positionName === profile.position);
|
||||
|
||||
if (currentTenure) {
|
||||
const normalized = normalizeDurationSumSimple(
|
||||
currentTenure.year,
|
||||
currentTenure.month,
|
||||
currentTenure.day,
|
||||
);
|
||||
const mapData: any = {
|
||||
profileEmployeeId: x.id,
|
||||
return {
|
||||
profileEmployeeId: profile.id,
|
||||
positionName: currentTenure.positionName,
|
||||
days_diff: null,
|
||||
Years: normalized.years,
|
||||
Months: normalized.months,
|
||||
Days: normalized.days,
|
||||
};
|
||||
data.push(mapData);
|
||||
}
|
||||
return null;
|
||||
} catch (error) {
|
||||
return null;
|
||||
}
|
||||
await this.positionEmployeeRepo.save(data);
|
||||
|
||||
return new HttpSuccess();
|
||||
}
|
||||
@Get("TenureLevelOfficer")
|
||||
public async cronjobTenureLevelOfficer() {
|
||||
let data: any = [];
|
||||
await this.levelOfficerRepo.clear();
|
||||
const profile = await this.profileRepo.find({ relations: ["posLevel", "posType"] });
|
||||
const CURRENT_DATE = await AppDataSource.query("SELECT CURRENT_DATE() as today");
|
||||
const baseCurrentDate = CURRENT_DATE[0].today;
|
||||
for await (const x of profile) {
|
||||
// Use leave date if available and valid, otherwise use current date
|
||||
let _currentDate = baseCurrentDate;
|
||||
if (x?.isLeave && x.leaveDate) {
|
||||
_currentDate = Extension.toDateOnlyString(x.leaveDate);
|
||||
|
||||
const profiles = await this.profileRepo.find({
|
||||
relations: ["posLevel", "posType"],
|
||||
select: ["id", "isLeave", "leaveDate", "posLevel", "posType"],
|
||||
where: {
|
||||
posLevel: Not(IsNull()),
|
||||
posType: Not(IsNull()),
|
||||
},
|
||||
});
|
||||
|
||||
const BATCH_SIZE = 100;
|
||||
let successCount = 0;
|
||||
let failCount = 0;
|
||||
const allData: CreateTenureLevelOfficer[] = [];
|
||||
|
||||
for (let i = 0; i < profiles.length; i += BATCH_SIZE) {
|
||||
const batch = profiles.slice(i, Math.min(i + BATCH_SIZE, profiles.length));
|
||||
const results = await Promise.allSettled(
|
||||
batch.map((profile) =>
|
||||
this.processSingleProfileForTenureLevelOfficer(profile, baseCurrentDate),
|
||||
),
|
||||
);
|
||||
|
||||
results.forEach((result) => {
|
||||
if (result.status === "fulfilled" && result.value) {
|
||||
allData.push(result.value);
|
||||
successCount++;
|
||||
} else {
|
||||
failCount++;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
await AppDataSource.transaction(async (transactionalEntityManager) => {
|
||||
await transactionalEntityManager.delete(TenureLevelOfficer, {});
|
||||
if (allData.length > 0) {
|
||||
const entities = allData.map((data) => {
|
||||
const entity = new TenureLevelOfficer();
|
||||
Object.assign(entity, data);
|
||||
return entity;
|
||||
});
|
||||
await transactionalEntityManager.save(TenureLevelOfficer, entities);
|
||||
}
|
||||
});
|
||||
|
||||
return new HttpSuccess({
|
||||
message: `อัปเดต tenure level officer สำเร็จ`,
|
||||
total: profiles.length,
|
||||
success: successCount,
|
||||
failed: failCount,
|
||||
});
|
||||
}
|
||||
|
||||
private async processSingleProfileForTenureLevelOfficer(
|
||||
profile: Pick<Profile, "id" | "isLeave" | "leaveDate" | "posLevel" | "posType"> & {
|
||||
posLevel?: { posLevelName?: string } | null;
|
||||
posType?: { posTypeName?: string } | null;
|
||||
},
|
||||
baseCurrentDate: string,
|
||||
): Promise<CreateTenureLevelOfficer | null> {
|
||||
try {
|
||||
let _currentDate = baseCurrentDate;
|
||||
if (profile.isLeave && profile.leaveDate) {
|
||||
_currentDate = Extension.toDateOnlyString(profile.leaveDate);
|
||||
}
|
||||
|
||||
const positionLevel = await AppDataSource.query("CALL GetProfileSalaryLevel(?, ?)", [
|
||||
x.id,
|
||||
profile.id,
|
||||
_currentDate,
|
||||
]);
|
||||
const _positionLevel = positionLevel.length > 0 ? positionLevel[0] : [];
|
||||
|
||||
const mapPositionLevel =
|
||||
_positionLevel.length > 1
|
||||
? _positionLevel.slice(1).map((curr: any, index: number) => ({
|
||||
|
|
@ -211,11 +371,12 @@ export class ProfileSalaryController extends Controller {
|
|||
curr.Days !== null && curr.Days !== undefined ? Math.floor(Number(curr.Days)) : 0,
|
||||
}))
|
||||
: [];
|
||||
|
||||
const calDayDiff = mapPositionLevel
|
||||
.filter(
|
||||
(curr: any) =>
|
||||
curr.positionLevel == (x.posLevel?.posLevelName ?? null) &&
|
||||
curr.positionType == (x.posType?.posTypeName ?? null),
|
||||
curr.positionLevel === (profile.posLevel?.posLevelName ?? null) &&
|
||||
curr.positionType === (profile.posType?.posTypeName ?? null),
|
||||
)
|
||||
.reduce(
|
||||
(acc: any, curr: any) => {
|
||||
|
|
@ -238,45 +399,103 @@ export class ProfileSalaryController extends Controller {
|
|||
day: 0,
|
||||
},
|
||||
);
|
||||
|
||||
const normalized = normalizeDurationSumSimple(
|
||||
calDayDiff.year,
|
||||
calDayDiff.month,
|
||||
calDayDiff.day,
|
||||
);
|
||||
const mapData: any = {
|
||||
profileId: x.id,
|
||||
|
||||
return {
|
||||
profileId: profile.id,
|
||||
positionType: calDayDiff.positionType,
|
||||
positionLevel: calDayDiff.positionLevel,
|
||||
positionCee: calDayDiff.positionCee,
|
||||
days_diff: calDayDiff.days_diff,
|
||||
Years: x.posLevel == null ? 0 : normalized.years,
|
||||
Months: x.posLevel == null ? 0 : normalized.months,
|
||||
Days: x.posLevel == null ? 0 : normalized.days,
|
||||
Years: profile.posLevel == null ? 0 : normalized.years,
|
||||
Months: profile.posLevel == null ? 0 : normalized.months,
|
||||
Days: profile.posLevel == null ? 0 : normalized.days,
|
||||
};
|
||||
data.push(mapData);
|
||||
} catch (error) {
|
||||
return null;
|
||||
}
|
||||
await this.levelOfficerRepo.save(data);
|
||||
|
||||
return new HttpSuccess();
|
||||
}
|
||||
@Get("TenureLevelEmployee")
|
||||
public async cronjobTenureLevelEmployee() {
|
||||
let data: any = [];
|
||||
await this.levelEmployeeRepo.clear();
|
||||
const profile = await this.profileEmployeeRepo.find({ relations: ["posLevel", "posType"] });
|
||||
const CURRENT_DATE = await AppDataSource.query("SELECT CURRENT_DATE() as today");
|
||||
const baseCurrentDate = CURRENT_DATE[0].today;
|
||||
for await (const x of profile) {
|
||||
// Use leave date if available and valid, otherwise use current date
|
||||
let _currentDate = baseCurrentDate;
|
||||
if (x?.isLeave && x.leaveDate) {
|
||||
_currentDate = Extension.toDateOnlyString(x.leaveDate);
|
||||
|
||||
const profiles = await this.profileEmployeeRepo.find({
|
||||
relations: ["posLevel", "posType"],
|
||||
select: ["id", "isLeave", "leaveDate", "posLevel", "posType"],
|
||||
where: {
|
||||
posLevel: Not(IsNull()),
|
||||
posType: Not(IsNull()),
|
||||
},
|
||||
});
|
||||
|
||||
const BATCH_SIZE = 100;
|
||||
let successCount = 0;
|
||||
let failCount = 0;
|
||||
const allData: CreateTenureLevelEmployee[] = [];
|
||||
|
||||
for (let i = 0; i < profiles.length; i += BATCH_SIZE) {
|
||||
const batch = profiles.slice(i, Math.min(i + BATCH_SIZE, profiles.length));
|
||||
const results = await Promise.allSettled(
|
||||
batch.map((profile) =>
|
||||
this.processSingleProfileForTenureLevelEmployee(profile, baseCurrentDate),
|
||||
),
|
||||
);
|
||||
|
||||
results.forEach((result) => {
|
||||
if (result.status === "fulfilled" && result.value) {
|
||||
allData.push(result.value);
|
||||
successCount++;
|
||||
} else {
|
||||
failCount++;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
await AppDataSource.transaction(async (transactionalEntityManager) => {
|
||||
await transactionalEntityManager.delete(TenureLevelEmployee, {});
|
||||
if (allData.length > 0) {
|
||||
const entities = allData.map((data) => {
|
||||
const entity = new TenureLevelEmployee();
|
||||
Object.assign(entity, data);
|
||||
return entity;
|
||||
});
|
||||
await transactionalEntityManager.save(TenureLevelEmployee, entities);
|
||||
}
|
||||
});
|
||||
|
||||
return new HttpSuccess({
|
||||
message: `อัปเดต tenure level employee สำเร็จ`,
|
||||
total: profiles.length,
|
||||
success: successCount,
|
||||
failed: failCount,
|
||||
});
|
||||
}
|
||||
|
||||
private async processSingleProfileForTenureLevelEmployee(
|
||||
profile: Pick<ProfileEmployee, "id" | "isLeave" | "leaveDate" | "posLevel" | "posType"> & {
|
||||
posLevel?: { posLevelName?: string } | null;
|
||||
posType?: { posTypeName?: string } | null;
|
||||
},
|
||||
baseCurrentDate: string,
|
||||
): Promise<CreateTenureLevelEmployee | null> {
|
||||
try {
|
||||
let _currentDate = baseCurrentDate;
|
||||
if (profile.isLeave && profile.leaveDate) {
|
||||
_currentDate = Extension.toDateOnlyString(profile.leaveDate);
|
||||
}
|
||||
|
||||
const positionLevel = await AppDataSource.query("CALL GetProfileEmployeeSalaryLevel(?, ?)", [
|
||||
x.id,
|
||||
profile.id,
|
||||
_currentDate,
|
||||
]);
|
||||
const _positionLevel = positionLevel.length > 0 ? positionLevel[0] : [];
|
||||
|
||||
const mapPositionLevel =
|
||||
_positionLevel.length > 1
|
||||
? _positionLevel.slice(1).map((curr: any, index: number) => ({
|
||||
|
|
@ -296,11 +515,12 @@ export class ProfileSalaryController extends Controller {
|
|||
curr.Days !== null && curr.Days !== undefined ? Math.floor(Number(curr.Days)) : 0,
|
||||
}))
|
||||
: [];
|
||||
|
||||
const calDayDiff = mapPositionLevel
|
||||
.filter(
|
||||
(curr: any) =>
|
||||
curr.positionLevel == (x.posLevel?.posLevelName ?? null) &&
|
||||
curr.positionType == (x.posType?.posTypeName ?? null),
|
||||
curr.positionLevel === (profile.posLevel?.posLevelName ?? null) &&
|
||||
curr.positionType === (profile.posType?.posTypeName ?? null),
|
||||
)
|
||||
.reduce(
|
||||
(acc: any, curr: any) => {
|
||||
|
|
@ -323,66 +543,97 @@ export class ProfileSalaryController extends Controller {
|
|||
day: 0,
|
||||
},
|
||||
);
|
||||
|
||||
const normalized = normalizeDurationSumSimple(
|
||||
calDayDiff.year,
|
||||
calDayDiff.month,
|
||||
calDayDiff.day,
|
||||
);
|
||||
const mapData: any = {
|
||||
profileEmployeeId: x.id,
|
||||
|
||||
return {
|
||||
profileEmployeeId: profile.id,
|
||||
positionType: calDayDiff.positionType,
|
||||
positionLevel: calDayDiff.positionLevel,
|
||||
positionCee: calDayDiff.positionCee,
|
||||
days_diff: calDayDiff.days_diff,
|
||||
Years: x.posLevel == null ? 0 : normalized.years,
|
||||
Months: x.posLevel == null ? 0 : normalized.months,
|
||||
Days: x.posLevel == null ? 0 : normalized.days,
|
||||
Years: profile.posLevel == null ? 0 : normalized.years,
|
||||
Months: profile.posLevel == null ? 0 : normalized.months,
|
||||
Days: profile.posLevel == null ? 0 : normalized.days,
|
||||
};
|
||||
data.push(mapData);
|
||||
} catch (error) {
|
||||
return null;
|
||||
}
|
||||
await this.levelEmployeeRepo.save(data);
|
||||
|
||||
return new HttpSuccess();
|
||||
}
|
||||
|
||||
@Get("TenurePositionExecutiveOfficer")
|
||||
public async cronjobTenureExecutivePositionOfficer() {
|
||||
let data: any = [];
|
||||
await this.positionExecutiveOfficerRepo.clear();
|
||||
const profile = await this.profileRepo.find();
|
||||
const orgRevision = await this.orgRevisionRepository.findOne({
|
||||
select: ["id"],
|
||||
where: {
|
||||
orgRevisionIsDraft: false,
|
||||
orgRevisionIsCurrent: true,
|
||||
},
|
||||
});
|
||||
const CURRENT_DATE = await AppDataSource.query("SELECT CURRENT_DATE() as today");
|
||||
const baseCurrentDate = CURRENT_DATE[0].today;
|
||||
for await (const x of profile) {
|
||||
// Use leave date if available and valid, otherwise use current date
|
||||
let _currentDate = baseCurrentDate;
|
||||
if (x?.isLeave && x.leaveDate) {
|
||||
_currentDate = Extension.toDateOnlyString(x.leaveDate);
|
||||
}
|
||||
const position = await this.positionRepo.findOne({
|
||||
where: {
|
||||
positionIsSelected: true,
|
||||
posMaster: {
|
||||
orgRevisionId: orgRevision?.id,
|
||||
current_holderId: x.id,
|
||||
},
|
||||
},
|
||||
order: { createdAt: "DESC" },
|
||||
relations: {
|
||||
posExecutive: true,
|
||||
},
|
||||
|
||||
const profiles = await this.profileRepo.find({
|
||||
select: ["id", "posExecutive", "isLeave", "leaveDate"],
|
||||
where: { posExecutive: Not(IsNull()) },
|
||||
});
|
||||
|
||||
const BATCH_SIZE = 100;
|
||||
let successCount = 0;
|
||||
let failCount = 0;
|
||||
const allData: CreateTenurePositionExecutiveOfficer[] = [];
|
||||
|
||||
for (let i = 0; i < profiles.length; i += BATCH_SIZE) {
|
||||
const batch = profiles.slice(i, Math.min(i + BATCH_SIZE, profiles.length));
|
||||
const results = await Promise.allSettled(
|
||||
batch.map((profile) =>
|
||||
this.processSingleProfileForTenureExecutivePositionOfficer(profile, baseCurrentDate),
|
||||
),
|
||||
);
|
||||
|
||||
results.forEach((result) => {
|
||||
if (result.status === "fulfilled" && result.value) {
|
||||
allData.push(result.value);
|
||||
successCount++;
|
||||
} else {
|
||||
failCount++;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
await AppDataSource.transaction(async (transactionalEntityManager) => {
|
||||
await transactionalEntityManager.delete(TenurePositionExecutiveOfficer, {});
|
||||
if (allData.length > 0) {
|
||||
const entities = allData.map((data) => {
|
||||
const entity = new TenurePositionExecutiveOfficer();
|
||||
Object.assign(entity, data);
|
||||
return entity;
|
||||
});
|
||||
await transactionalEntityManager.save(TenurePositionExecutiveOfficer, entities);
|
||||
}
|
||||
});
|
||||
|
||||
return new HttpSuccess({
|
||||
message: `อัปเดต tenure executive position officer สำเร็จ`,
|
||||
total: profiles.length,
|
||||
success: successCount,
|
||||
failed: failCount,
|
||||
});
|
||||
}
|
||||
|
||||
private async processSingleProfileForTenureExecutivePositionOfficer(
|
||||
profile: Pick<Profile, "id" | "isLeave" | "leaveDate" | "posExecutive">,
|
||||
baseCurrentDate: string,
|
||||
): Promise<CreateTenurePositionExecutiveOfficer | null> {
|
||||
try {
|
||||
let _currentDate = baseCurrentDate;
|
||||
if (profile.isLeave && profile.leaveDate) {
|
||||
_currentDate = Extension.toDateOnlyString(profile.leaveDate);
|
||||
}
|
||||
|
||||
const positionExecutive = await AppDataSource.query("CALL GetProfileSalaryExecutive(?, ?)", [
|
||||
x.id,
|
||||
profile.id,
|
||||
_currentDate,
|
||||
]);
|
||||
const _position = positionExecutive.length > 0 ? positionExecutive[0] : [];
|
||||
|
||||
const mapPosition =
|
||||
_position.length > 1
|
||||
? _position.slice(1).map((curr: any, index: number) => ({
|
||||
|
|
@ -400,9 +651,9 @@ export class ProfileSalaryController extends Controller {
|
|||
curr.Days !== null && curr.Days !== undefined ? Math.floor(Number(curr.Days)) : 0,
|
||||
}))
|
||||
: [];
|
||||
const _posExecutiveName = position?.posExecutive?.posExecutiveName;
|
||||
|
||||
const calDayDiff = mapPosition
|
||||
.filter((curr: any) => _posExecutiveName && curr.positionExecutive == _posExecutiveName)
|
||||
.filter((curr: any) => curr.positionExecutive === profile.posExecutive)
|
||||
.reduce(
|
||||
(acc: any, curr: any) => {
|
||||
acc.days_diff += Number(curr.days_diff) || 0;
|
||||
|
|
@ -414,23 +665,24 @@ export class ProfileSalaryController extends Controller {
|
|||
},
|
||||
{ days_diff: 0, positionExecutive: null, year: 0, month: 0, day: 0 },
|
||||
);
|
||||
|
||||
const normalized = normalizeDurationSumSimple(
|
||||
calDayDiff.year,
|
||||
calDayDiff.month,
|
||||
calDayDiff.day,
|
||||
);
|
||||
const mapData: any = {
|
||||
profileId: x.id,
|
||||
|
||||
return {
|
||||
profileId: profile.id,
|
||||
positionExecutiveName: calDayDiff.positionExecutive,
|
||||
days_diff: calDayDiff.days_diff,
|
||||
Years: normalized.years,
|
||||
Months: normalized.months,
|
||||
Days: normalized.days,
|
||||
};
|
||||
data.push(mapData);
|
||||
} catch (error) {
|
||||
return null;
|
||||
}
|
||||
await this.positionExecutiveOfficerRepo.save(data);
|
||||
return new HttpSuccess();
|
||||
}
|
||||
|
||||
@Get("Registry")
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ export class TenureLevelEmployee extends EntityBase {
|
|||
positionLevel: string;
|
||||
}
|
||||
|
||||
export class CreateTenureLevelOfficer {
|
||||
export class CreateTenureLevelEmployee {
|
||||
profileEmployeeId: string;
|
||||
positionCee: string | null;
|
||||
days_diff: number | null;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue