From ea69147711adbf9022c487b24c6913a2a37127a4 Mon Sep 17 00:00:00 2001 From: Narul Hidayah Date: Mon, 2 Feb 2026 01:40:32 +0700 Subject: [PATCH 1/5] upd --- src/entity/hrms/hrms_training_participant.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/entity/hrms/hrms_training_participant.ts b/src/entity/hrms/hrms_training_participant.ts index 769c3fd..a213072 100644 --- a/src/entity/hrms/hrms_training_participant.ts +++ b/src/entity/hrms/hrms_training_participant.ts @@ -17,6 +17,12 @@ export class HrmsTrainingParticipant { @JoinColumn() employee: HrmsEmployee; + @Column({ + nullable: true, + length: 512, + }) + certificate_url: string; + @Column({ nullable: false, length: 64, From 44d039b4e9cdfbf644eff5b733379fda74b3e8dc Mon Sep 17 00:00:00 2001 From: Narul Hidayah Date: Mon, 2 Feb 2026 11:52:16 +0700 Subject: [PATCH 2/5] upd --- src/entity/hrms/hrms_attendance.ts | 40 ++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/src/entity/hrms/hrms_attendance.ts b/src/entity/hrms/hrms_attendance.ts index 2dc75e3..cac059d 100644 --- a/src/entity/hrms/hrms_attendance.ts +++ b/src/entity/hrms/hrms_attendance.ts @@ -68,6 +68,46 @@ export class HrmsAttendance { }) is_late: boolean; + /** Snapshot: batas awal clock in shift saat absen (agar tidak berubah jika shift diubah nanti) */ + @Column({ + type: "time", + nullable: true, + }) + shift_in_start_time: string; + + /** Snapshot: batas akhir clock in shift saat absen (agar tidak berubah jika shift diubah nanti) */ + @Column({ + type: "time", + nullable: true, + }) + shift_in_end_time: string; + + /** Snapshot: batas break out shift saat absen */ + @Column({ + type: "time", + nullable: true, + }) + shift_break_out_start_time: string; + + @Column({ + type: "time", + nullable: true, + }) + shift_break_out_end_time: string; + + /** Snapshot: batas break in shift saat absen */ + @Column({ + type: "time", + nullable: true, + }) + shift_break_in_start_time: string; + + @Column({ + type: "time", + nullable: true, + }) + shift_break_in_end_time: string; + @Column({ nullable: false, length: 64, From baca5ff758f23a07c176ba8fb0a87732ee94502d Mon Sep 17 00:00:00 2001 From: Narul Hidayah Date: Mon, 2 Feb 2026 20:02:59 +0700 Subject: [PATCH 3/5] upd --- src/entity/hrms/hrms_attendance.ts | 3 +- src/entity/hrms/hrms_attendance_request.ts | 71 ++++++++++++++++++++++ src/schema/hrms.ts | 1 + 3 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 src/entity/hrms/hrms_attendance_request.ts diff --git a/src/entity/hrms/hrms_attendance.ts b/src/entity/hrms/hrms_attendance.ts index cac059d..ec7942e 100644 --- a/src/entity/hrms/hrms_attendance.ts +++ b/src/entity/hrms/hrms_attendance.ts @@ -24,8 +24,9 @@ export class HrmsAttendance { }) date_at: Date; + /** Nullable when record created from break punch only (no clock in) */ @Column({ - nullable: false, + nullable: true, }) in_at: Date; diff --git a/src/entity/hrms/hrms_attendance_request.ts b/src/entity/hrms/hrms_attendance_request.ts new file mode 100644 index 0000000..f78602c --- /dev/null +++ b/src/entity/hrms/hrms_attendance_request.ts @@ -0,0 +1,71 @@ +import { + Entity, + PrimaryGeneratedColumn, + Column, + CreateDateColumn, + UpdateDateColumn, + DeleteDateColumn, + ManyToOne, + JoinColumn, +} from "typeorm"; +import { HrmsEmployee } from "./hrms_employee"; + +export type AttendanceRequestStatus = "PENDING" | "APPROVED" | "REJECTED"; + +/** Type of punch being requested: maps to attendance column on approve */ +export type AttendanceRequestType = "in" | "break_out" | "break_in" | "out"; + +@Entity("hrms_attendance_requests", { schema: "hrms" }) +export class HrmsAttendanceRequest { + @PrimaryGeneratedColumn("uuid") + id: string; + + @ManyToOne(() => HrmsEmployee, { onDelete: "RESTRICT", nullable: false }) + @JoinColumn() + employee: HrmsEmployee; + + /** Type of punch: in → in_at, break_out → break_out_at, break_in → break_in_at, out → out_at */ + @Column({ length: 32, nullable: false }) + type: AttendanceRequestType; + + @Column({ type: "date", nullable: false }) + date_at: Date; + + /** Requested time for this punch (used for the column indicated by type) */ + @Column({ type: "timestamp", nullable: false }) + requested_at: Date; + + /** Employee reason on submit; supervisor can set when rejecting */ + @Column({ type: "text", nullable: true }) + remark: string; + + @Column({ length: 32, nullable: false, default: "PENDING" }) + status: AttendanceRequestStatus; + + @ManyToOne(() => HrmsEmployee, { onDelete: "SET NULL", nullable: true }) + @JoinColumn() + approved_by: HrmsEmployee; + + @Column({ type: "timestamp", nullable: true }) + approved_at: Date; + + @CreateDateColumn() + created_at: Date; + + @Column({ nullable: true, length: 256 }) + created_by: string; + + @Column({ nullable: true }) + @UpdateDateColumn() + updated_at: Date; + + @Column({ nullable: true, length: 256 }) + updated_by: string; + + @Column({ nullable: true }) + @DeleteDateColumn() + deleted_at: Date; + + @Column({ nullable: true, length: 256 }) + deleted_by: string; +} diff --git a/src/schema/hrms.ts b/src/schema/hrms.ts index a6978e4..6835b57 100644 --- a/src/schema/hrms.ts +++ b/src/schema/hrms.ts @@ -10,6 +10,7 @@ export * from "../entity/hrms/hrms_training"; export * from "../entity/hrms/hrms_training_participant"; export * from "../entity/hrms/hrms_bank"; export * from "../entity/hrms/hrms_attendance"; +export * from "../entity/hrms/hrms_attendance_request"; export * from "../entity/hrms/hrms_payroll"; export * from "../entity/hrms/hrms_payroll_monthly"; export * from "../entity/hrms/hrms_leave"; From e57d3f84d7148895e49a639a863906bf73c677ae Mon Sep 17 00:00:00 2001 From: Narul Hidayah Date: Tue, 3 Feb 2026 03:28:08 +0700 Subject: [PATCH 4/5] upd --- src/entity/hrms/hrms_attendance_request.ts | 5 ++ .../hrms/hrms_attendance_request_approval.ts | 53 +++++++++++++++++++ src/schema/hrms.ts | 1 + 3 files changed, 59 insertions(+) create mode 100644 src/entity/hrms/hrms_attendance_request_approval.ts diff --git a/src/entity/hrms/hrms_attendance_request.ts b/src/entity/hrms/hrms_attendance_request.ts index f78602c..e303259 100644 --- a/src/entity/hrms/hrms_attendance_request.ts +++ b/src/entity/hrms/hrms_attendance_request.ts @@ -7,8 +7,10 @@ import { DeleteDateColumn, ManyToOne, JoinColumn, + OneToMany, } from "typeorm"; import { HrmsEmployee } from "./hrms_employee"; +import { HrmsAttendanceRequestApproval } from "./hrms_attendance_request_approval"; export type AttendanceRequestStatus = "PENDING" | "APPROVED" | "REJECTED"; @@ -42,6 +44,9 @@ export class HrmsAttendanceRequest { @Column({ length: 32, nullable: false, default: "PENDING" }) status: AttendanceRequestStatus; + @OneToMany(() => HrmsAttendanceRequestApproval, (approval) => approval.attendance_request, { cascade: true }) + approvals: HrmsAttendanceRequestApproval[]; + @ManyToOne(() => HrmsEmployee, { onDelete: "SET NULL", nullable: true }) @JoinColumn() approved_by: HrmsEmployee; diff --git a/src/entity/hrms/hrms_attendance_request_approval.ts b/src/entity/hrms/hrms_attendance_request_approval.ts new file mode 100644 index 0000000..8595892 --- /dev/null +++ b/src/entity/hrms/hrms_attendance_request_approval.ts @@ -0,0 +1,53 @@ +import { + Entity, + PrimaryGeneratedColumn, + Column, + CreateDateColumn, + UpdateDateColumn, + ManyToOne, + JoinColumn, +} from "typeorm"; +import { HrmsAttendanceRequest } from "./hrms_attendance_request"; +import { HrmsEmployee } from "./hrms_employee"; +import { ApprovalType, ApprovalStatus } from "./hrms_leave_approval"; + +@Entity("hrms_attendance_request_approvals", { schema: "hrms" }) +export class HrmsAttendanceRequestApproval { + @PrimaryGeneratedColumn("uuid") + id: string; + + @ManyToOne(() => HrmsAttendanceRequest, { onDelete: "CASCADE", nullable: true }) + @JoinColumn() + attendance_request: HrmsAttendanceRequest; + + @Column({ + type: "enum", + enum: ApprovalType, + nullable: false, + }) + approval_type: ApprovalType; + + @ManyToOne(() => HrmsEmployee, { onDelete: "RESTRICT", nullable: true }) + @JoinColumn() + approver: HrmsEmployee; + + @Column({ + type: "enum", + enum: ApprovalStatus, + default: ApprovalStatus.PENDING, + nullable: false, + }) + status: ApprovalStatus; + + @Column({ type: "timestamp", nullable: true }) + approved_at: Date; + + @Column({ length: 512, nullable: true }) + notes: string; + + @CreateDateColumn() + created_at: Date; + + @UpdateDateColumn({ nullable: true }) + updated_at: Date; +} diff --git a/src/schema/hrms.ts b/src/schema/hrms.ts index 6835b57..599ba25 100644 --- a/src/schema/hrms.ts +++ b/src/schema/hrms.ts @@ -11,6 +11,7 @@ export * from "../entity/hrms/hrms_training_participant"; export * from "../entity/hrms/hrms_bank"; export * from "../entity/hrms/hrms_attendance"; export * from "../entity/hrms/hrms_attendance_request"; +export * from "../entity/hrms/hrms_attendance_request_approval"; export * from "../entity/hrms/hrms_payroll"; export * from "../entity/hrms/hrms_payroll_monthly"; export * from "../entity/hrms/hrms_leave"; From 362836cdfc0db99087a46bb5186df1562586fbba Mon Sep 17 00:00:00 2001 From: Narul Hidayah Date: Tue, 3 Feb 2026 11:18:20 +0700 Subject: [PATCH 5/5] upd --- src/entity/finance/finance_cpv_config.ts | 24 ++++++++++++++++++++++++ src/schema/finances.ts | 1 + 2 files changed, 25 insertions(+) create mode 100644 src/entity/finance/finance_cpv_config.ts diff --git a/src/entity/finance/finance_cpv_config.ts b/src/entity/finance/finance_cpv_config.ts new file mode 100644 index 0000000..b98d9f2 --- /dev/null +++ b/src/entity/finance/finance_cpv_config.ts @@ -0,0 +1,24 @@ +import { Entity, PrimaryColumn, ManyToOne, JoinColumn } from "typeorm"; +import { HrmsEmployee } from "../hrms/hrms_employee"; + +/** + * Single-row config for CPV default signatories. + * Used when creating CPV to auto-fill: AUTORIZADOR DA AGENCIA, CERTIFICADO DA AGENCIA, AUTORIZADOR DO TESOURO. + */ +@Entity("finance_cpv_config", { schema: "finances" }) +export class FinanceCpvConfig { + @PrimaryColumn({ length: 64, default: "default" }) + id: string; + + @ManyToOne(() => HrmsEmployee, { onDelete: "NO ACTION", nullable: true }) + @JoinColumn() + agency_authorizer: HrmsEmployee; + + @ManyToOne(() => HrmsEmployee, { onDelete: "NO ACTION", nullable: true }) + @JoinColumn() + agency_certifier: HrmsEmployee; + + @ManyToOne(() => HrmsEmployee, { onDelete: "NO ACTION", nullable: true }) + @JoinColumn() + treasury_authorizer: HrmsEmployee; +} diff --git a/src/schema/finances.ts b/src/schema/finances.ts index 8e67253..824b8ce 100644 --- a/src/schema/finances.ts +++ b/src/schema/finances.ts @@ -12,6 +12,7 @@ export * from "../entity/finance/finance_plan_items"; export * from "../entity/finance/finance_purchase_requests"; export * from "../entity/finance/finance_purchase_request_items"; export * from "../entity/finance/finance_cpvs"; +export * from "../entity/finance/finance_cpv_config"; export * from "../entity/finance/finance_checklist_payment"; export * from "../entity/finance/finance_checklist_payment_item"; export * from "../entity/finance/finance_checklist_payment_approval";