-- 2026-06-17 薪酬考勤完整模块升级脚本。
-- Execute with:
--   mysql -h localhost -P 3306 -u root -p12345678 financial_system < financial_system/database/sql/upgrade_20260617_payroll_modules.sql

USE `financial_system`;

CREATE TABLE IF NOT EXISTS `departments` (
  `id` INT NOT NULL AUTO_INCREMENT COMMENT '部门主键ID',
  `parent_id` INT NULL COMMENT '父级部门ID，顶级部门为空',
  `department_code` VARCHAR(64) NOT NULL COMMENT '部门编码，全局唯一',
  `name` VARCHAR(128) NOT NULL COMMENT '部门名称',
  `sort_order` INT NOT NULL DEFAULT 0 COMMENT '排序号，越小越靠前',
  `is_active` BOOL NOT NULL DEFAULT TRUE COMMENT '是否启用',
  `remark` TEXT NOT NULL COMMENT '部门备注',
  `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`id`),
  UNIQUE KEY `ix_departments_department_code` (`department_code`),
  UNIQUE KEY `ix_departments_name` (`name`),
  KEY `ix_departments_parent_id` (`parent_id`),
  KEY `ix_departments_is_active` (`is_active`),
  CONSTRAINT `fk_departments_parent_id` FOREIGN KEY (`parent_id`) REFERENCES `departments` (`id`) ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
  COMMENT='部门表，维护组织架构中的部门及上下级关系';

CREATE TABLE IF NOT EXISTS `positions` (
  `id` INT NOT NULL AUTO_INCREMENT COMMENT '岗位主键ID',
  `department_id` INT NOT NULL COMMENT '关联部门ID',
  `position_code` VARCHAR(64) NOT NULL COMMENT '岗位编码，全局唯一',
  `name` VARCHAR(128) NOT NULL COMMENT '岗位名称',
  `sort_order` INT NOT NULL DEFAULT 0 COMMENT '排序号，越小越靠前',
  `is_active` BOOL NOT NULL DEFAULT TRUE COMMENT '是否启用',
  `remark` TEXT NOT NULL COMMENT '岗位备注',
  `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`id`),
  UNIQUE KEY `ix_positions_position_code` (`position_code`),
  UNIQUE KEY `uq_positions_department_name` (`department_id`, `name`),
  KEY `ix_positions_department_id` (`department_id`),
  KEY `ix_positions_name` (`name`),
  KEY `ix_positions_is_active` (`is_active`),
  CONSTRAINT `fk_positions_department_id` FOREIGN KEY (`department_id`) REFERENCES `departments` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
  COMMENT='岗位表，维护部门下的职位/岗位';

SET @has_position_department_name_index := (
  SELECT COUNT(*) FROM INFORMATION_SCHEMA.STATISTICS
  WHERE TABLE_SCHEMA = DATABASE()
    AND TABLE_NAME = 'positions'
    AND INDEX_NAME = 'uq_positions_department_name'
);
SET @ddl := IF(@has_position_department_name_index = 0,
  'ALTER TABLE `positions` ADD UNIQUE KEY `uq_positions_department_name` (`department_id`, `name`)',
  'SELECT 1'
);
PREPARE stmt FROM @ddl;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

DROP TEMPORARY TABLE IF EXISTS `tmp_organization_departments`;
CREATE TEMPORARY TABLE `tmp_organization_departments` (
  `department_code` VARCHAR(64) NOT NULL,
  `name` VARCHAR(128) NOT NULL,
  `parent_name` VARCHAR(128) NULL,
  `sort_order` INT NOT NULL,
  `remark` VARCHAR(255) NOT NULL
) ENGINE=MEMORY;

