-- Financial System full MySQL initialization script.
-- Execute with:
--   mysql -h localhost -P 3306 -u root -p12345678 < financial_system/database/sql/init_mysql.sql

CREATE DATABASE IF NOT EXISTS `financial_system`
  DEFAULT CHARACTER SET utf8mb4
  DEFAULT COLLATE utf8mb4_unicode_ci;

USE `financial_system`;
SET time_zone = '+08:00';

CREATE TABLE IF NOT EXISTS `users` (
  `id` INT NOT NULL AUTO_INCREMENT COMMENT '用户主键ID',
  `username` VARCHAR(64) NOT NULL COMMENT '登录用户名，全局唯一',
  `display_name` VARCHAR(128) NOT NULL DEFAULT '' COMMENT '用户显示名称',
  `avatar_url` VARCHAR(512) NOT NULL DEFAULT '' COMMENT '用户头像URL或静态资源路径',
  `email` VARCHAR(128) NOT NULL DEFAULT '' COMMENT '用户邮箱',
  `phone` VARCHAR(32) NOT NULL DEFAULT '' COMMENT '用户手机号',
  `department` VARCHAR(128) NOT NULL DEFAULT '' COMMENT '用户所属部门',
  `position_title` VARCHAR(128) NOT NULL DEFAULT '' COMMENT '用户职位或岗位名称',
  `password_hash` VARCHAR(256) NOT NULL COMMENT '密码哈希值，不保存明文密码',
  `role` VARCHAR(32) NOT NULL COMMENT '用户角色：superuser、manager、viewer',
  `is_active` BOOL NOT NULL DEFAULT TRUE 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_users_username` (`username`),
  KEY `ix_users_role` (`role`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
  COMMENT='系统用户表，保存登录账号、角色和启用状态';

SET @has_avatar_url := (
  SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS
  WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'users' AND COLUMN_NAME = 'avatar_url'
);
SET @ddl := IF(@has_avatar_url = 0,
  'ALTER TABLE `users` ADD COLUMN `avatar_url` VARCHAR(512) NOT NULL DEFAULT '''' COMMENT ''用户头像URL或静态资源路径''',
  'SELECT 1'
);
PREPARE stmt FROM @ddl;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

SET @has_email := (
  SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS
  WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'users' AND COLUMN_NAME = 'email'
);
SET @ddl := IF(@has_email = 0,
  'ALTER TABLE `users` ADD COLUMN `email` VARCHAR(128) NOT NULL DEFAULT '''' COMMENT ''用户邮箱''',
  'SELECT 1'
);
PREPARE stmt FROM @ddl;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

SET @has_phone := (
  SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS
  WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'users' AND COLUMN_NAME = 'phone'
);
SET @ddl := IF(@has_phone = 0,
  'ALTER TABLE `users` ADD COLUMN `phone` VARCHAR(32) NOT NULL DEFAULT '''' COMMENT ''用户手机号''',
  'SELECT 1'
);
PREPARE stmt FROM @ddl;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

SET @has_department := (
  SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS
  WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'users' AND COLUMN_NAME = 'department'
);
SET @ddl := IF(@has_department = 0,
  'ALTER TABLE `users` ADD COLUMN `department` VARCHAR(128) NOT NULL DEFAULT '''' COMMENT ''用户所属部门''',
  'SELECT 1'
);
PREPARE stmt FROM @ddl;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

SET @has_position_title := (
  SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS
  WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'users' AND COLUMN_NAME = 'position_title'
);
SET @ddl := IF(@has_position_title = 0,
  'ALTER TABLE `users` ADD COLUMN `position_title` VARCHAR(128) NOT NULL DEFAULT '''' COMMENT ''用户职位或岗位名称''',
  'SELECT 1'
);
PREPARE stmt FROM @ddl;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

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`;

CREATE TABLE IF NOT EXISTS `employees` (
  `id` INT NOT NULL AUTO_INCREMENT COMMENT '员工主键ID',
  `employee_no` VARCHAR(64) NOT NULL COMMENT '员工编号，全局唯一，系统自动生成，默认ZA前缀',
  `name` VARCHAR(128) NOT NULL COMMENT '员工姓名',
  `dingtalk_user_id` VARCHAR(128) NOT NULL DEFAULT '' COMMENT '钉钉用户ID，用于对接钉钉考勤',
  `department` VARCHAR(128) NOT NULL DEFAULT '' COMMENT '部门名称',
  `position` VARCHAR(128) NOT NULL DEFAULT '' COMMENT '岗位名称',
  `phone` VARCHAR(32) NOT NULL DEFAULT '' COMMENT '手机号',
  `employment_status` VARCHAR(32) NOT NULL DEFAULT 'active' COMMENT '员工状态：active在职、inactive离职',
  `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_employees_employee_no` (`employee_no`),
  KEY `ix_employees_name` (`name`),
  KEY `ix_employees_dingtalk_user_id` (`dingtalk_user_id`),
  KEY `ix_employees_employment_status` (`employment_status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
  COMMENT='员工基础档案表，维护员工编号、姓名、部门、岗位和钉钉用户ID';

CREATE TABLE IF NOT EXISTS `salary_profiles` (
  `id` INT NOT NULL AUTO_INCREMENT COMMENT '薪资档案主键ID',
  `employee_id` INT NOT NULL COMMENT '关联员工ID，一名员工一条当前薪资档案',
  `salary_mode` VARCHAR(32) NOT NULL DEFAULT 'monthly' COMMENT '薪资模式：monthly包月、hourly计时、piecework计件、probation试用期',
  `base_salary` FLOAT NOT NULL DEFAULT 0 COMMENT '基础工资或底薪',
  `hourly_rate` FLOAT NOT NULL DEFAULT 0 COMMENT '计时工资小时单价',
  `piece_quantity` FLOAT NOT NULL DEFAULT 0 COMMENT '计件数量',
  `piece_unit_price` FLOAT NOT NULL DEFAULT 0 COMMENT '计件单价',
  `probation_type` VARCHAR(32) NOT NULL DEFAULT 'ratio' COMMENT '试用期计算方式：ratio固定比例、fixed固定金额',
  `probation_ratio` FLOAT NOT NULL DEFAULT 1 COMMENT '试用期工资比例',
  `probation_salary` FLOAT NOT NULL DEFAULT 0 COMMENT '试用期固定工资',
  `commission_amount` FLOAT NOT NULL DEFAULT 0 COMMENT '默认提成金额，月度提成优先维护到commission_record',
  `overtime_rate` FLOAT NOT NULL DEFAULT 0 COMMENT '工作日加班费小时单价，独立于基础工资维护',
  `weekend_overtime_rate` FLOAT NOT NULL DEFAULT 0 COMMENT '周末加班费小时单价',
  `holiday_overtime_rate` FLOAT NOT NULL DEFAULT 0 COMMENT '法定节假日加班费小时单价',
  `effective_month` VARCHAR(7) NOT NULL DEFAULT '' COMMENT '生效月份，格式YYYY-MM；为空表示长期当前档案',
  `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_profiles_employee_id` (`employee_id`),
  KEY `ix_salary_profiles_salary_mode` (`salary_mode`),
  CONSTRAINT `fk_salary_profiles_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 `operation_logs` (
  `id` INT NOT NULL AUTO_INCREMENT COMMENT '日志主键ID',
  `user_id` INT NULL COMMENT '操作用户ID，匿名或用户删除后为空',
  `username` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '操作用户名快照',
  `role` VARCHAR(32) NOT NULL DEFAULT '' COMMENT '操作用户角色快照',
  `module` VARCHAR(64) NOT NULL COMMENT '业务模块，例如auth、payroll、system',
  `action` VARCHAR(128) NOT NULL COMMENT '操作动作编码，例如login、payroll.excel.calculate',
  `target_type` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '操作对象类型，例如user、payroll_job、file',
  `target_id` VARCHAR(128) NOT NULL DEFAULT '' COMMENT '操作对象ID或业务标识',
  `status` VARCHAR(32) NOT NULL COMMENT '操作状态：success或failed',
  `detail` TEXT NOT NULL COMMENT '操作详情或失败原因',
  `ip_address` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '客户端IP地址',
  `user_agent` VARCHAR(512) NOT NULL DEFAULT '' COMMENT '客户端浏览器User-Agent',
  `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '操作时间',
  PRIMARY KEY (`id`),
  KEY `ix_operation_logs_user_id` (`user_id`),
  KEY `ix_operation_logs_username` (`username`),
  KEY `ix_operation_logs_module` (`module`),
  KEY `ix_operation_logs_action` (`action`),
  KEY `ix_operation_logs_status` (`status`),
  KEY `ix_operation_logs_created_at` (`created_at`),
  CONSTRAINT `fk_operation_logs_user_id`
    FOREIGN KEY (`user_id`) REFERENCES `users` (`id`)
    ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
  COMMENT='系统操作日志表，记录用户登录、资料维护、工资计算、下载和系统管理动作';

CREATE TABLE IF NOT EXISTS `payroll_jobs` (
  `id` VARCHAR(32) NOT NULL COMMENT '任务ID，UUID十六进制字符串',
  `source_type` VARCHAR(32) NOT NULL COMMENT '任务来源：excel或dingtalk',
  `status` VARCHAR(32) NOT NULL DEFAULT 'created' COMMENT '任务状态：running、completed、failed',
  `input_file` TEXT NULL COMMENT '上传的原始Excel文件路径',
  `output_file` TEXT NULL COMMENT '导出的工资结果Excel文件路径',
  `employee_count` INT NOT NULL DEFAULT 0 COMMENT '本次任务计算的员工数量',
  `error_message` TEXT 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`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
  COMMENT='工资计算任务表，记录每次Excel或钉钉实时计算任务';

CREATE TABLE IF NOT EXISTS `payroll_results` (
  `id` INT NOT NULL AUTO_INCREMENT COMMENT '结果主键ID',
  `job_id` VARCHAR(32) NOT NULL COMMENT '所属工资计算任务ID',
  `name` VARCHAR(128) NOT NULL COMMENT '员工姓名',
  `department` VARCHAR(128) NOT NULL DEFAULT '' COMMENT '部门名称',
  `position` VARCHAR(128) NOT NULL DEFAULT '' COMMENT '岗位名称',
  `attendance_group` VARCHAR(128) NOT NULL DEFAULT '' COMMENT '考勤组名称',
  `salary_month` VARCHAR(7) NOT NULL DEFAULT '' COMMENT '工资月份，格式YYYY-MM',
  `salary_mode` VARCHAR(32) NOT NULL DEFAULT 'monthly' COMMENT '薪资模式快照',
  `attendance_days` FLOAT NOT NULL DEFAULT 0 COMMENT '出勤天数',
  `absence_days` FLOAT NOT NULL DEFAULT 0 COMMENT '缺勤天数',
  `actual_work_hours` FLOAT NOT NULL DEFAULT 0 COMMENT '实际工作工时',
  `punch_overtime_hours` FLOAT NOT NULL DEFAULT 0 COMMENT '根据下班打卡时间推算的加班工时',
  `leave_hours` FLOAT NOT NULL DEFAULT 0 COMMENT '请假或调休工时',
  `remaining_overtime_hours` FLOAT NOT NULL DEFAULT 0 COMMENT '剩余加班工时：打卡推算加班工时减请假调休工时',
  `workday_overtime_hours` FLOAT NOT NULL DEFAULT 0 COMMENT '工作日剩余可计费加班工时',
  `weekend_overtime_hours` FLOAT NOT NULL DEFAULT 0 COMMENT '周末剩余可计费加班工时',
  `holiday_overtime_hours` FLOAT NOT NULL DEFAULT 0 COMMENT '法定节假日剩余可计费加班工时',
  `minor_late_count` INT NOT NULL DEFAULT 0 COMMENT '5分钟内迟到次数',
  `major_late_count` INT NOT NULL DEFAULT 0 COMMENT '超过5分钟迟到次数',
  `penalized_late_count` INT NOT NULL DEFAULT 0 COMMENT '实际计扣迟到次数',
  `late_deduction` FLOAT NOT NULL DEFAULT 0 COMMENT '迟到扣款金额',
  `missing_card_count` INT NOT NULL DEFAULT 0 COMMENT '缺卡次数',
  `missing_card_deduction` FLOAT NOT NULL DEFAULT 0 COMMENT '缺卡扣款金额',
  `total_deduction` FLOAT NOT NULL DEFAULT 0 COMMENT '扣款合计金额',
  `base_salary` FLOAT NULL COMMENT '员工底薪',
  `base_pay` FLOAT NULL COMMENT '按薪资模式计算后的基础工资',
  `commission_amount` FLOAT NOT NULL DEFAULT 0 COMMENT '手工维护的提成费用',
  `overtime_rate` FLOAT NOT NULL DEFAULT 0 COMMENT '加班小时单价',
  `weekend_overtime_rate` FLOAT NOT NULL DEFAULT 0 COMMENT '周末加班小时单价',
  `holiday_overtime_rate` FLOAT NOT NULL DEFAULT 0 COMMENT '法定节假日加班小时单价',
  `overtime_pay` FLOAT NOT NULL DEFAULT 0 COMMENT '加班费金额',
  `gross_salary` FLOAT NULL COMMENT '应发工资',
  `net_salary` FLOAT NULL COMMENT '实发工资',
  `note` TEXT NOT NULL COMMENT '备注',
  PRIMARY KEY (`id`),
  KEY `ix_payroll_results_job_id` (`job_id`),
  KEY `ix_payroll_results_salary_month` (`salary_month`),
  CONSTRAINT `fk_payroll_results_job_id`
    FOREIGN KEY (`job_id`) REFERENCES `payroll_jobs` (`id`)
    ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
  COMMENT='员工工资计算结果表，保存任务下每个员工的加班、请假、扣款和工资结果';

SET @has_payroll_commission_amount := (
  SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS
  WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'payroll_results' AND COLUMN_NAME = 'commission_amount'
);
SET @ddl := IF(@has_payroll_commission_amount = 0,
  'ALTER TABLE `payroll_results` ADD COLUMN `commission_amount` FLOAT NOT NULL DEFAULT 0 COMMENT ''手工维护的提成费用'' AFTER `base_salary`',
  'SELECT 1'
);
PREPARE stmt FROM @ddl;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

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 `attendance_sync_jobs` (
  `id` VARCHAR(32) NOT NULL COMMENT '同步任务ID，UUID十六进制字符串',
  `source_type` VARCHAR(32) NOT NULL COMMENT '数据来源：dingtalk钉钉、excel表格',
  `sync_mode` VARCHAR(32) NOT NULL DEFAULT 'today' COMMENT '同步模式：today今日、month本月至今、range自定义范围',
  `attendance_date` DATE NULL COMMENT '实时看板对应考勤日期',
  `salary_month` VARCHAR(7) NOT NULL DEFAULT '' COMMENT '工资月份，格式YYYY-MM',
  `start_date` DATE NULL COMMENT '同步开始日期',
  `end_date` DATE NULL COMMENT '同步结束日期',
  `status` VARCHAR(32) NOT NULL DEFAULT 'created' COMMENT '任务状态：created、running、completed、failed',
  `employee_count` INT NOT NULL DEFAULT 0 COMMENT '本次同步涉及员工数量',
  `record_count` INT NOT NULL DEFAULT 0 COMMENT '本次同步获得或解析的考勤记录数量',
  `error_message` TEXT NOT NULL COMMENT '任务失败时的错误信息',
  `created_by` VARCHAR(64) NOT NULL DEFAULT '' 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_attendance_sync_jobs_source_type` (`source_type`),
  KEY `ix_attendance_sync_jobs_sync_mode` (`sync_mode`),
  KEY `ix_attendance_sync_jobs_attendance_date` (`attendance_date`),
  KEY `ix_attendance_sync_jobs_salary_month` (`salary_month`),
  KEY `ix_attendance_sync_jobs_status` (`status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
  COMMENT='考勤同步任务表，记录钉钉实时同步或Excel导入的批次状态';

CREATE TABLE IF NOT EXISTS `salary_preview` (
  `id` INT NOT NULL AUTO_INCREMENT COMMENT '薪资预估主键ID',
  `sync_job_id` VARCHAR(32) NOT 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 '部门名称快照',
  `position` VARCHAR(128) NOT NULL DEFAULT '' COMMENT '岗位名称快照',
  `salary_month` VARCHAR(7) NOT NULL DEFAULT '' COMMENT '工资月份，格式YYYY-MM',
  `attendance_days` FLOAT NOT NULL DEFAULT 0 COMMENT '本月当前出勤天数',
  `actual_work_hours` FLOAT NOT NULL DEFAULT 0 COMMENT '本月当前实际工时',
  `punch_overtime_hours` FLOAT NOT NULL DEFAULT 0 COMMENT '打卡推算加班工时',
  `leave_hours` FLOAT NOT NULL DEFAULT 0 COMMENT '请假或调休工时',
  `remaining_overtime_hours` FLOAT NOT NULL DEFAULT 0 COMMENT '剩余加班工时',
  `late_deduction` FLOAT NOT NULL DEFAULT 0 COMMENT '当前迟到扣款',
  `missing_card_deduction` FLOAT NOT NULL DEFAULT 0 COMMENT '当前缺卡扣款',
  `commission_amount` FLOAT NOT NULL DEFAULT 0 COMMENT '当前已录入提成',
  `overtime_pay` FLOAT NOT NULL DEFAULT 0 COMMENT '当前加班费',
  `estimated_gross_salary` FLOAT NULL COMMENT '当前预估应发工资',
  `estimated_net_salary` FLOAT NULL COMMENT '当前预估实发工资',
  `status` VARCHAR(32) NOT NULL DEFAULT 'estimated' COMMENT '预估状态：estimated已预估、warning有异常',
  `note` 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 `uq_salary_preview_sync_employee` (`sync_job_id`, `employee_id`),
  KEY `ix_salary_preview_sync_job_id` (`sync_job_id`),
  KEY `ix_salary_preview_employee_id` (`employee_id`),
  KEY `ix_salary_preview_employee_no` (`employee_no`),
  KEY `ix_salary_preview_employee_name` (`employee_name`),
  KEY `ix_salary_preview_salary_month` (`salary_month`),
  KEY `ix_salary_preview_status` (`status`),
  CONSTRAINT `fk_salary_preview_sync_job_id`
    FOREIGN KEY (`sync_job_id`) REFERENCES `attendance_sync_jobs` (`id`) ON DELETE CASCADE,
  CONSTRAINT `fk_salary_preview_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 `monthly_payroll_runs` (
  `id` INT NOT NULL AUTO_INCREMENT COMMENT '月度核算批次主键ID',
  `salary_month` VARCHAR(7) NOT NULL COMMENT '工资月份，格式YYYY-MM',
  `source_type` VARCHAR(32) NOT NULL DEFAULT 'excel' COMMENT '数据来源：excel或dingtalk',
  `source_job_id` VARCHAR(32) NOT NULL DEFAULT '' COMMENT '来源任务ID，可关联工资任务或同步任务',
  `status` VARCHAR(32) NOT NULL DEFAULT 'draft' COMMENT '核算状态：draft、calculated、reviewed、locked、failed',
  `employee_count` INT NOT NULL DEFAULT 0 COMMENT '参与核算员工数量',
  `gross_total` FLOAT NOT NULL DEFAULT 0 COMMENT '应发工资合计',
  `net_total` FLOAT NOT NULL DEFAULT 0 COMMENT '实发工资合计',
  `deduction_total` FLOAT NOT NULL DEFAULT 0 COMMENT '扣款合计',
  `overtime_total` FLOAT NOT NULL DEFAULT 0 COMMENT '剩余加班工时合计',
  `locked_by` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '锁定人用户名快照',
  `locked_at` DATETIME NULL COMMENT '锁定时间',
  `created_by` VARCHAR(64) NOT NULL DEFAULT '' 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_monthly_payroll_runs_salary_month` (`salary_month`),
  KEY `ix_monthly_payroll_runs_source_job_id` (`source_job_id`),
  KEY `ix_monthly_payroll_runs_status` (`status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
  COMMENT='月度工资核算批次表，记录每月工资计算、复核和锁定状态';

CREATE TABLE IF NOT EXISTS `payroll_exceptions` (
  `id` INT NOT NULL AUTO_INCREMENT COMMENT '异常记录主键ID',
  `run_id` INT NULL COMMENT '关联月度核算批次ID',
  `sync_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 DEFAULT '' COMMENT '员工姓名快照',
  `salary_month` VARCHAR(7) NOT NULL DEFAULT '' COMMENT '工资月份，格式YYYY-MM',
  `exception_type` VARCHAR(64) NOT NULL COMMENT '异常类型编码',
  `severity` VARCHAR(32) NOT NULL DEFAULT 'warning' COMMENT '严重级别：info、warning、error',
  `message` TEXT NOT NULL COMMENT '异常说明',
  `status` VARCHAR(32) NOT NULL DEFAULT 'open' COMMENT '处理状态：open待处理、resolved已处理、ignored已忽略',
  `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `resolved_at` DATETIME NULL COMMENT '处理完成时间',
  PRIMARY KEY (`id`),
  KEY `ix_payroll_exceptions_run_id` (`run_id`),
  KEY `ix_payroll_exceptions_sync_job_id` (`sync_job_id`),
  KEY `ix_payroll_exceptions_employee_id` (`employee_id`),
  KEY `ix_payroll_exceptions_employee_no` (`employee_no`),
  KEY `ix_payroll_exceptions_employee_name` (`employee_name`),
  KEY `ix_payroll_exceptions_salary_month` (`salary_month`),
  KEY `ix_payroll_exceptions_exception_type` (`exception_type`),
  KEY `ix_payroll_exceptions_severity` (`severity`),
  KEY `ix_payroll_exceptions_status` (`status`),
  CONSTRAINT `fk_payroll_exceptions_run_id`
    FOREIGN KEY (`run_id`) REFERENCES `monthly_payroll_runs` (`id`) ON DELETE CASCADE,
  CONSTRAINT `fk_payroll_exceptions_sync_job_id`
    FOREIGN KEY (`sync_job_id`) REFERENCES `attendance_sync_jobs` (`id`) ON DELETE CASCADE,
  CONSTRAINT `fk_payroll_exceptions_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`);

INSERT INTO `users` (
  `username`,
  `display_name`,
  `avatar_url`,
  `email`,
  `phone`,
  `department`,
  `position_title`,
  `password_hash`,
  `role`,
  `is_active`,
  `created_at`,
  `updated_at`
) VALUES (
  'admin',
  '超级管理员',
  '',
  '',
  '',
  '系统管理',
  '超级管理员',
  'pbkdf2_sha256$260000$b3a9c1TDdorYhXOj4usDsA$BPH38v3hjJ-vj8tGw-senDM5czyhRX-wr_zS8lV4bBo',
  'superuser',
  TRUE,
  NOW(),
  NOW()
) ON DUPLICATE KEY UPDATE
  `display_name` = VALUES(`display_name`),
  `department` = VALUES(`department`),
  `position_title` = VALUES(`position_title`),
  `role` = VALUES(`role`),
  `is_active` = VALUES(`is_active`),
  `updated_at` = NOW();
