Commit 6ec72d2c authored by 332784038@qq.com's avatar 332784038@qq.com

Merge remote-tracking branch 'origin/dev' into dev

parents 91d4a4a9 03417dfe
...@@ -4,7 +4,6 @@ import cn.iocoder.yudao.framework.redis.helper.RedisDistributedLock; ...@@ -4,7 +4,6 @@ import cn.iocoder.yudao.framework.redis.helper.RedisDistributedLock;
import cn.iocoder.yudao.framework.redis.helper.RedisHelper; import cn.iocoder.yudao.framework.redis.helper.RedisHelper;
import cn.iocoder.yudao.framework.redis.helper.RedisLockTemplate; import cn.iocoder.yudao.framework.redis.helper.RedisLockTemplate;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.cache.CacheManager; import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching; import org.springframework.cache.annotation.EnableCaching;
......
package cn.iocoder.yudao.framework.apollo.core.event;
import lombok.AllArgsConstructor;
import lombok.Data;
/**
* 订单起运事件
*
* @author zhangfeng
*/
@Data
@AllArgsConstructor
public class OrderInShippingEvent {
private Long orderId;
private String orderNo;
}
package cn.iocoder.yudao.framework.apollo.core.event.export;
import lombok.Data;
import java.util.List;
@Data
public class MemberScoreDetailExpireEvent {
private List<Long> detailIds;
}
...@@ -3,6 +3,8 @@ package cn.iocoder.yudao.module.member.api.score; ...@@ -3,6 +3,8 @@ package cn.iocoder.yudao.module.member.api.score;
import cn.iocoder.yudao.module.member.api.score.dto.MemberUserScoreBatchOperateReqDTO; import cn.iocoder.yudao.module.member.api.score.dto.MemberUserScoreBatchOperateReqDTO;
import cn.iocoder.yudao.module.member.api.score.dto.MemberUserScoreOperateReqDTO; import cn.iocoder.yudao.module.member.api.score.dto.MemberUserScoreOperateReqDTO;
import cn.iocoder.yudao.module.member.api.score.dto.MemberUserScoreOperateRespDTO; import cn.iocoder.yudao.module.member.api.score.dto.MemberUserScoreOperateRespDTO;
import cn.iocoder.yudao.module.member.api.score.dto.ReleationScoreExpireInfoDTO;
import cn.iocoder.yudao.module.member.enums.ScoreSourceTypeEnum;
import java.util.List; import java.util.List;
...@@ -12,4 +14,5 @@ public interface MemberUserScoreApi { ...@@ -12,4 +14,5 @@ public interface MemberUserScoreApi {
List<MemberUserScoreOperateRespDTO> batchOperateScore(MemberUserScoreBatchOperateReqDTO req); List<MemberUserScoreOperateRespDTO> batchOperateScore(MemberUserScoreBatchOperateReqDTO req);
List<ReleationScoreExpireInfoDTO> getScoreExpireInfo(String releation, ScoreSourceTypeEnum scoreSourceTypeEnum);
} }
...@@ -14,4 +14,5 @@ public class MemberUserScoreDetailUpdateReqDto { ...@@ -14,4 +14,5 @@ public class MemberUserScoreDetailUpdateReqDto {
private ScoreSourceTypeEnum sourceType; private ScoreSourceTypeEnum sourceType;
private Long scoreLogId; private Long scoreLogId;
private Integer expireDays; private Integer expireDays;
private String releationId;
} }
...@@ -28,6 +28,10 @@ public class MemberUserScoreOperateReqDTO { ...@@ -28,6 +28,10 @@ public class MemberUserScoreOperateReqDTO {
* 人工操作时必传,其他来源不需要传 * 人工操作时必传,其他来源不需要传
*/ */
private ScoreOperateTypeEnum operateType; private ScoreOperateTypeEnum operateType;
/**
* 若操作的积分后续存在回退逻辑时必传, 目前存在 礼品兑换后, 兑换取消,扣除积分的回退
*/
private String releationId;
/** /**
* 积分规则id * 积分规则id
*/ */
......
package cn.iocoder.yudao.module.member.api.score.dto;
import lombok.Data;
import java.util.Date;
@Data
public class ReleationScoreExpireInfoDTO {
private Long detailId;
private Date expireDate;
private Integer scoreCount;
}
...@@ -52,4 +52,7 @@ public interface ErrorCodeConstants { ...@@ -52,4 +52,7 @@ public interface ErrorCodeConstants {
ErrorCode SCORE_RULE_FIELD_ERROR = new ErrorCode(1004008007, "score.rule.field.error"); ErrorCode SCORE_RULE_FIELD_ERROR = new ErrorCode(1004008007, "score.rule.field.error");
ErrorCode REVERSE_SOURCE_NO_RELEATION_ID = new ErrorCode(1004008008, "reverse.source.no.releation.id");
ErrorCode LEVEL_BOUND_RANGE_ERROR = new ErrorCode(1004008009, "level.bound.range.error");
ErrorCode LEVEL_BOUND_RANGE_CONFLICT = new ErrorCode(1004008010, "level.bound.range.conflict");
} }
package cn.iocoder.yudao.module.member.enums;
public enum MemberScoreDetailReleationStatueEnum {
AVAILABLE(1, "有效"),
NOT_AVAILABLE(2, "失效")
;
private final int value;
private final String name;
MemberScoreDetailReleationStatueEnum(int value, String name) {
this.value = value;
this.name = name;
}
public int getValue() {
return value;
}
public String getName() {
return name;
}
}
...@@ -5,11 +5,13 @@ import com.google.common.collect.Sets; ...@@ -5,11 +5,13 @@ import com.google.common.collect.Sets;
import java.util.Set; import java.util.Set;
public enum ScoreSourceTypeEnum { public enum ScoreSourceTypeEnum {
MANUAL_OPERATE(1, "人工操作", null), MANUAL_OPERATE(1, "人工操作", null, null),
EXCHANGE_REWARD(2, "兑换礼品", ScoreOperateTypeEnum.REDUCE), EXCHANGE_REWARD(2, "兑换礼品", ScoreOperateTypeEnum.REDUCE, null),
SYSTEM_EXPIRED(3, "系统失效", ScoreOperateTypeEnum.REDUCE), SYSTEM_EXPIRED(3, "系统失效", ScoreOperateTypeEnum.REDUCE, null),
EXCHANGE_REWARD_CANCEL(4, "兑换礼品撤销", ScoreOperateTypeEnum.ADD, EXCHANGE_REWARD),
; ;
private final int value; private final int value;
...@@ -18,16 +20,23 @@ public enum ScoreSourceTypeEnum { ...@@ -18,16 +20,23 @@ public enum ScoreSourceTypeEnum {
private final ScoreOperateTypeEnum operateType; private final ScoreOperateTypeEnum operateType;
ScoreSourceTypeEnum(int value, String name, ScoreOperateTypeEnum operateType) { private final ScoreSourceTypeEnum reverseSource;
ScoreSourceTypeEnum(int value, String name, ScoreOperateTypeEnum operateType, ScoreSourceTypeEnum reverseSource) {
this.value = value; this.value = value;
this.name = name; this.name = name;
this.operateType = operateType; this.operateType = operateType;
this.reverseSource = reverseSource;
} }
public int getValue() { public int getValue() {
return value; return value;
} }
public ScoreSourceTypeEnum getReverseSource() {
return reverseSource;
}
public String getName() { public String getName() {
return name; return name;
} }
......
package cn.iocoder.yudao.module.member.enums; package cn.iocoder.yudao.module.member.enums;
public enum TransportType { public enum TransportTypeEnum {
OCEAN_LCL(1, "海运拼柜"), OCEAN_LCL(1, "海运拼柜"),
SPECIAL_LINE_AIR_FREIGHT(3, "专线空运"); SPECIAL_LINE_AIR_FREIGHT(3, "专线空运");
...@@ -8,7 +8,7 @@ public enum TransportType { ...@@ -8,7 +8,7 @@ public enum TransportType {
private final String name; private final String name;
TransportType(int value, String name) { TransportTypeEnum(int value, String name) {
this.value = value; this.value = value;
this.name = name; this.name = name;
} }
......
...@@ -49,5 +49,10 @@ ...@@ -49,5 +49,10 @@
<artifactId>yudao-module-depository-core</artifactId> <artifactId>yudao-module-depository-core</artifactId>
<version>${revision}</version> <version>${revision}</version>
</dependency> </dependency>
<!-- <dependency>-->
<!-- <groupId>cn.iocoder.boot</groupId>-->
<!-- <artifactId>yudao-module-order-core</artifactId>-->
<!-- <version>${revision}</version>-->
<!-- </dependency>-->
</dependencies> </dependencies>
</project> </project>
package cn.iocoder.yudao.module.member.api.score; package cn.iocoder.yudao.module.member.api.score;
import cn.iocoder.yudao.framework.redis.helper.RedisDistributedLock; import cn.iocoder.yudao.framework.apollo.core.event.export.MemberScoreDetailExpireEvent;
import cn.iocoder.yudao.module.member.api.score.dto.*; import cn.iocoder.yudao.module.member.api.score.dto.*;
import cn.iocoder.yudao.module.member.dal.dataobject.memberUserScore.MemberUserScoreDO; import cn.iocoder.yudao.module.member.dal.dataobject.score.MemberUserScoreDO;
import cn.iocoder.yudao.module.member.dal.dataobject.scoreDetail.MemberUserScoreDetailDO;
import cn.iocoder.yudao.module.member.dal.dataobject.scoreDetailReleation.MemberUserScoreDetailReleationDO;
import cn.iocoder.yudao.module.member.dto.ScoreDetailChangeDto;
import cn.iocoder.yudao.module.member.enums.MemberScoreDetailReleationStatueEnum;
import cn.iocoder.yudao.module.member.enums.ScoreOperateTypeEnum; import cn.iocoder.yudao.module.member.enums.ScoreOperateTypeEnum;
import cn.iocoder.yudao.module.member.enums.ScoreSourceTypeEnum; import cn.iocoder.yudao.module.member.enums.ScoreSourceTypeEnum;
import cn.iocoder.yudao.module.member.service.memberUserScore.MemberUserScoreService; import cn.iocoder.yudao.module.member.service.score.MemberUserScoreService;
import cn.iocoder.yudao.module.member.service.memberUserScoreDetail.MemberUserScoreDetailService; import cn.iocoder.yudao.module.member.service.scoreDetail.MemberUserScoreDetailService;
import cn.iocoder.yudao.module.member.service.memberUserScoreLog.MemberUserScoreLogService; import cn.iocoder.yudao.module.member.service.scoreDetailReleation.MemberUserScoreDetailReleationService;
import cn.iocoder.yudao.module.member.service.scoreLog.MemberUserScoreLogService;
import cn.iocoder.yudao.module.member.vo.memberUserScoreLog.MemberUserScoreLogCreateReq; import cn.iocoder.yudao.module.member.vo.memberUserScoreLog.MemberUserScoreLogCreateReq;
import com.alibaba.excel.util.CollectionUtils; import com.alibaba.excel.util.CollectionUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
...@@ -36,7 +49,12 @@ public class MemberUserScoreApiImpl implements MemberUserScoreApi{ ...@@ -36,7 +49,12 @@ public class MemberUserScoreApiImpl implements MemberUserScoreApi{
@Resource @Resource
private MemberUserScoreService memberUserScoreService; private MemberUserScoreService memberUserScoreService;
@Resource @Resource
private RedisDistributedLock redisDistributedLock; private MemberUserScoreDetailReleationService memberUserScoreDetailReleationService;
@Resource
private ApplicationContext applicationContext;
@Resource
private RedissonClient redissonClient;
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public MemberUserScoreOperateRespDTO operateScore(MemberUserScoreOperateReqDTO req) { public MemberUserScoreOperateRespDTO operateScore(MemberUserScoreOperateReqDTO req) {
...@@ -46,21 +64,43 @@ public class MemberUserScoreApiImpl implements MemberUserScoreApi{ ...@@ -46,21 +64,43 @@ public class MemberUserScoreApiImpl implements MemberUserScoreApi{
if (req.getScoreCount() <= 0) { if (req.getScoreCount() <= 0) {
throw exception(SCORE_COUNT_ERROR); throw exception(SCORE_COUNT_ERROR);
} }
String lockKey = "member:operate:socre:" + req.getMemberId(); String lockKey = "member:operate:score:" + req.getMemberId();
boolean lock = redisDistributedLock.lock(lockKey, 5000, 3, 100); RLock lock = redissonClient.getLock(lockKey);
if (!lock) { try {
boolean lockSuccess = lock.tryLock(2, 2, TimeUnit.SECONDS);
if (!lockSuccess) {
throw exception(GET_LOCK_FAILED); throw exception(GET_LOCK_FAILED);
} }
try {
Long logId = saveScoreLog(req); Long logId = saveScoreLog(req);
saveScoreDetail(req, logId); List<ScoreDetailChangeDto> detailInfos = saveScoreDetail(req, logId);
saveScoreDetailReleation(req, detailInfos);
updateUserScore(req); updateUserScore(req);
publishDetailExpireEvent(req,detailInfos);
} catch (InterruptedException e) {
throw exception(GET_LOCK_FAILED);
} finally { } finally {
redisDistributedLock.releaseLock(lockKey); lock.unlock();
} }
return MemberUserScoreOperateRespDTO.success(req); return MemberUserScoreOperateRespDTO.success(req);
} }
private void publishDetailExpireEvent(MemberUserScoreOperateReqDTO req, List<ScoreDetailChangeDto> detailInfos) {
if (req.getSourceType().getReverseSource() == null || req.getOperateType() ==ScoreOperateTypeEnum.REDUCE) {
return;
}
//判断回退流程,回退的积分是否过期.如果过期再走正常的过期扣积分流程
MemberScoreDetailExpireEvent memberScoreDetailExpireEvent = new MemberScoreDetailExpireEvent();
memberScoreDetailExpireEvent.setDetailIds(detailInfos.stream().map(ScoreDetailChangeDto::getDetailId).collect(Collectors.toList()));
applicationContext.publishEvent(memberScoreDetailExpireEvent);
}
private void saveScoreDetailReleation(MemberUserScoreOperateReqDTO req, List<ScoreDetailChangeDto> detailInfos) {
if (StringUtils.isBlank(req.getReleationId())) {
return;
}
memberUserScoreDetailReleationService.updateReleation(req.getReleationId(), req.getSourceType(), detailInfos);
}
@Override @Override
@Transactional @Transactional
public List<MemberUserScoreOperateRespDTO> batchOperateScore(MemberUserScoreBatchOperateReqDTO req) { public List<MemberUserScoreOperateRespDTO> batchOperateScore(MemberUserScoreBatchOperateReqDTO req) {
...@@ -91,6 +131,31 @@ public class MemberUserScoreApiImpl implements MemberUserScoreApi{ ...@@ -91,6 +131,31 @@ public class MemberUserScoreApiImpl implements MemberUserScoreApi{
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
@Override
public List<ReleationScoreExpireInfoDTO> getScoreExpireInfo(String releationId, ScoreSourceTypeEnum scoreSourceTypeEnum) {
if (StringUtils.isBlank(releationId)) {
return Collections.emptyList();
}
LambdaQueryWrapper<MemberUserScoreDetailReleationDO> wrapper = Wrappers.lambdaQuery();
wrapper.eq(MemberUserScoreDetailReleationDO::getReleationId, releationId);
wrapper.eq(MemberUserScoreDetailReleationDO::getSourceType, scoreSourceTypeEnum.getValue());
wrapper.eq(MemberUserScoreDetailReleationDO::getStatus, MemberScoreDetailReleationStatueEnum.AVAILABLE.getValue());
List<MemberUserScoreDetailReleationDO> releationDOList = memberUserScoreDetailReleationService.list(wrapper);
Set<Long> detailIds = releationDOList.stream().map(MemberUserScoreDetailReleationDO::getDetailId).collect(Collectors.toSet());
LambdaQueryWrapper<MemberUserScoreDetailDO> detailWrappers = Wrappers.lambdaQuery();
detailWrappers.in(MemberUserScoreDetailDO::getId, detailIds);
Map<Long, MemberUserScoreDetailDO> detailIdInfoMap = scoreDetailService.list(detailWrappers).stream()
.collect(Collectors.toMap(MemberUserScoreDetailDO::getId, Function.identity(), (c1, c2) -> c1));
return releationDOList.stream().map(releation -> {
ReleationScoreExpireInfoDTO expireInfoDTO = new ReleationScoreExpireInfoDTO();
MemberUserScoreDetailDO detailDO = detailIdInfoMap.getOrDefault(releation.getDetailId(), new MemberUserScoreDetailDO());
expireInfoDTO.setDetailId(detailDO.getId());
expireInfoDTO.setExpireDate(detailDO.getExpireTime());
expireInfoDTO.setScoreCount(releation.getScoreCount());
return expireInfoDTO;
}).collect(Collectors.toList());
}
private void updateUserScore(MemberUserScoreOperateReqDTO req) { private void updateUserScore(MemberUserScoreOperateReqDTO req) {
memberUserScoreService.updateUserScore(MemberUserScoreUpdateReqDTO.builder() memberUserScoreService.updateUserScore(MemberUserScoreUpdateReqDTO.builder()
.memberId(req.getMemberId()) .memberId(req.getMemberId())
...@@ -101,8 +166,8 @@ public class MemberUserScoreApiImpl implements MemberUserScoreApi{ ...@@ -101,8 +166,8 @@ public class MemberUserScoreApiImpl implements MemberUserScoreApi{
.build()); .build());
} }
private void saveScoreDetail(MemberUserScoreOperateReqDTO req, Long scoreLogId) { private List<ScoreDetailChangeDto> saveScoreDetail(MemberUserScoreOperateReqDTO req, Long scoreLogId) {
scoreDetailService.updateScoreDetail(MemberUserScoreDetailUpdateReqDto.builder() return scoreDetailService.updateScoreDetail(MemberUserScoreDetailUpdateReqDto.builder()
.memberId(req.getMemberId()) .memberId(req.getMemberId())
.scoreCount(req.getScoreCount()) .scoreCount(req.getScoreCount())
.operateType(req.getSourceType() == ScoreSourceTypeEnum.MANUAL_OPERATE ? .operateType(req.getSourceType() == ScoreSourceTypeEnum.MANUAL_OPERATE ?
...@@ -110,6 +175,7 @@ public class MemberUserScoreApiImpl implements MemberUserScoreApi{ ...@@ -110,6 +175,7 @@ public class MemberUserScoreApiImpl implements MemberUserScoreApi{
.sourceType(req.getSourceType()) .sourceType(req.getSourceType())
.scoreLogId(scoreLogId) .scoreLogId(scoreLogId)
.expireDays(req.getExpireDays()) .expireDays(req.getExpireDays())
.releationId(req.getReleationId())
.build()); .build());
} }
......
package cn.iocoder.yudao.module.member.controller.admin.job; package cn.iocoder.yudao.module.member.controller.admin.job;
import cn.hutool.json.JSONArray;
import cn.iocoder.yudao.framework.common.util.date.DateUtils; import cn.iocoder.yudao.framework.common.util.date.DateUtils;
import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler; import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler;
import cn.iocoder.yudao.module.member.api.score.MemberUserScoreApi; import cn.iocoder.yudao.module.member.api.score.MemberUserScoreApi;
import cn.iocoder.yudao.module.member.api.score.dto.MemberUserScoreOperateReqDTO; import cn.iocoder.yudao.module.member.api.score.dto.MemberUserScoreOperateReqDTO;
import cn.iocoder.yudao.module.member.dal.dataobject.memberUserScoreDetail.MemberUserScoreDetailDO; import cn.iocoder.yudao.module.member.dal.dataobject.scoreDetail.MemberUserScoreDetailDO;
import cn.iocoder.yudao.module.member.enums.MemberScoreStatueEnum; import cn.iocoder.yudao.module.member.enums.MemberScoreStatueEnum;
import cn.iocoder.yudao.module.member.enums.ScoreSourceTypeEnum; import cn.iocoder.yudao.module.member.enums.ScoreSourceTypeEnum;
import cn.iocoder.yudao.module.member.service.memberUserScoreDetail.MemberUserScoreDetailService; import cn.iocoder.yudao.module.member.service.scoreDetail.MemberUserScoreDetailService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.core.toolkit.Wrappers;
...@@ -46,7 +47,7 @@ public class MemberUserScoreExpireTask implements JobHandler { ...@@ -46,7 +47,7 @@ public class MemberUserScoreExpireTask implements JobHandler {
LambdaQueryWrapper<MemberUserScoreDetailDO> wrapper = Wrappers.lambdaQuery(); LambdaQueryWrapper<MemberUserScoreDetailDO> wrapper = Wrappers.lambdaQuery();
wrapper.in(MemberUserScoreDetailDO::getStatus, Lists.newArrayList(MemberScoreStatueEnum.AVAILABLE.getValue(), wrapper.in(MemberUserScoreDetailDO::getStatus, Lists.newArrayList(MemberScoreStatueEnum.AVAILABLE.getValue(),
MemberScoreStatueEnum.PART_AVAILABLE.getValue())); MemberScoreStatueEnum.PART_AVAILABLE.getValue()));
wrapper.eq(MemberUserScoreDetailDO::getExpireTime, DateUtils.getNextNDayStart(new Date(), 0)); wrapper.le(MemberUserScoreDetailDO::getExpireTime, DateUtils.getNextNDayStart(new Date(), 0));
wrapper.orderByAsc(MemberUserScoreDetailDO::getCreateTime); wrapper.orderByAsc(MemberUserScoreDetailDO::getCreateTime);
List<MemberUserScoreDetailDO> todoList = scoreDetailService.list(wrapper); List<MemberUserScoreDetailDO> todoList = scoreDetailService.list(wrapper);
log.info("member user score expire task, to expire record count :{}", todoList.size()); log.info("member user score expire task, to expire record count :{}", todoList.size());
...@@ -56,9 +57,9 @@ public class MemberUserScoreExpireTask implements JobHandler { ...@@ -56,9 +57,9 @@ public class MemberUserScoreExpireTask implements JobHandler {
for (MemberUserScoreDetailDO memberUserScoreDetailDO : todoList) { for (MemberUserScoreDetailDO memberUserScoreDetailDO : todoList) {
try { try {
log.info("score expire, score detail id :{}", memberUserScoreDetailDO.getId()); log.info("score expire, score detail id :{}", memberUserScoreDetailDO.getId());
List logIds = (List) memberUserScoreDetailDO.getExtParamByKey(MemberUserScoreDetailDO.MemberUserScoreDetailExtKey.LOG_IDS); JSONArray logIds = memberUserScoreDetailDO.getExtParamByKey(MemberUserScoreDetailDO.MemberUserScoreDetailExtKey.LOG_IDS);
Map<String, Object> extParam = new HashMap<>(); Map<String, Object> extParam = new HashMap<>();
extParam.put("scoreLogIds", logIds); extParam.put("scoreLogIds", logIds.toList(Long.class));
memberUserScoreApi.operateScore(MemberUserScoreOperateReqDTO.builder() memberUserScoreApi.operateScore(MemberUserScoreOperateReqDTO.builder()
.memberId(memberUserScoreDetailDO.getMemberId()) .memberId(memberUserScoreDetailDO.getMemberId())
.scoreCount(memberUserScoreDetailDO.getRemainCount()) .scoreCount(memberUserScoreDetailDO.getRemainCount())
......
package cn.iocoder.yudao.module.member.controller.admin.level;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.member.service.level.MemberUserLevelConfigService;
import cn.iocoder.yudao.module.member.vo.userLevel.MemberUserLevelBaseRespVO;
import cn.iocoder.yudao.module.member.vo.userLevel.MemberUserLevelReqVO;
import cn.iocoder.yudao.module.member.vo.userLevel.MemberUserLevelUpdateVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.validation.Valid;
import java.util.List;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@Validated
@RestController
@Api(tags = "管理后台 - 会员等级配置")
@RequestMapping("/member/user-level")
public class MemberUserLevelConfigController {
private final MemberUserLevelConfigService userLevelConfigService;
public MemberUserLevelConfigController(MemberUserLevelConfigService userLevelConfigService) {
this.userLevelConfigService = userLevelConfigService;
}
@PostMapping("/page")
@ApiOperation("列表")
public CommonResult<PageResult<MemberUserLevelBaseRespVO>> getLevelPage(@Valid @RequestBody MemberUserLevelReqVO query) {
return success(userLevelConfigService.getLevelPage(query));
}
@PostMapping("/delete")
@ApiOperation("删除")
public CommonResult<Boolean> delete(@Valid @RequestBody List<Long> ids) {
return success(userLevelConfigService.delete(ids));
}
@PostMapping("/add")
@ApiOperation("新增")
public CommonResult<Boolean> add(@Valid @RequestBody MemberUserLevelUpdateVO query) {
return success(userLevelConfigService.add(query));
}
@PostMapping("/update")
@ApiOperation("编辑")
public CommonResult<Boolean> update(@Valid @RequestBody MemberUserLevelUpdateVO query) {
return success(userLevelConfigService.updateLevel(query));
}
}
...@@ -110,9 +110,9 @@ public class ScoreRuleController { ...@@ -110,9 +110,9 @@ public class ScoreRuleController {
return success(true); return success(true);
} }
@GetMapping("/getWarehouseTreeRegionList") @GetMapping("/warehouse-tree-region-list")
@ApiOperation("获得目的国、目的城市、目的仓列表") @ApiOperation("获得目的国、目的城市、目的仓列表")
public CommonResult<List<WarehouseTreeRegionVO>> WarehouseTreeRegionList() { public CommonResult<List<WarehouseTreeRegionVO>> warehouseTreeRegionList() {
List<WarehouseTreeRegionVO> listIn = warehouseService.getWarehouseTreeRegionList(1); List<WarehouseTreeRegionVO> listIn = warehouseService.getWarehouseTreeRegionList(1);
List<WarehouseTreeRegionVO> listOut = warehouseService.getWarehouseTreeRegionList(2); List<WarehouseTreeRegionVO> listOut = warehouseService.getWarehouseTreeRegionList(2);
List<WarehouseTreeRegionVO> list = ListUtils.sum(listIn, listOut); List<WarehouseTreeRegionVO> list = ListUtils.sum(listIn, listOut);
......
package cn.iocoder.yudao.module.member.controller.admin.memberUserScore; package cn.iocoder.yudao.module.member.controller.admin.userScore;
import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
...@@ -7,7 +7,7 @@ import cn.iocoder.yudao.module.member.api.score.dto.MemberUserScoreBatchOperateR ...@@ -7,7 +7,7 @@ import cn.iocoder.yudao.module.member.api.score.dto.MemberUserScoreBatchOperateR
import cn.iocoder.yudao.module.member.api.score.dto.MemberUserScoreOperateRespDTO; import cn.iocoder.yudao.module.member.api.score.dto.MemberUserScoreOperateRespDTO;
import cn.iocoder.yudao.module.member.enums.ScoreOperateTypeEnum; import cn.iocoder.yudao.module.member.enums.ScoreOperateTypeEnum;
import cn.iocoder.yudao.module.member.enums.ScoreSourceTypeEnum; import cn.iocoder.yudao.module.member.enums.ScoreSourceTypeEnum;
import cn.iocoder.yudao.module.member.service.memberUserScore.MemberUserScoreService; import cn.iocoder.yudao.module.member.service.score.MemberUserScoreService;
import cn.iocoder.yudao.module.member.vo.memberUserScore.MemberUserScoreBackVO; import cn.iocoder.yudao.module.member.vo.memberUserScore.MemberUserScoreBackVO;
import cn.iocoder.yudao.module.member.vo.memberUserScore.MemberUserScoreOperateQueryVO; import cn.iocoder.yudao.module.member.vo.memberUserScore.MemberUserScoreOperateQueryVO;
import cn.iocoder.yudao.module.member.vo.memberUserScore.MemberUserScoreQueryVO; import cn.iocoder.yudao.module.member.vo.memberUserScore.MemberUserScoreQueryVO;
......
package cn.iocoder.yudao.module.member.controller.admin.memberUserScoreLog; package cn.iocoder.yudao.module.member.controller.admin.userScoreLog;
import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.member.service.memberUserScoreLog.MemberUserScoreLogService; import cn.iocoder.yudao.module.member.service.scoreLog.MemberUserScoreLogService;
import cn.iocoder.yudao.module.member.vo.memberUserScoreLog.MemberUserScoreLogBackVO; import cn.iocoder.yudao.module.member.vo.memberUserScoreLog.MemberUserScoreLogBackVO;
import cn.iocoder.yudao.module.member.vo.memberUserScoreLog.MemberUserScoreLogQueryVO; import cn.iocoder.yudao.module.member.vo.memberUserScoreLog.MemberUserScoreLogQueryVO;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
......
package cn.iocoder.yudao.module.member.dal.dataobject.level;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@TableName("member_user_level_config")
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class MemberUserLevelConfigDO extends BaseDO {
/**
* 主键
*/
@TableId
private Long id;
/**
* 名称
*/
private String name;
/**
* 积分范围 下界
*/
private Integer lowerCount;
/**
* 积分范围 上界
*/
private Integer upperCount;
/**
* 图标
*/
private String icon;
}
package cn.iocoder.yudao.module.member.dal.dataobject.memberUserScore; package cn.iocoder.yudao.module.member.dal.dataobject.score;
public class MemberUserScoreBackDO { public class MemberUserScoreBackDO {
} }
package cn.iocoder.yudao.module.member.dal.dataobject.memberUserScore; package cn.iocoder.yudao.module.member.dal.dataobject.score;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
......
package cn.iocoder.yudao.module.member.dal.dataobject.memberUserScoreDetail; package cn.iocoder.yudao.module.member.dal.dataobject.scoreDetail;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject; import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil; import cn.hutool.json.JSONUtil;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
import io.vavr.collection.List;
import lombok.*; import lombok.*;
import org.apache.commons.lang.StringUtils;
import java.util.Date; import java.util.Date;
import java.util.Map;
/** /**
* 会员积分 DO * 会员积分 DO
...@@ -55,8 +53,8 @@ public class MemberUserScoreDetailDO extends BaseDO { ...@@ -55,8 +53,8 @@ public class MemberUserScoreDetailDO extends BaseDO {
} }
public Object getExtParamByKey(MemberUserScoreDetailExtKey key) { public JSONArray getExtParamByKey(MemberUserScoreDetailExtKey key) {
JSONObject extParamJsonObject = JSONUtil.parseObj(extParam); JSONObject extParamJsonObject = JSONUtil.parseObj(extParam);
return extParamJsonObject.get(key.getKey(), List.class); return extParamJsonObject.get(key.getKey(), JSONArray.class);
} }
} }
package cn.iocoder.yudao.module.member.dal.dataobject.scoreDetailReleation;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;
/**
* 会员积分 DO
*
* @author 系统管理员
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@TableName("member_user_score_detail_releation")
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class MemberUserScoreDetailReleationDO extends BaseDO {
@TableId
private Long id;
private String releationId;
private Integer sourceType;
private Long detailId;
private Integer scoreCount;
private Integer status;
}
package cn.iocoder.yudao.module.member.dal.dataobject.memberUserScoreLog; package cn.iocoder.yudao.module.member.dal.dataobject.scoreLog;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
......
package cn.iocoder.yudao.module.member.dal.mysql.memberUserLevel;
import cn.iocoder.yudao.framework.mybatis.core.mapper.AbstractMapper;
import cn.iocoder.yudao.module.member.dal.dataobject.level.MemberUserLevelConfigDO;
import org.apache.ibatis.annotations.Mapper;
/**
* 会员等级 Mapper
* @author 系统管理员
*/
@Mapper
public interface MemberUserLevelConfigMapper extends AbstractMapper<MemberUserLevelConfigDO> {
}
package cn.iocoder.yudao.module.member.dal.mysql.memberUserScore; package cn.iocoder.yudao.module.member.dal.mysql.memberUserScore;
import cn.iocoder.yudao.framework.mybatis.core.mapper.AbstractMapper; import cn.iocoder.yudao.framework.mybatis.core.mapper.AbstractMapper;
import cn.iocoder.yudao.module.member.dal.dataobject.memberUserScore.MemberUserScoreDO; import cn.iocoder.yudao.module.member.dal.dataobject.score.MemberUserScoreDO;
import cn.iocoder.yudao.module.member.vo.memberUserScore.MemberUserScoreBackVO; import cn.iocoder.yudao.module.member.vo.memberUserScore.MemberUserScoreBackVO;
import cn.iocoder.yudao.module.member.vo.memberUserScore.MemberUserScoreQueryVO; import cn.iocoder.yudao.module.member.vo.memberUserScore.MemberUserScoreQueryVO;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
......
package cn.iocoder.yudao.module.member.dal.mysql.memberUserScoreDetail; package cn.iocoder.yudao.module.member.dal.mysql.memberUserScoreDetail;
import cn.iocoder.yudao.framework.mybatis.core.mapper.AbstractMapper; import cn.iocoder.yudao.framework.mybatis.core.mapper.AbstractMapper;
import cn.iocoder.yudao.module.member.dal.dataobject.memberUserScoreDetail.MemberUserScoreDetailDO; import cn.iocoder.yudao.module.member.dal.dataobject.scoreDetail.MemberUserScoreDetailDO;
import cn.iocoder.yudao.module.member.dal.dataobject.memberUserScoreLog.MemberUserScoreLogDO;
import cn.iocoder.yudao.module.member.vo.memberUserScoreLog.MemberUserScoreLogBackVO;
import cn.iocoder.yudao.module.member.vo.memberUserScoreLog.MemberUserScoreLogQueryVO;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Param;
import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections;
import java.util.List;
/** /**
* 会员积分详情 Mapper * 会员积分详情 Mapper
......
package cn.iocoder.yudao.module.member.dal.mysql.memberUserScoreDetailReleation;
import cn.iocoder.yudao.framework.mybatis.core.mapper.AbstractMapper;
import cn.iocoder.yudao.module.member.dal.dataobject.scoreDetailReleation.MemberUserScoreDetailReleationDO;
import org.apache.ibatis.annotations.Mapper;
/**
* 会员积分详情 Mapper
* @author 系统管理员
*/
@Mapper
public interface MemberUserScoreDetailReleationMapper extends AbstractMapper<MemberUserScoreDetailReleationDO> {
}
package cn.iocoder.yudao.module.member.dal.mysql.memberUserScoreLog; package cn.iocoder.yudao.module.member.dal.mysql.memberUserScoreLog;
import cn.iocoder.yudao.framework.mybatis.core.mapper.AbstractMapper; import cn.iocoder.yudao.framework.mybatis.core.mapper.AbstractMapper;
import cn.iocoder.yudao.module.member.dal.dataobject.memberUserScoreLog.MemberUserScoreLogDO; import cn.iocoder.yudao.module.member.dal.dataobject.scoreLog.MemberUserScoreLogDO;
import cn.iocoder.yudao.module.member.vo.memberUserScoreLog.MemberUserScoreLogBackVO; import cn.iocoder.yudao.module.member.vo.memberUserScoreLog.MemberUserScoreLogBackVO;
import cn.iocoder.yudao.module.member.vo.memberUserScoreLog.MemberUserScoreLogQueryVO; import cn.iocoder.yudao.module.member.vo.memberUserScoreLog.MemberUserScoreLogQueryVO;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
......
package cn.iocoder.yudao.module.member.dto;
import lombok.Builder;
import lombok.Data;
@Data
@Builder
public class ScoreDetailChangeDto {
private Long detailId;
private Integer scoreCount;
}
package cn.iocoder.yudao.module.member.listener;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONUtil;
import cn.iocoder.yudao.framework.apollo.core.event.export.MemberScoreDetailExpireEvent;
import cn.iocoder.yudao.module.member.api.score.MemberUserScoreApi;
import cn.iocoder.yudao.module.member.api.score.dto.MemberUserScoreOperateReqDTO;
import cn.iocoder.yudao.module.member.dal.dataobject.scoreDetail.MemberUserScoreDetailDO;
import cn.iocoder.yudao.module.member.enums.ScoreSourceTypeEnum;
import cn.iocoder.yudao.module.member.service.scoreDetail.MemberUserScoreDetailService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Component
@AllArgsConstructor
@Slf4j
public class MemberUserScoreDetailExpireListener {
@Resource
private MemberUserScoreDetailService scoreDetailService;
@Resource
private MemberUserScoreApi memberUserScoreApi;
@Async
@EventListener(MemberScoreDetailExpireEvent.class)
public void listen(MemberScoreDetailExpireEvent event) {
log.info("member user score expire listen,event:{}", JSONUtil.toJsonStr(event));
if (CollectionUtils.isEmpty(event.getDetailIds())) {
return;
}
//暂停一会确保那边事务执行完成
ThreadUtil.safeSleep(3000L);
LambdaQueryWrapper<MemberUserScoreDetailDO> wrapper = Wrappers.lambdaQuery();
wrapper.in(MemberUserScoreDetailDO::getId, event.getDetailIds());
wrapper.le(MemberUserScoreDetailDO::getExpireTime, new Date());
List<MemberUserScoreDetailDO> todoList = scoreDetailService.list(wrapper);
todoList.forEach(detail -> {
try {
log.info("score expire, score detail id :{}", detail.getId());
JSONArray jsonArray = detail.getExtParamByKey(MemberUserScoreDetailDO.MemberUserScoreDetailExtKey.LOG_IDS);
Map<String, Object> extParam = new HashMap<>();
extParam.put("scoreLogIds", jsonArray.toList(Long.class));
memberUserScoreApi.operateScore(MemberUserScoreOperateReqDTO.builder()
.memberId(detail.getMemberId())
.scoreCount(detail.getRemainCount())
.sourceType(ScoreSourceTypeEnum.SYSTEM_EXPIRED)
.extParam(extParam)
.build());
} catch (Exception e) {
log.error("member user score expire exception, data:{}", detail, e);
}
});
log.info("member user score expire listen finished");
}
}
//package cn.iocoder.yudao.module.member.listener;
//
//import cn.hutool.core.util.ArrayUtil;
//import cn.hutool.json.JSONUtil;
//import cn.iocoder.yudao.framework.apollo.core.event.OrderInShippingEvent;
//import cn.iocoder.yudao.module.member.api.score.MemberUserScoreApi;
//import cn.iocoder.yudao.module.member.api.score.dto.MemberUserScoreOperateReqDTO;
//import cn.iocoder.yudao.module.member.dal.dataobject.scoreRule.ScoreRuleDO;
//import cn.iocoder.yudao.module.member.enums.ScoreSourceTypeEnum;
//import cn.iocoder.yudao.module.member.enums.TransportTypeEnum;
//import cn.iocoder.yudao.module.member.enums.YesOrNoTypeEnum;
//import cn.iocoder.yudao.module.member.service.memberUserScoreLog.MemberUserScoreLogService;
//import cn.iocoder.yudao.module.member.service.scoreRule.ScoreRuleService;
//import cn.iocoder.yudao.module.member.vo.scoreRule.extra.ScoreRuleOrderVExtraVO;
//import cn.iocoder.yudao.module.order.dal.dataobject.order.OrderDO;
//import cn.iocoder.yudao.module.order.dal.dataobject.orderObjective.OrderObjectiveDO;
//import cn.iocoder.yudao.module.order.enums.OrderStatusEnum;
//import cn.iocoder.yudao.module.order.service.order.OrderService;
//import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
//import lombok.AllArgsConstructor;
//import lombok.extern.slf4j.Slf4j;
//import org.springframework.context.event.EventListener;
//import org.springframework.stereotype.Component;
//
//import javax.annotation.Resource;
//import java.math.BigDecimal;
//import java.math.RoundingMode;
//import java.util.Date;
//import java.util.List;
//import java.util.Objects;
//
//@Component
//@AllArgsConstructor
//@Slf4j
//public class OrderInShippingListener {
// @Resource
// private OrderService orderService;
// @Resource
// private ScoreRuleService scoreRuleService;
// @Resource
// private MemberUserScoreApi memberUserScoreApi;
// @Resource
// private MemberUserScoreLogService memberUserScoreLogService;
//
// @EventListener(OrderInShippingEvent.class)
// public void listen(OrderInShippingEvent event) {
// Long orderId = event.getOrderId();
// String orderNo = event.getOrderNo();
// OrderDO orderDO;
// if (orderId != null) {
// orderDO = orderService.getById(orderId);
// } else {
// orderDO = orderService.selectOne(new LambdaQueryWrapper<OrderDO>().eq(OrderDO::getOrderNo, orderNo).last("limit 1"));
// }
// if (Objects.isNull(orderDO)) {
// log.error("Order in shipping listening error: The order does not exist,orderId:{},orderNo:{}", orderId, orderNo);
// }
// // 目的地信息
// OrderObjectiveDO orderObjectiveDO = orderDO.getOrderObjectiveDO();
// // 订单状态应为起运
// if (!Objects.equals(orderDO.getStatus(), OrderStatusEnum.IN_SHIPPING.getValue())) {
// return;
// }
// // 判断海运空运
// Integer transportId = orderDO.getTransportId();
// ScoreRuleDO scoreRuleDO = scoreRuleService.getEnabledOrderVScoreRuleByTransportType(transportId);
// if (Objects.isNull(scoreRuleDO)) {
// log.info("No score rule match");
// return;
// }
// // 是否过期
// if (scoreRuleDO.getEndTime().after(new Date())) {
// log.info("The score rule has expired");
// return;
// }
// ScoreRuleOrderVExtraVO extraInfo = JSONUtil.toBean(scoreRuleDO.getExtra(), ScoreRuleOrderVExtraVO.class);
// // 是否首单,首单只加一次
// if (extraInfo.getFirstOrder() == YesOrNoTypeEnum.YES.ordinal()){
// Long count = orderService.selectCount(new LambdaQueryWrapper<OrderDO>().eq(OrderDO::getUserId, orderDO.getUserId()));
// if (count > 1) {
// log.info("Not first order");
// return;
// }
// }
// // 提货点是否包含
// String[] warehouseIds = extraInfo.getReceiveAddr().split(",");
// if (!ArrayUtil.contains(warehouseIds, orderObjectiveDO.getObjectiveWarehouseId().toString())) {
// return;
// }
// // 计算积分
// Integer scoreCount = 0;
// List<ScoreRuleOrderVExtraVO.OrderVRule> orderVRule = extraInfo.getOrderVRule();
// if (transportId == TransportTypeEnum.OCEAN_LCL.getValue()) {
// // 海运算重量
// BigDecimal orgVWeight = orderDO.getOrgVWeight();
// int w = orgVWeight.setScale(0, RoundingMode.HALF_UP).intValue();
// for (ScoreRuleOrderVExtraVO.OrderVRule rule : orderVRule) {
// if (rule.getLow() <= w && rule.getHigh() >= w) {
// scoreCount = rule.getScore();
// break;
// }
// }
// } else if (transportId == TransportTypeEnum.SPECIAL_LINE_AIR_FREIGHT.getValue()) {
// // 空运校验渠道
// // 渠道id
// Long channelId = orderDO.getChannelId();
// String[] channels = extraInfo.getChannel().split(",");
// if (!ArrayUtil.contains(channels, channelId.toString())) {
// return;
// }
// // 空运算体积
// BigDecimal orgWVolume = orderDO.getOrgWVolume();
// int v = orgWVolume.setScale(0, RoundingMode.HALF_UP).intValue();
// for (ScoreRuleOrderVExtraVO.OrderVRule rule : orderVRule) {
// if (rule.getLow() <= v && rule.getHigh() >= v) {
// scoreCount = rule.getScore();
// break;
// }
// }
// }
// if (scoreCount > scoreRuleDO.getGetScoreOnce()){
// scoreCount = scoreRuleDO.getGetScoreOnce();
// }
// // 校验累计最高分,查member_user_score_log
//
// // 增加积分
// // 会员id
// Long userId = orderDO.getUserId();
// memberUserScoreApi.operateScore(MemberUserScoreOperateReqDTO.builder()
// .memberId(userId)
// .scoreCount(scoreCount)
// .sourceType(ScoreSourceTypeEnum.EXCHANGE_REWARD)
// .ruleId(scoreRuleDO.getId())
// .expireDays(scoreRuleDO.getScorePeriod())
// .build()
// );
// }
//}
package cn.iocoder.yudao.module.member.service.level;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.service.IService;
import cn.iocoder.yudao.module.member.dal.dataobject.level.MemberUserLevelConfigDO;
import cn.iocoder.yudao.module.member.vo.userLevel.MemberUserLevelBaseRespVO;
import cn.iocoder.yudao.module.member.vo.userLevel.MemberUserLevelReqVO;
import cn.iocoder.yudao.module.member.vo.userLevel.MemberUserLevelUpdateVO;
import java.util.List;
/**
* 会员等级 Service 接口
*
* @author 系统管理员
*/
public interface MemberUserLevelConfigService extends IService<MemberUserLevelConfigDO> {
PageResult<MemberUserLevelBaseRespVO> getLevelPage(MemberUserLevelReqVO query);
Boolean delete(List<Long> ids);
Boolean add(MemberUserLevelUpdateVO query);
Boolean updateLevel(MemberUserLevelUpdateVO query);
}
package cn.iocoder.yudao.module.member.service.level;
import cn.hutool.core.bean.BeanUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.service.AbstractService;
import cn.iocoder.yudao.module.member.dal.dataobject.level.MemberUserLevelConfigDO;
import cn.iocoder.yudao.module.member.dal.mysql.memberUserLevel.MemberUserLevelConfigMapper;
import cn.iocoder.yudao.module.member.vo.memberUserScore.MemberUserScoreBackVO;
import cn.iocoder.yudao.module.member.vo.userLevel.MemberUserLevelBaseRespVO;
import cn.iocoder.yudao.module.member.vo.userLevel.MemberUserLevelReqVO;
import cn.iocoder.yudao.module.member.vo.userLevel.MemberUserLevelUpdateVO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import java.util.List;
import java.util.stream.Collectors;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.GET_LOCK_FAILED;
import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.LEVEL_BOUND_RANGE_CONFLICT;
import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.LEVEL_BOUND_RANGE_ERROR;
/**
* 会员积分 Service 实现类
*
* @author 系统管理员
*/
@Service
@Validated
@Lazy
public class MemberUserLevelConfigServiceImpl extends AbstractService<MemberUserLevelConfigMapper, MemberUserLevelConfigDO> implements MemberUserLevelConfigService {
private final MemberUserLevelConfigMapper memberUserLevelConfigMapper;
public MemberUserLevelConfigServiceImpl(MemberUserLevelConfigMapper memberUserLevelConfigMapper) {
this.memberUserLevelConfigMapper = memberUserLevelConfigMapper;
}
@Override
public PageResult<MemberUserLevelBaseRespVO> getLevelPage(MemberUserLevelReqVO query) {
int start = (query.getPageNo() - 1) * query.getPageSize();
int size = query.getPageSize();
LambdaQueryWrapper<MemberUserLevelConfigDO> wrapper = Wrappers.lambdaQuery();
wrapper.eq(MemberUserLevelConfigDO::getDeleted, 0);
wrapper.last(String.format("limit %s, %s", start, size));
List<MemberUserLevelConfigDO> list = this.list(wrapper);
List<MemberUserLevelBaseRespVO> result = list.stream().map(i -> BeanUtil.copyProperties(i, MemberUserLevelBaseRespVO.class)).collect(Collectors.toList());
Long total = memberUserLevelConfigMapper.selectCount();
return new PageResult<>(result, total, query.getPageSize(), query.getPageNo(), (total + query.getPageSize() - 1) / query.getPageSize());
}
@Override
public Boolean delete(List<Long> ids) {
if (CollectionUtils.isEmpty(ids)) {
return true;
}
LambdaUpdateWrapper<MemberUserLevelConfigDO> wrapper = Wrappers.lambdaUpdate();
wrapper.in(MemberUserLevelConfigDO::getId, ids);
wrapper.set(MemberUserLevelConfigDO::getDeleted, 1);
return this.update(wrapper);
}
@Override
public Boolean add(MemberUserLevelUpdateVO query) {
validate(query);
MemberUserLevelConfigDO memberUserLevelConfigDO = BeanUtil.copyProperties(query, MemberUserLevelConfigDO.class);
return this.saveOrUpdate(memberUserLevelConfigDO);
}
private void validate(MemberUserLevelUpdateVO query) {
if (query.getLowerCount() > query.getUpperCount()) {
throw exception(LEVEL_BOUND_RANGE_ERROR);
}
LambdaQueryWrapper<MemberUserLevelConfigDO> wrapper = Wrappers.lambdaQuery();
wrapper.eq(MemberUserLevelConfigDO::getDeleted, 0);
if (query.getId() != null) {
wrapper.ne(MemberUserLevelConfigDO::getId, query.getId());
}
List<MemberUserLevelConfigDO> list = this.list(wrapper);
for (MemberUserLevelConfigDO memberUserLevelConfigDO : list) {
if (query.getLowerCount() >= memberUserLevelConfigDO.getLowerCount() && query.getLowerCount() <= memberUserLevelConfigDO.getUpperCount()) {
throw exception(LEVEL_BOUND_RANGE_CONFLICT);
}
if (query.getUpperCount() >= memberUserLevelConfigDO.getLowerCount() && query.getUpperCount() <= memberUserLevelConfigDO.getUpperCount()) {
throw exception(LEVEL_BOUND_RANGE_CONFLICT);
}
}
}
@Override
public Boolean updateLevel(MemberUserLevelUpdateVO query) {
validate(query);
MemberUserLevelConfigDO memberUserLevelConfigDO = BeanUtil.copyProperties(query, MemberUserLevelConfigDO.class);
return this.saveOrUpdate(memberUserLevelConfigDO);
}
}
package cn.iocoder.yudao.module.member.service.memberUserScore; package cn.iocoder.yudao.module.member.service.score;
import java.util.*; import java.util.*;
import cn.iocoder.yudao.framework.mybatis.core.service.IService; import cn.iocoder.yudao.framework.mybatis.core.service.IService;
import cn.iocoder.yudao.module.member.api.score.dto.MemberUserScoreUpdateReqDTO; import cn.iocoder.yudao.module.member.api.score.dto.MemberUserScoreUpdateReqDTO;
import cn.iocoder.yudao.module.member.vo.memberUserScore.*; import cn.iocoder.yudao.module.member.vo.memberUserScore.*;
import cn.iocoder.yudao.module.member.dal.dataobject.memberUserScore.MemberUserScoreDO; import cn.iocoder.yudao.module.member.dal.dataobject.score.MemberUserScoreDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
/** /**
......
package cn.iocoder.yudao.module.member.service.memberUserScore; package cn.iocoder.yudao.module.member.service.score;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.service.AbstractService; import cn.iocoder.yudao.framework.mybatis.core.service.AbstractService;
import cn.iocoder.yudao.module.member.api.score.dto.MemberUserScoreUpdateReqDTO; import cn.iocoder.yudao.module.member.api.score.dto.MemberUserScoreUpdateReqDTO;
import cn.iocoder.yudao.module.member.dal.dataobject.memberUserScore.MemberUserScoreDO; import cn.iocoder.yudao.module.member.dal.dataobject.score.MemberUserScoreDO;
import cn.iocoder.yudao.module.member.dal.mysql.memberUserScore.MemberUserScoreMapper; import cn.iocoder.yudao.module.member.dal.mysql.memberUserScore.MemberUserScoreMapper;
import cn.iocoder.yudao.module.member.enums.ScoreOperateTypeEnum; import cn.iocoder.yudao.module.member.enums.ScoreOperateTypeEnum;
import cn.iocoder.yudao.module.member.enums.ScoreSourceTypeEnum; import cn.iocoder.yudao.module.member.enums.ScoreSourceTypeEnum;
...@@ -76,6 +76,15 @@ public class MemberUserScoreServiceImpl extends AbstractService<MemberUserScoreM ...@@ -76,6 +76,15 @@ public class MemberUserScoreServiceImpl extends AbstractService<MemberUserScoreM
if (memberUserScoreDO == null) { if (memberUserScoreDO == null) {
memberUserScoreDO = initMemberUserScore(query.getMemberId()); memberUserScoreDO = initMemberUserScore(query.getMemberId());
} }
// 回退流程增加积分
if (query.getSourceType().getReverseSource() != null && query.getOperateType() == ScoreOperateTypeEnum.ADD) {
// 回退流程增加积分,不仅需要新增持有积分,还需要减少使用积分
memberUserScoreDO.setHoldScore(memberUserScoreDO.getHoldScore() + query.getScoreCount());
memberUserScoreDO.setUsedScore(memberUserScoreDO.getUsedScore() - query.getScoreCount());
this.saveOrUpdate(memberUserScoreDO);
return;
}
//正常流程 增加积分 减少积分
if (query.getOperateType() == ScoreOperateTypeEnum.ADD) { if (query.getOperateType() == ScoreOperateTypeEnum.ADD) {
memberUserScoreDO.setHoldScore(memberUserScoreDO.getHoldScore() + query.getScoreCount()); memberUserScoreDO.setHoldScore(memberUserScoreDO.getHoldScore() + query.getScoreCount());
this.saveOrUpdate(memberUserScoreDO); this.saveOrUpdate(memberUserScoreDO);
......
package cn.iocoder.yudao.module.member.service.memberUserScoreDetail; package cn.iocoder.yudao.module.member.service.scoreDetail;
import cn.iocoder.yudao.framework.mybatis.core.service.IService; import cn.iocoder.yudao.framework.mybatis.core.service.IService;
import cn.iocoder.yudao.module.member.api.score.dto.MemberUserScoreDetailUpdateReqDto; import cn.iocoder.yudao.module.member.api.score.dto.MemberUserScoreDetailUpdateReqDto;
import cn.iocoder.yudao.module.member.dal.dataobject.memberUserScoreDetail.MemberUserScoreDetailDO; import cn.iocoder.yudao.module.member.dal.dataobject.scoreDetail.MemberUserScoreDetailDO;
import cn.iocoder.yudao.module.member.dto.ScoreDetailChangeDto;
import java.util.List;
/** /**
* 会员积分日志 Service 接口 * 会员积分日志 Service 接口
...@@ -11,5 +14,5 @@ import cn.iocoder.yudao.module.member.dal.dataobject.memberUserScoreDetail.Membe ...@@ -11,5 +14,5 @@ import cn.iocoder.yudao.module.member.dal.dataobject.memberUserScoreDetail.Membe
*/ */
public interface MemberUserScoreDetailService extends IService<MemberUserScoreDetailDO> { public interface MemberUserScoreDetailService extends IService<MemberUserScoreDetailDO> {
void updateScoreDetail(MemberUserScoreDetailUpdateReqDto reqDto); List<ScoreDetailChangeDto> updateScoreDetail(MemberUserScoreDetailUpdateReqDto reqDto);
} }
package cn.iocoder.yudao.module.member.service.memberUserScoreDetail; package cn.iocoder.yudao.module.member.service.scoreDetail;
import cn.hutool.core.lang.generator.SnowflakeGenerator;
import cn.hutool.json.JSONObject; import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil; import cn.hutool.json.JSONUtil;
import cn.iocoder.yudao.framework.mybatis.core.service.AbstractService; import cn.iocoder.yudao.framework.mybatis.core.service.AbstractService;
import cn.iocoder.yudao.module.member.api.score.dto.MemberUserScoreDetailUpdateReqDto; import cn.iocoder.yudao.module.member.api.score.dto.MemberUserScoreDetailUpdateReqDto;
import cn.iocoder.yudao.module.member.dal.dataobject.memberUserScoreDetail.MemberUserScoreDetailDO; import cn.iocoder.yudao.module.member.dal.dataobject.scoreDetail.MemberUserScoreDetailDO;
import cn.iocoder.yudao.module.member.dal.dataobject.scoreDetailReleation.MemberUserScoreDetailReleationDO;
import cn.iocoder.yudao.module.member.dal.mysql.memberUserScoreDetail.MemberUserScoreDetailMapper; import cn.iocoder.yudao.module.member.dal.mysql.memberUserScoreDetail.MemberUserScoreDetailMapper;
import cn.iocoder.yudao.module.member.dto.ScoreDetailChangeDto;
import cn.iocoder.yudao.module.member.enums.MemberScoreStatueEnum; import cn.iocoder.yudao.module.member.enums.MemberScoreStatueEnum;
import cn.iocoder.yudao.module.member.enums.ScoreOperateTypeEnum; import cn.iocoder.yudao.module.member.enums.ScoreOperateTypeEnum;
import cn.iocoder.yudao.module.member.service.scoreDetailReleation.MemberUserScoreDetailReleationService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import java.util.*; import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.addDays; import static cn.iocoder.yudao.framework.common.util.date.DateUtils.addDays;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.getNextNDayStart; import static cn.iocoder.yudao.framework.common.util.date.DateUtils.getNextNDayStart;
import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.MEMBER_ID_IS_NULL; import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.*;
import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.MEMBER_SCORE_NOT_ENOUGH; import static cn.iocoder.yudao.module.member.enums.MemberScoreStatueEnum.AVAILABLE;
import static cn.iocoder.yudao.module.member.enums.MemberScoreStatueEnum.PART_AVAILABLE;
/** /**
* 会员积分详情 Service 实现类 * 会员积分详情 Service 实现类
...@@ -31,62 +39,124 @@ import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.MEMBER_SCO ...@@ -31,62 +39,124 @@ import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.MEMBER_SCO
@Service @Service
@Validated @Validated
public class MemberUserScoreDetailServiceImpl extends AbstractService<MemberUserScoreDetailMapper, MemberUserScoreDetailDO> implements MemberUserScoreDetailService { public class MemberUserScoreDetailServiceImpl extends AbstractService<MemberUserScoreDetailMapper, MemberUserScoreDetailDO> implements MemberUserScoreDetailService {
@Resource @Autowired
private MemberUserScoreDetailMapper detailMapper; private MemberUserScoreDetailMapper detailMapper;
@Autowired
private MemberUserScoreDetailReleationService memberUserScoreDetailReleationService;
@Autowired
private SnowflakeGenerator snowflakeGenerator;
@Override @Override
public void updateScoreDetail(MemberUserScoreDetailUpdateReqDto reqDto) { public List<ScoreDetailChangeDto> updateScoreDetail(MemberUserScoreDetailUpdateReqDto reqDto) {
// 增加积分,只需要新增一条记录 // 增加积分,只需要新增一条记录
// 减少积分,使已有记录失效 // 减少积分,使已有记录失效
if (reqDto.getMemberId() == null) { if (reqDto.getMemberId() == null) {
throw exception(MEMBER_ID_IS_NULL); throw exception(MEMBER_ID_IS_NULL);
} }
if (reqDto.getSourceType().getReverseSource() != null && reqDto.getOperateType() == ScoreOperateTypeEnum.ADD) {
//说明是回退流程新增加分 根据releationId 和source 获取之前操作过的detail
//如果是回退流程减少积分 则走正常的扣减逻辑
return dealReverseSourceDetail(reqDto);
}
if (reqDto.getOperateType() == ScoreOperateTypeEnum.ADD) { if (reqDto.getOperateType() == ScoreOperateTypeEnum.ADD) {
update4Add(reqDto); return update4Add(reqDto);
} }
if (reqDto.getOperateType() == ScoreOperateTypeEnum.REDUCE) { if (reqDto.getOperateType() == ScoreOperateTypeEnum.REDUCE) {
update4Reduce(reqDto); return update4Reduce(reqDto);
}
return Collections.emptyList();
}
private List<ScoreDetailChangeDto> dealReverseSourceDetail(MemberUserScoreDetailUpdateReqDto reqDto) {
if (StringUtils.isBlank(reqDto.getReleationId())) {
throw exception(REVERSE_SOURCE_NO_RELEATION_ID);
}
List<MemberUserScoreDetailReleationDO> releationDOList = memberUserScoreDetailReleationService.listByReleationIdAndSource(reqDto.getReleationId(),
reqDto.getSourceType().getReverseSource().getValue());
if (reqDto.getOperateType() == ScoreOperateTypeEnum.ADD) {
//积分恢复
dealReverseSourceAdd(releationDOList, reqDto);
} }
return releationDOList.stream().map(e ->ScoreDetailChangeDto.builder().detailId(e.getDetailId()).scoreCount(e.getScoreCount()).build())
.collect(Collectors.toList());
} }
private void update4Reduce(MemberUserScoreDetailUpdateReqDto reqDto) { private void dealReverseSourceAdd(List<MemberUserScoreDetailReleationDO> releationDOList, MemberUserScoreDetailUpdateReqDto reqDto) {
Long scoreCount = detailMapper.getScoreTotalByStatus(reqDto.getMemberId(), Lists.newArrayList(MemberScoreStatueEnum.AVAILABLE.getValue(), MemberScoreStatueEnum.PART_AVAILABLE.getValue())); List<Long> detailIds = releationDOList.stream().map(MemberUserScoreDetailReleationDO::getDetailId).collect(Collectors.toList());
Map<Long, MemberUserScoreDetailReleationDO> detailIdReleationDoMap = releationDOList.stream().collect(Collectors.toMap(MemberUserScoreDetailReleationDO::getDetailId, Function.identity(), (c1, c2) -> c1));
LambdaQueryWrapper<MemberUserScoreDetailDO> wrappers = Wrappers.lambdaQuery();
wrappers.in(MemberUserScoreDetailDO::getId, detailIds);
List<MemberUserScoreDetailDO> detailDOList = this.list(wrappers);
List<MemberUserScoreDetailDO> saveDetailList = new ArrayList<>();
detailDOList.forEach(detail -> {
MemberUserScoreDetailReleationDO releationDO = detailIdReleationDoMap.get(detail.getId());
if (releationDO == null) {
return;
}
MemberUserScoreDetailDO updateData = new MemberUserScoreDetailDO();
updateData.setId(detail.getId());
updateData.setRemainCount(detail.getRemainCount() + releationDO.getScoreCount());
updateData.setStatus(Objects.equals(detail.getScoreCount(), updateData.getRemainCount()) ? AVAILABLE.getValue() : PART_AVAILABLE.getValue());
updateData.setExtParam(addScoreLogId(detail.getExtParam(), reqDto.getScoreLogId()));
saveDetailList.add(updateData);
});
this.saveOrUpdateBatch(saveDetailList);
}
private List<ScoreDetailChangeDto> update4Reduce(MemberUserScoreDetailUpdateReqDto reqDto) {
Long scoreCount = detailMapper.getScoreTotalByStatus(reqDto.getMemberId(), Lists.newArrayList(AVAILABLE.getValue(), MemberScoreStatueEnum.PART_AVAILABLE.getValue()));
if (scoreCount == null || scoreCount < reqDto.getScoreCount()) { if (scoreCount == null || scoreCount < reqDto.getScoreCount()) {
throw exception(MEMBER_SCORE_NOT_ENOUGH); throw exception(MEMBER_SCORE_NOT_ENOUGH);
} }
LambdaQueryWrapper<MemberUserScoreDetailDO> wrappers = Wrappers.lambdaQuery(); LambdaQueryWrapper<MemberUserScoreDetailDO> wrappers = Wrappers.lambdaQuery();
wrappers.eq(MemberUserScoreDetailDO::getMemberId, reqDto.getMemberId()); wrappers.eq(MemberUserScoreDetailDO::getMemberId, reqDto.getMemberId());
wrappers.in(MemberUserScoreDetailDO::getStatus, Lists.newArrayList(MemberScoreStatueEnum.AVAILABLE.getValue(), MemberScoreStatueEnum.PART_AVAILABLE.getValue())); wrappers.in(MemberUserScoreDetailDO::getStatus, Lists.newArrayList(AVAILABLE.getValue(), MemberScoreStatueEnum.PART_AVAILABLE.getValue()));
wrappers.orderByAsc(MemberUserScoreDetailDO::getExpireTime);
List<MemberUserScoreDetailDO> detailList = this.list(wrappers); List<MemberUserScoreDetailDO> detailList = this.list(wrappers);
detailList = sort(detailList);
int needCount = reqDto.getScoreCount(); int needCount = reqDto.getScoreCount();
List<MemberUserScoreDetailDO> updateDetailList = new ArrayList<>(); List<MemberUserScoreDetailDO> updateDetailList = new ArrayList<>();
List<ScoreDetailChangeDto> scoreDetailChangeDtos = new ArrayList<>();
for (MemberUserScoreDetailDO memberUserScoreDetailDO : detailList) { for (MemberUserScoreDetailDO memberUserScoreDetailDO : detailList) {
if (needCount == 0) { if (needCount <= 0) {
break; break;
} }
Integer usedScoreCount;
if (memberUserScoreDetailDO.getRemainCount() <= needCount) { if (memberUserScoreDetailDO.getRemainCount() <= needCount) {
needCount -= memberUserScoreDetailDO.getRemainCount(); usedScoreCount = memberUserScoreDetailDO.getRemainCount();
needCount -= usedScoreCount;
memberUserScoreDetailDO.setRemainCount(0); memberUserScoreDetailDO.setRemainCount(0);
memberUserScoreDetailDO.setStatus(MemberScoreStatueEnum.NOT_AVAILABLE.getValue()); memberUserScoreDetailDO.setStatus(MemberScoreStatueEnum.NOT_AVAILABLE.getValue());
memberUserScoreDetailDO.setExtParam(addScoreLogId(memberUserScoreDetailDO.getExtParam(), reqDto.getScoreLogId())); memberUserScoreDetailDO.setExtParam(addScoreLogId(memberUserScoreDetailDO.getExtParam(), reqDto.getScoreLogId()));
updateDetailList.add(memberUserScoreDetailDO); updateDetailList.add(memberUserScoreDetailDO);
} else { } else {
memberUserScoreDetailDO.setRemainCount(memberUserScoreDetailDO.getRemainCount() - needCount); usedScoreCount = needCount;
memberUserScoreDetailDO.setRemainCount(memberUserScoreDetailDO.getRemainCount() - usedScoreCount);
needCount = 0; needCount = 0;
memberUserScoreDetailDO.setStatus(MemberScoreStatueEnum.PART_AVAILABLE.getValue()); memberUserScoreDetailDO.setStatus(MemberScoreStatueEnum.PART_AVAILABLE.getValue());
memberUserScoreDetailDO.setExtParam(addScoreLogId(memberUserScoreDetailDO.getExtParam(), reqDto.getScoreLogId())); memberUserScoreDetailDO.setExtParam(addScoreLogId(memberUserScoreDetailDO.getExtParam(), reqDto.getScoreLogId()));
updateDetailList.add(memberUserScoreDetailDO); updateDetailList.add(memberUserScoreDetailDO);
} }
scoreDetailChangeDtos.add(ScoreDetailChangeDto.builder().detailId(memberUserScoreDetailDO.getId()).scoreCount(usedScoreCount).build());
} }
this.updateBatch(updateDetailList); this.updateBatch(updateDetailList);
return scoreDetailChangeDtos;
}
private List<MemberUserScoreDetailDO> sort(List<MemberUserScoreDetailDO> detailList) {
// 使用优先级 expire time asc > 没有过期时间的积分
Map<Boolean, List<MemberUserScoreDetailDO>> groupDetailMap = detailList.stream().collect(Collectors.groupingBy(e -> e.getExpireTime() != null));
List<MemberUserScoreDetailDO> expireTimeDetail = groupDetailMap.getOrDefault(true, new ArrayList<>()).stream()
.sorted(Comparator.comparing(MemberUserScoreDetailDO::getExpireTime)).collect(Collectors.toList());
expireTimeDetail.addAll(groupDetailMap.getOrDefault(false, new ArrayList<>()));
return expireTimeDetail;
} }
private void update4Add(MemberUserScoreDetailUpdateReqDto reqDto) { private List<ScoreDetailChangeDto> update4Add(MemberUserScoreDetailUpdateReqDto reqDto) {
MemberUserScoreDetailDO memberUserScoreDetailDO = new MemberUserScoreDetailDO(); MemberUserScoreDetailDO memberUserScoreDetailDO = new MemberUserScoreDetailDO();
memberUserScoreDetailDO.setId(snowflakeGenerator.next());
memberUserScoreDetailDO.setMemberId(reqDto.getMemberId()); memberUserScoreDetailDO.setMemberId(reqDto.getMemberId());
memberUserScoreDetailDO.setScoreCount(reqDto.getScoreCount()); memberUserScoreDetailDO.setScoreCount(reqDto.getScoreCount());
memberUserScoreDetailDO.setStatus(MemberScoreStatueEnum.AVAILABLE.getValue()); memberUserScoreDetailDO.setStatus(AVAILABLE.getValue());
memberUserScoreDetailDO.setRemainCount(reqDto.getScoreCount()); memberUserScoreDetailDO.setRemainCount(reqDto.getScoreCount());
memberUserScoreDetailDO.setCreateTime(new Date()); memberUserScoreDetailDO.setCreateTime(new Date());
if (reqDto.getExpireDays() != null) { if (reqDto.getExpireDays() != null) {
...@@ -96,6 +166,7 @@ public class MemberUserScoreDetailServiceImpl extends AbstractService<MemberUser ...@@ -96,6 +166,7 @@ public class MemberUserScoreDetailServiceImpl extends AbstractService<MemberUser
extParma.put(MemberUserScoreDetailDO.MemberUserScoreDetailExtKey.LOG_IDS.getKey(), Lists.newArrayList(reqDto.getScoreLogId())); extParma.put(MemberUserScoreDetailDO.MemberUserScoreDetailExtKey.LOG_IDS.getKey(), Lists.newArrayList(reqDto.getScoreLogId()));
memberUserScoreDetailDO.setExtParam(JSONUtil.toJsonStr(extParma)); memberUserScoreDetailDO.setExtParam(JSONUtil.toJsonStr(extParma));
this.saveOrUpdate(memberUserScoreDetailDO); this.saveOrUpdate(memberUserScoreDetailDO);
return Lists.newArrayList(ScoreDetailChangeDto.builder().detailId(memberUserScoreDetailDO.getId()).scoreCount(reqDto.getScoreCount()).build());
} }
private String addScoreLogId(String extParam, Long scoreLogId) { private String addScoreLogId(String extParam, Long scoreLogId) {
......
package cn.iocoder.yudao.module.member.service.scoreDetailReleation;
import cn.iocoder.yudao.framework.mybatis.core.service.IService;
import cn.iocoder.yudao.module.member.dal.dataobject.scoreDetailReleation.MemberUserScoreDetailReleationDO;
import cn.iocoder.yudao.module.member.dto.ScoreDetailChangeDto;
import cn.iocoder.yudao.module.member.enums.ScoreSourceTypeEnum;
import java.util.List;
/**
* 会员积分日志 Service 接口
*
* @author 系统管理员
*/
public interface MemberUserScoreDetailReleationService extends IService<MemberUserScoreDetailReleationDO> {
void updateReleation(String releationId, ScoreSourceTypeEnum sourceType, List<ScoreDetailChangeDto> detailInfos);
List<MemberUserScoreDetailReleationDO> listByReleationIdAndSource(String releationId, int value);
}
package cn.iocoder.yudao.module.member.service.scoreDetailReleation;
import cn.iocoder.yudao.framework.mybatis.core.service.AbstractService;
import cn.iocoder.yudao.module.member.dal.dataobject.scoreDetailReleation.MemberUserScoreDetailReleationDO;
import cn.iocoder.yudao.module.member.dal.mysql.memberUserScoreDetailReleation.MemberUserScoreDetailReleationMapper;
import cn.iocoder.yudao.module.member.dto.ScoreDetailChangeDto;
import cn.iocoder.yudao.module.member.enums.MemberScoreDetailReleationStatueEnum;
import cn.iocoder.yudao.module.member.enums.ScoreSourceTypeEnum;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
/**
* 会员积分详情 Service 实现类
*
* @author 系统管理员
*/
@Service
@Validated
public class MemberUserScoreDetailReleationServiceImpl extends AbstractService<MemberUserScoreDetailReleationMapper, MemberUserScoreDetailReleationDO> implements MemberUserScoreDetailReleationService {
@Override
public void updateReleation(String releationId, ScoreSourceTypeEnum sourceType, List<ScoreDetailChangeDto> detailInfos) {
if (StringUtils.isBlank(releationId) || CollectionUtils.isEmpty(detailInfos)) {
return;
}
if (sourceType.getReverseSource() != null) {
//回退流程, 失效掉之前的关联关系
LambdaUpdateWrapper<MemberUserScoreDetailReleationDO> updateWrapper = Wrappers.lambdaUpdate();
updateWrapper.eq(MemberUserScoreDetailReleationDO::getReleationId, releationId);
updateWrapper.eq(MemberUserScoreDetailReleationDO::getSourceType, sourceType.getReverseSource().getValue());
updateWrapper.in(MemberUserScoreDetailReleationDO::getDetailId, detailInfos.stream().map(ScoreDetailChangeDto::getDetailId).collect(Collectors.toList()));
updateWrapper.set(MemberUserScoreDetailReleationDO::getStatus, MemberScoreDetailReleationStatueEnum.NOT_AVAILABLE.getValue());
this.update(updateWrapper);
return;
}
List<MemberUserScoreDetailReleationDO> dos = detailInfos.stream().map(scoreDetailChangeDto -> {
MemberUserScoreDetailReleationDO releationDO = new MemberUserScoreDetailReleationDO();
releationDO.setReleationId(releationId);
releationDO.setSourceType(sourceType.getValue());
releationDO.setDetailId(scoreDetailChangeDto.getDetailId());
releationDO.setScoreCount(scoreDetailChangeDto.getScoreCount());
releationDO.setStatus(MemberScoreDetailReleationStatueEnum.AVAILABLE.getValue());
return releationDO;
}).collect(Collectors.toList());
this.saveOrUpdateBatch(dos);
}
@Override
public List<MemberUserScoreDetailReleationDO> listByReleationIdAndSource(String releationId, int sourceType) {
if (StringUtils.isBlank(releationId)) {
return Collections.emptyList();
}
LambdaQueryWrapper<MemberUserScoreDetailReleationDO> wrapper = Wrappers.lambdaQuery();
wrapper.eq(MemberUserScoreDetailReleationDO::getReleationId, releationId);
wrapper.eq(MemberUserScoreDetailReleationDO::getSourceType, sourceType);
wrapper.eq(MemberUserScoreDetailReleationDO::getStatus, MemberScoreDetailReleationStatueEnum.AVAILABLE.getValue());
return this.list(wrapper);
}
}
package cn.iocoder.yudao.module.member.service.memberUserScoreLog; package cn.iocoder.yudao.module.member.service.scoreLog;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.service.IService; import cn.iocoder.yudao.framework.mybatis.core.service.IService;
import cn.iocoder.yudao.module.member.dal.dataobject.memberUserScoreLog.MemberUserScoreLogDO; import cn.iocoder.yudao.module.member.dal.dataobject.scoreLog.MemberUserScoreLogDO;
import cn.iocoder.yudao.module.member.vo.memberUserScoreLog.MemberUserScoreLogBackVO; import cn.iocoder.yudao.module.member.vo.memberUserScoreLog.MemberUserScoreLogBackVO;
import cn.iocoder.yudao.module.member.vo.memberUserScoreLog.MemberUserScoreLogCreateReq; import cn.iocoder.yudao.module.member.vo.memberUserScoreLog.MemberUserScoreLogCreateReq;
import cn.iocoder.yudao.module.member.vo.memberUserScoreLog.MemberUserScoreLogQueryVO; import cn.iocoder.yudao.module.member.vo.memberUserScoreLog.MemberUserScoreLogQueryVO;
......
package cn.iocoder.yudao.module.member.service.memberUserScoreLog; package cn.iocoder.yudao.module.member.service.scoreLog;
import cn.hutool.core.lang.generator.SnowflakeGenerator; import cn.hutool.core.lang.generator.SnowflakeGenerator;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil; import cn.hutool.json.JSONUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.service.AbstractService; import cn.iocoder.yudao.framework.mybatis.core.service.AbstractService;
import cn.iocoder.yudao.module.member.dal.dataobject.memberUserScoreLog.MemberUserScoreLogDO; import cn.iocoder.yudao.module.member.dal.dataobject.scoreLog.MemberUserScoreLogDO;
import cn.iocoder.yudao.module.member.dal.mysql.memberUserScoreLog.MemberUserScoreLogMapper; import cn.iocoder.yudao.module.member.dal.mysql.memberUserScoreLog.MemberUserScoreLogMapper;
import cn.iocoder.yudao.module.member.vo.memberUserScoreLog.MemberUserScoreLogBackVO; import cn.iocoder.yudao.module.member.vo.memberUserScoreLog.MemberUserScoreLogBackVO;
import cn.iocoder.yudao.module.member.vo.memberUserScoreLog.MemberUserScoreLogCreateReq; import cn.iocoder.yudao.module.member.vo.memberUserScoreLog.MemberUserScoreLogCreateReq;
import cn.iocoder.yudao.module.member.vo.memberUserScoreLog.MemberUserScoreLogQueryVO; import cn.iocoder.yudao.module.member.vo.memberUserScoreLog.MemberUserScoreLogQueryVO;
import cn.iocoder.yudao.module.system.service.dict.DictTypeService; import cn.iocoder.yudao.module.system.service.dict.DictTypeService;
import com.alibaba.excel.util.CollectionUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.Collections;
import java.util.Date;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.MEMBER_ID_IS_NULL; import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.MEMBER_ID_IS_NULL;
......
...@@ -87,4 +87,11 @@ public interface ScoreRuleService extends IService<ScoreRuleDO> { ...@@ -87,4 +87,11 @@ public interface ScoreRuleService extends IService<ScoreRuleDO> {
* @return * @return
*/ */
void delayScoreRule(ScoreDelayReqVO scoreDelayReqVO); void delayScoreRule(ScoreDelayReqVO scoreDelayReqVO);
/**
* 根据运输方式获取已启用订单V值规则
* @param transportType
* @return
*/
ScoreRuleDO getEnabledOrderVScoreRuleByTransportType(Integer transportType);
} }
...@@ -4,6 +4,7 @@ import java.time.Instant; ...@@ -4,6 +4,7 @@ import java.time.Instant;
import java.util.*; import java.util.*;
import javax.annotation.Resource; import javax.annotation.Resource;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.json.JSONUtil; import cn.hutool.json.JSONUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQuery; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQuery;
...@@ -13,7 +14,7 @@ import cn.iocoder.yudao.module.member.dal.dataobject.scoreRule.ScoreRuleDO; ...@@ -13,7 +14,7 @@ import cn.iocoder.yudao.module.member.dal.dataobject.scoreRule.ScoreRuleDO;
import cn.iocoder.yudao.module.member.dal.mysql.scoreRule.ScoreRuleMapper; import cn.iocoder.yudao.module.member.dal.mysql.scoreRule.ScoreRuleMapper;
import cn.iocoder.yudao.module.member.enums.ScoreRuleStatusEnum; import cn.iocoder.yudao.module.member.enums.ScoreRuleStatusEnum;
import cn.iocoder.yudao.module.member.enums.ScoreRuleTypeEnum; import cn.iocoder.yudao.module.member.enums.ScoreRuleTypeEnum;
import cn.iocoder.yudao.module.member.enums.TransportType; import cn.iocoder.yudao.module.member.enums.TransportTypeEnum;
import cn.iocoder.yudao.module.member.enums.YesOrNoTypeEnum; import cn.iocoder.yudao.module.member.enums.YesOrNoTypeEnum;
import cn.iocoder.yudao.module.member.vo.scoreRule.*; import cn.iocoder.yudao.module.member.vo.scoreRule.*;
import cn.iocoder.yudao.module.member.vo.scoreRule.extra.ScoreRuleOrderVExtraVO; import cn.iocoder.yudao.module.member.vo.scoreRule.extra.ScoreRuleOrderVExtraVO;
...@@ -44,10 +45,10 @@ public class ScoreRuleServiceImpl extends AbstractService<ScoreRuleMapper, Score ...@@ -44,10 +45,10 @@ public class ScoreRuleServiceImpl extends AbstractService<ScoreRuleMapper, Score
@Override @Override
public Long createScoreRule(ScoreRuleCreateReqVO createReqVO) { public Long createScoreRule(ScoreRuleCreateReqVO createReqVO) {
ScoreRuleDO scoreRule = ScoreRuleConvert.INSTANCE.convert(createReqVO); ScoreRuleDO scoreRule = ScoreRuleConvert.INSTANCE.convert(createReqVO);
if (scoreRule.getStatus() != ScoreRuleStatusEnum.DISABLED.getValue() && scoreRule.getStatus() != ScoreRuleStatusEnum.ENABLED.getValue()){ if (scoreRule.getStatus() != ScoreRuleStatusEnum.DISABLED.getValue() && scoreRule.getStatus() != ScoreRuleStatusEnum.ENABLED.getValue()) {
throw exception(SCORE_RULE_FIELD_ERROR); throw exception(SCORE_RULE_FIELD_ERROR);
} }
verifyCommon(scoreRule); verifyCommon(createReqVO);
Integer scoreRuleType = scoreRule.getType(); Integer scoreRuleType = scoreRule.getType();
verifyAndSetExtraDO(createReqVO, scoreRuleType, scoreRule); verifyAndSetExtraDO(createReqVO, scoreRuleType, scoreRule);
scoreRuleMapper.insert(scoreRule); scoreRuleMapper.insert(scoreRule);
...@@ -55,32 +56,51 @@ public class ScoreRuleServiceImpl extends AbstractService<ScoreRuleMapper, Score ...@@ -55,32 +56,51 @@ public class ScoreRuleServiceImpl extends AbstractService<ScoreRuleMapper, Score
return scoreRule.getId(); return scoreRule.getId();
} }
private void verifyCommon(ScoreRuleDO scoreRule) { private void verifyCommon(ScoreRuleBaseVO scoreRuleIn) {
//校验公共入参 //校验公共入参
if (scoreRule.getGetScoreOnce() <= 0) { if (scoreRuleIn.getGetScoreOnce() <= 0) {
throw exception(SCORE_RULE_FIELD_ERROR); throw exception(SCORE_RULE_FIELD_ERROR);
} }
if (scoreRule.getMaxScoreTotal() <= 0) { if (scoreRuleIn.getMaxScoreTotal() <= 0) {
throw exception(SCORE_RULE_FIELD_ERROR); throw exception(SCORE_RULE_FIELD_ERROR);
} }
if (scoreRule.getStartTime().after((scoreRule.getEndTime())) || scoreRule.getEndTime().before(Date.from(Instant.now()))) { if (scoreRuleIn.getStartTime().after((scoreRuleIn.getEndTime())) || scoreRuleIn.getEndTime().before(Date.from(Instant.now()))) {
throw exception(SCORE_RULE_FIELD_ERROR); throw exception(SCORE_RULE_FIELD_ERROR);
} }
if (scoreRule.getScorePeriod() <= 0) { if (scoreRuleIn.getScorePeriod() <= 0) {
throw exception(SCORE_RULE_FIELD_ERROR); throw exception(SCORE_RULE_FIELD_ERROR);
} }
//如果是启用,校验同一个规则下,有效期内有没有重复的规则设置,分享不校验 //如果是启用,校验同一个规则下,有效期内有没有重复的规则设置,分享不校验。海运空运分开算
if (scoreRule.getStatus() == ScoreRuleStatusEnum.ENABLED.getValue() && scoreRule.getType() != ScoreRuleTypeEnum.SHARE.getValue()) { if (scoreRuleIn.getStatus() == ScoreRuleStatusEnum.ENABLED.getValue() && scoreRuleIn.getType() != ScoreRuleTypeEnum.SHARE.getValue()) {
LambdaQuery<ScoreRuleDO> scoreRuleDOLambdaQuery = new LambdaQuery<>(); LambdaQuery<ScoreRuleDO> scoreRuleDOLambdaQuery = new LambdaQuery<>();
scoreRuleDOLambdaQuery.eq(ScoreRuleDO::getStatus, ScoreRuleStatusEnum.ENABLED.getValue()) scoreRuleDOLambdaQuery.eq(ScoreRuleDO::getStatus, ScoreRuleStatusEnum.ENABLED.getValue())
.eq(ScoreRuleDO::getType, scoreRule.getType()) .eq(ScoreRuleDO::getType, scoreRuleIn.getType());
.eq(ScoreRuleDO::getStatus, ScoreRuleStatusEnum.ENABLED.getValue()); if (scoreRuleIn.getType() == ScoreRuleTypeEnum.ORDER_V.getValue()) {
ScoreRuleOrderVExtraVO extraOrderV = scoreRuleIn.getExtraOrderV();
if (extraOrderV == null) {
throw exception(SCORE_RULE_FIELD_ERROR);
}
Integer transportType = extraOrderV.getTransportType();
if (transportType != TransportTypeEnum.OCEAN_LCL.getValue() && transportType != TransportTypeEnum.SPECIAL_LINE_AIR_FREIGHT.getValue()) {
throw exception(SCORE_RULE_FIELD_ERROR);
}
List<ScoreRuleDO> scoreRuleDOS = scoreRuleMapper.selectList(scoreRuleDOLambdaQuery);
if (scoreRuleDOS != null && !scoreRuleDOS.isEmpty()) {
for (ScoreRuleDO scoreRuleDO : scoreRuleDOS) {
ScoreRuleOrderVExtraVO bean = JSONUtil.toBean(scoreRuleDO.getExtra(), ScoreRuleOrderVExtraVO.class);
if (Objects.equals(bean.getTransportType(), transportType)) {
throw exception(SCORE_RULE_FIELD_ERROR);
}
}
}
} else {
Long count = scoreRuleMapper.selectCount(scoreRuleDOLambdaQuery); Long count = scoreRuleMapper.selectCount(scoreRuleDOLambdaQuery);
if (count > 0) { if (count > 0) {
throw exception(SCORE_RULE_FIELD_ERROR); throw exception(SCORE_RULE_FIELD_ERROR);
} }
} }
} }
}
@Override @Override
...@@ -93,7 +113,7 @@ public class ScoreRuleServiceImpl extends AbstractService<ScoreRuleMapper, Score ...@@ -93,7 +113,7 @@ public class ScoreRuleServiceImpl extends AbstractService<ScoreRuleMapper, Score
throw exception(SCORE_RULE_UPDATE_ERROR); throw exception(SCORE_RULE_UPDATE_ERROR);
} }
ScoreRuleDO scoreRule = ScoreRuleConvert.INSTANCE.convert(updateReqVO); ScoreRuleDO scoreRule = ScoreRuleConvert.INSTANCE.convert(updateReqVO);
verifyCommon(scoreRule); verifyCommon(updateReqVO);
verifyAndSetExtraDO(updateReqVO, updateReqVO.getType(), scoreRule); verifyAndSetExtraDO(updateReqVO, updateReqVO.getType(), scoreRule);
// 更新 // 更新
scoreRuleMapper.updateById(scoreRule); scoreRuleMapper.updateById(scoreRule);
...@@ -115,7 +135,7 @@ public class ScoreRuleServiceImpl extends AbstractService<ScoreRuleMapper, Score ...@@ -115,7 +135,7 @@ public class ScoreRuleServiceImpl extends AbstractService<ScoreRuleMapper, Score
if (extraOrderV.getFirstOrder() != YesOrNoTypeEnum.YES.ordinal() && extraOrderV.getFirstOrder() != YesOrNoTypeEnum.NO.ordinal()) { if (extraOrderV.getFirstOrder() != YesOrNoTypeEnum.YES.ordinal() && extraOrderV.getFirstOrder() != YesOrNoTypeEnum.NO.ordinal()) {
throw exception(SCORE_RULE_FIELD_ERROR); throw exception(SCORE_RULE_FIELD_ERROR);
} }
if (extraOrderV.getTransportType() != TransportType.OCEAN_LCL.getValue() && extraOrderV.getFirstOrder() != TransportType.SPECIAL_LINE_AIR_FREIGHT.getValue()) { if (extraOrderV.getTransportType() != TransportTypeEnum.OCEAN_LCL.getValue() && extraOrderV.getTransportType() != TransportTypeEnum.SPECIAL_LINE_AIR_FREIGHT.getValue()) {
throw exception(SCORE_RULE_FIELD_ERROR); throw exception(SCORE_RULE_FIELD_ERROR);
} }
if (StringUtils.isAnyBlank(extraOrderV.getTargetCountry(), extraOrderV.getTargetCity(), extraOrderV.getReceiveAddr(), extraOrderV.getOrderEntry())) { if (StringUtils.isAnyBlank(extraOrderV.getTargetCountry(), extraOrderV.getTargetCity(), extraOrderV.getReceiveAddr(), extraOrderV.getOrderEntry())) {
...@@ -208,15 +228,13 @@ public class ScoreRuleServiceImpl extends AbstractService<ScoreRuleMapper, Score ...@@ -208,15 +228,13 @@ public class ScoreRuleServiceImpl extends AbstractService<ScoreRuleMapper, Score
@Override @Override
public List<ScoreRuleBackVO> getScoreRuleList(Collection<Long> ids) { public List<ScoreRuleBackVO> getScoreRuleList(Collection<Long> ids) {
List<ScoreRuleDO> scoreRuleDOS = scoreRuleMapper.selectBatchIds(ids); List<ScoreRuleDO> scoreRuleDOS = scoreRuleMapper.selectBatchIds(ids);
List<ScoreRuleBackVO> scoreRuleBackVOS = ScoreRuleConvert.INSTANCE.convertList(scoreRuleDOS); return ScoreRuleConvert.INSTANCE.convertList(scoreRuleDOS);
return scoreRuleBackVOS;
} }
@Override @Override
public PageResult<ScoreRuleBackVO> getScoreRulePage(ScoreRuleQueryVO query, PageVO page) { public PageResult<ScoreRuleBackVO> getScoreRulePage(ScoreRuleQueryVO query, PageVO page) {
PageResult<ScoreRuleDO> pageResult = scoreRuleMapper.selectPage(page, query); PageResult<ScoreRuleDO> pageResult = scoreRuleMapper.selectPage(page, query);
PageResult<ScoreRuleBackVO> scoreRuleBackVOPageResult = ScoreRuleConvert.INSTANCE.convertPage(pageResult); return ScoreRuleConvert.INSTANCE.convertPage(pageResult);
return scoreRuleBackVOPageResult;
} }
/** /**
...@@ -307,4 +325,23 @@ public class ScoreRuleServiceImpl extends AbstractService<ScoreRuleMapper, Score ...@@ -307,4 +325,23 @@ public class ScoreRuleServiceImpl extends AbstractService<ScoreRuleMapper, Score
upScoreRuleDO.setEndTime(delayReqVO.getEndTime()); upScoreRuleDO.setEndTime(delayReqVO.getEndTime());
scoreRuleMapper.updateById(upScoreRuleDO); scoreRuleMapper.updateById(upScoreRuleDO);
} }
@Override
public ScoreRuleDO getEnabledOrderVScoreRuleByTransportType(Integer transportType) {
if (transportType != TransportTypeEnum.OCEAN_LCL.getValue() && transportType != TransportTypeEnum.SPECIAL_LINE_AIR_FREIGHT.getValue()) {
throw exception(SCORE_RULE_FIELD_ERROR);
}
LambdaQuery<ScoreRuleDO> lambdaQuery = new LambdaQuery<>();
lambdaQuery.eq(ScoreRuleDO::getStatus, ScoreRuleStatusEnum.ENABLED.getValue())
.eq(ScoreRuleDO::getType, ScoreRuleTypeEnum.ORDER_V.getValue());
List<ScoreRuleDO> scoreRuleDOS = scoreRuleMapper.selectList(lambdaQuery);
if (!CollectionUtil.isEmpty(scoreRuleDOS)) {
for (ScoreRuleDO scoreRuleDO : scoreRuleDOS) {
if (Objects.equals(JSONUtil.toBean(scoreRuleDO.getExtra(), ScoreRuleOrderVExtraVO.class).getTransportType(), transportType)) {
return scoreRuleDO;
}
}
}
return null;
}
} }
...@@ -4,15 +4,14 @@ import cn.hutool.core.date.DateUtil; ...@@ -4,15 +4,14 @@ import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.IoUtil; import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.apollo.core.event.MemberRegEvent; import cn.iocoder.yudao.framework.apollo.core.event.MemberRegEvent;
import cn.iocoder.yudao.framework.common.util.spring.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil; import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.date.DateUtils; import cn.iocoder.yudao.framework.common.util.date.DateUtils;
import cn.iocoder.yudao.framework.common.util.spring.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.i18n.core.I18nMessage; import cn.iocoder.yudao.framework.i18n.core.I18nMessage;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils; import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils;
import cn.iocoder.yudao.framework.mybatis.core.vo.PageVO; import cn.iocoder.yudao.framework.mybatis.core.vo.PageVO;
import cn.iocoder.yudao.framework.redis.helper.RedisDistributedLock;
import cn.iocoder.yudao.framework.redis.helper.RedisHelper; import cn.iocoder.yudao.framework.redis.helper.RedisHelper;
import cn.iocoder.yudao.module.ecw.api.customer.CustomerApi; import cn.iocoder.yudao.module.ecw.api.customer.CustomerApi;
import cn.iocoder.yudao.module.ecw.api.internalMessage.ClientInternalMessageApi; import cn.iocoder.yudao.module.ecw.api.internalMessage.ClientInternalMessageApi;
...@@ -49,6 +48,8 @@ import com.baomidou.mybatisplus.core.toolkit.Wrappers; ...@@ -49,6 +48,8 @@ import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
import org.springframework.data.redis.core.script.DefaultRedisScript; import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder;
...@@ -114,8 +115,7 @@ public class MemberUserServiceImpl implements MemberUserService { ...@@ -114,8 +115,7 @@ public class MemberUserServiceImpl implements MemberUserService {
private RedisHelper redisHelper; private RedisHelper redisHelper;
@Resource @Resource
private RedisDistributedLock redisDistributedLock; private RedissonClient redissonClient;
@Override @Override
public MemberUserDO getUserByMobile(String mobile) { public MemberUserDO getUserByMobile(String mobile) {
...@@ -581,15 +581,15 @@ public class MemberUserServiceImpl implements MemberUserService { ...@@ -581,15 +581,15 @@ public class MemberUserServiceImpl implements MemberUserService {
redisScript.setScriptText(incrIfExistScript); redisScript.setScriptText(incrIfExistScript);
redisScript.setResultType(Long.class); redisScript.setResultType(Long.class);
Long nextMemberCodeNumber = redisHelper.execute4Long(redisScript, Collections.singletonList(key)); Long nextMemberCodeNumber = redisHelper.execute4Long(redisScript, Collections.singletonList(key));
if (nextMemberCodeNumber != null) { if (nextMemberCodeNumber != null) {
return MemberUserCodeUtils.generateMemberCode(nextMemberCodeNumber); return MemberUserCodeUtils.generateMemberCode(nextMemberCodeNumber);
} }
boolean lock = redisDistributedLock.lock("next:member:code:lock", 2000, 3, 500); RLock lock = redissonClient.getLock("next:member:code:lock");
if (!lock) { try {
boolean lockSuccess = lock.tryLock(2, 2, TimeUnit.SECONDS);
if (!lockSuccess) {
throw exception(GET_LOCK_FAILED); throw exception(GET_LOCK_FAILED);
} }
try {
nextMemberCodeNumber = redisHelper.execute4Long(redisScript, Collections.singletonList(key)); nextMemberCodeNumber = redisHelper.execute4Long(redisScript, Collections.singletonList(key));
if (nextMemberCodeNumber != null) { if (nextMemberCodeNumber != null) {
return MemberUserCodeUtils.generateMemberCode(nextMemberCodeNumber); return MemberUserCodeUtils.generateMemberCode(nextMemberCodeNumber);
...@@ -598,8 +598,10 @@ public class MemberUserServiceImpl implements MemberUserService { ...@@ -598,8 +598,10 @@ public class MemberUserServiceImpl implements MemberUserService {
Long memberCodeMaxNumber = MemberUserCodeUtils.getMemberCodeNumber(currentMaxMemberCode); Long memberCodeMaxNumber = MemberUserCodeUtils.getMemberCodeNumber(currentMaxMemberCode);
redisHelper.set(key, String.valueOf(memberCodeMaxNumber), 5, TimeUnit.MINUTES); redisHelper.set(key, String.valueOf(memberCodeMaxNumber), 5, TimeUnit.MINUTES);
return MemberUserCodeUtils.generateMemberCode(redisHelper.incrBy(key, 1)); return MemberUserCodeUtils.generateMemberCode(redisHelper.incrBy(key, 1));
} catch (InterruptedException e) {
throw exception(GET_LOCK_FAILED);
} finally { } finally {
redisDistributedLock.releaseLock("next:member:code:lock"); lock.unlock();
} }
} }
......
package cn.iocoder.yudao.module.member.vo.userLevel;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel("管理后台 - 会员等级查询返回 VO")
public class MemberUserLevelBaseRespVO {
@ApiModelProperty(value = "id")
private Long id;
/**
* 名称
*/
@ApiModelProperty(value = "等级名称")
private String name;
/**
* 积分范围 下界
*/
@ApiModelProperty(value = "积分范围 下界")
private Integer lowerCount;
/**
* 积分范围 上界
*/
@ApiModelProperty(value = "积分范围 上界")
private Integer upperCount;
/**
* 图标
*/
@ApiModelProperty(value = "图标")
private String icon;
}
package cn.iocoder.yudao.module.member.vo.userLevel;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* @author zhaobiyan
*/
@Data
@ApiModel("管理后台 - 会员等级配置查询 VO")
public class MemberUserLevelReqVO extends PageParam {
@ApiModelProperty(value = "id")
private Long id;
}
package cn.iocoder.yudao.module.member.vo.userLevel;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotNull;
@Data
@ApiModel("管理后台 - 会员等级编辑 VO")
public class MemberUserLevelUpdateVO {
@ApiModelProperty(value = "id")
private Long id;
/**
* 名称
*/
@ApiModelProperty(value = "等级名称")
@NotNull(message = "name is null")
private String name;
/**
* 积分范围 下界
*/
@ApiModelProperty(value = "积分范围 下界")
@NotNull(message = "lowerCount is null")
private Integer lowerCount;
/**
* 积分范围 上界
*/
@ApiModelProperty(value = "积分范围 上界")
@NotNull(message = "upperCount is null")
private Integer upperCount;
/**
* 图标
*/
@ApiModelProperty(value = "图标")
@NotNull(message = "icon is null")
private String icon;
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.iocoder.yudao.module.member.dal.mysql.memberUserLevel.MemberUserLevelConfigMapper">
</mapper>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.iocoder.yudao.module.member.dal.mysql.memberUserScoreDetailReleation.MemberUserScoreDetailReleationMapper">
</mapper>
...@@ -36,7 +36,7 @@ ...@@ -36,7 +36,7 @@
<include refid="scoreCondition"/> <include refid="scoreCondition"/>
</select> </select>
<select id="getByMemberId" <select id="getByMemberId"
resultType="cn.iocoder.yudao.module.member.dal.dataobject.memberUserScore.MemberUserScoreDO"> resultType="cn.iocoder.yudao.module.member.dal.dataobject.score.MemberUserScoreDO">
select * from member_user_score where member_id = #{memberId} and deleted = 0 select * from member_user_score where member_id = #{memberId} and deleted = 0
</select> </select>
......
...@@ -29,5 +29,6 @@ public interface ErrorCodeConstants { ...@@ -29,5 +29,6 @@ public interface ErrorCodeConstants {
ErrorCode REWARD_REDEEM_BATCH_VERIFY_ERROR = new ErrorCode(1001011021, "reward.redeem.batch.verify.error"); ErrorCode REWARD_REDEEM_BATCH_VERIFY_ERROR = new ErrorCode(1001011021, "reward.redeem.batch.verify.error");
ErrorCode REWARD_REDEEM_VERIFY_BACK_STATUS = new ErrorCode(1001011022, "reward.redeem.verify.back.status"); ErrorCode REWARD_REDEEM_VERIFY_BACK_STATUS = new ErrorCode(1001011022, "reward.redeem.verify.back.status");
ErrorCode REDEEM_IMPORT_MAX_COUNT = new ErrorCode(1001011023, "redeem.import.max.count"); ErrorCode REDEEM_IMPORT_MAX_COUNT = new ErrorCode(1001011023, "redeem.import.max.count");
ErrorCode REDEEM_CANCEL_STATUS_ERROR = new ErrorCode(1001011024, "redeem.cancel.status.error");
} }
...@@ -7,6 +7,7 @@ import cn.iocoder.yudao.module.member.api.score.MemberUserScoreApi; ...@@ -7,6 +7,7 @@ import cn.iocoder.yudao.module.member.api.score.MemberUserScoreApi;
import cn.iocoder.yudao.module.member.api.score.dto.MemberUserScoreOperateReqDTO; import cn.iocoder.yudao.module.member.api.score.dto.MemberUserScoreOperateReqDTO;
import cn.iocoder.yudao.module.member.api.user.MemberUserApi; import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
import cn.iocoder.yudao.module.member.api.user.dto.UserRespDTO; import cn.iocoder.yudao.module.member.api.user.dto.UserRespDTO;
import cn.iocoder.yudao.module.member.enums.PlatformTypeEnum;
import cn.iocoder.yudao.module.member.enums.ScoreSourceTypeEnum; import cn.iocoder.yudao.module.member.enums.ScoreSourceTypeEnum;
import cn.iocoder.yudao.module.reward.api.reward.dto.RedeemRewardReqVO; import cn.iocoder.yudao.module.reward.api.reward.dto.RedeemRewardReqVO;
import cn.iocoder.yudao.module.reward.api.reward.dto.RedeemRewardRespDTO; import cn.iocoder.yudao.module.reward.api.reward.dto.RedeemRewardRespDTO;
...@@ -16,6 +17,7 @@ import cn.iocoder.yudao.module.reward.dal.mysql.redeem.RewardRedeemMapper; ...@@ -16,6 +17,7 @@ import cn.iocoder.yudao.module.reward.dal.mysql.redeem.RewardRedeemMapper;
import cn.iocoder.yudao.module.reward.dal.mysql.reward.RewardMapper; import cn.iocoder.yudao.module.reward.dal.mysql.reward.RewardMapper;
import cn.iocoder.yudao.module.reward.enums.RewardRedeemStatusEnum; import cn.iocoder.yudao.module.reward.enums.RewardRedeemStatusEnum;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
...@@ -30,6 +32,7 @@ import static cn.iocoder.yudao.module.reward.enums.ErrorCodeConstants.*; ...@@ -30,6 +32,7 @@ import static cn.iocoder.yudao.module.reward.enums.ErrorCodeConstants.*;
@Service @Service
@Validated @Validated
@Slf4j
public class RedeemRewardApiImpl implements RedeemRewardApi { public class RedeemRewardApiImpl implements RedeemRewardApi {
@Resource @Resource
...@@ -74,12 +77,12 @@ public class RedeemRewardApiImpl implements RedeemRewardApi { ...@@ -74,12 +77,12 @@ public class RedeemRewardApiImpl implements RedeemRewardApi {
if (!lock) { if (!lock) {
throw exception(GET_LOCK_FAILED); throw exception(GET_LOCK_FAILED);
} }
// 更新礼品
redeemReward(rewardDO, redeemRewardReqVO.getRewardCount());
// 添加兑换记录 // 添加兑换记录
Long redeemId = addRedeemRecord(redeemRewardReqVO); Long redeemId = addRedeemRecord(redeemRewardReqVO, rewardDO);
// 更新会员积分 // 更新会员积分
updateMemberScore(redeemRewardReqVO, rewardDO, redeemId); updateMemberScore(redeemRewardReqVO, rewardDO, redeemId);
// 更新礼品
redeemReward(rewardDO, redeemRewardReqVO.getRewardCount());
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} finally { } finally {
...@@ -106,14 +109,16 @@ public class RedeemRewardApiImpl implements RedeemRewardApi { ...@@ -106,14 +109,16 @@ public class RedeemRewardApiImpl implements RedeemRewardApi {
.memberId(redeemRewardReqVO.getMemberId()) .memberId(redeemRewardReqVO.getMemberId())
.sourceType(ScoreSourceTypeEnum.EXCHANGE_REWARD) .sourceType(ScoreSourceTypeEnum.EXCHANGE_REWARD)
.scoreCount(redeemRewardReqVO.getRewardCount() * rewardDO.getPointsRequire()) .scoreCount(redeemRewardReqVO.getRewardCount() * rewardDO.getPointsRequire())
.releationId(String.valueOf(redeemId))
.extParam(extParam) .extParam(extParam)
.build()); .build());
} }
private Long addRedeemRecord(RedeemRewardReqVO redeemRewardReqVO) { private Long addRedeemRecord(RedeemRewardReqVO redeemRewardReqVO, RewardDO rewardDO) {
RewardRedeemDO rewardRedeemDO = BeanUtil.copyProperties(redeemRewardReqVO, RewardRedeemDO.class); RewardRedeemDO rewardRedeemDO = BeanUtil.copyProperties(redeemRewardReqVO, RewardRedeemDO.class);
rewardRedeemDO.setId(snowflakeGenerator.next()); rewardRedeemDO.setId(snowflakeGenerator.next());
rewardRedeemDO.setStatus(RewardRedeemStatusEnum.REDEEMING.getValue()); rewardRedeemDO.setStatus(RewardRedeemStatusEnum.REDEEMING.getValue());
rewardRedeemDO.setScoreCount(redeemRewardReqVO.getRewardCount()* rewardDO.getPointsRequire());
rewardRedeemMapper.insert(rewardRedeemDO); rewardRedeemMapper.insert(rewardRedeemDO);
return rewardRedeemDO.getId(); return rewardRedeemDO.getId();
} }
...@@ -135,12 +140,14 @@ public class RedeemRewardApiImpl implements RedeemRewardApi { ...@@ -135,12 +140,14 @@ public class RedeemRewardApiImpl implements RedeemRewardApi {
int totalCount = 0; int totalCount = 0;
for (RedeemRewardReqVO redeemRewardReqVO : redeemRewardReqVOList) { for (RedeemRewardReqVO redeemRewardReqVO : redeemRewardReqVOList) {
// 每个兑换VO校验一遍 // 每个兑换VO校验一遍
// 兑换方式不匹配 // 兑换方式不匹配,后台不校验
if (redeemRewardReqVO.getEntrance() != PlatformTypeEnum.BACKEND.getValue()) {
String pickMethod = rewardDO.getPickMethod(); String pickMethod = rewardDO.getPickMethod();
String[] split = pickMethod.split(","); String[] split = pickMethod.split(",");
if (!Arrays.asList(split).contains(String.valueOf(redeemRewardReqVO.getRedeemType()))) { if (!Arrays.asList(split).contains(String.valueOf(redeemRewardReqVO.getRedeemType()))) {
throw exception(REWARD_PICK_METHOD_NOT_ALLOW_CREATE); throw exception(REWARD_PICK_METHOD_NOT_ALLOW_CREATE);
} }
}
verifyMemberUser(redeemRewardReqVO, rewardDO); verifyMemberUser(redeemRewardReqVO, rewardDO);
// 记录兑换总数 // 记录兑换总数
totalCount += redeemRewardReqVO.getRewardCount(); totalCount += redeemRewardReqVO.getRewardCount();
...@@ -156,15 +163,16 @@ public class RedeemRewardApiImpl implements RedeemRewardApi { ...@@ -156,15 +163,16 @@ public class RedeemRewardApiImpl implements RedeemRewardApi {
throw exception(GET_LOCK_FAILED); throw exception(GET_LOCK_FAILED);
} }
for (RedeemRewardReqVO redeemRewardReqVO : redeemRewardReqVOList) { for (RedeemRewardReqVO redeemRewardReqVO : redeemRewardReqVOList) {
// 更新礼品
redeemReward(rewardDO, redeemRewardReqVO.getRewardCount());
// 添加兑换记录 // 添加兑换记录
Long redeemId = addRedeemRecord(redeemRewardReqVO); Long redeemId = addRedeemRecord(redeemRewardReqVO, rewardDO);
// 更新会员积分 // 更新会员积分
updateMemberScore(redeemRewardReqVO, rewardDO, redeemId); updateMemberScore(redeemRewardReqVO, rewardDO, redeemId);
// 更新礼品
redeemReward(rewardDO, redeemRewardReqVO.getRewardCount());
} }
} catch (Exception e) { } catch (Exception e) {
throw exception(REWARD_REDEEM_FAIL); log.error("redeem reward exception",e);
throw e;
} finally { } finally {
redisDistributedLock.releaseLock("reward:redeem:lock:" + rewardId); redisDistributedLock.releaseLock("reward:redeem:lock:" + rewardId);
} }
......
...@@ -84,6 +84,18 @@ public class RedeemRewardController { ...@@ -84,6 +84,18 @@ public class RedeemRewardController {
return success(rewardRedeemService.export(reqVO)); return success(rewardRedeemService.export(reqVO));
} }
@PostMapping("record/cancel/check")
@ApiOperation("撤销检查")
public CommonResult<RedeemCancelCheckRespVO> cancelCheck(@Valid @RequestBody RewardRedeemUpdateReqVO reqVO) {
return success(rewardRedeemService.cancelCheck(reqVO));
}
@PostMapping("record/cancel")
@ApiOperation("撤销")
public CommonResult<Boolean> cancel(@Valid @RequestBody RewardRedeemUpdateReqVO reqVO) {
return success(rewardRedeemService.cancel(reqVO));
}
@PostMapping("record/import/template") @PostMapping("record/import/template")
@ApiOperation("导入模板下载") @ApiOperation("导入模板下载")
public void importTemplate(HttpServletResponse response) throws IOException { public void importTemplate(HttpServletResponse response) throws IOException {
......
...@@ -33,6 +33,7 @@ public class RewardRedeemDO extends BaseDO { ...@@ -33,6 +33,7 @@ public class RewardRedeemDO extends BaseDO {
* 兑换状态 * 兑换状态
*/ */
private Integer status; private Integer status;
private Integer scoreCount;
/** /**
* 兑换数量 * 兑换数量
*/ */
......
...@@ -90,7 +90,7 @@ public class RewardRedeemRecordExportListener { ...@@ -90,7 +90,7 @@ public class RewardRedeemRecordExportListener {
exportVO.setStatus(item.getStatus()); exportVO.setStatus(item.getStatus());
exportVO.setRewardCode(item.getRewardCode()); exportVO.setRewardCode(item.getRewardCode());
exportVO.setRewardTitle(item.getRewardTitleZh()); exportVO.setRewardTitle(item.getRewardTitleZh());
exportVO.setMemberName(item.getMemberName()); exportVO.setMemberName(item.getMemberNameZh());
exportVO.setRewardCount(item.getRewardCount()); exportVO.setRewardCount(item.getRewardCount());
exportVO.setRedeemType(item.getRedeemType()); exportVO.setRedeemType(item.getRedeemType());
exportVO.setEntrance(item.getEntrance()); exportVO.setEntrance(item.getEntrance());
......
...@@ -33,4 +33,8 @@ public interface RewardRedeemService extends IService<RewardRedeemDO> { ...@@ -33,4 +33,8 @@ public interface RewardRedeemService extends IService<RewardRedeemDO> {
Integer exportCount(RewardRedeemPageReqVO request); Integer exportCount(RewardRedeemPageReqVO request);
RecordInfoImportRespVO recordImport(List<RedeemInfoImportExcelVO> dataList); RecordInfoImportRespVO recordImport(List<RedeemInfoImportExcelVO> dataList);
Boolean cancel(RewardRedeemUpdateReqVO reqVO);
RedeemCancelCheckRespVO cancelCheck(RewardRedeemUpdateReqVO reqVO);
} }
...@@ -12,6 +12,10 @@ import cn.iocoder.yudao.module.ecw.api.currency.CurrencyApi; ...@@ -12,6 +12,10 @@ import cn.iocoder.yudao.module.ecw.api.currency.CurrencyApi;
import cn.iocoder.yudao.module.ecw.api.currency.dto.CurrencyRespDTO; import cn.iocoder.yudao.module.ecw.api.currency.dto.CurrencyRespDTO;
import cn.iocoder.yudao.module.ecw.api.express.ExpressApi; import cn.iocoder.yudao.module.ecw.api.express.ExpressApi;
import cn.iocoder.yudao.module.ecw.api.express.dto.ExpressRespDTO; import cn.iocoder.yudao.module.ecw.api.express.dto.ExpressRespDTO;
import cn.iocoder.yudao.module.member.api.score.MemberUserScoreApi;
import cn.iocoder.yudao.module.member.api.score.dto.MemberUserScoreOperateReqDTO;
import cn.iocoder.yudao.module.member.api.score.dto.ReleationScoreExpireInfoDTO;
import cn.iocoder.yudao.module.member.enums.ScoreSourceTypeEnum;
import cn.iocoder.yudao.module.reward.dal.dataobject.redeem.RewardRedeemDO; import cn.iocoder.yudao.module.reward.dal.dataobject.redeem.RewardRedeemDO;
import cn.iocoder.yudao.module.reward.dal.mysql.redeem.RewardRedeemMapper; import cn.iocoder.yudao.module.reward.dal.mysql.redeem.RewardRedeemMapper;
import cn.iocoder.yudao.module.reward.dto.RewardRedeemVerifyDTO; import cn.iocoder.yudao.module.reward.dto.RewardRedeemVerifyDTO;
...@@ -29,6 +33,7 @@ import com.baomidou.mybatisplus.core.toolkit.Wrappers; ...@@ -29,6 +33,7 @@ import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.*; import java.util.*;
import java.util.function.Function; import java.util.function.Function;
...@@ -53,13 +58,15 @@ public class RewardRedeemServiceImpl extends AbstractService<RewardRedeemMapper, ...@@ -53,13 +58,15 @@ public class RewardRedeemServiceImpl extends AbstractService<RewardRedeemMapper,
private final FileMakeApi fileMakeApi; private final FileMakeApi fileMakeApi;
private final ExpressApi expressApi; private final ExpressApi expressApi;
private final CurrencyApi currencyApi; private final CurrencyApi currencyApi;
private final MemberUserScoreApi memberUserScoreApi;
public RewardRedeemServiceImpl(RewardRedeemMapper rewardRedeemMapper, FileMakeApi fileMakeApi, public RewardRedeemServiceImpl(RewardRedeemMapper rewardRedeemMapper, FileMakeApi fileMakeApi,
ExpressApi expressApi, CurrencyApi currencyApi) { ExpressApi expressApi, CurrencyApi currencyApi, MemberUserScoreApi memberUserScoreApi) {
this.rewardRedeemMapper = rewardRedeemMapper; this.rewardRedeemMapper = rewardRedeemMapper;
this.fileMakeApi = fileMakeApi; this.fileMakeApi = fileMakeApi;
this.expressApi = expressApi; this.expressApi = expressApi;
this.currencyApi = currencyApi; this.currencyApi = currencyApi;
this.memberUserScoreApi = memberUserScoreApi;
} }
@Override @Override
...@@ -237,6 +244,59 @@ public class RewardRedeemServiceImpl extends AbstractService<RewardRedeemMapper, ...@@ -237,6 +244,59 @@ public class RewardRedeemServiceImpl extends AbstractService<RewardRedeemMapper,
return RecordInfoImportRespVO.builder().build(); return RecordInfoImportRespVO.builder().build();
} }
@Override
@Transactional
public Boolean cancel(RewardRedeemUpdateReqVO reqVO) {
//取消兑换 状态改为已取消 回退扣减的积分 ,如果存在已过期的积分,则直接过期
if (reqVO.getId() == null) {
throw exception(ErrorCodeConstants.REWARD_REDEEM_NOT_EXIST);
}
RewardRedeemDO rewardRedeemDO = this.getById(reqVO.getId());
if (rewardRedeemDO == null) {
throw exception(ErrorCodeConstants.REWARD_REDEEM_NOT_EXIST);
}
if (rewardRedeemDO.getStatus() != RewardRedeemStatusEnum.REDEEMING.getValue()) {
throw exception(ErrorCodeConstants.REDEEM_CANCEL_STATUS_ERROR);
}
LambdaUpdateWrapper<RewardRedeemDO> updateWrapper = Wrappers.lambdaUpdate();
updateWrapper.eq(RewardRedeemDO::getId, reqVO.getId());
updateWrapper.eq(RewardRedeemDO::getStatus, RewardRedeemStatusEnum.REDEEMING.getValue());
updateWrapper.set(RewardRedeemDO::getStatus, RewardRedeemStatusEnum.CANCELED.getValue());
boolean updateSuccess = this.update(null, updateWrapper);
if (!updateSuccess) {
throw exception(ErrorCodeConstants.REDEEM_CANCEL_STATUS_ERROR);
}
Map<String, Object> extParam = new HashMap<>();
extParam.put("redeemId", reqVO.getId());
memberUserScoreApi.operateScore(MemberUserScoreOperateReqDTO.builder()
.memberId(rewardRedeemDO.getMemberId())
.sourceType(ScoreSourceTypeEnum.EXCHANGE_REWARD_CANCEL)
.scoreCount(rewardRedeemDO.getScoreCount())
.extParam(extParam)
.releationId(String.valueOf(reqVO.getId()))
.build());
return true;
}
@Override
public RedeemCancelCheckRespVO cancelCheck(RewardRedeemUpdateReqVO reqVO) {
if (reqVO.getId() == null) {
throw exception(ErrorCodeConstants.REWARD_REDEEM_NOT_EXIST);
}
RewardRedeemDO rewardRedeemDO = this.getById(reqVO.getId());
if (rewardRedeemDO == null) {
throw exception(ErrorCodeConstants.REWARD_REDEEM_NOT_EXIST);
}
if (rewardRedeemDO.getStatus() != RewardRedeemStatusEnum.REDEEMING.getValue()) {
throw exception(ErrorCodeConstants.REDEEM_CANCEL_STATUS_ERROR);
}
List<ReleationScoreExpireInfoDTO> scoreExpireInfo = memberUserScoreApi
.getScoreExpireInfo(String.valueOf(reqVO.getId()), ScoreSourceTypeEnum.EXCHANGE_REWARD);
int totalExpireScore = scoreExpireInfo.stream().filter(e -> e.getExpireDate() != null && e.getExpireDate().compareTo(new Date()) < 0)
.mapToInt(ReleationScoreExpireInfoDTO::getScoreCount).sum();
return RedeemCancelCheckRespVO.builder().expireCount(totalExpireScore).build();
}
private Map<String, String> validate(List<RedeemInfoImportExcelVO> dataList, Map<String, CurrencyRespDTO> titleZhCurrencyMap, private Map<String, String> validate(List<RedeemInfoImportExcelVO> dataList, Map<String, CurrencyRespDTO> titleZhCurrencyMap,
Map<String, CurrencyRespDTO> titleEnCurrencyMap, Map<String, CurrencyRespDTO> titleEnCurrencyMap,
Map<String, ExpressRespDTO> nameExpressMap) { Map<String, ExpressRespDTO> nameExpressMap) {
......
package cn.iocoder.yudao.module.reward.vo.reward;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Builder;
import lombok.Data;
@Data
@Builder
public class RedeemCancelCheckRespVO {
@ExcelProperty("过期积分数量")
private int expireCount;
}
...@@ -7,8 +7,10 @@ import lombok.Data; ...@@ -7,8 +7,10 @@ import lombok.Data;
@Data @Data
@ApiModel("管理后台 - 礼品兑换记录分页结果 VO") @ApiModel("管理后台 - 礼品兑换记录分页结果 VO")
public class RewardRedeemPageRespVO extends RewardRedeemBaseVO { public class RewardRedeemPageRespVO extends RewardRedeemBaseVO {
@ApiModelProperty(value = "会员信息") @ApiModelProperty(value = "会员名称中文")
private String memberName; private String memberNameZh;
@ApiModelProperty(value = "会员名称英文")
private String memberNameEn;
@ApiModelProperty(value = "礼品ID") @ApiModelProperty(value = "礼品ID")
private String rewardCode; private String rewardCode;
@ApiModelProperty(value = "礼品名称(中文)") @ApiModelProperty(value = "礼品名称(中文)")
......
...@@ -95,14 +95,15 @@ ...@@ -95,14 +95,15 @@
err.deleted as deleted, err.deleted as deleted,
err.verify_user as verifyUser, err.verify_user as verifyUser,
err.verify_time as verifyTime, err.verify_time as verifyTime,
mu.nickname as memberName, mu.nickname as memberNameZh,
mu.english_name as memberNameEn,
er.code as rewardCode, er.code as rewardCode,
er.title_zh as rewardTitleZh, er.title_zh as rewardTitleZh,
er.title_en as rewardTitleEn, er.title_en as rewardTitleEn,
er.title_fr as rewardTitleFr, er.title_fr as rewardTitleFr,
en.title_zh as nodeTitleZh, en.title_zh as nodeTitleZh,
en.title_en as nodeTitleEn, en.title_en as nodeTitleEn,
er.points_require*err.reward_count as totalCount, err.score_count as totalCount,
suc.username as creatorName, suc.username as creatorName,
suu.username as updaterName, suu.username as updaterName,
cc.title_zh as currencyTitleZh, cc.title_zh as currencyTitleZh,
......
...@@ -1023,3 +1023,6 @@ dict.unknown.error = Not in dict {0}: {1} ...@@ -1023,3 +1023,6 @@ dict.unknown.error = Not in dict {0}: {1}
express.not.exist = express not exist express.not.exist = express not exist
currency.not.exist = currency not exist currency.not.exist = currency not exist
date.format.error = date format error, for example : 2024-01-01 12:11:11 date.format.error = date format error, for example : 2024-01-01 12:11:11
redeem.cancel.status.error = record status must be redeeming
level.bound.range.error = upper count must greater than lower count
level.bound.range.conflict = score range exist conflict
\ No newline at end of file
...@@ -1025,3 +1025,6 @@ dict.unknown.error = \u4E0D\u5728{0}\u5B57\u5178\u4E2D: {1} ...@@ -1025,3 +1025,6 @@ dict.unknown.error = \u4E0D\u5728{0}\u5B57\u5178\u4E2D: {1}
express.not.exist = \u5FEB\u9012\u516C\u53F8\u4E0D\u5B58\u5728 express.not.exist = \u5FEB\u9012\u516C\u53F8\u4E0D\u5B58\u5728
currency.not.exist = \u5E01\u79CD\u4E0D\u5B58\u5728 currency.not.exist = \u5E01\u79CD\u4E0D\u5B58\u5728
date.format.error = \u65E5\u671F\u683C\u5F0F\u4E0D\u6B63\u786E, \u6B63\u786E\u683C\u5F0F\u53C2\u8003: 2024-01-01 12:11:11 date.format.error = \u65E5\u671F\u683C\u5F0F\u4E0D\u6B63\u786E, \u6B63\u786E\u683C\u5F0F\u53C2\u8003: 2024-01-01 12:11:11
redeem.cancel.status.error = \u5151\u6362\u4E2D\u72B6\u6001\u7684\u8BB0\u5F55\u624D\u80FD\u64A4\u9500
level.bound.range.error = \u4E0A\u754C\u6570\u503C\u5FC5\u987B\u5927\u4E8E\u4E0B\u754C\u6570\u503C
level.bound.range.conflict = \u79EF\u5206\u8303\u56F4\u5B58\u5728\u51B2\u7A81
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment