From a76bda34b452de4993b30d09a3e1980c5220a2ed Mon Sep 17 00:00:00 2001 From: harid Date: Mon, 23 Mar 2026 15:36:54 +0700 Subject: [PATCH] =?UTF-8?q?Migration=20=E0=B8=9F=E0=B8=B4=E0=B8=A5?= =?UTF-8?q?=E0=B8=94=E0=B9=8C=E0=B8=95=E0=B8=B2=E0=B8=A3=E0=B8=B2=E0=B8=87?= =?UTF-8?q?=20profileLeave,=20profileLeaveHistory=20&=20=E0=B8=AA=E0=B8=A3?= =?UTF-8?q?=E0=B9=89=E0=B8=B2=E0=B8=87=E0=B8=95=E0=B8=B2=E0=B8=A3=E0=B8=B2?= =?UTF-8?q?=E0=B8=87=20profileAbsentLate,=20profileEmployeeAbsentLate?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ProfileAbsentLateController.ts | 217 ++++++++++++++++++ .../ProfileEmployeeAbsentLateController.ts | 217 ++++++++++++++++++ src/entities/Profile.ts | 4 + src/entities/ProfileAbsentLate.ts | 98 ++++++++ src/entities/ProfileEmployee.ts | 4 + src/entities/ProfileEmployeeAbsentLate.ts | 87 +++++++ src/entities/ProfileLeave.ts | 24 ++ ...5696453-create_table_profileAbsentLate_.ts | 34 +++ ...53766170-update_table_profileAbsentLate.ts | 21 ++ 9 files changed, 706 insertions(+) create mode 100644 src/controllers/ProfileAbsentLateController.ts create mode 100644 src/controllers/ProfileEmployeeAbsentLateController.ts create mode 100644 src/entities/ProfileAbsentLate.ts create mode 100644 src/entities/ProfileEmployeeAbsentLate.ts create mode 100644 src/migration/1774245696453-create_table_profileAbsentLate_.ts create mode 100644 src/migration/1774253766170-update_table_profileAbsentLate.ts diff --git a/src/controllers/ProfileAbsentLateController.ts b/src/controllers/ProfileAbsentLateController.ts new file mode 100644 index 00000000..b9e64a8f --- /dev/null +++ b/src/controllers/ProfileAbsentLateController.ts @@ -0,0 +1,217 @@ +import { + Body, + Controller, + Get, + Patch, + Path, + Post, + Request, + Route, + Security, + Tags, +} from "tsoa"; +import { AppDataSource } from "../database/data-source"; +import { In } from "typeorm"; +import { + ProfileAbsentLate, + CreateProfileAbsentLate, + CreateProfileAbsentLateBatch, + UpdateProfileAbsentLate, +} from "../entities/ProfileAbsentLate"; +import HttpSuccess from "../interfaces/http-success"; +import HttpStatus from "../interfaces/http-status"; +import HttpError from "../interfaces/http-error"; +import { RequestWithUser } from "../middlewares/user"; +import { Profile } from "../entities/Profile"; +import permission from "../interfaces/permission"; +import { setLogDataDiff } from "../interfaces/utils"; + +@Route("api/v1/org/profile/absent-late") +@Tags("ProfileAbsentLate") +@Security("bearerAuth") +export class ProfileAbsentLateController extends Controller { + private profileRepo = AppDataSource.getRepository(Profile); + private absentLateRepo = AppDataSource.getRepository(ProfileAbsentLate); + + /** + * API ดึงข้อมูลการมาสาย/ขาดราชการของ user + * @summary API ดึงข้อมูลการมาสาย/ขาดราชการของ user + */ + @Get("user") + public async getAbsentLateUser(@Request() request: { user: Record }) { + const profile = await this.profileRepo.findOneBy({ keycloak: request.user.sub }); + if (!profile) { + throw new HttpError(HttpStatus.BAD_REQUEST, "ไม่พบ profile ดังกล่าว"); + } + const record = await this.absentLateRepo.find({ + where: { profileId: profile.id, isDeleted: false }, + order: { stampDate: "DESC" }, + }); + return new HttpSuccess(record); + } + + /** + * API ดึงข้อมูลการมาสาย/ขาดราชการตาม profileId + * @summary API ดึงข้อมูลการมาสาย/ขาดราชการตาม profileId + * @param profileId คีย์ profile + */ + @Get("{profileId}") + public async getAbsentLate(@Path() profileId: string, @Request() req: RequestWithUser) { + let _workflow = await new permission().Workflow(req, profileId, "SYS_REGISTRY_OFFICER"); + if (_workflow == false) + await new permission().PermissionOrgUserGet(req, "SYS_REGISTRY_OFFICER", profileId); + const record = await this.absentLateRepo.find({ + where: { profileId, isDeleted: false }, + order: { stampDate: "DESC" }, + }); + return new HttpSuccess(record); + } + + /** + * API สร้างข้อมูลการมาสาย/ขาดราชการ + * @summary API สร้างข้อมูลการมาสาย/ขาดราชการ + */ + @Post() + public async newAbsentLate( + @Request() req: RequestWithUser, + @Body() body: CreateProfileAbsentLate, + ) { + if (!body.profileId) { + throw new HttpError(HttpStatus.BAD_REQUEST, "กรุณากรอก profileId"); + } + + const profile = await this.profileRepo.findOneBy({ id: body.profileId }); + if (!profile) { + throw new HttpError(HttpStatus.BAD_REQUEST, "ไม่พบ profile ดังกล่าว"); + } + await new permission().PermissionOrgUserUpdate(req, "SYS_REGISTRY_OFFICER", profile.id); + + const before = null; + const data = new ProfileAbsentLate(); + + const meta = { + createdUserId: req.user.sub, + createdFullName: req.user.name, + lastUpdateUserId: req.user.sub, + lastUpdateFullName: req.user.name, + createdAt: new Date(), + lastUpdatedAt: new Date(), + }; + + Object.assign(data, { ...body, ...meta }); + await this.absentLateRepo.save(data, { data: req }); + setLogDataDiff(req, { before, after: data }); + + return new HttpSuccess(data.id); + } + + /** + * API สร้างข้อมูลการมาสาย/ขาดราชการ (สำหรับ Job) + * @summary API สร้างข้อมูลการมาสาย/ขาดราชการ (สำหรับ Job) + */ + @Post("batch") + public async newAbsentLateBatch( + @Request() req: RequestWithUser, + @Body() body: CreateProfileAbsentLateBatch, + ) { + if (!body.records || body.records.length === 0) { + throw new HttpError(HttpStatus.BAD_REQUEST, "กรุณาระบุข้อมูลอย่างน้อย 1 รายการ"); + } + + const profileIds = [...new Set(body.records.map((r) => r.profileId))]; + const profiles = await this.profileRepo.findBy({ + id: In(profileIds), + }); + + const foundProfileIds = new Set(profiles.map((p) => p.id)); + const validRecords = body.records.filter((r) => foundProfileIds.has(r.profileId)); + + if (validRecords.length === 0) { + throw new HttpError(HttpStatus.BAD_REQUEST, "ไม่พบ profile ที่ระบุ"); + } + + const meta = { + createdUserId: req.user.sub, + createdFullName: req.user.name, + lastUpdateUserId: req.user.sub, + lastUpdateFullName: req.user.name, + createdAt: new Date(), + lastUpdatedAt: new Date(), + }; + + const records = validRecords.map((item) => { + const data = new ProfileAbsentLate(); + Object.assign(data, { ...item, ...meta }); + return data; + }); + + const result = await this.absentLateRepo.save(records, { data: req }); + + return new HttpSuccess({ count: result.length, ids: result.map((r) => r.id) }); + } + + /** + * API แก้ไขข้อมูลการมาสาย/ขาดราชการ + * @summary API แก้ไขข้อมูลการมาสาย/ขาดราชการ + * @param absentLateId คีย์การมาสาย/ขาดราชการ + */ + @Patch("{absentLateId}") + public async editAbsentLate( + @Request() req: RequestWithUser, + @Body() body: UpdateProfileAbsentLate, + @Path() absentLateId: string, + ) { + const record = await this.absentLateRepo.findOneBy({ id: absentLateId }); + if (!record) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูล"); + await new permission().PermissionOrgUserUpdate( + req, + "SYS_REGISTRY_OFFICER", + record.profileId, + ); + + const before = structuredClone(record); + + Object.assign(record, body); + record.lastUpdateUserId = req.user.sub; + record.lastUpdateFullName = req.user.name; + record.lastUpdatedAt = new Date(); + + await Promise.all([ + this.absentLateRepo.save(record, { data: req }), + setLogDataDiff(req, { before, after: record }), + ]); + + return new HttpSuccess(); + } + + /** + * API ลบข้อมูลการมาสาย/ขาดราชการ (Soft Delete) + * @summary API ลบข้อมูลการมาสาย/ขาดราชการ (Soft Delete) + * @param absentLateId คีย์การมาสาย/ขาดราชการ + */ + @Patch("update-delete/{absentLateId}") + public async updateIsDeleted( + @Request() req: RequestWithUser, + @Path() absentLateId: string, + ) { + const record = await this.absentLateRepo.findOneBy({ id: absentLateId }); + 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); + record.isDeleted = true; + record.lastUpdateUserId = req.user.sub; + record.lastUpdateFullName = req.user.name; + record.lastUpdatedAt = new Date(); + + await Promise.all([ + this.absentLateRepo.save(record, { data: req }), + setLogDataDiff(req, { before, after: record }), + ]); + + return new HttpSuccess(); + } +} diff --git a/src/controllers/ProfileEmployeeAbsentLateController.ts b/src/controllers/ProfileEmployeeAbsentLateController.ts new file mode 100644 index 00000000..37ce4994 --- /dev/null +++ b/src/controllers/ProfileEmployeeAbsentLateController.ts @@ -0,0 +1,217 @@ +import { + Body, + Controller, + Get, + Patch, + Path, + Post, + Request, + Route, + Security, + Tags, +} from "tsoa"; +import { AppDataSource } from "../database/data-source"; +import { In } from "typeorm"; +import { + ProfileEmployeeAbsentLate, + CreateProfileEmployeeAbsentLate, + CreateProfileEmployeeAbsentLateBatch, + UpdateProfileEmployeeAbsentLate, +} from "../entities/ProfileEmployeeAbsentLate"; +import HttpSuccess from "../interfaces/http-success"; +import HttpStatus from "../interfaces/http-status"; +import HttpError from "../interfaces/http-error"; +import { RequestWithUser } from "../middlewares/user"; +import { ProfileEmployee } from "../entities/ProfileEmployee"; +import permission from "../interfaces/permission"; +import { setLogDataDiff } from "../interfaces/utils"; + +@Route("api/v1/org/profile-employee/absent-late") +@Tags("ProfileEmployeeAbsentLate") +@Security("bearerAuth") +export class ProfileEmployeeAbsentLateController extends Controller { + private profileRepo = AppDataSource.getRepository(ProfileEmployee); + private absentLateRepo = AppDataSource.getRepository(ProfileEmployeeAbsentLate); + + /** + * API ดึงข้อมูลการมาสาย/ขาดราชการของ user + * @summary API ดึงข้อมูลการมาสาย/ขาดราชการของ user + */ + @Get("user") + public async getAbsentLateUser(@Request() request: { user: Record }) { + const profile = await this.profileRepo.findOneBy({ keycloak: request.user.sub }); + if (!profile) { + throw new HttpError(HttpStatus.BAD_REQUEST, "ไม่พบ profile ดังกล่าว"); + } + const record = await this.absentLateRepo.find({ + where: { profileEmployeeId: profile.id, isDeleted: false }, + order: { stampDate: "DESC" }, + }); + return new HttpSuccess(record); + } + + /** + * API ดึงข้อมูลการมาสาย/ขาดราชการตาม profileId + * @summary API ดึงข้อมูลการมาสาย/ขาดราชการตาม profileId + * @param profileId คีย์ profile + */ + @Get("{profileId}") + public async getAbsentLate(@Path() profileId: string, @Request() req: RequestWithUser) { + let _workflow = await new permission().Workflow(req, profileId, "SYS_REGISTRY_EMP"); + if (_workflow == false) + await new permission().PermissionOrgUserGet(req, "SYS_REGISTRY_EMP", profileId); + const record = await this.absentLateRepo.find({ + where: { profileEmployeeId: profileId, isDeleted: false }, + order: { stampDate: "DESC" }, + }); + return new HttpSuccess(record); + } + + /** + * API สร้างข้อมูลการมาสาย/ขาดราชการ + * @summary API สร้างข้อมูลการมาสาย/ขาดราชการ + */ + @Post() + public async newAbsentLate( + @Request() req: RequestWithUser, + @Body() body: CreateProfileEmployeeAbsentLate, + ) { + if (!body.profileEmployeeId) { + throw new HttpError(HttpStatus.BAD_REQUEST, "กรุณากรอก profileEmployeeId"); + } + + const profile = await this.profileRepo.findOneBy({ id: body.profileEmployeeId }); + if (!profile) { + throw new HttpError(HttpStatus.BAD_REQUEST, "ไม่พบ profile ดังกล่าว"); + } + await new permission().PermissionOrgUserUpdate(req, "SYS_REGISTRY_EMP", profile.id); + + const before = null; + const data = new ProfileEmployeeAbsentLate(); + + const meta = { + createdUserId: req.user.sub, + createdFullName: req.user.name, + lastUpdateUserId: req.user.sub, + lastUpdateFullName: req.user.name, + createdAt: new Date(), + lastUpdatedAt: new Date(), + }; + + Object.assign(data, { ...body, ...meta }); + await this.absentLateRepo.save(data, { data: req }); + setLogDataDiff(req, { before, after: data }); + + return new HttpSuccess(data.id); + } + + /** + * API สร้างข้อมูลการมาสาย/ขาดราชการ (Batch) + * @summary API สร้างข้อมูลการมาสาย/ขาดราชการ (Batch) สำหรับ Job + */ + @Post("batch") + public async newAbsentLateBatch( + @Request() req: RequestWithUser, + @Body() body: CreateProfileEmployeeAbsentLateBatch, + ) { + if (!body.records || body.records.length === 0) { + throw new HttpError(HttpStatus.BAD_REQUEST, "กรุณาระบุข้อมูลอย่างน้อย 1 รายการ"); + } + + const profileIds = [...new Set(body.records.map((r) => r.profileEmployeeId))]; + const profiles = await this.profileRepo.findBy({ + id: In(profileIds), + }); + + const foundProfileIds = new Set(profiles.map((p) => p.id)); + const validRecords = body.records.filter((r) => foundProfileIds.has(r.profileEmployeeId)); + + if (validRecords.length === 0) { + throw new HttpError(HttpStatus.BAD_REQUEST, "ไม่พบ profile ที่ระบุ"); + } + + const meta = { + createdUserId: req.user.sub, + createdFullName: req.user.name, + lastUpdateUserId: req.user.sub, + lastUpdateFullName: req.user.name, + createdAt: new Date(), + lastUpdatedAt: new Date(), + }; + + const records = validRecords.map((item) => { + const data = new ProfileEmployeeAbsentLate(); + Object.assign(data, { ...item, ...meta }); + return data; + }); + + const result = await this.absentLateRepo.save(records, { data: req }); + + return new HttpSuccess({ count: result.length, ids: result.map((r) => r.id) }); + } + + /** + * API แก้ไขข้อมูลการมาสาย/ขาดราชการ + * @summary API แก้ไขข้อมูลการมาสาย/ขาดราชการ + * @param absentLateId คีย์การมาสาย/ขาดราชการ + */ + @Patch("{absentLateId}") + public async editAbsentLate( + @Request() req: RequestWithUser, + @Body() body: UpdateProfileEmployeeAbsentLate, + @Path() absentLateId: string, + ) { + const record = await this.absentLateRepo.findOneBy({ id: absentLateId }); + if (!record) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูล"); + await new permission().PermissionOrgUserUpdate( + req, + "SYS_REGISTRY_EMP", + record.profileEmployeeId, + ); + + const before = structuredClone(record); + + Object.assign(record, body); + record.lastUpdateUserId = req.user.sub; + record.lastUpdateFullName = req.user.name; + record.lastUpdatedAt = new Date(); + + await Promise.all([ + this.absentLateRepo.save(record, { data: req }), + setLogDataDiff(req, { before, after: record }), + ]); + + return new HttpSuccess(); + } + + /** + * API ลบข้อมูลการมาสาย/ขาดราชการ (Soft Delete) + * @summary API ลบข้อมูลการมาสาย/ขาดราชการ (Soft Delete) + * @param absentLateId คีย์การมาสาย/ขาดราชการ + */ + @Patch("update-delete/{absentLateId}") + public async updateIsDeleted( + @Request() req: RequestWithUser, + @Path() absentLateId: string, + ) { + const record = await this.absentLateRepo.findOneBy({ id: absentLateId }); + if (!record) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูล"); + if (record.isDeleted === true) { + return new HttpSuccess(); + } + await new permission().PermissionOrgUserDelete(req, "SYS_REGISTRY_EMP", record.profileEmployeeId); + + const before = structuredClone(record); + record.isDeleted = true; + record.lastUpdateUserId = req.user.sub; + record.lastUpdateFullName = req.user.name; + record.lastUpdatedAt = new Date(); + + await Promise.all([ + this.absentLateRepo.save(record, { data: req }), + setLogDataDiff(req, { before, after: record }), + ]); + + return new HttpSuccess(); + } +} diff --git a/src/entities/Profile.ts b/src/entities/Profile.ts index 8fc1275f..fe2f55d6 100644 --- a/src/entities/Profile.ts +++ b/src/entities/Profile.ts @@ -50,6 +50,7 @@ import { ProfileAssistance } from "./ProfileAssistance"; import { ProfileSalaryTemp } from "./ProfileSalaryTemp"; import { PositionSalaryEditHistory } from "./PositionSalaryEditHistory"; import { ProfileChangeName } from "./ProfileChangeName"; +import { ProfileAbsentLate } from "./ProfileAbsentLate"; @Entity("profile") export class Profile extends EntityBase { @@ -546,6 +547,9 @@ export class Profile extends EntityBase { @OneToMany(() => ProfileChangeName, (v) => v.profile) profileChangeNames: ProfileChangeName[]; + @OneToMany(() => ProfileAbsentLate, (v) => v.profile) + profileAbsentLates: ProfileAbsentLate[]; + @ManyToOne(() => PosLevel, (posLevel) => posLevel.profiles) @JoinColumn({ name: "posLevelId" }) posLevel: PosLevel; diff --git a/src/entities/ProfileAbsentLate.ts b/src/entities/ProfileAbsentLate.ts new file mode 100644 index 00000000..858412de --- /dev/null +++ b/src/entities/ProfileAbsentLate.ts @@ -0,0 +1,98 @@ +import { Entity, Column, ManyToOne, JoinColumn } from "typeorm"; +import { EntityBase } from "./base/Base"; +import { Profile } from "./Profile"; + +// Enums +export enum AbsentLateStatus { + LATE = "LATE", // มาสาย + ABSENT = "ABSENT", // ขาดราชการ +} + +export enum StampType { + FULL_DAY = "FULL_DAY", // เต็มวัน + MORNING = "MORNING", // ครึ่งเช้า + AFTERNOON = "AFTERNOON", // ครึ่งบ่าย +} + +@Entity("profileAbsentLate") +export class ProfileAbsentLate extends EntityBase { + @Column({ + nullable: true, + length: 40, + comment: "คีย์นอก(FK)ของตาราง Profile", + default: null, + }) + profileId: string; + + @Column({ + type: "enum", + enum: AbsentLateStatus, + comment: "สถานะ มาสาย/ขาดราชการ", + nullable: false, + }) + status: AbsentLateStatus; + + @Column({ + type: "datetime", + comment: "วันที่และเวลาที่ลงเวลา", + nullable: false, + }) + stampDate: Date; + + @Column({ + type: "enum", + enum: StampType, + comment: "เต็มวัน/ครึ่งเช้า/ครึ่งบ่าย", + default: StampType.FULL_DAY, + }) + stampType: StampType; + + @Column({ + type: "decimal", + precision: 2, + scale: 1, + comment: "จำนวน (1.0/0.5)", + default: "1.0", + }) + stampAmount: number; + + @Column({ + type: "varchar", + length: 250, + comment: "หมายเหตุ", + nullable: true, + }) + remark: string; + + @Column({ + comment: "สถานะลบข้อมูล", + default: false, + }) + isDeleted: boolean; + + @ManyToOne(() => Profile, (profile) => profile.profileAbsentLates) + @JoinColumn({ name: "profileId" }) + profile: Profile; +} + +// DTO Classes +export class CreateProfileAbsentLate { + profileId: string; + status: AbsentLateStatus; + stampDate: Date; + stampType?: StampType; + stampAmount?: number; + remark?: string; +} + +export class CreateProfileAbsentLateBatch { + records: CreateProfileAbsentLate[]; +} + +export type UpdateProfileAbsentLate = { + status?: AbsentLateStatus; + stampDate?: Date; + stampType?: StampType; + stampAmount?: number; + remark?: string; +}; diff --git a/src/entities/ProfileEmployee.ts b/src/entities/ProfileEmployee.ts index 50b6d78f..2c3f06e4 100644 --- a/src/entities/ProfileEmployee.ts +++ b/src/entities/ProfileEmployee.ts @@ -38,6 +38,7 @@ import { StateOperatorUser } from "./StateOperatorUser"; import { EmployeeTempPosMaster } from "./EmployeeTempPosMaster"; import { ProfileSalaryTemp } from "./ProfileSalaryTemp"; import { PositionSalaryEditHistory } from "./PositionSalaryEditHistory"; +import { ProfileEmployeeAbsentLate } from "./ProfileEmployeeAbsentLate"; @Entity("profileEmployee") export class ProfileEmployee extends EntityBase { @@ -827,6 +828,9 @@ export class ProfileEmployee extends EntityBase { @OneToMany(() => PositionSalaryEditHistory, (v) => v.profileEmployee) positionSalaryEditHistory: PositionSalaryEditHistory[]; + @OneToMany(() => ProfileEmployeeAbsentLate, (v) => v.profileEmployee) + profileEmployeeAbsentLates: ProfileEmployeeAbsentLate[]; + //ที่อยู่ @Column({ nullable: true, diff --git a/src/entities/ProfileEmployeeAbsentLate.ts b/src/entities/ProfileEmployeeAbsentLate.ts new file mode 100644 index 00000000..d7b8ea71 --- /dev/null +++ b/src/entities/ProfileEmployeeAbsentLate.ts @@ -0,0 +1,87 @@ +import { Entity, Column, ManyToOne, JoinColumn } from "typeorm"; +import { EntityBase } from "./base/Base"; +import { ProfileEmployee } from "./ProfileEmployee"; +import { AbsentLateStatus, StampType } from "./ProfileAbsentLate"; + +@Entity("profileEmployeeAbsentLate") +export class ProfileEmployeeAbsentLate extends EntityBase { + @Column({ + nullable: true, + length: 40, + comment: "คีย์นอก(FK)ของตาราง ProfileEmployee", + default: null, + }) + profileEmployeeId: string; + + @Column({ + type: "enum", + enum: AbsentLateStatus, + comment: "สถานะ มาสาย/ขาดราชการ", + nullable: false, + }) + status: AbsentLateStatus; + + @Column({ + type: "datetime", + comment: "วันที่และเวลาที่ลงเวลา", + nullable: false, + }) + stampDate: Date; + + @Column({ + type: "enum", + enum: StampType, + comment: "เต็มวัน/ครึ่งเช้า/ครึ่งบ่าย", + default: StampType.FULL_DAY, + }) + stampType: StampType; + + @Column({ + type: "decimal", + precision: 2, + scale: 1, + comment: "จำนวน (1.0/0.5)", + default: "1.0", + }) + stampAmount: number; + + @Column({ + type: "varchar", + length: 250, + comment: "หมายเหตุ", + nullable: true, + }) + remark: string; + + @Column({ + comment: "สถานะลบข้อมูล", + default: false, + }) + isDeleted: boolean; + + @ManyToOne(() => ProfileEmployee, (profileEmployee) => profileEmployee.profileEmployeeAbsentLates) + @JoinColumn({ name: "profileEmployeeId" }) + profileEmployee: ProfileEmployee; +} + +// DTO Classes +export class CreateProfileEmployeeAbsentLate { + profileEmployeeId: string; + status: AbsentLateStatus; + stampDate: Date; + stampType?: StampType; + stampAmount?: number; + remark?: string; +} + +export class CreateProfileEmployeeAbsentLateBatch { + records: CreateProfileEmployeeAbsentLate[]; +} + +export type UpdateProfileEmployeeAbsentLate = { + status?: AbsentLateStatus; + stampDate?: Date; + stampType?: StampType; + stampAmount?: number; + remark?: string; +}; diff --git a/src/entities/ProfileLeave.ts b/src/entities/ProfileLeave.ts index f037e303..8ce08d94 100644 --- a/src/entities/ProfileLeave.ts +++ b/src/entities/ProfileLeave.ts @@ -107,6 +107,24 @@ export class ProfileLeave extends EntityBase { }) isDeleted: boolean; + @Column({ + nullable: true, + comment: "ประเภทย่อยการลา (เช่น ศึกษาต่อ, ฝึกอบรม, ปฎอบัติการวิจัย, ดูงาน)", + type: "varchar", + length: 255, + default: null, + }) + leaveSubTypeName: string; + + @Column({ + nullable: true, + comment: "ประเทศที่ไป", + type: "varchar", + length: 255, + default: null, + }) + coupleDayLevelCountry: string; + @OneToMany(() => ProfileLeaveHistory, (v) => v.profileLeave) histories: ProfileLeaveHistory[]; @@ -153,6 +171,8 @@ export class CreateProfileLeave { status?: string | null; reason: string | null; leaveId?: string | null; + leaveSubTypeName?: string | null; + coupleDayLevelCountry?: string | null; } export class CreateProfileEmployeeLeave { @@ -166,6 +186,8 @@ export class CreateProfileEmployeeLeave { status: string | null; reason: string | null; leaveId?: string | null; + leaveSubTypeName?: string | null; + coupleDayLevelCountry?: string | null; } export type UpdateProfileLeave = { @@ -177,4 +199,6 @@ export type UpdateProfileLeave = { totalLeave?: number | null; status?: string | null; reason?: string | null; + leaveSubTypeName?: string | null; + coupleDayLevelCountry?: string | null; }; diff --git a/src/migration/1774245696453-create_table_profileAbsentLate_.ts b/src/migration/1774245696453-create_table_profileAbsentLate_.ts new file mode 100644 index 00000000..11835568 --- /dev/null +++ b/src/migration/1774245696453-create_table_profileAbsentLate_.ts @@ -0,0 +1,34 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class CreateTableProfileAbsentLate_1774245696453 implements MigrationInterface { + name = 'CreateTableProfileAbsentLate_1774245696453' + + public async up(queryRunner: QueryRunner): Promise { + + await queryRunner.query(`CREATE TABLE \`profileAbsentLate\` (\`id\` varchar(36) NOT NULL, \`createdAt\` datetime(6) NOT NULL COMMENT 'สร้างข้อมูลเมื่อ' DEFAULT CURRENT_TIMESTAMP(6), \`createdUserId\` varchar(40) NOT NULL COMMENT 'User Id ที่สร้างข้อมูล' DEFAULT '00000000-0000-0000-0000-000000000000', \`lastUpdatedAt\` datetime(6) NOT NULL COMMENT 'แก้ไขข้อมูลล่าสุดเมื่อ' DEFAULT CURRENT_TIMESTAMP(6), \`lastUpdateUserId\` varchar(40) NOT NULL COMMENT 'User Id ที่แก้ไขข้อมูล' DEFAULT '00000000-0000-0000-0000-000000000000', \`createdFullName\` varchar(200) NOT NULL COMMENT 'ชื่อ User ที่สร้างข้อมูล' DEFAULT 'System Administrator', \`lastUpdateFullName\` varchar(200) NOT NULL COMMENT 'ชื่อ User ที่แก้ไขข้อมูลล่าสุด' DEFAULT 'System Administrator', \`profileId\` varchar(40) NULL COMMENT 'คีย์นอก(FK)ของตาราง Profile', \`status\` enum ('LATE', 'ABSENT') NOT NULL COMMENT 'สถานะ มาสาย/ขาดราชการ', \`stampDate\` date NOT NULL COMMENT 'วันที่ลงเวลา', \`stampType\` enum ('FULL_DAY', 'MORNING', 'AFTERNOON') NOT NULL COMMENT 'เต็มวัน/ครึ่งเช้า/ครึ่งบ่าย' DEFAULT 'FULL_DAY', \`stampAmount\` decimal(2,1) NOT NULL COMMENT 'จำนวน (1.0/0.5)' DEFAULT '1.0', \`remark\` varchar(250) NULL COMMENT 'หมายเหตุ', \`isDeleted\` tinyint NOT NULL COMMENT 'สถานะลบข้อมูล' DEFAULT 0, PRIMARY KEY (\`id\`)) ENGINE=InnoDB`); + await queryRunner.query(`CREATE TABLE \`profileEmployeeAbsentLate\` (\`id\` varchar(36) NOT NULL, \`createdAt\` datetime(6) NOT NULL COMMENT 'สร้างข้อมูลเมื่อ' DEFAULT CURRENT_TIMESTAMP(6), \`createdUserId\` varchar(40) NOT NULL COMMENT 'User Id ที่สร้างข้อมูล' DEFAULT '00000000-0000-0000-0000-000000000000', \`lastUpdatedAt\` datetime(6) NOT NULL COMMENT 'แก้ไขข้อมูลล่าสุดเมื่อ' DEFAULT CURRENT_TIMESTAMP(6), \`lastUpdateUserId\` varchar(40) NOT NULL COMMENT 'User Id ที่แก้ไขข้อมูล' DEFAULT '00000000-0000-0000-0000-000000000000', \`createdFullName\` varchar(200) NOT NULL COMMENT 'ชื่อ User ที่สร้างข้อมูล' DEFAULT 'System Administrator', \`lastUpdateFullName\` varchar(200) NOT NULL COMMENT 'ชื่อ User ที่แก้ไขข้อมูลล่าสุด' DEFAULT 'System Administrator', \`profileEmployeeId\` varchar(40) NULL COMMENT 'คีย์นอก(FK)ของตาราง ProfileEmployee', \`status\` enum ('LATE', 'ABSENT') NOT NULL COMMENT 'สถานะ มาสาย/ขาดราชการ', \`stampDate\` date NOT NULL COMMENT 'วันที่ลงเวลา', \`stampType\` enum ('FULL_DAY', 'MORNING', 'AFTERNOON') NOT NULL COMMENT 'เต็มวัน/ครึ่งเช้า/ครึ่งบ่าย' DEFAULT 'FULL_DAY', \`stampAmount\` decimal(2,1) NOT NULL COMMENT 'จำนวน (1.0/0.5)' DEFAULT '1.0', \`remark\` varchar(250) NULL COMMENT 'หมายเหตุ', \`isDeleted\` tinyint NOT NULL COMMENT 'สถานะลบข้อมูล' DEFAULT 0, PRIMARY KEY (\`id\`)) ENGINE=InnoDB`); + + await queryRunner.query(`ALTER TABLE \`profileLeave\` ADD \`leaveSubTypeName\` varchar(255) NULL COMMENT 'ประเภทย่อยการลา (เช่น ศึกษาต่อ, ฝึกอบรม, ปฎอบัติการวิจัย, ดูงาน)'`); + await queryRunner.query(`ALTER TABLE \`profileLeave\` ADD \`coupleDayLevelCountry\` varchar(255) NULL COMMENT 'ประเทศที่ไป'`); + await queryRunner.query(`ALTER TABLE \`profileLeaveHistory\` ADD \`leaveSubTypeName\` varchar(255) NULL COMMENT 'ประเภทย่อยการลา (เช่น ศึกษาต่อ, ฝึกอบรม, ปฎอบัติการวิจัย, ดูงาน)'`); + await queryRunner.query(`ALTER TABLE \`profileLeaveHistory\` ADD \`coupleDayLevelCountry\` varchar(255) NULL COMMENT 'ประเทศที่ไป'`); + + await queryRunner.query(`ALTER TABLE \`profileAbsentLate\` ADD CONSTRAINT \`FK_28f5579c548da2fd76b5295d8d5\` FOREIGN KEY (\`profileId\`) REFERENCES \`profile\`(\`id\`) ON DELETE NO ACTION ON UPDATE NO ACTION`); + await queryRunner.query(`ALTER TABLE \`profileEmployeeAbsentLate\` ADD CONSTRAINT \`FK_f22d4ae4155cafd14e9c6d888e6\` FOREIGN KEY (\`profileEmployeeId\`) REFERENCES \`profileEmployee\`(\`id\`) ON DELETE NO ACTION ON UPDATE NO ACTION`); + } + + public async down(queryRunner: QueryRunner): Promise { + + await queryRunner.query(`ALTER TABLE \`profileEmployeeAbsentLate\` DROP FOREIGN KEY \`FK_f22d4ae4155cafd14e9c6d888e6\``); + await queryRunner.query(`ALTER TABLE \`profileAbsentLate\` DROP FOREIGN KEY \`FK_28f5579c548da2fd76b5295d8d5\``); + + await queryRunner.query(`ALTER TABLE \`profileLeaveHistory\` DROP COLUMN \`coupleDayLevelCountry\``); + await queryRunner.query(`ALTER TABLE \`profileLeaveHistory\` DROP COLUMN \`leaveSubTypeName\``); + await queryRunner.query(`ALTER TABLE \`profileLeave\` DROP COLUMN \`coupleDayLevelCountry\``); + await queryRunner.query(`ALTER TABLE \`profileLeave\` DROP COLUMN \`leaveSubTypeName\``); + + await queryRunner.query(`DROP TABLE \`profileEmployeeAbsentLate\``); + await queryRunner.query(`DROP TABLE \`profileAbsentLate\``); + } + +} diff --git a/src/migration/1774253766170-update_table_profileAbsentLate.ts b/src/migration/1774253766170-update_table_profileAbsentLate.ts new file mode 100644 index 00000000..be05ca8c --- /dev/null +++ b/src/migration/1774253766170-update_table_profileAbsentLate.ts @@ -0,0 +1,21 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class UpdateTableProfileAbsentLate1774253766170 implements MigrationInterface { + name = 'UpdateTableProfileAbsentLate1774253766170' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE \`profileAbsentLate\` DROP COLUMN \`stampDate\``); + await queryRunner.query(`ALTER TABLE \`profileAbsentLate\` ADD \`stampDate\` datetime NOT NULL COMMENT 'วันที่และเวลาที่ลงเวลา'`); + await queryRunner.query(`ALTER TABLE \`profileEmployeeAbsentLate\` DROP COLUMN \`stampDate\``); + await queryRunner.query(`ALTER TABLE \`profileEmployeeAbsentLate\` ADD \`stampDate\` datetime NOT NULL COMMENT 'วันที่และเวลาที่ลงเวลา'`); + } + + public async down(queryRunner: QueryRunner): Promise { + + await queryRunner.query(`ALTER TABLE \`profileEmployeeAbsentLate\` DROP COLUMN \`stampDate\``); + await queryRunner.query(`ALTER TABLE \`profileEmployeeAbsentLate\` ADD \`stampDate\` date NOT NULL COMMENT 'วันที่ลงเวลา'`); + await queryRunner.query(`ALTER TABLE \`profileAbsentLate\` DROP COLUMN \`stampDate\``); + await queryRunner.query(`ALTER TABLE \`profileAbsentLate\` ADD \`stampDate\` date NOT NULL COMMENT 'วันที่ลงเวลา'`); + } + +}