|
@@ -0,0 +1,925 @@
|
|
|
+package com.dtb.portal.service.impl;
|
|
|
+
|
|
|
+import com.dtb.portal.config.WxPayAppConfig;
|
|
|
+import com.dtb.portal.config.WxPayMiniprogramConfig;
|
|
|
+import com.dtb.portal.config.interceptor.TokenUtils;
|
|
|
+import com.dtb.portal.controller.view.response.ResultMap;
|
|
|
+import com.dtb.portal.entity.AppPayData;
|
|
|
+import com.dtb.portal.entity.MiniprogramPayData;
|
|
|
+import com.dtb.portal.entity.VipGoodsData;
|
|
|
+import com.dtb.portal.entity.VipOrderData;
|
|
|
+import com.dtb.portal.entity.VipUserData;
|
|
|
+import com.dtb.portal.entity.SysUser;
|
|
|
+import com.dtb.portal.mapper.SysUserMapper;
|
|
|
+import com.dtb.portal.service.VipGoodsService;
|
|
|
+import com.dtb.portal.service.WxPayService;
|
|
|
+import com.dtb.portal.util.DateUtils;
|
|
|
+import com.dtb.portal.util.PrimaryIdUtils;
|
|
|
+import com.github.wxpay.sdk.WXPay;
|
|
|
+import com.github.wxpay.sdk.WXPayConstants;
|
|
|
+import com.github.wxpay.sdk.WXPayUtil;
|
|
|
+import com.wechat.pay.java.core.Config;
|
|
|
+import com.wechat.pay.java.core.RSAAutoCertificateConfig;
|
|
|
+
|
|
|
+import com.wechat.pay.java.core.cipher.SignatureResult;
|
|
|
+import com.wechat.pay.java.service.payments.app.AppService;
|
|
|
+import com.wechat.pay.java.service.payments.app.AppServiceExtension;
|
|
|
+import com.wechat.pay.java.service.payments.app.model.*;
|
|
|
+import com.wechat.pay.java.service.payments.jsapi.JsapiService;
|
|
|
+import com.wechat.pay.java.service.payments.jsapi.model.*;
|
|
|
+import com.wechat.pay.java.service.payments.jsapi.model.Payer;
|
|
|
+import com.wechat.pay.java.service.payments.model.Transaction;
|
|
|
+import org.apache.commons.lang3.StringUtils;
|
|
|
+import org.slf4j.Logger;
|
|
|
+import org.slf4j.LoggerFactory;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.beans.factory.annotation.Value;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+
|
|
|
+import java.io.IOException;
|
|
|
+import java.time.LocalDateTime;
|
|
|
+import java.util.*;
|
|
|
+
|
|
|
+import static java.util.Objects.requireNonNull;
|
|
|
+
|
|
|
+@Service
|
|
|
+public class WxPayServiceImpl implements WxPayService {
|
|
|
+ private final Logger logger = LoggerFactory.getLogger(WxPayServiceImpl.class);
|
|
|
+
|
|
|
+
|
|
|
+ @Value("${wxpay.app.v3-key}")
|
|
|
+ private String v3Key;
|
|
|
+ @Autowired
|
|
|
+ private SysUserMapper sysUserMapper;
|
|
|
+/* private HttpClient httpClient;
|
|
|
+
|
|
|
+
|
|
|
+ private WxPayServiceImpl(HttpClient httpClient) {
|
|
|
+ this.httpClient = httpClient;
|
|
|
+ }*/
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private WxPayAppConfig wxPayAppConfig;
|
|
|
+ @Autowired
|
|
|
+ private WxPayMiniprogramConfig wxPayMiniprogramConfig;
|
|
|
+ @Autowired
|
|
|
+ private VipGoodsService vipGoodsService;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @param vipGoodsId : 订单编号
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public ResultMap unifiedOrder(String vipGoodsId) {
|
|
|
+ Map<String, String> returnMap = new HashMap<>();
|
|
|
+ Map<String, String> responseMap = new HashMap<>();
|
|
|
+ Map<String, String> requestMap = new HashMap<>();
|
|
|
+ String orderNo = "";
|
|
|
+ try {
|
|
|
+
|
|
|
+ VipGoodsData vipGoodsData = vipGoodsService.getById(vipGoodsId);
|
|
|
+ if (Objects.isNull(vipGoodsData)) {
|
|
|
+ throw new RuntimeException("商品不存在");
|
|
|
+ }
|
|
|
+
|
|
|
+ String vipMoney = vipGoodsData.getVipMoney();
|
|
|
+ double amount = Double.parseDouble(vipMoney);
|
|
|
+ orderNo = PrimaryIdUtils.getId().toString();
|
|
|
+ WXPay wxpay = new WXPay(wxPayAppConfig);
|
|
|
+ requestMap.put("body", vipGoodsData.getName()); // 商品描述
|
|
|
+ requestMap.put("out_trade_no", orderNo); // 商户订单号
|
|
|
+ requestMap.put("total_fee", String.valueOf((int) (amount * 100))); // 总金额
|
|
|
+ //requestMap.put("spbill_create_ip", HttpContextUtils.getIpAddr()); // 终端IP
|
|
|
+ requestMap.put("trade_type", "APP"); // App支付类型
|
|
|
+ requestMap.put("notify_url", wxPayAppConfig.getPayNotifyUrl()); // 接收微信支付异步通知回调地址
|
|
|
+ Map<String, String> resultMap = wxpay.unifiedOrder(requestMap);
|
|
|
+ logger.info("下单返回的信息是:{}", resultMap);
|
|
|
+ //获取返回码
|
|
|
+ String returnCode = resultMap.get("return_code");
|
|
|
+ //String returnMsg = resultMap.get("return_msg");
|
|
|
+ //若返回码为SUCCESS,则会返回一个result_code,再对该result_code进行判断
|
|
|
+ if ("SUCCESS".equals(returnCode)) {
|
|
|
+ String resultCode = resultMap.get("result_code");
|
|
|
+ String errCodeDes = resultMap.get("err_code_des");
|
|
|
+ if ("SUCCESS".equals(resultCode)) {
|
|
|
+ responseMap = resultMap;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (responseMap.isEmpty()) {
|
|
|
+ return ResultMap.error("获取预支付交易会话标识失败");
|
|
|
+ }
|
|
|
+ // 3、签名生成算法
|
|
|
+ Long time = System.currentTimeMillis() / 1000;
|
|
|
+ String timestamp = time.toString();
|
|
|
+ returnMap.put("appid", wxPayAppConfig.getAppID());
|
|
|
+ returnMap.put("partnerid", wxPayAppConfig.getMchID());
|
|
|
+ returnMap.put("prepayid", responseMap.get("prepay_id"));
|
|
|
+ returnMap.put("noncestr", responseMap.get("nonce_str"));
|
|
|
+ returnMap.put("timestamp", timestamp);
|
|
|
+ returnMap.put("package", "Sign=WXPay");
|
|
|
+ returnMap.put("sign", responseMap.get("sign"));
|
|
|
+ returnMap.put("out_trade_no", orderNo);
|
|
|
+ String signMD5 = WXPayUtil.generateSignature(returnMap, wxPayAppConfig.getKey(), WXPayConstants.SignType.MD5);
|
|
|
+ String signSHA256 = WXPayUtil.generateSignature(returnMap, wxPayAppConfig.getKey(), WXPayConstants.SignType.HMACSHA256);
|
|
|
+ returnMap.put("signMD5", signMD5);
|
|
|
+ returnMap.put("signSHA256", signSHA256);
|
|
|
+ returnMap.put("base64SignMD5", Base64.getEncoder().encodeToString(signMD5.getBytes()));
|
|
|
+ returnMap.put("base64SignSHA256", Base64.getEncoder().encodeToString(signSHA256.getBytes()));
|
|
|
+ returnMap.put("key", wxPayAppConfig.getKey());
|
|
|
+ logger.info("返回的信息是:{}", returnMap);
|
|
|
+ return ResultMap.ok().put("data", returnMap);
|
|
|
+ } catch (Exception e) {
|
|
|
+ logger.error("订单号:{},错误信息:{}", orderNo, e.getMessage());
|
|
|
+ return ResultMap.error("微信支付统一下单失败");
|
|
|
+ } finally {
|
|
|
+ //生成订单在数据库
|
|
|
+ VipOrderData data = new VipOrderData();
|
|
|
+ data.setId(PrimaryIdUtils.getId().toString());
|
|
|
+ data.setOutTradeNo(orderNo);
|
|
|
+ data.setStatus("1");
|
|
|
+ data.setVipGoodsId(vipGoodsId);
|
|
|
+ data.setCreateTime(LocalDateTime.now());
|
|
|
+ data.setUpdateTime(LocalDateTime.now());
|
|
|
+ vipGoodsService.insertVipOrderData(data);
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public String notify(String notifyStr) {
|
|
|
+ String xmlBack = "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[报文为空]]></return_msg></xml> ";
|
|
|
+ try {
|
|
|
+// 转换成map
|
|
|
+ Map<String, String> resultMap = WXPayUtil.xmlToMap(notifyStr);
|
|
|
+ WXPay wxpayApp = new WXPay(wxPayAppConfig);
|
|
|
+ if (wxpayApp.isPayResultNotifySignatureValid(resultMap)) {
|
|
|
+ String returnCode = resultMap.get("return_code"); //状态
|
|
|
+ String outTradeNo = resultMap.get("out_trade_no");//商户订单号
|
|
|
+ String transactionId = resultMap.get("transaction_id");
|
|
|
+ if (returnCode.equals("SUCCESS")) {
|
|
|
+ if (StringUtils.isNotBlank(outTradeNo)) {
|
|
|
+/**
|
|
|
+ * 注意!!!
|
|
|
+ * 请根据业务流程,修改数据库订单支付状态,和其他数据的相应状态
|
|
|
+ *
|
|
|
+ */
|
|
|
+ logger.info("微信手机支付回调成功,订单号:{}", outTradeNo);
|
|
|
+ xmlBack = "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ return xmlBack;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public ResultMap refund(String orderNo, double amount, String refundReason) {
|
|
|
+
|
|
|
+ if (StringUtils.isBlank(orderNo)) {
|
|
|
+ return ResultMap.error("订单编号不能为空");
|
|
|
+ }
|
|
|
+ if (amount <= 0) {
|
|
|
+ return ResultMap.error("退款金额必须大于0");
|
|
|
+ }
|
|
|
+
|
|
|
+ Map<String, String> responseMap = new HashMap<>();
|
|
|
+ Map<String, String> requestMap = new HashMap<>();
|
|
|
+ WXPay wxpay = new WXPay(wxPayAppConfig);
|
|
|
+ requestMap.put("out_trade_no", orderNo);
|
|
|
+ requestMap.put("out_refund_no", UUID.randomUUID().toString().replaceAll("-", ""));
|
|
|
+ requestMap.put("total_fee", "订单支付时的总金额,需要从数据库查");
|
|
|
+ requestMap.put("refund_fee", String.valueOf((int) (amount * 100)));//所需退款金额
|
|
|
+ requestMap.put("refund_desc", refundReason);
|
|
|
+ try {
|
|
|
+ responseMap = wxpay.refund(requestMap);
|
|
|
+ } catch (Exception e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ String return_code = responseMap.get("return_code"); //返回状态码
|
|
|
+ String return_msg = responseMap.get("return_msg"); //返回信息
|
|
|
+ if ("SUCCESS".equals(return_code)) {
|
|
|
+ String result_code = responseMap.get("result_code"); //业务结果
|
|
|
+ String err_code_des = responseMap.get("err_code_des"); //错误代码描述
|
|
|
+ if ("SUCCESS".equals(result_code)) {
|
|
|
+//表示退款申请接受成功,结果通过退款查询接口查询
|
|
|
+//修改用户订单状态为退款申请中或已退款。退款异步通知根据需求,可选
|
|
|
+ return ResultMap.ok("退款申请成功");
|
|
|
+ } else {
|
|
|
+ logger.info("订单号:{}错误信息:{}", orderNo, err_code_des);
|
|
|
+ return ResultMap.error(err_code_des);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ logger.info("订单号:{}错误信息:{}", orderNo, return_msg);
|
|
|
+ return ResultMap.error(return_msg);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @param vipGoodsId 商品主键
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public AppPayData unifiedOrder2(String vipGoodsId) {
|
|
|
+ logger.info("微信APP支付基础信息:{}", wxPayAppConfig);
|
|
|
+ //查询商品是否存在,存在则下单,不存在则不下单
|
|
|
+ VipGoodsData data = vipGoodsService.getById(vipGoodsId);
|
|
|
+ if (Objects.isNull(data)) {
|
|
|
+ throw new RuntimeException("VIP商品不存在");
|
|
|
+ }
|
|
|
+ // 使用自动更新平台证书的RSA配置
|
|
|
+ // 一个商户号只能初始化一个配置,否则会因为重复的下载任务报错
|
|
|
+ Config config =
|
|
|
+ new RSAAutoCertificateConfig.Builder()
|
|
|
+ .merchantId(wxPayAppConfig.getMchID())
|
|
|
+ .privateKeyFromPath(wxPayAppConfig.getCertPath())
|
|
|
+ .merchantSerialNumber(wxPayAppConfig.getMerchantSerialNumber())
|
|
|
+ //.apiV3Key(wxPayAppConfig.getKey())
|
|
|
+ .apiV3Key(v3Key)
|
|
|
+ .build();
|
|
|
+
|
|
|
+ // 构建service
|
|
|
+ AppService service = new AppService.Builder().config(config).build();
|
|
|
+ String orderNo = PrimaryIdUtils.getId().toString();
|
|
|
+ com.wechat.pay.java.service.payments.app.model.PrepayRequest request = new com.wechat.pay.java.service.payments.app.model.PrepayRequest();
|
|
|
+ com.wechat.pay.java.service.payments.app.model.Amount amount = new com.wechat.pay.java.service.payments.app.model.Amount();
|
|
|
+ //金额计算 ,乘以100
|
|
|
+ String money = data.getVipMoney();
|
|
|
+
|
|
|
+ //int orderAmount = Integer.parseInt(money) * 100;
|
|
|
+ int orderAmount = (int) (Double.parseDouble(money) * 100);
|
|
|
+
|
|
|
+ amount.setTotal(orderAmount);
|
|
|
+ request.setAmount(amount);
|
|
|
+ request.setAppid(wxPayAppConfig.getAppID());
|
|
|
+ request.setMchid(wxPayAppConfig.getMchID());
|
|
|
+ request.setDescription(data.getName());
|
|
|
+ request.setNotifyUrl(wxPayAppConfig.getPayNotifyUrl());
|
|
|
+ request.setOutTradeNo(orderNo);
|
|
|
+ // 调用下单方法,得到应答
|
|
|
+ com.wechat.pay.java.service.payments.app.model.PrepayResponse response = service.prepay(request);
|
|
|
+ logger.info("调用微信app下单返回的信息是:{}", response);
|
|
|
+ String prepayId = response.getPrepayId();
|
|
|
+ AppPayData appPayData = new AppPayData();
|
|
|
+ appPayData.setAppid(wxPayAppConfig.getAppID());
|
|
|
+ appPayData.setPrepayid(prepayId);
|
|
|
+ appPayData.setPartnerid(wxPayAppConfig.getMchID());
|
|
|
+ String noncestr = UUID.randomUUID().toString().replaceAll("-", "");
|
|
|
+ appPayData.setNoncestr(noncestr);
|
|
|
+ //appPayData.setTimestamp(String.valueOf(System.currentTimeMillis()));
|
|
|
+
|
|
|
+ //生成签名
|
|
|
+ Map<String, String> returnMap = new HashMap<>();
|
|
|
+ Long time = System.currentTimeMillis() / 1000;
|
|
|
+ String timestamp = time.toString();
|
|
|
+ returnMap.put("appid", wxPayAppConfig.getAppID());
|
|
|
+ returnMap.put("timestamp", timestamp);
|
|
|
+ returnMap.put("noncestr", noncestr);
|
|
|
+
|
|
|
+ returnMap.put("prepayid", prepayId);
|
|
|
+ //returnMap.put("package", "Sign=WXPay");
|
|
|
+ //returnMap.put("package", "prepay_id="+prepayId);
|
|
|
+
|
|
|
+ AppServiceExtension appServiceExtension = new AppServiceExtension.Builder().config(config).build();
|
|
|
+
|
|
|
+ com.wechat.pay.java.service.payments.app.model.PrepayRequest prepayRequest = new com.wechat.pay.java.service.payments.app.model.PrepayRequest();
|
|
|
+
|
|
|
+ prepayRequest.setAmount(amount);
|
|
|
+ prepayRequest.setAppid(wxPayAppConfig.getAppID());
|
|
|
+ prepayRequest.setMchid(wxPayAppConfig.getMchID());
|
|
|
+ prepayRequest.setDescription(data.getName());
|
|
|
+ prepayRequest.setNotifyUrl(wxPayAppConfig.getPayNotifyUrl());
|
|
|
+ prepayRequest.setOutTradeNo(orderNo);
|
|
|
+
|
|
|
+ com.wechat.pay.java.service.payments.app.model.PrepayWithRequestPaymentResponse prepayWithRequestPaymentResponse = appServiceExtension.prepayWithRequestPayment(prepayRequest);
|
|
|
+ appPayData.setPrepayWithRequestPaymentResponse(prepayWithRequestPaymentResponse);
|
|
|
+
|
|
|
+
|
|
|
+ SignatureResult signatureResult = config.createSigner().sign(wxPayAppConfig.getAppID() + "\n" + timestamp + "\n" + noncestr + "\n" + "prepay_id=" + prepayId + "\n");
|
|
|
+ String sign = signatureResult.getSign();
|
|
|
+ logger.info("签名值是:{}", sign);
|
|
|
+ appPayData.setSign(sign);
|
|
|
+ appPayData.setBase64Sign(Base64.getEncoder().encodeToString(sign.getBytes()));
|
|
|
+ try {
|
|
|
+ String signMD5 = WXPayUtil.generateSignature(returnMap, v3Key, WXPayConstants.SignType.MD5);
|
|
|
+ String signSHA256 = WXPayUtil.generateSignature(returnMap, v3Key, WXPayConstants.SignType.HMACSHA256);
|
|
|
+ //生成微信签名
|
|
|
+ appPayData.setSignMD5(signMD5);
|
|
|
+ appPayData.setBase64SignMD5(Base64.getEncoder().encodeToString(signMD5.getBytes()));
|
|
|
+ appPayData.setSignSHA256(signSHA256);
|
|
|
+ appPayData.setBase64SignSHA256(Base64.getEncoder().encodeToString(signSHA256.getBytes()));
|
|
|
+ appPayData.setTimestamp(timestamp);
|
|
|
+ } catch (Exception e) {
|
|
|
+ logger.error("生成微信签名失败:", e);
|
|
|
+ throw new RuntimeException("生成微信签名失败");
|
|
|
+
|
|
|
+ } finally {
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ return appPayData;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * APP支付成功后调用,主要计算VIP时长
|
|
|
+ *
|
|
|
+ * @param vipGoodsId 商品主键
|
|
|
+ * @param out_trade_no
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public SysUser success(String vipGoodsId, String out_trade_no) {
|
|
|
+
|
|
|
+ //查询商品是否存在,存在则下单,不存在则不下单
|
|
|
+ VipGoodsData data = vipGoodsService.getById(vipGoodsId);
|
|
|
+ if (Objects.isNull(data)) {
|
|
|
+ throw new RuntimeException("VIP商品不存在");
|
|
|
+ }
|
|
|
+
|
|
|
+ VipOrderData vipOrderData = vipGoodsService.getOrderByOutTradeNo(out_trade_no);
|
|
|
+ if (Objects.isNull(vipOrderData)) {
|
|
|
+ throw new RuntimeException("订单不存在");
|
|
|
+ }
|
|
|
+ //查询订单是否支付成功,支付成功:生成VIP时长,失败异常
|
|
|
+ /* QueryOrderByOutTradeNoRequest queryOrderByOutTradeNoRequest = new QueryOrderByOutTradeNoRequest();
|
|
|
+ queryOrderByOutTradeNoRequest.setOutTradeNo(out_trade_no);
|
|
|
+ queryOrderByOutTradeNoRequest.setMchid(wxPayAppConfig.getMchID());
|
|
|
+ Transaction transaction = queryOrderByOutTradeNo(queryOrderByOutTradeNoRequest);*/
|
|
|
+ Transaction transaction = queryOrderByOutTradeNo(out_trade_no);
|
|
|
+
|
|
|
+ Transaction.TradeStateEnum tradeState = transaction.getTradeState();
|
|
|
+ //logger.info("支付返回的信息是:{}", transaction);
|
|
|
+ //logger.info("根据订单号查询是否支付成功:{}", tradeState.name());
|
|
|
+
|
|
|
+
|
|
|
+ if ("SUCCESS".equals(tradeState.name())) {
|
|
|
+ logger.info("支付成功:{}", transaction);
|
|
|
+ //查询用户是否已经开通过,开通过则续费,没有开通过怎插新数据
|
|
|
+ String userId = TokenUtils.getUserId();
|
|
|
+ VipUserData vipUserData = vipGoodsService.selectByUserId(userId, vipGoodsId);
|
|
|
+ //VIP时长
|
|
|
+ String vipStartDate = "";
|
|
|
+ String vipEndDate = "";
|
|
|
+ String vipDate = data.getVipDate();
|
|
|
+ if (Objects.isNull(vipUserData)) {
|
|
|
+ //没有开通过,新开通,开始时间=当天时间,结束时间=会员时长+当前时间
|
|
|
+ vipStartDate = DateUtils.toStringYMD(new Date());
|
|
|
+ vipEndDate = DateUtils.getAfterDate(Integer.parseInt(vipDate));
|
|
|
+
|
|
|
+ } else {
|
|
|
+ //开通过,查看有没有过期,过期:新开通,不过期,续费
|
|
|
+ String vipEndDateStr = vipUserData.getVipEndDate();
|
|
|
+ Date vipEndDate1 = DateUtils.toDateYMDHMS(vipEndDateStr);
|
|
|
+ Date todayDate = DateUtils.toDateYMDHMS(DateUtils.toStringYMD(new Date()));
|
|
|
+ int compareTo = todayDate.compareTo(vipEndDate1);
|
|
|
+ //0:到当天 1:过期 -1:不过期
|
|
|
+ if (compareTo == 0 || compareTo == -1) {
|
|
|
+ //不过期,续费,计算VIP结束时间
|
|
|
+ vipEndDate = DateUtils.getDesignDateStr(vipEndDate1, DateUtils.sdfyyyyMMdd, Integer.parseInt(vipDate));
|
|
|
+ vipStartDate = vipUserData.getVipStartDate();
|
|
|
+ } else {
|
|
|
+ //过期,删除原来的数据,在重新添加
|
|
|
+ vipGoodsService.deleteVipUser(vipUserData.getId());
|
|
|
+ //过期重新开通,设置新的开始和结束时间
|
|
|
+ vipStartDate = DateUtils.toStringYMD(new Date());
|
|
|
+ vipEndDate = DateUtils.getAfterDate(Integer.parseInt(vipDate));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ VipUserData saveVipUserData = new VipUserData();
|
|
|
+ saveVipUserData.setId(PrimaryIdUtils.getId().toString());
|
|
|
+ saveVipUserData.setUserId(userId);
|
|
|
+ saveVipUserData.setVipGoodsId(vipGoodsId);
|
|
|
+ saveVipUserData.setVipStartDate(vipStartDate);
|
|
|
+ saveVipUserData.setVipEndDate(vipEndDate);
|
|
|
+ saveVipUserData.setCreateTime(LocalDateTime.now());
|
|
|
+ saveVipUserData.setUpdateTime(LocalDateTime.now());
|
|
|
+ vipGoodsService.saveVipUserData(saveVipUserData);
|
|
|
+
|
|
|
+ //修改用户表,添加是VIP用户,VIP最后时间,剩余时长
|
|
|
+ Long vipResidueDate = DateUtils.getDifferenceTime(DateUtils.toDateYMDHMS(vipStartDate), DateUtils.toDateYMDHMS(vipEndDate));
|
|
|
+ SysUser sysUser = sysUserMapper.selectOne(userId);
|
|
|
+ sysUser.setIsVip(true);
|
|
|
+ sysUser.setVipResidueDate(vipResidueDate);
|
|
|
+ sysUser.setVipEndDate(vipEndDate);
|
|
|
+ sysUser.setUpdateTime(new Date());
|
|
|
+ sysUserMapper.update(sysUser);
|
|
|
+
|
|
|
+ //更新订单状态为已支付
|
|
|
+ vipOrderData.setStatus("2"); // 1:待支付 2:已支付 3:已取消
|
|
|
+ vipOrderData.setUpdateTime(LocalDateTime.now());
|
|
|
+ vipGoodsService.updateVipOrderData(vipOrderData);
|
|
|
+
|
|
|
+ logger.info("VIP支付成功处理完成,用户ID:{},订单号:{},VIP结束时间:{}", userId, out_trade_no, vipEndDate);
|
|
|
+
|
|
|
+ return sysUser;
|
|
|
+
|
|
|
+
|
|
|
+ } else {
|
|
|
+ throw new RuntimeException("订单支付失败");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Transaction queryOrderByOutTradeNo(String out_trade_no) {
|
|
|
+ return queryOrderByOutTradeNo(out_trade_no, "app");
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 根据订单号和支付类型查询订单状态
|
|
|
+ * @param out_trade_no 订单号
|
|
|
+ * @param payType 支付类型:app 或 miniprogram
|
|
|
+ * @return 交易信息
|
|
|
+ */
|
|
|
+ public Transaction queryOrderByOutTradeNo(String out_trade_no, String payType) {
|
|
|
+ Config config;
|
|
|
+
|
|
|
+ if ("miniprogram".equals(payType)) {
|
|
|
+ // 使用小程序配置
|
|
|
+ config = new RSAAutoCertificateConfig.Builder()
|
|
|
+ .merchantId(wxPayMiniprogramConfig.getMchID())
|
|
|
+ .privateKeyFromPath(wxPayMiniprogramConfig.getCertPath())
|
|
|
+ .merchantSerialNumber(wxPayMiniprogramConfig.getMerchantSerialNumber())
|
|
|
+ .apiV3Key(wxPayMiniprogramConfig.getV3Key())
|
|
|
+ .build();
|
|
|
+ } else {
|
|
|
+ // 使用APP配置
|
|
|
+ config = new RSAAutoCertificateConfig.Builder()
|
|
|
+ .merchantId(wxPayAppConfig.getMchID())
|
|
|
+ .privateKeyFromPath(wxPayAppConfig.getCertPath())
|
|
|
+ .merchantSerialNumber(wxPayAppConfig.getMerchantSerialNumber())
|
|
|
+ .apiV3Key(v3Key)
|
|
|
+ .build();
|
|
|
+ }
|
|
|
+
|
|
|
+ // 构建service - 对于查询订单,使用JsapiService即可(小程序和APP都支持)
|
|
|
+ JsapiService service = new JsapiService.Builder().config(config).build();
|
|
|
+ com.wechat.pay.java.service.payments.jsapi.model.QueryOrderByOutTradeNoRequest queryOrderByOutTradeNoRequest = new com.wechat.pay.java.service.payments.jsapi.model.QueryOrderByOutTradeNoRequest();
|
|
|
+ queryOrderByOutTradeNoRequest.setOutTradeNo(out_trade_no);
|
|
|
+ queryOrderByOutTradeNoRequest.setMchid("miniprogram".equals(payType) ?
|
|
|
+ wxPayMiniprogramConfig.getMchID() : wxPayAppConfig.getMchID());
|
|
|
+
|
|
|
+ Transaction transaction = service.queryOrderByOutTradeNo(queryOrderByOutTradeNoRequest);
|
|
|
+ Transaction.TradeStateEnum tradeState = transaction.getTradeState();
|
|
|
+ logger.info("{}支付订单查询结果 - 订单号:{},状态:{}", payType, out_trade_no, tradeState.name());
|
|
|
+
|
|
|
+ if ("SUCCESS".equals(tradeState.name())) {
|
|
|
+ logger.info("支付成功:{}", transaction);
|
|
|
+ }
|
|
|
+ return transaction;
|
|
|
+ }
|
|
|
+
|
|
|
+ // ============= 小程序支付相关实现 =============
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Object miniprogramUnifiedOrder(String vipGoodsId, String openid) {
|
|
|
+ logger.info("小程序支付基础信息:{}", wxPayMiniprogramConfig);
|
|
|
+ logger.info("用户openid:{}", openid);
|
|
|
+
|
|
|
+ //查询商品是否存在,存在则下单,不存在则不下单
|
|
|
+ VipGoodsData data = vipGoodsService.getById(vipGoodsId);
|
|
|
+ if (Objects.isNull(data)) {
|
|
|
+ throw new RuntimeException("VIP商品不存在");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (StringUtils.isBlank(openid)) {
|
|
|
+ throw new RuntimeException("用户openid不能为空");
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 使用自动更新平台证书的RSA配置
|
|
|
+ Config config = new RSAAutoCertificateConfig.Builder()
|
|
|
+ .merchantId(wxPayMiniprogramConfig.getMchID())
|
|
|
+ .privateKeyFromPath(wxPayMiniprogramConfig.getCertPath())
|
|
|
+ .merchantSerialNumber(wxPayMiniprogramConfig.getMerchantSerialNumber())
|
|
|
+ .apiV3Key(wxPayMiniprogramConfig.getV3Key())
|
|
|
+ .build();
|
|
|
+
|
|
|
+ // 构建service
|
|
|
+ JsapiService service = new JsapiService.Builder().config(config).build();
|
|
|
+ String orderNo = PrimaryIdUtils.getId().toString();
|
|
|
+
|
|
|
+ // 构建小程序支付请求
|
|
|
+ com.wechat.pay.java.service.payments.jsapi.model.PrepayRequest request = new com.wechat.pay.java.service.payments.jsapi.model.PrepayRequest();
|
|
|
+ com.wechat.pay.java.service.payments.jsapi.model.Amount amount = new com.wechat.pay.java.service.payments.jsapi.model.Amount();
|
|
|
+
|
|
|
+ //金额计算,乘以100转换为分
|
|
|
+ String money = data.getVipMoney();
|
|
|
+ int orderAmount = (int) (Double.parseDouble(money) * 100);
|
|
|
+
|
|
|
+ amount.setTotal(orderAmount);
|
|
|
+ request.setAmount(amount);
|
|
|
+ request.setAppid(wxPayMiniprogramConfig.getAppID());
|
|
|
+ request.setMchid(wxPayMiniprogramConfig.getMchID());
|
|
|
+ request.setDescription(data.getName());
|
|
|
+ request.setNotifyUrl(wxPayMiniprogramConfig.getPayNotifyUrl());
|
|
|
+ request.setOutTradeNo(orderNo);
|
|
|
+
|
|
|
+ // 设置支付者信息
|
|
|
+ Payer payer = new Payer();
|
|
|
+ payer.setOpenid(openid);
|
|
|
+ request.setPayer(payer);
|
|
|
+
|
|
|
+ // 调用下单方法,得到应答
|
|
|
+ com.wechat.pay.java.service.payments.jsapi.model.PrepayResponse response = service.prepay(request);
|
|
|
+ logger.info("调用微信小程序下单返回的信息是:{}", response);
|
|
|
+
|
|
|
+ String prepayId = response.getPrepayId();
|
|
|
+
|
|
|
+ // 构建小程序支付参数
|
|
|
+ MiniprogramPayData payData = new MiniprogramPayData();
|
|
|
+
|
|
|
+ // 生成时间戳
|
|
|
+ long timestamp = System.currentTimeMillis() / 1000;
|
|
|
+ String timeStamp = String.valueOf(timestamp);
|
|
|
+
|
|
|
+ // 生成随机字符串
|
|
|
+ String nonceStr = UUID.randomUUID().toString().replaceAll("-", "");
|
|
|
+
|
|
|
+ // 构建package参数
|
|
|
+ String packageParam = "prepay_id=" + prepayId;
|
|
|
+
|
|
|
+ // 生成签名
|
|
|
+ String signStr = wxPayMiniprogramConfig.getAppID() + "\n" + timeStamp + "\n" + nonceStr + "\n" + packageParam + "\n";
|
|
|
+ SignatureResult signatureResult = config.createSigner().sign(signStr);
|
|
|
+ String paySign = signatureResult.getSign();
|
|
|
+
|
|
|
+ // 设置小程序支付参数
|
|
|
+ payData.setTimeStamp(timeStamp);
|
|
|
+ payData.setNonceStr(nonceStr);
|
|
|
+ payData.setPackage_(packageParam);
|
|
|
+ payData.setPackageParam(packageParam); // 设置用于uni.requestPayment的package字段
|
|
|
+ payData.setSignType("MD5");
|
|
|
+ payData.setPaySign(paySign);
|
|
|
+ payData.setOut_trade_no(orderNo);
|
|
|
+ payData.setPrepay_id(prepayId);
|
|
|
+ payData.setDescription(data.getName());
|
|
|
+ payData.setTotal(orderAmount);
|
|
|
+ payData.setRawData(response);
|
|
|
+
|
|
|
+ logger.info("小程序支付参数:{}", payData);
|
|
|
+
|
|
|
+ // 通过openid查询用户ID
|
|
|
+ String userId = null;
|
|
|
+ try {
|
|
|
+ SysUser user = sysUserMapper.selectByOpenId(openid);
|
|
|
+ if (user != null) {
|
|
|
+ userId = user.getId();
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ logger.warn("根据openid查询用户失败: {}", openid, e);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 生成订单记录
|
|
|
+ VipOrderData orderData = new VipOrderData();
|
|
|
+ orderData.setId(PrimaryIdUtils.getId().toString());
|
|
|
+ orderData.setOutTradeNo(orderNo);
|
|
|
+ orderData.setStatus("1");
|
|
|
+ orderData.setVipGoodsId(vipGoodsId);
|
|
|
+ orderData.setUserId(userId); // 记录用户ID
|
|
|
+ orderData.setOpenid(openid); // 记录openid
|
|
|
+ orderData.setCreateTime(LocalDateTime.now());
|
|
|
+ orderData.setUpdateTime(LocalDateTime.now());
|
|
|
+ vipGoodsService.insertVipOrderData(orderData);
|
|
|
+
|
|
|
+ return payData;
|
|
|
+
|
|
|
+ } catch (Exception e) {
|
|
|
+ logger.error("小程序支付下单失败 - vipGoodsId: {}, openid: {}", vipGoodsId, openid, e);
|
|
|
+ String errorMsg = e.getMessage();
|
|
|
+ if (errorMsg == null || errorMsg.trim().isEmpty()) {
|
|
|
+ errorMsg = e.getClass().getSimpleName() + ": " + e.toString();
|
|
|
+ }
|
|
|
+ throw new RuntimeException("小程序支付下单失败: " + errorMsg);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public String miniprogramNotify(String notifyStr) {
|
|
|
+ String xmlBack = "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[报文为空]]></return_msg></xml>";
|
|
|
+ try {
|
|
|
+ // 转换成map
|
|
|
+ Map<String, String> resultMap = WXPayUtil.xmlToMap(notifyStr);
|
|
|
+ WXPay wxpayMiniprogram = new WXPay(wxPayMiniprogramConfig);
|
|
|
+ if (wxpayMiniprogram.isPayResultNotifySignatureValid(resultMap)) {
|
|
|
+ String returnCode = resultMap.get("return_code"); //状态
|
|
|
+ String outTradeNo = resultMap.get("out_trade_no");//商户订单号
|
|
|
+ String transactionId = resultMap.get("transaction_id");
|
|
|
+ if ("SUCCESS".equals(returnCode)) {
|
|
|
+ if (StringUtils.isNotBlank(outTradeNo)) {
|
|
|
+ logger.info("小程序支付异步通知成功,订单号:{}", outTradeNo);
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 查询订单信息
|
|
|
+ VipOrderData vipOrderData = vipGoodsService.getOrderByOutTradeNo(outTradeNo);
|
|
|
+ if (vipOrderData != null && "1".equals(vipOrderData.getStatus())) {
|
|
|
+ // 订单状态为待支付,进行VIP处理
|
|
|
+ String vipGoodsId = vipOrderData.getVipGoodsId();
|
|
|
+ String userId = vipOrderData.getUserId();
|
|
|
+
|
|
|
+ if (StringUtils.isNotBlank(userId)) {
|
|
|
+ // 有用户ID,执行完整的VIP处理逻辑
|
|
|
+ logger.info("开始处理小程序支付异步通知VIP逻辑 - 用户ID: {}, 订单号: {}", userId, outTradeNo);
|
|
|
+
|
|
|
+ // 查询VIP商品信息
|
|
|
+ VipGoodsData vipGoodsData = vipGoodsService.getById(vipGoodsId);
|
|
|
+ if (vipGoodsData != null) {
|
|
|
+ // 处理VIP逻辑(复用success方法的逻辑)
|
|
|
+ handleVipLogic(userId, vipGoodsId, vipGoodsData, outTradeNo);
|
|
|
+ logger.info("小程序支付异步通知VIP处理完成 - 用户ID: {}, 订单号: {}", userId, outTradeNo);
|
|
|
+ } else {
|
|
|
+ logger.warn("VIP商品不存在 - vipGoodsId: {}, 订单号: {}", vipGoodsId, outTradeNo);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ logger.warn("订单中缺少用户ID,无法处理VIP逻辑 - 订单号: {}", outTradeNo);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 更新订单状态为已支付
|
|
|
+ vipOrderData.setStatus("2"); // 已支付
|
|
|
+ vipOrderData.setUpdateTime(LocalDateTime.now());
|
|
|
+ vipGoodsService.updateVipOrderData(vipOrderData);
|
|
|
+
|
|
|
+ logger.info("小程序支付异步通知处理完成,订单号:{}", outTradeNo);
|
|
|
+ } else {
|
|
|
+ logger.info("小程序支付异步通知 - 订单已处理或不存在,订单号:{}", outTradeNo);
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ logger.error("小程序支付异步通知业务处理失败,订单号:{}", outTradeNo, e);
|
|
|
+ // 即使业务处理失败,也要返回SUCCESS,避免微信重复通知
|
|
|
+ }
|
|
|
+
|
|
|
+ xmlBack = "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ logger.warn("小程序支付异步通知签名验证失败");
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ logger.error("小程序支付通知处理失败", e);
|
|
|
+ }
|
|
|
+ return xmlBack;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public SysUser miniprogramSuccess(String vipGoodsId, String out_trade_no) {
|
|
|
+ //查询商品是否存在,存在则下单,不存在则不下单
|
|
|
+ VipGoodsData data = vipGoodsService.getById(vipGoodsId);
|
|
|
+ if (Objects.isNull(data)) {
|
|
|
+ throw new RuntimeException("VIP商品不存在");
|
|
|
+ }
|
|
|
+
|
|
|
+ VipOrderData vipOrderData = vipGoodsService.getOrderByOutTradeNo(out_trade_no);
|
|
|
+ if (Objects.isNull(vipOrderData)) {
|
|
|
+ throw new RuntimeException("订单不存在");
|
|
|
+ }
|
|
|
+
|
|
|
+ //查询订单是否支付成功,支付成功:生成VIP时长,失败异常
|
|
|
+ Transaction transaction = queryOrderByOutTradeNo(out_trade_no, "miniprogram");
|
|
|
+
|
|
|
+ Transaction.TradeStateEnum tradeState = transaction.getTradeState();
|
|
|
+ logger.info("小程序支付订单查询结果 - 订单号:{},状态:{}", out_trade_no, tradeState.name());
|
|
|
+
|
|
|
+ if ("SUCCESS".equals(tradeState.name())) {
|
|
|
+ logger.info("小程序支付成功:{}", transaction);
|
|
|
+ //查询用户是否已经开通过,开通过则续费,没有开通过怎插新数据
|
|
|
+ String userId = TokenUtils.getUserId();
|
|
|
+ VipUserData vipUserData = vipGoodsService.selectByUserId(userId, vipGoodsId);
|
|
|
+ //VIP时长
|
|
|
+ String vipStartDate = "";
|
|
|
+ String vipEndDate = "";
|
|
|
+ String vipDate = data.getVipDate();
|
|
|
+ if (Objects.isNull(vipUserData)) {
|
|
|
+ //没有开通过,新开通,开始时间=当天时间,结束时间=会员时长+当前时间
|
|
|
+ vipStartDate = DateUtils.toStringYMD(new Date());
|
|
|
+ vipEndDate = DateUtils.getAfterDate(Integer.parseInt(vipDate));
|
|
|
+
|
|
|
+ } else {
|
|
|
+ //开通过,查看有没有过期,过期:新开通,不过期,续费
|
|
|
+ String vipEndDateStr = vipUserData.getVipEndDate();
|
|
|
+ Date vipEndDate1 = DateUtils.toDateYMDHMS(vipEndDateStr);
|
|
|
+ Date todayDate = DateUtils.toDateYMDHMS(DateUtils.toStringYMD(new Date()));
|
|
|
+ int compareTo = todayDate.compareTo(vipEndDate1);
|
|
|
+ //0:到当天 1:过期 -1:不过期
|
|
|
+ if (compareTo == 0 || compareTo == -1) {
|
|
|
+ //不过期,续费,计算VIP结束时间
|
|
|
+ vipEndDate = DateUtils.getDesignDateStr(vipEndDate1, DateUtils.sdfyyyyMMdd, Integer.parseInt(vipDate));
|
|
|
+ vipStartDate = vipUserData.getVipStartDate();
|
|
|
+ } else {
|
|
|
+ //过期,删除原来的数据,在重新添加
|
|
|
+ vipGoodsService.deleteVipUser(vipUserData.getId());
|
|
|
+ //过期重新开通,设置新的开始和结束时间
|
|
|
+ vipStartDate = DateUtils.toStringYMD(new Date());
|
|
|
+ vipEndDate = DateUtils.getAfterDate(Integer.parseInt(vipDate));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ VipUserData saveVipUserData = new VipUserData();
|
|
|
+ saveVipUserData.setId(PrimaryIdUtils.getId().toString());
|
|
|
+ saveVipUserData.setUserId(userId);
|
|
|
+ saveVipUserData.setVipGoodsId(vipGoodsId);
|
|
|
+ saveVipUserData.setVipStartDate(vipStartDate);
|
|
|
+ saveVipUserData.setVipEndDate(vipEndDate);
|
|
|
+ saveVipUserData.setCreateTime(LocalDateTime.now());
|
|
|
+ saveVipUserData.setUpdateTime(LocalDateTime.now());
|
|
|
+ vipGoodsService.saveVipUserData(saveVipUserData);
|
|
|
+
|
|
|
+ //修改用户表,添加是VIP用户,VIP最后时间,剩余时长
|
|
|
+ Long vipResidueDate = DateUtils.getDifferenceTime(DateUtils.toDateYMDHMS(vipStartDate), DateUtils.toDateYMDHMS(vipEndDate));
|
|
|
+ SysUser sysUser = sysUserMapper.selectOne(userId);
|
|
|
+ sysUser.setIsVip(true);
|
|
|
+ sysUser.setVipResidueDate(vipResidueDate);
|
|
|
+ sysUser.setVipEndDate(vipEndDate);
|
|
|
+ sysUser.setUpdateTime(new Date());
|
|
|
+ sysUserMapper.update(sysUser);
|
|
|
+
|
|
|
+ //更新订单状态为已支付
|
|
|
+ vipOrderData.setStatus("2"); // 1:待支付 2:已支付 3:已取消
|
|
|
+ vipOrderData.setUpdateTime(LocalDateTime.now());
|
|
|
+ vipGoodsService.updateVipOrderData(vipOrderData);
|
|
|
+
|
|
|
+ logger.info("小程序VIP支付成功处理完成,用户ID:{},订单号:{},VIP结束时间:{}", userId, out_trade_no, vipEndDate);
|
|
|
+
|
|
|
+ return sysUser;
|
|
|
+
|
|
|
+ } else {
|
|
|
+ throw new RuntimeException("小程序订单支付失败,状态:" + tradeState.name());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 处理VIP逻辑(抽取的公共方法,供success和异步通知使用)
|
|
|
+ * @param userId 用户ID
|
|
|
+ * @param vipGoodsId VIP商品ID
|
|
|
+ * @param vipGoodsData VIP商品信息
|
|
|
+ * @param outTradeNo 订单号
|
|
|
+ */
|
|
|
+ private void handleVipLogic(String userId, String vipGoodsId, VipGoodsData vipGoodsData, String outTradeNo) {
|
|
|
+ try {
|
|
|
+ //查询用户是否已经开通过,开通过则续费,没有开通过则插新数据
|
|
|
+ VipUserData vipUserData = vipGoodsService.selectByUserId(userId, vipGoodsId);
|
|
|
+ //VIP时长
|
|
|
+ String vipStartDate = "";
|
|
|
+ String vipEndDate = "";
|
|
|
+ String vipDate = vipGoodsData.getVipDate();
|
|
|
+
|
|
|
+ if (Objects.isNull(vipUserData)) {
|
|
|
+ //没有开通过,新开通,开始时间=当天时间,结束时间=会员时长+当前时间
|
|
|
+ vipStartDate = DateUtils.toStringYMD(new Date());
|
|
|
+ vipEndDate = DateUtils.getAfterDate(Integer.parseInt(vipDate));
|
|
|
+ } else {
|
|
|
+ //开通过,查看有没有过期,过期:新开通,不过期,续费
|
|
|
+ String vipEndDateStr = vipUserData.getVipEndDate();
|
|
|
+ Date vipEndDate1 = DateUtils.toDateYMDHMS(vipEndDateStr);
|
|
|
+ Date todayDate = DateUtils.toDateYMDHMS(DateUtils.toStringYMD(new Date()));
|
|
|
+ int compareTo = todayDate.compareTo(vipEndDate1);
|
|
|
+ //0:到当天 1:过期 -1:不过期
|
|
|
+ if (compareTo == 0 || compareTo == -1) {
|
|
|
+ //不过期,续费,计算VIP结束时间
|
|
|
+ vipEndDate = DateUtils.getDesignDateStr(vipEndDate1, DateUtils.sdfyyyyMMdd, Integer.parseInt(vipDate));
|
|
|
+ vipStartDate = vipUserData.getVipStartDate();
|
|
|
+ } else {
|
|
|
+ //过期,删除原来的数据,在重新添加
|
|
|
+ vipGoodsService.deleteVipUser(vipUserData.getId());
|
|
|
+ //过期重新开通,设置新的开始和结束时间
|
|
|
+ vipStartDate = DateUtils.toStringYMD(new Date());
|
|
|
+ vipEndDate = DateUtils.getAfterDate(Integer.parseInt(vipDate));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ VipUserData saveVipUserData = new VipUserData();
|
|
|
+ saveVipUserData.setId(PrimaryIdUtils.getId().toString());
|
|
|
+ saveVipUserData.setUserId(userId);
|
|
|
+ saveVipUserData.setVipGoodsId(vipGoodsId);
|
|
|
+ saveVipUserData.setVipStartDate(vipStartDate);
|
|
|
+ saveVipUserData.setVipEndDate(vipEndDate);
|
|
|
+ saveVipUserData.setCreateTime(LocalDateTime.now());
|
|
|
+ saveVipUserData.setUpdateTime(LocalDateTime.now());
|
|
|
+ vipGoodsService.saveVipUserData(saveVipUserData);
|
|
|
+
|
|
|
+ //修改用户表,添加是VIP用户,VIP最后时间,剩余时长
|
|
|
+ Long vipResidueDate = DateUtils.getDifferenceTime(DateUtils.toDateYMDHMS(vipStartDate), DateUtils.toDateYMDHMS(vipEndDate));
|
|
|
+ SysUser sysUser = sysUserMapper.selectOne(userId);
|
|
|
+ if (sysUser != null) {
|
|
|
+ sysUser.setIsVip(true);
|
|
|
+ sysUser.setVipResidueDate(vipResidueDate);
|
|
|
+ sysUser.setVipEndDate(vipEndDate);
|
|
|
+ sysUser.setUpdateTime(new Date());
|
|
|
+ sysUserMapper.update(sysUser);
|
|
|
+
|
|
|
+ logger.info("VIP处理完成 - 用户ID: {}, 订单号: {}, VIP结束时间: {}", userId, outTradeNo, vipEndDate);
|
|
|
+ } else {
|
|
|
+ logger.warn("用户不存在,无法更新VIP状态 - 用户ID: {}", userId);
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ logger.error("VIP逻辑处理失败 - 用户ID: {}, 订单号: {}", userId, outTradeNo, e);
|
|
|
+ throw e;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public static void main(String[] args) throws IOException {
|
|
|
+
|
|
|
+
|
|
|
+/** Native 支付下单为例 */
|
|
|
+
|
|
|
+
|
|
|
+ /* *//** 商户号 *//*
|
|
|
+ String merchantId = "1659536133";
|
|
|
+ *//** 商户API私钥路径 *//*
|
|
|
+ String privateKeyPath = "D:\\soft\\WXCertUtil\\WXCertUtil\\cert\\1659536133_20240224_cert\\apiclient_key.pem";
|
|
|
+ *//** 商户证书序列号 *//*
|
|
|
+ String merchantSerialNumber = "2C9364545EF9C4C82700563B8C398451E14743B3";
|
|
|
+ *//** 商户APIV3密钥 *//*
|
|
|
+ String apiV3Key = "A123456789B123456789C1234567890D";
|
|
|
+
|
|
|
+ // 使用自动更新平台证书的RSA配置
|
|
|
+ // 一个商户号只能初始化一个配置,否则会因为重复的下载任务报错
|
|
|
+ Config config =
|
|
|
+ new RSAAutoCertificateConfig.Builder()
|
|
|
+ .merchantId(merchantId)
|
|
|
+ .privateKeyFromPath(privateKeyPath)
|
|
|
+ .merchantSerialNumber(merchantSerialNumber)
|
|
|
+ .apiV3Key(apiV3Key)
|
|
|
+ .build();
|
|
|
+ // 构建service
|
|
|
+ AppService service = new AppService.Builder().config(config).build();
|
|
|
+ // request.setXxx(val)设置所需参数,具体参数可见Request定义
|
|
|
+
|
|
|
+ String orderNo = PrimaryIdUtils.getId().toString();
|
|
|
+ PrepayRequest request = new PrepayRequest();
|
|
|
+ Amount amount = new Amount();
|
|
|
+ amount.setTotal(100);
|
|
|
+ request.setAmount(amount);
|
|
|
+ request.setAppid("wx8fdb27b97ed17533");
|
|
|
+ request.setMchid("1659536133");
|
|
|
+ request.setDescription("VIP一个月商品");
|
|
|
+ request.setNotifyUrl("http://120.46.40.61:18885/api/swagger-ui.html");
|
|
|
+ request.setOutTradeNo(orderNo);
|
|
|
+ // 调用下单方法,得到应答
|
|
|
+ PrepayResponse response = service.prepay(request);
|
|
|
+ // 使用微信扫描 code_url 对应的二维码,即可体验Native支付
|
|
|
+ System.out.println(">>>>>>>>>>>:" + response);*/
|
|
|
+
|
|
|
+
|
|
|
+ String noncestr = UUID.randomUUID().toString().replaceAll("-", "");
|
|
|
+ long currentTimeMillis = System.currentTimeMillis() / 1000;
|
|
|
+ System.out.println(currentTimeMillis);
|
|
|
+ // System.out.println(noncestr.length());
|
|
|
+
|
|
|
+
|
|
|
+ /* Calendar calendar = Calendar.getInstance();
|
|
|
+ calendar.add(Calendar.DAY_OF_MONTH, 2);
|
|
|
+
|
|
|
+ int year = calendar.get(Calendar.YEAR);
|
|
|
+ int month = calendar.get(Calendar.MONTH) + 1;
|
|
|
+ int day = calendar.get(Calendar.DAY_OF_MONTH);
|
|
|
+
|
|
|
+ System.out.println("7天后的日期为:" + year + "-" + month + "-" + day);*/
|
|
|
+
|
|
|
+ //Base64.getDecoder().decode("NDU1ODAwNjk2M0QyOTE2QTMwNjBGNUQwMTEwNkU4ODA0OTcyQTkyOTVDRkJGRTYzQUMzOUYyRkE5Q0RGQ0Y1Qg==");
|
|
|
+
|
|
|
+
|
|
|
+ String vipEndDateStr = "2024-03-3";
|
|
|
+ Date vipEndDate = DateUtils.toDateYMDHMS(vipEndDateStr);
|
|
|
+ Date date = DateUtils.toDateYMDHMS(DateUtils.toStringYMD(new Date()));
|
|
|
+ int compareTo = vipEndDate.compareTo(date);
|
|
|
+ System.out.println(compareTo);
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ /* public Transaction queryOrderByOutTradeNo(QueryOrderByOutTradeNoRequest request) {
|
|
|
+ String requestPath =
|
|
|
+ "https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/{out_trade_no}";
|
|
|
+ QueryOrderByOutTradeNoRequest realRequest = request;
|
|
|
+ // 添加 path param
|
|
|
+ requestPath =
|
|
|
+ requestPath.replace("{" + "out_trade_no" + "}", urlEncode(realRequest.getOutTradeNo()));
|
|
|
+
|
|
|
+ // 添加 query param
|
|
|
+ QueryParameter queryParameter = new QueryParameter();
|
|
|
+ if (realRequest.getMchid() != null) {
|
|
|
+ queryParameter.add("mchid", urlEncode(realRequest.getMchid()));
|
|
|
+ }
|
|
|
+ requestPath += queryParameter.getQueryStr();
|
|
|
+ HttpHeaders headers = new HttpHeaders();
|
|
|
+ headers.addHeader(Constant.ACCEPT, MediaType.APPLICATION_JSON.getValue());
|
|
|
+ headers.addHeader(Constant.CONTENT_TYPE, MediaType.APPLICATION_JSON.getValue());
|
|
|
+ HttpRequest httpRequest =
|
|
|
+ new HttpRequest.Builder()
|
|
|
+ .httpMethod(HttpMethod.GET)
|
|
|
+ .url(requestPath)
|
|
|
+ .headers(headers)
|
|
|
+ .build();
|
|
|
+
|
|
|
+ HttpResponse<Transaction> httpResponse = httpClient.execute(httpRequest, Transaction.class);
|
|
|
+ return httpResponse.getServiceResponse();
|
|
|
+ }*/
|
|
|
+
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|