package com.yhy.module.core.service.quota.impl;

import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
import com.yhy.module.core.controller.admin.quota.vo.QuotaResourceRespVO;
import com.yhy.module.core.controller.admin.quota.vo.QuotaResourceSaveReqVO;
import com.yhy.module.core.controller.admin.resource.vo.ResourceItemRespVO;
import com.yhy.module.core.dal.dataobject.quota.QuotaResourceDO;
import com.yhy.module.core.dal.dataobject.resource.ResourceItemDO;
import com.yhy.module.core.dal.dataobject.resource.ResourceMergedDO;
import com.yhy.module.core.dal.mysql.quota.QuotaResourceMapper;
import com.yhy.module.core.dal.mysql.resource.ResourceCatalogItemMapper;
import com.yhy.module.core.dal.mysql.resource.ResourceItemMapper;
import com.yhy.module.core.enums.ErrorCodeConstants;
import com.yhy.module.core.service.quota.QuotaItemService;
import com.yhy.module.core.service.quota.QuotaResourceService;
import com.yhy.module.core.util.ResourcePriceCalculator;
import java.math.BigDecimal;
import java.util.List;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

/**
 * 定额工料机组成 Service 实现类
 * 
 * @author yhy
 */
@Service
@Validated
@Slf4j
public class QuotaResourceServiceImpl implements QuotaResourceService {

    @Resource
    private QuotaResourceMapper quotaResourceMapper;

    @Resource
    private ResourceItemMapper resourceItemMapper;

    @Resource
    private ResourceCatalogItemMapper resourceCatalogItemMapper;

    @Resource
    @Lazy
    private QuotaItemService quotaItemService;

    @Resource
    private com.yhy.module.core.dal.mysql.resource.ResourceMergedMapper resourceMergedMapper;

    @Resource
    @Lazy
    private com.yhy.module.core.service.resource.ResourceMergedService resourceMergedService;

    @Resource
    private com.yhy.module.core.dal.mysql.resource.ResourceCategoryMapper resourceCategoryMapper;

    @Resource
    private com.yhy.module.core.dal.mysql.quota.QuotaAdjustmentSettingMapper quotaAdjustmentSettingMapper;

