package cn.lili.modules.wallet.serviceimpl; import cn.lili.common.enums.ResultCode; import cn.lili.common.exception.ServiceException; import cn.lili.common.properties.RocketmqCustomProperties; import cn.lili.common.security.AuthUser; import cn.lili.common.security.context.UserContext; import cn.lili.common.utils.CurrencyUtil; import cn.lili.common.utils.SnowFlake; import cn.lili.common.utils.StringUtils; import cn.lili.modules.member.entity.dos.Member; import cn.lili.modules.member.service.MemberService; import cn.lili.modules.payment.entity.enums.PaymentMethodEnum; import cn.lili.modules.payment.kit.CashierSupport; import cn.lili.modules.system.entity.dos.Setting; import cn.lili.modules.system.entity.dto.WithdrawalSetting; import cn.lili.modules.system.entity.enums.SettingEnum; import cn.lili.modules.system.service.SettingService; import cn.lili.modules.wallet.entity.dos.MemberWallet; import cn.lili.modules.wallet.entity.dos.MemberWithdrawApply; import cn.lili.modules.wallet.entity.dos.WalletLog; import cn.lili.modules.wallet.entity.dto.MemberWalletUpdateDTO; import cn.lili.modules.wallet.entity.dto.MemberWithdrawalMessage; import cn.lili.modules.wallet.entity.dto.TransferResultDTO; import cn.lili.modules.wallet.entity.enums.DepositServiceTypeEnum; import cn.lili.modules.wallet.entity.enums.WithdrawStatusEnum; import cn.lili.modules.wallet.entity.vo.MemberWalletVO; import cn.lili.modules.wallet.mapper.MemberWalletMapper; import cn.lili.modules.wallet.service.MemberWalletService; import cn.lili.modules.wallet.service.MemberWithdrawApplyService; import cn.lili.modules.wallet.service.WalletLogService; import cn.lili.rocketmq.RocketmqSendCallbackBuilder; import cn.lili.rocketmq.tags.MemberTagsEnum; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.google.gson.Gson; import org.apache.rocketmq.spring.core.RocketMQTemplate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.Date; /** * 会员余额业务层实现 * * @author pikachu * @since 2020-02-25 14:10:16 */ @Service public class MemberWalletServiceImpl extends ServiceImpl implements MemberWalletService { @Autowired private RocketMQTemplate rocketMQTemplate; @Autowired private RocketmqCustomProperties rocketmqCustomProperties; /** * 预存款日志 */ @Autowired private WalletLogService walletLogService; /** * 设置 */ @Autowired private SettingService settingService; /** * 会员 */ @Autowired private MemberService memberService; /** * 会员提现申请 */ @Autowired private MemberWithdrawApplyService memberWithdrawApplyService; @Autowired private CashierSupport cashierSupport; @Override public MemberWalletVO getMemberWallet(String memberId) { //构建查询条件 QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.eq("member_id", memberId); //执行查询 MemberWallet memberWallet = this.getOne(queryWrapper, false); //如果没有钱包,则创建钱包 if (memberWallet == null) { memberWallet = this.save(memberId, memberService.getById(memberId).getUsername()); } //返回查询数据 return new MemberWalletVO(memberWallet.getMemberWallet(), memberWallet.getMemberFrozenWallet()); } @Override @Transactional(rollbackFor = Exception.class) public Boolean increaseWithdrawal(MemberWalletUpdateDTO memberWalletUpdateDTO) { //检测会员预存款讯息是否存在,如果不存在则新建 MemberWallet memberWallet = this.checkMemberWallet(memberWalletUpdateDTO.getMemberId()); //余额变动 memberWallet.setMemberWallet(CurrencyUtil.add(memberWallet.getMemberWallet(), memberWalletUpdateDTO.getMoney())); memberWallet.setMemberFrozenWallet(CurrencyUtil.sub(memberWallet.getMemberFrozenWallet(), memberWalletUpdateDTO.getMoney())); this.updateById(memberWallet); //新增预存款日志 WalletLog walletLog = new WalletLog(memberWallet.getMemberName(), memberWalletUpdateDTO); walletLogService.save(walletLog); return true; } @Override @Transactional(rollbackFor = Exception.class) public Boolean increase(MemberWalletUpdateDTO memberWalletUpdateDTO) { //检测会员预存款讯息是否存在,如果不存在则新建 MemberWallet memberWallet = this.checkMemberWallet(memberWalletUpdateDTO.getMemberId()); //新增预存款 memberWallet.setMemberWallet(CurrencyUtil.add(memberWallet.getMemberWallet(), memberWalletUpdateDTO.getMoney())); this.baseMapper.updateById(memberWallet); //新增预存款日志 WalletLog walletLog = new WalletLog(memberWallet.getMemberName(), memberWalletUpdateDTO); walletLogService.save(walletLog); return true; } @Override @Transactional(rollbackFor = Exception.class) public Boolean reduce(MemberWalletUpdateDTO memberWalletUpdateDTO) { //检测会员预存款讯息是否存在,如果不存在则新建 MemberWallet memberWallet = this.checkMemberWallet(memberWalletUpdateDTO.getMemberId()); //减少预存款,需要校验 如果不够扣减预存款 if (0 > CurrencyUtil.sub(memberWallet.getMemberWallet(), memberWalletUpdateDTO.getMoney())) { return false; } memberWallet.setMemberWallet(CurrencyUtil.sub(memberWallet.getMemberWallet(), memberWalletUpdateDTO.getMoney())); //保存记录 this.updateById(memberWallet); //新增预存款日志 WalletLog walletLog = new WalletLog(memberWallet.getMemberName(), memberWalletUpdateDTO, true); walletLogService.save(walletLog); return true; } @Override @Transactional(rollbackFor = Exception.class) public Boolean reduceWithdrawal(MemberWalletUpdateDTO memberWalletUpdateDTO) { //检测会员预存款讯息是否存在,如果不存在则新建 MemberWallet memberWallet = this.checkMemberWallet(memberWalletUpdateDTO.getMemberId()); //减少预存款,需要校验 如果不够扣减预存款 if (0 > CurrencyUtil.sub(memberWallet.getMemberWallet(), memberWalletUpdateDTO.getMoney())) { throw new ServiceException(ResultCode.WALLET_WITHDRAWAL_INSUFFICIENT); } memberWallet.setMemberWallet(CurrencyUtil.sub(memberWallet.getMemberWallet(), memberWalletUpdateDTO.getMoney())); memberWallet.setMemberFrozenWallet(CurrencyUtil.add(memberWallet.getMemberFrozenWallet(), memberWalletUpdateDTO.getMoney())); //修改余额 this.updateById(memberWallet); //新增预存款日志 WalletLog walletLog = new WalletLog(memberWallet.getMemberName(), memberWalletUpdateDTO, true); walletLogService.save(walletLog); return true; } @Override @Transactional(rollbackFor = Exception.class) public Boolean reduceFrozen(MemberWalletUpdateDTO memberWalletUpdateDTO) { //检测会员预存款讯息是否存在,如果不存在则新建 MemberWallet memberWallet = this.checkMemberWallet(memberWalletUpdateDTO.getMemberId()); //校验此金额是否超过冻结金额 if (0 > CurrencyUtil.sub(memberWallet.getMemberFrozenWallet(), memberWalletUpdateDTO.getMoney())) { throw new ServiceException(ResultCode.WALLET_WITHDRAWAL_FROZEN_AMOUNT_INSUFFICIENT); } memberWallet.setMemberFrozenWallet(CurrencyUtil.sub(memberWallet.getMemberFrozenWallet(), memberWalletUpdateDTO.getMoney())); this.updateById(memberWallet); //新增预存款日志 WalletLog walletLog = new WalletLog(memberWallet.getMemberName(), memberWalletUpdateDTO, true); walletLogService.save(walletLog); return true; } /** * 检测会员预存款是否存在,如果不存在则新建 * * @param memberId 会员id */ private MemberWallet checkMemberWallet(String memberId) { //获取会员预存款信息 MemberWallet memberWallet = this.getOne(new QueryWrapper().eq("member_id", memberId), false); //如果会员预存款信息不存在则同步重新建立预存款信息 if (memberWallet == null) { Member member = memberService.getById(memberId); if (member != null) { memberWallet = this.save(memberId, member.getUsername()); } else { throw new ServiceException(ResultCode.USER_AUTHORITY_ERROR); } } return memberWallet; } @Override public void setMemberWalletPassword(Member member, String password) { //对密码进行加密 String pwd = new BCryptPasswordEncoder().encode(password); //校验会员预存款是否存在 QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.eq("member_id", member.getId()); MemberWallet memberWallet = this.getOne(queryWrapper); //如果 预存款信息不为空 执行设置密码 if (memberWallet != null) { memberWallet.setWalletPassword(pwd); this.updateById(memberWallet); } } @Override public Boolean checkPassword() { //获取当前登录会员 AuthUser authUser = UserContext.getCurrentUser(); //构建查询条件 QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.eq("member_id", authUser.getId()); MemberWallet wallet = this.getOne(queryWrapper); return wallet != null && !StringUtils.isEmpty(wallet.getWalletPassword()); } @Override public MemberWallet save(String memberId, String memberName) { //获取会员预存款信息 MemberWallet memberWallet = this.getOne(new QueryWrapper().eq("member_id", memberId)); if (memberWallet != null) { return memberWallet; } memberWallet = new MemberWallet(); memberWallet.setMemberId(memberId); memberWallet.setMemberName(memberName); memberWallet.setMemberWallet(0D); memberWallet.setMemberFrozenWallet(0D); this.save(memberWallet); return memberWallet; } /** * 提现方法 * 1、提现申请冻结用户的余额。 * 2、判断是否需要平台审核。不需要审核则直接调用第三方提现,需要审核则审核通过后调用第三方提现 * * @param price 提现金额 * @return */ @Override @Transactional(rollbackFor = Exception.class) public Boolean applyWithdrawal(Double price, String realName, String connectNumber) { if (price == null || price <= 0 || price > 1000000) { throw new ServiceException(ResultCode.WALLET_WITHDRAWAL_AMOUNT_ERROR); } AuthUser authUser = UserContext.getCurrentUser(); //校验金额是否满足提现,因为是从余额扣减,所以校验的是余额 MemberWalletVO memberWalletVO = this.getMemberWallet(authUser.getId()); if (memberWalletVO.getMemberWallet() < price) { throw new ServiceException(ResultCode.WALLET_WITHDRAWAL_INSUFFICIENT); } //获取提现设置 Setting setting = settingService.get(SettingEnum.WITHDRAWAL_SETTING.name()); WithdrawalSetting withdrawalSetting = new Gson().fromJson(setting.getSettingValue(), WithdrawalSetting.class); //判断金额是否小于最低提现金额 if (price < withdrawalSetting.getMinPrice()) { throw new ServiceException(ResultCode.WALLET_APPLY_MIN_PRICE_ERROR.message()); } //构建审核参数 MemberWithdrawApply memberWithdrawApply = new MemberWithdrawApply(); memberWithdrawApply.setMemberId(authUser.getId()); memberWithdrawApply.setMemberName(authUser.getNickName()); memberWithdrawApply.setApplyMoney(price); memberWithdrawApply.setRealName(realName); memberWithdrawApply.setConnectNumber(connectNumber); //判断提现是否需要审核 if (withdrawalSetting.getApply()) { memberWithdrawApply.setApplyStatus(WithdrawStatusEnum.APPLY.name()); } else { memberWithdrawApply.setApplyStatus(WithdrawStatusEnum.VIA_AUDITING.name()); } memberWithdrawApply.setSn("W" + SnowFlake.getId()); //添加提现申请记录 memberWithdrawApplyService.save(memberWithdrawApply); //扣减余额到冻结金额 this.reduceWithdrawal(new MemberWalletUpdateDTO(price, authUser.getId(), "提现金额已冻结", DepositServiceTypeEnum.WALLET_WITHDRAWAL.name())); //发送余额提现申请消息 MemberWithdrawalMessage memberWithdrawalMessage = new MemberWithdrawalMessage(); memberWithdrawalMessage.setMemberWithdrawApplyId(memberWithdrawApply.getId()); memberWithdrawalMessage.setStatus(memberWithdrawApply.getApplyStatus()); memberWithdrawalMessage.setMemberId(authUser.getId()); memberWithdrawalMessage.setPrice(price); String destination = rocketmqCustomProperties.getMemberTopic() + ":" + MemberTagsEnum.MEMBER_WITHDRAWAL.name(); rocketMQTemplate.asyncSend(destination, memberWithdrawalMessage, RocketmqSendCallbackBuilder.commonCallback()); return true; } @Override public void withdrawal(String withdrawApplyId) { MemberWithdrawApply memberWithdrawApply = memberWithdrawApplyService.getById(withdrawApplyId); memberWithdrawApply.setInspectTime(new Date()); //获取提现设置 Setting setting = settingService.get(SettingEnum.WITHDRAWAL_SETTING.name()); WithdrawalSetting withdrawalSetting = new Gson().fromJson(setting.getSettingValue(), WithdrawalSetting.class); //调用提现方法 TransferResultDTO transferResultDTO = "WECHAT".equals(withdrawalSetting.getType()) ? cashierSupport.transfer(PaymentMethodEnum.WECHAT, memberWithdrawApply) : cashierSupport.transfer(PaymentMethodEnum.ALIPAY, memberWithdrawApply); //成功则扣减冻结金额 //失败则恢复冻结金额 if (transferResultDTO.getResult()) { memberWithdrawApply.setApplyStatus(WithdrawStatusEnum.SUCCESS.name()); } else { memberWithdrawApply.setApplyStatus(WithdrawStatusEnum.ERROR.name()); memberWithdrawApply.setErrorMessage(transferResultDTO.getResponse()); } //修改提现申请 this.memberWithdrawApplyService.updateById(memberWithdrawApply); //发送余额提现申请消息 MemberWithdrawalMessage memberWithdrawalMessage = new MemberWithdrawalMessage(); memberWithdrawalMessage.setMemberWithdrawApplyId(memberWithdrawApply.getId()); memberWithdrawalMessage.setStatus(memberWithdrawApply.getApplyStatus()); memberWithdrawalMessage.setMemberId(memberWithdrawApply.getMemberId()); memberWithdrawalMessage.setPrice(memberWithdrawApply.getApplyMoney()); memberWithdrawalMessage.setStatus(memberWithdrawApply.getApplyStatus()); String destination = rocketmqCustomProperties.getMemberTopic() + ":" + MemberTagsEnum.MEMBER_WITHDRAWAL.name(); rocketMQTemplate.asyncSend(destination, memberWithdrawalMessage, RocketmqSendCallbackBuilder.commonCallback()); } }