Merge remote-tracking branch 'origin/cc_20251112_wallet' into cc_20251112_wallet

This commit is contained in:
wangff
2025-11-17 15:52:10 +08:00
12 changed files with 221 additions and 18 deletions

View File

@@ -10,7 +10,8 @@ public enum ResponseCodeEnum {
/** /**
* 成功返回 * 成功返回
*/ */
SUCCESS(200000, "SUCCESS"); SUCCESS(200000, "SUCCESS"),
SUCCESS_WALLET(200, "SUCCESS");
/** /**
* 返回码 * 返回码

View File

@@ -16,7 +16,7 @@ import lombok.Getter;
public enum PingAnAccountStatusEnum { public enum PingAnAccountStatusEnum {
UNCOMMITTED(1, "待提交"), UNCOMMITTED(1, "待提交"),
UNAUTHORIZED(2, "鉴权"), UNAUTHORIZED(2, "鉴权"),
AUTHENTICATING(3, "鉴权中"), AUTHENTICATING(3, "鉴权中"),
OPEN(4, "开通"), OPEN(4, "开通"),
; ;

View File

@@ -1,6 +1,6 @@
package com.cool.store.utils; package com.cool.store.utils;
import com.sun.deploy.net.URLEncoder; import java.net.URLEncoder;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.asn1.pkcs.RSAPrivateKey; import org.bouncycastle.asn1.pkcs.RSAPrivateKey;
import sun.security.util.DerInputStream; import sun.security.util.DerInputStream;

View File

@@ -97,8 +97,8 @@ public class ShopInfoDAO {
* @return * @return
*/ */
public Long addShopInfo(ShopInfoDO shopInfo){ public Long addShopInfo(ShopInfoDO shopInfo){
shopInfoMapper.insertSelective(shopInfo);
shopInfo.setStoreId(UUIDUtils.get32UUID()); shopInfo.setStoreId(UUIDUtils.get32UUID());
shopInfoMapper.insertSelective(shopInfo);
return shopInfo.getId(); return shopInfo.getId();
} }

View File

@@ -0,0 +1,21 @@
package com.cool.store.request.wallet;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* @Author suzhuhong
* @Date 2025/11/17 13:49
* @Version 1.0
*/
@Data
public class AddTagCallbackNoticeRequest {
@ApiModelProperty(name = "CRM门店编号", required = true)
private String outStoreId;
@ApiModelProperty(name = "状态1.打标成功 2.打标失败 3.处理中(打标状态)", required = true)
private Integer status;
@ApiModelProperty(name = "1.法人 2.非法人", required = true)
private Integer addTagType;
}

View File

@@ -0,0 +1,27 @@
package com.cool.store.request.wallet;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* @Author suzhuhong
* @Date 2025/11/17 11:20
* @Version 1.0
*/
@Data
public class UpdatePasswordRequest {
@ApiModelProperty(name = "CRM门店编号", required = true)
private String outStoreId;
@ApiModelProperty(name = "维护类型 1.设置密码 2.修改密码", required = true)
private Integer upholdType;
@ApiModelProperty(name = "新支付密码(sm3加密后字符串)", required = true)
private String newPayPwd;
@ApiModelProperty(name = "确认新支付密码(sm3加密后字符串)", required = true)
private String confirmPayPwd;
@ApiModelProperty(name = "当前使用的支付密码(sm3加密后字符串),维护类型为修改密码时必填", required = false)
private String currentPayPwd;
}

View File

@@ -3,9 +3,12 @@ package com.cool.store.response.bigdata;
import com.cool.store.constants.CommonConstants; import com.cool.store.constants.CommonConstants;
import com.cool.store.enums.ErrorCodeEnum; import com.cool.store.enums.ErrorCodeEnum;
import com.cool.store.enums.ResponseCodeEnum; import com.cool.store.enums.ResponseCodeEnum;
import com.cool.store.response.ResponseResult;
import lombok.Data; import lombok.Data;
import org.slf4j.MDC; import org.slf4j.MDC;
import java.text.MessageFormat;
/** /**
* @Author suzhuhong * @Author suzhuhong
* @Date 2025/4/1 10:49 * @Date 2025/4/1 10:49
@@ -31,7 +34,19 @@ public class ApiResponse<T> {
return new ApiResponse(ResponseCodeEnum.SUCCESS.getCode(), "ok", data); return new ApiResponse(ResponseCodeEnum.SUCCESS.getCode(), "ok", data);
} }
public static<T> ApiResponse<T> error(ErrorCodeEnum errorCodeEnum) { /**
return new ApiResponse(errorCodeEnum.getCode(), errorCodeEnum.getMessage(), null); * 钱包系统 响应用200
* @param data
* @param <T>
* @return
*/
public static<T> ApiResponse<T> successByWallet(T data) {
return new ApiResponse(ResponseCodeEnum.SUCCESS_WALLET.getCode(), "ok", data);
}
public static ApiResponse fail(ErrorCodeEnum responseEnum, Object... objects){
String message = MessageFormat.format(responseEnum.getMessage(), objects);
return new ApiResponse(responseEnum.getCode(), message, false);
} }
} }