INSERT INTO `tmp_organization_departments`
(`department_code`, `name`, `parent_name`, `sort_order`, `remark`) VALUES
('ORG001', '总经办', NULL, 1, '系统初始化部门'),
('ORG002', '行政人事部', NULL, 2, '系统初始化部门'),
('ORG003', '财务部', NULL, 3, '系统初始化部门'),
('ORG004', '订单部', NULL, 4, '系统初始化部门'),
('ORG005', '工程部', NULL, 5, '系统根据工程部子部门自动补齐的父级部门'),
('ORG006', '工程部-安装队', '工程部', 6, '系统初始化部门'),
('ORG007', '工程部-项目预算', '工程部', 7, '系统初始化部门'),
('ORG008', '杭州运营中心', NULL, 8, '系统根据杭州运营中心子部门自动补齐的父级部门'),
('ORG009', '杭州运营中心-销售部', '杭州运营中心', 9, '系统初始化部门'),
('ORG010', '华南运营中心', NULL, 10, '系统初始化部门'),
('ORG011', '华中运营中心', NULL, 11, '系统初始化部门'),
('ORG012', '生产中心', NULL, 12, '系统初始化部门'),
('ORG013', '生产中心-采购部', '生产中心', 13, '系统初始化部门'),
('ORG014', '生产中心-仓库', '生产中心', 14, '系统初始化部门'),
('ORG015', '生产中心-品管部', '生产中心', 15, '系统初始化部门'),
('ORG016', '生产中心-生产部', '生产中心', 16, '系统初始化部门'),
('ORG017', '西南运营中心', NULL, 17, '系统初始化部门'),
('ORG018', '西南运营中心-办事处', '西南运营中心', 18, '系统初始化部门'),
('ORG019', '西南运营中心-销售部', '西南运营中心', 19, '系统初始化部门');

INSERT INTO `departments` (`department_code`, `name`, `sort_order`, `is_active`, `remark`)
SELECT `department_code`, `name`, `sort_order`, TRUE, `remark`
FROM `tmp_organization_departments`
ON DUPLICATE KEY UPDATE
  `department_code` = VALUES(`department_code`),
  `sort_order` = VALUES(`sort_order`),
  `is_active` = VALUES(`is_active`),
  `remark` = VALUES(`remark`);

UPDATE `departments` child
JOIN `tmp_organization_departments` seed ON seed.name = child.name
LEFT JOIN `departments` parent ON parent.name = seed.parent_name
SET child.parent_id = parent.id;

DROP TEMPORARY TABLE IF EXISTS `tmp_organization_positions`;
CREATE TEMPORARY TABLE `tmp_organization_positions` (
  `department_name` VARCHAR(128) NOT NULL,
  `position_code` VARCHAR(64) NOT NULL,
  `name` VARCHAR(128) NOT NULL,
  `sort_order` INT NOT NULL
) ENGINE=MEMORY;

INSERT INTO `tmp_organization_positions`
(`department_name`, `position_code`, `name`, `sort_order`) VALUES
('总经办', 'POS001', '总经理', 1),
('总经办', 'POS002', '副总经理', 2),
('总经办', 'POS003', '总经理助理', 3),
('行政人事部', 'POS004', '人事经理', 1),
('行政人事部', 'POS005', '人事专员', 2),
('财务部', 'POS006', '财务', 1),
('财务部', 'POS007', '出纳专员', 2),
('订单部', 'POS008', '销售助理', 1),
('订单部', 'POS009', '订单助理', 2),
('工程部-安装队', 'POS010', '经理助理', 1),
('工程部-安装队', 'POS011', '安装师傅', 2),
('工程部-安装队', 'POS012', '项目经理', 3),
('工程部-项目预算', 'POS013', '项目预算', 1),
('杭州运营中心-销售部', 'POS014', '销售总监', 1),
('杭州运营中心-销售部', 'POS015', '销售', 2),
('华南运营中心', 'POS016', '销售总监', 1),
('华中运营中心', 'POS017', '销售总监', 1),
('生产中心', 'POS018', '机械工程师', 1),
('生产中心-采购部', 'POS019', '采购', 1),
('生产中心-仓库', 'POS020', '仓库', 1),
('生产中心-仓库', 'POS021', '仓库物料员', 2),
('生产中心-品管部', 'POS022', '品管', 1),
('生产中心-生产部', 'POS023', '焊接师傅', 1),
('生产中心-生产部', 'POS024', '普工', 2),
('生产中心-生产部', 'POS025', '技工', 3),
('西南运营中心', 'POS026', '销售总监', 1),
('西南运营中心-办事处', 'POS027', '经理助理', 1),
('西南运营中心-销售部', 'POS028', '销售工程师', 1);

