feat(schProdScheduleItem): 新增明细下发功能支持逐条明细独立下发
- 在 ISchProdScheduleItemService 中新增 receiveFromDetail 方法接口 - 在 SchProdScheduleItemController 中新增 /receiveFromDetail 接口 - 在 SchProdScheduleItemServiceImpl 中实现明细下发业务逻辑 - 新增 SchProdScheduleItemDispatchBo 数据传输对象 - 支持按明细+工序步骤维度删除重复记录后再重新插入 - 使用明细自身 scheduleDate 作为生产日期确保多天排产准确性 - 实现批量插入排产单明细项功能
This commit is contained in:
@@ -24,6 +24,7 @@ import com.klp.flow.domain.bo.SchProdScheduleItemMergeBo;
|
|||||||
import com.klp.flow.domain.bo.SchProdScheduleItemReceiveBo;
|
import com.klp.flow.domain.bo.SchProdScheduleItemReceiveBo;
|
||||||
import com.klp.flow.domain.bo.SchProdScheduleItemMergeValidateBo;
|
import com.klp.flow.domain.bo.SchProdScheduleItemMergeValidateBo;
|
||||||
import com.klp.flow.domain.bo.SchProdScheduleItemSortBo;
|
import com.klp.flow.domain.bo.SchProdScheduleItemSortBo;
|
||||||
|
import com.klp.flow.domain.bo.SchProdScheduleItemDispatchBo;
|
||||||
import com.klp.flow.service.ISchProdScheduleItemService;
|
import com.klp.flow.service.ISchProdScheduleItemService;
|
||||||
import com.klp.common.core.page.TableDataInfo;
|
import com.klp.common.core.page.TableDataInfo;
|
||||||
|
|
||||||
@@ -132,6 +133,18 @@ public class SchProdScheduleItemController extends BaseController {
|
|||||||
return toAjax(iSchProdScheduleItemService.receiveByBo(receiveBo));
|
return toAjax(iSchProdScheduleItemService.receiveByBo(receiveBo));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 明细下发:逐条从 sch_prod_schedule_detail 下发到 sch_prod_schedule_item
|
||||||
|
* 生产日期使用明细的 scheduleDate,支持一条一条明细独立下发
|
||||||
|
* 若已下发过(同明细+同工序),先删除旧记录再重新插入
|
||||||
|
*/
|
||||||
|
@Log(title = "排产单主加明细可合并", businessType = BusinessType.INSERT)
|
||||||
|
@RepeatSubmit()
|
||||||
|
@PostMapping("/receiveFromDetail")
|
||||||
|
public R<Void> receiveFromDetail(@Validated @RequestBody SchProdScheduleItemDispatchBo dispatchBo) {
|
||||||
|
return toAjax(iSchProdScheduleItemService.receiveFromDetail(dispatchBo));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 合并校验:检查待合并记录来源产需单的 header 字段是否一致
|
* 合并校验:检查待合并记录来源产需单的 header 字段是否一致
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -0,0 +1,69 @@
|
|||||||
|
package com.klp.flow.domain.bo;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotEmpty;
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 排产明细下发请求对象 —— 从 sch_prod_schedule_detail 逐条下发到 sch_prod_schedule_item
|
||||||
|
*
|
||||||
|
* @author klp
|
||||||
|
* @date 2026-07-10
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class SchProdScheduleItemDispatchBo {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 明细下发配置列表(每条明细独立下发,各自携带工序步骤)
|
||||||
|
*/
|
||||||
|
@NotEmpty(message = "明细下发配置不能为空")
|
||||||
|
private List<DetailDispatchConfig> detailList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 单条明细的下发配置
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public static class DetailDispatchConfig {
|
||||||
|
/**
|
||||||
|
* 排产明细ID(sch_prod_schedule_detail.schedule_detail_id)
|
||||||
|
*/
|
||||||
|
@NotNull(message = "明细ID不能为空")
|
||||||
|
private Long scheduleDetailId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 工序ID(sch_prod_process.process_id),用于区分下发后按工序分组
|
||||||
|
*/
|
||||||
|
@NotNull(message = "工序ID不能为空")
|
||||||
|
private Long processId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 工序步骤列表
|
||||||
|
*/
|
||||||
|
@NotEmpty(message = "工序步骤不能为空")
|
||||||
|
private List<StepConfig> stepList;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 工序步骤配置
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public static class StepConfig {
|
||||||
|
/**
|
||||||
|
* 步骤ID(sch_prod_process_step.step_id,下发后存为 actionId)
|
||||||
|
*/
|
||||||
|
@NotNull(message = "步骤ID不能为空")
|
||||||
|
private Long stepId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 步骤顺序号
|
||||||
|
*/
|
||||||
|
private Long stepOrder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 步骤名称
|
||||||
|
*/
|
||||||
|
private String stepName;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,6 +8,7 @@ import com.klp.flow.domain.bo.SchProdScheduleItemMergeBo;
|
|||||||
import com.klp.flow.domain.bo.SchProdScheduleItemReceiveBo;
|
import com.klp.flow.domain.bo.SchProdScheduleItemReceiveBo;
|
||||||
import com.klp.flow.domain.bo.SchProdScheduleItemMergeValidateBo;
|
import com.klp.flow.domain.bo.SchProdScheduleItemMergeValidateBo;
|
||||||
import com.klp.flow.domain.bo.SchProdScheduleItemSortBo;
|
import com.klp.flow.domain.bo.SchProdScheduleItemSortBo;
|
||||||
|
import com.klp.flow.domain.bo.SchProdScheduleItemDispatchBo;
|
||||||
import com.klp.common.core.page.TableDataInfo;
|
import com.klp.common.core.page.TableDataInfo;
|
||||||
import com.klp.common.core.domain.PageQuery;
|
import com.klp.common.core.domain.PageQuery;
|
||||||
|
|
||||||
@@ -76,4 +77,11 @@ public interface ISchProdScheduleItemService {
|
|||||||
* 保存已排产拖拽排序
|
* 保存已排产拖拽排序
|
||||||
*/
|
*/
|
||||||
Boolean saveSort(SchProdScheduleItemSortBo sortBo);
|
Boolean saveSort(SchProdScheduleItemSortBo sortBo);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 明细下发:逐条从 sch_prod_schedule_detail 下发到 sch_prod_schedule_item
|
||||||
|
* 若已下发过(同明细+同工序),先删除再重新插入
|
||||||
|
* 生产日期使用明细自身的 scheduleDate,而非主表的 prodDate
|
||||||
|
*/
|
||||||
|
Boolean receiveFromDetail(SchProdScheduleItemDispatchBo dispatchBo);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import com.klp.flow.domain.bo.SchProdScheduleItemMergeBo;
|
|||||||
import com.klp.flow.domain.bo.SchProdScheduleItemReceiveBo;
|
import com.klp.flow.domain.bo.SchProdScheduleItemReceiveBo;
|
||||||
import com.klp.flow.domain.bo.SchProdScheduleItemMergeValidateBo;
|
import com.klp.flow.domain.bo.SchProdScheduleItemMergeValidateBo;
|
||||||
import com.klp.flow.domain.bo.SchProdScheduleItemSortBo;
|
import com.klp.flow.domain.bo.SchProdScheduleItemSortBo;
|
||||||
|
import com.klp.flow.domain.bo.SchProdScheduleItemDispatchBo;
|
||||||
import com.klp.flow.domain.vo.SchProdScheduleItemVo;
|
import com.klp.flow.domain.vo.SchProdScheduleItemVo;
|
||||||
import com.klp.flow.domain.vo.SchProdScheduleItemMergeValidateVo;
|
import com.klp.flow.domain.vo.SchProdScheduleItemMergeValidateVo;
|
||||||
import com.klp.flow.domain.SchProdScheduleItem;
|
import com.klp.flow.domain.SchProdScheduleItem;
|
||||||
@@ -480,6 +481,103 @@ public class SchProdScheduleItemServiceImpl implements ISchProdScheduleItemServi
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 明细下发:逐条从 sch_prod_schedule_detail 下发到 sch_prod_schedule_item
|
||||||
|
* 若已下发过(同明细+同工序步骤),先删除再重新插入,避免重复
|
||||||
|
* 生产日期使用明细自身的 scheduleDate,保证多天排产的时间准确性
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public Boolean receiveFromDetail(SchProdScheduleItemDispatchBo dispatchBo) {
|
||||||
|
List<SchProdScheduleItemDispatchBo.DetailDispatchConfig> detailList = dispatchBo.getDetailList();
|
||||||
|
|
||||||
|
for (SchProdScheduleItemDispatchBo.DetailDispatchConfig config : detailList) {
|
||||||
|
Long detailId = config.getScheduleDetailId();
|
||||||
|
|
||||||
|
// 1. 查询排产明细
|
||||||
|
SchProdScheduleDetail detail = schProdScheduleDetailMapper.selectById(detailId);
|
||||||
|
if (detail == null) {
|
||||||
|
throw new RuntimeException("排产明细不存在,scheduleDetailId=" + detailId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 查询产需单主表
|
||||||
|
SchProdSchedule header = schProdScheduleMapper.selectById(detail.getScheduleId());
|
||||||
|
if (header == null) {
|
||||||
|
throw new RuntimeException("产需单不存在,scheduleId=" + detail.getScheduleId());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 收集本次下发的步骤ID列表
|
||||||
|
List<Long> stepIds = config.getStepList().stream()
|
||||||
|
.map(SchProdScheduleItemDispatchBo.StepConfig::getStepId)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
// 4. 删除该明细上一次下发的内容(同明细 + 同工序步骤),区分工序避免误删
|
||||||
|
baseMapper.delete(
|
||||||
|
Wrappers.<SchProdScheduleItem>lambdaQuery()
|
||||||
|
.eq(SchProdScheduleItem::getScheduleDetailIds, String.valueOf(detailId))
|
||||||
|
.in(SchProdScheduleItem::getActionId, stepIds)
|
||||||
|
);
|
||||||
|
|
||||||
|
// 5. 根据工序步骤逐条生成新的排产单明细项
|
||||||
|
List<SchProdScheduleItem> addList = new ArrayList<>();
|
||||||
|
for (SchProdScheduleItemDispatchBo.StepConfig step : config.getStepList()) {
|
||||||
|
SchProdScheduleItem item = new SchProdScheduleItem();
|
||||||
|
|
||||||
|
// —— 从 header 复制主表字段 ——
|
||||||
|
item.setScheduleNo(header.getScheduleNo());
|
||||||
|
item.setScheduleStatus(2L); // 已下达
|
||||||
|
item.setTotalPlanWeight(header.getTotalPlanWeight());
|
||||||
|
item.setRelContractNo(header.getRelContractNo());
|
||||||
|
item.setBusinessUser(header.getBusinessUser());
|
||||||
|
item.setBusinessPhone(header.getBusinessPhone());
|
||||||
|
item.setOrderDate(header.getOrderDate());
|
||||||
|
item.setCustomerName(header.getCustomerName());
|
||||||
|
item.setDeliveryCycle(header.getDeliveryCycle());
|
||||||
|
item.setUsePurpose(header.getUsePurpose());
|
||||||
|
item.setProductType(header.getProductType());
|
||||||
|
item.setThicknessTolerance(header.getThicknessTolerance());
|
||||||
|
item.setWidthTolerance(header.getWidthTolerance());
|
||||||
|
item.setSurfaceQuality(header.getSurfaceQuality());
|
||||||
|
item.setSurfaceTreatment(header.getSurfaceTreatment());
|
||||||
|
item.setInnerDiameter(header.getInnerDiameter());
|
||||||
|
item.setOuterDiameter(header.getOuterDiameter());
|
||||||
|
item.setPackReq(header.getPackReq());
|
||||||
|
item.setCutEdgeReq(header.getCutEdgeReq());
|
||||||
|
item.setSingleCoilWeight(header.getSingleCoilWeight());
|
||||||
|
item.setWeightDeviation(header.getWeightDeviation());
|
||||||
|
item.setOtherTechReq(header.getOtherTechReq());
|
||||||
|
item.setPaymentDesc(header.getPaymentDesc());
|
||||||
|
item.setRemark(header.getRemark());
|
||||||
|
|
||||||
|
// —— 生产日期使用明细自身的 scheduleDate,实现逐条明细独立时间 ——
|
||||||
|
item.setProdDate(detail.getScheduleDate());
|
||||||
|
|
||||||
|
// —— 从 detail 复制明细字段 ——
|
||||||
|
item.setSpec(detail.getSpec());
|
||||||
|
item.setMaterial(detail.getMaterial());
|
||||||
|
item.setScheduleWeight(detail.getScheduleWeight());
|
||||||
|
item.setProductItem(detail.getProductType());
|
||||||
|
item.setRowRemark(detail.getRemark());
|
||||||
|
|
||||||
|
// —— 工序步骤 ——
|
||||||
|
item.setActionId(step.getStepId());
|
||||||
|
|
||||||
|
// —— 来源追溯(未合并,存单明细ID) ——
|
||||||
|
item.setScheduleDetailIds(String.valueOf(detailId));
|
||||||
|
|
||||||
|
validEntityBeforeSave(item);
|
||||||
|
addList.add(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6. 批量插入新记录
|
||||||
|
if (!addList.isEmpty()) {
|
||||||
|
baseMapper.insertBatch(addList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 合并校验:检查待合并记录来源产需单的 header 字段是否一致
|
* 合并校验:检查待合并记录来源产需单的 header 字段是否一致
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user