View File

@@ -161,6 +161,14 @@ public class WalletApiService {
return walletHttpClientRest.postWithSign("https://api.dev.wenmatech.com:443/open/crm/base/v1/findPageBank", request, BankListDTO.class); return walletHttpClientRest.postWithSign("https://api.dev.wenmatech.com:443/open/crm/base/v1/findPageBank", request, BankListDTO.class);
} }
/**
* 修改密码
* @param request
* @return
*/
public String upholdPwd(UpdatePasswordRequest request){
return walletHttpClientRest.postWithSign("https://api.dev.wenmatech.com:443/open/crm/account/v1/upholdPwd", request, String.class);
}

View File

@@ -49,4 +49,11 @@ public interface WalletService {
* @param storeId 主数据门店id * @param storeId 主数据门店id
*/ */
void addTagIfUploadLicense(Long shopId, String storeId); void addTagIfUploadLicense(Long shopId, String storeId);
/**
* 打标成功回调通知
* @param request
* @return
*/
Boolean addTagCallback(AddTagCallbackNoticeRequest request);
} }

View File

@@ -27,6 +27,7 @@ import com.cool.store.vo.wallet.BankVO;
import com.github.pagehelper.PageInfo; import com.github.pagehelper.PageInfo;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@@ -149,25 +150,41 @@ public class WalletServiceImpl implements WalletService {
// 营业执照已上传,调用打标接口 // 营业执照已上传,调用打标接口
if (Objects.nonNull(licenseTransactDO) && StringUtils.isNotBlank(licenseTransactDO.getCreditUrl())) { if (Objects.nonNull(licenseTransactDO) && StringUtils.isNotBlank(licenseTransactDO.getCreditUrl())) {
try { try {
// 调用 签约人账户打标(升级)接口 // 判断一下账户的开通状态
log.info("营业执照已上传,账户打标"); if (enableAddTag(storeId)) {
AccountAddTagRequest tagRequest = AccountAddTagRequest.builder() // 调用 签约人账户打标(升级)接口
.outStoreId(storeId) log.info("营业执照已上传,账户打标");
.licenseNo(licenseTransactDO.getCreditCode()) AccountAddTagRequest tagRequest = AccountAddTagRequest.builder()
.licenseName(licenseTransactDO.getBusinessLicense()) .outStoreId(storeId)
.licenseNo(licenseTransactDO.getCreditCode())
.licenseName(licenseTransactDO.getBusinessLicense())
// .licenseExpire(Objects.nonNull(licenseTransactDO.getValidity()) ? CoolDateUtils.DateFormat(licenseTransactDO.getValidity(), "yyyy-MM-dd") : "2999-12-31") // .licenseExpire(Objects.nonNull(licenseTransactDO.getValidity()) ? CoolDateUtils.DateFormat(licenseTransactDO.getValidity(), "yyyy-MM-dd") : "2999-12-31")
.legalName(licenseTransactDO.getLicenseLegalPerson()) .legalName(licenseTransactDO.getLicenseLegalPerson())
.legalNo(licenseTransactDO.getLicenseLegalIdCardNo()) .legalNo(licenseTransactDO.getLicenseLegalIdCardNo())
.legalPhone(licenseTransactDO.getLicenseLegalMobile()) .legalPhone(licenseTransactDO.getLicenseLegalMobile())
.build(); .build();
AddTagDTO addTagDTO = walletApiService.addTag(tagRequest); AddTagDTO addTagDTO = walletApiService.addTag(tagRequest);
log.info("打标接口调用成功response:{}", JSONObject.toJSONString(addTagDTO)); log.info("打标接口调用成功response:{}", JSONObject.toJSONString(addTagDTO));
}
} catch (Exception e) { } catch (Exception e) {
log.error("营业执照已上传,打标失败", e); log.error("营业执照已上传,打标失败", e);
} }
} }
} }
/**
* 账户存在且未打标
*/
private boolean enableAddTag(String storeId) {
List<AccountInfoDTO> accountInfo = walletApiService.getAccountInfo(new OutStoreIdRequest(storeId));
return CollectionUtils.isNotEmpty(accountInfo) && accountInfo.size() == 1 && accountInfo.get(0).getLabelingStatus().equals(0);
}
@Override
public Boolean addTagCallback(AddTagCallbackNoticeRequest request) {
return Boolean.TRUE;
}
/** /**
* 查询并校验门店是否存在以及阶段是否处于平安钱包未开通状态 * 查询并校验门店是否存在以及阶段是否处于平安钱包未开通状态
*/ */

