Migrate add absentLateHistory
All checks were successful
Build & Deploy on Dev / build (push) Successful in 1m41s

This commit is contained in:
harid 2026-03-25 11:48:22 +07:00
parent ecb3cb1d2a
commit ef0d6ea1b5
5 changed files with 180 additions and 4 deletions

View file

@ -18,6 +18,7 @@ import {
CreateProfileAbsentLateBatch,
UpdateProfileAbsentLate,
} from "../entities/ProfileAbsentLate";
import { ProfileAbsentLateHistory } from "../entities/ProfileAbsentLateHistory";
import HttpSuccess from "../interfaces/http-success";
import HttpStatus from "../interfaces/http-status";
import HttpError from "../interfaces/http-error";
@ -32,6 +33,7 @@ import { setLogDataDiff } from "../interfaces/utils";
export class ProfileAbsentLateController extends Controller {
private profileRepo = AppDataSource.getRepository(Profile);
private absentLateRepo = AppDataSource.getRepository(ProfileAbsentLate);
private historyRepo = AppDataSource.getRepository(ProfileAbsentLateHistory);
/**
* API / user
@ -99,8 +101,15 @@ export class ProfileAbsentLateController extends Controller {
};
Object.assign(data, { ...body, ...meta });
// บันทึก history
const history = new ProfileAbsentLateHistory();
Object.assign(history, { ...data, id: undefined });
await this.absentLateRepo.save(data, { data: req });
setLogDataDiff(req, { before, after: data });
history.profileAbsentLateId = data.id;
await this.historyRepo.save(history, { data: req });
return new HttpSuccess(data.id);
}
@ -114,8 +123,9 @@ export class ProfileAbsentLateController extends Controller {
@Request() req: RequestWithUser,
@Body() body: CreateProfileAbsentLateBatch,
) {
// กรณีไม่มีข้อมูลส่งมา (วันที่ไม่มีคนขาด/มาสาย)
if (!body.records || body.records.length === 0) {
throw new HttpError(HttpStatus.BAD_REQUEST, "กรุณาระบุข้อมูลอย่างน้อย 1 รายการ");
return new HttpSuccess({ count: 0, ids: [] });
}
const profileIds = [...new Set(body.records.map((r) => r.profileId))];
@ -126,8 +136,9 @@ export class ProfileAbsentLateController extends Controller {
const foundProfileIds = new Set(profiles.map((p) => p.id));
const validRecords = body.records.filter((r) => foundProfileIds.has(r.profileId));
// กรณีไม่พบ profile เลย
if (validRecords.length === 0) {
throw new HttpError(HttpStatus.BAD_REQUEST, "ไม่พบ profile ที่ระบุ");
return new HttpSuccess({ count: 0, ids: [] });
}
const meta = {
@ -147,6 +158,15 @@ export class ProfileAbsentLateController extends Controller {
const result = await this.absentLateRepo.save(records, { data: req });
// บันทึก history สำหรับแต่ละ record
const historyRecords = result.map((data) => {
const history = new ProfileAbsentLateHistory();
Object.assign(history, { ...data, id: undefined });
history.profileAbsentLateId = data.id;
return history;
});
await this.historyRepo.save(historyRecords, { data: req });
return new HttpSuccess({ count: result.length, ids: result.map((r) => r.id) });
}
@ -170,15 +190,27 @@ export class ProfileAbsentLateController extends Controller {
);
const before = structuredClone(record);
const history = new ProfileAbsentLateHistory();
Object.assign(history, { ...record, id: undefined });
Object.assign(record, body);
Object.assign(history, { ...record, id: undefined });
history.profileAbsentLateId = absentLateId;
record.lastUpdateUserId = req.user.sub;
record.lastUpdateFullName = req.user.name;
record.lastUpdatedAt = new Date();
history.lastUpdateUserId = req.user.sub;
history.lastUpdateFullName = req.user.name;
history.createdUserId = req.user.sub;
history.createdFullName = req.user.name;
history.createdAt = new Date();
history.lastUpdatedAt = new Date();
await Promise.all([
this.absentLateRepo.save(record, { data: req }),
setLogDataDiff(req, { before, after: record }),
this.historyRepo.save(history, { data: req }),
]);
return new HttpSuccess();
@ -202,16 +234,44 @@ export class ProfileAbsentLateController extends Controller {
await new permission().PermissionOrgUserDelete(req, "SYS_REGISTRY_OFFICER", record.profileId);
const before = structuredClone(record);
const history = new ProfileAbsentLateHistory();
Object.assign(history, { ...record, id: undefined });
record.isDeleted = true;
record.lastUpdateUserId = req.user.sub;
record.lastUpdateFullName = req.user.name;
record.lastUpdatedAt = new Date();
history.profileAbsentLateId = absentLateId;
history.isDeleted = true;
history.lastUpdateUserId = req.user.sub;
history.lastUpdateFullName = req.user.name;
history.lastUpdatedAt = new Date();
await Promise.all([
this.absentLateRepo.save(record, { data: req }),
setLogDataDiff(req, { before, after: record }),
this.historyRepo.save(history, { data: req }),
]);
return new HttpSuccess();
}
/**
* API /
* @summary API /
* @param absentLateId /
*/
@Get("history/{absentLateId}")
public async getHistory(@Path() absentLateId: string, @Request() req: RequestWithUser) {
const record = await this.absentLateRepo.findOneBy({ id: absentLateId });
if (!record) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูล");
await new permission().PermissionOrgUserGet(req, "SYS_REGISTRY_OFFICER", record.profileId);
const history = await this.historyRepo.find({
where: { profileAbsentLateId: absentLateId },
order: { createdAt: "DESC" },
});
return new HttpSuccess(history);
}
}

