gaoluyang
12 小时以前 bc9d77f6061a5c7f7deceaabc7c5ed6c17ad8c2f
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
173
174
package cn.iocoder.yudao.module.mes.service.wm.productissue;
 
import cn.hutool.core.util.ObjUtil;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
import cn.iocoder.yudao.module.mes.controller.admin.wm.productissue.vo.detail.MesWmProductIssueDetailSaveReqVO;
import cn.iocoder.yudao.module.mes.dal.dataobject.mdm.MesMdmItemDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productissue.MesWmProductIssueDetailDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productissue.MesWmProductIssueDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productissue.MesWmProductIssueLineDO;
import cn.iocoder.yudao.module.mes.dal.mysql.wm.productissue.MesWmProductIssueDetailMapper;
import cn.iocoder.yudao.module.mes.enums.wm.MesWmProductIssueStatusEnum;
import cn.iocoder.yudao.module.mes.service.mdm.MesMdmItemService;
import cn.iocoder.yudao.module.mes.service.wm.materialstock.MesWmMaterialStockService;
import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseAreaService;
import jakarta.annotation.Resource;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
 
import java.util.List;
 
import cn.iocoder.yudao.framework.common.exception.ServiceException;
 
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*;
 
/**
 * MES 领料出库明细 Service 实现类
 */
@Service
@Validated
public class MesWmProductIssueDetailServiceImpl implements MesWmProductIssueDetailService {
 
    @Resource
    private MesWmProductIssueDetailMapper issueDetailMapper;
 
    @Resource
    @Lazy
    private MesWmProductIssueService issueService;
    @Resource
    @Lazy
    private MesWmProductIssueLineService issueLineService;
    @Resource
    private MesWmWarehouseAreaService warehouseAreaService;
    @Resource
    private MesWmMaterialStockService materialStockService;
    @Resource
    private MesMdmItemService mdmItemService;
 
    @Override
    public Long createProductIssueDetail(MesWmProductIssueDetailSaveReqVO createReqVO) {
        // 校验数据
        validateProductIssueDetailSaveData(createReqVO);
 
        // 插入
        MesWmProductIssueDetailDO detail = BeanUtils.toBean(createReqVO, MesWmProductIssueDetailDO.class);
        issueDetailMapper.insert(detail);
        return detail.getId();
    }
 
    @Override
    public void updateProductIssueDetail(MesWmProductIssueDetailSaveReqVO updateReqVO) {
        // 校验存在
        validateProductIssueDetailExists(updateReqVO.getId());
        // 校验数据
        validateProductIssueDetailSaveData(updateReqVO);
 
        // 更新
        MesWmProductIssueDetailDO updateObj = BeanUtils.toBean(updateReqVO, MesWmProductIssueDetailDO.class);
        issueDetailMapper.updateById(updateObj);
    }
 
    @Override
    public void deleteProductIssueDetail(Long id) {
        // 校验存在
        MesWmProductIssueDetailDO detail = issueDetailMapper.selectById(id);
        if (detail == null) {
            throw exception(WM_PRODUCT_ISSUE_DETAIL_NOT_EXISTS);
        }
        // 校验主单状态为草稿或待拣货(允许在拣货模式删除明细)
        MesWmProductIssueLineDO line = issueLineService.validateProductIssueLineExists(detail.getLineId());
        MesWmProductIssueDO issue = issueService.validateProductIssueExists(line.getIssueId());
        if (!ObjectUtils.equalsAny(issue.getStatus(),
                MesWmProductIssueStatusEnum.PREPARE.getStatus(),
                MesWmProductIssueStatusEnum.APPROVING.getStatus())) {
            throw exception(WM_PRODUCT_ISSUE_STATUS_INVALID);
        }
 
        // 删除
        issueDetailMapper.deleteById(id);
    }
 
    @Override
    public MesWmProductIssueDetailDO getProductIssueDetail(Long id) {
        return issueDetailMapper.selectById(id);
    }
 
    @Override
    public List<MesWmProductIssueDetailDO> getProductIssueDetailListByLineId(Long lineId) {
        return issueDetailMapper.selectListByLineId(lineId);
    }
 
    @Override
    public List<MesWmProductIssueDetailDO> getProductIssueDetailListByIssueId(Long issueId) {
        return issueDetailMapper.selectListByIssueId(issueId);
    }
 
    @Override
    public void deleteProductIssueDetailByIssueId(Long issueId) {
        issueDetailMapper.deleteByIssueId(issueId);
    }
 
    @Override
    public void deleteProductIssueDetailByLineId(Long lineId) {
        issueDetailMapper.deleteByLineId(lineId);
    }
 
    private void validateProductIssueDetailExists(Long id) {
        if (issueDetailMapper.selectById(id) == null) {
            throw exception(WM_PRODUCT_ISSUE_DETAIL_NOT_EXISTS);
        }
    }
 
    /**
     * 校验保存时的关联数据
     */
    private void validateProductIssueDetailSaveData(MesWmProductIssueDetailSaveReqVO reqVO) {
        // 校验父数据存在
        MesWmProductIssueLineDO line = issueLineService.validateProductIssueLineExists(reqVO.getLineId());
        if (ObjUtil.notEqual(line.getIssueId(), reqVO.getIssueId())) {
            throw exception(WM_PRODUCT_ISSUE_DETAIL_LINE_NOT_MATCH);
        }
        // 校验主单状态为待拣货(只有 APPROVING 状态才允许新增/修改明细)
        MesWmProductIssueDO issue = issueService.validateProductIssueExists(line.getIssueId());
        if (ObjUtil.notEqual(MesWmProductIssueStatusEnum.APPROVING.getStatus(), issue.getStatus())) {
            throw exception(WM_PRODUCT_ISSUE_STATUS_INVALID);
        }
        // 校验物料匹配(明细 itemId 必须与行 itemId 一致,两者都是 MDM 物料主数据 mdm_item.id)
        validateDetailItemMatch(reqVO.getItemId(), line.getItemId());
        // 校验仓库、库区、库位的关联关系
        warehouseAreaService.validateWarehouseAreaExists(
                reqVO.getWarehouseId(), reqVO.getLocationId(), reqVO.getAreaId());
        // 校验库存记录
        materialStockService.validateSelectedStock(
                reqVO.getMaterialStockId(), reqVO.getItemId(), reqVO.getBatchId(), reqVO.getBatchCode(),
                reqVO.getWarehouseId(), reqVO.getLocationId(), reqVO.getAreaId(), reqVO.getQuantity());
    }
 
    /**
     * 校验明细物料与行物料一致
     */
    private void validateDetailItemMatch(Long detailItemId, Long lineItemId) {
        if (ObjUtil.notEqual(detailItemId, lineItemId)) {
            // 名称解析放在异常分支,避免正常保存时多查表
            throw new ServiceException(WM_PRODUCT_ISSUE_DETAIL_ITEM_MISMATCH.getCode(),
                    "拣货明细的物料与领料出库单行的物料不一致:明细物料[" + describeItem(detailItemId)
                            + "],单据行物料[" + describeItem(lineItemId) + "]。"
                            + "请重新选择该行的物料后重试,或删除本条明细后重新添加。");
        }
    }
 
    /**
     * 描述物料,用于异常提示:优先给出「编码 名称」,查不到时回退为物料编号
     */
    private String describeItem(Long itemId) {
        if (itemId == null) {
            return "未选择";
        }
        MesMdmItemDO item = mdmItemService.getItem(itemId);
        return item != null ? item.getCode() + " " + item.getName() : "物料编号 ID=" + itemId;
    }
 
}