| | |
| | | |
| | | 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; |
| | |
| | | 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; |
| | | } |
| | | |
| | |
| | | .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 |
| | |
| | | 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)) { |
| | |
| | | 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); |
| | |
| | | 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); |
| | |
| | | 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); |
| | |
| | | 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()); |
| | |
| | | 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) |
| | |
| | | |
| | | 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) { |