From 1466672f09a4fc1037c78cc2bb096fca551c1683 Mon Sep 17 00:00:00 2001
From: tuqin <tuqin@tuqin.cn>
Date: 星期三, 28 十月 2026 09:46:29 +0800
Subject: [PATCH] feat(hrm): 薪酬核算新增全勤奖与实出天数,修正实发工资口径

---
 yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/dataobject/salary/HrmSalaryCalculationDO.java             |   16 +++++
 yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/salary/vo/HrmSalaryCalculationSaveReqVO.java |   14 ++++
 sql/mysql/hrm_salary_add_full_attendance_bonus.sql                                                                       |   49 ++++++++++++++++
 yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/dataobject/attendance/HrmAttendanceSummaryDO.java         |    5 +
 yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/salary/vo/HrmSalaryCalculationRespVO.java    |   12 +++
 yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/salary/HrmSalaryCalculationServiceImpl.java           |   33 +++++++++-
 6 files changed, 121 insertions(+), 8 deletions(-)

diff --git a/sql/mysql/hrm_salary_add_full_attendance_bonus.sql b/sql/mysql/hrm_salary_add_full_attendance_bonus.sql
new file mode 100644
index 0000000..800ca0c
--- /dev/null
+++ b/sql/mysql/hrm_salary_add_full_attendance_bonus.sql
@@ -0,0 +1,49 @@
+-- =============================================
+-- 钖叕鏍哥畻锛氭柊澧炪�屽叏鍕ゅ銆嶃�屽疄鍑哄ぉ鏁般��
+--
+-- 鑳屾櫙锛�
+--   1) 鍏ㄥ嫟濂栵細涓庡叾浠栨触璐村彛寰勪竴鑷达紝鐢变汉宸ュ湪鏍哥畻鍗曚腑缁存姢锛堥粯璁� 0锛夛紝璁″叆搴斿彂/瀹炲彂
+--   2) 瀹炲嚭澶╂暟锛氬彇鑷�冨嫟姹囨�昏〃 hrm_attendance_summary.actual_days
+--      銆屽簲鍑哄ぉ鏁般�嶆部鐢ㄥ師 work_days锛堟寜鎺掔彮绱鐨勫簲鍑哄嫟澶╂暟锛屾棤鎺掔彮鍥為�� 22锛夛紝璇箟涓嶅彉锛屼粎鍓嶇鏀瑰悕
+--      銆屾帓鐝伐鏃躲�嶅師鍒� total_work_hours 淇濈暀浣嗕笉鍐嶄娇鐢紙鍘嗗彶鏁版嵁涓嶅垹闄わ級
+--
+-- 鑴氭湰鍙噸澶嶆墽琛岋紙骞傜瓑锛�
+-- =============================================
+SET NAMES utf8mb4;
+
+SET @sch := DATABASE();
+
+-- 1. 鍏ㄥ嫟濂�
+SET @exists := (SELECT COUNT(*) FROM information_schema.COLUMNS
+    WHERE TABLE_SCHEMA = @sch AND TABLE_NAME = 'hrm_salary_calculation' AND COLUMN_NAME = 'full_attendance_bonus');
+SET @sql := IF(@exists = 0,
+    'ALTER TABLE `hrm_salary_calculation` ADD COLUMN `full_attendance_bonus` decimal(10,2) DEFAULT ''0.00'' COMMENT ''鍏ㄥ嫟濂�'' AFTER `other_allowance`',
+    'SELECT ''full_attendance_bonus 宸插瓨鍦�'' AS msg');
+PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
+
+-- 2. 瀹炲嚭澶╂暟
+SET @exists := (SELECT COUNT(*) FROM information_schema.COLUMNS
+    WHERE TABLE_SCHEMA = @sch AND TABLE_NAME = 'hrm_salary_calculation' AND COLUMN_NAME = 'actual_days');
+SET @sql := IF(@exists = 0,
+    'ALTER TABLE `hrm_salary_calculation` ADD COLUMN `actual_days` int DEFAULT 0 COMMENT ''瀹炲嚭澶╂暟锛堝彇鑷�冨嫟姹囨�伙級'' AFTER `work_days`',
+    'SELECT ''actual_days 宸插瓨鍦�'' AS msg');
+PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
+
+-- 3. 鍘嗗彶鏁版嵁鍥炲~瀹炲嚭澶╂暟锛堟寜鍚屽憳宸ュ悓鍛ㄦ湡浠庤�冨嫟姹囨�诲甫涓�娆★紝閬垮厤鍘嗗彶鍗曞叏鏄� 0锛�
+UPDATE `hrm_salary_calculation` c
+JOIN `hrm_attendance_summary` s
+  ON s.`user_id` = c.`user_id` AND s.`year_month` = c.`period` AND s.`deleted` = b'0'
+SET c.`actual_days` = s.`actual_days`
+WHERE c.`deleted` = b'0' AND (c.`actual_days` IS NULL OR c.`actual_days` = 0)
+  AND s.`actual_days` IS NOT NULL;
+
+-- 4. 鏍稿
+SELECT COLUMN_NAME, COLUMN_TYPE, COLUMN_DEFAULT, COLUMN_COMMENT
+FROM information_schema.COLUMNS
+WHERE TABLE_SCHEMA = @sch AND TABLE_NAME = 'hrm_salary_calculation'
+  AND COLUMN_NAME IN ('work_days','actual_days','full_attendance_bonus','total_work_hours')
+ORDER BY ORDINAL_POSITION;
+
+SELECT COUNT(*) AS 鏈夊疄鍑哄ぉ鏁扮殑鏍哥畻鍗曟暟 FROM `hrm_salary_calculation` WHERE `deleted` = b'0' AND `actual_days` > 0;
+
+SELECT '钖叕鏍哥畻 鍏ㄥ嫟濂�/瀹炲嚭澶╂暟 瀛楁鍒濆鍖栧畬鎴�' AS result;
diff --git a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/salary/vo/HrmSalaryCalculationRespVO.java b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/salary/vo/HrmSalaryCalculationRespVO.java
index 1383e02..e69c5a5 100644
--- a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/salary/vo/HrmSalaryCalculationRespVO.java
+++ b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/salary/vo/HrmSalaryCalculationRespVO.java
@@ -73,6 +73,10 @@
     @ExcelProperty("鍏朵粬琛ヨ创")
     private BigDecimal otherAllowance;
 
