fix - 篮球入场出场逻辑优化、丢弃二维码的逻辑、优化入场出场锁逻辑。

This commit is contained in:
2026-06-13 23:36:42 +08:00
parent 8cfe0ef7d8
commit cdb2543436
6 changed files with 174 additions and 163 deletions

View File

@@ -24,11 +24,8 @@ import org.apache.commons.lang3.time.DateFormatUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestBody;
import javax.annotation.Resource;
@@ -73,9 +70,6 @@ public class OrderService extends BaseServiceImpl {
@Resource
private MemberKeyLock memberKeyLock;
@Resource
private PlatformTransactionManager transactionManager;
@Transactional
public void save(Order order) {
if (order.getId() != null && order.getId() > 0) {
@@ -218,23 +212,25 @@ public class OrderService extends BaseServiceImpl {
logger.warn("[篮球][下单] 价格非法 memberId={}, venueId={}, priceList为空", memberId, venueId);
throw new ServiceException("价格非法!");
}
boolean checkPrice = false;
for (VenuePrice venuePrice : priceList) {
if (price.divideAndRemainder(price)[1].compareTo(BigDecimal.ZERO) == 0) {
checkPrice = true;
}
}
if (!checkPrice) {
logger.warn("[篮球][下单] 价格非法 memberId={}, venueId={}, price={}", memberId, venueId, price);
throw new ServiceException("价格非法!");
}
logger.info("[篮球][下单] 开始创建订单 memberId={}, venueId={}, enterFlag={}, price={}", memberId, venueId, enterFlag, price);
synchronized (memberKeyLock.getLock(memberId)) {
String orderSn;
Order pendingOrder = orderMapper.findPendingBasketballOrder(memberId, venueId);
if (pendingOrder != null) {
logger.info("[篮球][下单] 存在待处理订单 memberId={}, orderSn={}", memberId, pendingOrder.getOrderSn());
orderSn = pendingOrder.getOrderSn();
if (EnterEnum.OUT.value == enterFlag) {
BarcodeOrderTime lastOrder = barcodeOrderTimeMapper.findLastOrder(memberId, venueId);
if(lastOrder == null || StringUtils.isEmpty(lastOrder.getOrderAddSn())){
logger.error("memberId={}, venueId={}, 出场的时候的订单有问题!!!",memberId,venueId);
} else {
if (!orderSn.equals(lastOrder.getOrderAddSn())){
logger.error("memberId={}, venueId={},这是重复下单怎么会生成新的orderNo呢orderSn={}, 应该的orderNo={}",
memberId, venueId, orderSn, lastOrder.getOrderAddSn());
}
}
}
logger.info("[篮球][下单] 存在待处理订单 memberId={}, mobile={}, orderSn={}", memberId,member.getMobile(), pendingOrder.getOrderSn());
OrderResponse wxResponse = wechatPayService.queryWechatOrder(pendingOrder.getOrderSn());
if (wxResponse != null && wxResponse.isSuccess() && "SUCCESS".equals(wxResponse.getTradeState())) {
pendingOrder.setPayStatus(PayStatusEnum.PAYED.value);
@@ -242,81 +238,65 @@ public class OrderService extends BaseServiceImpl {
pendingOrder.setPayTime(new Date());
orderMapper.update(pendingOrder);
venueEnterService.paySuccess(pendingOrder);
logger.info("[篮球][下单] 微信已支付成功 orderSn={}, tradeSn={}", pendingOrder.getOrderSn(), wxResponse.getTransactionId());
logger.info("[篮球][下单] memberId={}, mobile={},微信已支付成功 orderSn={}, tradeSn={}", memberId,member.getMobile(), pendingOrder.getOrderSn(), wxResponse.getTransactionId());
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());
logger.info("[篮球][下单] 复用prepayId orderSn={}", pendingOrder.getOrderSn());
logger.info("[篮球][下单] memberId={}, mobile={},复用prepayId orderSn={}",memberId,member.getMobile(), pendingOrder.getOrderSn());
} else {
wechatPayParam = memberCardOrderService.createUnifiedOrder(pendingOrder.getOrderSn(), memberId, RequestUtils.getIp(), "入场结算订单");
logger.info("[篮球][下单] 重新统一下单 orderSn={}", pendingOrder.getOrderSn());
wechatPayParam = memberCardOrderService.createUnifiedOrder(pendingOrder.getOrderSn(), memberId, RequestUtils.getIp(), "篮球结算订单");
logger.info("[篮球][下单] memberId={}, mobile={},重新统一下单 orderSn={}", memberId,member.getMobile(), pendingOrder.getOrderSn());
}
wechatPayParam.setOrderSn(pendingOrder.getOrderSn());
BasketballPayResult result = new BasketballPayResult();
result.setPaidFlag(false);
result.setOrderSn(pendingOrder.getOrderSn());
result.setWechatPayParam(wechatPayParam);
return result;
}
}else {
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);
orderSn = order.getOrderSn();
logger.info("[篮球][下单] 插入新订单 orderSn={}, memberId={},mobile={}, venueId={}, enterFlag={}",
order.getOrderSn(), memberId, member.getMobile(), venueId, enterFlag);
OrderPaySignResponse.WechatPayParam wechatPayParam = memberCardOrderService.createUnifiedOrder(order.getOrderSn(), memberId, RequestUtils.getIp(),"篮球结算订单");
wechatPayParam.setOrderSn(orderSn);
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
TransactionStatus txStatus = transactionManager.getTransaction(def);
Order order;
try {
order = orderMapper.findPendingBasketballOrder(memberId, venueId);
if (order == null) {
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);
logger.info("[篮球][下单] 插入新订单 orderSn={}, memberId={}, venueId={}, enterFlag={}",
order.getOrderSn(), memberId, venueId, enterFlag);
if (EnterEnum.OUT.value == enterFlag) {
BarcodeOrderTime lastOrder = barcodeOrderTimeMapper.findLastOrder(memberId, venueId);
if (lastOrder != null) {
lastOrder.setPaying(1);
lastOrder.setPayMoney(new BigDecimal(-1));
lastOrder.setOrderAddSn(orderSn);
lastOrder.setModifiedTime(new Date());
barcodeOrderTimeMapper.updateByPrimaryKey(lastOrder);
logger.info("[篮球][下单] memberId={}, mobile={},出场补费订单关联 lastOrderSn={}, addOrderSn={}",
memberId, member.getMobile(),lastOrder.getOrderSn(), orderSn);
} else {
logger.warn("[篮球][下单] 出场补费但未找到原始订单 memberId={}", memberId);
}
}
transactionManager.commit(txStatus);
} catch (RuntimeException e) {
transactionManager.rollback(txStatus);
logger.error("[篮球][下单] 事务异常 memberId={}, venueId={}", memberId, venueId, e);
throw e;
}
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);
logger.info("[篮球][下单] 出场补费订单关联 lastOrderSn={}, addOrderSn={}",
lastOrder.getOrderSn(), order.getOrderSn());
} else {
logger.warn("[篮球][下单] 出场补费但未找到原始订单 memberId={}", memberId);
}
BasketballPayResult result = new BasketballPayResult();
result.setPaidFlag(false);
result.setOrderSn(orderSn);
result.setWechatPayParam(wechatPayParam);
return result;
}
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;
}
}

