Forráskód Böngészése

feat: 汇企云相关逻辑添加

李学松 2 éve
szülő
commit
a54c85a31f
20 módosított fájl, 1057 hozzáadás és 40 törlés
  1. 16 0
      db/v2.0/221219.sql
  2. 6 0
      hnqz-upms/hnqz-upms-api/src/main/java/com/qunzhixinxi/hnqz/admin/api/constant/CacheConstants.java
  3. 39 0
      hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/controller/GigThirdApiController.java
  4. 45 0
      hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/entity/HuiqiyunInputRecord.java
  5. 6 0
      hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/entity/SysDeptSub.java
  6. 2 1
      hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/enums/GigTypeEnum.java
  7. 39 0
      hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/enums/HuiQiYunCertStatus.java
  8. 4 1
      hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/enums/SubjectLocation.java
  9. 1 0
      hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/enums/SubjectTypeEnum.java
  10. 18 0
      hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/mapper/HuiqiyunInputRecordMapper.java
  11. 55 8
      hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/mq/GigSignCertReceiver.java
  12. 13 0
      hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/service/HuiqiyunInputRecordService.java
  13. 12 0
      hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/service/gig/GigThirdApiService.java
  14. 143 14
      hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/service/gig/impl/GigThirdApiServiceImpl.java
  15. 10 15
      hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/service/gig/impl/SysUserSignCertServiceImpl.java
  16. 22 0
      hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/service/impl/HuiqiyunInputRecordServiceImpl.java
  17. 1 0
      hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/service/impl/SysUserServiceImpl.java
  18. 199 0
      hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/service/impl/WmPayOffServiceImpl.java
  19. 364 1
      hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/service/impl/WmScorePackageSettleNoteServiceImpl.java
  20. 62 0
      hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/util/AESUtil.java

+ 16 - 0
db/v2.0/221219.sql

@@ -0,0 +1,16 @@
+-- 汇企云回调异步通知记录
+create table huiqiyun_input_record
+(
+    id           int auto_increment comment '主键id'
+        primary key,
+    req_msg_id   varchar(64)                        null comment '报文流水号',
+    req_body     text                               null comment '请求body',
+    decrypt_body text                               null comment '解密后的body',
+    create_time  datetime default CURRENT_TIMESTAMP null comment '创建时间'
+)
+    comment '汇企云回调异步通知记录';
+
+-- deptSub新增字段
+alter table sys_dept_sub
+    add path_no varchar(128) null comment '汇企云批次付款渠道编号' after subject_invoice_category;
+

+ 6 - 0
hnqz-upms/hnqz-upms-api/src/main/java/com/qunzhixinxi/hnqz/admin/api/constant/CacheConstants.java

