migrate add column isDeleted + API ลบข้อมูลฝึกอบรม/ดูงาน + การพัฒนารายบุคคล idp + รักษาการ Task #2276, #2279, #2278
All checks were successful
Build & Deploy on Dev / build (push) Successful in 50s

This commit is contained in:
harid 2026-02-03 17:44:30 +07:00
parent bb18fed9ae
commit 30bf5ad9e3
12 changed files with 317 additions and 9 deletions

View file

@ -392,6 +392,7 @@ export class CommandController extends Controller {
if (!commandType) {
throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบประเภทคำสั่งนี้ในระบบ");
}
const now = new Date();
command.detailHeader = commandType.detailHeader;
command.detailBody = commandType.detailBody;
command.detailFooter = commandType.detailFooter;
@ -401,11 +402,85 @@ export class CommandController extends Controller {
command.issue = commandType.name;
command.createdUserId = request.user.sub;
command.createdFullName = request.user.name;
command.createdAt = new Date();
command.createdAt = now;
command.lastUpdateUserId = request.user.sub;
command.lastUpdateFullName = request.user.name;
command.lastUpdatedAt = new Date();
command.lastUpdatedAt = now;
await this.commandRepository.save(command);
// insert commandOperator
if (request.user.sub) {
const profile = await this.profileRepository.findOne({
where: { keycloak: request.user.sub },
relations: {
posLevel: true,
posType: true,
current_holders: {
orgRevision: true,
orgRoot: true,
orgChild1: true,
orgChild2: true,
orgChild3: true,
orgChild4: true,
},
},
});
if (profile) {
const currentHolder = profile!.current_holders?.find(
x =>
x.orgRevision?.orgRevisionIsDraft === false &&
x.orgRevision?.orgRevisionIsCurrent === true,
);
const posNo =
currentHolder != null && currentHolder.orgChild4 != null
? `${currentHolder.orgChild4.orgChild4ShortName} ${currentHolder.posMasterNo}`
: currentHolder != null && currentHolder.orgChild3 != null
? `${currentHolder.orgChild3.orgChild3ShortName} ${currentHolder.posMasterNo}`
: currentHolder != null && currentHolder.orgChild2 != null
? `${currentHolder.orgChild2.orgChild2ShortName} ${currentHolder.posMasterNo}`
: currentHolder != null && currentHolder.orgChild1 != null
? `${currentHolder.orgChild1.orgChild1ShortName} ${currentHolder.posMasterNo}`
: currentHolder != null && currentHolder?.orgRoot != null
? `${currentHolder.orgRoot.orgRootShortName} ${currentHolder.posMasterNo}`
: null;
const position = await this.positionRepository.findOne({
where: {
positionIsSelected: true,
posMaster: {
orgRevisionId: currentHolder?.orgRevisionId,
current_holderId: profile!.id,
},
},
order: { createdAt: "DESC" },
relations: { posExecutive: true },
});
const operator = Object.assign(
new CommandOperator(),
{
profileId: profile?.id,
prefix: profile?.prefix,
firstName: profile?.firstName,
lastName: profile?.lastName,
posNo: posNo,
posType: profile?.posType?.posTypeName ?? null,
posLevel: profile?.posLevel?.posLevelName ?? null,
position: position?.positionName ?? null,
positionExecutive: position?.posExecutive?.posExecutiveName ?? null,
roleName: "เจ้าหน้าที่ดำเนินการ",
orderNo: 1,
commandId: command.id,
createdUserId: request.user.sub,
createdFullName: request.user.name,
createdAt: now,
lastUpdateUserId: request.user.sub,
lastUpdateFullName: request.user.name,
lastUpdatedAt: now,
}
);
await this.commandOperatorRepository.save(operator);
}
}
return new HttpSuccess(command.id);
}
@ -2538,7 +2613,7 @@ export class CommandController extends Controller {
roleName: "เจ้าหน้าที่ดำเนินการ",
orderNo: 1,
commandId: command.id,
createUserId: request.user.sub,
createdUserId: request.user.sub,
createdFullName: request.user.name,
createdAt: now,
lastUpdateUserId: request.user.sub,

View file

@ -40,7 +40,7 @@ export class ProfileActpositionController extends Controller {
throw new HttpError(HttpStatus.BAD_REQUEST, "ไม่พบ profile ดังกล่าว");
}
const getProfileActpositionId = await this.profileActpositionRepo.find({
where: { profileId: profile.id },
where: { profileId: profile.id, isDeleted: false },
order: { createdAt: "ASC" },
});
if (!getProfileActpositionId) {
@ -58,7 +58,7 @@ export class ProfileActpositionController extends Controller {
if (_workflow == false)
await new permission().PermissionOrgUserGet(req, "SYS_REGISTRY_OFFICER", profileId);
const getProfileActpositionId = await this.profileActpositionRepo.find({
where: { profileId: profileId },
where: { profileId: profileId, isDeleted: false },
order: { createdAt: "ASC" },
});
if (!getProfileActpositionId) {
@ -201,6 +201,44 @@ export class ProfileActpositionController extends Controller {
return new HttpSuccess();
}
/**
* API
* @summary API
* @param actpositionId
*/
@Patch("update-delete/{actpositionId}")
public async updateIsDeletedTraining(
@Request() req: RequestWithUser,
@Path() actpositionId: string,
) {
const record = await this.profileActpositionRepo.findOneBy({ id: actpositionId });
if (!record) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูล");
if (record.isDeleted === true) {
return new HttpSuccess();
}
await new permission().PermissionOrgUserDelete(req, "SYS_REGISTRY_OFFICER", record.profileId);
const before = structuredClone(record);
const history = new ProfileActpositionHistory();
const now = new Date();
record.isDeleted = true;
record.lastUpdateUserId = req.user.sub;
record.lastUpdateFullName = req.user.name;
record.lastUpdatedAt = now;
Object.assign(history, { ...record, id: undefined });
history.createdUserId = req.user.sub;
history.createdFullName = req.user.name;
history.createdAt = now;
await Promise.all([
this.profileActpositionRepo.save(record, { data: req }),
setLogDataDiff(req, { before, after: record }),
this.profileActpositionHistoryRepo.save(history, { data: req }),
]);
return new HttpSuccess();
}
@Delete("{actpositionId}")
public async deleteProfileActposition(
@Path() actpositionId: string,

View file

@ -28,6 +28,7 @@ import permission from "../interfaces/permission";
import { DevelopmentProject } from "../entities/DevelopmentProject";
import { In, Brackets } from "typeorm";
import { DevelopmentRequest } from "../entities/DevelopmentRequest";
import { setLogDataDiff } from "../interfaces/utils";
@Route("api/v1/org/profile/development")
@Tags("ProfileDevelopment")
@Security("bearerAuth")
@ -45,7 +46,7 @@ export class ProfileDevelopmentController extends Controller {
throw new HttpError(HttpStatus.BAD_REQUEST, "ไม่พบ profile ดังกล่าว");
}
const lists = await this.developmentRepository.find({
where: { profileId: profile.id },
where: { profileId: profile.id, isDeleted: false },
order: { createdAt: "ASC" },
});
return new HttpSuccess(lists);
@ -66,7 +67,7 @@ export class ProfileDevelopmentController extends Controller {
await new permission().PermissionOrgUserGet(req, "SYS_REGISTRY_OFFICER", profileId);
let query = await AppDataSource.getRepository(ProfileDevelopment)
.createQueryBuilder("profileDevelopment")
.where({ profileId: profileId })
.where({ profileId: profileId, isDeleted: false })
.andWhere(
new Brackets((qb) => {
qb.where(
@ -329,6 +330,44 @@ export class ProfileDevelopmentController extends Controller {
return new HttpSuccess();
}
/**
* API IDP
* @summary API IDP
* @param developmentId IDP
*/
@Patch("update-delete/{developmentId}")
public async updateIsDeletedTraining(
@Request() req: RequestWithUser,
@Path() developmentId: string,
) {
const record = await this.developmentRepository.findOneBy({ id: developmentId });
if (!record) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูล");
if (record.isDeleted === true) {
return new HttpSuccess();
}
await new permission().PermissionOrgUserDelete(req, "SYS_REGISTRY_OFFICER", record.profileId);
const before = structuredClone(record);
const history = new ProfileDevelopmentHistory();
const now = new Date();
record.isDeleted = true;
record.lastUpdateUserId = req.user.sub;
record.lastUpdateFullName = req.user.name;
record.lastUpdatedAt = now;
Object.assign(history, { ...record, id: undefined });
history.createdUserId = req.user.sub;
history.createdFullName = req.user.name;
history.createdAt = now;
await Promise.all([
this.developmentRepository.save(record, { data: req }),
setLogDataDiff(req, { before, after: record }),
this.developmentHistoryRepository.save(history, { data: req }),
]);
return new HttpSuccess();
}
@Delete("{developmentId}")
public async deleteDevelopment(@Path() developmentId: string, @Request() req: RequestWithUser) {
const _record = await this.developmentRepository.findOneBy({ id: developmentId });

View file

@ -25,6 +25,9 @@ import { RequestWithUser } from "../middlewares/user";
import { Profile } from "../entities/Profile";
import permission from "../interfaces/permission";
import { setLogDataDiff } from "../interfaces/utils";
import { ProfileDevelopment } from "../entities/ProfileDevelopment";
import { ProfileDevelopmentHistory } from "../entities/ProfileDevelopmentHistory";
import { In } from "typeorm";
@Route("api/v1/org/profile/training")
@Tags("ProfileTraining")
@Security("bearerAuth")
@ -32,6 +35,8 @@ export class ProfileTrainingController extends Controller {
private profileRepo = AppDataSource.getRepository(Profile);
private trainingRepo = AppDataSource.getRepository(ProfileTraining);
private trainingHistoryRepo = AppDataSource.getRepository(ProfileTrainingHistory);
private developmentRepo = AppDataSource.getRepository(ProfileDevelopment);
private developmentHistoryRepo = AppDataSource.getRepository(ProfileDevelopmentHistory);
@Get("user")
public async getTrainingUser(@Request() request: { user: Record<string, any> }) {
@ -40,7 +45,7 @@ export class ProfileTrainingController extends Controller {
throw new HttpError(HttpStatus.BAD_REQUEST, "ไม่พบ profile ดังกล่าว");
}
const record = await this.trainingRepo.find({
where: { profileId: profile.id },
where: { profileId: profile.id, isDeleted: false },
order: { createdAt: "ASC" },
});
return new HttpSuccess(record);
@ -52,7 +57,7 @@ export class ProfileTrainingController extends Controller {
if (_workflow == false)
await new permission().PermissionOrgUserGet(req, "SYS_REGISTRY_OFFICER", profileId);
const record = await this.trainingRepo.find({
where: { profileId },
where: { profileId: profileId, isDeleted: false },
order: { createdAt: "ASC" },
});
return new HttpSuccess(record);
@ -178,4 +183,77 @@ export class ProfileTrainingController extends Controller {
return new HttpSuccess();
}
/**
* API /
* @summary API /
* @param trainingId /
*/
@Patch("update-delete/{trainingId}")
public async updateIsDeletedTraining(
@Request() req: RequestWithUser,
@Path() trainingId: string,
) {
const record = await this.trainingRepo.findOneBy({ id: trainingId });
if (!record) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูล");
if (record.isDeleted === true) {
return new HttpSuccess();
}
await new permission().PermissionOrgUserDelete(req, "SYS_REGISTRY_OFFICER", record.profileId);
const before = structuredClone(record);
const history = new ProfileTrainingHistory();
const now = new Date();
record.isDeleted = true;
record.lastUpdateUserId = req.user.sub;
record.lastUpdateFullName = req.user.name;
record.lastUpdatedAt = now;
Object.assign(history, { ...record, id: undefined });
history.profileTrainingId = trainingId;
history.createdUserId = req.user.sub;
history.createdFullName = req.user.name;
history.createdAt = now;
await Promise.all([
this.trainingRepo.save(record, { data: req }),
setLogDataDiff(req, { before, after: record }),
this.trainingHistoryRepo.save(history, { data: req }),
]);
return new HttpSuccess();
}
/**
* API / IDP
* @summary API / IDP
*/
@Post("delete-all")
public async deleteAllTraining(
@Body() reqBody: { developmentId: string },
@Request() req: RequestWithUser
) {
const trainings = await this.trainingRepo.find({
select: { id: true },
where: { developmentId: reqBody.developmentId },
});
if (trainings.length > 0) {
const trainingIds = trainings.map((x) => x.id);
await this.trainingHistoryRepo.delete({
profileTrainingId: In(trainingIds),
});
await this.trainingRepo.delete({
developmentId: reqBody.developmentId,
});
}
await this.developmentHistoryRepo.delete({
kpiDevelopmentId: reqBody.developmentId,
});
await this.developmentRepo.delete({
kpiDevelopmentId: reqBody.developmentId
});
return new HttpSuccess();
}
}

View file

@ -86,6 +86,13 @@ export class ProfileActposition extends EntityBase {
})
profileEmployeeId: string;
@Column({
nullable: false,
comment: "สถานะลบข้อมูลรักษาการในตำแหน่ง",
default: false,
})
isDeleted: boolean;
@OneToMany(
() => ProfileActpositionHistory,
(profileActpositionHistory) => profileActpositionHistory.histories,

View file

@ -48,6 +48,13 @@ export class ProfileActpositionHistory extends EntityBase {
})
profileActpositionId: string;
@Column({
nullable: false,
comment: "สถานะลบข้อมูลรักษาการในตำแหน่ง",
default: false,
})
isDeleted: boolean;
@ManyToOne(
() => ProfileActposition,
(profileActposition) => profileActposition.profileActpositionHistorys,

View file

@ -154,6 +154,13 @@ export class ProfileDevelopment extends EntityBase {
})
kpiDevelopmentId: string;
@Column({
nullable: false,
comment: "สถานะลบข้อมูลการพัฒนารายบุคคล (Individual Development Plan)",
default: false,
})
isDeleted: boolean;
@OneToMany(
() => ProfileDevelopmentHistory,
(profileDevelopmentHistory) => profileDevelopmentHistory.histories,

View file

@ -144,6 +144,13 @@ export class ProfileDevelopmentHistory extends EntityBase {
})
profileDevelopmentId: string;
@Column({
nullable: false,
comment: "สถานะลบข้อมูลการพัฒนารายบุคคล (Individual Development Plan)",
default: false,
})
isDeleted: boolean;
@ManyToOne(
() => ProfileDevelopment,
(profileDevelopment) => profileDevelopment.profileDevelopmentHistories,

View file

@ -122,6 +122,13 @@ export class ProfileTraining extends EntityBase {
})
developmentId: string;
@Column({
nullable: false,
comment: "สถานะลบข้อมูลการฝึกอบรม/ดูงาน",
default: false,
})
isDeleted: boolean;
@OneToMany(
() => ProfileTrainingHistory,
(profileTrainingHistory) => profileTrainingHistory.histories,

View file

@ -98,6 +98,13 @@ export class ProfileTrainingHistory extends EntityBase {
})
isDate: boolean;
@Column({
nullable: false,
comment: "สถานะลบข้อมูลการฝึกอบรม/ดูงาน",
default: false,
})
isDeleted: boolean;
@ManyToOne(() => ProfileTraining, (profileTraining) => profileTraining.profileTrainingHistories)
@JoinColumn({ name: "profileTrainingId" })
histories: ProfileTraining;

View file

@ -0,0 +1,18 @@
import { MigrationInterface, QueryRunner } from "typeorm";
export class UpdateTablesTranningDevelopmentActPositionAddColumnIsDeleted1770110880489 implements MigrationInterface {
name = 'UpdateTablesTranningDevelopmentActPositionAddColumnIsDeleted1770110880489'
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE \`profileTraining\` ADD \`isDeleted\` tinyint NOT NULL COMMENT 'สถานะลบข้อมูลการฝึกอบรม/ดูงาน' DEFAULT 0`);
await queryRunner.query(`ALTER TABLE \`profileDevelopment\` ADD \`isDeleted\` tinyint NOT NULL COMMENT 'สถานะลบข้อมูลการพัฒนารายบุคคล (Individual Development Plan)' DEFAULT 0`);
await queryRunner.query(`ALTER TABLE \`profileActposition\` ADD \`isDeleted\` tinyint NOT NULL COMMENT 'สถานะลบข้อมูลรักษาการในตำแหน่ง' DEFAULT 0`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE \`profileActposition\` DROP COLUMN \`isDeleted\``);
await queryRunner.query(`ALTER TABLE \`profileDevelopment\` DROP COLUMN \`isDeleted\``);
await queryRunner.query(`ALTER TABLE \`profileTraining\` DROP COLUMN \`isDeleted\``);
}
}

View file

@ -0,0 +1,18 @@
import { MigrationInterface, QueryRunner } from "typeorm";
export class UpdateTablesHistoryTranningDevelopmentActPositionAddColumnIsDeleted1770112472041 implements MigrationInterface {
name = 'UpdateTablesHistoryTranningDevelopmentActPositionAddColumnIsDeleted1770112472041'
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE \`profileTrainingHistory\` ADD \`isDeleted\` tinyint NOT NULL COMMENT 'สถานะลบข้อมูลการฝึกอบรม/ดูงาน' DEFAULT 0`);
await queryRunner.query(`ALTER TABLE \`profileDevelopmentHistory\` ADD \`isDeleted\` tinyint NOT NULL COMMENT 'สถานะลบข้อมูลการพัฒนารายบุคคล (Individual Development Plan)' DEFAULT 0`);
await queryRunner.query(`ALTER TABLE \`profileActpositionHistory\` ADD \`isDeleted\` tinyint NOT NULL COMMENT 'สถานะลบข้อมูลรักษาการในตำแหน่ง' DEFAULT 0`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE \`profileActpositionHistory\` DROP COLUMN \`isDeleted\``);
await queryRunner.query(`ALTER TABLE \`profileDevelopmentHistory\` DROP COLUMN \`isDeleted\``);
await queryRunner.query(`ALTER TABLE \`profileTrainingHistory\` DROP COLUMN \`isDeleted\``);
}
}