rk
17 小时以前 ab9cd2c82bd64de8e33510db1d1e78a5b3b4de70
server/services/src/main/java/com/doumee/service/business/impl/WithdrawalOrdersServiceImpl.java
@@ -11,12 +11,17 @@
import com.doumee.core.model.PageWrap;
import com.doumee.core.utils.Utils;
import com.doumee.dao.business.DriverInfoMapper;
import com.doumee.dao.business.RevenueMapper;
import com.doumee.dao.business.ShopInfoMapper;
import com.doumee.dao.business.WithdrawalOrdersMapper;
import com.doumee.dao.business.model.DriverInfo;
import com.doumee.dao.business.model.Revenue;
import com.doumee.dao.business.model.ShopInfo;
import com.doumee.dao.business.model.WithdrawalOrders;
import com.doumee.dao.dto.WithdrawalApproveDTO;
import com.doumee.config.alipay.AlipayFundTransUniTransfer;
import com.doumee.dao.dto.AlipayTransferDTO;
import com.doumee.dao.dto.WithdrawalDTO;
import com.doumee.dao.system.SystemUserMapper;
import com.doumee.dao.system.model.SystemUser;
import com.doumee.service.business.WithdrawalOrdersService;
@@ -24,11 +29,15 @@
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.ThreadLocalRandom;
/**
 * 提现申请记录Service实现
@@ -49,6 +58,9 @@
    @Autowired
    private DriverInfoMapper driverInfoMapper;
    @Autowired
    private RevenueMapper revenueMapper;
    @Override
    public Integer create(WithdrawalOrders withdrawalOrders) {
@@ -220,6 +232,7 @@
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void approve(WithdrawalApproveDTO dto) {
        if (dto == null || dto.getId() == null || dto.getStatus() == null) {
            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "审批参数不完整");
@@ -238,15 +251,159 @@
        // 获取当前登录用户
        Integer currentUserId = getCurrentUserId();
        Date now = new Date();
        // 审批通过时,调用支付宝打款
        Integer finalStatus = dto.getStatus();
        String doneInfo = null;
        if (Constants.ONE.equals(dto.getStatus())) {
            String aliAccount = order.getAliAccount();
            String aliName = null;
            // 从司机或门店获取支付宝账户和实名姓名
            if (StringUtils.isBlank(aliAccount)) {
                if (Constants.equalsInteger(order.getMemberType(), Constants.ONE)) {
                    DriverInfo driver = driverInfoMapper.selectOne(new QueryWrapper<DriverInfo>().lambda()
                            .eq(DriverInfo::getMemberId, order.getMemberId())
                            .eq(DriverInfo::getDeleted, Constants.ZERO)
                            .last("limit 1"));
                    if (driver != null) {
                        aliAccount = driver.getAliAccount();
                        aliName = driver.getAliName();
                    }
                } else if (Constants.equalsInteger(order.getMemberType(), Constants.TWO)) {
                    ShopInfo shop = shopInfoMapper.selectOne(new QueryWrapper<ShopInfo>().lambda()
                            .eq(ShopInfo::getRegionMemberId, order.getMemberId())
                            .eq(ShopInfo::getDeleted, Constants.ZERO)
                            .last("limit 1"));
                    if (shop != null) {
                        aliAccount = shop.getAliAccount();
                        aliName = shop.getAliName();
                    }
                }
            } else {
                // 从 WithdrawalOrders 的 aliAccount 查对应姓名
                if (Constants.equalsInteger(order.getMemberType(), Constants.ONE)) {
                    DriverInfo driver = driverInfoMapper.selectOne(new QueryWrapper<DriverInfo>().lambda()
                            .eq(DriverInfo::getMemberId, order.getMemberId())
                            .eq(DriverInfo::getDeleted, Constants.ZERO)
                            .last("limit 1"));
                    if (driver != null) {
                        aliName = driver.getAliName();
                    }
                } else if (Constants.equalsInteger(order.getMemberType(), Constants.TWO)) {
                    ShopInfo shop = shopInfoMapper.selectOne(new QueryWrapper<ShopInfo>().lambda()
                            .eq(ShopInfo::getRegionMemberId, order.getMemberId())
                            .eq(ShopInfo::getDeleted, Constants.ZERO)
                            .last("limit 1"));
                    if (shop != null) {
                        aliName = shop.getAliName();
                    }
                }
            }
            if (StringUtils.isBlank(aliAccount)) {
                throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "支付宝提现账户未配置,无法打款");
            }
            // 金额转换:分 → 元
            Long amountFen = order.getAmount() != null ? order.getAmount() : 0L;
            BigDecimal transAmount = new BigDecimal(amountFen).divide(new BigDecimal(100), 2, BigDecimal.ROUND_HALF_UP);
            AlipayTransferDTO transferDTO = new AlipayTransferDTO();
            transferDTO.setOutBizNo(order.getOutBillNo());
            transferDTO.setTransAmount(transAmount);
            transferDTO.setPayeeAccount(aliAccount);
            transferDTO.setPayeeName(aliName);
            transferDTO.setRemark("提现打款");
            String alipayOrderId;
            try {
                alipayOrderId = AlipayFundTransUniTransfer.transfer(transferDTO);
            } catch (BusinessException e) {
                throw e;
            } catch (Exception e) {
                throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "支付宝打款失败:" + e.getMessage());
            }
            doneInfo = "支付宝转账单号:" + alipayOrderId;
        }
        WithdrawalOrders update = new WithdrawalOrders();
        update.setId(dto.getId());
        update.setStatus(dto.getStatus());
        update.setStatus(finalStatus);
        update.setUserId(currentUserId);
        update.setApproveTime(new Date());
        update.setApproveTime(now);
        update.setApproveRemark(dto.getApproveRemark());
        update.setUpdateTime(new Date());
        update.setUpdateTime(now);
        if (Constants.ONE.equals(finalStatus)) {
            update.setDoneTime(now);
            update.setDoneInfo(doneInfo);
        } else if (doneInfo != null) {
            update.setDoneTime(now);
            update.setDoneInfo(doneInfo);
        }
        withdrawalOrdersMapper.updateById(update);
        // 更新关联的提现 Revenue 记录状态
        // 通过 objId + objType=1(提现业务) + type=1(提现支出) 找到原始提现支出记录
        Revenue withdrawalRevenue = revenueMapper.selectOne(new QueryWrapper<Revenue>().lambda()
                .eq(Revenue::getObjId, order.getId())
                .eq(Revenue::getObjType, Constants.ONE)
                .eq(Revenue::getType, Constants.ONE)
                .eq(Revenue::getDeleted, Constants.ZERO)
                .last("limit 1"));
        if (withdrawalRevenue != null) {
            Integer revenueStatus = Constants.ONE.equals(finalStatus) ? Constants.ZERO : Constants.ONE; // 通过=0成功, 驳回=1失败
            revenueMapper.update(new UpdateWrapper<Revenue>().lambda()
                    .set(Revenue::getStatus, revenueStatus)
                    .set(Revenue::getUpdateTime, now)
                    .eq(Revenue::getId, withdrawalRevenue.getId()));
        }
        // 驳回或打款失败时退回余额
        if (Constants.TWO.equals(finalStatus)) {
            Long amountFen = order.getAmount() != null ? order.getAmount() : 0L;
            if (amountFen > 0 && order.getMemberId() != null) {
                if (Constants.equalsInteger(order.getMemberType(), Constants.ONE)) {
                    // 司机:通过 memberId 查 DriverInfo,退回 balance
                    DriverInfo driver = driverInfoMapper.selectOne(new QueryWrapper<DriverInfo>().lambda()
                            .eq(DriverInfo::getMemberId, order.getMemberId())
                            .eq(DriverInfo::getDeleted, Constants.ZERO)
                            .last("limit 1"));
                    if (driver != null) {
                        driverInfoMapper.update(new UpdateWrapper<DriverInfo>().lambda()
                                .setSql(" BALANCE = IFNULL(BALANCE, 0) + " + amountFen)
                                .eq(DriverInfo::getId, driver.getId()));
                    }
                } else if (Constants.equalsInteger(order.getMemberType(), Constants.TWO)) {
                    // 门店:通过 memberId 查 ShopInfo,退回 balance
                    ShopInfo shop = shopInfoMapper.selectOne(new QueryWrapper<ShopInfo>().lambda()
                            .eq(ShopInfo::getRegionMemberId, order.getMemberId())
                            .eq(ShopInfo::getDeleted, Constants.ZERO)
                            .last("limit 1"));
                    if (shop != null) {
                        shopInfoMapper.update(new UpdateWrapper<ShopInfo>().lambda()
                                .setSql(" BALANCE = IFNULL(BALANCE, 0) + " + amountFen)
                                .eq(ShopInfo::getId, shop.getId()));
                    }
                }
                // 创建退回 Revenue 记录
                Revenue revenue = new Revenue();
                revenue.setMemberId(order.getMemberId());
                revenue.setMemberType(order.getMemberType());
                revenue.setType(Constants.TWO); // 2=提现退回
                revenue.setOptType(Constants.ONE); // 1=收入
                revenue.setAmount(amountFen);
                revenue.setVaildStatus(Constants.ONE); // 已入账
                revenue.setObjId(order.getId());
                revenue.setObjType(Constants.ONE); // 1=提现业务
                revenue.setOrderNo(order.getOutBillNo());
                revenue.setStatus(Constants.ZERO); // 0=成功
                revenue.setDeleted(Constants.ZERO);
                revenue.setCreateTime(now);
                revenueMapper.insert(revenue);
            }
        }
    }
    private Integer getCurrentUserId() {
@@ -289,4 +446,115 @@
        }
    }
    @Override
    public void applyDriverWithdrawal(WithdrawalDTO dto, Integer memberId) {
        DriverInfo driver = driverInfoMapper.selectOne(new QueryWrapper<DriverInfo>().lambda()
                .eq(DriverInfo::getMemberId, memberId)
                .eq(DriverInfo::getDeleted, Constants.ZERO)
                .last("limit 1"));
        if (driver == null) {
            throw new BusinessException(ResponseStatus.DATA_EMPTY.getCode(), "司机信息不存在");
        }
        long amountFen = dto.getAmount().multiply(new BigDecimal(100)).setScale(0, BigDecimal.ROUND_HALF_UP).longValue();
        long balance = driver.getBalance() != null ? driver.getBalance() : 0L;
        if (amountFen <= 0) {
            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "提现金额必须大于0");
        }
        if (amountFen > balance) {
            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "提现金额不能超过可用余额");
        }
        String billNo = generateBillNo();
        Date now = new Date();
        // 扣减司机余额
        driverInfoMapper.update(new UpdateWrapper<DriverInfo>().lambda()
                .setSql(" BALANCE = IFNULL(BALANCE, 0) - " + amountFen)
                .eq(DriverInfo::getId, driver.getId()));
        // 创建提现记录
        WithdrawalOrders order = new WithdrawalOrders();
        order.setMemberId(memberId);
        order.setMemberType(Constants.ONE);
        order.setAmount(amountFen);
        order.setStatus(Constants.ZERO);
        order.setType(Constants.ZERO);
        order.setOutBillNo(billNo);
        order.setAliAccount(dto.getAliAccount());
        order.setDeleted(Constants.ZERO);
        order.setCreateTime(now);
        order.setUpdateTime(now);
        order.setCreateUser(memberId);
        withdrawalOrdersMapper.insert(order);
        // 创建支出 Revenue 记录
        Revenue revenue = new Revenue();
        revenue.setMemberId(memberId);
        revenue.setMemberType(Constants.ONE);
        revenue.setType(Constants.ONE);
        revenue.setOptType(-Constants.ONE);
        revenue.setAmount(amountFen);
        revenue.setVaildStatus(Constants.ONE);
        revenue.setObjId(order.getId());
        revenue.setObjType(Constants.ONE);
        revenue.setOrderNo(billNo);
        revenue.setStatus(Constants.TWO); // 2=处理中
        revenue.setDeleted(Constants.ZERO);
        revenue.setCreateTime(now);
        revenueMapper.insert(revenue);
    }
    @Override
    public void applyShopWithdrawal(WithdrawalDTO dto, Integer shopId) {
        ShopInfo shop = shopInfoMapper.selectById(shopId);
        if (shop == null) {
            throw new BusinessException(ResponseStatus.DATA_EMPTY);
        }
        long amountFen = dto.getAmount().multiply(new BigDecimal(100)).setScale(0, BigDecimal.ROUND_HALF_UP).longValue();
        long balance = shop.getBalance() != null ? shop.getBalance() : 0L;
        if (amountFen <= 0) {
            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "提现金额必须大于0");
        }
        if (amountFen > balance) {
            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "提现金额不能超过可用余额");
        }
        String billNo = generateBillNo();
        Date now = new Date();
        // 扣减门店余额
        shopInfoMapper.update(new UpdateWrapper<ShopInfo>().lambda()
                .setSql(" BALANCE = IFNULL(BALANCE, 0) - " + amountFen)
                .eq(ShopInfo::getId, shopId));
        // 创建提现记录
        WithdrawalOrders order = new WithdrawalOrders();
        order.setMemberId(shop.getRegionMemberId());
        order.setMemberType(Constants.TWO);
        order.setAmount(amountFen);
        order.setStatus(Constants.ZERO);
        order.setType(Constants.ZERO);
        order.setOutBillNo(billNo);
        order.setAliAccount(dto.getAliAccount());
        order.setDeleted(Constants.ZERO);
        order.setCreateTime(now);
        order.setUpdateTime(now);
        order.setCreateUser(shop.getRegionMemberId());
        withdrawalOrdersMapper.insert(order);
        // 创建支出 Revenue 记录
        Revenue revenue = new Revenue();
        revenue.setMemberId(shop.getRegionMemberId());
        revenue.setMemberType(Constants.TWO);
        revenue.setType(Constants.ONE); // 1=提现支出
        revenue.setOptType(-Constants.ONE); // -1=支出
        revenue.setAmount(amountFen);
        revenue.setVaildStatus(Constants.ONE); // 已入账
        revenue.setObjId(order.getId());
        revenue.setObjType(Constants.ONE); // 1=提现业务
        revenue.setOrderNo(billNo);
        revenue.setStatus(Constants.TWO); // 2=处理中
        revenue.setDeleted(Constants.ZERO);
        revenue.setCreateTime(now);
        revenueMapper.insert(revenue);
    }
    private String generateBillNo() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
        String random = String.valueOf(ThreadLocalRandom.current().nextInt(100000, 999999));
        return "TX" + sdf.format(new Date()) + random;
    }
}