View File

@@ -5,7 +5,9 @@ import com.cool.store.constants.CommonConstants;
import com.cool.store.enums.ErrorCodeEnum; import com.cool.store.enums.ErrorCodeEnum;
import com.cool.store.exception.ServiceException; import com.cool.store.exception.ServiceException;
import com.cool.store.response.ResponseResult; import com.cool.store.response.ResponseResult;
import com.cool.store.response.bigdata.ApiResponse;
import com.cool.store.utils.OpenSignatureUtil; import com.cool.store.utils.OpenSignatureUtil;
import com.cool.store.utils.RsaSignUtil;
import com.cool.store.utils.UUIDUtils; import com.cool.store.utils.UUIDUtils;
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.core.type.TypeReference;
@@ -42,6 +44,8 @@ public class OpenApiValidateFilter implements Filter {
private String coolAppKey; private String coolAppKey;
@Value("${cool.api.secret}") @Value("${cool.api.secret}")
private String coolAppSecret; private String coolAppSecret;
@Value("${cool.api.rsa.private.key}")
private String coolPrivateKey;
private static final Set<String> WHITELIST_URIS = new HashSet<>(Arrays.asList( private static final Set<String> WHITELIST_URIS = new HashSet<>(Arrays.asList(
"/zxjp/open/v1/statusRefresh", "/zxjp/open/v1/statusRefresh",
"/zxjp/open/v1/getStoreUser", "/zxjp/open/v1/getStoreUser",
@@ -52,6 +56,8 @@ public class OpenApiValidateFilter implements Filter {
"/zxjp/open/v1/getYlsToken", "/zxjp/open/v1/getStoreList", "/zxjp/open/v1/getYlsToken", "/zxjp/open/v1/getStoreList",
"/zxjp/open/v1/changeReceiptStatus", "/zxjp/open/v1/getStoreUser")); "/zxjp/open/v1/changeReceiptStatus", "/zxjp/open/v1/getStoreUser"));
// 添加钱包接口路径前缀常量
private static final String WALLET_API_PATTERN = "^/zxjp/open/v\\d+/wallet/.*$";
@Override @Override
public void init(FilterConfig filterConfig) throws ServletException { public void init(FilterConfig filterConfig) throws ServletException {
} }
@@ -70,6 +76,11 @@ public class OpenApiValidateFilter implements Filter {
filterChain.doFilter(servletRequest, response); filterChain.doFilter(servletRequest, response);
return; return;
} }
// 针对钱包接口的专用验签处理 所有符合 /zxjp/open/v{版本号}/wallet/ 格式的接口都会走钱包专用的验签流程。
if (uri.matches(WALLET_API_PATTERN)) {
handleWalletApiValidation(request, response, filterChain);
return;
}
HttpServletResponse res = (HttpServletResponse) response; HttpServletResponse res = (HttpServletResponse) response;
// 1. 验证时间戳 // 1. 验证时间戳
@@ -186,4 +197,90 @@ public class OpenApiValidateFilter implements Filter {
@Override @Override
public void destroy() { public void destroy() {
} }
private void handleWalletApiValidation(HttpServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
HttpServletResponse res = (HttpServletResponse) response;
try {
// 读取请求体
StringBuilder requestBody = new StringBuilder();
try (BufferedReader reader = request.getReader()) {
String line;
while ((line = reader.readLine()) != null) {
requestBody.append(line);
}
}
String jsonBody = requestBody.toString();
// 1. 验证时间戳
String timestampStr = extractTimestampFromJson(jsonBody);
if (timestampStr == null) {
writeErrorResponse(res, ErrorCodeEnum.SIGN_FAIL, "缺少timestamp参数");
return;
}
long timestamp = Long.parseLong(timestampStr) / 1000;
long currentTime = System.currentTimeMillis() / 1000;
long timeDiff = Math.abs(currentTime - timestamp);
if (timeDiff > 600) {
writeErrorResponse(res, ErrorCodeEnum.SIGN_FAIL, "请求已过期请保证timestamp时间在10分钟之内");
return;
}
// 2. 钱包接口专用验签逻辑
if (!verifyWalletSignatureFromBody(jsonBody)) {
writeErrorResponse(res, ErrorCodeEnum.SIGN_FAIL, "签名校验失败");
return;
}
filterChain.doFilter(request, response);
} catch (Exception e) {
log.error("钱包接口验签异常: ", e);
writeErrorResponse(res, ErrorCodeEnum.SIGN_FAIL, "验签异常");
}
}
/**
* 从JSON中提取timestamp字段
*/
private String extractTimestampFromJson(String jsonBody) {
try {
ObjectMapper objectMapper = new ObjectMapper();
Map<String, Object> params = objectMapper.readValue(jsonBody, new TypeReference<Map<String, Object>>() {});
Object timestamp = params.get("timestamp");
return timestamp != null ? timestamp.toString() : null;
} catch (Exception e) {
log.error("提取timestamp失败: ", e);
return null;
}
}
/**
* 钱包接口签名验证方法 - 签名在请求体中
*/
private boolean verifyWalletSignatureFromBody(String jsonBody) {
try {
// 解析请求参数
ObjectMapper objectMapper = new ObjectMapper();
Map<String, Object> params = objectMapper.readValue(jsonBody, new TypeReference<Map<String, Object>>() {});
// 使用RsaSignUtil.verifyWalletSign进行验签
return RsaSignUtil.verifyWalletSign(params, coolPrivateKey);
} catch (Exception e) {
log.error("钱包接口签名验证失败: ", e);
return false;
}
}
/**
* 写入错误响应
*/
private void writeErrorResponse(HttpServletResponse response, ErrorCodeEnum errorCode, String message) throws IOException {
response.setStatus(HttpStatus.OK.value());
response.setCharacterEncoding("UTF-8");
response.getWriter().write(JSON.toJSONString(ApiResponse.fail(errorCode, message)));
}
} }

