Compare commits

...

2 Commits

Author SHA1 Message Date
曹鹏飞 d6211aac84 feat(material-sync): 实现按日期范围同步主物料系统数据功能
- 在BomMaterialService中新增按日期范围查询物料列表接口getListByDate
- 新增MaterialMainListByDateDTO用于接收按日期查询返回的物料信息
- 新增MaterialListByDateQO定义按日期范围查询请求参数
- 在QmsQcMaterialController添加按日期范围同步物料接口syncFromMainByDate
- 在QmsQcMaterialControllerService实现syncFromMainByDate业务方法,支持插入和更新物料
- 新增QCMaterialSyncProcessor定时同步主物料数据到质检系统
- 调整RestTemplate连接超时时间从3000ms提升至5000ms
- 增强MaterialMainDTO,添加申请人编码、申请部门、材质、推荐度等字段
- 添加MaterialSyncTest单元测试覆盖按日期同步功能
- 优化日志打印,查询物料时超过1000条数据不打印详细内容
2026-04-25 12:24:46 +08:00
曹鹏飞 818db2cc57 feat(inspection): 新增来料检验任务记录及子项详情查询接口
- 新增接口以查询指定任务ID的来料检验任务检验记录,包含记录项和检验数据
- 新增接口以查询指定检验记录ID的检验记录子项列表,包含样本数据详情
- 引入相关VO类用于返回结构化的检验记录、检验项及检验数据
- 查询过程中关联检验标准项内容及检验标准项,丰富返回的数据内容
- 实现数据分组与映射,保证接口返回数据完整且结构清晰
- QmsIncomingInspectionTaskController增加对应REST接口支持前端调用
2026-04-25 10:13:10 +08:00
15 changed files with 997 additions and 9 deletions

View File

@ -6,6 +6,8 @@ import com.nflg.wms.common.pojo.PageData;
import com.nflg.wms.common.pojo.qo.*; import com.nflg.wms.common.pojo.qo.*;
import com.nflg.wms.common.pojo.vo.QmsIncomingInspectionTaskCheckDetailVO; import com.nflg.wms.common.pojo.vo.QmsIncomingInspectionTaskCheckDetailVO;
import com.nflg.wms.common.pojo.vo.QmsIncomingInspectionTaskCountVO; import com.nflg.wms.common.pojo.vo.QmsIncomingInspectionTaskCountVO;
import com.nflg.wms.common.pojo.vo.QmsIncomingInspectionTaskRecordItemDetailVO;
import com.nflg.wms.common.pojo.vo.QmsIncomingInspectionTaskRecordVO;
import com.nflg.wms.common.pojo.vo.QmsIncomingInspectionTaskVO; import com.nflg.wms.common.pojo.vo.QmsIncomingInspectionTaskVO;
import com.nflg.wms.repository.entity.QmsIncomingInspectionTaskRecord; import com.nflg.wms.repository.entity.QmsIncomingInspectionTaskRecord;
import com.nflg.wms.starter.BaseController; import com.nflg.wms.starter.BaseController;
@ -42,6 +44,14 @@ public class QmsIncomingInspectionTaskController extends BaseController {
return ApiResult.success(incomingInspectionTaskControllerService.getDetail(id)); return ApiResult.success(incomingInspectionTaskControllerService.getDetail(id));
} }
// /**
// * 查询来料检验任务检验记录含检验项和检验数据
// */
// @GetMapping("records")
// public ApiResult<List<QmsIncomingInspectionTaskRecordVO>> getInspectionRecords(@RequestParam Long taskId) {
// return ApiResult.success(incomingInspectionTaskControllerService.getInspectionRecords(taskId));
// }
/** /**
* 转办 * 转办
*/ */
@ -51,6 +61,22 @@ public class QmsIncomingInspectionTaskController extends BaseController {
return ApiResult.success(); return ApiResult.success();
} }
/**
* 查询来料检测任务记录
*/
@GetMapping("records")
public ApiResult<List<QmsIncomingInspectionTaskRecord>> getRecords(@RequestParam Long taskId){
return ApiResult.success(incomingInspectionTaskControllerService.getRecords(taskId));
}
/**
* 查询来料检验任务检验记录子项列表含样本列表
*/
@GetMapping("record-items")
public ApiResult<List<QmsIncomingInspectionTaskRecordItemDetailVO>> getRecordItems(@RequestParam Long recordId){
return ApiResult.success(incomingInspectionTaskControllerService.getInspectionRecordItems(recordId));
}
/** /**
* 查询当前登录用户的待检验任务列表 * 查询当前登录用户的待检验任务列表
*/ */
@ -67,14 +93,6 @@ public class QmsIncomingInspectionTaskController extends BaseController {
return ApiResult.success(incomingInspectionTaskControllerService.countByCurrentUser()); return ApiResult.success(incomingInspectionTaskControllerService.countByCurrentUser());
} }
/**
* 查询来料检测任务记录
*/
@GetMapping("pad/records")
public ApiResult<List<QmsIncomingInspectionTaskRecord>> getRecords(@RequestParam Long taskId){
return ApiResult.success(incomingInspectionTaskControllerService.getRecords(taskId));
}
/** /**
* 查询待检测项 * 查询待检测项
*/ */
@ -113,4 +131,5 @@ public class QmsIncomingInspectionTaskController extends BaseController {
return ApiResult.success(); return ApiResult.success();
} }
} }

View File