@@ -120,6 +120,12 @@ public interface CacheConstants {
 	 */
 	String ZHEGN_QI_ZHI_XING_NOTIFY_KEY = "ZHEGN:QI:ZHI:XING:NOTIFY:KEY:";
 
+	/**
+	 * 汇企云异步结果回调key
+	 */
+	String HUI_QI_YUN_NOTIFY_KEY = "HUI:QI:YUN:NOTIFY:KEY:";
+
+
 	/**
 	 * 发起阿拉丁认证渠道记录key
 	 */

+ 39 - 0
hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/controller/GigThirdApiController.java

@@ -8,9 +8,11 @@ import cn.hutool.json.JSONObject;
 import cn.hutool.json.JSONUtil;
 import com.qunzhixinxi.hnqz.admin.api.constant.CacheConstants;
 import com.qunzhixinxi.hnqz.admin.api.dto.OladingCommonRequest;
+import com.qunzhixinxi.hnqz.admin.entity.HuiqiyunInputRecord;
 import com.qunzhixinxi.hnqz.admin.entity.LingcaiaiInputRecord;
 import com.qunzhixinxi.hnqz.admin.entity.OladingInputRecord;
 import com.qunzhixinxi.hnqz.admin.entity.XinbadaInputRecord;
+import com.qunzhixinxi.hnqz.admin.service.HuiqiyunInputRecordService;
 import com.qunzhixinxi.hnqz.admin.service.LingcaiaiInputRecordService;
 import com.qunzhixinxi.hnqz.admin.service.XinbadaInputRecordService;
 import com.qunzhixinxi.hnqz.admin.service.gig.GigThirdApiService;
@@ -59,6 +61,7 @@ public class GigThirdApiController {
 
 	private final LingcaiaiInputRecordService lingcaiaiInputRecordService;
 
+	private final HuiqiyunInputRecordService huiqiyunInputRecordService;
 
 	private final RedisTemplate redisTemplate;
 
@@ -75,6 +78,42 @@ public class GigThirdApiController {
 //	 */
 //	private static final String ALGORITHM_TYPE = "HmacSHA256";
 
+	/**
+	 * 汇企云异步通知回调
+	 *
+	 * @param body
+	 * @param headers
+	 * @return
+	 */
+	@Inner(value = false)
+	@SysLog("汇企云异步通知回调")
+	@PostMapping("/huiqiyun")
+	public String huiQiYunRequest(@RequestBody String body, @RequestHeader HttpHeaders headers) {
+		log.info("汇企云请求方法参数:body={}, headers={}", body, headers);
+
+		// 请求body json
+		JSONObject bodyJson = JSONUtil.parseObj(body);
+
+
+		String reqMsgId = bodyJson.getStr("reqMsgId");
+		String redisKey = String.format("%s_%s", CacheConstants.HUI_QI_YUN_NOTIFY_KEY, reqMsgId);
+		Boolean absent = redisTemplate.opsForValue().setIfAbsent(redisKey, reqMsgId, 30, TimeUnit.MINUTES);
+		if (!absent) {
+			log.warn("存在在途操作reqMsgId={}", reqMsgId);
+			return "FAIL";
+		}
+
+		// 请求记录到数据库
+		HuiqiyunInputRecord record = new HuiqiyunInputRecord();
+		record.setReqMsgId(reqMsgId);
+		record.setReqBody(body);
+		huiqiyunInputRecordService.save(record);
+
+		gigThirdApiService.huiqiyunNotify(reqMsgId, bodyJson, record.getId());
+
+		return "SUCCESS";
+	}
+
 	/**
 	 * 浪潮(灵才接好活)结算回调
 	 *

+ 45 - 0
hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/entity/HuiqiyunInputRecord.java

@@ -0,0 +1,45 @@
+package com.qunzhixinxi.hnqz.admin.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+/**
+ * 汇企云回调异步通知记录
+ * @TableName huiqiyun_input_record
+ */
+@TableName(value ="huiqiyun_input_record")
+@Data
+public class HuiqiyunInputRecord extends Model<HuiqiyunInputRecord> {
+	private static final long serialVersionUID = 1L;
+
+    /**
+     * 主键id
+     */
+    @TableId(type = IdType.AUTO)
+    private Integer id;
+
+    /**
+     *  报文流水号
+     */
+    private String reqMsgId;
+
+    /**
+     * 请求body
+     */
+    private String reqBody;
+
+	/**
+	 * 解密后的body
+	 */
+	private String decryptBody;
+
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+}

+ 6 - 0
hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/entity/SysDeptSub.java

@@ -76,4 +76,10 @@ public class SysDeptSub extends Model<SysDeptSub> {
 	private LocalDateTime updateTime;
 
 	private BigDecimal serviceCharge;
+
+	/**
+	 * 批次付款渠道编号
+	 */
+	private String[] pathNo;
+
 }

+ 2 - 1
hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/enums/GigTypeEnum.java

@@ -21,7 +21,8 @@ public enum GigTypeEnum {
 	OLADING(2, "钉灵工", "钉灵工-海南飞亿", OladingCertStatus.class),
 	YEE(3, "易联数科", "易联数科", YeeCertStatus.class),
 	ZHENG_QI_ZHI_XING(4, "正启之星", "正启之星", ZhengQiZhiXingCertStatus.class),
-	LANG_CHAO(5, "浪潮", "浪潮", LangChaoCertStatus.class);
+	LANG_CHAO(5, "浪潮", "浪潮", LangChaoCertStatus.class),
+	HUI_QI_YUN(6, "汇企云", "汇企云", HuiQiYunCertStatus.class);
 
 	@EnumValue
 	private int code;

+ 39 - 0
hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/enums/HuiQiYunCertStatus.java

@@ -0,0 +1,39 @@
+package com.qunzhixinxi.hnqz.admin.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * @author: lixuesong
+ * @createTime: 2022/11/30 14:47
+ * @description: 汇企云认证状态
+ */
+@Getter
+@AllArgsConstructor
+public enum HuiQiYunCertStatus {
+
+	// 签约状态
+	UN_SIGN(0, "未签约"),
+	CERT(1, "已认证"),
+	SIGN(2, "已签约");
+
+	private final int code;
+
+	private final String message;
+
+	/**
+	 * 根据枚举编码获取枚举对象
+	 *
+	 * @param code 枚举编码
+	 * @return 如果存在返回枚举,否则返回 {@code null}
+	 */
+	public static HuiQiYunCertStatus resolve(final int code) {
+		for (HuiQiYunCertStatus certStatus : HuiQiYunCertStatus.values()) {
+			if (certStatus.getCode() == code) {
+				return certStatus;
+			}
+		}
+		return UN_SIGN;
+
+	}
+}

+ 4 - 1
hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/enums/SubjectLocation.java

@@ -36,7 +36,10 @@ public enum SubjectLocation {
 	LANG_CHAO("LANG_CHAO", GigTypeEnum.LANG_CHAO, "浪潮", 8),
 
 	// 正启之星-江西
-	JIANG_XI("JIANG_XI",  GigTypeEnum.ZHENG_QI_ZHI_XING, "正启之星-江西", 9);
+	JIANG_XI("JIANG_XI",  GigTypeEnum.ZHENG_QI_ZHI_XING, "正启之星-江西", 9),
+
+	// 汇企云
+	HUI_QI_YUN("HUI_QI_YUN", GigTypeEnum.HUI_QI_YUN, "汇企云", 10);
 
 	@EnumValue
 	private final String type;

+ 1 - 0
hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/enums/SubjectTypeEnum.java

@@ -16,6 +16,7 @@ public enum SubjectTypeEnum {
 	TYPE_YEE("3", "易联数科"),
 	TYPE_ZHENG_QI_ZHI_XING("4", "政企之星"),
 	TYPE_LANG_CHAO("5", "浪潮"),
+	TYPE_HUI_QI_YUN("6", "汇企云"),
 
 
 	ENABLE_FLAG_FALSE("0", "无效"),

+ 18 - 0
hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/mapper/HuiqiyunInputRecordMapper.java

@@ -0,0 +1,18 @@
+package com.qunzhixinxi.hnqz.admin.mapper;
+
+import com.qunzhixinxi.hnqz.admin.entity.HuiqiyunInputRecord;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+* @author lixuesong
+* @description 针对表【huiqiyun_input_record(汇企云回调异步通知记录)】的数据库操作Mapper
+* @createDate 2022-12-09 13:02:08
+* @Entity com.qunzhixinxi.hnqz.admin.entity.HuiqiyunInputRecord
+*/
+public interface HuiqiyunInputRecordMapper extends BaseMapper<HuiqiyunInputRecord> {
+
+}
+
+
+
+

+ 55 - 8
hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/mq/GigSignCertReceiver.java

@@ -14,14 +14,7 @@ import com.qunzhixinxi.hnqz.admin.api.dto.OladingCommonRequest;
 import com.qunzhixinxi.hnqz.admin.api.entity.SysDept;
 import com.qunzhixinxi.hnqz.admin.api.entity.SysUser;
 import com.qunzhixinxi.hnqz.admin.entity.SysUserSub;
-import com.qunzhixinxi.hnqz.admin.enums.DelEnum;
-import com.qunzhixinxi.hnqz.admin.enums.GigCallBackStatus;
-import com.qunzhixinxi.hnqz.admin.enums.GigTypeEnum;
-import com.qunzhixinxi.hnqz.admin.enums.LangChaoCertStatus;
-import com.qunzhixinxi.hnqz.admin.enums.LockEnum;
-import com.qunzhixinxi.hnqz.admin.enums.OladingCertStatus;
-import com.qunzhixinxi.hnqz.admin.enums.SubjectLocation;
-import com.qunzhixinxi.hnqz.admin.enums.ZhengQiZhiXingCertStatus;
+import com.qunzhixinxi.hnqz.admin.enums.*;
 import com.qunzhixinxi.hnqz.admin.service.SysDeptService;
 import com.qunzhixinxi.hnqz.admin.service.SysUserService;
 import com.qunzhixinxi.hnqz.admin.service.SysUserSubService;
@@ -81,6 +74,11 @@ public class GigSignCertReceiver extends BaseRabbiMqHandler<String> {
 	 */
 	private static final String ZHENG_QI_ZHI_XING_SUCCESS_CODE = "200";
 
+	/**
+	 * 汇企云成功code
+	 */
+	private static final String HUI_QI_YUN_SUCCESS_CODE = "0";
+
     @RabbitHandler
     public void onMessage(String jsonStr, Channel channel, @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag) {
         super.onMessageAck(jsonStr, deliveryTag, channel, (MqListener<String>) (String result, Channel channel1) -> {
@@ -139,6 +137,10 @@ public class GigSignCertReceiver extends BaseRabbiMqHandler<String> {
 								break;
 							case LANG_CHAO:
 								this.langchaoHandler(user, dept, subjectResult);
+								break;
+							case HUI_QI_YUN:
+								this.huiQiYunHandler(user, dept, subjectResult);
+								break;
 							default:
 						}
 					});
@@ -155,6 +157,51 @@ public class GigSignCertReceiver extends BaseRabbiMqHandler<String> {
         });
     }
 
+	/**
+	 * 汇企云结果处理
+	 *
+	 * @param user          用户
+	 * @param dept          部门
+	 * @param subjectResult 结果
+	 */
+	private void huiQiYunHandler(SysUser user, SysDept dept, JSONObject subjectResult) {
+		String code = subjectResult.getStr("code");
+		String certStatus = subjectResult.getStr("certStatus");
+		LocalDateTime now = LocalDateTime.now();
+		HuiQiYunCertStatus huiQiYunCertStatus = Enum.valueOf(HuiQiYunCertStatus.class, certStatus);
+
+		// 拼接更新条件
+		LambdaUpdateWrapper<SysUserSub> updateWrapper = Wrappers.<SysUserSub>lambdaUpdate()
+				.eq(SysUserSub::getUserId, user.getUserId())
+				.eq(SysUserSub::getDeptId, dept.getDeptId())
+				.eq(SysUserSub::getSubjectLocation, SubjectLocation.HUI_QI_YUN)
+				.eq(SysUserSub::getGigType, GigTypeEnum.HUI_QI_YUN)
+				.set(SysUserSub::getCallbackStatus, GigCallBackStatus.RETURNED)
+				.set(SysUserSub::getUpdateTime, now)
+				.set(SysUserSub::getUpdateUser, 0)
+				.set(SysUserSub::getCertRemark, JSONUtil.toJsonStr(subjectResult));
+
+		if (HUI_QI_YUN_SUCCESS_CODE.equals(code)) {
+			if (HuiQiYunCertStatus.SIGN.equals(huiQiYunCertStatus)) {
+				// 汇企云已签约 即对应这里的已认证
+				updateWrapper.set(SysUserSub::getCertStatus, HuiQiYunCertStatus.CERT.getCode());
+			} else {
+				updateWrapper.set(SysUserSub::getCertStatus, huiQiYunCertStatus.getCode());
+			}
+		}
+
+		sysUserSubService.update(updateWrapper);
+
+		// 结果放到redis
+		Map<String, Map<String, String>> resultMap = new HashMap<>(1);
+		Map<String, String> subMap = new HashMap<>(1);
+		subMap.put("certStatus", certStatus);
+		resultMap.put(SubjectLocation.HUI_QI_YUN.getType(), subMap);
+		String key = CacheConstants.USER_SIGN_CERT_RESPONSE_KEY + user.getUserId();
+		log.info("缓存认证结果到redis:{}", JSONUtil.toJsonStr(resultMap));
+		redisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(resultMap), 1, TimeUnit.MINUTES);
+	}
+
 	/**
 	 * 浪潮回调状态处理
 	 *

+ 13 - 0
hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/service/HuiqiyunInputRecordService.java

@@ -0,0 +1,13 @@
+package com.qunzhixinxi.hnqz.admin.service;
+
+import com.qunzhixinxi.hnqz.admin.entity.HuiqiyunInputRecord;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+* @author lixuesong
+* @description 针对表【huiqiyun_input_record(汇企云回调异步通知记录)】的数据库操作Service
+* @createDate 2022-12-09 13:02:08
+*/
+public interface HuiqiyunInputRecordService extends IService<HuiqiyunInputRecord> {
+
+}

+ 12 - 0
hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/service/gig/GigThirdApiService.java

@@ -1,5 +1,6 @@
 package com.qunzhixinxi.hnqz.admin.service.gig;
 
+import cn.hutool.json.JSONObject;
 import com.qunzhixinxi.hnqz.admin.api.dto.OladingCommonRequest;
 import com.qunzhixinxi.hnqz.admin.entity.WmScorePackage;
 import com.qunzhixinxi.hnqz.admin.entity.WmScorePackageSettleNote;
@@ -14,6 +15,17 @@ import java.util.List;
  */
 public interface GigThirdApiService {
 
+	/**
+	 * 汇企云回调业务处理
+	 *
+	 * @param reqMsgId 报文流水号
+	 * @param reqBody 请求总的body
+	 * @param inputId 记录id
+	 * @return
+	 */
+	boolean huiqiyunNotify(String reqMsgId, JSONObject reqBody, Integer inputId);
+
+
 	/**
 	 * 浪潮(灵才接好活)结算回调
 	 *

+ 143 - 14
hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/service/gig/impl/GigThirdApiServiceImpl.java

@@ -14,22 +14,14 @@ import com.qunzhixinxi.hnqz.admin.api.entity.SysDept;
 import com.qunzhixinxi.hnqz.admin.api.entity.SysUser;
 import com.qunzhixinxi.hnqz.admin.config.TaxNotifyConfig;
 import com.qunzhixinxi.hnqz.admin.config.UpmsConfig;
-import com.qunzhixinxi.hnqz.admin.entity.SysUserSub;
-import com.qunzhixinxi.hnqz.admin.entity.WmScorePackage;
-import com.qunzhixinxi.hnqz.admin.entity.WmScorePackageSettleNote;
+import com.qunzhixinxi.hnqz.admin.entity.*;
 import com.qunzhixinxi.hnqz.admin.entity.dto.UserSignCertDTO;
-import com.qunzhixinxi.hnqz.admin.enums.GigCallBackStatus;
-import com.qunzhixinxi.hnqz.admin.enums.GigTypeEnum;
-import com.qunzhixinxi.hnqz.admin.enums.OladingCertStatus;
-import com.qunzhixinxi.hnqz.admin.enums.SubjectLocation;
+import com.qunzhixinxi.hnqz.admin.enums.*;
 import com.qunzhixinxi.hnqz.admin.event.OladingFinishTaskEvent;
-import com.qunzhixinxi.hnqz.admin.service.SysDeptService;
-import com.qunzhixinxi.hnqz.admin.service.SysUserService;
-import com.qunzhixinxi.hnqz.admin.service.SysUserSubService;
-import com.qunzhixinxi.hnqz.admin.service.WmScorePackageService;
-import com.qunzhixinxi.hnqz.admin.service.WmScorePackageSettleNoteService;
+import com.qunzhixinxi.hnqz.admin.service.*;
 import com.qunzhixinxi.hnqz.admin.service.gig.GigThirdApiService;
 import com.qunzhixinxi.hnqz.admin.service.gig.SysUserSignCertService;
+import com.qunzhixinxi.hnqz.admin.util.AESUtil;
 import com.qunzhixinxi.hnqz.common.core.constant.CommonConstants;
 import com.qunzhixinxi.hnqz.common.core.exception.ValidateCodeException;
 import com.qunzhixinxi.hnqz.common.core.util.R;
@@ -37,6 +29,7 @@ import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.lang.RandomStringUtils;
+import org.apache.commons.lang3.StringUtils;
 import org.springframework.context.ApplicationEventPublisher;
 import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.http.HttpEntity;
@@ -47,15 +40,14 @@ import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.web.client.RestTemplate;
 
+import java.net.URLDecoder;
 import java.time.LocalDateTime;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
-import java.util.stream.Stream;
 
 /**
  * @author lixuesong
@@ -72,12 +64,149 @@ public class GigThirdApiServiceImpl implements GigThirdApiService {
 	private final WmScorePackageSettleNoteService scorePackageSettleNoteService;
 	private final WmScorePackageService scorePackageService;
 	private final SysDeptService sysDeptService;
+	private final SysDeptSubService sysDeptSubService;
 	private final SysUserService sysUserService;
 	private final UpmsConfig upmsConfig;
 	private final TaxNotifyConfig taxNotifyConfig;
 
 	private final ApplicationEventPublisher applicationEventPublisher;
 
+	private final HuiqiyunInputRecordService huiqiyunInputRecordService;
+
+	/**
+	 * 汇企云回调业务处理
+	 *
+	 * @param reqMsgId
+	 * @param reqBody
+	 * @param inputId
+	 * @return
+	 */
+	@Override
+	public boolean huiqiyunNotify(String reqMsgId, JSONObject reqBody, Integer inputId) {
+
+		// 查询privateKey
+		List<SysDeptSub> deptSubList = sysDeptSubService.list(Wrappers.<SysDeptSub>lambdaQuery()
+				.eq(SysDeptSub::getEnableFlag, SubjectTypeEnum.ENABLE_FLAG_TRUE.getCode())
+				.eq(SysDeptSub::getSubjectLocation, SubjectLocation.HUI_QI_YUN)
+				.isNotNull(SysDeptSub::getAppSecret));
+		if (CollUtil.isEmpty(deptSubList)) {
+			log.warn("汇企云privateKey不存在");
+			return false;
+		}
+
+		// 解密body
+		Map<String, Object> decryptData = this.decryptData(reqBody, deptSubList.get(0).getAppSecret());
+		log.info("汇企云解密后body={}", decryptData);
+
+		// 保存解密后的body
+		HuiqiyunInputRecord inputRecord = new HuiqiyunInputRecord();
+		inputRecord.setId(inputId);
+		inputRecord.setDecryptBody(JSONUtil.toJsonStr(decryptData));
+		huiqiyunInputRecordService.updateById(inputRecord);
+
+		// 内层body
+		String bodyStr = (String) decryptData.get("body");
+		JSONObject bodyJson = JSONUtil.parseObj(bodyStr);
+
+		// 批次出款流水号
+		String batchNo = bodyJson.getStr("batchNo");
+		// 批次成功总笔数
+		Integer totalSuccessNum = bodyJson.getInt("totalSuccessNum");
+		// 批次成功总金额
+		String totalSuccessAmt = bodyJson.getStr("totalSuccessAmt");
+		// 批次失败总笔数
+		Integer totalFailNum = bodyJson.getInt("totalFailNum");
+		// 批次失败总金额
+		String totalFailAmt = bodyJson.getStr("totalFailAmt");
+		// 批次请求总笔数
+		Integer totalNum = bodyJson.getInt("totalNum");
+		// 批次请求总金额
+		String totalAmt = bodyJson.getStr("totalAmt");
+
+		int yaoyiStatus;
+		if (totalSuccessNum.equals(totalNum)) {
+			// 批次成功笔数=批次总笔数,则认为是成功
+			yaoyiStatus = 1;
+		} else {
+			yaoyiStatus = 2;
+		}
+
+		// 根据orderNo查询结算单
+		List<WmScorePackageSettleNote> settleNoteList = scorePackageSettleNoteService.list(Wrappers.<WmScorePackageSettleNote>lambdaQuery()
+				.eq(WmScorePackageSettleNote::getStreamId, batchNo));
+		if (CollUtil.isEmpty(settleNoteList)) {
+			log.warn("订单batchNo={}对应结算单不存在", batchNo);
+			return false;
+		}
+
+		// 修改结算状态
+		List<WmScorePackageSettleNote> updateList = settleNoteList.stream().map(note -> {
+			WmScorePackageSettleNote updateEntity = new WmScorePackageSettleNote();
+			updateEntity.setId(note.getId());
+			updateEntity.setSettleNoteStatus(yaoyiStatus);
+			if (yaoyiStatus == 1){
+				updateEntity.setNotifyTime(LocalDateTime.now());
+			}
+			updateEntity.setUpdateTime(LocalDateTime.now());
+			return updateEntity;
+		}).collect(Collectors.toList());
+
+		scorePackageSettleNoteService.updateBatchById(updateList);
+
+		WmScorePackageSettleNote tmp = settleNoteList.get(0);
+		WmScorePackage scorePackage = scorePackageService.getById(tmp.getPackageId());
+
+		// 遥领不修改
+		if (!"1611890566".equals(scorePackage.getSendPackageDeptId())) {
+			// 更新积分包状态
+			log.info("更新积分包状态:{}", tmp);
+			WmScorePackage wmScorePackage = new WmScorePackage();
+			wmScorePackage.setId(tmp.getPackageId());
+			wmScorePackage.setSettleStatus(yaoyiStatus);
+			wmScorePackage.setUpdateTime(LocalDateTime.now());
+			scorePackageService.updateById(wmScorePackage);
+		}
+
+		redisTemplate.delete(CacheConstants.SETTLE_PACKAGE_KEY + tmp.getId());
+
+		return true;
+	}
+
+	/**
+	 * 通用解密方法
+	 *
+	 * @param encryptData 加密后的数据
+	 * @param privateKey  秘钥
+	 * @return 解密数据
+	 */
+	public Map<String, Object> decryptData(final Map<String, Object> encryptData, final String privateKey) {
+
+		Map<String, Object> res = new HashMap<>(encryptData.size());
+
+		try {
+			String headStr = (String) encryptData.get("head");
+			String srcHead = URLDecoder.decode(headStr, "UTF-8");
+
+
+			String cipherStr = (String) encryptData.get("cipher");
+			String bodyStr = (String) encryptData.get("body");
+			String signStr = (String) encryptData.get("sign");
+			String srcBody = null;
+			if (StringUtils.isNotBlank(bodyStr)) {
+				String resBody = AESUtil.decrypt(bodyStr, privateKey);
+				srcBody = URLDecoder.decode(resBody, "UTF-8");
+			}
+			res.put("head", srcHead);
+			res.put("cipher", cipherStr);
+			res.put("body", srcBody);
+			res.put("sign", signStr);
+
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+		return res;
+	}
+
 	/**
 	 * 浪潮(灵才接好活)结算回调
 	 *

+ 10 - 15
hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/service/gig/impl/SysUserSignCertServiceImpl.java

@@ -24,21 +24,7 @@ import com.qunzhixinxi.hnqz.admin.entity.model.GigBaseInfoModel;
 import com.qunzhixinxi.hnqz.admin.entity.model.GigInfoModel;
 import com.qunzhixinxi.hnqz.admin.entity.model.GigUserInfoModel;
 import com.qunzhixinxi.hnqz.admin.entity.vo.SysUserSubVO;
-import com.qunzhixinxi.hnqz.admin.enums.DelEnum;
-import com.qunzhixinxi.hnqz.admin.enums.GigCallBackStatus;
-import com.qunzhixinxi.hnqz.admin.enums.GigChannelEnum;
-import com.qunzhixinxi.hnqz.admin.enums.GigTypeEnum;
-import com.qunzhixinxi.hnqz.admin.enums.LangChaoCertStatus;
-import com.qunzhixinxi.hnqz.admin.enums.LockEnum;
-import com.qunzhixinxi.hnqz.admin.enums.MemberIDCardType;
-import com.qunzhixinxi.hnqz.admin.enums.MemberType;
-import com.qunzhixinxi.hnqz.admin.enums.OladingCertStatus;
-import com.qunzhixinxi.hnqz.admin.enums.PayChannel;
-import com.qunzhixinxi.hnqz.admin.enums.RenlijiaCertStatus;
-import com.qunzhixinxi.hnqz.admin.enums.SubjectLocation;
-import com.qunzhixinxi.hnqz.admin.enums.SubjectTypeEnum;
-import com.qunzhixinxi.hnqz.admin.enums.YeeCertStatus;
-import com.qunzhixinxi.hnqz.admin.enums.ZhengQiZhiXingCertStatus;
+import com.qunzhixinxi.hnqz.admin.enums.*;
 import com.qunzhixinxi.hnqz.admin.service.SysDeptService;
 import com.qunzhixinxi.hnqz.admin.service.SysDeptSubService;
 import com.qunzhixinxi.hnqz.admin.service.SysUserExtRecordService;
@@ -399,6 +385,13 @@ public class SysUserSignCertServiceImpl implements SysUserSignCertService {
 				}
 				this.updateUserCertStatus(userSub.getId(), "内部状态对其", LangChaoCertStatus.SIGN.getCode(), null);
 				return R.ok();
+			case HUI_QI_YUN:
+				// 浪潮
+				if (userSub.getCertStatus() > HuiQiYunCertStatus.UN_SIGN.getCode()) {
+					return R.ok();
+				}
+				this.updateUserCertStatus(userSub.getId(), "内部状态对其", HuiQiYunCertStatus.SIGN.getCode(), null);
+				return R.ok();
 			default:
 				message = "不支持该税源地操作";
 		}
@@ -569,6 +562,8 @@ public class SysUserSignCertServiceImpl implements SysUserSignCertService {
 					return true;
 				} else if (GigTypeEnum.LANG_CHAO.equals(sysUserSub.getGigType())) {
 					return true;
+				} else if (GigTypeEnum.HUI_QI_YUN.equals(sysUserSub.getGigType())) {
+					return true;
 				}
 				return false;
 			}).forEach(userSub -> {

+ 22 - 0
hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/service/impl/HuiqiyunInputRecordServiceImpl.java

@@ -0,0 +1,22 @@
+package com.qunzhixinxi.hnqz.admin.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.qunzhixinxi.hnqz.admin.entity.HuiqiyunInputRecord;
+import com.qunzhixinxi.hnqz.admin.service.HuiqiyunInputRecordService;
+import com.qunzhixinxi.hnqz.admin.mapper.HuiqiyunInputRecordMapper;
+import org.springframework.stereotype.Service;
+
+/**
+* @author lixuesong
+* @description 针对表【huiqiyun_input_record(汇企云回调异步通知记录)】的数据库操作Service实现
+* @createDate 2022-12-09 13:02:08
+*/
+@Service
+public class HuiqiyunInputRecordServiceImpl extends ServiceImpl<HuiqiyunInputRecordMapper, HuiqiyunInputRecord>
+    implements HuiqiyunInputRecordService{
+
+}
+
+
+
+

+ 1 - 0
hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/service/impl/SysUserServiceImpl.java

@@ -215,6 +215,7 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
 				case OLADING:
 				case ZHENG_QI_ZHI_XING:
 				case LANG_CHAO:
+				case HUI_QI_YUN:
 					if (!Objects.equals(userSub.getCertStatus(), DingEnum.CER_STATUS_1.getType())) {
 						throw new RuntimeException(user.getRealname() + "未认证,不能发起结算");
 					}

+ 199 - 0
hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/service/impl/WmPayOffServiceImpl.java

@@ -439,6 +439,10 @@ public class WmPayOffServiceImpl extends ServiceImpl<WmPayOffMapper, WmPayOff> i
 		else if (SubjectTypeEnum.TYPE_LANG_CHAO.getCode().equals(subType)) {
 			return this.settleByLangchao(input, wmScorePackage, taxCode, enterpriseName, operator);
 		}
+		// 汇企云
+		else if (SubjectTypeEnum.TYPE_HUI_QI_YUN.getCode().equals(subType)) {
+			return this.settleByHuiQiYun(input, wmScorePackage, taxCode, operator, sysDeptSub.getPathNo());
+		}
 		// 税邦云
 		else {
 			log.info("税邦云结算开始-获取会员所属企业的统一社会信用代码:{} ", taxCode);
@@ -447,6 +451,201 @@ public class WmPayOffServiceImpl extends ServiceImpl<WmPayOffMapper, WmPayOff> i
 
 	}
 
+	/**
+	 * 汇企云结算操作
+	 *
+	 * @param input          结算数据
+	 * @param wmScorePackage 积分包
+	 * @param taxCode        税号
+	 * @param operator       操作员
+	 * @return 结果
+	 */
+	private R<?> settleByHuiQiYun(WmScorePackageSettleInput input,
+								  WmScorePackage wmScorePackage,
+								  String taxCode,
+								  HnqzUser operator,
+								  String[] pathNo) {
+
+		List<WmScorePackageSettleNote> notes = input.getNotes();
+		StringBuilder noticeInfo = new StringBuilder();
+
+		// WmScorePackageSettleNote
+		for (WmScorePackageSettleNote note : notes) {
+			note.setInvoiceType(input.getInvoiceCategory());
+			note.setCategoryName(StrUtil.isNotBlank(input.getCategoryName()) ? input.getCategoryName() : note.getCategoryName());
+			note.setSubToGigTime(LocalDateTime.now());
+		}
+		noteService.updateBatchById(notes);
+
+
+		for (WmScorePackageSettleNote note : notes) {
+			SysUser sysUser = sysUserMapper.selectById(note.getUserId());
+
+			SysUserSub userSub = sysUserSubMapper.selectOne(Wrappers.<SysUserSub>lambdaQuery()
+					.eq(SysUserSub::getUserId, sysUser.getUserId())
+					.eq(SysUserSub::getSubjectLocation, input.getSubjectLocation())
+					.eq(SysUserSub::getDeptId, operator.getDeptId())
+			);
+
+			if (userSub == null) {
+				log.info("结算对象-" + sysUser.getRealname() + ":认证信息不存在,不能结算");
+				return R.failed("结算对象-" + sysUser.getRealname() + ":认证信息不存在,不能结算");
+			}
+
+			if (!Objects.equals(userSub.getCertStatus(), DingEnum.CER_STATUS_1.getType())) {
+				return R.failed(sysUser.getRealname() + "人员未认证或未绑卡,不能结算");
+			}
+
+			if (Boolean.TRUE.equals(redisTemplate.hasKey(CacheConstants.SETTLE_PACKAGE_KEY + note.getId()))) {
+				return R.failed("结算对象-" + sysUser.getRealname() + ":正在结算,请勿重复结算");
+			}
+
+			if (DingEnum.NOTE_STATUS_SUCCESS.getType().equals(note.getSettleNoteStatus())) {
+				log.info("结算对象-" + sysUser.getRealname() + ":已结算,请勿重复结算");
+				return R.failed("结算对象-" + sysUser.getRealname() + ":已结算,请勿重复结算");
+			}
+			if (DingEnum.NOTE_STATUS_SUBMIT.getType().equals(note.getSettleNoteStatus())) {
+				log.info("结算对象-" + sysUser.getRealname() + ":已提交,请等待耐心结算结果");
+				return R.failed("结算对象-" + sysUser.getRealname() + ":已提交,请等待耐心结算结果");
+			}
+		}
+
+		for (WmScorePackageSettleNote note : notes) {
+			// 加锁
+			redisTemplate.opsForValue().set(CacheConstants.SETTLE_PACKAGE_KEY + note.getId(),
+					note.getId(), CacheConstants.SETTLE_TIME, TimeUnit.DAYS);
+
+			SysUser sysUser = sysUserMapper.selectById(note.getUserId());
+
+			try {
+
+				// 获取请求token
+				String url = String.format(GIG_TOKEN_URL, upmsConfig.getGigServiceUrl());
+				log.info("远端请求gig-token:{}", url);
+				ResponseEntity<String> tokenResult = new RestTemplate().getForEntity(url, String.class,
+						String.valueOf(operator.getDeptId()), "settle", String.valueOf(operator.getId()));
+				log.warn("获取结算token:{}", tokenResult.getBody());
+				if (!JSONUtil.isJson(tokenResult.getBody())) {
+					return R.failed("获取结算token失败");
+				}
+
+				JSONObject jsonObject = JSONUtil.parseObj(tokenResult.getBody());
+
+				if (jsonObject.getInt("code") != 0 || StrUtil.isBlank(jsonObject.getStr("data"))) {
+					return R.failed("获取结算token失败");
+				}
+
+				String token = jsonObject.getStr("data");
+
+				// 间隔100毫秒
+				Thread.sleep(100);
+
+				// 封装结算参数
+				Map<String, Object> params = new HashMap<>();
+				params.put("token", token);
+				params.put("tenantId", operator.getDeptId());
+				params.put("operatorId", operator.getId());
+				params.put("requestId", RandomStringUtils.randomAlphabetic(12));
+				params.put("taskName", wmScorePackage.getScorePackageName() + "_" + System.currentTimeMillis());
+				params.put("amount", String.valueOf(note.getSettleAmount().doubleValue()));
+				params.put("taskStartTime", wmScorePackage.getCreateTime().toLocalDate());
+				params.put("taskEndTime", wmScorePackage.getUpdateTime().toLocalDate());
+				params.put("taskLocation", "要易云");
+				params.put("username", sysUser.getUsername());
+				params.put("idCard", sysUser.getIdCardNumber());
+				params.put("idCardType","ID_CARD");
+				params.put("realName", sysUser.getRealname());
+				params.put("bankCard", sysUser.getBankCardNumber());
+				// 市场推广
+				params.put("tagId", upmsConfig.getTagId());
+				params.put("taskInvoiceContent", note.getCategoryName());
+				params.put("endType", "JY");
+				params.put("enterpriseCode", taxCode);
+				params.put("subjectType", "HUI_QI_YUN");
+				params.put("channel", "DEFAULT");
+				params.put("subjectLocation", input.getSubjectLocation().getType());
+				params.put("notes", pathNo[0]);
+				params.put("pathNo", pathNo[0]);
+
+
+				if (SubjectLocation.JIN_YUAN.equals(input.getSubjectLocation())) {
+					params.put("taxMode", "GENERAL");
+					params.put("transactionModel", "SUPERVISE");
+				}
+				// 海南飞亿 和 河南薪泰梓
+				else {
+					params.put("taxMode", "SPECIAL");
+					params.put("transactionModel", "CHANNEL");
+				}
+
+				// 发起结算
+				String url1 = String.format(GIG_SETTLE_URL, upmsConfig.getGigServiceUrl());
+				log.info("远端请求gig-settle:{}", url);
+				HttpHeaders headers = new HttpHeaders();
+				headers.setContentType(MediaType.APPLICATION_JSON);
+				log.info("汇企云结算req: {}", params);
+				HttpEntity<String> result = new RestTemplate().exchange(url1, HttpMethod.POST, new HttpEntity<>(params, headers), String.class);
+				log.info("汇企云结算resp:{}", result.getBody());
+				if (!JSONUtil.isJson(result.getBody())) {
+					return R.failed("结算失败");
+				}
+
+				JSONObject settleObj = JSONUtil.parseObj(result.getBody());
+
+
+				if (Objects.equals(settleObj.getInt("code"), CommonConstants.SUCCESS)) {
+					JSONObject dataJsonObj = settleObj.getJSONObject("data");
+					log.info("汇企云结算提交成功: {}", settleObj.getStr("data"));
+					note.setUpdateTime(LocalDateTime.now());
+					//streamId 获取不到
+					if (dataJsonObj != null) {
+						String requestId = dataJsonObj.getStr("requestId");
+						if (StrUtil.isNotBlank(requestId)) {
+							note.setSettleNoteStatus(DingEnum.NOTE_STATUS_SUBMIT.getType());
+							// 新增字段streamId
+							note.setStreamId(requestId);
+							noticeInfo.append(sysUser.getRealname()).append(":提交结算成功;");
+						} else {
+							noticeInfo.append(sysUser.getRealname()).append(":" + dataJsonObj.getStr("message"));
+						}
+					} else {
+						log.warn("汇企云结算提交成功 data 获取不到: {}", note.getSettleNo());
+						noticeInfo.append(sysUser.getRealname()).append(":提交结算成功,业务流水号获取不到,请联系管理员;");
+					}
+				} else {
+					log.warn("汇企云结算失败: {}", note.getSettleNo());
+					note.setUpdateTime(LocalDateTime.now());
+					note.setSettleNoteStatus(DingEnum.NOTE_STATUS_FAIL.getType());
+					noticeInfo.append(sysUser.getRealname()).append(":结算提交失败-").append(settleObj.getStr("msg")).append(";");
+
+					log.info("认证状态异常,结算解锁settleNoteId:{}", note.getId());
+					redisTemplate.delete(CacheConstants.SETTLE_PACKAGE_KEY + note.getId());
+
+				}
+			} catch (Exception e) {
+				log.error("", e);
+				log.warn("汇企云结算提交失败: {}", note.getSettleNo());
+				note.setUpdateTime(LocalDateTime.now());
+				note.setSettleNoteStatus(DingEnum.NOTE_STATUS_FAIL.getType());
+				noticeInfo.append(sysUser.getRealname()).append(":结算提交失败;");
+
+				log.info("认证状态异常,结算解锁settleNoteId:{}", note.getId());
+				redisTemplate.delete(CacheConstants.SETTLE_PACKAGE_KEY + note.getId());
+			}
+		}
+
+		noteService.updateBatchById(notes);
+
+		// 更新结算结果
+		SettleNoteStatusOutput output = noteService.selectSettleNoteStatus(input.getId());
+		WmScorePackage updateEntity = new WmScorePackage();
+		updateEntity.setId(input.getId());
+		updateEntity.setSettleStatus(output.toSettleStatus());
+		wmScorePackageService.updateById(updateEntity);
+
+		return R.ok(null, noticeInfo.toString());
+	}
+
 	/**
 	 * 浪潮结算操作
 	 *

+ 364 - 1
hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/service/impl/WmScorePackageSettleNoteServiceImpl.java

@@ -589,6 +589,11 @@ public class WmScorePackageSettleNoteServiceImpl extends ServiceImpl<WmScorePack
 			String enterpriseName = sysDept.getName();
 			return this.settleByLangchao(note, wmScorePackage, sysUser, taxCode, enterpriseName);
 		}
+		// 汇企云
+		else if (SubjectTypeEnum.TYPE_HUI_QI_YUN.getCode().equals(subType)) {
+			String taxCode = sysDept.getTaxCode();
+			return this.settleByHuiQiYun(note, wmScorePackage, sysUser, taxCode, sysDeptSub.getPathNo());
+		}
 		// 税邦云
 		else {
 			String taxCode = sysDept.getTaxCode();
@@ -704,7 +709,8 @@ public class WmScorePackageSettleNoteServiceImpl extends ServiceImpl<WmScorePack
 
 			}
 			// 自由职家
-			else if (SubjectTypeEnum.TYPE_OLADING.getCode().equals(subType) || SubjectTypeEnum.TYPE_ZHENG_QI_ZHI_XING.getCode().equals(subType)) {
+			else if (SubjectTypeEnum.TYPE_OLADING.getCode().equals(subType) || SubjectTypeEnum.TYPE_ZHENG_QI_ZHI_XING.getCode().equals(subType)
+					|| SubjectTypeEnum.TYPE_HUI_QI_YUN.getCode().equals(subType)) {
 				oladingNoteList.add(note);
 			}
 			// 浪潮
@@ -761,6 +767,17 @@ public class WmScorePackageSettleNoteServiceImpl extends ServiceImpl<WmScorePack
 			return this.batchSettleByLangchao(langchaoNoteList, taxCode, enterpriseName);
 		}
 
+		// 汇企云结算
+		if (CollectionUtils.isNotEmpty(oladingNoteList)) {
+			if (StringUtils.isNotEmpty(taxCode)) {
+				log.info("汇企云结算开始-获取会员所属企业的统一社会信用代码:{} ", taxCode);
+			} else {
+				return R.failed("未配置企业的统一社会信用代码");
+			}
+			SysDeptSub sysDeptSub = subMap.get(SubjectLocation.HUI_QI_YUN.name());
+			return this.batchSettleByHuiQiYun(oladingNoteList, taxCode, sysDeptSub.getPathNo());
+		}
+
 		return R.ok();
 	}
 
@@ -769,6 +786,214 @@ public class WmScorePackageSettleNoteServiceImpl extends ServiceImpl<WmScorePack
 		return R.failed("因系统维护,暂时不能提起支付,有问题请联系客服");
 	}
 
+	/**
+	 * 汇企云结算
+	 *
+	 * @param noteList 结算记录
+	 * @param taxCode  企业三合一码
+	 * @param pathNo 批次付款渠道编号
+	 * @return 结果
+	 */
+	private R batchSettleByHuiQiYun(List<WmScorePackageSettleNote> noteList, String taxCode, String[] pathNo) {
+
+		// 加锁
+		List<Integer> noteIdList = noteList.stream().filter(note ->
+						redisTemplate.opsForValue().setIfAbsent(
+								CacheConstants.SETTLE_PACKAGE_KEY + ":note_id_" + note.getId(),
+								noteList, CacheConstants.SETTLE_TIME, TimeUnit.DAYS))
+				.mapToInt(WmScorePackageSettleNote::getId).boxed().collect(Collectors.toList());
+
+		// 加锁记录数不等于提交记录数,说明存在在途交易
+		if (CollectionUtils.isEmpty(noteIdList)) {
+			log.error("当前用户存在其他结算请求");
+			return R.failed("当前用户存在其他结算请求");
+		} else {
+			if (!Objects.equals(noteList.size(), noteIdList.size())) {
+				// 删除锁
+				noteIdList.forEach(id -> redisTemplate.delete(CacheConstants.SETTLE_PACKAGE_KEY + ":note_id_" + id));
+				log.error("当前用户存在其他结算请求");
+				return R.failed("当前用户存在其他结算请求");
+			}
+		}
+
+		HnqzUser operator = SecurityUtils.getUser();
+		String gigTokenUrl = upmsConfig.getGigServiceUrl() + "/gig/operation/token?tenantId={tenantId}&action={action}&userId={userId}";
+		String gigSettleUrl = upmsConfig.getGigServiceUrl() + "/gig/operation/settlement";
+
+		List<Map<String, Object>> settleParamsMapper = new ArrayList<>();
+		Map<String, Map<String, Object>> detailMap = new HashMap<>();
+		noteList.forEach(note -> {
+			WmScorePackage wmScorePackage = wmScorePackageMapper.selectById(note.getPackageId());
+			// 封装结算参数
+			Map<String, Object> params;
+			if (detailMap.containsKey(note.getIdCardNumber())) {
+				params = detailMap.get(note.getIdCardNumber());
+				params.put("amount", String.valueOf(new BigDecimal((String) params.get("amount")).add(note.getSettleAmount()).doubleValue()));
+
+
+				LocalDate startTime = (LocalDate) params.get("taskStartTime");
+				LocalDate endTime = (LocalDate) params.get("taskEndTime");
+				LocalDate noteCreateTime = wmScorePackage.getCreateTime().toLocalDate();
+				LocalDate noteUpdateTime = wmScorePackage.getUpdateTime().toLocalDate();
+
+				if (noteCreateTime.isBefore(startTime)) {
+					params.put("taskStartTime", wmScorePackage.getCreateTime().toLocalDate());
+				}
+				if (noteUpdateTime.isAfter(endTime)) {
+					params.put("taskEndTime", wmScorePackage.getUpdateTime().toLocalDate());
+				}
+
+				Set<Integer> ids = (Set<Integer>) params.get("noteIds");
+				ids.add(note.getId());
+				params.put("noteIds", ids);
+			} else {
+				SysUser sysUser = sysUserService.getById(note.getUserId());
+				params = new HashMap<>(19);
+				params.put("tenantId", operator.getDeptId());
+				params.put("operatorId", operator.getId());
+				params.put("requestId", RandomStringUtils.randomAlphabetic(12));
+				params.put("taskName", String.format("%s(%s)_%s", sysUser.getRealname(), sysUser.getUsername(), System.currentTimeMillis()));
+				params.put("amount", String.valueOf(note.getSettleAmount().doubleValue()));
+				params.put("taskStartTime", wmScorePackage.getCreateTime().toLocalDate());
+				params.put("taskEndTime", wmScorePackage.getUpdateTime().toLocalDate());
+				params.put("taskLocation", "要易云");
+				params.put("username", sysUser.getUsername());
+				params.put("idCard", note.getIdCardNumber());
+				params.put("idCardType","ID_CARD");
+				params.put("realName", sysUser.getRealname());
+				params.put("bankCard", sysUser.getBankCardNumber());
+				params.put("tagId", upmsConfig.getTagId());
+				params.put("taskInvoiceContent", note.getCategoryName());
+				params.put("endType", "JY");
+				params.put("enterpriseCode", taxCode);
+				params.put("subjectType", "HUI_QI_YUN");
+				params.put("channel", "DEFAULT");
+				params.put("subjectLocation", note.getSubjectLocation());
+				params.put("notes", pathNo[0]);
+				params.put("pathNo", pathNo[0]);
+
+				if (SubjectLocation.JIN_YUAN.equals(note.getSubjectLocation())) {
+					params.put("taxMode", "GENERAL");
+					params.put("transactionModel", "SUPERVISE");
+				}
+				// 海南飞亿 和 河南薪泰梓
+				else {
+					params.put("taxMode", "SPECIAL");
+					params.put("transactionModel", "CHANNEL");
+				}
+
+				Set<Integer> noteIds = new HashSet<>();
+				noteIds.add(note.getId());
+				params.put("noteIds", noteIds);
+				detailMap.put(note.getIdCardNumber(), params);
+			}
+		});
+
+		detailMap.forEach((key, value) -> settleParamsMapper.add(value));
+
+
+		// 开始结算
+		for (Map<String, Object> params : settleParamsMapper) {
+
+			Set<Integer> noteIds = (Set<Integer>) params.get("noteIds");
+			try {
+				// 获取请求token
+				ResponseEntity<String> tokenResult = new RestTemplate().getForEntity(gigTokenUrl, String.class,
+						String.valueOf(operator.getDeptId()), "settle", String.valueOf(operator.getId()));
+				log.warn("获取结算token:{}", tokenResult.getBody());
+				if (!JSONUtil.isJson(tokenResult.getBody())) {
+					return R.failed("获取结算token失败");
+				}
+
+				JSONObject jsonObject = JSONUtil.parseObj(tokenResult.getBody());
+
+				if (jsonObject.getInt("code") != 0 || StrUtil.isBlank(jsonObject.getStr("data"))) {
+					return R.failed("获取结算token失败");
+				}
+
+				String token = jsonObject.getStr("data");
+
+				// 间隔100毫秒
+				Thread.sleep(100);
+
+				params.put("token", token);
+
+				// 发起结算
+				HttpHeaders headers = new HttpHeaders();
+				headers.setContentType(MediaType.APPLICATION_JSON);
+				log.info("汇企云结算req: {}", params);
+				HttpEntity<String> result = new RestTemplate().exchange(gigSettleUrl, HttpMethod.POST, new HttpEntity<>(params, headers), String.class);
+				log.info("汇企云结算resp: {}", result.getBody());
+				if (!JSONUtil.isJson(result.getBody())) {
+					return R.failed("结算失败");
+				}
+				JSONObject settelObj = JSONUtil.parseObj(result.getBody());
+
+				if (Objects.equals(settelObj.getInt("code"), CommonConstants.SUCCESS)) {
+					JSONObject dataJsonObj = settelObj.getJSONObject("data");
+
+					noteIds.forEach(id -> {
+						log.info("汇企云结算结算提交成功");
+						// data获取不到
+						if (dataJsonObj == null) {
+							log.info("汇企云提交成功 data 获取不到");
+							return;
+						}
+
+						String requestId = dataJsonObj.getStr("requestId");
+						if (StrUtil.isNotBlank(requestId)) {
+							WmScorePackageSettleNote note = new WmScorePackageSettleNote();
+							LocalDateTime now = LocalDateTime.now();
+							note.setId(id);
+							note.setUpdateTime(LocalDateTime.now());
+							note.setSubToGigTime(now);
+							note.setSettleNoteStatus(DingEnum.NOTE_STATUS_SUBMIT.getType());
+							// 新增字段streamId
+							note.setStreamId(requestId);
+							this.baseMapper.updateById(note);
+						} else {
+							log.info("汇企云提交成功 message:{}", dataJsonObj.getStr("message"));
+						}
+					});
+
+				} else {
+					noteIds.forEach(id -> {
+						WmScorePackageSettleNote note = new WmScorePackageSettleNote();
+						note.setId(id);
+						log.info("汇企云结算提交失败: {}", note.getSettleNo());
+						LocalDateTime now = LocalDateTime.now();
+						note.setUpdateTime(LocalDateTime.now());
+						note.setSubToGigTime(now);
+						note.setSettleNoteStatus(DingEnum.NOTE_STATUS_FAIL.getType());
+						this.baseMapper.updateById(note);
+						log.info("认证状态异常,结算解锁settleNoteId:{}", note.getId());
+						redisTemplate.delete(CacheConstants.SETTLE_PACKAGE_KEY + ":note_id_" + note.getId());
+					});
+
+					return R.ok("结算失败");
+				}
+
+			} catch (Exception e) {
+				log.error("", e);
+				noteIds.forEach(id -> {
+					WmScorePackageSettleNote note = new WmScorePackageSettleNote();
+					note.setId(id);
+					log.info("汇企云结算提交失败: {}", note.getSettleNo());
+					LocalDateTime now = LocalDateTime.now();
+					note.setUpdateTime(LocalDateTime.now());
+					note.setSubToGigTime(now);
+					note.setSettleNoteStatus(DingEnum.NOTE_STATUS_FAIL.getType());
+					this.baseMapper.updateById(note);
+					log.info("认证状态异常,结算解锁settleNoteId:{}", note.getId());
+					redisTemplate.delete(CacheConstants.SETTLE_PACKAGE_KEY + ":note_id_" + note.getId());
+				});
+				return R.ok("结算失败");
+			}
+		}
+
+		return R.ok("提交结算成功");
+	}
+
 	/**
 	 * 浪潮结算
 	 *
@@ -1431,6 +1656,144 @@ public class WmScorePackageSettleNoteServiceImpl extends ServiceImpl<WmScorePack
 		}
 	}
 
+
+	/**
+	 * 汇企云结算
+	 *
+	 * @param note
+	 * @param wmScorePackage
+	 * @param sysUser
+	 * @param taxCode
+	 * @return
+	 */
+	private R settleByHuiQiYun(WmScorePackageSettleNote note,
+							   WmScorePackage wmScorePackage,
+							   SysUser sysUser,
+							   String taxCode,
+							   String[] pathNo) {
+
+		/**
+		 * 加锁
+		 */
+		redisTemplate.opsForValue().set(CacheConstants.SETTLE_PACKAGE_KEY + note.getId(),
+				note.getId(), CacheConstants.SETTLE_TIME, TimeUnit.DAYS);
+
+		/**
+		 * 开始结算
+		 */
+
+		HnqzUser operator = SecurityUtils.getUser();
+		String gigTokenUrl = upmsConfig.getGigServiceUrl() + "/gig/operation/token?tenantId={tenantId}&action={action}&userId={userId}";
+		String gigSettleUrl = upmsConfig.getGigServiceUrl() + "/gig/operation/settlement";
+
+		try {
+			// 获取请求token
+			ResponseEntity<String> tokenResult = new RestTemplate().getForEntity(gigTokenUrl, String.class,
+					String.valueOf(operator.getDeptId()), "settle", String.valueOf(operator.getId()));
+			log.warn("获取结算token:{}", tokenResult.getBody());
+			if (!JSONUtil.isJson(tokenResult.getBody())) {
+				return R.failed("获取结算token失败");
+			}
+
+			JSONObject jsonObject = JSONUtil.parseObj(tokenResult.getBody());
+
+			if (jsonObject.getInt("code") != 0 || StrUtil.isBlank(jsonObject.getStr("data"))) {
+				return R.failed("获取结算token失败");
+			}
+
+			String token = jsonObject.getStr("data");
+
+			// 间隔100毫秒
+			Thread.sleep(100);
+
+			// 封装结算参数
+			Map<String, Object> params = new HashMap<>();
+			params.put("token", token);
+			params.put("tenantId", operator.getDeptId());
+			params.put("operatorId", operator.getId());
+			params.put("requestId", RandomStringUtils.randomAlphabetic(12));
+			params.put("taskName", wmScorePackage.getScorePackageName() + "_" + System.currentTimeMillis());
+			params.put("amount", String.valueOf(note.getSettleAmount().doubleValue()));
+			params.put("taskStartTime", wmScorePackage.getCreateTime().toLocalDate());
+			params.put("taskEndTime", wmScorePackage.getUpdateTime().toLocalDate());
+			params.put("taskLocation", "要易云");
+			params.put("username", sysUser.getUsername());
+			params.put("idCard", sysUser.getIdCardNumber());
+			params.put("idCardType","ID_CARD");
+			params.put("realName", sysUser.getRealname());
+			params.put("bankCard", sysUser.getBankCardNumber());
+			// 市场推广
+			params.put("tagId", upmsConfig.getTagId());
+			params.put("taskInvoiceContent", note.getCategoryName());
+			params.put("endType", "JY");
+			params.put("enterpriseCode", taxCode);
+			params.put("subjectType", "HUI_QI_YUN");
+			params.put("channel", "DEFAULT");
+			params.put("subjectLocation", note.getSubjectLocation().getType());
+			params.put("notes", pathNo[0]);
+			params.put("pathNo", pathNo[0]);
+
+
+			if (SubjectLocation.JIN_YUAN.equals(note.getSubjectLocation())) {
+				params.put("taxMode", "GENERAL");
+				params.put("transactionModel", "SUPERVISE");
+			}
+			// 海南飞亿 和 河南薪泰梓
+			else {
+				params.put("taxMode", "SPECIAL");
+				params.put("transactionModel", "CHANNEL");
+			}
+
+			// 发起结算
+			HttpHeaders headers = new HttpHeaders();
+			headers.setContentType(MediaType.APPLICATION_JSON);
+			log.info("汇企云结算req: {}", params);
+			HttpEntity<String> result = new RestTemplate().exchange(gigSettleUrl, HttpMethod.POST, new HttpEntity<>(params, headers), String.class);
+			log.info("汇企云结算resp: {}", result.getBody());
+			if (!JSONUtil.isJson(result.getBody())) {
+				return R.failed("结算失败");
+			}
+			JSONObject settelObj = JSONUtil.parseObj(result.getBody());
+
+
+			if (Objects.equals(settelObj.getInt("code"), CommonConstants.SUCCESS)) {
+				JSONObject dataJsonObj = settelObj.getJSONObject("data");
+
+				log.info("汇企云结算提交成功: {}", note.getSettleNo());
+				note.setUpdateTime(LocalDateTime.now());
+				//data 获取不到
+				if (dataJsonObj != null) {
+					String requestId = dataJsonObj.getStr("requestId");
+					note.setSettleNoteStatus(DingEnum.NOTE_STATUS_SUBMIT.getType());
+					// 新增字段streamId
+					note.setStreamId(requestId);
+				} else {
+					log.warn("汇企云结算提交成功 data 获取不到: {}", note.getSettleNo());
+				}
+			} else {
+				log.warn("汇企云结算提交失败: {}", note.getSettleNo());
+				note.setUpdateTime(LocalDateTime.now());
+				note.setSettleNoteStatus(DingEnum.NOTE_STATUS_FAIL.getType());
+
+				log.info("认证状态异常,结算解锁settleNoteId:{}", note.getId());
+				redisTemplate.delete(CacheConstants.SETTLE_PACKAGE_KEY + note.getId());
+
+			}
+		} catch (Exception e) {
+			log.error("", e);
+			log.warn("汇企云结算提交失败: {}", note.getSettleNo());
+			note.setUpdateTime(LocalDateTime.now());
+			note.setSettleNoteStatus(DingEnum.NOTE_STATUS_FAIL.getType());
+
+			log.info("认证状态异常,结算解锁settleNoteId:{}", note.getId());
+			redisTemplate.delete(CacheConstants.SETTLE_PACKAGE_KEY + note.getId());
+		}
+
+		this.baseMapper.updateById(note);
+
+		return R.ok();
+	}
+
 	/**
 	 * 浪潮结算
 	 *

+ 62 - 0
hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/util/AESUtil.java

@@ -0,0 +1,62 @@
+package com.qunzhixinxi.hnqz.admin.util;
+
+import org.apache.commons.codec.binary.Base64;
+
+import javax.crypto.Cipher;
+import javax.crypto.spec.SecretKeySpec;
+import java.security.Security;
+
+public class AESUtil {
+    // add new bouncycastle ciphers
+    static {
+        Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
+    }
+
+    /**
+     * encrypt input text
+     *
+     * @param input
+     * @param key
+     * @return
+     */
+    public static String encrypt(String input, String key) {
+
+        try {
+            byte[] crypted = null;
+            SecretKeySpec skey = new SecretKeySpec(key.getBytes(), "AES");
+
+            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding");
+            cipher.init(Cipher.ENCRYPT_MODE, skey);
+            crypted = cipher.doFinal(input.getBytes());
+            return new String(Base64.encodeBase64(crypted));
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return null;
+
+    }
+
+    /**
+     * decrypt input text
+     *
+     * @param input
+     * @param key
+     * @return
+     */
+    public static String decrypt(String input, String key) {
+
+        try {
+            byte[] output = null;
+            SecretKeySpec skey = new SecretKeySpec(key.getBytes(), "AES");
+            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding");
+            cipher.init(Cipher.DECRYPT_MODE, skey);
+            output = cipher.doFinal(Base64.decodeBase64(input));
+            return new String(output);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return null;
+
+    }
+
+}