“mitao”
2026-05-08 5426ae4b1d662b6ede000571a51beaa35463e0f2
feat:白名单用户下单逻辑
3个文件已添加
9个文件已修改
572 ■■■■■ 已修改文件
ruoyi-api/ruoyi-api-account/src/main/java/com/ruoyi/account/api/factory/AppUserWhitelistFallbackFactory.java 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-account/src/main/java/com/ruoyi/account/api/feignClient/AppUserWhitelistClient.java 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-account/src/main/java/com/ruoyi/account/api/vo/AppUserWhitelistMatchVO.java 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/vo/SiteInfoVO.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-order/src/main/java/com/ruoyi/order/api/model/TChargingOrder.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/controller/TAppCouponController.java 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/controller/TAppUserWhitelistController.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/service/TAppUserWhitelistService.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/service/impl/TAppUserWhitelistServiceImpl.java 61 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/TChargingOrderServiceImpl.java 222 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/util/task/TaskUtil.java 152 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-order/src/main/resources/mapper/order/TChargingOrderMapper.xml 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-account/src/main/java/com/ruoyi/account/api/factory/AppUserWhitelistFallbackFactory.java
New file
@@ -0,0 +1,28 @@
package com.ruoyi.account.api.factory;
import com.ruoyi.account.api.feignClient.AppUserWhitelistClient;
import com.ruoyi.account.api.vo.AppUserWhitelistMatchVO;
import com.ruoyi.common.core.domain.R;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.openfeign.FallbackFactory;
import org.springframework.stereotype.Component;
/**
 * 白名单用户服务降级处理
 */
@Component
public class AppUserWhitelistFallbackFactory implements FallbackFactory<AppUserWhitelistClient> {
    private static final Logger log = LoggerFactory.getLogger(AppUserWhitelistFallbackFactory.class);
    @Override
    public AppUserWhitelistClient create(Throwable throwable) {
        log.error("白名单用户服务调用失败:{}", throwable.getMessage());
        return new AppUserWhitelistClient() {
            @Override
            public R<AppUserWhitelistMatchVO> matchWhitelist(Long appUserId, Integer siteId) {
                return R.fail("白名单用户服务调用失败:" + throwable.getMessage());
            }
        };
    }
}
ruoyi-api/ruoyi-api-account/src/main/java/com/ruoyi/account/api/feignClient/AppUserWhitelistClient.java
New file
@@ -0,0 +1,26 @@
package com.ruoyi.account.api.feignClient;
import com.ruoyi.account.api.factory.AppUserWhitelistFallbackFactory;
import com.ruoyi.account.api.vo.AppUserWhitelistMatchVO;
import com.ruoyi.common.core.constant.ServiceNameConstants;
import com.ruoyi.common.core.domain.R;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
/**
 * 白名单用户远程服务
 */
@FeignClient(contextId = "AppUserWhitelistClient", value = ServiceNameConstants.ACCOUNT_SERVICE, fallbackFactory = AppUserWhitelistFallbackFactory.class)
public interface AppUserWhitelistClient {
    /**
     * 根据用户和站点判断是否命中白名单规则
     *
     * @param appUserId APP用户ID
     * @param siteId 站点ID
     * @return 白名单命中结果
     */
    @GetMapping("/t-app-user-whitelist/match")
    R<AppUserWhitelistMatchVO> matchWhitelist(@RequestParam("appUserId") Long appUserId, @RequestParam("siteId") Integer siteId);
}
ruoyi-api/ruoyi-api-account/src/main/java/com/ruoyi/account/api/vo/AppUserWhitelistMatchVO.java
New file
@@ -0,0 +1,31 @@
package com.ruoyi.account.api.vo;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
 * 白名单用户命中结果
 */
@Data
@ApiModel(value = "AppUserWhitelistMatchVO", description = "白名单用户命中结果")
public class AppUserWhitelistMatchVO {
    @ApiModelProperty(value = "是否命中白名单")
    private Boolean matched = false;
    @ApiModelProperty(value = "白名单用户ID")
    @JsonSerialize(using = ToStringSerializer.class)
    private Long whitelistId;
    @ApiModelProperty(value = "享受权益:1=全部免费,2=免电费,3=免服务费")
    private Integer benefitType;
    @ApiModelProperty(value = "白名单电站范围:1=全部电站,2=指定站点,3=指定合作商")
    private Integer scopeType;
    @ApiModelProperty(value = "享受权益名称")
    private String benefitName;
}
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/vo/SiteInfoVO.java
@@ -43,4 +43,13 @@
    private String vehicleBrand;
    @ApiModelProperty(value = "上次选择车辆id")
    private String id;
    @ApiModelProperty(value = "是否命中白名单")
    private Boolean whitelistMatched = false;
    @ApiModelProperty(value = "白名单权益:1=全部免费,2=免电费,3=免服务费")
    private Integer whitelistBenefitType;
    @ApiModelProperty(value = "白名单权益名称")
    private String whitelistBenefitName;
}
ruoyi-api/ruoyi-api-order/src/main/java/com/ruoyi/order/api/model/TChargingOrder.java
@@ -188,6 +188,22 @@
    @TableField("coupon_discount_amount")
    private BigDecimal couponDiscountAmount;
    @ApiModelProperty(value = "是否白名单订单:0=否,1=是")
    @TableField("is_whitelist")
    private Integer isWhitelist;
    @ApiModelProperty(value = "白名单用户ID")
    @TableField("whitelist_id")
    private Long whitelistId;
    @ApiModelProperty(value = "白名单权益:1=全部免费,2=免电费,3=免服务费")
    @TableField("whitelist_benefit_type")
    private Integer whitelistBenefitType;
    @ApiModelProperty(value = "白名单减免金额")
    @TableField("whitelist_discount_amount")
    private BigDecimal whitelistDiscountAmount;
    @ApiModelProperty(value = "会员折扣")
    @TableField("vip_discount")
    private BigDecimal vipDiscount;
ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/controller/TAppCouponController.java
@@ -10,9 +10,11 @@
import com.ruoyi.account.api.model.TAppUser;
import com.ruoyi.account.api.model.TAppUserCar;
import com.ruoyi.account.api.model.TAppUserTag;
import com.ruoyi.account.api.vo.AppUserWhitelistMatchVO;
import com.ruoyi.account.api.query.ExchangeRecordGoodsQuery;
import com.ruoyi.account.service.TAppUserService;
import com.ruoyi.account.service.TAppUserTagService;
import com.ruoyi.account.service.TAppUserWhitelistService;
import com.ruoyi.chargingPile.api.feignClient.ChargingGunClient;
import com.ruoyi.chargingPile.api.model.TChargingGun;
import com.ruoyi.chargingPile.api.model.TChargingPile;
@@ -48,7 +50,6 @@
import javax.annotation.Resource;
import java.math.BigDecimal;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;
@@ -85,6 +86,8 @@
    private TAppUserTagService appUserTagService;
    @Autowired
    private TAppUserService appUserService;
    @Resource
    private TAppUserWhitelistService whitelistService;
    @Autowired
    private RedissonClient redissonClient;