@ -5,6 +5,7 @@ import com.nflg.wms.common.pojo.ApiResult;
import com.nflg.wms.common.pojo.PageData; import com.nflg.wms.common.pojo.PageData;
import com.nflg.wms.common.pojo.dto.MaterialMainDTO; import com.nflg.wms.common.pojo.dto.MaterialMainDTO;
import com.nflg.wms.common.pojo.qo.BomMaterialListQO; import com.nflg.wms.common.pojo.qo.BomMaterialListQO;
import com.nflg.wms.common.pojo.qo.MaterialListByDateQO;
import com.nflg.wms.common.pojo.qo.QmsQcMaterialAddQO; import com.nflg.wms.common.pojo.qo.QmsQcMaterialAddQO;
import com.nflg.wms.common.pojo.qo.QmsQcMaterialSearchQO; import com.nflg.wms.common.pojo.qo.QmsQcMaterialSearchQO;
import com.nflg.wms.common.pojo.qo.QmsQcMaterialUpdateQO; import com.nflg.wms.common.pojo.qo.QmsQcMaterialUpdateQO;
@ -108,4 +109,13 @@ public class QmsQcMaterialController extends BaseController {
qcMaterialControllerService.syncFromMain(ids); qcMaterialControllerService.syncFromMain(ids);
return ApiResult.success(); return ApiResult.success();
} }
/**
* 按日期范围从主物料系统同步物料信息
*/
@PostMapping("syncFromMainByDate")
public ApiResult<Void> syncFromMainByDate(@Valid @RequestBody MaterialListByDateQO request){
qcMaterialControllerService.syncFromMainByDate(request.getStartDate(), request.getEndDate());
return ApiResult.success();
}
} }

View File