+    @Schema(description = "鍏ㄥ嫟濂�", example = "200.00")
+    @ExcelProperty("鍏ㄥ嫟濂�")
+    private BigDecimal fullAttendanceBonus;
+
     @Schema(description = "绀句繚鎵i櫎")
     @ExcelProperty("绀句繚鎵i櫎")
     private BigDecimal socialSecurityDeduction;
@@ -97,10 +101,14 @@
     @ExcelProperty("瀹炲彂宸ヨ祫")
     private BigDecimal actualSalary;
 
-    @Schema(description = "鍑哄嫟澶╂暟")
-    @ExcelProperty("鍑哄嫟澶╂暟")
+    @Schema(description = "搴斿嚭澶╂暟")
+    @ExcelProperty("搴斿嚭澶╂暟")
     private Integer workDays;
 
+    @Schema(description = "瀹炲嚭澶╂暟锛堝彇鑷�冨嫟姹囨�伙級", example = "21")
+    @ExcelProperty("瀹炲嚭澶╂暟")
+    private Integer actualDays;
+
     @Schema(description = "鍔犵彮鏃堕暱")
     @ExcelProperty("鍔犵彮鏃堕暱")
     private BigDecimal overtimeHours;
diff --git a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/salary/vo/HrmSalaryCalculationSaveReqVO.java b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/salary/vo/HrmSalaryCalculationSaveReqVO.java
index 550c6c9..5c2cf34 100644
--- a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/salary/vo/HrmSalaryCalculationSaveReqVO.java
+++ b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/salary/vo/HrmSalaryCalculationSaveReqVO.java
@@ -41,6 +41,12 @@
         @NotNull(message = "鍩烘湰宸ヨ祫涓嶈兘涓虹┖")
         private BigDecimal baseSalary;
 
