package cn.iocoder.yudao.module.mes.service.wm.unitconvert; import cn.hutool.core.util.ObjUtil; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.exception.ServiceException; import cn.iocoder.yudao.module.mdm.api.item.MdmItemApi; import cn.iocoder.yudao.module.mdm.api.item.MdmItemModelApi; import cn.iocoder.yudao.module.mdm.api.item.dto.MdmItemModelRespDTO; import cn.iocoder.yudao.module.mdm.api.item.dto.MdmItemRespDTO; import cn.iocoder.yudao.module.mdm.api.unit.MdmUnitMeasureApi; import cn.iocoder.yudao.module.mdm.api.unit.dto.MdmUnitMeasureRespDTO; import jakarta.annotation.Resource; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; import java.math.BigDecimal; import java.util.List; import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*; /** * MES 物料主辅单位换算 Service 实现类 * * @author 超级管理员 */ @Service @Validated public class MesWmItemUnitConvertServiceImpl implements MesWmItemUnitConvertService { @Resource private MdmItemApi mdmItemApi; @Resource private MdmItemModelApi mdmItemModelApi; @Resource private MdmUnitMeasureApi mdmUnitMeasureApi; @Override public BigDecimal resolveRateToPrimaryUnit(Long itemId, Long itemModelId, Long unitMeasureId) { MdmItemRespDTO item = mdmItemApi.validateItemExists(itemId).getCheckedData(); // 1. 未指定录入单位,或录入单位就是物料主单位 → 比率 1 if (unitMeasureId == null || ObjUtil.equal(item.getUnitMeasureId(), unitMeasureId)) { return BigDecimal.ONE; } // 2. 指定了型号 → 以型号上配置的单位与比率为准 if (itemModelId != null) { MdmItemModelRespDTO model = mdmItemModelApi.validateItemModelExistsAndEnable(itemModelId, itemId) .getCheckedData(); if (ObjUtil.notEqual(model.getUnitMeasureId(), unitMeasureId)) { throw new ServiceException(WM_ITEM_UNIT_CONVERT_MODEL_UNIT_MISMATCH.getCode(), String.format( "所选型号【%s】的计量单位是【%s】,与本次录入单位【%s】不一致,请重新选择型号或改回型号对应的计量单位", model.getModel(), unitName(model.getUnitMeasureId()), unitName(unitMeasureId))); } return validateRate(model); } // 3. 未指定型号 → 先匹配物料主数据上的辅单位 1 / 辅单位 2 if (ObjUtil.equal(item.getUnitMeasureId2(), unitMeasureId) && item.getUnitMeasureRate1() != null) { return item.getUnitMeasureRate1(); } if (ObjUtil.equal(item.getUnitMeasureId3(), unitMeasureId) && item.getUnitMeasureRate2() != null) { return item.getUnitMeasureRate2(); } // 4. 再从物料型号中找该单位:比率唯一可直接使用,比率有多个取值则必须指定型号 List models = mdmItemModelApi.getItemModelListByItemId(itemId).getCheckedData().stream() .filter(model -> ObjUtil.equal(model.getUnitMeasureId(), unitMeasureId)) .filter(model -> CommonStatusEnum.ENABLE.getStatus().equals(model.getStatus())) .toList(); List distinctRates = models.stream() .map(MdmItemModelRespDTO::getUnitMeasureRate) .filter(java.util.Objects::nonNull) .distinct() .toList(); if (distinctRates.size() > 1) { throw new ServiceException(WM_ITEM_UNIT_CONVERT_MODEL_REQUIRED.getCode(), String.format( "物料【%s-%s】下使用计量单位【%s】的型号有多个且换算比率不同,请先选择型号后再录入数量", item.getCode(), item.getName(), unitName(unitMeasureId))); } if (distinctRates.size() == 1) { return validateRate(distinctRates.get(0), models.get(0).getModel()); } // 5. 主数据与型号均未配置该单位的换算比率 throw new ServiceException(WM_ITEM_UNIT_CONVERT_NOT_CONFIGURED.getCode(), String.format( "物料【%s-%s】没有配置计量单位【%s】到主单位【%s】的换算比率,无法换算," + "请先到【基础数据-物料主数据-型号】为该物料新增型号并填写换算比率", item.getCode(), item.getName(), unitName(unitMeasureId), unitName(item.getUnitMeasureId()))); } @Override public BigDecimal convertToPrimaryUnit(Long itemId, Long itemModelId, Long unitMeasureId, BigDecimal enterQuantity) { BigDecimal rate = resolveRateToPrimaryUnit(itemId, itemModelId, unitMeasureId); // 1. 录入单位即主单位 → 数量原样返回 if (BigDecimal.ONE.compareTo(rate) == 0) { return enterQuantity; } // 2. 按非主单位录入时,录入数量必填 if (enterQuantity == null) { MdmItemRespDTO item = mdmItemApi.validateItemExists(itemId).getCheckedData(); throw new ServiceException(WM_ITEM_UNIT_CONVERT_QUANTITY_REQUIRED.getCode(), String.format( "计量单位【%s】不是物料【%s-%s】的主单位,按该单位录入时录入数量不能为空,请填写录入数量或改用主单位【%s】", unitName(unitMeasureId), item.getCode(), item.getName(), unitName(item.getUnitMeasureId()))); } // 3. 辅单位数量 × 换算比率 = 主单位数量 return enterQuantity.multiply(rate); } private BigDecimal validateRate(MdmItemModelRespDTO model) { return validateRate(model.getUnitMeasureRate(), model.getModel()); } private BigDecimal validateRate(BigDecimal rate, String modelName) { if (rate == null || rate.compareTo(BigDecimal.ZERO) <= 0) { throw new ServiceException(WM_ITEM_UNIT_CONVERT_RATE_INVALID.getCode(), String.format( "型号【%s】的换算比率为【%s】不合理,1 个型号单位必须对应大于 0 的主单位数量," + "请到【基础数据-物料主数据-型号】修正该型号的换算比率", modelName, rate)); } return rate; } private String unitName(Long unitMeasureId) { if (unitMeasureId == null) { return "未指定"; } MdmUnitMeasureRespDTO unit = mdmUnitMeasureApi.getUnitMeasure(unitMeasureId).getCheckedData(); return unit != null ? unit.getName() : "ID=" + unitMeasureId; } }