From 7c2c2435ae5d5443593e260177d28dcc990ddea4 Mon Sep 17 00:00:00 2001 From: xiaoyong931011 <15274802129@163.com> Date: Tue, 20 Dec 2022 14:49:41 +0800 Subject: [PATCH] 20221220 1、会员注册后level为会员 2、代理每天一点更新一次定时器 3、确认收货后返还订单金额,并且产生其余补贴 --- src/main/java/cc/mrbird/febs/rabbit/enumerates/RabbitQueueEnum.java | 2 src/main/java/cc/mrbird/febs/rabbit/consumer/AgentConsumer.java | 10 src/main/java/cc/mrbird/febs/mall/entity/MallMoneyFlow.java | 6 src/main/java/cc/mrbird/febs/mall/mapper/MallMemberMapper.java | 10 src/main/java/cc/mrbird/febs/mall/service/impl/ApiMallOrderInfoServiceImpl.java | 75 ++--- src/main/java/cc/mrbird/febs/mall/service/impl/MallMoneyFlowServiceImpl.java | 17 + src/main/resources/mapper/modules/MallMemberMapper.xml | 31 ++ src/main/java/cc/mrbird/febs/common/enumerates/MallMoneyFlowTypeEnum.java | 22 + src/main/java/cc/mrbird/febs/mall/service/IAgentService.java | 6 src/main/java/cc/mrbird/febs/mall/service/impl/ApiMallMemberServiceImpl.java | 2 src/main/java/cc/mrbird/febs/mall/quartz/OrderOvertimeJob.java | 95 +++++++ src/main/java/cc/mrbird/febs/common/enumerates/MoneyFlowTypeEnum.java | 11 src/main/java/cc/mrbird/febs/common/enumerates/MemberAgentLevelEnum.java | 102 ++++++++ src/main/java/cc/mrbird/febs/mall/service/impl/AgentServiceImpl.java | 252 ++++++++++++++++++++ src/main/java/cc/mrbird/febs/common/enumerates/DataDictionaryEnum.java | 31 ++ src/main/java/cc/mrbird/febs/rabbit/constants/QueueConstants.java | 1 src/main/java/cc/mrbird/febs/rabbit/producter/AgentProducer.java | 9 src/main/resources/mapper/modules/MallMoneyFlowMapper.xml | 10 src/main/java/cc/mrbird/febs/mall/entity/MallOrderInfo.java | 2 src/main/java/cc/mrbird/febs/mall/mapper/MallMoneyFlowMapper.java | 6 src/main/java/cc/mrbird/febs/mall/service/IMallMoneyFlowService.java | 2 21 files changed, 641 insertions(+), 61 deletions(-) diff --git a/src/main/java/cc/mrbird/febs/common/enumerates/DataDictionaryEnum.java b/src/main/java/cc/mrbird/febs/common/enumerates/DataDictionaryEnum.java index 995697d..cf1ddf1 100644 --- a/src/main/java/cc/mrbird/febs/common/enumerates/DataDictionaryEnum.java +++ b/src/main/java/cc/mrbird/febs/common/enumerates/DataDictionaryEnum.java @@ -6,8 +6,39 @@ @Getter public enum DataDictionaryEnum { + /** + * 代理等级 + * value : {"levelSelf":"一星","directLevelCnt":"3","teamLevelCnt":"5","minTeamLevelCnt":"2","ManageSubsidyPercent":"2"} + * levelSelf:自身星级 + * directLevelCnt:直推星级数量 + * teamLevelCnt:团队星级数量 + * minTeamLevelCnt:两个市场均有上一个代理等级 + * ManageSubsidyPercent:团队管理补贴百分比例,基数为订单补贴金额 + * subsidyPercent:平级团队管理补贴百分比例,基数为订单补贴金额 + */ + //{"levelSelf":"一星","directLevelCnt":"3","teamLevelCnt":"5","minTeamLevelCnt":"0","manageSubsidyPercent":"2","subsidyPercent":"0"} + AGENT_ONE("MEMBER_AGENT_LEVEL", "AGENT_ONE"),//区代 + //{"levelSelf":"二星","directLevelCnt":"5","teamLevelCnt":"50","minTeamLevelCnt":"2","manageSubsidyPercent":"4","subsidyPercent":"1"} + AGENT_TWO("MEMBER_AGENT_LEVEL", "AGENT_TWO"),//县代 + //{"levelSelf":"二星","directLevelCnt":"10","teamLevelCnt":"300","minTeamLevelCnt":"2","manageSubsidyPercent":"7","subsidyPercent":"1"} + AGENT_THREE("MEMBER_AGENT_LEVEL", "AGENT_THREE"),//市代 + //{"levelSelf":"三星","directLevelCnt":"10","teamLevelCnt":"1000","minTeamLevelCnt":"2","manageSubsidyPercent":"12","subsidyPercent":"1"} + AGENT_FOUR("MEMBER_AGENT_LEVEL", "AGENT_FOUR"),//省代 + //{"levelSelf":"三星","directLevelCnt":"10","teamLevelCnt":"5000","minTeamLevelCnt":"2","manageSubsidyPercent":"20","subsidyPercent":"1"} + AGENT_FIVE("MEMBER_AGENT_LEVEL", "AGENT_FIVE"),//总代 + + //第一代分享奖比例 + LEVEL_ONE("SHARE_PERCENT", "LEVEL_ONE"), + + //第二代分享奖比例 + LEVEL_TWO("SHARE_PERCENT", "LEVEL_TWO"), + + //直推返利的比例 + REWARD_PERCENT("DIRECT_REWARD", "REWARD_PERCENT"), + //会员每日可用订单数 BUY_TIMES("ORDER_BUY", "BUY_TIMES"), + //商品补贴比例 SUBSIDY_PERCENT("GOODS_SUBSIDY", "SUBSIDY_PERCENT"), diff --git a/src/main/java/cc/mrbird/febs/common/enumerates/MallMoneyFlowTypeEnum.java b/src/main/java/cc/mrbird/febs/common/enumerates/MallMoneyFlowTypeEnum.java new file mode 100644 index 0000000..7a65496 --- /dev/null +++ b/src/main/java/cc/mrbird/febs/common/enumerates/MallMoneyFlowTypeEnum.java @@ -0,0 +1,22 @@ +package cc.mrbird.febs.common.enumerates; + +import lombok.Getter; + +@Getter +public enum MallMoneyFlowTypeEnum { + + TEAM_REWARD("团队管理补贴",6), + PAY("支付",5), + SHARE_REWARD_TWO("第二代分享奖励",4), + SHARE_REWARD_ONE("第一代分享奖励",3), + DIRECT_REWARD("直推奖励",2), + MARKET_SUBSIDIES("市场补贴",1); + + private String name; + private Integer code; + + MallMoneyFlowTypeEnum(String name,Integer code) { + this.name = name; + this.code = code; + } +} diff --git a/src/main/java/cc/mrbird/febs/common/enumerates/MemberAgentLevelEnum.java b/src/main/java/cc/mrbird/febs/common/enumerates/MemberAgentLevelEnum.java new file mode 100644 index 0000000..e1065d7 --- /dev/null +++ b/src/main/java/cc/mrbird/febs/common/enumerates/MemberAgentLevelEnum.java @@ -0,0 +1,102 @@ +package cc.mrbird.febs.common.enumerates; + +import lombok.Getter; + +@Getter +public enum MemberAgentLevelEnum { + AGENT_FIVE("总代","AGENT_FIVE",5),//总代 + AGENT_FOUR("省代","AGENT_FOUR",4),//省代 + AGENT_THREE("市代","AGENT_THREE",3),//市代 + AGENT_TWO("县代","AGENT_TWO",2),//县代 + AGENT_ONE("区代","AGENT_ONE",1),//区代 + AGENT("会员","AGENT",0);//会员 + + private String name; + private String code; + private Integer value; + + MemberAgentLevelEnum(String name,String code,Integer value) { + this.name = name; + this.code = code; + this.value = value; + } + + /** + * + 根据传入的name,比较两个级别的大小 + levelOne等于levelTwo返回2,levelOne大于levelTwo返回1,否则返回0 + */ + public int compareLevel(String levelOne ,String levelTwo) { + int codeOne = 0; + int codeTwo = 0; + for (MemberAgentLevelEnum memberAgentLevelEnum : MemberAgentLevelEnum.values()) { + if(memberAgentLevelEnum.name.equals(levelOne)){ + codeOne = memberAgentLevelEnum.value; + } + if(memberAgentLevelEnum.name.equals(levelTwo)){ + codeTwo = memberAgentLevelEnum.value; + } + } + if(codeOne > codeTwo){ + return 1; + } + if(codeOne == codeTwo){ + return 2; + } + return 0; + } + + /** + * 根据传入的等级code,输出上一等级name + * @param code + * @return + */ + public String minLevel(String code) { + String minLevel = null; + for (MemberAgentLevelEnum memberAgentLevelEnum : MemberAgentLevelEnum.values()) { + if(memberAgentLevelEnum.getCode().equals(code)){ + minLevel = getNameByValue(memberAgentLevelEnum.getValue() - 1); + } + } + return minLevel; + } + private String getNameByValue(Integer value){ + String name = null; + for (MemberAgentLevelEnum memberAgentLevelEnum : MemberAgentLevelEnum.values()) { + if(memberAgentLevelEnum.getValue() == value){ + name = memberAgentLevelEnum.getName(); + } + } + return name; + } + + /** + * 根据传入的等级code,输出等级name + * @param code + * @return + */ + public String getNameByCode(String code){ + String name = null; + for (MemberAgentLevelEnum memberAgentLevelEnum : MemberAgentLevelEnum.values()) { + if(memberAgentLevelEnum.getCode() == code){ + name = memberAgentLevelEnum.getName(); + } + } + return name; + } + + /** + * 根据传入的等级name,输出等级code + * @param name + * @return + */ + public String getCodeByName(String name){ + String code = null; + for (MemberAgentLevelEnum memberAgentLevelEnum : MemberAgentLevelEnum.values()) { + if(memberAgentLevelEnum.getName() == name){ + code = memberAgentLevelEnum.getCode(); + } + } + return code; + } +} diff --git a/src/main/java/cc/mrbird/febs/common/enumerates/MoneyFlowTypeEnum.java b/src/main/java/cc/mrbird/febs/common/enumerates/MoneyFlowTypeEnum.java index d560d5d..e1c2865 100644 --- a/src/main/java/cc/mrbird/febs/common/enumerates/MoneyFlowTypeEnum.java +++ b/src/main/java/cc/mrbird/febs/common/enumerates/MoneyFlowTypeEnum.java @@ -2,18 +2,13 @@ import lombok.Getter; -/** - * - * 1-静态收益 2-直推奖 3-代理收益 4-排名收益 5-总监收益 6-社区点补 7-一代收益 8-提现 9-转增 10-支付 11-退款 - * @author wzy - * @date 2021-09-24 - **/ @Getter public enum MoneyFlowTypeEnum { /** - * 静态收益 + * 市场补贴 */ - STATIC_BONUS(1), + MARKET_DUBSIDIES(1), + STATIC_BONUS(100), /** * 直推奖 */ diff --git a/src/main/java/cc/mrbird/febs/mall/entity/MallMoneyFlow.java b/src/main/java/cc/mrbird/febs/mall/entity/MallMoneyFlow.java index 5d43427..a5d8bbf 100644 --- a/src/main/java/cc/mrbird/febs/mall/entity/MallMoneyFlow.java +++ b/src/main/java/cc/mrbird/febs/mall/entity/MallMoneyFlow.java @@ -32,15 +32,19 @@ private Long rtMemberId; /** - * 提现状态 1-提现中2-成功 3-拒绝 + * 提现状态 1-进行中2-成功 3-拒绝 */ private Integer status; + public static final Integer STATUS_ING = 1; + public static final Integer STATUS_SUCCESS = 2; + public static final Integer STATUS_FAIL = 3; /** * 是否返利 1-是 2-否 */ private Integer isReturn; public static final Integer IS_RETURN_Y = 1; + public static final Integer IS_RETURN_N = 2; /** * 流水类型 1-余额 2-赠送积分 3-竞猜积分 4-佣金 diff --git a/src/main/java/cc/mrbird/febs/mall/entity/MallOrderInfo.java b/src/main/java/cc/mrbird/febs/mall/entity/MallOrderInfo.java index 072fd1e..8e06c2f 100644 --- a/src/main/java/cc/mrbird/febs/mall/entity/MallOrderInfo.java +++ b/src/main/java/cc/mrbird/febs/mall/entity/MallOrderInfo.java @@ -93,4 +93,6 @@ private Integer deliverType; private Long shopId; + //补贴金额 + private BigDecimal subsidyAmount; } diff --git a/src/main/java/cc/mrbird/febs/mall/mapper/MallMemberMapper.java b/src/main/java/cc/mrbird/febs/mall/mapper/MallMemberMapper.java index 5c4787a..7840717 100644 --- a/src/main/java/cc/mrbird/febs/mall/mapper/MallMemberMapper.java +++ b/src/main/java/cc/mrbird/febs/mall/mapper/MallMemberMapper.java @@ -85,4 +85,14 @@ List<MallMember> selectDirectorsOrStoreMaster(@Param("type") Integer type); List<MallMember> selectMemberWithLevel(String level); + + List<MallMember> selectByAccountLevel(@Param("accountLevel")String accountLevel); + + Integer selectByRefererIdAndAccountLevel(@Param("refererId")String refererId,@Param("accountLevel") String accountLevel); + + Integer selectByReferersIdAndAccountLevel(@Param("inviteId")String inviteId,@Param("accountLevel") String accountLevel); + + void updateLevelById(@Param("level")String name, @Param("id")Long id); + + Integer selectByReferersIdAndLevel(@Param("inviteId")String inviteId, @Param("level")String minLevel); } diff --git a/src/main/java/cc/mrbird/febs/mall/mapper/MallMoneyFlowMapper.java b/src/main/java/cc/mrbird/febs/mall/mapper/MallMoneyFlowMapper.java index eaa05c6..37d7687 100644 --- a/src/main/java/cc/mrbird/febs/mall/mapper/MallMoneyFlowMapper.java +++ b/src/main/java/cc/mrbird/febs/mall/mapper/MallMoneyFlowMapper.java @@ -37,4 +37,10 @@ BigDecimal selectCommissionIncome(@Param("type") Integer type, @Param("date") Date date, @Param("memberId") Long memebrid); BigDecimal selectThankfulCommission(@Param("date") Date date, @Param("memberId") Long memberId); + + MallMoneyFlow selectOneByMemberIdAndOrderNoAndTypeAndStatusAndIsReturn(@Param("memberId")Long memberId, + @Param("orderNo")String orderNo, + @Param("type")Integer type, + @Param("status")Integer status, + @Param("isReturn")Integer isReturn); } diff --git a/src/main/java/cc/mrbird/febs/mall/quartz/OrderOvertimeJob.java b/src/main/java/cc/mrbird/febs/mall/quartz/OrderOvertimeJob.java index c9ca6a6..18f657c 100644 --- a/src/main/java/cc/mrbird/febs/mall/quartz/OrderOvertimeJob.java +++ b/src/main/java/cc/mrbird/febs/mall/quartz/OrderOvertimeJob.java @@ -1,11 +1,20 @@ package cc.mrbird.febs.mall.quartz; +import cc.mrbird.febs.common.enumerates.DataDictionaryEnum; +import cc.mrbird.febs.common.enumerates.MemberAccountLevelEnum; +import cc.mrbird.febs.common.enumerates.MemberAgentLevelEnum; import cc.mrbird.febs.common.enumerates.OrderStatusEnum; +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.mall.mapper.DataDictionaryCustomMapper; +import cc.mrbird.febs.mall.mapper.MallMemberMapper; import cc.mrbird.febs.mall.mapper.MallOrderInfoMapper; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.date.DateUnit; import cn.hutool.core.date.DateUtil; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Scheduled; @@ -25,6 +34,12 @@ @Autowired private MallOrderInfoMapper orderInfoMapper; + @Autowired + private MallMemberMapper mallMemberMapper; + + @Autowired + private DataDictionaryCustomMapper dataDictionaryCustomMapper; + @Scheduled(cron = "0 0/5 * * * ? ") public void overtimeJob() { log.info("订单超时任务执行"); @@ -42,4 +57,84 @@ } } + + @Scheduled(cron = "0 0 1 * * ? ") + public void updateMemberAgentLevel() { + log.info("会员代理等级升级任务执行"); + /** + * 获取会员信息 + * 1、已经升级成为一星 + */ + /** + * 区代 + * 1、自身一星 + * 2、直推三个星级 + * 3、团队五个星级 + */ + updateMemberAgentLevelByName(DataDictionaryEnum.AGENT_ONE.getType(),DataDictionaryEnum.AGENT_ONE.getCode()); + /** + * 县代 + * 1、自身2星 + * 2、直推5个星级 + * 3、团队50个星级 + */ + updateMemberAgentLevelByName(DataDictionaryEnum.AGENT_TWO.getType(),DataDictionaryEnum.AGENT_TWO.getCode()); + updateMemberAgentLevelByName(DataDictionaryEnum.AGENT_THREE.getType(),DataDictionaryEnum.AGENT_THREE.getCode()); + updateMemberAgentLevelByName(DataDictionaryEnum.AGENT_FOUR.getType(),DataDictionaryEnum.AGENT_FOUR.getCode()); + updateMemberAgentLevelByName(DataDictionaryEnum.AGENT_FIVE.getType(),DataDictionaryEnum.AGENT_FIVE.getCode()); + } + + private void updateMemberAgentLevelByName(String name,String code){ + DataDictionaryCustom agentDic = dataDictionaryCustomMapper.selectDicDataByTypeAndCode( + name, + code + ); + JSONObject jsonObject = JSONUtil.parseObj(agentDic.getValue()); + //自身星级 + String levelSelf = jsonObject.get("levelSelf").toString(); + //直推星级数量 + String directLevelCnt = jsonObject.get("directLevelCnt").toString(); + //团队星级数量 + String teamLevelCnt = jsonObject.get("teamLevelCnt").toString(); + //两个市场均有上一个代理等级 + String minTeamLevelCnt = jsonObject.get("minTeamLevelCnt").toString(); + List<MallMember> agentLevelList = mallMemberMapper.selectByAccountLevel(levelSelf); + if(CollUtil.isNotEmpty(agentLevelList)){ + for(MallMember mallMember : agentLevelList){ + //有星级的直推 + Integer directCnt = mallMemberMapper.selectByRefererIdAndAccountLevel(mallMember.getInviteId(),MemberAccountLevelEnum.NORMAL.getName()); + //团队中星级会员数量 + Integer teamCnt = mallMemberMapper.selectByReferersIdAndAccountLevel(mallMember.getInviteId(),MemberAccountLevelEnum.NORMAL.getName()); + //两个市场均有上一个代理等级 + Integer minCnt = 0; + if(0 < Integer.parseInt(minTeamLevelCnt)){ + String minLevel = MemberAgentLevelEnum.AGENT_ONE.minLevel(code); + //获取所有直推用户 + List<MallMember> mallMembers = mallMemberMapper.selectByRefererId(mallMember.getInviteId()); + if(CollUtil.isNotEmpty(mallMembers) && mallMembers.size() > 2){ + Integer levelCnt = 0; + for(MallMember directMember : mallMembers){ + Integer minlevelCnt = mallMemberMapper.selectByReferersIdAndLevel(directMember.getInviteId(),minLevel); + if(0 < minlevelCnt){ + levelCnt = levelCnt + 1; + } + if(levelCnt >= Integer.parseInt(minTeamLevelCnt)){ + minCnt = 1; + break; + } + } + } + }else{ + //区代不需要判断这个市场条件 + minCnt = 1; + } + if(Integer.parseInt(directLevelCnt) <= directCnt + && Integer.parseInt(teamLevelCnt) <= teamCnt + && minCnt > 0){ + //更新会员代理等级 + mallMemberMapper.updateLevelById(MemberAgentLevelEnum.AGENT_ONE.getNameByCode(code),mallMember.getId()); + } + } + } + } } diff --git a/src/main/java/cc/mrbird/febs/mall/service/IAgentService.java b/src/main/java/cc/mrbird/febs/mall/service/IAgentService.java index bccd530..59cf4e9 100644 --- a/src/main/java/cc/mrbird/febs/mall/service/IAgentService.java +++ b/src/main/java/cc/mrbird/febs/mall/service/IAgentService.java @@ -7,4 +7,10 @@ void returnMoneyToAgent(Long orderId); void rankReturnMoney(Long orderId); + + /** + * 消费补贴奖励、直推返利、分享奖励直推上级、分享奖励直推上级的直推、团队管理补贴消息 + * @param directRewardId + */ + void directReward(Long directRewardId); } diff --git a/src/main/java/cc/mrbird/febs/mall/service/IMallMoneyFlowService.java b/src/main/java/cc/mrbird/febs/mall/service/IMallMoneyFlowService.java index 5b35700..2fe88cd 100644 --- a/src/main/java/cc/mrbird/febs/mall/service/IMallMoneyFlowService.java +++ b/src/main/java/cc/mrbird/febs/mall/service/IMallMoneyFlowService.java @@ -15,4 +15,6 @@ void addMoneyFlow(Long memberId, BigDecimal amount, Integer type, String orderNo, Long rtMemberId, Integer flowType); + Long addMoneyFlow(Long memberId, String orderNo,BigDecimal amount, Integer type, Integer status, Integer isReturn,Long rtMemberId, Integer flowType,String description); + } diff --git a/src/main/java/cc/mrbird/febs/mall/service/impl/AgentServiceImpl.java b/src/main/java/cc/mrbird/febs/mall/service/impl/AgentServiceImpl.java index eb14dd2..10a8612 100644 --- a/src/main/java/cc/mrbird/febs/mall/service/impl/AgentServiceImpl.java +++ b/src/main/java/cc/mrbird/febs/mall/service/impl/AgentServiceImpl.java @@ -1,19 +1,14 @@ 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.enumerates.*; 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.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 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; @@ -39,6 +34,9 @@ private final DataDictionaryCustomMapper dataDictionaryCustomMapper; private final MallMemberMapper memberMapper; + private final MallOrderInfoMapper mallOrderInfoMapper; + private final IMallMoneyFlowService mallMoneyFlowService; + private final IApiMallMemberWalletService memberWalletService; @Override @Transactional(rollbackFor = Exception.class) @@ -136,7 +134,6 @@ /** * 团队业绩是否达标 * - * @param mallMember * @param agentInfo * @return */ @@ -161,4 +158,237 @@ public void rankReturnMoney(Long orderId) { } + + @Override + public void directReward(Long directRewardId) { + log.info("消费补贴奖励、直推返利、分享奖励直推上级、分享奖励直推上级的直推、团队管理补贴消息,ID:{}", directRewardId); + //获取订单信息 + MallOrderInfo orderInfo = mallOrderInfoMapper.selectById(directRewardId); + if(ObjectUtil.isEmpty(orderInfo)){ + return; + } + Integer status = orderInfo.getStatus(); + if(OrderStatusEnum.FINISH.getValue() != status){ + return; + } + //下单补贴金额 + BigDecimal subsidyAmount = orderInfo.getSubsidyAmount(); + //下单人 + Long memberId = orderInfo.getMemberId(); + MallMember mallMember = memberMapper.selectById(memberId); + /** + * 生成补贴的流水记录 + * 1、待生效 + * 2、返利对象,下单人 + * 3、金额,补贴金额 + */ + Long subsidyAmountFlowId = mallMoneyFlowService.addMoneyFlow( + mallMember.getId(), + orderInfo.getOrderNo(), + subsidyAmount.setScale(BigDecimal.ROUND_DOWN, 2), + MallMoneyFlowTypeEnum.MARKET_SUBSIDIES.getCode(), + MallMoneyFlow.STATUS_SUCCESS, + MallMoneyFlow.IS_RETURN_Y, + mallMember.getId(), + FlowTypeEnum.BALANCE.getValue(), + MallMoneyFlowTypeEnum.MARKET_SUBSIDIES.getName() + ); + + memberWalletService.addBalance(subsidyAmount.setScale(BigDecimal.ROUND_DOWN, 2),mallMember.getId()); + + /** + * 生成直推返利的流水记录 + * 1、待生效 + * 2、返利对象:下单人的直推上级 + * 3、金额:返利比例乘以补贴金额 + */ + //下单人的直推上级 + MallMember mallMemberOne = memberMapper.selectInfoByInviteId(mallMember.getReferrerId()); + DataDictionaryCustom rewardPercentDic = dataDictionaryCustomMapper.selectDicDataByTypeAndCode( + DataDictionaryEnum.REWARD_PERCENT.getType(), + DataDictionaryEnum.REWARD_PERCENT.getCode() + ); + BigDecimal rewardPercent = new BigDecimal(rewardPercentDic.getValue()).multiply(new BigDecimal(0.01)).setScale(BigDecimal.ROUND_DOWN,2); + BigDecimal directRewardAmount = subsidyAmount.multiply(rewardPercent).setScale(BigDecimal.ROUND_DOWN, 2); + + Long marketSubsidyFlowId = mallMoneyFlowService.addMoneyFlow( + mallMember.getId(), + orderInfo.getOrderNo(), + directRewardAmount, + MallMoneyFlowTypeEnum.DIRECT_REWARD.getCode(), + MallMoneyFlow.STATUS_SUCCESS, + MallMoneyFlow.IS_RETURN_Y, + mallMemberOne.getId(), + FlowTypeEnum.BALANCE.getValue(), + MallMoneyFlowTypeEnum.DIRECT_REWARD.getName() + ); + memberWalletService.addBalance(directRewardAmount,mallMemberOne.getId()); + /** + * 生成分享奖励的流水记录 + * 1、待生效 + * 2、返利对象:下单人的直推上级 10%,直推的直推 5% + * 3、金额:补贴金额乘以分享奖励的比例 + */ + DataDictionaryCustom shareOneDic = dataDictionaryCustomMapper.selectDicDataByTypeAndCode( + DataDictionaryEnum.LEVEL_ONE.getType(), + DataDictionaryEnum.LEVEL_ONE.getCode() + ); + BigDecimal shareOne = new BigDecimal(shareOneDic.getValue()).multiply(new BigDecimal(0.01)).setScale(BigDecimal.ROUND_DOWN,2); + BigDecimal shareOneAmount = subsidyAmount.multiply(shareOne).setScale(BigDecimal.ROUND_DOWN, 2); + Long ShareOneFlowId = mallMoneyFlowService.addMoneyFlow( + mallMember.getId(), + orderInfo.getOrderNo(), + shareOneAmount, + MallMoneyFlowTypeEnum.SHARE_REWARD_ONE.getCode(), + MallMoneyFlow.STATUS_SUCCESS, + MallMoneyFlow.IS_RETURN_Y, + mallMemberOne.getId(), + FlowTypeEnum.BALANCE.getValue(), + MallMoneyFlowTypeEnum.SHARE_REWARD_ONE.getName() + ); + memberWalletService.addBalance(shareOneAmount,mallMemberOne.getId()); + //下单人的直推上级的直推 + MallMember mallMemberTwo = memberMapper.selectInfoByInviteId(mallMemberOne.getReferrerId()); + if(ObjectUtil.isNotEmpty(mallMemberTwo)){ + DataDictionaryCustom shareTwoDic = dataDictionaryCustomMapper.selectDicDataByTypeAndCode( + DataDictionaryEnum.LEVEL_TWO.getType(), + DataDictionaryEnum.LEVEL_TWO.getCode() + ); + BigDecimal shareTwo = new BigDecimal(shareTwoDic.getValue()).multiply(new BigDecimal(0.01)).setScale(BigDecimal.ROUND_DOWN,2); + BigDecimal shareTwoAmount = subsidyAmount.multiply(shareTwo).setScale(BigDecimal.ROUND_DOWN, 2); + Long shareTwoFlowId = mallMoneyFlowService.addMoneyFlow( + mallMember.getId(), + orderInfo.getOrderNo(), + shareTwoAmount, + MallMoneyFlowTypeEnum.SHARE_REWARD_TWO.getCode(), + MallMoneyFlow.STATUS_SUCCESS, + MallMoneyFlow.IS_RETURN_Y, + mallMemberTwo.getId(), + FlowTypeEnum.BALANCE.getValue(), + MallMoneyFlowTypeEnum.SHARE_REWARD_TWO.getName() + ); + memberWalletService.addBalance(shareTwoAmount,mallMemberTwo.getId()); + } + /** + * 团队管理补贴 + */ + //下单人所有的上级 + String referrerIds = mallMember.getReferrerIds(); + List<String> refererIdList = StrUtil.split(referrerIds, ",", -1, true, true); + //下单人所有符合条件的上级-邀请码 + ArrayList<String> refererIdListUp = new ArrayList<>(); + //初始级别即当前下单人的级别 + String levelStart = mallMember.getLevel(); + for(String inviteId : refererIdList){ + MallMember mallMemberUp = memberMapper.selectInfoByInviteId(inviteId); + String levelUp = mallMemberUp.getLevel(); + //团队补贴从区代开始 + if(!MemberAgentLevelEnum.AGENT.getName().equals(levelUp)){ + //比较两个代理级别,同级别或者大于下单人的级别都保留 + int compareLevel = MemberAgentLevelEnum.AGENT_ONE.compareLevel(levelUp,levelStart); + if(0 < compareLevel){ + levelStart = levelUp; + refererIdListUp.add(inviteId); + } + } + } + if(CollUtil.isNotEmpty(refererIdListUp)){ + for(String inviteId : refererIdList){ + MallMember mallMemberUp = memberMapper.selectInfoByInviteId(inviteId); + String levelUp = mallMemberUp.getLevel(); + //获取团队分享比例 + BigDecimal manageSubsidyPercent = getManageSubsidyPercent(levelStart, levelUp); + if(manageSubsidyPercent.compareTo(BigDecimal.ZERO) > 0){ + BigDecimal teamManageAmount = subsidyAmount.multiply(manageSubsidyPercent).setScale(BigDecimal.ROUND_DOWN, 2); + //生成团队分享流水 + Long teamManageFlowId = mallMoneyFlowService.addMoneyFlow( + mallMember.getId(), + orderInfo.getOrderNo(), + teamManageAmount, + MallMoneyFlowTypeEnum.SHARE_REWARD_TWO.getCode(), + MallMoneyFlow.STATUS_SUCCESS, + MallMoneyFlow.IS_RETURN_Y, + mallMemberUp.getId(), + FlowTypeEnum.BALANCE.getValue(), + MallMoneyFlowTypeEnum.TEAM_REWARD.getName() + ); + + memberWalletService.addBalance(teamManageAmount,mallMemberUp.getId()); + } + levelStart = levelUp; + } + } + } + + /** + * 根据传入的两个级别,比较之后获取对应的团队管理奖励比例 + * @param levelStart + * @param levelUp + * @return + */ + private BigDecimal getManageSubsidyPercent(String levelStart,String levelUp){ + BigDecimal manageSubsidyPercent = BigDecimal.ZERO; + String agentCodeStart = MemberAgentLevelEnum.AGENT_ONE.getCodeByName(levelStart); + String agentCodeUp = MemberAgentLevelEnum.AGENT_ONE.getCodeByName(levelUp); + int compareLevel = MemberAgentLevelEnum.AGENT_ONE.compareLevel(levelUp, levelStart); + //如果是平级 + if(compareLevel == 2){ + manageSubsidyPercent = getDicSubsidyPercent(agentCodeStart); + } + //如果不是平级 + if(compareLevel == 1){ + //1、初始级别不能是会员 + //2、当前级别的上一个级别是否是levelStart, + // 满足,需要减去levelStart的团队管理奖励 + String minLevel = MemberAgentLevelEnum.AGENT_ONE.minLevel(agentCodeUp); + if(levelStart.equals(minLevel) + && MemberAgentLevelEnum.AGENT.getName() != levelStart){ + BigDecimal dicManageSubsidyPercentUp = getDicManageSubsidyPercent(agentCodeUp); + BigDecimal dicManageSubsidyPercentStart = getDicManageSubsidyPercent(agentCodeStart); + manageSubsidyPercent = dicManageSubsidyPercentUp.subtract(dicManageSubsidyPercentStart); + }else{ + manageSubsidyPercent = getDicManageSubsidyPercent(agentCodeUp); + } + } + return manageSubsidyPercent; + } + + /** + * 获取对应的团队管理奖励比例 + * @param agentCode + * @return + */ + private BigDecimal getDicManageSubsidyPercent(String agentCode){ + BigDecimal manageSubsidyPercent = BigDecimal.ZERO; + DataDictionaryCustom agentDic = dataDictionaryCustomMapper.selectDicDataByTypeAndCode( + DataDictionaryEnum.AGENT_ONE.getType(), + agentCode + ); + cn.hutool.json.JSONObject jsonObject = JSONUtil.parseObj(agentDic.getValue()); + String manageSubsidyPercentStr = jsonObject.get("manageSubsidyPercent").toString(); + manageSubsidyPercent = new BigDecimal(manageSubsidyPercentStr) + .multiply(new BigDecimal(0.01)) + .setScale(BigDecimal.ROUND_DOWN,2); + return manageSubsidyPercent; + } + + /** + * 获取对应的平级团队管理奖励比例 + * @param agentCode + * @return + */ + private BigDecimal getDicSubsidyPercent(String agentCode){ + BigDecimal subsidyPercent = BigDecimal.ZERO; + DataDictionaryCustom agentDic = dataDictionaryCustomMapper.selectDicDataByTypeAndCode( + DataDictionaryEnum.AGENT_ONE.getType(), + agentCode + ); + cn.hutool.json.JSONObject jsonObject = JSONUtil.parseObj(agentDic.getValue()); + String subsidyPercentStr = jsonObject.get("manageSubsidyPercent").toString(); + subsidyPercent = new BigDecimal(subsidyPercentStr) + .multiply(new BigDecimal(0.01)) + .setScale(BigDecimal.ROUND_DOWN,2); + return subsidyPercent; + } + } diff --git a/src/main/java/cc/mrbird/febs/mall/service/impl/ApiMallMemberServiceImpl.java b/src/main/java/cc/mrbird/febs/mall/service/impl/ApiMallMemberServiceImpl.java index 324e026..8b6aae4 100644 --- a/src/main/java/cc/mrbird/febs/mall/service/impl/ApiMallMemberServiceImpl.java +++ b/src/main/java/cc/mrbird/febs/mall/service/impl/ApiMallMemberServiceImpl.java @@ -112,7 +112,7 @@ mallMember.setAccountStatus(MallMember.ACCOUNT_STATUS_ENABLE); mallMember.setAccountType(MallMember.ACCOUNT_TYPE_NORMAL); mallMember.setAccountLevel(MemberAccountLevelEnum.NORMAL.getName()); - mallMember.setLevel(AgentLevelEnum.ZERO_LEVEL.name()); + mallMember.setLevel(MemberAgentLevelEnum.AGENT.getName()); mallMember.setSex("男"); mallMember.setBindPhone(registerDto.getAccount()); diff --git a/src/main/java/cc/mrbird/febs/mall/service/impl/ApiMallOrderInfoServiceImpl.java b/src/main/java/cc/mrbird/febs/mall/service/impl/ApiMallOrderInfoServiceImpl.java index 113348b..54860bf 100644 --- a/src/main/java/cc/mrbird/febs/mall/service/impl/ApiMallOrderInfoServiceImpl.java +++ b/src/main/java/cc/mrbird/febs/mall/service/impl/ApiMallOrderInfoServiceImpl.java @@ -69,6 +69,7 @@ private final MallShoppingCartMapper mallShoppingCartMapper; private final IApiMallMemberService memberService; private final IMallMoneyFlowService mallMoneyFlowService; + private final MallMoneyFlowMapper mallMoneyFlowMapper; private final RedisUtils redisUtils; private final AgentProducer agentProducer; @@ -131,7 +132,8 @@ // orderInfo.setLongitude(address.getLongitude()); orderInfo.setRemark(addOrderDto.getRemark()); orderInfo.setOrderType(addOrderDto.getOrderType()); - + //补贴金额 + orderInfo.setSubsidyAmount(goods.getSubsidyAmount()); if (CollUtil.isEmpty(addOrderDto.getItems())) { throw new FebsException("参数错误"); } @@ -361,46 +363,22 @@ orderInfo.setPayTime(new Date()); orderInfo.setPayResult("1"); -// boolean hasTc = false; - // 静态倍数 -// List<MallOrderItem> orderItems = this.baseMapper.getMallOrderItemByOrderId(orderInfo.getId()); -// if (CollUtil.isNotEmpty(orderItems)) { -// for (MallOrderItem orderItem : orderItems) { -// MallGoods mallGoods = mallGoodsMapper.selectById(orderItem.getGoodsId()); -// BigDecimal score = BigDecimal.ZERO; -// MallGoodsSku sku = mallGoodsSkuMapper.selectById(orderItem.getSkuId()); -// if (mallGoods.getIsNormal() == 2) { -// hasTc = true; -// score = sku.getPresentPrice().multiply(mallGoods.getStaticMulti()).multiply(new BigDecimal(orderItem.getCnt())); -//// BigDecimal staticMulti = mallGoods.getStaticMulti() == null ? BigDecimal.ZERO : mallGoods.getStaticMulti(); -//// score = sku.getPresentPrice().multiply(staticMulti); -// // 普通商品也及时结算,不再10天结算 -// } else { -// score = sku.getPresentPrice(); -// } -// -// if (score.compareTo(BigDecimal.ZERO) > 0) { -// memberWalletService.add(score, member.getId(), "score"); -// mallMoneyFlowService.addMoneyFlow(member.getId(), score, MoneyFlowTypeEnum.STATIC_BONUS.getValue(), orderInfo.getOrderNo(), FlowTypeEnum.SCORE.getValue()); -// -// // 添加业绩 -// mallAchieveService.add(orderItem.getId()); -// } -// } -// } +// mallMoneyFlowService.addMoneyFlow(member.getId(), orderInfo.getAmount().negate(), MoneyFlowTypeEnum.PAY.getValue(), orderInfo.getOrderNo(), FlowTypeEnum.BALANCE.getValue()); + /** + * 生成下单的流水记录 + */ + Long payFlowId = mallMoneyFlowService.addMoneyFlow( + member.getId(), + orderInfo.getOrderNo(), + orderInfo.getAmount().negate().setScale(BigDecimal.ROUND_DOWN, 2), + MallMoneyFlowTypeEnum.PAY.getCode(), + MallMoneyFlow.STATUS_SUCCESS, + MallMoneyFlow.IS_RETURN_N, + member.getId(), + FlowTypeEnum.BALANCE.getValue(), + MallMoneyFlowTypeEnum.PAY.getName() + ); - // 购买套餐后,升级为普通会员 -// if (hasTc) { -// MallMember mallMember = memberMapper.selectById(member.getId()); -// if (AgentLevelEnum.ZERO_LEVEL.name().equals(mallMember.getLevel())) { -// mallMember.setLevel(AgentLevelEnum.FIRST_LEVEL.name()); -// memberMapper.updateById(mallMember); -// } -// } - - mallMoneyFlowService.addMoneyFlow(member.getId(), orderInfo.getAmount().negate(), MoneyFlowTypeEnum.PAY.getValue(), orderInfo.getOrderNo(), FlowTypeEnum.BALANCE.getValue()); -// agentProducer.sendAutoLevelUpMsg(member.getId()); -// agentProducer.sendOrderReturn(orderInfo.getId()); break; case "4": if (orderInfo.getOrderType() != 2) { @@ -600,6 +578,23 @@ orderInfo.setStatus(OrderStatusEnum.FINISH.getValue()); orderInfo.setReceivingTime(new Date()); this.baseMapper.updateById(orderInfo); + /** + * 通过支付流水记录,返回下单金额 + */ + MallMoneyFlow payFlow = mallMoneyFlowMapper.selectOneByMemberIdAndOrderNoAndTypeAndStatusAndIsReturn( + member.getId(), + orderInfo.getOrderNo(), + MallMoneyFlowTypeEnum.PAY.getCode(), + MallMoneyFlow.STATUS_SUCCESS, + MallMoneyFlow.IS_RETURN_N); + if(ObjectUtil.isNotEmpty(payFlow)){ + memberWalletService.addBalance(payFlow.getAmount().negate(),payFlow.getRtMemberId()); + payFlow.setIsReturn(MallMoneyFlow.IS_RETURN_Y); + mallMoneyFlowMapper.updateById(payFlow); + } + //产生补贴流水记录 + agentProducer.sendDirectRewardMsg(orderInfo.getId()); + } @Override diff --git a/src/main/java/cc/mrbird/febs/mall/service/impl/MallMoneyFlowServiceImpl.java b/src/main/java/cc/mrbird/febs/mall/service/impl/MallMoneyFlowServiceImpl.java index 54e1212..4519acc 100644 --- a/src/main/java/cc/mrbird/febs/mall/service/impl/MallMoneyFlowServiceImpl.java +++ b/src/main/java/cc/mrbird/febs/mall/service/impl/MallMoneyFlowServiceImpl.java @@ -49,4 +49,21 @@ public void addMoneyFlow(Long memberId, BigDecimal amount, Integer type, String orderNo, Long rtMemberId, Integer flowType) { this.addMoneyFlow(memberId, amount, type, orderNo, null, null, rtMemberId, null, flowType, null); } + + @Override + public Long addMoneyFlow(Long memberId,String orderNo,BigDecimal amount, Integer type, Integer status, Integer isReturn, Long rtMemberId, Integer flowType, String description) { + MallMoneyFlow flow = new MallMoneyFlow(); + flow.setMemberId(memberId); + flow.setOrderNo(orderNo); + flow.setAmount(amount); + flow.setType(type); + flow.setStatus(status); + flow.setIsReturn(isReturn); + flow.setRtMemberId(rtMemberId); + flow.setFlowType(flowType); + flow.setDescription(description); + this.baseMapper.insert(flow); + return flow.getId(); + } + } diff --git a/src/main/java/cc/mrbird/febs/rabbit/constants/QueueConstants.java b/src/main/java/cc/mrbird/febs/rabbit/constants/QueueConstants.java index 47cee57..bf5cf07 100644 --- a/src/main/java/cc/mrbird/febs/rabbit/constants/QueueConstants.java +++ b/src/main/java/cc/mrbird/febs/rabbit/constants/QueueConstants.java @@ -10,4 +10,5 @@ public static final String AGENT_AUTO_LEVEL_UP = "queue_agent_auto_level_up"; public static final String AGENT_RETURN_MONEY = "queue_agent_return_money"; public static final String ORDER_RETURN_MONEY = "queue_order_return_money"; + public static final String MALL_COIN_DIRECT_REWARD = "queue_mall_coin_direct_reward"; } diff --git a/src/main/java/cc/mrbird/febs/rabbit/consumer/AgentConsumer.java b/src/main/java/cc/mrbird/febs/rabbit/consumer/AgentConsumer.java index 46c50a1..a4e09f8 100644 --- a/src/main/java/cc/mrbird/febs/rabbit/consumer/AgentConsumer.java +++ b/src/main/java/cc/mrbird/febs/rabbit/consumer/AgentConsumer.java @@ -72,4 +72,14 @@ log.error("订单返利异常:", e); } } + + @RabbitListener(queues = QueueConstants.MALL_COIN_DIRECT_REWARD) + public void directReward(Long directRewardId) { + log.info("消费补贴奖励、直推返利、分享奖励直推上级、分享奖励直推上级的直推、团队管理补贴消息:{}", directRewardId); + try { + agentService.directReward(directRewardId); + } catch (Exception e) { + log.error("消费奖励异常", e); + } + } } diff --git a/src/main/java/cc/mrbird/febs/rabbit/enumerates/RabbitQueueEnum.java b/src/main/java/cc/mrbird/febs/rabbit/enumerates/RabbitQueueEnum.java index 90122ca..1bbae80 100644 --- a/src/main/java/cc/mrbird/febs/rabbit/enumerates/RabbitQueueEnum.java +++ b/src/main/java/cc/mrbird/febs/rabbit/enumerates/RabbitQueueEnum.java @@ -4,6 +4,8 @@ @Getter public enum RabbitQueueEnum { + //补贴奖励、直推返利、分享奖励直推上级、分享奖励直推上级的直推、团队管理补贴 + MALL_COIN_DIRECT_REWARD("exchange_mall_coin_direct_reward", "route_key_mall_coin_direct_reward", "queue_mall_coin_direct_reward"), DEFAULT("exchange_default", "route_key_default", "queue_default"), diff --git a/src/main/java/cc/mrbird/febs/rabbit/producter/AgentProducer.java b/src/main/java/cc/mrbird/febs/rabbit/producter/AgentProducer.java index 0ddb24b..2bef42e 100644 --- a/src/main/java/cc/mrbird/febs/rabbit/producter/AgentProducer.java +++ b/src/main/java/cc/mrbird/febs/rabbit/producter/AgentProducer.java @@ -76,4 +76,13 @@ log.info("发送返利消息:{}", orderId); rabbitTemplate.convertAndSend(RabbitQueueEnum.AGENT_REUTRN_MONEY.getExchange(), RabbitQueueEnum.AGENT_REUTRN_MONEY.getRoute(), orderId); } + + /** + * 发送直推奖励消息 + * @param directRewardId 订单ID + */ + public void sendDirectRewardMsg(@NotNull Long directRewardId) { + log.info("发送补贴奖励、直推返利、分享奖励直推上级、分享奖励直推上级的直推、团队管理补贴消息:{}", directRewardId); + rabbitTemplate.convertAndSend(RabbitQueueEnum.MALL_COIN_DIRECT_REWARD.getExchange(), RabbitQueueEnum.MALL_COIN_DIRECT_REWARD.getRoute(), directRewardId); + } } diff --git a/src/main/resources/mapper/modules/MallMemberMapper.xml b/src/main/resources/mapper/modules/MallMemberMapper.xml index 060eb78..97e4d64 100644 --- a/src/main/resources/mapper/modules/MallMemberMapper.xml +++ b/src/main/resources/mapper/modules/MallMemberMapper.xml @@ -400,4 +400,35 @@ select * from mall_member where level=#{level} </select> + + <select id="selectByAccountLevel" resultType="cc.mrbird.febs.mall.entity.MallMember"> + select * from mall_member + where account_level = #{accountLevel} + </select> + + <select id="selectByRefererIdAndAccountLevel" resultType="java.lang.Integer"> + select count(id) from mall_member + where account_level != #{accountLevel} + and referer_id = #{refererId} + </select> + + <select id="selectByReferersIdAndAccountLevel" resultType="java.lang.Integer"> + select count(id) from mall_member + where account_level != #{accountLevel} + and FIND_IN_SET(#{inviteId}, referrer_ids) + </select> + + <update id="updateLevelById"> + update mall_member + set + level = #{level} + where + id = #{id} + </update> + + <select id="selectByReferersIdAndLevel" resultType="java.lang.Integer"> + select count(id) from mall_member + where level = #{level} + and FIND_IN_SET(#{inviteId}, referrer_ids) + </select> </mapper> \ No newline at end of file diff --git a/src/main/resources/mapper/modules/MallMoneyFlowMapper.xml b/src/main/resources/mapper/modules/MallMoneyFlowMapper.xml index 8b00702..de38deb 100644 --- a/src/main/resources/mapper/modules/MallMoneyFlowMapper.xml +++ b/src/main/resources/mapper/modules/MallMoneyFlowMapper.xml @@ -132,4 +132,14 @@ and date_format(created_time, '%Y-%m-%d') = date_format(#{date}, '%Y-%m-%d') and type in (2,3,4) </select> + + <select id="selectOneByMemberIdAndOrderNoAndTypeAndStatusAndIsReturn" resultType="cc.mrbird.febs.mall.entity.MallMoneyFlow"> + select a.* + from mall_money_flow a + where a.memberId = #{memberId} + and a.order_no = #{orderNo} + and a.type = #{type} + and a.status = #{status} + and a.is_return = #{isReturn} + </select> </mapper> \ No newline at end of file -- Gitblit v1.9.1