@ -10,6 +10,10 @@ import com.nflg.wms.common.pojo.qo.*;
import com.nflg.wms.common.pojo.vo.QmsIncomingInspectionTaskCheckDetailVO; import com.nflg.wms.common.pojo.vo.QmsIncomingInspectionTaskCheckDetailVO;
import com.nflg.wms.common.pojo.vo.QmsIncomingInspectionTaskCheckItemVO; import com.nflg.wms.common.pojo.vo.QmsIncomingInspectionTaskCheckItemVO;
import com.nflg.wms.common.pojo.vo.QmsIncomingInspectionTaskCountVO; import com.nflg.wms.common.pojo.vo.QmsIncomingInspectionTaskCountVO;
import com.nflg.wms.common.pojo.vo.QmsIncomingInspectionTaskRecordItemDataVO;
import com.nflg.wms.common.pojo.vo.QmsIncomingInspectionTaskRecordItemDetailVO;
import com.nflg.wms.common.pojo.vo.QmsIncomingInspectionTaskRecordItemVO;
import com.nflg.wms.common.pojo.vo.QmsIncomingInspectionTaskRecordVO;
import com.nflg.wms.common.pojo.vo.QmsIncomingInspectionTaskVO; import com.nflg.wms.common.pojo.vo.QmsIncomingInspectionTaskVO;
import com.nflg.wms.common.util.UserUtil; import com.nflg.wms.common.util.UserUtil;
import com.nflg.wms.common.util.VUtil; import com.nflg.wms.common.util.VUtil;
@ -24,7 +28,10 @@ import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;
/** /**
* 来料检测任务 Controller 服务 * 来料检测任务 Controller 服务
@ -93,6 +100,9 @@ public class IncomingInspectionTaskControllerService {
@Resource @Resource
private IQmsCodeLetterMatrixService codeLetterMatrixService; private IQmsCodeLetterMatrixService codeLetterMatrixService;
@Resource
private IQmsInspectionStandardItemContentService inspectionStandardItemContentService;
/** /**
* 来料检验申请对外接口 * 来料检验申请对外接口
* 业务规则 * 业务规则
@ -590,6 +600,116 @@ public class IncomingInspectionTaskControllerService {
.list(); .list();
} }
/**
* 查询来料检验任务检验记录含检验项和检验数据
*/
public List<QmsIncomingInspectionTaskRecordVO> getInspectionRecords(Long taskId) {
// 1. 查询该任务下所有检验记录
List<QmsIncomingInspectionTaskRecord> records = incomingInspectionTaskRecordService.lambdaQuery()
.eq(QmsIncomingInspectionTaskRecord::getTaskId, taskId)
.list();
if (CollectionUtil.isEmpty(records)) {
return List.of();
}
// 2. 收集所有记录ID
List<Long> recordIds = records.stream()
.map(QmsIncomingInspectionTaskRecord::getId)
.toList();
// 3. 查询所有记录下的检验项
List<QmsIncomingInspectionTaskRecordItem> allItems = incomingInspectionTaskRecordItemService.lambdaQuery()
.in(QmsIncomingInspectionTaskRecordItem::getRecordId, recordIds)
.list();
// 4. 收集所有检验项ID并构建 recordId -> items 映射
Map<Long, List<QmsIncomingInspectionTaskRecordItem>> recordItemMap = allItems.stream()
.collect(Collectors.groupingBy(QmsIncomingInspectionTaskRecordItem::getRecordId));
// 5. 查询检验标准项内容获取检测项名称标准等信息
List<Long> contentIds = allItems.stream()
.map(QmsIncomingInspectionTaskRecordItem::getInspectionStandardItemContentId)
.filter(Objects::nonNull)
.distinct()
.toList();
Map<Long, QmsInspectionStandardItemContent> contentMap = Map.of();
if (!contentIds.isEmpty()) {
contentMap = inspectionStandardItemContentService.lambdaQuery()
.in(QmsInspectionStandardItemContent::getId, contentIds)
.list()
.stream()
.collect(Collectors.toMap(QmsInspectionStandardItemContent::getId, Function.identity()));
}
// 6. 查询所有检验项下的检验数据
List<Long> itemIds = allItems.stream()
.map(QmsIncomingInspectionTaskRecordItem::getId)
.toList();
Map<Long, List<QmsIncomingInspectionTaskRecordItemData>> itemDataMap = Map.of();
if (!itemIds.isEmpty()) {
itemDataMap = incomingInspectionTaskRecordItemDataService.lambdaQuery()
.in(QmsIncomingInspectionTaskRecordItemData::getItemId, itemIds)
.list()
.stream()
.collect(Collectors.groupingBy(QmsIncomingInspectionTaskRecordItemData::getItemId));
}
// 7. 组装返回VO
Map<Long, QmsInspectionStandardItemContent> finalContentMap = contentMap;
Map<Long, List<QmsIncomingInspectionTaskRecordItemData>> finalItemDataMap = itemDataMap;
return records.stream().map(record -> {
QmsIncomingInspectionTaskRecordVO vo = new QmsIncomingInspectionTaskRecordVO();
vo.setId(record.getId());
vo.setTaskId(record.getTaskId());
vo.setMaterialUniqueNo(record.getMaterialUniqueNo());
vo.setQualified(record.getQualified());
vo.setInspectionQty(record.getInspectionQty());
vo.setQualifiedQty(record.getQualifiedQty());
vo.setUnqualifiedQty(record.getUnqualifiedQty());
vo.setCreateUserId(record.getCreateUserId());
vo.setCreateUserName(record.getCreateUserName());
vo.setCreateTime(record.getCreateTime());
// 组装检验项
List<QmsIncomingInspectionTaskRecordItem> items = recordItemMap.getOrDefault(record.getId(), List.of());
List<QmsIncomingInspectionTaskRecordItemVO> itemVOs = items.stream().map(item -> {
QmsIncomingInspectionTaskRecordItemVO itemVO = new QmsIncomingInspectionTaskRecordItemVO();
itemVO.setId(item.getId());
itemVO.setRecordId(item.getRecordId());
itemVO.setInspectionStandardItemContentId(item.getInspectionStandardItemContentId());
itemVO.setRemark(item.getRemark());
// 填充检验标准项内容信息
QmsInspectionStandardItemContent content = finalContentMap.get(item.getInspectionStandardItemContentId());
if (content != null) {
itemVO.setName(content.getName());
itemVO.setTestStandard(content.getTestStandard());
itemVO.setJudgmentType(content.getJudgmentType());
}
// 组装检验数据
List<QmsIncomingInspectionTaskRecordItemData> datas = finalItemDataMap.getOrDefault(item.getId(), List.of());
List<QmsIncomingInspectionTaskRecordItemDataVO> dataVOs = datas.stream().map(data -> {
QmsIncomingInspectionTaskRecordItemDataVO dataVO = new QmsIncomingInspectionTaskRecordItemDataVO();
dataVO.setId(data.getId());
dataVO.setTaskId(data.getTaskId());
dataVO.setItemId(data.getItemId());
dataVO.setMeasuredValue(data.getMeasuredValue());
dataVO.setQualified(data.getQualified());
dataVO.setImages(StrUtil.isNotBlank(data.getImages())
? List.of(data.getImages().split(","))
: List.of());
return dataVO;
}).toList();
itemVO.setDatas(dataVOs);
return itemVO;
}).toList();
vo.setItems(itemVOs);
return vo;
}).toList();
}
public QmsIncomingInspectionTaskCheckDetailVO getItemsForCheck(@Valid QmsIncomingInspectionTaskTodoCheckItemsQO request) { public QmsIncomingInspectionTaskCheckDetailVO getItemsForCheck(@Valid QmsIncomingInspectionTaskTodoCheckItemsQO request) {
QmsIncomingInspectionTask task = incomingInspectionTaskService.getById(request.getTaskId()); QmsIncomingInspectionTask task = incomingInspectionTaskService.getById(request.getTaskId());
VUtil.trueThrowBusinessError(Objects.isNull(task)).throwMessage("任务不存在"); VUtil.trueThrowBusinessError(Objects.isNull(task)).throwMessage("任务不存在");
@ -779,4 +899,115 @@ public class IncomingInspectionTaskControllerService {
//TODO //TODO
} }
} }
/**
* 查询来料检验任务检验记录子项列表含样本列表
* @param recordId 检验记录ID
* @return 检验记录子项列表每个子项包含其下的样本数据
*/
public List<QmsIncomingInspectionTaskRecordItemDetailVO> getInspectionRecordItems(Long recordId) {
// 1. 查询该记录下的所有检验项
List<QmsIncomingInspectionTaskRecordItem> items = incomingInspectionTaskRecordItemService.lambdaQuery()
.eq(QmsIncomingInspectionTaskRecordItem::getRecordId, recordId)
.list();
if (CollectionUtil.isEmpty(items)) {
return List.of();
}
// 2. 收集所有检验标准项内容ID查询检验标准项内容获取检测项名称标准等信息
List<Long> contentIds = items.stream()
.map(QmsIncomingInspectionTaskRecordItem::getInspectionStandardItemContentId)
.filter(Objects::nonNull)
.distinct()
.toList();
Map<Long, QmsInspectionStandardItemContent> contentMap = Map.of();
if (!contentIds.isEmpty()) {
contentMap = inspectionStandardItemContentService.lambdaQuery()
.in(QmsInspectionStandardItemContent::getId, contentIds)
.list()
.stream()
.collect(Collectors.toMap(QmsInspectionStandardItemContent::getId, Function.identity()));
}
// 3. 收集所有检验标准项ID查询检验标准项获取检验标准项类型和名称
List<Long> standardItemIds = contentMap.values().stream()
.map(QmsInspectionStandardItemContent::getInspectionStandardItemId)
.filter(Objects::nonNull)
.distinct()
.toList();
Map<Long, QmsInspectionStandardItem> standardItemMap = Map.of();
if (!standardItemIds.isEmpty()) {
standardItemMap = inspectionStandardItemService.lambdaQuery()
.in(QmsInspectionStandardItem::getId, standardItemIds)
.list()
.stream()
.collect(Collectors.toMap(QmsInspectionStandardItem::getId, Function.identity()));
}
// 4. 查询所有检验项下的检验数据样本
List<Long> itemIds = items.stream()
.map(QmsIncomingInspectionTaskRecordItem::getId)
.toList();
Map<Long, List<QmsIncomingInspectionTaskRecordItemData>> itemDataMap = Map.of();
if (!itemIds.isEmpty()) {
itemDataMap = incomingInspectionTaskRecordItemDataService.lambdaQuery()
.in(QmsIncomingInspectionTaskRecordItemData::getItemId, itemIds)
.list()
.stream()
.collect(Collectors.groupingBy(QmsIncomingInspectionTaskRecordItemData::getItemId));
}
// 5. 组装返回VO
Map<Long, QmsInspectionStandardItemContent> finalContentMap = contentMap;
Map<Long, QmsInspectionStandardItem> finalStandardItemMap = standardItemMap;
Map<Long, List<QmsIncomingInspectionTaskRecordItemData>> finalItemDataMap = itemDataMap;
return items.stream().map(item -> {
QmsIncomingInspectionTaskRecordItemDetailVO vo = new QmsIncomingInspectionTaskRecordItemDetailVO();
vo.setId(item.getId());
vo.setRecordId(item.getRecordId());
vo.setInspectionStandardItemContentId(item.getInspectionStandardItemContentId());
vo.setRemark(item.getRemark());
// 填充检验标准项内容信息
QmsInspectionStandardItemContent content = finalContentMap.get(item.getInspectionStandardItemContentId());
if (content != null) {
vo.setTestStandard(content.getTestStandard());
vo.setJudgmentType(content.getJudgmentType());
// 根据检验标准项类型设置检测项名称
QmsInspectionStandardItem standardItem = finalStandardItemMap.get(content.getInspectionStandardItemId());
if (standardItem != null) {
// 检验标准项类型0-标准检测项1-尺寸检测项
if (standardItem.getItemType() != null && standardItem.getItemType() == 0) {
// 标准检测项使用检验标准项的名称
vo.setName(standardItem.getName());
} else {
// 尺寸检测项使用检验内容的名称
vo.setName(content.getName());
}
} else {
// 如果找不到检验标准项默认使用检验内容的名称
vo.setName(content.getName());
}
}
// 组装检验数据样本
List<QmsIncomingInspectionTaskRecordItemData> datas = finalItemDataMap.getOrDefault(item.getId(), List.of());
List<QmsIncomingInspectionTaskRecordItemDataVO> dataVOs = datas.stream().map(data -> {
QmsIncomingInspectionTaskRecordItemDataVO dataVO = new QmsIncomingInspectionTaskRecordItemDataVO();
dataVO.setId(data.getId());
dataVO.setTaskId(data.getTaskId());
dataVO.setItemId(data.getItemId());
dataVO.setMeasuredValue(data.getMeasuredValue());
dataVO.setQualified(data.getQualified());
dataVO.setImages(StrUtil.isNotBlank(data.getImages())
? List.of(data.getImages().split(","))
: List.of());
return dataVO;
}).toList();
vo.setDatas(dataVOs);
return vo;
}).toList();
}
} }

