From ba100c651a81162a9a9a4533ff4d072f2889171a Mon Sep 17 00:00:00 2001
From: tuqin <tuqin@tuqin.cn>
Date: 星期五, 06 十一月 2026 09:38:46 +0800
Subject: [PATCH] fix(hrm): 考勤统计支持员工姓名搜索;缺卡统计补全(与考勤记录联动)

---
 yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/salary/HrmSalaryCalculationServiceImpl.java |   71 ++++++++++++++++++++++++-----------
 1 files changed, 48 insertions(+), 23 deletions(-)

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 faa80ef..aa54240 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
@@ -281,7 +281,7 @@
                 .add(fullAttendanceBonus)
                 .add(mealAllowance).add(transportAllowance).add(otherAllowance).add(overtimePay);
 
-        // 鑾峰彇绀句繚鍩烘暟锛氬憳宸ョぞ淇濇。妗� > 鍛樺伐鍩烘湰宸ヨ祫
+        // 绀句繚鍩烘暟锛氬彧鍙栧憳宸ョぞ淇濇。妗堥噷閰嶇疆鐨勭即绾冲熀鏁帮紱鏈厤缃椂鐢ㄥ熀鏈伐璧�
         BigDecimal socialSecurityBase = (socialSecurity != null && socialSecurity.getSocialSecurityBase() != null)
                 ? socialSecurity.getSocialSecurityBase() : baseSalary;
 
@@ -292,17 +292,31 @@
                 ? scheme.getMedicalPersonalRatio() : DEFAULT_MEDICAL_PERSONAL_RATIO;
         BigDecimal unemploymentPersonalRatio = (scheme != null && scheme.getUnemploymentPersonalRatio() != null)
                 ? scheme.getUnemploymentPersonalRatio() : DEFAULT_UNEMPLOYMENT_PERSONAL_RATIO;
+        // 澶х梾鍖荤枟 / 闀挎湡鎶ょ悊鐨勪釜浜烘瘮渚嬶細鏂规閲屽彲鑳戒负绌猴紝涓虹┖瑙嗕负 0锛堜笉鎵o級
+        BigDecimal seriousIllnessPersonalRatio = (scheme != null && scheme.getSeriousIllnessPersonalRatio() != null)
+                ? scheme.getSeriousIllnessPersonalRatio() : BigDecimal.ZERO;
+        BigDecimal longTermCarePersonalRatio = (scheme != null && scheme.getLongTermCarePersonalRatio() != null)
+                ? scheme.getLongTermCarePersonalRatio() : BigDecimal.ZERO;
 
         // 鍏Н閲戜釜浜烘瘮渚嬶細鍙彇鏂规閰嶇疆鍊硷紝涓嶅啀鍥為��榛樿姣斾緥銆�
         // 鍚﹀垯銆屽叕鍙告病閰嶅叕绉噾鏂规銆嶆椂浼氳鎸夐粯璁� 12% 鎵f锛堣繖灏辨槸瀹㈡埛鍙嶉鐨勯棶棰橈級銆�
         BigDecimal housingFundPersonalRatio = scheme != null ? scheme.getHousingFundPersonalRatio() : null;
 
-        // 绀句繚鎵i櫎 = 鍩烘暟 脳 (鍏昏�佷釜浜烘瘮渚� + 鍖荤枟涓汉姣斾緥 + 澶变笟涓汉姣斾緥)
-        BigDecimal socialSecurityDeduction = socialSecurityBase
-                .multiply(pensionPersonalRatio)
-                .add(socialSecurityBase.multiply(medicalPersonalRatio))
-                .add(socialSecurityBase.multiply(unemploymentPersonalRatio))
-                .setScale(2, RoundingMode.HALF_UP);
+        // 绀句繚鎵i櫎锛氬繀椤汇�屽憳宸ラ厤缃簡绀句繚妗f銆嶆墠鎵f銆�
+        // 涔嬪墠鏃犺鏈夋病鏈夌ぞ淇濇。妗堥兘鎸� 鍩烘暟 脳 榛樿姣斾緥(0.08+0.02+0.005=10.5%) 鎵f锛�
+        // 瀵艰嚧 102 涓病鍔犵ぞ淇濈殑鍛樺伐琚墸浜� 204.75锛�= 鍩烘湰宸ヨ祫 1950 脳 10.5%锛夈��
+        // 涓汉搴旂即 = 鍏昏�� + 鍖荤枟 + 澶变笟 + 澶х梾鍖荤枟 + 闀挎湡鎶ょ悊銆�
+        // 娉ㄦ剰锛氬師鏉ユ紡绠椾簡鍚庝袱椤癸紝浣垮緱銆屽叺鍥簲闄┿�嶄笌銆屽湴鏂逛簲闄┿�嶄袱涓柟妗堢畻鍑烘潵鐨勬墸娆惧畬鍏ㄤ竴鏍枫��
+        BigDecimal socialSecurityDeduction = BigDecimal.ZERO;
+        if (socialSecurity != null) {
+            BigDecimal personalTotalRatio = pensionPersonalRatio
+                    .add(medicalPersonalRatio)
+                    .add(unemploymentPersonalRatio)
+                    .add(seriousIllnessPersonalRatio)
+                    .add(longTermCarePersonalRatio);
+            socialSecurityDeduction = socialSecurityBase.multiply(personalTotalRatio)
+                    .setScale(2, RoundingMode.HALF_UP);
+        }
 
         // 鍏Н閲戞墸闄わ細蹇呴』鍚屾椂婊¤冻銆屾柟妗堥厤缃簡鍏Н閲戞瘮渚� > 0銆嶄笖銆屽憳宸ユ。妗堥厤缃簡鍏Н閲戝熀鏁� > 0銆嶆墠鎵f锛�
         // 浠讳竴涓嶆弧瓒抽兘瑙嗕负鍏徃鏈即绾冲叕绉噾锛屾墸娆句负 0銆�
