|
|
@@ -55,8 +55,10 @@ import java.math.BigDecimal;
|
|
|
import java.math.RoundingMode;
|
|
|
import java.time.LocalDateTime;
|
|
|
import java.time.format.DateTimeFormatter;
|
|
|
+import java.time.temporal.ChronoUnit;
|
|
|
import java.util.*;
|
|
|
import java.util.concurrent.TimeUnit;
|
|
|
+import java.util.concurrent.atomic.AtomicInteger;
|
|
|
|
|
|
@Service
|
|
|
@AllArgsConstructor
|
|
|
@@ -118,6 +120,7 @@ public class OrderService {
|
|
|
int stock = Optional.ofNullable(collectionService.decreaseStock(collectionId, qty))
|
|
|
.map(Math::toIntExact)
|
|
|
.orElseThrow(new BusinessException("很遗憾,藏品已售罄"));
|
|
|
+ // 创建订单出错后需要回滚库存,所以需要try-catch
|
|
|
try {
|
|
|
if (stock < 0) {
|
|
|
throw new BusinessException("很遗憾,藏品已售罄");
|
|
|
@@ -432,6 +435,7 @@ public class OrderService {
|
|
|
log.info("createOrderResponse {}", JSON.toJSONString(response, SerializerFeature.PrettyFormat));
|
|
|
AdapayService.checkSuccess(response);
|
|
|
|
|
|
+ // 保存adapay的订单id,用于后续取消订单时的查询
|
|
|
BoundSetOperations<String, Object> ops = redisTemplate.boundSetOps(RedisKeys.PAY_RECORD + order.getId());
|
|
|
ops.add(MapUtils.getString(response, "id"));
|
|
|
ops.expire(7, TimeUnit.DAYS);
|
|
|
@@ -485,6 +489,7 @@ public class OrderService {
|
|
|
public void notifyOrder(Long orderId, PayMethod payMethod, String transactionId) {
|
|
|
log.info("订单回调 orderId: {}, payMethod: {}, transactionId: {}", orderId, payMethod, transactionId);
|
|
|
|
|
|
+ // 取消订单与订单回调不能同时进行,需要抢锁
|
|
|
if (!getOrderLock(orderId)) {
|
|
|
log.info("订单回调失败 orderId: {} redis锁定, 重新发送到队列", orderId);
|
|
|
rocketMQTemplate.syncSend(generalProperties.getOrderNotifyTopic(),
|
|
|
@@ -610,6 +615,7 @@ public class OrderService {
|
|
|
}
|
|
|
|
|
|
public void cancel(Order order) {
|
|
|
+ // 取消订单与订单回调不能同时进行,需要抢锁
|
|
|
if (!getOrderLock(order.getId())) {
|
|
|
log.error("订单取消失败 {}, redis锁了", order.getId());
|
|
|
return;
|
|
|
@@ -620,19 +626,33 @@ public class OrderService {
|
|
|
throw new BusinessException("已支付订单无法取消");
|
|
|
}
|
|
|
|
|
|
+ // 查询adapay支付记录,如果已经支付,则不能取消
|
|
|
Set<Object> transactionIds = redisTemplate.opsForSet().members(RedisKeys.PAY_RECORD + order.getId());
|
|
|
if (transactionIds != null && transactionIds.size() > 0) {
|
|
|
- if (transactionIds.parallelStream().anyMatch(transactionId -> {
|
|
|
+ AtomicInteger succeeded = new AtomicInteger();
|
|
|
+ AtomicInteger pending = new AtomicInteger();
|
|
|
+ transactionIds.parallelStream().forEach(transactionId -> {
|
|
|
try {
|
|
|
Map<String, Object> map = Payment.query(transactionId.toString());
|
|
|
- return "succeeded".equalsIgnoreCase(MapUtils.getString(map, "status")) ||
|
|
|
- "pending".equalsIgnoreCase(MapUtils.getString(map, "status"));
|
|
|
+ if ("succeeded".equalsIgnoreCase(MapUtils.getString(map, "status"))) {
|
|
|
+ succeeded.getAndIncrement();
|
|
|
+ }
|
|
|
+ if ("pending".equalsIgnoreCase(MapUtils.getString(map, "status"))) {
|
|
|
+ pending.getAndIncrement();
|
|
|
+ // 未支付的订单调用关单接口
|
|
|
+ Payment.close(new HashMap<>() {{
|
|
|
+ put("payment_id", transactionId);
|
|
|
+ }});
|
|
|
+ }
|
|
|
} catch (BaseAdaPayException e) {
|
|
|
- e.printStackTrace();
|
|
|
+ log.error("adapay error", e);
|
|
|
+ }
|
|
|
+ });
|
|
|
+// if (succeeded.get() + pending.get() > 0) {
|
|
|
+ if (succeeded.get() > 0) {
|
|
|
+ if (ChronoUnit.MINUTES.between(order.getCreatedAt(), LocalDateTime.now()) < 10) {
|
|
|
+ throw new BusinessException("订单已经支付成功或待支付,不能取消 " + order.getId());
|
|
|
}
|
|
|
- return false;
|
|
|
- })) {
|
|
|
- throw new BusinessException("订单已经支付成功或待支付,不能取消 " + order.getId());
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -664,7 +684,11 @@ public class OrderService {
|
|
|
rocketMQTemplate.syncSend(generalProperties.getUpdateStockTopic(), order.getCollectionId(), 10000);
|
|
|
log.info("取消订单{}", order.getId());
|
|
|
} catch (Exception e) {
|
|
|
- log.error("订单取消错误 orderId: " + order.getId(), e);
|
|
|
+ if (e instanceof BusinessException) {
|
|
|
+ log.error(e.getMessage());
|
|
|
+ } else {
|
|
|
+ log.error("订单取消错误 orderId: " + order.getId(), e);
|
|
|
+ }
|
|
|
}
|
|
|
releaseOrderLock(order.getId());
|
|
|
}
|
|
|
@@ -744,12 +768,14 @@ public class OrderService {
|
|
|
return redisTemplate.opsForValue().get(RedisKeys.CREATE_ORDER + id);
|
|
|
}
|
|
|
|
|
|
+ // 获取订单锁,有效时间1小时
|
|
|
public boolean getOrderLock(Long orderId) {
|
|
|
BoundValueOperations<String, Object> ops = redisTemplate.boundValueOps(RedisKeys.ORDER_LOCK + orderId);
|
|
|
- Boolean flag = ops.setIfAbsent(1, 1, TimeUnit.DAYS);
|
|
|
+ Boolean flag = ops.setIfAbsent(1, 1, TimeUnit.HOURS);
|
|
|
return Boolean.TRUE.equals(flag);
|
|
|
}
|
|
|
|
|
|
+ // 释放订单锁
|
|
|
public void releaseOrderLock(Long orderId) {
|
|
|
redisTemplate.delete(RedisKeys.ORDER_LOCK + orderId);
|
|
|
}
|