docs/hrm_social_security_scheme_dept_frontend_integration.md
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,93 @@ # 社ä¿å ¬ç§¯éæ¹æ¡æ¹ä¸ºãæé¨é¨ç»å®ã - å端èè°æ¹æ¡ ## åæ´èæ¯ åæ¥ç¤¾ä¿å ¬ç§¯éæ¹æ¡åªè½ä¸ä¸ªåå·¥ä¸ä¸ªåå·¥å°å¨ãå工社ä¿å ¬ç§¯éæ¡£æ¡ãéç»å®ï¼å ç¾å·äººé个维æ¤ä¸ç°å®ã ç°å¨æ¹æ¡æ¬èº«å¯ä»¥æãéç¨é¨é¨ãï¼èªèµæ ¸ç®æ¶æåå·¥æå¨é¨é¨åæ¹æ¡ï¼åæ¥çå工档æ¡ä¿çä½ä¸ªå«è¦çã ## æ¶åé¡µé¢ - 社ä¿å ¬ç§¯éæ¹æ¡ï¼`/hrm/salary/social-security-scheme`ï¼ï¼è¡¨åæ°å¢ãéç¨é¨é¨ããé»è®¤ç¤¾ä¿åºæ°ããé»è®¤å ¬ç§¯éåºæ°ãï¼å表æ°å¢ãéç¨é¨é¨ãå - èªèµæ ¸ç®ï¼`/hrm/salary/calculation`ï¼ï¼æ éæ¹é ï¼æ¥å£å ¥åæ¬æ¥å°±æ `deptId`ï¼è¡ä¸ºèªå¨çæ - å工社ä¿å ¬ç§¯éæ¡£æ¡ï¼ä¸æ¹ï¼ç»§ç»ä½ä¸ºä¸ªå«è¦çå ¥å£ ## API | æ¹æ³ | è·¯å¾ | 说æ | |------|------|------| | POST | /hrm/salary/social-security-scheme/create | æ°å¢æ¹æ¡ï¼å¯å¸¦éç¨é¨é¨ä¸é»è®¤åºæ° | | PUT | /hrm/salary/social-security-scheme/update | ä¿®æ¹æ¹æ¡ï¼éç¨é¨é¨ä¸ºæ´ç»æ¿æ¢ï¼ä¼ 空æ°ç»å³è§£é¤å ¨é¨é¨é¨ï¼ | | GET | /hrm/salary/social-security-scheme/get | 详æ ï¼è¿å `deptIds` / `deptNames` | | GET | /hrm/salary/social-security-scheme/list | å表ï¼è¿å `deptIds` / `deptNames` | | GET | /hrm/salary/calculation/preview | è¯ç®ï¼å ¥å `period` + å¯é `deptId` | **请æ±åæ°æ°å¢ï¼create / updateï¼ï¼** | åæ° | ç±»å | å¿ å¡« | 说æ | |------|------|------|------| | deptIds | Long[] | å¦ | éç¨é¨é¨IDå表ï¼ç©ºæ°ç»æä¸ä¼ = ä¸éå®é¨é¨ï¼å ¨å±é»è®¤æ¹æ¡ï¼ | | defaultSocialSecurityBase | Decimal | å¦ | é»è®¤ç¤¾ä¿ç¼´è´¹åºæ°ï¼ç空åç¨åå·¥åºæ¬å·¥èµ | | defaultHousingFundBase | Decimal | å¦ | é»è®¤å ¬ç§¯éç¼´è´¹åºæ°ï¼ç空æ 0 åç¨ç¤¾ä¿åºæ° | **ååºå段æ°å¢ï¼get / listï¼ï¼** | åæ®µ | ç±»å | 说æ | |------|------|------| | deptIds | Long[] | éç¨é¨é¨IDåè¡¨ï¼æªç»å®è¿å `[]` | | deptNames | String | éç¨é¨é¨åç§°ï¼å¤ä¸ªç¨ãããè¿æ¥ï¼æªç»å®è¿å空串ãåç§°è§£æå¤±è´¥æ¶åé `ID=xxx` | | defaultSocialSecurityBase | Decimal | é»è®¤ç¤¾ä¿ç¼´è´¹åºæ°ï¼å¯ä¸º null | | defaultHousingFundBase | Decimal | é»è®¤å ¬ç§¯éç¼´è´¹åºæ°ï¼å¯ä¸º null | **ååºç¤ºä¾ï¼** ```json { "code": 0, "data": { "id": 3, "name": "2026å¹´å®å¤ç¤¾ä¿æ å", "effectiveDate": "2026-01-01", "deptIds": [119, 129], "deptNames": "ç产é¨ãä»å¨é¨", "defaultSocialSecurityBase": 5023.00, "defaultHousingFundBase": 0.00, "status": 0 } } ``` **é¨é¨å²çªæ¥éï¼code 1030005027ï¼ï¼** ```json { "code": 1030005027, "data": null, "msg": "é¨é¨ãç产é¨ãå·²ç»å®æ¹æ¡ã2025å¹´å®å¤ç¤¾ä¿æ åãï¼æ æ³åç»å®å°æ¹æ¡ã2026å¹´å®å¤ç¤¾ä¿æ åãã请å å¨åæ¹æ¡ä¸åæ¶è¯¥é¨é¨ï¼ææ¹éå ¶å®é¨é¨" } ``` ## åæ®µå±ç¤ºè§å | åæ®µ | å±ç¤ºä½ç½® | 说æ | |------|----------|------| | éç¨é¨é¨ | æ¹æ¡è¡¨åï¼å¤éæ ï¼ | ä¸éè¡¨ç¤ºå ¨å±é»è®¤æ¹æ¡ï¼placeholder å·²åæãåªå¯¹æéé¨é¨æ¬çº§çåå·¥çæã | | éç¨é¨é¨ | æ¹æ¡å表 | ç´æ¥å±ç¤ºå端 `deptNames`ï¼ä¸ºç©ºæ¶æ¾ç¤ºãå ¨å±é»è®¤ãæ ç¾ | | é»è®¤ç¤¾ä¿åºæ° / é»è®¤å ¬ç§¯éåºæ° | æ¹æ¡è¡¨å | `InputNumber`ï¼`min: 0`ã`precision: 2`ï¼å 许ç空 | | 社ä¿/å ¬ç§¯éæ£æ¬¾ | æ ¸ç®å表ãè¯ç®å¼¹çª | æ éæ¹å¨ï¼åç«¯ææ°ä¼å çº§åæ° | ## ä¸å¡è§å说æ | åºæ¯ | è§å | |------|------| | æ¯ä¾æ¥æºä¼å 级 | â åå·¥ç¤¾ä¿æ¡£æ¡æå®çæ¹æ¡ â¡ åå·¥æå¨é¨é¨ç»å®çå¯ç¨æ¹æ¡ï¼çææ¥æ â¤ æ ¸ç®æé´ï¼åææ°ï¼ â¢ æªç»å®ä»»ä½é¨é¨çå¯ç¨æ¹æ¡ä¸çææ¥æææ°è ï¼å ¨å±é»è®¤ï¼ â£ é½æ²¡æåç¨ä»£ç é»è®¤æ¯ä¾ | | ç¼´è´¹åºæ°ä¼å 级 | 社ä¿åºæ°ï¼æ¡£æ¡ â æ¹æ¡é»è®¤ç¤¾ä¿åºæ° â åå·¥åºæ¬å·¥èµï¼å ¬ç§¯éåºæ°ï¼æ¡£æ¡ â æ¹æ¡é»è®¤å ¬ç§¯éåºæ°ï¼>0 æç¨ï¼â 社ä¿åºæ° | | é¨é¨è¦çèå´ | åªè¦çæéé¨é¨**æ¬çº§**çåå·¥ï¼ä¸å«åé¨é¨ | | ä¸ä¸ªé¨é¨çå½å± | ä¸ä¸ªé¨é¨åæ¶åªè½ç»å®ä¸ä¸ªæ¹æ¡ï¼ä¿åæ¶è¥è¯¥é¨é¨å·²è¢«å«çæ¹æ¡å ç¨ï¼è¿åä¸é¢é£æ¡ç²¾ç¡®æ¥é | | å 餿¹æ¡ | æ¹æ¡å 餿¶å ¶é¨é¨å ³èä¸å¹¶è§£é¤ï¼é¨é¨éä¹ç©ºé² | ## 注æäºé¡¹ - æ¹æ¡çãéç¨é¨é¨ãæ¯**æ´ç»æ¿æ¢**è¯ä¹ï¼ç¼è¾æ¶è¦æå½åç»å®çé¨é¨å ¨é¨åæ¾å°å¤éæ¡éåæäº¤ï¼ä¸è½åªæäº¤æ¬æ¬¡æ°å¢çé¨é¨ã - åéæ¹æ¡é»è®¤æ²¡æç»å®ä»»ä½é¨é¨ï¼å æ¤é½æ¯ãå ¨å±é»è®¤ãåéï¼æ¤æ¶æ ¸ç®ç»æä¸æ¹é åå®å ¨ä¸è´ï¼ä¸é 23 ååå·¥å£å¾å·²éè¡æ ¸å¯¹ä¸è´ï¼ï¼è¦çæå¿ é¡»å ç»æ¹æ¡å¡«ãé»è®¤ç¼´è´¹åºæ°ãå¹¶ææ¹æ¡ç»å°é¨é¨ã - å工社ä¿å ¬ç§¯éæ¡£æ¡éå·²æå®æ¹æ¡çåå·¥ï¼æ°¸è¿ä¼å èµ°æ¡£æ¡ï¼æ¹æ¡ç»å®é¨é¨ä¸ä¼æ¹åä»ä»¬çéé¢ã - æ¯ä¾è¾å ¥æ¡èµ°çæ¯ãç¾åæ¯æ¾ç¤ºãå°æ°åå¨ãï¼çé¢å¡« 8.5 表示 8.5%ï¼è½åº 0.085ï¼æ¾ç¤ºä¿ç 2 ä½ç¾åæ¯å°æ°ï¼ä¸æ°æ®åº `decimal(5,4)` 精度ä¸ä¸å¯¹åºã个ç¨ç¨çé 置页ç表åä¸å表åå£å¾ã docs/sql/config_export_all_20260904.sql
@@ -5525,6 +5525,8 @@ `maternity_ratio` decimal(5,4) NOT NULL DEFAULT '0.0050' COMMENT 'çè²ä¿é©ä¼ä¸ç¼´çº³æ¯ä¾', `housing_fund_company_ratio` decimal(5,4) NOT NULL DEFAULT '0.1200' COMMENT 'å ¬ç§¯éä¼ä¸ç¼´çº³æ¯ä¾', `housing_fund_personal_ratio` decimal(5,4) NOT NULL DEFAULT '0.1200' COMMENT 'å ¬ç§¯é个人缴纳æ¯ä¾', `default_social_security_base` decimal(12,2) DEFAULT NULL COMMENT 'é»è®¤ç¤¾ä¿ç¼´è´¹åºæ°ï¼ç©ºåç¨åå·¥åºæ¬å·¥èµï¼', `default_housing_fund_base` decimal(12,2) DEFAULT NULL COMMENT 'é»è®¤å ¬ç§¯éç¼´è´¹åºæ°ï¼ç©ºæ 0 åç¨ç¤¾ä¿ç¼´è´¹åºæ°ï¼', `status` tinyint NOT NULL DEFAULT '0' COMMENT 'ç¶æï¼0-å¯ç¨ï¼1-ç¦ç¨', `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '夿³¨', `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT 'å建è ', @@ -5536,6 +5538,22 @@ KEY `idx_effective_date` (`effective_date`) USING BTREE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='HRM社ä¿å ¬ç§¯éæ¹æ¡è¡¨'; -- ============ 表ï¼hrm_social_security_scheme_deptï¼ä» DDLï¼æ æ°æ®ï¼ ============ DROP TABLE IF EXISTS `hrm_social_security_scheme_dept`; CREATE TABLE `hrm_social_security_scheme_dept` ( `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主é®', `scheme_id` bigint NOT NULL COMMENT '社ä¿å ¬ç§¯éæ¹æ¡ID', `dept_id` bigint NOT NULL COMMENT 'éç¨é¨é¨ID', `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT 'å建è ', `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'å建æ¶é´', `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT 'æ´æ°è ', `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'æ´æ°æ¶é´', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT 'æ¯å¦å é¤', PRIMARY KEY (`id`) USING BTREE, KEY `idx_scheme_id` (`scheme_id`) USING BTREE, KEY `idx_dept_id` (`dept_id`) USING BTREE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='HRM社ä¿å ¬ç§¯éæ¹æ¡éç¨é¨é¨è¡¨'; -- ============ 表ï¼hrm_tax_rate_configï¼ä» DDLï¼æ æ°æ®ï¼ ============ DROP TABLE IF EXISTS `hrm_tax_rate_config`; CREATE TABLE `hrm_tax_rate_config` ( sql/mysql/hrm_social_security_scheme_dept.sql
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,43 @@ -- 社ä¿å ¬ç§¯éæ¹æ¡ï¼æ¹ä¸ºãæé¨é¨ç»å®ã -- 1) æ¹æ¡è¡¨å¢å é»è®¤ç¼´è´¹åºæ°ï¼ä¸éé¨é¨çåå·¥æå®è®¡ç®ï¼ -- 2) æ°å¢ãæ¹æ¡ - éç¨é¨é¨ãå ³è表ï¼ä¸ä¸ªæ¹æ¡å¯ç»å®å¤ä¸ªé¨é¨ï¼ä¸ä¸ªé¨é¨åªè½ç»å®ä¸ä¸ªæ¹æ¡ï¼å¯ä¸æ§å¨æå¡å±æ ¡éªï¼ -- 说æï¼ALTER TABLE ADD COLUMN 䏿¯æ IF NOT EXISTSï¼è¿éå æ¥ information_schema åå³å®æ¯å¦æ§è¡ SET @db := DATABASE(); -- 1.1 é»è®¤ç¤¾ä¿ç¼´è´¹åºæ° SET @exists := (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = @db AND table_name = 'hrm_social_security_scheme' AND column_name = 'default_social_security_base'); SET @sql := IF(@exists = 0, 'ALTER TABLE `hrm_social_security_scheme` ADD COLUMN `default_social_security_base` decimal(12,2) DEFAULT NULL COMMENT ''é»è®¤ç¤¾ä¿ç¼´è´¹åºæ°ï¼ç©ºåç¨åå·¥åºæ¬å·¥èµï¼'' AFTER `housing_fund_personal_ratio`', 'SELECT 1'); PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; -- 1.2 é»è®¤å ¬ç§¯éç¼´è´¹åºæ° SET @exists := (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = @db AND table_name = 'hrm_social_security_scheme' AND column_name = 'default_housing_fund_base'); SET @sql := IF(@exists = 0, 'ALTER TABLE `hrm_social_security_scheme` ADD COLUMN `default_housing_fund_base` decimal(12,2) DEFAULT NULL COMMENT ''é»è®¤å ¬ç§¯éç¼´è´¹åºæ°ï¼ç©ºæ 0 åç¨ç¤¾ä¿ç¼´è´¹åºæ°ï¼'' AFTER `default_social_security_base`', 'SELECT 1'); PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; -- 2. æ¹æ¡ - éç¨é¨é¨å ³è表 CREATE TABLE IF NOT EXISTS `hrm_social_security_scheme_dept` ( `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主é®', `scheme_id` bigint NOT NULL COMMENT '社ä¿å ¬ç§¯éæ¹æ¡ID', `dept_id` bigint NOT NULL COMMENT 'éç¨é¨é¨ID', `creator` varchar(64) DEFAULT '' COMMENT 'å建人', `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'å建æ¶é´', `updater` varchar(64) DEFAULT '' COMMENT 'æ´æ°äºº', `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'æ´æ°æ¶é´', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT 'æ¯å¦å é¤', PRIMARY KEY (`id`), KEY `idx_scheme_id` (`scheme_id`), KEY `idx_dept_id` (`dept_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT '社ä¿å ¬ç§¯éæ¹æ¡éç¨é¨é¨'; -- åæ»ï¼å¦éï¼ï¼ -- ALTER TABLE `hrm_social_security_scheme` DROP COLUMN `default_social_security_base`, DROP COLUMN `default_housing_fund_base`; -- DROP TABLE IF EXISTS `hrm_social_security_scheme_dept`; yudao-module-hrm-api/src/main/java/cn/iocoder/yudao/module/hrm/enums/ErrorCodeConstants.java
@@ -123,6 +123,7 @@ ErrorCode SALARY_PAYMENT_HAS_PAID_DETAIL = new ErrorCode(1_030_005_024, "å é¤å¤±è´¥ï¼åå ï¼åå¨å·²åæ¾æç»ï¼è¯·å æ¤é"); ErrorCode SALARY_STRUCTURE_NAME_EXISTS = new ErrorCode(1_030_005_025, "èªé ¬ç»æåç§°å·²åå¨"); ErrorCode SALARY_STRUCTURE_IN_USE = new ErrorCode(1_030_005_026, "èªé ¬ç»ææ£å¨è¢«å工使ç¨ï¼æ æ³å é¤"); ErrorCode SOCIAL_SECURITY_SCHEME_DEPT_EXISTS = new ErrorCode(1_030_005_027, "é¨é¨ã{}ãå·²ç»å®æ¹æ¡ã{}ãï¼æ æ³åç»å®å°æ¹æ¡ã{}ãã请å å¨åæ¹æ¡ä¸åæ¶è¯¥é¨é¨ï¼ææ¹éå ¶å®é¨é¨"); // ========== çæ¬¡ç®¡ç 1-030-009-000 ========== ErrorCode SHIFT_NOT_EXISTS = new ErrorCode(1_030_009_000, "çæ¬¡ä¸åå¨"); yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/salary/HrmSocialSecuritySchemeController.java
@@ -1,11 +1,14 @@ package cn.iocoder.yudao.module.hrm.controller.admin.salary; import cn.hutool.core.collection.CollUtil; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.hrm.controller.admin.salary.vo.HrmSocialSecuritySchemeRespVO; import cn.iocoder.yudao.module.hrm.controller.admin.salary.vo.HrmSocialSecuritySchemeSaveReqVO; import cn.iocoder.yudao.module.hrm.dal.dataobject.salary.HrmSocialSecuritySchemeDO; import cn.iocoder.yudao.module.hrm.service.salary.HrmSocialSecuritySchemeService; import cn.iocoder.yudao.module.system.api.dept.DeptApi; import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; @@ -15,7 +18,10 @@ import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; @@ -28,20 +34,21 @@ @Resource private HrmSocialSecuritySchemeService schemeService; @Resource private DeptApi deptApi; @PostMapping("/create") @Operation(summary = "å建社ä¿å ¬ç§¯éæ¹æ¡") @PreAuthorize("@ss.hasPermission('hrm:social-security:create')") public CommonResult<Long> createScheme(@Valid @RequestBody HrmSocialSecuritySchemeSaveReqVO createReqVO) { HrmSocialSecuritySchemeDO scheme = BeanUtils.toBean(createReqVO, HrmSocialSecuritySchemeDO.class); return success(schemeService.createScheme(scheme)); return success(schemeService.createScheme(createReqVO)); } @PutMapping("/update") @Operation(summary = "æ´æ°ç¤¾ä¿å ¬ç§¯éæ¹æ¡") @PreAuthorize("@ss.hasPermission('hrm:social-security:update')") public CommonResult<Boolean> updateScheme(@Valid @RequestBody HrmSocialSecuritySchemeSaveReqVO updateReqVO) { HrmSocialSecuritySchemeDO scheme = BeanUtils.toBean(updateReqVO, HrmSocialSecuritySchemeDO.class); schemeService.updateScheme(scheme); schemeService.updateScheme(updateReqVO); return success(true); } @@ -60,7 +67,13 @@ @PreAuthorize("@ss.hasPermission('hrm:social-security:query')") public CommonResult<HrmSocialSecuritySchemeRespVO> getScheme(@RequestParam("id") Long id) { HrmSocialSecuritySchemeDO scheme = schemeService.getScheme(id); return success(BeanUtils.toBean(scheme, HrmSocialSecuritySchemeRespVO.class)); if (scheme == null) { return success(null); } HrmSocialSecuritySchemeRespVO respVO = BeanUtils.toBean(scheme, HrmSocialSecuritySchemeRespVO.class); // å¡«å éç¨é¨é¨ fillDeptInfo(List.of(respVO)); return success(respVO); } @GetMapping("/list") @@ -70,7 +83,34 @@ public CommonResult<List<HrmSocialSecuritySchemeRespVO>> getSchemeList( @RequestParam(value = "status", required = false) Integer status) { List<HrmSocialSecuritySchemeDO> list = schemeService.getSchemeList(status); return success(BeanUtils.toBean(list, HrmSocialSecuritySchemeRespVO.class)); List<HrmSocialSecuritySchemeRespVO> respList = BeanUtils.toBean(list, HrmSocialSecuritySchemeRespVO.class); // å¡«å éç¨é¨é¨ fillDeptInfo(respList); return success(respList); } /** * å¡«å æ¹æ¡çéç¨é¨é¨IDä¸é¨é¨åç§° */ private void fillDeptInfo(List<HrmSocialSecuritySchemeRespVO> list) { if (CollUtil.isEmpty(list)) { return; } List<Long> schemeIds = list.stream().map(HrmSocialSecuritySchemeRespVO::getId).toList(); Map<Long, List<Long>> schemeDeptIdMap = schemeService.getSchemeDeptIdMap(schemeIds); List<Long> allDeptIds = schemeDeptIdMap.values().stream().flatMap(List::stream).distinct().toList(); Map<Long, DeptRespDTO> deptMap = CollUtil.isEmpty(allDeptIds) ? Collections.emptyMap() : deptApi.getDeptMap(allDeptIds); for (HrmSocialSecuritySchemeRespVO respVO : list) { List<Long> deptIds = schemeDeptIdMap.getOrDefault(respVO.getId(), Collections.emptyList()); respVO.setDeptIds(deptIds); respVO.setDeptNames(deptIds.stream() .map(deptId -> { DeptRespDTO dept = deptMap.get(deptId); return dept != null ? dept.getName() : "ID=" + deptId; }) .collect(Collectors.joining("ã"))); } } } yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/salary/vo/HrmSocialSecuritySchemeRespVO.java
@@ -6,6 +6,7 @@ import java.math.BigDecimal; import java.time.LocalDate; import java.time.LocalDateTime; import java.util.List; @Schema(description = "管çåå° - 社ä¿å ¬ç§¯éæ¹æ¡ Response VO") @Data @@ -56,6 +57,19 @@ @Schema(description = "å ¬ç§¯é个人缴纳æ¯ä¾", example = "0.12") private BigDecimal housingFundPersonalRatio; // ========== ç¼´è´¹åºæ° ========== @Schema(description = "é»è®¤ç¤¾ä¿ç¼´è´¹åºæ°ï¼ç©ºåç¨åå·¥åºæ¬å·¥èµï¼", example = "5023.00") private BigDecimal defaultSocialSecurityBase; @Schema(description = "é»è®¤å ¬ç§¯éç¼´è´¹åºæ°ï¼ç©ºæ 0 åç¨ç¤¾ä¿ç¼´è´¹åºæ°ï¼", example = "5023.00") private BigDecimal defaultHousingFundBase; @Schema(description = "éç¨é¨é¨IDå表ï¼ä¸ºç©ºè¡¨ç¤ºå ¨å±é»è®¤æ¹æ¡ï¼", example = "[119,129]") private List<Long> deptIds; @Schema(description = "éç¨é¨é¨åç§°ï¼å¤ä¸ªç¨ãåéï¼ä¸ºç©ºè¡¨ç¤ºå ¨å±é»è®¤ï¼", example = "ç产é¨ãä»å¨é¨") private String deptNames; @Schema(description = "ç¶æï¼0-å¯ç¨ï¼1-ç¦ç¨", example = "0") private Integer status; yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/salary/vo/HrmSocialSecuritySchemeSaveReqVO.java
@@ -7,6 +7,7 @@ import java.math.BigDecimal; import java.time.LocalDate; import java.util.List; @Schema(description = "管çåå° - 社ä¿å ¬ç§¯éæ¹æ¡æ°å¢/ä¿®æ¹ Request VO") @Data @@ -59,6 +60,16 @@ @Schema(description = "å ¬ç§¯é个人缴纳æ¯ä¾", example = "0.12") private BigDecimal housingFundPersonalRatio; // ========== ç¼´è´¹åºæ° ========== @Schema(description = "é»è®¤ç¤¾ä¿ç¼´è´¹åºæ°ï¼ç©ºåç¨åå·¥åºæ¬å·¥èµï¼", example = "5023.00") private BigDecimal defaultSocialSecurityBase; @Schema(description = "é»è®¤å ¬ç§¯éç¼´è´¹åºæ°ï¼ç©ºæ 0 åç¨ç¤¾ä¿ç¼´è´¹åºæ°ï¼", example = "5023.00") private BigDecimal defaultHousingFundBase; @Schema(description = "éç¨é¨é¨IDå表ï¼ä¸ºç©ºè¡¨ç¤ºå ¨å±é»è®¤æ¹æ¡ï¼", example = "[119,129]") private List<Long> deptIds; @Schema(description = "ç¶æï¼0-å¯ç¨ï¼1-ç¦ç¨", example = "0") private Integer status; yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/dataobject/salary/HrmSocialSecuritySchemeDO.java
@@ -1,7 +1,9 @@ package cn.iocoder.yudao.module.hrm.dal.dataobject.salary; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import com.baomidou.mybatisplus.annotation.FieldStrategy; 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.*; @@ -94,6 +96,22 @@ */ private BigDecimal housingFundPersonalRatio; // ========== ç¼´è´¹åºæ° ========== /** * é»è®¤ç¤¾ä¿ç¼´è´¹åºæ°ï¼ç©ºåç¨åå·¥åºæ¬å·¥èµï¼ * * updateStrategy=ALWAYSï¼æ¸ ç©ºè¯¥åæ®µæ¶è¦è½åå NULL */ @TableField(updateStrategy = FieldStrategy.ALWAYS) private BigDecimal defaultSocialSecurityBase; /** * é»è®¤å ¬ç§¯éç¼´è´¹åºæ°ï¼ç©ºæ 0 åç¨ç¤¾ä¿ç¼´è´¹åºæ°ï¼ * * updateStrategy å {@link #defaultSocialSecurityBase} */ @TableField(updateStrategy = FieldStrategy.ALWAYS) private BigDecimal defaultHousingFundBase; /** * ç¶æï¼0-å¯ç¨ï¼1-ç¦ç¨ */ yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/dataobject/salary/HrmSocialSecuritySchemeDeptDO.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,42 @@ package cn.iocoder.yudao.module.hrm.dal.dataobject.salary; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.*; /** * 社ä¿å ¬ç§¯éæ¹æ¡éç¨é¨é¨ DO * * ä¸ä¸ªæ¹æ¡å¯ç»å®å¤ä¸ªé¨é¨ï¼ä¸ä¸ªé¨é¨åªè½ç»å®ä¸ä¸ªæ¹æ¡ï¼å¨ Service 屿 ¡éªï¼ * * @author è¶ çº§ç®¡çå */ @TableName("hrm_social_security_scheme_dept") @KeySequence("hrm_social_security_scheme_dept_seq") @Data @EqualsAndHashCode(callSuper = true) @ToString(callSuper = true) @Builder @NoArgsConstructor @AllArgsConstructor public class HrmSocialSecuritySchemeDeptDO extends BaseDO { /** * ä¸»é® */ @TableId private Long id; /** * 社ä¿å ¬ç§¯éæ¹æ¡ID */ private Long schemeId; /** * éç¨é¨é¨ID */ private Long deptId; } yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/mysql/salary/HrmSocialSecuritySchemeDeptMapper.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,58 @@ package cn.iocoder.yudao.module.hrm.dal.mysql.salary; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.module.hrm.dal.dataobject.salary.HrmSocialSecuritySchemeDeptDO; import org.apache.ibatis.annotations.Mapper; import java.util.Collection; import java.util.List; import java.util.Set; import java.util.stream.Collectors; /** * 社ä¿å ¬ç§¯éæ¹æ¡éç¨é¨é¨ Mapper * * @author è¶ çº§ç®¡çå */ @Mapper public interface HrmSocialSecuritySchemeDeptMapper extends BaseMapperX<HrmSocialSecuritySchemeDeptDO> { /** * ææ¹æ¡æ´ç»æ¿æ¢ï¼å å é¤è¯¥æ¹æ¡çå ¨é¨ï¼é»è¾å é¤ï¼å ³èè¡ */ default void deleteBySchemeId(Long schemeId) { delete(new LambdaQueryWrapperX<HrmSocialSecuritySchemeDeptDO>() .eq(HrmSocialSecuritySchemeDeptDO::getSchemeId, schemeId)); } default List<HrmSocialSecuritySchemeDeptDO> selectListBySchemeId(Long schemeId) { return selectList(new LambdaQueryWrapperX<HrmSocialSecuritySchemeDeptDO>() .eq(HrmSocialSecuritySchemeDeptDO::getSchemeId, schemeId)); } default List<HrmSocialSecuritySchemeDeptDO> selectListBySchemeIds(Collection<Long> schemeIds) { return selectList(new LambdaQueryWrapperX<HrmSocialSecuritySchemeDeptDO>() .inIfPresent(HrmSocialSecuritySchemeDeptDO::getSchemeId, schemeIds)); } default List<HrmSocialSecuritySchemeDeptDO> selectListByDeptIds(Collection<Long> deptIds) { return selectList(new LambdaQueryWrapperX<HrmSocialSecuritySchemeDeptDO>() .inIfPresent(HrmSocialSecuritySchemeDeptDO::getDeptId, deptIds)); } default List<HrmSocialSecuritySchemeDeptDO> selectListByDeptId(Long deptId) { return selectList(new LambdaQueryWrapperX<HrmSocialSecuritySchemeDeptDO>() .eq(HrmSocialSecuritySchemeDeptDO::getDeptId, deptId)); } /** * æ¥è¯¢å ¨é¨å·²ç»å®é¨é¨çæ¹æ¡IDï¼ç¨äºåºåãé¨é¨ä¸å±æ¹æ¡ãä¸ãå ¨å±é»è®¤æ¹æ¡ãï¼ */ default Set<Long> selectAllBoundSchemeIds() { return selectObjs(new LambdaQueryWrapperX<HrmSocialSecuritySchemeDeptDO>() .select(HrmSocialSecuritySchemeDeptDO::getSchemeId)) .stream().map(obj -> (Long) obj).collect(Collectors.toSet()); } } yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/salary/HrmSalaryCalculationServiceImpl.java
@@ -44,6 +44,7 @@ import java.time.LocalDateTime; import java.time.YearMonth; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; @@ -85,6 +86,8 @@ private HrmEmployeeSocialSecurityMapper employeeSocialSecurityMapper; @Resource private HrmSocialSecuritySchemeMapper socialSecuritySchemeMapper; @Resource private HrmSocialSecuritySchemeService socialSecuritySchemeService; @Resource private HrmNoRedisDAO noRedisDAO; @Resource @@ -140,6 +143,8 @@ .toList(); // 2. éååå·¥è¿è¡èªé ¬æ ¸ç® // é¨é¨ -> æ¹æ¡ çè§£æç»æå¨æ¬æ¬¡æ ¸ç®å ç¼åï¼é¿å éåå·¥é夿¥åº Map<Long, HrmSocialSecuritySchemeDO> deptSchemeCache = new HashMap<>(); for (HrmEmployeeDO employee : employees) { // employeeId æ¯åå·¥IDï¼ç¨äºå ³èèªé ¬æ¡£æ¡ãç¤¾ä¿æ¡£æ¡ãæ ¸ç®è®°å½ Long employeeId = employee.getId(); @@ -165,11 +170,8 @@ // 2.3 è·åå工社ä¿å ¬ç§¯éæ¡£æ¡ï¼æåå·¥IDæ¥è¯¢ï¼åææ°çæçï¼ HrmEmployeeSocialSecurityDO socialSecurity = employeeSocialSecurityMapper.selectLatestByUserId(employeeId); // 2.4 妿æç¤¾ä¿æ¡£æ¡ï¼è·åç»å®çæ¹æ¡ HrmSocialSecuritySchemeDO scheme = null; if (socialSecurity != null && socialSecurity.getSocialSecuritySchemeId() != null) { scheme = socialSecuritySchemeMapper.selectById(socialSecurity.getSocialSecuritySchemeId()); } // 2.4 è·åæ¹æ¡ï¼åå·¥æ¡£æ¡æå® > æå¨é¨é¨ç»å® > å ¨å±é»è®¤ HrmSocialSecuritySchemeDO scheme = resolveScheme(socialSecurity, employee, effectiveDate, deptSchemeCache); // 2.5 æå»ºæ ¸ç®è®°å½ï¼å 嫿£é¤è®¡ç®ï¼éè¿æ¹æ¡è·åæ¯ä¾ï¼ HrmSalaryCalculationDO calculation = buildSalaryCalculation(period, employeeId, employee, employeeSalary, socialSecurity, scheme, effectiveDate); @@ -245,13 +247,22 @@ BigDecimal totalIncome = baseSalary.add(performanceSalary).add(mealAllowance) .add(transportAllowance).add(otherAllowance).add(overtimePay); // è·å社ä¿åºæ°ï¼åå·¥ç¤¾ä¿æ¡£æ¡ > åå·¥åºæ¬å·¥èµ // è·å社ä¿åºæ°ï¼åå·¥ç¤¾ä¿æ¡£æ¡ > æ¹æ¡é»è®¤ç¼´è´¹åºæ° > åå·¥åºæ¬å·¥èµ BigDecimal socialSecurityBase = (socialSecurity != null && socialSecurity.getSocialSecurityBase() != null) ? socialSecurity.getSocialSecurityBase() : baseSalary; ? socialSecurity.getSocialSecurityBase() : (scheme != null && scheme.getDefaultSocialSecurityBase() != null ? scheme.getDefaultSocialSecurityBase() : baseSalary); // è·åå ¬ç§¯éåºæ°ï¼åå·¥ç¤¾ä¿æ¡£æ¡ > åå·¥åºæ¬å·¥èµ BigDecimal housingFundBase = (socialSecurity != null && socialSecurity.getHousingFundBase() != null) ? socialSecurity.getHousingFundBase() : baseSalary; // è·åå ¬ç§¯éåºæ°ï¼åå·¥ç¤¾ä¿æ¡£æ¡ > æ¹æ¡é»è®¤å ¬ç§¯éåºæ°ï¼å¤§äº 0 æ¶ï¼> 社ä¿åºæ° BigDecimal housingFundBase; if (socialSecurity != null && socialSecurity.getHousingFundBase() != null) { housingFundBase = socialSecurity.getHousingFundBase(); } else if (scheme != null && scheme.getDefaultHousingFundBase() != null && scheme.getDefaultHousingFundBase().compareTo(BigDecimal.ZERO) > 0) { housingFundBase = scheme.getDefaultHousingFundBase(); } else { housingFundBase = socialSecurityBase; } // 仿¹æ¡ä¸è·å缴纳æ¯ä¾ï¼ä¼å ä½¿ç¨æ¹æ¡ä¸çæ¯ä¾ï¼å¦å使ç¨é»è®¤æ¯ä¾ï¼ BigDecimal pensionPersonalRatio = (scheme != null && scheme.getPensionPersonalRatio() != null) @@ -316,6 +327,30 @@ .totalWorkHours(totalWorkHours) .status(0) // å¾ ç¡®è®¤ .build(); } /** * è§£æåå·¥æ ¸ç®ç¨ç社ä¿å ¬ç§¯éæ¹æ¡ * * ä¼å 级ï¼åå·¥ç¤¾ä¿æ¡£æ¡æå®çæ¹æ¡ï¼ä¸ªå«è¦çï¼> åå·¥æå¨é¨é¨ç»å®çæ¹æ¡ > å ¨å±é»è®¤æ¹æ¡ã * é½åä¸å°æ¶è¿å nullï¼ç± {@link #buildSalaryCalculation} 使ç¨é»è®¤æ¯ä¾å¸¸éã * * @param deptSchemeCache æ¬æ¬¡æ ¸ç®å ãé¨é¨ -> æ¹æ¡ãçç¼åï¼å 许 null å¼ï¼ç¨äºç¼å"该é¨é¨æ æ¹æ¡"ï¼ */ private HrmSocialSecuritySchemeDO resolveScheme(HrmEmployeeSocialSecurityDO socialSecurity, HrmEmployeeDO employee, LocalDate periodDate, Map<Long, HrmSocialSecuritySchemeDO> deptSchemeCache) { if (socialSecurity != null && socialSecurity.getSocialSecuritySchemeId() != null) { HrmSocialSecuritySchemeDO scheme = socialSecuritySchemeMapper.selectById(socialSecurity.getSocialSecuritySchemeId()); if (scheme != null) { return scheme; } } Long deptId = employee.getDeptId(); if (!deptSchemeCache.containsKey(deptId)) { deptSchemeCache.put(deptId, socialSecuritySchemeService.resolveSchemeByDeptId(deptId, periodDate)); } return deptSchemeCache.get(deptId); } /** @@ -531,6 +566,8 @@ // 2. éåå工宿¶è®¡ç®èªé ¬ List<HrmSalaryCalculationDO> resultList = new java.util.ArrayList<>(); // é¨é¨ -> æ¹æ¡ çè§£æç»æå¨æ¬æ¬¡é¢è§å ç¼åï¼é¿å éåå·¥é夿¥åº Map<Long, HrmSocialSecuritySchemeDO> deptSchemeCache = new HashMap<>(); for (HrmEmployeeDO employee : employees) { Long employeeId = employee.getId(); @@ -543,11 +580,8 @@ // 2.2 è·åå工社ä¿å ¬ç§¯éæ¡£æ¡ï¼æåå·¥IDæ¥è¯¢ï¼åææ°çæçï¼ HrmEmployeeSocialSecurityDO socialSecurity = employeeSocialSecurityMapper.selectLatestByUserId(employeeId); // 2.3 妿æç¤¾ä¿æ¡£æ¡ï¼è·åç»å®çæ¹æ¡ HrmSocialSecuritySchemeDO scheme = null; if (socialSecurity != null && socialSecurity.getSocialSecuritySchemeId() != null) { scheme = socialSecuritySchemeMapper.selectById(socialSecurity.getSocialSecuritySchemeId()); } // 2.3 è·åæ¹æ¡ï¼åå·¥æ¡£æ¡æå® > æå¨é¨é¨ç»å® > å ¨å±é»è®¤ HrmSocialSecuritySchemeDO scheme = resolveScheme(socialSecurity, employee, effectiveDate, deptSchemeCache); // 2.4 æå»ºæ ¸ç®è®°å½ï¼å®æ¶è®¡ç®ï¼ä¸åå¨ï¼ HrmSalaryCalculationDO calculation = buildSalaryCalculation(period, employeeId, employee, employeeSalary, socialSecurity, scheme, effectiveDate); yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/salary/HrmSocialSecuritySchemeService.java
@@ -1,8 +1,12 @@ package cn.iocoder.yudao.module.hrm.service.salary; import cn.iocoder.yudao.module.hrm.controller.admin.salary.vo.HrmSocialSecuritySchemeSaveReqVO; import cn.iocoder.yudao.module.hrm.dal.dataobject.salary.HrmSocialSecuritySchemeDO; import java.time.LocalDate; import java.util.Collection; import java.util.List; import java.util.Map; /** * 社ä¿å ¬ç§¯éæ¹æ¡ Service æ¥å£ @@ -12,19 +16,19 @@ public interface HrmSocialSecuritySchemeService { /** * å建社ä¿å ¬ç§¯éæ¹æ¡ * å建社ä¿å ¬ç§¯éæ¹æ¡ï¼å«éç¨é¨é¨ï¼ * * @param scheme æ¹æ¡ä¿¡æ¯ * @param createReqVO æ¹æ¡ä¿¡æ¯ * @return æ¹æ¡ID */ Long createScheme(HrmSocialSecuritySchemeDO scheme); Long createScheme(HrmSocialSecuritySchemeSaveReqVO createReqVO); /** * æ´æ°ç¤¾ä¿å ¬ç§¯éæ¹æ¡ * æ´æ°ç¤¾ä¿å ¬ç§¯éæ¹æ¡ï¼å«éç¨é¨é¨ï¼æ´ç»æ¿æ¢ï¼ * * @param scheme æ¹æ¡ä¿¡æ¯ * @param updateReqVO æ¹æ¡ä¿¡æ¯ */ void updateScheme(HrmSocialSecuritySchemeDO scheme); void updateScheme(HrmSocialSecuritySchemeSaveReqVO updateReqVO); /** * å é¤ç¤¾ä¿å ¬ç§¯éæ¹æ¡ @@ -49,4 +53,31 @@ */ List<HrmSocialSecuritySchemeDO> getSchemeList(Integer status); } /** * è·åæ¹æ¡ç»å®çéç¨é¨é¨IDå表 * * @param schemeId æ¹æ¡ID * @return é¨é¨IDå表 */ List<Long> getSchemeDeptIds(Long schemeId); /** * æ¹éè·åæ¹æ¡ç»å®çéç¨é¨é¨IDï¼æ¹æ¡ID -> é¨é¨IDåè¡¨ï¼ * * @param schemeIds æ¹æ¡IDéå * @return æ¹æ¡ID -> é¨é¨IDå表 */ Map<Long, List<Long>> getSchemeDeptIdMap(Collection<Long> schemeIds); /** * æé¨é¨è§£ææ ¸ç®ç¨ç社ä¿å ¬ç§¯éæ¹æ¡ * * ä¼å 级ï¼è¯¥é¨é¨ç»å®çæ¹æ¡ï¼çææ¥æä¸æäºæ ¸ç®æé´ï¼åææ°ï¼> å ¨å±é»è®¤æ¹æ¡ï¼æªç»å®ä»»ä½é¨é¨çæ¹æ¡ä¸çææ¥æææ°è ï¼ * * @param deptId åå·¥æå¨é¨é¨IDï¼å¯ä¸ºç©ºï¼ * @param periodDate æ ¸ç®æé´çæåæ¥æ * @return æ¹æ¡ï¼æ¥ä¸å°è¿å nullï¼ç±è°ç¨æ¹ä½¿ç¨é»è®¤æ¯ä¾å¸¸é */ HrmSocialSecuritySchemeDO resolveSchemeByDeptId(Long deptId, LocalDate periodDate); } yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/salary/HrmSocialSecuritySchemeServiceImpl.java
@@ -1,18 +1,36 @@ package cn.iocoder.yudao.module.hrm.service.salary; import cn.hutool.core.collection.CollUtil; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.module.hrm.controller.admin.salary.vo.HrmSocialSecuritySchemeSaveReqVO; import cn.iocoder.yudao.module.hrm.dal.dataobject.salary.HrmSocialSecuritySchemeDO; import cn.iocoder.yudao.module.hrm.dal.dataobject.salary.HrmSocialSecuritySchemeDeptDO; import cn.iocoder.yudao.module.hrm.dal.mysql.salary.HrmSocialSecuritySchemeDeptMapper; import cn.iocoder.yudao.module.hrm.dal.mysql.salary.HrmSocialSecuritySchemeMapper; import cn.iocoder.yudao.module.system.api.dept.DeptApi; import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; import jakarta.annotation.Resource; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import java.time.LocalDate; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.hrm.enums.ErrorCodeConstants.SOCIAL_SECURITY_SCHEME_DEPT_EXISTS; import static cn.iocoder.yudao.module.hrm.enums.ErrorCodeConstants.SOCIAL_SECURITY_SCHEME_NOT_EXISTS; /** * 社ä¿å ¬ç§¯éæ¹æ¡ Service å®ç°ç±» * * æ¹æ¡ç缴纳æ¯ä¾æãæ¹æ¡ - éç¨é¨é¨ãå ³è表çæï¼ä¸ä¸ªé¨é¨åªè½ç»å®ä¸ä¸ªæ¹æ¡ï¼æªç»å®ä»»ä½é¨é¨çæ¹æ¡ä½ä¸ºå ¨å±é»è®¤æ¹æ¡ã * * @author è¶ çº§ç®¡çå */ @@ -20,24 +38,42 @@ @Validated public class HrmSocialSecuritySchemeServiceImpl implements HrmSocialSecuritySchemeService { /** * å¯ç¨ç¶æ */ private static final Integer STATUS_ENABLE = 0; @Resource private HrmSocialSecuritySchemeMapper schemeMapper; @Resource private HrmSocialSecuritySchemeDeptMapper schemeDeptMapper; @Resource private DeptApi deptApi; @Override public Long createScheme(HrmSocialSecuritySchemeDO scheme) { @Transactional(rollbackFor = Exception.class) public Long createScheme(HrmSocialSecuritySchemeSaveReqVO createReqVO) { HrmSocialSecuritySchemeDO scheme = BeanUtils.toBean(createReqVO, HrmSocialSecuritySchemeDO.class); schemeMapper.insert(scheme); saveSchemeDepts(scheme.getId(), createReqVO.getName(), createReqVO.getDeptIds()); return scheme.getId(); } @Override public void updateScheme(HrmSocialSecuritySchemeDO scheme) { validateSchemeExists(scheme.getId()); schemeMapper.updateById(scheme); @Transactional(rollbackFor = Exception.class) public void updateScheme(HrmSocialSecuritySchemeSaveReqVO updateReqVO) { validateSchemeExists(updateReqVO.getId()); schemeMapper.updateById(BeanUtils.toBean(updateReqVO, HrmSocialSecuritySchemeDO.class)); saveSchemeDepts(updateReqVO.getId(), updateReqVO.getName(), updateReqVO.getDeptIds()); } @Override @Transactional(rollbackFor = Exception.class) public void deleteScheme(Long id) { validateSchemeExists(id); schemeDeptMapper.deleteBySchemeId(id); schemeMapper.deleteById(id); } @@ -51,10 +87,115 @@ return schemeMapper.selectListByStatus(status); } private void validateSchemeExists(Long id) { if (schemeMapper.selectById(id) == null) { throw exception(SOCIAL_SECURITY_SCHEME_NOT_EXISTS); @Override public List<Long> getSchemeDeptIds(Long schemeId) { return schemeDeptMapper.selectListBySchemeId(schemeId).stream() .map(HrmSocialSecuritySchemeDeptDO::getDeptId) .toList(); } @Override public Map<Long, List<Long>> getSchemeDeptIdMap(Collection<Long> schemeIds) { if (CollUtil.isEmpty(schemeIds)) { return Map.of(); } return schemeDeptMapper.selectListBySchemeIds(schemeIds).stream() .collect(Collectors.groupingBy(HrmSocialSecuritySchemeDeptDO::getSchemeId, Collectors.mapping(HrmSocialSecuritySchemeDeptDO::getDeptId, Collectors.toList()))); } @Override public HrmSocialSecuritySchemeDO resolveSchemeByDeptId(Long deptId, LocalDate periodDate) { // 1. ä¼å å该é¨é¨ç»å®çæ¹æ¡ if (deptId != null) { List<Long> boundSchemeIds = schemeDeptMapper.selectListByDeptId(deptId).stream() .map(HrmSocialSecuritySchemeDeptDO::getSchemeId) .toList(); HrmSocialSecuritySchemeDO scheme = pickLatestEnabled(boundSchemeIds, periodDate); if (scheme != null) { return scheme; } } // 2. å åºåå ¨å±é»è®¤æ¹æ¡ï¼æªç»å®ä»»ä½é¨é¨çæ¹æ¡ä¸çææ¥æææ°è Set<Long> boundSchemeIds = schemeDeptMapper.selectAllBoundSchemeIds(); List<Long> globalSchemeIds = schemeMapper.selectListByStatus(STATUS_ENABLE).stream() .map(HrmSocialSecuritySchemeDO::getId) .filter(id -> !boundSchemeIds.contains(id)) .toList(); return pickLatestEnabled(globalSchemeIds, periodDate); } /** * ä»åéæ¹æ¡ä¸åãçææ¥æä¸æäºæ ¸ç®æé´ãçææ°ä¸æ¡å¯ç¨æ¹æ¡ * * è¥å ¨é¨åéæ¹æ¡é½æäºæ ¸ç®æé´ï¼ä¾å¦åå»ºå¥½ä¸ææçæçæ¹æ¡å°±æåæ ¸ç®ï¼ï¼åéå为åå ¶ä¸çææ¥æææ°ç䏿¡ï¼ * é¿å æ ¸ç®éé¢éé»è½å°ä»£ç éçé»è®¤æ¯ä¾ä¸ã */ private HrmSocialSecuritySchemeDO pickLatestEnabled(Collection<Long> schemeIds, LocalDate periodDate) { if (CollUtil.isEmpty(schemeIds)) { return null; } List<HrmSocialSecuritySchemeDO> schemes = schemeMapper.selectList( new LambdaQueryWrapperX<HrmSocialSecuritySchemeDO>() .in(HrmSocialSecuritySchemeDO::getId, schemeIds) .eq(HrmSocialSecuritySchemeDO::getStatus, STATUS_ENABLE) .orderByDesc(HrmSocialSecuritySchemeDO::getEffectiveDate) .orderByDesc(HrmSocialSecuritySchemeDO::getId)); if (CollUtil.isEmpty(schemes)) { return null; } return schemes.stream() .filter(scheme -> scheme.getEffectiveDate() == null || !scheme.getEffectiveDate().isAfter(periodDate)) .findFirst() .orElse(schemes.get(0)); } /** * æ´ç»æ¿æ¢æ¹æ¡çéç¨é¨é¨ï¼å æ ¡éªï¼åå æ§è¡ãææ°è¡ */ private void saveSchemeDepts(Long schemeId, String schemeName, List<Long> deptIds) { List<Long> distinctDeptIds = CollUtil.isEmpty(deptIds) ? List.of() : deptIds.stream().filter(Objects::nonNull).distinct().toList(); if (CollUtil.isNotEmpty(distinctDeptIds)) { // é¨é¨å¿ é¡»åå¨ deptApi.validateDeptList(distinctDeptIds); // ä¸ä¸ªé¨é¨åªè½ç»å®ä¸ä¸ªæ¹æ¡ validateDeptNotBoundByOtherScheme(schemeId, schemeName, distinctDeptIds); } schemeDeptMapper.deleteBySchemeId(schemeId); distinctDeptIds.forEach(deptId -> schemeDeptMapper.insert( HrmSocialSecuritySchemeDeptDO.builder().schemeId(schemeId).deptId(deptId).build())); } /** * æ ¡éªè¿äºé¨é¨æ²¡æè¢«å«çæ¹æ¡å ç¨ */ private void validateDeptNotBoundByOtherScheme(Long schemeId, String schemeName, List<Long> deptIds) { List<HrmSocialSecuritySchemeDeptDO> bindings = schemeDeptMapper.selectListByDeptIds(deptIds); if (CollUtil.isEmpty(bindings)) { return; } // åç§°è§£æåªæ¾å¨å¼å¸¸åæ¯ï¼é¿å æ£å¸¸ä¿å夿¥è¡¨ for (HrmSocialSecuritySchemeDeptDO binding : bindings) { if (Objects.equals(binding.getSchemeId(), schemeId)) { continue; } HrmSocialSecuritySchemeDO otherScheme = schemeMapper.selectById(binding.getSchemeId()); DeptRespDTO dept = deptApi.getDept(binding.getDeptId()); throw exception(SOCIAL_SECURITY_SCHEME_DEPT_EXISTS, dept != null ? dept.getName() : "ID=" + binding.getDeptId(), otherScheme != null ? otherScheme.getName() : "ID=" + binding.getSchemeId(), schemeName); } } } private HrmSocialSecuritySchemeDO validateSchemeExists(Long id) { HrmSocialSecuritySchemeDO scheme = schemeMapper.selectById(id); if (scheme == null) { throw exception(SOCIAL_SECURITY_SCHEME_NOT_EXISTS); } return scheme; } }