gaoluyang
昨天 8c65f898ed6e5b0c7a94c792c4562f6ec831dccd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
package cn.iocoder.yudao.module.mes.service.pro.wage;
 
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.mes.controller.admin.pro.wage.vo.MesProProcessWageFieldSaveListReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.pro.wage.vo.MesProProcessWageFieldSaveReqVO;
import cn.iocoder.yudao.module.mes.dal.dataobject.pro.process.MesProProcessDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.pro.wage.MesProProcessWageFieldDO;
import cn.iocoder.yudao.module.mes.dal.mysql.pro.wage.MesProProcessWageFieldMapper;
import cn.iocoder.yudao.module.mes.service.pro.process.MesProProcessService;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
 
import java.math.BigDecimal;
import java.util.*;
 
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*;
 
/**
 * MES 工序工资字段 Service 实现类
 *
 * @author 超级管理员
 */
@Service
@Validated
public class MesProProcessWageFieldServiceImpl implements MesProProcessWageFieldService {
 
    @Resource
    private MesProProcessWageFieldMapper fieldMapper;
    @Resource
    private MesProProcessService processService;
 
    @Override
    public List<MesProProcessWageFieldDO> getFieldList(Long processId) {
        if (processId == null) {
            return Collections.emptyList();
        }
        return fieldMapper.selectListByProcessId(processId);
    }
 
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveFieldList(MesProProcessWageFieldSaveListReqVO reqVO) {
        MesProProcessDO process = processService.getProcess(reqVO.getProcessId());
        if (process == null) {
            throw exception(PRO_FEEDBACK_PROCESS_NOT_EXISTS, reqVO.getProcessId());
        }
        List<MesProProcessWageFieldSaveReqVO> list = reqVO.getList() == null
                ? Collections.emptyList() : reqVO.getList();
        validateFieldList(process, list);
 
        // 1. 已存在的字段编号
        List<MesProProcessWageFieldDO> existingList = fieldMapper.selectListByProcessId(process.getId());
        Set<Long> existingIds = new HashSet<>();
        existingList.forEach(field -> existingIds.add(field.getId()));
        Set<Long> retainedIds = new HashSet<>();
 
        // 2. 新增 / 修改
        for (MesProProcessWageFieldSaveReqVO item : list) {
            MesProProcessWageFieldDO field = BeanUtils.toBean(item, MesProProcessWageFieldDO.class);
            field.setProcessId(process.getId());
            field.setFieldCode(StrUtil.trim(field.getFieldCode()));
            field.setFieldName(StrUtil.trim(field.getFieldName()));
            field.setStatus(item.getStatus() != null ? item.getStatus() : CommonStatusEnum.ENABLE.getStatus());
            field.setSort(item.getSort() != null ? item.getSort() : 0);
            if (field.getId() == null) {
                fieldMapper.insert(field);
                retainedIds.add(field.getId());
            } else {
                if (!existingIds.contains(field.getId())) {
                    throw exception(PRO_PROCESS_WAGE_FIELD_NOT_EXISTS);
                }
                fieldMapper.updateById(field);
                retainedIds.add(field.getId());
            }
        }
 
        // 3. 删除本次未保留的字段
        for (Long existingId : existingIds) {
            if (!retainedIds.contains(existingId)) {
                fieldMapper.deleteById(existingId);
            }
        }
    }
 