+        @Schema(description = "宀椾綅宸ヨ祫")
+        private BigDecimal postSalary;
+
+        @Schema(description = "宸ラ緞宸ヨ祫")
+        private BigDecimal senioritySalary;
+
         @Schema(description = "缁╂晥宸ヨ祫")
         private BigDecimal performanceSalary;
 
@@ -55,6 +61,9 @@
 
         @Schema(description = "鍏朵粬琛ヨ创")
         private BigDecimal otherAllowance;
+
+        @Schema(description = "鍏ㄥ嫟濂�")
+        private BigDecimal fullAttendanceBonus;
 
         @Schema(description = "绀句繚鎵i櫎")
         private BigDecimal socialSecurityDeduction;
@@ -72,9 +81,12 @@
         @NotNull(message = "瀹炲彂宸ヨ祫涓嶈兘涓虹┖")
         private BigDecimal actualSalary;
 
-        @Schema(description = "鍑哄嫟澶╂暟")
+        @Schema(description = "搴斿嚭澶╂暟")
         private Integer workDays;
 
+        @Schema(description = "瀹炲嚭澶╂暟")
+        private Integer actualDays;
+
         @Schema(description = "鍔犵彮鏃堕暱")
         private BigDecimal overtimeHours;
 
diff --git a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/dataobject/attendance/HrmAttendanceSummaryDO.java b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/dataobject/attendance/HrmAttendanceSummaryDO.java
index 56d350a..91efade 100644
--- a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/dataobject/attendance/HrmAttendanceSummaryDO.java
+++ b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/dataobject/attendance/HrmAttendanceSummaryDO.java
@@ -2,6 +2,7 @@
 
 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
 import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableName;
 import lombok.*;
@@ -43,7 +44,11 @@
 
     /**
      * 骞存湀锛屾牸寮忥細yyyy-MM
+     *
+     * 娉ㄦ剰锛歽ear_month 鏄� MySQL 鐨勪繚鐣欏瓧锛圷EAR_MONTH 涓� interval 鍗曚綅锛夛紝
+     * 蹇呴』鐢ㄥ弽寮曞彿鍖呰9锛屽惁鍒� MyBatis-Plus 鎷煎嚭鐨� SQL 浼氳娉曢敊璇��
      */
+    @TableField("`year_month`")
     private String yearMonth;
 
     /**
diff --git a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/dataobject/salary/HrmSalaryCalculationDO.java b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/dataobject/salary/HrmSalaryCalculationDO.java
index 4b08d9b..cc83d1c 100644
--- a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/dataobject/salary/HrmSalaryCalculationDO.java
+++ b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/dataobject/salary/HrmSalaryCalculationDO.java
@@ -91,6 +91,12 @@
      * 鍏朵粬琛ヨ创
      */
     private BigDecimal otherAllowance;
+    /**
+     * 鍏ㄥ嫟濂�
+     *
+     * 涓庡叾浠栨触璐翠竴鑷达紝鐢变汉宸ュ湪鏍哥畻鍗曚腑缁存姢锛岄粯璁� 0
+     */
+    private BigDecimal fullAttendanceBonus;
 
     /**
      * 绀句繚鎵i櫎
@@ -123,11 +129,19 @@
     private BigDecimal actualSalary;
 
     /**
-     * 鍑哄嫟澶╂暟
+     * 搴斿嚭澶╂暟锛堟寜鎺掔彮绱鐨勫簲鍑哄嫟澶╂暟锛屾棤鎺掔彮鏃跺洖閫� 22锛�
      */
     private Integer workDays;
 
     /**
+     * 瀹炲嚭澶╂暟
+     *
+     * 鍙栬嚜鑰冨嫟姹囨�伙紙hrm_attendance_summary.actual_days锛夛紝鏃犳眹鎬昏褰曟椂涓� 0銆�
+     * 璇存槑锛氬師銆屾帓鐝�诲伐鏃躲�嶅瓧娈典繚鐣欎絾涓嶅啀浣跨敤锛堝巻鍙叉暟鎹笉鍒犻櫎锛夈��
+     */
+    private Integer actualDays;
+
+    /**
      * 鍔犵彮鏃堕暱
      */
     private BigDecimal overtimeHours;