View File

@@ -11,11 +11,13 @@ import com.cool.store.request.StoreCodeDTO;
import com.cool.store.request.*; import com.cool.store.request.*;
import com.cool.store.request.notice.ThirdHandleMessageRequest; import com.cool.store.request.notice.ThirdHandleMessageRequest;
import com.cool.store.request.notice.ThirdMatterRequest; import com.cool.store.request.notice.ThirdMatterRequest;
import com.cool.store.request.wallet.AddTagCallbackNoticeRequest;
import com.cool.store.request.xgj.FranchiseFeeCallBackRequest; import com.cool.store.request.xgj.FranchiseFeeCallBackRequest;
import com.cool.store.request.xgj.ReceiptCallBackRequest; import com.cool.store.request.xgj.ReceiptCallBackRequest;
import com.cool.store.response.ResponseResult; import com.cool.store.response.ResponseResult;
import com.cool.store.response.bigdata.ApiResponse; import com.cool.store.response.bigdata.ApiResponse;
import com.cool.store.service.*; import com.cool.store.service.*;
import com.cool.store.service.wallet.WalletService;
import com.cool.store.utils.poi.StringUtils; import com.cool.store.utils.poi.StringUtils;
import com.github.pagehelper.PageInfo; import com.github.pagehelper.PageInfo;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
@@ -57,6 +59,8 @@ public class OpenApiController {
WechatMiniAppService wechatMiniAppService; WechatMiniAppService wechatMiniAppService;
@Autowired @Autowired
WeChatHandler weChatHandler; WeChatHandler weChatHandler;
@Resource
WalletService walletService;
@PostMapping("/statusRefresh") @PostMapping("/statusRefresh")
public ApiResponse<Boolean> statusRefresh(@RequestBody StatusRefreshDTO statusRefreshDTO){ public ApiResponse<Boolean> statusRefresh(@RequestBody StatusRefreshDTO statusRefreshDTO){
@@ -214,4 +218,10 @@ public class OpenApiController {
} }
return echostr; return echostr;
} }
@ApiOperation("打标回调通知接口")
@PostMapping("/wallet/addTagCallback")
public ApiResponse<Boolean> addTagCallback(@RequestBody @Validated AddTagCallbackNoticeRequest request) {
return ApiResponse.successByWallet(walletService.addTagCallback(request));
}
} }