|
@@ -14,6 +14,8 @@ import com.lframework.starter.common.utils.StringUtil; |
|
@@ -14,6 +14,8 @@ import com.lframework.starter.common.utils.StringUtil; |
|
14
|
import com.lframework.starter.web.core.impl.BaseMpServiceImpl;
|
14
|
import com.lframework.starter.web.core.impl.BaseMpServiceImpl;
|
|
15
|
import com.lframework.starter.web.core.utils.IdUtil;
|
15
|
import com.lframework.starter.web.core.utils.IdUtil;
|
|
16
|
import com.lframework.starter.web.core.utils.PageHelperUtil;
|
16
|
import com.lframework.starter.web.core.utils.PageHelperUtil;
|
|
|
|
17
|
+import com.lframework.starter.web.inner.entity.SysDept;
|
|
|
|
18
|
+import com.lframework.starter.web.inner.service.system.SysDeptService;
|
|
17
|
import com.lframework.starter.web.core.components.resp.PageResult;
|
19
|
import com.lframework.starter.web.core.components.resp.PageResult;
|
|
18
|
import com.lframework.starter.web.core.utils.PageResultUtil;
|
20
|
import com.lframework.starter.web.core.utils.PageResultUtil;
|
|
19
|
import com.lframework.xingyun.sc.bo.procurement.GetProcurementPlanBo;
|
21
|
import com.lframework.xingyun.sc.bo.procurement.GetProcurementPlanBo;
|
|
@@ -32,6 +34,9 @@ import java.time.LocalDate; |
|
@@ -32,6 +34,9 @@ import java.time.LocalDate; |
|
32
|
import java.time.format.DateTimeFormatter;
|
34
|
import java.time.format.DateTimeFormatter;
|
|
33
|
import java.util.ArrayList;
|
35
|
import java.util.ArrayList;
|
|
34
|
import java.util.Collections;
|
36
|
import java.util.Collections;
|
|
|
|
37
|
+import java.util.Comparator;
|
|
|
|
38
|
+import java.util.HashMap;
|
|
|
|
39
|
+import java.util.LinkedHashMap;
|
|
35
|
import java.util.List;
|
40
|
import java.util.List;
|
|
36
|
import java.util.Map;
|
41
|
import java.util.Map;
|
|
37
|
import java.util.stream.Collectors;
|
42
|
import java.util.stream.Collectors;
|
|
@@ -46,6 +51,8 @@ public class ProcurementPlanServiceImpl extends BaseMpServiceImpl<ProcurementPla |
|
@@ -46,6 +51,8 @@ public class ProcurementPlanServiceImpl extends BaseMpServiceImpl<ProcurementPla |
|
46
|
|
51
|
|
|
47
|
@Autowired
|
52
|
@Autowired
|
|
48
|
private ProcurementPlanLineService procurementPlanLineService;
|
53
|
private ProcurementPlanLineService procurementPlanLineService;
|
|
|
|
54
|
+ @Autowired
|
|
|
|
55
|
+ private SysDeptService sysDeptService;
|
|
49
|
|
56
|
|
|
50
|
@Override
|
57
|
@Override
|
|
51
|
public PageResult<ProcurementPlan> query(Integer pageIndex, Integer pageSize,
|
58
|
public PageResult<ProcurementPlan> query(Integer pageIndex, Integer pageSize,
|
|
@@ -218,6 +225,10 @@ public class ProcurementPlanServiceImpl extends BaseMpServiceImpl<ProcurementPla |
|
@@ -218,6 +225,10 @@ public class ProcurementPlanServiceImpl extends BaseMpServiceImpl<ProcurementPla |
|
218
|
if (StringUtil.isBlank(id)) {
|
225
|
if (StringUtil.isBlank(id)) {
|
|
219
|
throw new InputErrorException("ID不能为空!");
|
226
|
throw new InputErrorException("ID不能为空!");
|
|
220
|
}
|
227
|
}
|
|
|
|
228
|
+ ProcurementPlan procurementPlan = getBaseMapper().selectById(id);
|
|
|
|
229
|
+ if (procurementPlan == null || procurementPlan.getCompanyShortId() == null) {
|
|
|
|
230
|
+ throw new InputErrorException("请先补充公司名称!");
|
|
|
|
231
|
+ }
|
|
221
|
//todo 后面合同模块需要补充生成合同的逻辑
|
232
|
//todo 后面合同模块需要补充生成合同的逻辑
|
|
222
|
LambdaUpdateWrapper<ProcurementPlan> updateWrapper = Wrappers.lambdaUpdate(ProcurementPlan.class)
|
233
|
LambdaUpdateWrapper<ProcurementPlan> updateWrapper = Wrappers.lambdaUpdate(ProcurementPlan.class)
|
|
223
|
.set(ProcurementPlan::getProcessNode, "GYGLKZLGLG")
|
234
|
.set(ProcurementPlan::getProcessNode, "GYGLKZLGLG")
|
|
@@ -227,6 +238,146 @@ public class ProcurementPlanServiceImpl extends BaseMpServiceImpl<ProcurementPla |
|
@@ -227,6 +238,146 @@ public class ProcurementPlanServiceImpl extends BaseMpServiceImpl<ProcurementPla |
|
227
|
getBaseMapper().update(updateWrapper);
|
238
|
getBaseMapper().update(updateWrapper);
|
|
228
|
}
|
239
|
}
|
|
229
|
|
240
|
|
|
|
|
241
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
|
242
|
+ @Override
|
|
|
|
243
|
+ public void submit(String id) {
|
|
|
|
244
|
+ if (StringUtil.isBlank(id)) {
|
|
|
|
245
|
+ throw new InputErrorException("ID不能为空!");
|
|
|
|
246
|
+ }
|
|
|
|
247
|
+ ProcurementPlan mainPlan = getBaseMapper().findById(id);
|
|
|
|
248
|
+ if (mainPlan == null) {
|
|
|
|
249
|
+ throw new DefaultClientException("采购计划不存在!");
|
|
|
|
250
|
+ }
|
|
|
|
251
|
+ List<ProcurementPlanLine> allLines = procurementPlanLineService.getByProcurementPlanId(id);
|
|
|
|
252
|
+
|
|
|
|
253
|
+ if (CollectionUtil.isEmpty(allLines)) {
|
|
|
|
254
|
+ throw new DefaultClientException("采购计划明细不能为空,无法提交!");
|
|
|
|
255
|
+ }
|
|
|
|
256
|
+
|
|
|
|
257
|
+ // 1. 校验明细:只要有任意一条明细未配置分厂ID,就不允许拆分
|
|
|
|
258
|
+ boolean hasEmptyWorkshopId = allLines.stream()
|
|
|
|
259
|
+ .anyMatch(line -> line.getWorkshopId() == null); // 检查是否存在空的分厂ID
|
|
|
|
260
|
+
|
|
|
|
261
|
+ if (hasEmptyWorkshopId) {
|
|
|
|
262
|
+ throw new DefaultClientException("部分采购计划明细未选择分厂,请先选择分厂!");
|
|
|
|
263
|
+ }
|
|
|
|
264
|
+
|
|
|
|
265
|
+ // 2. 校验通过后,再提取所有的 workshopId(此时可保证全部非空)
|
|
|
|
266
|
+ List<String> workshopIds = allLines.stream()
|
|
|
|
267
|
+ .map(ProcurementPlanLine::getWorkshopId)
|
|
|
|
268
|
+ .distinct()
|
|
|
|
269
|
+ .collect(Collectors.toList());
|
|
|
|
270
|
+ Map<String, String> deptId2CodeMap = new HashMap<>();
|
|
|
|
271
|
+ List<SysDept> deptList = sysDeptService.listByIds(workshopIds);
|
|
|
|
272
|
+ if (CollectionUtil.isNotEmpty(deptList)) {
|
|
|
|
273
|
+ deptId2CodeMap = deptList.stream()
|
|
|
|
274
|
+ .filter(d -> StringUtil.isNotBlank(d.getCode()))
|
|
|
|
275
|
+ .collect(Collectors.toMap(SysDept::getId, SysDept::getCode, (v1, v2) -> v1));
|
|
|
|
276
|
+ }
|
|
|
|
277
|
+
|
|
|
|
278
|
+ // 分厂顺序:yfc(01) / efc(02) / sfc(03) / ztfc(04)
|
|
|
|
279
|
+ Map<String, Integer> workOrderMap = new LinkedHashMap<>();
|
|
|
|
280
|
+ workOrderMap.put("yfc", 1);
|
|
|
|
281
|
+ workOrderMap.put("efc", 2);
|
|
|
|
282
|
+ workOrderMap.put("sfc", 3);
|
|
|
|
283
|
+ workOrderMap.put("ztfc", 4);
|
|
|
|
284
|
+
|
|
|
|
285
|
+ // 按分厂code分组明细(非法/缺失code的明细都提示)
|
|
|
|
286
|
+ Map<String, List<ProcurementPlanLine>> code2LinesMap = new LinkedHashMap<>();
|
|
|
|
287
|
+ for (ProcurementPlanLine line : allLines) {
|
|
|
|
288
|
+ String code = deptId2CodeMap.get(line.getWorkshopId());
|
|
|
|
289
|
+ code2LinesMap.computeIfAbsent(code, k -> new ArrayList<>()).add(line);
|
|
|
|
290
|
+ }
|
|
|
|
291
|
+
|
|
|
|
292
|
+ long distinctFactoryCount = code2LinesMap.keySet().stream().distinct().count();
|
|
|
|
293
|
+ if (distinctFactoryCount <= 1) {
|
|
|
|
294
|
+ // 所有明细都同一分厂,不需要拆分,直接把主计划推到下一节点
|
|
|
|
295
|
+ LambdaUpdateWrapper<ProcurementPlan> updateWrapper = Wrappers.lambdaUpdate(ProcurementPlan.class)
|
|
|
|
296
|
+ .set(ProcurementPlan::getProcessNode, "GYGLKZG")
|
|
|
|
297
|
+ .set(ProcurementPlan::getProcessStatus, "TO_SUBMIT_REVIEW")
|
|
|
|
298
|
+ .eq(ProcurementPlan::getId, id);
|
|
|
|
299
|
+ getBaseMapper().update(updateWrapper);
|
|
|
|
300
|
+ //todo 生成买断操作申请单
|
|
|
|
301
|
+ return;
|
|
|
|
302
|
+ }
|
|
|
|
303
|
+
|
|
|
|
304
|
+ // 2. 多分厂:按 yfc/efc/sfc/ztfc 的顺序生成子计划
|
|
|
|
305
|
+ List<Map.Entry<String, List<ProcurementPlanLine>>> sortedEntries = code2LinesMap.entrySet().stream()
|
|
|
|
306
|
+ .sorted(Comparator.comparingInt(e -> workOrderMap.getOrDefault(e.getKey(), Integer.MAX_VALUE)))
|
|
|
|
307
|
+ .collect(Collectors.toList());
|
|
|
|
308
|
+
|
|
|
|
309
|
+ int subSeq = 0;
|
|
|
|
310
|
+ for (Map.Entry<String, List<ProcurementPlanLine>> entry : sortedEntries) {
|
|
|
|
311
|
+ List<ProcurementPlanLine> factoryLines = entry.getValue();
|
|
|
|
312
|
+ if (CollectionUtil.isEmpty(factoryLines)) {
|
|
|
|
313
|
+ continue;
|
|
|
|
314
|
+ }
|
|
|
|
315
|
+ subSeq++;
|
|
|
|
316
|
+ String suffix = String.format("%02d", subSeq);
|
|
|
|
317
|
+ String subCode = mainPlan.getCode() + "_" + suffix;
|
|
|
|
318
|
+
|
|
|
|
319
|
+ // 3. 子计划主表:除明细/编号/parentId/流程状态节点外,其余同主计划
|
|
|
|
320
|
+ CreateProcurementPlanVo subVo = BeanUtil.copyProperties(mainPlan, CreateProcurementPlanVo.class);
|
|
|
|
321
|
+ subVo.setCode(subCode);
|
|
|
|
322
|
+ subVo.setParentId(mainPlan.getId());
|
|
|
|
323
|
+ subVo.setProcessStatus("TO_SUBMIT_REVIEW");
|
|
|
|
324
|
+ subVo.setProcessNode("GYGLKZG");
|
|
|
|
325
|
+
|
|
|
|
326
|
+ // 子明细:只保留当前分厂,workshopId 保持原明细的,其它字段按原明细 copy
|
|
|
|
327
|
+ List<ProcurementPlanLineVo> subLineVoList = new ArrayList<>();
|
|
|
|
328
|
+ for (ProcurementPlanLine line : factoryLines) {
|
|
|
|
329
|
+ ProcurementPlanLineVo lineVo = BeanUtil.copyProperties(line, ProcurementPlanLineVo.class);
|
|
|
|
330
|
+ lineVo.setWorkshopId(line.getWorkshopId());
|
|
|
|
331
|
+ subLineVoList.add(lineVo);
|
|
|
|
332
|
+ }
|
|
|
|
333
|
+ subVo.setProcurementPlanLineList(subLineVoList);
|
|
|
|
334
|
+
|
|
|
|
335
|
+ // 子计划创建(不重新生成编号,因为使用父code+后缀)
|
|
|
|
336
|
+ createSubPlan(subVo);
|
|
|
|
337
|
+ //todo 生成买断操作申请单
|
|
|
|
338
|
+ }
|
|
|
|
339
|
+
|
|
|
|
340
|
+ // 4. 冻结主计划(不再变更主计划)
|
|
|
|
341
|
+ LambdaUpdateWrapper<ProcurementPlan> mainUpdateWrapper = Wrappers.lambdaUpdate(ProcurementPlan.class)
|
|
|
|
342
|
+ .set(ProcurementPlan::getFrozen, Boolean.TRUE)
|
|
|
|
343
|
+ .set(ProcurementPlan::getProcessNode, null)
|
|
|
|
344
|
+ .set(ProcurementPlan::getProcessStatus, null)
|
|
|
|
345
|
+ .eq(ProcurementPlan::getId, id);
|
|
|
|
346
|
+ getBaseMapper().update(mainUpdateWrapper);
|
|
|
|
347
|
+ }
|
|
|
|
348
|
+
|
|
|
|
349
|
+ /**
|
|
|
|
350
|
+ * 子计划创建:与 create() 逻辑一致,但不重新 buildPlanCode(因为子计划编号已按父code+后缀生成)
|
|
|
|
351
|
+ */
|
|
|
|
352
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
|
353
|
+ public void createSubPlan(CreateProcurementPlanVo vo) {
|
|
|
|
354
|
+ vo.validate();
|
|
|
|
355
|
+
|
|
|
|
356
|
+ ProcurementPlan plan = BeanUtil.copyProperties(vo, ProcurementPlan.class);
|
|
|
|
357
|
+ plan.setId(IdUtil.getId());
|
|
|
|
358
|
+
|
|
|
|
359
|
+ BigDecimal totalQuantity = BigDecimal.ZERO;
|
|
|
|
360
|
+ if (!CollectionUtil.isEmpty(vo.getProcurementPlanLineList())) {
|
|
|
|
361
|
+ for (ProcurementPlanLineVo lineVo : vo.getProcurementPlanLineList()) {
|
|
|
|
362
|
+ if (lineVo.getQuantity() != null) {
|
|
|
|
363
|
+ totalQuantity = NumberUtil.add(totalQuantity, lineVo.getQuantity());
|
|
|
|
364
|
+ }
|
|
|
|
365
|
+ }
|
|
|
|
366
|
+ }
|
|
|
|
367
|
+ plan.setTotalQuantity(totalQuantity);
|
|
|
|
368
|
+
|
|
|
|
369
|
+ getBaseMapper().insert(plan);
|
|
|
|
370
|
+
|
|
|
|
371
|
+ if (!CollectionUtil.isEmpty(vo.getProcurementPlanLineList())) {
|
|
|
|
372
|
+ for (ProcurementPlanLineVo lineVo : vo.getProcurementPlanLineList()) {
|
|
|
|
373
|
+ ProcurementPlanLine line = BeanUtil.copyProperties(lineVo, ProcurementPlanLine.class);
|
|
|
|
374
|
+ line.setId(IdUtil.getId());
|
|
|
|
375
|
+ line.setProcurementPlanId(plan.getId());
|
|
|
|
376
|
+ procurementPlanLineService.save(line);
|
|
|
|
377
|
+ }
|
|
|
|
378
|
+ }
|
|
|
|
379
|
+ }
|
|
|
|
380
|
+
|
|
230
|
/**
|
381
|
/**
|
|
231
|
* 生成采购计划编号(业务要求按日期时间生成,保证唯一)
|
382
|
* 生成采购计划编号(业务要求按日期时间生成,保证唯一)
|
|
232
|
*
|
383
|
*
|