@@ -149,7 +152,7 @@
        String token = SecurityUtils.getToken(ServletUtils.getRequest());
        if(com.ruoyi.common.core.utils.StringUtils.isNotEmpty(token)){
            List<TAppUserCar> cars = appUserCarService.list(new QueryWrapper<TAppUserCar>()
                    .eq("app_user_id",tokenService.getLoginUserApplet().getUserId())
                        .eq("app_user_id",tokenService.getLoginUserApplet().getUserId())
                            .eq("del_flag", 0)
                    .orderByDesc("create_time"));
            if (!cars.isEmpty()){
@@ -157,6 +160,10 @@
                data.setVehicleBrand(cars.get(0).getVehicleBrand());
                data.setId(cars.get(0).getId().toString());
            }
            AppUserWhitelistMatchVO whitelist = whitelistService.matchWhitelist(tokenService.getLoginUserApplet().getUserId(), chargingGun.getSiteId());
            data.setWhitelistMatched(Boolean.TRUE.equals(whitelist.getMatched()));
            data.setWhitelistBenefitType(whitelist.getBenefitType());
            data.setWhitelistBenefitName(whitelist.getBenefitName());
        }
        Integer data2 = otherClient.getAddCarIntegral().getData();
        data.setIntegral(data2);
ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/controller/TAppUserWhitelistController.java
@@ -5,6 +5,7 @@
import com.ruoyi.account.api.dto.AppUserWhitelistQueryDTO;
import com.ruoyi.account.api.dto.AppUserWhitelistSaveDTO;
import com.ruoyi.account.api.model.TAppUserWhitelist;
import com.ruoyi.account.api.vo.AppUserWhitelistMatchVO;
import com.ruoyi.account.api.vo.AppUserWhitelistImportResultVO;
import com.ruoyi.account.service.TAppUserWhitelistService;
import com.ruoyi.common.core.domain.R;
@@ -54,6 +55,12 @@
        return R.ok(whitelistService.detail(id));
    }
    @ApiOperation("判断用户当前站点是否命中白名单")
    @GetMapping("/match")
    public R<AppUserWhitelistMatchVO> match(@RequestParam("appUserId") Long appUserId, @RequestParam("siteId") Integer siteId) {
        return R.ok(whitelistService.matchWhitelist(appUserId, siteId));
    }
    @ApiOperation("新增或修改白名单用户")
    @RequiresPermissions(value = {"/appUserWhitelist/add", "/appUserWhitelist/update"}, logical = Logical.OR)
    @Log(title = "【白名单用户】新增或修改", businessType = BusinessType.INSERT, operatorType = OperatorType.MANAGE)
ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/service/TAppUserWhitelistService.java
@@ -5,6 +5,7 @@
import com.ruoyi.account.api.dto.AppUserWhitelistQueryDTO;
import com.ruoyi.account.api.dto.AppUserWhitelistSaveDTO;
import com.ruoyi.account.api.model.TAppUserWhitelist;
import com.ruoyi.account.api.vo.AppUserWhitelistMatchVO;
import com.ruoyi.account.api.vo.AppUserWhitelistImportResultVO;
import org.springframework.web.multipart.MultipartFile;
@@ -22,4 +23,6 @@
    void deleteByIds(String ids);
    AppUserWhitelistImportResultVO importWhitelist(MultipartFile file) throws Exception;
    AppUserWhitelistMatchVO matchWhitelist(Long appUserId, Integer siteId);
}
ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/service/impl/TAppUserWhitelistServiceImpl.java
@@ -9,6 +9,7 @@
import com.ruoyi.account.api.model.TAppUser;
import com.ruoyi.account.api.model.TAppUserWhitelist;
import com.ruoyi.account.api.model.TAppUserWhitelistSite;
import com.ruoyi.account.api.vo.AppUserWhitelistMatchVO;
import com.ruoyi.account.api.vo.AppUserWhitelistImportErrorVO;
import com.ruoyi.account.api.vo.AppUserWhitelistImportResultVO;
import com.ruoyi.account.mapper.TAppUserWhitelistMapper;
@@ -178,6 +179,66 @@
        return result;
    }
    /**
     * 判断指定用户在指定站点是否命中启用状态的白名单规则
     *
     * @param appUserId APP用户ID
     * @param siteId 站点ID
     * @return 白名单命中结果
     */
    @Override
    public AppUserWhitelistMatchVO matchWhitelist(Long appUserId, Integer siteId) {
        AppUserWhitelistMatchVO emptyResult = new AppUserWhitelistMatchVO();
        if (appUserId == null || siteId == null) {
            return emptyResult;
        }
        TAppUser appUser = appUserService.getById(appUserId);
        if (appUser == null || StringUtils.isBlank(appUser.getPhone())) {
            return emptyResult;
        }
        TAppUserWhitelist whitelist = this.lambdaQuery()
                .eq(TAppUserWhitelist::getPhone, appUser.getPhone())
                .eq(TAppUserWhitelist::getStatus, STATUS_ENABLED)
                .eq(TAppUserWhitelist::getDelFlag, false)
                .last("LIMIT 1")
                .one();
        if (whitelist == null || !isWhitelistScopeMatched(whitelist, siteId)) {
            return emptyResult;
        }
        AppUserWhitelistMatchVO result = new AppUserWhitelistMatchVO();
        result.setMatched(true);
        result.setWhitelistId(whitelist.getId());
        result.setBenefitType(whitelist.getBenefitType());
        result.setScopeType(whitelist.getScopeType());
        result.setBenefitName(getBenefitName(whitelist.getBenefitType()));
        return result;
    }
    /**
     * 根据白名单范围类型判断当前站点是否在可用范围内
     *
     * @param whitelist 白名单配置
     * @param siteId 站点ID
     * @return true=命中范围
     */
    private boolean isWhitelistScopeMatched(TAppUserWhitelist whitelist, Integer siteId) {
        if (Objects.equals(whitelist.getScopeType(), SCOPE_ALL_SITE)) {
            return true;
        }
        if (Objects.equals(whitelist.getScopeType(), SCOPE_SELECTED_SITE)) {
            return whitelistSiteService.lambdaQuery()
                    .eq(TAppUserWhitelistSite::getWhitelistId, whitelist.getId())
                    .eq(TAppUserWhitelistSite::getSiteId, siteId)
                    .count() > 0;
        }
        if (Objects.equals(whitelist.getScopeType(), SCOPE_PARTNER)) {
            R<List<Site>> siteResult = siteClient.getSiteByIds(Collections.singletonList(siteId));
            List<Site> sites = siteResult == null || siteResult.getData() == null ? Collections.emptyList() : siteResult.getData();
            return !sites.isEmpty() && Objects.equals(sites.get(0).getPartnerId(), whitelist.getPartnerId());
        }
        return false;
    }
    private int getImportTitleNum(MultipartFile file) throws Exception {
        try (InputStream inputStream = file.getInputStream(); Workbook workbook = WorkbookFactory.create(inputStream)) {
            Sheet sheet = workbook.getSheetAt(0);
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/TChargingOrderServiceImpl.java
@@ -9,6 +9,7 @@
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.account.api.feignClient.*;
import com.ruoyi.account.api.model.*;
import com.ruoyi.account.api.vo.AppUserWhitelistMatchVO;
import com.ruoyi.account.api.vo.GetAppUserVipDetail;
import com.ruoyi.account.api.vo.GetInviteUser;
import com.ruoyi.chargingPile.api.dto.GetSiteListDTO;
@@ -115,6 +116,9 @@
public class TChargingOrderServiceImpl extends ServiceImpl<TChargingOrderMapper, TChargingOrder> implements TChargingOrderService {
    
    private Logger log = LoggerFactory.getLogger(TChargingOrderServiceImpl.class);
    private static final int WHITELIST_BENEFIT_ALL_FREE = 1;
    private static final int WHITELIST_BENEFIT_ELECTRIC_FREE = 2;
    private static final int WHITELIST_BENEFIT_SERVICE_FREE = 3;
    
    @Resource
    private ChargingGunClient chargingGunClient;
@@ -149,6 +153,8 @@
    
    @Resource
    private AppCouponClient appCouponClient;
    @Resource
    private AppUserWhitelistClient appUserWhitelistClient;
    
    @Resource
    private AppUserVipDetailClient appUserVipDetailClient;
@@ -422,14 +428,32 @@
     * @return
     */
    
    /**
     * 判断订单是否使用余额或余额组合支付
     *
     * @param payMethod 支付方式
     * @return true=余额相关支付方式
     */
    private boolean isBalancePayMode(Integer payMethod) {
        return payMethod != null && (payMethod == 1 || payMethod == 2);
    }
    /**
     * 将金额空值统一转换为两位小数,避免白名单退款和余额退款计算出现空指针
     *
     * @param amount 原始金额
     * @return 非空两位小数金额
     */
    private BigDecimal money(BigDecimal amount) {
        return amount == null ? BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP) : amount.setScale(2, RoundingMode.HALF_UP);
    }
    /**
     * 调整用户余额
     *
     * @param userId 用户ID
     * @param delta 余额变动金额
     */
    private void changeUserBalance(Long userId, BigDecimal delta) {
        if (userId == null || delta == null || delta.compareTo(BigDecimal.ZERO) == 0) {
            return;
@@ -443,6 +467,12 @@
    }
    /**
     * 记录兑换码余额消费流水
     *
     * @param chargingOrder 充电订单
     * @param consumeAmount 消费金额
     */
    private void recordBalanceConsume(TChargingOrder chargingOrder, BigDecimal consumeAmount) {
        if (chargingOrder == null || chargingOrder.getAppUserId() == null || chargingOrder.getId() == null
                || consumeAmount == null || consumeAmount.compareTo(BigDecimal.ZERO) <= 0) {
@@ -458,6 +488,13 @@
        }
    }
    /**
     * 记录兑换码余额退款流水
     *
     * @param chargingOrder 充电订单
     * @param refundAmount 退款金额
     * @param refundNo 退款单号
     */
    private void recordBalanceRefund(TChargingOrder chargingOrder, BigDecimal refundAmount, String refundNo) {
        if (chargingOrder == null || chargingOrder.getAppUserId() == null || chargingOrder.getId() == null
                || refundAmount == null || refundAmount.compareTo(BigDecimal.ZERO) <= 0) {
@@ -474,8 +511,17 @@
        }
    }
    private void finishManualChargingRefund(TChargingOrder chargingOrder, TChargingOrderRefund refund,
                                            BigDecimal refundAmount, BigDecimal balanceRefundAmount, BigDecimal thirdRefundAmount) {
    /**
     * 完成人工退款结果落库,并同步余额退款流水
     *
     * @param chargingOrder 充电订单
     * @param refund 退款记录
     * @param refundAmount 退款总金额
     * @param balanceRefundAmount 余额退款金额
     * @param thirdRefundAmount 三方退款金额
     */
    private void finishManualChargingRefund(TChargingOrder chargingOrder, TChargingOrderRefund refund,
                                                BigDecimal refundAmount, BigDecimal balanceRefundAmount, BigDecimal thirdRefundAmount) {
        chargingOrder.setRefundStatus(2);
        chargingOrder.setRefundAmount(money(chargingOrder.getRefundAmount()).add(refundAmount));
        chargingOrder.setBalanceRefundAmount(money(chargingOrder.getBalanceRefundAmount()).add(balanceRefundAmount));
@@ -489,12 +535,66 @@
        }
    }
    /**
     * 判断订单是否为白名单订单
     *
     * @param chargingOrder 充电订单
     * @return true=白名单订单
     */
    private boolean isWhitelistOrder(TChargingOrder chargingOrder) {
        return chargingOrder != null && Integer.valueOf(1).equals(chargingOrder.getIsWhitelist());
    }
    /**
     * 判断订单是否为白名单全部免费权益
     *
     * @param chargingOrder 充电订单
     * @return true=全部免费白名单订单
     */
    private boolean isWhitelistAllFreeOrder(TChargingOrder chargingOrder) {
        return isWhitelistOrder(chargingOrder)
                && Integer.valueOf(WHITELIST_BENEFIT_ALL_FREE).equals(chargingOrder.getWhitelistBenefitType());
    }
    /**
     * 根据白名单权益计算订单应减免的电费或服务费
     *
     * @param chargingOrder 充电订单
     * @param electrovalence 电费
     * @param serviceCharge 服务费
     * @return 白名单减免金额
     */
    private BigDecimal calculateWhitelistDiscount(TChargingOrder chargingOrder, BigDecimal electrovalence, BigDecimal serviceCharge) {
        if (!isWhitelistOrder(chargingOrder)) {
            return BigDecimal.ZERO;
        }
        if (Integer.valueOf(WHITELIST_BENEFIT_ALL_FREE).equals(chargingOrder.getWhitelistBenefitType())) {
            return money(electrovalence).add(money(serviceCharge)).setScale(4, RoundingMode.HALF_EVEN);
        }
        if (Integer.valueOf(WHITELIST_BENEFIT_ELECTRIC_FREE).equals(chargingOrder.getWhitelistBenefitType())) {
            return money(electrovalence).setScale(4, RoundingMode.HALF_EVEN);
        }
        if (Integer.valueOf(WHITELIST_BENEFIT_SERVICE_FREE).equals(chargingOrder.getWhitelistBenefitType())) {
            return money(serviceCharge).setScale(4, RoundingMode.HALF_EVEN);
        }
        return BigDecimal.ZERO;
    }
    @Override
    public AjaxResult paymentChargingOrder(AddChargingOrder addChargingOrder) {
        Long userId = tokenService.getLoginUserApplet().getUserId();
        TAppUser appUser = appUserClient.getUserById(userId).getData();
        Integer payMethod = addChargingOrder.getPayMethod() == null ? 3 : addChargingOrder.getPayMethod();
        BigDecimal rechargeAmount = money(addChargingOrder.getPaymentAmount());
        TChargingGun tChargingGun = chargingGunClient.getChargingGunById(addChargingOrder.getId()).getData();
        TChargingPile chargingPile = chargingPileClient.getChargingPileById(tChargingGun.getChargingPileId()).getData();
        AppUserWhitelistMatchVO whitelist = appUserWhitelistClient.matchWhitelist(userId, tChargingGun.getSiteId()).getData();
        boolean whitelistMatched = whitelist != null && Boolean.TRUE.equals(whitelist.getMatched());
        if (whitelistMatched) {
            payMethod = 3;
            addChargingOrder.setPayMethod(3);
            addChargingOrder.setAppUserCouponId(null);
        }
        BigDecimal userBalance = money(appUser.getBalance());
        BigDecimal balancePayAmount = BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP);
        BigDecimal thirdPayAmount = rechargeAmount;
@@ -509,6 +609,12 @@
            }
            balancePayAmount = payMethod == 1 ? rechargeAmount : userBalance.min(rechargeAmount).setScale(2, RoundingMode.HALF_UP);
            thirdPayAmount = rechargeAmount.subtract(balancePayAmount).setScale(2, RoundingMode.HALF_UP);
        }
        if (whitelistMatched) {
            balancePayAmount = BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP);
            thirdPayAmount = Integer.valueOf(WHITELIST_BENEFIT_ALL_FREE).equals(whitelist.getBenefitType())
                    ? BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP)
                    : rechargeAmount;
        }
        //查询待支付状态的订单,没有支付则删除订单
        List<TChargingOrder> list = this.list(new LambdaQueryWrapper<TChargingOrder>().eq(TChargingOrder::getAppUserId, userId)
@@ -620,8 +726,6 @@
                chargingOrder.setPlateNum(userCar.getLicensePlate());
            }
        }
        TChargingGun tChargingGun = chargingGunClient.getChargingGunById(addChargingOrder.getId()).getData();
        TChargingPile chargingPile = chargingPileClient.getChargingPileById(tChargingGun.getChargingPileId()).getData();
        chargingOrder.setSiteId(tChargingGun.getSiteId());
        chargingOrder.setChargingPileId(tChargingGun.getChargingPileId());
        chargingOrder.setChargingGunId(addChargingOrder.getId());
