feat 增加充值模块

This commit is contained in:
damonyuan 2024-10-22 00:37:52 +08:00
parent d44dc4e799
commit 56f0b88c7c
16 changed files with 221 additions and 21 deletions

View File

@ -119,7 +119,11 @@
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
</dependency>
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>4.38.72.ALL</version>
</dependency>
<!-- Gson工具 -->
<dependency>
<groupId>com.google.code.gson</groupId>

View File

@ -0,0 +1,26 @@
package com.mdd.common.config;
public class AlipayConfig
{
// 支付宝网关
public static String GATEWAY_URL = "https://openapi.alipay.com/gateway.do";
public static String GATEWAY_URL_DEBUG = "https://openapi-sandbox.dl.alipaydev.com/gateway.do";
// 应用ID,您的APPID收款账号既是您的APPID对应支付宝账号
public static String APP_ID = "";
// 商户私钥您的PKCS8格式RSA2私钥
public static String MERCHANT_PRIVATE_KEY = "";
// https://openhome.alipay.com/platform/keyManage.htm 对应APPID下的支付宝公钥
public static String ALIPAY_PUBLIC_KEY = "";
// 服务器异步通知页面路径 需http://格式的完整路径由自己系统开发实现
public static String NOTIFY_URL = "";
// 页面跳转同步通知页面路径 需http://格式的完整路径由自己系统开发实现
public static String RETURN_URL = "";
// 签名方式
public static String SIGN_TYPE = "RSA2";
// 字符编码格式
public static String CHARSET = "utf-8";
}

View File

