puzhibing
2026-09-29 a70433b2ee5bb37823ab73422a01251343cb5f58
ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/service/impl/TAppUserWhitelistServiceImpl.java
@@ -83,9 +83,6 @@
    private static final Pattern PHONE_PATTERN = Pattern.compile("^1\\d{10}$");
    private static final String IMPORT_HEADER_PHONE = "用户手机号";
    private static final int BENEFIT_ALL_FREE = 1;
    private static final int BENEFIT_ELECTRIC_FREE = 2;
    private static final int BENEFIT_SERVICE_FREE = 3;
    private static final int SCOPE_ALL_SITE = 1;
    private static final int SCOPE_SELECTED_SITE = 2;
    private static final int SCOPE_PARTNER = 3;
@@ -346,11 +343,12 @@
        AppUserWhitelistMatchVO result = new AppUserWhitelistMatchVO();
        result.setMatched(true);
        result.setWhitelistId(whitelist.getId());
        result.setBenefitType(whitelist.getBenefitType());
        // 白名单权益已下线(充电完全按企业优惠结算),命中结果不再返回权益类型与名称
        result.setScopeType(whitelist.getScopeType());
        result.setBenefitName(getBenefitName(whitelist.getBenefitType()));
        result.setCompanyId(whitelist.getCompanyId());
        result.setFleetId(whitelist.getFleetId());
        //企业账户分配模式:返回白名单账户可用余额,供建单侧计算下发金额与锁定额度
        result.setBalance(whitelist.getBalance());
        return result;
    }
@@ -364,6 +362,73 @@
                .eq(TAppUserWhitelist::getDelFlag, false)
                .orderByDesc(BasePojo::getCreateTime)
                .list();
    }
    /**
     * 锁定白名单账户余额(企业账户流程-分配模式,实扣冻结):
     * 余额立即扣减并计入 locked_amount,余额不足时条件更新命中 0 行直接失败;
     * 与 VIN/刷卡账户锁定口径一致(T VinManagementServiceImpl/TChargingCardServiceImpl)。
     */
    @Override
    public BigDecimal lockBalance(Long whitelistId, BigDecimal amount) {
        if (whitelistId == null || amount == null || amount.compareTo(BigDecimal.ZERO) <= 0) {
            throw new ServiceException("锁定金额参数错误");
        }
        boolean updated = lambdaUpdate()
                .eq(TAppUserWhitelist::getId, whitelistId)
                .eq(TAppUserWhitelist::getDelFlag, false)
                .ge(TAppUserWhitelist::getBalance, amount)
                .setSql("balance = IFNULL(balance, 0) - " + amount.toPlainString()
                        + ", locked_amount = IFNULL(locked_amount, 0) + " + amount.toPlainString())
                .update();
        if (!updated) {
            throw new ServiceException("白名单账户余额不足");
        }
        TAppUserWhitelist latest = getById(whitelistId);
        return latest == null || latest.getBalance() == null ? BigDecimal.ZERO : latest.getBalance();
    }
    /**
     * 结算白名单账户余额:先释放锁定额,再按实际消费扣减,允许扣成负余额
     * (与 VIN 结算口径一致:balance = balance + locked - actual,locked_amount 归零下限保护)。
     */
    @Override
    public BigDecimal settleBalance(Long whitelistId, BigDecimal lockedAmount, BigDecimal actualAmount) {
        BigDecimal lock = lockedAmount == null ? BigDecimal.ZERO : lockedAmount;
        BigDecimal actual = actualAmount == null ? BigDecimal.ZERO : actualAmount;
        if (whitelistId == null || lock.compareTo(BigDecimal.ZERO) < 0 || actual.compareTo(BigDecimal.ZERO) < 0) {
            throw new ServiceException("结算金额参数错误");
        }
        boolean updated = lambdaUpdate()
                .eq(TAppUserWhitelist::getId, whitelistId)
                .setSql("balance = IFNULL(balance, 0) + " + lock.toPlainString() + " - " + actual.toPlainString()
                        + ", locked_amount = GREATEST(IFNULL(locked_amount, 0) - " + lock.toPlainString() + ", 0)")
                .update();
        if (!updated) {
            throw new ServiceException("白名单用户不存在或已删除");
        }
        TAppUserWhitelist latest = getById(whitelistId);
        return latest == null || latest.getBalance() == null ? BigDecimal.ZERO : latest.getBalance();
    }
    /**
     * 释放白名单账户锁定金额:余额回补、锁定额度扣减(未产生消费/订单回滚时使用)。
     */
    @Override
    public BigDecimal unlockBalance(Long whitelistId, BigDecimal amount) {
        if (whitelistId == null || amount == null || amount.compareTo(BigDecimal.ZERO) <= 0) {
            throw new ServiceException("释放金额参数错误");
        }
        boolean updated = lambdaUpdate()
                .eq(TAppUserWhitelist::getId, whitelistId)
                .setSql("balance = IFNULL(balance, 0) + " + amount.toPlainString()
                        + ", locked_amount = GREATEST(IFNULL(locked_amount, 0) - " + amount.toPlainString() + ", 0)")
                .update();
        if (!updated) {
            throw new ServiceException("白名单用户不存在或已删除");
        }
        TAppUserWhitelist latest = getById(whitelistId);
        return latest == null || latest.getBalance() == null ? BigDecimal.ZERO : latest.getBalance();
    }
    @Override