View File

@ -11,6 +11,7 @@ import com.nflg.wms.common.pojo.ApiResult;
import com.nflg.wms.common.pojo.PageData; import com.nflg.wms.common.pojo.PageData;
import com.nflg.wms.common.pojo.dto.BomPageResultDTO; import com.nflg.wms.common.pojo.dto.BomPageResultDTO;
import com.nflg.wms.common.pojo.dto.MaterialMainDTO; import com.nflg.wms.common.pojo.dto.MaterialMainDTO;
import com.nflg.wms.common.pojo.dto.MaterialMainListByDateDTO;
import com.nflg.wms.common.pojo.dto.QmsQcMaterialImportDTO; import com.nflg.wms.common.pojo.dto.QmsQcMaterialImportDTO;
import com.nflg.wms.common.pojo.qo.BomMaterialListQO; import com.nflg.wms.common.pojo.qo.BomMaterialListQO;
import com.nflg.wms.common.pojo.qo.QmsQcMaterialAddQO; import com.nflg.wms.common.pojo.qo.QmsQcMaterialAddQO;
@ -32,6 +33,7 @@ import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid; import jakarta.validation.Valid;
import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotEmpty;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
@ -43,6 +45,7 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -52,6 +55,7 @@ import java.util.stream.Collectors;
/** /**
* 质检物料业务逻辑 * 质检物料业务逻辑
*/ */
@Slf4j
@Component @Component
public class QmsQcMaterialControllerService { public class QmsQcMaterialControllerService {
@ -472,4 +476,104 @@ public class QmsQcMaterialControllerService {
qcMaterialService.updateBatchById(list); qcMaterialService.updateBatchById(list);
} }
} }
/**
* 按日期范围从主物料系统同步物料信息
* @param startDate 开始日期
* @param endDate 结束日期
*/
@Transactional
public void syncFromMainByDate(LocalDate startDate, LocalDate endDate) {
// 将日期转换为日期时间字符串格式以便调用外部API
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String startDateTime = startDate.atStartOfDay().format(formatter);
String endDateTime = endDate.atTime(23, 59, 59).format(formatter);
// 从主物料系统查询指定日期范围的物料列表
List<MaterialMainListByDateDTO> materials = bomMaterialService.getListByDate(startDateTime, endDateTime);
if (CollectionUtil.isEmpty(materials)) {
return;
}
Long userId = UserUtil.getUserId();
String operator = UserUtil.getUserName();
LocalDateTime now = LocalDateTime.now();
// 过滤掉物料类别编码为空的记录
List<MaterialMainListByDateDTO> validMaterials = materials.stream()
.filter(dto -> {
if (StrUtil.isBlank(dto.getMaterialCategoryCode())) {
log.warn("物料类别编码为空:{}", dto.getMaterialNo());
return false;
}
return true;
})
.collect(java.util.stream.Collectors.toList());
if (CollectionUtil.isEmpty(validMaterials)) {
return;
}
// 批量查询已存在的物料构建 materialNo -> QmsQcMaterial 映射
List<String> materialNos = validMaterials.stream()
.map(MaterialMainListByDateDTO::getMaterialNo)
.collect(java.util.stream.Collectors.toList());
Map<String, QmsQcMaterial> existMaterialMap = qcMaterialService.lambdaQuery()
.in(QmsQcMaterial::getMaterialNo, materialNos)
.list()
.stream()
.collect(java.util.stream.Collectors.toMap(QmsQcMaterial::getMaterialNo, m -> m));
List<QmsQcMaterial> insertList = new java.util.ArrayList<>();
List<QmsQcMaterial> updateList = new java.util.ArrayList<>();
for (MaterialMainListByDateDTO materialDTO : validMaterials) {
QmsQcMaterial existMaterial = existMaterialMap.get(materialDTO.getMaterialNo());
if (existMaterial == null) {
// 待新增
QmsQcMaterial newMaterial = new QmsQcMaterial()
.setMaterialNo(materialDTO.getMaterialNo())
.setMaterialName(materialDTO.getMaterialName())
.setMaterialDesc(materialDTO.getMaterialDesc())
.setMaterialSpecifications(materialDTO.getMaterialSpecifications())
.setDrawingNo(materialDTO.getDrawingNo())
.setDrawingNoVer(materialDTO.getDrawingNoVersion())
.setMaterialTexture(materialDTO.getMaterialTexture())
.setMaterialCategoryCode(materialDTO.getMaterialCategoryCode())
.setMaterialCategoryCodePathName(materialDTO.getMaterialCategoryFullName())
.setIsStandardMaintained(false)
.setMaterialDescIsUpgrade(false)
.setCreatedType(1) // 1=系统同步
.setCreateBy(userId)
.setCreateByName(operator)
.setCreateTime(now);
insertList.add(newMaterial);
} else {
// 待更新
boolean descChanged = !StrUtil.equals(existMaterial.getMaterialDesc(), materialDTO.getMaterialDesc());
existMaterial.setMaterialName(materialDTO.getMaterialName())
.setMaterialDesc(materialDTO.getMaterialDesc())
.setMaterialDescIsUpgrade(descChanged)
.setMaterialSpecifications(materialDTO.getMaterialSpecifications())
.setDrawingNo(materialDTO.getDrawingNo())
.setDrawingNoVer(materialDTO.getDrawingNoVersion())
.setMaterialCategoryCode(materialDTO.getMaterialCategoryCode())
.setMaterialCategoryCodePathName(materialDTO.getMaterialCategoryFullName())
.setUpdateBy(userId)
.setUpdateByName(operator)
.setUpdateTime(now);
updateList.add(existMaterial);
}
}
// 批量新增
if (CollectionUtil.isNotEmpty(insertList)) {
qcMaterialService.saveBatch(insertList);
}
// 批量更新
if (CollectionUtil.isNotEmpty(updateList)) {
qcMaterialService.updateBatchById(updateList);
}
}
} }