INSERT INTO `positions` (`department_id`, `position_code`, `name`, `sort_order`, `is_active`, `remark`)
SELECT d.id, p.position_code, p.name, p.sort_order, TRUE, '系统初始化岗位'
FROM `tmp_organization_positions` p
JOIN `departments` d ON d.name = p.department_name
ON DUPLICATE KEY UPDATE
  `department_id` = VALUES(`department_id`),
  `position_code` = VALUES(`position_code`),
  `name` = VALUES(`name`),
  `sort_order` = VALUES(`sort_order`),
  `is_active` = VALUES(`is_active`),
  `remark` = VALUES(`remark`);

DROP TEMPORARY TABLE IF EXISTS `tmp_organization_positions`;
DROP TEMPORARY TABLE IF EXISTS `tmp_organization_departments`;

ALTER TABLE `salary_profiles`
  ADD COLUMN IF NOT EXISTS `salary_mode` VARCHAR(32) NOT NULL DEFAULT 'monthly' COMMENT '薪资模式：monthly包月、hourly计时、piecework计件、probation试用期' AFTER `employee_id`,
  ADD COLUMN IF NOT EXISTS `hourly_rate` FLOAT NOT NULL DEFAULT 0 COMMENT '计时工资小时单价' AFTER `base_salary`,
  ADD COLUMN IF NOT EXISTS `piece_quantity` FLOAT NOT NULL DEFAULT 0 COMMENT '计件数量' AFTER `hourly_rate`,
  ADD COLUMN IF NOT EXISTS `piece_unit_price` FLOAT NOT NULL DEFAULT 0 COMMENT '计件单价' AFTER `piece_quantity`,
  ADD COLUMN IF NOT EXISTS `probation_type` VARCHAR(32) NOT NULL DEFAULT 'ratio' COMMENT '试用期计算方式：ratio固定比例、fixed固定金额' AFTER `piece_unit_price`,
  ADD COLUMN IF NOT EXISTS `probation_ratio` FLOAT NOT NULL DEFAULT 1 COMMENT '试用期工资比例' AFTER `probation_type`,
  ADD COLUMN IF NOT EXISTS `probation_salary` FLOAT NOT NULL DEFAULT 0 COMMENT '试用期固定工资' AFTER `probation_ratio`,
  ADD COLUMN IF NOT EXISTS `weekend_overtime_rate` FLOAT NOT NULL DEFAULT 0 COMMENT '周末加班费小时单价' AFTER `overtime_rate`,
  ADD COLUMN IF NOT EXISTS `holiday_overtime_rate` FLOAT NOT NULL DEFAULT 0 COMMENT '法定节假日加班费小时单价' AFTER `weekend_overtime_rate`;

ALTER TABLE `payroll_results`
  ADD COLUMN IF NOT EXISTS `salary_month` VARCHAR(7) NOT NULL DEFAULT '' COMMENT '工资月份，格式YYYY-MM' AFTER `attendance_group`,
  ADD COLUMN IF NOT EXISTS `salary_mode` VARCHAR(32) NOT NULL DEFAULT 'monthly' COMMENT '薪资模式快照' AFTER `salary_month`,
  ADD COLUMN IF NOT EXISTS `attendance_days` FLOAT NOT NULL DEFAULT 0 COMMENT '出勤天数' AFTER `salary_mode`,
  ADD COLUMN IF NOT EXISTS `absence_days` FLOAT NOT NULL DEFAULT 0 COMMENT '缺勤天数' AFTER `attendance_days`,
  ADD COLUMN IF NOT EXISTS `actual_work_hours` FLOAT NOT NULL DEFAULT 0 COMMENT '实际工作工时' AFTER `absence_days`,
  ADD COLUMN IF NOT EXISTS `workday_overtime_hours` FLOAT NOT NULL DEFAULT 0 COMMENT '工作日剩余可计费加班工时' AFTER `remaining_overtime_hours`,
  ADD COLUMN IF NOT EXISTS `weekend_overtime_hours` FLOAT NOT NULL DEFAULT 0 COMMENT '周末剩余可计费加班工时' AFTER `workday_overtime_hours`,
  ADD COLUMN IF NOT EXISTS `holiday_overtime_hours` FLOAT NOT NULL DEFAULT 0 COMMENT '法定节假日剩余可计费加班工时' AFTER `weekend_overtime_hours`,
  ADD COLUMN IF NOT EXISTS `base_pay` FLOAT NULL COMMENT '按薪资模式计算后的基础工资' AFTER `base_salary`,
  ADD COLUMN IF NOT EXISTS `weekend_overtime_rate` FLOAT NOT NULL DEFAULT 0 COMMENT '周末加班小时单价' AFTER `overtime_rate`,
  ADD COLUMN IF NOT EXISTS `holiday_overtime_rate` FLOAT NOT NULL DEFAULT 0 COMMENT '法定节假日加班小时单价' AFTER `weekend_overtime_rate`;