diff --git a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/salary/HrmSalaryCalculationServiceImpl.java b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/salary/HrmSalaryCalculationServiceImpl.java
index ed13d18..5ed819e 100644
--- a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/salary/HrmSalaryCalculationServiceImpl.java
+++ b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/salary/HrmSalaryCalculationServiceImpl.java
@@ -6,6 +6,7 @@
 import cn.iocoder.yudao.module.hrm.controller.admin.salary.vo.HrmSalaryCalculationPageReqVO;
 import cn.iocoder.yudao.module.hrm.dal.dataobject.approval.HrmLeaveApplicationDO;
 import cn.iocoder.yudao.module.hrm.dal.dataobject.approval.HrmOvertimeApplicationDO;
+import cn.iocoder.yudao.module.hrm.dal.dataobject.attendance.HrmAttendanceSummaryDO;
 import cn.iocoder.yudao.module.hrm.dal.dataobject.attendance.HrmEmployeeScheduleDO;
 import cn.iocoder.yudao.module.hrm.dal.dataobject.attendance.HrmShiftDO;
 import cn.iocoder.yudao.module.hrm.dal.dataobject.employee.HrmEmployeeDO;
@@ -18,6 +19,7 @@
 import cn.iocoder.yudao.module.hrm.dal.dataobject.salary.HrmSocialSecuritySchemeDO;
 import cn.iocoder.yudao.module.hrm.dal.dataobject.salary.HrmSalaryStructureDO;
 import cn.iocoder.yudao.module.hrm.dal.mysql.approval.HrmLeaveApplicationMapper;
+import cn.iocoder.yudao.module.hrm.dal.mysql.attendance.HrmAttendanceSummaryMapper;
 import cn.iocoder.yudao.module.hrm.dal.mysql.attendance.HrmEmployeeScheduleMapper;
 import cn.iocoder.yudao.module.hrm.dal.mysql.attendance.HrmShiftMapper;
 import cn.iocoder.yudao.module.hrm.dal.mysql.approval.HrmOvertimeApplicationMapper;
@@ -114,6 +116,8 @@
     private HrmEmployeeScheduleMapper employeeScheduleMapper;
     @Resource
     private HrmShiftMapper shiftMapper;
