This commit is contained in:
zt
2025-06-10 21:17:29 +08:00
parent 0cc91a0894
commit 6b92d0f800
123 changed files with 6837 additions and 19 deletions

View File

@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.pay.controller.admin.notify;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.json.JSONUtil;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
@ -10,6 +11,8 @@ import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO;
import cn.iocoder.yudao.framework.pay.core.enums.divide.PayDivideRefundStatusRespEnum;
import cn.iocoder.yudao.framework.pay.core.enums.refund.PayRefundStatusRespEnum;
import cn.iocoder.yudao.module.member.api.activitypay.ActivityApi;
import cn.iocoder.yudao.module.member.api.activitypay.dto.ActivityPayDTO;
import cn.iocoder.yudao.module.member.api.card.CardApi;
import cn.iocoder.yudao.module.pay.controller.admin.notify.vo.PayNotifyTaskDetailRespVO;
import cn.iocoder.yudao.module.pay.controller.admin.notify.vo.PayNotifyTaskPageReqVO;
@ -38,18 +41,14 @@ import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.annotation.security.PermitAll;
import javax.validation.Valid;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -87,6 +86,8 @@ public class PayNotifyController {
private StringRedisTemplate notifyRedisTemplate;
@Resource
private CardApi cardApi;
@Resource
private ActivityApi activityApi;
@PostMapping(value = "/order/{channelId}")
@Operation(summary = "支付渠道的统一【支付】回调")
@ -117,6 +118,45 @@ public class PayNotifyController {
return "success";
}
@PostMapping(value = "/reserved/{channelId}")
@Operation(summary = "支付渠道的统一【支付】回调")
@PermitAll
@OperateLog(enable = false) // 回调地址,无需记录操作日志
public String reservedNotifyOrder(@PathVariable("channelId") Long channelId,
@RequestParam(required = false) Map<String, String> params,
@RequestBody(required = false) String body) {
log.info("[notifyOrder][channelId({}) 回调数据({}/{})]", channelId, params, body);
// 1. 校验支付渠道是否存在
PayClient payClient = channelService.getPayClient(channelId);
if (payClient == null) {
log.error("[notifyCallback][渠道编号({}) 找不到对应的支付客户端]", channelId);
throw exception(CHANNEL_NOT_FOUND);
}
// 2. 解析通知数据
PayOrderRespDTO notify = payClient.parseOrderNotify(params, body);
orderService.notifyOrder(channelId, notify);
String re = notifyRedisTemplate.opsForValue().get("RESERVED" + notify.getOutTradeNo());
if(StringUtils.isNotBlank(re) ){
log.info("开始进行订单记录增加,获取的数据:{}", re);
HashMap<String, String> deserializedMap = JSONUtil.toBean(re, HashMap.class);
ActivityPayDTO activityPayDTO = new ActivityPayDTO();
activityPayDTO.setActivityId(Long.valueOf(deserializedMap.get("activityId")));
activityPayDTO.setSerialNumbers(deserializedMap.get("serialNumbers"));
activityPayDTO.setPrice(new BigDecimal(deserializedMap.get("price")).divide(new BigDecimal("100"), 2, RoundingMode.HALF_UP));
activityPayDTO.setUserId(Long.valueOf(deserializedMap.get("userId")));
activityPayDTO.setStatus(deserializedMap.get("status"));
activityPayDTO.setReserveTime(deserializedMap.get("reserveTime"));
activityPayDTO.setDish( deserializedMap.get("dish"));
activityPayDTO.setDiningPeriod( deserializedMap.get("diningPeriod"));
activityApi.createActivityPay(activityPayDTO);
notifyRedisTemplate.delete("RESERVED" + notify.getOutTradeNo());
}
return "success";
}
@PostMapping(value = "/refund/{channelId}")
@Operation(summary = "支付渠道的统一【退款】回调")
@PermitAll

View File

@ -30,4 +30,17 @@ public class PayOrderSubmitReqVO {
@URL(message = "回跳地址的格式必须是 URL")
private String returnUrl;
private String serialNumbers;
private Long activityId;
private Long userId;
private String status;
private String reserveTime;
private String dish;
private String diningPeriod;
}

View File

@ -18,6 +18,9 @@ public class AppPayWalletRechargeCreateReqVO {
@Schema(description = "充值套餐编号", example = "1024")
private Long packageId;
@Schema(description = "充值类型1-充值 2-活动订餐", example = "1024")
private String type;
@AssertTrue(message = "充值金额和充钱套餐不能同时为空")
public boolean isValidPayPriceAndPackageId() {
return Objects.nonNull(payPrice) || Objects.nonNull(packageId);

View File

@ -28,6 +28,11 @@ public class PayProperties {
@URL(message = "支付回调地址的格式必须是 URL")
private String orderNotifyUrl;
@NotEmpty(message = "预定支付回调地址不能为空")
@URL(message = "预定支付回调地址的格式必须是 URL")
private String reservedNotifyUrl;
/**
* 退款回调地址
*

View File

@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
import cn.iocoder.yudao.framework.common.util.number.MoneyUtils;
@ -43,10 +44,7 @@ import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.*;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
@ -174,10 +172,28 @@ public class PayOrderServiceImpl implements PayOrderService {
.setReturnUrl(reqVO.getReturnUrl())
// 订单相关字段
.setPrice(order.getPrice()).setExpireTime(order.getExpireTime());
if (reqVO.getActivityId()!=null){
unifiedOrderReqDTO.setNotifyUrl(genChannelReservedNotifyUrl(channel));
HashMap<String, String> stringStringHashMap = new HashMap<>();
stringStringHashMap.put("activityId",reqVO.getActivityId().toString());
stringStringHashMap.put("userId",getLoginUserId().toString());
stringStringHashMap.put("serialNumbers",reqVO.getSerialNumbers());
stringStringHashMap.put("price",unifiedOrderReqDTO.getPrice().toString());
stringStringHashMap.put("status",reqVO.getStatus());
stringStringHashMap.put("reserveTime",reqVO.getReserveTime());
stringStringHashMap.put("dish",reqVO.getDish());
stringStringHashMap.put("diningPeriod",reqVO.getDiningPeriod());
payRedis.opsForValue().set("RESERVED"+unifiedOrderReqDTO.getOutTradeNo()
, JSONUtil.toJsonStr(stringStringHashMap));
log.info("REDIS_ID:RESERVED{} 总金额:{}", unifiedOrderReqDTO.getOutTradeNo(), unifiedOrderReqDTO.getPrice().toString());
}else{
payRedis.opsForValue().set("ADD"+unifiedOrderReqDTO.getOutTradeNo()
,unifiedOrderReqDTO.getPrice().toString()+"-"+getLoginUserId());
log.info("REDIS_ID:ADD{} 总金额:{}", unifiedOrderReqDTO.getOutTradeNo(), unifiedOrderReqDTO.getPrice().toString());
}
PayOrderRespDTO unifiedOrderResp = client.unifiedOrder(unifiedOrderReqDTO);
payRedis.opsForValue().set("ADD"+unifiedOrderReqDTO.getOutTradeNo()
,unifiedOrderReqDTO.getPrice().toString()+"-"+getLoginUserId());
log.info("REDISID:"+"ADD"+unifiedOrderReqDTO.getOutTradeNo()+" 总金额:"+unifiedOrderReqDTO.getPrice().toString());
// 4. 如果调用直接支付成功,则直接更新支付单状态为成功。例如说:付款码支付,免密支付时,就直接验证支付成功
if (unifiedOrderResp != null) {
getSelf().notifyOrder(channel, unifiedOrderResp);
@ -265,6 +281,10 @@ public class PayOrderServiceImpl implements PayOrderService {
return payProperties.getOrderNotifyUrl() + "/" + channel.getId();
}
private String genChannelReservedNotifyUrl(PayChannelDO channel) {
return payProperties.getReservedNotifyUrl() + "/" + channel.getId();
}
@Override
public void notifyOrder(Long channelId, PayOrderRespDTO notify) {
// 校验支付渠道是否有效

View File

@ -82,10 +82,15 @@ public class PayWalletRechargeServiceImpl implements PayWalletRechargeService {
walletRechargeMapper.insert(recharge);
// 2.1 创建支付单
String subject = WALLET_RECHARGE_ORDER_SUBJECT;
if("2".equals(reqVO.getType())){
subject = "活动订餐";
}
Long payOrderId = payOrderService.createOrder(new PayOrderCreateReqDTO()
.setAppId(WALLET_PAY_APP_ID).setUserIp(userIp)
.setMerchantOrderId(recharge.getId().toString()) // 业务的订单编号
.setSubject(WALLET_RECHARGE_ORDER_SUBJECT).setBody("")
.setSubject(subject)
.setBody("")
.setPrice(recharge.getPayPrice())
.setExpireTime(addTime(Duration.ofHours(2L)))); // TODO @芋艿:支付超时时间
// 2.2 更新钱包充值记录中支付订单