View file

@ -18,6 +18,7 @@ import {
CreateProfileEmployeeAbsentLateBatch,
UpdateProfileEmployeeAbsentLate,
} from "../entities/ProfileEmployeeAbsentLate";
import { ProfileEmployeeAbsentLateHistory } from "../entities/ProfileEmployeeAbsentLateHistory";
import HttpSuccess from "../interfaces/http-success";
import HttpStatus from "../interfaces/http-status";
import HttpError from "../interfaces/http-error";
@ -32,6 +33,7 @@ import { setLogDataDiff } from "../interfaces/utils";
export class ProfileEmployeeAbsentLateController extends Controller {
private profileRepo = AppDataSource.getRepository(ProfileEmployee);
private absentLateRepo = AppDataSource.getRepository(ProfileEmployeeAbsentLate);
private historyRepo = AppDataSource.getRepository(ProfileEmployeeAbsentLateHistory);
/**
* API / user
@ -99,8 +101,15 @@ export class ProfileEmployeeAbsentLateController extends Controller {
};
Object.assign(data, { ...body, ...meta });
// บันทึก history
const history = new ProfileEmployeeAbsentLateHistory();
Object.assign(history, { ...data, id: undefined });
await this.absentLateRepo.save(data, { data: req });
setLogDataDiff(req, { before, after: data });
history.profileEmployeeAbsentLateId = data.id;
await this.historyRepo.save(history, { data: req });
return new HttpSuccess(data.id);
}
@ -114,8 +123,9 @@ export class ProfileEmployeeAbsentLateController extends Controller {
@Request() req: RequestWithUser,
@Body() body: CreateProfileEmployeeAbsentLateBatch,
) {
// กรณีไม่มีข้อมูลส่งมา (วันที่ไม่มีคนขาด/มาสาย)
if (!body.records || body.records.length === 0) {
throw new HttpError(HttpStatus.BAD_REQUEST, "กรุณาระบุข้อมูลอย่างน้อย 1 รายการ");
return new HttpSuccess({ count: 0, ids: [] });
}
const profileIds = [...new Set(body.records.map((r) => r.profileEmployeeId))];
@ -126,8 +136,9 @@ export class ProfileEmployeeAbsentLateController extends Controller {
const foundProfileIds = new Set(profiles.map((p) => p.id));
const validRecords = body.records.filter((r) => foundProfileIds.has(r.profileEmployeeId));
// กรณีไม่พบ profile เลย
if (validRecords.length === 0) {
throw new HttpError(HttpStatus.BAD_REQUEST, "ไม่พบ profile ที่ระบุ");
return new HttpSuccess({ count: 0, ids: [] });
}
const meta = {
@ -147,6 +158,15 @@ export class ProfileEmployeeAbsentLateController extends Controller {
const result = await this.absentLateRepo.save(records, { data: req });
// บันทึก history สำหรับแต่ละ record
const historyRecords = result.map((data) => {
const history = new ProfileEmployeeAbsentLateHistory();
Object.assign(history, { ...data, id: undefined });
history.profileEmployeeAbsentLateId = data.id;
return history;
});
await this.historyRepo.save(historyRecords, { data: req });
return new HttpSuccess({ count: result.length, ids: result.map((r) => r.id) });
}
@ -170,15 +190,27 @@ export class ProfileEmployeeAbsentLateController extends Controller {
);
const before = structuredClone(record);
const history = new ProfileEmployeeAbsentLateHistory();
Object.assign(history, { ...record, id: undefined });
Object.assign(record, body);
Object.assign(history, { ...record, id: undefined });
history.profileEmployeeAbsentLateId = absentLateId;
record.lastUpdateUserId = req.user.sub;
record.lastUpdateFullName = req.user.name;
record.lastUpdatedAt = new Date();
history.lastUpdateUserId = req.user.sub;
history.lastUpdateFullName = req.user.name;
history.createdUserId = req.user.sub;
history.createdFullName = req.user.name;
history.createdAt = new Date();
history.lastUpdatedAt = new Date();
await Promise.all([
this.absentLateRepo.save(record, { data: req }),
setLogDataDiff(req, { before, after: record }),
this.historyRepo.save(history, { data: req }),
]);
return new HttpSuccess();
@ -202,16 +234,44 @@ export class ProfileEmployeeAbsentLateController extends Controller {
await new permission().PermissionOrgUserDelete(req, "SYS_REGISTRY_EMP", record.profileEmployeeId);
const before = structuredClone(record);
const history = new ProfileEmployeeAbsentLateHistory();
Object.assign(history, { ...record, id: undefined });
record.isDeleted = true;
record.lastUpdateUserId = req.user.sub;
record.lastUpdateFullName = req.user.name;
record.lastUpdatedAt = new Date();
history.profileEmployeeAbsentLateId = absentLateId;
history.isDeleted = true;
history.lastUpdateUserId = req.user.sub;
history.lastUpdateFullName = req.user.name;
history.lastUpdatedAt = new Date();
await Promise.all([
this.absentLateRepo.save(record, { data: req }),
setLogDataDiff(req, { before, after: record }),
this.historyRepo.save(history, { data: req }),
]);
return new HttpSuccess();
}
/**
* API /
* @summary API /
* @param absentLateId /
*/
@Get("history/{absentLateId}")
public async getHistory(@Path() absentLateId: string, @Request() req: RequestWithUser) {
const record = await this.absentLateRepo.findOneBy({ id: absentLateId });
if (!record) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูล");
await new permission().PermissionOrgUserGet(req, "SYS_REGISTRY_EMP", record.profileEmployeeId);
const history = await this.historyRepo.find({
where: { profileEmployeeAbsentLateId: absentLateId },
order: { createdAt: "DESC" },
});
return new HttpSuccess(history);
}
}

