fix: 캘린더 모달 중복 카드 문제 및 삭제 권한 개선
- monthly_worker_status 조회 시 GROUP BY로 중복 데이터 합산 - 작업보고서 삭제 권한을 그룹장 이상으로 제한 (admin, system, group_leader) - 중복 데이터 정리를 위한 마이그레이션 SQL 추가 (009_fix_duplicate_monthly_status.sql) - synology_deployment 버전에도 동일 수정 적용
This commit is contained in:
@@ -0,0 +1,359 @@
|
||||
-- 근로 및 휴가 관리를 위한 테이블 확장
|
||||
-- 작성일: 2025-11-03
|
||||
|
||||
-- 1. 근로 유형 테이블 생성
|
||||
CREATE TABLE IF NOT EXISTS work_attendance_types (
|
||||
id INT PRIMARY KEY AUTO_INCREMENT,
|
||||
type_code VARCHAR(20) NOT NULL UNIQUE COMMENT '근로 유형 코드',
|
||||
type_name VARCHAR(50) NOT NULL COMMENT '근로 유형명',
|
||||
description TEXT COMMENT '설명',
|
||||
is_active BOOLEAN DEFAULT TRUE COMMENT '활성 상태',
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||
) COMMENT='근로 유형 관리 테이블';
|
||||
|
||||
-- 2. 휴가 유형 테이블 생성
|
||||
CREATE TABLE IF NOT EXISTS vacation_types (
|
||||
id INT PRIMARY KEY AUTO_INCREMENT,
|
||||
type_code VARCHAR(20) NOT NULL UNIQUE COMMENT '휴가 유형 코드',
|
||||
type_name VARCHAR(50) NOT NULL COMMENT '휴가 유형명',
|
||||
hours_deduction DECIMAL(4,2) NOT NULL COMMENT '차감 시간',
|
||||
description TEXT COMMENT '설명',
|
||||
is_active BOOLEAN DEFAULT TRUE COMMENT '활성 상태',
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||
) COMMENT='휴가 유형 관리 테이블';
|
||||
|
||||
-- 3. 일일 근태 기록 테이블 생성
|
||||
CREATE TABLE IF NOT EXISTS daily_attendance_records (
|
||||
id INT PRIMARY KEY AUTO_INCREMENT,
|
||||
record_date DATE NOT NULL COMMENT '기록 날짜',
|
||||
worker_id INT NOT NULL COMMENT '작업자 ID',
|
||||
total_work_hours DECIMAL(4,2) DEFAULT 0 COMMENT '총 작업 시간',
|
||||
attendance_type_id INT COMMENT '근로 유형 ID',
|
||||
vacation_type_id INT NULL COMMENT '휴가 유형 ID',
|
||||
is_vacation_processed BOOLEAN DEFAULT FALSE COMMENT '휴가 처리 여부',
|
||||
overtime_approved BOOLEAN DEFAULT FALSE COMMENT '초과근무 승인 여부',
|
||||
overtime_approved_by INT NULL COMMENT '초과근무 승인자 ID',
|
||||
overtime_approved_at TIMESTAMP NULL COMMENT '초과근무 승인 시간',
|
||||
status ENUM('incomplete', 'partial', 'complete', 'overtime', 'vacation', 'error') DEFAULT 'incomplete' COMMENT '상태',
|
||||
notes TEXT COMMENT '비고',
|
||||
created_by INT NOT NULL COMMENT '생성자 ID',
|
||||
updated_by INT NULL COMMENT '수정자 ID',
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
|
||||
-- 외래키 제약조건
|
||||
FOREIGN KEY (worker_id) REFERENCES workers(worker_id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (attendance_type_id) REFERENCES work_attendance_types(id),
|
||||
FOREIGN KEY (vacation_type_id) REFERENCES vacation_types(id),
|
||||
FOREIGN KEY (overtime_approved_by) REFERENCES users(user_id),
|
||||
FOREIGN KEY (created_by) REFERENCES users(user_id),
|
||||
FOREIGN KEY (updated_by) REFERENCES users(user_id),
|
||||
|
||||
-- 유니크 제약조건 (작업자별 날짜별 하나의 기록)
|
||||
UNIQUE KEY unique_worker_date (worker_id, record_date),
|
||||
|
||||
-- 인덱스
|
||||
INDEX idx_record_date (record_date),
|
||||
INDEX idx_worker_date (worker_id, record_date),
|
||||
INDEX idx_status (status)
|
||||
) COMMENT='일일 근태 기록 테이블';
|
||||
|
||||
-- 4. 휴가 잔여 관리 테이블 생성
|
||||
CREATE TABLE IF NOT EXISTS worker_vacation_balance (
|
||||
id INT PRIMARY KEY AUTO_INCREMENT,
|
||||
worker_id INT NOT NULL COMMENT '작업자 ID',
|
||||
year YEAR NOT NULL COMMENT '연도',
|
||||
total_annual_leave DECIMAL(4,2) DEFAULT 15.0 COMMENT '연간 총 연차 (일)',
|
||||
used_annual_leave DECIMAL(4,2) DEFAULT 0 COMMENT '사용한 연차 (일)',
|
||||
remaining_annual_leave DECIMAL(4,2) GENERATED ALWAYS AS (total_annual_leave - used_annual_leave) STORED COMMENT '잔여 연차 (일)',
|
||||
notes TEXT COMMENT '비고',
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
|
||||
-- 외래키 제약조건
|
||||
FOREIGN KEY (worker_id) REFERENCES workers(worker_id) ON DELETE CASCADE,
|
||||
|
||||
-- 유니크 제약조건 (작업자별 연도별 하나의 기록)
|
||||
UNIQUE KEY unique_worker_year (worker_id, year),
|
||||
|
||||
-- 인덱스
|
||||
INDEX idx_worker_year (worker_id, year)
|
||||
) COMMENT='작업자별 휴가 잔여 관리 테이블';
|
||||
|
||||
-- 5. 기본 데이터 삽입
|
||||
|
||||
-- 근로 유형 기본 데이터
|
||||
INSERT INTO work_attendance_types (type_code, type_name, description) VALUES
|
||||
('REGULAR', '정시근로', '8시간 정규 근무'),
|
||||
('OVERTIME', '연장근로', '8시간 초과 근무'),
|
||||
('PARTIAL', '부분근로', '8시간 미만 근무'),
|
||||
('VACATION', '휴가근로', '휴가와 함께하는 부분 근무')
|
||||
ON DUPLICATE KEY UPDATE
|
||||
type_name = VALUES(type_name),
|
||||
description = VALUES(description);
|
||||
|
||||
-- 휴가 유형 기본 데이터
|
||||
INSERT INTO vacation_types (type_code, type_name, hours_deduction, description) VALUES
|
||||
('ANNUAL_FULL', '연차', 8.0, '하루 전체 연차'),
|
||||
('ANNUAL_HALF', '반차', 4.0, '반일 연차'),
|
||||
('ANNUAL_QUARTER', '반반차', 2.0, '1/4일 연차'),
|
||||
('SICK_FULL', '병가', 8.0, '하루 전체 병가'),
|
||||
('SICK_HALF', '반일병가', 4.0, '반일 병가'),
|
||||
('PERSONAL_FULL', '개인사유', 8.0, '개인사유로 인한 휴가'),
|
||||
('PERSONAL_HALF', '반일개인사유', 4.0, '반일 개인사유 휴가')
|
||||
ON DUPLICATE KEY UPDATE
|
||||
type_name = VALUES(type_name),
|
||||
hours_deduction = VALUES(hours_deduction),
|
||||
description = VALUES(description);
|
||||
|
||||
-- 6. daily_work_reports 테이블에 근태 기록 연결 컬럼 추가
|
||||
ALTER TABLE daily_work_reports
|
||||
ADD COLUMN attendance_record_id INT NULL COMMENT '근태 기록 ID' AFTER updated_by,
|
||||
ADD INDEX idx_attendance_record (attendance_record_id);
|
||||
|
||||
-- 외래키 제약조건 추가 (나중에 데이터 정리 후)
|
||||
-- ALTER TABLE daily_work_reports
|
||||
-- ADD FOREIGN KEY (attendance_record_id) REFERENCES daily_attendance_records(id);
|
||||
|
||||
-- 7. 휴가 전용 작업 유형 추가 (work_types 테이블에)
|
||||
INSERT INTO work_types (name, description, is_active) VALUES
|
||||
('휴가', '연차, 반차, 병가 등 휴가 처리용', TRUE)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
description = VALUES(description),
|
||||
is_active = VALUES(is_active);
|
||||
|
||||
-- 8. 뷰 생성 - 일일 근태 현황 조회용
|
||||
CREATE OR REPLACE VIEW v_daily_attendance_summary AS
|
||||
SELECT
|
||||
dar.id,
|
||||
dar.record_date,
|
||||
dar.worker_id,
|
||||
w.worker_name,
|
||||
w.job_type,
|
||||
dar.total_work_hours,
|
||||
wat.type_name as attendance_type,
|
||||
vt.type_name as vacation_type,
|
||||
dar.is_vacation_processed,
|
||||
dar.overtime_approved,
|
||||
dar.status,
|
||||
CASE
|
||||
WHEN dar.status = 'incomplete' THEN '미입력'
|
||||
WHEN dar.status = 'partial' THEN '부분입력'
|
||||
WHEN dar.status = 'complete' THEN '정시근로'
|
||||
WHEN dar.status = 'overtime' THEN '연장근로'
|
||||
WHEN dar.status = 'vacation' THEN '휴가'
|
||||
WHEN dar.status = 'error' THEN '오류'
|
||||
ELSE '알수없음'
|
||||
END as status_text,
|
||||
dar.notes,
|
||||
dar.created_at,
|
||||
dar.updated_at
|
||||
FROM daily_attendance_records dar
|
||||
LEFT JOIN workers w ON dar.worker_id = w.worker_id
|
||||
LEFT JOIN work_attendance_types wat ON dar.attendance_type_id = wat.id
|
||||
LEFT JOIN vacation_types vt ON dar.vacation_type_id = vt.id
|
||||
ORDER BY dar.record_date DESC, w.worker_name;
|
||||
|
||||
-- 9. 트리거 생성 - daily_work_reports 변경 시 근태 기록 자동 업데이트
|
||||
DELIMITER //
|
||||
|
||||
CREATE OR REPLACE TRIGGER tr_update_attendance_on_work_report
|
||||
AFTER INSERT ON daily_work_reports
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
DECLARE total_hours DECIMAL(4,2);
|
||||
DECLARE attendance_type INT;
|
||||
DECLARE vacation_type INT;
|
||||
DECLARE record_status VARCHAR(20);
|
||||
DECLARE existing_record_id INT;
|
||||
|
||||
-- 해당 작업자의 해당 날짜 총 작업시간 계산
|
||||
SELECT COALESCE(SUM(work_hours), 0) INTO total_hours
|
||||
FROM daily_work_reports
|
||||
WHERE worker_id = NEW.worker_id
|
||||
AND report_date = NEW.report_date;
|
||||
|
||||
-- 휴가 처리 여부 확인 (work_type_id가 휴가용인지)
|
||||
SELECT id INTO vacation_type
|
||||
FROM vacation_types
|
||||
WHERE (total_hours = 0 AND type_code = 'ANNUAL_FULL')
|
||||
OR (total_hours = 4 AND type_code = 'ANNUAL_HALF')
|
||||
OR (total_hours = 6 AND type_code = 'ANNUAL_QUARTER')
|
||||
LIMIT 1;
|
||||
|
||||
-- 근로 유형 결정
|
||||
IF total_hours = 0 THEN
|
||||
SELECT id INTO attendance_type FROM work_attendance_types WHERE type_code = 'PARTIAL';
|
||||
SET record_status = 'incomplete';
|
||||
ELSEIF total_hours < 8 THEN
|
||||
SELECT id INTO attendance_type FROM work_attendance_types WHERE type_code = 'PARTIAL';
|
||||
SET record_status = 'partial';
|
||||
ELSEIF total_hours = 8 THEN
|
||||
SELECT id INTO attendance_type FROM work_attendance_types WHERE type_code = 'REGULAR';
|
||||
SET record_status = 'complete';
|
||||
ELSE
|
||||
SELECT id INTO attendance_type FROM work_attendance_types WHERE type_code = 'OVERTIME';
|
||||
SET record_status = 'overtime';
|
||||
END IF;
|
||||
|
||||
-- 휴가 처리된 경우 상태 조정
|
||||
IF vacation_type IS NOT NULL THEN
|
||||
SET record_status = 'vacation';
|
||||
END IF;
|
||||
|
||||
-- 기존 근태 기록 확인
|
||||
SELECT id INTO existing_record_id
|
||||
FROM daily_attendance_records
|
||||
WHERE worker_id = NEW.worker_id AND record_date = NEW.report_date;
|
||||
|
||||
-- 근태 기록 업데이트 또는 생성
|
||||
IF existing_record_id IS NOT NULL THEN
|
||||
UPDATE daily_attendance_records
|
||||
SET
|
||||
total_work_hours = total_hours,
|
||||
attendance_type_id = attendance_type,
|
||||
vacation_type_id = vacation_type,
|
||||
is_vacation_processed = (vacation_type IS NOT NULL),
|
||||
status = record_status,
|
||||
updated_by = NEW.created_by,
|
||||
updated_at = CURRENT_TIMESTAMP
|
||||
WHERE id = existing_record_id;
|
||||
ELSE
|
||||
INSERT INTO daily_attendance_records (
|
||||
record_date, worker_id, total_work_hours, attendance_type_id,
|
||||
vacation_type_id, is_vacation_processed, status, created_by
|
||||
) VALUES (
|
||||
NEW.report_date, NEW.worker_id, total_hours, attendance_type,
|
||||
vacation_type, (vacation_type IS NOT NULL), record_status, NEW.created_by
|
||||
);
|
||||
END IF;
|
||||
END//
|
||||
|
||||
DELIMITER ;
|
||||
|
||||
-- 10. 기존 데이터 마이그레이션을 위한 프로시저
|
||||
DELIMITER //
|
||||
|
||||
CREATE OR REPLACE PROCEDURE sp_migrate_existing_work_reports()
|
||||
BEGIN
|
||||
DECLARE done INT DEFAULT FALSE;
|
||||
DECLARE v_worker_id INT;
|
||||
DECLARE v_report_date DATE;
|
||||
DECLARE cur CURSOR FOR
|
||||
SELECT DISTINCT worker_id, report_date
|
||||
FROM daily_work_reports
|
||||
ORDER BY report_date DESC, worker_id;
|
||||
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
|
||||
|
||||
OPEN cur;
|
||||
|
||||
read_loop: LOOP
|
||||
FETCH cur INTO v_worker_id, v_report_date;
|
||||
IF done THEN
|
||||
LEAVE read_loop;
|
||||
END IF;
|
||||
|
||||
-- 각 작업자별 날짜별로 근태 기록 생성/업데이트
|
||||
CALL sp_update_attendance_record(v_worker_id, v_report_date);
|
||||
END LOOP;
|
||||
|
||||
CLOSE cur;
|
||||
END//
|
||||
|
||||
CREATE OR REPLACE PROCEDURE sp_update_attendance_record(
|
||||
IN p_worker_id INT,
|
||||
IN p_report_date DATE
|
||||
)
|
||||
BEGIN
|
||||
DECLARE total_hours DECIMAL(4,2);
|
||||
DECLARE attendance_type INT;
|
||||
DECLARE vacation_type INT;
|
||||
DECLARE record_status VARCHAR(20);
|
||||
DECLARE existing_record_id INT;
|
||||
DECLARE has_vacation_work INT DEFAULT 0;
|
||||
|
||||
-- 해당 작업자의 해당 날짜 총 작업시간 계산
|
||||
SELECT COALESCE(SUM(work_hours), 0) INTO total_hours
|
||||
FROM daily_work_reports
|
||||
WHERE worker_id = p_worker_id
|
||||
AND report_date = p_report_date;
|
||||
|
||||
-- 휴가 관련 작업이 있는지 확인 (work_type_id = 999 또는 휴가 관련)
|
||||
SELECT COUNT(*) INTO has_vacation_work
|
||||
FROM daily_work_reports dwr
|
||||
JOIN work_types wt ON dwr.work_type_id = wt.id
|
||||
WHERE dwr.worker_id = p_worker_id
|
||||
AND dwr.report_date = p_report_date
|
||||
AND (wt.name LIKE '%휴가%' OR wt.name LIKE '%연차%' OR wt.name LIKE '%반차%');
|
||||
|
||||
-- 휴가 유형 결정
|
||||
IF has_vacation_work > 0 THEN
|
||||
IF total_hours = 0 THEN
|
||||
SELECT id INTO vacation_type FROM vacation_types WHERE type_code = 'ANNUAL_FULL' LIMIT 1;
|
||||
ELSEIF total_hours = 4 THEN
|
||||
SELECT id INTO vacation_type FROM vacation_types WHERE type_code = 'ANNUAL_HALF' LIMIT 1;
|
||||
ELSEIF total_hours = 6 THEN
|
||||
SELECT id INTO vacation_type FROM vacation_types WHERE type_code = 'ANNUAL_QUARTER' LIMIT 1;
|
||||
END IF;
|
||||
END IF;
|
||||
|
||||
-- 근로 유형 및 상태 결정
|
||||
IF vacation_type IS NOT NULL THEN
|
||||
SELECT id INTO attendance_type FROM work_attendance_types WHERE type_code = 'VACATION';
|
||||
SET record_status = 'vacation';
|
||||
ELSEIF total_hours = 0 THEN
|
||||
SELECT id INTO attendance_type FROM work_attendance_types WHERE type_code = 'PARTIAL';
|
||||
SET record_status = 'incomplete';
|
||||
ELSEIF total_hours < 8 THEN
|
||||
SELECT id INTO attendance_type FROM work_attendance_types WHERE type_code = 'PARTIAL';
|
||||
SET record_status = 'partial';
|
||||
ELSEIF total_hours = 8 THEN
|
||||
SELECT id INTO attendance_type FROM work_attendance_types WHERE type_code = 'REGULAR';
|
||||
SET record_status = 'complete';
|
||||
ELSE
|
||||
SELECT id INTO attendance_type FROM work_attendance_types WHERE type_code = 'OVERTIME';
|
||||
SET record_status = 'overtime';
|
||||
END IF;
|
||||
|
||||
-- 기존 근태 기록 확인
|
||||
SELECT id INTO existing_record_id
|
||||
FROM daily_attendance_records
|
||||
WHERE worker_id = p_worker_id AND record_date = p_report_date;
|
||||
|
||||
-- 근태 기록 업데이트 또는 생성
|
||||
IF existing_record_id IS NOT NULL THEN
|
||||
UPDATE daily_attendance_records
|
||||
SET
|
||||
total_work_hours = total_hours,
|
||||
attendance_type_id = attendance_type,
|
||||
vacation_type_id = vacation_type,
|
||||
is_vacation_processed = (vacation_type IS NOT NULL),
|
||||
status = record_status,
|
||||
updated_by = 1,
|
||||
updated_at = CURRENT_TIMESTAMP
|
||||
WHERE id = existing_record_id;
|
||||
ELSE
|
||||
INSERT INTO daily_attendance_records (
|
||||
record_date, worker_id, total_work_hours, attendance_type_id,
|
||||
vacation_type_id, is_vacation_processed, status, created_by
|
||||
) VALUES (
|
||||
p_report_date, p_worker_id, total_hours, attendance_type,
|
||||
vacation_type, (vacation_type IS NOT NULL), record_status, 1
|
||||
);
|
||||
END IF;
|
||||
END//
|
||||
|
||||
DELIMITER ;
|
||||
|
||||
-- 11. 권한 및 인덱스 최적화
|
||||
-- 추가 인덱스 생성
|
||||
CREATE INDEX idx_daily_work_reports_worker_date ON daily_work_reports(worker_id, report_date);
|
||||
CREATE INDEX idx_daily_work_reports_work_type ON daily_work_reports(work_type_id);
|
||||
|
||||
-- 마이그레이션 실행 (주석 해제하여 실행)
|
||||
-- CALL sp_migrate_existing_work_reports();
|
||||
|
||||
-- 완료 메시지
|
||||
SELECT 'DB 확장 완료: 근로 및 휴가 관리 시스템이 성공적으로 구축되었습니다.' as message;
|
||||
@@ -0,0 +1,143 @@
|
||||
-- 근태 관리 시스템 테이블 추가
|
||||
-- 작성일: 2025-11-03
|
||||
-- 설명: 근로 유형, 휴가 유형, 일일 근태 기록, 휴가 잔여 관리 테이블
|
||||
|
||||
-- 1. 근로 유형 테이블 생성
|
||||
CREATE TABLE IF NOT EXISTS `work_attendance_types` (
|
||||
`id` INT PRIMARY KEY AUTO_INCREMENT,
|
||||
`type_code` VARCHAR(20) NOT NULL UNIQUE COMMENT '근로 유형 코드',
|
||||
`type_name` VARCHAR(50) NOT NULL COMMENT '근로 유형명',
|
||||
`description` TEXT COMMENT '설명',
|
||||
`is_active` BOOLEAN DEFAULT TRUE COMMENT '활성 상태',
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='근로 유형 관리 테이블';
|
||||
|
||||
-- 2. 휴가 유형 테이블 생성
|
||||
CREATE TABLE IF NOT EXISTS `vacation_types` (
|
||||
`id` INT PRIMARY KEY AUTO_INCREMENT,
|
||||
`type_code` VARCHAR(20) NOT NULL UNIQUE COMMENT '휴가 유형 코드',
|
||||
`type_name` VARCHAR(50) NOT NULL COMMENT '휴가 유형명',
|
||||
`hours_deduction` DECIMAL(4,2) NOT NULL COMMENT '차감 시간',
|
||||
`description` TEXT COMMENT '설명',
|
||||
`is_active` BOOLEAN DEFAULT TRUE COMMENT '활성 상태',
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='휴가 유형 관리 테이블';
|
||||
|
||||
-- 3. 일일 근태 기록 테이블 생성
|
||||
CREATE TABLE IF NOT EXISTS `daily_attendance_records` (
|
||||
`id` INT PRIMARY KEY AUTO_INCREMENT,
|
||||
`record_date` DATE NOT NULL COMMENT '기록 날짜',
|
||||
`worker_id` INT NOT NULL COMMENT '작업자 ID',
|
||||
`total_work_hours` DECIMAL(4,2) DEFAULT 0 COMMENT '총 작업 시간',
|
||||
`attendance_type_id` INT COMMENT '근로 유형 ID',
|
||||
`vacation_type_id` INT NULL COMMENT '휴가 유형 ID',
|
||||
`is_vacation_processed` BOOLEAN DEFAULT FALSE COMMENT '휴가 처리 여부',
|
||||
`overtime_approved` BOOLEAN DEFAULT FALSE COMMENT '초과근무 승인 여부',
|
||||
`overtime_approved_by` INT NULL COMMENT '초과근무 승인자 ID',
|
||||
`overtime_approved_at` TIMESTAMP NULL COMMENT '초과근무 승인 시간',
|
||||
`status` ENUM('incomplete', 'partial', 'complete', 'overtime', 'vacation', 'error') DEFAULT 'incomplete' COMMENT '상태',
|
||||
`notes` TEXT COMMENT '비고',
|
||||
`created_by` INT NOT NULL DEFAULT 1 COMMENT '생성자 ID',
|
||||
`updated_by` INT NULL COMMENT '수정자 ID',
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
|
||||
-- 인덱스
|
||||
UNIQUE KEY `unique_worker_date` (`worker_id`, `record_date`),
|
||||
INDEX `idx_record_date` (`record_date`),
|
||||
INDEX `idx_worker_date` (`worker_id`, `record_date`),
|
||||
INDEX `idx_status` (`status`),
|
||||
|
||||
-- 외래키 (기존 테이블과의 관계)
|
||||
FOREIGN KEY (`worker_id`) REFERENCES `workers`(`worker_id`) ON DELETE CASCADE,
|
||||
FOREIGN KEY (`attendance_type_id`) REFERENCES `work_attendance_types`(`id`),
|
||||
FOREIGN KEY (`vacation_type_id`) REFERENCES `vacation_types`(`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='일일 근태 기록 테이블';
|
||||
|
||||
-- 4. 작업자 휴가 잔여 관리 테이블 생성
|
||||
CREATE TABLE IF NOT EXISTS `worker_vacation_balance` (
|
||||
`id` INT PRIMARY KEY AUTO_INCREMENT,
|
||||
`worker_id` INT NOT NULL COMMENT '작업자 ID',
|
||||
`year` YEAR NOT NULL COMMENT '연도',
|
||||
`total_annual_leave` DECIMAL(4,2) DEFAULT 15.0 COMMENT '연간 총 연차 (일)',
|
||||
`used_annual_leave` DECIMAL(4,2) DEFAULT 0 COMMENT '사용한 연차 (일)',
|
||||
`remaining_annual_leave` DECIMAL(4,2) GENERATED ALWAYS AS (`total_annual_leave` - `used_annual_leave`) STORED COMMENT '잔여 연차 (일)',
|
||||
`notes` TEXT COMMENT '비고',
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
|
||||
-- 인덱스
|
||||
UNIQUE KEY `unique_worker_year` (`worker_id`, `year`),
|
||||
INDEX `idx_worker_year` (`worker_id`, `year`),
|
||||
|
||||
-- 외래키
|
||||
FOREIGN KEY (`worker_id`) REFERENCES `workers`(`worker_id`) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='작업자별 휴가 잔여 관리 테이블';
|
||||
|
||||
-- 5. daily_work_reports 테이블에 근태 기록 연결 컬럼 추가
|
||||
ALTER TABLE `daily_work_reports`
|
||||
ADD COLUMN IF NOT EXISTS `attendance_record_id` INT NULL COMMENT '근태 기록 ID' AFTER `updated_by`;
|
||||
|
||||
-- 인덱스 추가
|
||||
CREATE INDEX IF NOT EXISTS `idx_attendance_record` ON `daily_work_reports`(`attendance_record_id`);
|
||||
CREATE INDEX IF NOT EXISTS `idx_daily_work_reports_worker_date` ON `daily_work_reports`(`worker_id`, `report_date`);
|
||||
|
||||
-- 6. 기본 데이터 삽입
|
||||
|
||||
-- 근로 유형 기본 데이터
|
||||
INSERT IGNORE INTO `work_attendance_types` (`type_code`, `type_name`, `description`) VALUES
|
||||
('REGULAR', '정시근로', '8시간 정규 근무'),
|
||||
('OVERTIME', '연장근로', '8시간 초과 근무'),
|
||||
('PARTIAL', '부분근로', '8시간 미만 근무'),
|
||||
('VACATION', '휴가근로', '휴가와 함께하는 부분 근무');
|
||||
|
||||
-- 휴가 유형 기본 데이터
|
||||
INSERT IGNORE INTO `vacation_types` (`type_code`, `type_name`, `hours_deduction`, `description`) VALUES
|
||||
('ANNUAL_FULL', '연차', 8.0, '하루 전체 연차'),
|
||||
('ANNUAL_HALF', '반차', 4.0, '반일 연차'),
|
||||
('ANNUAL_QUARTER', '반반차', 2.0, '1/4일 연차'),
|
||||
('SICK_FULL', '병가', 8.0, '하루 전체 병가'),
|
||||
('SICK_HALF', '반일병가', 4.0, '반일 병가'),
|
||||
('PERSONAL_FULL', '개인사유', 8.0, '개인사유로 인한 휴가'),
|
||||
('PERSONAL_HALF', '반일개인사유', 4.0, '반일 개인사유 휴가');
|
||||
|
||||
-- 7. 휴가 전용 작업 유형 추가 (이미 있으면 무시)
|
||||
INSERT IGNORE INTO `work_types` (`name`, `description`, `is_active`) VALUES
|
||||
('휴가', '연차, 반차, 병가 등 휴가 처리용', TRUE);
|
||||
|
||||
-- 8. 뷰 생성 - 일일 근태 현황 조회용
|
||||
CREATE OR REPLACE VIEW `v_daily_attendance_summary` AS
|
||||
SELECT
|
||||
dar.id,
|
||||
dar.record_date,
|
||||
dar.worker_id,
|
||||
w.worker_name,
|
||||
w.job_type,
|
||||
dar.total_work_hours,
|
||||
wat.type_name as attendance_type,
|
||||
vt.type_name as vacation_type,
|
||||
dar.is_vacation_processed,
|
||||
dar.overtime_approved,
|
||||
dar.status,
|
||||
CASE
|
||||
WHEN dar.status = 'incomplete' THEN '미입력'
|
||||
WHEN dar.status = 'partial' THEN '부분입력'
|
||||
WHEN dar.status = 'complete' THEN '정시근로'
|
||||
WHEN dar.status = 'overtime' THEN '연장근로'
|
||||
WHEN dar.status = 'vacation' THEN '휴가'
|
||||
WHEN dar.status = 'error' THEN '오류'
|
||||
ELSE '알수없음'
|
||||
END as status_text,
|
||||
dar.notes,
|
||||
dar.created_at,
|
||||
dar.updated_at
|
||||
FROM daily_attendance_records dar
|
||||
LEFT JOIN workers w ON dar.worker_id = w.worker_id
|
||||
LEFT JOIN work_attendance_types wat ON dar.attendance_type_id = wat.id
|
||||
LEFT JOIN vacation_types vt ON dar.vacation_type_id = vt.id
|
||||
ORDER BY dar.record_date DESC, w.worker_name;
|
||||
|
||||
-- 완료 메시지
|
||||
SELECT '✅ 근태 관리 시스템 테이블이 성공적으로 생성되었습니다.' as message;
|
||||
@@ -0,0 +1,16 @@
|
||||
-- 006_add_description_column.sql
|
||||
-- daily_work_reports 테이블에 description 컬럼 추가
|
||||
|
||||
-- description 컬럼 추가 (이미 존재하는 경우 무시)
|
||||
SET @sql = (SELECT IF(
|
||||
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS
|
||||
WHERE table_name = 'daily_work_reports'
|
||||
AND table_schema = 'hyungi'
|
||||
AND column_name = 'description') = 0,
|
||||
'ALTER TABLE daily_work_reports ADD COLUMN description TEXT COMMENT ''작업 설명'' AFTER work_hours',
|
||||
'SELECT ''description column already exists'' as message'
|
||||
));
|
||||
|
||||
PREPARE stmt FROM @sql;
|
||||
EXECUTE stmt;
|
||||
DEALLOCATE PREPARE stmt;
|
||||
@@ -0,0 +1,249 @@
|
||||
-- 007_create_monthly_worker_status.sql
|
||||
-- 월별 작업자 상태 집계 테이블 생성
|
||||
|
||||
-- 월별 작업자 상태 집계 테이블
|
||||
CREATE TABLE IF NOT EXISTS monthly_worker_status (
|
||||
id INT PRIMARY KEY AUTO_INCREMENT,
|
||||
year INT NOT NULL COMMENT '연도',
|
||||
month INT NOT NULL COMMENT '월 (1-12)',
|
||||
worker_id INT NOT NULL COMMENT '작업자 ID',
|
||||
date DATE NOT NULL COMMENT '날짜',
|
||||
|
||||
-- 작업 시간 정보
|
||||
total_work_hours DECIMAL(5,2) DEFAULT 0.00 COMMENT '총 작업시간',
|
||||
actual_work_hours DECIMAL(5,2) DEFAULT 0.00 COMMENT '실제 작업시간 (휴가 제외)',
|
||||
vacation_hours DECIMAL(5,2) DEFAULT 0.00 COMMENT '휴가 시간',
|
||||
|
||||
-- 작업 건수
|
||||
total_work_count INT DEFAULT 0 COMMENT '총 작업 건수',
|
||||
regular_work_count INT DEFAULT 0 COMMENT '정규 작업 건수',
|
||||
error_work_count INT DEFAULT 0 COMMENT '오류 작업 건수',
|
||||
|
||||
-- 상태 정보
|
||||
work_status ENUM(
|
||||
'incomplete', -- 미입력 (0시간)
|
||||
'partial', -- 부분입력 (8시간 미만)
|
||||
'complete', -- 정시근로 (8시간)
|
||||
'overtime', -- 연장근로 (8시간 초과)
|
||||
'vacation-full', -- 연차 (8시간)
|
||||
'vacation-half', -- 반차 (4시간)
|
||||
'vacation-quarter',-- 반반차 (2시간)
|
||||
'vacation-half-half', -- 조퇴 (6시간)
|
||||
'error', -- 오류 발생
|
||||
'overtime-warning' -- 초과근무 확인필요 (12시간 초과)
|
||||
) NOT NULL DEFAULT 'incomplete' COMMENT '작업 상태',
|
||||
|
||||
has_vacation BOOLEAN DEFAULT FALSE COMMENT '휴가 여부',
|
||||
has_error BOOLEAN DEFAULT FALSE COMMENT '오류 여부',
|
||||
has_issues BOOLEAN DEFAULT FALSE COMMENT '문제 여부 (미입력/부분입력)',
|
||||
|
||||
-- 메타 정보
|
||||
last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '마지막 업데이트 시간',
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
-- 인덱스
|
||||
UNIQUE KEY unique_worker_date (worker_id, date),
|
||||
KEY idx_year_month (year, month),
|
||||
KEY idx_worker_year_month (worker_id, year, month),
|
||||
KEY idx_status (work_status),
|
||||
KEY idx_has_issues (has_issues),
|
||||
KEY idx_has_error (has_error),
|
||||
|
||||
-- 외래키
|
||||
FOREIGN KEY (worker_id) REFERENCES workers(worker_id) ON DELETE CASCADE
|
||||
) COMMENT='월별 작업자 상태 집계 테이블';
|
||||
|
||||
-- 월별 집계 요약 테이블 (캘린더 최적화용)
|
||||
CREATE TABLE IF NOT EXISTS monthly_summary (
|
||||
id INT PRIMARY KEY AUTO_INCREMENT,
|
||||
year INT NOT NULL COMMENT '연도',
|
||||
month INT NOT NULL COMMENT '월 (1-12)',
|
||||
date DATE NOT NULL COMMENT '날짜',
|
||||
|
||||
-- 작업자 수
|
||||
total_workers INT DEFAULT 0 COMMENT '총 작업자 수',
|
||||
working_workers INT DEFAULT 0 COMMENT '작업한 작업자 수',
|
||||
|
||||
-- 상태별 작업자 수
|
||||
incomplete_workers INT DEFAULT 0 COMMENT '미입력 작업자 수',
|
||||
partial_workers INT DEFAULT 0 COMMENT '부분입력 작업자 수',
|
||||
complete_workers INT DEFAULT 0 COMMENT '완료 작업자 수',
|
||||
overtime_workers INT DEFAULT 0 COMMENT '연장근로 작업자 수',
|
||||
vacation_workers INT DEFAULT 0 COMMENT '휴가 작업자 수',
|
||||
error_workers INT DEFAULT 0 COMMENT '오류 작업자 수',
|
||||
|
||||
-- 집계 정보
|
||||
total_work_hours DECIMAL(8,2) DEFAULT 0.00 COMMENT '총 작업시간',
|
||||
total_work_count INT DEFAULT 0 COMMENT '총 작업 건수',
|
||||
total_error_count INT DEFAULT 0 COMMENT '총 오류 건수',
|
||||
|
||||
-- 상태 플래그 (캘린더 표시용)
|
||||
has_issues BOOLEAN DEFAULT FALSE COMMENT '문제 있음 (미입력/부분입력)',
|
||||
has_errors BOOLEAN DEFAULT FALSE COMMENT '오류 있음',
|
||||
|
||||
-- 메타 정보
|
||||
last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
-- 인덱스
|
||||
UNIQUE KEY unique_date (date),
|
||||
KEY idx_year_month (year, month),
|
||||
KEY idx_has_issues (has_issues),
|
||||
KEY idx_has_errors (has_errors)
|
||||
) COMMENT='월별 일자별 요약 테이블 (캘린더 최적화용)';
|
||||
|
||||
-- 집계 데이터 업데이트 함수
|
||||
DELIMITER $$
|
||||
|
||||
CREATE OR REPLACE PROCEDURE UpdateMonthlyWorkerStatus(
|
||||
IN p_date DATE,
|
||||
IN p_worker_id INT
|
||||
)
|
||||
BEGIN
|
||||
DECLARE v_year INT;
|
||||
DECLARE v_month INT;
|
||||
DECLARE v_total_hours DECIMAL(5,2);
|
||||
DECLARE v_actual_hours DECIMAL(5,2);
|
||||
DECLARE v_vacation_hours DECIMAL(5,2);
|
||||
DECLARE v_total_count INT;
|
||||
DECLARE v_regular_count INT;
|
||||
DECLARE v_error_count INT;
|
||||
DECLARE v_has_vacation BOOLEAN;
|
||||
DECLARE v_has_error BOOLEAN;
|
||||
DECLARE v_has_issues BOOLEAN;
|
||||
DECLARE v_status VARCHAR(20);
|
||||
|
||||
-- 연도, 월 추출
|
||||
SET v_year = YEAR(p_date);
|
||||
SET v_month = MONTH(p_date);
|
||||
|
||||
-- 해당 날짜의 작업자 데이터 집계
|
||||
SELECT
|
||||
COALESCE(SUM(work_hours), 0),
|
||||
COALESCE(SUM(CASE WHEN project_id != 13 THEN work_hours ELSE 0 END), 0),
|
||||
COALESCE(SUM(CASE WHEN project_id = 13 THEN work_hours ELSE 0 END), 0),
|
||||
COUNT(*),
|
||||
COUNT(CASE WHEN project_id != 13 AND work_status_id != 2 THEN 1 END),
|
||||
COUNT(CASE WHEN work_status_id = 2 THEN 1 END),
|
||||
MAX(CASE WHEN project_id = 13 THEN 1 ELSE 0 END),
|
||||
MAX(CASE WHEN work_status_id = 2 THEN 1 ELSE 0 END)
|
||||
INTO
|
||||
v_total_hours, v_actual_hours, v_vacation_hours,
|
||||
v_total_count, v_regular_count, v_error_count,
|
||||
v_has_vacation, v_has_error
|
||||
FROM daily_work_reports
|
||||
WHERE report_date = p_date AND worker_id = p_worker_id;
|
||||
|
||||
-- 상태 결정 로직
|
||||
IF v_has_error THEN
|
||||
SET v_status = 'error';
|
||||
SET v_has_issues = FALSE;
|
||||
ELSEIF v_total_hours > 12 THEN
|
||||
SET v_status = 'overtime-warning';
|
||||
SET v_has_issues = TRUE;
|
||||
ELSEIF v_has_vacation AND v_vacation_hours > 0 THEN
|
||||
-- 휴가 상태 결정
|
||||
CASE v_vacation_hours
|
||||
WHEN 8 THEN SET v_status = 'vacation-full';
|
||||
WHEN 6 THEN SET v_status = 'vacation-half-half';
|
||||
WHEN 4 THEN SET v_status = 'vacation-half';
|
||||
WHEN 2 THEN SET v_status = 'vacation-quarter';
|
||||
ELSE SET v_status = 'vacation-full';
|
||||
END CASE;
|
||||
SET v_has_issues = FALSE;
|
||||
ELSEIF v_total_hours > 8 THEN
|
||||
SET v_status = 'overtime';
|
||||
SET v_has_issues = FALSE;
|
||||
ELSEIF v_total_hours = 8 THEN
|
||||
SET v_status = 'complete';
|
||||
SET v_has_issues = FALSE;
|
||||
ELSEIF v_total_hours > 0 THEN
|
||||
SET v_status = 'partial';
|
||||
SET v_has_issues = TRUE;
|
||||
ELSE
|
||||
SET v_status = 'incomplete';
|
||||
SET v_has_issues = TRUE;
|
||||
END IF;
|
||||
|
||||
-- 데이터 업서트
|
||||
INSERT INTO monthly_worker_status (
|
||||
year, month, worker_id, date,
|
||||
total_work_hours, actual_work_hours, vacation_hours,
|
||||
total_work_count, regular_work_count, error_work_count,
|
||||
work_status, has_vacation, has_error, has_issues
|
||||
) VALUES (
|
||||
v_year, v_month, p_worker_id, p_date,
|
||||
v_total_hours, v_actual_hours, v_vacation_hours,
|
||||
v_total_count, v_regular_count, v_error_count,
|
||||
v_status, v_has_vacation, v_has_error, v_has_issues
|
||||
) ON DUPLICATE KEY UPDATE
|
||||
total_work_hours = v_total_hours,
|
||||
actual_work_hours = v_actual_hours,
|
||||
vacation_hours = v_vacation_hours,
|
||||
total_work_count = v_total_count,
|
||||
regular_work_count = v_regular_count,
|
||||
error_work_count = v_error_count,
|
||||
work_status = v_status,
|
||||
has_vacation = v_has_vacation,
|
||||
has_error = v_has_error,
|
||||
has_issues = v_has_issues,
|
||||
last_updated = CURRENT_TIMESTAMP;
|
||||
|
||||
-- 일별 요약도 업데이트
|
||||
CALL UpdateDailySummary(p_date);
|
||||
END$$
|
||||
|
||||
-- 일별 요약 업데이트 함수
|
||||
CREATE OR REPLACE PROCEDURE UpdateDailySummary(
|
||||
IN p_date DATE
|
||||
)
|
||||
BEGIN
|
||||
DECLARE v_year INT;
|
||||
DECLARE v_month INT;
|
||||
|
||||
SET v_year = YEAR(p_date);
|
||||
SET v_month = MONTH(p_date);
|
||||
|
||||
INSERT INTO monthly_summary (
|
||||
year, month, date,
|
||||
total_workers, working_workers,
|
||||
incomplete_workers, partial_workers, complete_workers,
|
||||
overtime_workers, vacation_workers, error_workers,
|
||||
total_work_hours, total_work_count, total_error_count,
|
||||
has_issues, has_errors
|
||||
)
|
||||
SELECT
|
||||
v_year, v_month, p_date,
|
||||
COUNT(*) as total_workers,
|
||||
COUNT(CASE WHEN work_status != 'incomplete' THEN 1 END) as working_workers,
|
||||
COUNT(CASE WHEN work_status = 'incomplete' THEN 1 END) as incomplete_workers,
|
||||
COUNT(CASE WHEN work_status = 'partial' THEN 1 END) as partial_workers,
|
||||
COUNT(CASE WHEN work_status IN ('complete') THEN 1 END) as complete_workers,
|
||||
COUNT(CASE WHEN work_status = 'overtime' THEN 1 END) as overtime_workers,
|
||||
COUNT(CASE WHEN work_status LIKE 'vacation%' THEN 1 END) as vacation_workers,
|
||||
COUNT(CASE WHEN work_status = 'error' THEN 1 END) as error_workers,
|
||||
SUM(total_work_hours) as total_work_hours,
|
||||
SUM(total_work_count) as total_work_count,
|
||||
SUM(error_work_count) as total_error_count,
|
||||
MAX(has_issues) as has_issues,
|
||||
MAX(has_error) as has_errors
|
||||
FROM monthly_worker_status
|
||||
WHERE date = p_date
|
||||
ON DUPLICATE KEY UPDATE
|
||||
total_workers = VALUES(total_workers),
|
||||
working_workers = VALUES(working_workers),
|
||||
incomplete_workers = VALUES(incomplete_workers),
|
||||
partial_workers = VALUES(partial_workers),
|
||||
complete_workers = VALUES(complete_workers),
|
||||
overtime_workers = VALUES(overtime_workers),
|
||||
vacation_workers = VALUES(vacation_workers),
|
||||
error_workers = VALUES(error_workers),
|
||||
total_work_hours = VALUES(total_work_hours),
|
||||
total_work_count = VALUES(total_work_count),
|
||||
total_error_count = VALUES(total_error_count),
|
||||
has_issues = VALUES(has_issues),
|
||||
has_errors = VALUES(has_errors),
|
||||
last_updated = CURRENT_TIMESTAMP;
|
||||
END$$
|
||||
|
||||
DELIMITER ;
|
||||
@@ -0,0 +1,36 @@
|
||||
-- 008_create_update_triggers.sql
|
||||
-- 작업보고서 변경 시 월별 집계 자동 업데이트 트리거
|
||||
|
||||
DELIMITER $$
|
||||
|
||||
-- 작업보고서 INSERT 트리거
|
||||
CREATE OR REPLACE TRIGGER tr_daily_work_reports_insert
|
||||
AFTER INSERT ON daily_work_reports
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
CALL UpdateMonthlyWorkerStatus(NEW.report_date, NEW.worker_id);
|
||||
END$$
|
||||
|
||||
-- 작업보고서 UPDATE 트리거
|
||||
CREATE OR REPLACE TRIGGER tr_daily_work_reports_update
|
||||
AFTER UPDATE ON daily_work_reports
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
-- 기존 날짜 업데이트
|
||||
CALL UpdateMonthlyWorkerStatus(OLD.report_date, OLD.worker_id);
|
||||
|
||||
-- 새 날짜가 다르면 새 날짜도 업데이트
|
||||
IF OLD.report_date != NEW.report_date OR OLD.worker_id != NEW.worker_id THEN
|
||||
CALL UpdateMonthlyWorkerStatus(NEW.report_date, NEW.worker_id);
|
||||
END IF;
|
||||
END$$
|
||||
|
||||
-- 작업보고서 DELETE 트리거
|
||||
CREATE OR REPLACE TRIGGER tr_daily_work_reports_delete
|
||||
AFTER DELETE ON daily_work_reports
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
CALL UpdateMonthlyWorkerStatus(OLD.report_date, OLD.worker_id);
|
||||
END$$
|
||||
|
||||
DELIMITER ;
|
||||
@@ -0,0 +1,67 @@
|
||||
-- 009_add_overtime_warning_columns.sql
|
||||
-- monthly_summary 테이블에 12시간 초과(확인필요) 상태 컬럼 추가
|
||||
|
||||
-- monthly_summary 테이블에 컬럼 추가
|
||||
ALTER TABLE monthly_summary
|
||||
ADD COLUMN overtime_warning_workers INT DEFAULT 0 COMMENT '확인필요(12시간초과) 작업자 수' AFTER error_workers,
|
||||
ADD COLUMN has_overtime_warning BOOLEAN DEFAULT FALSE COMMENT '확인필요 상태 있음' AFTER has_errors;
|
||||
|
||||
-- UpdateDailySummary 프로시저 업데이트
|
||||
DROP PROCEDURE IF EXISTS UpdateDailySummary;
|
||||
DELIMITER //
|
||||
CREATE PROCEDURE UpdateDailySummary(
|
||||
IN p_date DATE
|
||||
)
|
||||
BEGIN
|
||||
DECLARE v_year INT;
|
||||
DECLARE v_month INT;
|
||||
|
||||
SET v_year = YEAR(p_date);
|
||||
SET v_month = MONTH(p_date);
|
||||
|
||||
INSERT INTO monthly_summary (
|
||||
year, month, date,
|
||||
total_workers, working_workers,
|
||||
incomplete_workers, partial_workers, complete_workers,
|
||||
overtime_workers, vacation_workers, error_workers, overtime_warning_workers,
|
||||
total_work_hours, total_work_count, total_error_count,
|
||||
has_issues, has_errors, has_overtime_warning
|
||||
)
|
||||
SELECT
|
||||
v_year, v_month, p_date,
|
||||
COUNT(*) as total_workers,
|
||||
COUNT(CASE WHEN work_status != 'incomplete' THEN 1 END) as working_workers,
|
||||
COUNT(CASE WHEN work_status = 'incomplete' THEN 1 END) as incomplete_workers,
|
||||
COUNT(CASE WHEN work_status = 'partial' THEN 1 END) as partial_workers,
|
||||
COUNT(CASE WHEN work_status IN ('complete', 'overtime', 'vacation-full', 'vacation-half', 'vacation-quarter', 'vacation-half-half') THEN 1 END) as complete_workers,
|
||||
COUNT(CASE WHEN work_status = 'overtime' THEN 1 END) as overtime_workers,
|
||||
COUNT(CASE WHEN work_status LIKE 'vacation%' THEN 1 END) as vacation_workers,
|
||||
COUNT(CASE WHEN work_status = 'error' THEN 1 END) as error_workers,
|
||||
COUNT(CASE WHEN work_status = 'overtime-warning' THEN 1 END) as overtime_warning_workers,
|
||||
SUM(total_work_hours) as total_work_hours,
|
||||
SUM(total_work_count) as total_work_count,
|
||||
SUM(error_work_count) as total_error_count,
|
||||
MAX(has_issues) as has_issues,
|
||||
MAX(has_error) as has_errors,
|
||||
MAX(CASE WHEN work_status = 'overtime-warning' THEN 1 ELSE 0 END) as has_overtime_warning
|
||||
FROM monthly_worker_status
|
||||
WHERE date = p_date
|
||||
ON DUPLICATE KEY UPDATE
|
||||
total_workers = VALUES(total_workers),
|
||||
working_workers = VALUES(working_workers),
|
||||
incomplete_workers = VALUES(incomplete_workers),
|
||||
partial_workers = VALUES(partial_workers),
|
||||
complete_workers = VALUES(complete_workers),
|
||||
overtime_workers = VALUES(overtime_workers),
|
||||
vacation_workers = VALUES(vacation_workers),
|
||||
error_workers = VALUES(error_workers),
|
||||
overtime_warning_workers = VALUES(overtime_warning_workers),
|
||||
total_work_hours = VALUES(total_work_hours),
|
||||
total_work_count = VALUES(total_work_count),
|
||||
total_error_count = VALUES(total_error_count),
|
||||
has_issues = VALUES(has_issues),
|
||||
has_errors = VALUES(has_errors),
|
||||
has_overtime_warning = VALUES(has_overtime_warning),
|
||||
last_updated = CURRENT_TIMESTAMP;
|
||||
END //
|
||||
DELIMITER ;
|
||||
@@ -0,0 +1,22 @@
|
||||
-- 010_add_project_status.sql
|
||||
-- 프로젝트 테이블에 활성화/비활성화 상태 필드 추가
|
||||
|
||||
-- 프로젝트 상태 필드 추가
|
||||
ALTER TABLE projects
|
||||
ADD COLUMN is_active BOOLEAN DEFAULT TRUE COMMENT '프로젝트 활성화 상태 (TRUE: 활성, FALSE: 비활성)';
|
||||
|
||||
-- 프로젝트 완료일 필드 추가 (납품일)
|
||||
ALTER TABLE projects
|
||||
ADD COLUMN completed_date DATE NULL COMMENT '프로젝트 완료일 (납품일)';
|
||||
|
||||
-- 프로젝트 상태 필드 추가 (진행상태)
|
||||
ALTER TABLE projects
|
||||
ADD COLUMN project_status ENUM('planning', 'active', 'completed', 'cancelled') DEFAULT 'active' COMMENT '프로젝트 진행 상태';
|
||||
|
||||
-- 기존 프로젝트들을 모두 활성 상태로 설정
|
||||
UPDATE projects SET is_active = TRUE WHERE is_active IS NULL;
|
||||
|
||||
-- 인덱스 추가 (성능 최적화)
|
||||
CREATE INDEX idx_projects_is_active ON projects(is_active);
|
||||
CREATE INDEX idx_projects_status ON projects(project_status);
|
||||
CREATE INDEX idx_projects_completed_date ON projects(completed_date);
|
||||
30
synology_deployment/api/migrations/011_add_worker_status.sql
Normal file
30
synology_deployment/api/migrations/011_add_worker_status.sql
Normal file
@@ -0,0 +1,30 @@
|
||||
-- 011_add_worker_status.sql
|
||||
-- workers 테이블에 추가 정보 필드 추가
|
||||
|
||||
-- 작업자 상태 필드 수정 (기존 text에서 ENUM으로)
|
||||
ALTER TABLE workers
|
||||
MODIFY COLUMN status ENUM('active', 'inactive') DEFAULT 'active' COMMENT '작업자 상태 (active: 활성, inactive: 비활성)';
|
||||
|
||||
-- 작업자 추가 정보 필드들 추가
|
||||
ALTER TABLE workers
|
||||
ADD COLUMN phone_number VARCHAR(20) NULL COMMENT '전화번호';
|
||||
|
||||
ALTER TABLE workers
|
||||
ADD COLUMN email VARCHAR(100) NULL COMMENT '이메일';
|
||||
|
||||
ALTER TABLE workers
|
||||
ADD COLUMN hire_date DATE NULL COMMENT '입사일';
|
||||
|
||||
ALTER TABLE workers
|
||||
ADD COLUMN department VARCHAR(100) NULL COMMENT '부서';
|
||||
|
||||
ALTER TABLE workers
|
||||
ADD COLUMN notes TEXT NULL COMMENT '비고';
|
||||
|
||||
-- 기존 작업자들을 모두 활성 상태로 설정
|
||||
UPDATE workers SET status = 'active' WHERE status IS NULL;
|
||||
|
||||
-- 인덱스 추가 (성능 최적화)
|
||||
CREATE INDEX idx_workers_status ON workers(status);
|
||||
CREATE INDEX idx_workers_job_type ON workers(job_type);
|
||||
CREATE INDEX idx_workers_hire_date ON workers(hire_date);
|
||||
4567
synology_deployment/api/migrations/01_complete_data.sql
Normal file
4567
synology_deployment/api/migrations/01_complete_data.sql
Normal file
File diff suppressed because it is too large
Load Diff
4567
synology_deployment/api/migrations/99_restore_data.sql
Normal file
4567
synology_deployment/api/migrations/99_restore_data.sql
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user