feat:钱包接口对接

This commit is contained in:
苏竹红
2025-11-15 15:11:14 +08:00
parent 7d810b2a0d
commit 0646022baf
20 changed files with 530 additions and 20 deletions

View File

@@ -306,4 +306,42 @@ public class RsaSignUtil {
return null;
}
}
/**
* 针对 /zxjp/open/v1/wallet/** 接口的专用验签方法
* @param params 包含签名参数的Map
* @param privateKeyPEM 用于生成签名的私钥
* @return 验签是否通过
*/
public static boolean verifyWalletSign(Map<String, Object> params, String privateKeyPEM) {
try {
// 1. 获取请求中的签名
String requestSign = String.valueOf(params.get("sign"));
if (requestSign == null || requestSign.isEmpty()) {
log.warn("请求中缺少签名参数");
return false;
}
// 2. 移除签名参数,生成待签名字符串
Map<String, Object> paramsToSign = new HashMap<>(params);
paramsToSign.remove("sign");
// 3. 使用相同的私钥生成签名
String generatedSign = generateSign(paramsToSign, privateKeyPEM);
// 4. 对比签名
boolean isVerified = Objects.equals(requestSign, generatedSign);
if (!isVerified) {
log.warn("签名验证失败,请求签名: {}, 生成签名: {}", requestSign, generatedSign);
}
return isVerified;
} catch (Exception e) {
log.error("验签过程中发生异常", e);
return false;
}
}
}

View File

@@ -61,4 +61,10 @@ public class AccountInfoDTO {
@ApiModelProperty(value = "账户余额", required = true)
private String totalAmount;
@ApiModelProperty(value = "打标状态 0 未打标 1 已打标", required = true)
private Integer labelingStatus;
@ApiModelProperty(value = "是否签约人账户 0 否 1 是", required = true)
private Integer isLegal;
}

View File

@@ -0,0 +1,78 @@
package com.cool.store.dto.wallet;
import lombok.Data;
/**
* @Author suzhuhong
* @Date 2025/11/14 10:09
* @Version 1.0
*/
@Data
public class BillDetailDTO {
/**
* 外部门店唯一标识
*/
private String outStoreId;
/**
* 业务系统付款单号(如 CRM 单号)
*/
private String reqNo;
/**
* 交易Id营帐通
*/
private Long tradeId;
/**
* 交易编号(扫呗)
*/
private String outTradeNo;
/**
* 交易科目
*/
private Integer feeItemId;
/**
* 门店账户编号
*/
private String storeAccountNo;
/**
* 公司编号
*/
private String companyCode;
/**
* 公司账户编号
*/
private String companyAccountNo;
/**
* 提现银行卡
*/
private String withdrawalBankCardNo;
/**
* 提现银行卡户名
*/
private String withdrawalBankCardName;
/**
* 金额(元)
*/
private String amount;
/**
* 交易状态 1.成功 2.失败 3.处理中
*/
private Integer tradeStatus;
/**
* 交易类型 1.转账 2.提现
*/
private Integer tradeType;
}

View File

@@ -0,0 +1,74 @@
package com.cool.store.dto.wallet;
import lombok.Data;
/**
* @Author suzhuhong
* @Date 2025/11/14 10:31
* @Version 1.0
*/
@Data
public class BillPageDTO {
/**
* 业务系统付款单号(如 CRM 单号)
*/
private String reqNo;
/**
* 交易Id营帐通
*/
private Long tradeId;
/**
* 交易编号(扫呗)
*/
private String outTradeNo;
/**
* 交易科目
*/
private Integer feeItemId;
/**
* 门店账户编号
*/
private String storeAccountNo;
/**
* 公司编号
*/
private String companyCode;
/**
* 公司账户编号
*/
private String companyAccountNo;
/**
* 提现银行卡
*/
private String withdrawalBankCradNo;
/**
* 提现银行卡户名
*/
private String withdrawalBankCradName;
/**
* 金额(元)
*/
private String amount;
/**
* 交易状态 1.成功 2.失败 3.处理中
*/
private Integer tradeStatus;
/**
* 交易类型 1.转账 2.提现
*/
private Integer tradeType;
}

View File

@@ -0,0 +1,23 @@
package com.cool.store.dto.wallet;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* @Author suzhuhong
* @Date 2025/11/14 10:34
* @Version 1.0
*/
@Data
public class CompanyDTO {
@ApiModelProperty(value = "公司编号")
private String companyCode;
@ApiModelProperty(value = "公司名称")
private String companyName;
@ApiModelProperty(value = "公司账户")
private String companyAccountNo;
}

View File