View file

@ -0,0 +1,20 @@
import { Entity, Column } from "typeorm";
import {
ProfileAbsentLate,
AbsentLateStatus,
StampType,
} from "./ProfileAbsentLate";
@Entity("profileAbsentLateHistory")
export class ProfileAbsentLateHistory extends ProfileAbsentLate {
@Column({
nullable: true,
length: 40,
comment: "คีย์นอก(FK)ของตาราง ProfileAbsentLate",
default: null,
})
profileAbsentLateId: string;
}
// Export enums for re-use
export { AbsentLateStatus, StampType };

View file

@ -0,0 +1,17 @@
import { Entity, Column } from "typeorm";
import { ProfileEmployeeAbsentLate } from "./ProfileEmployeeAbsentLate";
import { AbsentLateStatus, StampType } from "./ProfileAbsentLate";
@Entity("profileEmployeeAbsentLateHistory")
export class ProfileEmployeeAbsentLateHistory extends ProfileEmployeeAbsentLate {
@Column({
nullable: true,
length: 40,
comment: "คีย์นอก(FK)ของตาราง ProfileEmployeeAbsentLate",
default: null,
})
profileEmployeeAbsentLateId: string;
}
// Export enums for re-use
export { AbsentLateStatus, StampType };

View file

@ -0,0 +1,19 @@
import { MigrationInterface, QueryRunner } from "typeorm";
export class AddTableAbsentLateHistory1774408245407 implements MigrationInterface {
name = 'AddTableAbsentLateHistory1774408245407'
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`CREATE TABLE \`profileEmployeeAbsentLateHistory\` (\`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\` datetime 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, \`profileEmployeeAbsentLateId\` varchar(40) NULL COMMENT 'คีย์นอก(FK)ของตาราง ProfileEmployeeAbsentLate', PRIMARY KEY (\`id\`)) ENGINE=InnoDB`);
await queryRunner.query(`CREATE TABLE \`profileAbsentLateHistory\` (\`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\` datetime 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, \`profileAbsentLateId\` varchar(40) NULL COMMENT 'คีย์นอก(FK)ของตาราง ProfileAbsentLate', PRIMARY KEY (\`id\`)) ENGINE=InnoDB`);
await queryRunner.query(`ALTER TABLE \`profileEmployeeAbsentLateHistory\` ADD CONSTRAINT \`FK_8b06ca79d6f75c7d6577c86f3d4\` FOREIGN KEY (\`profileEmployeeId\`) REFERENCES \`profileEmployee\`(\`id\`) ON DELETE NO ACTION ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE \`profileAbsentLateHistory\` ADD CONSTRAINT \`FK_0fa6a843d0e6d901a4f2f56c541\` FOREIGN KEY (\`profileId\`) REFERENCES \`profile\`(\`id\`) ON DELETE NO ACTION ON UPDATE NO ACTION`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`DROP TABLE \`profileAbsentLateHistory\``);
await queryRunner.query(`DROP TABLE \`profileEmployeeAbsentLateHistory\``);
}
}