@@ -314,9 +328,14 @@
                     .setScale(2, RoundingMode.HALF_UP);
         }
 
-        // 璁$畻璇峰亣鎵f
-        // 璁$畻缂哄嫟鎵f锛堣鍋� + 鏃峰伐锛�
-        BigDecimal leaveDeduction = calculateAttendanceDeduction(employee, period, baseSalary, workDays, actualDays);
+        // 缂哄嫟鎵f锛堣鍋� + 鏃峰伐锛�
+        // 璁¤柂鍩烘暟 = 鍩烘湰宸ヨ祫 + 宀椾綅宸ヨ祫 + 宸ラ緞宸ヨ祫 + 缁╂晥宸ヨ祫锛堣繖浜涗笌鍑哄嫟澶╂暟鐩存帴鐩稿叧锛夛紱
+        // 涓嶅惈鍔犵彮璐�/鍚勯」琛ヨ创/鍏ㄥ嫟濂栵紙杩欎簺涓嶉殢鍑哄嫟澶╂暟鎶樼畻锛夈��
+        // 娉ㄦ剰锛氫笉鑳界敤"鍩烘湰宸ヨ祫"褰撳熀鏁扳�斺�斿緢澶氬憳宸ュ伐璧勪富浣撴槸宀椾綅宸ヨ祫锛屽惁鍒欏疄鍑� 0 澶╂椂鍙墸鎺夊熀鏈伐璧勶紝宀椾綅宸ヨ祫鐓у彂銆�
+        BigDecimal attendanceBaseSalary = baseSalary
+                .add(postSalary).add(senioritySalary).add(performanceSalary);
+        BigDecimal leaveDeduction = calculateAttendanceDeduction(
+                employee, period, attendanceBaseSalary, workDays, actualDays);
 
         // 璁$畻涓◣鎵i櫎
         // 搴旂撼绋庢墍寰楅 = 搴斿彂宸ヨ祫 - 绀句繚鎵i櫎 - 鍏Н閲戞墸闄� - 璧峰緛鐐�(5000)
@@ -376,18 +395,18 @@
      *     <li>鎵f鎬婚灏侀《涓哄熀鏈伐璧勶紝閬垮厤鍑虹幇璐熷伐璧勩��</li>
      * </ol>
      *
