feat(mall): 添加会员购买功能并优化节点助力逻辑
- 新增 ApiBalanceBuyDto 类用于会员购买参数接收
- 在 ApiRunVipController 中添加 balanceBuy 方法处理会员购买请求
- 在 IRunVipService 接口中添加 balanceBuy 方法
- 在 RunVipServiceImpl 中实现 balanceBuy 方法的逻辑
- 优化节点助力逻辑,使用最小业绩的节点设置作为标准
- 调整节点助力奖励的计算方式,直接使用碳币数量
- 更新相关的枚举类和 VO 类以支持新的功能
1 files added
8 files modified
| | |
| | | /** |
| | | * 碳币兑换USDT |
| | | */ |
| | | COMMISSION_PAY(16,"购买会员,APP支付{}","购买会员,APP支付"), |
| | | |
| | | /** |
| | | * 碳币兑换USDT |
| | | */ |
| | | BALANCE_OUT_COMMISSION_IN(15,"{}碳币兑换{}USDT","获得USDT"), |
| | | |
| | | /** |
| | |
| | | /** |
| | | * 节点助力 |
| | | */ |
| | | NODE_BALANCE(10,"节点助力碳币{}","节点助力碳币"), |
| | | NODE_COMMISSION(10,"节点助力{}","节点助力"), |
| | | |
| | | /** |
| | | * 获得碳积分 |
| | |
| | | |
| | | import cc.mrbird.febs.common.annotation.SubmitRepeat; |
| | | import cc.mrbird.febs.common.entity.FebsResponse; |
| | | import cc.mrbird.febs.mall.dto.ApiChargeListDto; |
| | | import cc.mrbird.febs.mall.dto.ApiGetRunDateDto; |
| | | import cc.mrbird.febs.mall.dto.ApiGoChargeDto; |
| | | import cc.mrbird.febs.mall.dto.ApiGoChargeInfoDto; |
| | | import cc.mrbird.febs.mall.dto.*; |
| | | import cc.mrbird.febs.mall.service.IRunVipService; |
| | | import cc.mrbird.febs.mall.vo.*; |
| | | import io.swagger.annotations.Api; |
| | |
| | | return new FebsResponse().success().data(iRunVipService.getChargeList(apiChargeListDto)); |
| | | } |
| | | |
| | | @ApiOperation(value = "【购买VIP】APP支付", notes = "【购买VIP】APP支付") |
| | | @PostMapping(value = "/goCharge") |
| | | @SubmitRepeat |
| | | public FebsResponse balanceBuy(@RequestBody @Valid ApiBalanceBuyDto apiBalanceBuyDto) { |
| | | return iRunVipService.balanceBuy(apiBalanceBuyDto); |
| | | } |
| | | |
| | | @ApiOperation(value = "【购买VIP】立即购买", notes = "【购买VIP】立即购买") |
| | | @ApiResponses({ |
| | | @ApiResponse(code = 200, message = "success", response = ApiGoChargeVo.class) |
New file |
| | |
| | | package cc.mrbird.febs.mall.dto; |
| | | |
| | | import io.swagger.annotations.ApiModel; |
| | | import io.swagger.annotations.ApiModelProperty; |
| | | import lombok.Data; |
| | | |
| | | import javax.validation.constraints.NotNull; |
| | | |
| | | @Data |
| | | @ApiModel(value = "ApiBalanceBuyDto", description = "参数接收类") |
| | | public class ApiBalanceBuyDto { |
| | | |
| | | @NotNull(message = "请选择会员") |
| | | @ApiModelProperty(value = "会员ID", example = "123456") |
| | | private Long runVipId; |
| | | |
| | | @NotNull(message = "请输入资金密码") |
| | | @ApiModelProperty(value = "资金密码", example = "123456") |
| | | private String tradeWord; |
| | | |
| | | @NotNull(message = "请选择数量") |
| | | @ApiModelProperty(value = "数量", example = "123456") |
| | | private Integer vipCnt; |
| | | } |
| | |
| | | void releaseScore(BigDecimal amount,Long memberId); |
| | | |
| | | @Async(FebsConstant.ASYNC_POOL) |
| | | void releaseNodeCoin(BigDecimal amount, BigDecimal percent, BigDecimal balanceToCoin, Long memberId); |
| | | void releaseNodeCoin(BigDecimal amount, BigDecimal percent, Long memberId); |
| | | } |
| | |
| | | package cc.mrbird.febs.mall.service; |
| | | |
| | | import cc.mrbird.febs.common.entity.FebsResponse; |
| | | import cc.mrbird.febs.mall.dto.ApiChargeListDto; |
| | | import cc.mrbird.febs.mall.dto.ApiGetRunDateDto; |
| | | import cc.mrbird.febs.mall.dto.ApiGoChargeDto; |
| | | import cc.mrbird.febs.mall.dto.ApiGoChargeInfoDto; |
| | | import cc.mrbird.febs.mall.dto.*; |
| | | import cc.mrbird.febs.mall.entity.RunVip; |
| | | import cc.mrbird.febs.mall.vo.*; |
| | | import com.baomidou.mybatisplus.extension.service.IService; |
| | |
| | | |
| | | FebsResponse goCharge(ApiGoChargeDto apiGoChargeDto); |
| | | |
| | | FebsResponse balanceBuy(ApiBalanceBuyDto apiBalanceBuyDto); |
| | | |
| | | FebsResponse goChargeInfo(ApiGoChargeInfoDto apiGoChargeInfoDto); |
| | | |
| | | List<ApiChargeVo> getChargeList(ApiChargeListDto apiChargeListDto); |
| | |
| | | } |
| | | |
| | | @Override |
| | | public void releaseNodeCoin(BigDecimal amount, BigDecimal percent, BigDecimal balanceToCoin, Long memberId) { |
| | | public void releaseNodeCoin(BigDecimal amount, BigDecimal percent, Long memberId) { |
| | | //实际节点助力的碳币 |
| | | BigDecimal multiply = amount.multiply(percent); |
| | | BigDecimal multiply = amount.multiply(percent).setScale(2,RoundingMode.DOWN); |
| | | if(BigDecimal.ZERO.compareTo(multiply) >=0){ |
| | | return; |
| | | } |
| | | BigDecimal divide = multiply.divide(balanceToCoin, 2, RoundingMode.DOWN); |
| | | if(BigDecimal.ZERO.compareTo(divide) >=0){ |
| | | return; |
| | | } |
| | | walletService.addBalance(divide,memberId); |
| | | walletService.addCommission(multiply,memberId); |
| | | String orderNo = MallUtils.getOrderNum("JD"); |
| | | mallMoneyFlowService.runVipMoneyFlowAdd( |
| | | memberId, |
| | | memberId, |
| | | orderNo, |
| | | FlowTypeEnum.BALANCE.getValue(), |
| | | RunVipMoneyFlowTypeEnum.NODE_BALANCE.getValue(), |
| | | divide, |
| | | StrUtil.format(RunVipMoneyFlowTypeEnum.NODE_BALANCE.getDescription(),divide), |
| | | FlowTypeEnum.COMMISSION.getValue(), |
| | | RunVipMoneyFlowTypeEnum.NODE_COMMISSION.getValue(), |
| | | multiply, |
| | | StrUtil.format(RunVipMoneyFlowTypeEnum.NODE_COMMISSION.getDescription(),multiply), |
| | | YesOrNoEnum.YES.getValue() |
| | | ); |
| | | |
| | |
| | | } |
| | | //获取节点设置 |
| | | List<RunNodeSet> runNodeSets = runNodeSetMapper.selectList(null); |
| | | BigDecimal balanceToCoin = new BigDecimal( |
| | | dataDictionaryCustomMapper.selectDicDataByTypeAndCode( |
| | | RunVipDataDictionaryEnum.RUN_VIP_BALANCE_TO_COIN.getType(), |
| | | RunVipDataDictionaryEnum.RUN_VIP_BALANCE_TO_COIN.getCode()).getValue() |
| | | ).setScale(2, BigDecimal.ROUND_DOWN); |
| | | |
| | | //获取节点设置runNodeSets中orderNumber最小的节点 |
| | | RunNodeSet minRunNodeSet = runNodeSets.stream().min(Comparator.comparingInt(RunNodeSet::getOrderNumber)).orElse(null); |
| | | if(null == minRunNodeSet){ |
| | | return; |
| | | } |
| | | |
| | | DateTime endTime = DateUtil.date(); |
| | | for (MallMember item : mallMembers) { |
| | | //获取总业绩 |
| | | BigDecimal achieve = getDirectAchieve(item.getInviteId(),item.getDirectorTime(),endTime); |
| | | if(BigDecimal.ZERO.compareTo(achieve) >= 0){ |
| | | //判断总业绩是否小于最小业绩 |
| | | if(minRunNodeSet.getMinAchieve().compareTo(achieve) > 0){ |
| | | item.setDirector(YesOrNoEnum.NO.getValue()); |
| | | mallMemberMapper.updateById(item); |
| | | continue; |
| | | } |
| | | BigDecimal nodePercent = getNodePercent(runNodeSets, achieve); |
| | | if(BigDecimal.ZERO.compareTo(nodePercent) >= 0){ |
| | | continue; |
| | | } |
| | | asyncService.releaseNodeCoin(achieve,nodePercent,balanceToCoin,item.getId()); |
| | | asyncService.releaseNodeCoin(achieve,nodePercent,item.getId()); |
| | | item.setDirectorTime(endTime); |
| | | mallMemberMapper.updateById(item); |
| | | } |
| | |
| | | import cc.mrbird.febs.mall.dto.*; |
| | | import cc.mrbird.febs.mall.entity.*; |
| | | import cc.mrbird.febs.mall.mapper.*; |
| | | import cc.mrbird.febs.mall.service.IApiMallMemberWalletService; |
| | | import cc.mrbird.febs.mall.service.IMallMoneyFlowService; |
| | | import cc.mrbird.febs.mall.service.IRunVipService; |
| | | import cc.mrbird.febs.mall.vo.*; |
| | | import cc.mrbird.febs.rabbit.producter.AgentProducer; |
| | |
| | | private final MallMoneyFlowMapper mallMoneyFlowMapper; |
| | | private final MallMemberWalletMapper mallMemberWalletMapper; |
| | | private final MallMemberMapper mallMemberMapper; |
| | | private final IApiMallMemberWalletService walletService; |
| | | private final IMallMoneyFlowService mallMoneyFlowService; |
| | | @Override |
| | | public List<ApiRunVipVo> vipInfo() { |
| | | Long memberId = LoginUserUtil.getLoginUser().getId(); |
| | |
| | | } |
| | | |
| | | @Override |
| | | public FebsResponse balanceBuy(ApiBalanceBuyDto apiBalanceBuyDto) { |
| | | Long memberId = LoginUserUtil.getLoginUser().getId(); |
| | | MallMember mallMember = mallMemberMapper.selectById(memberId); |
| | | if (StrUtil.isBlank(mallMember.getTradePassword())) { |
| | | throw new FebsException("未设置资金密码"); |
| | | } |
| | | |
| | | if (!mallMember.getTradePassword().equals(SecureUtil.md5(apiBalanceBuyDto.getTradeWord()))) { |
| | | throw new FebsException("资金密码错误"); |
| | | } |
| | | Long runVipId = apiBalanceBuyDto.getRunVipId(); |
| | | RunVip runVip = this.baseMapper.selectById(runVipId); |
| | | if(runVip.getState() != YesOrNoEnum.YES.getValue()){ |
| | | throw new FebsException("会员套餐已下架"); |
| | | } |
| | | //价格 |
| | | BigDecimal presentAmount = runVip.getPresentPrice().setScale(2,BigDecimal.ROUND_DOWN); |
| | | MallMemberWallet mallMemberWallet = mallMemberWalletMapper.selectWalletByMemberId(memberId); |
| | | if(mallMemberWallet.getCommission().compareTo(BigDecimal.ZERO) <= 0){ |
| | | throw new FebsException("余额不足"); |
| | | } |
| | | if(mallMemberWallet.getCommission().compareTo(presentAmount) < 0){ |
| | | throw new FebsException("余额不足"); |
| | | } |
| | | |
| | | String orderNo = MallUtils.getOrderNum(); |
| | | walletService.reduceCommission(presentAmount,memberId); |
| | | mallMoneyFlowService.runVipMoneyFlowAdd( |
| | | memberId, |
| | | memberId, |
| | | orderNo, |
| | | FlowTypeEnum.COMMISSION.getValue(), |
| | | RunVipMoneyFlowTypeEnum.COMMISSION_PAY.getValue(), |
| | | presentAmount, |
| | | StrUtil.format(RunVipMoneyFlowTypeEnum.COMMISSION_PAY.getDescription(),presentAmount), |
| | | YesOrNoEnum.YES.getValue() |
| | | ); |
| | | |
| | | MallCharge mallCharge = new MallCharge(); |
| | | mallCharge.setMemberId(memberId); |
| | | mallCharge.setOrderNo(orderNo); |
| | | mallCharge.setState(YesOrNoEnum.YES.getValue()); |
| | | mallCharge.setType(StrUtil.format(RunVipMoneyFlowTypeEnum.COMMISSION_PAY.getDescription(),presentAmount)); |
| | | mallCharge.setAddress(mallMember.getPhone()); |
| | | mallCharge.setAmount(presentAmount); |
| | | mallCharge.setVipCode(runVip.getVipCode()); |
| | | mallCharge.setVipName(runVip.getVipName()); |
| | | mallCharge.setVipCnt(apiBalanceBuyDto.getVipCnt()); |
| | | mallChargeMapper.insert(mallCharge); |
| | | |
| | | agentProducer.sendBuyVipSuccessMsg(mallCharge.getId()); |
| | | |
| | | return new FebsResponse().success().message("操作成功"); |
| | | } |
| | | |
| | | @Override |
| | | public FebsResponse goChargeInfo(ApiGoChargeInfoDto apiGoChargeInfoDto) { |
| | | Long memberId = LoginUserUtil.getLoginUser().getId(); |
| | | String orderNo = apiGoChargeInfoDto.getOrderNo(); |
| | |
| | | private Integer commissionState;//是否允许USDT提现 1是0否 |
| | | @ApiModelProperty(value = "是否允许内转 1-是0-否") |
| | | private Integer insideState;//是否允许内转 1-是0-否 |
| | | |
| | | @ApiModelProperty(value = "是否允许权益升级 1-是0-否") |
| | | private Integer growState;//是否允许权益升级 1-是0-否 |
| | | |
| | | @ApiModelProperty(value = "每日碳积分增长倍数") |
| | | private BigDecimal growthValue;//每日碳积分增长倍数 |
| | | @ApiModelProperty(value = "每日获取碳积分最大值") |
| | | private Integer growthCnt;//每日获取碳积分最大值 |
| | | |
| | | @ApiModelProperty(value = "购买会员返利金额比例(实际支付金额 * rebatePercent = 返利金额)") |
| | | private BigDecimal rebatePercent;//购买会员返利金额比例(实际支付金额 * rebatePercent = 返利金额) |
| | | } |