mirror of
https://gitee.com/hhyykk/ipms-sjy.git
synced 2025-08-14 10:11:53 +08:00
code review:拼团记录流程
This commit is contained in:
@@ -29,6 +29,7 @@ public class CombinationRecordApiImpl implements CombinationRecordApi {
|
||||
recordService.validateCombinationRecord(userId, activityId, headId, skuId, count);
|
||||
}
|
||||
|
||||
// TODO @puhui999:搞个创建的 RespDTO 哈;
|
||||
@Override
|
||||
public KeyValue<Long, Long> createCombinationRecord(CombinationRecordCreateReqDTO reqDTO) {
|
||||
return recordService.createCombinationRecord(reqDTO);
|
||||
|
@@ -40,6 +40,9 @@ public class CombinationRecordController {
|
||||
@Lazy
|
||||
private CombinationRecordService combinationRecordService;
|
||||
|
||||
// TODO @puhui999:getBargainRecordPage 和 getBargainRecordPage 是不是可以合并;然后 CombinationRecordReqPageVO 加一个 headId;
|
||||
// 然后如果 headId 非空,并且第一页,单独多查询一条 head ;放到第 0 个位置;相当于说,第一页特殊一点;
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得拼团记录分页")
|
||||
@PreAuthorize("@ss.hasPermission('promotion:combination-record:query')")
|
||||
@@ -47,6 +50,7 @@ public class CombinationRecordController {
|
||||
PageResult<CombinationRecordDO> recordPage = combinationRecordService.getCombinationRecordPage(pageVO);
|
||||
List<CombinationActivityDO> activities = combinationActivityService.getCombinationActivityListByIds(
|
||||
convertSet(recordPage.getList(), CombinationRecordDO::getActivityId));
|
||||
// TODO @puhui999:商品没读取
|
||||
return success(CombinationActivityConvert.INSTANCE.convert(recordPage, activities));
|
||||
}
|
||||
|
||||
|
@@ -27,7 +27,6 @@ import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.Parameters;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@@ -49,20 +48,15 @@ public class AppBargainRecordController {
|
||||
@Resource
|
||||
private BargainHelpService bargainHelpService;
|
||||
@Resource
|
||||
@Lazy
|
||||
private BargainRecordService bargainRecordService;
|
||||
@Resource
|
||||
@Lazy
|
||||
private BargainActivityService bargainActivityService;
|
||||
|
||||
|
||||
@Resource
|
||||
private TradeOrderApi tradeOrderApi;
|
||||
@Resource
|
||||
@Lazy
|
||||
private MemberUserApi memberUserApi;
|
||||
@Resource
|
||||
@Lazy
|
||||
private ProductSpuApi productSpuApi;
|
||||
|
||||
@GetMapping("/get-summary")
|
||||
|
@@ -9,7 +9,6 @@ import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainActivityD
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Collection;
|
||||
@@ -87,6 +86,7 @@ public interface BargainActivityMapper extends BaseMapperX<BargainActivityDO> {
|
||||
.last("LIMIT " + count));
|
||||
}
|
||||
|
||||
// TODO @puhui999:是不是返回 BargainActivityDO 更干净哈?
|
||||
/**
|
||||
* 查询出指定 spuId 的 spu 参加的活动最接近现在的一条记录。多个的话,一个 spuId 对应一个最近的活动编号
|
||||
*
|
||||
@@ -94,7 +94,7 @@ public interface BargainActivityMapper extends BaseMapperX<BargainActivityDO> {
|
||||
* @param status 状态
|
||||
* @return 包含 spuId 和 activityId 的 map 对象列表
|
||||
*/
|
||||
default List<Map<String, Object>> selectSpuIdAndActivityIdMapsBySpuIdsAndStatus(@Param("spuIds") Collection<Long> spuIds, @Param("status") Integer status) {
|
||||
default List<Map<String, Object>> selectSpuIdAndActivityIdMapsBySpuIdsAndStatus(Collection<Long> spuIds, Integer status) {
|
||||
return selectMaps(new QueryWrapper<BargainActivityDO>()
|
||||
.select("spu_id AS spuId, MAX(DISTINCT(id)) AS activityId") // 时间越大 id 也越大 直接用 id
|
||||
.in("spu_id", spuIds)
|
||||
|
@@ -120,6 +120,7 @@ public interface CombinationRecordMapper extends BaseMapperX<CombinationRecordDO
|
||||
*/
|
||||
default Long selectCountByHeadAndStatusAndVirtualGroup(Integer status, Boolean virtualGroup, Long headId) {
|
||||
return selectCount(new QueryWrapper<CombinationRecordDO>()
|
||||
// TODO @puhui999:这种偏逻辑性的,不要给 mapper 哈;可以考虑拆成 2 个 mapper,上层也是 2 个 service;
|
||||
.select(status == null && virtualGroup == null && headId == null, "DISTINCT (user_id)")
|
||||
.eq(status != null, "status", status)
|
||||
.eq(virtualGroup != null, "virtual_group", virtualGroup)
|
||||
|
@@ -22,7 +22,7 @@ public class CombinationRecordExpireJob implements JobHandler {
|
||||
|
||||
@Override
|
||||
@TenantJob
|
||||
public String execute(String param) throws Exception {
|
||||
public String execute(String param) {
|
||||
KeyValue<Integer, Integer> keyValue = combinationRecordService.expireCombinationRecord();
|
||||
return StrUtil.format("过期拼团 {} 个, 虚拟成团 {} 个", keyValue.getKey(), keyValue.getValue());
|
||||
}
|
||||
|
@@ -94,7 +94,6 @@ public class BargainActivityServiceImpl implements BargainActivityService {
|
||||
} else if (count > 0) {
|
||||
bargainActivityMapper.updateStock(id, count);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void validateBargainConflict(Long spuId, Long activityId) {
|
||||
@@ -184,12 +183,13 @@ public class BargainActivityServiceImpl implements BargainActivityService {
|
||||
|
||||
@Override
|
||||
public List<BargainActivityDO> getBargainActivityBySpuIdsAndStatus(Collection<Long> spuIds, Integer status) {
|
||||
// 1.查询出指定 spuId 的 spu 参加的活动最接近现在的一条记录。多个的话,一个 spuId 对应一个最近的活动编号
|
||||
// 1. 查询出指定 spuId 的 spu 参加的活动最接近现在的一条记录。多个的话,一个 spuId 对应一个最近的活动编号
|
||||
// TODO @puhui999:我想了下,这种是不是只展示当前正在进行中的。已经结束、或者未开始的,可能没啥意义?
|
||||
List<Map<String, Object>> spuIdAndActivityIdMaps = bargainActivityMapper.selectSpuIdAndActivityIdMapsBySpuIdsAndStatus(spuIds, status);
|
||||
if (CollUtil.isEmpty(spuIdAndActivityIdMaps)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
// 2.查询活动详情
|
||||
// 2. 查询活动详情
|
||||
return bargainActivityMapper.selectListByIds(convertSet(spuIdAndActivityIdMaps, map -> MapUtil.getLong(map, "activityId")));
|
||||
}
|
||||
|
||||
|
@@ -146,7 +146,6 @@ public interface CombinationRecordService {
|
||||
*/
|
||||
PageResult<CombinationRecordDO> getCombinationRecordPage2(CombinationRecordReqPage2VO pageVO);
|
||||
|
||||
|
||||
/**
|
||||
* 【拼团活动】获得拼团记录数量 Map
|
||||
*
|
||||
@@ -159,7 +158,6 @@ public interface CombinationRecordService {
|
||||
@Nullable Integer status,
|
||||
@Nullable Long headId);
|
||||
|
||||
|
||||
/**
|
||||
* 获取拼团记录
|
||||
*
|
||||
|
@@ -23,7 +23,6 @@ import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationR
|
||||
import cn.iocoder.yudao.module.promotion.dal.mysql.combination.CombinationRecordMapper;
|
||||
import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum;
|
||||
import cn.iocoder.yudao.module.trade.api.order.TradeOrderApi;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
@@ -52,7 +51,6 @@ import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
|
||||
public class CombinationRecordServiceImpl implements CombinationRecordService {
|
||||
|
||||
@Resource
|
||||
@Lazy
|
||||
private CombinationActivityService combinationActivityService;
|
||||
@Resource
|
||||
private CombinationRecordMapper combinationRecordMapper;
|
||||
@@ -60,16 +58,13 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
|
||||
@Resource
|
||||
private MemberUserApi memberUserApi;
|
||||
@Resource
|
||||
@Lazy
|
||||
private ProductSpuApi productSpuApi;
|
||||
@Resource
|
||||
@Lazy
|
||||
private ProductSkuApi productSkuApi;
|
||||
|
||||
@Resource
|
||||
private TradeOrderApi tradeOrderApi;
|
||||
|
||||
// TODO @芋艿:在详细预览下;
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void updateCombinationRecordStatusByUserIdAndOrderId(Integer status, Long userId, Long orderId) {
|
||||
@@ -77,6 +72,7 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
|
||||
CombinationRecordDO record = validateCombinationRecord(userId, orderId);
|
||||
|
||||
// 更新状态
|
||||
// TODO @puhui999:不要整个更新,new 一个出来;why?例如说,两个线程都去更新,这样存在相互覆盖的问题
|
||||
record.setStatus(status);
|
||||
combinationRecordMapper.updateById(record);
|
||||
}
|
||||
@@ -169,16 +165,16 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public KeyValue<Long, Long> createCombinationRecord(CombinationRecordCreateReqDTO reqDTO) {
|
||||
// 1.校验拼团活动
|
||||
// 1. 校验拼团活动
|
||||
KeyValue<CombinationActivityDO, CombinationProductDO> keyValue = validateCombinationRecord(reqDTO.getUserId(),
|
||||
reqDTO.getActivityId(), reqDTO.getHeadId(), reqDTO.getSkuId(), reqDTO.getCount());
|
||||
|
||||
// 2.组合数据创建拼团记录
|
||||
// 2. 组合数据创建拼团记录
|
||||
MemberUserRespDTO user = memberUserApi.getUser(reqDTO.getUserId());
|
||||
ProductSpuRespDTO spu = productSpuApi.getSpu(reqDTO.getSpuId());
|
||||
ProductSkuRespDTO sku = productSkuApi.getSku(reqDTO.getSkuId());
|
||||
CombinationRecordDO record = CombinationActivityConvert.INSTANCE.convert(reqDTO, keyValue.getKey(), user, spu, sku);
|
||||
// 2.1.如果是团长需要设置 headId 为 CombinationRecordDO#HEAD_ID_GROUP
|
||||
// 2.1. 如果是团长需要设置 headId 为 CombinationRecordDO#HEAD_ID_GROUP
|
||||
if (record.getHeadId() == null) {
|
||||
record.setStartTime(LocalDateTime.now())
|
||||
.setExpireTime(keyValue.getKey().getStartTime().plusHours(keyValue.getKey().getLimitDuration()))
|
||||
@@ -191,12 +187,10 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
|
||||
}
|
||||
combinationRecordMapper.insert(record);
|
||||
|
||||
if (ObjUtil.equal(CombinationRecordDO.HEAD_ID_GROUP, record.getHeadId())) {
|
||||
return new KeyValue<>(record.getId(), record.getHeadId());
|
||||
// 3. 更新拼团记录
|
||||
if (ObjUtil.notEqual(CombinationRecordDO.HEAD_ID_GROUP, record.getHeadId())) {
|
||||
updateCombinationRecordWhenCreate(reqDTO.getHeadId(), keyValue.getKey());
|
||||
}
|
||||
|
||||
// 3、更新拼团记录
|
||||
updateCombinationRecordWhenCreate(reqDTO.getHeadId(), keyValue.getKey());
|
||||
return new KeyValue<>(record.getId(), record.getHeadId());
|
||||
}
|
||||
|
||||
@@ -349,6 +343,7 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
|
||||
|
||||
@Override
|
||||
public KeyValue<Integer, Integer> expireCombinationRecord() {
|
||||
// TODO @puhui999:数字一般是 1. 2. 这种格式哈
|
||||
// 1。获取所有正在进行中的过期的父拼团
|
||||
List<CombinationRecordDO> headExpireRecords = combinationRecordMapper.selectListByHeadIdAndStatusAndExpireTimeLt(
|
||||
CombinationRecordDO.HEAD_ID_GROUP, CombinationRecordStatusEnum.IN_PROGRESS.getStatus(), LocalDateTime.now());
|
||||
@@ -356,18 +351,21 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
|
||||
return new KeyValue<>(0, 0);
|
||||
}
|
||||
|
||||
// 2.获取拼团活动
|
||||
// 2. 获取拼团活动
|
||||
// TODO @puhui999:在自己模块里,变量可以简略点;例如说 activityList
|
||||
List<CombinationActivityDO> combinationActivities = combinationActivityService.getCombinationActivityListByIds(
|
||||
convertSet(headExpireRecords, CombinationRecordDO::getActivityId));
|
||||
Map<Long, CombinationActivityDO> activityMap = convertMap(combinationActivities, CombinationActivityDO::getId);
|
||||
|
||||
// 3.校验是否虚拟成团
|
||||
// TODO @puhui999:job 一般不建议异步跑;因为可能下次跑,结果上次还没跑完;
|
||||
// TODO 这里,我们可以每个 record 处理下;然后按照是否需要虚拟拼团,各搞一个方法逻辑 + 事务;这样,保证 job 里面尽量不要大事务,而是 n 个独立小事务的处理。
|
||||
// 3. 校验是否虚拟成团
|
||||
List<CombinationRecordDO> virtualGroupHeadRecords = new ArrayList<>(); // 虚拟成团
|
||||
for (Iterator<CombinationRecordDO> iterator = headExpireRecords.iterator(); iterator.hasNext(); ) {
|
||||
CombinationRecordDO record = iterator.next();
|
||||
// 3.1 不匹配,则直接跳过
|
||||
CombinationActivityDO activityDO = activityMap.get(record.getActivityId());
|
||||
if (activityDO == null || !activityDO.getVirtualGroup()) { // 取不到活动的或者不是虚拟拼团的
|
||||
CombinationActivityDO activity = activityMap.get(record.getActivityId());
|
||||
if (activity == null || !activity.getVirtualGroup()) { // 取不到活动的或者不是虚拟拼团的
|
||||
continue;
|
||||
}
|
||||
// 3.2 匹配,则移除,添加到虚拟成团中,并结束寻找
|
||||
@@ -380,7 +378,6 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
|
||||
getSelf().handleExpireRecord(headExpireRecords);
|
||||
// 5.虚拟成团
|
||||
getSelf().handleVirtualGroupRecord(virtualGroupHeadRecords);
|
||||
|
||||
return new KeyValue<>(headExpireRecords.size(), virtualGroupHeadRecords.size());
|
||||
}
|
||||
|
||||
@@ -401,7 +398,6 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
|
||||
headsAndRecords.forEach(item -> {
|
||||
tradeOrderApi.cancelPaidOrder(item.getUserId(), item.getOrderId());
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@Async
|
||||
@@ -410,9 +406,9 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
|
||||
return;
|
||||
}
|
||||
|
||||
// 1.团员补齐
|
||||
// 1. 团员补齐
|
||||
combinationRecordMapper.insertBatch(CombinationActivityConvert.INSTANCE.convertVirtualGroupList(virtualGroupHeadRecords));
|
||||
// 2.更新拼团记录
|
||||
// 2. 更新拼团记录
|
||||
updateBatchCombinationRecords(virtualGroupHeadRecords, CombinationRecordStatusEnum.SUCCESS);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user