[fix]修改红包和提现
This commit is contained in:
parent
2e5cc3afbb
commit
a74ed5dde0
@ -111,8 +111,8 @@ public class AppPayController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Operation(summary = "查询支付结果")
|
@Operation(summary = "查询支付结果")
|
||||||
@GetMapping(value = "/result")
|
@PostMapping(value = "/result")
|
||||||
public R<Boolean> paymentResult(PayParam payParam) {
|
public R<Boolean> paymentResult(@RequestBody PayParam payParam) {
|
||||||
return R.ok(cashierSupport.paymentResult(payParam));
|
return R.ok(cashierSupport.paymentResult(payParam));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,19 @@
|
|||||||
|
|
||||||
package com.wzj.soopin.order.controller;
|
package org.dromara.app.customer;
|
||||||
|
|
||||||
import com.wzj.soopin.order.domain.query.GrabRedPacketRequest;
|
import com.wzj.soopin.order.domain.query.GrabRedPacketRequest;
|
||||||
import com.wzj.soopin.order.domain.query.SendRedPacketRequest;
|
import com.wzj.soopin.order.domain.query.SendRedPacketRequest;
|
||||||
import com.wzj.soopin.order.service.RedPacketService;
|
import com.wzj.soopin.transaction.service.RedPacketService;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import org.dromara.common.core.domain.R;
|
import org.dromara.common.core.domain.R;
|
||||||
|
import org.dromara.common.core.domain.model.LoginUser;
|
||||||
|
import org.dromara.common.satoken.utils.LoginHelper;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@ -16,9 +21,9 @@ import java.util.Map;
|
|||||||
* 红包功能控制器
|
* 红包功能控制器
|
||||||
*/
|
*/
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/packet")
|
@RequestMapping("/app/customer/packet")
|
||||||
@Tag(name = "红包功能接口")
|
@Tag(name = "红包功能接口")
|
||||||
public class RedPacketController {
|
public class AppRedPacketController {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private RedPacketService redPacketService;
|
private RedPacketService redPacketService;
|
||||||
@ -31,6 +36,11 @@ public class RedPacketController {
|
|||||||
@PostMapping("/send")
|
@PostMapping("/send")
|
||||||
@Operation(summary = "发红包")
|
@Operation(summary = "发红包")
|
||||||
public R<Map<String, Object>> sendRedPacket(@RequestBody SendRedPacketRequest request) {
|
public R<Map<String, Object>> sendRedPacket(@RequestBody SendRedPacketRequest request) {
|
||||||
|
LoginUser user = LoginHelper.getLoginUser();
|
||||||
|
if (user == null) {
|
||||||
|
return R.notLogin();
|
||||||
|
}
|
||||||
|
request.setSenderId(user.getUserId());
|
||||||
Map<String, Object> result = redPacketService.sendRedPacket(request);
|
Map<String, Object> result = redPacketService.sendRedPacket(request);
|
||||||
return R.ok("红包发送成功", result);
|
return R.ok("红包发送成功", result);
|
||||||
}
|
}
|
||||||
@ -42,6 +52,11 @@ public class RedPacketController {
|
|||||||
@PostMapping("/grab")
|
@PostMapping("/grab")
|
||||||
@Operation(summary = "抢红包")
|
@Operation(summary = "抢红包")
|
||||||
public R<Map<String, Object>> grabRedPacket(@RequestBody GrabRedPacketRequest request) {
|
public R<Map<String, Object>> grabRedPacket(@RequestBody GrabRedPacketRequest request) {
|
||||||
|
LoginUser user = LoginHelper.getLoginUser();
|
||||||
|
if (user == null) {
|
||||||
|
return R.notLogin();
|
||||||
|
}
|
||||||
|
request.setMemberId(user.getUserId());
|
||||||
Map<String, Object> result = redPacketService.grabRedPacket(request);
|
Map<String, Object> result = redPacketService.grabRedPacket(request);
|
||||||
return R.ok("红包领取成功", result);
|
return R.ok("红包领取成功", result);
|
||||||
}
|
}
|
@ -381,7 +381,7 @@ wechat:
|
|||||||
mch-serial-no: 6BA681D9B219034D6F7851F57D61BE9317AB48FD # 商户证书序列号
|
mch-serial-no: 6BA681D9B219034D6F7851F57D61BE9317AB48FD # 商户证书序列号
|
||||||
api-v3-key: T9iE71aHSmjtM35z4bDLuU3gFX8s2I2h # APIv3密钥
|
api-v3-key: T9iE71aHSmjtM35z4bDLuU3gFX8s2I2h # APIv3密钥
|
||||||
private-key-path: "classpath:cert/apiclient_key.pem" # 商户私钥文件路径
|
private-key-path: "classpath:cert/apiclient_key.pem" # 商户私钥文件路径
|
||||||
transfer-notify-url: https://a94aeb5582c2.ngrok-free.app/no-auth/wechat/notify # 转账回调地址
|
transfer-notify-url: https://wuzhongjie.com.cn/prod-api/api/transfer/callback # 转账回调地址
|
||||||
app-id: wxebcdaea31881caab # 应用ID
|
app-id: wxebcdaea31881caab # 应用ID
|
||||||
secret: your_wechat_secret # 应用密钥
|
secret: your_wechat_secret # 应用密钥
|
||||||
mini-program:
|
mini-program:
|
||||||
|
@ -79,7 +79,7 @@ public class WxPayController {
|
|||||||
request.setTransferSceneReportInfos(transferDetailList);
|
request.setTransferSceneReportInfos(transferDetailList);
|
||||||
//异步接收微信支付结果通知的回调地址,通知url必须为公网可访问的URL,必须为HTTPS,不能携带参数
|
//异步接收微信支付结果通知的回调地址,通知url必须为公网可访问的URL,必须为HTTPS,不能携带参数
|
||||||
// 注意:此处需要填写公网可访问的服务器地址,不能携带任何参数
|
// 注意:此处需要填写公网可访问的服务器地址,不能携带任何参数
|
||||||
request.setNotifyUrl("https://2e879e23cc0e.ngrok-free.app/api/transfer/callback");
|
request.setNotifyUrl("https://wuzhongjie.com.cn/prod-api/api/transfer/callback");
|
||||||
try{
|
try{
|
||||||
response = wxPayService.initiateBatchTransferNew(request);
|
response = wxPayService.initiateBatchTransferNew(request);
|
||||||
}catch (ServiceException e){
|
}catch (ServiceException e){
|
||||||
|
@ -76,4 +76,6 @@ public class Charge extends BaseAudit {
|
|||||||
* 审核状态
|
* 审核状态
|
||||||
*/
|
*/
|
||||||
private Integer auditStatus;
|
private Integer auditStatus;
|
||||||
|
|
||||||
|
private String payNo;
|
||||||
}
|
}
|
||||||
|
@ -5,9 +5,8 @@ import lombok.Getter;
|
|||||||
@Getter
|
@Getter
|
||||||
public enum ChargeStatus {
|
public enum ChargeStatus {
|
||||||
WAITING(0, "未支付"),
|
WAITING(0, "未支付"),
|
||||||
PENDING(1, "待验证"),
|
SUCCESS(1, "充值成功"),
|
||||||
SUCCESS(2, "充值成功"),
|
FAIL(2, "充值失败");
|
||||||
FAIL(3, "充值失败");
|
|
||||||
|
|
||||||
private Integer code;
|
private Integer code;
|
||||||
private String message;
|
private String message;
|
||||||
|
@ -191,11 +191,9 @@ public class CashierSupport {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public Boolean paymentResult(PayParam payParam) {
|
public Boolean paymentResult(PayParam payParam) {
|
||||||
for (CashierExecute cashierExecute : cashierExecuteList) {
|
PaymentMethodEnum paymentMethodEnum = PaymentMethodEnum.valueOf(payParam.getPaymentMethod());
|
||||||
if (cashierExecute.cashierEnum().name().equals(payParam.getOrderType())) {
|
Payment payment = (Payment) SpringUtils.getBean( paymentMethodEnum.getPlugin());
|
||||||
return cashierExecute.paymentResult(payParam);
|
payment.searchByOutTradeNo(payParam.getSn());
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -204,6 +202,8 @@ public class CashierSupport {
|
|||||||
paramInterface.paymentSuccess(payParam);
|
paramInterface.paymentSuccess(payParam);
|
||||||
log.info("订单编号{}支付成功", payParam.getReceivableNo());
|
log.info("订单编号{}支付成功", payParam.getReceivableNo());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -153,4 +153,13 @@ public interface Payment {
|
|||||||
return api + "/buyer/payment/cashierRefund/notify/" + paymentMethodEnum.name();
|
return api + "/buyer/payment/cashierRefund/notify/" + paymentMethodEnum.name();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 订单查询
|
||||||
|
*
|
||||||
|
* @param outTradeNo 订单编号
|
||||||
|
* @return 订单详情
|
||||||
|
*/
|
||||||
|
default R<Object> searchByOutTradeNo(String outTradeNo) {
|
||||||
|
throw new ServiceException(ResultCode.PAY_ERROR);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -124,7 +124,7 @@ public class WxPayKit {
|
|||||||
* @param params 需要签名的参数
|
* @param params 需要签名的参数
|
||||||
* @return 签名后的数据
|
* @return 签名后的数据
|
||||||
*/
|
*/
|
||||||
public static String createAppSign(Map<String, String> params, String privateKey) {
|
public static String createAppSign(Map<String, String> params, String keyPath) {
|
||||||
|
|
||||||
String appid = params.get("appid");
|
String appid = params.get("appid");
|
||||||
String timestamp = params.get("timestamp");
|
String timestamp = params.get("timestamp");
|
||||||
@ -134,7 +134,7 @@ public class WxPayKit {
|
|||||||
String encrypt = appid + "\n" + timestamp + "\n" + noncestr + "\n" + prepayid + "\n";
|
String encrypt = appid + "\n" + timestamp + "\n" + noncestr + "\n" + prepayid + "\n";
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return PayKit.createSign(encrypt, privateKey);
|
return PayKit.createSign(encrypt, keyPath);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new ServiceException(ResultCode.ERROR);
|
throw new ServiceException(ResultCode.ERROR);
|
||||||
}
|
}
|
||||||
@ -377,9 +377,9 @@ public class WxPayKit {
|
|||||||
if (signType == null) {
|
if (signType == null) {
|
||||||
signType = SignType.MD5;
|
signType = SignType.MD5;
|
||||||
}
|
}
|
||||||
String packageSign = createSign(packageParams, partnerKey, signType);
|
// String packageSign = createSign(packageParams, partnerKey, signType);
|
||||||
// 部分微信APP支付 提示签名错误 解开下方注释 替换上边的代码就好。
|
// 部分微信APP支付 提示签名错误 解开下方注释 替换上边的代码就好。
|
||||||
// String packageSign = createAppSign(packageParams, partnerKey);
|
String packageSign = createAppSign(packageParams, partnerKey);
|
||||||
packageParams.put("sign", packageSign);
|
packageParams.put("sign", packageSign);
|
||||||
return packageParams;
|
return packageParams;
|
||||||
}
|
}
|
||||||
|
@ -66,7 +66,7 @@ public class RechargeCashier implements CashierExecute {
|
|||||||
if (!recharge.getStatus().equals(ChargeStatus.WAITING.getCode())) {
|
if (!recharge.getStatus().equals(ChargeStatus.WAITING.getCode())) {
|
||||||
throw new ServiceException(ResultCode.PAY_DOUBLE_ERROR);
|
throw new ServiceException(ResultCode.PAY_DOUBLE_ERROR);
|
||||||
}
|
}
|
||||||
cashierParam.setPrice( recharge.getMoney().longValue());
|
cashierParam.setPrice( recharge.getMoney().multiply(BigDecimal.valueOf(100)).longValue());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
cashierParam.setTitle("在线充值");
|
cashierParam.setTitle("在线充值");
|
||||||
@ -75,6 +75,7 @@ public class RechargeCashier implements CashierExecute {
|
|||||||
}
|
}
|
||||||
cashierParam.setDetail("余额充值");
|
cashierParam.setDetail("余额充值");
|
||||||
cashierParam.setCreateTime(recharge.getCreateTime());
|
cashierParam.setCreateTime(recharge.getCreateTime());
|
||||||
|
cashierParam.setOrderSns(payParam.getSn());
|
||||||
return cashierParam;
|
return cashierParam;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,6 +29,7 @@ import com.wzj.soopin.transaction.service.PaymentService;
|
|||||||
import com.wzj.soopin.transaction.service.RefundLogService;
|
import com.wzj.soopin.transaction.service.RefundLogService;
|
||||||
import com.wzj.soopin.transaction.util.CurrencyUtil;
|
import com.wzj.soopin.transaction.util.CurrencyUtil;
|
||||||
import com.wzj.soopin.transaction.util.SnowFlake;
|
import com.wzj.soopin.transaction.util.SnowFlake;
|
||||||
|
import com.wzj.soopin.transaction.wechat.WXPayUtility;
|
||||||
import com.wzj.soopin.transaction.wechat.WechatPayConfig;
|
import com.wzj.soopin.transaction.wechat.WechatPayConfig;
|
||||||
import com.wzj.soopin.transaction.wechat.WechatPayException;
|
import com.wzj.soopin.transaction.wechat.WechatPayException;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
@ -255,7 +256,7 @@ public class WechatPlugin implements Payment {
|
|||||||
//支付金额
|
//支付金额
|
||||||
Integer fen = cashierParam.getPrice().intValue();
|
Integer fen = cashierParam.getPrice().intValue();
|
||||||
//第三方付款订单
|
//第三方付款订单
|
||||||
String outOrderNo = SnowFlake.getIdStr();
|
String outOrderNo = cashierParam.getOrderSns();
|
||||||
//过期时间
|
//过期时间
|
||||||
ZonedDateTime zonedDateTime = LocalDateTime.now().plusMinutes(3).atZone(ZoneId.of("UTC"));
|
ZonedDateTime zonedDateTime = LocalDateTime.now().plusMinutes(3).atZone(ZoneId.of("UTC"));
|
||||||
|
|
||||||
@ -263,9 +264,9 @@ public class WechatPlugin implements Payment {
|
|||||||
DateTimeFormatter rfc3339NoMillis = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssXXX");
|
DateTimeFormatter rfc3339NoMillis = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssXXX");
|
||||||
String timeExpire = zonedDateTime.format(rfc3339NoMillis);
|
String timeExpire = zonedDateTime.format(rfc3339NoMillis);
|
||||||
|
|
||||||
Map<String,String> attachMap=new HashMap<>();
|
Map<String, String> attachMap = new HashMap<>();
|
||||||
attachMap.put("orderType",payParam.getOrderType());
|
attachMap.put("orderType", payParam.getOrderType());
|
||||||
attachMap.put("outOrderNo",outOrderNo);
|
attachMap.put("outOrderNo", outOrderNo);
|
||||||
String attach = URLEncoder.createDefault().encode(JSONUtil.toJsonStr(attachMap), StandardCharsets.UTF_8);
|
String attach = URLEncoder.createDefault().encode(JSONUtil.toJsonStr(attachMap), StandardCharsets.UTF_8);
|
||||||
|
|
||||||
String appid = setting.getAppId();
|
String appid = setting.getAppId();
|
||||||
@ -273,26 +274,26 @@ public class WechatPlugin implements Payment {
|
|||||||
throw new ServiceException(ResultCode.WECHAT_PAYMENT_NOT_SETTING);
|
throw new ServiceException(ResultCode.WECHAT_PAYMENT_NOT_SETTING);
|
||||||
}
|
}
|
||||||
UnifiedOrderModel unifiedOrderModel = new UnifiedOrderModel()
|
UnifiedOrderModel unifiedOrderModel = new UnifiedOrderModel()
|
||||||
.setAppid(appid)
|
.setAppid(appid)
|
||||||
.setMchid(setting.getMchId())
|
.setMchid(setting.getMchId())
|
||||||
.setDescription(cashierParam.getDetail())
|
.setDescription(cashierParam.getDetail())
|
||||||
.setOut_trade_no(outOrderNo)
|
.setOut_trade_no(outOrderNo)
|
||||||
.setTime_expire(timeExpire)
|
.setTime_expire(timeExpire)
|
||||||
.setAttach(attach)
|
.setAttach(attach)
|
||||||
.setNotify_url("http://cjh.wuzhongjie.com.cn/app/payment/callback/"+PaymentMethodEnum.WECHAT)
|
.setNotify_url("http://cjh.wuzhongjie.com.cn/app/payment/callback/" + PaymentMethodEnum.WECHAT)
|
||||||
.setAmount(new Amount().setTotal(fen));
|
.setAmount(new Amount().setTotal(fen));
|
||||||
|
|
||||||
|
|
||||||
log.info("统一下单参数 {}", JSONUtil.toJsonStr(unifiedOrderModel));
|
log.info("统一下单参数 {}", JSONUtil.toJsonStr(unifiedOrderModel));
|
||||||
PaymentHttpResponse response = WechatApi.v3(
|
PaymentHttpResponse response = WechatApi.v3(
|
||||||
RequestMethodEnums.POST,
|
RequestMethodEnums.POST,
|
||||||
WechatDomain.CHINA.toString(),
|
WechatDomain.CHINA.toString(),
|
||||||
WechatApiEnum.APP_PAY.toString(),
|
WechatApiEnum.APP_PAY.toString(),
|
||||||
setting.getMchId(),
|
setting.getMchId(),
|
||||||
setting.getMchSerialNo(),
|
setting.getMchSerialNo(),
|
||||||
setting.getMchSerialNo(),
|
setting.getMchSerialNo(),
|
||||||
setting.getPrivateKeyPath() ,
|
setting.getPrivateKeyPath(),
|
||||||
JSONUtil.toJsonStr(unifiedOrderModel)
|
JSONUtil.toJsonStr(unifiedOrderModel)
|
||||||
|
|
||||||
);
|
);
|
||||||
//根据证书序列号查询对应的证书来验证签名结果
|
//根据证书序列号查询对应的证书来验证签名结果
|
||||||
@ -304,11 +305,15 @@ public class WechatPlugin implements Payment {
|
|||||||
JSONObject jsonObject = JSONUtil.parseObj(response.getBody());
|
JSONObject jsonObject = JSONUtil.parseObj(response.getBody());
|
||||||
String prepayId = jsonObject.getStr("prepay_id");
|
String prepayId = jsonObject.getStr("prepay_id");
|
||||||
Map<String, String> map = WxPayKit.appPrepayIdCreateSign(appid,
|
Map<String, String> map = WxPayKit.appPrepayIdCreateSign(appid,
|
||||||
setting.getMchId(),
|
setting.getMchId(),
|
||||||
prepayId,
|
prepayId,
|
||||||
setting.getApiclient_key(), SignType.HMACSHA256);
|
setting.getPrivateKeyPath(), SignType.HMACSHA256);
|
||||||
log.info("唤起支付参数:{}", map);
|
log.info("唤起支付参数:{}", map);
|
||||||
|
|
||||||
|
|
||||||
|
//更新订单的prepayId
|
||||||
|
|
||||||
|
|
||||||
return R.ok(map);
|
return R.ok(map);
|
||||||
}
|
}
|
||||||
log.error("微信支付参数验证错误,请及时处理");
|
log.error("微信支付参数验证错误,请及时处理");
|
||||||
@ -499,7 +504,7 @@ public class WechatPlugin implements Payment {
|
|||||||
|
|
||||||
//校验服务器端响应¬7
|
//校验服务器端响应¬7
|
||||||
String plainText = WxPayKit.verifyNotify(serialNo, result, signature, nonce, timestamp,
|
String plainText = WxPayKit.verifyNotify(serialNo, result, signature, nonce, timestamp,
|
||||||
setting.getApiV3Key(), Objects.requireNonNull(getPlatformCert()));
|
setting.getApiV3Key(), Objects.requireNonNull(getPlatformCert()));
|
||||||
|
|
||||||
log.info("微信支付通知明文 {}", plainText);
|
log.info("微信支付通知明文 {}", plainText);
|
||||||
|
|
||||||
@ -513,16 +518,81 @@ public class WechatPlugin implements Payment {
|
|||||||
// Double totalAmount = CurrencyUtil.reversalFen(jsonObject.getJSONObject("amount").getDouble("total"));
|
// Double totalAmount = CurrencyUtil.reversalFen(jsonObject.getJSONObject("amount").getDouble("total"));
|
||||||
|
|
||||||
PaymentSuccessParams paymentSuccessParams = new PaymentSuccessParams(
|
PaymentSuccessParams paymentSuccessParams = new PaymentSuccessParams(
|
||||||
PaymentMethodEnum.WECHAT.getCode(),
|
PaymentMethodEnum.WECHAT.getCode(),
|
||||||
tradeNo,
|
tradeNo,
|
||||||
0d,
|
0d,
|
||||||
payParam
|
payParam
|
||||||
);
|
);
|
||||||
|
|
||||||
cashierSupport.paymentSuccess(paymentSuccessParams);
|
cashierSupport.paymentSuccess(paymentSuccessParams);
|
||||||
log.info("微信支付回调:支付成功{}", plainText);
|
log.info("微信支付回调:支付成功{}", plainText);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public R searchByOutTradeNo(String outTradeNo) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
|
||||||
|
String appid = setting.getAppId();
|
||||||
|
if (appid == null) {
|
||||||
|
throw new ServiceException(ResultCode.WECHAT_PAYMENT_NOT_SETTING);
|
||||||
|
}
|
||||||
|
UnifiedOrderModel unifiedOrderModel = new UnifiedOrderModel()
|
||||||
|
.setAppid(appid)
|
||||||
|
.setMchid(setting.getMchId())
|
||||||
|
.setOut_trade_no(outTradeNo);
|
||||||
|
String uri = WechatApiEnum.ORDER_QUERY_BY_NO.toString().formatted(outTradeNo);
|
||||||
|
Map<String, String> args = new HashMap<>();
|
||||||
|
args.put("mchid", setting.getMchId());
|
||||||
|
|
||||||
|
|
||||||
|
log.info("统一下单参数 {}", JSONUtil.toJsonStr(unifiedOrderModel));
|
||||||
|
PaymentHttpResponse response = WechatApi.v3(
|
||||||
|
RequestMethodEnums.GET,
|
||||||
|
WechatDomain.CHINA.toString(),
|
||||||
|
uri,
|
||||||
|
setting.getMchId(),
|
||||||
|
setting.getMchSerialNo(),
|
||||||
|
setting.getMchSerialNo(),
|
||||||
|
setting.getPrivateKeyPath(),
|
||||||
|
args
|
||||||
|
);
|
||||||
|
//根据证书序列号查询对应的证书来验证签名结果
|
||||||
|
boolean verifySignature = WxPayKit.verifySignature(response, getPlatformCert());
|
||||||
|
log.info("verifySignature: {}", verifySignature);
|
||||||
|
log.info("统一下单响应 {}", response);
|
||||||
|
|
||||||
|
if (verifySignature) {
|
||||||
|
JSONObject jsonObject = JSONUtil.parseObj(response.getBody());
|
||||||
|
String tradeState = jsonObject.getStr("trade_state");
|
||||||
|
if (tradeState.equals("SUCCESS")) {
|
||||||
|
String payParamStr = jsonObject.getStr("attach");
|
||||||
|
String payParamJson = URLDecoder.decode(payParamStr, StandardCharsets.UTF_8);
|
||||||
|
PayParam payParam = JSONUtil.toBean(payParamJson, PayParam.class);
|
||||||
|
|
||||||
|
String tradeNo = jsonObject.getStr("transaction_id");
|
||||||
|
PaymentSuccessParams paymentSuccessParams = new PaymentSuccessParams(
|
||||||
|
PaymentMethodEnum.WECHAT.getCode(),
|
||||||
|
tradeNo,
|
||||||
|
0d,
|
||||||
|
payParam
|
||||||
|
);
|
||||||
|
|
||||||
|
cashierSupport.paymentSuccess(paymentSuccessParams);
|
||||||
|
}
|
||||||
|
return R.ok();
|
||||||
|
}
|
||||||
|
log.error("微信支付参数验证错误,请及时处理");
|
||||||
|
throw new ServiceException(ResultCode.PAY_ERROR);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("微信退款申请失败", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return R.ok();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void refund(RefundLog refundLog) {
|
public void refund(RefundLog refundLog) {
|
||||||
|
|
||||||
@ -654,14 +724,14 @@ public class WechatPlugin implements Payment {
|
|||||||
|
|
||||||
|
|
||||||
PaymentHttpResponse response = WechatApi.v3(
|
PaymentHttpResponse response = WechatApi.v3(
|
||||||
RequestMethodEnums.GET,
|
RequestMethodEnums.GET,
|
||||||
WechatDomain.CHINA.toString(),
|
WechatDomain.CHINA.toString(),
|
||||||
WechatApiEnum.GET_CERTIFICATES.toString(),
|
WechatApiEnum.GET_CERTIFICATES.toString(),
|
||||||
setting.getMchId(),
|
setting.getMchId(),
|
||||||
setting.getMchSerialNo(),
|
setting.getMchSerialNo(),
|
||||||
null,
|
null,
|
||||||
setting.getPrivateKeyPath(),
|
setting.getPrivateKeyPath(),
|
||||||
""
|
""
|
||||||
);
|
);
|
||||||
String body = response.getBody();
|
String body = response.getBody();
|
||||||
log.info("获取微信平台证书body: {}", body);
|
log.info("获取微信平台证书body: {}", body);
|
||||||
@ -708,10 +778,13 @@ public class WechatPlugin implements Payment {
|
|||||||
//平台证书密文解密
|
//平台证书密文解密
|
||||||
//encrypt_certificate 中的 associated_data nonce ciphertext
|
//encrypt_certificate 中的 associated_data nonce ciphertext
|
||||||
return aesUtil.decryptToString(
|
return aesUtil.decryptToString(
|
||||||
associatedData.getBytes(StandardCharsets.UTF_8),
|
associatedData.getBytes(StandardCharsets.UTF_8),
|
||||||
nonce.getBytes(StandardCharsets.UTF_8),
|
nonce.getBytes(StandardCharsets.UTF_8),
|
||||||
cipherText
|
cipherText
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package com.wzj.soopin.order.service;
|
package com.wzj.soopin.transaction.service;
|
||||||
|
|
||||||
import com.wzj.soopin.order.domain.query.GrabRedPacketRequest;
|
import com.wzj.soopin.order.domain.query.GrabRedPacketRequest;
|
||||||
import com.wzj.soopin.order.domain.query.SendRedPacketRequest;
|
import com.wzj.soopin.order.domain.query.SendRedPacketRequest;
|
@ -76,10 +76,7 @@ public class AccountBillServiceImpl extends
|
|||||||
if (memberAccount == null) {
|
if (memberAccount == null) {
|
||||||
throw new RuntimeException("用户不存在");
|
throw new RuntimeException("用户不存在");
|
||||||
}
|
}
|
||||||
//检查当前用于的账户余额是否充足
|
|
||||||
BigDecimal balance = memberAccount.getWallet();
|
BigDecimal balance = memberAccount.getWallet();
|
||||||
|
|
||||||
|
|
||||||
BigDecimal newBalance = balance.add(money);
|
BigDecimal newBalance = balance.add(money);
|
||||||
//锁定用户余额
|
//锁定用户余额
|
||||||
memberAccountService.updateById(memberAccount.toBuilder().wallet(newBalance).build());
|
memberAccountService.updateById(memberAccount.toBuilder().wallet(newBalance).build());
|
||||||
|
@ -97,9 +97,13 @@ public class ChargeServiceImpl extends ServiceImpl<ChargeMapper, Charge> impleme
|
|||||||
log.error("充值记录不存在,code:{}",code);
|
log.error("充值记录不存在,code:{}",code);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
charge.setStatus(ChargeStatus.PENDING.getCode());
|
charge.setStatus(ChargeStatus.SUCCESS.getCode());
|
||||||
// charge.setPayNo(payNo);
|
charge.setPayNo(payNo);
|
||||||
charge.setMethod(method);
|
charge.setMethod(method);
|
||||||
return updateById(charge);
|
boolean result= updateById(charge);
|
||||||
|
if (result){
|
||||||
|
accountBillService.addMoney(charge.getActualMoney(),charge.getMemberId(),AccountBillSourceEnum.RECHARGE,"充值");
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
package com.wzj.soopin.order.service.impl;
|
package com.wzj.soopin.transaction.service.impl;
|
||||||
|
|
||||||
import cn.hutool.core.date.DateTime;
|
import cn.hutool.core.date.DateTime;
|
||||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
import com.wzj.soopin.member.domain.po.AccountBill;
|
|
||||||
import com.wzj.soopin.member.enums.AccountBillChangeTypeEnum;
|
|
||||||
import com.wzj.soopin.member.enums.AccountBillSourceEnum;
|
import com.wzj.soopin.member.enums.AccountBillSourceEnum;
|
||||||
import com.wzj.soopin.member.mapper.MemberAccountMapper;
|
import com.wzj.soopin.member.mapper.MemberAccountMapper;
|
||||||
import com.wzj.soopin.order.domain.entity.RedPacket;
|
import com.wzj.soopin.order.domain.entity.RedPacket;
|
||||||
@ -12,18 +10,23 @@ import com.wzj.soopin.order.domain.query.GrabRedPacketRequest;
|
|||||||
import com.wzj.soopin.order.domain.query.SendRedPacketRequest;
|
import com.wzj.soopin.order.domain.query.SendRedPacketRequest;
|
||||||
import com.wzj.soopin.order.mapper.RedPacketMapper;
|
import com.wzj.soopin.order.mapper.RedPacketMapper;
|
||||||
import com.wzj.soopin.order.mapper.RedPacketReceiveMapper;
|
import com.wzj.soopin.order.mapper.RedPacketReceiveMapper;
|
||||||
import com.wzj.soopin.order.service.RedPacketService;
|
import com.wzj.soopin.transaction.service.IAccountBillService;
|
||||||
|
import com.wzj.soopin.transaction.service.RedPacketService;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.dromara.common.core.exception.ServiceException;
|
||||||
|
import org.dromara.common.core.exception.base.BaseException;
|
||||||
import org.springframework.data.redis.core.RedisTemplate;
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
import org.springframework.scheduling.annotation.Scheduled;
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
import java.math.RoundingMode;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Random;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@ -35,6 +38,8 @@ public class RedPacketServiceImpl extends ServiceImpl<RedPacketMapper, RedPacket
|
|||||||
private final MemberAccountMapper umsAccountMapper;
|
private final MemberAccountMapper umsAccountMapper;
|
||||||
private final RedisTemplate<String, Object> redisTemplate;
|
private final RedisTemplate<String, Object> redisTemplate;
|
||||||
|
|
||||||
|
private final IAccountBillService accountBillService;
|
||||||
|
|
||||||
// Redis锁前缀
|
// Redis锁前缀
|
||||||
private static final String LOCK_PREFIX = "red_packet:lock:";
|
private static final String LOCK_PREFIX = "red_packet:lock:";
|
||||||
|
|
||||||
@ -68,9 +73,8 @@ public class RedPacketServiceImpl extends ServiceImpl<RedPacketMapper, RedPacket
|
|||||||
RedPacket redPacket = createRedPacket(request);
|
RedPacket redPacket = createRedPacket(request);
|
||||||
redPacketMapper.insert(redPacket);
|
redPacketMapper.insert(redPacket);
|
||||||
Long packetId = redPacket.getId();
|
Long packetId = redPacket.getId();
|
||||||
|
|
||||||
// 扣减发送者余额并记录变动
|
// 扣减发送者余额并记录变动
|
||||||
deductSenderBalance(request.getSenderId(), redPacket, balance);
|
accountBillService.reduceMoney(balance, memberId, AccountBillSourceEnum.RED_PACKAGE_SEND, "红包发放");
|
||||||
|
|
||||||
// 返回结果
|
// 返回结果
|
||||||
Map<String, Object> result = new HashMap<>();
|
Map<String, Object> result = new HashMap<>();
|
||||||
@ -108,17 +112,17 @@ public class RedPacketServiceImpl extends ServiceImpl<RedPacketMapper, RedPacket
|
|||||||
// 查询红包信息
|
// 查询红包信息
|
||||||
RedPacket redPacket = redPacketMapper.selectById(packetId);
|
RedPacket redPacket = redPacketMapper.selectById(packetId);
|
||||||
if (redPacket == null) {
|
if (redPacket == null) {
|
||||||
throw new RuntimeException("红包不存在");
|
throw new BaseException("红包不存在");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 验证红包状态
|
// 验证红包状态
|
||||||
validateRedPacketStatus(redPacket, memberId);
|
validateRedPacketStatus(redPacket, memberId);
|
||||||
|
|
||||||
// 检查是否已领取
|
// 检查是否已领取
|
||||||
Integer received = redPacketReceiveMapper.checkReceived(packetId, memberId);
|
// Integer received = redPacketReceiveMapper.checkReceived(packetId, memberId);
|
||||||
if (received != null && received > 0) {
|
// if (received != null && received > 0) {
|
||||||
throw new RuntimeException("您已领取过该红包");
|
// throw new ServiceException("您已领取过该红包");
|
||||||
}
|
// }
|
||||||
|
|
||||||
// 计算领取金额
|
// 计算领取金额
|
||||||
BigDecimal receiveAmount = calculateReceiveAmount(redPacket);
|
BigDecimal receiveAmount = calculateReceiveAmount(redPacket);
|
||||||
@ -131,7 +135,7 @@ public class RedPacketServiceImpl extends ServiceImpl<RedPacketMapper, RedPacket
|
|||||||
redPacketReceiveMapper.insert(receiveRecord);
|
redPacketReceiveMapper.insert(receiveRecord);
|
||||||
|
|
||||||
// 增加领取者余额并记录变动
|
// 增加领取者余额并记录变动
|
||||||
addReceiverBalance(memberId, receiveAmount, packetId);
|
accountBillService.addMoney(receiveAmount, memberId, AccountBillSourceEnum.RED_PACKAGE_RECEIVE, "红包领取");
|
||||||
|
|
||||||
// 更新红包状态
|
// 更新红包状态
|
||||||
updateRedPacketStatus(redPacket);
|
updateRedPacketStatus(redPacket);
|
||||||
@ -179,7 +183,7 @@ public class RedPacketServiceImpl extends ServiceImpl<RedPacketMapper, RedPacket
|
|||||||
redPacket.setReceiverId(request.getReceiverId());
|
redPacket.setReceiverId(request.getReceiverId());
|
||||||
redPacket.setGroupId(request.getGroupId());
|
redPacket.setGroupId(request.getGroupId());
|
||||||
// 默认为普通红包
|
// 默认为普通红包
|
||||||
redPacket.setPacketType(1);
|
redPacket.setPacketType(redPacket.getPacketType());
|
||||||
redPacket.setTotalAmount(request.getTotalAmount());
|
redPacket.setTotalAmount(request.getTotalAmount());
|
||||||
redPacket.setTotalCount(request.getTotalCount());
|
redPacket.setTotalCount(request.getTotalCount());
|
||||||
redPacket.setRemainingAmount(request.getTotalAmount());
|
redPacket.setRemainingAmount(request.getTotalAmount());
|
||||||
@ -193,28 +197,6 @@ public class RedPacketServiceImpl extends ServiceImpl<RedPacketMapper, RedPacket
|
|||||||
return redPacket;
|
return redPacket;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 扣减发送者余额并记录变动
|
|
||||||
*/
|
|
||||||
private void deductSenderBalance(Long senderId, RedPacket redPacket, BigDecimal beforeBalance) {
|
|
||||||
// 计算扣减后的余额
|
|
||||||
BigDecimal afterBalance = beforeBalance.subtract(redPacket.getTotalAmount());
|
|
||||||
umsAccountMapper.updateMoneyBalance(senderId, afterBalance);
|
|
||||||
|
|
||||||
// 记录金额变动
|
|
||||||
// AccountBill record = AccountBill.builder()
|
|
||||||
// .moneyBalance(beforeBalance)
|
|
||||||
// .accountId(senderId)
|
|
||||||
// .beforeBalance(beforeBalance)
|
|
||||||
// .afterBalance(afterBalance)
|
|
||||||
// .changeAmount(redPacket.getTotalAmount())
|
|
||||||
// .changeType(AccountBillChangeTypeEnum.OUT.getCode())
|
|
||||||
// .source(AccountBillSourceEnum.RED_PACKAGE_SEND.getCode())
|
|
||||||
// .changeDesc("发送红包扣减,红包ID:" + redPacket.getId())
|
|
||||||
// .build();
|
|
||||||
//
|
|
||||||
// accountChangeRecordMapper.insert(record);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 验证红包状态
|
* 验证红包状态
|
||||||
@ -227,24 +209,24 @@ public class RedPacketServiceImpl extends ServiceImpl<RedPacketMapper, RedPacket
|
|||||||
} else {
|
} else {
|
||||||
redPacket.setStatus(STATUS_EXPIRED);
|
redPacket.setStatus(STATUS_EXPIRED);
|
||||||
redPacketMapper.updateById(redPacket);
|
redPacketMapper.updateById(redPacket);
|
||||||
throw new RuntimeException("红包已过期");
|
throw new BaseException("红包已过期");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查是否已领完
|
// 检查是否已领完
|
||||||
if (redPacket.getStatus() == STATUS_ALL_RECEIVED) {
|
if (redPacket.getStatus() == STATUS_ALL_RECEIVED) {
|
||||||
throw new RuntimeException("红包已被领完");
|
throw new BaseException("红包已被领完");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查是否是自己发的红包
|
// 检查是否是自己发的红包
|
||||||
if (redPacket.getSenderId().equals(memberId)) {
|
// if (redPacket.getSenderId().equals(memberId)) {
|
||||||
throw new RuntimeException("不能领取自己发送的红包");
|
// throw new RuntimeException("不能领取自己发送的红包");
|
||||||
}
|
// }
|
||||||
|
|
||||||
// 单聊红包只能指定接收者领取
|
// 单聊红包只能指定接收者领取
|
||||||
if (redPacket.getChatType() == CHAT_TYPE_SINGLE &&
|
if (redPacket.getChatType() == CHAT_TYPE_SINGLE &&
|
||||||
!redPacket.getReceiverId().equals(memberId)) {
|
!redPacket.getReceiverId().equals(memberId)) {
|
||||||
throw new RuntimeException("您无权领取该红包");
|
throw new BaseException("您无权领取该红包");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -258,25 +240,9 @@ public class RedPacketServiceImpl extends ServiceImpl<RedPacketMapper, RedPacket
|
|||||||
// 查询当前余额
|
// 查询当前余额
|
||||||
BigDecimal beforeBalance = umsAccountMapper.getMoneyBalanceByMemberId(senderId);
|
BigDecimal beforeBalance = umsAccountMapper.getMoneyBalanceByMemberId(senderId);
|
||||||
if (beforeBalance == null) {
|
if (beforeBalance == null) {
|
||||||
throw new RuntimeException("发送者账户不存在");
|
throw new BaseException("发送者账户不存在");
|
||||||
}
|
}
|
||||||
|
accountBillService.addMoney(remainingAmount, senderId, AccountBillSourceEnum.RED_PACKAGE_REFUND, "红包退回");
|
||||||
// 增加余额
|
|
||||||
BigDecimal afterBalance = beforeBalance.add(remainingAmount);
|
|
||||||
umsAccountMapper.updateMoneyBalance(senderId, afterBalance);
|
|
||||||
|
|
||||||
// // 记录金额变动
|
|
||||||
// AccountBill record = AccountBill.builder()
|
|
||||||
// .accountId(senderId)
|
|
||||||
// .beforeBalance(beforeBalance)
|
|
||||||
// .afterBalance(afterBalance)
|
|
||||||
// .changeAmount(remainingAmount)
|
|
||||||
// .changeType(AccountBillChangeTypeEnum.IN.getCode())
|
|
||||||
// .source(AccountBillSourceEnum.RED_PACKAGE_REFUND.getCode())
|
|
||||||
// .changeDesc("红包退款,红包ID:" + redPacket.getId())
|
|
||||||
// .build();
|
|
||||||
//
|
|
||||||
// accountChangeRecordMapper.insert(record);
|
|
||||||
|
|
||||||
// 更新红包状态为已退款
|
// 更新红包状态为已退款
|
||||||
redPacket.setStatus(STATUS_REFUNDED);
|
redPacket.setStatus(STATUS_REFUNDED);
|
||||||
@ -295,11 +261,16 @@ public class RedPacketServiceImpl extends ServiceImpl<RedPacketMapper, RedPacket
|
|||||||
// 最后一个红包,领取全部剩余金额
|
// 最后一个红包,领取全部剩余金额
|
||||||
return remainingAmount;
|
return remainingAmount;
|
||||||
}
|
}
|
||||||
BigDecimal minAmount = new BigDecimal("0.01");
|
int fenAmount = remainingAmount.multiply(new BigDecimal("100")).intValue();
|
||||||
BigDecimal maxAmount = remainingAmount.subtract(new BigDecimal(remainingCount - 1).multiply(minAmount));
|
|
||||||
BigDecimal randomAmount = minAmount.add(new BigDecimal(Math.random() * maxAmount.doubleValue())).setScale(2, BigDecimal.ROUND_HALF_UP);
|
|
||||||
|
|
||||||
return randomAmount;
|
Random random = new Random();
|
||||||
|
// 4. 分配前 count-1 个红包
|
||||||
|
// 最大可分配金额:剩余金额/剩余数量×2(确保后续每人至少1分)
|
||||||
|
int max = (fenAmount / remainingCount) * 2;
|
||||||
|
// 随机金额:[1, max]
|
||||||
|
int money = random.nextInt(max) + 1;
|
||||||
|
// 累加结果,更新剩余
|
||||||
|
return new BigDecimal(money / 100.0).setScale(2, RoundingMode.HALF_UP);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -323,33 +294,6 @@ public class RedPacketServiceImpl extends ServiceImpl<RedPacketMapper, RedPacket
|
|||||||
return record;
|
return record;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 增加领取者余额并记录变动
|
|
||||||
*/
|
|
||||||
private void addReceiverBalance(Long memberId, BigDecimal amount, Long packetId) {
|
|
||||||
// 查询当前余额
|
|
||||||
BigDecimal beforeBalance = umsAccountMapper.getMoneyBalanceByMemberId(memberId);
|
|
||||||
if (beforeBalance == null) {
|
|
||||||
throw new RuntimeException("领取者账户不存在");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 增加余额
|
|
||||||
BigDecimal afterBalance = beforeBalance.add(amount);
|
|
||||||
umsAccountMapper.updateMoneyBalance(memberId, afterBalance);
|
|
||||||
|
|
||||||
// // 记录金额变动
|
|
||||||
// AccountBill record = AccountBill.builder()
|
|
||||||
// .accountId(memberId)
|
|
||||||
// .beforeBalance(beforeBalance)
|
|
||||||
// .afterBalance(afterBalance)
|
|
||||||
// .changeAmount(amount)
|
|
||||||
// .changeType(AccountBillChangeTypeEnum.IN.getCode())
|
|
||||||
// .source(AccountBillSourceEnum.RED_PACKAGE_RECEIVE.getCode())
|
|
||||||
// .changeDesc("红包领取,红包ID:" + packetId)
|
|
||||||
// .build();
|
|
||||||
//
|
|
||||||
// accountChangeRecordMapper.insert(record);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新红包状态
|
* 更新红包状态
|
@ -1,22 +1,28 @@
|
|||||||
package com.wzj.soopin.transaction.service.impl;
|
package com.wzj.soopin.transaction.service.impl;
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import com.wzj.soopin.member.domain.po.Member;
|
||||||
import com.wzj.soopin.transaction.domain.bo.WithdrawBO;
|
import com.wzj.soopin.transaction.domain.bo.WithdrawBO;
|
||||||
import com.wzj.soopin.member.domain.po.MemberAccount;
|
import com.wzj.soopin.member.domain.po.MemberAccount;
|
||||||
import com.wzj.soopin.member.domain.po.AccountBill;
|
import com.wzj.soopin.member.domain.po.AccountBill;
|
||||||
|
import com.wzj.soopin.transaction.domain.entity.InitiateBatchTransferRequestNew;
|
||||||
|
import com.wzj.soopin.transaction.domain.entity.TransferSceneReportInfoNew;
|
||||||
import com.wzj.soopin.transaction.domain.po.Withdraw;
|
import com.wzj.soopin.transaction.domain.po.Withdraw;
|
||||||
import com.wzj.soopin.member.enums.AccountBillChangeTypeEnum;
|
import com.wzj.soopin.member.enums.AccountBillChangeTypeEnum;
|
||||||
import com.wzj.soopin.member.enums.AccountBillSourceEnum;
|
import com.wzj.soopin.member.enums.AccountBillSourceEnum;
|
||||||
import com.wzj.soopin.transaction.enums.WithdrawAuditStatus;
|
import com.wzj.soopin.transaction.enums.WithdrawAuditStatus;
|
||||||
import com.wzj.soopin.transaction.enums.WithdrawStatus;
|
import com.wzj.soopin.transaction.enums.WithdrawStatus;
|
||||||
|
import com.wzj.soopin.transaction.enums.WithdrawType;
|
||||||
import com.wzj.soopin.transaction.mapper.WithdrawMapper;
|
import com.wzj.soopin.transaction.mapper.WithdrawMapper;
|
||||||
import com.wzj.soopin.member.service.*;
|
import com.wzj.soopin.member.service.*;
|
||||||
import com.wzj.soopin.transaction.domain.vo.EasypayAccountVO;
|
import com.wzj.soopin.transaction.domain.vo.EasypayAccountVO;
|
||||||
import com.wzj.soopin.transaction.service.IAccountBillService;
|
import com.wzj.soopin.transaction.service.IAccountBillService;
|
||||||
import com.wzj.soopin.transaction.service.IWithdrawService;
|
import com.wzj.soopin.transaction.service.IWithdrawService;
|
||||||
import com.wzj.soopin.transaction.service.IEasypayService;
|
import com.wzj.soopin.transaction.service.IEasypayService;
|
||||||
|
import com.wzj.soopin.transaction.wechat.WechatPayConfig;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.dromara.common.core.exception.ServiceException;
|
||||||
import org.dromara.common.satoken.utils.LoginHelper;
|
import org.dromara.common.satoken.utils.LoginHelper;
|
||||||
import org.dromara.system.domain.SysTenantAccount;
|
import org.dromara.system.domain.SysTenantAccount;
|
||||||
import org.dromara.system.service.ISysTenantAccountService;
|
import org.dromara.system.service.ISysTenantAccountService;
|
||||||
@ -24,6 +30,8 @@ import org.springframework.stereotype.Service;
|
|||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -48,6 +56,10 @@ public class WithdrawServiceImpl extends ServiceImpl<WithdrawMapper, Withdraw> i
|
|||||||
|
|
||||||
private final IAccountBillService accountBillService;
|
private final IAccountBillService accountBillService;
|
||||||
|
|
||||||
|
private final WxPayService wxPayService;
|
||||||
|
|
||||||
|
private final IMemberService memberService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean audit(WithdrawBO bo) {
|
public boolean audit(WithdrawBO bo) {
|
||||||
Withdraw withdraw = getById(bo.getId());
|
Withdraw withdraw = getById(bo.getId());
|
||||||
@ -58,9 +70,12 @@ public class WithdrawServiceImpl extends ServiceImpl<WithdrawMapper, Withdraw> i
|
|||||||
throw new RuntimeException("提现申请已处理");
|
throw new RuntimeException("提现申请已处理");
|
||||||
}
|
}
|
||||||
//发起提现
|
//发起提现
|
||||||
boolean chargeSuccess = easypayService.withdraw(withdraw.getMemberId(), withdraw.getMoney());
|
|
||||||
if (!chargeSuccess) {
|
try{
|
||||||
throw new RuntimeException("提现失败");
|
wxPayService.initiateBatchTransferNew(buildWechatPayParam(bo));
|
||||||
|
}catch (ServiceException e){
|
||||||
|
log.error("提现申请失败",e);
|
||||||
|
throw new RuntimeException("提现申请失败");
|
||||||
}
|
}
|
||||||
withdraw = Withdraw.builder().id(bo.getId())
|
withdraw = Withdraw.builder().id(bo.getId())
|
||||||
.auditReason(bo.getAuditReason())
|
.auditReason(bo.getAuditReason())
|
||||||
@ -72,6 +87,43 @@ public class WithdrawServiceImpl extends ServiceImpl<WithdrawMapper, Withdraw> i
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private InitiateBatchTransferRequestNew buildWechatPayParam(WithdrawBO withdraw) {
|
||||||
|
InitiateBatchTransferRequestNew request = new InitiateBatchTransferRequestNew();
|
||||||
|
WechatPayConfig wechatPayConfig = new WechatPayConfig();
|
||||||
|
//商户AppID
|
||||||
|
request.setAppid(wechatPayConfig.getAppId());
|
||||||
|
//商户单号
|
||||||
|
request.setOutBillNo(withdraw.getCode());
|
||||||
|
request.setTransferAmount(withdraw.getMoney().multiply(BigDecimal.valueOf(100)).intValue());
|
||||||
|
//转账场景ID
|
||||||
|
// /** 转账场景ID 说明:该批次转账使用的转账场景,如不填写则使用商家的默认场景,如无默认场景可为空,可前往“商家转账到零钱-前往功能”中申请。 如:1001-现金营销 */
|
||||||
|
request.setTransferSceneId("1005");
|
||||||
|
//用户的openId
|
||||||
|
Member member=memberService.getById(withdraw.getMemberId());
|
||||||
|
request.setOpenid(member.getOpenId());
|
||||||
|
//收款用户姓名
|
||||||
|
request.setUserName(member.getNickname());
|
||||||
|
//转账备注
|
||||||
|
request.setTransferRemark("提现");
|
||||||
|
//转账场景报备信息 佣金的固定类型
|
||||||
|
List<TransferSceneReportInfoNew> transferDetailList = new ArrayList<>();
|
||||||
|
TransferSceneReportInfoNew transferSceneReportInfoNew = new TransferSceneReportInfoNew();
|
||||||
|
transferSceneReportInfoNew.setInfoType("岗位类型");
|
||||||
|
transferSceneReportInfoNew.setInfoContent("代理人");
|
||||||
|
transferDetailList.add(transferSceneReportInfoNew);
|
||||||
|
TransferSceneReportInfoNew transferSceneReportInfoNew1 = new TransferSceneReportInfoNew();
|
||||||
|
transferSceneReportInfoNew1.setInfoType("报酬说明");
|
||||||
|
transferSceneReportInfoNew1.setInfoContent("手续费");
|
||||||
|
transferDetailList.add(transferSceneReportInfoNew1);
|
||||||
|
request.setTransferSceneReportInfos(transferDetailList);
|
||||||
|
//异步接收微信支付结果通知的回调地址,通知url必须为公网可访问的URL,必须为HTTPS,不能携带参数
|
||||||
|
// 注意:此处需要填写公网可访问的服务器地址,不能携带任何参数
|
||||||
|
request.setNotifyUrl(wechatPayConfig.getTransferNotifyUrl());
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean withdrawCallback(WithdrawBO withdraw) {
|
public boolean withdrawCallback(WithdrawBO withdraw) {
|
||||||
MemberAccount memberAccount = memberAccountService.getMemberAccount(withdraw.getMemberId());
|
MemberAccount memberAccount = memberAccountService.getMemberAccount(withdraw.getMemberId());
|
||||||
|
@ -42,6 +42,8 @@ public class WxPayService {
|
|||||||
private static final Logger logger = LoggerFactory.getLogger(WxPayService.class);
|
private static final Logger logger = LoggerFactory.getLogger(WxPayService.class);
|
||||||
@Autowired
|
@Autowired
|
||||||
private WechatPayConfig WechatPayConfig;
|
private WechatPayConfig WechatPayConfig;
|
||||||
|
@Autowired
|
||||||
|
private RSAAutoCertificateConfig wxPayConfig;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 商家转账 - 发起转账 - 2025年1月15号之后,商户转账零线必须用户确认收款
|
* 商家转账 - 发起转账 - 2025年1月15号之后,商户转账零线必须用户确认收款
|
||||||
@ -51,30 +53,32 @@ public class WxPayService {
|
|||||||
*/
|
*/
|
||||||
public InitiateBatchTransferResponseNew initiateBatchTransferNew(InitiateBatchTransferRequestNew request) {
|
public InitiateBatchTransferResponseNew initiateBatchTransferNew(InitiateBatchTransferRequestNew request) {
|
||||||
logger.info("WxPayService.initiateBatchTransferNew request:{}", request.toString());
|
logger.info("WxPayService.initiateBatchTransferNew request:{}", request.toString());
|
||||||
Config config = new RSAAutoCertificateConfig.Builder()
|
try{
|
||||||
.merchantId(WechatPayConfig.getMchId())
|
|
||||||
.privateKeyFromPath(WechatPayConfig.getPrivateKeyPath())
|
String encryptName = wxPayConfig.createEncryptor().encrypt(request.getUserName());
|
||||||
.merchantSerialNumber(WechatPayConfig.getMchSerialNo())
|
request.setUserName(encryptName);
|
||||||
.apiV3Key(WechatPayConfig.getApiV3Key())
|
String requestPath = "https://api.mch.weixin.qq.com/v3/fund-app/mch-transfer/transfer-bills";
|
||||||
.build();
|
HttpHeaders headers = new HttpHeaders();
|
||||||
String encryptName = config.createEncryptor().encrypt(request.getUserName());
|
headers.addHeader("Accept", MediaType.APPLICATION_JSON.getValue());
|
||||||
request.setUserName(encryptName);
|
headers.addHeader("Content-Type", MediaType.APPLICATION_JSON.getValue());
|
||||||
String requestPath = "https://api.mch.weixin.qq.com/v3/fund-app/mch-transfer/transfer-bills";
|
headers.addHeader("Wechatpay-Serial", wxPayConfig.createEncryptor().getWechatpaySerial());
|
||||||
HttpHeaders headers = new HttpHeaders();
|
HttpRequest httpRequest =
|
||||||
headers.addHeader("Accept", MediaType.APPLICATION_JSON.getValue());
|
|
||||||
headers.addHeader("Content-Type", MediaType.APPLICATION_JSON.getValue());
|
|
||||||
headers.addHeader("Wechatpay-Serial", config.createEncryptor().getWechatpaySerial());
|
|
||||||
HttpRequest httpRequest =
|
|
||||||
new HttpRequest.Builder()
|
new HttpRequest.Builder()
|
||||||
.httpMethod(HttpMethod.POST)
|
.httpMethod(HttpMethod.POST)
|
||||||
.url(requestPath)
|
.url(requestPath)
|
||||||
.headers(headers)
|
.headers(headers)
|
||||||
.body(createRequestBody(request))
|
.body(createRequestBody(request))
|
||||||
.build();
|
.build();
|
||||||
HttpClient httpClient = new DefaultHttpClientBuilder().config(config).build();
|
HttpClient httpClient = new DefaultHttpClientBuilder().config(wxPayConfig).build();
|
||||||
HttpResponse<InitiateBatchTransferResponseNew> httpResponse = httpClient.execute(httpRequest, InitiateBatchTransferResponseNew.class);
|
HttpResponse<InitiateBatchTransferResponseNew> httpResponse = httpClient.execute(httpRequest, InitiateBatchTransferResponseNew.class);
|
||||||
logger.info("WxPayService.initiateBatchTransferNew response:{}", httpResponse.getServiceResponse());
|
logger.info("WxPayService.initiateBatchTransferNew response:{}", httpResponse.getServiceResponse());
|
||||||
return httpResponse.getServiceResponse();
|
return httpResponse.getServiceResponse();
|
||||||
|
|
||||||
|
}catch (Exception e){
|
||||||
|
logger.error("WxPayService.initiateBatchTransferNew error:{}", e);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -85,6 +89,7 @@ public class WxPayService {
|
|||||||
*/
|
*/
|
||||||
public TransferDetailEntityNew getTransferDetailByOutNoNew(String outBillNo) {
|
public TransferDetailEntityNew getTransferDetailByOutNoNew(String outBillNo) {
|
||||||
logger.info("WxPayService.getTransferDetailByOutNoNew request:{}", outBillNo);
|
logger.info("WxPayService.getTransferDetailByOutNoNew request:{}", outBillNo);
|
||||||
|
|
||||||
Config config = new RSAAutoCertificateConfig.Builder()
|
Config config = new RSAAutoCertificateConfig.Builder()
|
||||||
.merchantId(WechatPayConfig.getMchId())
|
.merchantId(WechatPayConfig.getMchId())
|
||||||
.privateKeyFromPath(WechatPayConfig.getPrivateKeyPath())
|
.privateKeyFromPath(WechatPayConfig.getPrivateKeyPath())
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package com.wzj.soopin.transaction.wechat;
|
package com.wzj.soopin.transaction.wechat;
|
||||||
|
|
||||||
|
import com.wechat.pay.java.core.Config;
|
||||||
|
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
@ -42,4 +44,16 @@ public class WechatPayConfig {
|
|||||||
return WXPayUtility.loadPrivateKeyFromPath(privateKeyPath);
|
return WXPayUtility.loadPrivateKeyFromPath(privateKeyPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public RSAAutoCertificateConfig wxPayConfig() throws IOException {
|
||||||
|
return new RSAAutoCertificateConfig.Builder()
|
||||||
|
.merchantId(this.getMchId())
|
||||||
|
.privateKey(this.merchantPrivateKey())
|
||||||
|
.merchantSerialNumber(this.getMchSerialNo())
|
||||||
|
.apiV3Key(this.getApiV3Key())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -170,7 +170,7 @@ http {
|
|||||||
#
|
#
|
||||||
server {
|
server {
|
||||||
listen 443 ssl;
|
listen 443 ssl;
|
||||||
server_name wuzhongjie.com.cn www.wuzhongjie.com.cn;
|
server_name wuzhongjie.com.cn www.wuzhongjie.com.cn ;
|
||||||
|
|
||||||
ssl_certificate /etc/nginx/cert/wuzhongjie.com.cn_bundle.pem;
|
ssl_certificate /etc/nginx/cert/wuzhongjie.com.cn_bundle.pem;
|
||||||
ssl_certificate_key /etc/nginx/cert/wuzhongjie.com.cn.key;
|
ssl_certificate_key /etc/nginx/cert/wuzhongjie.com.cn.key;
|
||||||
@ -199,6 +199,7 @@ http {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
location ^~ /busniess {
|
location ^~ /busniess {
|
||||||
alias /data/nginx/wzj/busniess/;
|
alias /data/nginx/wzj/busniess/;
|
||||||
index index.html;
|
index index.html;
|
||||||
@ -244,7 +245,27 @@ http {
|
|||||||
proxy_redirect off;
|
proxy_redirect off;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
server {
|
||||||
|
listen 443 ssl;
|
||||||
|
ssl_certificate /etc/nginx/cert/wuzhongjie.com.cn_bundle.pem;
|
||||||
|
ssl_certificate_key /etc/nginx/cert/wuzhongjie.com.cn.key;
|
||||||
|
ssl_session_timeout 5m;
|
||||||
|
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
|
||||||
|
ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;
|
||||||
|
ssl_prefer_server_ciphers on;
|
||||||
|
# 设置 gzip 压缩
|
||||||
|
gzip on;
|
||||||
|
#gzip_static on;
|
||||||
|
gzip_types text/plain text/css application/javascript application/json;
|
||||||
|
gzip_min_length 256;
|
||||||
|
server_name cjh.wuzhongjie.com.cn;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
proxy_pass http://43.143.227.203:7002;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user