@@ -634,6 +738,10 @@
        chargingOrder.setThirdRefundAmount(BigDecimal.ZERO);
        chargingOrder.setRechargeAmount(rechargeAmount);
        chargingOrder.setAppCouponId(addChargingOrder.getAppUserCouponId());
        chargingOrder.setIsWhitelist(whitelistMatched ? 1 : 0);
        chargingOrder.setWhitelistId(whitelistMatched ? whitelist.getWhitelistId() : null);
        chargingOrder.setWhitelistBenefitType(whitelistMatched ? whitelist.getBenefitType() : null);
        chargingOrder.setWhitelistDiscountAmount(BigDecimal.ZERO);
        chargingOrder.setVipDiscountAmount(BigDecimal.ZERO);
        chargingOrder.setOrderSource(1);
        chargingOrder.setTitle("【充电桩充电】" + chargingPile.getNumber() + "号桩/" + tChargingGun.getCode() + "号枪");
@@ -647,7 +755,7 @@
        TAccountingStrategy accountingStrategy = accountingStrategyClient.getAccountingStrategyById(accountingStrategyId).getData();
        
        //直营站点才可以享受会员折扣
        if (!isBalancePayMode(payMethod) && null != appUser.getVipId() && 1 == site.getBusinessCategory()) {
        if (!whitelistMatched && !isBalancePayMode(payMethod) && null != appUser.getVipId() && 1 == site.getBusinessCategory()) {
            TVip vip = vipClient.getInfo1(appUser.getVipId()).getData();
            BigDecimal discount = null;
            if (1 == vip.getType()) {
@@ -692,7 +800,7 @@
            recordBalanceConsume(chargingOrder, balancePayAmount);
        }
        if (thirdPayAmount.compareTo(BigDecimal.ZERO) == 0) {
            return chargingOrderCallback(addChargingOrder.getPaymentType(), chargingOrder.getCode(), "BALANCE", null);
            return chargingOrderCallback(addChargingOrder.getPaymentType(), chargingOrder.getCode(), whitelistMatched ? "WHITELIST" : "BALANCE", null);
        }
        //会员优惠折扣将其计入增加充电时长(增加总充电金额)
        //如果充电总金额未使用完,则需要退回费用=(原金额/总金额)*(总金额-实际充电金额)
@@ -795,7 +903,7 @@
        
        TAppUser appUser = appUserClient.getUserById(chargingOrder.getAppUserId()).getData();
        //判断会员是否还有充电优惠次数,计算会员优惠的折扣金额
        if (null != appUser.getVipId()) {
        if (!isWhitelistOrder(chargingOrder) && null != appUser.getVipId()) {
            GetAppUserVipDetail getAppUserVipDetail = new GetAppUserVipDetail();
            getAppUserVipDetail.setAppUserId(chargingOrder.getAppUserId());
            getAppUserVipDetail.setVipId(appUser.getVipId());
@@ -1162,22 +1270,22 @@
                TChargingOrder chargingOrder = this.getOne(new LambdaQueryWrapper<TChargingOrder>().eq(TChargingOrder::getCode, code));
                if (chargingOrder.getOrderSource() == 1 && chargingOrder.getStatus() == 2
                        && (chargingOrder.getRefundStatus() == null || chargingOrder.getRefundStatus() != 2)) {
                    Integer rechargePaymentType = chargingOrder.getRechargePaymentType();
                    BigDecimal rechargeAmount = money(chargingOrder.getRechargeAmount());
                    BigDecimal totalRefundAmount = isBalancePayMode(chargingOrder.getPayMethod())
                            ? money(chargingOrder.getBalancePayAmount()).add(money(chargingOrder.getThirdPayAmount())).setScale(2, RoundingMode.HALF_UP)
                            : rechargeAmount;
                    BigDecimal thirdRefundAmount = totalRefundAmount.min(money(chargingOrder.getThirdPayAmount())).setScale(2, RoundingMode.HALF_UP);
                    if (!isBalancePayMode(chargingOrder.getPayMethod())) {
                        thirdRefundAmount = totalRefundAmount;
                    }
                    BigDecimal balanceRefundAmount = totalRefundAmount.subtract(thirdRefundAmount).min(money(chargingOrder.getBalancePayAmount())).setScale(2, RoundingMode.HALF_UP);
                        Integer rechargePaymentType = chargingOrder.getRechargePaymentType();
                        BigDecimal rechargeAmount = money(chargingOrder.getRechargeAmount());
                        BigDecimal totalRefundAmount = isBalancePayMode(chargingOrder.getPayMethod())
                                ? money(chargingOrder.getBalancePayAmount()).add(money(chargingOrder.getThirdPayAmount())).setScale(2, RoundingMode.HALF_UP)
                                : rechargeAmount;
                        // 白名单全部免费启动失败同样只记录预估金额,避免未支付订单进入实际退款流程。
                        BigDecimal recordedRefundAmount = isWhitelistAllFreeOrder(chargingOrder) ? rechargeAmount : totalRefundAmount;
                        BigDecimal channelRefundAmount = isWhitelistAllFreeOrder(chargingOrder) ? BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP) : totalRefundAmount;
                        BigDecimal thirdRefundAmount = channelRefundAmount.min(money(chargingOrder.getThirdPayAmount())).setScale(2, RoundingMode.HALF_UP);
                        BigDecimal balanceRefundAmount = channelRefundAmount.subtract(thirdRefundAmount).min(money(chargingOrder.getBalancePayAmount())).setScale(2, RoundingMode.HALF_UP);
                    //构建退款明细
                    TChargingOrderRefund chargingOrderRefund = new TChargingOrderRefund();
                    chargingOrderRefund.setChargingOrderId(chargingOrder.getId());
                    SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
                    chargingOrderRefund.setRefundCode("CDF" + sdf.format(new Date()) + Double.valueOf(Math.random() * 1000).intValue());
                    chargingOrderRefund.setRefundAmount(totalRefundAmount);
                    chargingOrderRefund.setRefundAmount(recordedRefundAmount);
                    chargingOrderRefund.setBalanceRefundAmount(balanceRefundAmount);
                    chargingOrderRefund.setThirdRefundAmount(thirdRefundAmount);
                    chargingOrderRefund.setRefundStatus(1);
@@ -1187,12 +1295,12 @@
                    chargingOrderRefund.setRefundTitle("充电失败");
                    chargingOrderRefund.setRefundContent("充电失败");
                    chargingOrderRefund.setRefundReason("充电失败");
                    chargingOrderRefund.setRefundRemark("全额退款");
                    chargingOrderRefund.setRefundTotalAmount(totalRefundAmount);
                    chargingOrderRefund.setRefundRemark(isWhitelistAllFreeOrder(chargingOrder) ? "白名单全部免费,启动失败记录预估退款金额" : "全额退款");
                    chargingOrderRefund.setRefundTotalAmount(recordedRefundAmount);
                    chargingOrderRefund.setPayAmount(rechargeAmount);
                    chargingOrder.setBalanceRefundAmount(balanceRefundAmount);
                    chargingOrder.setThirdRefundAmount(thirdRefundAmount);
                    chargingOrder.setRefundAmount(totalRefundAmount);
                    chargingOrder.setRefundAmount(recordedRefundAmount);
                    chargingOrder.setRefundStatus(thirdRefundAmount.compareTo(BigDecimal.ZERO) > 0 ? 1 : 2);
                    if (thirdRefundAmount.compareTo(BigDecimal.ZERO) == 0) {
                        if (balanceRefundAmount.compareTo(BigDecimal.ZERO) > 0) {
@@ -1200,7 +1308,7 @@
                            recordBalanceRefund(chargingOrder, balanceRefundAmount, chargingOrderRefund.getRefundCode());
                        }
                        chargingOrderRefund.setRefundStatus(2);
                        chargingOrderRefund.setRefundSerialNumber("BALANCE");
                        chargingOrderRefund.setRefundSerialNumber(isWhitelistAllFreeOrder(chargingOrder) ? "WHITELIST" : "BALANCE");
                        chargingOrderRefund.setRefundTime(LocalDateTime.now());
                        chargingOrderRefundService.save(chargingOrderRefund);
                        this.updateById(chargingOrder);
@@ -2959,7 +3067,7 @@
                //计算优惠券
                BigDecimal couponDiscount = BigDecimal.ZERO;
                if (!isBalancePayMode(chargingOrder.getPayMethod()) && null != chargingOrder.getAppCouponId()) {
                if (!isWhitelistOrder(chargingOrder) && !isBalancePayMode(chargingOrder.getPayMethod()) && null != chargingOrder.getAppCouponId()) {
                    //判断实际充电金额是否满足优惠券使用条件,如果不满足则不适用优惠券。
                    TAppCoupon appCoupon = appCouponClient.getAppCouponById(chargingOrder.getAppCouponId()).getData();
                    String couponJson = appCoupon.getCouponJson();
@@ -3007,6 +3115,23 @@
                        }
                    }
                }
                BigDecimal whitelistDiscount = calculateWhitelistDiscount(chargingOrder, periodElectricPrice_total, serviceCharge_total);
                if (whitelistDiscount.compareTo(BigDecimal.ZERO) > 0) {
                    BigDecimal electricDiscount = BigDecimal.ZERO;
                    BigDecimal serviceDiscount = BigDecimal.ZERO;
                    if (Integer.valueOf(WHITELIST_BENEFIT_ALL_FREE).equals(chargingOrder.getWhitelistBenefitType())) {
                        electricDiscount = periodElectricPrice_total;
                        serviceDiscount = serviceCharge_total;
                    } else if (Integer.valueOf(WHITELIST_BENEFIT_ELECTRIC_FREE).equals(chargingOrder.getWhitelistBenefitType())) {
                        electricDiscount = periodElectricPrice_total;
                    } else if (Integer.valueOf(WHITELIST_BENEFIT_SERVICE_FREE).equals(chargingOrder.getWhitelistBenefitType())) {
                        serviceDiscount = serviceCharge_total;
                    }
                    periodElectricPrice_total = periodElectricPrice_total.subtract(electricDiscount).max(BigDecimal.ZERO);
                    serviceCharge_total = serviceCharge_total.subtract(serviceDiscount).max(BigDecimal.ZERO);
                    refundAmount = refundAmount.add(whitelistDiscount);
                    payAmount = payAmount.subtract(whitelistDiscount).max(BigDecimal.ZERO);
                }
                //优惠券优惠金额
                couponDiscount = couponDiscount.setScale(4, RoundingMode.HALF_EVEN);
                //退款金额+优惠券
@@ -3017,18 +3142,29 @@
                    serviceCharge_total = serviceCharge_total.subtract(couponDiscount);
                }
                chargingOrder.setCouponDiscountAmount(couponDiscount.setScale(2, RoundingMode.HALF_EVEN));
                chargingOrder.setWhitelistDiscountAmount(whitelistDiscount.setScale(2, RoundingMode.HALF_EVEN));
                chargingOrder.setElectrovalence(periodElectricPrice_total.setScale(2, RoundingMode.HALF_EVEN));
                chargingOrder.setServiceCharge(serviceCharge_total.setScale(2, RoundingMode.HALF_EVEN));
                refundAmount = refundAmount.max(BigDecimal.ZERO).setScale(2, RoundingMode.HALF_UP);
                // 白名单全部免费无需实际渠道退款,但财务展示需要将预估预充金额记录到订单退款金额。
                BigDecimal recordedRefundAmount = isWhitelistAllFreeOrder(chargingOrder)
                        ? money(chargingOrder.getRechargeAmount())
                        : refundAmount;
                Integer payMethod = chargingOrder.getPayMethod();
                BigDecimal thirdRefundAmount = BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP);
                BigDecimal balanceRefundAmount = BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP);
                BigDecimal refundableAmount = money(chargingOrder.getThirdPayAmount()).add(money(chargingOrder.getBalancePayAmount())).setScale(2, RoundingMode.HALF_UP);
                // 全部免费订单启动时未拉起支付,渠道可退金额固定为0,避免误触发微信/支付宝/余额退款。
                BigDecimal channelRefundAmount = isWhitelistAllFreeOrder(chargingOrder)
                        ? BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP)
                        : refundAmount.min(refundableAmount).setScale(2, RoundingMode.HALF_UP);
                if (Integer.valueOf(1).equals(payMethod)) {
                    balanceRefundAmount = refundAmount.min(money(chargingOrder.getBalancePayAmount())).setScale(2, RoundingMode.HALF_UP);
                    balanceRefundAmount = channelRefundAmount.min(money(chargingOrder.getBalancePayAmount())).setScale(2, RoundingMode.HALF_UP);
                } else if (Integer.valueOf(2).equals(payMethod)) {
                    thirdRefundAmount = refundAmount.min(money(chargingOrder.getThirdPayAmount())).setScale(2, RoundingMode.HALF_UP);
                    balanceRefundAmount = refundAmount.subtract(thirdRefundAmount).min(money(chargingOrder.getBalancePayAmount())).setScale(2, RoundingMode.HALF_UP);
                    thirdRefundAmount = channelRefundAmount.min(money(chargingOrder.getThirdPayAmount())).setScale(2, RoundingMode.HALF_UP);
                    balanceRefundAmount = channelRefundAmount.subtract(thirdRefundAmount).min(money(chargingOrder.getBalancePayAmount())).setScale(2, RoundingMode.HALF_UP);
                } else {
                    thirdRefundAmount = refundAmount;
                    thirdRefundAmount = channelRefundAmount.min(money(chargingOrder.getThirdPayAmount())).setScale(2, RoundingMode.HALF_UP);
                }
                BigDecimal actualThirdPayAmount = money(chargingOrder.getThirdPayAmount()).subtract(thirdRefundAmount);
                if (actualThirdPayAmount.compareTo(BigDecimal.ZERO) < 0) {
@@ -3038,12 +3174,12 @@
                if (actualBalancePayAmount.compareTo(BigDecimal.ZERO) < 0) {
                    actualBalancePayAmount = BigDecimal.ZERO;
                }
                refundAmount = thirdRefundAmount.add(balanceRefundAmount);
                refundAmount = recordedRefundAmount;
                chargingOrder.setBalanceRefundAmount(balanceRefundAmount.setScale(2, RoundingMode.HALF_UP));
                chargingOrder.setThirdRefundAmount(thirdRefundAmount.setScale(2, RoundingMode.HALF_UP));
                chargingOrder.setPaymentAmount(actualThirdPayAmount.setScale(2, RoundingMode.HALF_EVEN));
                chargingOrder.setRefundAmount(refundAmount.setScale(2, RoundingMode.HALF_EVEN));
                chargingOrder.setRefundStatus(1);
                chargingOrder.setRefundStatus(channelRefundAmount.compareTo(BigDecimal.ZERO) > 0 ? 1 : 2);
                UploadRealTimeMonitoringData asc = uploadRealTimeMonitoringDataService.getDataByOrderCode(chargingOrder.getCode(), "asc");
                UploadRealTimeMonitoringData desc = uploadRealTimeMonitoringDataService.getDataByOrderCode(chargingOrder.getCode(), "desc");
                if(null != asc){
@@ -3146,7 +3282,7 @@
                    //开始构建退款费用
                    refundAmount = refundAmount.setScale(2, RoundingMode.HALF_EVEN);
                    Integer rechargePaymentType = chargingOrder.getRechargePaymentType();
                    if (refundAmount.compareTo(BigDecimal.ZERO) > 0) {
                    if (channelRefundAmount.compareTo(BigDecimal.ZERO) > 0) {
                        //构建退款明细
                        TChargingOrderRefund chargingOrderRefund = new TChargingOrderRefund();
                        chargingOrderRefund.setChargingOrderId(chargingOrder.getId());
@@ -3222,7 +3358,31 @@
                                this.chargingOrderStartupFailureWxRefund(chargingOrderRefund.getRefundCode(), resp.getTradeNo(), "SUCCESS", null);
                            }
                        }
                    }else{
                    } else if (recordedRefundAmount.compareTo(BigDecimal.ZERO) > 0) {
                        TChargingOrderRefund chargingOrderRefund = new TChargingOrderRefund();
                        chargingOrderRefund.setChargingOrderId(chargingOrder.getId());
                        SimpleDateFormat sdf1 = new SimpleDateFormat("yyyyMMddHHmmssSSS");
                        chargingOrderRefund.setRefundCode("CDF" + sdf1.format(new Date()) + (Double.valueOf(Math.random() * 1000).intValue()));
                        chargingOrderRefund.setRefundAmount(recordedRefundAmount);
                        chargingOrderRefund.setBalanceRefundAmount(balanceRefundAmount);
                        chargingOrderRefund.setThirdRefundAmount(thirdRefundAmount);
                        chargingOrderRefund.setRefundStatus(2);
                        chargingOrderRefund.setRefundSerialNumber(isWhitelistAllFreeOrder(chargingOrder) ? "WHITELIST" : "BALANCE");
                        chargingOrderRefund.setPayType(rechargePaymentType);
                        chargingOrderRefund.setCode(chargingOrder.getCode());
                        chargingOrderRefund.setRefundTitle("充电完成退款");
                        chargingOrderRefund.setRefundContent("充电完成退款");
                        chargingOrderRefund.setRefundReason("充电完成退款");
                        chargingOrderRefund.setRefundRemark(isWhitelistAllFreeOrder(chargingOrder) ? "白名单全部免费,记录预估退款金额" : "实际充电消费金额:" + chargingOrder.getPaymentAmount());
                        chargingOrderRefund.setRefundTotalAmount(recordedRefundAmount);
                        chargingOrderRefund.setPayAmount(rechargeAmount);
                        chargingOrderRefund.setRefundTime(LocalDateTime.now());
                        chargingOrderRefundService.save(chargingOrderRefund);
                        chargingOrder.setRefundStatus(2);
                        chargingOrder.setRefundTime(LocalDateTime.now());
                        this.updateById(chargingOrder);
                    } else {
                        //构建退款明细
                        TChargingOrderRefund chargingOrderRefund = new TChargingOrderRefund();
                        chargingOrderRefund.setChargingOrderId(chargingOrder.getId());
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/util/task/TaskUtil.java
@@ -77,6 +77,9 @@
@Slf4j
@Component
public class TaskUtil implements ApplicationListener<WebServerInitializedEvent> {
    private static final int WHITELIST_BENEFIT_ALL_FREE = 1;
    private static final int WHITELIST_BENEFIT_ELECTRIC_FREE = 2;
    private static final int WHITELIST_BENEFIT_SERVICE_FREE = 3;
    @Resource
    private TChargingBillService chargingBillService;
@@ -152,14 +155,78 @@
    /**
     * 判断订单是否使用余额或余额组合支付
     *
     * @param payMethod 支付方式
     * @return true=余额相关支付方式
     */
    private boolean isBalancePayMode(Integer payMethod) {
        return payMethod != null && (payMethod == 1 || payMethod == 2);
    }
    /**
     * 将金额空值统一转换为两位小数,避免补偿结算金额计算出现空指针
     *
     * @param amount 原始金额
     * @return 非空两位小数金额
     */
    private BigDecimal money(BigDecimal amount) {
        return amount == null ? BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP) : amount.setScale(2, RoundingMode.HALF_UP);
    }
    /**
     * 判断订单是否为白名单订单
     *
     * @param order 充电订单
     * @return true=白名单订单
     */
    private boolean isWhitelistOrder(TChargingOrder order) {
        return order != null && Integer.valueOf(1).equals(order.getIsWhitelist());
    }
    /**
     * 判断订单是否为白名单全部免费权益
     *
     * @param order 充电订单
     * @return true=全部免费白名单订单
     */
    private boolean isWhitelistAllFreeOrder(TChargingOrder order) {
        return isWhitelistOrder(order)
                && Integer.valueOf(WHITELIST_BENEFIT_ALL_FREE).equals(order.getWhitelistBenefitType());
    }
    /**
     * 根据白名单权益计算补偿结算时应减免的电费或服务费
     *
     * @param order 充电订单
     * @param electrovalence 电费
     * @param serviceCharge 服务费
     * @return 白名单减免金额
     */
    private BigDecimal calculateWhitelistDiscount(TChargingOrder order, BigDecimal electrovalence, BigDecimal serviceCharge) {
        if (!isWhitelistOrder(order)) {
            return BigDecimal.ZERO;
        }
        if (Integer.valueOf(WHITELIST_BENEFIT_ALL_FREE).equals(order.getWhitelistBenefitType())) {
            return money(electrovalence).add(money(serviceCharge)).setScale(4, RoundingMode.HALF_EVEN);
        }
        if (Integer.valueOf(WHITELIST_BENEFIT_ELECTRIC_FREE).equals(order.getWhitelistBenefitType())) {
            return money(electrovalence).setScale(4, RoundingMode.HALF_EVEN);
        }
        if (Integer.valueOf(WHITELIST_BENEFIT_SERVICE_FREE).equals(order.getWhitelistBenefitType())) {
            return money(serviceCharge).setScale(4, RoundingMode.HALF_EVEN);
        }
        return BigDecimal.ZERO;
    }
    /**
     * 记录兑换码余额退款流水
     *
     * @param order 充电订单
     * @param refundAmount 退款金额
     * @param refundNo 退款单号
     */
    private void recordBalanceRefund(TChargingOrder order, BigDecimal refundAmount, String refundNo) {
        if (order == null || order.getAppUserId() == null || order.getId() == null
                || refundAmount == null || refundAmount.compareTo(BigDecimal.ZERO) <= 0) {
@@ -456,7 +523,7 @@
                                BigDecimal serviceCharge = originalServicePrice;
                                BigDecimal vipDiscountAmount = BigDecimal.ZERO;
                                //计算优惠金额
                                if (null != order.getVipDiscount()) {
                                if (!isWhitelistOrder(order) && null != order.getVipDiscount()) {
                                    //0.58折
                                    vipDiscountAmount = serviceCharge.multiply(new BigDecimal(1).subtract(order.getVipDiscount()));
                                    serviceCharge = serviceCharge.multiply(order.getVipDiscount());
@@ -519,7 +586,7 @@
                    //计算优惠券
                    BigDecimal couponDiscount = BigDecimal.ZERO;
                    if (null != order.getAppCouponId()) {
                    if (!isWhitelistOrder(order) && null != order.getAppCouponId()) {
                        //判断实际充电金额是否满足优惠券使用条件,如果不满足则不适用优惠券。
                        TAppCoupon appCoupon = appCouponClient.getAppCouponById(order.getAppCouponId()).getData();
                        String couponJson = appCoupon.getCouponJson();
@@ -567,6 +634,23 @@
                            }
                        }
                    }
                    BigDecimal whitelistDiscount = calculateWhitelistDiscount(order, periodElectricPrice_total, serviceCharge_total);
                    if (whitelistDiscount.compareTo(BigDecimal.ZERO) > 0) {
                        BigDecimal electricDiscount = BigDecimal.ZERO;
                        BigDecimal serviceDiscount = BigDecimal.ZERO;
                        if (Integer.valueOf(WHITELIST_BENEFIT_ALL_FREE).equals(order.getWhitelistBenefitType())) {
                            electricDiscount = periodElectricPrice_total;
                            serviceDiscount = serviceCharge_total;
                        } else if (Integer.valueOf(WHITELIST_BENEFIT_ELECTRIC_FREE).equals(order.getWhitelistBenefitType())) {
                            electricDiscount = periodElectricPrice_total;
                        } else if (Integer.valueOf(WHITELIST_BENEFIT_SERVICE_FREE).equals(order.getWhitelistBenefitType())) {
                            serviceDiscount = serviceCharge_total;
                        }
                        periodElectricPrice_total = periodElectricPrice_total.subtract(electricDiscount).max(BigDecimal.ZERO);
                        serviceCharge_total = serviceCharge_total.subtract(serviceDiscount).max(BigDecimal.ZERO);
                        refundAmount = refundAmount.add(whitelistDiscount);
                        payAmount = payAmount.subtract(whitelistDiscount).max(BigDecimal.ZERO);
                    }
                    //优惠券优惠金额
                    couponDiscount = couponDiscount.setScale(4, RoundingMode.HALF_EVEN);
                    //退款金额+优惠券
@@ -577,6 +661,8 @@
                        serviceCharge_total = serviceCharge_total.subtract(couponDiscount);
                    }
                    order.setCouponDiscountAmount(couponDiscount.setScale(2, RoundingMode.HALF_EVEN));
                    order.setWhitelistDiscountAmount(whitelistDiscount.setScale(2, RoundingMode.HALF_EVEN));
                    order.setElectrovalence(periodElectricPrice_total.setScale(2, RoundingMode.HALF_EVEN));
                    order.setServiceCharge(serviceCharge_total.setScale(2, RoundingMode.HALF_EVEN));
                    order.setPaymentAmount(payAmount.setScale(2, RoundingMode.HALF_EVEN));
                    order.setRefundAmount(refundAmount.setScale(2, RoundingMode.HALF_EVEN));
@@ -681,25 +767,31 @@
                        //用户推荐奖励
                        chargingOrderService.referralReward(order);
                         //开始构建退款费用
                        //开始构建退款费用
                        refundAmount = refundAmount.setScale(2, RoundingMode.HALF_EVEN);
                        if (refundAmount.compareTo(BigDecimal.ZERO) > 0) {
                            Integer rechargePaymentType = order.getRechargePaymentType();
                            Integer payMethod = order.getPayMethod();
                            BigDecimal thirdRefundAmount = BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP);
                            BigDecimal balanceRefundAmount = BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP);
                            if (Integer.valueOf(1).equals(payMethod)) {
                                balanceRefundAmount = refundAmount.min(money(order.getBalancePayAmount())).setScale(2, RoundingMode.HALF_UP);
                            } else if (Integer.valueOf(2).equals(payMethod)) {
                                thirdRefundAmount = refundAmount.min(money(order.getThirdPayAmount())).setScale(2, RoundingMode.HALF_UP);
                                balanceRefundAmount = refundAmount.subtract(thirdRefundAmount).min(money(order.getBalancePayAmount())).setScale(2, RoundingMode.HALF_UP);
                            } else {
                                thirdRefundAmount = refundAmount;
                            }
                        BigDecimal refundableAmount = money(order.getThirdPayAmount()).add(money(order.getBalancePayAmount())).setScale(2, RoundingMode.HALF_UP);
                        // 白名单全部免费只记录预估预充金额,实际渠道退款金额保持0,防止补偿任务重复发起退款。
                        BigDecimal recordedRefundAmount = isWhitelistAllFreeOrder(order) ? money(order.getRechargeAmount()) : refundAmount;
                        BigDecimal channelRefundAmount = isWhitelistAllFreeOrder(order)
                                ? BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP)
                                : refundAmount.min(refundableAmount).setScale(2, RoundingMode.HALF_UP);
                        Integer rechargePaymentType = order.getRechargePaymentType();
                        Integer payMethod = order.getPayMethod();
                        BigDecimal thirdRefundAmount = BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP);
                        BigDecimal balanceRefundAmount = BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP);
                        if (Integer.valueOf(1).equals(payMethod)) {
                            balanceRefundAmount = channelRefundAmount.min(money(order.getBalancePayAmount())).setScale(2, RoundingMode.HALF_UP);
                        } else if (Integer.valueOf(2).equals(payMethod)) {
                            thirdRefundAmount = channelRefundAmount.min(money(order.getThirdPayAmount())).setScale(2, RoundingMode.HALF_UP);
                            balanceRefundAmount = channelRefundAmount.subtract(thirdRefundAmount).min(money(order.getBalancePayAmount())).setScale(2, RoundingMode.HALF_UP);
                        } else {
                            thirdRefundAmount = channelRefundAmount.min(money(order.getThirdPayAmount())).setScale(2, RoundingMode.HALF_UP);
                        }
                        if (channelRefundAmount.compareTo(BigDecimal.ZERO) > 0) {
                            refundAmount = thirdRefundAmount.add(balanceRefundAmount).setScale(2, RoundingMode.HALF_UP);
                            order.setThirdRefundAmount(thirdRefundAmount);
                            order.setBalanceRefundAmount(balanceRefundAmount);
                            order.setRefundAmount(refundAmount);
                            order.setRefundAmount(recordedRefundAmount);
                            order.setRefundStatus(refundAmount.compareTo(BigDecimal.ZERO) > 0 ? 1 : 2);
                            chargingOrderService.updateById(order);
                            //构建退款明细
@@ -774,6 +866,32 @@
                                    chargingOrderService.chargingOrderStartupFailureWxRefund(chargingOrderRefund.getRefundCode(), resp.getTradeNo(), "SUCCESS", null);
                                }
                            }
                        } else if (recordedRefundAmount.compareTo(BigDecimal.ZERO) > 0) {
                            order.setThirdRefundAmount(thirdRefundAmount);
                            order.setBalanceRefundAmount(balanceRefundAmount);
                            order.setRefundAmount(recordedRefundAmount);
                            order.setRefundStatus(2);
                            chargingOrderService.updateById(order);
                            TChargingOrderRefund chargingOrderRefund = new TChargingOrderRefund();
                            chargingOrderRefund.setChargingOrderId(order.getId());
                            SimpleDateFormat sdfaa = new SimpleDateFormat("yyyyMMddHHmmssSSS");
                            chargingOrderRefund.setRefundCode("CDF" + sdfaa.format(new Date()) + (Double.valueOf(Math.random() * 1000).intValue()));
                            chargingOrderRefund.setRefundAmount(recordedRefundAmount);
                            chargingOrderRefund.setBalanceRefundAmount(balanceRefundAmount);
                            chargingOrderRefund.setThirdRefundAmount(thirdRefundAmount);
                            chargingOrderRefund.setRefundStatus(2);
                            chargingOrderRefund.setRefundSerialNumber("WHITELIST");
                            chargingOrderRefund.setRefundTime(LocalDateTime.now());
                            chargingOrderRefund.setPayType(rechargePaymentType);
                            chargingOrderRefund.setCode(order.getCode());
                            chargingOrderRefund.setRefundTitle("充电完成退款");
                            chargingOrderRefund.setRefundContent("充电完成退款");
                            chargingOrderRefund.setRefundReason("充电完成退款");
                            chargingOrderRefund.setRefundRemark("白名单全部免费,记录预估退款金额");
                            chargingOrderRefund.setRefundTotalAmount(recordedRefundAmount);
                            chargingOrderRefund.setPayAmount(rechargeAmount);
                            chargingOrderRefundService.save(chargingOrderRefund);
                        }
                    }
