|
@@ -152,6 +152,12 @@ public class WithdrawServiceImpl implements IWithdrawService {
|
|
|
throw new ServiceException("提现状态不正确,当前状态:{}", withdraw.getWithdrawStatus());
|
|
throw new ServiceException("提现状态不正确,当前状态:{}", withdraw.getWithdrawStatus());
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ // 查询收款账户,判断提现方式
|
|
|
|
|
+ WithdrawAccount account = withdrawAccountMapper.selectById(withdraw.getAccountId());
|
|
|
|
|
+ if (account == null) {
|
|
|
|
|
+ throw new ServiceException("收款账户不存在");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
withdraw.setWithdrawStatus(1);
|
|
withdraw.setWithdrawStatus(1);
|
|
|
withdraw.setAuditorId(LoginHelper.getUserId());
|
|
withdraw.setAuditorId(LoginHelper.getUserId());
|
|
|
withdraw.setAuditTime(new Date());
|
|
withdraw.setAuditTime(new Date());
|
|
@@ -159,7 +165,14 @@ public class WithdrawServiceImpl implements IWithdrawService {
|
|
|
withdrawMapper.updateById(withdraw);
|
|
withdrawMapper.updateById(withdraw);
|
|
|
|
|
|
|
|
try {
|
|
try {
|
|
|
- String tradeNo = transferToAlipay(withdraw);
|
|
|
|
|
|
|
+ String tradeNo;
|
|
|
|
|
+ if (Objects.equals(account.getAccountType(), 2)) {
|
|
|
|
|
+ // 微信提现
|
|
|
|
|
+ tradeNo = transferToWechat(withdraw);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // 支付宝提现(默认)
|
|
|
|
|
+ tradeNo = transferToAlipay(withdraw);
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
SysTenant tenant = sysTenantMapper.selectById(withdraw.getCompanyId());
|
|
SysTenant tenant = sysTenantMapper.selectById(withdraw.getCompanyId());
|
|
|
if (tenant == null) {
|
|
if (tenant == null) {
|
|
@@ -174,8 +187,9 @@ public class WithdrawServiceImpl implements IWithdrawService {
|
|
|
update.setWithdrawingBalance(withdrawingBalance.subtract(withdraw.getWithdrawAmount()));
|
|
update.setWithdrawingBalance(withdrawingBalance.subtract(withdraw.getWithdrawAmount()));
|
|
|
sysTenantMapper.updateById(update);
|
|
sysTenantMapper.updateById(update);
|
|
|
|
|
|
|
|
|
|
+ String channelName = Objects.equals(account.getAccountType(), 2) ? "微信" : "支付宝";
|
|
|
insertFlow(tenant.getId(), 2, withdraw.getWithdrawAmount(), 3, withdrawingBalance,
|
|
insertFlow(tenant.getId(), 2, withdraw.getWithdrawAmount(), 3, withdrawingBalance,
|
|
|
- withdrawingBalance.subtract(withdraw.getWithdrawAmount()), 6, withdraw.getId(), withdraw.getWithdrawNo(), "提现成功:" + withdraw.getWithdrawNo());
|
|
|
|
|
|
|
+ withdrawingBalance.subtract(withdraw.getWithdrawAmount()), 6, withdraw.getId(), withdraw.getWithdrawNo(), channelName + "提现成功:" + withdraw.getWithdrawNo());
|
|
|
|
|
|
|
|
withdraw.setWithdrawStatus(3);
|
|
withdraw.setWithdrawStatus(3);
|
|
|
withdraw.setTradeNo(tradeNo);
|
|
withdraw.setTradeNo(tradeNo);
|
|
@@ -456,6 +470,122 @@ public class WithdrawServiceImpl implements IWithdrawService {
|
|
|
throw new ServiceException("支付宝返回错误:{}", response.getSubMsg());
|
|
throw new ServiceException("支付宝返回错误:{}", response.getSubMsg());
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 微信商家转账到零钱
|
|
|
|
|
+ * 注意:由于微信没有沙盒环境,实际API调用已注释,仅做数据库操作测试
|
|
|
|
|
+ */
|
|
|
|
|
+ private String transferToWechat(Withdraw withdraw) throws Exception {
|
|
|
|
|
+ // ---------- 以下为实际微信转账逻辑,暂时注释掉 ----------
|
|
|
|
|
+ /*
|
|
|
|
|
+ PaymentConfig config = paymentConfigService.getEnabledWechatTransferConfig();
|
|
|
|
|
+ if (config == null) {
|
|
|
|
|
+ throw new ServiceException("未找到启用的微信付款配置,请先配置微信付款参数");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ WithdrawAccount account = withdrawAccountMapper.selectById(withdraw.getAccountId());
|
|
|
|
|
+ if (account == null) {
|
|
|
|
|
+ throw new ServiceException("收款账户不存在");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 使用 wechatpay-java SDK 发起商家转账
|
|
|
|
|
+ // 1. 构建配置
|
|
|
|
|
+ RSAAutoCertificateConfig wxConfig = new RSAAutoCertificateConfig.Builder()
|
|
|
|
|
+ .merchantId(config.getMchId())
|
|
|
|
|
+ .privateKeyFromPath(config.getPrivateKeyPath())
|
|
|
|
|
+ .merchantSerialNumber(config.getSerialNo())
|
|
|
|
|
+ .apiV3Key(config.getApiV3Key())
|
|
|
|
|
+ .build();
|
|
|
|
|
+
|
|
|
|
|
+ // 2. 构建转账请求
|
|
|
|
|
+ com.wechat.pay.java.service.transferbatch.TransferBatchService transferService =
|
|
|
|
|
+ new com.wechat.pay.java.service.transferbatch.TransferBatchService.Builder().config(wxConfig).build();
|
|
|
|
|
+
|
|
|
|
|
+ com.wechat.pay.java.service.transferbatch.model.InitiateBatchTransferRequest request =
|
|
|
|
|
+ new com.wechat.pay.java.service.transferbatch.model.InitiateBatchTransferRequest();
|
|
|
|
|
+ request.setAppid(config.getAppId());
|
|
|
|
|
+ request.setOutBatchNo(withdraw.getWithdrawNo());
|
|
|
|
|
+ request.setBatchName("平台背调佣金提现");
|
|
|
|
|
+ request.setBatchRemark("提现单号:" + withdraw.getWithdrawNo());
|
|
|
|
|
+ request.setTotalAmount(withdraw.getWithdrawAmount().multiply(new java.math.BigDecimal(100)).longValue());
|
|
|
|
|
+ request.setTotalNum(1);
|
|
|
|
|
+
|
|
|
|
|
+ com.wechat.pay.java.service.transferbatch.model.TransferDetailInput detail =
|
|
|
|
|
+ new com.wechat.pay.java.service.transferbatch.model.TransferDetailInput();
|
|
|
|
|
+ detail.setOutDetailNo(withdraw.getWithdrawNo() + "D1");
|
|
|
|
|
+ detail.setTransferAmount(withdraw.getWithdrawAmount().multiply(new java.math.BigDecimal(100)).longValue());
|
|
|
|
|
+ detail.setTransferRemark("佣金提现");
|
|
|
|
|
+ detail.setOpenid(account.getAccountNumber()); // 微信账户存的是openid
|
|
|
|
|
+ request.setTransferDetailList(java.util.List.of(detail));
|
|
|
|
|
+
|
|
|
|
|
+ // 3. 发起转账
|
|
|
|
|
+ com.wechat.pay.java.service.transferbatch.model.InitiateBatchTransferResponse response =
|
|
|
|
|
+ transferService.initiateBatchTransfer(request);
|
|
|
|
|
+ return response.getBatchId();
|
|
|
|
|
+ */
|
|
|
|
|
+ // ---------- 以上为实际微信转账逻辑,暂时注释掉 ----------
|
|
|
|
|
+
|
|
|
|
|
+ // 测试模式:跳过实际微信打款,直接返回模拟交易号
|
|
|
|
|
+ return "WX_TEST_" + System.currentTimeMillis();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 处理微信转账回调通知
|
|
|
|
|
+ * 注意:由于微信没有沙盒环境,此方法暂时注释核心逻辑
|
|
|
|
|
+ */
|
|
|
|
|
+ @Override
|
|
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
|
|
+ public String handleWechatTransferNotify(String requestBody) {
|
|
|
|
|
+ // ---------- 以下为实际微信回调处理逻辑,暂时注释掉 ----------
|
|
|
|
|
+ /*
|
|
|
|
|
+ try {
|
|
|
|
|
+ PaymentConfig config = paymentConfigService.getEnabledWechatTransferConfig();
|
|
|
|
|
+ if (config == null) {
|
|
|
|
|
+ return "{\"code\":\"FAIL\",\"message\":\"未找到微信付款配置\"}";
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 解密回调数据中的 resource 字段,获取转账详情
|
|
|
|
|
+ // 根据 out_batch_no 查找提现记录
|
|
|
|
|
+ // 根据转账状态更新提现记录
|
|
|
|
|
+ // SUCCESS -> 提现成功(状态3)
|
|
|
|
|
+ // FAIL -> 提现失败(状态4),退回余额
|
|
|
|
|
+
|
|
|
|
|
+ JSONObject notify = JSONUtil.parseObj(requestBody);
|
|
|
|
|
+ String outBatchNo = notify.getStr("out_batch_no");
|
|
|
|
|
+ String batchStatus = notify.getStr("batch_status");
|
|
|
|
|
+
|
|
|
|
|
+ Withdraw withdraw = withdrawMapper.selectOne(Wrappers.<Withdraw>lambdaQuery()
|
|
|
|
|
+ .eq(Withdraw::getWithdrawNo, outBatchNo)
|
|
|
|
|
+ .last("limit 1"));
|
|
|
|
|
+ if (withdraw == null) {
|
|
|
|
|
+ return "{\"code\":\"FAIL\",\"message\":\"提现记录不存在\"}";
|
|
|
|
|
+ }
|
|
|
|
|
+ if (Objects.equals(withdraw.getWithdrawStatus(), 3)) {
|
|
|
|
|
+ return "{\"code\":\"SUCCESS\",\"message\":\"已处理\"}";
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if ("FINISHED".equals(batchStatus)) {
|
|
|
|
|
+ withdraw.setTradeNo(notify.getStr("batch_id"));
|
|
|
|
|
+ withdraw.setWithdrawStatus(3);
|
|
|
|
|
+ withdraw.setTransferTime(new Date());
|
|
|
|
|
+ withdrawMapper.updateById(withdraw);
|
|
|
|
|
+ } else if ("CLOSED".equals(batchStatus)) {
|
|
|
|
|
+ refundWithdrawToAvailable(withdraw, "微信转账失败,退回可使用余额");
|
|
|
|
|
+ withdraw.setWithdrawStatus(4);
|
|
|
|
|
+ withdraw.setFailReason("微信转账批次关闭");
|
|
|
|
|
+ withdrawMapper.updateById(withdraw);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return "{\"code\":\"SUCCESS\",\"message\":\"成功\"}";
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ return "{\"code\":\"FAIL\",\"message\":\"处理异常\"}";
|
|
|
|
|
+ }
|
|
|
|
|
+ */
|
|
|
|
|
+ // ---------- 以上为实际微信回调处理逻辑,暂时注释掉 ----------
|
|
|
|
|
+
|
|
|
|
|
+ // 测试模式:直接返回成功
|
|
|
|
|
+ return "{\"code\":\"SUCCESS\",\"message\":\"测试模式\"}";
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
private void insertFlow(Long companyId, Integer flowType, BigDecimal amount, Integer balanceType,
|
|
private void insertFlow(Long companyId, Integer flowType, BigDecimal amount, Integer balanceType,
|
|
|
BigDecimal balanceBefore, BigDecimal balanceAfter, Integer businessType,
|
|
BigDecimal balanceBefore, BigDecimal balanceAfter, Integer businessType,
|
|
|
Long businessId, String businessNo, String remark) {
|
|
Long businessId, String businessNo, String remark) {
|