<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.oa.mapper.SysOaAttendanceMapper">

    <resultMap type="com.ruoyi.oa.domain.vo.SysOaAttendanceVo" id="SysOaAttendanceResult">
        <result property="id" column="id"/>
        <result property="userId" column="user_id"/>
        <result property="attendanceDay" column="attendance_day"/>
        <result property="projectId" column="project_id"/>
        <result property="dayLength" column="day_length"/>
        <result property="hour" column="hour"/>
        <result property="createTime" column="create_time"/>
        <result property="createBy" column="create_by"/>
        <result property="updateTime" column="update_time"/>
        <result property="updateBy" column="update_by"/>
        <result property="remark" column="remark"/>
        <result property="delFlag" column="del_flag"/>
        <result property="count" column="count"/>
        <result property="workTimes" column="work_times"/>
        <result property="hourWorkTimes" column="hour_work_times"/>
        <result property="color" column="color"/>
    </resultMap>


    <resultMap type="com.ruoyi.oa.domain.vo.SysUserVo" id="SysUserResult">
        <id property="userId" column="user_id"/>
        <result property="deptId" column="dept_id"/>
        <result property="userName" column="user_name"/>
        <result property="nickName" column="nick_name"/>
        <result property="userType" column="user_type"/>
        <result property="email" column="email"/>
        <result property="phonenumber" column="phonenumber"/>
        <result property="sex" column="sex"/>
        <result property="avatar" column="avatar"/>
        <result property="password" column="password"/>
        <result property="status" column="status"/>
        <result property="delFlag" column="del_flag"/>
        <result property="loginIp" column="login_ip"/>
        <result property="loginDate" column="login_date"/>
        <result property="createBy" column="create_by"/>
        <result property="createTime" column="create_time"/>
        <result property="updateBy" column="update_by"/>
        <result property="updateTime" column="update_time"/>
        <result property="remark" column="remark"/>
        <result property="idCard" column="id_card"/>
        <result property="bankCard" column="bank_card"/>
        <result property="laborCost" column="labor_cost"/>
        <collection property="projects" javaType="java.util.List" resultMap="projectResult"/>
        <collection property="attendances" javaType="java.util.List" resultMap="SysOaAttendanceResult"/>
    </resultMap>

    <resultMap id="projectResult" type="com.ruoyi.oa.domain.vo.SysOaProjectVo">
        <result property="projectId" column="project_id"/>
        <result property="projectName" column="project_name"/>
        <result property="projectNum" column="project_num"/>
        <result property="projectType" column="project_type"/>
        <result property="address" column="address"/>
        <result property="funds" column="funds"/>
        <result property="functionary" column="functionary"/>
        <result property="beginTime" column="begin_time"/>
        <result property="finishTime" column="finish_time"/>
        <result property="delivery" column="delivery"/>
        <result property="guarantee" column="guarantee"/>
        <result property="introduction" column="introduction"/>
        <result property="projectGrade" column="project_grade"/>
        <result property="projectStatus" column="project_status"/>
        <result property="contractId" column="contract_id"/>
        <result property="invoiceName" column="invoice_name"/>
        <result property="invoiceNumber" column="invoice_number"/>
        <result property="invoiceAddress" column="invoice_address"/>
        <result property="invoiceBank" column="invoice_bank"/>
        <result property="accessory" column="accessory"/>
        <result property="bail" column="bail"/>
        <result property="remark" column="remark"/>
        <result property="createBy" column="create_by"/>
        <result property="createTime" column="create_time"/>
    </resultMap>


    <update id="updateDelAttendance" parameterType="com.ruoyi.oa.domain.SysOaAttendance">
        update fad_oa.sys_oa_attendance
        <trim prefix="SET" suffixOverrides=",">
            <if test="projectId != null">project_id=#{projectId},</if>
            <if test="userId != null and userId!=''">user_id = #{userId},</if>
            <if test="attendanceDay != null and attendanceDay!=''">attendance_day = #{attendanceDay},</if>
            <if test="updateTime != null">update_time = #{updateTime},</if>
            <if test="updateBy != null">update_by = #{updateBy},</if>
            <if test="delFlag != null">del_flag = #{delFlag},</if>
            <if test="dayLength != null and dayLength!=''">day_length = #{dayLength},</if>
            <if test="hour != null and hour!=''">hour = #{hour},</if>
            <if test="createTime != null">create_time = #{createTime},</if>
        </trim>
        where id = #{id}
    </update>


    <select id="selectVoListAndTime" resultType="com.ruoyi.oa.domain.vo.SysOaAttendanceVo">
        SELECT ANY_VALUE(id)             AS id,
               user_id,
               ANY_VALUE(attendance_day) AS attendance_day,
               project_id,
               ANY_VALUE(day_length)     AS day_length,
               ANY_VALUE(hour)           AS hour,
               ANY_VALUE(create_time)    AS create_time,
               ANY_VALUE(create_by)      AS create_by,
               ANY_VALUE(update_time)    AS update_time,
               ANY_VALUE(update_by)      AS update_by,
               ANY_VALUE(remark)         AS remark,
               ANY_VALUE(del_flag)       AS del_flag,
               COUNT(id)                 AS count,
               SUM(
                       CASE
                           WHEN day_length != 0 OR hour != 0 THEN 1
                           ELSE 0
                           END
               ) AS work_times,
               SUM(
                       CASE
                           WHEN day_length > 0 THEN day_length * 8
                           WHEN hour > 0 THEN hour
                           ELSE 0
                           END
               )                         AS hour_work_times,

               SUM(
                       IF(hour > 8, hour - 8, 0)
               )                         AS overTime,
               SUM(
                       IF(project_id = 0, 1, 0)
               )                         AS tripDays,
               SUM(
                       IF(project_id = 1, 1, 0)
               )                         AS absenceDays

        FROM sys_oa_attendance soa
        WHERE user_id = #{userId}
          AND #{lastDay} >= create_time
          AND create_time >= #{firstDay}
          AND del_flag = '0'
        GROUP BY soa.project_id;

    </select>

    <select id="selectUserListAndAttendanceListAndProjectListByUserIds"
            resultMap="SysUserResult">
        SELECT su.user_id, su.dept_id, su.user_name, su.nick_name, su.user_type, su.email, su.phonenumber, su.sex,
        su.avatar,
        su.status,su.login_date, su.id_card,
        su.bank_card, su.labor_cost,
        soa.id,soa.attendance_day,soa.project_id,soa.day_length,soa.hour,
        color,
        sop.project_name, sop.project_num, sop.project_type, sop.address, sop.funds, sop.functionary, sop.begin_time,
        sop.finish_time, sop.delivery, sop.guarantee, sop.introduction, sop.project_grade, sop.project_status,
        sop.contract_id, sop.invoice_name,
        sop.invoice_number, sop.invoice_address, sop.invoice_bank, sop.accessory, sop.bail,sop.is_postpone,
        sop.postpone_reason,sop.postpone_time
        FROM sys_user su
        left join sys_oa_attendance soa on (su.user_id = soa.user_id and (soa.create_time BETWEEN #{firstDay} AND
        #{lastDay}))
        left join sys_oa_project sop on soa.project_id = sop.project_id
        WHERE su.user_id IN
        <foreach item="userId" index="index" collection="userIds"
                 open="(" separator="," close=")">
            #{userId}
        </foreach>

    </select>


    <select id="queryListByTime" resultMap="SysOaAttendanceResult">
        SELECT id,
               user_id,
               attendance_day,
               project_id,
               day_length,
               hour,
               create_time,
               create_by,
               update_time,
               update_by,
               remark,
               del_flag
        FROM sys_oa_attendance
        WHERE create_time BETWEEN #{startTime} AND #{endTime}
          AND user_id = #{userId}
          AND attendance_day = #{attendanceDay}
    </select>


    <delete id="delOaAttendanceAll">
        delete
        from sys_oa_attendance
        where attendance_day = #{day}
          and #{lastDay} > create_time
          and create_time > #{firstDay}
    </delete>


    <select id="getAttendanceDay" resultType="java.lang.Double">
        select sum(day_length)
        from sys_oa_attendance
        where user_id = #{userId}
          and project_id = #{projectId}
          and del_flag = '0'
    </select>
    <select id="selectNowMonthUserId" resultType="java.lang.Long">
        select distinct user_id
        from sys_oa_attendance
        where YEAR(create_time) = YEAR(#{firstDay})
          and MONTH(create_time) = MONTH(#{firstDay})
    </select>


    <!-- 结果映射 -->
    <resultMap id="AttendanceMonthlyCountMap" type="com.ruoyi.oa.domain.vo.AttendanceMonthlyCount">
        <result column="month" property="month"/>
        <result column="attendance_count" property="attendanceCount"/>
        <result column="leave_count" property="leaveCount"/>
    </resultMap>


    <select id="selectLastSixMonthsByMonth"
            resultMap="AttendanceMonthlyCountMap">
        SELECT DATE_FORMAT(create_time, '%Y-%m')                AS month,
               SUM(CASE WHEN project_id != 1 THEN 1 ELSE 0 END) AS attendance_count,
               SUM(CASE WHEN project_id = 1 THEN 1 ELSE 0 END)  AS leave_count
        FROM sys_oa_attendance
        WHERE create_time >= DATE_FORMAT(DATE_SUB(#{refDate}, INTERVAL 6 MONTH), '%Y-%m-01')
          AND IF(DATE_FORMAT(#{refDate}, '%Y-%m') = DATE_FORMAT(CURDATE(), '%Y-%m'), NOW(),
                 TIMESTAMP(LAST_DAY(DATE_SUB(#{refDate}, INTERVAL 1 MONTH)), '23:59:59'))
            >= create_time
          AND del_flag = 0
        GROUP BY month
        ORDER BY month;
    </select>
    <select id="selectAttendanceMonthlyCountByMonth"
            resultType="com.ruoyi.oa.domain.vo.AttendanceMonthlyCount">
        SELECT
            -- 1) project_id = 0 : 出勤 / 出差工时（天长 * 8 + 小时）
            SUM(
                    IF(project_id != 1 and project_id != 0, IFNULL(day_length, 0) * 8 -- day_length（天）换算成小时
                        + IFNULL(hour, 0), 0)
            ) AS workHours,
            SUM(
                    IF(project_id = 0,8,0)
            ) AS tripHours,
            -- 2) project_id = 1 : 请假工时（每条记录按 8 小时计）
            SUM(
                    IF(project_id = 1, 8, 0)
            ) AS leaveHours,
            -- 3) 加班工时：project_id = 0 情况下，hour 字段超出 8 小时的部分求和
            SUM(
                    IF(project_id != 1, GREATEST(IFNULL(hour, 0) - 8, 0), 0)
            ) AS overtimeHours
        FROM sys_oa_attendance
        WHERE del_flag = 0
          AND YEAR(create_time) = YEAR(#{refDate})
          and MONTH(create_time) = MONTH(#{refDate})
    </select>


    <select id="selectMonthlyCounts" resultType="com.ruoyi.oa.domain.vo.AttendanceMonthlyCount">
        SELECT m.month,

               ROUND(
                       COUNT(DISTINCT CASE
                                          WHEN a.project_id NOT IN (0, 1)
                                              THEN CONCAT(a.user_id, '_', DATE(a.create_time)) END) /
                       NULLIF(COUNT(DISTINCT CASE WHEN a.project_id != 0 THEN a.user_id END) *
                              COUNT(DISTINCT CASE WHEN a.project_id != 0 THEN DATE(a.create_time) END), 0), 4
               )                                                 AS attendanceRate,

               SUM(CASE WHEN a.project_id = 0 THEN 1 ELSE 0 END) AS tripCount,
               COUNT(CASE WHEN a.project_id = 1 THEN 1 END)      AS leavePeople,
               SUM(CASE
                       WHEN a.project_id NOT IN (0, 1)
                           AND IFNULL(a.hour, 0) > 8
                           THEN IFNULL(a.hour, 0) - 8
                       ELSE 0
                   END)                                          AS overtimeHours
        FROM (SELECT DATE_FORMAT(#{refDate}, '%Y-%m') AS month,
                     LAST_DAY(#{refDate})             AS last_day,
                     CASE
                         WHEN DATE_FORMAT(#{refDate}, '%Y-%m') = DATE_FORMAT(CURDATE(), '%Y-%m')
                             THEN DAY(#{refDate}) -- 本月：已过天数
                         ELSE DAY(LAST_DAY(#{refDate})) -- 历史月：整月天数
                         END                          AS days_so_far
              UNION ALL
              SELECT DATE_FORMAT(DATE_SUB(#{refDate}, INTERVAL 1 MONTH), '%Y-%m'),
                     LAST_DAY(DATE_SUB(#{refDate}, INTERVAL 1 MONTH)),
                     DAY(LAST_DAY(DATE_SUB(#{refDate}, INTERVAL 1 MONTH)))) m

                 LEFT JOIN sys_oa_attendance a
                           ON a.del_flag = 0
                               AND DATE_FORMAT(a.create_time, '%Y-%m') = m.month
                               AND a.create_time &lt;=
                                   CASE
                                       WHEN m.month = DATE_FORMAT(CURDATE(), '%Y-%m')
                                           THEN #{refDate}
                                       ELSE TIMESTAMP(m.last_day, '23:59:59')
                                       END

        GROUP BY m.month
        ORDER BY m.month DESC; -- 本月在前，上月在后
    </select>
    <select id="getWorkDaysByUserIdAndProjectId" resultType="java.lang.Long">
        SELECT
        COALESCE(SUM(CASE
        WHEN (day_length > 0 OR hour > 0)
        OR project_id IN (0, 1)
        THEN 1 ELSE 0 END), 0) AS work_days
        FROM sys_oa_attendance oas
        WHERE oas.user_id = #{userId}
        AND oas.project_id = #{projectId}
        AND oas.del_flag = 0
        AND (
        <!-- 如果 calcTime 不为空 -->
        (#{calcTime} IS NOT NULL AND (
        <!-- 如果 calcTime 和 relationMonth 在同一个月，查询从月初到 calcTime 的记录 -->
        (DATE_FORMAT(#{calcTime}, '%Y-%m') = DATE_FORMAT(#{relationMonth}, '%Y-%m')
        AND oas.create_time BETWEEN DATE_FORMAT(#{relationMonth}, '%Y-%m-01') AND #{calcTime})
        <!-- 如果 calcTime 和 relationMonth 不在同一个月，查询整个 relationMonth 月的记录 -->
        OR (DATE_FORMAT(#{calcTime}, '%Y-%m') != DATE_FORMAT(#{relationMonth}, '%Y-%m')
        AND oas.create_time BETWEEN DATE_FORMAT(#{relationMonth}, '%Y-%m-01')
        AND DATE_ADD(DATE_FORMAT(#{relationMonth}, '%Y-%m-01'), INTERVAL 1 MONTH) - INTERVAL 1 DAY)
        ))
        OR (
        #{calcTime} IS NULL AND (
        <!-- 如果 relationMonth 是当前月，则查询本月最晚的记录 -->
        (DATE_FORMAT(#{relationMonth}, '%Y-%m') = DATE_FORMAT(CURRENT_DATE, '%Y-%m')
        AND oas.create_time BETWEEN DATE_FORMAT(#{relationMonth}, '%Y-%m-01')
        AND (
        SELECT MAX(oar.calc_time)
        FROM oa_attendance_record oar
        WHERE oar.user_id = #{userId}
        AND oar.del_flag = 0
        ))
        <!-- 如果 relationMonth 不是当前月，则查询整个 relationMonth 的记录 -->
        OR (DATE_FORMAT(#{relationMonth}, '%Y-%m') != DATE_FORMAT(CURRENT_DATE, '%Y-%m')
        AND oas.create_time BETWEEN
        DATE_FORMAT(#{relationMonth}, '%Y-%m-01')
        AND DATE_ADD(DATE_FORMAT(#{relationMonth}, '%Y-%m-01'), INTERVAL 1 MONTH) - INTERVAL 1 DAY)
        ))
        )
    </select>




</mapper>
