|
@@ -16,7 +16,6 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|
|
import com.ekyong.www.pay.pay.qrcode.api.RhtQrcodePayApi;
|
|
import com.ekyong.www.pay.pay.qrcode.api.RhtQrcodePayApi;
|
|
|
import com.ekyong.www.pay.pay.qrcode.bean.QrcodeQueryRequestBean;
|
|
import com.ekyong.www.pay.pay.qrcode.bean.QrcodeQueryRequestBean;
|
|
|
import com.ekyong.www.pay.pay.qrcode.bean.QrcodeQueryResponseBean;
|
|
import com.ekyong.www.pay.pay.qrcode.bean.QrcodeQueryResponseBean;
|
|
|
-import com.github.wxpay.sdk.WXPay;
|
|
|
|
|
import com.sqx.common.constant.RedisKey;
|
|
import com.sqx.common.constant.RedisKey;
|
|
|
import com.sqx.common.exception.SqxException;
|
|
import com.sqx.common.exception.SqxException;
|
|
|
import com.sqx.common.sms.SmsSendResult;
|
|
import com.sqx.common.sms.SmsSendResult;
|
|
@@ -85,7 +84,6 @@ import com.sqx.modules.order.entity.OrderGoods;
|
|
|
import com.sqx.modules.order.entity.TbOrder;
|
|
import com.sqx.modules.order.entity.TbOrder;
|
|
|
import com.sqx.modules.order.service.AppOrderService;
|
|
import com.sqx.modules.order.service.AppOrderService;
|
|
|
import com.sqx.modules.order.service.EvaluateRiderService;
|
|
import com.sqx.modules.order.service.EvaluateRiderService;
|
|
|
-import com.sqx.modules.pay.config.WXConfig;
|
|
|
|
|
import com.sqx.modules.pay.config.WechatPayConfig;
|
|
import com.sqx.modules.pay.config.WechatPayConfig;
|
|
|
import com.sqx.modules.pay.controller.app.AliPayController;
|
|
import com.sqx.modules.pay.controller.app.AliPayController;
|
|
|
import com.sqx.modules.pay.dao.PayDetailsDao;
|
|
import com.sqx.modules.pay.dao.PayDetailsDao;
|
|
@@ -129,7 +127,6 @@ import java.math.RoundingMode;
|
|
|
import java.text.SimpleDateFormat;
|
|
import java.text.SimpleDateFormat;
|
|
|
import java.time.LocalDateTime;
|
|
import java.time.LocalDateTime;
|
|
|
import java.time.LocalTime;
|
|
import java.time.LocalTime;
|
|
|
-import java.time.OffsetDateTime;
|
|
|
|
|
import java.time.format.DateTimeFormatter;
|
|
import java.time.format.DateTimeFormatter;
|
|
|
import java.time.temporal.ChronoUnit;
|
|
import java.time.temporal.ChronoUnit;
|
|
|
import java.util.ArrayList;
|
|
import java.util.ArrayList;
|
|
@@ -138,6 +135,7 @@ import java.util.Date;
|
|
|
import java.util.HashMap;
|
|
import java.util.HashMap;
|
|
|
import java.util.List;
|
|
import java.util.List;
|
|
|
import java.util.Map;
|
|
import java.util.Map;
|
|
|
|
|
+import java.util.concurrent.TimeUnit;
|
|
|
import java.util.stream.Collectors;
|
|
import java.util.stream.Collectors;
|
|
|
|
|
|
|
|
@Service
|
|
@Service
|
|
@@ -711,6 +709,12 @@ public class AppAppOrderServiceImpl extends ServiceImpl<AppOrderDao, TbOrder> im
|
|
|
|
|
|
|
|
@Override
|
|
@Override
|
|
|
public void updateOrderAfterPaySuccess(TbOrder order, String payTime) {
|
|
public void updateOrderAfterPaySuccess(TbOrder order, String payTime) {
|
|
|
|
|
+ TbOrder latestOrder = getById(order.getOrderId());
|
|
|
|
|
+ if (latestOrder.getIsPay() == 1) {
|
|
|
|
|
+ log.info("订单【{}】已支付,跳过重复处理", order.getOrderId());
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
String currentTimeStr = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
|
|
String currentTimeStr = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
|
|
|
order.setOrderCode(generateOrderCode());
|
|
order.setOrderCode(generateOrderCode());
|
|
|
order.setIsPay(1);
|
|
order.setIsPay(1);
|
|
@@ -737,7 +741,7 @@ public class AppAppOrderServiceImpl extends ServiceImpl<AppOrderDao, TbOrder> im
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
RLock lock = redissonClient.getLock(String.format(RedisKey.UPDATE_ORDER_LOCK, order.getOrderId()));
|
|
RLock lock = redissonClient.getLock(String.format(RedisKey.UPDATE_ORDER_LOCK, order.getOrderId()));
|
|
|
- lock.lock();
|
|
|
|
|
|
|
+ lock.lock(20, TimeUnit.SECONDS);
|
|
|
TransactionStatus status = null;
|
|
TransactionStatus status = null;
|
|
|
try {
|
|
try {
|
|
|
// 开启编程式事务
|
|
// 开启编程式事务
|
|
@@ -746,9 +750,6 @@ public class AppAppOrderServiceImpl extends ServiceImpl<AppOrderDao, TbOrder> im
|
|
|
// 更新订单状态及订单序号
|
|
// 更新订单状态及订单序号
|
|
|
updateOrderStatusAndSequence(order);
|
|
updateOrderStatusAndSequence(order);
|
|
|
|
|
|
|
|
- // 优惠券变成已使用状态
|
|
|
|
|
- updateCouponState(order);
|
|
|
|
|
-
|
|
|
|
|
// 如果是支付宝或者微信支付,用户钱包新增消费记录
|
|
// 如果是支付宝或者微信支付,用户钱包新增消费记录
|
|
|
addConsumeRecordInUserMoneyDetail(order);
|
|
addConsumeRecordInUserMoneyDetail(order);
|
|
|
|
|
|
|
@@ -771,6 +772,13 @@ public class AppAppOrderServiceImpl extends ServiceImpl<AppOrderDao, TbOrder> im
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
MyGlobalThreadPool.execute(() -> {
|
|
MyGlobalThreadPool.execute(() -> {
|
|
|
|
|
+ // 优惠券变成已使用状态,允许失败,后续优化优惠券扣减失败问题
|
|
|
|
|
+ try {
|
|
|
|
|
+ updateCouponState(order);
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.error("订单:{},优惠券状态更新失败,失败原因:{}", order.getOrderId(), e);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
// 扣减库存,允许部分超卖,后续再优化超卖问题
|
|
// 扣减库存,允许部分超卖,后续再优化超卖问题
|
|
|
try {
|
|
try {
|
|
|
this.subStock(order);
|
|
this.subStock(order);
|
|
@@ -2839,111 +2847,91 @@ public class AppAppOrderServiceImpl extends ServiceImpl<AppOrderDao, TbOrder> im
|
|
|
|
|
|
|
|
@Override
|
|
@Override
|
|
|
public Result updateTimeOutOrder(Long userId, Integer orderId) {
|
|
public Result updateTimeOutOrder(Long userId, Integer orderId) {
|
|
|
- RLock lock = redissonClient.getLock(String.format(RedisKey.TIME_OUT_LOCK, orderId));
|
|
|
|
|
- lock.lock();
|
|
|
|
|
- try {
|
|
|
|
|
- TbOrder tbOrder = baseMapper.selectById(orderId);
|
|
|
|
|
- if (ObjectUtils.isEmpty(tbOrder)) {
|
|
|
|
|
- return Result.error("该订单不存在");
|
|
|
|
|
- }
|
|
|
|
|
- Integer status = tbOrder.getStatus();
|
|
|
|
|
- if (status != 0) {
|
|
|
|
|
- return Result.error("当前订单不是待结算订单");
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- //region
|
|
|
|
|
- WXConfig config = new WXConfig();
|
|
|
|
|
-// 当前都是小程序支付
|
|
|
|
|
- config.setAppId(commonInfoService.findOne(74).getValue());
|
|
|
|
|
- //微信商户key
|
|
|
|
|
- config.setKey(commonInfoService.findOne(250).getValue());
|
|
|
|
|
- //微信商户号mchId
|
|
|
|
|
- config.setMchId(commonInfoService.findOne(251).getValue());
|
|
|
|
|
- WXPay wxpay = new WXPay(config);
|
|
|
|
|
-
|
|
|
|
|
- WechatPayConfig wechatMchConfig = WechatPayConfig.builder()
|
|
|
|
|
- .appId(commonInfoService.findOne(45).getValue())
|
|
|
|
|
- .mchId(commonInfoService.findOne(434).getValue())
|
|
|
|
|
- .mchKey(commonInfoService.findOne(435).getValue())
|
|
|
|
|
- .h5Url(commonInfoService.findOne(19).getValue())
|
|
|
|
|
- .build();
|
|
|
|
|
-
|
|
|
|
|
- PayDetails pd = payDetailsService.getByOrderNo(tbOrder.getOrderNumber());
|
|
|
|
|
- if (pd != null) {
|
|
|
|
|
- Integer state = pd.getState();
|
|
|
|
|
- if (0 == state) {
|
|
|
|
|
- // 状态为待支付需要调用支付系统订单查询接口判断支付系统对应的订单状态
|
|
|
|
|
- Map<String, String> data = new HashMap<>();
|
|
|
|
|
- String orderNumber = tbOrder.getOrderNumber();
|
|
|
|
|
- //商户订单号
|
|
|
|
|
- data.put("out_trade_no", orderNumber);
|
|
|
|
|
- Map<String, String> response = wxpay.orderQuery(data);
|
|
|
|
|
- String trade_state = response.get("trade_state");
|
|
|
|
|
- //SUCCESS—支付成功,REFUND—转入退款,NOTPAY—未支付,CLOSED—已关闭,REVOKED—已撤销(刷卡支付),USERPAYING--用户支付中,PAYERROR--支付失败(其他原因,如银行返回失败)
|
|
|
|
|
- if (ObjectUtils.isNotEmpty(trade_state)) {
|
|
|
|
|
- if ("NOTPAY".equals(trade_state)) {
|
|
|
|
|
- tbOrder.setStatus(5);
|
|
|
|
|
- } else if ("SUCCESS".equals(trade_state)) {
|
|
|
|
|
- tbOrder.setPayType(1);
|
|
|
|
|
-
|
|
|
|
|
- // 获取微信支付成功时间
|
|
|
|
|
- String success_time = response.get("success_time");
|
|
|
|
|
- // 解析 RFC3339
|
|
|
|
|
- OffsetDateTime offsetDateTime = OffsetDateTime.parse(success_time);
|
|
|
|
|
- // 格式化输出
|
|
|
|
|
- DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
|
|
|
|
- // 转换时间格式
|
|
|
|
|
- String payTime = offsetDateTime.format(df);
|
|
|
|
|
- // 设置为支付时间
|
|
|
|
|
- updateOrderAfterPaySuccess(tbOrder,payTime);
|
|
|
|
|
- }
|
|
|
|
|
- } else {
|
|
|
|
|
- RhtQrcodePayApi qrcodePay = new RhtQrcodePayApi(wechatMchConfig.getMchId(), wechatMchConfig.getMchKey(), RHT_PAY_BASE_URL);
|
|
|
|
|
- QrcodeQueryRequestBean qqrb = new QrcodeQueryRequestBean();
|
|
|
|
|
- qqrb.setTraceno(orderNumber);// 商户流水号
|
|
|
|
|
- QrcodeQueryResponseBean response2 = qrcodePay.query(qqrb);
|
|
|
|
|
- String respCode = response2.getRespCode();
|
|
|
|
|
- log.info("超时任务处理订单【{}】查询支付结果,支付通知信息:{}", orderNumber, response2);
|
|
|
|
|
-// 0未支付,1支付成功,2支付失败,4退款中,5退款成功,6退款失败
|
|
|
|
|
- if ("0".equals(respCode)) {
|
|
|
|
|
- tbOrder.setStatus(5);
|
|
|
|
|
- } else if ("1".equals(respCode)) {
|
|
|
|
|
- PayDetails payDetails = payDetailsService.getByOrderNo(orderNumber);
|
|
|
|
|
- String payTime = response2.getTransDate() + " " + response2.getTransTime();
|
|
|
|
|
- if (!ObjectUtil.isNull(payDetails)) {
|
|
|
|
|
- payDetails.setState(PayStateEnums.PAY_SUCCESS.getStateCode());
|
|
|
|
|
- payDetails.setPayTime(payTime);
|
|
|
|
|
- payDetails.setTradeNo(response2.getChannelOrderno());
|
|
|
|
|
- payDetails.setRemark("Scheduled RHT PAY SUCCESS");
|
|
|
|
|
- payDetailsService.updateDetail(payDetails);
|
|
|
|
|
- } else {
|
|
|
|
|
- log.error("超时任务处理订单【{}】支付成功,但未获取到支付订单!支付通知信息:{}", orderNumber, response2);
|
|
|
|
|
- }
|
|
|
|
|
- tbOrder.setPayType(1);
|
|
|
|
|
- tbOrder.setPayTime(payTime);
|
|
|
|
|
- updateOrderAfterPaySuccess(tbOrder,payTime);
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ TbOrder tbOrder = baseMapper.selectById(orderId);
|
|
|
|
|
+ if (ObjectUtils.isEmpty(tbOrder)) {
|
|
|
|
|
+ return Result.error("该订单不存在");
|
|
|
|
|
+ }
|
|
|
|
|
+ Integer status = tbOrder.getStatus();
|
|
|
|
|
+ if (status != 0) {
|
|
|
|
|
+ return Result.error("当前订单不是待结算订单");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ String orderNumber = tbOrder.getOrderNumber();
|
|
|
|
|
+ PayDetails pd = payDetailsService.getByOrderNo(orderNumber);
|
|
|
|
|
+
|
|
|
|
|
+ boolean shouldCancel = false;
|
|
|
|
|
+ boolean shouldPaySuccess = false;
|
|
|
|
|
+ String payTime = null;
|
|
|
|
|
+ if (pd != null) {
|
|
|
|
|
+ Integer state = pd.getState();
|
|
|
|
|
+ if (state == PayStateEnums.WAIT_PAY.getStateCode()) {
|
|
|
|
|
+ WechatPayConfig wechatMchConfig = WechatPayConfig.builder()
|
|
|
|
|
+ .appId(commonInfoService.findOne(45).getValue())
|
|
|
|
|
+ .mchId(commonInfoService.findOne(434).getValue())
|
|
|
|
|
+ .mchKey(commonInfoService.findOne(435).getValue())
|
|
|
|
|
+ .h5Url(commonInfoService.findOne(19).getValue())
|
|
|
|
|
+ .build();
|
|
|
|
|
+ RhtQrcodePayApi qrcodePay = new RhtQrcodePayApi(wechatMchConfig.getMchId(), wechatMchConfig.getMchKey(), RHT_PAY_BASE_URL);
|
|
|
|
|
+ QrcodeQueryRequestBean qqrb = new QrcodeQueryRequestBean();
|
|
|
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ qqrb.setTraceno(orderNumber);// 商户流水号
|
|
|
|
|
+ QrcodeQueryResponseBean response2;
|
|
|
|
|
+ try {
|
|
|
|
|
+ response2 = qrcodePay.query(qqrb);
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.error("订单【{}】查询支付结果异常", orderNumber, e);
|
|
|
|
|
+ throw new SqxException("查询支付结果失败", e);
|
|
|
|
|
+ }
|
|
|
|
|
+ String respCode = response2.getRespCode();
|
|
|
|
|
+ log.info("超时任务处理订单【{}】查询支付结果,支付通知信息:{}", orderNumber, response2);
|
|
|
|
|
+ // 0未支付,1支付成功,2支付失败,4退款中,5退款成功,6退款失败
|
|
|
|
|
+ if ("1".equals(respCode)) {
|
|
|
|
|
+ shouldPaySuccess = true;
|
|
|
|
|
+ payTime = response2.getTransDate() + " " + response2.getTransTime();
|
|
|
|
|
+ pd.setState(PayStateEnums.PAY_SUCCESS.getStateCode());
|
|
|
|
|
+ pd.setPayTime(payTime);
|
|
|
|
|
+ pd.setTradeNo(response2.getChannelOrderno());
|
|
|
|
|
+ pd.setRemark("Scheduled RHT PAY SUCCESS");
|
|
|
|
|
+ payDetailsService.updateDetail(pd);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ shouldCancel = true;
|
|
|
}
|
|
}
|
|
|
|
|
+ } else if (state == PayStateEnums.PAY_SUCCESS.getStateCode()){
|
|
|
|
|
+ payTime = pd.getPayTime();
|
|
|
|
|
+ shouldPaySuccess = true;
|
|
|
} else {
|
|
} else {
|
|
|
- tbOrder.setStatus(5);
|
|
|
|
|
|
|
+ shouldCancel = true;
|
|
|
}
|
|
}
|
|
|
|
|
+ } else {
|
|
|
|
|
+ shouldCancel = true;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- //list为空不要执行
|
|
|
|
|
- if (tbOrder.getStatus().intValue() == 5) {
|
|
|
|
|
- baseMapper.updateById(tbOrder);
|
|
|
|
|
|
|
+ if (shouldCancel || shouldPaySuccess) {
|
|
|
|
|
+ RLock lock = redissonClient.getLock(String.format(RedisKey.UPDATE_ORDER_LOCK, orderId));
|
|
|
|
|
+ lock.lock(20, TimeUnit.SECONDS);
|
|
|
|
|
+ try {
|
|
|
|
|
+ // 双重检查,防止并发
|
|
|
|
|
+ TbOrder latestOrder = baseMapper.selectById(orderId);
|
|
|
|
|
+ if (latestOrder.getStatus() == 0 && latestOrder.getIsPay() == 0) {
|
|
|
|
|
+ if (shouldCancel) {
|
|
|
|
|
+ latestOrder.setStatus(5);
|
|
|
|
|
+ baseMapper.updateById(latestOrder);
|
|
|
|
|
+ log.info("订单【{}】超时未支付,已取消", orderId);
|
|
|
|
|
+ } else if (shouldPaySuccess) {
|
|
|
|
|
+ latestOrder.setPayType(1);
|
|
|
|
|
+ latestOrder.setPayTime(payTime);
|
|
|
|
|
+ updateOrderAfterPaySuccess(latestOrder, payTime);
|
|
|
|
|
+ log.info("订单【{}】超时任务处理支付成功", orderId);
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ log.info("订单【{}】状态已变更,status={}, isPay={},跳过处理", orderId, latestOrder.getStatus(), latestOrder.getIsPay());
|
|
|
|
|
+ }
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ lock.unlock();
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- //endregion
|
|
|
|
|
- return Result.success();
|
|
|
|
|
- } catch (Exception e) {
|
|
|
|
|
- log.error("超时订单自动取消任务运行失败失败原因:{}", e.getMessage());
|
|
|
|
|
- return Result.error("自动取消订单异常");
|
|
|
|
|
- } finally {
|
|
|
|
|
- lock.unlock();
|
|
|
|
|
-
|
|
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ return Result.success();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
@Override
|
|
@@ -3132,7 +3120,7 @@ public class AppAppOrderServiceImpl extends ServiceImpl<AppOrderDao, TbOrder> im
|
|
|
private void updateOrderStatusAndSequence(TbOrder order) {
|
|
private void updateOrderStatusAndSequence(TbOrder order) {
|
|
|
Long shopId = order.getShopId();
|
|
Long shopId = order.getShopId();
|
|
|
RLock lock = redissonClient.getLock(String.format(RedisKey.ORDER_SEQUENCE_LOCK, shopId));
|
|
RLock lock = redissonClient.getLock(String.format(RedisKey.ORDER_SEQUENCE_LOCK, shopId));
|
|
|
- lock.lock();
|
|
|
|
|
|
|
+ lock.lock(5, TimeUnit.SECONDS);
|
|
|
try {
|
|
try {
|
|
|
int count = appOrderDao.countCurDayPayByShopId(shopId, order.getPayTime());
|
|
int count = appOrderDao.countCurDayPayByShopId(shopId, order.getPayTime());
|
|
|
order.setOrderSequence(String.format("%04d", count + 1));
|
|
order.setOrderSequence(String.format("%04d", count + 1));
|