View File

@ -0,0 +1,99 @@
package com.nflg.qms.admin;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONConfig;
import cn.hutool.json.JSONUtil;
import com.nflg.wms.common.pojo.ApiResult;
import com.nflg.wms.common.pojo.qo.MaterialListByDateQO;
import org.junit.jupiter.api.Test;
import java.time.LocalDate;
import java.util.HashMap;
import java.util.Map;
/**
* 物料同步功能测试
*/
public class MaterialSyncTest {
// 测试环境地址
private static final String BASE_URL = "http://localhost:8105";
// 需要根据实际情况修改token
private static final String TOKEN = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJsb2dpblR5cGUiOiJsb2dpbiIsImxvZ2luSWQiOjEsInJuU3RyIjoiZFN6UmVWbnEyY01HRVI2aGU4aDZMWGZzNjVhaFpMdk0iLCJuYW1lIjoi6LaF57qn566h55CG5ZGYIiwiY29kZSI6ImFkbWluIiwicm9sZXMiOlsiU3VwZXJBZG1pbiJdLCJ0eXBlIjoxfQ.4sm4ASfsEBIpiDXVuz4CJD3fMcPVgeb1Wvc8NknUMZg";
/**
* 测试按日期范围同步物料
*/
@Test
public void testSyncFromMainByDate() {
// 构建请求参数
MaterialListByDateQO request = new MaterialListByDateQO();
LocalDate startDate = LocalDate.of(2025, 1, 1);
LocalDate endDate = LocalDate.of(2025, 12, 31);
for (LocalDate date = startDate; !date.isAfter(endDate); date = date.plusMonths(1)){
request.setStartDate(date);
request.setEndDate(date.plusMonths(1).minusDays(1));
SyncFromMainByDate(request);
}
}
private void SyncFromMainByDate(MaterialListByDateQO request){
String url = BASE_URL + "/qcMaterial/syncFromMainByDate";
// 使用Hutool的JSONConfig配置日期格式
JSONConfig jsonConfig = JSONConfig.create()
.setDateFormat("yyyy-MM-dd");
String requestBody = JSONUtil.toJsonStr(request, jsonConfig);
System.out.println("请求URL: " + url);
System.out.println("请求参数: " + requestBody);
// 发送请求
HttpResponse response = HttpRequest.post(url)
.header("authorization", TOKEN)
.header("Content-Type", "application/json")
.body(requestBody)
.execute();
String responseBody = response.body();
System.out.println("响应状态码: " + response.getStatus());
System.out.println("响应内容: " + responseBody);
// 解析响应
ApiResult<Void> result = JSONUtil.toBean(responseBody, ApiResult.class);
assert result.getCode() == 200 : "同步失败: " + result.getMessage();
System.out.println("✅ 物料同步成功");
}
/**
* 测试直接调用外部物料系统接口
*/
@Test
public void testExternalMaterialApi() {
String url = "http://192.168.0.194:89/material/rest/main/listByDate";
// 构建请求参数
Map<String, String> params = new HashMap<>();
params.put("startDateTime", "2025-01-01 00:00:00");
params.put("endDateTime", "2025-01-11 23:59:59");
String requestBody = JSONUtil.toJsonStr(params);
System.out.println("请求外部物料系统URL: " + url);
System.out.println("请求参数: " + requestBody);
// 发送请求需要先获取token
// 这里只是示例实际需要先调用登录接口获取token
HttpResponse response = HttpRequest.post(url)
.header("Content-Type", "application/json")
.body(requestBody)
.execute();
String responseBody = response.body();
System.out.println("响应状态码: " + response.getStatus());
System.out.println("响应内容: " + responseBody);
}
}

