src/main/java/cc/mrbird/febs/common/configure/RabbitConfigure.java
@@ -122,4 +122,25 @@ return BindingBuilder.bind(orderReturnMoneyQueue()).to(orderReturnMoneyExchange()).with(RabbitQueueEnum.ORDER_RETURN_MONEY.getRoute()); } /** * 补贴金额 * @return */ //补贴金额 start @Bean public DirectExchange perkMoneyExchange() { return new DirectExchange(RabbitQueueEnum.PERK_MONEY.getExchange()); } @Bean public Queue perkMoneyQueue() { return new Queue(QueueConstants.PERK_MONEY); } @Bean public Binding perkMoneyBind() { return BindingBuilder.bind(perkMoneyQueue()).to(perkMoneyExchange()).with(RabbitQueueEnum.PERK_MONEY.getRoute()); } //补贴金额 end } src/main/java/cc/mrbird/febs/common/enumerates/MemberLevelEnum.java
New file @@ -0,0 +1,62 @@ package cc.mrbird.febs.common.enumerates; import lombok.Getter; import java.util.ArrayList; import java.util.List; @Getter public enum MemberLevelEnum { SEVEN_LEVEL("SEVEN_LEVEL",6), SIX_LEVEL("SIX_LEVEL",5), FIFTH_LEVEL("FIFTH_LEVEL",4), FOUR_LEVEL("FOUR_LEVEL",3), THIRD_LEVEL("THIRD_LEVEL",2), SECOND_LEVEL("SECOND_LEVEL",1); private String type; private Integer code; MemberLevelEnum(String type, Integer code) { this.type = type; this.code = code; } public List<String> getLevelType(){ List<String> strs = new ArrayList<>(); for (MemberLevelEnum value : MemberLevelEnum.values()) { strs.add(value.type); } return strs; } public int getLevelCode(String Level){ int codeOne = 0; for (MemberLevelEnum value : MemberLevelEnum.values()) { if(value.type.equals(Level)){ codeOne = value.code; } } return codeOne; } //比较两个级别的大小,levelOne大于levelTwo返回1,否则返回0 public int compareLevel(String levelOne ,String levelTwo) { int codeOne = 0; int codeTwo = 0; for (MemberLevelEnum value : MemberLevelEnum.values()) { if(value.type.equals(levelOne)){ codeOne = value.code; } if(value.type.equals(levelTwo)){ codeTwo = value.code; } } if(codeOne > codeTwo){ return 1; } return 0; } } src/main/java/cc/mrbird/febs/common/enumerates/MoneyFlowTypeEnum.java
@@ -93,7 +93,37 @@ /** * 积分池收益 */ SCORE_POOL(18); SCORE_POOL(18), /** * 星级奖励 */ STAR_PERK_TWO(19), /** * 星级奖励 */ STAR_PERK_THREE(20), /** * 星级奖励 */ STAR_PERK_FOUR(21), /** * 星级奖励 */ STAR_PERK_FIVE(22), /** * 星级奖励 */ STAR_PERK_SIX(23), /** * 星级奖励 */ STAR_PERK_SEVEN(24); private final int value; src/main/java/cc/mrbird/febs/mall/entity/AgentInfo.java
@@ -14,12 +14,12 @@ public class AgentInfo { /** * 团队业绩 * 团队贡献值 */ private BigDecimal teamIncome; /** * 代理收益比例 * 补贴比例 */ private BigDecimal profitProp; src/main/java/cc/mrbird/febs/mall/entity/MallMemberWallet.java
@@ -43,4 +43,9 @@ * 佣金 */ private BigDecimal commission; /** * 贡献点 */ private Integer star; } src/main/java/cc/mrbird/febs/mall/mapper/MallMemberMapper.java
@@ -85,4 +85,6 @@ List<MallMember> selectDirectorsOrStoreMaster(@Param("type") Integer type); List<MallMember> selectMemberWithLevel(String level); List<Long> selectMemberIdWithLevel(String levelParam); } src/main/java/cc/mrbird/febs/mall/mapper/MallMemberWalletMapper.java
@@ -5,6 +5,8 @@ import org.apache.ibatis.annotations.Param; import java.math.BigDecimal; import java.util.List; import java.util.Map; public interface MallMemberWalletMapper extends BaseMapper<MallMemberWallet> { @@ -25,4 +27,8 @@ BigDecimal selectSumPrizeScore(); BigDecimal selectSumCommission(); List<MallMemberWallet> selectSumStarByIds(@Param("list")List<Long> ids); int updateStarByList(@Param("list")List<Map<String, Object>> result); } src/main/java/cc/mrbird/febs/mall/mapper/MallMoneyFlowMapper.java
@@ -37,4 +37,6 @@ BigDecimal selectCommissionIncome(@Param("type") Integer type, @Param("date") Date date, @Param("memberId") Long memebrid); BigDecimal selectThankfulCommission(@Param("date") Date date, @Param("memberId") Long memberId); void insertMoneyFlow(MallMoneyFlow mallMoneyFlow); } src/main/java/cc/mrbird/febs/mall/service/IAgentService.java
@@ -7,4 +7,6 @@ void returnMoneyToAgent(Long orderId); void rankReturnMoney(Long orderId); void perkMoneyConsumer(long parseLong); } src/main/java/cc/mrbird/febs/mall/service/impl/AgentServiceImpl.java
@@ -1,23 +1,21 @@ package cc.mrbird.febs.mall.service.impl; import cc.mrbird.febs.common.enumerates.AgentLevelEnum; import cc.mrbird.febs.common.enumerates.MoneyFlowTypeEnum; import cc.mrbird.febs.common.utils.AppContants; import cc.mrbird.febs.mall.entity.AgentInfo; import cc.mrbird.febs.mall.entity.DataDictionaryCustom; import cc.mrbird.febs.mall.entity.MallMember; import cc.mrbird.febs.mall.entity.MallOrderInfo; import cc.mrbird.febs.common.enumerates.*; import cc.mrbird.febs.mall.entity.*; import cc.mrbird.febs.mall.mapper.*; import cc.mrbird.febs.mall.service.IAgentService; import cc.mrbird.febs.mall.service.IApiMallMemberService; import cc.mrbird.febs.mall.service.IApiMallMemberWalletService; import cc.mrbird.febs.mall.service.IMallAchieveService; import cc.mrbird.febs.mall.service.*; import cc.mrbird.febs.system.mapper.UserMapper; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.json.JSONUtil; import com.alibaba.fastjson.JSONObject; import jdk.nashorn.internal.ir.IfNode; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.ibatis.session.ExecutorType; import org.apache.ibatis.session.SqlSession; import org.mybatis.spring.SqlSessionTemplate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -27,6 +25,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; /** * @author wzy @@ -39,6 +38,12 @@ private final DataDictionaryCustomMapper dataDictionaryCustomMapper; private final MallMemberMapper memberMapper; private final MallOrderInfoMapper mallOrderInfoMapper; private final IApiMallMemberWalletService iApiMallMemberWalletService; private final IMallMoneyFlowService mallMoneyFlowService; private final MallMemberWalletMapper mallMemberWalletMapper; private final SqlSessionTemplate sqlSessionTemplate; @Override @Transactional(rollbackFor = Exception.class) @@ -136,7 +141,6 @@ /** * 团队业绩是否达标 * * @param mallMember * @param agentInfo * @return */ @@ -161,4 +165,146 @@ public void rankReturnMoney(Long orderId) { } @Override @Transactional(rollbackFor = Exception.class) public void perkMoneyConsumer(long orderId) { MallOrderInfo mallOrderInfo = mallOrderInfoMapper.selectById(orderId); if(ObjectUtil.isEmpty(mallOrderInfo)){ return; } if(2 != mallOrderInfo.getStatus()){ return; } /** * 分享补贴 直推消费额10% */ BigDecimal amount = mallOrderInfo.getAmount(); Long memberId = mallOrderInfo.getMemberId(); MallMember mallMember = memberMapper.selectById(memberId); //补贴对象 直属上级 MallMember mallMemberUp = memberMapper.selectInfoByInviteId(mallMember.getReferrerId()); if(ObjectUtil.isNotEmpty(mallMemberUp)){ //分享补贴百分比 DataDictionaryCustom sharePerkDic = dataDictionaryCustomMapper.selectDicDataByTypeAndCode( DataDictionaryEnum.SHARE_PERK.getType(), DataDictionaryEnum.SHARE_PERK.getCode()); String sharePerk = ObjectUtil.isEmpty(sharePerkDic.getValue()) ? "0" : sharePerkDic.getValue(); BigDecimal sharePerkPercent = new BigDecimal(sharePerk).abs().divide(new BigDecimal(100)); //分享补贴金额 BigDecimal sharePerkAmount = amount.multiply(sharePerkPercent); iApiMallMemberWalletService.addBalance(sharePerkAmount, mallMemberUp.getId()); mallMoneyFlowService.addMoneyFlow( mallMemberUp.getId(), sharePerkAmount, MoneyFlowTypeEnum.DYNAMIC_ACHIEVE.getValue(), mallOrderInfo.getOrderNo(), FlowTypeEnum.BALANCE.getValue()); } /** * 星级奖励 * 从最顶级级别的合伙人开始补贴 * 补贴完,把已经补贴的合伙人加入下一个级别 */ List<MallMember> sevenLevelRecord = getStarRecord(null, MemberLevelEnum.SEVEN_LEVEL.name(), amount, mallOrderInfo.getOrderNo(), memberId,MoneyFlowTypeEnum.STAR_PERK_SEVEN.getValue()); List<MallMember> sixLevelRecord = getStarRecord(sevenLevelRecord, MemberLevelEnum.SIX_LEVEL.name(), amount, mallOrderInfo.getOrderNo(), memberId,MoneyFlowTypeEnum.STAR_PERK_SIX.getValue()); List<MallMember> fifthLevelRecord = getStarRecord(sixLevelRecord, MemberLevelEnum.FIFTH_LEVEL.name(), amount, mallOrderInfo.getOrderNo(), memberId,MoneyFlowTypeEnum.STAR_PERK_FIVE.getValue()); List<MallMember> fourLevelRecord = getStarRecord(fifthLevelRecord, MemberLevelEnum.FOUR_LEVEL.name(), amount, mallOrderInfo.getOrderNo(), memberId,MoneyFlowTypeEnum.STAR_PERK_FOUR.getValue()); List<MallMember> thirdLevelRecord = getStarRecord(fourLevelRecord, MemberLevelEnum.THIRD_LEVEL.name(), amount, mallOrderInfo.getOrderNo(), memberId,MoneyFlowTypeEnum.STAR_PERK_THREE.getValue()); List<MallMember> secondLevelRecord = getStarRecord(thirdLevelRecord, MemberLevelEnum.SECOND_LEVEL.name(), amount, mallOrderInfo.getOrderNo(), memberId,MoneyFlowTypeEnum.STAR_PERK_TWO.getValue()); } /** * * @param mallMembersOlds 高一级别的用户 * @param LevelParam 当前级别 * @param amount 补贴金额的基数 * @param orderNo 订单编号 * @param memberId 会员id * @return */ public List<MallMember> getStarRecord(List<MallMember> mallMembersOlds,String LevelParam,BigDecimal amount,String orderNo,Long memberId,int starPerkType){ //根据用户的level获取用户 List<MallMember> mallMemberStars = memberMapper.selectMemberWithLevel(LevelParam); if(CollUtil.isNotEmpty(mallMembersOlds)){ for(MallMember mallMemberOld : mallMembersOlds){ mallMemberStars.add(mallMemberOld); } } if(CollUtil.isNotEmpty(mallMemberStars)){ List<Long> mallMemberStarIds = mallMemberStars.stream().map(MallMember::getId).collect(Collectors.toList()); //当前等级的总贡献点 List<MallMemberWallet> mallMemberWallets = mallMemberWalletMapper.selectSumStarByIds(mallMemberStarIds); Integer starSum = mallMemberWallets.stream().mapToInt(MallMemberWallet::getStar).sum(); //星级补贴比例 DataDictionaryCustom starPerkDic = dataDictionaryCustomMapper.selectDicDataByTypeAndCode( "AGENT_LEVEL_REQUIRE", LevelParam); String starPerkStr = starPerkDic.getValue(); AgentInfo agentInfo = JSONObject.parseObject(starPerkStr, AgentInfo.class); BigDecimal profitProp = agentInfo.getProfitProp().abs().divide(new BigDecimal(100)); //当前等级的星级补贴 BigDecimal starPerkAmountSum = amount.multiply(profitProp); //当前等级的每一个贡献点的补贴金额 BigDecimal starPerkAmountAva = starPerkAmountSum.divide(new BigDecimal(starSum),BigDecimal.ROUND_DOWN).setScale(2, BigDecimal.ROUND_DOWN); /** * 给当前等级的每个用户发放星级奖励 * 生成星级奖励的流水 */ if(CollUtil.isNotEmpty(mallMemberWallets)){ //给当前等级的每个用户发放星级奖励 int count = 0; List<Map<String,Object>> result = new ArrayList<>(); List<MallMoneyFlow> mallMoneyFlows = new ArrayList<>(); for(MallMemberWallet mallMemberWallet : mallMemberWallets){ Map<String,Object> hashMap = new HashMap<>(); Integer starCnt = mallMemberWallet.getStar(); //当前用户的星级奖励 BigDecimal starPerkAmount = starPerkAmountAva .multiply(new BigDecimal(starCnt)).abs().setScale(2, BigDecimal.ROUND_DOWN); hashMap.put("id",mallMemberWallet.getId()); hashMap.put("starPerkAmount",starPerkAmount); result.add(hashMap); //生成星级奖励的流水对象 MallMoneyFlow mallMoneyFlow = new MallMoneyFlow(); mallMoneyFlow.setMemberId(mallMemberWallet.getMemberId()); mallMoneyFlow.setAmount(starPerkAmount); mallMoneyFlow.setType(starPerkType); mallMoneyFlow.setOrderNo(orderNo); mallMoneyFlow.setRtMemberId(memberId); mallMoneyFlow.setStatus(2); mallMoneyFlow.setFlowType(FlowTypeEnum.BALANCE.getValue()); mallMoneyFlows.add(mallMoneyFlow); count = count + 1; if (count % 1000 == 0 || count == mallMemberWallets.size()) { int updateCount = mallMemberWalletMapper.updateStarByList(result); if(updateCount>0){ log.info("============更新============第{}条数据===========",count); } //每更新完一批数据,在result内进行删除操作。 result.clear(); } } SqlSession sqlSession = sqlSessionTemplate.getSqlSessionFactory().openSession(ExecutorType.BATCH,false); MallMoneyFlowMapper mallMoneyFlowMapper = sqlSession.getMapper(MallMoneyFlowMapper.class); long start = System.currentTimeMillis(); for(int i = 1; i <= mallMoneyFlows.size(); i++){ mallMoneyFlowMapper.insertMoneyFlow(mallMoneyFlows.get(i-1)); if (i % 1000 == 0 || i == mallMoneyFlows.size()) { long end = System.currentTimeMillis(); log.info("============插入============第{}条数据,时间:{}===========",mallMoneyFlows.size(),(end - start)/1000); sqlSession.commit(); sqlSession.clearCache(); } } sqlSession.close(); } } return mallMemberStars; } } src/main/java/cc/mrbird/febs/rabbit/constants/QueueConstants.java
@@ -10,4 +10,9 @@ public static final String AGENT_AUTO_LEVEL_UP = "hlm_queue_agent_auto_level_up"; public static final String AGENT_RETURN_MONEY = "hlm_queue_agent_return_money"; public static final String ORDER_RETURN_MONEY = "hlm_queue_order_return_money"; /** * 补贴金额 , * 分享补贴,星级补贴 */ public static final String PERK_MONEY = "hlm_queue_perk_money"; } src/main/java/cc/mrbird/febs/rabbit/consumer/AgentConsumer.java
@@ -72,4 +72,16 @@ log.error("订单返利异常:", e); } } @RabbitListener(queues = QueueConstants.PERK_MONEY) public void perkMoneyConsumer(String id) { log.info("收到补贴消息:{}", id); try { agentService.perkMoneyConsumer(Long.parseLong(id)); } catch (Exception e) { log.error("用户补贴异常", e); // todo 更新表 } } } src/main/java/cc/mrbird/febs/rabbit/enumerates/RabbitQueueEnum.java
@@ -22,7 +22,11 @@ ORDER_RETURN_MONEY("hlm_exchange_order_return_money", "hlm_route_key_order_return_money", "hlm_queue_order_return_money"); "hlm_queue_order_return_money"), PERK_MONEY("hlm_exchange_perk_money", "hlm_route_key_perk_money", "hlm_queue_perk_money"); private String exchange; src/main/resources/application-dev.yml
@@ -18,7 +18,7 @@ username: db_mall_hongloumeng password: hongloumeng123!@#123 driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://47.111.90.145:3306/db_mall_hongloumeng?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2b8 url: jdbc:mysql://47.111.90.145:3306/db_mall_hongloumeng?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2b8&rewriteBatchedStatements=true&allowMultiQueries=true # username: db_mall # password: mall!@#123 # driver-class-name: com.mysql.cj.jdbc.Driver src/main/resources/application-prod.yml
@@ -18,7 +18,7 @@ username: db_mall_hongloumeng password: hongloumeng123!@#123 driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://127.0.0.1:3306/db_mall_hongloumeng?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2b8 url: jdbc:mysql://127.0.0.1:3306/db_mall_hongloumeng?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2b8&rewriteBatchedStatements=true&allowMultiQueries=true redis: # Redis数据库索引(默认为 0) src/main/resources/mapper/modules/MallMemberMapper.xml
@@ -400,4 +400,9 @@ select * from mall_member where level=#{level} </select> <select id="selectMemberIdWithLevel" resultType="java.lang.Long"> select id from mall_member where level = #{level} </select> </mapper> src/main/resources/mapper/modules/MallMemberWalletMapper.xml
@@ -60,4 +60,24 @@ <select id="selectSumCommission" resultType="java.math.BigDecimal"> select ifnull(sum(commission),0) total from mall_member_wallet </select> <select id="selectSumStarByIds" resultType="cc.mrbird.febs.mall.entity.MallMemberWallet"> select * from mall_member_wallet where member_id IN <foreach collection = "list" item = "item" separator="," open = "(" close = ")" > #{item} </foreach > </select> <update id="updateStarByList" parameterType="java.util.List" > -- //注意sql语句应被;分隔开,否则批量更新多少条数据就有多少条sql拼在一起。 <foreach collection="list" item="item" index="index" open="" close="" separator=";"> update mall_member_wallet <set> balance = balance + #{item.starPerkAmount}, </set> WHERE id = #{item.id} </foreach> </update> </mapper> src/main/resources/mapper/modules/MallMoneyFlowMapper.xml
@@ -132,4 +132,34 @@ and date_format(created_time, '%Y-%m-%d') = date_format(#{date}, '%Y-%m-%d') and type in (2,3,4) </select> <insert id="insertMoneyFlow" parameterType="cc.mrbird.febs.mall.entity.MallMoneyFlow"> insert into mall_money_flow( REVISION, CREATED_BY, CREATED_TIME, UPDATED_BY, UPDATED_TIME, member_id, amount, type, order_no, rt_member_id, status, flow_type) VALUES ( #{revision}, #{createdBy}, #{createdTime}, #{updatedBy}, #{updatedTime}, #{memberId}, #{amount}, #{type}, #{orderNo}, #{rtMemberId}, #{status}, #{flowType} ) </insert> </mapper> src/test/java/cc/mrbird/febs/ProfitTest.java
@@ -42,7 +42,7 @@ @Test public void dynamicProfit() { memberProfitService.dynamicProfit(21L); agentService.perkMoneyConsumer(Long.parseLong("571")); } @Test public void agentProfit() {