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<MdmItemModelRespDTO> models = mdmItemModelApi.getItemModelListByItemId(itemId).getCheckedData().stream()
|
.filter(model -> ObjUtil.equal(model.getUnitMeasureId(), unitMeasureId))
|
.filter(model -> CommonStatusEnum.ENABLE.getStatus().equals(model.getStatus()))
|
.toList();
|
List<BigDecimal> 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;
|
}
|
|
}
|