@@ -0,0 +1,21 @@
package com.cool.store.dto.wallet;
import com.cool.store.request.wallet.WalletBasicPageInfo;
import lombok.Data;
import java.util.List;
/**
* @Author suzhuhong
* @Date 2025/11/14 10:57
* @Version 1.0
*/
@Data
public class CompanyListDTO {
private List<CompanyDTO> pageData;
private WalletBasicPageInfo page;
}

View File

@@ -14,6 +14,6 @@ public class StoreAccountDTO {
/**
* 营帐通的账户ID
*/
private String accountId;
private String accountNo;
}

View File

@@ -0,0 +1,23 @@
package com.cool.store.dto.wallet;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* @Author suzhuhong
* @Date 2025/11/14 9:49
* @Version 1.0
*/
@Data
public class TransferDTO {
@ApiModelProperty(value="业务系统付款单号(如 CRM 单号)",required = true)
private String reqNo;
@ApiModelProperty(value="转账交易Id",required = true)
private Long tradeId;
@ApiModelProperty(value="金额(元)",required = true)
private String amount;
@ApiModelProperty(value="交易状态1.成功 2.失败 3.处理中",required = true)
private Integer tradeStatus;
}

View File

@@ -0,0 +1,29 @@
package com.cool.store.dto.wallet;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* @Author suzhuhong
* @Date 2025/11/14 9:59
* @Version 1.0
*/
@Data
public class WithDrawerDTO {
@ApiModelProperty(value = "门店ID",required = true)
private String outStoreId;
@ApiModelProperty(value = "业务系统付款单号(如 CRM 单号)",required = true)
private String reqNo;
@ApiModelProperty(value = "转账交易Id营帐通系统",required = true)
private String tradeId;
@ApiModelProperty(value = "提现科目",required = true)
private Long feeItemId;
@ApiModelProperty(value = "提现账户编号",required = true)
private String accountNo;
@ApiModelProperty(value = "金额(元)",required = true)
private String amount;
@ApiModelProperty(value = "交易状态1.成功 2.失败 3.处理中",required = true)
private String tradeStatus;
}

View File

@@ -0,0 +1,18 @@
package com.cool.store.request.wallet;
import io.swagger.annotations.ApiModelProperty;
/**
* @Description 门店签约账户转账提现查询接口
* @Author suzhuhong
* @Date 2025/11/14 10:05
* @Version 1.0
*/
public class BillDetailRequest {
@ApiModelProperty(value = "转账交易Id(转账交易编号二选一)")
private Long tradeId;
@ApiModelProperty(value = "转账交易编号(转账交易Id二选一)")
private String outTradeNo;
}

View File

@@ -0,0 +1,32 @@
package com.cool.store.request.wallet;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* @Author suzhuhong
* @Date 2025/11/14 10:17
* @Version 1.0
*/
@Data
public class BillPageRequest {
@ApiModelProperty(value = "门店ID", required = true)
private String outStoreId;
@ApiModelProperty(value = "交易开始时间YYYY-MM-DD HH:MM:SS", required = true)
private String beginDate;
@ApiModelProperty(value = "交易结束时间YYYY-MM-DD HH:MM:SS", required = true)
private String endDate;
@ApiModelProperty(value = "钱包类型 1.门店钱包(平安) 2.签约人钱包(平安) 3.返利钱包(网商)", required = true)
private Integer walletType;
@ApiModelProperty(value = "交易类型: 0.全部,1.支出 2.收入", required = false)
private Integer recordType;
@ApiModelProperty(value = "费用类型ID", required = true)
private Long feeItemId;
@ApiModelProperty(value = "当前页码", required = true)
private Integer currentPage;
@ApiModelProperty(value = "每页数量", required = true)
private Integer pageSize;
}

View File

@@ -0,0 +1,22 @@
package com.cool.store.request.wallet;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* @Author suzhuhong
* @Date 2025/11/14 10:32
* @Version 1.0
*/
@Data
public class FindPageCompanyRequest {
@ApiModelProperty(value = "公司编码")
private String companyCode;
@ApiModelProperty(value = "公司名称")
private String companyName;
private WalletBasicPageInfo page;
}

View File

@@ -11,16 +11,16 @@ import lombok.Data;
@Data
public class LargePaymentRequest {
@ApiModelProperty(name = "商户门店编号",required = true)
@ApiModelProperty(value = "商户门店编号",required = true)
private String outStoreId;
@ApiModelProperty(name = "请求预支付Id",required = true)
@ApiModelProperty(value = "请求预支付Id",required = true)
private String paymentId;
@ApiModelProperty(name = "签约人名称",required = true)
@ApiModelProperty(value = "签约人名称",required = true)
private String payerAccName;
@ApiModelProperty(name = "支付金额",required = true)
@ApiModelProperty(value = "支付金额",required = true)
private String amt;
}

View File