ruoyi-service/ruoyi-order/src/main/resources/mapper/order/TChargingOrderMapper.xml
@@ -33,6 +33,10 @@
        <result column="order_amount" property="orderAmount"/>
        <result column="app_coupon_id" property="appCouponId"/>
        <result column="coupon_discount_amount" property="couponDiscountAmount"/>
        <result column="is_whitelist" property="isWhitelist"/>
        <result column="whitelist_id" property="whitelistId"/>
        <result column="whitelist_benefit_type" property="whitelistBenefitType"/>
        <result column="whitelist_discount_amount" property="whitelistDiscountAmount"/>
        <result column="vip_discount" property="vipDiscount"/>
        <result column="vip_discount_amount" property="vipDiscountAmount"/>
        <result column="payment_amount" property="paymentAmount"/>
@@ -53,7 +57,7 @@
        charging_pile_id, charging_gun_id,
        start_time, end_time, status, recharge_amount, recharge_payment_type, recharge_payment_status, pay_method, balance_pay_amount, third_pay_amount, balance_refund_amount, third_refund_amount,
        recharge_serial_number,
        order_amount, app_coupon_id, coupon_discount_amount, vip_discount, vip_discount_amount, payment_amount,
        order_amount, app_coupon_id, coupon_discount_amount, is_whitelist, whitelist_id, whitelist_benefit_type, whitelist_discount_amount, vip_discount, vip_discount_amount, payment_amount,
        refund_code,
        refund_amount, refund_status, refund_serial_number, refund_time, create_time,
        del_flag,need_elec,total_electricity