package cc.mrbird.febs.mall.service.impl; import cc.mrbird.febs.common.entity.FebsResponse; import cc.mrbird.febs.common.enumerates.FlowTypeEnum; import cc.mrbird.febs.common.enumerates.RunVipDataDictionaryEnum; import cc.mrbird.febs.common.enumerates.RunVipMoneyFlowTypeEnum; import cc.mrbird.febs.common.enumerates.YesOrNoEnum; import cc.mrbird.febs.common.exception.FebsException; import cc.mrbird.febs.common.utils.LoginUserUtil; import cc.mrbird.febs.common.utils.MallUtils; import cc.mrbird.febs.mall.conversion.RunVipConversion; 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; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.date.DateTime; import cn.hutool.core.date.DateUnit; import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.crypto.SecureUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import java.math.BigDecimal; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import java.util.stream.IntStream; @Slf4j @Service @RequiredArgsConstructor public class RunVipServiceImpl extends ServiceImpl implements IRunVipService { private final DataDictionaryCustomMapper dataDictionaryCustomMapper; private final MallMemberPaymentMapper mallMemberPaymentMapper; private final MallChargeMapper mallChargeMapper; private final AgentProducer agentProducer; private final MallMoneyFlowMapper mallMoneyFlowMapper; private final MallMemberWalletMapper mallMemberWalletMapper; private final MallMemberMapper mallMemberMapper; private final IApiMallMemberWalletService walletService; private final IMallMoneyFlowService mallMoneyFlowService; @Override public List vipInfo() { Long memberId = LoginUserUtil.getLoginUser().getId(); List apiRunVipVos = new ArrayList<>(); MallMember mallMember = mallMemberMapper.selectById(memberId); if (StrUtil.isEmpty(mallMember.getLevel())) { return apiRunVipVos; } String level = mallMember.getLevel(); //获取当前用户的VIP等级 RunVip runVip = this.baseMapper.selectOne(new LambdaQueryWrapper().eq(RunVip::getVipCode, level)); //获取大于当前用户等级序号的所有的VIP等级 LambdaQueryWrapper runVipLambdaQueryWrapper = new LambdaQueryWrapper<>(); runVipLambdaQueryWrapper.eq(RunVip::getState, YesOrNoEnum.YES.getValue()); runVipLambdaQueryWrapper.ge(RunVip::getOrderNumber, runVip.getOrderNumber()); List runVips = this.baseMapper.selectList(runVipLambdaQueryWrapper); apiRunVipVos = RunVipConversion.INSTANCE.entityToVos(runVips); return apiRunVipVos; } @Override public FebsResponse goCharge(ApiGoChargeDto apiGoChargeDto) { Long memberId = LoginUserUtil.getLoginUser().getId(); MallMember mallMember = mallMemberMapper.selectById(memberId); if (StrUtil.isBlank(mallMember.getTradePassword())) { throw new FebsException("未设置资金密码"); } if (!mallMember.getTradePassword().equals(SecureUtil.md5(apiGoChargeDto.getTradeWord()))) { throw new FebsException("资金密码错误"); } Long runVipId = apiGoChargeDto.getRunVipId(); RunVip runVip = this.baseMapper.selectById(runVipId); if(runVip.getState() != YesOrNoEnum.YES.getValue()){ throw new FebsException("会员套餐已下架"); } //价格 BigDecimal presentAmount = runVip.getPresentPrice().multiply(new BigDecimal(apiGoChargeDto.getVipCnt())).setScale(2,BigDecimal.ROUND_DOWN); Long addressId = apiGoChargeDto.getAddressId(); MallMemberPayment mallMemberPayment = mallMemberPaymentMapper.selectById(addressId); if(ObjectUtil.isEmpty(mallMemberPayment)){ return new FebsResponse().fail().message("请先绑定你的地址"); } //判断系统的充值地址 String trcType = dataDictionaryCustomMapper.selectDicDataByTypeAndCode( RunVipDataDictionaryEnum.CHARGE_TYPE_TRC.getType(), RunVipDataDictionaryEnum.CHARGE_TYPE_TRC.getCode() ).getValue(); String sysAddress = ""; if(trcType.equals(mallMemberPayment.getBankNo())){ sysAddress = dataDictionaryCustomMapper.selectDicDataByTypeAndCode( RunVipDataDictionaryEnum.CHARGE_SYS_ADDRESS_TRC.getType(), RunVipDataDictionaryEnum.CHARGE_SYS_ADDRESS_TRC.getCode() ).getValue(); }else{ sysAddress = dataDictionaryCustomMapper.selectDicDataByTypeAndCode( RunVipDataDictionaryEnum.CHARGE_SYS_ADDRESS_BSC.getType(), RunVipDataDictionaryEnum.CHARGE_SYS_ADDRESS_BSC.getCode() ).getValue(); } String failMinutes = dataDictionaryCustomMapper.selectDicDataByTypeAndCode( RunVipDataDictionaryEnum.CHARGE_SYS_FAIL_TIME.getType(), RunVipDataDictionaryEnum.CHARGE_SYS_FAIL_TIME.getCode() ).getValue(); DateTime failTime = DateUtil.offsetMinute(DateUtil.date(), Integer.parseInt(failMinutes)); MallCharge mallCharge = new MallCharge(); mallCharge.setMemberId(memberId); mallCharge.setOrderNo(MallUtils.getOrderNum()); mallCharge.setState(YesOrNoEnum.ING.getValue()); mallCharge.setType(mallMemberPayment.getBankNo()); mallCharge.setAddress(mallMemberPayment.getBank()); mallCharge.setAmount(presentAmount); mallCharge.setFailTime(failTime); mallCharge.setSysAddress(sysAddress); mallCharge.setVipCode(runVip.getVipCode()); mallCharge.setVipName(runVip.getVipName()); mallCharge.setVipCnt(apiGoChargeDto.getVipCnt()); mallChargeMapper.insert(mallCharge); ApiGoChargeVo apiGoChargeVo = new ApiGoChargeVo(); apiGoChargeVo.setFailTime(mallCharge.getFailTime()); apiGoChargeVo.setAddress(mallCharge.getAddress()); apiGoChargeVo.setAmount(mallCharge.getAmount()); apiGoChargeVo.setSysAddress(mallCharge.getSysAddress()); apiGoChargeVo.setSysAddressType(mallCharge.getType()); /** * 充值接口调用后,发送一个延时队列 * 功能:延迟时间为【failMinutes】后,更新充值记录为失败。 */ ApiMemberChargeFailDto apiMemberChargeFailDto = new ApiMemberChargeFailDto(); apiMemberChargeFailDto.setChargeId(mallCharge.getId()); apiMemberChargeFailDto.setFailTime(Integer.parseInt(failMinutes) * 60L* 1000L); agentProducer.sendMemberChargeFailMsg(apiMemberChargeFailDto); return new FebsResponse().success().data(apiGoChargeVo); } @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(); LambdaQueryWrapper objectLambdaQueryWrapper = new LambdaQueryWrapper<>(); objectLambdaQueryWrapper.eq(MallCharge::getMemberId,memberId); objectLambdaQueryWrapper.eq(MallCharge::getOrderNo,orderNo); MallCharge mallCharge = mallChargeMapper.selectOne(objectLambdaQueryWrapper); ApiGoChargeVo apiGoChargeVo = new ApiGoChargeVo(); if(null == mallCharge){ throw new FebsException("记录不存在"); } apiGoChargeVo.setFailTime(mallCharge.getFailTime()); apiGoChargeVo.setAddress(mallCharge.getAddress()); apiGoChargeVo.setAmount(mallCharge.getAmount()); apiGoChargeVo.setSysAddress(mallCharge.getSysAddress()); apiGoChargeVo.setSysAddressType(mallCharge.getType()); return new FebsResponse().success().data(apiGoChargeVo); } @Override public List getChargeList(ApiChargeListDto apiChargeListDto) { Long memberId = LoginUserUtil.getLoginUser().getId(); apiChargeListDto.setMemberId(memberId); Page page = new Page<>(apiChargeListDto.getPageNum(), apiChargeListDto.getPageSize()); return mallChargeMapper.selectChargeListInPage(apiChargeListDto, page); } @Override public List getRunDate(ApiGetRunDateDto queryDto) { Long memberId = LoginUserUtil.getLoginUser().getId(); DateTime dateTime = DateUtil.parseDate(queryDto.getDateStr()); DateTime startTime = DateUtil.beginOfMonth(dateTime); DateTime endTime = DateUtil.endOfMonth(dateTime); long between = DateUtil.between(startTime, endTime, DateUnit.DAY); List apiGetRunDateVos = generateDateList(startTime, between); List mallMoneyFlows = mallMoneyFlowMapper.selectList( new LambdaQueryWrapper() .eq(MallMoneyFlow::getMemberId, memberId) .eq(MallMoneyFlow::getFlowType, FlowTypeEnum.SCORE.getValue()) .eq(MallMoneyFlow::getType, RunVipMoneyFlowTypeEnum.SCORE_OUT_BALANCE.getValue()) .ge(MallMoneyFlow::getCreatedTime, startTime) .le(MallMoneyFlow::getCreatedTime, endTime) ); if(CollUtil.isNotEmpty(mallMoneyFlows)){ calculateProfits(apiGetRunDateVos,mallMoneyFlows); } return apiGetRunDateVos; } /** * 生成日期列表 * * @param startDate 开始日期 * @param days 从开始日期算起的天数 * @return 一个包含日期信息的ApiGetRunDateVo对象列表 */ private List generateDateList(DateTime startDate, long days) { // 使用IntStream生成从0到days(包含days)的整数流,表示每一天 return IntStream.range(0, (int) days + 1) // 将每个整数映射为一个ApiGetRunDateVo对象 .mapToObj(i -> { // 创建ApiGetRunDateVo对象 ApiGetRunDateVo apiGetRunDateVo = new ApiGetRunDateVo(); // 计算日期:从起始日期开始偏移i天 DateTime dateTime = DateUtil.offsetDay(startDate, i); // 格式化日期为"yyyy-MM-dd"字符串,并设置到对象中 apiGetRunDateVo.setDateStr(DateUtil.format(dateTime, "yyyy-MM-dd")); // 初始化碳积分为0 apiGetRunDateVo.setScore(BigDecimal.ZERO); // 返回构建好的对象 return apiGetRunDateVo; }) // 将流中的对象收集到一个列表中 .collect(Collectors.toList()); } /** * 计算每日累计碳积分 * * @param dateList 日期列表,包含了每日的碳积分信息 * @param mallMoneyFlows 商城资金流列表,包含了每笔碳积分信息 */ private void calculateProfits(List dateList, List mallMoneyFlows) { // 将日期列表转换为映射,以便通过日期快速访问每日碳积分信息 Map dateMap = dateList.stream() .collect(Collectors.toMap(ApiGetRunDateVo::getDateStr, vo -> vo)); // 遍历mallMoneyFlows for (MallMoneyFlow item : mallMoneyFlows) { // 格式化当前项的创建时间,提取日期 String date = DateUtil.format(item.getCreatedTime(), "yyyy-MM-dd"); // 从日期映射中获取对应的每日碳积分信息 ApiGetRunDateVo apiGetRunDateVo = dateMap.get(date); // 如果找到了对应的每日碳积分信息 if (apiGetRunDateVo != null) { // 获取当前日期的碳积分 BigDecimal score = apiGetRunDateVo.getScore(); // 计算新的碳积分,将碳积分与碳积分相加,并向下取整到个位数 BigDecimal profit = score.add(item.getAmount().abs()).setScale(0,BigDecimal.ROUND_DOWN); // 更新每日碳积分信息的利润值 apiGetRunDateVo.setScore(profit); } } } @Override public ApiRunDataVo runData() { Long memberId = LoginUserUtil.getLoginUser().getId(); ApiRunDataVo apiRunDataVo = new ApiRunDataVo(); MallMember mallMember = mallMemberMapper.selectById(memberId); String level = mallMember.getLevel(); RunVip runVip = this.baseMapper.selectOne(new LambdaQueryWrapper().eq(RunVip::getVipCode, level)); apiRunDataVo.setAimScore(runVip.getGrowthCnt()); List mallMoneyFlows = mallMoneyFlowMapper.selectList( new LambdaQueryWrapper() .eq(MallMoneyFlow::getMemberId, memberId) .eq(MallMoneyFlow::getFlowType, FlowTypeEnum.SCORE.getValue()) .in(MallMoneyFlow::getType, RunVipMoneyFlowTypeEnum.GET_SCORE.getValue(),RunVipMoneyFlowTypeEnum.SYS_SCORE.getValue()) .ge(MallMoneyFlow::getCreatedTime, DateUtil.beginOfDay(DateUtil.date())) .le(MallMoneyFlow::getCreatedTime, DateUtil.endOfDay(DateUtil.date())) ); if(CollUtil.isNotEmpty(mallMoneyFlows)){ BigDecimal reduce = mallMoneyFlows.stream().map(MallMoneyFlow::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add); apiRunDataVo.setScore(reduce.intValue()); } MallMemberWallet mallMemberWallet = mallMemberWalletMapper.selectWalletByMemberId(memberId); apiRunDataVo.setBalance(mallMemberWallet.getBalance()); apiRunDataVo.setRealScore(mallMemberWallet.getScore().intValue()); return apiRunDataVo; } @Override public ApiRunHealthVo runHealth() { Long memberId = LoginUserUtil.getLoginUser().getId(); ApiRunHealthVo apiRunHealthVo = new ApiRunHealthVo(); MallMemberWallet mallMemberWallet = mallMemberWalletMapper.selectWalletByMemberId(memberId); int realScore = mallMemberWallet.getScore().intValue(); apiRunHealthVo.setScore(realScore); List mallMoneyFlows = mallMoneyFlowMapper.selectList( new LambdaQueryWrapper() .eq(MallMoneyFlow::getMemberId, memberId) .eq(MallMoneyFlow::getFlowType, FlowTypeEnum.SCORE.getValue()) .in(MallMoneyFlow::getType, RunVipMoneyFlowTypeEnum.GET_SCORE.getValue(),RunVipMoneyFlowTypeEnum.SYS_SCORE.getValue()) .ge(MallMoneyFlow::getCreatedTime, DateUtil.beginOfDay(DateUtil.date())) .le(MallMoneyFlow::getCreatedTime, DateUtil.endOfDay(DateUtil.date())) ); if(CollUtil.isNotEmpty(mallMoneyFlows)){ BigDecimal reduce = mallMoneyFlows.stream().map(MallMoneyFlow::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add); apiRunHealthVo.setScoreTotal(reduce.intValue()); } List mallMoneyFlowScoreOuts = mallMoneyFlowMapper.selectList( new LambdaQueryWrapper() .eq(MallMoneyFlow::getMemberId, memberId) .eq(MallMoneyFlow::getFlowType, FlowTypeEnum.SCORE.getValue()) .eq(MallMoneyFlow::getType, RunVipMoneyFlowTypeEnum.SCORE_OUT_BALANCE.getValue()) .ge(MallMoneyFlow::getCreatedTime, DateUtil.beginOfDay(DateUtil.date())) .le(MallMoneyFlow::getCreatedTime, DateUtil.endOfDay(DateUtil.date())) ); if(CollUtil.isNotEmpty(mallMoneyFlowScoreOuts)){ BigDecimal reduce = mallMoneyFlowScoreOuts.stream().map(MallMoneyFlow::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add).abs(); apiRunHealthVo.setScoreUsed(reduce.intValue()); } return apiRunHealthVo; } }