Commit ec8e84d5 authored by zhaobiyan's avatar zhaobiyan

Merge branch 'feature_member_score_zby' into feature_member_score

# Conflicts:
#	yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/enums/ErrorCodeConstants.java
#	yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/api/score/MemberUserScoreApiImpl.java
parents 87815697 3d427878
...@@ -41,4 +41,6 @@ public class MemberUserScoreBatchOperateReqDTO { ...@@ -41,4 +41,6 @@ public class MemberUserScoreBatchOperateReqDTO {
* 扩展参数 * 扩展参数
*/ */
private Map<String, Object> extParam; private Map<String, Object> extParam;
private String uniqueId;
} }
...@@ -12,6 +12,10 @@ import java.util.Map; ...@@ -12,6 +12,10 @@ import java.util.Map;
@Builder @Builder
@ToString @ToString
public class MemberUserScoreOperateReqDTO { public class MemberUserScoreOperateReqDTO {
/**
* 唯一键 增加积分时必须,做幂等判断使用
*/
private String uniqueId;
/** /**
* 会员id * 会员id
*/ */
......
...@@ -45,14 +45,20 @@ public interface ErrorCodeConstants { ...@@ -45,14 +45,20 @@ public interface ErrorCodeConstants {
ErrorCode SCORE_COUNT_ERROR = new ErrorCode(1004008002, "score.count.error"); ErrorCode SCORE_COUNT_ERROR = new ErrorCode(1004008002, "score.count.error");
ErrorCode MEMBER_SCORE_NOT_ENOUGH = new ErrorCode(1004008003, "member.score.not.enough"); ErrorCode MEMBER_SCORE_NOT_ENOUGH = new ErrorCode(1004008003, "member.score.not.enough");
ErrorCode REVERSE_SOURCE_NO_RELEATION_ID = new ErrorCode(1004008004, "reverse.source.no.releation.id");
ErrorCode SCORE_RULE_NOT_EXISTS = new ErrorCode(1004008004, "score.rule.not.exists"); ErrorCode LEVEL_BOUND_RANGE_ERROR = new ErrorCode(1004008005, "level.bound.range.error");
ErrorCode SCORE_RULE_DELETE_ERROR = new ErrorCode(1004008005, "score.rule.delete.error"); ErrorCode LEVEL_BOUND_RANGE_CONFLICT = new ErrorCode(1004008006, "level.bound.range.conflict");
ErrorCode SCORE_RULE_UPDATE_ERROR = new ErrorCode(1004008006, "score.rule.update.error"); ErrorCode SOURCE_TYPE_IS_NULL = new ErrorCode(1004008007, "source.type.is.null");
ErrorCode SCORE_RULE_FIELD_ERROR = new ErrorCode(1004008007, "score.rule.field.error"); ErrorCode SCORE_OPERATE_MUST_HAVE_UNIQUE_ID = new ErrorCode(1004008008, "score.operate.must.have.unique.id");
ErrorCode SCORE_OPERATE_IDEMPOTENT_ERROR = new ErrorCode(1004008009, "score.operate.idempotent.error");
ErrorCode REVERSE_SOURCE_NO_RELEATION_ID = new ErrorCode(1004008008, "reverse.source.no.releation.id"); ErrorCode SCORE_RULE_NOT_EXISTS = new ErrorCode(1004008010, "score.rule.not.exists");
ErrorCode LEVEL_BOUND_RANGE_ERROR = new ErrorCode(1004008009, "level.bound.range.error"); ErrorCode SCORE_RULE_DELETE_ERROR = new ErrorCode(1004008011, "score.rule.delete.error");
ErrorCode LEVEL_BOUND_RANGE_CONFLICT = new ErrorCode(1004008010, "level.bound.range.conflict"); ErrorCode SCORE_RULE_UPDATE_ERROR = new ErrorCode(1004008012, "score.rule.update.error");
ErrorCode SCORE_RULE_FIELD_ERROR = new ErrorCode(10040080013, "score.rule.field.error");
ErrorCode REVERSE_SOURCE_NO_RELEATION_ID = new ErrorCode(1004008014, "reverse.source.no.releation.id");
ErrorCode LEVEL_BOUND_RANGE_ERROR = new ErrorCode(1004008015, "level.bound.range.error");
ErrorCode LEVEL_BOUND_RANGE_CONFLICT = new ErrorCode(1004008016, "level.bound.range.conflict");
} }
...@@ -5,6 +5,7 @@ import cn.iocoder.yudao.module.member.api.score.dto.*; ...@@ -5,6 +5,7 @@ import cn.iocoder.yudao.module.member.api.score.dto.*;
import cn.iocoder.yudao.module.member.dal.dataobject.score.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.scoreDetail.MemberUserScoreDetailDO;
import cn.iocoder.yudao.module.member.dal.dataobject.scoreDetailReleation.MemberUserScoreDetailReleationDO; import cn.iocoder.yudao.module.member.dal.dataobject.scoreDetailReleation.MemberUserScoreDetailReleationDO;
import cn.iocoder.yudao.module.member.dal.dataobject.scoreLog.MemberUserScoreLogDO;
import cn.iocoder.yudao.module.member.dto.ScoreDetailChangeDto; import cn.iocoder.yudao.module.member.dto.ScoreDetailChangeDto;
import cn.iocoder.yudao.module.member.enums.MemberScoreDetailReleationStatueEnum; import cn.iocoder.yudao.module.member.enums.MemberScoreDetailReleationStatueEnum;
import cn.iocoder.yudao.module.member.enums.ScoreOperateTypeEnum; import cn.iocoder.yudao.module.member.enums.ScoreOperateTypeEnum;
...@@ -64,6 +65,16 @@ public class MemberUserScoreApiImpl implements MemberUserScoreApi { ...@@ -64,6 +65,16 @@ public class MemberUserScoreApiImpl implements MemberUserScoreApi {
if (req.getScoreCount() <= 0) { if (req.getScoreCount() <= 0) {
throw exception(SCORE_COUNT_ERROR); throw exception(SCORE_COUNT_ERROR);
} }
if (req.getSourceType() == null) {
throw exception(SOURCE_TYPE_IS_NULL);
}
if (StringUtils.isBlank(req.getUniqueId())) {
throw exception(SCORE_OPERATE_MUST_HAVE_UNIQUE_ID);
}
MemberUserScoreLogDO memberUserScoreLogDO = logService.getByUniqueId(req.getUniqueId());
if (memberUserScoreLogDO != null) {
throw exception(SCORE_OPERATE_IDEMPOTENT_ERROR);
}
String lockKey = "member:operate:score:" + req.getMemberId(); String lockKey = "member:operate:score:" + req.getMemberId();
RLock lock = redissonClient.getLock(lockKey); RLock lock = redissonClient.getLock(lockKey);
try { try {
...@@ -122,12 +133,13 @@ public class MemberUserScoreApiImpl implements MemberUserScoreApi { ...@@ -122,12 +133,13 @@ public class MemberUserScoreApiImpl implements MemberUserScoreApi {
} }
} }
return req.getMemberIds().stream().map(memberId -> operateScore(MemberUserScoreOperateReqDTO.builder() return req.getMemberIds().stream().map(memberId -> operateScore(MemberUserScoreOperateReqDTO.builder()
.memberId(memberId) .memberId(memberId)
.scoreCount(req.getScoreCount()) .scoreCount(req.getScoreCount())
.operateType(req.getOperateType()) .operateType(req.getOperateType())
.sourceType(req.getSourceType()) .sourceType(req.getSourceType())
.extParam(req.getExtParam()) .extParam(req.getExtParam())
.build())) .uniqueId(req.getUniqueId() + "_" + memberId)
.build()))
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
...@@ -188,6 +200,7 @@ public class MemberUserScoreApiImpl implements MemberUserScoreApi { ...@@ -188,6 +200,7 @@ public class MemberUserScoreApiImpl implements MemberUserScoreApi {
req.getOperateType().getValue() : req.getSourceType().getOperateType().getValue()) req.getOperateType().getValue() : req.getSourceType().getOperateType().getValue())
.sourceType(req.getSourceType().getValue()) .sourceType(req.getSourceType().getValue())
.extParam(req.getExtParam()) .extParam(req.getExtParam())
.uniqueId(req.getUniqueId())
.build()); .build());
} }
} }
...@@ -64,6 +64,7 @@ public class MemberUserScoreExpireTask implements JobHandler { ...@@ -64,6 +64,7 @@ public class MemberUserScoreExpireTask implements JobHandler {
.memberId(memberUserScoreDetailDO.getMemberId()) .memberId(memberUserScoreDetailDO.getMemberId())
.scoreCount(memberUserScoreDetailDO.getRemainCount()) .scoreCount(memberUserScoreDetailDO.getRemainCount())
.sourceType(ScoreSourceTypeEnum.SYSTEM_EXPIRED) .sourceType(ScoreSourceTypeEnum.SYSTEM_EXPIRED)
.uniqueId(ScoreSourceTypeEnum.SYSTEM_EXPIRED +"_"+ memberUserScoreDetailDO.getId() + "_" + System.currentTimeMillis())
.extParam(extParam) .extParam(extParam)
.build()); .build());
} catch (Exception e) { } catch (Exception e) {
......
...@@ -60,6 +60,7 @@ public class MemberUserScoreController { ...@@ -60,6 +60,7 @@ public class MemberUserScoreController {
.operateType(ScoreOperateTypeEnum.parseByValue(query.getOperateType())) .operateType(ScoreOperateTypeEnum.parseByValue(query.getOperateType()))
.sourceType(ScoreSourceTypeEnum.MANUAL_OPERATE) .sourceType(ScoreSourceTypeEnum.MANUAL_OPERATE)
.extParam(extParam) .extParam(extParam)
.uniqueId(ScoreSourceTypeEnum.MANUAL_OPERATE + "_" + System.currentTimeMillis())
.build()); .build());
return success(null); return success(null);
} }
......
...@@ -32,4 +32,6 @@ public class MemberUserScoreLogDO extends BaseDO { ...@@ -32,4 +32,6 @@ public class MemberUserScoreLogDO extends BaseDO {
private Long ruleId; private Long ruleId;
private String extParam = "{}"; private String extParam = "{}";
private String uniqueId;
} }
...@@ -55,6 +55,7 @@ public class MemberUserScoreDetailExpireListener { ...@@ -55,6 +55,7 @@ public class MemberUserScoreDetailExpireListener {
.memberId(detail.getMemberId()) .memberId(detail.getMemberId())
.scoreCount(detail.getRemainCount()) .scoreCount(detail.getRemainCount())
.sourceType(ScoreSourceTypeEnum.SYSTEM_EXPIRED) .sourceType(ScoreSourceTypeEnum.SYSTEM_EXPIRED)
.uniqueId(ScoreSourceTypeEnum.SYSTEM_EXPIRED +"_"+ detail.getId() + "_" + System.currentTimeMillis())
.extParam(extParam) .extParam(extParam)
.build()); .build());
} catch (Exception e) { } catch (Exception e) {
......
...@@ -17,4 +17,6 @@ public interface MemberUserScoreLogService extends IService<MemberUserScoreLogDO ...@@ -17,4 +17,6 @@ public interface MemberUserScoreLogService extends IService<MemberUserScoreLogDO
PageResult<MemberUserScoreLogBackVO> getPage(MemberUserScoreLogQueryVO query); PageResult<MemberUserScoreLogBackVO> getPage(MemberUserScoreLogQueryVO query);
Long createScoreLog(MemberUserScoreLogCreateReq createReq); Long createScoreLog(MemberUserScoreLogCreateReq createReq);
MemberUserScoreLogDO getByUniqueId(String uniqueId);
} }
...@@ -10,6 +10,8 @@ import cn.iocoder.yudao.module.member.vo.memberUserScoreLog.MemberUserScoreLogBa ...@@ -10,6 +10,8 @@ import cn.iocoder.yudao.module.member.vo.memberUserScoreLog.MemberUserScoreLogBa
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.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
...@@ -59,10 +61,18 @@ public class MemberUserScoreLogServiceImpl extends AbstractService<MemberUserSco ...@@ -59,10 +61,18 @@ public class MemberUserScoreLogServiceImpl extends AbstractService<MemberUserSco
userScoreLogDO.setOperateType(createReq.getOperateType()); userScoreLogDO.setOperateType(createReq.getOperateType());
userScoreLogDO.setSourceType(createReq.getSourceType()); userScoreLogDO.setSourceType(createReq.getSourceType());
userScoreLogDO.setRuleId(createReq.getRuleId()); userScoreLogDO.setRuleId(createReq.getRuleId());
userScoreLogDO.setUniqueId(createReq.getUniqueId());
if (createReq.getExtParam() != null) { if (createReq.getExtParam() != null) {
userScoreLogDO.setExtParam(JSONUtil.toJsonStr(createReq.getExtParam())); userScoreLogDO.setExtParam(JSONUtil.toJsonStr(createReq.getExtParam()));
} }
this.saveOrUpdate(userScoreLogDO); this.saveOrUpdate(userScoreLogDO);
return userScoreLogDO.getId(); return userScoreLogDO.getId();
} }
@Override
public MemberUserScoreLogDO getByUniqueId(String uniqueId) {
LambdaQueryWrapper<MemberUserScoreLogDO> wrapper = Wrappers.lambdaQuery();
wrapper.eq(MemberUserScoreLogDO::getUniqueId, uniqueId);
return this.selectOne(wrapper);
}
} }
...@@ -17,4 +17,5 @@ public class MemberUserScoreLogCreateReq { ...@@ -17,4 +17,5 @@ public class MemberUserScoreLogCreateReq {
private Integer sourceType; private Integer sourceType;
private Long ruleId; private Long ruleId;
private Map<String, Object> extParam; private Map<String, Object> extParam;
private String uniqueId;
} }
...@@ -116,6 +116,7 @@ public class RedeemRewardApiImpl implements RedeemRewardApi { ...@@ -116,6 +116,7 @@ public class RedeemRewardApiImpl implements RedeemRewardApi {
.sourceType(ScoreSourceTypeEnum.EXCHANGE_REWARD) .sourceType(ScoreSourceTypeEnum.EXCHANGE_REWARD)
.scoreCount(redeemRewardReqVO.getRewardCount() * rewardDO.getPointsRequire()) .scoreCount(redeemRewardReqVO.getRewardCount() * rewardDO.getPointsRequire())
.releationId(String.valueOf(redeemId)) .releationId(String.valueOf(redeemId))
.uniqueId(ScoreSourceTypeEnum.EXCHANGE_REWARD + "_" + redeemId)
.extParam(extParam) .extParam(extParam)
.build()); .build());
} }
......
...@@ -274,6 +274,7 @@ public class RewardRedeemServiceImpl extends AbstractService<RewardRedeemMapper, ...@@ -274,6 +274,7 @@ public class RewardRedeemServiceImpl extends AbstractService<RewardRedeemMapper,
.scoreCount(rewardRedeemDO.getScoreCount()) .scoreCount(rewardRedeemDO.getScoreCount())
.extParam(extParam) .extParam(extParam)
.releationId(String.valueOf(req.getId())) .releationId(String.valueOf(req.getId()))
.uniqueId(ScoreSourceTypeEnum.EXCHANGE_REWARD_CANCEL + "_" + req.getId())
.build()); .build());
return true; return true;
} }
......
...@@ -35,4 +35,7 @@ public class RewardRedeemPageRespVO extends RewardRedeemBaseVO { ...@@ -35,4 +35,7 @@ public class RewardRedeemPageRespVO extends RewardRedeemBaseVO {
private String currencyTitleEn; private String currencyTitleEn;
@ApiModelProperty(value = "快递公司名称") @ApiModelProperty(value = "快递公司名称")
private String courierCompanyName; private String courierCompanyName;
private Integer holdScore;
private Integer pointsRequire;
} }
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
left join ecw_express ee on err.courier_company = ee.id left join ecw_express ee on err.courier_company = ee.id
where 1=1 where 1=1
<include refid="pageCondition"/> <include refid="pageCondition"/>
order by er.create_time desc order by err.create_time desc
limit #{start}, #{size} limit #{start}, #{size}
</select> </select>
<select id="pageCount" resultType="java.lang.Integer"> <select id="pageCount" resultType="java.lang.Integer">
...@@ -39,10 +39,13 @@ ...@@ -39,10 +39,13 @@
</select> </select>
<select id="detail" resultType="cn.iocoder.yudao.module.reward.vo.reward.RewardRedeemPageRespVO"> <select id="detail" resultType="cn.iocoder.yudao.module.reward.vo.reward.RewardRedeemPageRespVO">
select select
mus.hold_score as holdScore,
er.points_require as pointsRequire,
<include refid="columns"/> <include refid="columns"/>
from ecw_reward_redeem err from ecw_reward_redeem err
left join ecw_reward er on err.reward_id = er.id left join ecw_reward er on err.reward_id = er.id
left join member_user mu on mu.id = err.member_id left join member_user mu on mu.id = err.member_id
left join member_user_score mus on mu.id = mus.member_id
left join ecw_node en on er.node_id = en.id left join ecw_node en on er.node_id = en.id
left join system_user suc on suc.id = er.creator left join system_user suc on suc.id = er.creator
left join system_user suu on suu.id = er.updater left join system_user suu on suu.id = er.updater
......
...@@ -1023,4 +1023,5 @@ currency.not.exist = currency not exist ...@@ -1023,4 +1023,5 @@ 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 redeem.cancel.status.error = record status must be redeeming
level.bound.range.error = upper count must greater than lower count level.bound.range.error = upper count must greater than lower count
level.bound.range.conflict = score range exist conflict level.bound.range.conflict = score range exist conflict
\ No newline at end of file score.operate.idempotent.error = idempotent key conflict
\ No newline at end of file
...@@ -1027,4 +1027,5 @@ currency.not.exist = \u5E01\u79CD\u4E0D\u5B58\u5728 ...@@ -1027,4 +1027,5 @@ 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 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.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 level.bound.range.conflict = \u79EF\u5206\u8303\u56F4\u5B58\u5728\u51B2\u7A81
\ No newline at end of file score.operate.idempotent.error = \u5E42\u7B49key\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