View File

@@ -10,20 +10,20 @@ 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.OrderService;
import com.sv.service.api.config.WechatPayService;
import com.sv.service.api.util.DateUtilCard;
import com.sv.service.common.DoorLockUtil;
import com.ydd.framework.core.common.Pagination;
import com.ydd.framework.core.common.utils.ValidationUtils;
import com.ydd.framework.core.exception.ServiceException;
import com.ydd.framework.core.service.impl.BaseServiceImpl;
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;
import org.springframework.util.StringUtils;
import javax.annotation.Resource;
import java.math.BigDecimal;
@@ -59,12 +59,14 @@ public class VenueEnterService extends BaseServiceImpl {
@Lazy
@Resource
private WechatPayService wechatPayService;
@Resource
DoorLockUtil doorLockUtil;
/**
* api 接口
* 我要进场
*/
public BasketEnterResult join(Integer memberId, Integer venueId) {
public BasketEnterResult join(Integer memberId, Integer venueId, String doorSn) {
BasketEnterResult basketEnterResult = new BasketEnterResult();
basketEnterResult.setFlg(0);
if (memberId == null) {
@@ -95,10 +97,11 @@ public class VenueEnterService extends BaseServiceImpl {
boolean hasEffOrder = lastOrder != null
&& lastOrder.getStatus() == BarCodeStatusEnum.INIT.getValue()
&& lastOrder.getOrderEnd().after(new Date());
doorLockUtil.lockOpeDoor(doorSn);
if (!hasEffOrder) {
basketballLog.info("[篮球][入场] memberId={}, 无有效订单,创建新订单", memberId);
if (price.compareTo(BigDecimal.ZERO) > 0) {
checkOrderPaying(memberId);
Order pendingOrder = orderMapper.findPendingBasketballOrder(memberId, venueId);
if (pendingOrder != null) {
basketballLog.info("[篮球][入场] memberId={}, 存在待支付订单 orderSn={}", memberId, pendingOrder.getOrderSn());
@@ -127,7 +130,6 @@ public class VenueEnterService extends BaseServiceImpl {
basketballLog.info("[篮球][入场] memberId={}, 待支付订单未完成支付 orderSn={}", memberId, pendingOrder.getOrderSn());
return basketEnterResult;
}
checkOrderPaying(memberId);
basketEnterResult.setFlg(2);
if (PayStyleEnum.HOUR.getValue() == venue.getPayStyle()) {
basketEnterResult.setMsg("预付押金" + price + "元,出门后按分钟结算,收费规则见场馆主页详情");
@@ -167,12 +169,13 @@ public class VenueEnterService extends BaseServiceImpl {
/**
* 我要出场
*
*
* @param memberId
* @param venueId
* @param doorSn
* @return
*/
public BasketEnterResult out(Integer memberId, Integer venueId) {
public BasketEnterResult out(Integer memberId, Integer venueId, String doorSn) {
BasketEnterResult result = new BasketEnterResult();
result.setFlg(0);
if (memberId == null) {
@@ -184,25 +187,25 @@ public class VenueEnterService extends BaseServiceImpl {
memberService.verify(member);
BarcodeOrderTime lastOrder = barcodeOrderTimeMapper.findLastOrder(memberId, venueId);
if (lastOrder == null || lastOrder.getPaying() == 2) {
basketballLog.warn("[篮球][出场] memberId={}, venueId={}, 无可结算订单 lastOrder={}",
memberId, venueId, lastOrder == null ? "null" :
if (lastOrder == null) {
basketballLog.error("[篮球][出场] memberId={}, mobile={} ,venueId={}, 无可结算订单 lastOrder={}",
memberId, member.getMobile(), venueId, lastOrder == null ? "null" :
String.format("orderSn=%s,paying=%s,status=%s", lastOrder.getOrderSn(), lastOrder.getPaying(), lastOrder.getStatus()));
return result;
throw new ServiceException("门禁异常,无可结算订单,请联系管理员出门!");
}
basketballLog.info("[篮球][出场] memberId={}, venueId={}, payStyle={}, orderSn={}, orderStart={}, lastEnter={}, paying={}",
memberId, venueId, venue.getPayStyle(), lastOrder.getOrderSn(),
lastOrder.getOrderStart(), lastOrder.getLastEnter(), lastOrder.getPaying());
doorLockUtil.lockOpeDoor(doorSn);
if (PayStyleEnum.HOUR.getValue() == venue.getPayStyle()) {
String enterTime = DateUtilCard.getTimeFromDate(lastOrder.getOrderStart());
Date dateNow = new Date();
basketballLog.info("[篮球][出场] memberId={}, 按时计费结算 venueId={}", memberId, venueId);
basketballLog.info("[篮球][出场] memberId={} ,mobile={} , 按时计费结算 venueId={}", memberId, member.getMobile(),venueId);
VenuePrice venuePriceEnter = venuePriceService.findPrice(venueId, enterTime);
if (venuePriceEnter == null) {
basketballLog.warn("[篮球][出场] memberId={}, 场馆暂未开放 venueId={}", memberId, venueId);
basketballLog.warn("[篮球][出场] memberId={}, 未找到价格 venueId={}", memberId, venueId);
throw new ServiceException(ExceptionCodeTemplate.VENUE_ERROR);
}
@@ -214,31 +217,42 @@ public class VenueEnterService extends BaseServiceImpl {
BigDecimal deposit = basePrice.multiply(new BigDecimal(2));
BigDecimal difference = actualCost.subtract(deposit);
basketballLog.info("[篮球][出场] memberId={}, 费用结算: basePrice={}, 停留{}分钟, 实际费用={}, 押金={}, 差额={}",
memberId, basePrice, minutes, actualCost, deposit, difference);
basketballLog.info("[篮球][出场] memberId={}, mobile={}, 费用结算: basePrice={}, 停留{}分钟, 实际费用={}, 押金={}, 差额={}",
memberId, member.getMobile(), basePrice, minutes, actualCost, deposit, 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("补交费用已支付成功,出场成功");
basketballLog.info("[篮球][出场] memberId={}, 补交费用已支付 orderSn={}, tradeSn={}, 补交金额={}",
memberId, pendingOrder.getOrderSn(), wxResponse.getTransactionId(), difference);
String orderAddSn = lastOrder.getOrderAddSn();
if (!StringUtils.isEmpty(orderAddSn)){
// 这时是已经有过新增的订单了
Order pendingOrder = orderService.findOrderSn(orderAddSn, memberId);
if (pendingOrder != null) {
if (PayStatusEnum.PAYED.value.equals(pendingOrder.getPayStatus())) {
result.setFlg(0);
result.setMsg("补交费用已支付成功,出场成功");
basketballLog.info("[篮球][出场] memberId={}, 补交费用已支付 orderSn={}, 补交金额={}",
memberId, pendingOrder.getOrderSn(), difference);
return result;
}
OrderResponse wxResponse = wechatPayService.queryWechatOrder(orderAddSn);
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("补交费用已支付成功,出场成功");
basketballLog.info("[篮球][出场] memberId={}, 补交费用已支付 orderSn={}, tradeSn={}, 补交金额={}",
memberId, pendingOrder.getOrderSn(), wxResponse.getTransactionId(), difference);
return result;
}
checkOrderPaying(memberId);
result.setFlg(2);
result.setMoney(difference);
result.setOrderSn(pendingOrder.getOrderSn());
result.setMsg("您有未完成的补交订单,请继续支付。实际费用" + actualCost + "元,需补交" + difference + "");
basketballLog.info("[篮球][出场] memberId={}, 需补交费用 orderSn={}, 需补交={}", memberId, pendingOrder.getOrderSn(), difference);
return result;
}
result.setFlg(2);
result.setMoney(difference);
result.setOrderSn(pendingOrder.getOrderSn());
result.setMsg("您有未完成的补交订单,请继续支付。实际费用" + actualCost + "元,需补交" + difference + "");
basketballLog.info("[篮球][出场] memberId={}, 需补交费用 orderSn={}, 需补交={}", memberId, pendingOrder.getOrderSn(), difference);
return result;
}
checkOrderPaying(memberId);
result.setFlg(2);

View File

@@ -11,6 +11,8 @@ public class DoorLockUtil {
private final static String DOOR_LOCK = "DOOR_LOCK_";
private final static Integer LOCK_TIMEOUT = 20;
private final static Integer LOCK_OPE_TIMEOUT = 10;
@Resource
RedisCache redisCache;
@@ -35,4 +37,9 @@ public class DoorLockUtil {
redisCache.setCacheObject(doorKey,true,LOCK_TIMEOUT, TimeUnit.SECONDS);
}
public void lockOpeDoor(String doorSn){
String doorKey = DOOR_LOCK + doorSn;
redisCache.setCacheObject(doorKey,true,LOCK_OPE_TIMEOUT, TimeUnit.SECONDS);
}
}