fix - 用户可能会有多个订单的情况优化。保持订单幂等。

This commit is contained in:
2026-06-03 16:40:06 +08:00
parent 6074da7c87
commit d66010a830
17 changed files with 362 additions and 66 deletions

View File

@@ -92,6 +92,11 @@ public interface OrderMapper {
Order findLastOrder(@Param("memberId") Integer memberId);
/**
* api 查询用户在当前场馆的待支付篮球订单近10分钟内
*/
Order findPendingBasketballOrder(@Param("memberId") Integer memberId, @Param("venueId") Integer venueId);
/**
* api 根据订单编号查询总价钱
*/

View File

@@ -9,6 +9,7 @@ import com.sv.dto.api.wechat.OrderPaySignResponse;
import com.sv.entity.*;
import com.sv.mapper.MemberCardOrderMapper;
import com.sv.service.api.config.WechatPayService;
import com.sv.service.common.MemberKeyLock;
import com.ydd.framework.core.common.Pagination;
import com.ydd.framework.core.common.utils.ValidationUtils;
import com.ydd.framework.core.exception.ExceptionCodeTemplate;
@@ -51,6 +52,8 @@ public class MemberCardOrderService extends BaseServiceImpl {
private MemberService memberService;
@Resource
private MemberCardService memberCardService;
@Resource
private MemberKeyLock memberKeyLock;
/**
* 创建用户会员卡订单
@@ -138,8 +141,9 @@ public class MemberCardOrderService extends BaseServiceImpl {
* @return
*/
@Transactional
public synchronized OrderPaySignResponse.WechatPayParam createCardOrder(Integer memberId,Integer cardType,
public OrderPaySignResponse.WechatPayParam createCardOrder(Integer memberId,Integer cardType,
Integer type,Integer venueId,Integer num,Integer platformId,String ip){
synchronized (memberKeyLock.getLock(memberId)) {
// 判断用户是否登录
if (memberId == null){
throw new ServiceException(ExceptionCodeTemplate.NEED_LOGIN);
@@ -183,6 +187,7 @@ public class MemberCardOrderService extends BaseServiceImpl {
// 4.调支付
OrderPaySignResponse.WechatPayParam wechatPayParam = createUnifiedOrder(order.getOrderSn(), memberId,ip,"购买商品");
return wechatPayParam;
}
}
/**

View File

@@ -10,6 +10,7 @@ import com.sv.entity.*;
import com.sv.exception.api.ExceptionCodeTemplate;
import com.sv.mapper.MemberLessonTicketMapper;
import com.sv.service.api.util.DateUtilCard;
import com.sv.service.common.MemberKeyLock;
import com.sv.service.common.RedisLock;
import com.sv.service.message.AsyncTaskUtil;
import com.sv.service.message.NotifyAdminMsgThread;
@@ -73,6 +74,8 @@ public class MemberLessonTicketService extends BaseServiceImpl {
private MemberRefundService memberRefundService;
@Resource
private RedisTemplate<String, Object> redisTemplate;
@Resource
private MemberKeyLock memberKeyLock;
/**
@@ -175,7 +178,7 @@ public class MemberLessonTicketService extends BaseServiceImpl {
* 预约课程微信下单LessonTicketOrderDTO
*/
@Transactional
public synchronized OrderPaySignResponse.WechatPayParam createOrder(Integer memberId, LessonTicketOrderDTO lessonTicketOrderDTO, Integer platformId, String ip) {
public OrderPaySignResponse.WechatPayParam createOrder(Integer memberId, LessonTicketOrderDTO lessonTicketOrderDTO, Integer platformId, String ip) {
// 判断用户信息
if (memberId == null) {
@@ -237,17 +240,16 @@ public class MemberLessonTicketService extends BaseServiceImpl {
}
OrderPaySignResponse.WechatPayParam wechatPayParam = new OrderPaySignResponse.WechatPayParam();
synchronized (lessonTicketOrderDTO.getLessonId()) {
// 2.判断票是否足够
Integer count = venueLessonTicketService.findCount(lessonTicketOrderDTO.getLessonId());
if (count.intValue() < lessonTicketOrderDTO.getNum().intValue()) {
throw new ServiceException(com.sv.exception.api.ExceptionCodeTemplate.LESSON_TICKET_ERROR);
}
/**
* 课程库存锁
*/
RedisLock redisLock = new RedisLock(redisTemplate, LESSON_TICKET_LOCK_KEY + venueLesson.getId());
// 2.判断票是否足够
Integer count = venueLessonTicketService.findCount(lessonTicketOrderDTO.getLessonId());
if (count.intValue() < lessonTicketOrderDTO.getNum().intValue()) {
throw new ServiceException(com.sv.exception.api.ExceptionCodeTemplate.LESSON_TICKET_ERROR);
}
/**
* 课程库存锁
*/
RedisLock redisLock = new RedisLock(redisTemplate, LESSON_TICKET_LOCK_KEY + venueLesson.getId());
try {
//加锁
boolean flag = redisLock.lock();
@@ -298,7 +300,6 @@ public class MemberLessonTicketService extends BaseServiceImpl {
redisLock.unlock();
throw new ServiceException(com.sv.exception.api.ExceptionCodeTemplate.SERVER_ERROR);
}
}
return wechatPayParam;
}
@@ -313,7 +314,7 @@ public class MemberLessonTicketService extends BaseServiceImpl {
* 预约课程,会员卡支付
*/
@Transactional
public synchronized String createOrderByMemberCard(Integer memberId, LessonTicketOrderDTO lessonTicketOrderDTO, Integer platformId) {
public String createOrderByMemberCard(Integer memberId, LessonTicketOrderDTO lessonTicketOrderDTO, Integer platformId) {
// 判断用户信息
if (memberId == null) {
@@ -355,7 +356,7 @@ public class MemberLessonTicketService extends BaseServiceImpl {
memberCardService.findByStatus(memberCard.getVenueId(),memberCard.getVeneuType(),memberId,memberCard);
}*/
String orderSn = "";
synchronized (lessonTicketOrderDTO.getLessonId()) {
synchronized (memberKeyLock.getLock(lessonTicketOrderDTO.getLessonId())) {
// 2.判断票是否足够
Integer count = venueLessonTicketService.findCount(lessonTicketOrderDTO.getLessonId());
if (count.intValue() < lessonTicketOrderDTO.getNum().intValue()) {

View File

@@ -2,6 +2,8 @@ package com.sv.service.api;
import com.enums.*;
import com.github.pagehelper.PageHelper;
import com.dw.ccm.wechat.base.pay.response.OrderResponse;
import com.sv.dto.api.BasketballPayResult;
import com.sv.dto.api.wechat.BaseResult;
import com.sv.dto.api.wechat.OrderPaySignResponse;
import com.sv.entity.*;
@@ -11,6 +13,7 @@ import com.sv.mapper.OrderMapper;
import com.sv.mapper.VenueMapper;
import com.sv.mapper.VenuePriceMapper;
import com.sv.service.api.config.WechatPayService;
import com.sv.service.common.MemberKeyLock;
import com.ydd.framework.core.common.Pagination;
import com.ydd.framework.core.common.utils.RequestUtils;
import com.ydd.framework.core.exception.ServiceException;
@@ -61,6 +64,10 @@ public class OrderService extends BaseServiceImpl {
private VenuePriceMapper venuePriceMapper;
@Resource
private BarcodeOrderTimeMapper barcodeOrderTimeMapper;
@Resource
private VenueEnterService venueEnterService;
@Resource
private MemberKeyLock memberKeyLock;
/**
* 创建订单
@@ -244,11 +251,11 @@ public class OrderService extends BaseServiceImpl {
}
/**
* 生成进场订单
* 生成进场订单(防重复下单)
* @param memberId
* @return
*/
public OrderPaySignResponse.WechatPayParam createEnterVenueOrder(Integer venueId, Integer memberId, Integer enterFlag,PayTypeEnum payTypeEnum, BigDecimal price){
public BasketballPayResult createEnterVenueOrder(Integer venueId, Integer memberId, Integer enterFlag,PayTypeEnum payTypeEnum, BigDecimal price){
Venue venue = venueMapper.findById(venueId);
if (venue == null) {
throw new ServiceException("未找到该场馆");
@@ -256,7 +263,6 @@ public class OrderService extends BaseServiceImpl {
Member member = memberService.findById(memberId);
memberService.verify(member);
// 判断用户是否使用微信登录
MemberAuth memberAuth = memberAuthService.findByMemberId(memberId);
if (memberAuth == null){
throw new ServiceException(ExceptionCodeTemplate.BUY_ERROR);
@@ -269,43 +275,76 @@ public class OrderService extends BaseServiceImpl {
boolean checkPrice = false;
for (VenuePrice venuePrice : priceList) {
if (price.divideAndRemainder(price)[1].compareTo(BigDecimal.ZERO) == 0) {
// 取余数为0
checkPrice = true;
}
}
if (!checkPrice) {
throw new ServiceException("价格非法!");
}
//创建订单
Order order = new Order();
order.setOrderSn(createSn());
order.setPayType(payTypeEnum.value);
order.setPrice(price);
order.setPayStatus(PayStatusEnum.NOT_PAY.value);
order.setType(OrderTypeEnum.BASKETBALL_ORDER.value);
order.setPlatformId(venue.getPlatformId());
order.setMemberId(memberId);
order.setParentOrderId(venueId); /** 篮球入场这里输入场馆ID */
order.setCreatedId(enterFlag); /** 篮球入场这里输入出场结算还是入场结算 */
orderMapper.insert(order);
//扣除用户余额 目前篮球订单不支持余额支付
// if(payTypeEnum.value.equals(PayTypeEnum.BALANCE.value)) {
// memberMoneyLogService.create(memberId, venue.getPlatformId(), MoneyLogEnum.JOIN.value, price.negate(), PayTypeEnum.BALANCE.value, null, venue.getId(), venue.getType(), null);
// }
if (EnterEnum.OUT.value == enterFlag) {
// 出场的话,将出场的订单设定 未结算 支付金额为 -1 这样批处理不会被结算,需要支付回调处理
BarcodeOrderTime lastOrder = barcodeOrderTimeMapper.findLastOrder(memberId, venueId);
if (lastOrder != null) {
lastOrder.setPaying(1);
lastOrder.setPayMoney(new BigDecimal(-1));
lastOrder.setOrderAddSn(order.getOrderSn());
// lastOrder.setOrderSn(order.getOrderSn());
lastOrder.setModifiedTime(new Date());
barcodeOrderTimeMapper.updateByPrimaryKey(lastOrder);
synchronized (memberKeyLock.getLock(memberId)) {
Order pendingOrder = orderMapper.findPendingBasketballOrder(memberId, venueId);
if (pendingOrder != null) {
OrderResponse wxResponse = wechatPayService.queryWechatOrder(pendingOrder.getOrderSn());
if (wxResponse != null && wxResponse.isSuccess() && "SUCCESS".equals(wxResponse.getTradeState())) {
pendingOrder.setPayStatus(PayStatusEnum.PAYED.value);
pendingOrder.setTradeSn(wxResponse.getTransactionId());
pendingOrder.setPayTime(new Date());
orderMapper.update(pendingOrder);
venueEnterService.paySuccess(pendingOrder);
BasketballPayResult paidResult = new BasketballPayResult();
paidResult.setPaidFlag(true);
paidResult.setOrderSn(pendingOrder.getOrderSn());
return paidResult;
}
OrderPaySignResponse.WechatPayParam wechatPayParam;
if (pendingOrder.getPrepayId() != null) {
wechatPayParam = wechatPayService.resignPayParam(pendingOrder.getOrderSn(), pendingOrder.getPrepayId());
} else {
wechatPayParam = memberCardOrderService.createUnifiedOrder(pendingOrder.getOrderSn(), memberId, RequestUtils.getIp(), "入场结算订单");
}
wechatPayParam.setOrderSn(pendingOrder.getOrderSn());
BasketballPayResult result = new BasketballPayResult();
result.setPaidFlag(false);
result.setOrderSn(pendingOrder.getOrderSn());
result.setWechatPayParam(wechatPayParam);
return result;
}
Order order = new Order();
order.setOrderSn(createSn());
order.setPayType(payTypeEnum.value);
order.setPrice(price);
order.setPayStatus(PayStatusEnum.NOT_PAY.value);
order.setType(OrderTypeEnum.BASKETBALL_ORDER.value);
order.setPlatformId(venue.getPlatformId());
order.setMemberId(memberId);
order.setParentOrderId(venueId);
order.setCreatedId(enterFlag);
orderMapper.insert(order);
if (EnterEnum.OUT.value == enterFlag) {
BarcodeOrderTime lastOrder = barcodeOrderTimeMapper.findLastOrder(memberId, venueId);
if (lastOrder != null) {
lastOrder.setPaying(1);
lastOrder.setPayMoney(new BigDecimal(-1));
lastOrder.setOrderAddSn(order.getOrderSn());
lastOrder.setModifiedTime(new Date());
barcodeOrderTimeMapper.updateByPrimaryKey(lastOrder);
}
}
OrderPaySignResponse.WechatPayParam wechatPayParam = memberCardOrderService.createUnifiedOrder(order.getOrderSn(), memberId, RequestUtils.getIp(),"入场结算订单");
wechatPayParam.setOrderSn(order.getOrderSn());
BasketballPayResult result = new BasketballPayResult();
result.setPaidFlag(false);
result.setOrderSn(order.getOrderSn());
result.setWechatPayParam(wechatPayParam);
return result;
}
OrderPaySignResponse.WechatPayParam wechatPayParam = memberCardOrderService.createUnifiedOrder(order.getOrderSn(), memberId, RequestUtils.getIp(),"入场结算订单");
return wechatPayParam;
}
}

View File

@@ -1,5 +1,6 @@
package com.sv.service.api;
import com.dw.ccm.wechat.base.pay.response.OrderResponse;
import com.enums.*;
import com.github.pagehelper.PageHelper;
import com.sv.dto.BasketEnterResult;
@@ -9,6 +10,7 @@ import com.sv.exception.api.ExceptionCodeTemplate;
import com.sv.mapper.BarcodeOrderTimeMapper;
import com.sv.mapper.OrderMapper;
import com.sv.mapper.VenueMapper;
import com.sv.service.api.config.WechatPayService;
import com.sv.service.api.util.DateUtilCard;
import com.ydd.framework.core.common.Pagination;
import com.ydd.framework.core.common.utils.ValidationUtils;
@@ -18,6 +20,7 @@ import com.ydd.oms.entity.enums.PayStatusEnum;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
@@ -49,6 +52,9 @@ public class VenueEnterService extends BaseServiceImpl {
BarcodeOrderTimeMapper barcodeOrderTimeMapper;
@Resource
OrderMapper orderMapper;
@Lazy
@Resource
private WechatPayService wechatPayService;
/**
* api 接口
@@ -84,6 +90,30 @@ public class VenueEnterService extends BaseServiceImpl {
if (!hasEffOrder) {
logger.info(memberId + "&用户创建订单,开始进场,需要支付金额");
if (price.compareTo(BigDecimal.ZERO) > 0) {
Order pendingOrder = orderMapper.findPendingBasketballOrder(memberId, venueId);
if (pendingOrder != null) {
OrderResponse wxResponse = wechatPayService.queryWechatOrder(pendingOrder.getOrderSn());
if (wxResponse != null && wxResponse.isSuccess() && "SUCCESS".equals(wxResponse.getTradeState())) {
pendingOrder.setPayStatus(PayStatusEnum.PAYED.value);
pendingOrder.setTradeSn(wxResponse.getTransactionId());
pendingOrder.setPayTime(new Date());
orderMapper.update(pendingOrder);
paySuccess(pendingOrder);
basketEnterResult.setFlg(0);
basketEnterResult.setOrderSn(pendingOrder.getOrderSn());
basketEnterResult.setMsg("已支付成功,请入场");
return basketEnterResult;
}
basketEnterResult.setFlg(2);
basketEnterResult.setOrderSn(pendingOrder.getOrderSn());
if (PayStyleEnum.HOUR.getValue() == venue.getPayStyle()) {
basketEnterResult.setMsg("您有未完成的订单,请继续支付。预付押金" + price + "元,出门后按分钟结算");
} else {
basketEnterResult.setMsg("您有未完成的订单,请继续支付。订单金额" + price + "");
}
basketEnterResult.setMoney(price);
return basketEnterResult;
}
checkOrderPaying(memberId);
basketEnterResult.setFlg(2);
if (PayStyleEnum.HOUR.getValue() == venue.getPayStyle()) {
@@ -101,15 +131,18 @@ public class VenueEnterService extends BaseServiceImpl {
createBarcodeTimeOrder(memberId, venueId, timePayHour, "000");
}
} else {
// 已有有效订单
if (lastOrder.getPaying() == 1 && PayStyleEnum.TIME.getValue() == venue.getPayStyle()) {
// 按次计费10分钟内重新入场沿用原订单
lastOrder.setPaying(0);
lastOrder.setModifiedTime(new Date());
barcodeOrderTimeMapper.updateByPrimaryKey(lastOrder);
logger.info(memberId + "&用户10分钟内重新入场沿用原订单");
basketEnterResult.setOrderSn(lastOrder.getOrderSn());
if (lastOrder.getLastEnter() == null) {
logger.info(memberId + "&支付成功但门禁未开门,允许重试");
} else {
logger.info(memberId + "&用户已在场内,无需重复入场");
if (lastOrder.getPaying() == 1 && PayStyleEnum.TIME.getValue() == venue.getPayStyle()) {
lastOrder.setPaying(0);
lastOrder.setModifiedTime(new Date());
barcodeOrderTimeMapper.updateByPrimaryKey(lastOrder);
logger.info(memberId + "&用户10分钟内重新入场沿用原订单");
} else {
logger.info(memberId + "&用户已在场内,无需重复入场");
}
}
}
return basketEnterResult;
@@ -150,6 +183,10 @@ public class VenueEnterService extends BaseServiceImpl {
}
BigDecimal basePrice = venuePriceEnter.getPrice();
// FIXME orderStart 是支付回调时间paySuccess→createBarcodeTimeOrder 设的 new Date()
// 门禁异常场景下用户实际入场时间lastEnter可能晚于 orderStart
// 导致结算时长偏多。如需精准计算,应优先取 lastEnter
// Date startTime = lastOrder.getLastEnter() != null ? lastOrder.getLastEnter() : lastOrder.getOrderStart();
int minutes = DateUtilCard.diffMinute(lastOrder.getOrderStart(), dateNow);
BigDecimal actualCost = basePrice.multiply(new BigDecimal(minutes))
@@ -161,6 +198,25 @@ public class VenueEnterService extends BaseServiceImpl {
+ difference);
if (difference.compareTo(BigDecimal.ZERO) > 0) {
Order pendingOrder = orderMapper.findPendingBasketballOrder(memberId, venueId);
if (pendingOrder != null) {
OrderResponse wxResponse = wechatPayService.queryWechatOrder(pendingOrder.getOrderSn());
if (wxResponse != null && wxResponse.isSuccess() && "SUCCESS".equals(wxResponse.getTradeState())) {
pendingOrder.setPayStatus(PayStatusEnum.PAYED.value);
pendingOrder.setTradeSn(wxResponse.getTransactionId());
pendingOrder.setPayTime(new Date());
orderMapper.update(pendingOrder);
paySuccess(pendingOrder);
result.setFlg(0);
result.setMsg("补交费用已支付成功,出场成功");
return result;
}
result.setFlg(2);
result.setMoney(difference);
result.setOrderSn(pendingOrder.getOrderSn());
result.setMsg("您有未完成的补交订单,请继续支付。实际费用" + actualCost + "元,需补交" + difference + "");
return result;
}
checkOrderPaying(memberId);
result.setFlg(2);
result.setMoney(difference);

View File

@@ -53,6 +53,50 @@ public class WechatPayService extends BaseServiceImpl {
@Resource
private VenueEnterService venueEnterService;
/**
* 查询微信订单状态
*
* @param orderSn 商户订单号
* @return OrderResponse
*/
public OrderResponse queryWechatOrder(String orderSn) {
try {
PayConfig payConfig = payConfigService.findKey("face");
Assert.hasText(payConfig.getCert(), "证书找不到");
WeChatPayHelper weChatPayHelper = new WeChatPayHelper(payConfig.getCert());
weChatPayHelper.setAppId(payConfig.getAppId());
weChatPayHelper.setMchId(payConfig.getMchId());
weChatPayHelper.setKey(payConfig.getKey());
return weChatPayHelper.getOrder(null, orderSn, CommonUtils.CreateNonceStr(30));
} catch (Exception e) {
logger.error("查询微信订单异常", e);
return null;
}
}
/**
* 根据已存在的订单重新签名支付参数(不调用统一下单)
*/
public OrderPaySignResponse.WechatPayParam resignPayParam(String orderSn, String prepayId) {
PayConfig payConfig = payConfigService.findKey("face");
OrderPaySignResponse.WechatPayParam wechatPayParam = new OrderPaySignResponse.WechatPayParam();
Map<String, String> param = Maps.newHashMap();
param.put("appId", payConfig.getAppId());
param.put("nonceStr", CommonUtils.CreateNonceStr(30));
param.put("package", "prepay_id=" + prepayId);
param.put("signType", "MD5");
param.put("timeStamp", String.valueOf(System.currentTimeMillis() / 1000));
param.put("paySign", CommonUtils.getSign(param, payConfig.getKey()));
wechatPayParam.setAppId(param.get("appId"));
wechatPayParam.setPrepayId(prepayId);
wechatPayParam.setTimeStamp(param.get("timeStamp"));
wechatPayParam.setPaySign(param.get("paySign"));
wechatPayParam.setNonceStr(param.get("nonceStr"));
wechatPayParam.setSignType("MD5");
wechatPayParam.setOrderSn(orderSn);
return wechatPayParam;
}
/**
* 创建微信支付的统一订单
*

View File

@@ -0,0 +1,19 @@
package com.sv.service.common;
import org.springframework.stereotype.Component;
import java.util.concurrent.ConcurrentHashMap;
@Component
public class MemberKeyLock {
private final ConcurrentHashMap<Object, Object> lockMap = new ConcurrentHashMap<>();
public Object getLock(Object key) {
return lockMap.computeIfAbsent(key, k -> new Object());
}
public void removeLock(Object key) {
lockMap.remove(key);
}
}

View File

@@ -10,6 +10,7 @@ import com.sv.mapper.MemberMapper;
import com.sv.service.api.MemberAuthService;
import com.sv.service.api.MemberTokenService;
import com.sv.service.common.MemberCardCommonService;
import com.sv.service.common.MemberKeyLock;
import com.sv.service.common.MemberMoney;
import com.ydd.framework.core.common.Pagination;
import com.ydd.framework.core.common.utils.ValidationUtils;
@@ -150,6 +151,9 @@ public class MemberService extends MemberCardCommonService {
return memberMapper.updateStatus(ids, status);
}
@Resource
private MemberKeyLock memberKeyLock;
/**
* 保存用户
*/
@@ -157,7 +161,7 @@ public class MemberService extends MemberCardCommonService {
ValidationUtils.assertNotBlank(member.getMobile(), "请输入手机号码");
VenueValidateUtils.assertMobile(member.getMobile());
synchronized (member.getMobile()){
synchronized (memberKeyLock.getLock(member.getMobile())){
// 根据手机号码创建新用户
Member memberInfo = createByMobile(member);
}

View File

@@ -12,6 +12,7 @@ import com.sv.mapper.VenueLessonTicketMapper;
import com.sv.service.api.util.DateUtilCard;
import com.sv.service.common.OSSClientUtil;
import com.sv.service.common.PlatformService;
import com.sv.service.common.MemberKeyLock;
import com.sv.service.common.RedisLock;
import com.ydd.framework.core.common.Pagination;
import com.ydd.framework.core.service.CacheService;
@@ -66,6 +67,8 @@ public class VenueLessonService extends BaseServiceImpl {
@Resource
private OSSClientUtil ossClientUtil;
@Resource
private MemberKeyLock memberKeyLock;
/**
* 创建场馆课程
@@ -77,7 +80,7 @@ public class VenueLessonService extends BaseServiceImpl {
validateLessonDate(venueLesson);
RedisLock redisLock = new RedisLock(redisTemplate,LESSON_TICKET_LOCK_KEY+venueLesson.getId());
if (venueLesson.getId() != null && venueLesson.getId() > 0) {
synchronized ("lesson" + venueLesson.getId().toString().intern()) {
synchronized (memberKeyLock.getLock(venueLesson.getId())) {
venueLessonMapper.deleteImagesById(venueLesson.getId());
venueLessonTagMapper.deleteByLessonId(venueLesson.getId());
VenueLesson dbVenueLesson = venueLessonMapper.findById(venueLesson.getId());

View File

@@ -436,4 +436,20 @@
WHERE
deleted = 0 and member_id = #{memberId} order by modified_time desc limit 1
</select>
<select id="findPendingBasketballOrder" resultMap="OrderMap">
SELECT
<include refid="Field"></include>
FROM
<include refid="tableName"></include>
WHERE
deleted = 0
AND member_id = #{memberId}
AND parent_order_id = #{venueId}
AND type = 3
AND pay_status = 0
AND created_time >= DATE_SUB(NOW(), INTERVAL 10 MINUTE)
ORDER BY created_time DESC
LIMIT 1
</select>
</mapper>