    private void validateFieldList(MesProProcessDO process, List<MesProProcessWageFieldSaveReqVO> list) {
        if (CollUtil.isEmpty(list)) {
            return;
        }
        Set<String> codes = new HashSet<>();
        for (MesProProcessWageFieldSaveReqVO item : list) {
            String code = StrUtil.trim(item.getFieldCode());
            String name = StrUtil.trim(item.getFieldName());
            if (!codes.add(code)) {
                throw new ServiceException(PRO_PROCESS_WAGE_FIELD_CODE_DUPLICATE.getCode(),
                        StrUtil.format("工序[{}]下字段编码[{}]重复,请修改字段编码后重试", process.getName(), code));
            }
            Integer fieldType = item.getFieldType();
            if (fieldType == null || fieldType < MesProProcessWageFieldDO.FIELD_TYPE_NUMBER
                    || fieldType > MesProProcessWageFieldDO.FIELD_TYPE_BOOLEAN) {
                throw new ServiceException(PRO_PROCESS_WAGE_FIELD_TYPE_INVALID.getCode(),
                        StrUtil.format("工序[{}]字段[{}]的字段类型[{}]不合法;期望 1-数值 / 2-文本 / 3-下拉 / 4-布尔,请重新选择",
                                process.getName(), name, fieldType));
            }
            Integer calcRole = item.getCalcRole();
            if (calcRole == null || calcRole < MesProProcessWageFieldDO.CALC_ROLE_COEFFICIENT
                    || calcRole > MesProProcessWageFieldDO.CALC_ROLE_RECORD_ONLY) {
                throw new ServiceException(PRO_PROCESS_WAGE_FIELD_ROLE_INVALID.getCode(),
                        StrUtil.format("工序[{}]字段[{}]的计算角色[{}]不合法;期望 1-系数 / 2-加减金额 / 3-计价数量 / 4-仅记录,请重新选择",
                                process.getName(), name, calcRole));
            }
            boolean numericRole = calcRole == MesProProcessWageFieldDO.CALC_ROLE_COEFFICIENT
                    || calcRole == MesProProcessWageFieldDO.CALC_ROLE_AMOUNT
                    || calcRole == MesProProcessWageFieldDO.CALC_ROLE_QUANTITY_PRICE;
            if (numericRole && !Objects.equals(fieldType, MesProProcessWageFieldDO.FIELD_TYPE_NUMBER)) {
                throw new ServiceException(PRO_PROCESS_WAGE_FIELD_TYPE_INVALID.getCode(),
                        StrUtil.format("工序[{}]字段[{}]参与工资计算,字段类型必须为「数值」,实际为[{}];请改为数值类型后重试",
                                process.getName(), name, fieldTypeName(fieldType)));
            }
            if (numericRole) {
                // 固定值允许留空:由质检在过程检验单上填写,计算时系数按 1、金额/数量按 0 处理
                BigDecimal value = parseValue(process.getName(), name, item.getFieldValue());
                if (calcRole == MesProProcessWageFieldDO.CALC_ROLE_COEFFICIENT
                        && value != null && value.signum() <= 0) {
                    throw new ServiceException(PRO_PROCESS_WAGE_FIELD_VALUE_INVALID.getCode(),
                            StrUtil.format("工序[{}]字段[{}]为工资系数,期望大于 0 的数值,实际为[{}];请填写大于 0 的系数,或留空由质检填写",
                                    process.getName(), name, item.getFieldValue()));
                }
                if (calcRole == MesProProcessWageFieldDO.CALC_ROLE_QUANTITY_PRICE
                        && (item.getUnitPrice() == null || item.getUnitPrice().signum() < 0)) {
                    throw new ServiceException(PRO_PROCESS_WAGE_FIELD_VALUE_INVALID.getCode(),
                            StrUtil.format("工序[{}]字段[{}]为计价数量,期望配置单价且不小于 0,实际为[{}];请补充单价后重试",
                                    process.getName(), name, item.getUnitPrice()));
                }
            }
        }
    }
 
    private BigDecimal parseValue(String processName, String fieldName, String fieldValue) {
        // 留空返回 null,由质检在过程检验单填写;非空则必须是数值
        if (StrUtil.isBlank(fieldValue)) {
            return null;
        }
        try {
            return new BigDecimal(fieldValue.trim());
        } catch (NumberFormatException ex) {
            throw new ServiceException(PRO_PROCESS_WAGE_FIELD_VALUE_INVALID.getCode(),
                    StrUtil.format("工序[{}]字段[{}]参与工资计算,期望数值,实际为[{}];请改为数值后重试",
                            processName, fieldName, fieldValue));
        }
    }
 
    private static String fieldTypeName(Integer fieldType) {
        if (fieldType == null) {
            return "未知";
        }
        return switch (fieldType) {
            case MesProProcessWageFieldDO.FIELD_TYPE_NUMBER -> "数值";
            case MesProProcessWageFieldDO.FIELD_TYPE_TEXT -> "文本";
            case MesProProcessWageFieldDO.FIELD_TYPE_SELECT -> "下拉";
            case MesProProcessWageFieldDO.FIELD_TYPE_BOOLEAN -> "布尔";
            default -> "未知";
        };
    }
 
}