@ -61,13 +61,13 @@ public class WxMnpConfiguration {
@Bean
@ConditionalOnMissingBean
public WxMpService wxOaService() {
Map<String, String> config = this.getChannelConfig("oa_channel");
Map<String, String> config = this.getChannelConfig("oa_setting");
WxMpDefaultConfigImpl wxMpDefaultConfig = new WxMpDefaultConfigImpl();
wxMpDefaultConfig.setAppId(config.getOrDefault("appId", "").trim());
wxMpDefaultConfig.setSecret(config.getOrDefault("appSecret", "").trim());
wxMpDefaultConfig.setAppId(config.getOrDefault("app_id", "").trim());
wxMpDefaultConfig.setSecret(config.getOrDefault("app_secret", "").trim());
wxMpDefaultConfig.setToken(config.getOrDefault("token", "").trim());
wxMpDefaultConfig.setAesKey(config.getOrDefault("encodingAesKey", "").trim());
wxMpDefaultConfig.setAesKey(config.getOrDefault("encoding_aes_key", "").trim());
WxMpService wxService = new WxMpServiceImpl();
wxService.setWxMpConfigStorage(wxMpDefaultConfig);

View File

@ -85,8 +85,8 @@ public class WxPayConfiguration {
.last("limit 1"));
Config systemConfig = systemConfigMapper.selectOne(new QueryWrapper<Config>()
.eq("name", "appId")
.eq("type", "oa_channel")
.eq("name", "app_id")
.eq("type", "oa_setting")
.last("limit 1"));
String paramJson = StringUtils.isNull(config.getConfig()) ? "{}" : config.getConfig().toString();

View File

@ -59,6 +59,21 @@ public enum AccountLogEnum {
return ret.getString(String.valueOf(changeType));
}
/**
* @notes 获取变动对象
* @param changeType
* @return false
* @author damonyuan
*/
public static Integer getChangeObject(Integer changeType) {
List<Integer> typeList = getUserMoneyChangeType();
if (typeList.contains(changeType)) {
return UM.getCode();
} else {
return 0;
}
}
/**
* 获取状态码
*

View File

@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.mdd.common.core.basics.IBaseMapper;
import com.mdd.common.entity.log.UserAccountLog;
import com.mdd.common.entity.user.User;
import com.mdd.common.enums.AccountLogEnum;
import com.mdd.common.mapper.user.UserMapper;
import com.mdd.common.util.SpringUtils;
import com.mdd.common.util.StringUtils;
@ -40,11 +41,14 @@ public interface UserAccountLogMapper extends IBaseMapper<UserAccountLog> {
break;
}
Integer changeObject = AccountLogEnum.getChangeObject(changeType);
BigDecimal leftAmount = user.getUserMoney().add(changeAmount);
UserAccountLog logMoney = new UserAccountLog();
logMoney.setSn(this.randMakeOrderSn());
logMoney.setUserId(userId);
logMoney.setSourceSn(sourceSn);
logMoney.setChangeObject(changeObject);
logMoney.setChangeType(changeType);
logMoney.setChangeAmount(changeAmount);
logMoney.setLeftAmount(leftAmount);

View File

@ -65,13 +65,13 @@ public class WxMnpDriver {
* @return WxMpService
*/
public static WxMpService oa() {
Map<String, String> config = ConfigUtils.get("oa_channel");
Map<String, String> config = ConfigUtils.get("oa_setting");
WxMpDefaultConfigImpl wxMpDefaultConfig = new WxMpDefaultConfigImpl();
wxMpDefaultConfig.setAppId(config.getOrDefault("appId", "").trim());
wxMpDefaultConfig.setSecret(config.getOrDefault("appSecret", "").trim());
wxMpDefaultConfig.setAppId(config.getOrDefault("app_id", "").trim());
wxMpDefaultConfig.setSecret(config.getOrDefault("app_secret", "").trim());
wxMpDefaultConfig.setToken(config.getOrDefault("token", "").trim());
wxMpDefaultConfig.setAesKey(config.getOrDefault("encodingAesKey", "").trim());
wxMpDefaultConfig.setAesKey(config.getOrDefault("encoding_aes_key", "").trim());
wxMpService.setWxMpConfigStorage(wxMpDefaultConfig);
return wxMpService;

View File

@ -161,14 +161,14 @@ public class WxPayDriver {
.eq("pay_way", 2)
.last("limit 1"));
String scene = type.equals("oa") ? "oa_channel" : "mp_channel";
String appId = ConfigUtils.get(scene, "appId", "");
String scene = type.equals("oa") ? "oa_setting" : "mnp_setting";
String appId = ConfigUtils.get(scene, "app_id", "");
Map<String, String> params = MapUtils.jsonToMap(config.getConfig().toString());
String mchId = params.get("mch_id");
String paySignKey = params.get("pay_sign_key");
byte[] privateCert = params.getOrDefault("private_cert", "").getBytes();
byte[] privateKey = params.getOrDefault("private_key", "").getBytes();
byte[] privateCert = params.getOrDefault("apiclient_cert", "").getBytes();
byte[] privateKey = params.getOrDefault("apiclient_key", "").getBytes();
WxPayConfig payConfig = new WxPayConfig();
payConfig.setAppId(appId);

View File

@ -1,9 +1,13 @@
package com.mdd.common.util;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.mdd.common.cache.ConfigCache;
import com.mdd.common.entity.Config;
import com.mdd.common.entity.setting.DevPayConfig;
import com.mdd.common.enums.PaymentEnum;
import com.mdd.common.mapper.ConfigMapper;
import com.mdd.common.mapper.setting.DevPayConfigMapper;
import java.util.LinkedHashMap;
import java.util.List;
@ -163,4 +167,18 @@ public class ConfigUtils {
ConfigCache.set();
}
//返回支付宝配置信息
public static String getAliDevPay(String field) {
DevPayConfigMapper model = SpringUtils.getBean(DevPayConfigMapper.class);
DevPayConfig devPay = model.selectOne(
new QueryWrapper<DevPayConfig>()
.eq("way", PaymentEnum.ALI_PAY.getCode()));
if (StringUtils.isNull(devPay)) {
return "";
} else {
JSONObject jsonObject = JSONObject.parseObject(devPay.getConfig().toString());
return StringUtils.isNull(jsonObject.getString(field)) ? "" : jsonObject.getString(field);
}
}
}

View File

@ -100,4 +100,26 @@ public class UrlUtils {
return "";
}
/**
* 获取域名
* 示例: https://127.0.0.1/
*
* @author fzr
* @return String
*/
public static String localDomain(String url){
return RequestUtils.uri() + url;
}
/**
* 为了避免负载均衡而导致的域名失效增加该方法
* @return
*/
public static String getRequestUrl() {
if (StringUtils.isNull(YmlUtils.get("like.url"))) {
return RequestUtils.uri();
} else {
return YmlUtils.get("like.url");
}
}
}

View File

@ -12,6 +12,7 @@ import com.mdd.common.enums.PaymentEnum;
import com.mdd.common.exception.OperateException;
import com.mdd.common.mapper.RechargeOrderMapper;
import com.mdd.common.plugin.wechat.WxPayDriver;
import com.mdd.common.util.StringUtils;
import com.mdd.front.LikeFrontThreadLocal;
import com.mdd.front.service.IPayService;
import com.mdd.front.validate.PaymentValidate;
@ -60,10 +61,14 @@ public class PayController {
@ApiOperation("发起支付")
public AjaxResult<Object> prepay(@Validated @RequestBody PaymentValidate requestObj) {
// 接收参数
if (StringUtils.isNull(requestObj.getScene())) {
requestObj.setScene("recharge");
}
String scene = requestObj.getScene();
Integer payWay = requestObj.getPayWay();
Integer orderId = requestObj.getOrderId();
Integer terminal = LikeFrontThreadLocal.getTerminal();
requestObj.setTerminal(terminal);
// 订单处理
int payStatus = 0;

View File

@ -1,5 +1,7 @@
package com.mdd.front.service;
import com.alibaba.fastjson2.JSONObject;
import com.alipay.api.AlipayApiException;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.mdd.front.validate.PaymentValidate;
import com.mdd.front.vo.pay.PayStatusVo;
@ -52,4 +54,6 @@ public interface IPayService {
*/
void handlePaidNotify(String attach, String outTradeNo, String transactionId) throws WxPayException;
JSONObject createAliH5Order(PaymentValidate params) throws AlipayApiException;
}

View File

@ -1,6 +1,13 @@
package com.mdd.front.service.impl;
import com.alibaba.fastjson2.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.alipay.api.request.AlipayTradeWapPayRequest;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.mdd.common.config.AlipayConfig;
import com.mdd.common.entity.RechargeOrder;
import com.mdd.common.entity.setting.DevPayConfig;
import com.mdd.common.entity.setting.DevPayWay;
@ -27,11 +34,13 @@ import com.mdd.front.vo.pay.PayStatusVo;
import com.mdd.front.vo.pay.PayWayInfoVo;
import com.mdd.front.vo.pay.PayWayListVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
@Slf4j
@ -55,6 +64,8 @@ public class PayServiceImpl implements IPayService {
@Resource
UserAccountLogMapper logMoneyMapper;
@Value("${ali.pay.order-notify-url}")
private String aliPayNotifyUrl;
/**
* 支付方式
@ -180,13 +191,15 @@ public class PayServiceImpl implements IPayService {
requestV3.setDescription(params.getDescription());
Object result = WxPayDriver.unifiedOrder(requestV3);
if (terminal == ClientEnum.H5.getCode()) {
Assert.notNull(params.getRedirectUrl(), "redirectUrl参数缺失");
Assert.notNull(params.getRedirect(), "redirectUrl参数缺失");
Map<String, String> map = new LinkedHashMap<>();
String h5Url = result.toString();
map.put("url", h5Url);
return map;
}
return WxPayDriver.unifiedOrder(requestV3);
case 3: //支付宝
return this.createAliH5Order(params);
}
} catch (Exception e) {
throw new PaymentException(e.getMessage());
@ -215,6 +228,89 @@ public class PayServiceImpl implements IPayService {
}
}
@Override
public JSONObject createAliH5Order(PaymentValidate params) throws AlipayApiException {
JSONObject ret = new JSONObject();
// 订单编号
String orderSn = "";
// 订单状态
Integer orderStatus = 0;
// 订单金额
BigDecimal orderAmount = BigDecimal.ZERO;
Long orderId = 0L;
String payReturnUrl = "";
switch (params.getScene()){
case "member":
break;
case "recharge":
RechargeOrder rechargeOrder = rechargeOrderMapper.selectOne(new QueryWrapper<RechargeOrder>()
.eq("id", params.getOrderId())
.eq("pay_status", PaymentEnum.UN_PAID.getCode())
.eq("user_id", params.getUserId())
.last("limit 1"));
orderSn = rechargeOrder.getSn();
orderStatus = rechargeOrder.getPayStatus();
orderAmount = rechargeOrder.getOrderAmount();
orderId = Long.valueOf(rechargeOrder.getId());
payReturnUrl = UrlUtils.localDomain(params.getRedirect());
Assert.notNull(rechargeOrder, "订单不存在");
break;
default:
throw new OperateException("不支持当前订单类型");
}
Assert.isTrue(orderStatus != null && orderStatus == PaymentEnum.UN_PAID.getCode(), "订单非待支付状态,不能创建支付单");
String gateWay = StringUtils.isNotNull(YmlUtils.get("like.alidebug")) && YmlUtils.get("like.alidebug").equals("true") ? AlipayConfig.GATEWAY_URL_DEBUG : AlipayConfig.GATEWAY_URL;
AlipayClient alipayClient = new DefaultAlipayClient(gateWay, ConfigUtils.getAliDevPay("app_id"), ConfigUtils.getAliDevPay("private_key"), "json", AlipayConfig.CHARSET, ConfigUtils.getAliDevPay("ali_public_key"), AlipayConfig.SIGN_TYPE);
//2封装 Request
String form = "";
JSONObject bizContent = new JSONObject();
bizContent.put("out_trade_no", orderSn);
bizContent.put("total_amount", orderAmount);
bizContent.put("subject", params.getDescription());
bizContent.put("product_code", "FAST_INSTANT_TRADE_PAY");
bizContent.put("app_pay", "Y");
bizContent.put("passback_params", JSONObject.toJSONString(new JSONObject(){{
put("from", params.getScene());
}}));
if (params.getTerminal().equals(ClientEnum.H5.getCode())) {
AlipayTradeWapPayRequest alipayRequest = new AlipayTradeWapPayRequest();
//alipayRequest.setNotifyUrl("hhttp://bq93pv.natappfree.cc" + aliPayNotifyUrl);
alipayRequest.setNotifyUrl(UrlUtils.getRequestUrl() + aliPayNotifyUrl);
alipayRequest.setReturnUrl(payReturnUrl);
alipayRequest.setBizContent(bizContent.toString());
try {
form = alipayClient.pageExecute(alipayRequest).getBody();
ret.put("config", form);
ret.put("pay_way", params.getPayWay());
return ret;
} catch (Exception e) {
throw new PaymentException(e.getMessage());
//throw new OperateException(e.getMessage());
}
} else {
AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();
//alipayRequest.setNotifyUrl("http://bq93pv.natappfree.cc" + aliPayNotifyUrl);
alipayRequest.setNotifyUrl(UrlUtils.getRequestUrl() + aliPayNotifyUrl);
alipayRequest.setReturnUrl(payReturnUrl);
alipayRequest.setBizContent(bizContent.toString());
try {
form = alipayClient.pageExecute(alipayRequest).getBody();
ret.put("config", form);
ret.put("pay_way", params.getPayWay());
return ret;
} catch (Exception e) {
throw new PaymentException(e.getMessage());
}
}
}
/**
* 余额充值回调
*
@ -226,7 +322,7 @@ public class PayServiceImpl implements IPayService {
for (int i=0; i<=0; i++) {
RechargeOrder rechargeOrder = rechargeOrderMapper.selectOne(
new QueryWrapper<RechargeOrder>()
.eq("order_sn", outTradeNo)
.eq("sn", outTradeNo).isNull("delete_time")
.last("limit 1"));
if (StringUtils.isNull(rechargeOrder)) {

View File

@ -12,7 +12,7 @@ public class WechatServiceImpl implements IWechatService {
@Override
public Map<String, Object> jsConfig(String url) throws Exception {
String appId = ConfigUtils.get("oa_channel", "appId");
String appId = ConfigUtils.get("oa_setting", "app_id");
String accessToken = WxMnpDriver.mnp().getAccessToken();
String jsapiTicket = WxMnpDriver.getJsSdkGetTicket(accessToken);
String timestamp = Long.toString(System.currentTimeMillis() / 1000);

View File

@ -14,7 +14,7 @@ public class PaymentValidate implements Serializable {
private static final long serialVersionUID = 1L;
@NotNull(message = "scene参数缺失")
//@NotNull(message = "scene参数缺失")
@ApiModelProperty("支付场景: [recharge=充值,order=普通订单]")
private String scene;
@ -27,7 +27,7 @@ public class PaymentValidate implements Serializable {
private Integer orderId;
@ApiModelProperty(value = "重定向链接: H5端需要")
private String redirectUrl;
private String redirect;
@ApiModelProperty(value = "用户ID", notes = "该参数无需传递")
private Integer userId;
@ -44,4 +44,7 @@ public class PaymentValidate implements Serializable {
@ApiModelProperty(value = "用户描述", notes = "该参数无需传递")
private String description;
@ApiModelProperty(value = "Terminal")
private Integer Terminal;
}

View File

@ -80,4 +80,7 @@ sa-token:
is-share: false # 多人同登账号共用token
token-style: random-64 # token生成的风格
is-print: false # 打印版本字符画
is-log: false # 是否输出操作日志
is-log: false # 是否输出操作日志
ali:
pay:
order-notify-url: /api/pay/ali/notify/order