View File

@ -58,6 +58,26 @@ public class MaterialMainDTO {
*/ */
private String drawingNoVer; private String drawingNoVer;
/**
* 申请人编码
*/
private String applyUserCode;
/**
* 申请部门
*/
private String applyDeptName;
/**
* 材质
*/
private String materialTexture;
/**
* 推荐度0-5
*/
private Integer recommend;
public String getDrawingNoVer() { public String getDrawingNoVer() {
return StrUtil.isBlank(drawingNoVer) ? "" : drawingNoVer; return StrUtil.isBlank(drawingNoVer) ? "" : drawingNoVer;
} }

View File

@ -0,0 +1,85 @@
package com.nflg.wms.common.pojo.dto;
import cn.hutool.core.util.StrUtil;
import lombok.Data;
/**
* 主物料系统按日期查询返回的物料信息
*/
@Data
public class MaterialMainListByDateDTO {
/**
* 物料编码
*/
private String materialNo;
/**
* 物料名称
*/
private String materialName;
/**
* 物料描述
*/
private String materialDesc;
/**
* 图号
*/
private String drawingNo;
/**
* 图号版本号
*/
private String drawingNoVersion;
/**
* 物料状态 1:正常 2:禁止采购 3:售后专用 4:冻结 5:完全弃用
*/
private Integer materialState;
/**
* 物料分类编码
*/
private String materialCategoryCode;
/**
* 物料分类编码名称
*/
private String materialCategoryName;
/**
* 物料分类编码全路径名称
*/
private String materialCategoryFullName;
/**
* 申请人编码
*/
private String applyUserCode;
/**
* 申请部门
*/
private String applyDeptName;
/**
* 物料规格
*/
private String materialSpecifications;
/**
* 材质
*/
private String materialTexture;
/**
* 推荐度0-5
*/
private Integer recommend;
public String getDrawingNoVersion() {
return StrUtil.isBlank(drawingNoVersion) ? "" : drawingNoVersion;
}
}

View File

@ -0,0 +1,32 @@
package com.nflg.wms.common.pojo.qo;
import com.fasterxml.jackson.annotation.JsonFormat;
import jakarta.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDate;
/**
* 按日期范围查询物料请求参数
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class MaterialListByDateQO {
/**
* 开始日期
*/
@NotNull(message = "开始日期不能为空")
@JsonFormat(pattern = "yyyy-MM-dd")
private LocalDate startDate;
/**
* 结束日期
*/
@NotNull(message = "结束日期不能为空")
@JsonFormat(pattern = "yyyy-MM-dd")
private LocalDate endDate;
}

View File

@ -0,0 +1,40 @@
package com.nflg.wms.common.pojo.vo;
import lombok.Data;
import java.math.BigDecimal;
import java.util.List;
@Data
public class QmsIncomingInspectionTaskRecordItemDataVO {
/**
* 记录项数据ID
*/
private Long id;
/**
* 来料检测任务ID
*/
private Long taskId;
/**
* 来料检测任务记录项ID
*/
private Long itemId;
/**
* 测量值
*/
private BigDecimal measuredValue;
/**
* 是否合格
*/
private Boolean qualified;
/**
* 图片列表
*/
private List<String> images;
}

View File

@ -0,0 +1,53 @@
package com.nflg.wms.common.pojo.vo;
import lombok.Data;
import java.util.List;
/**
* 来料检验任务检验记录子项详情VO
* 包含检验记录子项及其下的样本列表
*/
@Data
public class QmsIncomingInspectionTaskRecordItemDetailVO {
/**
* 记录项ID
*/
private Long id;
/**
* 来料检测任务记录ID
*/
private Long recordId;
/**
* 检验标准项内容ID
*/
private Long inspectionStandardItemContentId;
/**
* 检测项名称
*/
private String name;
/**
* 检测标准
*/
private String testStandard;
/**
* 判定类型0直接判定1测量值
*/
private Integer judgmentType;
/**
* 备注
*/
private String remark;
/**
* 检测数据列表样本列表
*/
private List<QmsIncomingInspectionTaskRecordItemDataVO> datas;
}