-     * @param employee   鍛樺伐淇℃伅
-     * @param period     鏍哥畻鍛ㄦ湡锛堝 2026-02锛�
-     * @param baseSalary 鍩烘湰宸ヨ祫
-     * @param workDays   搴斿嚭澶╂暟锛堟帓鐝疮璁★紝鏃犳帓鐝椂浼� 22锛�
-     * @param actualDays 瀹炲嚭澶╂暟锛堝彇鑷�冨嫟姹囨�伙紱null 琛ㄧず璇ユ湀鏈敓鎴愭眹鎬伙級
-     * @return 缂哄嫟鎵f閲戦
+     * @param employee       鍛樺伐淇℃伅
+     * @param period         鏍哥畻鍛ㄦ湡锛堝 2026-02锛�
+     * @param attendanceBase 璁¤柂鍩烘暟 = 鍩烘湰 + 宀椾綅 + 宸ラ緞 + 缁╂晥锛堜笌鍑哄嫟鐩存帴鐩稿叧鐨勫浐瀹氬伐璧勶級
+     * @param workDays       搴斿嚭澶╂暟锛堟帓鐝疮璁★紝鏃犳帓鐝椂浼� 22锛�
+     * @param actualDays     瀹炲嚭澶╂暟锛堝彇鑷�冨嫟姹囨�伙紱null 琛ㄧず璇ユ湀鏈敓鎴愭眹鎬伙級
+     * @return 缂哄嫟鎵f閲戦锛堝皝椤朵负璁¤柂鍩烘暟锛�
      */
     private BigDecimal calculateAttendanceDeduction(HrmEmployeeDO employee, String period,
-                                                    BigDecimal baseSalary, Integer workDays, Integer actualDays) {
+                                                    BigDecimal attendanceBase, Integer workDays, Integer actualDays) {
         int shouldDays = (workDays != null && workDays > 0) ? workDays : 22;
-        // 鏃ュ伐璧� = 鍩烘湰宸ヨ祫 / 搴斿嚭澶╂暟锛堜繚鐣� 4 浣嶏紝鏈�鍚庣粺涓�淇濈暀 2 浣嶏級
-        BigDecimal dailySalary = baseSalary.divide(new BigDecimal(shouldDays), 4, RoundingMode.HALF_UP);
+        // 鏃ュ伐璧� = 璁¤柂鍩烘暟 / 搴斿嚭澶╂暟锛堜繚鐣� 4 浣嶏紝鏈�鍚庣粺涓�淇濈暀 2 浣嶏級
+        BigDecimal dailySalary = attendanceBase.divide(new BigDecimal(shouldDays), 4, RoundingMode.HALF_UP);
 
         BigDecimal totalDeduction = BigDecimal.ZERO;
         BigDecimal leaveDays = BigDecimal.ZERO;
@@ -428,7 +447,7 @@
 
         // 3. 灏侀《锛氭墸娆句笉瓒呰繃鍩烘湰宸ヨ祫
         BigDecimal result = totalDeduction.setScale(2, RoundingMode.HALF_UP);
-        BigDecimal cap = baseSalary.setScale(2, RoundingMode.HALF_UP);
+        BigDecimal cap = attendanceBase.setScale(2, RoundingMode.HALF_UP);
         return result.compareTo(cap) > 0 ? cap : result;
     }
 
@@ -766,16 +785,22 @@
      * 閲嶇畻銆岀己鍕ゆ墸娆俱�嶄笌銆屽疄鍙戝伐璧勩��
      *
      * <p>鏍哥畻鍗� userId 瀛樼殑鏄憳宸D锛坔rm_employee.id锛夈�傛寜銆屽簲鍑哄ぉ鏁� / 瀹炲嚭澶╂暟 + 璇峰亣鍗曘�嶉噸绠�
-     * 缂哄嫟鎵f锛堣鍋囨寜閰嶇疆姣斾緥鎵c�佹椃宸ユ寜 100% 鎵c�佸皝椤跺熀鏈伐璧勶級锛屽啀閲嶇畻瀹炲彂宸ヨ祫锛堜笉鍙负璐燂級銆�
-     * 鏌ヤ笉鍒板憳宸ユ垨鏍哥畻鍛ㄦ湡鏃讹紝淇濈暀鍘熺己鍕ゆ墸娆撅紝鍙噸绠楀疄鍙戙��
+     * 缂哄嫟鎵f锛堣鍋囨寜閰嶇疆姣斾緥鎵c�佹椃宸ユ寜 100% 鎵c�佸皝椤惰钖熀鏁帮級锛屽啀閲嶇畻瀹炲彂宸ヨ祫锛堜笉鍙负璐燂級銆�
+     *
+     * <p>璁¤柂鍩烘暟 = 鍩烘湰 + 宀椾綅 + 宸ラ緞 + 缁╂晥锛堜笌鍑哄嫟鐩存帴鐩稿叧鐨勫浐瀹氬伐璧勯儴鍒嗭級锛�
+     * 涓嶈兘鐢ㄥ熀鏈伐璧勫崟鐙皝椤讹紝鍚﹀垯宸ヨ祫涓讳綋涓哄矖浣嶅伐璧勭殑鍛樺伐瀹炲嚭 0 澶╂椂浠嶄細鍙戞斁澶ч儴鍒嗗伐璧勩��
      */
     private void recalcAttendanceDeduction(HrmSalaryCalculationDO calculation) {
         HrmEmployeeDO employee = calculation.getUserId() != null
                 ? employeeMapper.selectById(calculation.getUserId()) : null;
         if (employee != null && calculation.getPeriod() != null) {
+            BigDecimal attendanceBaseSalary = nvl(calculation.getBaseSalary())
+                    .add(nvl(calculation.getPostSalary()))
+                    .add(nvl(calculation.getSenioritySalary()))
+                    .add(nvl(calculation.getPerformanceSalary()));
             BigDecimal deduction = calculateAttendanceDeduction(
                     employee, calculation.getPeriod(),
-                    nvl(calculation.getBaseSalary()),
+                    attendanceBaseSalary,
                     calculation.getWorkDays(),
                     calculation.getActualDays());
             calculation.setLeaveDeduction(deduction);

--
Gitblit v1.9.3