From 7f91a73329f7c27754ecbc7a676cfa1a2441990a Mon Sep 17 00:00:00 2001 From: Administrator Date: Sat, 18 Jan 2025 16:33:07 +0800 Subject: [PATCH] =?UTF-8?q?1.=20=E8=A7=A3=E6=9E=90=E5=BE=AE=E4=BF=A1?= =?UTF-8?q?=E6=94=AF=E4=BB=98=E5=9B=9E=E8=B0=83=202.=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E8=AE=A2=E5=8D=95=E5=BE=AE=E4=BF=A1=E6=94=AF=E4=BB=98=E5=90=8E?= =?UTF-8?q?=E7=9A=84=E5=A4=84=E7=90=86=E9=80=BB=E8=BE=91=203.=20=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E5=BE=AE=E4=BF=A1=E9=A2=84=E6=94=AF=E4=BB=98=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=E6=95=B0=E6=8D=AE=E4=BF=9D=E5=AD=98=E6=B5=81=E7=A8=8B?= =?UTF-8?q?=204.=20=E6=B7=BB=E5=8A=A0=E5=BE=AE=E4=BF=A1=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E9=92=B1=E5=8C=85=E5=8A=9F=E8=83=BD=205.=20=E5=AE=8C=E5=96=84?= =?UTF-8?q?=E4=BA=A4=E6=98=93=E5=AE=9E=E4=BD=93=E5=85=B7=E4=BD=93=E5=AD=97?= =?UTF-8?q?=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/dao/wechat/WechatPayPreOrderDao.java | 12 + .../common/core/entity/cloud/TradeDetail.java | 48 ++-- .../core/entity/cloud/WalletAccount.java | 2 +- .../cloud}/request/PageListWalletRequest.java | 2 +- .../core/entity/wechat/WechatPayAttach.java | 29 +++ .../core/entity/wechat/WechatPayPreOrder.java | 98 ++++++++ .../common/core/enums/TradeResultEnums.java | 39 ++++ .../evotech/hd/common/core/utils/XCXUtil.java | 18 ++ .../controller/order/TradeController.java | 10 + .../order/WalletAccountController.java | 2 +- .../hd/cloud/service/TradeService.java | 2 + .../cloud/service/WalletAccountService.java | 2 +- .../cloud/service/impl/TradeServiceImpl.java | 53 ++++- .../impl/WalletAccountServiceImpl.java | 2 +- .../utils/components/HDStepDictComponent.java | 2 +- .../hd/gateway/filter/AccessLogFilter.java | 8 +- .../oauth2/WechatAuthorizationManager.java | 18 +- resource-server/pom.xml | 5 + ...{IDController.java => UtilController.java} | 28 ++- .../controller/ResourceServerController.java | 7 + .../controller/WechatPayController.java | 15 +- .../controller/WechatUserController.java | 33 +++ .../evotech/hd/wechat/entity/PrePayVO.java | 63 ++++++ .../hd/wechat/service/CloudService.java | 20 ++ .../hd/wechat/service/ResourceService.java | 4 + .../hd/wechat/service/WechatPayService.java | 9 +- .../hd/wechat/service/WechatUserService.java | 13 ++ .../service/impl/WechatPayServiceImpl.java | 209 ++++++++++++++---- .../service/impl/WechatUserServiceImpl.java | 42 ++++ ...F671A0B59945ECDF68E7560D79CDD683501AF5.pem | 24 ++ 30 files changed, 724 insertions(+), 95 deletions(-) create mode 100644 base-commons/common-core/src/main/java/com/evotech/hd/common/core/dao/wechat/WechatPayPreOrderDao.java rename {cloud-manage-server/src/main/java/com/evotech/hd/cloud/entity => base-commons/common-core/src/main/java/com/evotech/hd/common/core/entity/cloud}/request/PageListWalletRequest.java (91%) create mode 100644 base-commons/common-core/src/main/java/com/evotech/hd/common/core/entity/wechat/WechatPayAttach.java create mode 100644 base-commons/common-core/src/main/java/com/evotech/hd/common/core/entity/wechat/WechatPayPreOrder.java create mode 100644 base-commons/common-core/src/main/java/com/evotech/hd/common/core/enums/TradeResultEnums.java rename resource-server/src/main/java/com/evotech/hd/resource/controller/{IDController.java => UtilController.java} (55%) create mode 100644 wechat-server/src/main/java/com/evotech/hd/wechat/entity/PrePayVO.java create mode 100644 wechat-server/src/main/resources/static/key/wechatpay_2CF671A0B59945ECDF68E7560D79CDD683501AF5.pem diff --git a/base-commons/common-core/src/main/java/com/evotech/hd/common/core/dao/wechat/WechatPayPreOrderDao.java b/base-commons/common-core/src/main/java/com/evotech/hd/common/core/dao/wechat/WechatPayPreOrderDao.java new file mode 100644 index 0000000..94f89f2 --- /dev/null +++ b/base-commons/common-core/src/main/java/com/evotech/hd/common/core/dao/wechat/WechatPayPreOrderDao.java @@ -0,0 +1,12 @@ +package com.evotech.hd.common.core.dao.wechat; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.evotech.hd.common.core.entity.wechat.WechatPayPreOrder; + +/** + * @author zrb + * @since 2025-01-13 + */ +public interface WechatPayPreOrderDao extends BaseMapper { + +} diff --git a/base-commons/common-core/src/main/java/com/evotech/hd/common/core/entity/cloud/TradeDetail.java b/base-commons/common-core/src/main/java/com/evotech/hd/common/core/entity/cloud/TradeDetail.java index df9a4d3..7aa18ea 100644 --- a/base-commons/common-core/src/main/java/com/evotech/hd/common/core/entity/cloud/TradeDetail.java +++ b/base-commons/common-core/src/main/java/com/evotech/hd/common/core/entity/cloud/TradeDetail.java @@ -31,18 +31,30 @@ public class TradeDetail implements Serializable { @Schema(description = "换电站编码") private String stationCode; - @Schema(description = "账号编码") - private String accountCode; + @Schema(description = "交易人") + private String trader; - @Schema(description = "账号") - private String accountName; + @Schema(description = "交易人编码") + private String traderCode; + + @Schema(description = "交易类型:1-充值,2-订单消费,3-提现") + private Integer tradeType; + + @Schema(description = "变动金额的钱包账户,钱包金额不变时不需要") + private String wallet; + + @Schema(description = "appid") + private String appid; + + @Schema(description = "银行类型") + private String bankType; + + @Schema(description = "收款商户号") + private String mchid; @Schema(description = "交易编码") private String outTradeNo; - @Schema(description = "交易类型:1-充值,2-订单消费,3-提现") - private Integer tradeType; - @Schema(description = "支付方式:1-账户余额,2-微信,3-支付宝,4-网银,5 -充电补偿") private Integer payType; @@ -50,17 +62,11 @@ public class TradeDetail implements Serializable { private Integer orderCount; @Schema(description = "订单编码") - private String orderNums; + private String orderNo; @Schema(description = "交易金额") private Integer tradeAmount; - @Schema(description = "交易前账户余额") - private Integer preAccountAmount; - - @Schema(description = "交易后账户余额") - private Integer afterAccountAmount; - @Schema(description = "优惠券编码") private String couponCode; @@ -70,13 +76,21 @@ public class TradeDetail implements Serializable { @Schema(description = "微信支付订单号") private String transactionId; - @Schema(description = "支付结果: 0-未支付, 1-已支付, 2-支付失败") - private Integer payResult; + @Schema(description = "支付结果,暂用微信结果的枚举类型") + private String payResult; @Schema(description = "在微信等支付网关创建支付订单时失败,返回的失败原因") private String payMsg; + + @Schema(description = "付款人编码,对于个人账户,交易发起人和付款人一般是同一人。公司账户交易发起人是公司,付款人可能是 微信账户") + private String payer; + + @Schema(description = "支付完成时间") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8") + private Date payTime; - @Schema(description = "删除标识,1-已删除,0-未删除") + @Schema(description = "删除标识,1-已删除,0-未删除", hidden = true) private Integer delFlag; @Schema(description = "创建人") diff --git a/base-commons/common-core/src/main/java/com/evotech/hd/common/core/entity/cloud/WalletAccount.java b/base-commons/common-core/src/main/java/com/evotech/hd/common/core/entity/cloud/WalletAccount.java index 6d2287d..b478327 100644 --- a/base-commons/common-core/src/main/java/com/evotech/hd/common/core/entity/cloud/WalletAccount.java +++ b/base-commons/common-core/src/main/java/com/evotech/hd/common/core/entity/cloud/WalletAccount.java @@ -64,7 +64,7 @@ public class WalletAccount implements Serializable { private Integer rent; @Schema(description = "状态") - private Boolean status; + private Integer status; @Schema(description = "引入站点", requiredMode = RequiredMode.REQUIRED) @NotBlank(message = "站点编码不能为空") diff --git a/cloud-manage-server/src/main/java/com/evotech/hd/cloud/entity/request/PageListWalletRequest.java b/base-commons/common-core/src/main/java/com/evotech/hd/common/core/entity/cloud/request/PageListWalletRequest.java similarity index 91% rename from cloud-manage-server/src/main/java/com/evotech/hd/cloud/entity/request/PageListWalletRequest.java rename to base-commons/common-core/src/main/java/com/evotech/hd/common/core/entity/cloud/request/PageListWalletRequest.java index 166b15d..f1ee501 100644 --- a/cloud-manage-server/src/main/java/com/evotech/hd/cloud/entity/request/PageListWalletRequest.java +++ b/base-commons/common-core/src/main/java/com/evotech/hd/common/core/entity/cloud/request/PageListWalletRequest.java @@ -1,4 +1,4 @@ -package com.evotech.hd.cloud.entity.request; +package com.evotech.hd.common.core.entity.cloud.request; import com.evotech.hd.common.core.entity.BasePageRequest; diff --git a/base-commons/common-core/src/main/java/com/evotech/hd/common/core/entity/wechat/WechatPayAttach.java b/base-commons/common-core/src/main/java/com/evotech/hd/common/core/entity/wechat/WechatPayAttach.java new file mode 100644 index 0000000..649a818 --- /dev/null +++ b/base-commons/common-core/src/main/java/com/evotech/hd/common/core/entity/wechat/WechatPayAttach.java @@ -0,0 +1,29 @@ +package com.evotech.hd.common.core.entity.wechat; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Data +@Schema(name = "微信支付附加信息") +/** + * 附加信息中是交易发起人的信息 + * 支付回调中的openid 确认 付款人信息 + * 对于公司账户,这2部分信息可能不一样 + */ +public class WechatPayAttach { + + @Schema(description = "类型:1-充值,2-订单") + private Integer type; + + @Schema(description = "订单号") + private String orderNo; + + @Schema(description = "交易发起人") + private String trader; + + @Schema(description = "交易人编码") + private String traderCode; + + @Schema(description = "钱包编码") + private String walletCode; +} diff --git a/base-commons/common-core/src/main/java/com/evotech/hd/common/core/entity/wechat/WechatPayPreOrder.java b/base-commons/common-core/src/main/java/com/evotech/hd/common/core/entity/wechat/WechatPayPreOrder.java new file mode 100644 index 0000000..2c58785 --- /dev/null +++ b/base-commons/common-core/src/main/java/com/evotech/hd/common/core/entity/wechat/WechatPayPreOrder.java @@ -0,0 +1,98 @@ +package com.evotech.hd.common.core.entity.wechat; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.fasterxml.jackson.annotation.JsonFormat; + +import java.io.Serializable; +import java.util.Date; + +import org.springframework.format.annotation.DateTimeFormat; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * @author zrb + * @since 2025-01-13 + */ +@Data +@TableName("yt_t_wechat_pay_pre_order") +@Schema(name = "WechatPayPreOrder", description = "微信预支付订单") +public class WechatPayPreOrder implements Serializable { + + private static final long serialVersionUID = 1L; + + @TableId(value = "pk_id", type = IdType.AUTO) + private Integer pkId; + + @Schema(description = "用户编码") + private String wuid; + + private String openid; + + @Schema(description = "订单总描述") + private String description; + + @Schema(description = "小程序ID") + private String appid; + + @Schema(description = "商户号") + private String mchid; + + @Schema(description = "商户订单号") + private String outTradeNo; + + @Schema(description = "支付的最后时限") + private Date timeExpire; + + @Schema(description = "订单附加信息") + private String attach; + + @Schema(description = "商户回调地址") + private String notifyUrl; + + @Schema(description = "使用的优惠活动编码") + private String goodsTag; + + @Schema(description = "订单支付总金额") + private Integer total; + + @Schema(description = "商家小票ID") + private String invoiceId; + + @Schema(description = "商家小票金额") + private Integer costPrice; + + @Schema(description = "商品详情") + private String goodsDetail; + + @Schema(description = "门店号或收银设备ID") + private String deviceId; + + @Schema(description = "用户的客户端IP") + private String payerClientIp; + + @Schema(description = "商户门店信息") + private String storeInfo; + + @Schema(description = "支付串") + private String prePayResponse; + + @Schema(description = "创建人", hidden = true) + private String creater; + + @Schema(description = "创建时间", hidden = true) + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8") + private Date ctime; + + @Schema(description = "更新人", hidden = true) + private String updater; + + @Schema(description = "更新时间", hidden = true) + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8") + private Date uptime; +} diff --git a/base-commons/common-core/src/main/java/com/evotech/hd/common/core/enums/TradeResultEnums.java b/base-commons/common-core/src/main/java/com/evotech/hd/common/core/enums/TradeResultEnums.java new file mode 100644 index 0000000..cbe7443 --- /dev/null +++ b/base-commons/common-core/src/main/java/com/evotech/hd/common/core/enums/TradeResultEnums.java @@ -0,0 +1,39 @@ +package com.evotech.hd.common.core.enums; + +public enum TradeResultEnums { + + SUCCESS(1, "SUCCESS"), + + REFUND(2, "REFUND"), + + NOTPAY(3, "NOTPAY"), + + CLOSED(4, "CLOSED"), + + REVOKED(5, "REVOKED"), + + USERPAYING(6, "USERPAYING"), + + PAYERROR(7, "PAYERROR"), + + ACCEPT(8, "ACCEPT"); + + + Integer code; + + String name; + + public Integer getCode() { + return code; + } + + public String getName() { + return name; + } + + TradeResultEnums(Integer code, String name) { + this.code = code; + this.name = name; + } + +} diff --git a/base-commons/common-core/src/main/java/com/evotech/hd/common/core/utils/XCXUtil.java b/base-commons/common-core/src/main/java/com/evotech/hd/common/core/utils/XCXUtil.java index 7cf3285..8d23a56 100644 --- a/base-commons/common-core/src/main/java/com/evotech/hd/common/core/utils/XCXUtil.java +++ b/base-commons/common-core/src/main/java/com/evotech/hd/common/core/utils/XCXUtil.java @@ -1,5 +1,12 @@ package com.evotech.hd.common.core.utils; +import java.util.Date; + +import org.springframework.util.StringUtils; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.RandomUtil; import cn.hutool.crypto.digest.MD5; public class XCXUtil { @@ -11,5 +18,16 @@ public class XCXUtil { public static String wechatToken(String wuid, String randomStr) { return MD5.create().digestHex(wuid + randomStr + "HBYTXCX"); } + + /** + * 微信支付订单号:30位,预留2位不用 + * @param stationCode + * @return + */ + public static String payOutTradeNo(String stationCode) { + String prefix = "YTHD" + (StringUtils.hasText(stationCode)?stationCode.substring(stationCode.length() - 4):"1001"); + return prefix + DateUtil.format(new Date(), DatePattern.PURE_DATETIME_MS_PATTERN) + + RandomUtil.randomInt(100, 1000) + RandomUtil.randomStringUpper(2); + } } diff --git a/cloud-manage-server/src/main/java/com/evotech/hd/cloud/controller/order/TradeController.java b/cloud-manage-server/src/main/java/com/evotech/hd/cloud/controller/order/TradeController.java index 2e69a89..e1977f2 100644 --- a/cloud-manage-server/src/main/java/com/evotech/hd/cloud/controller/order/TradeController.java +++ b/cloud-manage-server/src/main/java/com/evotech/hd/cloud/controller/order/TradeController.java @@ -15,6 +15,7 @@ import com.evotech.hd.common.core.entity.cloud.TradeDetail; import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport; import com.github.xiaoymin.knife4j.annotations.ApiSupport; +import io.swagger.v3.oas.annotations.Hidden; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.Resource; @@ -59,5 +60,14 @@ public class TradeController { public Result> list(@ParameterObject PageListTradeRequest pltr) { return tradeService.list(pltr); } + + + @Operation(summary = "微信支付回调业务处理") + @PostMapping({"/wechatpay/notify"}) + @ApiOperationSupport(order = 5) + @Hidden + public Result wechatPayNotifyHandle(@ParameterObject TradeDetail tradeDetail) { + return tradeService.wechatPayNotifyHandle(tradeDetail); + } } diff --git a/cloud-manage-server/src/main/java/com/evotech/hd/cloud/controller/order/WalletAccountController.java b/cloud-manage-server/src/main/java/com/evotech/hd/cloud/controller/order/WalletAccountController.java index ce69357..8c2de30 100644 --- a/cloud-manage-server/src/main/java/com/evotech/hd/cloud/controller/order/WalletAccountController.java +++ b/cloud-manage-server/src/main/java/com/evotech/hd/cloud/controller/order/WalletAccountController.java @@ -8,11 +8,11 @@ import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import com.evotech.hd.cloud.entity.request.PageListWalletRequest; import com.evotech.hd.cloud.service.WalletAccountService; import com.evotech.hd.common.core.entity.Result; import com.evotech.hd.common.core.entity.cloud.WalletAccount; import com.evotech.hd.common.core.entity.cloud.WalletAccountDetail; +import com.evotech.hd.common.core.entity.cloud.request.PageListWalletRequest; import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport; import com.github.xiaoymin.knife4j.annotations.ApiSupport; diff --git a/cloud-manage-server/src/main/java/com/evotech/hd/cloud/service/TradeService.java b/cloud-manage-server/src/main/java/com/evotech/hd/cloud/service/TradeService.java index f9d6f47..6914891 100644 --- a/cloud-manage-server/src/main/java/com/evotech/hd/cloud/service/TradeService.java +++ b/cloud-manage-server/src/main/java/com/evotech/hd/cloud/service/TradeService.java @@ -15,5 +15,7 @@ public interface TradeService { public Result update(TradeDetail td); public Result> list(PageListTradeRequest pltr); + + public Result wechatPayNotifyHandle(TradeDetail tradeDetail); } diff --git a/cloud-manage-server/src/main/java/com/evotech/hd/cloud/service/WalletAccountService.java b/cloud-manage-server/src/main/java/com/evotech/hd/cloud/service/WalletAccountService.java index 8ab110a..16da867 100644 --- a/cloud-manage-server/src/main/java/com/evotech/hd/cloud/service/WalletAccountService.java +++ b/cloud-manage-server/src/main/java/com/evotech/hd/cloud/service/WalletAccountService.java @@ -2,10 +2,10 @@ package com.evotech.hd.cloud.service; import java.util.List; -import com.evotech.hd.cloud.entity.request.PageListWalletRequest; import com.evotech.hd.common.core.entity.Result; import com.evotech.hd.common.core.entity.cloud.WalletAccount; import com.evotech.hd.common.core.entity.cloud.WalletAccountDetail; +import com.evotech.hd.common.core.entity.cloud.request.PageListWalletRequest; public interface WalletAccountService { diff --git a/cloud-manage-server/src/main/java/com/evotech/hd/cloud/service/impl/TradeServiceImpl.java b/cloud-manage-server/src/main/java/com/evotech/hd/cloud/service/impl/TradeServiceImpl.java index 676d045..df8e2d2 100644 --- a/cloud-manage-server/src/main/java/com/evotech/hd/cloud/service/impl/TradeServiceImpl.java +++ b/cloud-manage-server/src/main/java/com/evotech/hd/cloud/service/impl/TradeServiceImpl.java @@ -4,24 +4,34 @@ import java.util.Date; import java.util.List; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import org.springframework.util.StringUtils; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.evotech.hd.cloud.dao.OrderSwapBatteryDao; import com.evotech.hd.cloud.dao.TradeDetailDao; import com.evotech.hd.cloud.entity.request.PageListTradeRequest; import com.evotech.hd.cloud.service.TradeService; +import com.evotech.hd.cloud.service.newthread.GZHTemplateMessageService; import com.evotech.hd.common.core.entity.Result; +import com.evotech.hd.common.core.entity.cloud.OrderSwapBattery; import com.evotech.hd.common.core.entity.cloud.TradeDetail; import com.evotech.hd.common.core.enums.CodeMsg; - +import com.evotech.hd.common.core.enums.TradeResultEnums; import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; @Service +@Slf4j public class TradeServiceImpl implements TradeService { @Resource private TradeDetailDao tradeDetailDao; + @Resource + private OrderSwapBatteryDao orderSwapBatteryDao; + @Resource + private GZHTemplateMessageService templateMessageService; @Override public Result add(TradeDetail td) { @@ -72,4 +82,45 @@ public class TradeServiceImpl implements TradeService { return new Result>().success(page); } + @Override + @Transactional + public Result wechatPayNotifyHandle(TradeDetail tradeDetail) { + // 1. 添加交易 + boolean b = tradeDetailDao.exists(new QueryWrapper() + .eq("out_trade_no", tradeDetail.getOutTradeNo()) + .eq("transaction_id", tradeDetail.getTransactionId()) + .eq("pay_result", tradeDetail.getPayResult())); + if (b) { + log.info("\r\n===>>>已处理过此回调:" + tradeDetail); + return new Result().error("重复消息!"); + } + add(tradeDetail); + // 2. 业务类型 + if (tradeDetail.getTradeType() == 1) { + // 充值 + + } else if (tradeDetail.getTradeType() == 2) { + // 支付订单 + OrderSwapBattery one = orderSwapBatteryDao.selectOne(new QueryWrapper().eq("order_no", tradeDetail.getOrderNo())); + if (one.getStatus() == 6) { + if (TradeResultEnums.SUCCESS.getName().equals(tradeDetail.getPayResult())) { + // 支付成功,修改订单 + OrderSwapBattery osb = new OrderSwapBattery(); + osb.setStatus(7); + osb.setTradeNo(tradeDetail.getOutTradeNo()); + orderSwapBatteryDao.update(osb, new QueryWrapper().eq("order_no", tradeDetail.getOrderNo())); + // 发送公众号消息 + templateMessageService.orderMessageSend(one, 3); + } + } else { + log.info("\r\n===>>>支付订单存在问题:" + tradeDetail); + } + + } else { + + } + + return new Result().success("OK"); + } + } diff --git a/cloud-manage-server/src/main/java/com/evotech/hd/cloud/service/impl/WalletAccountServiceImpl.java b/cloud-manage-server/src/main/java/com/evotech/hd/cloud/service/impl/WalletAccountServiceImpl.java index d986834..ba4bae4 100644 --- a/cloud-manage-server/src/main/java/com/evotech/hd/cloud/service/impl/WalletAccountServiceImpl.java +++ b/cloud-manage-server/src/main/java/com/evotech/hd/cloud/service/impl/WalletAccountServiceImpl.java @@ -12,11 +12,11 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.evotech.hd.cloud.dao.WalletAccountDao; import com.evotech.hd.cloud.dao.WalletAccountDetailDao; -import com.evotech.hd.cloud.entity.request.PageListWalletRequest; import com.evotech.hd.cloud.service.WalletAccountService; import com.evotech.hd.common.core.entity.Result; import com.evotech.hd.common.core.entity.cloud.WalletAccount; import com.evotech.hd.common.core.entity.cloud.WalletAccountDetail; +import com.evotech.hd.common.core.entity.cloud.request.PageListWalletRequest; import com.evotech.hd.common.core.enums.CodeMsg; import com.evotech.hd.common.core.utils.SnowflakeUtil; diff --git a/cloud-manage-server/src/main/java/com/evotech/hd/cloud/utils/components/HDStepDictComponent.java b/cloud-manage-server/src/main/java/com/evotech/hd/cloud/utils/components/HDStepDictComponent.java index a0fccec..01b92c0 100644 --- a/cloud-manage-server/src/main/java/com/evotech/hd/cloud/utils/components/HDStepDictComponent.java +++ b/cloud-manage-server/src/main/java/com/evotech/hd/cloud/utils/components/HDStepDictComponent.java @@ -16,7 +16,7 @@ import jakarta.annotation.Resource; @Component public class HDStepDictComponent { - private static String stepPrefix = "hd:resource:dict:hdstep-"; + private static String stepPrefix = "hd:resource:dict:hdstep:step-"; @Resource private RedisUtil redisUtil; diff --git a/gateway-server/src/main/java/com/evotech/hd/gateway/filter/AccessLogFilter.java b/gateway-server/src/main/java/com/evotech/hd/gateway/filter/AccessLogFilter.java index 55341d9..e0cd4d9 100644 --- a/gateway-server/src/main/java/com/evotech/hd/gateway/filter/AccessLogFilter.java +++ b/gateway-server/src/main/java/com/evotech/hd/gateway/filter/AccessLogFilter.java @@ -120,8 +120,8 @@ public class AccessLogFilter implements GlobalFilter, Ordered { * %(?![0-9a-fA-F]{2})意思是'%'开始, 不匹配%后面两位为数字或字母(包括大小写)的字符; * 这样就把正确的排除掉了,剩下的就是需要匹配替换的。 */ - body = body.replaceAll("%(?![0-9a-fA-F]{2})", "%25"); - body = body.replaceAll("\\+", "%2B"); +// body = body.replaceAll("%(?![0-9a-fA-F]{2})", "%25"); +// body = body.replaceAll("\\+", "%2B"); // body = URLEncoder.encode(body, "UTF-8"); return Mono.just(body); }); @@ -145,7 +145,7 @@ public class AccessLogFilter implements GlobalFilter, Ordered { .filter(exchange.mutate().request(decoratedRequest).response(decoratedResponse).build()) .then(Mono.fromRunnable(() -> { // 打印日志 - if (!gatewayLog.getRequestPath().contains("/v2/api-docs") && !gatewayLog.getRequestPath().contains("/dict/")) { + if (!gatewayLog.getRequestPath().contains("/v3/api-docs") && !gatewayLog.getRequestPath().contains("/dict/")) { logService.writeGatewayLog(gatewayLog); } })); @@ -164,7 +164,7 @@ public class AccessLogFilter implements GlobalFilter, Ordered { return chain.filter(exchange.mutate().response(decoratedResponse).build()) .then(Mono.fromRunnable(() -> { // 打印日志 - if (!accessLog.getRequestPath().contains("/v2/api-docs") && !accessLog.getRequestPath().contains("/dict/")) { + if (!accessLog.getRequestPath().contains("/v3/api-docs") && !accessLog.getRequestPath().contains("/dict/")) { logService.writeGatewayLog(accessLog); } })); diff --git a/gateway-server/src/main/java/com/evotech/hd/gateway/oauth2/WechatAuthorizationManager.java b/gateway-server/src/main/java/com/evotech/hd/gateway/oauth2/WechatAuthorizationManager.java index cb04a45..819fc83 100644 --- a/gateway-server/src/main/java/com/evotech/hd/gateway/oauth2/WechatAuthorizationManager.java +++ b/gateway-server/src/main/java/com/evotech/hd/gateway/oauth2/WechatAuthorizationManager.java @@ -22,6 +22,7 @@ import com.evotech.hd.common.redis.utils.RedisUtil; import com.evotech.hd.gateway.oauth2.service.WechatService; import cn.hutool.json.JSONUtil; import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; import reactor.core.publisher.Mono; /** @@ -29,6 +30,7 @@ import reactor.core.publisher.Mono; * 鉴权时统一抛出OAuth2AuthorizationException */ @Component +@Slf4j public class WechatAuthorizationManager implements ReactiveAuthorizationManager { @Resource @@ -42,14 +44,14 @@ public class WechatAuthorizationManager implements ReactiveAuthorizationManager< @Override public Mono check(Mono mono, AuthorizationContext authorizationContext) { - System.out.println("\r\n===>>>进微信权限检查的了........."); + log.info("\r\n===>>>进微信权限检查的了........."); if (isPass) { return Mono.just(new AuthorizationDecision(true)); } ServerHttpRequest request = authorizationContext.getExchange().getRequest(); String uri = request.getURI().toString(); - System.out.println("*****>" + uri); + log.info("\r\n*****>" + uri); // 1. 对应跨域的预检请求直接放行 if (request.getMethod() == HttpMethod.OPTIONS) { return Mono.just(new AuthorizationDecision(true)); @@ -69,6 +71,8 @@ public class WechatAuthorizationManager implements ReactiveAuthorizationManager< private Mono wechatTokenCheck(ServerHttpRequest request, String uri) { String wuid = request.getHeaders().getFirst(HDConstant.WECHAT_SERVER_AUTHORIZATION_KEY); String wxToken = request.getHeaders().getFirst(HDConstant.WECHAT_SERVER_TOKEN_KEY); + log.info("\r\n---wuid---" + wuid); + log.info("\r\n---token---" + wxToken); if (!StringUtils.hasText(wxToken) || !StringUtils.hasText(wuid)) { throw new OAuth2AuthorizationException(new OAuth2Error(CodeMsg.WECHAT_NOT_LOGIN.getCode(), CodeMsg.WECHAT_NOT_LOGIN.getMsg(), "")); } @@ -78,19 +82,20 @@ public class WechatAuthorizationManager implements ReactiveAuthorizationManager< } // 验证token正确 if (!redisUtil.hasKey(HDConstant.wxToken + wuid)) { + log.info("\r\n===>>>" + redisUtil.get(HDConstant.tokenRandomStr + wuid).toString()); // 缓存没了,过期了 if (!wxToken.equals(XCXUtil.wechatToken(wuid, redisUtil.get(HDConstant.tokenRandomStr + wuid).toString()))) { - System.out.println("------555------"); + log.error("\r\n------555------"); throw new OAuth2AuthorizationException(new OAuth2Error(CodeMsg.WECHAT_TOKEN_INVALID.getCode(), CodeMsg.WECHAT_TOKEN_INVALID.getMsg(), "token异常")); } - System.out.println("------666------"); + log.error("\r\n------666------"); CompletableFuture> asyncRes = CompletableFuture.supplyAsync(() -> { return wechatService.tokenBuilder(wuid); }); Map m = null; try { m = asyncRes.get(); - System.out.println("---777---" + m); + log.error("\r\n---777---" + m); } catch (Exception e) { e.printStackTrace(); throw new OAuth2AuthorizationException(new OAuth2Error(CodeMsg.WECHAT_LOGIN_ERROR.getCode(), CodeMsg.WECHAT_LOGIN_ERROR.getMsg(), "token异常")); @@ -103,7 +108,8 @@ public class WechatAuthorizationManager implements ReactiveAuthorizationManager< return Mono.just(new AuthorizationDecision(true)); } else { // token对不上 - System.out.println("-----88888----"); + log.error("\r\n-----88888----" + wxToken); + log.error("\r\n-----" + redisUtil.get(HDConstant.wxToken + wuid).toString()); throw new OAuth2AuthorizationException(new OAuth2Error(CodeMsg.WECHAT_TOKEN_INVALID.getCode(), CodeMsg.WECHAT_TOKEN_INVALID.getMsg(), "token异常")); } } diff --git a/resource-server/pom.xml b/resource-server/pom.xml index 419a02b..c62c7e9 100644 --- a/resource-server/pom.xml +++ b/resource-server/pom.xml @@ -58,6 +58,11 @@ hutool-json + + cn.hutool + hutool-http + + io.minio minio diff --git a/resource-server/src/main/java/com/evotech/hd/resource/controller/IDController.java b/resource-server/src/main/java/com/evotech/hd/resource/controller/UtilController.java similarity index 55% rename from resource-server/src/main/java/com/evotech/hd/resource/controller/IDController.java rename to resource-server/src/main/java/com/evotech/hd/resource/controller/UtilController.java index 638fdd1..6ff11d9 100644 --- a/resource-server/src/main/java/com/evotech/hd/resource/controller/IDController.java +++ b/resource-server/src/main/java/com/evotech/hd/resource/controller/UtilController.java @@ -3,25 +3,34 @@ package com.evotech.hd.resource.controller; import java.util.ArrayList; import java.util.List; +import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import com.evotech.hd.common.core.entity.Result; import com.evotech.hd.common.core.utils.SnowflakeUtil; +import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport; import com.github.xiaoymin.knife4j.annotations.ApiSupport; + +import cn.hutool.http.HttpUtil; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; -@Tag(name = "ID生成, 测试用") +@Tag(name = "工具类") @ApiSupport(order = 199) @RestController -@RequestMapping("/id") -public class IDController { +@RequestMapping("/util") +public class UtilController { - @Operation(description = "获取") - @GetMapping("/list") + @Value("${yt.util.ip-url1}") + private String ipUrl; + + + @Operation(description = "获取id") + @GetMapping("/id/list") + @ApiOperationSupport(order = 1) public Result> getIds(Integer num) { List list = new ArrayList<>(); for (int i = 0; i < (num==null?1:num); i++) { @@ -29,5 +38,14 @@ public class IDController { } return new Result>().success(list); } + + + @Operation(description = "获取ip") + @GetMapping("/ip") + @ApiOperationSupport(order = 2) + public Result getIp() { + String res = HttpUtil.get(ipUrl); + return new Result().success("OK", res.trim()); + } } diff --git a/wechat-server/src/main/java/com/evotech/hd/wechat/controller/ResourceServerController.java b/wechat-server/src/main/java/com/evotech/hd/wechat/controller/ResourceServerController.java index a91c5f6..a5c3454 100644 --- a/wechat-server/src/main/java/com/evotech/hd/wechat/controller/ResourceServerController.java +++ b/wechat-server/src/main/java/com/evotech/hd/wechat/controller/ResourceServerController.java @@ -43,5 +43,12 @@ public class ResourceServerController { public Result> listSwiper(@NotBlank @RequestParam String appid, @NotNull @RequestParam Integer type) { return resourceService.listSwiper(appid, type, 1); } + + @Operation(summary = "获取ip") + @GetMapping("/util/ip") + @ApiOperationSupport(order = 3) + public Result ip() { + return resourceService.getIp(); + } } diff --git a/wechat-server/src/main/java/com/evotech/hd/wechat/controller/WechatPayController.java b/wechat-server/src/main/java/com/evotech/hd/wechat/controller/WechatPayController.java index fa2b1c0..46970e5 100644 --- a/wechat-server/src/main/java/com/evotech/hd/wechat/controller/WechatPayController.java +++ b/wechat-server/src/main/java/com/evotech/hd/wechat/controller/WechatPayController.java @@ -9,11 +9,10 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import com.evotech.hd.common.core.entity.Result; +import com.evotech.hd.wechat.entity.PrePayVO; import com.evotech.hd.wechat.service.WechatPayService; import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport; import com.github.xiaoymin.knife4j.annotations.ApiSupport; -import com.wechat.pay.java.service.payments.jsapi.model.Detail; - import io.swagger.v3.oas.annotations.Hidden; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; @@ -35,8 +34,8 @@ public class WechatPayController { @Operation(summary = "小程序预支付订单") @PostMapping("/xcx/prepay") @ApiOperationSupport(order = 1) - public Result xcxPrepay(String wuid, String remarks, Integer money, Detail detail) { - return wechatPayService.xcxPrepay(wuid, remarks, money, detail); + public Result xcxPrepay(@RequestBody PrePayVO prePay) { + return wechatPayService.xcxPrepay(prePay); } @@ -44,8 +43,8 @@ public class WechatPayController { @PostMapping("/prepayback/msg") @ApiOperationSupport(order = 2) @Hidden - public ResponseEntity prepayBack(@RequestBody String body, HttpServletRequest request) { - return wechatPayService.PrepayBack(body, request); + public ResponseEntity prepayBack(HttpServletRequest request) { + return wechatPayService.PrepayBack(request); } @@ -69,8 +68,8 @@ public class WechatPayController { @PostMapping("/refundsback/msg") @ApiOperationSupport(order = 5) @Hidden - public ResponseEntity refundsBack(@RequestBody String body, HttpServletRequest request) { - return wechatPayService.refundsBack(body, request); + public ResponseEntity refundsBack(HttpServletRequest request) { + return wechatPayService.refundsBack(request); } diff --git a/wechat-server/src/main/java/com/evotech/hd/wechat/controller/WechatUserController.java b/wechat-server/src/main/java/com/evotech/hd/wechat/controller/WechatUserController.java index 43ae806..1baeed7 100644 --- a/wechat-server/src/main/java/com/evotech/hd/wechat/controller/WechatUserController.java +++ b/wechat-server/src/main/java/com/evotech/hd/wechat/controller/WechatUserController.java @@ -1,18 +1,25 @@ package com.evotech.hd.wechat.controller; +import java.util.List; + import org.springdoc.core.annotations.ParameterObject; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import com.evotech.hd.common.core.entity.BasePageRequest; import com.evotech.hd.common.core.entity.Result; +import com.evotech.hd.common.core.entity.cloud.WalletAccount; +import com.evotech.hd.common.core.entity.cloud.WalletAccountDetail; import com.evotech.hd.common.core.entity.wechat.WechatUser; import com.evotech.hd.wechat.service.WechatUserService; +import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport; import com.github.xiaoymin.knife4j.annotations.ApiSupport; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletRequest; @Tag(name = "微信用户") @RestController @@ -26,6 +33,7 @@ public class WechatUserController { @Operation(summary = "修改") @PostMapping("/update") + @ApiOperationSupport(order = 1) public Result update(@ParameterObject WechatUser wuser) { return wechatUserService.update(wuser); } @@ -33,15 +41,40 @@ public class WechatUserController { @Operation(summary = "查询") @PostMapping("/userbyuid") + @ApiOperationSupport(order = 2) public Result userByUid(String wuid) { return wechatUserService.userByUid(wuid); } @Operation(summary = "绑定公司") @PostMapping("/bindcompany") + @ApiOperationSupport(order = 3) public Result bindCompany(String wuid, String code, String name) { return wechatUserService.bindCompany(wuid, code, name); } + @Operation(summary = "开通钱包账户") + @PostMapping("/wallet/open") + @ApiOperationSupport(order = 4) + public Result openWallet(String wuid, HttpServletRequest request) { + return wechatUserService.openWallet(wuid, request); + } + + + @Operation(summary = "查询钱包账户") + @PostMapping("/wallet/list") + @ApiOperationSupport(order = 5) + public Result> listWallet(String wuid, HttpServletRequest request) { + return wechatUserService.listWallet(wuid, request); + } + + + @Operation(summary = "查询钱包明细") + @PostMapping("/wallet/detail/list") + @ApiOperationSupport(order = 6) + public Result> listWalletDetail(String walletCode, @ParameterObject BasePageRequest basePage) { + return wechatUserService.listWalletDetail(walletCode, basePage); + } + } diff --git a/wechat-server/src/main/java/com/evotech/hd/wechat/entity/PrePayVO.java b/wechat-server/src/main/java/com/evotech/hd/wechat/entity/PrePayVO.java new file mode 100644 index 0000000..a06ef02 --- /dev/null +++ b/wechat-server/src/main/java/com/evotech/hd/wechat/entity/PrePayVO.java @@ -0,0 +1,63 @@ +package com.evotech.hd.wechat.entity; + +import java.util.Date; +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.wechat.pay.java.service.payments.jsapi.model.GoodsDetail; + +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.media.Schema.RequiredMode; +import jakarta.validation.constraints.Max; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +@Data +@Schema(name = "预下单参数") +public class PrePayVO { + + @Schema(description = "用户编码", requiredMode = RequiredMode.REQUIRED) + @NotBlank + private String wuid; + + @Schema(description = "订单总描述", requiredMode = RequiredMode.REQUIRED) + @NotBlank + private String description; + + @Schema(description = "支付金额,单位:分", requiredMode = RequiredMode.REQUIRED) + @NotNull + @Min(1) + @Max(100000000) + private Integer total; + + @Schema(description = "支付结束时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8") + private Date timeExp; + + @Schema(description = "换电站编码", requiredMode = RequiredMode.REQUIRED) + private String StationCode; + + @Schema(description = "订单附加信息") + private String attach; + + @Schema(description = "使用的优惠活动编码", hidden = true) + private String goodsTag; + + @Schema(description = "商家小票ID", hidden = true) + private String invoiceId; + + @Schema(description = "商家小票金额", hidden = true) + private Integer costPrice; + + @Schema(description = "商品详情") + private List goodsDetail; + + @Schema(description = "用户IP", requiredMode = RequiredMode.REQUIRED) + private String payerClientIp; + + @Schema(description = "用户设备型号") + private String deviceId; + +} diff --git a/wechat-server/src/main/java/com/evotech/hd/wechat/service/CloudService.java b/wechat-server/src/main/java/com/evotech/hd/wechat/service/CloudService.java index 9175e0f..3f93e12 100644 --- a/wechat-server/src/main/java/com/evotech/hd/wechat/service/CloudService.java +++ b/wechat-server/src/main/java/com/evotech/hd/wechat/service/CloudService.java @@ -15,7 +15,11 @@ import com.evotech.hd.common.core.entity.cloud.OrderSwapBattery; import com.evotech.hd.common.core.entity.cloud.OrderSwapBatteryPre; import com.evotech.hd.common.core.entity.cloud.OrderSwapBatteryStep; import com.evotech.hd.common.core.entity.cloud.PageListSwapOrderRequest; +import com.evotech.hd.common.core.entity.cloud.TradeDetail; import com.evotech.hd.common.core.entity.cloud.VehicleInfo; +import com.evotech.hd.common.core.entity.cloud.WalletAccount; +import com.evotech.hd.common.core.entity.cloud.WalletAccountDetail; +import com.evotech.hd.common.core.entity.cloud.request.PageListWalletRequest; import com.evotech.hd.common.core.entity.cloud.vo.BatteryStationVO; @FeignClient(value = "cloud-server") @@ -53,5 +57,21 @@ public interface CloudService { @GetMapping(value = "/cloud/vehicle/wechatuser/relation/list", consumes = {MediaType.APPLICATION_FORM_URLENCODED_VALUE}) public Result> listWechatUserCar(@RequestParam String wuid); + + @PostMapping(value = "/cloud/wallet/add", + consumes = {MediaType.APPLICATION_FORM_URLENCODED_VALUE}) + public Result addWallet(WalletAccount wa); + + @GetMapping(value = "/cloud/wallet/list", + consumes = {MediaType.APPLICATION_FORM_URLENCODED_VALUE}) + public Result> listWallet(@RequestParam String wuid); + + @GetMapping(value = "/cloud/wallet/detail/list", + consumes = {MediaType.APPLICATION_FORM_URLENCODED_VALUE}) + public Result> listWalletDetail(@SpringQueryMap PageListWalletRequest plwr); + + @PostMapping(value = "/cloud/trade/wechatpay/notify", + consumes = {MediaType.APPLICATION_FORM_URLENCODED_VALUE}) + public void wechatPayNotifyHandle(TradeDetail tradeDetail); } diff --git a/wechat-server/src/main/java/com/evotech/hd/wechat/service/ResourceService.java b/wechat-server/src/main/java/com/evotech/hd/wechat/service/ResourceService.java index 34448fe..0cc9928 100644 --- a/wechat-server/src/main/java/com/evotech/hd/wechat/service/ResourceService.java +++ b/wechat-server/src/main/java/com/evotech/hd/wechat/service/ResourceService.java @@ -21,4 +21,8 @@ public interface ResourceService { @GetMapping(value = "/resource/wechat/swiper/list", consumes = {MediaType.APPLICATION_FORM_URLENCODED_VALUE}) public Result> listSwiper(@RequestParam String appid, @RequestParam Integer type, @RequestParam Integer status); + + @GetMapping(value = "/resource/util/ip", + consumes = {MediaType.APPLICATION_FORM_URLENCODED_VALUE}) + public Result getIp(); } diff --git a/wechat-server/src/main/java/com/evotech/hd/wechat/service/WechatPayService.java b/wechat-server/src/main/java/com/evotech/hd/wechat/service/WechatPayService.java index 8c0b76d..12ab7a6 100644 --- a/wechat-server/src/main/java/com/evotech/hd/wechat/service/WechatPayService.java +++ b/wechat-server/src/main/java/com/evotech/hd/wechat/service/WechatPayService.java @@ -2,21 +2,20 @@ package com.evotech.hd.wechat.service; import org.springframework.http.ResponseEntity; import com.evotech.hd.common.core.entity.Result; -import com.wechat.pay.java.service.payments.jsapi.model.Detail; - +import com.evotech.hd.wechat.entity.PrePayVO; import jakarta.servlet.http.HttpServletRequest; public interface WechatPayService { - public Result xcxPrepay(String wuid, String remarks, Integer money, Detail detail); + public Result xcxPrepay(PrePayVO prePay); - public ResponseEntity PrepayBack(String body, HttpServletRequest request); + public ResponseEntity PrepayBack(HttpServletRequest request); public Result orderQuery(Integer type, String transactionId, String outTradeNo); public Result refunds(String outTradeNo, String transactionId, String reason, Integer money, Integer total); - public ResponseEntity refundsBack(String body, HttpServletRequest request); + public ResponseEntity refundsBack(HttpServletRequest request); public Result refundsQuery(String outRefundNo); diff --git a/wechat-server/src/main/java/com/evotech/hd/wechat/service/WechatUserService.java b/wechat-server/src/main/java/com/evotech/hd/wechat/service/WechatUserService.java index 5c8bde2..a8b7e02 100644 --- a/wechat-server/src/main/java/com/evotech/hd/wechat/service/WechatUserService.java +++ b/wechat-server/src/main/java/com/evotech/hd/wechat/service/WechatUserService.java @@ -1,8 +1,15 @@ package com.evotech.hd.wechat.service; +import java.util.List; + +import com.evotech.hd.common.core.entity.BasePageRequest; import com.evotech.hd.common.core.entity.Result; +import com.evotech.hd.common.core.entity.cloud.WalletAccount; +import com.evotech.hd.common.core.entity.cloud.WalletAccountDetail; import com.evotech.hd.common.core.entity.wechat.WechatUser; +import jakarta.servlet.http.HttpServletRequest; + public interface WechatUserService { public Result update(WechatUser wuser); @@ -10,5 +17,11 @@ public interface WechatUserService { public Result userByUid(String wuid); public Result bindCompany(String wuid, String code, String name); + + public Result openWallet(String wuid, HttpServletRequest request); + + public Result> listWallet(String wuid, HttpServletRequest request); + + public Result> listWalletDetail(String walletCode, BasePageRequest basePage); } diff --git a/wechat-server/src/main/java/com/evotech/hd/wechat/service/impl/WechatPayServiceImpl.java b/wechat-server/src/main/java/com/evotech/hd/wechat/service/impl/WechatPayServiceImpl.java index ba3bc51..5a2c1c4 100644 --- a/wechat-server/src/main/java/com/evotech/hd/wechat/service/impl/WechatPayServiceImpl.java +++ b/wechat-server/src/main/java/com/evotech/hd/wechat/service/impl/WechatPayServiceImpl.java @@ -1,30 +1,48 @@ package com.evotech.hd.wechat.service.impl; +import java.io.IOException; import java.util.Date; +import java.util.List; +import org.springframework.beans.BeanUtils; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; +import org.springframework.util.StringUtils; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.evotech.hd.common.core.dao.wechat.WechatPayPreOrderDao; +import com.evotech.hd.common.core.dao.wechat.WechatUserDao; import com.evotech.hd.common.core.entity.Result; +import com.evotech.hd.common.core.entity.cloud.TradeDetail; +import com.evotech.hd.common.core.entity.wechat.WechatPayAttach; +import com.evotech.hd.common.core.entity.wechat.WechatPayPreOrder; +import com.evotech.hd.common.core.entity.wechat.WechatUser; +import com.evotech.hd.common.core.utils.XCXUtil; import com.evotech.hd.wechat.config.XcxProperties; +import com.evotech.hd.wechat.entity.PrePayVO; +import com.evotech.hd.wechat.service.CloudService; import com.evotech.hd.wechat.service.WechatPayService; import com.evotech.hd.wechat.utils.wechatpay.WechatPayUtil; import com.wechat.pay.java.core.RSAAutoCertificateConfig; import com.wechat.pay.java.core.notification.NotificationParser; import com.wechat.pay.java.core.notification.RequestParam; +import com.wechat.pay.java.core.util.IOUtil; import com.wechat.pay.java.service.billdownload.BillDownloadService; import com.wechat.pay.java.service.billdownload.model.GetTradeBillRequest; import com.wechat.pay.java.service.billdownload.model.QueryBillEntity; import com.wechat.pay.java.service.payments.jsapi.JsapiServiceExtension; import com.wechat.pay.java.service.payments.jsapi.model.Amount; import com.wechat.pay.java.service.payments.jsapi.model.Detail; +import com.wechat.pay.java.service.payments.jsapi.model.GoodsDetail; import com.wechat.pay.java.service.payments.jsapi.model.Payer; import com.wechat.pay.java.service.payments.jsapi.model.PrepayRequest; import com.wechat.pay.java.service.payments.jsapi.model.PrepayWithRequestPaymentResponse; import com.wechat.pay.java.service.payments.jsapi.model.QueryOrderByIdRequest; import com.wechat.pay.java.service.payments.jsapi.model.QueryOrderByOutTradeNoRequest; +import com.wechat.pay.java.service.payments.jsapi.model.SceneInfo; import com.wechat.pay.java.service.payments.model.Transaction; +import com.wechat.pay.java.service.payments.model.Transaction.TradeTypeEnum; import com.wechat.pay.java.service.refund.RefundService; import com.wechat.pay.java.service.refund.model.AmountReq; import com.wechat.pay.java.service.refund.model.CreateRequest; @@ -37,37 +55,85 @@ import cn.hutool.core.util.RandomUtil; import cn.hutool.json.JSONObject; import cn.hutool.json.JSONUtil; import jakarta.annotation.Resource; +import jakarta.servlet.ServletInputStream; import jakarta.servlet.http.HttpServletRequest; +import lombok.extern.slf4j.Slf4j; @Service +@Slf4j public class WechatPayServiceImpl implements WechatPayService { @Resource private RSAAutoCertificateConfig config; @Resource private XcxProperties xcxProperties; + @Resource + private WechatUserDao wechatUserDao; + @Resource + private WechatPayPreOrderDao preOrderDao; + @Resource + private CloudService cloudService; @Override - public Result xcxPrepay(String wuid, String remarks, Integer money, Detail detail) { + public Result xcxPrepay(PrePayVO prePay) { + // 校验用户 + WechatUser wuser = wechatUserDao.selectOne(new QueryWrapper().eq("wuid", prePay.getWuid())); + if (wuser == null || !StringUtils.hasText(wuser.getOpenid())) { + return new Result().error("用户信息错误"); + } + WechatPayPreOrder preOrder = new WechatPayPreOrder(); + // 组装数据 PrepayRequest request = new PrepayRequest(); - Amount amount = new Amount(); -// amount.setTotal(money); - amount.setTotal(1); - request.setAmount(amount); - request.setAttach(remarks); + // 基础信息 + request.setTimeExpire(prePay.getTimeExp() == null?DateUtil.format(DateUtil.offsetMinute(new Date(), 30), DatePattern.UTC_PATTERN): DateUtil.format(prePay.getTimeExp(), DatePattern.UTC_PATTERN)); + request.setAttach(prePay.getAttach()); request.setAppid(xcxProperties.getAppid()); request.setMchid(xcxProperties.getMchid()); - request.setDescription("测试商品标题"); + request.setDescription(prePay.getDescription()); request.setNotifyUrl(xcxProperties.getNotifyUrl()); - request.setOutTradeNo("HD1001" + DateUtil.format(new Date(), DatePattern.PURE_DATETIME_FORMATTER) + RandomUtil.randomInt(10000, 100000)); + request.setOutTradeNo(XCXUtil.payOutTradeNo(prePay.getStationCode())); + // 金额 + Amount amount = new Amount(); +// amount.setTotal(prePay.getMoney()); + amount.setTotal(1); + request.setAmount(amount); + // 付款人 Payer payer = new Payer(); - payer.setOpenid("ocEmP7fbW-QD6tbNpi7B665xJu2g"); + payer.setOpenid(wuser.getOpenid()); request.setPayer(payer); -// request.setDetail(detail); - request.setTimeExpire(DateUtil.format(DateUtil.offsetHour(new Date(), 1), DatePattern.UTC_PATTERN)); + // 商品信息 + Detail detail = new Detail(); + detail.setCostPrice(prePay.getCostPrice()); + detail.setInvoiceId(prePay.getInvoiceId()); + List goodsDetail = prePay.getGoodsDetail(); + if (goodsDetail != null && !goodsDetail.isEmpty()) { + detail.setGoodsDetail(goodsDetail); + preOrder.setGoodsDetail(JSONUtil.toJsonStr(goodsDetail)); + request.setDetail(detail); + } + + // 场景信息 + if (StringUtils.hasText(prePay.getPayerClientIp())) { + SceneInfo si = new SceneInfo(); + si.setPayerClientIp(prePay.getPayerClientIp()); + si.setDeviceId(prePay.getDeviceId()); + request.setSceneInfo(si); + preOrder.setPayerClientIp(prePay.getPayerClientIp()); + preOrder.setDeviceId(prePay.getDeviceId()); + } PrepayWithRequestPaymentResponse response = WechatPayUtil.jsapiPrepay(config, request); - System.out.println("\r\n=====>>>>>" + response); +// System.out.println("\r\n=====response>>>>>" + response); + // 写表 + BeanUtils.copyProperties(request, preOrder); + preOrder.setPrePayResponse(JSONUtil.toJsonStr(response)); + preOrder.setWuid(prePay.getWuid()); + preOrder.setTotal(amount.getTotal()); + preOrder.setOpenid(payer.getOpenid()); + preOrder.setCostPrice(prePay.getCostPrice()); + preOrder.setCtime(new Date()); + preOrderDao.insert(preOrder); + return new Result().success(response); } @@ -75,7 +141,39 @@ public class WechatPayServiceImpl implements WechatPayService { * 用SDK中封装的NotificationParser解析器进行验签和解密 */ @Override - public ResponseEntity PrepayBack(String body, HttpServletRequest request) { + public ResponseEntity PrepayBack(HttpServletRequest request) { + // 1. 验签解密 + Transaction transaction; + try { + transaction = decryptWechatPayNotify(request); + } catch (Exception e) { + JSONObject jo = new JSONObject(); + jo.set("code", "FAIL"); + jo.set("message", "解析body异常"); + return new ResponseEntity(jo.toJSONString(0), HttpStatus.FAILED_DEPENDENCY); + } + // 2. 业务处理逻辑 + wechatPayBussinessHandle(transaction); + + // 3. 回复微信 + return new ResponseEntity("", HttpStatus.OK); + } + + /** + * 微信支付回调 解密 + * @param request + * @return + * @throws IOException + */ + private Transaction decryptWechatPayNotify(HttpServletRequest request) throws IOException { + String body = ""; + try { + ServletInputStream inputStream = request.getInputStream(); + body = IOUtil.toString(inputStream); + } catch (IOException e) { + e.printStackTrace(); + throw e; + } // 1. 初始化解析器 NotificationParser parser = new NotificationParser(config); // 2. 构造解析器所需参数 @@ -88,46 +186,64 @@ public class WechatPayServiceImpl implements WechatPayService { .signature(request.getHeader("Wechatpay-Signature")) // 时间戳 .timestamp(request.getHeader("Wechatpay-Timestamp")) + // 默认值为 WECHATPAY2-SHA256-RSA2048 + .signType(request.getHeader("Wechatpay-Signature-Type")) .body(body) .build(); - // 3. 验签、解密,parse方法中包含2个方法,一个验签,一个解密 Transaction transaction; try { transaction = parser.parse(param, Transaction.class); + log.info("\r\n===>>>支付回调信息:" + JSONUtil.toJsonStr(transaction)); } catch (Exception e) { e.printStackTrace(); - JSONObject jo = new JSONObject(); - jo.set("code", "FAIL"); - jo.set("message", e.getMessage()); - return new ResponseEntity(jo.toJSONString(0), HttpStatus.FAILED_DEPENDENCY); + throw e; } - // 4. 业务处理逻辑 - System.out.println("\r\n=====>>>>>" + JSONUtil.toJsonPrettyStr(transaction)); - if (Transaction.TradeStateEnum.SUCCESS.equals(transaction.getTradeState())) { - - System.out.println(transaction.toString()); - // 支付成功,根据订单编号更新订单状态 - // 查询订单信息 -// Order orderOld = orderService.selectForUpdateByOrderNumber(transaction.getOutTradeNo()); - // 校验金额 -// if (0 == 0) { -// // 金额相等 完成支付 更新订单状态 -//// WechatPayUtil.success(orderOld, transaction); -// } else { -// // 金额异常 执行退款 -//// WechatPayUtil.refunded(new WechatPayRedis(transaction.getOutTradeNo(), transaction.getAmount().getTotal(), null)); -// } - } else { - // 订单支付失败 - System.out.println(transaction.getTradeStateDesc()); + return transaction; + } + + /** + * 微信支付回调业务处理 + * @param transaction + */ + private void wechatPayBussinessHandle(Transaction transaction) { + // 1. 生成交易信息 + TradeDetail tradeDetail = new TradeDetail(); + BeanUtils.copyProperties(transaction, tradeDetail); + + WechatUser wuser = wechatUserDao.selectOne(new QueryWrapper().eq("openid", transaction.getPayer().getOpenid())); + if (wuser != null) { + tradeDetail.setPayer(wuser.getWuid()); + } else { + tradeDetail.setPayer(transaction.getPayer().getOpenid()); + } + // 附加信息处理 + WechatPayAttach payAttach = JSONUtil.toBean(transaction.getAttach(), WechatPayAttach.class); + tradeDetail.setTradeType(payAttach.getType()); + tradeDetail.setTrader(payAttach.getTrader()); + tradeDetail.setTraderCode(payAttach.getTraderCode()); + tradeDetail.setWallet(payAttach.getWalletCode()); + if (payAttach.getType() == 2) { + tradeDetail.setOrderNo(payAttach.getOrderNo()); + tradeDetail.setOrderCount(payAttach.getOrderNo().split(",").length); } - return new ResponseEntity("", HttpStatus.OK); - // 发生异常 - - - + tradeDetail.setTradeAmount(transaction.getAmount().getPayerTotal()); + + TradeTypeEnum tradePayType = transaction.getTradeType(); + if (tradePayType.equals(Transaction.TradeTypeEnum.JSAPI)) { + tradeDetail.setPayType(21); + } + if (tradePayType.equals(Transaction.TradeTypeEnum.NATIVE)) { + tradeDetail.setPayType(22); + } + + tradeDetail.setPayResult(transaction.getTradeState().name()); + tradeDetail.setPayMsg(transaction.getTradeStateDesc()); + tradeDetail.setPayTime(DateUtil.parseUTC(transaction.getSuccessTime())); + + // 2. 处理订单,看要不要异步 + cloudService.wechatPayNotifyHandle(tradeDetail); } @Override @@ -169,7 +285,14 @@ public class WechatPayServiceImpl implements WechatPayService { } @Override - public ResponseEntity refundsBack(String body, HttpServletRequest request) { + public ResponseEntity refundsBack(HttpServletRequest request) { + String body = ""; + try { + ServletInputStream inputStream = request.getInputStream(); + body = IOUtil.toString(inputStream); + } catch (IOException e) { + e.printStackTrace(); + } // 1. 初始化解析器 NotificationParser parser = new NotificationParser(config); // 2. 构造解析器所需参数 diff --git a/wechat-server/src/main/java/com/evotech/hd/wechat/service/impl/WechatUserServiceImpl.java b/wechat-server/src/main/java/com/evotech/hd/wechat/service/impl/WechatUserServiceImpl.java index f7d5caa..1654f8e 100644 --- a/wechat-server/src/main/java/com/evotech/hd/wechat/service/impl/WechatUserServiceImpl.java +++ b/wechat-server/src/main/java/com/evotech/hd/wechat/service/impl/WechatUserServiceImpl.java @@ -1,16 +1,25 @@ package com.evotech.hd.wechat.service.impl; +import java.util.List; + import org.springframework.stereotype.Service; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.evotech.hd.common.core.constant.HDConstant; import com.evotech.hd.common.core.dao.wechat.WechatUserDao; +import com.evotech.hd.common.core.entity.BasePageRequest; import com.evotech.hd.common.core.entity.Result; +import com.evotech.hd.common.core.entity.cloud.WalletAccount; +import com.evotech.hd.common.core.entity.cloud.WalletAccountDetail; +import com.evotech.hd.common.core.entity.cloud.request.PageListWalletRequest; import com.evotech.hd.common.core.entity.wechat.WechatUser; import com.evotech.hd.common.core.enums.CodeMsg; +import com.evotech.hd.wechat.service.CloudService; import com.evotech.hd.wechat.service.WechatUserService; import cn.hutool.core.util.DesensitizedUtil; import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletRequest; @Service @@ -18,6 +27,8 @@ public class WechatUserServiceImpl implements WechatUserService { @Resource private WechatUserDao wechatUserDao; + @Resource + private CloudService cloudService; @Override @@ -59,4 +70,35 @@ public class WechatUserServiceImpl implements WechatUserService { return new Result().error("绑定出错!"); } + @Override + public Result openWallet(String wuid, HttpServletRequest request) { + if (!wuid.equals(request.getHeader(HDConstant.WECHAT_SERVER_AUTHORIZATION_KEY))) { + return new Result().error("账号错误"); + } + WalletAccount wa = new WalletAccount(); + wa.setOwnerType(1); + wa.setOwnerId(wuid); + Result res = cloudService.addWallet(wa); + return res; + } + + @Override + public Result> listWallet(String wuid, HttpServletRequest request) { + if (!wuid.equals(request.getHeader(HDConstant.WECHAT_SERVER_AUTHORIZATION_KEY))) { + return new Result>().error("账号错误"); + } + + return cloudService.listWallet(wuid); + } + + @Override + public Result> listWalletDetail(String walletCode, BasePageRequest basePage) { + PageListWalletRequest plwr = new PageListWalletRequest(); + plwr.setCode(walletCode); + plwr.setPageSize(basePage.getPageSize()); + plwr.setPageNo(basePage.getPageNo()); + + return cloudService.listWalletDetail(plwr); + } + } diff --git a/wechat-server/src/main/resources/static/key/wechatpay_2CF671A0B59945ECDF68E7560D79CDD683501AF5.pem b/wechat-server/src/main/resources/static/key/wechatpay_2CF671A0B59945ECDF68E7560D79CDD683501AF5.pem new file mode 100644 index 0000000..5e9d4cd --- /dev/null +++ b/wechat-server/src/main/resources/static/key/wechatpay_2CF671A0B59945ECDF68E7560D79CDD683501AF5.pem @@ -0,0 +1,24 @@ +-----BEGIN CERTIFICATE----- +MIIEFDCCAvygAwIBAgIULPZxoLWZRezfaOdWDXnN1oNQGvUwDQYJKoZIhvcNAQEL +BQAwXjELMAkGA1UEBhMCQ04xEzARBgNVBAoTClRlbnBheS5jb20xHTAbBgNVBAsT +FFRlbnBheS5jb20gQ0EgQ2VudGVyMRswGQYDVQQDExJUZW5wYXkuY29tIFJvb3Qg +Q0EwHhcNMjQxMDIxMDIzMzI5WhcNMjkxMDIwMDIzMzI5WjBuMRgwFgYDVQQDDA9U +ZW5wYXkuY29tIHNpZ24xEzARBgNVBAoMClRlbnBheS5jb20xHTAbBgNVBAsMFFRl +bnBheS5jb20gQ0EgQ2VudGVyMQswCQYDVQQGEwJDTjERMA8GA1UEBwwIU2hlblpo +ZW4wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDIsrKwNh8t+mysE46b +joB8yqSy+4sL+mfqvc+9bSIbwv5pi2ESwKch73wHObXS1rK3PEt4o+3gF3yNtBWh +/IuOFXysZOFySnlw8ii87mIXp5AMQwxUdfvnI/kUuhveLOsDAC8E6uAV1uPFJD2q +4uh0MyohwxHSA8V66V0caeoEDj80zW5V0ArV+EWw1/WW/bL2IWHfZ02xPWDCHxYT +4XmMtDn7U/gndg8QTOTI+2iPKaUoN12GeBLEuoq3Ot93jgpdh3KVYReSWpNWZ9mT +d3wL84DoI+V9IpAfEPOUq9zTdMB5MEr1ZtmxlcbZWhc++upGz10sv46NDnJ1YZBs +gs/pAgMBAAGjgbkwgbYwCQYDVR0TBAIwADALBgNVHQ8EBAMCA/gwgZsGA1UdHwSB +kzCBkDCBjaCBiqCBh4aBhGh0dHA6Ly9ldmNhLml0cnVzLmNvbS5jbi9wdWJsaWMv +aXRydXNjcmw/Q0E9MUJENDIyMEU1MERCQzA0QjA2QUQzOTc1NDk4NDZDMDFDM0U4 +RUJEMiZzZz1IQUNDNDcxQjY1NDIyRTEyQjI3QTlEMzNBODdBRDFDREY1OTI2RTE0 +MDM3MTANBgkqhkiG9w0BAQsFAAOCAQEACiuWYNkqA2bZPV5EOE8aFXXCFiU8I/sa +lNn7qWE42n2qf1BspTihFU2xZhDA8tqcBkQcw2W+quOMNv3Di43jXBFS9d/PI1o0 ++Pt/UePgpDVLyaZXl1i8Bo739XCVnG7MSB6++TbRnIFZLDp1WXn+jR2OUvQbUsyN +pdZr578juOmXCkeZewXtHuhd/zR4iCVD05miB11msIuH0F3f8DD4y6W8hxCEjuE0 +WV68UT+D90dIFjOQmraRNH9Os9FYRvJ1QwcYvDjPQF4KuyvWM5vC4j/FOR91vg/Q +gxKzttDmA7RW/C27HUgNh83bytJsPPkRiUxKmhbHnwgWwa/FdPsmPg== +-----END CERTIFICATE----- \ No newline at end of file