    @Resource
    private com.yhy.module.core.dal.mysql.quota.QuotaItemMapper quotaItemMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createQuotaResource(QuotaResourceSaveReqVO createReqVO) {
        // 1. 验证工料机是否在范围内
        validateResourceInScope(createReqVO.getQuotaItemId(), createReqVO.getResourceItemId());
        
        // 2. 验证工料机是否存在
        ResourceItemDO resourceItem = resourceItemMapper.selectById(createReqVO.getResourceItemId());
        if (resourceItem == null) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.RESOURCE_ITEM_NOT_EXISTS);
        }
        
        // 3. 转换为 DO
        QuotaResourceDO quotaResource = convertToDO(createReqVO);
        
        // 4. 处理 sortOrder
        if (quotaResource.getSortOrder() == null) {
            // 没有指定 sortOrder，追加到末尾
            Integer maxSortOrder = getMaxSortOrder(createReqVO.getQuotaItemId());
            quotaResource.setSortOrder(maxSortOrder + 1);
        } else {
            // 指定了 sortOrder，需要将该位置及之后的记录的 sortOrder 都 +1
            shiftSortOrdersFrom(createReqVO.getQuotaItemId(), quotaResource.getSortOrder());
        }
        
        // 5. 插入（标准库不需要快照，查询时实时读取）
        quotaResourceMapper.insert(quotaResource);
        
        log.info("[createQuotaResource] 添加定额工料机组成成功，quotaItemId={}, resourceItemId={}", 
            createReqVO.getQuotaItemId(), createReqVO.getResourceItemId());
        
        // 注意：四个价格字段现在是虚拟字段，不需要更新到数据库
        
        return quotaResource.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateQuotaResource(QuotaResourceSaveReqVO updateReqVO) {
        // 校验存在
        validateExists(updateReqVO.getId());
        
        // 验证工料机是否在范围内（如果修改了 resourceItemId）
        QuotaResourceDO existing = quotaResourceMapper.selectById(updateReqVO.getId());
        if (!existing.getResourceItemId().equals(updateReqVO.getResourceItemId())) {
            validateResourceInScope(updateReqVO.getQuotaItemId(), updateReqVO.getResourceItemId());
            
            // 验证新的工料机是否存在
            ResourceItemDO resourceItem = resourceItemMapper.selectById(updateReqVO.getResourceItemId());
            if (resourceItem == null) {
                throw ServiceExceptionUtil.exception(ErrorCodeConstants.RESOURCE_ITEM_NOT_EXISTS);
            }
        }
        
        // 校验：单位为%的工料机不允许修改定额消耗量
        ResourceItemDO resourceItem = resourceItemMapper.selectById(existing.getResourceItemId());
        if (resourceItem != null && "%".equals(resourceItem.getUnit())) {
            // 检查是否尝试修改定额消耗量
            if (updateReqVO.getDosage() != null && existing.getDosage() != null 
                    && updateReqVO.getDosage().compareTo(existing.getDosage()) != 0) {
                throw ServiceExceptionUtil.exception(ErrorCodeConstants.QUOTA_RESOURCE_PERCENT_UNIT_DOSAGE_READONLY);
            }
        }
        
        // 转换为 DO
        QuotaResourceDO updateObj = convertToDO(updateReqVO);
        updateObj.setId(updateReqVO.getId());
        
        // 合并 attributes：保留原有字段，只更新传入的字段
        if (existing.getAttributes() != null) {
            java.util.Map<String, Object> mergedAttributes = new java.util.HashMap<>(existing.getAttributes());
            if (updateReqVO.getAttributes() != null) {
                mergedAttributes.putAll(updateReqVO.getAttributes());
            }
            updateObj.setAttributes(mergedAttributes);
        }
        
        // 更新（标准库不需要快照，查询时实时读取）
        quotaResourceMapper.updateById(updateObj);
        
        // 注意：四个价格字段现在是虚拟字段，不需要更新到数据库
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteQuotaResource(Long id) {
        // 校验存在
        QuotaResourceDO quotaResource = validateExists(id);
        
        // 删除
        quotaResourceMapper.deleteById(id);
        
        // 注意：四个价格字段现在是虚拟字段，不需要更新到数据库
    }

    @Override
    public QuotaResourceDO getQuotaResource(Long id) {
        return quotaResourceMapper.selectById(id);
    }

    @Override
    public List<QuotaResourceRespVO> getQuotaResourceList(Long quotaItemId) {
        List<QuotaResourceDO> list = quotaResourceMapper.selectListByQuotaItemId(quotaItemId);
        List<QuotaResourceRespVO> result = list.stream().map(this::convertToVO).collect(Collectors.toList());
        
        // 计算单位为 % 的工料机的合价（需要先有其他工料机的合价数据）
        calculatePercentUnitTotalSums(result);
        
        // 【已禁用】后台定额调整功能改为纯展示效果，不再计算调整消耗量和调整公式
        // 计算逻辑已移至工作台，后台仅保留排版展示
        // calculateAdjustmentValues(quotaItemId, result);
        
        // 格式化数值：价格/税率保留2位小数，消耗量保留4位小数
        result.forEach(this::formatResourceVO);
        
        return result;
    }
    
    /**
     * 格式化工料机VO的数值字段
     * 价格、税率、合价：保留2位小数，四舍五入
     * 消耗量：保留4位小数，四舍五入
     */
    private void formatResourceVO(QuotaResourceRespVO vo) {
        // 价格/税率/合价：2位小数
        vo.setResourceTaxRate(roundToScale(vo.getResourceTaxRate(), 2));
        vo.setResourceTaxExclBasePrice(roundToScale(vo.getResourceTaxExclBasePrice(), 2));
        vo.setResourceTaxInclBasePrice(roundToScale(vo.getResourceTaxInclBasePrice(), 2));
        vo.setResourceTaxExclCompilePrice(roundToScale(vo.getResourceTaxExclCompilePrice(), 2));
        vo.setResourceTaxInclCompilePrice(roundToScale(vo.getResourceTaxInclCompilePrice(), 2));
        vo.setTaxExclBaseTotalSum(roundToScale(vo.getTaxExclBaseTotalSum(), 2));
        vo.setTaxInclBaseTotalSum(roundToScale(vo.getTaxInclBaseTotalSum(), 2));
        vo.setTaxExclCompileTotalSum(roundToScale(vo.getTaxExclCompileTotalSum(), 2));
        vo.setTaxInclCompileTotalSum(roundToScale(vo.getTaxInclCompileTotalSum(), 2));
        vo.setPrice(roundToScale(vo.getPrice(), 2));
        vo.setAmount(roundToScale(vo.getAmount(), 2));
        
        // 消耗量：4位小数
        vo.setDosage(roundToScale(vo.getDosage(), 4));
        vo.setAdjustedDosage(roundToScale(vo.getAdjustedDosage(), 4));
        vo.setActualDosage(roundToScale(vo.getActualDosage(), 4));
        
        // 格式化子工料机
        if (vo.getMergedItems() != null) {
            vo.getMergedItems().forEach(this::formatMergedItemVO);
        }
    }
    
    /**
     * 格式化复合工料机子项VO的数值字段
     */
    private void formatMergedItemVO(QuotaResourceRespVO.MergedResourceItemVO item) {
        // 价格/税率/合价：2位小数
        item.setResourceTaxRate(roundToScale(item.getResourceTaxRate(), 2));
        item.setResourceTaxExclBasePrice(roundToScale(item.getResourceTaxExclBasePrice(), 2));
        item.setResourceTaxInclBasePrice(roundToScale(item.getResourceTaxInclBasePrice(), 2));
        item.setResourceTaxExclCompilePrice(roundToScale(item.getResourceTaxExclCompilePrice(), 2));
        item.setResourceTaxInclCompilePrice(roundToScale(item.getResourceTaxInclCompilePrice(), 2));
        item.setTaxExclBaseTotalSum(roundToScale(item.getTaxExclBaseTotalSum(), 2));
        item.setTaxInclBaseTotalSum(roundToScale(item.getTaxInclBaseTotalSum(), 2));
        item.setTaxExclCompileTotalSum(roundToScale(item.getTaxExclCompileTotalSum(), 2));
        item.setTaxInclCompileTotalSum(roundToScale(item.getTaxInclCompileTotalSum(), 2));
        item.setPrice(roundToScale(item.getPrice(), 2));
        item.setAmount(roundToScale(item.getAmount(), 2));
        
        // 消耗量：4位小数
        item.setDosage(roundToScale(item.getDosage(), 4));
        item.setActualDosage(roundToScale(item.getActualDosage(), 4));
    }
    
    /**
     * 四舍五入到指定小数位数
     */
    private BigDecimal roundToScale(BigDecimal value, int scale) {
        if (value == null) {
            return null;
        }
        return value.setScale(scale, java.math.RoundingMode.HALF_UP);
    }
    
    /**
     * 计算定额基价中单位为 % 的工料机的合价
     * 委托给 ResourcePriceCalculator 统一处理
     */
    private void calculatePercentUnitTotalSums(List<QuotaResourceRespVO> resources) {
        ResourcePriceCalculator.calculatePercentUnitTotalSums(
                resources, resources, quotaResourceFieldAccessor());
    }

    // 【已删除】calculateAdjustmentValues 方法 - 后台定额调整功能已禁用，计算逻辑收归工作台
    
    /**
     * 重新计算合价（使用调整消耗量）
     * 委托给 ResourcePriceCalculator 统一处理
     */
    @SuppressWarnings("unchecked")
    private void recalculateTotalSums(List<QuotaResourceRespVO> resources) {
        ResourcePriceCalculator.recalculateTotalSums(
                resources,
                quotaResourceFieldAccessor(),
                QuotaResourceRespVO::getIsMerged,
                QuotaResourceRespVO::getResourceTaxExclBasePrice,
                QuotaResourceRespVO::getResourceTaxInclBasePrice,
                QuotaResourceRespVO::getResourceTaxExclCompilePrice,
                QuotaResourceRespVO::getResourceTaxInclCompilePrice);
    }
    
    /**
     * 构建后台定额工料机的 FieldAccessor
     * 映射 QuotaResourceRespVO 的字段名到 ResourcePriceCalculator 的通用接口
     */
    private ResourcePriceCalculator.FieldAccessor<QuotaResourceRespVO> quotaResourceFieldAccessor() {
        return ResourcePriceCalculator.FieldAccessor.<QuotaResourceRespVO>builder()
                .getUnit(QuotaResourceRespVO::getResourceUnit)
                .getCategoryId(QuotaResourceRespVO::getResourceCategoryId)
                .getEffectiveDosage(vo -> vo.getAdjustedDosage() != null ? vo.getAdjustedDosage() : vo.getDosage())
                .getCalcBase(QuotaResourceRespVO::getCalcBase)
                .getTaxExclBaseTotalSum(QuotaResourceRespVO::getTaxExclBaseTotalSum)
                .getTaxInclBaseTotalSum(QuotaResourceRespVO::getTaxInclBaseTotalSum)
                .getTaxExclCompileTotalSum(QuotaResourceRespVO::getTaxExclCompileTotalSum)
                .getTaxInclCompileTotalSum(QuotaResourceRespVO::getTaxInclCompileTotalSum)
                .setTaxExclBaseTotalSum(QuotaResourceRespVO::setTaxExclBaseTotalSum)
                .setTaxInclBaseTotalSum(QuotaResourceRespVO::setTaxInclBaseTotalSum)
                .setTaxExclCompileTotalSum(QuotaResourceRespVO::setTaxExclCompileTotalSum)
                .setTaxInclCompileTotalSum(QuotaResourceRespVO::setTaxInclCompileTotalSum)
                .build();
    }
    
    /**
     * 格式化数字用于公式显示
     * 整数不显示小数点，小数最多保留3位
     */
    private String formatNumber(BigDecimal value) {
        if (value == null) {
            return "0";
        }
        // 去除尾部多余的0
        value = value.stripTrailingZeros();
        // 如果是整数（scale <= 0），直接转为整数字符串
        if (value.scale() <= 0) {
            return value.toBigInteger().toString();
        }
        // 如果小数位数超过3位，保留3位
        if (value.scale() > 3) {
            value = value.setScale(3, java.math.RoundingMode.HALF_UP).stripTrailingZeros();
        }
        return value.toPlainString();
    }

    @Override
    public List<ResourceItemRespVO> getAvailableResourceItems(Long quotaItemId) {
        // 1. 获取定额专业绑定的工料机专业ID
        Long categoryTreeId = quotaItemService.getCategoryTreeIdByQuotaItem(quotaItemId);
        
        // 2. 查询该工料机专业下的所有工料机数据
        List<ResourceItemDO> resourceItems = resourceItemMapper.selectByCategoryTreeId(categoryTreeId);
        
        // 3. 转换为 VO
        return resourceItems.stream()
            .map(this::convertResourceItemToVO)
            .collect(Collectors.toList());
    }

    @Override
    public List<ResourceItemRespVO> getAvailableResourceItemsWithFilter(Long quotaItemId, String code, String name, String spec) {
        // 1. 获取定额专业绑定的工料机专业ID
        Long categoryTreeId = quotaItemService.getCategoryTreeIdByQuotaItem(quotaItemId);
        
        // 2. 查询该工料机专业下的工料机数据（支持模糊查询）
        List<ResourceItemDO> resourceItems = resourceItemMapper.selectByCategoryTreeIdWithFilter(
            categoryTreeId, code, name, spec);
        
        // 3. 转换为 VO
        return resourceItems.stream()
            .map(this::convertResourceItemToVO)
            .collect(Collectors.toList());
    }

    @Override
    public ResourceItemRespVO getResourceItemByCode(Long quotaItemId, String code) {
        // 1. 获取定额专业绑定的工料机专业ID
        Long categoryTreeId = quotaItemService.getCategoryTreeIdByQuotaItem(quotaItemId);
        
        // 2. 根据编码精确查询工料机
        ResourceItemDO resourceItem = resourceItemMapper.selectByCategoryTreeIdAndCode(categoryTreeId, code);
        
        // 3. 如果未找到返回null
        if (resourceItem == null) {
            return null;
        }
        
        // 4. 转换为 VO
        return convertResourceItemToVO(resourceItem);
    }

    @Override
    public void validateResourceInScope(Long quotaItemId, Long resourceItemId) {
        // 1. 获取定额专业绑定的工料机专业ID
        Long allowedCategoryTreeId = quotaItemService.getCategoryTreeIdByQuotaItem(quotaItemId);
        
        // 2. 获取工料机数据
        ResourceItemDO resourceItem = resourceItemMapper.selectById(resourceItemId);
        if (resourceItem == null) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.RESOURCE_ITEM_NOT_EXISTS);
        }
        
        // 3. 获取工料机所属的目录节点（yhy_resource_catalog_item 表）
        com.yhy.module.core.dal.dataobject.resource.ResourceCatalogItemDO catalogItem = 
            resourceCatalogItemMapper.selectById(resourceItem.getCatalogItemId());
        if (catalogItem == null) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.RESOURCE_CATALOG_ITEM_NOT_EXISTS);
        }
        
        // 4. 验证工料机是否在范围内
        if (!allowedCategoryTreeId.equals(catalogItem.getCategoryTreeId())) {
            log.warn("[validateResourceInScope] 工料机不在定额专业的数据范围内，" +
                "quotaItemId={}, resourceItemId={}, allowedCategoryTreeId={}, actualCategoryTreeId={}", 
                quotaItemId, resourceItemId, allowedCategoryTreeId, catalogItem.getCategoryTreeId());
            
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.QUOTA_RESOURCE_OUT_OF_SCOPE);
        }
        
        log.debug("[validateResourceInScope] 工料机在范围内，quotaItemId={}, resourceItemId={}", 
            quotaItemId, resourceItemId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchCreateQuotaResources(Long quotaItemId, List<QuotaResourceSaveReqVO> resources) {
        for (QuotaResourceSaveReqVO resource : resources) {
            resource.setQuotaItemId(quotaItemId);
            createQuotaResource(resource);
        }
    }

    // ========== 私有方法 ==========

    private QuotaResourceDO validateExists(Long id) {
        QuotaResourceDO quotaResource = quotaResourceMapper.selectById(id);
        if (quotaResource == null) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.QUOTA_RESOURCE_NOT_EXISTS);
        }
        return quotaResource;
    }

    private QuotaResourceDO convertToDO(QuotaResourceSaveReqVO vo) {
        QuotaResourceDO quotaResource = new QuotaResourceDO();
        quotaResource.setQuotaItemId(vo.getQuotaItemId());
        quotaResource.setResourceItemId(vo.getResourceItemId());
        quotaResource.setDosage(vo.getDosage());
        // 注意：adjustedDosage 是虚拟字段，由后端动态计算，不从请求中设置
        // quotaResource.setAdjustedDosage(vo.getAdjustedDosage());
        quotaResource.setAttributes(vo.getAttributes());
        quotaResource.setSortOrder(vo.getSortOrder());
        return quotaResource;
    }

    /**
     * 获取指定定额基价下工料机的最大排序值
     */
    private Integer getMaxSortOrder(Long quotaItemId) {
        List<QuotaResourceDO> resources = quotaResourceMapper.selectListByQuotaItemId(quotaItemId);
        if (resources == null || resources.isEmpty()) {
            return 0;
        }
        return resources.stream()
                .map(QuotaResourceDO::getSortOrder)
                .filter(java.util.Objects::nonNull)
                .max(Integer::compareTo)
                .orElse(0);
    }

    /**
     * 将指定位置及之后的记录的 sortOrder 都 +1
     * 用于在指定位置插入新记录
     */
    private void shiftSortOrdersFrom(Long quotaItemId, Integer fromSortOrder) {
        List<QuotaResourceDO> resources = quotaResourceMapper.selectListByQuotaItemId(quotaItemId);
        for (QuotaResourceDO resource : resources) {
            if (resource.getSortOrder() != null && resource.getSortOrder() >= fromSortOrder) {
                resource.setSortOrder(resource.getSortOrder() + 1);
                quotaResourceMapper.updateById(resource);
            }
        }
    }

    private QuotaResourceRespVO convertToVO(QuotaResourceDO quotaResource) {
        QuotaResourceRespVO vo = new QuotaResourceRespVO();
        vo.setId(quotaResource.getId());
        vo.setQuotaItemId(quotaResource.getQuotaItemId());
        vo.setResourceItemId(quotaResource.getResourceItemId());
        vo.setDosage(quotaResource.getDosage());
        // 注意：adjustedDosage 是虚拟字段，由 calculateAdjustmentValues 方法动态计算
        // 这里不再从数据库读取，初始化为 null
        vo.setAdjustedDosage(null);
        vo.setAttributes(quotaResource.getAttributes());
        vo.setCreateTime(quotaResource.getCreateTime());
        vo.setUpdateTime(quotaResource.getUpdateTime());
        
        // 扩展字段
        vo.setLossRate(quotaResource.getLossRate());
        
        // 实时查询工料机信息（不使用快照）
        ResourceItemDO resourceItem = resourceItemMapper.selectById(quotaResource.getResourceItemId());
        if (resourceItem != null) {
            vo.setResourceCode(resourceItem.getCode());
            vo.setResourceName(resourceItem.getName());
            vo.setResourceUnit(resourceItem.getUnit());
            vo.setResourceSpec(resourceItem.getSpec());
            vo.setResourceCategoryId(resourceItem.getCategoryId());
            vo.setResourceType(convertTypeToDisplay(resourceItem.getType()));
            vo.setCalcBase(resourceItem.getCalcBase());
            
            // 判断是否为复合工料机
            boolean isMerged = resourceItem.getIsMerged() != null && resourceItem.getIsMerged() == 1;
            vo.setIsMerged(isMerged);
            
            if (isMerged) {
                // 复合工料机：税率和四个价格字段应该为空
                vo.setResourceTaxRate(null);
                vo.setResourceTaxExclBasePrice(null);
                vo.setResourceTaxInclBasePrice(null);
                vo.setResourceTaxExclCompilePrice(null);
                vo.setResourceTaxInclCompilePrice(null);
                vo.setPrice(null);
            } else {
                // 普通工料机：设置税率和价格字段
                vo.setResourceTaxRate(resourceItem.getTaxRate());
                vo.setResourceTaxExclBasePrice(resourceItem.getTaxExclBasePrice());
                vo.setResourceTaxInclBasePrice(resourceItem.getTaxInclBasePrice());
                vo.setResourceTaxExclCompilePrice(resourceItem.getTaxExclCompilePrice());
                vo.setResourceTaxInclCompilePrice(resourceItem.getTaxInclCompilePrice());
                
                // 价格优先使用除税基价
                if (resourceItem.getTaxExclBasePrice() != null) {
                    vo.setPrice(resourceItem.getTaxExclBasePrice());
                } else if (resourceItem.getTaxInclBasePrice() != null) {
                    vo.setPrice(resourceItem.getTaxInclBasePrice());
                }
                
                // 普通工料机：计算四个合价虚拟字段
                // 合价 = 价格 × 定额消耗量
                // 注意：这里先使用原始消耗量计算，后续在 calculateAdjustmentValues 中会根据调整消耗量重新计算
                BigDecimal effectiveDosage = quotaResource.getDosage();
                if (effectiveDosage != null) {
                    vo.setTaxExclBaseTotalSum(multiplyOrZero(resourceItem.getTaxExclBasePrice(), effectiveDosage));
                    vo.setTaxInclBaseTotalSum(multiplyOrZero(resourceItem.getTaxInclBasePrice(), effectiveDosage));
                    vo.setTaxExclCompileTotalSum(multiplyOrZero(resourceItem.getTaxExclCompilePrice(), effectiveDosage));
                    vo.setTaxInclCompileTotalSum(multiplyOrZero(resourceItem.getTaxInclCompilePrice(), effectiveDosage));
                }
            }
            
            // 计算实际消耗量和金额
            vo.setActualDosage(quotaResource.getActualDosage());
            if (vo.getPrice() != null) {
                vo.setAmount(vo.getActualDosage().multiply(vo.getPrice()));
            }
            
            // 如果是复合工料机，查询子数据
            if (isMerged) {
                
                // 查询复合工料机的子数据
                List<ResourceMergedDO> mergedList = resourceMergedMapper.selectByMergedId(resourceItem.getId());
                
                if (mergedList != null && !mergedList.isEmpty()) {
                    // 先构建类别价格映射表（用于计算单位为 % 的工料机）
                    java.util.Map<Long, CategoryPriceSum> categoryPriceMap = new java.util.HashMap<>();
                    
                    // 第一次遍历：构建类别价格映射表（只处理普通工料机）
                    // 类别价格映射表中的合价需要乘以父定额消耗量，用于单位%工料机的计算基数
                    BigDecimal parentDosageForMap = quotaResource.getDosage();
                    for (ResourceMergedDO merged : mergedList) {
                        if (merged.getSourceId() == null || merged.getQuotaConsumption() == null) {
                            continue;
                        }
                        
                        ResourceItemDO source = resourceItemMapper.selectById(merged.getSourceId());
                        if (source == null || "%".equals(source.getUnit())) {
                            continue;
                        }
                        
                        // 子工料机合价：factor = 子定额消耗量 × 父定额消耗量
                        // 这样计算出的合价与显示的子项合价一致
                        BigDecimal factor = merged.getQuotaConsumption();
                        if (parentDosageForMap != null) {
                            factor = factor.multiply(parentDosageForMap);
                        }
                        
                        // 计算合价并累加到类别映射表
                        if (source.getCategoryId() != null) {
                            CategoryPriceSum categoryPrice = categoryPriceMap.computeIfAbsent(
                                    source.getCategoryId(), k -> new CategoryPriceSum());
                            
                            categoryPrice.taxExclBasePrice = categoryPrice.taxExclBasePrice.add(
                                    multiplyOrZero(source.getTaxExclBasePrice(), factor));
                            categoryPrice.taxInclBasePrice = categoryPrice.taxInclBasePrice.add(
                                    multiplyOrZero(source.getTaxInclBasePrice(), factor));
                            categoryPrice.taxExclCompilePrice = categoryPrice.taxExclCompilePrice.add(
                                    multiplyOrZero(source.getTaxExclCompilePrice(), factor));
                            categoryPrice.taxInclCompilePrice = categoryPrice.taxInclCompilePrice.add(
                                    multiplyOrZero(source.getTaxInclCompilePrice(), factor));
                        }
                    }
                    
                    // 第二次遍历：构建 mergedItems 并计算虚拟字段
                    List<QuotaResourceRespVO.MergedResourceItemVO> mergedItems = mergedList.stream()
                        .map(merged -> {
                            QuotaResourceRespVO.MergedResourceItemVO item = new QuotaResourceRespVO.MergedResourceItemVO();
                            item.setId(merged.getId());
                            item.setResourceItemId(merged.getSourceId());
                            item.setRegionCode(merged.getRegionCode());
                            // 子项定额消耗量 = 原定额消耗量 × 父定额消耗量
                            BigDecimal childDosage = merged.getQuotaConsumption();
                            BigDecimal parentDosage = quotaResource.getDosage();
                            if (childDosage != null && parentDosage != null) {
                                item.setDosage(childDosage.multiply(parentDosage).setScale(6, java.math.RoundingMode.HALF_UP));
                            } else {
                                item.setDosage(childDosage);
                            }
                            item.setPrice(merged.getTaxExclMarketPrice());
                            
                            // 查询源工料机信息
                            if (merged.getSourceId() != null) {
                                ResourceItemDO sourceItem = resourceItemMapper.selectById(merged.getSourceId());
                                if (sourceItem != null) {
                                    item.setResourceCode(sourceItem.getCode());
                                    item.setResourceName(sourceItem.getName());
                                    item.setResourceUnit(sourceItem.getUnit());
                                    item.setResourceSpec(sourceItem.getSpec());
                                    item.setResourceCategoryId(sourceItem.getCategoryId());
                                    item.setResourceType(convertTypeToDisplay(sourceItem.getType()));
                                    item.setResourceTaxRate(sourceItem.getTaxRate());
                                    item.setCalcBase(sourceItem.getCalcBase()); // 设置计算基数
                                    
                                    // 设置原工料机的四个价格字段（子工料机保留原工料机的价格）
                                    item.setResourceTaxExclBasePrice(sourceItem.getTaxExclBasePrice());
                                    item.setResourceTaxInclBasePrice(sourceItem.getTaxInclBasePrice());
                                    item.setResourceTaxExclCompilePrice(sourceItem.getTaxExclCompilePrice());
                                    item.setResourceTaxInclCompilePrice(sourceItem.getTaxInclCompilePrice());
                                    
                                    // 计算虚拟字段（四个合价）
                                    BigDecimal quotaConsumption = merged.getQuotaConsumption();
                                    BigDecimal parentDosageForCalc = quotaResource.getDosage();
                                    
                                    if (quotaConsumption == null || parentDosageForCalc == null) {
                                        // 消耗量为空时，设置合价为0
                                        item.setTaxExclBaseTotalSum(BigDecimal.ZERO);
                                        item.setTaxInclBaseTotalSum(BigDecimal.ZERO);
                                        item.setTaxExclCompileTotalSum(BigDecimal.ZERO);
                                        item.setTaxInclCompileTotalSum(BigDecimal.ZERO);
                                    } else {
                                        // 子工料机合价计算：factor = 子定额消耗量 × 父定额消耗量
                                        BigDecimal factor = quotaConsumption.multiply(parentDosageForCalc);
                                        
                                        if ("%".equals(sourceItem.getUnit()) && sourceItem.getCalcBase() != null) {
                                            // 单位为 % 的工料机：使用计算基数公式
                                            // 合价 = 公式结果 × (显示的定额消耗量 / 100)
                                            // 显示的定额消耗量 = 子定额消耗量 × 父定额消耗量
                                            BigDecimal displayDosage = quotaConsumption.multiply(parentDosageForCalc);
                                            // percentFactor = 显示的定额消耗量 / 100（作为百分比）
                                            BigDecimal percentFactor = displayDosage.divide(new BigDecimal("100"), 6, java.math.RoundingMode.HALF_UP);
                                            boolean calculated = false;
                                            try {
                                                java.util.Map<String, Object> calcBase = sourceItem.getCalcBase();
                                                if (calcBase.containsKey("formula") && calcBase.containsKey("variables")) {
                                                    String formula = (String) calcBase.get("formula");
                                                    @SuppressWarnings("unchecked")
                                                    java.util.Map<String, Object> variablesConfig = (java.util.Map<String, Object>) calcBase.get("variables");
                                                    
                                                    // 构建变量值映射表
                                                    java.util.Map<String, BigDecimal> taxExclBaseVars = new java.util.HashMap<>();
                                                    java.util.Map<String, BigDecimal> taxInclBaseVars = new java.util.HashMap<>();
                                                    java.util.Map<String, BigDecimal> taxExclCompileVars = new java.util.HashMap<>();
                                                    java.util.Map<String, BigDecimal> taxInclCompileVars = new java.util.HashMap<>();
                                                    
                                                    for (java.util.Map.Entry<String, Object> varEntry : variablesConfig.entrySet()) {
                                                        String varName = varEntry.getKey();
                                                        Long categoryId = Long.valueOf(varEntry.getValue().toString());
                                                        
                                                        CategoryPriceSum categoryPrice = categoryPriceMap.get(categoryId);
                                                        if (categoryPrice == null) {
                                                            // 如果类别不存在，使用 0 作为默认值
                                                            log.debug("[convertToVO] 单位为%的工料机类别数据为空，使用0作为默认值，sourceId={}, categoryId={}", 
                                                                    sourceItem.getId(), categoryId);
                                                            taxExclBaseVars.put(varName, BigDecimal.ZERO);
                                                            taxInclBaseVars.put(varName, BigDecimal.ZERO);
                                                            taxExclCompileVars.put(varName, BigDecimal.ZERO);
                                                            taxInclCompileVars.put(varName, BigDecimal.ZERO);
                                                        } else {
                                                            taxExclBaseVars.put(varName, categoryPrice.taxExclBasePrice);
                                                            taxInclBaseVars.put(varName, categoryPrice.taxInclBasePrice);
                                                            taxExclCompileVars.put(varName, categoryPrice.taxExclCompilePrice);
                                                            taxInclCompileVars.put(varName, categoryPrice.taxInclCompilePrice);
                                                        }
                                                    }
                                                    
                                                    {
                                                        // 计算公式结果
                                                        BigDecimal taxExclBaseSum = com.yhy.module.core.util.FormulaEvaluator.evaluate(formula, taxExclBaseVars);
                                                        BigDecimal taxInclBaseSum = com.yhy.module.core.util.FormulaEvaluator.evaluate(formula, taxInclBaseVars);
                                                        BigDecimal taxExclCompileSum = com.yhy.module.core.util.FormulaEvaluator.evaluate(formula, taxExclCompileVars);
                                                        BigDecimal taxInclCompileSum = com.yhy.module.core.util.FormulaEvaluator.evaluate(formula, taxInclCompileVars);
                                                        
                                                        // 设置虚拟字段：合价 = 公式结果 × 显示的定额消耗量%
                                                        item.setTaxExclBaseTotalSum(taxExclBaseSum.multiply(percentFactor).setScale(4, java.math.RoundingMode.HALF_UP));
                                                        item.setTaxInclBaseTotalSum(taxInclBaseSum.multiply(percentFactor).setScale(4, java.math.RoundingMode.HALF_UP));
                                                        item.setTaxExclCompileTotalSum(taxExclCompileSum.multiply(percentFactor).setScale(4, java.math.RoundingMode.HALF_UP));
                                                        item.setTaxInclCompileTotalSum(taxInclCompileSum.multiply(percentFactor).setScale(4, java.math.RoundingMode.HALF_UP));
                                                        calculated = true;
                                                    }
                                                }
                                            } catch (Exception e) {
                                                log.error("[convertToVO] 计算单位为%的工料机合价失败，sourceId={}, error={}", 
                                                        sourceItem.getId(), e.getMessage(), e);
                                            }
                                            
                                            // 如果缺少类别数据或计算失败，设置合价为0
                                            if (!calculated) {
                                                item.setTaxExclBaseTotalSum(BigDecimal.ZERO);
                                                item.setTaxInclBaseTotalSum(BigDecimal.ZERO);
                                                item.setTaxExclCompileTotalSum(BigDecimal.ZERO);
                                                item.setTaxInclCompileTotalSum(BigDecimal.ZERO);
                                            }
                                        } else {
                                            // 普通工料机：合价 = 价格 × 子定额消耗量 × 父定额消耗量
                                            item.setTaxExclBaseTotalSum(multiplyOrZero(sourceItem.getTaxExclBasePrice(), factor));
                                            item.setTaxInclBaseTotalSum(multiplyOrZero(sourceItem.getTaxInclBasePrice(), factor));
                                            item.setTaxExclCompileTotalSum(multiplyOrZero(sourceItem.getTaxExclCompilePrice(), factor));
                                            item.setTaxInclCompileTotalSum(multiplyOrZero(sourceItem.getTaxInclCompilePrice(), factor));
                                        }
                                    }
                                }
                            }
                            
                            // 计算实际消耗量和金额
                            if (merged.getQuotaConsumption() != null && quotaResource.getDosage() != null) {
                                // 实际消耗量 = 父定额消耗量 × 子定额消耗量 × (1 + 损耗率)
                                BigDecimal actualDosage = merged.getQuotaConsumption()
                                    .multiply(quotaResource.getDosage());
                                
                                if (quotaResource.getLossRate() != null) {
                                    actualDosage = actualDosage.multiply(
                                        BigDecimal.ONE.add(quotaResource.getLossRate())
                                    );
                                }
                                
                                item.setActualDosage(actualDosage);
                                
                                // 金额 = 实际消耗量 × 价格
                                if (merged.getTaxExclMarketPrice() != null) {
                                    item.setAmount(actualDosage.multiply(merged.getTaxExclMarketPrice()));
                                }
                            }
                            
                            return item;
                        })
                        .collect(Collectors.toList());
                    
                    vo.setMergedItems(mergedItems);
                    
                    // 计算复合工料机的虚拟字段（四个合价总和 = 子项合价之和）
                    calculateMergedTotalSumsFromItems(vo, mergedItems);
                    
                    // 反算复合工料机的四个单价字段：单价 = 合价 / 定额消耗量
                    BigDecimal parentDosageForPrice = quotaResource.getDosage();
                    if (parentDosageForPrice != null && parentDosageForPrice.compareTo(BigDecimal.ZERO) != 0) {
                        vo.setResourceTaxExclBasePrice(vo.getTaxExclBaseTotalSum() != null ?
                                vo.getTaxExclBaseTotalSum().divide(parentDosageForPrice, 6, java.math.RoundingMode.HALF_UP) : null);
                        vo.setResourceTaxInclBasePrice(vo.getTaxInclBaseTotalSum() != null ?
                                vo.getTaxInclBaseTotalSum().divide(parentDosageForPrice, 6, java.math.RoundingMode.HALF_UP) : null);
                        vo.setResourceTaxExclCompilePrice(vo.getTaxExclCompileTotalSum() != null ?
                                vo.getTaxExclCompileTotalSum().divide(parentDosageForPrice, 6, java.math.RoundingMode.HALF_UP) : null);
                        vo.setResourceTaxInclCompilePrice(vo.getTaxInclCompileTotalSum() != null ?
                                vo.getTaxInclCompileTotalSum().divide(parentDosageForPrice, 6, java.math.RoundingMode.HALF_UP) : null);
                    }
                }
            }
        }
        
        return vo;
    }

    /**
     * 计算复合工料机的虚拟字段（四个合价总和）
     * 
     * @param vo 定额工料机组成 VO
     * @param mergedList 复合工料机子数据列表
     * @param quotaDosage 定额基价中的定额消耗量
     */
    private void calculateMergedTotalSums(QuotaResourceRespVO vo, List<ResourceMergedDO> mergedList, BigDecimal quotaDosage) {
        if (mergedList == null || mergedList.isEmpty() || quotaDosage == null) {
            return;
        }
        
        // 按类别分组，用于计算基数公式
        java.util.Map<Long, CategoryPriceSum> categoryPriceMap = new java.util.HashMap<>();
        
        // 计算父定额消耗量因子
        // 第一次遍历：构建类别价格映射表（只处理普通工料机）
        for (ResourceMergedDO merged : mergedList) {
            if (merged.getSourceId() == null || merged.getQuotaConsumption() == null) {
                continue;
            }
            
            ResourceItemDO source = resourceItemMapper.selectById(merged.getSourceId());
            if (source == null || "%".equals(source.getUnit())) {
                continue;
            }
            
            // 子工料机合价：factor = 子定额消耗量 × 父定额消耗量
            BigDecimal factor = merged.getQuotaConsumption().multiply(quotaDosage);
            
            // 计算合价并累加到类别映射表
            if (source.getCategoryId() != null) {
                CategoryPriceSum categoryPrice = categoryPriceMap.computeIfAbsent(
                        source.getCategoryId(), k -> new CategoryPriceSum());
                
                categoryPrice.taxExclBasePrice = categoryPrice.taxExclBasePrice.add(
                        multiplyOrZero(source.getTaxExclBasePrice(), factor));
                categoryPrice.taxInclBasePrice = categoryPrice.taxInclBasePrice.add(
                        multiplyOrZero(source.getTaxInclBasePrice(), factor));
                categoryPrice.taxExclCompilePrice = categoryPrice.taxExclCompilePrice.add(
                        multiplyOrZero(source.getTaxExclCompilePrice(), factor));
                categoryPrice.taxInclCompilePrice = categoryPrice.taxInclCompilePrice.add(
                        multiplyOrZero(source.getTaxInclCompilePrice(), factor));
            }
        }
        
        // 第二次遍历：处理单位为 % 的工料机
        for (ResourceMergedDO merged : mergedList) {
            if (merged.getSourceId() == null || merged.getQuotaConsumption() == null) {
                continue;
            }
            
            ResourceItemDO source = resourceItemMapper.selectById(merged.getSourceId());
            if (source == null || !"%".equals(source.getUnit()) || source.getCalcBase() == null) {
                continue;
            }
            
            try {
                // 解析 calc_base
                java.util.Map<String, Object> calcBase = source.getCalcBase();
                if (!calcBase.containsKey("formula") || !calcBase.containsKey("variables")) {
                    continue;
                }
                
                String formula = (String) calcBase.get("formula");
                @SuppressWarnings("unchecked")
                java.util.Map<String, Object> variablesConfig = (java.util.Map<String, Object>) calcBase.get("variables");
                
                // 构建变量值映射表
                java.util.Map<String, BigDecimal> taxExclBaseVars = new java.util.HashMap<>();
                java.util.Map<String, BigDecimal> taxInclBaseVars = new java.util.HashMap<>();
                java.util.Map<String, BigDecimal> taxExclCompileVars = new java.util.HashMap<>();
                java.util.Map<String, BigDecimal> taxInclCompileVars = new java.util.HashMap<>();
                
                for (java.util.Map.Entry<String, Object> varEntry : variablesConfig.entrySet()) {
                    String varName = varEntry.getKey();
                    Long categoryId = Long.valueOf(varEntry.getValue().toString());
                    
                    CategoryPriceSum categoryPrice = categoryPriceMap.get(categoryId);
                    if (categoryPrice == null) {
                        // 如果类别不存在，使用 0 作为默认值
                        taxExclBaseVars.put(varName, BigDecimal.ZERO);
                        taxInclBaseVars.put(varName, BigDecimal.ZERO);
                        taxExclCompileVars.put(varName, BigDecimal.ZERO);
                        taxInclCompileVars.put(varName, BigDecimal.ZERO);
                    } else {
                        taxExclBaseVars.put(varName, categoryPrice.taxExclBasePrice);
                        taxInclBaseVars.put(varName, categoryPrice.taxInclBasePrice);
                        taxExclCompileVars.put(varName, categoryPrice.taxExclCompilePrice);
                        taxInclCompileVars.put(varName, categoryPrice.taxInclCompilePrice);
                    }
                }
                
                // 计算公式结果
                BigDecimal taxExclBaseSum = com.yhy.module.core.util.FormulaEvaluator.evaluate(formula, taxExclBaseVars);
                BigDecimal taxInclBaseSum = com.yhy.module.core.util.FormulaEvaluator.evaluate(formula, taxInclBaseVars);
                BigDecimal taxExclCompileSum = com.yhy.module.core.util.FormulaEvaluator.evaluate(formula, taxExclCompileVars);
                BigDecimal taxInclCompileSum = com.yhy.module.core.util.FormulaEvaluator.evaluate(formula, taxInclCompileVars);
                
                // 单位为 % 的工料机：合价 = 公式结果 × (显示的定额消耗量 / 100)
                // 显示的定额消耗量 = 子定额消耗量 × 父定额消耗量
                BigDecimal displayDosage = merged.getQuotaConsumption().multiply(quotaDosage);
                BigDecimal percentFactor = displayDosage.divide(new BigDecimal("100"), 6, java.math.RoundingMode.HALF_UP);
                
                // 累加到类别价格映射表
                if (source.getCategoryId() != null) {
                    CategoryPriceSum categoryPrice = categoryPriceMap.computeIfAbsent(
                            source.getCategoryId(), k -> new CategoryPriceSum());
                    
                    categoryPrice.taxExclBasePrice = categoryPrice.taxExclBasePrice.add(
                            taxExclBaseSum.multiply(percentFactor).setScale(4, java.math.RoundingMode.HALF_UP));
                    categoryPrice.taxInclBasePrice = categoryPrice.taxInclBasePrice.add(
                            taxInclBaseSum.multiply(percentFactor).setScale(4, java.math.RoundingMode.HALF_UP));
                    categoryPrice.taxExclCompilePrice = categoryPrice.taxExclCompilePrice.add(
                            taxExclCompileSum.multiply(percentFactor).setScale(4, java.math.RoundingMode.HALF_UP));
                    categoryPrice.taxInclCompilePrice = categoryPrice.taxInclCompilePrice.add(
                            taxInclCompileSum.multiply(percentFactor).setScale(4, java.math.RoundingMode.HALF_UP));
                }
            } catch (Exception e) {
                log.error("[calculateMergedTotalSums] 计算失败，mergedId={}, sourceId={}, error={}", 
                        merged.getMergedId(), merged.getSourceId(), e.getMessage(), e);
            }
        }
        
        // 汇总所有类别的价格
        BigDecimal totalTaxExclBase = BigDecimal.ZERO;
        BigDecimal totalTaxInclBase = BigDecimal.ZERO;
        BigDecimal totalTaxExclCompile = BigDecimal.ZERO;
        BigDecimal totalTaxInclCompile = BigDecimal.ZERO;
        
        for (CategoryPriceSum categoryPrice : categoryPriceMap.values()) {
            totalTaxExclBase = totalTaxExclBase.add(categoryPrice.taxExclBasePrice);
            totalTaxInclBase = totalTaxInclBase.add(categoryPrice.taxInclBasePrice);
            totalTaxExclCompile = totalTaxExclCompile.add(categoryPrice.taxExclCompilePrice);
            totalTaxInclCompile = totalTaxInclCompile.add(categoryPrice.taxInclCompilePrice);
        }
        
        // 设置虚拟字段
        vo.setTaxExclBaseTotalSum(totalTaxExclBase);
        vo.setTaxInclBaseTotalSum(totalTaxInclBase);
        vo.setTaxExclCompileTotalSum(totalTaxExclCompile);
        vo.setTaxInclCompileTotalSum(totalTaxInclCompile);
    }

    /**
     * 从子项列表直接汇总复合工料机的四个合价
     * 委托给 ResourcePriceCalculator.sumChildrenToParent（支持父子不同类型）
     */
    private void calculateMergedTotalSumsFromItems(QuotaResourceRespVO vo, List<QuotaResourceRespVO.MergedResourceItemVO> mergedItems) {
        ResourcePriceCalculator.sumChildrenToParent(
                vo, mergedItems, mergedItemFieldAccessor(), quotaResourceFieldAccessor());
    }
    
    /**
     * 构建复合工料机子项的 FieldAccessor（只需 getter）
     */
    private ResourcePriceCalculator.FieldAccessor<QuotaResourceRespVO.MergedResourceItemVO> mergedItemFieldAccessor() {
        return ResourcePriceCalculator.FieldAccessor.<QuotaResourceRespVO.MergedResourceItemVO>builder()
                .getTaxExclBaseTotalSum(QuotaResourceRespVO.MergedResourceItemVO::getTaxExclBaseTotalSum)
                .getTaxInclBaseTotalSum(QuotaResourceRespVO.MergedResourceItemVO::getTaxInclBaseTotalSum)
                .getTaxExclCompileTotalSum(QuotaResourceRespVO.MergedResourceItemVO::getTaxExclCompileTotalSum)
                .getTaxInclCompileTotalSum(QuotaResourceRespVO.MergedResourceItemVO::getTaxInclCompileTotalSum)
                .build();
    }
    
    /**
     * 安全乘法（处理 null 值）
     * 委托给 ResourcePriceCalculator.multiplyOrZero
     */
    private BigDecimal multiplyOrZero(BigDecimal value, BigDecimal factor) {
        return ResourcePriceCalculator.multiplyOrZero(value, factor);
    }

    // 注意：updateQuotaItemPrices 方法已删除，因为四个价格字段现在是虚拟字段，
    // 由 QuotaItemServiceImpl.calculateQuotaItemPrices 方法在查询时动态计算

    /**
     * 类别价格汇总
     */
    private static class CategoryPriceSum {
        BigDecimal taxExclBasePrice = BigDecimal.ZERO;
        BigDecimal taxInclBasePrice = BigDecimal.ZERO;
        BigDecimal taxExclCompilePrice = BigDecimal.ZERO;
        BigDecimal taxInclCompilePrice = BigDecimal.ZERO;
    }

    private ResourceItemRespVO convertResourceItemToVO(ResourceItemDO resourceItem) {
        ResourceItemRespVO vo = new ResourceItemRespVO();
        vo.setId(resourceItem.getId());
        vo.setCatalogItemId(resourceItem.getCatalogItemId());
        vo.setCode(resourceItem.getCode());
        vo.setName(resourceItem.getName());
        vo.setSpec(resourceItem.getSpec());
        vo.setType(convertTypeToDisplay(resourceItem.getType()));
        vo.setUnit(resourceItem.getUnit());
        vo.setCategoryId(resourceItem.getCategoryId());
        vo.setCategoryTreeId(resourceItem.getCategoryTreeId());
        vo.setTaxRate(resourceItem.getTaxRate());
        vo.setTaxExclBasePrice(resourceItem.getTaxExclBasePrice());
        vo.setTaxInclBasePrice(resourceItem.getTaxInclBasePrice());
        vo.setTaxExclCompilePrice(resourceItem.getTaxExclCompilePrice());
        vo.setTaxInclCompilePrice(resourceItem.getTaxInclCompilePrice());
        vo.setCalcBase(resourceItem.getCalcBase());
        vo.setIsMerged(resourceItem.getIsMerged());
        return vo;
    }

    // 【已删除】后台定额调整功能改为纯展示效果，以下方法已删除：
    // - applyAdjustmentSetting
    // - applyAdjustCoefficient
    // - applyConsumptionAdjustment
    // - applyDynamicAdjustment
    // - applyDynamicMerge
    // - applyValueRule
    // - DynamicAdjustParams
    // - DynamicMergeParams
    
    /**
     * 将英文类型转换为中文显示
     */
    private String convertTypeToDisplay(String type) {
        if (type == null) return null;
        switch (type) {
            case "labor": return "人";
            case "material": return "材";
            case "machine": return "机";
            default: return type;
        }
    }
}