+    @Resource
+    private HrmAttendanceSummaryMapper attendanceSummaryMapper;
 
     @Override
     public PageResult<HrmSalaryCalculationDO> getSalaryCalculationPage(HrmSalaryCalculationPageReqVO pageReqVO) {
@@ -248,13 +252,25 @@
         OvertimeSalary overtimeSalary = calculateOvertimeSalary(employee, employeeSalary, period, baseSalary);
         BigDecimal overtimePay = overtimeSalary.pay();
 
-        // 鎸夋帓鐝疮璁″嚭鍕ゅぉ鏁颁笌鎺掔彮鎬诲伐鏃讹紙鏃犳帓鐝椂鍑哄嫟澶╂暟鍥為��榛樿 22锛�
+        // 鎸夋帓鐝疮璁″簲鍑哄ぉ鏁颁笌鎺掔彮鎬诲伐鏃讹紙鏃犳帓鐝椂搴斿嚭澶╂暟鍥為��榛樿 22锛�
         ScheduleStat scheduleStat = calculateScheduleStat(employeeId, period);
         Integer workDays = scheduleStat.scheduledDays() > 0 ? scheduleStat.scheduledDays() : 22;
         BigDecimal totalWorkHours = scheduleStat.totalWorkHours();
 
-        // 搴斿彂宸ヨ祫鎬婚
+        // 瀹炲嚭澶╂暟锛氬彇鑷�冨嫟姹囨�伙紙鏃犳眹鎬昏褰曟椂鎸� 0 澶勭悊锛�
+        Integer actualDays = 0;
+        HrmAttendanceSummaryDO attendanceSummary =
+                attendanceSummaryMapper.selectByUserIdAndYearMonth(employeeId, period);
+        if (attendanceSummary != null && attendanceSummary.getActualDays() != null) {
+            actualDays = attendanceSummary.getActualDays();
+        }
+
+        // 鍏ㄥ嫟濂栵細涓庡叾浠栨触璐翠竴鑷达紝鐢变汉宸ュ湪鏍哥畻鍗曚腑缁存姢锛屾柊寤烘椂榛樿 0
+        BigDecimal fullAttendanceBonus = BigDecimal.ZERO;
+
+        // 搴斿彂宸ヨ祫鎬婚锛堟敹鍏ラ」鍙e緞蹇呴』涓� calcActualSalary 淇濇寔涓�鑷达級
         BigDecimal totalIncome = baseSalary.add(performanceSalary).add(postSalary).add(senioritySalary)
+                .add(fullAttendanceBonus)
                 .add(mealAllowance).add(transportAllowance).add(otherAllowance).add(overtimePay);
 
         // 鑾峰彇绀句繚鍩烘暟锛氬憳宸ョぞ淇濇。妗� > 鍛樺伐鍩烘湰宸ヨ祫
@@ -319,15 +335,17 @@
                 .mealAllowance(mealAllowance)
                 .transportAllowance(transportAllowance)
                 .otherAllowance(otherAllowance)
+                .fullAttendanceBonus(fullAttendanceBonus)
                 .socialSecurityDeduction(socialSecurityDeduction)
                 .housingFundDeduction(housingFundDeduction)
                 .taxDeduction(taxDeduction)
                 .otherDeduction(otherDeduction)
                 .leaveDeduction(leaveDeduction)
                 .actualSalary(actualSalary)
-                .workDays(workDays) // 鎸夋帓鐝疮璁″簲鍑哄嫟澶╂暟锛屾棤鎺掔彮鏃跺洖閫� 22
+                .workDays(workDays) // 搴斿嚭澶╂暟锛氭寜鎺掔彮绱锛屾棤鎺掔彮鏃跺洖閫� 22
+                .actualDays(actualDays) // 瀹炲嚭澶╂暟锛氬彇鑷�冨嫟姹囨��
                 .overtimeHours(overtimeSalary.hours())
-                .totalWorkHours(totalWorkHours)
+                .totalWorkHours(totalWorkHours) // 淇濈暀鍘嗗彶瀛楁锛屼笟鍔″凡鏀圭敤 actualDays
                 .status(0) // 寰呯‘璁�
                 .build();
     }
@@ -700,6 +718,7 @@
         calculation.setMealAllowance(nvl(calculation.getMealAllowance()));
         calculation.setTransportAllowance(nvl(calculation.getTransportAllowance()));
         calculation.setOtherAllowance(nvl(calculation.getOtherAllowance()));
+        calculation.setFullAttendanceBonus(nvl(calculation.getFullAttendanceBonus()));
         calculation.setSocialSecurityDeduction(nvl(calculation.getSocialSecurityDeduction()));
         calculation.setHousingFundDeduction(nvl(calculation.getHousingFundDeduction()));
         calculation.setTaxDeduction(nvl(calculation.getTaxDeduction()));
@@ -712,10 +731,16 @@
 
     /**
      * 璁$畻瀹炲彂宸ヨ祫 = 鏀跺叆椤瑰悎璁� - 鎵i櫎椤瑰悎璁★紝淇濈暀涓や綅灏忔暟
+     *
+     * 鏀跺叆椤瑰繀椤讳笌 buildSalaryCalculation 涓� totalIncome 鐨勫彛寰勫畬鍏ㄤ竴鑷达紝
+     * 鍚﹀垯浼氬嚭鐜般�屾柊寤烘牳绠楃畻寰楀銆佷慨鏀逛竴娆℃牳绠楀崟瀹炲彂灏卞彉灏戙�嶇殑涓嶄竴鑷淬��
      */
     private static BigDecimal calcActualSalary(HrmSalaryCalculationDO c) {
         BigDecimal income = nvl(c.getBaseSalary())
+                .add(nvl(c.getPostSalary()))
+                .add(nvl(c.getSenioritySalary()))
                 .add(nvl(c.getPerformanceSalary()))
+                .add(nvl(c.getFullAttendanceBonus()))
                 .add(nvl(c.getOvertimePay()))
                 .add(nvl(c.getMealAllowance()))
                 .add(nvl(c.getTransportAllowance()))

--
Gitblit v1.9.3