@@ -512,12 +577,8 @@
            throw new ServiceException("请选择正确的状态");
        }
        saveDTO.setStatus(status);
        // 享受权益不传默认全部免费,传了仍按原规则校验
        Integer benefitType = saveDTO.getBenefitType() == null ? BENEFIT_ALL_FREE : saveDTO.getBenefitType();
        if (!isValidBenefit(benefitType)) {
            throw new ServiceException("请选择正确的享受权益");
        }
        saveDTO.setBenefitType(benefitType);
        // 白名单权益已下线:白名单用户充电完全按企业优惠结算,忽略入参中的享受权益
        saveDTO.setBenefitType(null);
        // 白名单电站不传默认全部电站,传了仍按原规则校验
        Integer scopeType = saveDTO.getScopeType() == null ? SCOPE_ALL_SITE : saveDTO.getScopeType();
        if (!isValidScope(scopeType)) {
@@ -569,7 +630,6 @@
            whitelist.setAppUserId(appUser == null ? null : appUser.getId());
            whitelist.setPhone(saveDTO.getPhone());
            whitelist.setName(saveDTO.getName());
            whitelist.setBenefitType(saveDTO.getBenefitType());
            whitelist.setScopeType(saveDTO.getScopeType());
            whitelist.setPartnerId(resolveWhitelistPartnerId(saveDTO));
            whitelist.setCompanyId(companyId);
@@ -673,7 +733,6 @@
            whitelist.setAppUserId(appUser == null ? null : appUser.getId());
            whitelist.setPhone(saveDTO.getPhone());
            whitelist.setName(saveDTO.getName());
            whitelist.setBenefitType(saveDTO.getBenefitType());
            whitelist.setScopeType(saveDTO.getScopeType());
            whitelist.setPartnerId(resolveWhitelistPartnerId(saveDTO));
            whitelist.setCompanyId(newCompanyId);
@@ -746,11 +805,10 @@
        return errors;
    }
    /** 导入数据统一按默认值处理:全部免费 + 全部电站 + 启用 */
    /** 导入数据统一按默认值处理:全部电站 + 启用(权益已下线,不再写入享受权益) */
    private AppUserWhitelistSaveDTO buildSaveDTO(AppUserWhitelistImportDTO row) {
        AppUserWhitelistSaveDTO dto = new AppUserWhitelistSaveDTO();
        dto.setPhone(normalize(row.getPhone()));
        dto.setBenefitType(BENEFIT_ALL_FREE);
        dto.setScopeType(SCOPE_ALL_SITE);
        dto.setSiteIds(Collections.emptyList());
        dto.setStatus(STATUS_ENABLED);
@@ -765,7 +823,7 @@
        Map<Integer, Partner> partnerMap = getPartnerMap(records, siteMap);
        for (TAppUserWhitelist record : records) {
            record.setUid(record.getId() == null ? null : record.getId().toString());
            record.setBenefitName(getBenefitName(record.getBenefitType()));
            // 白名单权益已下线,列表不再填充享受权益名称
            record.setScopeName(getScopeName(record.getScopeType()));
            if (record.getPartnerId() != null) {
                Partner partner = partnerMap.get(record.getPartnerId());
@@ -1235,12 +1293,6 @@
        return StringUtils.isNotBlank(phone) && PHONE_PATTERN.matcher(phone).matches();
    }
    private boolean isValidBenefit(Integer benefitType) {
        return Objects.equals(benefitType, BENEFIT_ALL_FREE)
                || Objects.equals(benefitType, BENEFIT_ELECTRIC_FREE)
                || Objects.equals(benefitType, BENEFIT_SERVICE_FREE);
    }
    private boolean isValidScope(Integer scopeType) {
        return Objects.equals(scopeType, SCOPE_ALL_SITE)
                || Objects.equals(scopeType, SCOPE_SELECTED_SITE)
@@ -1249,19 +1301,6 @@
    private String normalize(String value) {
        return value == null ? null : value.trim();
    }
    private String getBenefitName(Integer benefitType) {
        if (Objects.equals(benefitType, BENEFIT_ALL_FREE)) {
            return "全部免费";
        }
        if (Objects.equals(benefitType, BENEFIT_ELECTRIC_FREE)) {
            return "免电费";
        }
        if (Objects.equals(benefitType, BENEFIT_SERVICE_FREE)) {
            return "免服务费";
        }
        return "";
    }
    private String getScopeName(Integer scopeType) {