View File

@ -0,0 +1,49 @@
package com.nflg.wms.common.pojo.vo;
import lombok.Data;
import java.util.List;
@Data
public class QmsIncomingInspectionTaskRecordItemVO {
/**
* 记录项ID
*/
private Long id;
/**
* 来料检测任务记录ID
*/
private Long recordId;
/**
* 检验标准项内容ID
*/
private Long inspectionStandardItemContentId;
/**
* 检测项名称
*/
private String name;
/**
* 检测标准
*/
private String testStandard;
/**
* 判定类型0直接判定1测量值
*/
private Integer judgmentType;
/**
* 备注
*/
private String remark;
/**
* 检测数据列表
*/
private List<QmsIncomingInspectionTaskRecordItemDataVO> datas;
}

View File

@ -0,0 +1,65 @@
package com.nflg.wms.common.pojo.vo;
import lombok.Data;
import java.time.LocalDateTime;
import java.util.List;
@Data
public class QmsIncomingInspectionTaskRecordVO {
/**
* 检验记录ID
*/
private Long id;
/**
* 来料检测任务ID
*/
private Long taskId;
/**
* 物料唯一码
*/
private String materialUniqueNo;
/**
* 是否合格
*/
private Boolean qualified;
/**
* 样本数量
*/
private Integer inspectionQty;
/**
* 合格数量
*/
private Integer qualifiedQty;
/**
* 不合格数量
*/
private Integer unqualifiedQty;
/**
* 创建人ID
*/
private Long createUserId;
/**
* 创建人姓名
*/
private String createUserName;
/**
* 创建时间
*/
private LocalDateTime createTime;
/**
* 检验记录项列表
*/
private List<QmsIncomingInspectionTaskRecordItemVO> items;
}

View File

@ -0,0 +1,140 @@
package com.nflg.wms.scheduled.processor;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.nflg.wms.common.pojo.dto.MaterialMainListByDateDTO;
import com.nflg.wms.common.util.UserUtil;
import com.nflg.wms.repository.entity.QmsQcMaterial;
import com.nflg.wms.repository.service.IQmsQcMaterialService;
import com.nflg.wms.starter.service.BomMaterialService;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Component;
import tech.powerjob.worker.core.processor.ProcessResult;
import tech.powerjob.worker.core.processor.TaskContext;
import tech.powerjob.worker.core.processor.sdk.BasicProcessor;
import tech.powerjob.worker.log.OmsLogger;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Map;
/**
* 从主物料同步物料到QMS
*/
@Component(value = "QCMaterialSyncProcessor")
public class QCMaterialSyncProcessor implements BasicProcessor {
@Resource
private BomMaterialService bomMaterialService;
@Resource
private IQmsQcMaterialService qcMaterialService;
@Override
public ProcessResult process(TaskContext context) throws Exception {
OmsLogger log = context.getOmsLogger();
try {
log.info("开始");
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String startDateTime = LocalDate.now().minusDays(1).atStartOfDay().format(formatter);
String endDateTime = LocalDate.now().minusDays(1).atTime(23, 59, 59).format(formatter);
log.info("开始同步物料,范围开始时间:{},结束时间:{}", startDateTime, endDateTime);
// 从主物料系统查询指定日期范围的物料列表
List<MaterialMainListByDateDTO> materials = bomMaterialService.getListByDate(startDateTime, endDateTime);
if (CollectionUtil.isEmpty(materials)) {
log.info("没有需要同步的物料");
} else {
Long userId = UserUtil.getUserId();
String operator = UserUtil.getUserName();
LocalDateTime now = LocalDateTime.now();
// 过滤掉物料类别编码为空的记录
List<MaterialMainListByDateDTO> validMaterials = materials.stream()
.filter(dto -> {
if (StrUtil.isBlank(dto.getMaterialCategoryCode())) {
log.warn("物料类别编码为空:{}", dto.getMaterialNo());
return false;
}
return true;
})
.collect(java.util.stream.Collectors.toList());
if (CollectionUtil.isEmpty(validMaterials)) {
log.info("没有需要同步的物料");
} else {
// 批量查询已存在的物料构建 materialNo -> QmsQcMaterial 映射
List<String> materialNos = validMaterials.stream()
.map(MaterialMainListByDateDTO::getMaterialNo)
.collect(java.util.stream.Collectors.toList());
Map<String, QmsQcMaterial> existMaterialMap = qcMaterialService.lambdaQuery()
.in(QmsQcMaterial::getMaterialNo, materialNos)
.list()
.stream()
.collect(java.util.stream.Collectors.toMap(QmsQcMaterial::getMaterialNo, m -> m));
List<QmsQcMaterial> insertList = new java.util.ArrayList<>();
List<QmsQcMaterial> updateList = new java.util.ArrayList<>();
for (MaterialMainListByDateDTO materialDTO : validMaterials) {
QmsQcMaterial existMaterial = existMaterialMap.get(materialDTO.getMaterialNo());
if (existMaterial == null) {
// 待新增
QmsQcMaterial newMaterial = new QmsQcMaterial()
.setMaterialNo(materialDTO.getMaterialNo())
.setMaterialName(materialDTO.getMaterialName())
.setMaterialDesc(materialDTO.getMaterialDesc())
.setMaterialSpecifications(materialDTO.getMaterialSpecifications())
.setDrawingNo(materialDTO.getDrawingNo())
.setDrawingNoVer(materialDTO.getDrawingNoVersion())
.setMaterialTexture(materialDTO.getMaterialTexture())
.setMaterialCategoryCode(materialDTO.getMaterialCategoryCode())
.setMaterialCategoryCodePathName(materialDTO.getMaterialCategoryFullName())
.setIsStandardMaintained(false)
.setMaterialDescIsUpgrade(false)
.setCreatedType(1) // 1=系统同步
.setCreateBy(userId)
.setCreateByName(operator)
.setCreateTime(now);
insertList.add(newMaterial);
} else {
// 待更新
boolean descChanged = !StrUtil.equals(existMaterial.getMaterialDesc(), materialDTO.getMaterialDesc());
existMaterial.setMaterialName(materialDTO.getMaterialName())
.setMaterialDesc(materialDTO.getMaterialDesc())
.setMaterialDescIsUpgrade(descChanged)
.setMaterialSpecifications(materialDTO.getMaterialSpecifications())
.setDrawingNo(materialDTO.getDrawingNo())
.setDrawingNoVer(materialDTO.getDrawingNoVersion())
.setMaterialCategoryCode(materialDTO.getMaterialCategoryCode())
.setMaterialCategoryCodePathName(materialDTO.getMaterialCategoryFullName())
.setUpdateBy(userId)
.setUpdateByName(operator)
.setUpdateTime(now);
updateList.add(existMaterial);
}
}
// 批量新增
if (CollectionUtil.isNotEmpty(insertList)) {
log.info("开始新增物料,数量:{}", insertList.size());
qcMaterialService.saveBatch(insertList);
}
// 批量更新
if (CollectionUtil.isNotEmpty(updateList)) {
log.info("开始更新物料,数量:{}", updateList.size());
qcMaterialService.updateBatchById(updateList);
}
}
}
return new ProcessResult(true);
} catch (Exception ex) {
return new ProcessResult(false, "同步物料失败");
}
}
}

