修改取单号逻辑算法

This commit is contained in:
Jack 2025-12-05 15:57:39 +08:00
parent 7a26bdec49
commit f9192c74ff
4 changed files with 113 additions and 51 deletions

View File

@ -2,6 +2,7 @@ package com.suisung.mall.shop.number.service;
import com.suisung.mall.common.modules.number.ShopNumberSeq;
import com.suisung.mall.core.web.service.IBaseService;
import org.springframework.data.util.Pair;
import java.util.List;
@ -17,6 +18,14 @@ public interface ShopNumberSeqService extends IBaseService<ShopNumberSeq> {
String createNextSeq(String prefix);
/**
* 创建下一个编号(键值对)
*
* @param prefix 前缀
* @return 序号和完整编号
*/
Pair<Long, String> createNextSeqPair(String prefix);
Long createNextNo(String prefix);
List<Long> batchCreateNextNo(String seqName, int batchSize);

View File

@ -27,6 +27,7 @@ import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.util.Pair;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@ -125,6 +126,44 @@ public class ShopNumberSeqServiceImpl extends BaseServiceImpl<ShopNumberSeqMappe
return null;
}
/**
* 得到下一个编号键值对
* 方法走到这里会产生串行化集群部署这里不能使用单机锁
*
* @param prefix
* @return
*/
@Override
@Transactional(propagation = Propagation.NOT_SUPPORTED)
@DistributedLock(
key = "CREATENEXTSEQ_LOCK", // 锁的key
waitTime = 3, // 等待3秒
leaseTime = 10, // 锁持有10秒
errorMsg = "生成ID繁忙请稍后重试" // 自定义错误消息
)
public synchronized Pair<Long, String> createNextSeqPair(String prefix) {
String ymd = DateUtil.format(new Date(), "yyyyMMdd");
String id = String.format("%s_%s_", prefix, ymd);
ShopNumberSeq shopNumberSeq = this.baseMapper.selectById(id);
if (shopNumberSeq == null) {
shopNumberSeq = new ShopNumberSeq();
shopNumberSeq.setPrefix(id);
shopNumberSeq.setNumber(1L);
if (!save(shopNumberSeq)) {
return null;
}
}
String order_id = String.format("%s_%s_%s", prefix, ymd, shopNumberSeq.getNumber());
shopNumberSeq.setPrefix(id);
boolean flag = edit(shopNumberSeq);
if (flag) {
return Pair.of(shopNumberSeq.getNumber(), order_id);
}
return null;
}
/**
* 得到下一个Id
*
@ -280,12 +319,12 @@ public class ShopNumberSeqServiceImpl extends BaseServiceImpl<ShopNumberSeqMappe
boolean isLocked = false;
int start = 0;
try {
isLocked = lock.tryLock(2, 30, TimeUnit.SECONDS);
isLocked = lock.tryLock(2, 30, TimeUnit.SECONDS);
if (!isLocked) {
// 获取锁失败可以根据业务逻辑进行重试或抛出异常
throw new RuntimeException("系统繁忙,请稍后再试");
}
log.info("成功获得锁:{}",lockKey);
log.info("成功获得锁:{}", lockKey);
if (null != redisService.get(RedisKey.STOREDATASPECID)) {
start = (Integer) redisService.get(RedisKey.STOREDATASPECID);
redisService.set(RedisKey.STOREDATASPECID, start + batchSize);
@ -305,12 +344,12 @@ public class ShopNumberSeqServiceImpl extends BaseServiceImpl<ShopNumberSeqMappe
return IntStream.rangeClosed(start + 1, start + batchSize).boxed().collect(Collectors.toList());
} catch (Exception e) {
throw new ApiException(e);
}finally {
} finally {
// 5. 最终检查并释放锁确保锁一定被释放
if (lock != null && lock.isLocked() && lock.isHeldByCurrentThread()) {
lock.unlock();
}
log.info("成功释放锁:{}",lockKey);
log.info("成功释放锁:{}", lockKey);
}
}
@ -322,7 +361,7 @@ public class ShopNumberSeqServiceImpl extends BaseServiceImpl<ShopNumberSeqMappe
* @return
*/
@Override
public List<Integer> getBatchSpecItemId(int batchSize) {
public List<Integer> getBatchSpecItemId(int batchSize) {
// 定义锁的key这个key在所有服务实例中必须一致
String lockKey = "LOCK:" + RedisKey.STOREDATASPECITEMID;
// 2. 获取分布式锁对象
@ -330,12 +369,12 @@ public class ShopNumberSeqServiceImpl extends BaseServiceImpl<ShopNumberSeqMappe
boolean isLocked = false;
int start = 0;
try {
isLocked=lock.tryLock(2,30,TimeUnit.SECONDS);
isLocked = lock.tryLock(2, 30, TimeUnit.SECONDS);
if (!isLocked) {
// 获取锁失败可以根据业务逻辑进行重试或抛出异常
throw new ApiException("系统繁忙,请稍后再试");
}
log.info("成功获得锁:{}",lockKey);
log.info("成功获得锁:{}", lockKey);
if (null != redisService.get(RedisKey.STOREDATASPECITEMID)) {
start = (Integer) redisService.get(RedisKey.STOREDATASPECITEMID);
redisService.set(RedisKey.STOREDATASPECITEMID, start + batchSize);
@ -355,12 +394,12 @@ public class ShopNumberSeqServiceImpl extends BaseServiceImpl<ShopNumberSeqMappe
return IntStream.rangeClosed(start + 1, start + batchSize).boxed().collect(Collectors.toList());
} catch (InterruptedException e) {
throw new ApiException(e);
}finally {
} finally {
// 5. 最终检查并释放锁确保锁一定被释放
if (lock != null && lock.isLocked() && lock.isHeldByCurrentThread()) {
lock.unlock();
}
log.info("成功释放锁:{}",lockKey);
log.info("成功释放锁:{}", lockKey);
}
}
@ -383,7 +422,7 @@ public class ShopNumberSeqServiceImpl extends BaseServiceImpl<ShopNumberSeqMappe
// 获取锁失败可以根据业务逻辑进行重试或抛出异常
throw new RuntimeException("系统繁忙,请稍后再试");
}
log.info("成功获得锁:{}",lockKey);
log.info("成功获得锁:{}", lockKey);
int start = 0;
if (null != redisService.get(RedisKey.STOREDATACCOUNTBASEID)) {
start = (Integer) redisService.get(RedisKey.STOREDATACCOUNTBASEID);
@ -403,12 +442,12 @@ public class ShopNumberSeqServiceImpl extends BaseServiceImpl<ShopNumberSeqMappe
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException("getBatchUserAccountBaseId获取锁时被中断", e);
}finally {
} finally {
// 5. 最终检查并释放锁确保锁一定被释放
if (lock != null && lock.isLocked() && lock.isHeldByCurrentThread()) {
lock.unlock();
}
log.info("成功释放锁:{}",lockKey);
log.info("成功释放锁:{}", lockKey);
}
}
@ -421,7 +460,7 @@ public class ShopNumberSeqServiceImpl extends BaseServiceImpl<ShopNumberSeqMappe
* @return
*/
@Override
public List<Integer> getBatchLibraryProductId(int batchSize) {
public List<Integer> getBatchLibraryProductId(int batchSize) {
// 定义锁的key这个key在所有服务实例中必须一致
String lockKey = "LOCK:" + RedisKey.STOREDATALIBRARYID;
// 2. 获取分布式锁对象
@ -434,7 +473,7 @@ public class ShopNumberSeqServiceImpl extends BaseServiceImpl<ShopNumberSeqMappe
// 获取锁失败可以根据业务逻辑进行重试或抛出异常
throw new RuntimeException("系统繁忙,请稍后再试");
}
log.info("成功获得锁:{}",lockKey);
log.info("成功获得锁:{}", lockKey);
if (null != redisService.get(RedisKey.STOREDATALIBRARYID)) {
start = (Integer) redisService.get(RedisKey.STOREDATALIBRARYID);
redisService.set(RedisKey.STOREDATALIBRARYID, start + batchSize);
@ -454,12 +493,12 @@ public class ShopNumberSeqServiceImpl extends BaseServiceImpl<ShopNumberSeqMappe
return IntStream.rangeClosed(start + 1, start + batchSize).boxed().collect(Collectors.toList());
} catch (InterruptedException e) {
throw new RuntimeException(e);
}finally {
} finally {
// 5. 最终检查并释放锁确保锁一定被释放
if (lock != null && lock.isLocked() && lock.isHeldByCurrentThread()) {
lock.unlock();
}
log.info("成功释放锁:{}",lockKey);
log.info("成功释放锁:{}", lockKey);
}
}
@ -478,12 +517,12 @@ public class ShopNumberSeqServiceImpl extends BaseServiceImpl<ShopNumberSeqMappe
boolean isLocked = false;
long start = 0;
try {
isLocked=lock.tryLock(2,30,TimeUnit.SECONDS);
isLocked = lock.tryLock(2, 30, TimeUnit.SECONDS);
if (!isLocked) {
// 获取锁失败可以根据业务逻辑进行重试或抛出异常
throw new ApiException("系统繁忙,请稍后再试");
}
log.info("成功获得锁:{}",lockKey);
log.info("成功获得锁:{}", lockKey);
QueryWrapper<ShopPageBase> queryWrapper = new QueryWrapper<>();
queryWrapper.select("max(page_id) as page_id");
ShopPageBase shopPageBase = shopPageBaseService.getOne(queryWrapper);
@ -493,41 +532,41 @@ public class ShopNumberSeqServiceImpl extends BaseServiceImpl<ShopNumberSeqMappe
return LongStream.rangeClosed(start + 1, start + batchSize).boxed().collect(Collectors.toList());
} catch (InterruptedException e) {
throw new ApiException(e);
}finally {
} finally {
// 5. 最终检查并释放锁确保锁一定被释放
if (lock != null && lock.isLocked() && lock.isHeldByCurrentThread()) {
lock.unlock();
}
log.info("成功释放锁:{}",lockKey);
log.info("成功释放锁:{}", lockKey);
}
}
/**
* 初始化主键
*/
private void syncPrimaryKey(){
List<ShopNumberSeq> shopNumberSeqList=new ArrayList<>();
QueryWrapper<ShopProductBase> baseWrapper=new QueryWrapper<>();
private void syncPrimaryKey() {
List<ShopNumberSeq> shopNumberSeqList = new ArrayList<>();
QueryWrapper<ShopProductBase> baseWrapper = new QueryWrapper<>();
baseWrapper.select("MAX(product_id) as product_id");
ShopProductBase shopProductBase= shopProductBaseService.getOne(baseWrapper);
Long productId= shopProductBase.getProduct_id();
ShopProductBase shopProductBase = shopProductBaseService.getOne(baseWrapper);
Long productId = shopProductBase.getProduct_id();
//QueryWrapper<ShopNumberSeq> baseSeWrapper=new QueryWrapper();
//baseSeWrapper.eq("prefix", "product_id");
ShopNumberSeq shopNumberSeqBase= new ShopNumberSeq();
ShopNumberSeq shopNumberSeqBase = new ShopNumberSeq();
shopNumberSeqBase.setPrefix("product_id");
shopNumberSeqBase.setNumber(productId);
//shopNumberSeqServiceImpl.edit(shopNumberSeqBase,baseWrapper);
//查询产品item
QueryWrapper<ShopProductItem> itemQuery=new QueryWrapper<>();
QueryWrapper<ShopProductItem> itemQuery = new QueryWrapper<>();
itemQuery.select("MAX(item_id) as item_id");
ShopProductItem shopProductItem= shopProductItemService.getOne(itemQuery);
Long itemtId=1L;
if(null!=shopProductItem){
itemtId= shopProductItem.getItem_id();
ShopProductItem shopProductItem = shopProductItemService.getOne(itemQuery);
Long itemtId = 1L;
if (null != shopProductItem) {
itemtId = shopProductItem.getItem_id();
}
// QueryWrapper<ShopNumberSeq> itemWrapper=new QueryWrapper();
//itemWrapper.eq("prefix", "item_id");
ShopNumberSeq shopNumberSeqItem= new ShopNumberSeq();
ShopNumberSeq shopNumberSeqItem = new ShopNumberSeq();
shopNumberSeqItem.setNumber(itemtId);
shopNumberSeqItem.setPrefix("item_id");
shopNumberSeqList.add(shopNumberSeqBase);
@ -537,5 +576,4 @@ public class ShopNumberSeqServiceImpl extends BaseServiceImpl<ShopNumberSeqMappe
}
}

View File

@ -5289,17 +5289,17 @@ public class ShopOrderBaseServiceImpl extends BaseServiceImpl<ShopOrderBaseMappe
throw new ApiException(I18nUtil._("无符合取消条件的订单!"));
}
ShopOrderBase shopOrderBase = new ShopOrderBase();
shopOrderBase.setOrder_id(order_id);
shopOrderBase.setOrder_state_id(StateCode.ORDER_STATE_CANCEL);
if (!shopOrderBaseService.edit(shopOrderBase)) {
ShopOrderBase shopOrderBaseUpd = new ShopOrderBase();
shopOrderBaseUpd.setOrder_id(order_id);
shopOrderBaseUpd.setOrder_state_id(StateCode.ORDER_STATE_CANCEL);
if (!shopOrderBaseService.edit(shopOrderBaseUpd)) {
throw new ApiException(ResultCode.FAILED);
}
ShopOrderInfo orderInfo = new ShopOrderInfo();
orderInfo.setOrder_id(order_id);
orderInfo.setOrder_state_id(StateCode.ORDER_STATE_CANCEL);
if (!shopOrderInfoService.edit(orderInfo)) {
ShopOrderInfo orderInfoUpd = new ShopOrderInfo();
orderInfoUpd.setOrder_id(order_id);
orderInfoUpd.setOrder_state_id(StateCode.ORDER_STATE_CANCEL);
if (!shopOrderInfoService.edit(orderInfoUpd)) {
throw new ApiException(ResultCode.FAILED);
}
@ -5319,7 +5319,7 @@ public class ShopOrderBaseServiceImpl extends BaseServiceImpl<ShopOrderBaseMappe
if (shopOrderInfo.getDelivery_type_id() != null
&& StateCode.DELIVERY_TYPE_SAME_CITY == shopOrderInfo.getDelivery_type_id().intValue()) {
try {
logger.info("开始取消顺丰同城配送订单orderId: {}, delivery_type_id: {}", order_id, shopOrderInfo.getDelivery_type_id());
logger.warn("开始取消顺丰同城配送订单orderId: {}, delivery_type_id: {}", order_id, shopOrderInfo.getDelivery_type_id());
ThirdApiRes sfResult = sfExpressApiService.cancelOrder(order_id, 313, "用户或商家取消订单。");
if (sfResult != null && !sfResult.getError_code().equals(0)) {
log.error("顺丰同城取消订单返回错误orderId: {}, errorCode: {}, errorMsg: {}",
@ -6421,7 +6421,9 @@ public class ShopOrderBaseServiceImpl extends BaseServiceImpl<ShopOrderBaseMappe
type_code = StrUtil.isBlank(type_code) ? "DD" : type_code;
String xid = RootContext.getXID();
RootContext.unbind();
String order_id = shopNumberSeqService.createNextSeq(type_code);
Pair<Long, String> seqPair = shopNumberSeqService.createNextSeqPair(type_code);// 位数的序号 DD_20251205_1 2025-12-05 1
String order_id = seqPair.getSecond();
Long seqNo = seqPair.getFirst(); // 序号 DD_20251205_1 得出 1
RootContext.bind(xid);
List<ShopOrderItem> item_rows = new ArrayList();
@ -6666,6 +6668,7 @@ public class ShopOrderBaseServiceImpl extends BaseServiceImpl<ShopOrderBaseMappe
}
info_row.setOrder_id(order_id);
info_row.setOrder_pickup_num(seqNo); //重要配送员的取单号
info_row.setOrder_title(product_item_name); // 订单标题
if (fixOrderVo != null && fixOrderVo.isFix_price() && StrUtil.isNotEmpty(fixOrderVo.getOrder_title())) {
info_row.setOrder_title(fixOrderVo.getOrder_title()); // 订单标题

View File

@ -207,7 +207,7 @@ public class ShopOrderInfoServiceImpl extends BaseServiceImpl<ShopOrderInfoMappe
QueryWrapper<ShopOrderInfo> queryWrapper = new QueryWrapper<>();
// 已发货已签收
queryWrapper.in("order_state_id", StateCode.ORDER_STATE_SHIPPED, StateCode.ORDER_STATE_RECEIVED);
queryWrapper.eq("order_is_received",CommonConstant.Disable);
queryWrapper.eq("order_is_received", CommonConstant.Disable);
// 默认7天自动收货
// 配置了发货或已签收的订单1天自动收货
Float order_autofinish_time = accountBaseConfigService.getConfig("order_autofinish_time", 7f);
@ -372,8 +372,8 @@ public class ShopOrderInfoServiceImpl extends BaseServiceImpl<ShopOrderInfoMappe
/**
* 已支付的订单生成取单号打票机并打印订单
*
* @param storeId
* @param orderId
* @param storeId 商家ID
* @param orderId 订单ID
* @return 取货单号
*/
// @Transactional
@ -403,11 +403,22 @@ public class ShopOrderInfoServiceImpl extends BaseServiceImpl<ShopOrderInfoMappe
}
try {
// 生成取单号
Long orderPickupNum = genTodayPickupNum(storeId);
if (orderPickupNum == null || orderPickupNum <= 0) {
logger.error("生成取单号失败: storeId={}", storeId);
return 0L;
// 生成取单号废弃
// Long orderPickupNum = genTodayPickupNum(storeId);
// if (orderPickupNum == null || orderPickupNum <= 0) {
// logger.error("生成取单号失败: storeId={}", storeId);
// return 0L;
// }
Long orderPickupNum = 0L;
// 如果订单中尚未设置取单号则从订单ID中提取
if (CheckUtil.isEmpty(orderInfoOld.getOrder_pickup_num())) {
// 从订单ID中提取最后的数字部分作为取单号
// 例如订单ID为 DD_20250510_11则提取出 11 作为取单号
orderPickupNum = Convert.toLong(StrUtil.subAfter(orderId, "_", true));
} else {
// 如果已有取单号则使用现有的
orderPickupNum = orderInfoOld.getOrder_pickup_num();
}
// 更新订单信息
@ -432,6 +443,7 @@ public class ShopOrderInfoServiceImpl extends BaseServiceImpl<ShopOrderInfoMappe
}
}
/**
* 根据订单Id订单状态配送方式退款状态 获取订单的数量
*