@@ -0,0 +1,31 @@
package com.cool.store.request.wallet;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* @Author suzhuhong
* @Date 2025/11/14 9:40
* @Version 1.0
*/
@Data
public class TransferRequest {
@ApiModelProperty(name = "门店唯一标识",required = true)
private String outStoreId;
@ApiModelProperty(name = "支付密码(sm3加密后字符串)",required = true)
private String payPwd;
@ApiModelProperty(name = "业务系统付款单号(如 CRM 单号),业务系统唯一",required = true)
private String reqNo;
@ApiModelProperty(name = "付款科目",required = true)
private Integer feeItemId;
@ApiModelProperty(name = "公司编号",required = true)
private String companyCode;
@ApiModelProperty(name = "公司编号绑定多个账户时,必传",required = false)
private String companyAccountCode;
@ApiModelProperty(name = "金额(元)",required = true)
private String amount;
@ApiModelProperty(name = "备注 ,交易摘要",required = true)
private String remark;
}

View File

@@ -17,10 +17,10 @@ import lombok.NoArgsConstructor;
@NoArgsConstructor
public class WalletBasicPageInfo {
@ApiModelProperty(name = "当前页码",required = true)
@ApiModelProperty(value = "当前页码",required = true)
private Integer currentPage;
@ApiModelProperty(name = "每页数量",required = true)
@ApiModelProperty(value = "每页数量",required = true)
private Integer pageSize;
private Integer total;

View File

@@ -0,0 +1,25 @@
package com.cool.store.request.wallet;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* @Author suzhuhong
* @Date 2025/11/14 9:56
* @Version 1.0
*/
@Data
public class WithDrawerRequest {
@ApiModelProperty(value = "门店ID")
private String outStoreId;
@ApiModelProperty(value = "支付密码(sm3加密后字符串)")
private String payPwd;
@ApiModelProperty(value = "业务系统付款单号(如 CRM 单号)")
private String reqNo;
@ApiModelProperty(value = "提现金额")
private String amount;
@ApiModelProperty(value = "提现备注")
private String remark;
}

View File

@@ -1,5 +1,6 @@
package com.cool.store.http;
import com.alibaba.fastjson.JSONObject;
import com.cool.store.enums.ErrorCodeEnum;
import com.cool.store.exception.ServiceException;
import com.cool.store.utils.RsaSignUtil;
@@ -14,6 +15,7 @@ import org.springframework.stereotype.Service;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
@@ -167,16 +169,11 @@ public class WalletHttpClientRest {
*/
@SuppressWarnings("unchecked")
private <T> T parseResponse(String responseJson, Class<T> responseType) throws Exception {
if (responseType == String.class) {
return (T) responseJson;
}
// 解析为通用响应格式
Map<String, Object> responseMap = objectMapper.readValue(responseJson,
new TypeReference<Map<String, Object>>() {});
// 如果返回类型是Map直接返回
if (responseType == Map.class) {
return (T) responseMap;
@@ -185,6 +182,10 @@ public class WalletHttpClientRest {
// 提取data字段
Object data = responseMap.get("data");
if (data != null && responseType != Object.class) {
if (data instanceof List) {
// 保持List结构让调用方处理具体类型转换
return (T)JSONObject.toJSONString(data);
}
return objectMapper.convertValue(data, responseType);
}

View File

@@ -1,11 +1,14 @@
package com.cool.store.service.wallet;
import com.alibaba.fastjson.JSONObject;
import com.cool.store.dto.wallet.*;
import com.cool.store.http.WalletHttpClientRest;
import com.cool.store.request.wallet.*;
import com.cool.store.utils.StringUtil;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
/**
* @Author suzhuhong
@@ -77,8 +80,12 @@ public class WalletApiService {
* @param request
* @return
*/
public AccountInfoDTO getAccountInfo(OutStoreIdRequest request){
return walletHttpClientRest.postWithSign("https://api.dev.wenmatech.com:443/open/crm/account/v1/getAccountInfo", request, AccountInfoDTO.class);
public List<AccountInfoDTO> getAccountInfo(OutStoreIdRequest request){
String accountInfoStr = walletHttpClientRest.postWithSign("https://api.dev.wenmatech.com:443/open/crm/account/v1/queryAccountInfo", request, String.class);
if (StringUtil.isNotEmpty(accountInfoStr)){
return JSONObject.parseArray(accountInfoStr, AccountInfoDTO.class);
}
return null;
}
/**
@@ -87,7 +94,7 @@ public class WalletApiService {
* @return
*/
public LargePaymentDTO largePayment(LargePaymentRequest request){
return walletHttpClientRest.postWithSign("https://api.dev.wenmatech.com:443/open/crm/payment/v1/largePayment", request, LargePaymentDTO.class);
return walletHttpClientRest.postWithSign("https://api.dev.wenmatech.com:443/open/crm/trans/v1/largePayment", request, LargePaymentDTO.class);
}
/**
@@ -99,6 +106,52 @@ public class WalletApiService {
return walletHttpClientRest.postWithSign("https://api.dev.wenmatech.com:443/open/crm/trans/v1/largePaymentQuery", request, PaymentDTO.class);
}
/**
* 门店账户向公司分账转账接口
* @param request
* @return
*/
public TransferDTO transfer(TransferRequest request){
return walletHttpClientRest.postWithSign("https://api.dev.wenmatech.com:443/open/crm/trans/v1/transfer", request, TransferDTO.class);
}
/**
* 门店签约账户,退款提现至提现卡
* @param request
* @return
*/
public WithDrawerDTO withdraw(WithDrawerRequest request){
return walletHttpClientRest.postWithSign("https://api.dev.wenmatech.com:443/open/crm/trans/v1/withdraw", request, WithDrawerDTO.class);
}
/**
* 账单详情
* @param request
* @return
*/
public BillDetailDTO getBillDetail(BillDetailRequest request){
return walletHttpClientRest.postWithSign("https://api.dev.wenmatech.com:443/open/crm/trans/v1/billDetail", request, BillDetailDTO.class);
}
/**
* 获取门店账户流水
* @param request
* @return
*/
public BillPageDTO getBillPage(BillPageRequest request){
return walletHttpClientRest.postWithSign("https://api.dev.wenmatech.com:443/open/crm/trans/v1/billPage", request, BillPageDTO.class);
}
/**
* 获取门店账户信息
* @param request
* @return
*/
public CompanyListDTO getCompanyInfo(FindPageCompanyRequest request){
return walletHttpClientRest.postWithSign("https://api.dev.wenmatech.com:443/open/crm/base/v1/findPageCompany", request, CompanyListDTO.class);
}
/**
* 获取支行信息
* @param request

View File

@@ -70,6 +70,7 @@ public class OpenApiValidateFilter implements Filter {
filterChain.doFilter(servletRequest, response);
return;
}
HttpServletResponse res = (HttpServletResponse) response;
// 1. 验证时间戳
try {

View File

@@ -752,7 +752,6 @@ public class PCTestController {
return ResponseResult.success(accountAuthenticationDTO);
}
@ApiOperation("门店签约人账户开通接口")
@PostMapping("/openAccount")
public ResponseResult<AccountVerifyDTO> openAccount(@RequestBody AccountVerifyRequest request) {
@@ -762,12 +761,11 @@ public class PCTestController {
@ApiOperation("获取账户信息")
@PostMapping("/getAccountInfo")
public ResponseResult<AccountInfoDTO> getAccountInfo(@RequestBody OutStoreIdRequest request) {
AccountInfoDTO accountInfo = walletApiService.getAccountInfo(request);
return ResponseResult.success(accountInfo);
public ResponseResult<List<AccountInfoDTO>> getAccountInfo(@RequestBody OutStoreIdRequest request) {
List<AccountInfoDTO> accountInfoList = walletApiService.getAccountInfo(request);
return ResponseResult.success(accountInfoList);
}
@ApiOperation("大额预支付接口")
@PostMapping("/largePayment")
public ResponseResult<LargePaymentDTO> largePayment(@RequestBody LargePaymentRequest request) {
@@ -782,6 +780,43 @@ public class PCTestController {
return ResponseResult.success(PaymentDTO);
}
@ApiOperation("门店账户向公司分账转账接口")
@PostMapping("/transfer")
public ResponseResult<TransferDTO> transfer(@RequestBody TransferRequest request) {
TransferDTO transfer = walletApiService.transfer(request);
return ResponseResult.success(transfer);
}
@ApiOperation("门店签约账户,退款提现至提现卡")
@PostMapping("/withdraw")
public ResponseResult<WithDrawerDTO> withdraw(@RequestBody WithDrawerRequest request) {
WithDrawerDTO withdraw = walletApiService.withdraw(request);
return ResponseResult.success(withdraw);
}
@ApiOperation(" 获取账单详情")
@PostMapping("/getBillDetail")
public ResponseResult<BillDetailDTO> getBillDetail(@RequestBody BillDetailRequest request) {
BillDetailDTO billDetail = walletApiService.getBillDetail(request);
return ResponseResult.success(billDetail);
}
@ApiOperation("获取账单列表")
@PostMapping("/getBillPage")
public ResponseResult<BillPageDTO> getBillPage(@RequestBody BillPageRequest request) {
BillPageDTO billPage = walletApiService.getBillPage(request);
return ResponseResult.success(billPage);
}
@ApiOperation("获取银行信息")
@PostMapping("/getCompanyInfo")
public ResponseResult<CompanyListDTO> getCompanyInfo(@RequestBody FindPageCompanyRequest request) {
CompanyListDTO companyDTO = walletApiService.getCompanyInfo(request);
return ResponseResult.success(companyDTO);
}