diff --git a/ebike-payment/pom.xml b/ebike-payment/pom.xml index 036b922e..61176243 100644 --- a/ebike-payment/pom.xml +++ b/ebike-payment/pom.xml @@ -32,12 +32,12 @@ ebike-feign 0.0.1-SNAPSHOT - - com.github.wechatpay-apiv3 - wechatpay-java - 0.2.17 + org.springframework.boot + spring-boot-starter-web + ${boot.version} + com.mybatis-flex @@ -50,6 +50,33 @@ ${mybatis-flex.version} provided + + + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-discovery + ${nacos.version} + + + com.mysql + mysql-connector-j + ${mysql.version} + runtime + + + org.springframework.boot + spring-boot-starter + ${boot.version} + + + org.springframework.cloud + spring-cloud-starter-loadbalancer + + + + com.github.wechatpay-apiv3 + wechatpay-java + 0.2.17 + org.projectlombok lombok @@ -101,28 +128,6 @@ fastjson2 ${fastjson.version} - - - com.alibaba.cloud - spring-cloud-starter-alibaba-nacos-discovery - ${nacos.version} - - - org.springframework.cloud - spring-cloud-starter-loadbalancer - - - com.mysql - mysql-connector-j - ${mysql.version} - runtime - - - jakarta.servlet - jakarta.servlet-api - 6.0.0 - provided - org.springframework.boot diff --git a/ebike-payment/src/main/java/com/cdzy/payment/EbikePaymentApplication.java b/ebike-payment/src/main/java/com/cdzy/payment/EbikePaymentApplication.java index f4aaa2e2..950d1016 100644 --- a/ebike-payment/src/main/java/com/cdzy/payment/EbikePaymentApplication.java +++ b/ebike-payment/src/main/java/com/cdzy/payment/EbikePaymentApplication.java @@ -3,6 +3,7 @@ package com.cdzy.payment; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.openfeign.EnableFeignClients; import org.springframework.scheduling.annotation.EnableScheduling; /** @@ -14,6 +15,7 @@ import org.springframework.scheduling.annotation.EnableScheduling; */ @SpringBootApplication @MapperScan("com.cdzy.payment.mapper") +@EnableFeignClients(basePackages = "com.ebike.feign") public class EbikePaymentApplication { public static void main(String[] args) { SpringApplication.run(EbikePaymentApplication.class, args); diff --git a/ebike-payment/src/main/java/com/cdzy/payment/config/WxPayConfig.java b/ebike-payment/src/main/java/com/cdzy/payment/config/WxPayConfig.java index 2b42de6a..a5f281ae 100644 --- a/ebike-payment/src/main/java/com/cdzy/payment/config/WxPayConfig.java +++ b/ebike-payment/src/main/java/com/cdzy/payment/config/WxPayConfig.java @@ -3,6 +3,7 @@ package com.cdzy.payment.config; import com.wechat.pay.java.core.Config; import com.wechat.pay.java.core.RSAPublicKeyConfig; import com.wechat.pay.java.core.cipher.RSASigner; +import com.wechat.pay.java.core.cipher.Signer; import com.wechat.pay.java.core.util.PemUtil; import com.wechat.pay.java.service.payments.jsapi.JsapiService; import com.wechat.pay.java.service.refund.RefundService; @@ -62,9 +63,14 @@ public class WxPayConfig { private String refundNotifyUrl; /** * 支付、退款过期时间(分钟) - * 默认5分钟,超过5分钟订单会自动关闭 + * 默认24小时,超过24小时订单会自动关闭 */ - private Integer expireMinute = 5; + private Integer expireMinute = 1440; + /** + * 定时任务执行表达式 + * 默认每12小时执行1次 + */ + private String cronExpression = "0 0 0,12 * * ?"; @Bean public Config certificateConfig() { @@ -90,9 +96,8 @@ public class WxPayConfig { } @Bean - public RSASigner wxRsaSigner(){ - PrivateKey privateKey = PemUtil.loadPrivateKeyFromPath(privateKeyPath); - return new RSASigner(merchantSerialNumber, privateKey); + public Signer wxRsaSigner(Config certificateConfig){ + return certificateConfig.createSigner(); } } diff --git a/ebike-payment/src/main/java/com/cdzy/payment/controller/EbikeWxPaymentController.java b/ebike-payment/src/main/java/com/cdzy/payment/controller/EbikeWxPaymentController.java index 9f7509f5..4882b754 100644 --- a/ebike-payment/src/main/java/com/cdzy/payment/controller/EbikeWxPaymentController.java +++ b/ebike-payment/src/main/java/com/cdzy/payment/controller/EbikeWxPaymentController.java @@ -31,7 +31,7 @@ public class EbikeWxPaymentController { * @param orderId 骑行订单id * @return 下单成功返回true,否则返回false */ - @PostMapping("/prepay") + @GetMapping("/prepay") public JsonResult prepay(@RequestParam(name = "orderId") String orderId) { JSONObject r = wxPayService.prepay(orderId); return r.containsKey("error")?JsonResult.failed("下单失败: "+ r.getString("error")):JsonResult.success(r); @@ -44,8 +44,8 @@ public class EbikeWxPaymentController { * @return 支付订单信息 */ @GetMapping("/queryOrder/{orderId}") - public JsonResult queryOrderByOutTradeNo(@PathVariable String orderId) { - Transaction r = wxPayService.queryOrderByOutTradeNo(orderId); + public JsonResult queryOrderByOrderId(@PathVariable(name = "orderId") String orderId) { + Transaction r = wxPayService.queryOrderByOrderId(orderId); return r == null?JsonResult.failed(String.format("骑行订单号{%s}查询支付订单失败", orderId)):JsonResult.success(r); } @@ -56,8 +56,8 @@ public class EbikeWxPaymentController { * @return 订单信息支付状态 */ @GetMapping("/queryOrderStatus/{orderId}") - public JsonResult queryOrderStatusById(@PathVariable String orderId) { - HandleNotifyResult r = wxPayService.queryOrderStatusByOutTradeNo(orderId); + public JsonResult queryOrderStatusById(@PathVariable(name = "orderId") String orderId) { + HandleNotifyResult r = wxPayService.queryOrderStatusByOrderId(orderId); return JsonResult.success(r); } @@ -93,7 +93,7 @@ public class EbikeWxPaymentController { * @return 退款信息 */ @GetMapping("/queryRefund/{refundId}") - public JsonResult refundQuery(@PathVariable String refundId) { + public JsonResult refundQuery(@PathVariable(name = "refundId") String refundId) { Refund r = wxPayService.queryRefundByOutNo(refundId); return r == null?JsonResult.failed(String.format("退款单号{%s}查询退款失败", refundId)):JsonResult.success(r); } diff --git a/ebike-payment/src/main/java/com/cdzy/payment/model/dto/WxJsapiPromptDto.java b/ebike-payment/src/main/java/com/cdzy/payment/model/dto/WxJsapiPromptDto.java index 93896d5b..b8abd887 100644 --- a/ebike-payment/src/main/java/com/cdzy/payment/model/dto/WxJsapiPromptDto.java +++ b/ebike-payment/src/main/java/com/cdzy/payment/model/dto/WxJsapiPromptDto.java @@ -2,8 +2,8 @@ package com.cdzy.payment.model.dto; import com.alibaba.fastjson2.JSONObject; import com.alibaba.fastjson2.annotation.JSONField; -import com.wechat.pay.java.core.cipher.RSASigner; import com.wechat.pay.java.core.cipher.SignatureResult; +import com.wechat.pay.java.core.cipher.Signer; import lombok.Data; import lombok.NoArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -49,15 +49,11 @@ public class WxJsapiPromptDto { */ private String paySign; - public JSONObject toJson(RSASigner rsaSigner) { + public JSONObject toJson(Signer rsaSigner) { try{ // 计算签名 - StringJoiner signMsg = new StringJoiner("\n"); - signMsg.add(appId); - signMsg.add(timeStamp); - signMsg.add(nonceStr); - signMsg.add(extension); - SignatureResult sign = rsaSigner.sign(signMsg.toString()); + String signMsg = appId + "\n" + timeStamp + "\n" + nonceStr + "\n" + extension + "\n"; + SignatureResult sign = rsaSigner.sign(signMsg); this.paySign = sign.getSign(); //result.put("package", result.remove("extension")); return JSONObject.parseObject(JSONObject.toJSONString(this)); diff --git a/ebike-payment/src/main/java/com/cdzy/payment/model/entity/EbikePayment.java b/ebike-payment/src/main/java/com/cdzy/payment/model/entity/EbikePayment.java index e2ee5841..e5ebdb5f 100644 --- a/ebike-payment/src/main/java/com/cdzy/payment/model/entity/EbikePayment.java +++ b/ebike-payment/src/main/java/com/cdzy/payment/model/entity/EbikePayment.java @@ -40,7 +40,7 @@ public class EbikePayment implements Serializable { private String orderId; /** - * 预支付交易会话标识;有效期为2小时 + * 支付交易用订单编号,重新请求时需要更新 */ private String paymentId; diff --git a/ebike-payment/src/main/java/com/cdzy/payment/model/entity/EbikeRefund.java b/ebike-payment/src/main/java/com/cdzy/payment/model/entity/EbikeRefund.java index 582e3a3d..3fa0490b 100644 --- a/ebike-payment/src/main/java/com/cdzy/payment/model/entity/EbikeRefund.java +++ b/ebike-payment/src/main/java/com/cdzy/payment/model/entity/EbikeRefund.java @@ -39,10 +39,6 @@ public class EbikeRefund implements Serializable { */ private String orderId; - /** - * 支付记录id - */ - private String recordId; /** * 微信支付订单号 @@ -76,7 +72,7 @@ public class EbikeRefund implements Serializable { private Double refund; /** - * 退款总金额 + * 原订单金额 */ private Double total; diff --git a/ebike-payment/src/main/java/com/cdzy/payment/service/WxPayService.java b/ebike-payment/src/main/java/com/cdzy/payment/service/WxPayService.java index 0ca5189f..11c42fbb 100644 --- a/ebike-payment/src/main/java/com/cdzy/payment/service/WxPayService.java +++ b/ebike-payment/src/main/java/com/cdzy/payment/service/WxPayService.java @@ -27,27 +27,36 @@ public interface WxPayService { /** * JSAPI支付下单 * - * @param outTradeNo 订单id + * @param orderId 订单id * @return 下单成功返回wx支付请求参数,否则返回null */ - JSONObject prepay(String outTradeNo); + JSONObject prepay(String orderId); + + + /** + * 通过支付订单号查询支付订单 + * + * @param outTradeNo 支付订单号 + * @return 支付订单信息 + */ + Transaction queryOrderByOutTradeNo(String outTradeNo); /** * 通过商户(骑行)订单号查询支付订单 * - * @param outTradeNo 商户(骑行)订单号 + * @param orderId 商户(骑行)订单号 * @return 支付订单信息 */ - Transaction queryOrderByOutTradeNo(String outTradeNo); + Transaction queryOrderByOrderId(String orderId); /** * 通过订单号查询支付订单状态 * - * @param outTradeNo 商户(骑行)订单号 + * @param orderId 商户(骑行)订单号 * @return 支付订单信息 */ - HandleNotifyResult queryOrderStatusByOutTradeNo(String outTradeNo); + HandleNotifyResult queryOrderStatusByOrderId(String orderId); /** * 处理支付回调 diff --git a/ebike-payment/src/main/java/com/cdzy/payment/service/impl/EbikePaymentServiceImpl.java b/ebike-payment/src/main/java/com/cdzy/payment/service/impl/EbikePaymentServiceImpl.java index fe01d420..235649a6 100644 --- a/ebike-payment/src/main/java/com/cdzy/payment/service/impl/EbikePaymentServiceImpl.java +++ b/ebike-payment/src/main/java/com/cdzy/payment/service/impl/EbikePaymentServiceImpl.java @@ -4,8 +4,6 @@ import com.cdzy.payment.model.enums.PayMethod; import com.cdzy.payment.utils.StringUtils; import com.ebike.feign.clients.OrdersFeignClient; import com.ebike.feign.model.res.ResFeignOrderPaymentDto; -import com.mybatisflex.core.query.QueryColumn; -import com.mybatisflex.core.query.QueryMethods; import com.mybatisflex.core.query.QueryWrapper; import com.mybatisflex.spring.service.impl.ServiceImpl; import com.cdzy.payment.model.entity.EbikePayment; @@ -18,6 +16,7 @@ import org.springframework.stereotype.Service; import java.util.List; import static com.cdzy.payment.model.entity.table.EbikePaymentTableDef.EBIKE_PAYMENT; +import static com.mybatisflex.core.constant.FuncName.*; /** * 用户订单支付记录 服务层实现。 @@ -33,27 +32,29 @@ public class EbikePaymentServiceImpl extends ServiceImpl getNoPayOrderByDuration(int duration) { - QueryColumn time = QueryMethods.secToTime(String.valueOf(duration * 60)); // trade_state 等于 NOTPAY未支付的, 并且创建时间未超过duration分钟的订单 + String timeFilter = String.format("%s(%s, %s(%s))<%s()", ADDTIME, EBIKE_PAYMENT.CREATE_TIME.getName(), SEC_TO_TIME + , String.valueOf(duration * 60), NOW); QueryWrapper query = QueryWrapper.create() .where(EBIKE_PAYMENT.TRADE_STATE.eq(Transaction.TradeStateEnum.NOTPAY.ordinal())) - .and(QueryMethods.addTime(EBIKE_PAYMENT.CREATE_TIME, time).lt(QueryMethods.now())); + .and(timeFilter); return list(query); } @Override public List getExpireOrderByDuration(int duration) { - QueryColumn time = QueryMethods.secToTime(String.valueOf(duration * 60)); // trade_state 等于 NOTPAY未支付的, 并且创建时间超过duration分钟的订单 + String timeFilter = String.format("%s(%s, %s(%s))>=%s()", ADDTIME, EBIKE_PAYMENT.CREATE_TIME.getName(), SEC_TO_TIME + , String.valueOf(duration * 60), NOW); QueryWrapper query = QueryWrapper.create() .where(EBIKE_PAYMENT.TRADE_STATE.eq(Transaction.TradeStateEnum.NOTPAY.ordinal())) - .and(QueryMethods.addTime(EBIKE_PAYMENT.CREATE_TIME, time).ge(QueryMethods.now())); + .and(timeFilter); return list(query); } @Override public Boolean updatePaymentStatus(Transaction transaction) { - EbikePayment ebikePayment = new EbikePayment(); + EbikePayment ebikePayment = getByPaymentId(transaction.getOutTradeNo()); //ebikePayment.setRecordId(recordId); ebikePayment.setTradeState(String.valueOf(transaction.getTradeState().ordinal())); if (Transaction.TradeStateEnum.SUCCESS.equals(transaction.getTradeState())) { @@ -65,14 +66,12 @@ public class EbikePaymentServiceImpl extends ServiceImpl getNoSuccessRefundOrderByDuration(int duration) { - // trade_state 不等于 SUCCESS退款成功的, 并且创建时间超过duration分钟的订单 + // trade_state 等于 PROCESSING正在退款中的, 并且创建时间超过duration分钟的订单 + String timeFilter = String.format("%s(%s, %s(%s))>=%s()", ADDTIME, EBIKE_REFUND.CREATE_TIME.getName(), SEC_TO_TIME + , String.valueOf(duration * 60), NOW); QueryWrapper query = QueryWrapper.create() .where(EBIKE_REFUND.STATUS.eq(Status.PROCESSING.ordinal())) - .and(QueryMethods.addTime(EBIKE_REFUND.CREATE_TIME, QueryMethods.secToTime(String.valueOf(duration * 60))).ge(QueryMethods.now())); + .and(timeFilter); return list(query); } diff --git a/ebike-payment/src/main/java/com/cdzy/payment/service/impl/WxPayServiceImpl.java b/ebike-payment/src/main/java/com/cdzy/payment/service/impl/WxPayServiceImpl.java index daad6155..64cd1be4 100644 --- a/ebike-payment/src/main/java/com/cdzy/payment/service/impl/WxPayServiceImpl.java +++ b/ebike-payment/src/main/java/com/cdzy/payment/service/impl/WxPayServiceImpl.java @@ -18,7 +18,7 @@ import com.ebike.feign.model.rsp.AmountDto; import com.ebike.feign.model.rsp.DetailDto; import com.ebike.feign.model.rsp.EbikePaymentDto; import com.wechat.pay.java.core.Config; -import com.wechat.pay.java.core.cipher.RSASigner; +import com.wechat.pay.java.core.cipher.Signer; import com.wechat.pay.java.core.exception.HttpException; import com.wechat.pay.java.core.exception.MalformedMessageException; import com.wechat.pay.java.core.exception.ServiceException; @@ -41,6 +41,8 @@ import org.springframework.stereotype.Service; import javax.servlet.http.HttpServletRequest; import java.math.BigDecimal; import java.time.*; +import java.util.ArrayList; +import java.util.List; import static com.wechat.pay.java.core.http.Constant.*; import static com.wechat.pay.java.core.http.Constant.WECHAT_PAY_SERIAL; @@ -63,7 +65,7 @@ public class WxPayServiceImpl implements WxPayService { @Resource private WxPayConfig wxPayConfig; @Resource - private RSASigner wxRsaSigner; + private Signer wxRsaSigner; @Resource private Config certificateConfig; @Resource @@ -71,13 +73,14 @@ public class WxPayServiceImpl implements WxPayService { @Resource private EbikeRefundService ebikeRefundService; @Resource - private OrdersFeignClient orderFeingClient; + private OrdersFeignClient ordersFeignClient; @Override public boolean closeOrder(String outTradeNo) { try { CloseOrderRequest request = new CloseOrderRequest(); request.setOutTradeNo(outTradeNo); + request.setMchid(wxPayConfig.getMerchantId()); wxJsapiService.closeOrder(request); log.info("关闭订单成功,订单号:{}", outTradeNo); // ebikePaymentService.updatePaymentStatus(outTradeNo, 2); @@ -90,27 +93,42 @@ public class WxPayServiceImpl implements WxPayService { @Override - public JSONObject prepay(String outTradeNo){ + public JSONObject prepay(String orderId){ JSONObject r = new JSONObject(); // 首先检查订单是否正在付中、或者已经支付成功 - EbikePayment ebikePayment = ebikePaymentService.getByOrderId(outTradeNo); + // 关闭了的订单,重新发起请求 + EbikePayment ebikePayment = ebikePaymentService.getByOrderId(orderId); if (ebikePayment != null) { - if (String.valueOf(Transaction.TradeStateEnum.SUCCESS.ordinal()).equals(ebikePayment.getTradeState())) { - log.info("订单已经支付成功,订单号:{}", outTradeNo); + String tradeState = ebikePayment.getTradeState(); + if (String.valueOf(Transaction.TradeStateEnum.SUCCESS.ordinal()).equals(tradeState)) { + log.info("订单已经支付成功,订单号:{}", orderId); r.put("error", "订单已经支付成功"); return r; } - if (String.valueOf(Transaction.TradeStateEnum.NOTPAY.ordinal()).equals(ebikePayment.getTradeState()) - ||String.valueOf(Transaction.TradeStateEnum.USERPAYING.ordinal()).equals(ebikePayment.getTradeState())) { - log.info("订单正在支付中,订单号:{}", outTradeNo); - r.put("error", "订单正在支付中"); - return null; + if (String.valueOf(Transaction.TradeStateEnum.NOTPAY.ordinal()).equals(tradeState) + ||String.valueOf(Transaction.TradeStateEnum.USERPAYING.ordinal()).equals(tradeState)) { + // 检查订单是否关闭 + Transaction t = queryOrderByOutTradeNo(ebikePayment.getPaymentId()); + if (t != null && Transaction.TradeStateEnum.CLOSED.equals(t.getTradeState())) { + log.info("订单已经关闭,订单号:{}, 重新发起请求", orderId); + ebikePayment.setTradeState(String.valueOf(Transaction.TradeStateEnum.CLOSED.ordinal())); + ebikePayment.setPaymentId(StringUtils.generateSnowflakeId("paymentId")); + }else{ + log.info("订单正在支付中,订单号:{}", orderId); + } + } else if (String.valueOf(Transaction.TradeStateEnum.CLOSED.ordinal()).equals(tradeState)) { + log.info("订单已经关闭,订单号:{}, 重新发起请求", orderId); + ebikePayment.setPaymentId(StringUtils.generateSnowflakeId("paymentId")); + }else { + log.info("订单状态异常,订单号:{}", orderId); + r.put("error", "订单状态异常: "); + return r; } } //查询订单, orderFeingClient.getOrderById(orderId) - JsonResult result = orderFeingClient.getPaymentDetails(Long.valueOf(outTradeNo)); + JsonResult result = ordersFeignClient.getPaymentDetails(Long.valueOf(orderId)); if (result.getCode() != 200) { - log.error("查询订单 {} 失败, {}", outTradeNo, result.getMessage()); + log.error("查询订单 {} 失败, {}", orderId, result.getMessage()); r.put("error", "查询订单失败, "+result.getMessage()); return r; } @@ -127,18 +145,20 @@ public class WxPayServiceImpl implements WxPayService { * @return 下单成功返回wx支付请求参数,否则返回null */ private JSONObject prepay(EbikePaymentDto paymentDto, EbikePayment ebikePayment) { + JSONObject r = new JSONObject(); String outTradeNo = paymentDto.getOrderId(); String description = paymentDto.getDescription(); String goodsTag = paymentDto.getGoodsTag(); String openId = paymentDto.getOpenId(); AmountDto amount = paymentDto.getAmount(); DetailDto detail = paymentDto.getDetail(); + String payId = ebikePayment==null?outTradeNo : ebikePayment.getPaymentId(); try { PrepayRequest request = new PrepayRequest(); request.setAppid(wxPayConfig.getAppId()); request.setMchid(wxPayConfig.getMerchantId()); request.setDescription(description); - request.setOutTradeNo(outTradeNo); + request.setOutTradeNo(payId); request.setNotifyUrl(wxPayConfig.getPayNotifyUrl()); LocalDateTime expireTime = LocalDateTime.now().plusMinutes(wxPayConfig.getExpireMinute()); request.setTimeExpire(StringUtils.formatLocalDatetime(expireTime)); @@ -151,22 +171,36 @@ public class WxPayServiceImpl implements WxPayService { payer.setOpenid(openId); request.setPayer(payer); Detail detailReq = new Detail(); - detailReq.setGoodsDetail(detail.getGoodsDetail().stream().map(goodsDetail -> { + List goodsDetails = detail.getGoodsDetail().stream().map(goodsDetail -> { GoodsDetail goodsDetailReq = new GoodsDetail(); goodsDetailReq.setGoodsName(goodsDetail.getItemName()); goodsDetailReq.setMerchantGoodsId(goodsDetail.getItemId()); goodsDetailReq.setQuantity(goodsDetail.getQuantity()); goodsDetailReq.setUnitPrice(BigDecimal.valueOf(goodsDetail.getUnitPrice()*100.0).intValue()); return goodsDetailReq; - }).toList()); + }).toList(); + if (goodsDetails.isEmpty()){ + goodsDetails = new ArrayList<>(); + GoodsDetail goodsDetail = new GoodsDetail(); + String snowId = StringUtils.generateSnowflakeId("goodsId"); + goodsDetail.setMerchantGoodsId(snowId); + goodsDetail.setGoodsName(goodsTag); + goodsDetail.setQuantity(1); + goodsDetail.setUnitPrice(BigDecimal.valueOf(amount.getTotal()*100.0).intValue()); + goodsDetails.add(goodsDetail); + } + detailReq.setGoodsDetail(goodsDetails); detailReq.setCostPrice(BigDecimal.valueOf(detail.getCostPrice()*100.0).intValue()); detailReq.setInvoiceId(detail.getInvoiceId()); request.setDetail(detailReq); - + SettleInfo settleInfo = new SettleInfo(); + settleInfo.setProfitSharing(false); + request.setSettleInfo(settleInfo); + //log.info("微信支付下单prepay,订单号:{}, {}", outTradeNo, JSONObject.toJSONString(request)); PrepayResponse response = wxJsapiService.prepay(request); - String payId = response.getPrepayId(); //入库, 重新发起支付更新记录(订单号<-->记录号一一对应) - if (payId != null) { + if (response != null && response.getPrepayId() != null) { + log.info("微信支付下单prepay成功,支付订单号:{}", response.getPrepayId()); if (ebikePayment == null) { ebikePayment = new EbikePayment(); ebikePayment.setOrderId(outTradeNo); @@ -189,14 +223,16 @@ public class WxPayServiceImpl implements WxPayService { wxJsapiPromptDto.setAppId(wxPayConfig.getAppId()); wxJsapiPromptDto.setTimeStamp(String.valueOf(Instant.now().getEpochSecond())); wxJsapiPromptDto.setNonceStr(NonceUtil.createNonce(32)); - wxJsapiPromptDto.setExtension("prepay_id=" + payId); + wxJsapiPromptDto.setExtension("prepay_id=" + response.getPrepayId()); return wxJsapiPromptDto.toJson(wxRsaSigner); } log.error("微信支付下单prepay失败,订单号:{}", outTradeNo); - return null; + r.put("error", "微信支付下单prepay失败"); + return r; }catch (Exception e) { logError("微信支付下单prepay", e); - return null; + r.put("error", "微信支付下单prepay失败: "+e.getMessage()); + return r; } } @@ -209,13 +245,23 @@ public class WxPayServiceImpl implements WxPayService { } @Override - public HandleNotifyResult queryOrderStatusByOutTradeNo(String outTradeNo) { + public Transaction queryOrderByOrderId(String orderId) { + EbikePayment ebikePayment = ebikePaymentService.getByOrderId(orderId); + if (ebikePayment==null){ + log.error("{}支付订单不存在", orderId); + return null; + } + return queryOrderByOutTradeNo(ebikePayment.getPaymentId()); + } + + @Override + public HandleNotifyResult queryOrderStatusByOrderId(String orderId) { // 先查本地数据库,如果退款状态不为SUCCESS,需要查询微信支付 HandleNotifyResult result = new HandleNotifyResult(); - EbikePayment ebikePayment = ebikePaymentService.getByOrderId(outTradeNo); + EbikePayment ebikePayment = ebikePaymentService.getByOrderId(orderId); if (ebikePayment==null){ - log.error("{}支付订单不存在", outTradeNo); - result.setMessage(String.format("{%s}支付订单不存在", outTradeNo)); + log.error("{}支付订单不存在", orderId); + result.setMessage(String.format("{%s}支付订单不存在", orderId)); return result; } result.setSuccess(String.valueOf(Transaction.TradeStateEnum.SUCCESS.ordinal()).equals(ebikePayment.getTradeState())); @@ -223,11 +269,9 @@ public class WxPayServiceImpl implements WxPayService { result.setMessage(String.format("订单%s支付成功", ebikePayment.getOrderId())); return result; } - QueryOrderByOutTradeNoRequest request = new QueryOrderByOutTradeNoRequest(); - request.setOutTradeNo(outTradeNo); - request.setMchid(wxPayConfig.getMerchantId()); - Transaction r = wxJsapiService.queryOrderByOutTradeNo(request); - if(r!=null&& r.getTradeState().equals(Transaction.TradeStateEnum.SUCCESS)) { + + Transaction r =queryOrderByOutTradeNo(ebikePayment.getPaymentId()); + if(r!=null&& Transaction.TradeStateEnum.SUCCESS.equals(r.getTradeState())) { result.setMessage(String.format("订单%s支付成功", ebikePayment.getOrderId())); result.setSuccess(true); // 更新支付状态 @@ -295,6 +339,7 @@ public class WxPayServiceImpl implements WxPayService { ebikeRefund.setCreateTime(LocalDateTime.now()); ebikeRefund.setRefundId(outRefundNo); ebikeRefund.setOrderId(outTradeNo); + ebikeRefund.setTotal(ebikePayment.getTotal()); ebikeRefund.setTransactionId(transactionId); ebikeRefund.setReason(reason); ebikeRefund.setStatus(String.valueOf(Status.PROCESSING.ordinal())); diff --git a/ebike-payment/src/main/java/com/cdzy/payment/task/ScheduledTaskManager.java b/ebike-payment/src/main/java/com/cdzy/payment/task/ScheduledTaskManager.java index 3fa11b05..b2bd8456 100644 --- a/ebike-payment/src/main/java/com/cdzy/payment/task/ScheduledTaskManager.java +++ b/ebike-payment/src/main/java/com/cdzy/payment/task/ScheduledTaskManager.java @@ -1,5 +1,6 @@ package com.cdzy.payment.task; +import com.cdzy.payment.config.WxPayConfig; import jakarta.annotation.PostConstruct; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; @@ -17,17 +18,18 @@ import org.springframework.stereotype.Component; @Slf4j @Component public class ScheduledTaskManager { - // 每隔30秒执行1次 - private final static String CRON_EXPRESSION = "0/30 * * * *?"; // @Scheduled任务线程默认串行执行,需要考虑并发问题 @Resource + private WxPayConfig wxPayConfig; + @Resource private ThreadPoolTaskScheduler threadPoolTaskScheduler; @Resource private WsPayTask wxPayTask; @PostConstruct public void init() { + String CRON_EXPRESSION = wxPayConfig.getCronExpression(); // 启动定时任务 // 1. 每隔30秒执行1次,查询创建未超过5分钟,并且未支付的订单 threadPoolTaskScheduler.schedule(new Runnable() { @@ -41,17 +43,18 @@ public class ScheduledTaskManager { } }, new CronTrigger(CRON_EXPRESSION)); - // 2. 每隔30秒执行1次,查询创建超过5分钟,并且未支付的订单 - threadPoolTaskScheduler.schedule(new Runnable() { - @Override - public void run() { - try { - wxPayTask.closeOrder(); - } catch (Exception e) { - log.error("closeOrder 执行异常", e); - } - } - }, new CronTrigger(CRON_EXPRESSION)); + //========支付系统自动关闭,不主动关闭,每次发起请求的时候检测是否关闭======== + //// 2. 每隔30秒执行1次,查询创建超过5分钟,并且未支付的订单 + //threadPoolTaskScheduler.schedule(new Runnable() { + // @Override + // public void run() { + // try { + // wxPayTask.closeOrder(); + // } catch (Exception e) { + // log.error("closeOrder 执行异常", e); + // } + // } + //}, new CronTrigger(CRON_EXPRESSION)); // 3. 每隔30秒执行1次,查询创建未超过5分钟,并且未成功的退款单 threadPoolTaskScheduler.schedule(new Runnable() { diff --git a/ebike-payment/src/main/java/com/cdzy/payment/task/WsPayTask.java b/ebike-payment/src/main/java/com/cdzy/payment/task/WsPayTask.java index 3a0e0dc2..a68b2b9b 100644 --- a/ebike-payment/src/main/java/com/cdzy/payment/task/WsPayTask.java +++ b/ebike-payment/src/main/java/com/cdzy/payment/task/WsPayTask.java @@ -36,7 +36,7 @@ public class WsPayTask { /** - * 查询创建未超过5分钟,并且未支付的订单 + * 查询创建未超过24小时,并且未支付的订单 */ public void checkOrderStatus() throws Exception { log.info("checkOrderStatus 执行......"); @@ -54,7 +54,7 @@ public class WsPayTask { } /** - * 查询创建超过5分钟,并且未支付的订单 + * 查询创建超过24小时,并且未支付的订单 */ public void closeOrder() throws Exception { log.info("closeOrder 执行......"); @@ -76,7 +76,7 @@ public class WsPayTask { } /** - * 查询创建未超过5分钟,并且未成功的退款单 + * 查询创建未超过24小时,并且未成功的退款单 */ public void checkRefundStatus() throws Exception { log.info("checkRefundStatus 执行......"); diff --git a/ebike-payment/src/main/resources/application-dev.yml b/ebike-payment/src/main/resources/application-dev.yml index 946a6df1..5531b6d4 100644 --- a/ebike-payment/src/main/resources/application-dev.yml +++ b/ebike-payment/src/main/resources/application-dev.yml @@ -36,13 +36,14 @@ payment: app-id: wx327d788d7bd6eddf merchant-id: 1715147005 private-key-path: D:/Projects/eBIKE/docs/secrets/apiclient_key.pem - public-key-path: D:/Projects/eBIKE/docs/secrets/apiclient_cert.pem + public-key-path: D:/Projects/eBIKE/docs/secrets/apiclient_pubkey.pem merchant-serial-number: 7873E3E694ADD0368EA3E9FAC929F496EECB8DF9 api-v3-key: 1715147005V3Key20250425174554633 public-key-id: PUB_KEY_ID_0117151470052025042500331704000601 pay-notify_url: http://192.168.2.156:10017/wxPayment/pay-notify refund-notify_url: http://192.168.2.156:10017/wxPayment/refund-notify - expire-minutes: 5 + expire-minutes: 1440 + cron-expression: 0 0 0,12 * * ? task-scheduler-pool: poolSize: 100 threadNamePrefix: task-scheduled-