| | |
| | | `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'ç»æåç§°', |
| | | `base_salary` decimal(12, 2) NOT NULL COMMENT 'åºæ¬å·¥èµ', |
| | | `performance_ratio` decimal(4, 2) NULL DEFAULT 0.00 COMMENT '绩æå·¥èµå æ¯ï¼%ï¼', |
| | | `overtime_pay_ratio` decimal(4, 2) NULL DEFAULT 1.50 COMMENT 'å çå·¥èµåç', |
| | | `overtime_pay_ratio` decimal(4, 2) NULL DEFAULT 1.50 COMMENT '工使¥å çå·¥èµåç', |
| | | `rest_day_overtime_pay_ratio` decimal(4, 2) NULL DEFAULT 2.00 COMMENT '伿¯æ¥å çå·¥èµåç', |
| | | `legal_holiday_overtime_pay_ratio` decimal(4, 2) NULL DEFAULT 3.00 COMMENT 'æ³å®è忥å çå·¥èµåç', |
| | | `social_security_base` decimal(12, 2) NULL DEFAULT NULL COMMENT '社ä¿åºæ°', |
| | | `housing_fund_base` decimal(12, 2) NULL DEFAULT NULL COMMENT 'å
¬ç§¯éåºæ°', |
| | | `status` tinyint NOT NULL DEFAULT 0 COMMENT 'ç¶æï¼0-å¯ç¨ï¼1-ç¦ç¨', |
| | |
| | | `name` varchar(100) NOT NULL COMMENT 'ç»æåç§°', |
| | | `base_salary` decimal(12,2) NOT NULL COMMENT 'åºæ¬å·¥èµ', |
| | | `performance_ratio` decimal(4,2) DEFAULT 0 COMMENT '绩æå·¥èµå æ¯ï¼%ï¼', |
| | | `overtime_pay_ratio` decimal(4,2) DEFAULT 1.5 COMMENT 'å çå·¥èµåç', |
| | | `overtime_pay_ratio` decimal(4,2) DEFAULT 1.5 COMMENT '工使¥å çå·¥èµåç', |
| | | `rest_day_overtime_pay_ratio` decimal(4,2) DEFAULT 2.0 COMMENT '伿¯æ¥å çå·¥èµåç', |
| | | `legal_holiday_overtime_pay_ratio` decimal(4,2) DEFAULT 3.0 COMMENT 'æ³å®è忥å çå·¥èµåç', |
| | | `social_security_base` decimal(12,2) DEFAULT NULL COMMENT '社ä¿åºæ°', |
| | | `housing_fund_base` decimal(12,2) DEFAULT NULL COMMENT 'å
¬ç§¯éåºæ°', |
| | | `status` tinyint NOT NULL DEFAULT 0 COMMENT 'ç¶æï¼0-å¯ç¨ï¼1-ç¦ç¨', |
| | |
| | | -- ============================================= |
| | | -- æ§è¡å®ææç¤º |
| | | -- ============================================= |
| | | SELECT 'HRM 人åèµæºæ¨¡å SQL åå§å宿ï¼' AS result; |
| | | SELECT 'HRM 人åèµæºæ¨¡å SQL åå§å宿ï¼' AS result; |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | -- HRM å çç³è¯·ï¼åååå
¬å®¡æ¹ + èªé
¬æ ¸ç®æ°æ®æº |
| | | |
| | | CREATE TABLE IF NOT EXISTS `hrm_overtime_application` ( |
| | | `id` bigint NOT NULL AUTO_INCREMENT COMMENT 'ç³è¯·ID', |
| | | `no` varchar(32) NOT NULL COMMENT 'ç³è¯·åå·', |
| | | `user_id` bigint NOT NULL COMMENT 'ç³»ç»ç¨æ·ID', |
| | | `employee_id` bigint NOT NULL COMMENT 'åå·¥ID', |
| | | `dept_id` bigint NOT NULL COMMENT 'é¨é¨ID', |
| | | `overtime_date` date NOT NULL COMMENT 'å çæ¥æ', |
| | | `start_time` time NOT NULL COMMENT 'å¼å§æ¶é´', |
| | | `end_time` time NOT NULL COMMENT 'ç»ææ¶é´', |
| | | `duration` decimal(6,1) NOT NULL COMMENT 'æ£é¤ç¨é¤åçå çæ¶é¿ï¼0.5å°æ¶åæ´ï¼', |
| | | `overtime_type` tinyint NOT NULL COMMENT '1-工使¥ï¼2-伿¯æ¥ï¼3-æ³å®è忥', |
| | | `cross_day` bit(1) NOT NULL DEFAULT b'0' COMMENT 'æ¯å¦è·¨å¤©', |
| | | `meal_deduction` bit(1) NOT NULL DEFAULT b'0' COMMENT 'æ¯å¦æ£é¤ç¨é¤æ¶é´', |
| | | `meal_deduction_hours` decimal(4,1) NOT NULL DEFAULT 0 COMMENT 'ç¨é¤æ£é¤å°æ¶æ°', |
| | | `reason` varchar(500) NOT NULL COMMENT 'å çåå ', |
| | | `related_type` tinyint DEFAULT NULL COMMENT 'å
³èç±»åï¼1-项ç®ï¼2-å·¥å', |
| | | `related_code` varchar(100) DEFAULT NULL COMMENT '项ç®/å·¥åç¼å·', |
| | | `work_content` varchar(1000) DEFAULT NULL COMMENT 'å·¥ä½å
容ç®è¿°', |
| | | `status` tinyint NOT NULL DEFAULT 0 COMMENT '0-è稿ï¼10-审æ¹ä¸ï¼20-éè¿ï¼30-驳åï¼40-æ¤é', |
| | | `process_instance_id` varchar(64) DEFAULT NULL COMMENT 'åååå
¬æµç¨å®ä¾ID', |
| | | `approve_time` datetime DEFAULT NULL COMMENT '审æ¹å®ææ¶é´', |
| | | `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`), |
| | | UNIQUE KEY `uk_hrm_overtime_no` (`no`), |
| | | KEY `idx_hrm_overtime_user_date_status` (`user_id`, `overtime_date`, `status`), |
| | | KEY `idx_hrm_overtime_process_instance` (`process_instance_id`) |
| | | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='HRMå çç³è¯·è¡¨'; |
| | | |
| | | -- åååå
¬æµç¨åç±»å·²å¨ bpm/manager/category ä¸ç»´æ¤ï¼åç±»ç¼ç 为 overtime_approveã |
| | | -- ä»éå¨è¯¥åç±»ä¸å»ºç«å¹¶å叿µç¨å®ä¹ key=hrm_overtimeã |
| | | |
| | | -- 人äºå®¡æ¹èååæé®æé |
| | | INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) |
| | | SELECT 6007, 'å çç³è¯·', '', 2, 4, 6002, 'overtime', 'ep:timer', 'hrm/overtime/index', 'HrmOvertimeApplication', 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0' |
| | | FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `system_menu` WHERE `id` = 6007); |
| | | |
| | | INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) |
| | | SELECT 60071, 'å çç³è¯·æ¥è¯¢', 'hrm:overtime:query', 3, 1, 6007, '', '', '', NULL, 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0' FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `system_menu` WHERE `id` = 60071); |
| | | INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) |
| | | SELECT 60072, 'å çç³è¯·æ°å¢', 'hrm:overtime:create', 3, 2, 6007, '', '', '', NULL, 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0' FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `system_menu` WHERE `id` = 60072); |
| | | INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) |
| | | SELECT 60073, 'å çç³è¯·ä¿®æ¹', 'hrm:overtime:update', 3, 3, 6007, '', '', '', NULL, 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0' FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `system_menu` WHERE `id` = 60073); |
| | | INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) |
| | | SELECT 60074, 'å çç³è¯·å é¤', 'hrm:overtime:delete', 3, 4, 6007, '', '', '', NULL, 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0' FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `system_menu` WHERE `id` = 60074); |
| | | INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) |
| | | SELECT 60075, 'å çç³è¯·æäº¤', 'hrm:overtime:submit', 3, 5, 6007, '', '', '', NULL, 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0' FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `system_menu` WHERE `id` = 60075); |
| | | INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) |
| | | SELECT 60076, 'å çç³è¯·æ¤é', 'hrm:overtime:cancel', 3, 6, 6007, '', '', '', NULL, 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0' FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `system_menu` WHERE `id` = 60076); |
| | | INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) |
| | | SELECT 60077, 'å çç³è¯·ç®¡ç', 'hrm:overtime:manage', 3, 7, 6007, '', '', '', NULL, 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0' FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `system_menu` WHERE `id` = 60077); |
| | | |
| | | INSERT INTO `system_role_menu` (`role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) |
| | | SELECT 1, menu_id, '1', NOW(), '1', NOW(), b'0' FROM ( |
| | | SELECT 6007 menu_id UNION ALL SELECT 60071 UNION ALL SELECT 60072 UNION ALL |
| | | SELECT 60073 UNION ALL SELECT 60074 UNION ALL SELECT 60075 UNION ALL SELECT 60076 UNION ALL SELECT 60077 |
| | | ) ids WHERE NOT EXISTS (SELECT 1 FROM `system_role_menu` rm WHERE rm.`role_id` = 1 AND rm.`menu_id` = ids.menu_id); |
| | | |
| | | SELECT 'HRM å çç³è¯·åå§å宿ï¼è¯·å¨åååå
¬åå¸ hrm_overtime æµç¨' AS result; |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | -- HRM èªé
¬ç»æé
ç½®èå䏿éï¼å¯é夿§è¡ï¼ |
| | | |
| | | INSERT INTO `system_menu` |
| | | (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, |
| | | `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) |
| | | VALUES |
| | | (6025, 'èªé
Ⱦ', '', 2, 3, 6020, 'structure', 'ep:set-up', |
| | | 'hrm/salary/structure/index', 'HrmSalaryStructure', 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0'), |
| | | (60251, 'èªé
¬ç»ææ¥è¯¢', 'hrm:salary-structure:query', 3, 1, 6025, '', '', '', NULL, |
| | | 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0'), |
| | | (60252, 'èªé
¬ç»ææ°å¢', 'hrm:salary-structure:create', 3, 2, 6025, '', '', '', NULL, |
| | | 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0'), |
| | | (60253, 'èªé
¬ç»æä¿®æ¹', 'hrm:salary-structure:update', 3, 3, 6025, '', '', '', NULL, |
| | | 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0'), |
| | | (60254, 'èªé
¬ç»æå é¤', 'hrm:salary-structure:delete', 3, 4, 6025, '', '', '', NULL, |
| | | 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0') |
| | | ON DUPLICATE KEY UPDATE |
| | | `name` = VALUES(`name`), `permission` = VALUES(`permission`), `parent_id` = VALUES(`parent_id`), |
| | | `path` = VALUES(`path`), `icon` = VALUES(`icon`), `component` = VALUES(`component`), |
| | | `component_name` = VALUES(`component_name`), `status` = VALUES(`status`), `deleted` = b'0'; |
| | | |
| | | INSERT INTO `system_role_menu` |
| | | (`role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) |
| | | SELECT 1, menu_id, '1', NOW(), '1', NOW(), b'0' |
| | | FROM ( |
| | | SELECT 6025 AS menu_id UNION ALL SELECT 60251 UNION ALL SELECT 60252 |
| | | UNION ALL SELECT 60253 UNION ALL SELECT 60254 |
| | | ) menu_ids |
| | | WHERE NOT EXISTS ( |
| | | SELECT 1 FROM `system_role_menu` role_menu |
| | | WHERE role_menu.`role_id` = 1 AND role_menu.`menu_id` = menu_ids.menu_id AND role_menu.`deleted` = b'0' |
| | | ); |
| | | |
| | | SELECT 'HRM èªé
¬ç»æèååå§å宿' AS result; |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | -- èªé
¬ç»æå¢å 伿¯æ¥ãæ³å®è忥å çå·¥èµåç |
| | | -- å·²æç工使¥åçç»§ç»ä½¿ç¨ overtime_pay_ratio åæ®µ |
| | | |
| | | ALTER TABLE `hrm_salary_structure` |
| | | ADD COLUMN `rest_day_overtime_pay_ratio` decimal(4,2) DEFAULT 2.00 |
| | | COMMENT '伿¯æ¥å çå·¥èµåç' AFTER `overtime_pay_ratio`, |
| | | ADD COLUMN `legal_holiday_overtime_pay_ratio` decimal(4,2) DEFAULT 3.00 |
| | | COMMENT 'æ³å®è忥å çå·¥èµåç' AFTER `rest_day_overtime_pay_ratio`; |
| | |
| | | import org.flowable.task.api.TaskInfo; |
| | | import tools.jackson.databind.JsonNode; |
| | | |
| | | import java.util.Collections; |
| | | import java.util.HashMap; |
| | | import java.util.LinkedHashMap; |
| | | import java.util.List; |
| | |
| | | || !BpmModelFormTypeEnum.NORMAL.getType().equals(processDefinitionInfo.getFormType())) { |
| | | return null; |
| | | } |
| | | // å岿µç¨å®ä¹ãä¸å¡è¡¨åæµç¨å¯è½æ²¡æåä½ formFieldsãæ¤æ¶æ²¡æå¯å±ç¤ºçæè¦ï¼ |
| | | // ä¸è½å ä¸ºåæ¡æµç¨æ°æ®ç¼ºå°è¡¨ååæ®µé
ç½®å¯¼è´æ´ä¸ªâæçæµç¨/å¾
åâå页æ¥è¯¢å¤±è´¥ã |
| | | if (ObjectUtil.isEmpty(processDefinitionInfo.getFormFields())) { |
| | | return Collections.emptyList(); |
| | | } |
| | | |
| | | // è§£æè¡¨åé
ç½® |
| | | Map<String, BpmFormFieldVO> formFieldsMap = new LinkedHashMap<>(); |
| | |
| | | } |
| | | |
| | | @Test |
| | | public void testGetSummary_normalFormWithoutFields_returnEmpty() { |
| | | // åå¤åæ°ï¼ä¸å¡è¡¨åæå岿µç¨å®ä¹å¯è½æ²¡æåä½ formFieldsã |
| | | BpmProcessDefinitionInfoDO processDefinitionInfo = processDefinitionInfo(null, null); |
| | | |
| | | // è°ç¨ & æè¨ï¼ç¼ºå°æè¦å段æ¶è¿å空æè¦ï¼ä¸è½å½±åæ´ä¸ªå页æ¥å£ã |
| | | assertEquals(Collections.emptyList(), |
| | | FlowableUtils.getSummary(processDefinitionInfo, Collections.emptyMap())); |
| | | } |
| | | |
| | | @Test |
| | | public void testGetSummary_notNormalForm_returnNull() { |
| | | // åå¤åæ° |
| | | BpmProcessDefinitionInfoDO processDefinitionInfo = BpmProcessDefinitionInfoDO.builder() |
| | |
| | | ErrorCode RESIGNATION_APPLICATION_EXISTS = new ErrorCode(1_030_003_005, "该å工已åå¨ç¦»èç³è¯·ï¼è¯·å¿éå¤æäº¤"); |
| | | ErrorCode RESIGNATION_APPLICATION_BPM_PROCESS_DEFINITION_NOT_EXISTS = new ErrorCode(1_030_003_006, "离èå®¡æ¹æµç¨ä¸åå¨"); |
| | | |
| | | // ========== å çç³è¯· 1-030-008-000 ========== |
| | | ErrorCode OVERTIME_APPLICATION_NOT_EXISTS = new ErrorCode(1_030_008_000, "å çç³è¯·ä¸åå¨"); |
| | | ErrorCode OVERTIME_APPLICATION_UPDATE_FAIL_NOT_DRAFT = new ErrorCode(1_030_008_001, "å çç³è¯·æ´æ°å¤±è´¥ï¼åå ï¼ä¸æ¯èç¨¿ç¶æ"); |
| | | ErrorCode OVERTIME_APPLICATION_SUBMIT_FAIL_NOT_DRAFT = new ErrorCode(1_030_008_002, "å çç³è¯·æäº¤å¤±è´¥ï¼åå ï¼ä¸æ¯èç¨¿ç¶æ"); |
| | | ErrorCode OVERTIME_APPLICATION_UPDATE_AUDIT_STATUS_FAIL_NOT_PROCESS = new ErrorCode(1_030_008_003, "æ´æ°å çç³è¯·å®¡æ¹ç¶æå¤±è´¥ï¼åå ï¼ä¸æ¯å®¡æ¹ä¸ç¶æ"); |
| | | ErrorCode OVERTIME_APPLICATION_BPM_PROCESS_DEFINITION_NOT_EXISTS = new ErrorCode(1_030_008_004, "å çå®¡æ¹æµç¨ä¸åå¨ï¼è¯·å
å¨åååå
¬ä¸é
置并å叿µç¨"); |
| | | ErrorCode OVERTIME_APPLICATION_EMPLOYEE_NOT_EXISTS = new ErrorCode(1_030_008_005, "å½åè´¦å·æªå
³èå工档æ¡"); |
| | | ErrorCode OVERTIME_APPLICATION_TIME_INVALID = new ErrorCode(1_030_008_006, "å çæ¶æ®µææ£é¤æ¶é¿ä¸åæ³"); |
| | | |
| | | // ========== ç¨æ·æ°æ®äº¤æ¥ 1-030-007-000 ========== |
| | | ErrorCode USER_HANDOVER_NOT_EXISTS = new ErrorCode(1_030_007_000, "ç¨æ·äº¤æ¥è®°å½ä¸åå¨"); |
| | | ErrorCode USER_HANDOVER_ALREADY_EXISTS = new ErrorCode(1_030_007_001, "该离èç³è¯·å·²åå¨äº¤æ¥è®°å½"); |
| | |
| | | ErrorCode SALARY_PAYMENT_REVOKE_FAIL = new ErrorCode(1_030_005_022, "æ¤éåæ¾å¤±è´¥ï¼åå ï¼è¯¥æç»æªåæ¾"); |
| | | ErrorCode SALARY_PAYMENT_DELETE_FAIL = new ErrorCode(1_030_005_023, "å é¤å¤±è´¥ï¼åå ï¼ä»
å¾
åæ¾ç¶æå¯å é¤ï¼è¯·å
æ¤é已忾æç»"); |
| | | 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, "èªé
¬ç»ææ£å¨è¢«å工使ç¨ï¼æ æ³å é¤"); |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.hrm.enums; |
| | | |
| | | import lombok.Getter; |
| | | import lombok.RequiredArgsConstructor; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.util.Arrays; |
| | | |
| | | /** å çç±»ååæ³å®å·¥èµåçã */ |
| | | @Getter |
| | | @RequiredArgsConstructor |
| | | public enum HrmOvertimeTypeEnum { |
| | | |
| | | WORKDAY(1, "工使¥å ç", new BigDecimal("1.5")), |
| | | REST_DAY(2, "伿¯æ¥å ç", new BigDecimal("2.0")), |
| | | LEGAL_HOLIDAY(3, "æ³å®è忥å ç", new BigDecimal("3.0")); |
| | | |
| | | private final Integer type; |
| | | private final String name; |
| | | private final BigDecimal salaryMultiplier; |
| | | |
| | | public static HrmOvertimeTypeEnum valueOfType(Integer type) { |
| | | return Arrays.stream(values()).filter(item -> item.type.equals(type)).findFirst().orElse(null); |
| | | } |
| | | |
| | | public static String getName(Integer type) { |
| | | HrmOvertimeTypeEnum value = valueOfType(type); |
| | | return value == null ? "" : value.name; |
| | | } |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.hrm.controller.admin.approval; |
| | | |
| | | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| | | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| | | import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; |
| | | import cn.iocoder.yudao.framework.security.core.service.SecurityFrameworkService; |
| | | import cn.iocoder.yudao.module.hrm.controller.admin.approval.vo.*; |
| | | import cn.iocoder.yudao.module.hrm.service.approval.HrmOvertimeApplicationService; |
| | | import io.swagger.v3.oas.annotations.Operation; |
| | | import io.swagger.v3.oas.annotations.tags.Tag; |
| | | import jakarta.annotation.Resource; |
| | | import jakarta.validation.Valid; |
| | | import org.springframework.security.access.prepost.PreAuthorize; |
| | | import org.springframework.validation.annotation.Validated; |
| | | import org.springframework.web.bind.annotation.*; |
| | | |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | |
| | | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| | | |
| | | @Tag(name = "管çåå° - HRM å çç³è¯·") |
| | | @RestController |
| | | @RequestMapping("/hrm/overtime") |
| | | @Validated |
| | | public class HrmOvertimeApplicationController { |
| | | @Resource private HrmOvertimeApplicationService service; |
| | | @Resource private SecurityFrameworkService securityFrameworkService; |
| | | |
| | | @PostMapping("/create") @PreAuthorize("@ss.hasPermission('hrm:overtime:create')") |
| | | public CommonResult<Long> create(@Valid @RequestBody HrmOvertimeApplicationSaveReqVO reqVO) { |
| | | return success(service.create(reqVO, SecurityFrameworkUtils.getLoginUserId())); |
| | | } |
| | | @PutMapping("/update") @PreAuthorize("@ss.hasPermission('hrm:overtime:update')") |
| | | public CommonResult<Boolean> update(@Valid @RequestBody HrmOvertimeApplicationSaveReqVO reqVO) { |
| | | service.update(reqVO, SecurityFrameworkUtils.getLoginUserId()); return success(true); |
| | | } |
| | | @DeleteMapping("/delete") @PreAuthorize("@ss.hasPermission('hrm:overtime:delete')") |
| | | public CommonResult<Boolean> delete(@RequestParam Long id) { |
| | | service.delete(id, SecurityFrameworkUtils.getLoginUserId()); return success(true); |
| | | } |
| | | @GetMapping("/get") @PreAuthorize("@ss.hasAnyPermissions('hrm:overtime:query', 'bpm:task:query')") |
| | | public CommonResult<HrmOvertimeApplicationRespVO> get(@RequestParam Long id) { |
| | | return success(service.getDetail(id, SecurityFrameworkUtils.getLoginUserId(), canManage())); |
| | | } |
| | | @GetMapping("/current-applicant") @PreAuthorize("@ss.hasPermission('hrm:overtime:create')") |
| | | public CommonResult<HrmOvertimeApplicationRespVO> currentApplicant() { |
| | | return success(service.getCurrentApplicant(SecurityFrameworkUtils.getLoginUserId())); |
| | | } |
| | | @GetMapping("/page") @PreAuthorize("@ss.hasPermission('hrm:overtime:query')") |
| | | public CommonResult<PageResult<HrmOvertimeApplicationRespVO>> page(@Valid HrmOvertimeApplicationPageReqVO reqVO) { |
| | | if (!canManage()) { |
| | | reqVO.setUserId(SecurityFrameworkUtils.getLoginUserId()); |
| | | } |
| | | return success(service.getPage(reqVO)); |
| | | } |
| | | @PostMapping("/submit") @PreAuthorize("@ss.hasPermission('hrm:overtime:submit')") |
| | | public CommonResult<Boolean> submit(@RequestParam Long id, @RequestParam String processDefinitionKey) { |
| | | service.submit(id, processDefinitionKey, SecurityFrameworkUtils.getLoginUserId()); return success(true); |
| | | } |
| | | @PostMapping("/cancel") @PreAuthorize("@ss.hasPermission('hrm:overtime:cancel')") |
| | | public CommonResult<Boolean> cancel(@RequestParam Long id) { |
| | | service.cancel(id, SecurityFrameworkUtils.getLoginUserId()); return success(true); |
| | | } |
| | | @GetMapping("/approve-process-definition-list") @PreAuthorize("@ss.hasPermission('hrm:overtime:query')") |
| | | public CommonResult<List<Map<String, Object>>> processes() { return success(service.getApproveProcessDefinitionList()); } |
| | | |
| | | private boolean canManage() { |
| | | return securityFrameworkService.hasPermission("hrm:overtime:manage"); |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.hrm.controller.admin.approval.vo; |
| | | |
| | | import cn.iocoder.yudao.framework.common.pojo.PageParam; |
| | | import lombok.Data; |
| | | import lombok.EqualsAndHashCode; |
| | | |
| | | import java.time.LocalDate; |
| | | |
| | | @Data |
| | | @EqualsAndHashCode(callSuper = true) |
| | | public class HrmOvertimeApplicationPageReqVO extends PageParam { |
| | | private String no; |
| | | private Long userId; |
| | | private Long deptId; |
| | | private LocalDate overtimeDate; |
| | | private Integer overtimeType; |
| | | private Integer status; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.hrm.controller.admin.approval.vo; |
| | | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDate; |
| | | import java.time.LocalDateTime; |
| | | import java.time.LocalTime; |
| | | |
| | | @Schema(description = "管çåå° - å çç³è¯· Response VO") |
| | | @Data |
| | | public class HrmOvertimeApplicationRespVO { |
| | | private Long id; |
| | | private String no; |
| | | private Long userId; |
| | | private Long employeeId; |
| | | private String employeeName; |
| | | private String employeeNo; |
| | | private Long deptId; |
| | | private String deptName; |
| | | private String postName; |
| | | private LocalDate overtimeDate; |
| | | private LocalTime startTime; |
| | | private LocalTime endTime; |
| | | private BigDecimal duration; |
| | | private Integer overtimeType; |
| | | private String overtimeTypeName; |
| | | private Boolean crossDay; |
| | | private Boolean mealDeduction; |
| | | private BigDecimal mealDeductionHours; |
| | | private String reason; |
| | | private Integer relatedType; |
| | | private String relatedCode; |
| | | private String workContent; |
| | | private Integer status; |
| | | private String statusName; |
| | | private String processInstanceId; |
| | | private LocalDateTime approveTime; |
| | | private LocalDateTime createTime; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.hrm.controller.admin.approval.vo; |
| | | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import jakarta.validation.constraints.DecimalMin; |
| | | import jakarta.validation.constraints.NotBlank; |
| | | import jakarta.validation.constraints.NotNull; |
| | | import lombok.Data; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDate; |
| | | import java.time.LocalTime; |
| | | |
| | | @Schema(description = "管çåå° - å çç³è¯·æ°å¢/ä¿®æ¹ Request VO") |
| | | @Data |
| | | public class HrmOvertimeApplicationSaveReqVO { |
| | | private Long id; |
| | | @NotNull(message = "å çæ¥æä¸è½ä¸ºç©º") |
| | | private LocalDate overtimeDate; |
| | | @NotNull(message = "å¼å§æ¶é´ä¸è½ä¸ºç©º") |
| | | private LocalTime startTime; |
| | | @NotNull(message = "ç»ææ¶é´ä¸è½ä¸ºç©º") |
| | | private LocalTime endTime; |
| | | @NotNull(message = "å çæ¶é¿ä¸è½ä¸ºç©º") |
| | | @DecimalMin(value = "0.5", message = "å çæ¶é¿ä¸è½å°äº 0.5 å°æ¶") |
| | | private BigDecimal duration; |
| | | @NotNull(message = "å çç±»åä¸è½ä¸ºç©º") |
| | | private Integer overtimeType; |
| | | private Boolean crossDay; |
| | | private Boolean mealDeduction; |
| | | private BigDecimal mealDeductionHours; |
| | | @NotBlank(message = "å çåå ä¸è½ä¸ºç©º") |
| | | private String reason; |
| | | private Integer relatedType; |
| | | private String relatedCode; |
| | | private String workContent; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.hrm.controller.admin.salary; |
| | | |
| | | 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.HrmSalaryStructureRespVO; |
| | | import cn.iocoder.yudao.module.hrm.controller.admin.salary.vo.HrmSalaryStructureSaveReqVO; |
| | | import cn.iocoder.yudao.module.hrm.dal.dataobject.salary.HrmSalaryStructureDO; |
| | | import cn.iocoder.yudao.module.hrm.service.salary.HrmSalaryStructureService; |
| | | import io.swagger.v3.oas.annotations.Operation; |
| | | import io.swagger.v3.oas.annotations.Parameter; |
| | | import io.swagger.v3.oas.annotations.tags.Tag; |
| | | import jakarta.annotation.Resource; |
| | | import jakarta.validation.Valid; |
| | | import org.springframework.security.access.prepost.PreAuthorize; |
| | | import org.springframework.validation.annotation.Validated; |
| | | import org.springframework.web.bind.annotation.DeleteMapping; |
| | | import org.springframework.web.bind.annotation.GetMapping; |
| | | import org.springframework.web.bind.annotation.PostMapping; |
| | | import org.springframework.web.bind.annotation.PutMapping; |
| | | import org.springframework.web.bind.annotation.RequestBody; |
| | | import org.springframework.web.bind.annotation.RequestMapping; |
| | | import org.springframework.web.bind.annotation.RequestParam; |
| | | import org.springframework.web.bind.annotation.RestController; |
| | | |
| | | import java.util.List; |
| | | |
| | | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| | | |
| | | @Tag(name = "管çåå° - HRM èªé
Ⱦ") |
| | | @RestController |
| | | @RequestMapping("/hrm/salary/structure") |
| | | @Validated |
| | | public class HrmSalaryStructureController { |
| | | |
| | | @Resource |
| | | private HrmSalaryStructureService salaryStructureService; |
| | | |
| | | @PostMapping("/create") |
| | | @Operation(summary = "å建èªé
Ⱦ") |
| | | @PreAuthorize("@ss.hasPermission('hrm:salary-structure:create')") |
| | | public CommonResult<Long> createSalaryStructure(@Valid @RequestBody HrmSalaryStructureSaveReqVO reqVO) { |
| | | return success(salaryStructureService.createSalaryStructure( |
| | | BeanUtils.toBean(reqVO, HrmSalaryStructureDO.class))); |
| | | } |
| | | |
| | | @PutMapping("/update") |
| | | @Operation(summary = "æ´æ°èªé
Ⱦ") |
| | | @PreAuthorize("@ss.hasPermission('hrm:salary-structure:update')") |
| | | public CommonResult<Boolean> updateSalaryStructure(@Valid @RequestBody HrmSalaryStructureSaveReqVO reqVO) { |
| | | salaryStructureService.updateSalaryStructure(BeanUtils.toBean(reqVO, HrmSalaryStructureDO.class)); |
| | | return success(true); |
| | | } |
| | | |
| | | @DeleteMapping("/delete") |
| | | @Operation(summary = "å é¤èªé
Ⱦ") |
| | | @Parameter(name = "id", description = "ç»æç¼å·", required = true) |
| | | @PreAuthorize("@ss.hasPermission('hrm:salary-structure:delete')") |
| | | public CommonResult<Boolean> deleteSalaryStructure(@RequestParam("id") Long id) { |
| | | salaryStructureService.deleteSalaryStructure(id); |
| | | return success(true); |
| | | } |
| | | |
| | | @GetMapping("/get") |
| | | @Operation(summary = "è·å¾èªé
Ⱦ") |
| | | @PreAuthorize("@ss.hasPermission('hrm:salary-structure:query')") |
| | | public CommonResult<HrmSalaryStructureRespVO> getSalaryStructure(@RequestParam("id") Long id) { |
| | | return success(BeanUtils.toBean(salaryStructureService.getSalaryStructure(id), |
| | | HrmSalaryStructureRespVO.class)); |
| | | } |
| | | |
| | | @GetMapping("/list") |
| | | @Operation(summary = "è·å¾èªé
¬ç»æå表") |
| | | @PreAuthorize("@ss.hasPermission('hrm:salary-structure:query')") |
| | | public CommonResult<List<HrmSalaryStructureRespVO>> getSalaryStructureList( |
| | | @RequestParam(value = "name", required = false) String name, |
| | | @RequestParam(value = "status", required = false) Integer status) { |
| | | return success(BeanUtils.toBean(salaryStructureService.getSalaryStructureList(name, status), |
| | | HrmSalaryStructureRespVO.class)); |
| | | } |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.hrm.controller.admin.salary.vo; |
| | | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDateTime; |
| | | |
| | | @Schema(description = "管çåå° - èªé
Ⱦ Response VO") |
| | | @Data |
| | | public class HrmSalaryStructureRespVO { |
| | | |
| | | @Schema(description = "ç»æç¼å·") |
| | | private Long id; |
| | | @Schema(description = "ç»æåç§°") |
| | | private String name; |
| | | @Schema(description = "工使¥å çå·¥èµåç") |
| | | private BigDecimal overtimePayRatio; |
| | | @Schema(description = "伿¯æ¥å çå·¥èµåç") |
| | | private BigDecimal restDayOvertimePayRatio; |
| | | @Schema(description = "æ³å®è忥å çå·¥èµåç") |
| | | private BigDecimal legalHolidayOvertimePayRatio; |
| | | @Schema(description = "ç¶æï¼0-å¯ç¨ï¼1-ç¦ç¨") |
| | | private Integer status; |
| | | @Schema(description = "夿³¨") |
| | | private String remark; |
| | | @Schema(description = "å建æ¶é´") |
| | | private LocalDateTime createTime; |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.hrm.controller.admin.salary.vo; |
| | | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import jakarta.validation.constraints.DecimalMax; |
| | | import jakarta.validation.constraints.DecimalMin; |
| | | import jakarta.validation.constraints.NotBlank; |
| | | import jakarta.validation.constraints.NotNull; |
| | | import jakarta.validation.constraints.Size; |
| | | import lombok.Data; |
| | | |
| | | import java.math.BigDecimal; |
| | | |
| | | @Schema(description = "管çåå° - èªé
¬ç»ææ°å¢/ä¿®æ¹ Request VO") |
| | | @Data |
| | | public class HrmSalaryStructureSaveReqVO { |
| | | |
| | | @Schema(description = "ç»æç¼å·", example = "1") |
| | | private Long id; |
| | | |
| | | @Schema(description = "ç»æåç§°", requiredMode = Schema.RequiredMode.REQUIRED, example = "æ ååå·¥èªé
¬") |
| | | @NotBlank(message = "ç»æåç§°ä¸è½ä¸ºç©º") |
| | | @Size(max = 100, message = "ç»æåç§°ä¸è½è¶
è¿ 100 个å符") |
| | | private String name; |
| | | |
| | | @Schema(description = "工使¥å çå·¥èµåçï¼0 表示ä¸è®¡å çå·¥èµ", example = "1.50") |
| | | @NotNull(message = "工使¥å çåçä¸è½ä¸ºç©º") |
| | | @DecimalMin(value = "0", message = "工使¥å çåçä¸è½å°äº 0") |
| | | @DecimalMax(value = "10", message = "工使¥å çåçä¸è½å¤§äº 10") |
| | | private BigDecimal overtimePayRatio; |
| | | |
| | | @Schema(description = "伿¯æ¥å çå·¥èµåçï¼0 表示ä¸è®¡è¯¥ç±»åå çå·¥èµ", example = "2.00") |
| | | @NotNull(message = "伿¯æ¥å çåçä¸è½ä¸ºç©º") |
| | | @DecimalMin(value = "0", message = "伿¯æ¥å çåçä¸è½å°äº 0") |
| | | @DecimalMax(value = "10", message = "伿¯æ¥å çåçä¸è½å¤§äº 10") |
| | | private BigDecimal restDayOvertimePayRatio; |
| | | |
| | | @Schema(description = "æ³å®è忥å çå·¥èµåçï¼0 表示ä¸è®¡è¯¥ç±»åå çå·¥èµ", example = "3.00") |
| | | @NotNull(message = "æ³å®è忥å çåçä¸è½ä¸ºç©º") |
| | | @DecimalMin(value = "0", message = "æ³å®è忥å çåçä¸è½å°äº 0") |
| | | @DecimalMax(value = "10", message = "æ³å®è忥å çåçä¸è½å¤§äº 10") |
| | | private BigDecimal legalHolidayOvertimePayRatio; |
| | | |
| | | @Schema(description = "ç¶æï¼0-å¯ç¨ï¼1-ç¦ç¨", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") |
| | | @NotNull(message = "ç¶æä¸è½ä¸ºç©º") |
| | | private Integer status; |
| | | |
| | | @Schema(description = "夿³¨") |
| | | @Size(max = 500, message = "夿³¨ä¸è½è¶
è¿ 500 个å符") |
| | | private String remark; |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.hrm.dal.dataobject.approval; |
| | | |
| | | 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.*; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDate; |
| | | import java.time.LocalDateTime; |
| | | import java.time.LocalTime; |
| | | |
| | | @TableName("hrm_overtime_application") |
| | | @KeySequence("hrm_overtime_application_seq") |
| | | @Data |
| | | @EqualsAndHashCode(callSuper = true) |
| | | @ToString(callSuper = true) |
| | | @Builder |
| | | @NoArgsConstructor |
| | | @AllArgsConstructor |
| | | public class HrmOvertimeApplicationDO extends BaseDO { |
| | | @TableId |
| | | private Long id; |
| | | private String no; |
| | | /** ç³»ç»ç¨æ· ID */ |
| | | private Long userId; |
| | | private Long deptId; |
| | | private Long employeeId; |
| | | private LocalDate overtimeDate; |
| | | private LocalTime startTime; |
| | | private LocalTime endTime; |
| | | private BigDecimal duration; |
| | | private Integer overtimeType; |
| | | private Boolean crossDay; |
| | | private Boolean mealDeduction; |
| | | private BigDecimal mealDeductionHours; |
| | | private String reason; |
| | | /** 1-项ç®ï¼2-å·¥å */ |
| | | private Integer relatedType; |
| | | private String relatedCode; |
| | | private String workContent; |
| | | private Integer status; |
| | | private String processInstanceId; |
| | | private LocalDateTime approveTime; |
| | | } |
| | |
| | | private BigDecimal performanceRatio; |
| | | |
| | | /** |
| | | * å çå·¥èµåç |
| | | * 工使¥å çå·¥èµåç |
| | | */ |
| | | private BigDecimal overtimePayRatio; |
| | | |
| | | /** |
| | | * 伿¯æ¥å çå·¥èµåç |
| | | */ |
| | | private BigDecimal restDayOvertimePayRatio; |
| | | |
| | | /** |
| | | * æ³å®è忥å çå·¥èµåç |
| | | */ |
| | | private BigDecimal legalHolidayOvertimePayRatio; |
| | | |
| | | /** |
| | | * 社ä¿åºæ° |
| | |
| | | */ |
| | | private String remark; |
| | | |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.hrm.dal.mysql.approval; |
| | | |
| | | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| | | import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; |
| | | import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; |
| | | import cn.iocoder.yudao.module.hrm.controller.admin.approval.vo.HrmOvertimeApplicationPageReqVO; |
| | | import cn.iocoder.yudao.module.hrm.dal.dataobject.approval.HrmOvertimeApplicationDO; |
| | | import cn.iocoder.yudao.module.hrm.enums.HrmAuditStatusEnum; |
| | | import org.apache.ibatis.annotations.Mapper; |
| | | |
| | | import java.time.LocalDate; |
| | | import java.util.List; |
| | | |
| | | @Mapper |
| | | public interface HrmOvertimeApplicationMapper extends BaseMapperX<HrmOvertimeApplicationDO> { |
| | | |
| | | default PageResult<HrmOvertimeApplicationDO> selectPage(HrmOvertimeApplicationPageReqVO reqVO) { |
| | | return selectPage(reqVO, new LambdaQueryWrapperX<HrmOvertimeApplicationDO>() |
| | | .likeIfPresent(HrmOvertimeApplicationDO::getNo, reqVO.getNo()) |
| | | .eqIfPresent(HrmOvertimeApplicationDO::getUserId, reqVO.getUserId()) |
| | | .eqIfPresent(HrmOvertimeApplicationDO::getDeptId, reqVO.getDeptId()) |
| | | .eqIfPresent(HrmOvertimeApplicationDO::getOvertimeDate, reqVO.getOvertimeDate()) |
| | | .eqIfPresent(HrmOvertimeApplicationDO::getOvertimeType, reqVO.getOvertimeType()) |
| | | .eqIfPresent(HrmOvertimeApplicationDO::getStatus, reqVO.getStatus()) |
| | | .orderByDesc(HrmOvertimeApplicationDO::getId)); |
| | | } |
| | | |
| | | default HrmOvertimeApplicationDO selectByProcessInstanceId(String processInstanceId) { |
| | | return selectOne(HrmOvertimeApplicationDO::getProcessInstanceId, processInstanceId); |
| | | } |
| | | |
| | | default List<HrmOvertimeApplicationDO> selectApprovedByUserAndDateRange(Long userId, LocalDate start, LocalDate end) { |
| | | return selectList(new LambdaQueryWrapperX<HrmOvertimeApplicationDO>() |
| | | .eq(HrmOvertimeApplicationDO::getUserId, userId) |
| | | .eq(HrmOvertimeApplicationDO::getStatus, HrmAuditStatusEnum.APPROVE.getStatus()) |
| | | .between(HrmOvertimeApplicationDO::getOvertimeDate, start, end)); |
| | | } |
| | | } |
| | |
| | | .orderByAsc(HrmEmployeeDO::getName)); |
| | | } |
| | | |
| | | } |
| | | default Long selectCountBySalaryStructureId(Long salaryStructureId) { |
| | | return selectCount(HrmEmployeeDO::getSalaryStructureId, salaryStructureId); |
| | | } |
| | | |
| | | } |
| | |
| | | .orderByDesc(HrmEmployeeSalaryDO::getEffectiveDate)); |
| | | } |
| | | |
| | | } |
| | | default Long selectCountBySalaryStructureId(Long salaryStructureId) { |
| | | return selectCount(HrmEmployeeSalaryDO::getSalaryStructureId, salaryStructureId); |
| | | } |
| | | |
| | | } |
| | |
| | | @Mapper |
| | | public interface HrmSalaryStructureMapper extends BaseMapperX<HrmSalaryStructureDO> { |
| | | |
| | | default List<HrmSalaryStructureDO> selectListByStatus(Integer status) { |
| | | default List<HrmSalaryStructureDO> selectListByCondition(String name, Integer status) { |
| | | return selectList(new LambdaQueryWrapperX<HrmSalaryStructureDO>() |
| | | .likeIfPresent(HrmSalaryStructureDO::getName, name) |
| | | .eqIfPresent(HrmSalaryStructureDO::getStatus, status) |
| | | .orderByAsc(HrmSalaryStructureDO::getName)); |
| | | } |
| | | |
| | | } |
| | | default List<HrmSalaryStructureDO> selectListByStatus(Integer status) { |
| | | return selectListByCondition(null, status); |
| | | } |
| | | |
| | | default HrmSalaryStructureDO selectByName(String name) { |
| | | return selectOne(HrmSalaryStructureDO::getName, name); |
| | | } |
| | | |
| | | } |
| | |
| | | */ |
| | | public static final String RESIGNATION_APPLICATION_NO_PREFIX = "RA"; |
| | | |
| | | /** å çç³è¯·ç¼å·åç¼ */ |
| | | public static final String OVERTIME_APPLICATION_NO_PREFIX = "OT"; |
| | | |
| | | /** |
| | | * åå·¥ååç¼å·åç¼ |
| | | */ |
| | |
| | | return generate(RESIGNATION_APPLICATION_NO_PREFIX, 4); |
| | | } |
| | | |
| | | public String generateOvertimeApplicationNo() { |
| | | return generate(OVERTIME_APPLICATION_NO_PREFIX, 4); |
| | | } |
| | | |
| | | /** |
| | | * çæåå·¥ååç¼å·ï¼æ ¼å¼ï¼HT + yyyyMMdd + 4ä½èªå¢ |
| | | * ä¾å¦ï¼HT202401010001 |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.hrm.service.approval; |
| | | |
| | | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| | | import cn.iocoder.yudao.module.hrm.controller.admin.approval.vo.HrmOvertimeApplicationPageReqVO; |
| | | import cn.iocoder.yudao.module.hrm.controller.admin.approval.vo.HrmOvertimeApplicationRespVO; |
| | | import cn.iocoder.yudao.module.hrm.controller.admin.approval.vo.HrmOvertimeApplicationSaveReqVO; |
| | | import jakarta.validation.Valid; |
| | | |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | |
| | | public interface HrmOvertimeApplicationService { |
| | | String BPM_PROCESS_DEFINITION_KEY = "hrm_overtime"; |
| | | String APPROVE_CATEGORY_CODE = "overtime_approve"; |
| | | |
| | | Long create(@Valid HrmOvertimeApplicationSaveReqVO reqVO, Long loginUserId); |
| | | void update(@Valid HrmOvertimeApplicationSaveReqVO reqVO, Long loginUserId); |
| | | void delete(Long id, Long loginUserId); |
| | | HrmOvertimeApplicationRespVO getDetail(Long id, Long loginUserId, boolean canManage); |
| | | HrmOvertimeApplicationRespVO getCurrentApplicant(Long loginUserId); |
| | | PageResult<HrmOvertimeApplicationRespVO> getPage(HrmOvertimeApplicationPageReqVO reqVO); |
| | | void submit(Long id, String processDefinitionKey, Long loginUserId); |
| | | void cancel(Long id, Long loginUserId); |
| | | List<Map<String, Object>> getApproveProcessDefinitionList(); |
| | | void updateAuditStatus(Long id, Integer status); |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.hrm.service.approval; |
| | | |
| | | import cn.hutool.core.collection.CollUtil; |
| | | import cn.hutool.core.util.NumberUtil; |
| | | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| | | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| | | import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi; |
| | | import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; |
| | | import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCancelReqVO; |
| | | import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO; |
| | | import cn.iocoder.yudao.module.bpm.service.definition.BpmCategoryService; |
| | | import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; |
| | | import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; |
| | | import cn.iocoder.yudao.module.bpm.service.task.BpmTaskService; |
| | | import cn.iocoder.yudao.module.hrm.controller.admin.approval.vo.*; |
| | | import cn.iocoder.yudao.module.hrm.dal.dataobject.approval.HrmOvertimeApplicationDO; |
| | | import cn.iocoder.yudao.module.hrm.dal.dataobject.employee.HrmEmployeeDO; |
| | | import cn.iocoder.yudao.module.hrm.dal.mysql.approval.HrmOvertimeApplicationMapper; |
| | | import cn.iocoder.yudao.module.hrm.dal.mysql.employee.HrmEmployeeMapper; |
| | | import cn.iocoder.yudao.module.hrm.dal.redis.HrmNoRedisDAO; |
| | | import cn.iocoder.yudao.module.hrm.enums.HrmAuditStatusEnum; |
| | | import cn.iocoder.yudao.module.hrm.enums.HrmOvertimeTypeEnum; |
| | | import cn.iocoder.yudao.module.system.api.dept.DeptApi; |
| | | import cn.iocoder.yudao.module.system.api.dept.PostApi; |
| | | import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; |
| | | import cn.iocoder.yudao.module.system.api.dept.dto.PostRespDTO; |
| | | import jakarta.annotation.Resource; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.flowable.engine.repository.ProcessDefinition; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.math.RoundingMode; |
| | | import java.time.Duration; |
| | | import java.time.LocalDateTime; |
| | | import java.util.*; |
| | | import java.util.stream.Collectors; |
| | | |
| | | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| | | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; |
| | | import static cn.iocoder.yudao.module.hrm.enums.ErrorCodeConstants.*; |
| | | |
| | | @Service |
| | | @Slf4j |
| | | public class HrmOvertimeApplicationServiceImpl implements HrmOvertimeApplicationService { |
| | | @Resource private HrmOvertimeApplicationMapper mapper; |
| | | @Resource private HrmEmployeeMapper employeeMapper; |
| | | @Resource private HrmNoRedisDAO noRedisDAO; |
| | | @Resource private DeptApi deptApi; |
| | | @Resource private PostApi postApi; |
| | | @Resource private BpmProcessInstanceApi bpmProcessInstanceApi; |
| | | @Resource private BpmProcessInstanceService bpmProcessInstanceService; |
| | | @Resource private BpmTaskService bpmTaskService; |
| | | @Resource private BpmCategoryService bpmCategoryService; |
| | | @Resource private BpmProcessDefinitionService bpmProcessDefinitionService; |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public Long create(HrmOvertimeApplicationSaveReqVO reqVO, Long loginUserId) { |
| | | HrmEmployeeDO employee = requireEmployee(loginUserId); |
| | | HrmOvertimeApplicationDO application = BeanUtils.toBean(reqVO, HrmOvertimeApplicationDO.class); |
| | | applyApplicantAndCalculatedTime(application, employee); |
| | | application.setNo(noRedisDAO.generateOvertimeApplicationNo()); |
| | | application.setStatus(HrmAuditStatusEnum.DRAFT.getStatus()); |
| | | mapper.insert(application); |
| | | return application.getId(); |
| | | } |
| | | |
| | | @Override |
| | | public void update(HrmOvertimeApplicationSaveReqVO reqVO, Long loginUserId) { |
| | | HrmOvertimeApplicationDO existing = requireOwnedDraft(reqVO.getId(), loginUserId); |
| | | HrmOvertimeApplicationDO update = BeanUtils.toBean(reqVO, HrmOvertimeApplicationDO.class); |
| | | applyApplicantAndCalculatedTime(update, requireEmployee(loginUserId)); |
| | | update.setId(existing.getId()); |
| | | mapper.updateById(update); |
| | | } |
| | | |
| | | @Override |
| | | public void delete(Long id, Long loginUserId) { |
| | | HrmOvertimeApplicationDO application = require(id); |
| | | boolean deletable = Objects.equals(application.getStatus(), HrmAuditStatusEnum.DRAFT.getStatus()) |
| | | || Objects.equals(application.getStatus(), HrmAuditStatusEnum.CANCEL.getStatus()); |
| | | if (!Objects.equals(application.getUserId(), loginUserId) || !deletable) { |
| | | throw exception(OVERTIME_APPLICATION_UPDATE_FAIL_NOT_DRAFT); |
| | | } |
| | | mapper.deleteById(id); |
| | | } |
| | | |
| | | @Override |
| | | public HrmOvertimeApplicationRespVO getDetail(Long id, Long loginUserId, boolean canManage) { |
| | | HrmOvertimeApplicationDO application = mapper.selectById(id); |
| | | if (application != null && !canManage && !Objects.equals(application.getUserId(), loginUserId) |
| | | && !isProcessParticipant(application.getProcessInstanceId(), loginUserId)) { |
| | | return null; |
| | | } |
| | | return application == null ? null : buildResp(application); |
| | | } |
| | | |
| | | @Override |
| | | public HrmOvertimeApplicationRespVO getCurrentApplicant(Long loginUserId) { |
| | | HrmEmployeeDO employee = requireEmployee(loginUserId); |
| | | HrmOvertimeApplicationRespVO resp = new HrmOvertimeApplicationRespVO(); |
| | | fillEmployee(resp, employee); |
| | | return resp; |
| | | } |
| | | |
| | | @Override |
| | | public PageResult<HrmOvertimeApplicationRespVO> getPage(HrmOvertimeApplicationPageReqVO reqVO) { |
| | | PageResult<HrmOvertimeApplicationDO> page = mapper.selectPage(reqVO); |
| | | return new PageResult<>(page.getList().stream().map(this::buildResp).toList(), page.getTotal()); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void submit(Long id, String processDefinitionKey, Long loginUserId) { |
| | | HrmOvertimeApplicationDO application = requireOwnedDraft(id, loginUserId); |
| | | validateProcessDefinitions(); |
| | | ProcessDefinition definition = bpmProcessDefinitionService.getActiveProcessDefinition(processDefinitionKey); |
| | | if (definition == null || !BPM_PROCESS_DEFINITION_KEY.equals(definition.getKey())) { |
| | | throw exception(OVERTIME_APPLICATION_BPM_PROCESS_DEFINITION_NOT_EXISTS); |
| | | } |
| | | String processInstanceId = bpmProcessInstanceApi.createProcessInstance(loginUserId, |
| | | new BpmProcessInstanceCreateReqDTO().setProcessDefinitionKey(processDefinitionKey) |
| | | .setBusinessKey(String.valueOf(id))); |
| | | mapper.updateById(HrmOvertimeApplicationDO.builder().id(id).processInstanceId(processInstanceId) |
| | | .status(HrmAuditStatusEnum.PROCESS.getStatus()).build()); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void cancel(Long id, Long loginUserId) { |
| | | HrmOvertimeApplicationDO application = require(id); |
| | | if (!Objects.equals(application.getUserId(), loginUserId) |
| | | || !Objects.equals(application.getStatus(), HrmAuditStatusEnum.PROCESS.getStatus())) { |
| | | throw exception(OVERTIME_APPLICATION_UPDATE_AUDIT_STATUS_FAIL_NOT_PROCESS); |
| | | } |
| | | bpmProcessInstanceService.cancelProcessInstanceByStartUser(loginUserId, |
| | | new BpmProcessInstanceCancelReqVO().setId(application.getProcessInstanceId()).setReason("ç³è¯·äººæ¤éå çç³è¯·")); |
| | | } |
| | | |
| | | @Override |
| | | public List<Map<String, Object>> getApproveProcessDefinitionList() { |
| | | validateProcessDefinitions(); |
| | | List<BpmProcessDefinitionInfoDO> infos = bpmProcessDefinitionService |
| | | .getProcessDefinitionInfoListByCategory(APPROVE_CATEGORY_CODE); |
| | | Set<String> ids = convertSet(infos, BpmProcessDefinitionInfoDO::getProcessDefinitionId); |
| | | Map<String, ProcessDefinition> latest = new HashMap<>(); |
| | | for (ProcessDefinition definition : bpmProcessDefinitionService.getProcessDefinitionList(ids)) { |
| | | if (definition.isSuspended()) continue; |
| | | latest.compute(definition.getKey(), (key, old) -> old == null || definition.getVersion() > old.getVersion() ? definition : old); |
| | | } |
| | | return latest.values().stream().map(item -> { |
| | | Map<String, Object> value = new HashMap<>(); |
| | | value.put("id", item.getId()); value.put("key", item.getKey()); value.put("name", item.getName()); |
| | | value.put("version", item.getVersion()); return value; |
| | | }).collect(Collectors.toList()); |
| | | } |
| | | |
| | | @Override |
| | | public void updateAuditStatus(Long id, Integer status) { |
| | | HrmOvertimeApplicationDO application = require(id); |
| | | if (!Objects.equals(application.getStatus(), HrmAuditStatusEnum.PROCESS.getStatus())) { |
| | | throw exception(OVERTIME_APPLICATION_UPDATE_AUDIT_STATUS_FAIL_NOT_PROCESS); |
| | | } |
| | | mapper.updateById(HrmOvertimeApplicationDO.builder().id(id).status(status) |
| | | .approveTime(LocalDateTime.now()).build()); |
| | | } |
| | | |
| | | private void validateProcessDefinitions() { |
| | | if (!bpmCategoryService.getCategoryMap(Collections.singleton(APPROVE_CATEGORY_CODE)).containsKey(APPROVE_CATEGORY_CODE)) { |
| | | throw exception(OVERTIME_APPLICATION_BPM_PROCESS_DEFINITION_NOT_EXISTS); |
| | | } |
| | | List<BpmProcessDefinitionInfoDO> infos = bpmProcessDefinitionService.getProcessDefinitionInfoListByCategory(APPROVE_CATEGORY_CODE); |
| | | if (CollUtil.isEmpty(infos)) throw exception(OVERTIME_APPLICATION_BPM_PROCESS_DEFINITION_NOT_EXISTS); |
| | | Set<String> ids = convertSet(infos, BpmProcessDefinitionInfoDO::getProcessDefinitionId); |
| | | if (bpmProcessDefinitionService.getProcessDefinitionList(ids).stream().noneMatch(item -> !item.isSuspended())) { |
| | | throw exception(OVERTIME_APPLICATION_BPM_PROCESS_DEFINITION_NOT_EXISTS); |
| | | } |
| | | } |
| | | |
| | | private void applyApplicantAndCalculatedTime(HrmOvertimeApplicationDO application, HrmEmployeeDO employee) { |
| | | if (HrmOvertimeTypeEnum.valueOfType(application.getOvertimeType()) == null) { |
| | | throw exception(OVERTIME_APPLICATION_TIME_INVALID); |
| | | } |
| | | application.setUserId(employee.getUserId()); |
| | | application.setEmployeeId(employee.getId()); |
| | | application.setDeptId(employee.getDeptId()); |
| | | long minutes = Duration.between(application.getStartTime(), application.getEndTime()).toMinutes(); |
| | | boolean crossDay = minutes <= 0; |
| | | if (crossDay) minutes += 24 * 60; |
| | | BigDecimal mealHours = Boolean.TRUE.equals(application.getMealDeduction()) |
| | | ? Optional.ofNullable(application.getMealDeductionHours()).orElse(BigDecimal.ONE) : BigDecimal.ZERO; |
| | | BigDecimal rawHours = BigDecimal.valueOf(minutes).divide(BigDecimal.valueOf(60), 2, RoundingMode.HALF_UP); |
| | | if (Boolean.TRUE.equals(application.getMealDeduction()) |
| | | && (mealHours.compareTo(new BigDecimal("0.5")) < 0 |
| | | || mealHours.compareTo(new BigDecimal("4")) > 0 |
| | | || mealHours.compareTo(rawHours) >= 0)) { |
| | | throw exception(OVERTIME_APPLICATION_TIME_INVALID); |
| | | } |
| | | BigDecimal hours = rawHours |
| | | .subtract(mealHours).multiply(BigDecimal.valueOf(2)).setScale(0, RoundingMode.HALF_UP) |
| | | .divide(BigDecimal.valueOf(2), 1, RoundingMode.UNNECESSARY); |
| | | if (hours.compareTo(BigDecimal.ZERO) <= 0) throw exception(OVERTIME_APPLICATION_TIME_INVALID); |
| | | application.setCrossDay(crossDay); |
| | | application.setMealDeductionHours(mealHours); |
| | | application.setDuration(hours); |
| | | } |
| | | |
| | | private HrmOvertimeApplicationDO require(Long id) { |
| | | HrmOvertimeApplicationDO value = mapper.selectById(id); |
| | | if (value == null) throw exception(OVERTIME_APPLICATION_NOT_EXISTS); |
| | | return value; |
| | | } |
| | | |
| | | private HrmOvertimeApplicationDO requireOwnedDraft(Long id, Long userId) { |
| | | HrmOvertimeApplicationDO value = require(id); |
| | | if (!Objects.equals(value.getUserId(), userId) |
| | | || !Objects.equals(value.getStatus(), HrmAuditStatusEnum.DRAFT.getStatus())) { |
| | | throw exception(OVERTIME_APPLICATION_UPDATE_FAIL_NOT_DRAFT); |
| | | } |
| | | return value; |
| | | } |
| | | |
| | | private HrmEmployeeDO requireEmployee(Long userId) { |
| | | HrmEmployeeDO employee = employeeMapper.selectByUserId(userId); |
| | | if (employee == null) throw exception(OVERTIME_APPLICATION_EMPLOYEE_NOT_EXISTS); |
| | | return employee; |
| | | } |
| | | |
| | | /** å½åå¾
å审æ¹äººææ¾å¤çè¿è¯¥æµç¨ç审æ¹äººå¯æ¥çä¸å¡è¯¦æ
ã */ |
| | | private boolean isProcessParticipant(String processInstanceId, Long userId) { |
| | | if (processInstanceId == null || userId == null) { |
| | | return false; |
| | | } |
| | | if (bpmTaskService.getTodoTask(userId, null, processInstanceId) != null) { |
| | | return true; |
| | | } |
| | | return bpmTaskService.getTaskListByProcessInstanceId(processInstanceId, true).stream() |
| | | .anyMatch(task -> Objects.equals(NumberUtil.parseLong(task.getAssignee(), null), userId) |
| | | || Objects.equals(NumberUtil.parseLong(task.getOwner(), null), userId)); |
| | | } |
| | | |
| | | private HrmOvertimeApplicationRespVO buildResp(HrmOvertimeApplicationDO application) { |
| | | HrmOvertimeApplicationRespVO resp = BeanUtils.toBean(application, HrmOvertimeApplicationRespVO.class); |
| | | HrmEmployeeDO employee = employeeMapper.selectById(application.getEmployeeId()); |
| | | if (employee != null) fillEmployee(resp, employee); |
| | | resp.setOvertimeTypeName(HrmOvertimeTypeEnum.getName(application.getOvertimeType())); |
| | | resp.setStatusName(HrmAuditStatusEnum.getNameByStatus(application.getStatus())); |
| | | return resp; |
| | | } |
| | | |
| | | private void fillEmployee(HrmOvertimeApplicationRespVO resp, HrmEmployeeDO employee) { |
| | | resp.setUserId(employee.getUserId()); resp.setEmployeeId(employee.getId()); |
| | | resp.setEmployeeName(employee.getName()); resp.setEmployeeNo(employee.getEmployeeNo()); |
| | | resp.setDeptId(employee.getDeptId()); |
| | | DeptRespDTO dept = employee.getDeptId() == null ? null : deptApi.getDept(employee.getDeptId()); |
| | | PostRespDTO post = employee.getPostId() == null ? null |
| | | : postApi.getPostMap(Collections.singleton(employee.getPostId())).get(employee.getPostId()); |
| | | resp.setDeptName(dept == null ? null : dept.getName()); |
| | | resp.setPostName(post == null ? null : post.getName()); |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.hrm.service.approval.listener; |
| | | |
| | | import cn.iocoder.yudao.module.bpm.api.event.BpmProcessInstanceStatusEvent; |
| | | import cn.iocoder.yudao.module.bpm.api.event.BpmProcessInstanceStatusEventListener; |
| | | import cn.iocoder.yudao.module.hrm.enums.HrmAuditStatusEnum; |
| | | import cn.iocoder.yudao.module.hrm.service.approval.HrmOvertimeApplicationService; |
| | | import cn.iocoder.yudao.module.hrm.util.HrmAuditStatusUtils; |
| | | import jakarta.annotation.Resource; |
| | | import org.springframework.stereotype.Component; |
| | | |
| | | @Component |
| | | public class HrmOvertimeApplicationStatusListener extends BpmProcessInstanceStatusEventListener { |
| | | @Resource private HrmOvertimeApplicationService service; |
| | | @Override protected String getProcessDefinitionKey() { return HrmOvertimeApplicationService.BPM_PROCESS_DEFINITION_KEY; } |
| | | @Override protected void onEvent(BpmProcessInstanceStatusEvent event) { |
| | | Integer status = HrmAuditStatusUtils.convertBpmResultToAuditStatus(event.getStatus()); |
| | | if (status == null) status = HrmAuditStatusEnum.PROCESS.getStatus(); |
| | | service.updateAuditStatus(Long.valueOf(event.getBusinessKey()), status); |
| | | } |
| | | } |
| | |
| | | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| | | 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.employee.HrmEmployeeDO; |
| | | import cn.iocoder.yudao.module.hrm.dal.dataobject.salary.HrmEmployeeSalaryDO; |
| | | import cn.iocoder.yudao.module.hrm.dal.dataobject.salary.HrmEmployeeSocialSecurityDO; |
| | |
| | | import cn.iocoder.yudao.module.hrm.dal.dataobject.salary.HrmSalaryPaymentDetailDO; |
| | | import cn.iocoder.yudao.module.hrm.dal.dataobject.salary.HrmSalaryPaymentDO; |
| | | 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.approval.HrmOvertimeApplicationMapper; |
| | | import cn.iocoder.yudao.module.hrm.dal.mysql.employee.HrmEmployeeMapper; |
| | | import cn.iocoder.yudao.module.hrm.dal.mysql.salary.HrmEmployeeSalaryMapper; |
| | | import cn.iocoder.yudao.module.hrm.dal.mysql.salary.HrmEmployeeSocialSecurityMapper; |
| | |
| | | import cn.iocoder.yudao.module.hrm.dal.mysql.salary.HrmSalaryPaymentDetailMapper; |
| | | import cn.iocoder.yudao.module.hrm.dal.mysql.salary.HrmSalaryPaymentMapper; |
| | | import cn.iocoder.yudao.module.hrm.dal.mysql.salary.HrmSocialSecuritySchemeMapper; |
| | | import cn.iocoder.yudao.module.hrm.dal.mysql.salary.HrmSalaryStructureMapper; |
| | | import cn.iocoder.yudao.module.hrm.dal.redis.HrmNoRedisDAO; |
| | | import cn.iocoder.yudao.module.system.api.dept.DeptApi; |
| | | import cn.iocoder.yudao.module.hrm.enums.HrmOvertimeTypeEnum; |
| | | import jakarta.annotation.Resource; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | |
| | | @Resource |
| | | private HrmLeaveApplicationMapper leaveApplicationMapper; |
| | | @Resource |
| | | private HrmOvertimeApplicationMapper overtimeApplicationMapper; |
| | | @Resource |
| | | private HrmSalaryStructureMapper salaryStructureMapper; |
| | | @Resource |
| | | private HrmLeaveTypeConfigMapper leaveTypeConfigMapper; |
| | | @Resource |
| | | private HrmSalaryPaymentMapper salaryPaymentMapper; |
| | |
| | | if (existCalculations.size() > 1) { |
| | | throw exception(SALARY_CALCULATION_DUPLICATE, employee.getName(), period); |
| | | } |
| | | continue; // å·²åå¨åè·³è¿ |
| | | // 已确认æå·²åæ¾çè®°å½ä¸å¯èªå¨æ¹åï¼å¾
确认记å½å
许éç®ï¼ä»¥å¸æ¶åæ¥å®¡æ¹éè¿çå çã |
| | | if (existCalculations.get(0).getStatus() != 0) { |
| | | continue; |
| | | } |
| | | } |
| | | |
| | | // 2.2 è·ååå·¥èªé
¬æ¡£æ¡ï¼æåå·¥IDæ¥è¯¢ï¼ |
| | |
| | | // 2.5 æå»ºæ ¸ç®è®°å½ï¼å
嫿£é¤è®¡ç®ï¼éè¿æ¹æ¡è·åæ¯ä¾ï¼ |
| | | HrmSalaryCalculationDO calculation = buildSalaryCalculation(period, employeeId, employee, employeeSalary, socialSecurity, scheme, effectiveDate); |
| | | |
| | | // 2.6 çææ ¸ç®åå· |
| | | String no = noRedisDAO.generateSalaryCalculationNo(); |
| | | while (salaryCalculationMapper.selectByNo(no) != null) { |
| | | no = noRedisDAO.generateSalaryCalculationNo(); |
| | | // 2.6 ä¿åï¼é¦æ¬¡çæåå·ï¼å·²æå¾
确认记å½åä¿çåå·å¹¶è¦çéç®ç»æ |
| | | if (CollUtil.isNotEmpty(existCalculations)) { |
| | | HrmSalaryCalculationDO existing = existCalculations.get(0); |
| | | calculation.setId(existing.getId()); |
| | | calculation.setNo(existing.getNo()); |
| | | salaryCalculationMapper.updateById(calculation); |
| | | } else { |
| | | String no = noRedisDAO.generateSalaryCalculationNo(); |
| | | while (salaryCalculationMapper.selectByNo(no) != null) { |
| | | no = noRedisDAO.generateSalaryCalculationNo(); |
| | | } |
| | | calculation.setNo(no); |
| | | salaryCalculationMapper.insert(calculation); |
| | | } |
| | | calculation.setNo(no); |
| | | |
| | | // 2.7 ä¿åæ ¸ç®è®°å½ |
| | | salaryCalculationMapper.insert(calculation); |
| | | } |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | /** |
| | | * æå»ºé»è®¤çåå·¥èªé
¬æ¡£æ¡ï¼åºäºå工表çåºæ¬å·¥èµï¼ |
| | | * æå»ºé»è®¤çåå·¥èªé
¬æ¡£æ¡ãåºæ¬å·¥èµç»ä¸åå工档æ¡ï¼ç»©æå·¥èµé»è®¤ä¸èªå¨çæã |
| | | */ |
| | | private HrmEmployeeSalaryDO buildDefaultEmployeeSalary(Long employeeId, HrmEmployeeDO employee) { |
| | | BigDecimal baseSalary = employee.getBaseSalary() != null ? employee.getBaseSalary() : BigDecimal.ZERO; |
| | | return HrmEmployeeSalaryDO.builder() |
| | | .userId(employeeId) // 使ç¨åå·¥ID |
| | | .salaryStructureId(employee.getSalaryStructureId()) |
| | | .baseSalary(employee.getBaseSalary() != null ? employee.getBaseSalary() : BigDecimal.ZERO) |
| | | .baseSalary(baseSalary) |
| | | .performanceSalary(BigDecimal.ZERO) |
| | | .mealAllowance(BigDecimal.ZERO) |
| | | .transportAllowance(BigDecimal.ZERO) |
| | |
| | | BigDecimal mealAllowance = employeeSalary.getMealAllowance() != null ? employeeSalary.getMealAllowance() : BigDecimal.ZERO; |
| | | BigDecimal transportAllowance = employeeSalary.getTransportAllowance() != null ? employeeSalary.getTransportAllowance() : BigDecimal.ZERO; |
| | | BigDecimal otherAllowance = employeeSalary.getOtherAllowance() != null ? employeeSalary.getOtherAllowance() : BigDecimal.ZERO; |
| | | BigDecimal overtimePay = BigDecimal.ZERO; |
| | | OvertimeSalary overtimeSalary = calculateOvertimeSalary(employee, employeeSalary, period, baseSalary); |
| | | BigDecimal overtimePay = overtimeSalary.pay(); |
| | | |
| | | // åºåå·¥èµæ»é¢ |
| | | BigDecimal totalIncome = baseSalary.add(performanceSalary).add(mealAllowance) |
| | | .add(transportAllowance).add(otherAllowance).add(overtimePay); |
| | | |
| | | // è·å社ä¿åºæ°ï¼å工档æ¡ä¸ç个æ§ååºæ°ï¼ |
| | | // è·å社ä¿åºæ°ï¼åå·¥ç¤¾ä¿æ¡£æ¡ > åå·¥åºæ¬å·¥èµ |
| | | BigDecimal socialSecurityBase = (socialSecurity != null && socialSecurity.getSocialSecurityBase() != null) |
| | | ? socialSecurity.getSocialSecurityBase() : baseSalary; |
| | | |
| | | // è·åå
¬ç§¯éåºæ°ï¼å工档æ¡ä¸ç个æ§ååºæ°ï¼ |
| | | // è·åå
¬ç§¯éåºæ°ï¼åå·¥ç¤¾ä¿æ¡£æ¡ > åå·¥åºæ¬å·¥èµ |
| | | BigDecimal housingFundBase = (socialSecurity != null && socialSecurity.getHousingFundBase() != null) |
| | | ? socialSecurity.getHousingFundBase() : baseSalary; |
| | | |
| | |
| | | .leaveDeduction(leaveDeduction) |
| | | .actualSalary(actualSalary) |
| | | .workDays(22) // é»è®¤å·¥ä½æ¥ |
| | | .overtimeHours(BigDecimal.ZERO) |
| | | .overtimeHours(overtimeSalary.hours()) |
| | | .status(0) // å¾
确认 |
| | | .build(); |
| | | } |
| | |
| | | |
| | | return totalLeaveDeduction; |
| | | } |
| | | |
| | | /** |
| | | * æ±æ»å½æå®¡æ¹éè¿çå çç³è¯·ãå°æ¶å·¥èµæåºæ¬å·¥èµ / 21.75 / 8 计ç®ï¼ |
| | | * 工使¥é»è®¤ 1.5 åã伿¯æ¥é»è®¤ 2 åãæ³å®è忥é»è®¤ 3 åï¼åå¯ç±èªé
¬ç»æè¦çã |
| | | */ |
| | | private OvertimeSalary calculateOvertimeSalary(HrmEmployeeDO employee, HrmEmployeeSalaryDO employeeSalary, |
| | | String period, BigDecimal baseSalary) { |
| | | if (employee.getUserId() == null) { |
| | | return new OvertimeSalary(BigDecimal.ZERO, BigDecimal.ZERO); |
| | | } |
| | | YearMonth month = YearMonth.parse(period); |
| | | List<HrmOvertimeApplicationDO> applications = overtimeApplicationMapper.selectApprovedByUserAndDateRange( |
| | | employee.getUserId(), month.atDay(1), month.atEndOfMonth()); |
| | | if (CollUtil.isEmpty(applications)) { |
| | | return new OvertimeSalary(BigDecimal.ZERO, BigDecimal.ZERO); |
| | | } |
| | | Long structureId = employeeSalary.getSalaryStructureId() != null |
| | | ? employeeSalary.getSalaryStructureId() : employee.getSalaryStructureId(); |
| | | HrmSalaryStructureDO structure = structureId == null ? null : salaryStructureMapper.selectById(structureId); |
| | | BigDecimal workdayMultiplier = structure != null && structure.getOvertimePayRatio() != null |
| | | ? structure.getOvertimePayRatio() : HrmOvertimeTypeEnum.WORKDAY.getSalaryMultiplier(); |
| | | BigDecimal restDayMultiplier = structure != null && structure.getRestDayOvertimePayRatio() != null |
| | | ? structure.getRestDayOvertimePayRatio() : HrmOvertimeTypeEnum.REST_DAY.getSalaryMultiplier(); |
| | | BigDecimal legalHolidayMultiplier = structure != null && structure.getLegalHolidayOvertimePayRatio() != null |
| | | ? structure.getLegalHolidayOvertimePayRatio() : HrmOvertimeTypeEnum.LEGAL_HOLIDAY.getSalaryMultiplier(); |
| | | BigDecimal hourlySalary = baseSalary.divide(new BigDecimal("21.75"), 8, RoundingMode.HALF_UP) |
| | | .divide(new BigDecimal("8"), 8, RoundingMode.HALF_UP); |
| | | BigDecimal totalHours = BigDecimal.ZERO; |
| | | BigDecimal totalPay = BigDecimal.ZERO; |
| | | for (HrmOvertimeApplicationDO application : applications) { |
| | | BigDecimal hours = application.getDuration() == null ? BigDecimal.ZERO : application.getDuration(); |
| | | HrmOvertimeTypeEnum type = HrmOvertimeTypeEnum.valueOfType(application.getOvertimeType()); |
| | | if (type == null || hours.signum() <= 0) { |
| | | continue; |
| | | } |
| | | BigDecimal multiplier = switch (type) { |
| | | case WORKDAY -> workdayMultiplier; |
| | | case REST_DAY -> restDayMultiplier; |
| | | case LEGAL_HOLIDAY -> legalHolidayMultiplier; |
| | | }; |
| | | totalHours = totalHours.add(hours); |
| | | totalPay = totalPay.add(hourlySalary.multiply(hours).multiply(multiplier)); |
| | | } |
| | | return new OvertimeSalary(totalHours.setScale(1, RoundingMode.HALF_UP), |
| | | totalPay.setScale(2, RoundingMode.HALF_UP)); |
| | | } |
| | | |
| | | private record OvertimeSalary(BigDecimal hours, BigDecimal pay) {} |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | |
| | | salaryCalculationMapper.deleteById(id); |
| | | } |
| | | |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.hrm.service.salary; |
| | | |
| | | import cn.iocoder.yudao.module.hrm.dal.dataobject.salary.HrmSalaryStructureDO; |
| | | |
| | | import java.util.List; |
| | | |
| | | public interface HrmSalaryStructureService { |
| | | |
| | | Long createSalaryStructure(HrmSalaryStructureDO structure); |
| | | |
| | | void updateSalaryStructure(HrmSalaryStructureDO structure); |
| | | |
| | | void deleteSalaryStructure(Long id); |
| | | |
| | | HrmSalaryStructureDO getSalaryStructure(Long id); |
| | | |
| | | List<HrmSalaryStructureDO> getSalaryStructureList(String name, Integer status); |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.hrm.service.salary; |
| | | |
| | | import cn.iocoder.yudao.module.hrm.dal.dataobject.salary.HrmSalaryStructureDO; |
| | | import cn.iocoder.yudao.module.hrm.dal.mysql.employee.HrmEmployeeMapper; |
| | | import cn.iocoder.yudao.module.hrm.dal.mysql.salary.HrmEmployeeSalaryMapper; |
| | | import cn.iocoder.yudao.module.hrm.dal.mysql.salary.HrmSalaryStructureMapper; |
| | | import jakarta.annotation.Resource; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.validation.annotation.Validated; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.util.List; |
| | | |
| | | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| | | import static cn.iocoder.yudao.module.hrm.enums.ErrorCodeConstants.SALARY_STRUCTURE_IN_USE; |
| | | import static cn.iocoder.yudao.module.hrm.enums.ErrorCodeConstants.SALARY_STRUCTURE_NAME_EXISTS; |
| | | import static cn.iocoder.yudao.module.hrm.enums.ErrorCodeConstants.SALARY_STRUCTURE_NOT_EXISTS; |
| | | |
| | | @Service |
| | | @Validated |
| | | public class HrmSalaryStructureServiceImpl implements HrmSalaryStructureService { |
| | | |
| | | @Resource |
| | | private HrmSalaryStructureMapper salaryStructureMapper; |
| | | @Resource |
| | | private HrmEmployeeMapper employeeMapper; |
| | | @Resource |
| | | private HrmEmployeeSalaryMapper employeeSalaryMapper; |
| | | |
| | | @Override |
| | | public Long createSalaryStructure(HrmSalaryStructureDO structure) { |
| | | validateNameUnique(null, structure.getName()); |
| | | // åºæ¬å·¥èµç±å工档æ¡ç»´æ¤ãæ°æ®åºåå²å段éç©ºï¼æ°å»ºç»æç»ä¸åå
¥å ä½å¼ 0ã |
| | | structure.setBaseSalary(BigDecimal.ZERO); |
| | | salaryStructureMapper.insert(structure); |
| | | return structure.getId(); |
| | | } |
| | | |
| | | @Override |
| | | public void updateSalaryStructure(HrmSalaryStructureDO structure) { |
| | | validateExists(structure.getId()); |
| | | validateNameUnique(structure.getId(), structure.getName()); |
| | | salaryStructureMapper.updateById(structure); |
| | | } |
| | | |
| | | @Override |
| | | public void deleteSalaryStructure(Long id) { |
| | | validateExists(id); |
| | | if (employeeMapper.selectCountBySalaryStructureId(id) > 0 |
| | | || employeeSalaryMapper.selectCountBySalaryStructureId(id) > 0) { |
| | | throw exception(SALARY_STRUCTURE_IN_USE); |
| | | } |
| | | salaryStructureMapper.deleteById(id); |
| | | } |
| | | |
| | | @Override |
| | | public HrmSalaryStructureDO getSalaryStructure(Long id) { |
| | | return salaryStructureMapper.selectById(id); |
| | | } |
| | | |
| | | @Override |
| | | public List<HrmSalaryStructureDO> getSalaryStructureList(String name, Integer status) { |
| | | return salaryStructureMapper.selectListByCondition(name, status); |
| | | } |
| | | |
| | | private void validateExists(Long id) { |
| | | if (id == null || salaryStructureMapper.selectById(id) == null) { |
| | | throw exception(SALARY_STRUCTURE_NOT_EXISTS); |
| | | } |
| | | } |
| | | |
| | | private void validateNameUnique(Long id, String name) { |
| | | HrmSalaryStructureDO structure = salaryStructureMapper.selectByName(name); |
| | | if (structure != null && !structure.getId().equals(id)) { |
| | | throw exception(SALARY_STRUCTURE_NAME_EXISTS); |
| | | } |
| | | } |
| | | |
| | | } |