mirror of
https://gitee.com/zhijiantianya/yudao-cloud.git
synced 2026-10-06 07:22:58 +08:00
Merge branch 'master-jdk17' of https://gitee.com/zhijiantianya/yudao-cloud
# Conflicts: # yudao-module-fms/yudao-module-fms-server/src/test/java/cn/iocoder/yudao/module/fms/service/config/FmsAccountUserServiceImplTest.java # yudao-module-hrm/yudao-module-hrm-server/src/test/java/cn/iocoder/yudao/module/hrm/service/insurance/monthrecord/HrmInsuranceMonthEmployeeRecordServiceImplTest.java # yudao-module-hrm/yudao-module-hrm-server/src/test/java/cn/iocoder/yudao/module/hrm/service/performance/assessment/HrmPerformanceAssessmentProcessServiceImplTest.java # yudao-module-hrm/yudao-module-hrm-server/src/test/java/cn/iocoder/yudao/module/hrm/service/recruit/candidate/HrmRecruitInterviewServiceImplTest.java # yudao-module-hrm/yudao-module-hrm-server/src/test/java/cn/iocoder/yudao/module/hrm/service/recruit/post/HrmRecruitPostServiceImplTest.java # yudao-module-hrm/yudao-module-hrm-server/src/test/java/cn/iocoder/yudao/module/hrm/service/salary/config/HrmSalaryGroupServiceImplTest.java # yudao-module-hrm/yudao-module-hrm-server/src/test/java/cn/iocoder/yudao/module/hrm/service/salary/slip/HrmSalarySlipServiceImplTest.java
This commit is contained in:
@@ -716,6 +716,7 @@ INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_t
|
||||
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (117, 11, '支付宝 Wap 网站支付', 'alipay_wap', 'pay_channel_code', 0, 'primary', '', '支付宝 Wap 网站支付', '1', '2021-12-03 10:42:26', '1', '2023-07-19 20:09:16', '0');
|
||||
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (118, 12, '支付宝 App 支付', 'alipay_app', 'pay_channel_code', 0, 'primary', '', '支付宝 App 支付', '1', '2021-12-03 10:42:55', '1', '2023-07-19 20:09:20', '0');
|
||||
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (119, 14, '支付宝扫码支付', 'alipay_qr', 'pay_channel_code', 0, 'primary', '', '支付宝扫码支付', '1', '2021-12-03 10:43:10', '1', '2023-07-19 20:09:28', '0');
|
||||
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3449, 15, '支付宝小程序支付', 'alipay_lite', 'pay_channel_code', 0, 'primary', '', '支付宝小程序支付', '1', '2026-08-18 00:00:00', '1', '2026-08-18 00:00:00', '0');
|
||||
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (120, 10, '通知成功', '10', 'pay_notify_status', 0, 'success', '', '通知成功', '1', '2021-12-03 11:02:41', '1', '2023-07-19 10:08:19', '0');
|
||||
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (121, 20, '通知失败', '20', 'pay_notify_status', 0, 'danger', '', '通知失败', '1', '2021-12-03 11:02:59', '1', '2023-07-19 10:08:21', '0');
|
||||
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (122, 0, '等待通知', '0', 'pay_notify_status', 0, 'info', '', '未通知', '1', '2021-12-03 11:03:10', '1', '2023-07-19 10:08:24', '0');
|
||||
|
||||
@@ -817,6 +817,7 @@ INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_t
|
||||
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (117, 11, '支付宝 Wap 网站支付', 'alipay_wap', 'pay_channel_code', 0, 'primary', '', '支付宝 Wap 网站支付', '1', '2021-12-03 10:42:26', '1', '2023-07-19 20:09:16', '0');
|
||||
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (118, 12, '支付宝 App 支付', 'alipay_app', 'pay_channel_code', 0, 'primary', '', '支付宝 App 支付', '1', '2021-12-03 10:42:55', '1', '2023-07-19 20:09:20', '0');
|
||||
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (119, 14, '支付宝扫码支付', 'alipay_qr', 'pay_channel_code', 0, 'primary', '', '支付宝扫码支付', '1', '2021-12-03 10:43:10', '1', '2023-07-19 20:09:28', '0');
|
||||
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3449, 15, '支付宝小程序支付', 'alipay_lite', 'pay_channel_code', 0, 'primary', '', '支付宝小程序支付', '1', '2026-08-18 00:00:00', '1', '2026-08-18 00:00:00', '0');
|
||||
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (120, 10, '通知成功', '10', 'pay_notify_status', 0, 'success', '', '通知成功', '1', '2021-12-03 11:02:41', '1', '2023-07-19 10:08:19', '0');
|
||||
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (121, 20, '通知失败', '20', 'pay_notify_status', 0, 'danger', '', '通知失败', '1', '2021-12-03 11:02:59', '1', '2023-07-19 10:08:21', '0');
|
||||
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (122, 0, '等待通知', '0', 'pay_notify_status', 0, 'info', '', '未通知', '1', '2021-12-03 11:03:10', '1', '2023-07-19 10:08:24', '0');
|
||||
@@ -6195,4 +6196,3 @@ COMMIT;
|
||||
DROP SEQUENCE IF EXISTS yudao_demo03_student_seq;
|
||||
CREATE SEQUENCE yudao_demo03_student_seq
|
||||
START 10;
|
||||
|
||||
|
||||
@@ -817,6 +817,7 @@ INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_t
|
||||
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (117, 11, '支付宝 Wap 网站支付', 'alipay_wap', 'pay_channel_code', 0, 'primary', '', '支付宝 Wap 网站支付', '1', '2021-12-03 10:42:26', '1', '2023-07-19 20:09:16', '0');
|
||||
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (118, 12, '支付宝 App 支付', 'alipay_app', 'pay_channel_code', 0, 'primary', '', '支付宝 App 支付', '1', '2021-12-03 10:42:55', '1', '2023-07-19 20:09:20', '0');
|
||||
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (119, 14, '支付宝扫码支付', 'alipay_qr', 'pay_channel_code', 0, 'primary', '', '支付宝扫码支付', '1', '2021-12-03 10:43:10', '1', '2023-07-19 20:09:28', '0');
|
||||
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3449, 15, '支付宝小程序支付', 'alipay_lite', 'pay_channel_code', 0, 'primary', '', '支付宝小程序支付', '1', '2026-08-18 00:00:00', '1', '2026-08-18 00:00:00', '0');
|
||||
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (120, 10, '通知成功', '10', 'pay_notify_status', 0, 'success', '', '通知成功', '1', '2021-12-03 11:02:41', '1', '2023-07-19 10:08:19', '0');
|
||||
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (121, 20, '通知失败', '20', 'pay_notify_status', 0, 'danger', '', '通知失败', '1', '2021-12-03 11:02:59', '1', '2023-07-19 10:08:21', '0');
|
||||
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (122, 0, '等待通知', '0', 'pay_notify_status', 0, 'info', '', '未通知', '1', '2021-12-03 11:03:10', '1', '2023-07-19 10:08:24', '0');
|
||||
@@ -1663,7 +1664,7 @@ COMMIT;
|
||||
|
||||
DROP SEQUENCE IF EXISTS system_dict_data_seq;
|
||||
CREATE SEQUENCE system_dict_data_seq
|
||||
START 3449;
|
||||
START 3450;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for system_dict_type
|
||||
|
||||
+508
-293
File diff suppressed because it is too large
Load Diff
@@ -817,6 +817,7 @@ INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_t
|
||||
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (117, 11, '支付宝 Wap 网站支付', 'alipay_wap', 'pay_channel_code', 0, 'primary', '', '支付宝 Wap 网站支付', '1', '2021-12-03 10:42:26', '1', '2023-07-19 20:09:16', '0');
|
||||
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (118, 12, '支付宝 App 支付', 'alipay_app', 'pay_channel_code', 0, 'primary', '', '支付宝 App 支付', '1', '2021-12-03 10:42:55', '1', '2023-07-19 20:09:20', '0');
|
||||
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (119, 14, '支付宝扫码支付', 'alipay_qr', 'pay_channel_code', 0, 'primary', '', '支付宝扫码支付', '1', '2021-12-03 10:43:10', '1', '2023-07-19 20:09:28', '0');
|
||||
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3449, 15, '支付宝小程序支付', 'alipay_lite', 'pay_channel_code', 0, 'primary', '', '支付宝小程序支付', '1', '2026-08-18 00:00:00', '1', '2026-08-18 00:00:00', '0');
|
||||
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (120, 10, '通知成功', '10', 'pay_notify_status', 0, 'success', '', '通知成功', '1', '2021-12-03 11:02:41', '1', '2023-07-19 10:08:19', '0');
|
||||
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (121, 20, '通知失败', '20', 'pay_notify_status', 0, 'danger', '', '通知失败', '1', '2021-12-03 11:02:59', '1', '2023-07-19 10:08:21', '0');
|
||||
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (122, 0, '等待通知', '0', 'pay_notify_status', 0, 'info', '', '未通知', '1', '2021-12-03 11:03:10', '1', '2023-07-19 10:08:24', '0');
|
||||
@@ -1663,7 +1664,7 @@ COMMIT;
|
||||
|
||||
DROP SEQUENCE IF EXISTS system_dict_data_seq;
|
||||
CREATE SEQUENCE system_dict_data_seq
|
||||
START 3449;
|
||||
START 3450;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for system_dict_type
|
||||
|
||||
@@ -769,6 +769,7 @@ INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_t
|
||||
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (117, 11, '支付宝 Wap 网站支付', 'alipay_wap', 'pay_channel_code', 0, 'primary', '', '支付宝 Wap 网站支付', '1', to_date('2021-12-03 10:42:26', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-07-19 20:09:16', 'SYYYY-MM-DD HH24:MI:SS'), '0');
|
||||
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (118, 12, '支付宝 App 支付', 'alipay_app', 'pay_channel_code', 0, 'primary', '', '支付宝 App 支付', '1', to_date('2021-12-03 10:42:55', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-07-19 20:09:20', 'SYYYY-MM-DD HH24:MI:SS'), '0');
|
||||
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (119, 14, '支付宝扫码支付', 'alipay_qr', 'pay_channel_code', 0, 'primary', '', '支付宝扫码支付', '1', to_date('2021-12-03 10:43:10', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-07-19 20:09:28', 'SYYYY-MM-DD HH24:MI:SS'), '0');
|
||||
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3449, 15, '支付宝小程序支付', 'alipay_lite', 'pay_channel_code', 0, 'primary', '', '支付宝小程序支付', '1', to_date('2026-08-18 00:00:00', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2026-08-18 00:00:00', 'SYYYY-MM-DD HH24:MI:SS'), '0');
|
||||
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (120, 10, '通知成功', '10', 'pay_notify_status', 0, 'success', '', '通知成功', '1', to_date('2021-12-03 11:02:41', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-07-19 10:08:19', 'SYYYY-MM-DD HH24:MI:SS'), '0');
|
||||
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (121, 20, '通知失败', '20', 'pay_notify_status', 0, 'danger', '', '通知失败', '1', to_date('2021-12-03 11:02:59', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-07-19 10:08:21', 'SYYYY-MM-DD HH24:MI:SS'), '0');
|
||||
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (122, 0, '等待通知', '0', 'pay_notify_status', 0, 'info', '', '未通知', '1', to_date('2021-12-03 11:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-07-19 10:08:24', 'SYYYY-MM-DD HH24:MI:SS'), '0');
|
||||
@@ -1614,7 +1615,7 @@ COMMIT;
|
||||
-- @formatter:on
|
||||
|
||||
CREATE SEQUENCE system_dict_data_seq
|
||||
START WITH 3449;
|
||||
START WITH 3450;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for system_dict_type
|
||||
|
||||
@@ -817,6 +817,7 @@ INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_t
|
||||
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (117, 11, '支付宝 Wap 网站支付', 'alipay_wap', 'pay_channel_code', 0, 'primary', '', '支付宝 Wap 网站支付', '1', '2021-12-03 10:42:26', '1', '2023-07-19 20:09:16', '0');
|
||||
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (118, 12, '支付宝 App 支付', 'alipay_app', 'pay_channel_code', 0, 'primary', '', '支付宝 App 支付', '1', '2021-12-03 10:42:55', '1', '2023-07-19 20:09:20', '0');
|
||||
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (119, 14, '支付宝扫码支付', 'alipay_qr', 'pay_channel_code', 0, 'primary', '', '支付宝扫码支付', '1', '2021-12-03 10:43:10', '1', '2023-07-19 20:09:28', '0');
|
||||
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3449, 15, '支付宝小程序支付', 'alipay_lite', 'pay_channel_code', 0, 'primary', '', '支付宝小程序支付', '1', '2026-08-18 00:00:00', '1', '2026-08-18 00:00:00', '0');
|
||||
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (120, 10, '通知成功', '10', 'pay_notify_status', 0, 'success', '', '通知成功', '1', '2021-12-03 11:02:41', '1', '2023-07-19 10:08:19', '0');
|
||||
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (121, 20, '通知失败', '20', 'pay_notify_status', 0, 'danger', '', '通知失败', '1', '2021-12-03 11:02:59', '1', '2023-07-19 10:08:21', '0');
|
||||
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (122, 0, '等待通知', '0', 'pay_notify_status', 0, 'info', '', '未通知', '1', '2021-12-03 11:03:10', '1', '2023-07-19 10:08:24', '0');
|
||||
|
||||
@@ -2258,6 +2258,7 @@ GO
|
||||
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (118, 12, N'支付宝 App 支付', N'alipay_app', N'pay_channel_code', 0, N'primary', N'', N'支付宝 App 支付', N'1', N'2021-12-03 10:42:55', N'1', N'2023-07-19 20:09:20', N'0')
|
||||
GO
|
||||
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (119, 14, N'支付宝扫码支付', N'alipay_qr', N'pay_channel_code', 0, N'primary', N'', N'支付宝扫码支付', N'1', N'2021-12-03 10:43:10', N'1', N'2023-07-19 20:09:28', N'0')
|
||||
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3449, 15, N'支付宝小程序支付', N'alipay_lite', N'pay_channel_code', 0, N'primary', N'', N'支付宝小程序支付', N'1', N'2026-08-18 00:00:00', N'1', N'2026-08-18 00:00:00', N'0')
|
||||
GO
|
||||
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (120, 10, N'通知成功', N'10', N'pay_notify_status', 0, N'success', N'', N'通知成功', N'1', N'2021-12-03 11:02:41', N'1', N'2023-07-19 10:08:19', N'0')
|
||||
GO
|
||||
|
||||
-2
@@ -5,8 +5,6 @@ package cn.iocoder.yudao.framework.datasource.core.enums;
|
||||
*
|
||||
* 通过在方法上,使用 {@link com.baomidou.dynamic.datasource.annotation.DS} 注解,设置使用的数据源。
|
||||
* 注意,默认是 {@link #MASTER} 数据源
|
||||
*
|
||||
* 对应官方文档为 http://dynamic-datasource.com/guide/customize/Annotation.html
|
||||
*/
|
||||
public interface DataSourceEnum {
|
||||
|
||||
|
||||
+37
@@ -9,6 +9,7 @@ import org.springframework.util.StringUtils;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Collection;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* 拓展 MyBatis Plus QueryWrapper 类,主要增加如下功能:
|
||||
@@ -158,4 +159,40 @@ public class LambdaQueryWrapperX<T> extends LambdaQueryWrapper<T> {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LambdaQueryWrapperX<T> exists(boolean condition, String existsSql, Object... values) {
|
||||
super.exists(condition, existsSql, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LambdaQueryWrapperX<T> notExists(boolean condition, String existsSql, Object... values) {
|
||||
super.notExists(condition, existsSql, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LambdaQueryWrapperX<T> and(boolean condition, Consumer<LambdaQueryWrapper<T>> consumer) {
|
||||
super.and(condition, consumer);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LambdaQueryWrapperX<T> or(boolean condition, Consumer<LambdaQueryWrapper<T>> consumer) {
|
||||
super.or(condition, consumer);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LambdaQueryWrapperX<T> nested(boolean condition, Consumer<LambdaQueryWrapper<T>> consumer) {
|
||||
super.nested(condition, consumer);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LambdaQueryWrapperX<T> not(boolean condition, Consumer<LambdaQueryWrapper<T>> consumer) {
|
||||
super.not(condition, consumer);
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+14
@@ -13,6 +13,7 @@ import org.springframework.beans.factory.config.MethodInvokingFactoryBean;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureOrder;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
@@ -74,6 +75,19 @@ public class YudaoSecurityAutoConfiguration {
|
||||
return new TokenAuthenticationFilter(securityProperties, globalExceptionHandler, oauth2TokenApi);
|
||||
}
|
||||
|
||||
/**
|
||||
* Token 过滤器由 Spring Security FilterChain 管理,禁止 Spring Boot 再注册为 Servlet 全局 Filter
|
||||
*
|
||||
* @see <a href="https://github.com/YunaiV/ruoyi-vue-pro/issues/1198">Issue #1198</a>
|
||||
*/
|
||||
@Bean
|
||||
public FilterRegistrationBean<TokenAuthenticationFilter> tokenAuthenticationFilterRegistration(
|
||||
TokenAuthenticationFilter filter) {
|
||||
FilterRegistrationBean<TokenAuthenticationFilter> registration = new FilterRegistrationBean<>(filter);
|
||||
registration.setEnabled(false);
|
||||
return registration;
|
||||
}
|
||||
|
||||
@Bean("ss") // 使用 Spring Security 的缩写,方便使用
|
||||
public SecurityFrameworkService securityFrameworkService(PermissionCommonApi permissionApi) {
|
||||
return new SecurityFrameworkServiceImpl(permissionApi);
|
||||
|
||||
+3
-2
@@ -17,17 +17,19 @@ import javax.validation.constraints.NotNull;
|
||||
public class WebProperties {
|
||||
|
||||
@NotNull(message = "APP API 不能为空")
|
||||
@Valid
|
||||
private Api appApi = new Api("/app-api", "**.controller.app.**");
|
||||
@NotNull(message = "Admin API 不能为空")
|
||||
@Valid
|
||||
private Api adminApi = new Api("/admin-api", "**.controller.admin.**");
|
||||
|
||||
@NotNull(message = "Admin UI 不能为空")
|
||||
@Valid
|
||||
private Ui adminUi;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Valid
|
||||
public static class Api {
|
||||
|
||||
/**
|
||||
@@ -53,7 +55,6 @@ public class WebProperties {
|
||||
}
|
||||
|
||||
@Data
|
||||
@Valid
|
||||
public static class Ui {
|
||||
|
||||
/**
|
||||
|
||||
+5
@@ -300,6 +300,11 @@ public class GlobalExceptionHandler {
|
||||
// 忽略日志,避免影响主流程
|
||||
}
|
||||
}
|
||||
// ServiceException 的错误码可能为成功码,直接调用 CommonResult.error 会抛出异常,此处统一按系统异常处理。
|
||||
// 详见 Issue #1196:https://github.com/YunaiV/ruoyi-vue-pro/issues/1196
|
||||
if (CommonResult.isSuccess(ex.getCode())) {
|
||||
return CommonResult.error(INTERNAL_SERVER_ERROR.getCode(), INTERNAL_SERVER_ERROR.getMsg());
|
||||
}
|
||||
return CommonResult.error(ex.getCode(), ex.getMessage());
|
||||
}
|
||||
|
||||
|
||||
+17
@@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.d
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateStrategy;
|
||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils;
|
||||
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
|
||||
import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
|
||||
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
|
||||
@@ -12,6 +13,7 @@ import javax.annotation.Resource;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
@@ -91,4 +93,19 @@ public abstract class AbstractBpmTaskCandidateDeptLeaderStrategy implements BpmT
|
||||
return deptApi.getDept(startUser.getDeptId()).getCheckedData();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取发起人的部门(优先使用流程变量中的发起人编号)
|
||||
*
|
||||
* @param startUserId 发起人 Id(流程变量不存在时使用)
|
||||
* @param processVariables 流程变量
|
||||
* @return 发起人的部门
|
||||
*/
|
||||
protected DeptRespDTO getStartUserDept(Long startUserId, Map<String, Object> processVariables) {
|
||||
Long processStartUserId = FlowableUtils.getProcessInstanceStartUserId(processVariables);
|
||||
if (processStartUserId != null && processStartUserId > 0) {
|
||||
startUserId = processStartUserId;
|
||||
}
|
||||
return getStartUserDept(startUserId);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-2
@@ -49,7 +49,7 @@ public class BpmTaskCandidateStartUserDeptLeaderMultiStrategy extends AbstractBp
|
||||
ProcessInstance processInstance = processInstanceService.getProcessInstance(execution.getProcessInstanceId());
|
||||
Long startUserId = NumberUtils.parseLong(processInstance.getStartUserId());
|
||||
// 获取发起人的 multi 部门负责人
|
||||
DeptRespDTO dept = super.getStartUserDept(startUserId);
|
||||
DeptRespDTO dept = super.getStartUserDept(startUserId, processInstance.getProcessVariables());
|
||||
if (dept == null) {
|
||||
return new HashSet<>();
|
||||
}
|
||||
@@ -60,7 +60,7 @@ public class BpmTaskCandidateStartUserDeptLeaderMultiStrategy extends AbstractBp
|
||||
public Set<Long> calculateUsersByActivity(BpmnModel bpmnModel, String activityId, String param,
|
||||
Long startUserId, String processDefinitionId, Map<String, Object> processVariables) {
|
||||
int level = Integer.parseInt(param); // 参数是部门的层级
|
||||
DeptRespDTO dept = super.getStartUserDept(startUserId);
|
||||
DeptRespDTO dept = super.getStartUserDept(startUserId, processVariables);
|
||||
if (dept == null) {
|
||||
return new HashSet<>();
|
||||
}
|
||||
|
||||
+5
-4
@@ -48,19 +48,20 @@ public class BpmTaskCandidateStartUserDeptLeaderStrategy extends AbstractBpmTask
|
||||
ProcessInstance processInstance = processInstanceService.getProcessInstance(execution.getProcessInstanceId());
|
||||
Long startUserId = NumberUtils.parseLong(processInstance.getStartUserId());
|
||||
// 获取发起人的部门负责人
|
||||
return getStartUserDeptLeader(startUserId, param);
|
||||
return getStartUserDeptLeader(startUserId, param, processInstance.getProcessVariables());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Long> calculateUsersByActivity(BpmnModel bpmnModel, String activityId, String param,
|
||||
Long startUserId, String processDefinitionId, Map<String, Object> processVariables) {
|
||||
// 获取发起人的部门负责人
|
||||
return getStartUserDeptLeader(startUserId, param);
|
||||
return getStartUserDeptLeader(startUserId, param, processVariables);
|
||||
}
|
||||
|
||||
private Set<Long> getStartUserDeptLeader(Long startUserId, String param) {
|
||||
private Set<Long> getStartUserDeptLeader(Long startUserId, String param,
|
||||
Map<String, Object> processVariables) {
|
||||
int level = Integer.parseInt(param); // 参数是部门的层级
|
||||
DeptRespDTO dept = super.getStartUserDept(startUserId);
|
||||
DeptRespDTO dept = super.getStartUserDept(startUserId, processVariables);
|
||||
if (dept == null) {
|
||||
return new HashSet<>();
|
||||
}
|
||||
|
||||
+12
@@ -1,5 +1,6 @@
|
||||
package cn.iocoder.yudao.module.bpm.framework.flowable.core.util;
|
||||
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
@@ -133,6 +134,17 @@ public class FlowableUtils {
|
||||
return (Integer) processVariables.get(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_STATUS);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得流程实例的发起用户 ID
|
||||
*
|
||||
* @param processVariables 流程实例的 variables
|
||||
* @return 发起用户 ID
|
||||
*/
|
||||
public static Long getProcessInstanceStartUserId(Map<String, Object> processVariables) {
|
||||
return processVariables == null ? null : Convert.toLong(
|
||||
processVariables.get(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_START_USER_ID));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得流程实例的审批原因
|
||||
*
|
||||
|
||||
+14
-5
@@ -1,6 +1,7 @@
|
||||
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.dept;
|
||||
|
||||
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
|
||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnVariableConstants;
|
||||
import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService;
|
||||
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
|
||||
import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
|
||||
@@ -13,6 +14,8 @@ import org.junit.jupiter.api.Test;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
@@ -42,12 +45,16 @@ public class BpmTaskCandidateStartUserDeptLeaderMultiStrategyTest extends BaseMo
|
||||
String param = "2";
|
||||
// mock 方法(获得流程发起人)
|
||||
Long startUserId = 1L;
|
||||
Long processVariableStartUserId = 2L;
|
||||
ProcessInstance processInstance = mock(ProcessInstance.class);
|
||||
DelegateExecution execution = mock(DelegateExecution.class);
|
||||
when(processInstanceService.getProcessInstance(eq(execution.getProcessInstanceId()))).thenReturn(processInstance);
|
||||
when(processInstance.getStartUserId()).thenReturn(startUserId.toString());
|
||||
Map<String, Object> processVariables = new HashMap<>();
|
||||
processVariables.put(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_START_USER_ID, processVariableStartUserId);
|
||||
when(processInstance.getProcessVariables()).thenReturn(processVariables);
|
||||
// mock 方法(获取发起人的 multi 部门负责人)
|
||||
mockGetStartUserDept(startUserId);
|
||||
mockGetStartUserDept(processVariableStartUserId);
|
||||
|
||||
// 调用
|
||||
Set<Long> userIds = strategy.calculateUsersByTask(execution, param);
|
||||
@@ -61,12 +68,14 @@ public class BpmTaskCandidateStartUserDeptLeaderMultiStrategyTest extends BaseMo
|
||||
String param = "2";
|
||||
// mock 方法
|
||||
Long startUserId = 1L;
|
||||
mockGetStartUserDept(startUserId);
|
||||
Long processVariableStartUserId = 2L;
|
||||
Map<String, Object> processVariables = new HashMap<>();
|
||||
processVariables.put(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_START_USER_ID, processVariableStartUserId);
|
||||
mockGetStartUserDept(processVariableStartUserId);
|
||||
|
||||
// 调用
|
||||
Set<Long> userIds = strategy.calculateUsersByActivity(null, null, param,
|
||||
startUserId, null, null);
|
||||
// 断言
|
||||
startUserId, null, processVariables);
|
||||
|
||||
assertEquals(Sets.newLinkedHashSet(11L, 1001L), userIds);
|
||||
}
|
||||
|
||||
|
||||
+14
-5
@@ -1,6 +1,7 @@
|
||||
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.dept;
|
||||
|
||||
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
|
||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnVariableConstants;
|
||||
import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService;
|
||||
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
|
||||
import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
|
||||
@@ -13,6 +14,8 @@ import org.junit.jupiter.api.Test;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
@@ -42,12 +45,16 @@ public class BpmTaskCandidateStartUserDeptLeaderStrategyTest extends BaseMockito
|
||||
String param = "2";
|
||||
// mock 方法(获得流程发起人)
|
||||
Long startUserId = 1L;
|
||||
Long processVariableStartUserId = 2L;
|
||||
ProcessInstance processInstance = mock(ProcessInstance.class);
|
||||
DelegateExecution execution = mock(DelegateExecution.class);
|
||||
when(processInstanceService.getProcessInstance(eq(execution.getProcessInstanceId()))).thenReturn(processInstance);
|
||||
when(processInstance.getStartUserId()).thenReturn(startUserId.toString());
|
||||
Map<String, Object> processVariables = new HashMap<>();
|
||||
processVariables.put(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_START_USER_ID, processVariableStartUserId);
|
||||
when(processInstance.getProcessVariables()).thenReturn(processVariables);
|
||||
// mock 方法(获取发起人的部门负责人)
|
||||
mockGetStartUserDeptLeader(startUserId);
|
||||
mockGetStartUserDeptLeader(processVariableStartUserId);
|
||||
|
||||
// 调用
|
||||
Set<Long> userIds = strategy.calculateUsersByTask(execution, param);
|
||||
@@ -61,12 +68,14 @@ public class BpmTaskCandidateStartUserDeptLeaderStrategyTest extends BaseMockito
|
||||
String param = "2";
|
||||
// mock 方法
|
||||
Long startUserId = 1L;
|
||||
mockGetStartUserDeptLeader(startUserId);
|
||||
Long processVariableStartUserId = 2L;
|
||||
Map<String, Object> processVariables = new HashMap<>();
|
||||
processVariables.put(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_START_USER_ID, processVariableStartUserId);
|
||||
mockGetStartUserDeptLeader(processVariableStartUserId);
|
||||
|
||||
// 调用
|
||||
Set<Long> userIds = strategy.calculateUsersByActivity(null, null, param,
|
||||
startUserId, null, null);
|
||||
// 断言
|
||||
startUserId, null, processVariables);
|
||||
|
||||
assertEquals(Sets.newLinkedHashSet(1001L), userIds);
|
||||
}
|
||||
|
||||
|
||||
+24
@@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.common.core.KeyValue;
|
||||
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.BpmModelMetaInfoVO;
|
||||
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO;
|
||||
import cn.iocoder.yudao.module.bpm.enums.definition.BpmModelFormTypeEnum;
|
||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnVariableConstants;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
@@ -22,6 +23,29 @@ import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
*/
|
||||
class FlowableUtilsTest {
|
||||
|
||||
@Test
|
||||
public void testGetProcessInstanceStartUserId() {
|
||||
// 准备参数
|
||||
Map<String, Object> processVariables = new HashMap<>();
|
||||
processVariables.put(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_START_USER_ID, "1");
|
||||
|
||||
// 调用
|
||||
Long startUserId = FlowableUtils.getProcessInstanceStartUserId(processVariables);
|
||||
|
||||
// 断言
|
||||
assertEquals(1L, startUserId);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetProcessInstanceStartUserId_empty() {
|
||||
// 准备参数
|
||||
Map<String, Object> processVariables = new HashMap<>();
|
||||
|
||||
// 调用 & 断言
|
||||
assertNull(FlowableUtils.getProcessInstanceStartUserId(processVariables));
|
||||
assertNull(FlowableUtils.getProcessInstanceStartUserId(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetSummary_customSummary_parseDbFormFields() {
|
||||
// 准备参数:模拟 DB 中 form_fields 字段,列表里每个元素都是一个 form-create 字段 JSON。
|
||||
|
||||
+1
-1
@@ -102,7 +102,7 @@ public class FmsAccountUserServiceImpl implements FmsAccountUserService {
|
||||
FmsAccountUserUpdateReqVO.Member::getUserId, FmsAccountUserUpdateReqVO.Member::getLevel);
|
||||
Set<Long> memberUserIds = new HashSet<>(memberLevelMap.keySet());
|
||||
memberUserIds.removeAll(founderUserIds);
|
||||
adminUserApi.validateUserList(memberUserIds);
|
||||
adminUserApi.validateUserList(memberUserIds).checkError();
|
||||
|
||||
// 2.1 移出取消授权的成员
|
||||
Set<Long> currentMemberUserIds = convertSet(accountUsers, FmsAccountUserDO::getUserId,
|
||||
|
||||
+12
-4
@@ -7,10 +7,11 @@ import cn.iocoder.yudao.module.fms.dal.dataobject.config.FmsAccountUserDO;
|
||||
import cn.iocoder.yudao.module.fms.dal.mysql.config.FmsAccountUserMapper;
|
||||
import cn.iocoder.yudao.module.fms.enums.config.FmsAccountUserLevelEnum;
|
||||
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
|
||||
import javax.annotation.Resource;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.test.context.bean.override.mockito.MockitoBean;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
@@ -22,6 +23,8 @@ import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
import static org.mockito.ArgumentMatchers.anyCollection;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@@ -33,11 +36,16 @@ public class FmsAccountUserServiceImplTest extends BaseDbUnitTest {
|
||||
@Resource
|
||||
private FmsAccountUserMapper accountUserMapper;
|
||||
|
||||
@MockBean
|
||||
@MockitoBean
|
||||
private FmsAccountSetService accountSetService;
|
||||
@MockBean
|
||||
@MockitoBean
|
||||
private AdminUserApi adminUserApi;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
when(adminUserApi.validateUserList(anyCollection())).thenReturn(success(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateAccountOwner_firstAccountSet() {
|
||||
// 准备参数
|
||||
|
||||
+1
-1
@@ -312,7 +312,7 @@ public class HrmAttendanceGroupServiceImpl implements HrmAttendanceGroupService
|
||||
|
||||
private void validateAttendanceGroup(HrmAttendanceGroupSaveReqVO reqVO) {
|
||||
// 1. 校验适用部门存在
|
||||
deptApi.validateDeptList(reqVO.getDeptIds());
|
||||
deptApi.validateDeptList(reqVO.getDeptIds()).checkError();
|
||||
// 2. 校验适用员工存在
|
||||
employeeService.validateEmployeeListExists(reqVO.getEmployeeIds());
|
||||
}
|
||||
|
||||
+3
-3
@@ -628,7 +628,7 @@ public class HrmEmployeeServiceImpl implements HrmEmployeeService {
|
||||
throw exception(EMPLOYEE_CREATE_USER_LIST_DUPLICATE);
|
||||
}
|
||||
}
|
||||
adminUserApi.validateUserList(userIds);
|
||||
adminUserApi.validateUserList(userIds).checkError();
|
||||
Map<Long, AdminUserRespDTO> userMap = convertMap(
|
||||
adminUserApi.getUserList(userIds).getCheckedData(), AdminUserRespDTO::getId);
|
||||
// 1.2 构建并校验全部员工档案,避免部分数据校验失败时已经执行写库
|
||||
@@ -1179,7 +1179,7 @@ public class HrmEmployeeServiceImpl implements HrmEmployeeService {
|
||||
private void validateDeptAndLeader(Long employeeId, Long deptId, Long leaderEmployeeId) {
|
||||
// 1. 校验部门是否存在
|
||||
if (deptId != null) {
|
||||
deptApi.validateDeptList(Collections.singleton(deptId));
|
||||
deptApi.validateDeptList(Collections.singleton(deptId)).checkError();
|
||||
}
|
||||
// 2. 校验直属上级链路不存在自引用或环路
|
||||
if (leaderEmployeeId == null) {
|
||||
@@ -1417,7 +1417,7 @@ public class HrmEmployeeServiceImpl implements HrmEmployeeService {
|
||||
try {
|
||||
notifyMessageSendApi.sendSingleMessageToAdmin(new NotifySendSingleToUserReqDTO()
|
||||
.setUserId(employee.getUserId()).setTemplateCode(templateCode)
|
||||
.setTemplateParams(Collections.singletonMap("employeeName", employee.getName())));
|
||||
.setTemplateParams(Collections.singletonMap("employeeName", employee.getName()))).checkError();
|
||||
return true;
|
||||
} catch (RuntimeException ex) {
|
||||
log.warn("[sendEmployeeMessage][employeeId({}) userId({}) templateCode({}) 发送失败]",
|
||||
|
||||
+1
-1
@@ -536,7 +536,7 @@ public class HrmInsuranceMonthEmployeeRecordServiceImpl implements HrmInsuranceM
|
||||
notifyMessageSendApi.sendSingleMessageToAdmin(new NotifySendSingleToUserReqDTO()
|
||||
.setUserId(employee.getUserId())
|
||||
.setTemplateCode(MessageTemplateConstants.INSURANCE_MONTH_RECORD_CREATED)
|
||||
.setTemplateParams(templateParams));
|
||||
.setTemplateParams(templateParams)).checkError();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-2
@@ -350,7 +350,7 @@ public class HrmPerformanceAssessmentProcessServiceImpl
|
||||
notifyMessageSendApi.sendSingleMessageToAdmin(new NotifySendSingleToUserReqDTO()
|
||||
.setUserId(handler.getUserId())
|
||||
.setTemplateCode(MessageTemplateConstants.PERFORMANCE_TASK_PENDING)
|
||||
.setTemplateParams(templateParams));
|
||||
.setTemplateParams(templateParams)).checkError();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -386,7 +386,7 @@ public class HrmPerformanceAssessmentProcessServiceImpl
|
||||
notifyMessageSendApi.sendSingleMessageToAdmin(new NotifySendSingleToUserReqDTO()
|
||||
.setUserId(employee.getUserId())
|
||||
.setTemplateCode(MessageTemplateConstants.PERFORMANCE_PROCESS_RESULT)
|
||||
.setTemplateParams(templateParams));
|
||||
.setTemplateParams(templateParams)).checkError();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -555,7 +555,7 @@ public class HrmPerformancePlanServiceImpl implements HrmPerformancePlanService
|
||||
employeeService.validateEmployeeListExists(employeeIds);
|
||||
}
|
||||
if (CollUtil.isNotEmpty(deptIds)) {
|
||||
deptApi.validateDeptList(deptIds);
|
||||
deptApi.validateDeptList(deptIds).checkError();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -351,7 +351,7 @@ public class HrmRecruitInterviewServiceImpl implements HrmRecruitInterviewServic
|
||||
templateParams.put("interviewTime", INTERVIEW_TIME_FORMATTER.format(recruitInterview.getInterviewTime()));
|
||||
userIds.forEach(userId -> notifyMessageSendApi.sendSingleMessageToAdmin(new NotifySendSingleToUserReqDTO()
|
||||
.setUserId(userId).setTemplateCode(MessageTemplateConstants.RECRUIT_INTERVIEW_ARRANGED)
|
||||
.setTemplateParams(templateParams)));
|
||||
.setTemplateParams(templateParams)).checkError());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
-1
@@ -146,7 +146,7 @@ public class HrmRecruitPostServiceImpl implements HrmRecruitPostService {
|
||||
// 1. 校验职位类型和用人部门存在
|
||||
recruitPostTypeService.validateRecruitPostTypeExists(reqVO.getPostTypeId());
|
||||
if (reqVO.getDeptId() != null) {
|
||||
deptApi.validateDeptList(Collections.singleton(reqVO.getDeptId()));
|
||||
deptApi.validateDeptList(Collections.singleton(reqVO.getDeptId())).checkError();
|
||||
}
|
||||
|
||||
// 2. 校验招聘负责人和面试官存在
|
||||
|
||||
+1
-1
@@ -221,7 +221,7 @@ public class HrmSalaryGroupServiceImpl implements HrmSalaryGroupService {
|
||||
// 1. 校验适用部门及其上下级部门未归属其他薪资组
|
||||
Set<Long> selectedDeptIds = CollUtil.isEmpty(deptIds)
|
||||
? Collections.emptySet() : new HashSet<>(deptIds);
|
||||
deptApi.validateDeptList(selectedDeptIds);
|
||||
deptApi.validateDeptList(selectedDeptIds).checkError();
|
||||
List<HrmSalaryGroupDO> otherSalaryGroups = convertList(salaryGroupMapper.selectListByIdDesc(),
|
||||
salaryGroup -> salaryGroup, salaryGroup -> ObjUtil.notEqual(salaryGroup.getId(), id));
|
||||
if (CollUtil.isNotEmpty(selectedDeptIds)) {
|
||||
|
||||
+1
-1
@@ -256,7 +256,7 @@ public class HrmSalarySlipServiceImpl implements HrmSalarySlipService {
|
||||
templateParams.put("realSalary", employeeRecord.getRealPaySalary().toPlainString());
|
||||
notifyMessageSendApi.sendSingleMessageToAdmin(new NotifySendSingleToUserReqDTO()
|
||||
.setUserId(employee.getUserId()).setTemplateCode(MessageTemplateConstants.SALARY_SLIP_SENT)
|
||||
.setTemplateParams(templateParams));
|
||||
.setTemplateParams(templateParams)).checkError();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+19
-3
@@ -13,6 +13,7 @@ import cn.iocoder.yudao.module.hrm.enums.attendance.config.HrmAttendanceMisscard
|
||||
import cn.iocoder.yudao.module.hrm.service.employee.info.HrmEmployeeService;
|
||||
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
|
||||
import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.InjectMocks;
|
||||
@@ -22,13 +23,23 @@ import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
import java.util.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyCollection;
|
||||
import static org.mockito.Mockito.*;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.lenient;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* {@link HrmAttendanceGroupServiceImpl} 的单元测试类
|
||||
@@ -49,6 +60,11 @@ public class HrmAttendanceGroupServiceImplTest extends BaseMockitoUnitTest {
|
||||
@Mock
|
||||
private DeptApi deptApi;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
lenient().when(deptApi.validateDeptList(anyCollection())).thenReturn(success(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAttendanceGroupMap_employeeAndDeptAndDefaultGroup() {
|
||||
// mock 数据
|
||||
|
||||
+4
@@ -68,6 +68,7 @@ import static java.util.Arrays.asList;
|
||||
import static java.util.Collections.*;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyCollection;
|
||||
import static org.mockito.ArgumentMatchers.argThat;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
@@ -128,6 +129,9 @@ public class HrmEmployeeServiceImplTest extends BaseDbUnitTest {
|
||||
HrmEmployeeChangeRecordCreateReqVO reqVO = invocation.getArgument(0);
|
||||
return BeanUtils.toBean(reqVO, HrmEmployeeChangeRecordDO.class).setId(randomLongId());
|
||||
});
|
||||
lenient().when(deptApi.validateDeptList(anyCollection())).thenReturn(success(true));
|
||||
lenient().when(adminUserApi.validateUserList(anyCollection())).thenReturn(success(true));
|
||||
lenient().when(notifyMessageSendApi.sendSingleMessageToAdmin(any())).thenReturn(success(randomLongId()));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+15
-7
@@ -24,10 +24,11 @@ import cn.iocoder.yudao.module.hrm.service.employee.info.HrmEmployeeService;
|
||||
import cn.iocoder.yudao.module.hrm.service.insurance.config.HrmInsuranceSchemeService;
|
||||
import cn.iocoder.yudao.module.hrm.service.insurance.employee.HrmInsuranceEmployeeInfoService;
|
||||
import cn.iocoder.yudao.module.system.api.notify.NotifyMessageSendApi;
|
||||
import javax.annotation.Resource;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.test.context.bean.override.mockito.MockitoBean;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
@@ -37,6 +38,8 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
|
||||
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId;
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
|
||||
import static cn.iocoder.yudao.module.hrm.enums.ErrorCodeConstants.INSURANCE_EMPLOYEE_SCHEME_NOT_CONFIGURED;
|
||||
import static cn.iocoder.yudao.module.hrm.enums.ErrorCodeConstants.INSURANCE_MONTH_EMPLOYEE_NOT_ELIGIBLE;
|
||||
@@ -62,17 +65,22 @@ public class HrmInsuranceMonthEmployeeRecordServiceImplTest extends BaseDbUnitTe
|
||||
@Resource
|
||||
private HrmInsuranceMonthEmployeeRecordMapper monthEmployeeRecordMapper;
|
||||
|
||||
@MockBean
|
||||
@MockitoBean
|
||||
private HrmInsuranceMonthRecordService monthRecordService;
|
||||
@MockBean
|
||||
@MockitoBean
|
||||
private HrmInsuranceSchemeService insuranceSchemeService;
|
||||
@MockBean
|
||||
@MockitoBean
|
||||
private HrmInsuranceEmployeeInfoService insuranceEmployeeInfoService;
|
||||
@MockBean
|
||||
@MockitoBean
|
||||
private HrmEmployeeService employeeService;
|
||||
@MockBean
|
||||
@MockitoBean
|
||||
private NotifyMessageSendApi notifyMessageSendApi;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
when(notifyMessageSendApi.sendSingleMessageToAdmin(any())).thenReturn(success(randomLongId()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateMonthEmployeeRecordList_success() {
|
||||
// mock 数据
|
||||
|
||||
+15
-7
@@ -42,11 +42,12 @@ import cn.iocoder.yudao.module.hrm.service.employee.info.HrmEmployeeService;
|
||||
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
|
||||
import cn.iocoder.yudao.module.system.api.notify.NotifyMessageSendApi;
|
||||
import cn.iocoder.yudao.module.system.api.notify.dto.NotifySendSingleToUserReqDTO;
|
||||
import javax.annotation.Resource;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.test.context.bean.override.mockito.MockitoBean;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
@@ -57,6 +58,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId;
|
||||
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
|
||||
import static cn.iocoder.yudao.module.hrm.enums.ErrorCodeConstants.PERFORMANCE_STAGE_NO_PERMISSION;
|
||||
@@ -70,6 +72,7 @@ import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.lenient;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@@ -100,17 +103,22 @@ public class HrmPerformanceAssessmentProcessServiceImplTest extends BaseDbUnitTe
|
||||
@Resource
|
||||
private HrmPerformancePlanMapper planMapper;
|
||||
|
||||
@MockBean
|
||||
@MockitoBean
|
||||
private HrmEmployeeService employeeService;
|
||||
@MockBean
|
||||
@MockitoBean
|
||||
private DeptApi deptApi;
|
||||
@MockBean
|
||||
@MockitoBean
|
||||
private HrmPerformancePlanService planService;
|
||||
@MockBean
|
||||
@MockitoBean
|
||||
private NotifyMessageSendApi notifyMessageSendApi;
|
||||
@MockBean
|
||||
@MockitoBean
|
||||
private HrmPerformanceAssessmentActionRecordService assessmentActionRecordService;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
lenient().when(notifyMessageSendApi.sendSingleMessageToAdmin(any())).thenReturn(success(randomLongId()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInitializeAssessmentStages_unboundEmployee_fail() {
|
||||
// mock 数据
|
||||
|
||||
+12
-5
@@ -14,11 +14,12 @@ import cn.iocoder.yudao.module.hrm.enums.recruit.candidate.HrmRecruitInterviewRe
|
||||
import cn.iocoder.yudao.module.hrm.service.employee.info.HrmEmployeeService;
|
||||
import cn.iocoder.yudao.module.system.api.notify.NotifyMessageSendApi;
|
||||
import cn.iocoder.yudao.module.system.api.notify.dto.NotifySendSingleToUserReqDTO;
|
||||
import javax.annotation.Resource;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.test.context.bean.override.mockito.MockitoBean;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
@@ -27,6 +28,7 @@ import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
|
||||
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
|
||||
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
|
||||
@@ -61,13 +63,18 @@ public class HrmRecruitInterviewServiceImplTest extends BaseDbUnitTest {
|
||||
@Resource
|
||||
private HrmRecruitInterviewMapper recruitInterviewMapper;
|
||||
|
||||
@MockBean
|
||||
@MockitoBean
|
||||
private HrmRecruitCandidateService recruitCandidateService;
|
||||
@MockBean
|
||||
@MockitoBean
|
||||
private HrmEmployeeService employeeService;
|
||||
@MockBean
|
||||
@MockitoBean
|
||||
private NotifyMessageSendApi notifyMessageSendApi;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
when(notifyMessageSendApi.sendSingleMessageToAdmin(any())).thenReturn(success(randomLongId()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateRecruitInterview_success() {
|
||||
// mock 数据
|
||||
|
||||
+13
-5
@@ -12,10 +12,11 @@ import cn.iocoder.yudao.module.hrm.enums.employee.info.HrmEmployeeEntryStatusEnu
|
||||
import cn.iocoder.yudao.module.hrm.enums.recruit.post.HrmRecruitPostStatusEnum;
|
||||
import cn.iocoder.yudao.module.hrm.service.employee.info.HrmEmployeeService;
|
||||
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
|
||||
import javax.annotation.Resource;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.test.context.bean.override.mockito.MockitoBean;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
@@ -25,6 +26,7 @@ import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
|
||||
import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime;
|
||||
import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.getDateTimeRange;
|
||||
@@ -44,6 +46,7 @@ import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.mockito.ArgumentMatchers.anyCollection;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.doThrow;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoInteractions;
|
||||
|
||||
@@ -61,13 +64,18 @@ public class HrmRecruitPostServiceImplTest extends BaseDbUnitTest {
|
||||
@Resource
|
||||
private HrmRecruitPostMapper recruitPostMapper;
|
||||
|
||||
@MockBean
|
||||
@MockitoBean
|
||||
private HrmRecruitPostTypeService recruitPostTypeService;
|
||||
@MockBean
|
||||
@MockitoBean
|
||||
private HrmEmployeeService employeeService;
|
||||
@MockBean
|
||||
@MockitoBean
|
||||
private DeptApi deptApi;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
when(deptApi.validateDeptList(anyCollection())).thenReturn(success(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateRecruitPost_success() {
|
||||
// 准备参数
|
||||
|
||||
+13
-7
@@ -12,10 +12,11 @@ import cn.iocoder.yudao.module.hrm.dal.mysql.salary.config.HrmSalaryGroupMapper;
|
||||
import cn.iocoder.yudao.module.hrm.service.employee.info.HrmEmployeeService;
|
||||
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
|
||||
import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
|
||||
import javax.annotation.Resource;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.test.context.bean.override.mockito.MockitoBean;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
@@ -32,10 +33,10 @@ import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
|
||||
import static cn.iocoder.yudao.module.hrm.enums.ErrorCodeConstants.*;
|
||||
import static java.util.Collections.emptyList;
|
||||
import static java.util.Collections.singletonList;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.mockito.ArgumentMatchers.anyCollection;
|
||||
import static org.mockito.ArgumentMatchers.argThat;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* {@link HrmSalaryGroupServiceImpl} 的单元测试类
|
||||
@@ -51,13 +52,18 @@ public class HrmSalaryGroupServiceImplTest extends BaseDbUnitTest {
|
||||
@Resource
|
||||
private HrmSalaryGroupMapper salaryGroupMapper;
|
||||
|
||||
@MockBean
|
||||
@MockitoBean
|
||||
private HrmSalaryTaxRuleService salaryTaxRuleService;
|
||||
@MockBean
|
||||
@MockitoBean
|
||||
private HrmEmployeeService employeeService;
|
||||
@MockBean
|
||||
@MockitoBean
|
||||
private DeptApi deptApi;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
when(deptApi.validateDeptList(anyCollection())).thenReturn(success(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateSalaryGroup_success() {
|
||||
// 准备参数
|
||||
|
||||
+13
-4
@@ -13,10 +13,11 @@ import cn.iocoder.yudao.module.hrm.service.employee.info.HrmEmployeeService;
|
||||
import cn.iocoder.yudao.module.system.api.notify.NotifyMessageSendApi;
|
||||
import cn.iocoder.yudao.module.hrm.enums.salary.slip.HrmSalarySlipReadStatusEnum;
|
||||
import cn.iocoder.yudao.module.hrm.enums.salary.slip.HrmSalarySlipTemplateOptionTypeEnum;
|
||||
import javax.annotation.Resource;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.test.context.bean.override.mockito.MockitoBean;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.YearMonth;
|
||||
@@ -27,6 +28,7 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
import static cn.iocoder.yudao.module.hrm.enums.ErrorCodeConstants.SALARY_SLIP_ALREADY_SENT;
|
||||
import static cn.iocoder.yudao.module.hrm.enums.ErrorCodeConstants.SALARY_SLIP_NOT_EXISTS;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
@@ -37,6 +39,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.argThat;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId;
|
||||
|
||||
/**
|
||||
* {@link HrmSalarySlipServiceImpl} 的单元测试类
|
||||
@@ -51,11 +54,17 @@ public class HrmSalarySlipServiceImplTest extends BaseDbUnitTest {
|
||||
@Resource
|
||||
private HrmSalarySlipMapper salarySlipMapper;
|
||||
|
||||
@MockBean
|
||||
@MockitoBean
|
||||
private HrmEmployeeService employeeService;
|
||||
@MockBean
|
||||
@MockitoBean
|
||||
private NotifyMessageSendApi notifyMessageSendApi;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
when(notifyMessageSendApi.sendSingleMessageToAdmin(org.mockito.ArgumentMatchers.any()))
|
||||
.thenReturn(success(randomLongId()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateSalarySlipList_success() {
|
||||
// mock 数据
|
||||
|
||||
-2
@@ -36,7 +36,6 @@ public class AppFileController {
|
||||
@Operation(summary = "上传文件")
|
||||
@Parameter(name = "file", description = "文件附件", required = true,
|
||||
schema = @Schema(type = "string", format = "binary"))
|
||||
@PermitAll
|
||||
public CommonResult<String> uploadFile(@Valid AppFileUploadReqVO uploadReqVO) throws Exception {
|
||||
MultipartFile file = uploadReqVO.getFile();
|
||||
byte[] content = IoUtil.readBytes(file.getInputStream());
|
||||
@@ -58,7 +57,6 @@ public class AppFileController {
|
||||
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "创建文件", description = "模式二:前端上传文件:配合 presigned-url 接口,记录上传了上传的文件")
|
||||
@PermitAll
|
||||
public CommonResult<Long> createFile(@Valid @RequestBody FileCreateReqVO createReqVO) {
|
||||
return success(fileService.createFile(createReqVO));
|
||||
}
|
||||
|
||||
+6
@@ -173,6 +173,12 @@ public class S3FileClient extends AbstractFileClient<S3FileClientConfig> {
|
||||
* @return 节点地址
|
||||
*/
|
||||
private String buildPresignerEndpoint() {
|
||||
// 阿里云 OSS、七牛云的自定义域名仅用于文件访问,不能作为 S3 签名节点。
|
||||
// Presigner 必须使用服务商提供的 endpoint,否则生成的签名无法用于直传。
|
||||
if (StrUtil.contains(config.getEndpoint(), S3FileClientConfig.ENDPOINT_ALIYUN)
|
||||
|| StrUtil.contains(config.getEndpoint(), S3FileClientConfig.ENDPOINT_QINIU)) {
|
||||
return buildEndpoint();
|
||||
}
|
||||
// 补全 domain
|
||||
if (StrUtil.isEmpty(config.getDomain())) {
|
||||
config.setDomain(buildDomain());
|
||||
|
||||
+36
@@ -69,6 +69,42 @@ public class S3FileClientTest {
|
||||
assertFalse(result.contains("%25E4%25B8%25AD"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPresignPutUrl_aliyunUsesEndpointInsteadOfCustomDomain() {
|
||||
S3FileClientConfig config = new S3FileClientConfig();
|
||||
config.setAccessKey("access-key");
|
||||
config.setAccessSecret("access-secret");
|
||||
config.setBucket("test-bucket");
|
||||
config.setDomain("https://custom.example.com");
|
||||
config.setEndpoint("oss-cn-beijing.aliyuncs.com");
|
||||
config.setEnablePathStyleAccess(false);
|
||||
config.setEnablePublicAccess(false);
|
||||
S3FileClient client = new S3FileClient(0L, config);
|
||||
client.init();
|
||||
|
||||
String result = client.presignPutUrl("avatar.jpg");
|
||||
|
||||
assertTrue(result.startsWith("https://test-bucket.oss-cn-beijing.aliyuncs.com/"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPresignPutUrl_qiniuUsesEndpointInsteadOfCustomDomain() {
|
||||
S3FileClientConfig config = new S3FileClientConfig();
|
||||
config.setAccessKey("access-key");
|
||||
config.setAccessSecret("access-secret");
|
||||
config.setBucket("test-bucket");
|
||||
config.setDomain("https://custom.example.com");
|
||||
config.setEndpoint("s3-cn-south-1.qiniucs.com");
|
||||
config.setEnablePathStyleAccess(false);
|
||||
config.setEnablePublicAccess(false);
|
||||
S3FileClient client = new S3FileClient(0L, config);
|
||||
client.init();
|
||||
|
||||
String result = client.presignPutUrl("avatar.jpg");
|
||||
|
||||
assertTrue(result.startsWith("https://test-bucket.s3-cn-south-1.qiniucs.com/"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Disabled // MinIO,如果要集成测试,可以注释本行
|
||||
public void testMinIO() throws Exception {
|
||||
|
||||
+3
-1
@@ -66,6 +66,8 @@ public interface ErrorCodeConstants {
|
||||
|
||||
ErrorCode OTA_FIRMWARE_NOT_EXISTS = new ErrorCode(1_050_008_000, "固件信息不存在");
|
||||
ErrorCode OTA_FIRMWARE_PRODUCT_VERSION_DUPLICATE = new ErrorCode(1_050_008_001, "产品版本号重复");
|
||||
ErrorCode OTA_FIRMWARE_DELETE_FAIL_TASK_IN_PROGRESS = new ErrorCode(1_050_008_002,
|
||||
"删除 OTA 固件失败,原因:存在进行中的升级任务");
|
||||
|
||||
// ========== OTA 升级任务相关 1-050-008-100 ==========
|
||||
|
||||
@@ -105,4 +107,4 @@ public interface ErrorCodeConstants {
|
||||
// ========== IoT 告警记录 1-050-014-000 ==========
|
||||
ErrorCode ALERT_RECORD_NOT_EXISTS = new ErrorCode(1_050_014_000, "IoT 告警记录不存在");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -83,10 +83,10 @@ public class IotDeviceMessageController {
|
||||
|
||||
@PostMapping("/send")
|
||||
@Operation(summary = "发送消息", description = "可用于设备模拟")
|
||||
@PreAuthorize("@ss.hasPermission('iot:device:message-end')")
|
||||
@PreAuthorize("@ss.hasPermission('iot:device:message-send')")
|
||||
public CommonResult<Boolean> sendDeviceMessage(@Valid @RequestBody IotDeviceMessageSendReqVO sendReqVO) {
|
||||
deviceMessageService.sendDeviceMessage(BeanUtils.toBean(sendReqVO, IotDeviceMessage.class));
|
||||
return success(true);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
+10
@@ -12,6 +12,7 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;
|
||||
import cn.iocoder.yudao.module.iot.service.ota.IotOtaFirmwareService;
|
||||
import cn.iocoder.yudao.module.iot.service.product.IotProductService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
@@ -48,6 +49,15 @@ public class IotOtaFirmwareController {
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete")
|
||||
@Operation(summary = "删除 OTA 固件")
|
||||
@Parameter(name = "id", description = "固件编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('iot:ota-firmware:delete')")
|
||||
public CommonResult<Boolean> deleteOtaFirmware(@RequestParam("id") Long id) {
|
||||
otaFirmwareService.deleteOtaFirmware(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得 OTA 固件")
|
||||
@PreAuthorize("@ss.hasPermission('iot:ota-firmware:query')")
|
||||
|
||||
+7
@@ -5,6 +5,7 @@ import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.task.IotOtaTaskPageReqVO;
|
||||
import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaTaskDO;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@@ -16,6 +17,12 @@ public interface IotOtaTaskMapper extends BaseMapperX<IotOtaTaskDO> {
|
||||
IotOtaTaskDO::getName, name);
|
||||
}
|
||||
|
||||
default Long selectCountByFirmwareIdAndStatus(Long firmwareId, Integer status) {
|
||||
return selectCount(new LambdaQueryWrapper<IotOtaTaskDO>()
|
||||
.eq(IotOtaTaskDO::getFirmwareId, firmwareId)
|
||||
.eq(IotOtaTaskDO::getStatus, status));
|
||||
}
|
||||
|
||||
default PageResult<IotOtaTaskDO> selectPage(IotOtaTaskPageReqVO pageReqVO) {
|
||||
return selectPage(pageReqVO, new LambdaQueryWrapperX<IotOtaTaskDO>()
|
||||
.eqIfPresent(IotOtaTaskDO::getFirmwareId, pageReqVO.getFirmwareId())
|
||||
|
||||
+7
@@ -35,6 +35,13 @@ public interface IotOtaFirmwareService {
|
||||
*/
|
||||
void updateOtaFirmware(@Valid IotOtaFirmwareUpdateReqVO updateReqVO);
|
||||
|
||||
/**
|
||||
* 删除 OTA 固件信息
|
||||
*
|
||||
* @param id 固件编号
|
||||
*/
|
||||
void deleteOtaFirmware(Long id);
|
||||
|
||||
/**
|
||||
* 获取 OTA 固件信息
|
||||
*
|
||||
|
||||
+18
@@ -10,6 +10,8 @@ import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware.IotOtaFirmwa
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware.IotOtaFirmwareUpdateReqVO;
|
||||
import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaFirmwareDO;
|
||||
import cn.iocoder.yudao.module.iot.dal.mysql.ota.IotOtaFirmwareMapper;
|
||||
import cn.iocoder.yudao.module.iot.dal.mysql.ota.IotOtaTaskMapper;
|
||||
import cn.iocoder.yudao.module.iot.enums.ota.IotOtaTaskStatusEnum;
|
||||
import cn.iocoder.yudao.module.iot.service.product.IotProductService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
@@ -23,6 +25,7 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.OTA_FIRMWARE_DELETE_FAIL_TASK_IN_PROGRESS;
|
||||
import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.OTA_FIRMWARE_NOT_EXISTS;
|
||||
import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.OTA_FIRMWARE_PRODUCT_VERSION_DUPLICATE;
|
||||
|
||||
@@ -38,6 +41,8 @@ public class IotOtaFirmwareServiceImpl implements IotOtaFirmwareService {
|
||||
|
||||
@Resource
|
||||
private IotOtaFirmwareMapper otaFirmwareMapper;
|
||||
@Resource
|
||||
private IotOtaTaskMapper otaTaskMapper;
|
||||
@Lazy
|
||||
@Resource
|
||||
private IotProductService productService;
|
||||
@@ -74,6 +79,19 @@ public class IotOtaFirmwareServiceImpl implements IotOtaFirmwareService {
|
||||
otaFirmwareMapper.updateById(updateObj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteOtaFirmware(Long id) {
|
||||
// 1.1 校验存在
|
||||
validateFirmwareExists(id);
|
||||
// 1.2 校验是否有进行中的升级任务
|
||||
if (otaTaskMapper.selectCountByFirmwareIdAndStatus(id, IotOtaTaskStatusEnum.IN_PROGRESS.getStatus()) > 0) {
|
||||
throw exception(OTA_FIRMWARE_DELETE_FAIL_TASK_IN_PROGRESS);
|
||||
}
|
||||
|
||||
// 2. 删除
|
||||
otaFirmwareMapper.deleteById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IotOtaFirmwareDO getOtaFirmware(Long id) {
|
||||
return otaFirmwareMapper.selectById(id);
|
||||
|
||||
+2
@@ -137,6 +137,8 @@ public interface ErrorCodeConstants {
|
||||
ErrorCode CAL_TEAM_SHIFT_NOT_EXISTS = new ErrorCode(1_040_201_200, "班组排班记录不存在");
|
||||
ErrorCode CAL_TEAM_SHIFT_GENERATE_TEAM_NOT_ENOUGH = new ErrorCode(1_040_201_201, "班组数量不满足轮班方式要求");
|
||||
ErrorCode CAL_TEAM_SHIFT_GENERATE_SHIFT_NOT_ENOUGH = new ErrorCode(1_040_201_202, "班次数量不满足轮班方式要求");
|
||||
ErrorCode CAL_TEAM_SHIFT_GENERATE_SHIFT_COUNT_INVALID = new ErrorCode(1_040_201_203, "按天倒班必须填写合法的倒班天数");
|
||||
ErrorCode CAL_TEAM_SHIFT_GENERATE_SHIFT_METHOD_INVALID = new ErrorCode(1_040_201_204, "不支持的倒班方式:{}");
|
||||
|
||||
// ========== MES 日历排班-排班计划(1-040-202-000) ==========
|
||||
ErrorCode CAL_PLAN_NOT_EXISTS = new ErrorCode(1_040_202_000, "排班计划不存在");
|
||||
|
||||
+8
@@ -5,6 +5,7 @@ import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||
import cn.iocoder.yudao.module.mes.controller.admin.cal.plan.vo.MesCalPlanPageReqVO;
|
||||
import cn.iocoder.yudao.module.mes.dal.dataobject.cal.plan.MesCalPlanDO;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
@@ -31,4 +32,11 @@ public interface MesCalPlanMapper extends BaseMapperX<MesCalPlanDO> {
|
||||
return selectOne(MesCalPlanDO::getCode, code);
|
||||
}
|
||||
|
||||
default void updateWithShiftFieldCleanup(MesCalPlanDO plan, boolean clearShiftMethod, boolean clearShiftCount) {
|
||||
update(plan, Wrappers.<MesCalPlanDO>lambdaUpdate()
|
||||
.eq(MesCalPlanDO::getId, plan.getId())
|
||||
.set(clearShiftMethod, MesCalPlanDO::getShiftMethod, null)
|
||||
.set(clearShiftCount, MesCalPlanDO::getShiftCount, null));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+14
-2
@@ -9,6 +9,7 @@ import cn.iocoder.yudao.module.mes.controller.admin.cal.plan.vo.MesCalPlanSaveRe
|
||||
import cn.iocoder.yudao.module.mes.dal.dataobject.cal.plan.MesCalPlanDO;
|
||||
import cn.iocoder.yudao.module.mes.dal.mysql.cal.plan.MesCalPlanMapper;
|
||||
import cn.iocoder.yudao.module.mes.enums.cal.MesCalPlanStatusEnum;
|
||||
import cn.iocoder.yudao.module.mes.enums.cal.MesCalShiftMethodEnum;
|
||||
import cn.iocoder.yudao.module.mes.enums.cal.MesCalShiftTypeEnum;
|
||||
import cn.iocoder.yudao.module.mes.service.cal.team.MesCalTeamShiftService;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
@@ -35,6 +36,7 @@ public class MesCalPlanServiceImpl implements MesCalPlanService {
|
||||
|
||||
@Resource
|
||||
private MesCalPlanMapper planMapper;
|
||||
|
||||
@Resource
|
||||
@Lazy
|
||||
private MesCalPlanShiftService planShiftService;
|
||||
@@ -75,10 +77,20 @@ public class MesCalPlanServiceImpl implements MesCalPlanService {
|
||||
// 1.3 校验编码唯一
|
||||
validatePlanCodeUnique(updateReqVO.getId(), updateReqVO.getCode());
|
||||
|
||||
// 2. 更新
|
||||
// 2.1 倒班字段联动清理:单白班不倒班,倒班方式非按天时不需要倒班天数
|
||||
updateReqVO.setStatus(null); // 不允许通过 update 修改状态,状态变更走专用接口
|
||||
boolean clearShiftMethod = MesCalShiftTypeEnum.SINGLE.getType().equals(updateReqVO.getShiftType());
|
||||
boolean clearShiftCount = clearShiftMethod || updateReqVO.getShiftMethod() == null
|
||||
|| !MesCalShiftMethodEnum.DAY.getMethod().equals(updateReqVO.getShiftMethod());
|
||||
if (clearShiftMethod) {
|
||||
updateReqVO.setShiftMethod(null);
|
||||
}
|
||||
if (clearShiftCount) {
|
||||
updateReqVO.setShiftCount(null);
|
||||
}
|
||||
// 2.2 更新
|
||||
MesCalPlanDO updateObj = BeanUtils.toBean(updateReqVO, MesCalPlanDO.class);
|
||||
planMapper.updateById(updateObj);
|
||||
planMapper.updateWithShiftFieldCleanup(updateObj, clearShiftMethod, clearShiftCount);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+13
-4
@@ -25,6 +25,8 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.CAL_TEAM_SHIFT_GENERATE_SHIFT_COUNT_INVALID;
|
||||
import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.CAL_TEAM_SHIFT_GENERATE_SHIFT_METHOD_INVALID;
|
||||
import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.CAL_TEAM_SHIFT_GENERATE_SHIFT_NOT_ENOUGH;
|
||||
import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.CAL_TEAM_SHIFT_GENERATE_TEAM_NOT_ENOUGH;
|
||||
|
||||
@@ -39,6 +41,7 @@ public class MesCalTeamShiftServiceImpl implements MesCalTeamShiftService {
|
||||
|
||||
@Resource
|
||||
private MesCalTeamShiftMapper teamShiftMapper;
|
||||
|
||||
@Resource
|
||||
@Lazy
|
||||
private MesCalPlanService planService;
|
||||
@@ -77,8 +80,10 @@ public class MesCalTeamShiftServiceImpl implements MesCalTeamShiftService {
|
||||
for (int i = 0; i < days; i++) {
|
||||
LocalDate currentDate = startDate.plusDays(i);
|
||||
LocalDateTime currentDay = currentDate.atStartOfDay();
|
||||
// 2.2.1 根据倒班方式计算 shiftIndex
|
||||
shiftIndex = calculateShiftIndex(shiftIndex, i, currentDate, startDate, plan);
|
||||
// 2.2.1 根据倒班方式计算 shiftIndex 单白班不倒班,跳过
|
||||
if (!MesCalShiftTypeEnum.SINGLE.getType().equals(plan.getShiftType())) {
|
||||
shiftIndex = calculateShiftIndex(shiftIndex, i, currentDate, startDate, plan);
|
||||
}
|
||||
// 2.2.2 根据轮班方式生成排班记录,收集到列表
|
||||
buildRecordsForDay(allRecords, planId, currentDay, shiftIndex, plan.getShiftType(), teams, shifts);
|
||||
}
|
||||
@@ -118,11 +123,15 @@ public class MesCalTeamShiftServiceImpl implements MesCalTeamShiftService {
|
||||
}
|
||||
} else if (MesCalShiftMethodEnum.DAY.getMethod().equals(plan.getShiftMethod())) {
|
||||
// 按天轮班:到了指定轮班天数的倍数
|
||||
if (dayOffset % plan.getShiftCount() == 0) {
|
||||
Integer shiftCount = plan.getShiftCount();
|
||||
if (shiftCount == null || shiftCount <= 0) {
|
||||
throw exception(CAL_TEAM_SHIFT_GENERATE_SHIFT_COUNT_INVALID);
|
||||
}
|
||||
if (dayOffset % shiftCount == 0) {
|
||||
return shiftIndex + 1;
|
||||
}
|
||||
} else {
|
||||
throw new IllegalArgumentException("不支持的倒班方式: " + plan.getShiftMethod());
|
||||
throw exception(CAL_TEAM_SHIFT_GENERATE_SHIFT_METHOD_INVALID, plan.getShiftMethod());
|
||||
}
|
||||
return shiftIndex;
|
||||
}
|
||||
|
||||
+1
@@ -29,6 +29,7 @@ public enum PayChannelEnum implements ArrayValuable<String> {
|
||||
ALIPAY_APP("alipay_app", "支付宝App 支付"),
|
||||
ALIPAY_QR("alipay_qr", "支付宝扫码支付"),
|
||||
ALIPAY_BAR("alipay_bar", "支付宝条码支付"),
|
||||
ALIPAY_LITE("alipay_lite", "支付宝小程序支付"),
|
||||
|
||||
MOCK("mock", "模拟支付"),
|
||||
|
||||
|
||||
+1
-1
@@ -136,7 +136,7 @@ public class PayOrderDO extends BaseDO {
|
||||
/**
|
||||
* 渠道用户编号
|
||||
*
|
||||
* 例如说,微信 openid、支付宝账号
|
||||
* 例如说,微信 openid、支付宝 buyerId(buyerOpenId)
|
||||
*/
|
||||
private String channelUserId;
|
||||
/**
|
||||
|
||||
+1
@@ -54,6 +54,7 @@ public class PayClientFactoryImpl implements PayClientFactory {
|
||||
clientClass.put(ALIPAY_APP, AlipayAppPayClient.class);
|
||||
clientClass.put(ALIPAY_PC, AlipayPcPayClient.class);
|
||||
clientClass.put(ALIPAY_BAR, AlipayBarPayClient.class);
|
||||
clientClass.put(ALIPAY_LITE, AlipayLitePayClient.class);
|
||||
// 钱包支付客户端
|
||||
clientClass.put(WALLET, WalletPayClient.class);
|
||||
// Mock 支付客户端
|
||||
|
||||
+6
-2
@@ -4,6 +4,7 @@ import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.date.LocalDateTimeUtil;
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.text.CharSequenceUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.http.HttpUtil;
|
||||
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
|
||||
@@ -92,9 +93,12 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient<AlipayPa
|
||||
status = PayOrderStatusEnum.REFUND.getStatus();
|
||||
}
|
||||
Assert.notNull(status, (Supplier<Throwable>) () -> {
|
||||
throw new IllegalArgumentException(StrUtil.format("body({}) 的 trade_status 不正确", body));
|
||||
throw new IllegalArgumentException(CharSequenceUtil.format("body({}) 的 trade_status 不正确", body));
|
||||
});
|
||||
return PayOrderRespDTO.of(status, bodyObj.get("trade_no"), bodyObj.get("seller_id"), parseTime(params.get("gmt_payment")),
|
||||
// https://opendocs.alipay.com/open/00dn78?pathHash=fef00e6d#%E5%BC%82%E6%AD%A5%E9%80%9A%E7%9F%A5%E5%8F%82%E6%95%B0
|
||||
// buyer_id(buyer_open_id)买家支付宝用户号,seller_id 卖家支付宝用户号
|
||||
String channelUserId = CharSequenceUtil.nullToDefault(bodyObj.get("buyer_open_id"), bodyObj.get("buyer_id"));
|
||||
return PayOrderRespDTO.of(status, bodyObj.get("trade_no"), channelUserId, parseTime(params.get("gmt_payment")),
|
||||
bodyObj.get("out_trade_no"), body);
|
||||
}
|
||||
|
||||
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
package cn.iocoder.yudao.module.pay.framework.pay.core.client.impl.alipay;
|
||||
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.iocoder.yudao.module.pay.enums.PayChannelEnum;
|
||||
import cn.iocoder.yudao.module.pay.framework.pay.core.client.dto.order.PayOrderRespDTO;
|
||||
import cn.iocoder.yudao.module.pay.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
|
||||
import cn.iocoder.yudao.module.pay.framework.pay.core.enums.PayOrderDisplayModeEnum;
|
||||
import com.alipay.api.AlipayApiException;
|
||||
import com.alipay.api.domain.AlipayTradeCreateModel;
|
||||
import com.alipay.api.request.AlipayTradeCreateRequest;
|
||||
import com.alipay.api.response.AlipayTradeCreateResponse;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.invalidParamException;
|
||||
import static cn.iocoder.yudao.module.pay.framework.pay.core.client.impl.alipay.AlipayPayClientConfig.MODE_CERTIFICATE;
|
||||
|
||||
/**
|
||||
* 支付宝【小程序】的 PayClient 实现类
|
||||
*
|
||||
* 文档:<a href="https://opendocs.alipay.com/mini/6039ed0c_alipay.trade.create">统一收单交易创建</a>
|
||||
*
|
||||
* @author graypxl
|
||||
*/
|
||||
public class AlipayLitePayClient extends AbstractAlipayPayClient {
|
||||
|
||||
public static final String BUYER_ID_KEY = "buyer_id";
|
||||
public static final String BUYER_OPEN_ID_KEY = "buyer_open_id";
|
||||
|
||||
public AlipayLitePayClient(Long channelId, AlipayPayClientConfig config) {
|
||||
super(channelId, PayChannelEnum.ALIPAY_LITE.getCode(), config);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PayOrderRespDTO doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO) throws AlipayApiException {
|
||||
AlipayTradeCreateModel model = new AlipayTradeCreateModel();
|
||||
model.setOutTradeNo(reqDTO.getOutTradeNo());
|
||||
model.setSubject(reqDTO.getSubject());
|
||||
model.setBody(reqDTO.getBody());
|
||||
model.setTotalAmount(formatAmount(reqDTO.getPrice()));
|
||||
model.setTimeExpire(formatTime(reqDTO.getExpireTime()));
|
||||
model.setProductCode("JSAPI_PAY");
|
||||
model.setOpAppId(config.getAppId());
|
||||
applyBuyerIdentity(model, reqDTO);
|
||||
|
||||
AlipayTradeCreateRequest request = new AlipayTradeCreateRequest();
|
||||
request.setBizModel(model);
|
||||
request.setNotifyUrl(reqDTO.getNotifyUrl());
|
||||
|
||||
AlipayTradeCreateResponse response;
|
||||
if (Objects.equals(config.getMode(), MODE_CERTIFICATE)) {
|
||||
response = client.certificateExecute(request);
|
||||
} else {
|
||||
response = client.execute(request);
|
||||
}
|
||||
if (!response.isSuccess()) {
|
||||
return buildClosedPayOrderRespDTO(reqDTO, response);
|
||||
}
|
||||
return PayOrderRespDTO.waitingOf(PayOrderDisplayModeEnum.APP.getMode(), response.getTradeNo(),
|
||||
reqDTO.getOutTradeNo(), response);
|
||||
}
|
||||
|
||||
static void applyBuyerIdentity(AlipayTradeCreateModel model, PayOrderUnifiedReqDTO reqDTO) {
|
||||
String buyerId = MapUtil.getStr(reqDTO.getChannelExtras(), BUYER_ID_KEY);
|
||||
String buyerOpenId = MapUtil.getStr(reqDTO.getChannelExtras(), BUYER_OPEN_ID_KEY);
|
||||
if (StrUtil.isBlank(buyerOpenId)) {
|
||||
buyerOpenId = MapUtil.getStr(reqDTO.getChannelExtras(), "openid");
|
||||
}
|
||||
if (isAlipayUserId(buyerId)) {
|
||||
model.setBuyerId(buyerId);
|
||||
} else if (StrUtil.isNotBlank(buyerOpenId)) {
|
||||
model.setBuyerOpenId(buyerOpenId);
|
||||
} else if (StrUtil.isNotBlank(buyerId)) {
|
||||
model.setBuyerOpenId(buyerId);
|
||||
} else {
|
||||
throw invalidParamException("支付请求的 buyer_open_id 不能为空!");
|
||||
}
|
||||
}
|
||||
|
||||
static boolean isAlipayUserId(String value) {
|
||||
return StrUtil.isNotBlank(value) && value.startsWith("2088") && value.length() <= 28
|
||||
&& StrUtil.isNumeric(value);
|
||||
}
|
||||
|
||||
}
|
||||
+4
-6
@@ -6,7 +6,6 @@ import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.date.LocalDateTimeUtil;
|
||||
import cn.hutool.core.date.TemporalAccessorUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.iocoder.yudao.framework.common.util.io.FileUtils;
|
||||
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
|
||||
import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
|
||||
import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum;
|
||||
@@ -63,18 +62,17 @@ public abstract class AbstractWxPayClient extends AbstractPayClient<WxPayClientC
|
||||
WxPayConfig payConfig = new WxPayConfig();
|
||||
BeanUtil.copyProperties(config, payConfig, "keyContent", "privateKeyContent", "publicKeyContent");
|
||||
payConfig.setTradeType(tradeType);
|
||||
// weixin-pay-java 无法设置内容,只允许读取文件,所以这里要创建临时文件来解决
|
||||
if (Objects.equals(config.getApiVersion(), API_VERSION_V2)) {
|
||||
payConfig.setKeyPath(FileUtils.createTempFile(Base64.decode(config.getKeyContent())).getPath());
|
||||
payConfig.setKeyContent(Base64.decode(config.getKeyContent()));
|
||||
} else if (Objects.equals(config.getApiVersion(), API_VERSION_V3)) {
|
||||
payConfig.setPrivateKeyPath(FileUtils.createTempFile(config.getPrivateKeyContent()).getPath());
|
||||
payConfig.setPrivateKeyContent(StrUtil.utf8Bytes(config.getPrivateKeyContent()));
|
||||
// 参考 https://gitee.com/yudaocode/yudao-ui-admin-vue3/issues/ICUE53 和 https://t.zsxq.com/ODR5V
|
||||
if (StrUtil.isNotBlank(config.getPublicKeyContent())) {
|
||||
payConfig.setPublicKeyPath(FileUtils.createTempFile(config.getPublicKeyContent()).getPath());
|
||||
payConfig.setPublicKeyContent(StrUtil.utf8Bytes(config.getPublicKeyContent()));
|
||||
}
|
||||
// 特殊:强制使用微信公钥模式,避免灰度期间的问题!!!
|
||||
payConfig.setStrictlyNeedWechatPaySerial(true);
|
||||
// 特殊:weixin-java-pay 只有配置 publicKeyPath 后,再开启 fullPublicKeyModel,才会使用 PublicCertificateVerifier
|
||||
// 特殊:weixin-java-pay 只有配置 publicKeyContent 后,再开启 fullPublicKeyModel,才会使用 PublicCertificateVerifier
|
||||
// 对应 https://t.zsxq.com/5Q9lO 帖子
|
||||
payConfig.setFullPublicKeyModel(true);
|
||||
}
|
||||
|
||||
+201
@@ -0,0 +1,201 @@
|
||||
package cn.iocoder.yudao.module.pay.framework.pay.core.client.impl.alipay;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.exception.ServiceException;
|
||||
import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;
|
||||
import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
|
||||
import cn.iocoder.yudao.module.pay.framework.pay.core.client.dto.order.PayOrderRespDTO;
|
||||
import cn.iocoder.yudao.module.pay.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
|
||||
import cn.iocoder.yudao.module.pay.framework.pay.core.enums.PayOrderDisplayModeEnum;
|
||||
import cn.iocoder.yudao.module.pay.framework.pay.core.client.exception.PayClientException;
|
||||
import com.alipay.api.AlipayApiException;
|
||||
import com.alipay.api.domain.AlipayTradeCreateModel;
|
||||
import com.alipay.api.request.AlipayTradeCreateRequest;
|
||||
import com.alipay.api.response.AlipayTradeCreateResponse;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.ArgumentMatcher;
|
||||
import org.mockito.InjectMocks;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
|
||||
import static cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum.CLOSED;
|
||||
import static cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum.WAITING;
|
||||
import static cn.iocoder.yudao.module.pay.framework.pay.core.client.impl.alipay.AlipayPayClientConfig.MODE_CERTIFICATE;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.mockito.ArgumentMatchers.argThat;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* {@link AlipayLitePayClient} 单元测试
|
||||
*
|
||||
* @author graypxl
|
||||
*/
|
||||
public class AlipayLitePayClientTest extends AbstractAlipayClientTest {
|
||||
|
||||
@InjectMocks
|
||||
private AlipayLitePayClient client = new AlipayLitePayClient(randomLongId(), config);
|
||||
|
||||
@Override
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
setClient(client);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("支付宝小程序支付:buyer_open_id 下单成功")
|
||||
public void testUnifiedOrder_buyerOpenId() throws AlipayApiException {
|
||||
String buyerOpenId = "060d4dhFytu7VF5haNiDacG7b-n5toPeevhdLa07Kz9ass8";
|
||||
String tradeNo = randomString();
|
||||
AlipayTradeCreateResponse response = randomPojo(AlipayTradeCreateResponse.class, o -> {
|
||||
o.setSubCode("");
|
||||
o.setTradeNo(tradeNo);
|
||||
});
|
||||
when(defaultAlipayClient.execute(argThat(assertRequest(config.getAppId(), null, buyerOpenId))))
|
||||
.thenReturn(response);
|
||||
PayOrderUnifiedReqDTO reqDTO = buildOrderUnifiedReqDTO(randomURL(), randomString(), randomInteger());
|
||||
reqDTO.setChannelExtras(Map.of(AlipayLitePayClient.BUYER_OPEN_ID_KEY, buyerOpenId));
|
||||
|
||||
PayOrderRespDTO resp = client.unifiedOrder(reqDTO);
|
||||
|
||||
assertEquals(WAITING.getStatus(), resp.getStatus());
|
||||
assertEquals(reqDTO.getOutTradeNo(), resp.getOutTradeNo());
|
||||
assertNull(resp.getChannelOrderNo());
|
||||
assertNull(resp.getChannelUserId());
|
||||
assertNull(resp.getSuccessTime());
|
||||
assertEquals(PayOrderDisplayModeEnum.APP.getMode(), resp.getDisplayMode());
|
||||
assertEquals(tradeNo, resp.getDisplayContent());
|
||||
assertSame(response, resp.getRawData());
|
||||
assertNull(resp.getChannelErrorCode());
|
||||
assertNull(resp.getChannelErrorMsg());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("支付宝小程序支付:buyer_id 下单成功")
|
||||
public void testUnifiedOrder_buyerId() throws AlipayApiException {
|
||||
String buyerId = "2088123456789012";
|
||||
AlipayTradeCreateResponse response = randomPojo(AlipayTradeCreateResponse.class, o -> o.setSubCode(""));
|
||||
when(defaultAlipayClient.execute(argThat(assertRequest(config.getAppId(), buyerId, null))))
|
||||
.thenReturn(response);
|
||||
PayOrderUnifiedReqDTO reqDTO = buildOrderUnifiedReqDTO(randomURL(), randomString(), randomInteger());
|
||||
reqDTO.setChannelExtras(Map.of(AlipayLitePayClient.BUYER_ID_KEY, buyerId));
|
||||
|
||||
PayOrderRespDTO resp = client.unifiedOrder(reqDTO);
|
||||
|
||||
assertEquals(WAITING.getStatus(), resp.getStatus());
|
||||
assertEquals(reqDTO.getOutTradeNo(), resp.getOutTradeNo());
|
||||
assertEquals(PayOrderDisplayModeEnum.APP.getMode(), resp.getDisplayMode());
|
||||
assertSame(response, resp.getRawData());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("支付宝小程序支付:兼容 openid 参数")
|
||||
public void testUnifiedOrder_openidAlias() throws AlipayApiException {
|
||||
String buyerOpenId = randomString();
|
||||
AlipayTradeCreateResponse response = randomPojo(AlipayTradeCreateResponse.class, o -> o.setSubCode(""));
|
||||
when(defaultAlipayClient.execute(argThat(assertRequest(config.getAppId(), null, buyerOpenId))))
|
||||
.thenReturn(response);
|
||||
PayOrderUnifiedReqDTO reqDTO = buildOrderUnifiedReqDTO(randomURL(), randomString(), randomInteger());
|
||||
reqDTO.setChannelExtras(Map.of("openid", buyerOpenId));
|
||||
|
||||
PayOrderRespDTO resp = client.unifiedOrder(reqDTO);
|
||||
|
||||
assertEquals(WAITING.getStatus(), resp.getStatus());
|
||||
assertEquals(reqDTO.getOutTradeNo(), resp.getOutTradeNo());
|
||||
assertEquals(PayOrderDisplayModeEnum.APP.getMode(), resp.getDisplayMode());
|
||||
assertSame(response, resp.getRawData());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("支付宝小程序支付:证书模式下单成功")
|
||||
public void testUnifiedOrder_certificateMode() throws AlipayApiException {
|
||||
config.setMode(MODE_CERTIFICATE);
|
||||
String buyerOpenId = randomString();
|
||||
AlipayTradeCreateResponse response = randomPojo(AlipayTradeCreateResponse.class, o -> o.setSubCode(""));
|
||||
when(defaultAlipayClient.certificateExecute(argThat(assertRequest(config.getAppId(), null, buyerOpenId))))
|
||||
.thenReturn(response);
|
||||
PayOrderUnifiedReqDTO reqDTO = buildOrderUnifiedReqDTO(randomURL(), randomString(), randomInteger());
|
||||
reqDTO.setChannelExtras(Map.of(AlipayLitePayClient.BUYER_OPEN_ID_KEY, buyerOpenId));
|
||||
|
||||
PayOrderRespDTO resp = client.unifiedOrder(reqDTO);
|
||||
|
||||
assertEquals(WAITING.getStatus(), resp.getStatus());
|
||||
assertEquals(reqDTO.getOutTradeNo(), resp.getOutTradeNo());
|
||||
assertEquals(PayOrderDisplayModeEnum.APP.getMode(), resp.getDisplayMode());
|
||||
assertSame(response, resp.getRawData());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("支付宝小程序支付:渠道返回失败")
|
||||
public void testUnifiedOrder_channelFailed() throws AlipayApiException {
|
||||
String subCode = randomString();
|
||||
String subMsg = randomString();
|
||||
AlipayTradeCreateResponse response = randomPojo(AlipayTradeCreateResponse.class, o -> {
|
||||
o.setSubCode(subCode);
|
||||
o.setSubMsg(subMsg);
|
||||
});
|
||||
when(defaultAlipayClient.execute(argThat((ArgumentMatcher<AlipayTradeCreateRequest>) request -> true)))
|
||||
.thenReturn(response);
|
||||
PayOrderUnifiedReqDTO reqDTO = buildOrderUnifiedReqDTO(randomURL(), randomString(), randomInteger());
|
||||
reqDTO.setChannelExtras(Map.of(AlipayLitePayClient.BUYER_OPEN_ID_KEY, randomString()));
|
||||
|
||||
PayOrderRespDTO resp = client.unifiedOrder(reqDTO);
|
||||
|
||||
assertEquals(CLOSED.getStatus(), resp.getStatus());
|
||||
assertEquals(reqDTO.getOutTradeNo(), resp.getOutTradeNo());
|
||||
assertNull(resp.getChannelOrderNo());
|
||||
assertNull(resp.getChannelUserId());
|
||||
assertNull(resp.getSuccessTime());
|
||||
assertNull(resp.getDisplayMode());
|
||||
assertNull(resp.getDisplayContent());
|
||||
assertSame(response, resp.getRawData());
|
||||
assertEquals(subCode, resp.getChannelErrorCode());
|
||||
assertEquals(subMsg, resp.getChannelErrorMsg());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("支付宝小程序支付:买家标识为空")
|
||||
public void testUnifiedOrder_buyerEmpty() {
|
||||
PayOrderUnifiedReqDTO reqDTO = buildOrderUnifiedReqDTO(randomURL(), randomString(), randomInteger());
|
||||
reqDTO.setChannelExtras(new HashMap<>());
|
||||
|
||||
assertThrows(ServiceException.class, () -> client.unifiedOrder(reqDTO));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("支付宝小程序支付:抛出业务异常")
|
||||
public void testUnifiedOrder_throwServiceException() throws AlipayApiException {
|
||||
when(defaultAlipayClient.execute(argThat((ArgumentMatcher<AlipayTradeCreateRequest>) request -> true)))
|
||||
.thenThrow(ServiceExceptionUtil.exception(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR));
|
||||
PayOrderUnifiedReqDTO reqDTO = buildOrderUnifiedReqDTO(randomURL(), randomString(), randomInteger());
|
||||
reqDTO.setChannelExtras(Map.of(AlipayLitePayClient.BUYER_OPEN_ID_KEY, randomString()));
|
||||
|
||||
assertThrows(ServiceException.class, () -> client.unifiedOrder(reqDTO));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("支付宝小程序支付:抛出系统异常")
|
||||
public void testUnifiedOrder_throwPayException() throws AlipayApiException {
|
||||
when(defaultAlipayClient.execute(argThat((ArgumentMatcher<AlipayTradeCreateRequest>) request -> true)))
|
||||
.thenThrow(new RuntimeException("系统异常"));
|
||||
PayOrderUnifiedReqDTO reqDTO = buildOrderUnifiedReqDTO(randomURL(), randomString(), randomInteger());
|
||||
reqDTO.setChannelExtras(Map.of(AlipayLitePayClient.BUYER_OPEN_ID_KEY, randomString()));
|
||||
|
||||
assertThrows(PayClientException.class, () -> client.unifiedOrder(reqDTO));
|
||||
}
|
||||
|
||||
private static ArgumentMatcher<AlipayTradeCreateRequest> assertRequest(String appId, String buyerId,
|
||||
String buyerOpenId) {
|
||||
return request -> {
|
||||
AlipayTradeCreateModel model = (AlipayTradeCreateModel) request.getBizModel();
|
||||
assertEquals("JSAPI_PAY", model.getProductCode());
|
||||
assertEquals(appId, model.getOpAppId());
|
||||
assertEquals(buyerId, model.getBuyerId());
|
||||
assertEquals(buyerOpenId, model.getBuyerOpenId());
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
+4
-4
@@ -1,13 +1,13 @@
|
||||
package cn.iocoder.yudao.module.system.controller.admin.socail;
|
||||
package cn.iocoder.yudao.module.system.controller.admin.social;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.system.api.social.SocialClientApi;
|
||||
import cn.iocoder.yudao.module.system.api.social.dto.SocialWxaSubscribeMessageSendReqDTO;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialClientPageReqVO;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialClientRespVO;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialClientSaveReqVO;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.social.vo.client.SocialClientPageReqVO;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.social.vo.client.SocialClientRespVO;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.social.vo.client.SocialClientSaveReqVO;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialClientDO;
|
||||
import cn.iocoder.yudao.module.system.service.social.SocialClientService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
+5
-5
@@ -1,14 +1,14 @@
|
||||
package cn.iocoder.yudao.module.system.controller.admin.socail;
|
||||
package cn.iocoder.yudao.module.system.controller.admin.social;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.socail.vo.user.SocialUserBindReqVO;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.socail.vo.user.SocialUserPageReqVO;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.socail.vo.user.SocialUserRespVO;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.socail.vo.user.SocialUserUnbindReqVO;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.social.vo.user.SocialUserBindReqVO;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.social.vo.user.SocialUserPageReqVO;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.social.vo.user.SocialUserRespVO;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.social.vo.user.SocialUserUnbindReqVO;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserDO;
|
||||
import cn.iocoder.yudao.module.system.service.social.SocialUserService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package cn.iocoder.yudao.module.system.controller.admin.socail.vo.client;
|
||||
package cn.iocoder.yudao.module.system.controller.admin.social.vo.client;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package cn.iocoder.yudao.module.system.controller.admin.socail.vo.client;
|
||||
package cn.iocoder.yudao.module.system.controller.admin.social.vo.client;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package cn.iocoder.yudao.module.system.controller.admin.socail.vo.client;
|
||||
package cn.iocoder.yudao.module.system.controller.admin.social.vo.client;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package cn.iocoder.yudao.module.system.controller.admin.socail.vo.user;
|
||||
package cn.iocoder.yudao.module.system.controller.admin.social.vo.user;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.validation.InEnum;
|
||||
import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package cn.iocoder.yudao.module.system.controller.admin.socail.vo.user;
|
||||
package cn.iocoder.yudao.module.system.controller.admin.social.vo.user;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package cn.iocoder.yudao.module.system.controller.admin.socail.vo.user;
|
||||
package cn.iocoder.yudao.module.system.controller.admin.social.vo.user;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package cn.iocoder.yudao.module.system.controller.admin.socail.vo.user;
|
||||
package cn.iocoder.yudao.module.system.controller.admin.social.vo.user;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.validation.InEnum;
|
||||
import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
|
||||
+1
-1
@@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.system.dal.mysql.social;
|
||||
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.system.controller.admin.socail.vo.client.SocialClientPageReqVO;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.social.vo.client.SocialClientPageReqVO;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialClientDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.system.dal.mysql.social;
|
||||
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.system.controller.admin.socail.vo.user.SocialUserPageReqVO;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.social.vo.user.SocialUserPageReqVO;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
|
||||
+3
-2
@@ -166,7 +166,7 @@ public class MailTemplateServiceImpl implements MailTemplateService {
|
||||
// 提取 <pre> 标签内的内容
|
||||
String innerContent = matcher.group(1);
|
||||
// 返回 div 标签包裹的内容
|
||||
matcher.appendReplacement(sb, "<div>" + innerContent + "</div>");
|
||||
matcher.appendReplacement(sb, Matcher.quoteReplacement("<div>" + innerContent + "</div>"));
|
||||
}
|
||||
matcher.appendTail(sb);
|
||||
return sb.toString();
|
||||
@@ -207,7 +207,8 @@ public class MailTemplateServiceImpl implements MailTemplateService {
|
||||
String codeBlock = matcher.group(1);
|
||||
// 为代码块添加样式
|
||||
String replacement = "<pre style=\"background-color: #f5f5f5; padding: 10px; border-radius: 5px; overflow-x: auto;\"><code>" + codeBlock + "</code></pre>";
|
||||
matcher.appendReplacement(sb, replacement);
|
||||
// 代码块内容可能包含 $ 或 \\,需要 quoteReplacement,否则会抛 IllegalArgumentException: Illegal group reference
|
||||
matcher.appendReplacement(sb, Matcher.quoteReplacement(replacement));
|
||||
}
|
||||
matcher.appendTail(sb);
|
||||
return sb.toString();
|
||||
|
||||
+2
-2
@@ -6,8 +6,8 @@ import cn.iocoder.yudao.module.system.api.social.dto.SocialWxQrcodeReqDTO;
|
||||
import cn.iocoder.yudao.module.system.api.social.dto.SocialWxaOrderNotifyConfirmReceiveReqDTO;
|
||||
import cn.iocoder.yudao.module.system.api.social.dto.SocialWxaOrderUploadShippingInfoReqDTO;
|
||||
import cn.iocoder.yudao.module.system.api.social.dto.SocialWxaSubscribeMessageSendReqDTO;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialClientPageReqVO;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialClientSaveReqVO;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.social.vo.client.SocialClientPageReqVO;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.social.vo.client.SocialClientSaveReqVO;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialClientDO;
|
||||
import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
|
||||
import javax.validation.Valid;
|
||||
|
||||
+2
-2
@@ -26,8 +26,8 @@ import cn.iocoder.yudao.module.system.api.social.dto.SocialWxQrcodeReqDTO;
|
||||
import cn.iocoder.yudao.module.system.api.social.dto.SocialWxaOrderNotifyConfirmReceiveReqDTO;
|
||||
import cn.iocoder.yudao.module.system.api.social.dto.SocialWxaOrderUploadShippingInfoReqDTO;
|
||||
import cn.iocoder.yudao.module.system.api.social.dto.SocialWxaSubscribeMessageSendReqDTO;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialClientPageReqVO;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialClientSaveReqVO;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.social.vo.client.SocialClientPageReqVO;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.social.vo.client.SocialClientSaveReqVO;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialClientDO;
|
||||
import cn.iocoder.yudao.module.system.dal.mysql.social.SocialClientMapper;
|
||||
import cn.iocoder.yudao.module.system.dal.redis.RedisKeyConstants;
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ import cn.iocoder.yudao.framework.common.exception.ServiceException;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO;
|
||||
import cn.iocoder.yudao.module.system.api.social.dto.SocialUserRespDTO;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.socail.vo.user.SocialUserPageReqVO;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.social.vo.user.SocialUserPageReqVO;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserDO;
|
||||
import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
|
||||
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@ import cn.iocoder.yudao.framework.common.exception.ServiceException;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO;
|
||||
import cn.iocoder.yudao.module.system.api.social.dto.SocialUserRespDTO;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.socail.vo.user.SocialUserPageReqVO;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.social.vo.user.SocialUserPageReqVO;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserBindDO;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserDO;
|
||||
import cn.iocoder.yudao.module.system.dal.mysql.social.SocialUserBindMapper;
|
||||
|
||||
+14
@@ -398,4 +398,18 @@ public class MailTemplateServiceImplTest extends BaseDbUnitTest {
|
||||
assertFalse(formattedContent.contains("{activationLink}"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFormatMailTemplateContent_dollarInCodeBlock() {
|
||||
// 准备参数
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
|
||||
// 测试代码块中包含 $ 与 \\(历史上 appendReplacement 会抛 IllegalArgumentException: Illegal group reference)
|
||||
String content = "<pre><code>echo $HOME && ls \\root</code></pre>";
|
||||
|
||||
// 调用,并断言内容原样保留
|
||||
String result = mailTemplateService.formatMailTemplateContent(content, params);
|
||||
assertTrue(result.contains("echo $HOME && ls \\root"));
|
||||
assertTrue(result.contains("<div><code>"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-2
@@ -12,8 +12,8 @@ import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
|
||||
import cn.iocoder.yudao.module.system.api.social.dto.SocialWxaOrderUploadShippingInfoReqDTO;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialClientPageReqVO;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialClientSaveReqVO;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.social.vo.client.SocialClientPageReqVO;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.social.vo.client.SocialClientSaveReqVO;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialClientDO;
|
||||
import cn.iocoder.yudao.module.system.dal.mysql.social.SocialClientMapper;
|
||||
import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
|
||||
import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO;
|
||||
import cn.iocoder.yudao.module.system.api.social.dto.SocialUserRespDTO;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.socail.vo.user.SocialUserPageReqVO;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.social.vo.user.SocialUserPageReqVO;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserBindDO;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserDO;
|
||||
import cn.iocoder.yudao.module.system.dal.mysql.social.SocialUserBindMapper;
|
||||
|
||||
Reference in New Issue
Block a user