CREATE TABLE IF NOT EXISTS `attendance_record` (
  `id` INT NOT NULL AUTO_INCREMENT COMMENT '考勤记录主键ID',
  `job_id` VARCHAR(32) NULL COMMENT '关联工资计算任务ID',
  `employee_id` INT NULL COMMENT '关联员工ID，未匹配员工时为空',
  `employee_no` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '员工编号快照',
  `employee_name` VARCHAR(128) NOT NULL COMMENT '员工姓名快照',
  `department` VARCHAR(128) NOT NULL DEFAULT '' COMMENT '部门名称快照',
  `work_date` DATE NOT NULL COMMENT '考勤日期',
  `first_punch` VARCHAR(5) NOT NULL DEFAULT '' COMMENT '上班打卡时间HH:MM',
  `last_punch` VARCHAR(5) NOT NULL DEFAULT '' COMMENT '下班打卡时间HH:MM',
  `attendance_status` VARCHAR(32) NOT NULL DEFAULT 'present' COMMENT '考勤状态：present出勤、absent缺勤、leave请假、missing缺卡',
  `late_minutes` INT NOT NULL DEFAULT 0 COMMENT '当日迟到分钟合计',
  `missing_card_count` INT NOT NULL DEFAULT 0 COMMENT '当日缺卡次数',
  `leave_hours` FLOAT NOT NULL DEFAULT 0 COMMENT '当日请假或调休工时',
  `overtime_hours` FLOAT NOT NULL DEFAULT 0 COMMENT '当日打卡推算加班工时',
  `raw_text` TEXT NOT NULL COMMENT '原始考勤单元格内容',
  `source_type` VARCHAR(32) NOT NULL DEFAULT 'excel' COMMENT '来源：excel或dingtalk',
  `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  PRIMARY KEY (`id`),
  KEY `ix_attendance_record_job_id` (`job_id`),
  KEY `ix_attendance_record_employee_id` (`employee_id`),
  KEY `ix_attendance_record_employee_no` (`employee_no`),
  KEY `ix_attendance_record_employee_name` (`employee_name`),
  KEY `ix_attendance_record_work_date` (`work_date`),
  KEY `ix_attendance_record_attendance_status` (`attendance_status`),
  CONSTRAINT `fk_attendance_record_job_id` FOREIGN KEY (`job_id`) REFERENCES `payroll_jobs` (`id`) ON DELETE SET NULL,
  CONSTRAINT `fk_attendance_record_employee_id` FOREIGN KEY (`employee_id`) REFERENCES `employees` (`id`) ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
  COMMENT='考勤记录表，保存标准化后的每日打卡、迟到、缺卡、请假和加班工时';

CREATE TABLE IF NOT EXISTS `leave_record` (
  `id` INT NOT NULL AUTO_INCREMENT COMMENT '请假记录主键ID',
  `job_id` VARCHAR(32) NULL COMMENT '关联工资计算任务ID',
  `employee_id` INT NULL COMMENT '关联员工ID，未匹配员工时为空',
  `employee_no` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '员工编号快照',
  `employee_name` VARCHAR(128) NOT NULL COMMENT '员工姓名快照',
  `leave_type` VARCHAR(32) NOT NULL COMMENT '请假类型',
  `start_text` VARCHAR(32) NOT NULL DEFAULT '' COMMENT '原始开始时间文本',
  `end_text` VARCHAR(32) NOT NULL DEFAULT '' COMMENT '原始结束时间文本',
  `hours` FLOAT NOT NULL DEFAULT 0 COMMENT '请假工时',
  `source_type` VARCHAR(32) NOT NULL DEFAULT 'excel' COMMENT '来源：excel或dingtalk',
  `status` VARCHAR(32) NOT NULL DEFAULT 'approved' COMMENT '状态：approved已生效',
  `remark` TEXT NOT NULL COMMENT '备注',
  `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  PRIMARY KEY (`id`),
  KEY `ix_leave_record_job_id` (`job_id`),
  KEY `ix_leave_record_employee_id` (`employee_id`),
  KEY `ix_leave_record_employee_no` (`employee_no`),
  KEY `ix_leave_record_employee_name` (`employee_name`),
  KEY `ix_leave_record_leave_type` (`leave_type`),
  CONSTRAINT `fk_leave_record_job_id` FOREIGN KEY (`job_id`) REFERENCES `payroll_jobs` (`id`) ON DELETE SET NULL,
  CONSTRAINT `fk_leave_record_employee_id` FOREIGN KEY (`employee_id`) REFERENCES `employees` (`id`) ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
  COMMENT='请假记录表，保存事假、病假、年假、调休等统一工时记录';

CREATE TABLE IF NOT EXISTS `overtime_record` (
  `id` INT NOT NULL AUTO_INCREMENT COMMENT '加班记录主键ID',
  `job_id` VARCHAR(32) NULL COMMENT '关联工资计算任务ID',
  `employee_id` INT NULL COMMENT '关联员工ID，未匹配员工时为空',
  `employee_no` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '员工编号快照',
  `employee_name` VARCHAR(128) NOT NULL COMMENT '员工姓名快照',
  `work_date` DATE NOT NULL COMMENT '加班日期',
  `overtime_type` VARCHAR(32) NOT NULL DEFAULT 'workday' COMMENT '加班类型：workday工作日、weekend周末、holiday法定节假日',
  `hours` FLOAT NOT NULL DEFAULT 0 COMMENT '加班工时',
  `rate` FLOAT NOT NULL DEFAULT 0 COMMENT '加班小时单价',
  `amount` FLOAT NOT NULL DEFAULT 0 COMMENT '加班费金额',
  `source_type` VARCHAR(32) NOT NULL DEFAULT 'excel' COMMENT '来源：excel或dingtalk',
  `status` VARCHAR(32) NOT NULL DEFAULT 'calculated' COMMENT '状态：calculated已计算',
  `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  PRIMARY KEY (`id`),
  KEY `ix_overtime_record_job_id` (`job_id`),
  KEY `ix_overtime_record_employee_id` (`employee_id`),
  KEY `ix_overtime_record_employee_no` (`employee_no`),
  KEY `ix_overtime_record_employee_name` (`employee_name`),
  KEY `ix_overtime_record_work_date` (`work_date`),
  KEY `ix_overtime_record_overtime_type` (`overtime_type`),
  CONSTRAINT `fk_overtime_record_job_id` FOREIGN KEY (`job_id`) REFERENCES `payroll_jobs` (`id`) ON DELETE SET NULL,
  CONSTRAINT `fk_overtime_record_employee_id` FOREIGN KEY (`employee_id`) REFERENCES `employees` (`id`) ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
  COMMENT='加班记录表，保存每日加班工时、加班类型、单价和金额';

CREATE TABLE IF NOT EXISTS `commission_record` (
  `id` INT NOT NULL AUTO_INCREMENT COMMENT '提成记录主键ID',
  `employee_id` INT NOT NULL COMMENT '关联员工ID',
  `commission_month` VARCHAR(7) NOT NULL COMMENT '提成月份，格式YYYY-MM',
  `commission_type` VARCHAR(64) NOT NULL DEFAULT '销售提成' COMMENT '提成类型',
  `amount` FLOAT NOT NULL DEFAULT 0 COMMENT '提成金额',
  `source_type` VARCHAR(32) NOT NULL DEFAULT 'manual' COMMENT '来源：manual手工、excel导入',
  `business_ref` VARCHAR(128) NOT NULL DEFAULT '' COMMENT '业务单号或来源标识',
  `remark` TEXT NOT NULL COMMENT '备注',
  `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`id`),
  KEY `ix_commission_record_employee_id` (`employee_id`),
  KEY `ix_commission_record_commission_month` (`commission_month`),
  CONSTRAINT `fk_commission_record_employee_id` FOREIGN KEY (`employee_id`) REFERENCES `employees` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
  COMMENT='提成记录表，保存销售提成、项目奖金、绩效奖励等月度金额';

CREATE TABLE IF NOT EXISTS `salary_record` (
  `id` INT NOT NULL AUTO_INCREMENT COMMENT '工资记录主键ID',
  `job_id` VARCHAR(32) NULL COMMENT '关联工资计算任务ID',
  `employee_id` INT NULL COMMENT '关联员工ID，未匹配员工时为空',
  `employee_no` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '员工编号快照',
  `employee_name` VARCHAR(128) NOT NULL COMMENT '员工姓名快照',
  `department` VARCHAR(128) NOT NULL DEFAULT '' COMMENT '部门名称快照',
  `salary_month` VARCHAR(7) NOT NULL COMMENT '工资月份，格式YYYY-MM',
  `salary_mode` VARCHAR(32) NOT NULL DEFAULT 'monthly' COMMENT '薪资模式快照',
  `base_pay` FLOAT NOT NULL DEFAULT 0 COMMENT '基础工资金额',
  `commission_amount` FLOAT NOT NULL DEFAULT 0 COMMENT '提成金额',
  `overtime_pay` FLOAT NOT NULL DEFAULT 0 COMMENT '加班费金额',
  `deduction_amount` FLOAT NOT NULL DEFAULT 0 COMMENT '扣款合计金额',
  `gross_salary` FLOAT NOT NULL DEFAULT 0 COMMENT '应发工资',
  `net_salary` FLOAT NOT NULL DEFAULT 0 COMMENT '实发工资',
  `status` VARCHAR(32) NOT NULL DEFAULT 'calculated' COMMENT '状态：calculated已计算',
  `remark` TEXT NOT NULL COMMENT '备注',
  `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`id`),
  KEY `ix_salary_record_job_id` (`job_id`),
  KEY `ix_salary_record_employee_id` (`employee_id`),
  KEY `ix_salary_record_employee_no` (`employee_no`),
  KEY `ix_salary_record_employee_name` (`employee_name`),
  KEY `ix_salary_record_department` (`department`),
  KEY `ix_salary_record_salary_month` (`salary_month`),
  CONSTRAINT `fk_salary_record_job_id` FOREIGN KEY (`job_id`) REFERENCES `payroll_jobs` (`id`) ON DELETE SET NULL,
  CONSTRAINT `fk_salary_record_employee_id` FOREIGN KEY (`employee_id`) REFERENCES `employees` (`id`) ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
  COMMENT='工资记录表，保存员工月度工资汇总结果';

CREATE TABLE IF NOT EXISTS `salary_detail` (
  `id` INT NOT NULL AUTO_INCREMENT COMMENT '工资明细主键ID',
  `salary_record_id` INT NOT NULL COMMENT '关联工资记录ID',
  `item_type` VARCHAR(32) NOT NULL COMMENT '工资项类型：earning收入、deduction扣款、stat统计',
  `item_name` VARCHAR(64) NOT NULL COMMENT '工资项名称',
  `amount` FLOAT NOT NULL DEFAULT 0 COMMENT '金额',
  `quantity` FLOAT NOT NULL DEFAULT 0 COMMENT '数量或工时',
  `unit_price` FLOAT NOT NULL DEFAULT 0 COMMENT '单价',
  `remark` TEXT NOT NULL COMMENT '备注',
  `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  PRIMARY KEY (`id`),
  KEY `ix_salary_detail_salary_record_id` (`salary_record_id`),
  KEY `ix_salary_detail_item_type` (`item_type`),
  CONSTRAINT `fk_salary_detail_salary_record_id` FOREIGN KEY (`salary_record_id`) REFERENCES `salary_record` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
  COMMENT='工资明细表，保存工资记录下的每个工资项';

CREATE TABLE IF NOT EXISTS `salary_config` (
  `id` INT NOT NULL AUTO_INCREMENT COMMENT '配置主键ID',
  `config_key` VARCHAR(128) NOT NULL COMMENT '配置键',
  `config_name` VARCHAR(128) NOT NULL COMMENT '配置名称',
  `config_group` VARCHAR(64) NOT NULL COMMENT '配置分组',
  `config_value` TEXT NOT NULL COMMENT '配置值，按value_type解析',
  `value_type` VARCHAR(32) NOT NULL DEFAULT 'string' COMMENT '值类型：string、number、integer、boolean、json',
  `is_enabled` BOOL NOT NULL DEFAULT TRUE COMMENT '是否启用',
  `remark` TEXT NOT NULL COMMENT '配置说明',
  `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`id`),
  UNIQUE KEY `ix_salary_config_config_key` (`config_key`),
  KEY `ix_salary_config_config_group` (`config_group`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
  COMMENT='系统配置表，保存可后台维护的考勤、薪资和集成规则';

INSERT INTO `salary_config` (`config_key`, `config_name`, `config_group`, `config_value`, `value_type`, `is_enabled`, `remark`) VALUES
('attendance.on_work_time', '上班时间', 'attendance', '08:30', 'string', TRUE, '用于迟到识别，格式HH:MM'),
('attendance.off_work_time', '下班时间', 'attendance', '17:00', 'string', TRUE, '加班按下班打卡超过该时间后向下取整'),
('attendance.overtime_round_minutes', '加班取整分钟', 'attendance', '60', 'integer', TRUE, '例如60表示20:30按3小时计算'),
('attendance.standard_daily_hours', '标准日工时', 'attendance', '8', 'number', TRUE, '计时工资按出勤天数折算工时'),
('attendance.minor_late_minutes', '轻微迟到分钟', 'attendance', '5', 'integer', TRUE, '小于等于该分钟数按轻微迟到统计'),
('attendance.minor_late_free_times', '轻微迟到免扣次数', 'attendance', '3', 'integer', TRUE, '5分钟内迟到3次内合格，超过后按次扣款'),
('attendance.late_penalty', '迟到扣款', 'attendance', '30', 'number', TRUE, '每次计扣迟到扣款金额'),
('attendance.missing_card_penalty', '缺卡扣款', 'attendance', '20', 'number', TRUE, '每次缺卡扣款金额'),
('attendance.weekend_days', '周末星期', 'attendance', '[5, 6]', 'json', TRUE, 'Python weekday：周一0，周六5，周日6'),
('attendance.legal_holidays', '法定节假日', 'attendance', '[]', 'json', TRUE, '日期数组，例如["2026-10-01"]'),
('attendance.leave_keywords', '请假关键字', 'attendance', '["调休", "请假", "事假", "病假", "年假", "婚假", "产假", "陪产假", "丧假"]', 'json', TRUE, '从钉钉单元格识别请假/调休类型'),
('payroll.default_overtime_rate', '工作日加班单价', 'payroll', '0', 'number', TRUE, '未维护员工单价时使用'),
('payroll.default_weekend_overtime_rate', '周末加班单价', 'payroll', '0', 'number', TRUE, '未维护员工周末单价时使用'),
('payroll.default_holiday_overtime_rate', '节假日加班单价', 'payroll', '0', 'number', TRUE, '未维护员工节假日单价时使用')
ON DUPLICATE KEY UPDATE `config_key` = VALUES(`config_key`);
