Commit d5638121 authored by zhaobiyan's avatar zhaobiyan

Merge branch 'feature_member_score' into dev

parents c7e283e5 fb550f73
package cn.iocoder.yudao.module.member.api;
import cn.iocoder.yudao.module.member.enums.ScoreRuleTypeEnum;
/**
* @author zhangfeng
*/
public interface ScoreProducerApi {
void sendOderMessage(ScoreRuleTypeEnum scoreRuleType, Long orderId);
void sendRecommendMessage(ScoreRuleTypeEnum scoreRuleType, Long userId);
void sendRegisterMessage(ScoreRuleTypeEnum scoreRuleType, Long userId);
}
...@@ -54,5 +54,10 @@ ...@@ -54,5 +54,10 @@
<artifactId>yudao-module-order-api</artifactId> <artifactId>yudao-module-order-api</artifactId>
<version>${revision}</version> <version>${revision}</version>
</dependency> </dependency>
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-module-customer-core</artifactId>
<version>${revision}</version>
</dependency>
</dependencies> </dependencies>
</project> </project>
package cn.iocoder.yudao.module.member.controller.admin.scoreRule; package cn.iocoder.yudao.module.member.controller.admin.scoreRule;
import cn.iocoder.yudao.framework.apollo.core.event.OrderInShippingEvent;
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.framework.excel.util.ExcelUtils; import cn.iocoder.yudao.framework.excel.util.ExcelUtils;
...@@ -8,8 +7,10 @@ import cn.iocoder.yudao.framework.mybatis.core.vo.PageVO; ...@@ -8,8 +7,10 @@ import cn.iocoder.yudao.framework.mybatis.core.vo.PageVO;
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
import cn.iocoder.yudao.module.depository.service.warehouse.WarehouseService; import cn.iocoder.yudao.module.depository.service.warehouse.WarehouseService;
import cn.iocoder.yudao.module.depository.vo.warehouse.WarehouseTreeRegionVO; import cn.iocoder.yudao.module.depository.vo.warehouse.WarehouseTreeRegionVO;
import cn.iocoder.yudao.module.member.api.ScoreProducerApi;
import cn.iocoder.yudao.module.member.convert.scoreRule.ScoreRuleConvert; import cn.iocoder.yudao.module.member.convert.scoreRule.ScoreRuleConvert;
import cn.iocoder.yudao.module.member.dal.dataobject.scoreRule.ScoreRuleDO; import cn.iocoder.yudao.module.member.dal.dataobject.scoreRule.ScoreRuleDO;
import cn.iocoder.yudao.module.member.enums.ScoreRuleTypeEnum;
import cn.iocoder.yudao.module.member.service.scoreRule.ScoreRuleService; import cn.iocoder.yudao.module.member.service.scoreRule.ScoreRuleService;
import cn.iocoder.yudao.module.member.vo.scoreRule.*; import cn.iocoder.yudao.module.member.vo.scoreRule.*;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
...@@ -45,6 +46,8 @@ public class ScoreRuleController { ...@@ -45,6 +46,8 @@ public class ScoreRuleController {
private WarehouseService warehouseService; private WarehouseService warehouseService;
@Resource @Resource
private ApplicationContext applicationContext; private ApplicationContext applicationContext;
@Resource
private ScoreProducerApi scoreProducerApi;
@PostMapping("/create") @PostMapping("/create")
@ApiOperation("创建积分规则") @ApiOperation("创建积分规则")
...@@ -93,6 +96,7 @@ public class ScoreRuleController { ...@@ -93,6 +96,7 @@ public class ScoreRuleController {
PageResult<ScoreRuleBackVO> pageResult = scoreRuleService.getScoreRulePage(query, page); PageResult<ScoreRuleBackVO> pageResult = scoreRuleService.getScoreRulePage(query, page);
return success(pageResult); return success(pageResult);
} }
@PostMapping("/status") @PostMapping("/status")
@ApiOperation("启用关闭") @ApiOperation("启用关闭")
@PreAuthorize("@ss.hasPermission('member:score-rule:update')") @PreAuthorize("@ss.hasPermission('member:score-rule:update')")
...@@ -100,12 +104,14 @@ public class ScoreRuleController { ...@@ -100,12 +104,14 @@ public class ScoreRuleController {
scoreRuleService.updateStatus(scoreRuleStatusReqVO); scoreRuleService.updateStatus(scoreRuleStatusReqVO);
return success(true); return success(true);
} }
@PostMapping("/copy") @PostMapping("/copy")
@ApiOperation("复制规则") @ApiOperation("复制规则")
@PreAuthorize("@ss.hasPermission('member:score-rule:create')") @PreAuthorize("@ss.hasPermission('member:score-rule:create')")
public CommonResult<Long> copyScoreRule(@Valid @RequestBody IdReqVo idReqVo) { public CommonResult<Long> copyScoreRule(@Valid @RequestBody IdReqVo idReqVo) {
return success(scoreRuleService.copyScoreRule(idReqVo.getId())); return success(scoreRuleService.copyScoreRule(idReqVo.getId()));
} }
@PostMapping("/delay") @PostMapping("/delay")
@ApiOperation("延期规则") @ApiOperation("延期规则")
@PreAuthorize("@ss.hasPermission('member:score-rule:update')") @PreAuthorize("@ss.hasPermission('member:score-rule:update')")
...@@ -126,12 +132,12 @@ public class ScoreRuleController { ...@@ -126,12 +132,12 @@ public class ScoreRuleController {
@GetMapping("/test-score-rule") @GetMapping("/test-score-rule")
@ApiOperation("测试订单V值触发") @ApiOperation("测试订单V值触发")
public CommonResult<Void> testScoreRule(@RequestParam Long orderId, @RequestParam String orderNo) { public CommonResult<Void> testScoreRule(@RequestParam Long orderId, @RequestParam String orderNo) {
applicationContext.publishEvent(new OrderInShippingEvent(orderId, orderNo)); //applicationContext.publishEvent(new OrderInShippingEvent(orderId, orderNo));
scoreProducerApi.sendOderMessage(ScoreRuleTypeEnum.ORDER_V, orderId);
return success(null); return success(null);
} }
@GetMapping("/export-excel") @GetMapping("/export-excel")
@ApiOperation("导出积分规则Excel") @ApiOperation("导出积分规则Excel")
@PreAuthorize("@ss.hasPermission('member:score-rule:export')") @PreAuthorize("@ss.hasPermission('member:score-rule:export')")
......
package cn.iocoder.yudao.module.member.listener; package cn.iocoder.yudao.module.member.listener;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.ArrayUtil;
import cn.hutool.json.JSONUtil; import cn.hutool.json.JSONUtil;
import cn.iocoder.boot.module.order.api.OrderApi; import cn.iocoder.boot.module.order.api.OrderApi;
...@@ -8,6 +9,8 @@ import cn.iocoder.boot.module.order.api.dto.OrderObjectiveApiDO; ...@@ -8,6 +9,8 @@ import cn.iocoder.boot.module.order.api.dto.OrderObjectiveApiDO;
import cn.iocoder.boot.module.order.api.dto.OrderRespDTO; import cn.iocoder.boot.module.order.api.dto.OrderRespDTO;
import cn.iocoder.boot.module.order.enums.OrderStatusApiEnum; import cn.iocoder.boot.module.order.enums.OrderStatusApiEnum;
import cn.iocoder.yudao.framework.apollo.core.event.OrderInShippingEvent; import cn.iocoder.yudao.framework.apollo.core.event.OrderInShippingEvent;
import cn.iocoder.yudao.module.customer.dal.dataobject.customerContacts.CustomerContactsDO;
import cn.iocoder.yudao.module.customer.service.customerContacts.CustomerContactsService;
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.scoreLog.MemberUserScoreLogDO; import cn.iocoder.yudao.module.member.dal.dataobject.scoreLog.MemberUserScoreLogDO;
...@@ -23,6 +26,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; ...@@ -23,6 +26,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
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.context.annotation.Lazy;
import org.springframework.context.event.EventListener; import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
...@@ -46,6 +50,8 @@ public class OrderInShippingListener { ...@@ -46,6 +50,8 @@ public class OrderInShippingListener {
private MemberUserScoreApi memberUserScoreApi; private MemberUserScoreApi memberUserScoreApi;
@Resource @Resource
private MemberUserScoreLogService memberUserScoreLogService; private MemberUserScoreLogService memberUserScoreLogService;
@Resource
private CustomerContactsService customerContactsService;
@EventListener(OrderInShippingEvent.class) @EventListener(OrderInShippingEvent.class)
public void listen(OrderInShippingEvent event) { public void listen(OrderInShippingEvent event) {
...@@ -107,6 +113,9 @@ public class OrderInShippingListener { ...@@ -107,6 +113,9 @@ public class OrderInShippingListener {
} }
if (scoreCount > scoreRuleDO.getGetScoreOnce()) { if (scoreCount > scoreRuleDO.getGetScoreOnce()) {
scoreCount = scoreRuleDO.getGetScoreOnce(); scoreCount = scoreRuleDO.getGetScoreOnce();
} else if (scoreCount <= 0) {
log.info("Order in shipping listener: The score count is less than or equal to 0,orderId:{}", orderId);
return;
} }
// 会员id // 会员id
...@@ -118,14 +127,27 @@ public class OrderInShippingListener { ...@@ -118,14 +127,27 @@ public class OrderInShippingListener {
return; return;
} }
String[] orderEntry = orderEntryString.split(","); String[] orderEntry = orderEntryString.split(",");
// TODO:后台下单会员获取待确认
if (userId <= 0) { if (userId <= 0) {
// 后台下单 // 后台下单
if (!ArrayUtil.contains(orderEntry, String.valueOf(PlatformTypeEnum.BACKEND.getValue()))) { if (!ArrayUtil.contains(orderEntry, String.valueOf(PlatformTypeEnum.BACKEND.getValue()))) {
log.info("Order in shipping listener: The order is placed by the background, userId:{}", userId); log.info("Order in shipping listener: The order is placed by the background, userId:{}", userId);
return; return;
} }
//userId = order.getCustomerId(); // 查询客户绑定会员
List<CustomerContactsDO> customerContacts = customerContactsService.getCustomerContactsListByCustomerId(order.getCustomerId());
if (CollectionUtil.isEmpty(customerContacts)) {
log.info("Order in shipping listener: The customer is not bound to the member, customerId:{}", order.getCustomerId());
return;
}
for (CustomerContactsDO customerContact : customerContacts) {
if (customerContact.getIsDefault() == 1 && customerContact.getUserid() != null) {
userId = customerContact.getUserid();
}
}
if (userId <= 0) {
log.info("Order in shipping listener: The customer is not have default userId, customerId:{}", order.getCustomerId());
return;
}
} else if (!ArrayUtil.contains(orderEntry, String.valueOf(PlatformTypeEnum.APP.getValue())) && !ArrayUtil.contains(orderEntry, String.valueOf(PlatformTypeEnum.WEB.getValue()))) { } else if (!ArrayUtil.contains(orderEntry, String.valueOf(PlatformTypeEnum.APP.getValue())) && !ArrayUtil.contains(orderEntry, String.valueOf(PlatformTypeEnum.WEB.getValue()))) {
log.info("Order in shipping listener: The order is placed by the app or web, userId:{}", userId); log.info("Order in shipping listener: The order is placed by the app or web, userId:{}", userId);
return; return;
...@@ -183,13 +205,13 @@ public class OrderInShippingListener { ...@@ -183,13 +205,13 @@ public class OrderInShippingListener {
private Integer computeScoreCount(BigDecimal weightOrVolume, List<ScoreRuleOrderVExtraVO.OrderVRule> orderVRules) { private Integer computeScoreCount(BigDecimal weightOrVolume, List<ScoreRuleOrderVExtraVO.OrderVRule> orderVRules) {
Integer scoreCount = 0; Integer scoreCount = 0;
int w = weightOrVolume.setScale(0, RoundingMode.HALF_UP).intValue(); int w = weightOrVolume.setScale(0, RoundingMode.HALF_UP).intValue();
ScoreRuleOrderVExtraVO.OrderVRule lastRule = orderVRules.get(orderVRules.size() - 1);
if (w >= lastRule.getHigh()) {
scoreCount = lastRule.getScore();
}
for (int i = orderVRules.size() - 1; i >= 0; i--) { for (int i = orderVRules.size() - 1; i >= 0; i--) {
ScoreRuleOrderVExtraVO.OrderVRule orderVRule = orderVRules.get(i); ScoreRuleOrderVExtraVO.OrderVRule orderVRule = orderVRules.get(i);
if (w > orderVRule.getHigh()) { if (orderVRule.getLow() <= w && orderVRule.getHigh() >= w) {
scoreCount = orderVRule.getScore();
break;
}
if (orderVRule.getLow() <= w && orderVRule.getHigh() > w) {
scoreCount = orderVRule.getScore(); scoreCount = orderVRule.getScore();
break; break;
} }
......
package cn.iocoder.yudao.module.member.mq.consumer.score;
import cn.iocoder.yudao.framework.mq.core.stream.AbstractStreamMessageListener;
import cn.iocoder.yudao.module.member.mq.consumer.score.core.ScoreRuleStrategy;
import cn.iocoder.yudao.module.member.mq.consumer.score.core.ScoreRuleStrategyFactory;
import cn.iocoder.yudao.module.member.mq.message.ScoreMessage;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
* @author zhangfeng
*/
@Component
@Slf4j
public class ScoreConsumer extends AbstractStreamMessageListener<ScoreMessage> {
@Resource
private ScoreRuleStrategyFactory strategyFactory;
@Override
public void onMessage(ScoreMessage message) {
ScoreRuleStrategy strategy = strategyFactory.getStrategy(message.getScoreRuleType());
if (strategy != null) {
strategy.addScore(message);
}
}
}
package cn.iocoder.yudao.module.member.mq.consumer.score.core;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.json.JSONUtil;
import cn.iocoder.boot.module.order.api.OrderApi;
import cn.iocoder.boot.module.order.api.dto.OrderObjectiveApiDO;
import cn.iocoder.boot.module.order.api.dto.OrderRespDTO;
import cn.iocoder.boot.module.order.enums.OrderStatusApiEnum;
import cn.iocoder.yudao.module.customer.dal.dataobject.customerContacts.CustomerContactsDO;
import cn.iocoder.yudao.module.customer.service.customerContacts.CustomerContactsService;
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.scoreLog.MemberUserScoreLogDO;
import cn.iocoder.yudao.module.member.dal.dataobject.scoreRule.ScoreRuleDO;
import cn.iocoder.yudao.module.member.enums.*;
import cn.iocoder.yudao.module.member.mq.message.ScoreMessage;
import cn.iocoder.yudao.module.member.service.scoreLog.MemberUserScoreLogService;
import cn.iocoder.yudao.module.member.service.scoreRule.ScoreRuleService;
import cn.iocoder.yudao.module.member.vo.scoreRule.extra.ScoreRuleOrderVExtraVO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Objects;
/**
* @author zhangfeng
*/
@Service
@Slf4j
public class OderVStrategy implements ScoreRuleStrategy {
@Resource
private OrderApi orderApi;
@Resource
private ScoreRuleService scoreRuleService;
@Resource
private MemberUserScoreApi memberUserScoreApi;
@Resource
private MemberUserScoreLogService memberUserScoreLogService;
@Resource
private CustomerContactsService customerContactsService;
@Override
public void addScore(ScoreMessage message) {
log.info("订单V值增加积分");
Long orderId = message.getOrderId();
OrderRespDTO order;
try {
order = orderApi.getOrder(orderId, "");
} catch (Exception e) {
log.error("Order in shipping listener: Get order error,orderId:{},orderNo:{}", orderId, "");
return;
}
if (Objects.isNull(order)) {
log.error("Order in shipping listener: The order does not exist,orderId:{}", orderId);
return;
}
// 订单状态应为起运
if (!Objects.equals(order.getStatus(), OrderStatusApiEnum.IN_SHIPPING.getValue())) {
return;
}
// 判断海运空运
Integer transportId = order.getTransportId();
ScoreRuleDO scoreRuleDO = scoreRuleService.getEnabledOrderVScoreRuleByTransportType(transportId);
if (Objects.isNull(scoreRuleDO)) {
log.info("Order in shipping listener: No score rule match");
return;
}
// 是否过期,或者活动还没开始
if (!scoreRuleDO.getEndTime().after(new Date()) || !scoreRuleDO.getStartTime().before(new Date())) {
log.info("Order in shipping listener: The score rule has expired");
return;
}
// 目的地信息
OrderObjectiveApiDO orderObjectiveDO = order.getOrderObjectiveDO();
ScoreRuleOrderVExtraVO extraInfo = JSONUtil.toBean(scoreRuleDO.getExtra(), ScoreRuleOrderVExtraVO.class);
// 提货点是否包含
String[] warehouseIds = extraInfo.getReceiveAddr().split(",");
if (!ArrayUtil.contains(warehouseIds, orderObjectiveDO.getObjectiveWarehouseId().toString())) {
return;
}
// 计算积分
List<ScoreRuleOrderVExtraVO.OrderVRule> orderVRules = extraInfo.getOrderVRule();
Integer scoreCount = 0;
if (transportId == TransportTypeEnum.OCEAN_LCL.getValue()) {
// 海运算重量
BigDecimal orgVWeight = order.getOrgVWeight();
scoreCount = computeScoreCount(orgVWeight, orderVRules);
} else if (transportId == TransportTypeEnum.SPECIAL_LINE_AIR_FREIGHT.getValue()) {
// 空运校验渠道
// 渠道id
Long channelId = order.getChannelId();
String[] channels = extraInfo.getChannel().split(",");
if (!ArrayUtil.contains(channels, channelId.toString())) {
return;
}
// 空运算体积
BigDecimal orgWVolume = order.getOrgWVolume();
scoreCount = computeScoreCount(orgWVolume, orderVRules);
}
if (scoreCount <= 0) {
log.info("Order in shipping listener: The score count is less than or equal to 0,orderId:{}", orderId);
return;
}
// 会员id
Long userId = order.getUserId();
// 订单入口
String orderEntryString = extraInfo.getOrderEntry();
if (StringUtils.isBlank(orderEntryString)) {
log.info("Order in shipping listener: orderEntry is null");
return;
}
String[] orderEntry = orderEntryString.split(",");
if (userId <= 0) {
// 后台下单
if (!ArrayUtil.contains(orderEntry, String.valueOf(PlatformTypeEnum.BACKEND.getValue()))) {
log.info("Order in shipping listener: The order is placed by the background, userId:{}", userId);
return;
}
// 查询客户绑定会员
List<CustomerContactsDO> customerContacts = customerContactsService.getCustomerContactsListByCustomerId(order.getCustomerId());
if (CollectionUtil.isEmpty(customerContacts)) {
log.info("Order in shipping listener: The customer is not bound to the member, customerId:{}", order.getCustomerId());
return;
}
for (CustomerContactsDO customerContact : customerContacts) {
if (customerContact.getIsDefault() == 1 && customerContact.getUserid() != null) {
userId = customerContact.getUserid();
}
}
if (userId <= 0) {
log.info("Order in shipping listener: The customer is not have default userId, customerId:{}", order.getCustomerId());
return;
}
} else if (!ArrayUtil.contains(orderEntry, String.valueOf(PlatformTypeEnum.APP.getValue())) && !ArrayUtil.contains(orderEntry, String.valueOf(PlatformTypeEnum.WEB.getValue()))) {
log.info("Order in shipping listener: The order is placed by the app or web, userId:{}", userId);
return;
}
// 是否首单,首单只加一次
if (extraInfo.getFirstOrder() == YesOrNoTypeEnum.YES.ordinal()) {
if (!orderApi.isFirstOrder(userId)) {
log.info("Order in shipping listener: Not first order");
return;
}
}
// 校验累计最高分
Integer userScoreTotalCount = 0;
LambdaQueryWrapper<MemberUserScoreLogDO> scoreLogQueryWrapper = new LambdaQueryWrapper<>();
scoreLogQueryWrapper.eq(MemberUserScoreLogDO::getMemberId, userId)
.eq(MemberUserScoreLogDO::getRuleId, scoreRuleDO.getId());
List<MemberUserScoreLogDO> memberUserScoreLogs = memberUserScoreLogService.selectList(scoreLogQueryWrapper);
if (CollUtil.isNotEmpty(memberUserScoreLogs)) {
for (MemberUserScoreLogDO memberUserScoreLog : memberUserScoreLogs) {
userScoreTotalCount += memberUserScoreLog.getScoreCount();
}
}
if (userScoreTotalCount >= scoreRuleDO.getMaxScoreTotal()) {
log.info("Order in shipping listener: The user has reached the maximum score,userId:{},scoreRuleId:{}", userId, scoreRuleDO.getId());
return;
}
//if (userScoreTotalCount + scoreCount > scoreRuleDO.getMaxScoreTotal()) {
// scoreCount = scoreRuleDO.getMaxScoreTotal() - userScoreTotalCount;
//}
// 增加积分
try {
HashMap<String, Object> map = new HashMap<>();
map.put("orderId", orderId);
// TODO:增加订单号和唯一键
memberUserScoreApi.operateScore(MemberUserScoreOperateReqDTO.builder()
.memberId(userId)
.scoreCount(scoreCount)
.sourceType(ScoreSourceTypeEnum.ORDER_V)
.ruleId(scoreRuleDO.getId())
.expireDays(scoreRuleDO.getScorePeriod())
.extParam(map)
.build()
);
} catch (Exception e) {
log.error("Order in shipping listener: operateScore error", e);
}
}
@Override
public ScoreRuleTypeEnum getScoreRuleType() {
return ScoreRuleTypeEnum.ORDER_V;
}
/**
* 根据规则计算获取积分
*
* @param weightOrVolume 重量或体积
* @param orderVRules 规则
* @return
*/
private Integer computeScoreCount(BigDecimal weightOrVolume, List<ScoreRuleOrderVExtraVO.OrderVRule> orderVRules) {
Integer scoreCount = 0;
int w = weightOrVolume.setScale(0, RoundingMode.HALF_UP).intValue();
ScoreRuleOrderVExtraVO.OrderVRule lastRule = orderVRules.get(orderVRules.size() - 1);
if (w >= lastRule.getHigh()) {
scoreCount = lastRule.getScore();
}
for (int i = orderVRules.size() - 1; i >= 0; i--) {
ScoreRuleOrderVExtraVO.OrderVRule orderVRule = orderVRules.get(i);
if (orderVRule.getLow() <= w && orderVRule.getHigh() >= w) {
scoreCount = orderVRule.getScore();
break;
}
}
return scoreCount;
}
}
package cn.iocoder.yudao.module.member.mq.consumer.score.core;
import cn.iocoder.yudao.module.member.enums.ScoreRuleTypeEnum;
import cn.iocoder.yudao.module.member.mq.message.ScoreMessage;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
/**
* @author zhangfeng
*/
@Service
@Slf4j
public class RecommendStrategy implements ScoreRuleStrategy{
@Override
public void addScore(ScoreMessage message) {
log.info("推荐增加积分");
}
@Override
public ScoreRuleTypeEnum getScoreRuleType() {
return ScoreRuleTypeEnum.RECOMMEND;
}
}
package cn.iocoder.yudao.module.member.mq.consumer.score.core;
import cn.iocoder.yudao.module.member.enums.ScoreRuleTypeEnum;
import cn.iocoder.yudao.module.member.mq.message.ScoreMessage;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
/**
* @author zhangfeng
*/
@Service
@Slf4j
public class RegisterStrategy implements ScoreRuleStrategy{
@Override
public void addScore(ScoreMessage message) {
log.info("注册增加积分");
}
@Override
public ScoreRuleTypeEnum getScoreRuleType() {
return ScoreRuleTypeEnum.REGISTER;
}
}
package cn.iocoder.yudao.module.member.mq.consumer.score.core;
import cn.iocoder.yudao.module.member.enums.ScoreRuleTypeEnum;
import cn.iocoder.yudao.module.member.mq.message.ScoreMessage;
/**
* @author zhangfeng
*/
public interface ScoreRuleStrategy {
void addScore(ScoreMessage message);
ScoreRuleTypeEnum getScoreRuleType();
}
package cn.iocoder.yudao.module.member.mq.consumer.score.core;
import cn.iocoder.yudao.module.member.enums.ScoreRuleTypeEnum;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author zhangfeng
*/
@Component
public class ScoreRuleStrategyFactory {
private final Map<ScoreRuleTypeEnum, ScoreRuleStrategy> strategies = new HashMap<>();
@Autowired
public void setStrategyFactory(List<ScoreRuleStrategy> strategyList) {
for (ScoreRuleStrategy strategy : strategyList) {
strategies.put(strategy.getScoreRuleType(), strategy);
}
}
public ScoreRuleStrategy getStrategy(ScoreRuleTypeEnum scoreRuleType) {
return strategies.get(scoreRuleType);
}
}
package cn.iocoder.yudao.module.member.mq.message;
import cn.iocoder.yudao.framework.mq.core.stream.AbstractStreamMessage;
import cn.iocoder.yudao.module.member.enums.ScoreRuleTypeEnum;
import lombok.*;
/**
* @author zhangfeng
*/
@Data
@EqualsAndHashCode(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ScoreMessage extends AbstractStreamMessage {
private ScoreRuleTypeEnum scoreRuleType;
private Long orderId;
@Override
public String getStreamKey() {
return "member.score.add";
}
}
package cn.iocoder.yudao.module.member.mq.producer.score;
import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate;
import cn.iocoder.yudao.module.member.api.ScoreProducerApi;
import cn.iocoder.yudao.module.member.enums.ScoreRuleTypeEnum;
import cn.iocoder.yudao.module.member.mq.message.ScoreMessage;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
* @author zhangfeng
*/
@Slf4j
@Component
public class ScoreProducer implements ScoreProducerApi {
@Resource
private RedisMQTemplate redisMQTemplate;
@Override
public void sendOderMessage(ScoreRuleTypeEnum scoreRuleType, Long orderId) {
ScoreMessage message = ScoreMessage.builder()
.scoreRuleType(scoreRuleType)
.orderId(orderId)
.build();
redisMQTemplate.send(message);
}
@Override
public void sendRecommendMessage(ScoreRuleTypeEnum scoreRuleType, Long userId) {
}
@Override
public void sendRegisterMessage(ScoreRuleTypeEnum scoreRuleType, Long userId) {
}
}
...@@ -58,10 +58,10 @@ public class ScoreRuleServiceImpl extends AbstractService<ScoreRuleMapper, Score ...@@ -58,10 +58,10 @@ public class ScoreRuleServiceImpl extends AbstractService<ScoreRuleMapper, Score
private void verifyCommon(ScoreRuleBaseVO scoreRuleIn) { private void verifyCommon(ScoreRuleBaseVO scoreRuleIn) {
//校验公共入参 //校验公共入参
if (scoreRuleIn.getGetScoreOnce() <= 0) { if (scoreRuleIn.getType() != ScoreRuleTypeEnum.ORDER_V.getValue() && scoreRuleIn.getGetScoreOnce() <= 0) {
throw exception(SCORE_RULE_FIELD_ERROR); throw exception(SCORE_RULE_FIELD_ERROR);
} }
if (scoreRuleIn.getMaxScoreTotal() <= 0) { if (scoreRuleIn.getType() != ScoreRuleTypeEnum.RECOMMEND.getValue() && scoreRuleIn.getMaxScoreTotal() <= 0) {
throw exception(SCORE_RULE_FIELD_ERROR); throw exception(SCORE_RULE_FIELD_ERROR);
} }
if (scoreRuleIn.getStartTime().after((scoreRuleIn.getEndTime())) || scoreRuleIn.getEndTime().before(Date.from(Instant.now()))) { if (scoreRuleIn.getStartTime().after((scoreRuleIn.getEndTime())) || scoreRuleIn.getEndTime().before(Date.from(Instant.now()))) {
......
...@@ -45,12 +45,11 @@ public class ScoreRuleBaseVO { ...@@ -45,12 +45,11 @@ public class ScoreRuleBaseVO {
@ApiModelProperty(value = "封面图英文") @ApiModelProperty(value = "封面图英文")
private String coverImageEn; private String coverImageEn;
@ApiModelProperty(value = "单次获取积分数,订单V值中代表单次最高获取积分数", required = true) @ApiModelProperty(value = "单次获取积分数(订单V值不传)", required = true)
@NotNull(message = "单次获取积分数不能为空") private Integer getScoreOnce = 0;
private Integer getScoreOnce;
@ApiModelProperty(value = "累积最高积分(注册直接传null)", required = true) @ApiModelProperty(value = "累积最高积分(注册不传)", required = true)
private Integer maxScoreTotal; private Integer maxScoreTotal = 0;
@ApiModelProperty(value = "活动开始时间", required = true) @ApiModelProperty(value = "活动开始时间", required = true)
@NotNull(message = "活动开始时间不能为空") @NotNull(message = "活动开始时间不能为空")
......
...@@ -86,14 +86,14 @@ public class RedeemRewardController { ...@@ -86,14 +86,14 @@ public class RedeemRewardController {
@PostMapping("record/cancel/check") @PostMapping("record/cancel/check")
@ApiOperation("撤销检查") @ApiOperation("撤销检查")
public CommonResult<RedeemCancelCheckRespVO> cancelCheck(@Valid @RequestBody RewardRedeemUpdateReqVO reqVO) { public CommonResult<RedeemCancelCheckRespVO> cancelCheck(@Valid @RequestBody List<Long> ids) {
return success(rewardRedeemService.cancelCheck(reqVO)); return success(rewardRedeemService.cancelCheck(ids));
} }
@PostMapping("record/cancel") @PostMapping("record/cancel")
@ApiOperation("撤销") @ApiOperation("撤销")
public CommonResult<Boolean> cancel(@Valid @RequestBody RewardRedeemUpdateReqVO reqVO) { public CommonResult<Boolean> cancel(@Valid @RequestBody List<Long> ids) {
return success(rewardRedeemService.cancel(reqVO)); return success(rewardRedeemService.cancel(ids));
} }
@PostMapping("record/import/template") @PostMapping("record/import/template")
......
...@@ -34,7 +34,7 @@ public interface RewardRedeemService extends IService<RewardRedeemDO> { ...@@ -34,7 +34,7 @@ public interface RewardRedeemService extends IService<RewardRedeemDO> {
RecordInfoImportRespVO recordImport(List<RedeemInfoImportExcelVO> dataList); RecordInfoImportRespVO recordImport(List<RedeemInfoImportExcelVO> dataList);
Boolean cancel(RewardRedeemUpdateReqVO reqVO); Boolean cancel(List<Long> ids);
RedeemCancelCheckRespVO cancelCheck(RewardRedeemUpdateReqVO reqVO); RedeemCancelCheckRespVO cancelCheck(List<Long> ids);
} }
...@@ -208,7 +208,7 @@ public class RewardRedeemServiceImpl extends AbstractService<RewardRedeemMapper, ...@@ -208,7 +208,7 @@ public class RewardRedeemServiceImpl extends AbstractService<RewardRedeemMapper,
@Override @Override
public RecordInfoImportRespVO recordImport(List<RedeemInfoImportExcelVO> dataList) { public RecordInfoImportRespVO recordImport(List<RedeemInfoImportExcelVO> dataList) {
if (CollectionUtils.isEmpty(dataList)) { if (CollectionUtils.isEmpty(dataList)) {
return RecordInfoImportRespVO.builder().build(); return RecordInfoImportRespVO.builder().redeemIdFailedMap(Collections.emptyMap()).build();
} }
if (dataList.size() > MAX_IMPORT_RECORD_COUNT) { if (dataList.size() > MAX_IMPORT_RECORD_COUNT) {
throw exception(ErrorCodeConstants.REDEEM_IMPORT_MAX_COUNT, MAX_IMPORT_RECORD_COUNT); throw exception(ErrorCodeConstants.REDEEM_IMPORT_MAX_COUNT, MAX_IMPORT_RECORD_COUNT);
...@@ -241,17 +241,20 @@ public class RewardRedeemServiceImpl extends AbstractService<RewardRedeemMapper, ...@@ -241,17 +241,20 @@ public class RewardRedeemServiceImpl extends AbstractService<RewardRedeemMapper,
return rewardRedeemDO; return rewardRedeemDO;
}).collect(Collectors.toList()); }).collect(Collectors.toList());
this.updateBatchById(saveDataList); this.updateBatchById(saveDataList);
return RecordInfoImportRespVO.builder().build(); return RecordInfoImportRespVO.builder().redeemIdFailedMap(Collections.emptyMap()).build();
} }
@Override @Override
@Transactional public Boolean cancel(List<Long> ids) {
public Boolean cancel(RewardRedeemUpdateReqVO reqVO) { if (CollectionUtils.isEmpty(ids)) {
throw exception(ErrorCodeConstants.REWARD_REDEEM_NOT_EXIST);
}
ids.forEach(id -> {
//取消兑换 状态改为已取消 回退扣减的积分 ,如果存在已过期的积分,则直接过期 //取消兑换 状态改为已取消 回退扣减的积分 ,如果存在已过期的积分,则直接过期
if (reqVO.getId() == null) { if (id == null) {
throw exception(ErrorCodeConstants.REWARD_REDEEM_NOT_EXIST); throw exception(ErrorCodeConstants.REWARD_REDEEM_NOT_EXIST);
} }
RewardRedeemDO rewardRedeemDO = this.getById(reqVO.getId()); RewardRedeemDO rewardRedeemDO = this.getById(id);
if (rewardRedeemDO == null) { if (rewardRedeemDO == null) {
throw exception(ErrorCodeConstants.REWARD_REDEEM_NOT_EXIST); throw exception(ErrorCodeConstants.REWARD_REDEEM_NOT_EXIST);
} }
...@@ -259,7 +262,7 @@ public class RewardRedeemServiceImpl extends AbstractService<RewardRedeemMapper, ...@@ -259,7 +262,7 @@ public class RewardRedeemServiceImpl extends AbstractService<RewardRedeemMapper,
throw exception(ErrorCodeConstants.REDEEM_CANCEL_STATUS_ERROR); throw exception(ErrorCodeConstants.REDEEM_CANCEL_STATUS_ERROR);
} }
LambdaUpdateWrapper<RewardRedeemDO> updateWrapper = Wrappers.lambdaUpdate(); LambdaUpdateWrapper<RewardRedeemDO> updateWrapper = Wrappers.lambdaUpdate();
updateWrapper.eq(RewardRedeemDO::getId, reqVO.getId()); updateWrapper.eq(RewardRedeemDO::getId, id);
updateWrapper.eq(RewardRedeemDO::getStatus, RewardRedeemStatusEnum.REDEEMING.getValue()); updateWrapper.eq(RewardRedeemDO::getStatus, RewardRedeemStatusEnum.REDEEMING.getValue());
updateWrapper.set(RewardRedeemDO::getStatus, RewardRedeemStatusEnum.CANCELED.getValue()); updateWrapper.set(RewardRedeemDO::getStatus, RewardRedeemStatusEnum.CANCELED.getValue());
boolean updateSuccess = this.update(null, updateWrapper); boolean updateSuccess = this.update(null, updateWrapper);
...@@ -267,23 +270,24 @@ public class RewardRedeemServiceImpl extends AbstractService<RewardRedeemMapper, ...@@ -267,23 +270,24 @@ public class RewardRedeemServiceImpl extends AbstractService<RewardRedeemMapper,
throw exception(ErrorCodeConstants.REDEEM_CANCEL_STATUS_ERROR); throw exception(ErrorCodeConstants.REDEEM_CANCEL_STATUS_ERROR);
} }
Map<String, Object> extParam = new HashMap<>(); Map<String, Object> extParam = new HashMap<>();
extParam.put("redeemId", reqVO.getId()); extParam.put("redeemId", id);
memberUserScoreApi.operateScore(MemberUserScoreOperateReqDTO.builder() memberUserScoreApi.operateScore(MemberUserScoreOperateReqDTO.builder()
.memberId(rewardRedeemDO.getMemberId()) .memberId(rewardRedeemDO.getMemberId())
.sourceType(ScoreSourceTypeEnum.EXCHANGE_REWARD_CANCEL) .sourceType(ScoreSourceTypeEnum.EXCHANGE_REWARD_CANCEL)
.scoreCount(rewardRedeemDO.getScoreCount()) .scoreCount(rewardRedeemDO.getScoreCount())
.extParam(extParam) .extParam(extParam)
.releationId(String.valueOf(reqVO.getId())) .releationId(String.valueOf(id))
.build()); .build());
});
return true; return true;
} }
@Override @Override
public RedeemCancelCheckRespVO cancelCheck(RewardRedeemUpdateReqVO reqVO) { public RedeemCancelCheckRespVO cancelCheck(List<Long> ids) {
if (reqVO.getId() == null) { if (CollectionUtils.isEmpty(ids)) {
throw exception(ErrorCodeConstants.REWARD_REDEEM_NOT_EXIST); throw exception(ErrorCodeConstants.REWARD_REDEEM_NOT_EXIST);
} }
RewardRedeemDO rewardRedeemDO = this.getById(reqVO.getId()); RewardRedeemDO rewardRedeemDO = this.getById(ids.get(0));
if (rewardRedeemDO == null) { if (rewardRedeemDO == null) {
throw exception(ErrorCodeConstants.REWARD_REDEEM_NOT_EXIST); throw exception(ErrorCodeConstants.REWARD_REDEEM_NOT_EXIST);
} }
...@@ -291,7 +295,7 @@ public class RewardRedeemServiceImpl extends AbstractService<RewardRedeemMapper, ...@@ -291,7 +295,7 @@ public class RewardRedeemServiceImpl extends AbstractService<RewardRedeemMapper,
throw exception(ErrorCodeConstants.REDEEM_CANCEL_STATUS_ERROR); throw exception(ErrorCodeConstants.REDEEM_CANCEL_STATUS_ERROR);
} }
List<ReleationScoreExpireInfoDTO> scoreExpireInfo = memberUserScoreApi List<ReleationScoreExpireInfoDTO> scoreExpireInfo = memberUserScoreApi
.getScoreExpireInfo(String.valueOf(reqVO.getId()), ScoreSourceTypeEnum.EXCHANGE_REWARD); .getScoreExpireInfo(String.valueOf(ids.get(0)), ScoreSourceTypeEnum.EXCHANGE_REWARD);
int totalExpireScore = scoreExpireInfo.stream().filter(e -> e.getExpireDate() != null && e.getExpireDate().compareTo(new Date()) < 0) int totalExpireScore = scoreExpireInfo.stream().filter(e -> e.getExpireDate() != null && e.getExpireDate().compareTo(new Date()) < 0)
.mapToInt(ReleationScoreExpireInfoDTO::getScoreCount).sum(); .mapToInt(ReleationScoreExpireInfoDTO::getScoreCount).sum();
return RedeemCancelCheckRespVO.builder().expireCount(totalExpireScore).build(); return RedeemCancelCheckRespVO.builder().expireCount(totalExpireScore).build();
......
...@@ -65,6 +65,10 @@ ...@@ -65,6 +65,10 @@
<artifactId>yudao-module-sale-core</artifactId> <artifactId>yudao-module-sale-core</artifactId>
<version>${revision}</version> <version>${revision}</version>
</dependency> </dependency>
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-module-member-api</artifactId>
<version>${revision}</version>
</dependency>
</dependencies> </dependencies>
</project> </project>
...@@ -4,11 +4,11 @@ import cn.hutool.core.collection.CollectionUtil; ...@@ -4,11 +4,11 @@ import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateTime; import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil; import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.util.spring.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.exception.ServiceException; import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.code.CodeUtils; import cn.iocoder.yudao.framework.common.util.code.CodeUtils;
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.dict.core.dto.DictDataRespDTO; import cn.iocoder.yudao.framework.dict.core.dto.DictDataRespDTO;
import cn.iocoder.yudao.framework.dict.core.util.DictFrameworkUtils; import cn.iocoder.yudao.framework.dict.core.util.DictFrameworkUtils;
import cn.iocoder.yudao.framework.i18n.core.I18nMessage; import cn.iocoder.yudao.framework.i18n.core.I18nMessage;
...@@ -44,8 +44,10 @@ import cn.iocoder.yudao.module.ecw.dal.mysql.ladingTemplate.LadingTemplateMapper ...@@ -44,8 +44,10 @@ import cn.iocoder.yudao.module.ecw.dal.mysql.ladingTemplate.LadingTemplateMapper
import cn.iocoder.yudao.module.ecw.service.busiPwd.BusiPwdService; import cn.iocoder.yudao.module.ecw.service.busiPwd.BusiPwdService;
import cn.iocoder.yudao.module.ecw.service.cabinet.CabinetService; import cn.iocoder.yudao.module.ecw.service.cabinet.CabinetService;
import cn.iocoder.yudao.module.ecw.service.region.RegionService; import cn.iocoder.yudao.module.ecw.service.region.RegionService;
import cn.iocoder.yudao.module.member.api.ScoreProducerApi;
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.ScoreRuleTypeEnum;
import cn.iocoder.yudao.module.order.convert.orderLocation.OrderLocationConvert; import cn.iocoder.yudao.module.order.convert.orderLocation.OrderLocationConvert;
import cn.iocoder.yudao.module.order.dal.dataobject.approval.OrderApprovalDO; import cn.iocoder.yudao.module.order.dal.dataobject.approval.OrderApprovalDO;
import cn.iocoder.yudao.module.order.dal.dataobject.order.OrderDO; import cn.iocoder.yudao.module.order.dal.dataobject.order.OrderDO;
...@@ -420,6 +422,9 @@ public class BoxServiceImpl extends AbstractService<BoxMapper, BoxDO> implements ...@@ -420,6 +422,9 @@ public class BoxServiceImpl extends AbstractService<BoxMapper, BoxDO> implements
@Lazy @Lazy
private BoxPkgOrderService boxPkgOrderService; private BoxPkgOrderService boxPkgOrderService;
@Resource
private ScoreProducerApi scoreProducerApi;
static { static {
String key = "130-4174-1"; String key = "130-4174-1";
minNumMap.put(key, 3633); minNumMap.put(key, 3633);
...@@ -1868,6 +1873,11 @@ public class BoxServiceImpl extends AbstractService<BoxMapper, BoxDO> implements ...@@ -1868,6 +1873,11 @@ public class BoxServiceImpl extends AbstractService<BoxMapper, BoxDO> implements
//订单不存在 //订单不存在
if (CollectionUtil.isEmpty(orderIdList)) return; if (CollectionUtil.isEmpty(orderIdList)) return;
updateOrderStatusByOrderIdAndTransportType(orderIdList, orderStatus, inWarehouseState, shipmentState, auditType, auditResult, businessTime, estTime, transportType); updateOrderStatusByOrderIdAndTransportType(orderIdList, orderStatus, inWarehouseState, shipmentState, auditType, auditResult, businessTime, estTime, transportType);
if (Objects.equals(orderStatus, OrderStatusEnum.IN_SHIPPING.getValue())) {
for (Long orderId : orderIdList) {
scoreProducerApi.sendOderMessage(ScoreRuleTypeEnum.ORDER_V, orderId);
}
}
} }
@Override @Override
...@@ -4959,7 +4969,7 @@ public class BoxServiceImpl extends AbstractService<BoxMapper, BoxDO> implements ...@@ -4959,7 +4969,7 @@ public class BoxServiceImpl extends AbstractService<BoxMapper, BoxDO> implements
BoxOrderMarkUpVO boxOrderMarkUpVO = BoxOrderMarkUpVO boxOrderMarkUpVO =
JSON.parseObject(details, BoxOrderMarkUpVO.class); JSON.parseObject(details, BoxOrderMarkUpVO.class);
zTest z=new zTest(); zTest z = new zTest();
z.setTestname("开始调用 handleAirOrderBatchMarkup"); z.setTestname("开始调用 handleAirOrderBatchMarkup");
z.setCreatedate(new Date()); z.setCreatedate(new Date());
zTestMapper2.insert(z); zTestMapper2.insert(z);
......
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