View File

@ -13,7 +13,7 @@ public class RestTemplateConfig {
@Lazy @Lazy
public RestTemplate restTemplate() { public RestTemplate restTemplate() {
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory(); SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
factory.setConnectTimeout(3_000); factory.setConnectTimeout(5_000);
factory.setReadTimeout(10_000); factory.setReadTimeout(10_000);
return new RestTemplate(factory); return new RestTemplate(factory);
} }

View File

@ -54,6 +54,9 @@ public class BomMaterialService {
@Value("${bom.material.queryMaterial.url}") @Value("${bom.material.queryMaterial.url}")
private String materialQueryMaterialUrl; private String materialQueryMaterialUrl;
@Value("${bom.material.listByDate.url}")
private String materialListByDateUrl;
@Resource @Resource
private RestTemplate restTemplate; private RestTemplate restTemplate;
@ -159,6 +162,7 @@ public class BomMaterialService {
HttpHeaders headers = new HttpHeaders(); HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON); headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<BomLoginQO> requestEntity = new HttpEntity<>(new BomLoginQO(userName, password), headers); HttpEntity<BomLoginQO> requestEntity = new HttpEntity<>(new BomLoginQO(userName, password), headers);
log.info("登录主物料系统{}userName{}password{}", baseUrl + loginUrl, userName, password);
ResponseEntity<BomResultDTO<BomLoginResultDTO>> response = restTemplate.exchange( ResponseEntity<BomResultDTO<BomLoginResultDTO>> response = restTemplate.exchange(
baseUrl + loginUrl, baseUrl + loginUrl,
HttpMethod.POST, HttpMethod.POST,
@ -217,4 +221,41 @@ public class BomMaterialService {
log.info("查询主物料系统返回数据:" + JSONUtil.toJsonStr(resultDTO)); log.info("查询主物料系统返回数据:" + JSONUtil.toJsonStr(resultDTO));
return resultDTO.getData(); return resultDTO.getData();
} }
/**
* 按日期范围查询物料列表
* @param startDateTime 开始时间 格式yyyy-MM-dd HH:mm:ss
* @param endDateTime 结束时间 格式yyyy-MM-dd HH:mm:ss
* @return 物料列表
*/
public List<MaterialMainListByDateDTO> getListByDate(String startDateTime, String endDateTime) {
log.info("按日期查询主物料系统,开始时间:{}, 结束时间:{}", startDateTime, endDateTime);
// 构建请求参数
Map<String, String> params = new HashMap<>();
params.put("startDateTime", startDateTime);
params.put("endDateTime", endDateTime);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.add("authorization", getToken());
HttpEntity<Map<String, String>> requestEntity = new HttpEntity<>(params, headers);
ResponseEntity<BomResultDTO<List<MaterialMainListByDateDTO>>> response = restTemplate.exchange(
baseUrl + materialListByDateUrl,
HttpMethod.POST,
requestEntity,
new ParameterizedTypeReference<>() {
}
);
log.info("按日期查询主物料系统返回状态码:" + response.getStatusCode().value());
VUtil.trueThrowBusinessError(!response.getStatusCode().is2xxSuccessful())
.throwMessage("查询主物料系统失败");
BomResultDTO<List<MaterialMainListByDateDTO>> resultDTO = response.getBody();
log.info("按日期查询主物料系统返回数据:" + (Objects.nonNull(resultDTO.getData()) && resultDTO.getData().size() > 1000
? "数据超过1000条不打印"
: JSONUtil.toJsonStr(resultDTO)));
return Optional.ofNullable(resultDTO.getData()).orElse(Collections.emptyList());
}
} }