|  |  |  | 
|---|
|  |  |  | package com.mzl.flower.service.impl.wallet; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; | 
|---|
|  |  |  | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; | 
|---|
|  |  |  | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; | 
|---|
|  |  |  | import com.mzl.flower.config.PyamentV3Configurer; | 
|---|
|  |  |  | import com.mzl.flower.config.exception.ValidationException; | 
|---|
|  |  |  | import com.mzl.flower.config.security.SecurityUtils; | 
|---|
|  |  |  | import com.mzl.flower.constant.Constants; | 
|---|
|  |  |  | import com.mzl.flower.constant.LockConstants; | 
|---|
|  |  |  | import com.mzl.flower.dto.request.payment.TransferDetailReqDTO; | 
|---|
|  |  |  | import com.mzl.flower.dto.request.payment.TransferReqDTO; | 
|---|
|  |  |  | import com.mzl.flower.dto.request.wallet.CreateWalletWithdrawRecordDTO; | 
|---|
|  |  |  | import com.mzl.flower.dto.request.wallet.QueryWalletWithdrawDTO; | 
|---|
|  |  |  | import com.mzl.flower.dto.request.wallet.WalletWithdrawRecordDTO; | 
|---|
|  |  |  | import com.mzl.flower.dto.response.supplier.SupplierDTO; | 
|---|
|  |  |  | import com.mzl.flower.dto.response.wallet.WalletWithdrawRecordVO; | 
|---|
|  |  |  | import com.mzl.flower.entity.supplier.Supplier; | 
|---|
|  |  |  | import com.mzl.flower.entity.system.UserWechat; | 
|---|
|  |  |  | import com.mzl.flower.entity.wallet.WalletBillRecordDO; | 
|---|
|  |  |  | import com.mzl.flower.entity.wallet.WalletDO; | 
|---|
|  |  |  | import com.mzl.flower.entity.wallet.WalletWithdrawRecordDO; | 
|---|
|  |  |  | import com.mzl.flower.mapper.supplier.SupplierMapper; | 
|---|
|  |  |  | import com.mzl.flower.mapper.system.UserWechatMapper; | 
|---|
|  |  |  | import com.mzl.flower.mapper.wallet.WalletBillRecordMapper; | 
|---|
|  |  |  | import com.mzl.flower.mapper.wallet.WalletMapper; | 
|---|
|  |  |  | import com.mzl.flower.mapper.wallet.WalletWithdrawRecordMapper; | 
|---|
|  |  |  | import com.mzl.flower.service.payment.UserPaymentV3Service; | 
|---|
|  |  |  | import com.mzl.flower.service.supplier.SupplierService; | 
|---|
|  |  |  | import com.mzl.flower.service.wallet.WalletBillRecordService; | 
|---|
|  |  |  | import com.mzl.flower.service.wallet.WalletService; | 
|---|
|  |  |  | import com.mzl.flower.service.wallet.WalletWithdrawRecordService; | 
|---|
|  |  |  | import com.mzl.flower.utils.UUIDGenerator; | 
|---|
|  |  |  | import lombok.RequiredArgsConstructor; | 
|---|
|  |  |  | import lombok.extern.slf4j.Slf4j; | 
|---|
|  |  |  | import org.redisson.api.RLock; | 
|---|
|  |  |  | import org.redisson.api.RedissonClient; | 
|---|
|  |  |  | import org.springframework.beans.BeanUtils; | 
|---|
|  |  |  | import org.springframework.beans.factory.annotation.Autowired; | 
|---|
|  |  |  | import org.springframework.stereotype.Service; | 
|---|
|  |  |  | import org.springframework.transaction.annotation.Transactional; | 
|---|
|  |  |  | import org.springframework.util.ObjectUtils; | 
|---|
|  |  |  | import org.springframework.util.StringUtils; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | import java.math.BigDecimal; | 
|---|
|  |  |  | import java.time.LocalDateTime; | 
|---|
|  |  |  | import java.time.ZoneId; | 
|---|
|  |  |  | import java.time.format.DateTimeFormatter; | 
|---|
|  |  |  | import java.util.ArrayList; | 
|---|
|  |  |  | import java.util.List; | 
|---|
|  |  |  | import java.util.concurrent.TimeUnit; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | 
|---|
|  |  |  | * @author @TaoJie | 
|---|
|  |  |  | * @since 2024-10-22 | 
|---|
|  |  |  | */ | 
|---|
|  |  |  | @Slf4j | 
|---|
|  |  |  | @Service | 
|---|
|  |  |  | @Transactional | 
|---|
|  |  |  | @RequiredArgsConstructor | 
|---|
|  |  |  | 
|---|
|  |  |  | private final WalletWithdrawRecordMapper walletWithdrawRecordMapper; | 
|---|
|  |  |  | private final WalletService walletService; | 
|---|
|  |  |  | private final SupplierService supplierService; | 
|---|
|  |  |  | private final SupplierMapper supplierMapper; | 
|---|
|  |  |  | private final UserWechatMapper wechatMapper; | 
|---|
|  |  |  | private final UserPaymentV3Service paymentV3Service; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | private final WalletBillRecordMapper walletBillRecordMapper; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | private final WalletBillRecordService walletBillRecordService; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | private final WalletMapper walletMapper; | 
|---|
|  |  |  |  | 
|---|
|  |  |  |  | 
|---|
|  |  |  | @Autowired | 
|---|
|  |  |  | 
|---|
|  |  |  |  | 
|---|
|  |  |  | @Override | 
|---|
|  |  |  | public void updateWallet(WalletWithdrawRecordDTO walletWithdrawRecordDTO) { | 
|---|
|  |  |  |  | 
|---|
|  |  |  | WalletWithdrawRecordDO withdrawRecordDO = walletWithdrawRecordMapper.selectById(walletWithdrawRecordDTO.getId()); | 
|---|
|  |  |  | if (withdrawRecordDO == null) { | 
|---|
|  |  |  | throw new ValidationException("提现记录信息不存在"); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | if (StringUtils.isEmpty(walletWithdrawRecordDTO.getApproveState())) { | 
|---|
|  |  |  | throw new ValidationException("审批状态不能为空"); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | if (Constants.WALLET_APPROVE_STATE.REJECT.name().equals(walletWithdrawRecordDTO.getApproveState())) { | 
|---|
|  |  |  | if (StringUtils.isEmpty(walletWithdrawRecordDTO.getRejectReason())) { | 
|---|
|  |  |  | throw new ValidationException("不通过理由不能为空"); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | BeanUtils.copyProperties(walletWithdrawRecordDTO, withdrawRecordDO); | 
|---|
|  |  |  | withdrawRecordDO.update(SecurityUtils.getUserId()); | 
|---|
|  |  |  | withdrawRecordDO.setApproveState(walletWithdrawRecordDTO.getApproveState()); | 
|---|
|  |  |  | withdrawRecordDO.setApproveBy(SecurityUtils.getUserId()); | 
|---|
|  |  |  | withdrawRecordDO.setApproveTime(LocalDateTime.now()); | 
|---|
|  |  |  | walletWithdrawRecordMapper.updateById(withdrawRecordDO); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | //审批通过之后写转账信息 | 
|---|
|  |  |  | if (Constants.WALLET_APPROVE_STATE.APPROVE.name().equals(walletWithdrawRecordDTO.getApproveState())) { | 
|---|
|  |  |  | Supplier s = supplierMapper.selectById(withdrawRecordDO.getSupplierId()); | 
|---|
|  |  |  | String name = ""; | 
|---|
|  |  |  | name = "供应商" + s.getName(); | 
|---|
|  |  |  | UserWechat wechat = wechatMapper.selectOne(new QueryWrapper<UserWechat>().eq("user_id", s.getUserId())); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | if (wechat == null) { | 
|---|
|  |  |  | String msg = name + "未绑定账号无法结算"; | 
|---|
|  |  |  | log.error(msg); | 
|---|
|  |  |  | throw new ValidationException(msg); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | LocalDateTime now = LocalDateTime.now(); | 
|---|
|  |  |  | String day = format(now, "yyyy-MM-dd"); | 
|---|
|  |  |  | String remarks = name + "钱包提现"; | 
|---|
|  |  |  | String appId = PyamentV3Configurer.supplier_app_id; | 
|---|
|  |  |  | TransferReqDTO transferReqDTO = new TransferReqDTO(); | 
|---|
|  |  |  | transferReqDTO.setId(UUIDGenerator.getUUID()); | 
|---|
|  |  |  | transferReqDTO.setAppId(appId); | 
|---|
|  |  |  | transferReqDTO.setName(day + "日" + remarks); | 
|---|
|  |  |  | transferReqDTO.setRemarks(remarks); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | //保存账单信息 | 
|---|
|  |  |  | WalletBillRecordDO walletBillRecordDO = new WalletBillRecordDO(); | 
|---|
|  |  |  | walletBillRecordDO.setSupplierId(s.getId()); | 
|---|
|  |  |  | walletBillRecordDO.setType(Constants.BILL_CHANGE_TYPE.withdraw.name()); | 
|---|
|  |  |  | walletBillRecordDO.setMethod(Constants.BILL_CHANGE_METHOD.reduce.name()); | 
|---|
|  |  |  | walletBillRecordDO.setTransferId(transferReqDTO.getAppId()); | 
|---|
|  |  |  | //提现金额 | 
|---|
|  |  |  | BigDecimal withdrawAmount = withdrawRecordDO.getAmount(); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | if (withdrawAmount.doubleValue() > 0) {//结算金额>0时才去转账 | 
|---|
|  |  |  | TransferDetailReqDTO dr = new TransferDetailReqDTO(); | 
|---|
|  |  |  | dr.setId(UUIDGenerator.getUUID()); | 
|---|
|  |  |  | dr.setAmount(withdrawAmount.multiply(new BigDecimal(100)).longValue()); | 
|---|
|  |  |  | dr.setOpenId(wechat.getOpenId()); | 
|---|
|  |  |  | dr.setRemarks(remarks); | 
|---|
|  |  |  | if (withdrawAmount.doubleValue() >= 2000) { | 
|---|
|  |  |  | dr.setUserName(wechat.getRealName()); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | List<TransferDetailReqDTO> details = new ArrayList<>(); | 
|---|
|  |  |  | details.add(dr); | 
|---|
|  |  |  | walletBillRecordDO.setTransferDetailId(dr.getId()); | 
|---|
|  |  |  | log.info("发起转账"); | 
|---|
|  |  |  | transferReqDTO.setDetails(details); | 
|---|
|  |  |  | //发起转账 | 
|---|
|  |  |  | paymentV3Service.doBatchTransfer(transferReqDTO, SecurityUtils.getUserId()); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | //记录转账状态,定时任务定时获取状态并更新钱包交易记录表信息 | 
|---|
|  |  |  | walletBillRecordDO.setTransferDetailId(Constants.TRANSFER_STATUS.ACCEPTED.name()); | 
|---|
|  |  |  | walletBillRecordMapper.insert(walletBillRecordDO); | 
|---|
|  |  |  | //不需要更新结算单了,此时提现的金额和计算单上的金额不一致 | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | if (Constants.WALLET_APPROVE_STATE.REJECT.name().equals(walletWithdrawRecordDTO.getApproveState())) { | 
|---|
|  |  |  | //更新钱包 | 
|---|
|  |  |  | Supplier s = supplierMapper.selectById(withdrawRecordDO.getSupplierId()); | 
|---|
|  |  |  | WalletDO walletDO = walletService.getBySupplierId(s.getId()); | 
|---|
|  |  |  | if(!ObjectUtils.isEmpty(walletDO)){ | 
|---|
|  |  |  | //提现中金额:审核失败体现中金额扣减 | 
|---|
|  |  |  | walletDO.setWithdrawingAmount(walletDO.getWithdrawingAmount().subtract(withdrawRecordDO.getAmount())); | 
|---|
|  |  |  | //可提现金额:审核失败可提现金额增加 | 
|---|
|  |  |  | walletDO.setWithdrawableAmount(walletDO.getWithdrawableAmount().add(withdrawRecordDO.getAmount())); | 
|---|
|  |  |  | walletMapper.updateById(walletDO); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  | public String format(LocalDateTime dateTime, String format) { | 
|---|
|  |  |  | if (dateTime == null || format == null) { | 
|---|
|  |  |  | return null; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(format).withZone(ZoneId.of("Asia/Shanghai")); | 
|---|
|  |  |  | return dateTimeFormatter.format(dateTime); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|