1263 lines
58 KiB
Java
1263 lines
58 KiB
Java
package com.klp.service.impl;
|
||
|
||
import cn.hutool.core.bean.BeanUtil;
|
||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||
import com.klp.common.core.page.TableDataInfo;
|
||
import com.klp.common.core.domain.PageQuery;
|
||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||
import com.klp.common.helper.LoginHelper;
|
||
import com.klp.common.utils.StringUtils;
|
||
import lombok.RequiredArgsConstructor;
|
||
import org.springframework.stereotype.Service;
|
||
import org.springframework.transaction.annotation.Transactional;
|
||
import com.klp.domain.bo.WmsMaterialCoilBo;
|
||
import com.klp.domain.bo.WmsGenerateRecordBo;
|
||
import com.klp.domain.vo.WmsMaterialCoilVo;
|
||
import com.klp.domain.vo.WmsGenerateRecordVo;
|
||
import com.klp.domain.vo.WmsWarehouseVo;
|
||
import com.klp.domain.vo.WmsRawMaterialVo;
|
||
import com.klp.domain.vo.WmsBomItemVo;
|
||
import com.klp.domain.bo.WmsBomItemBo;
|
||
import com.klp.domain.WmsMaterialCoil;
|
||
import com.klp.domain.bo.WmsStockBo;
|
||
import com.klp.domain.vo.WmsStockVo;
|
||
import com.klp.mapper.WmsMaterialCoilMapper;
|
||
import com.klp.mapper.WmsStockMapper;
|
||
import com.klp.service.IWmsMaterialCoilService;
|
||
import com.klp.service.IWmsStockService;
|
||
import com.klp.service.IWmsGenerateRecordService;
|
||
import com.klp.service.IWmsWarehouseService;
|
||
import com.klp.service.IWmsActualWarehouseService;
|
||
import com.klp.service.IWmsRawMaterialService;
|
||
import com.klp.service.IWmsBomItemService;
|
||
import com.klp.domain.vo.WmsActualWarehouseVo;
|
||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||
|
||
import java.util.List;
|
||
import java.util.Collection;
|
||
import java.util.ArrayList;
|
||
import java.util.Map;
|
||
import java.util.HashMap;
|
||
import java.util.stream.Collectors;
|
||
import java.util.HashSet;
|
||
import java.util.Set;
|
||
import java.math.BigDecimal;
|
||
|
||
/**
|
||
* 钢卷物料表Service业务层处理
|
||
*
|
||
* @author Joshi
|
||
* @date 2025-07-18
|
||
*/
|
||
@RequiredArgsConstructor
|
||
@Service
|
||
public class WmsMaterialCoilServiceImpl implements IWmsMaterialCoilService {
|
||
|
||
private final WmsMaterialCoilMapper baseMapper;
|
||
private final IWmsStockService stockService;
|
||
private final IWmsGenerateRecordService generateRecordService;
|
||
private final IWmsWarehouseService warehouseService;
|
||
private final IWmsActualWarehouseService actualWarehouseService;
|
||
private final IWmsRawMaterialService rawMaterialService;
|
||
private final IWmsBomItemService bomItemService;
|
||
|
||
/**
|
||
* 查询钢卷物料表
|
||
*/
|
||
@Override
|
||
public WmsMaterialCoilVo queryById(Long coilId) {
|
||
WmsMaterialCoilVo vo = baseMapper.selectVoById(coilId);
|
||
if (vo == null) {
|
||
return null;
|
||
}
|
||
|
||
// 查询关联对象
|
||
fillRelatedObjects(vo);
|
||
|
||
return vo;
|
||
}
|
||
|
||
/**
|
||
* 填充关联对象信息
|
||
*/
|
||
private void fillRelatedObjects(WmsMaterialCoilVo vo) {
|
||
// 查询所在库区信息
|
||
if (vo.getWarehouseId() != null) {
|
||
WmsWarehouseVo warehouse = warehouseService.queryById(vo.getWarehouseId());
|
||
vo.setWarehouse(warehouse);
|
||
}
|
||
|
||
// 查询下一库区信息
|
||
if (vo.getNextWarehouseId() != null) {
|
||
WmsWarehouseVo nextWarehouse = warehouseService.queryById(vo.getNextWarehouseId());
|
||
vo.setNextWarehouse(nextWarehouse);
|
||
}
|
||
|
||
// 查询实际库区信息
|
||
if (vo.getActualWarehouseId() != null) {
|
||
WmsActualWarehouseVo actualWarehouse = actualWarehouseService.queryById(vo.getActualWarehouseId());
|
||
if (actualWarehouse != null) {
|
||
vo.setActualWarehouseName(actualWarehouse.getActualWarehouseName());
|
||
}
|
||
}
|
||
|
||
// 查询二维码信息
|
||
if (vo.getQrcodeRecordId() != null) {
|
||
WmsGenerateRecordVo qrcodeRecord = generateRecordService.queryById(vo.getQrcodeRecordId());
|
||
vo.setQrcodeRecord(qrcodeRecord);
|
||
}
|
||
|
||
// 查询原材料信息(当itemType为raw_material时)
|
||
if ("raw_material".equals(vo.getItemType()) && vo.getItemId() != null) {
|
||
WmsRawMaterialVo rawMaterial = rawMaterialService.queryById(vo.getItemId());
|
||
vo.setRawMaterial(rawMaterial);
|
||
|
||
// 查询原材料对应的BOM信息(通过bomId查询BomItem列表)
|
||
if (rawMaterial != null && rawMaterial.getBomId() != null) {
|
||
WmsBomItemBo bomItemBo = new WmsBomItemBo();
|
||
bomItemBo.setBomId(rawMaterial.getBomId());
|
||
List<WmsBomItemVo> bomItemList = bomItemService.queryList(bomItemBo);
|
||
vo.setBomItemList(bomItemList);
|
||
}
|
||
}
|
||
|
||
// 查询产品信息(当itemType为product时)
|
||
if ("product".equals(vo.getItemType()) && vo.getItemId() != null) {
|
||
// 产品和原材料的查询逻辑相同,都通过itemId查询
|
||
WmsRawMaterialVo rawMaterial = rawMaterialService.queryById(vo.getItemId());
|
||
|
||
// 查询原材料对应的BOM信息(通过bomId查询BomItem列表)
|
||
if (rawMaterial != null && rawMaterial.getBomId() != null) {
|
||
WmsBomItemBo bomItemBo = new WmsBomItemBo();
|
||
bomItemBo.setBomId(rawMaterial.getBomId());
|
||
List<WmsBomItemVo> bomItemList = bomItemService.queryList(bomItemBo);
|
||
vo.setBomItemList(bomItemList);
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 查询钢卷物料表列表
|
||
*/
|
||
@Override
|
||
public TableDataInfo<WmsMaterialCoilVo> queryPageList(WmsMaterialCoilBo bo, PageQuery pageQuery) {
|
||
QueryWrapper<WmsMaterialCoil> qw = buildQueryWrapperPlus(bo);
|
||
Page<WmsMaterialCoilVo> result = baseMapper.selectVoPagePlus(pageQuery.build(), qw);
|
||
return TableDataInfo.build(result);
|
||
}
|
||
|
||
private QueryWrapper<WmsMaterialCoil> buildQueryWrapperPlus(WmsMaterialCoilBo bo) {
|
||
QueryWrapper<WmsMaterialCoil> qw = Wrappers.query();
|
||
qw.like(StringUtils.isNotBlank(bo.getEnterCoilNo()), "mc.enter_coil_no", bo.getEnterCoilNo());
|
||
qw.like(StringUtils.isNotBlank(bo.getCurrentCoilNo()), "mc.current_coil_no", bo.getCurrentCoilNo());
|
||
qw.like(StringUtils.isNotBlank(bo.getSupplierCoilNo()), "mc.supplier_coil_no", bo.getSupplierCoilNo());
|
||
qw.eq(bo.getDataType() != null, "mc.data_type", bo.getDataType());
|
||
qw.eq(bo.getMaterialType() != null, "mc.material_type", bo.getMaterialType());
|
||
qw.eq(bo.getWarehouseId() != null, "mc.warehouse_id", bo.getWarehouseId());
|
||
qw.eq(bo.getHasMergeSplit() != null, "mc.has_merge_split", bo.getHasMergeSplit());
|
||
qw.eq(bo.getStatus() != null, "mc.status", bo.getStatus());
|
||
qw.eq(bo.getActualWarehouseId() != null, "mc.actual_warehouse_id", bo.getActualWarehouseId());
|
||
qw.eq(StringUtils.isNotBlank(bo.getItemType()), "mc.item_type", bo.getItemType());
|
||
// 修改itemId筛选逻辑,支持逗号分隔的多个ID查询
|
||
if (StringUtils.isNotBlank(bo.getItemIds())) {
|
||
String[] itemIdArray = bo.getItemIds().split(",");
|
||
List<Long> itemIdList = new ArrayList<>();
|
||
for (String itemIdStr : itemIdArray) {
|
||
if (StringUtils.isNotBlank(itemIdStr)) {
|
||
try {
|
||
itemIdList.add(Long.parseLong(itemIdStr.trim()));
|
||
} catch (NumberFormatException e) {
|
||
// 忽略无效的ID格式
|
||
}
|
||
}
|
||
}
|
||
if (!itemIdList.isEmpty()) {
|
||
qw.in("mc.item_id", itemIdList);
|
||
}
|
||
} else if (bo.getItemId() != null) {
|
||
// 兼容原来的itemId单值查询
|
||
qw.eq("mc.item_id", bo.getItemId());
|
||
}
|
||
//逻辑删除
|
||
qw.eq("mc.del_flag", 0);
|
||
//把team字段作为筛选条件
|
||
qw.eq(StringUtils.isNotBlank(bo.getTeam()), "mc.team", bo.getTeam());
|
||
//根据开始时间和结束时间筛选修改时间
|
||
qw.ge(bo.getStartTime() != null, "mc.update_time", bo.getStartTime());
|
||
qw.le(bo.getEndTime() != null, "mc.update_time", bo.getEndTime());
|
||
return qw;
|
||
}
|
||
|
||
|
||
/**
|
||
* 查询钢卷物料表列表
|
||
*/
|
||
@Override
|
||
public List<WmsMaterialCoilVo> queryList(WmsMaterialCoilBo bo) {
|
||
QueryWrapper<WmsMaterialCoil> lqw = buildQueryWrapperPlus(bo);
|
||
return baseMapper.selectVoListWithDynamicJoin(lqw);
|
||
}
|
||
|
||
/**
|
||
* 新增钢卷物料表
|
||
*/
|
||
@Override
|
||
@Transactional(rollbackFor = Exception.class)
|
||
public Boolean insertByBo(WmsMaterialCoilBo bo) {
|
||
// 1. 生成二维码
|
||
Long qrcodeRecordId = generateQrcodeForInsert(bo);
|
||
bo.setQrcodeRecordId(qrcodeRecordId);
|
||
|
||
// 2. 查找或创建stock
|
||
findOrCreateStock(bo);
|
||
|
||
|
||
// 3. 插入钢卷数据
|
||
WmsMaterialCoil add = BeanUtil.toBean(bo, WmsMaterialCoil.class);
|
||
add.setDataType(1); // 新增的钢卷默认为当前数据
|
||
validEntityBeforeSave(add);
|
||
boolean flag = baseMapper.insert(add) > 0;
|
||
if (flag) {
|
||
bo.setCoilId(add.getCoilId());
|
||
// 4. 更新二维码内容中的coilId
|
||
updateQrcodeCoilId(qrcodeRecordId, add.getCoilId());
|
||
}
|
||
return flag;
|
||
}
|
||
|
||
/**
|
||
* 生成二维码(新增)
|
||
*/
|
||
private Long generateQrcodeForInsert(WmsMaterialCoilBo bo) {
|
||
try {
|
||
Map<String, Object> contentMap = new HashMap<>();
|
||
String currentCoilNo = bo.getCurrentCoilNo() != null ? bo.getCurrentCoilNo() : bo.getEnterCoilNo();
|
||
|
||
contentMap.put("enter_coil_no", bo.getEnterCoilNo()); // 入场钢卷号(唯一不变)
|
||
contentMap.put("current_coil_no", currentCoilNo); // 当前钢卷号(可变)
|
||
contentMap.put("coil_id", "null"); // 初始钢卷ID(新增时暂时为null,插入后更新)
|
||
contentMap.put("current_coil_id", "null"); // 当前有效的钢卷ID(新增时暂时为null,插入后更新)
|
||
|
||
// 创建steps数组
|
||
List<Map<String, Object>> steps = new ArrayList<>();
|
||
Map<String, Object> step1 = new HashMap<>();
|
||
step1.put("step", 1);
|
||
step1.put("action", "新增");
|
||
step1.put("current_coil_no", currentCoilNo);
|
||
|
||
// 判断是合卷还是分卷
|
||
if (bo.getHasMergeSplit() != null && bo.getHasMergeSplit() == 2) {
|
||
// 合卷:父编号字符串用逗号分隔
|
||
step1.put("operation", "合卷");
|
||
step1.put("parent_coil_nos", bo.getParentCoilNos());
|
||
} else if (bo.getHasMergeSplit() != null && bo.getHasMergeSplit() == 1) {
|
||
// 分卷:多个当前钢卷号用逗号分隔
|
||
step1.put("operation", "分卷");
|
||
step1.put("current_coil_nos", currentCoilNo);
|
||
} else {
|
||
// 默认:当前钢卷号
|
||
step1.put("operation", "新增");
|
||
}
|
||
|
||
steps.add(step1);
|
||
contentMap.put("steps", steps);
|
||
|
||
ObjectMapper objectMapper = new ObjectMapper();
|
||
String contentJson = objectMapper.writeValueAsString(contentMap);
|
||
|
||
WmsGenerateRecordBo recordBo = new WmsGenerateRecordBo();
|
||
recordBo.setContent(contentJson);
|
||
recordBo.setSerialNumber(bo.getEnterCoilNo()); // 使用入场钢卷号作为编号
|
||
recordBo.setQrcodeType(0L);
|
||
recordBo.setIsEnabled(0L);
|
||
recordBo.setSize(200L);
|
||
recordBo.setStatus(1); // 1=当前有效码
|
||
|
||
WmsGenerateRecordVo record = generateRecordService.insertByBo(recordBo);
|
||
return record.getRecordId();
|
||
} catch (Exception e) {
|
||
throw new RuntimeException("生成二维码失败: " + e.getMessage());
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 查找或创建stock
|
||
*/
|
||
private void findOrCreateStock(WmsMaterialCoilBo bo) {
|
||
if (bo.getItemType() == null || bo.getItemId() == null) {
|
||
throw new RuntimeException("物品类型和物品ID不能为空");
|
||
}
|
||
|
||
// 查询是否存在相同的stock(匹配itemType和itemId)
|
||
WmsStockBo stockBo = new WmsStockBo();
|
||
stockBo.setItemType(bo.getItemType());
|
||
stockBo.setItemId(bo.getItemId());
|
||
List<WmsStockVo> stockList = stockService.queryList(stockBo);
|
||
|
||
if (stockList.isEmpty()) {
|
||
// 如果没有找到匹配的stock,新增一条stock记录
|
||
WmsStockBo newStockBo = new WmsStockBo();
|
||
newStockBo.setItemType(bo.getItemType());
|
||
newStockBo.setItemId(bo.getItemId());
|
||
|
||
|
||
// 调用stockService新增stock
|
||
Boolean insertResult = stockService.insertByBo(newStockBo);
|
||
if (!insertResult) {
|
||
throw new RuntimeException("新增库存记录失败");
|
||
}
|
||
}
|
||
// 如果已存在stock记录,则不需要重复创建
|
||
}
|
||
|
||
/**
|
||
* 修改钢卷物料表
|
||
* 如果newCoils不为空,则进行批量更新(分卷/合卷)
|
||
* 如果newCoils为空,则进行单个更新
|
||
*/
|
||
@Override
|
||
@Transactional(rollbackFor = Exception.class)
|
||
public Boolean updateByBo(WmsMaterialCoilBo bo) {
|
||
// 判断是否批量更新
|
||
if (bo.getNewCoils() != null && !bo.getNewCoils().isEmpty()) {
|
||
// 批量更新逻辑(分卷/合卷)
|
||
return updateByBatch(bo);
|
||
} else {
|
||
// 单个更新逻辑,需要coilId
|
||
if (bo.getCoilId() == null) {
|
||
throw new RuntimeException("钢卷ID不能为空");
|
||
}
|
||
return updateBySingle(bo);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 简单更新钢卷物料表
|
||
* 直接更新属性内容,不进行历史记录处理
|
||
*/
|
||
@Override
|
||
@Transactional(rollbackFor = Exception.class)
|
||
public Boolean updateSimple(WmsMaterialCoilBo bo) {
|
||
if (bo.getCoilId() == null) {
|
||
throw new RuntimeException("钢卷ID不能为空");
|
||
}
|
||
|
||
// 查询原钢卷是否存在
|
||
WmsMaterialCoil oldCoil = baseMapper.selectById(bo.getCoilId());
|
||
if (oldCoil == null) {
|
||
throw new RuntimeException("钢卷不存在");
|
||
}
|
||
|
||
// 直接更新钢卷属性
|
||
WmsMaterialCoil updateCoil = BeanUtil.toBean(bo, WmsMaterialCoil.class);
|
||
validEntityBeforeSave(updateCoil);
|
||
|
||
// 使用MyBatis-Plus的updateById方法直接更新
|
||
boolean flag = baseMapper.updateById(updateCoil) > 0;
|
||
|
||
return flag;
|
||
}
|
||
|
||
/**
|
||
* 单个更新
|
||
*/
|
||
private Boolean updateBySingle(WmsMaterialCoilBo bo) {
|
||
// 查询原钢卷
|
||
WmsMaterialCoil oldCoil = baseMapper.selectById(bo.getCoilId());
|
||
if (oldCoil == null) {
|
||
throw new RuntimeException("原钢卷不存在");
|
||
}
|
||
|
||
// 1. 将原钢卷标记为历史数据(dataType = 0)
|
||
LambdaUpdateWrapper<WmsMaterialCoil> updateWrapper = new LambdaUpdateWrapper<>();
|
||
updateWrapper.eq(WmsMaterialCoil::getCoilId, oldCoil.getCoilId())
|
||
.set(WmsMaterialCoil::getDataType, 0); // 设置为历史数据
|
||
baseMapper.update(null, updateWrapper);
|
||
|
||
// 2. 创建新记录
|
||
WmsMaterialCoil newCoil = BeanUtil.toBean(bo, WmsMaterialCoil.class);
|
||
newCoil.setCoilId(null); // 清空ID,让数据库自动生成新ID
|
||
newCoil.setDataType(1); // 设置为当前数据
|
||
newCoil.setQrcodeRecordId(oldCoil.getQrcodeRecordId()); // 继续使用原二维码
|
||
|
||
// 继承原记录的关键字段
|
||
if (newCoil.getEnterCoilNo() == null) {
|
||
newCoil.setEnterCoilNo(oldCoil.getEnterCoilNo());
|
||
}
|
||
if (newCoil.getSupplierCoilNo() == null) {
|
||
newCoil.setSupplierCoilNo(oldCoil.getSupplierCoilNo());
|
||
}
|
||
|
||
validEntityBeforeSave(newCoil);
|
||
|
||
// 插入新记录
|
||
boolean flag = baseMapper.insert(newCoil) > 0;
|
||
|
||
if (flag) {
|
||
// 3. 更新二维码内容(添加更新步骤并更新current_coil_id)
|
||
if (oldCoil.getQrcodeRecordId() != null) {
|
||
updateQrcodeContentForNormalUpdate(oldCoil, bo, newCoil.getCoilId());
|
||
}
|
||
}
|
||
|
||
return flag;
|
||
}
|
||
|
||
/**
|
||
* 生成二维码(更新时库区变化)
|
||
*/
|
||
private Long generateQrcodeForUpdate(WmsMaterialCoil oldCoil, WmsMaterialCoilBo bo) {
|
||
try {
|
||
// 1. 将原二维码标记为历史码(status = 0)
|
||
if (oldCoil.getQrcodeRecordId() != null) {
|
||
WmsGenerateRecordBo oldQrBo = new WmsGenerateRecordBo();
|
||
oldQrBo.setRecordId(oldCoil.getQrcodeRecordId());
|
||
oldQrBo.setStatus(0); // 0=历史码
|
||
generateRecordService.updateByBo(oldQrBo);
|
||
}
|
||
|
||
Map<String, Object> contentMap = new HashMap<>();
|
||
String currentCoilNo = bo.getCurrentCoilNo() != null ? bo.getCurrentCoilNo() : oldCoil.getCurrentCoilNo();
|
||
|
||
contentMap.put("enter_coil_no", oldCoil.getEnterCoilNo()); // 入场钢卷号(始终不变)
|
||
contentMap.put("current_coil_no", currentCoilNo); // 当前钢卷号
|
||
contentMap.put("coil_id", String.valueOf(oldCoil.getCoilId())); // 初始钢卷ID(记录最初的ID)
|
||
contentMap.put("current_coil_id", "null"); // 当前钢卷ID(更新时暂时为null,插入后更新)
|
||
|
||
// 复制原钢卷的历史steps
|
||
List<Map<String, Object>> steps = new ArrayList<>();
|
||
if (oldCoil.getQrcodeRecordId() != null) {
|
||
WmsGenerateRecordVo oldRecord = generateRecordService.queryById(oldCoil.getQrcodeRecordId());
|
||
if (oldRecord != null) {
|
||
ObjectMapper objectMapper = new ObjectMapper();
|
||
@SuppressWarnings("unchecked")
|
||
Map<String, Object> oldContentMap = objectMapper.readValue(oldRecord.getContent(), Map.class);
|
||
@SuppressWarnings("unchecked")
|
||
List<Map<String, Object>> oldSteps = (List<Map<String, Object>>) oldContentMap.get("steps");
|
||
if (oldSteps != null) {
|
||
steps.addAll(oldSteps);
|
||
}
|
||
}
|
||
}
|
||
|
||
// 添加更新步骤(库区变化)
|
||
Map<String, Object> updateStep = new HashMap<>();
|
||
updateStep.put("step", steps.size() + 1);
|
||
updateStep.put("action", "更新");
|
||
updateStep.put("operation", "库区变更");
|
||
updateStep.put("old_warehouse_id", String.valueOf(oldCoil.getWarehouseId()));
|
||
updateStep.put("new_warehouse_id", String.valueOf(bo.getWarehouseId()));
|
||
//放入真实库区
|
||
updateStep.put("old_actual_warehouse_id", String.valueOf(oldCoil.getActualWarehouseId()));
|
||
updateStep.put("new_actual_warehouse_id", String.valueOf(bo.getActualWarehouseId()));
|
||
updateStep.put("old_coil_id", String.valueOf(oldCoil.getCoilId()));
|
||
updateStep.put("current_coil_no", currentCoilNo);
|
||
updateStep.put("operator", LoginHelper.getUsername()); // 操作者
|
||
steps.add(updateStep);
|
||
|
||
contentMap.put("steps", steps);
|
||
|
||
ObjectMapper objectMapper = new ObjectMapper();
|
||
String contentJson = objectMapper.writeValueAsString(contentMap);
|
||
|
||
// 2. 生成新的二维码(status = 1)
|
||
WmsGenerateRecordBo recordBo = new WmsGenerateRecordBo();
|
||
recordBo.setContent(contentJson);
|
||
recordBo.setSerialNumber(oldCoil.getEnterCoilNo() + "-W" + bo.getWarehouseId()); // 使用入场钢卷号+库区ID作为编号
|
||
recordBo.setQrcodeType(0L);
|
||
recordBo.setIsEnabled(0L);
|
||
recordBo.setSize(200L);
|
||
recordBo.setStatus(1); // 1=当前有效码
|
||
|
||
WmsGenerateRecordVo record = generateRecordService.insertByBo(recordBo);
|
||
return record.getRecordId();
|
||
} catch (Exception e) {
|
||
throw new RuntimeException("生成更新二维码失败: " + e.getMessage());
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 批量更新(分卷/合卷)
|
||
*/
|
||
private Boolean updateByBatch(WmsMaterialCoilBo bo) {
|
||
// 查询原钢卷(分卷时需要,合卷时可能不需要)
|
||
WmsMaterialCoil oldCoil = null;
|
||
if (bo.getCoilId() != null) {
|
||
oldCoil = baseMapper.selectById(bo.getCoilId());
|
||
if (oldCoil == null) {
|
||
throw new RuntimeException("原钢卷不存在");
|
||
}
|
||
}
|
||
|
||
// 判断是分卷还是合卷
|
||
boolean isSplit = false;
|
||
boolean isMerge = false;
|
||
|
||
// 检查bo本身是否为合卷
|
||
if (bo.getHasMergeSplit() != null && bo.getHasMergeSplit() == 2) {
|
||
isMerge = true;
|
||
} else if (bo.getNewCoils() != null && !bo.getNewCoils().isEmpty()) {
|
||
// 检查newCoils中是否有分卷
|
||
for (WmsMaterialCoilBo newCoilBo : bo.getNewCoils()) {
|
||
if (newCoilBo.getHasMergeSplit() != null && newCoilBo.getHasMergeSplit() == 1) {
|
||
isSplit = true;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 1. 将原数据更新为历史数据(data_type=0)
|
||
// 注意:合卷时bo的coilId可能为空,因为bo是合卷后的新钢卷
|
||
if (bo.getCoilId() != null) {
|
||
LambdaUpdateWrapper<WmsMaterialCoil> updateWrapper = new LambdaUpdateWrapper<>();
|
||
updateWrapper.eq(WmsMaterialCoil::getCoilId, bo.getCoilId())
|
||
.set(WmsMaterialCoil::getDataType, 0); // 设置为历史数据
|
||
baseMapper.update(null, updateWrapper);
|
||
}
|
||
|
||
// 2. 插入多条新的当前数据(data_type=1)
|
||
List<WmsMaterialCoil> newCoils = new ArrayList<>();
|
||
List<String> allNewCoilNos = new ArrayList<>();
|
||
|
||
// 收集所有新钢卷号
|
||
for (WmsMaterialCoilBo newCoilBo : bo.getNewCoils()) {
|
||
allNewCoilNos.add(newCoilBo.getCurrentCoilNo());
|
||
}
|
||
|
||
if (isSplit) {
|
||
// 分卷:将bo作为被分卷的原始对象,newCoils中的对象作为分卷后产生的新钢卷
|
||
if (oldCoil == null) {
|
||
throw new RuntimeException("分卷操作需要原钢卷信息");
|
||
}
|
||
|
||
// 1. 将原始钢卷的二维码标记为失效(status=0)
|
||
if (oldCoil.getQrcodeRecordId() != null) {
|
||
WmsGenerateRecordBo oldQrBo = new WmsGenerateRecordBo();
|
||
oldQrBo.setRecordId(oldCoil.getQrcodeRecordId());
|
||
oldQrBo.setStatus(0); // 0=失效
|
||
generateRecordService.updateByBo(oldQrBo);
|
||
}
|
||
|
||
// 2. 将原始钢卷标记为历史数据,并记录所有子卷号
|
||
// 在母卷的 parent_coil_nos 字段中记录所有子卷号(用逗号分隔)
|
||
String childCoilNos = String.join(",", allNewCoilNos);
|
||
LambdaUpdateWrapper<WmsMaterialCoil> motherUpdateWrapper = new LambdaUpdateWrapper<>();
|
||
motherUpdateWrapper.eq(WmsMaterialCoil::getCoilId, oldCoil.getCoilId())
|
||
.set(WmsMaterialCoil::getParentCoilNos, childCoilNos); // 记录子卷号
|
||
baseMapper.update(null, motherUpdateWrapper);
|
||
|
||
// 3. 为每个分卷后的子钢卷生成独立的二维码并插入数据库
|
||
for (WmsMaterialCoilBo newCoilBo : bo.getNewCoils()) {
|
||
WmsMaterialCoil newCoil = BeanUtil.toBean(newCoilBo, WmsMaterialCoil.class);
|
||
newCoil.setCoilId(null);
|
||
newCoil.setDataType(1);
|
||
// 继承原钢卷的基本信息(强制继承,不能修改的字段)
|
||
newCoil.setEnterCoilNo(oldCoil.getEnterCoilNo());
|
||
newCoil.setSupplierCoilNo(oldCoil.getSupplierCoilNo()); // 保留厂家原料卷号
|
||
// materialType, itemType 和 itemId 使用前端传递的值,不强制继承
|
||
if (newCoil.getItemType() == null) {
|
||
newCoil.setItemType(oldCoil.getItemType());
|
||
}
|
||
if (newCoil.getItemId() == null) {
|
||
newCoil.setItemId(oldCoil.getItemId());
|
||
}
|
||
// 如果前端没传team,使用原钢卷的team
|
||
if (newCoil.getTeam() == null) {
|
||
newCoil.setTeam(oldCoil.getTeam());
|
||
}
|
||
// 如果没有指定库区,使用原库区
|
||
if (newCoil.getWarehouseId() == null) {
|
||
newCoil.setWarehouseId(oldCoil.getWarehouseId());
|
||
}
|
||
if (newCoil.getActualWarehouseId() == null){
|
||
newCoil.setActualWarehouseId(oldCoil.getActualWarehouseId());
|
||
}
|
||
|
||
// 在子卷的 parent_coil_nos 字段中记录母卷号
|
||
newCoil.setParentCoilNos(oldCoil.getCurrentCoilNo());
|
||
|
||
// 为每个子钢卷生成独立二维码
|
||
Long newQrcodeId = generateQrcodeForSplit(oldCoil, newCoilBo, allNewCoilNos);
|
||
newCoil.setQrcodeRecordId(newQrcodeId);
|
||
|
||
validEntityBeforeSave(newCoil);
|
||
baseMapper.insert(newCoil);
|
||
newCoils.add(newCoil);
|
||
|
||
// 更新二维码内容中的coilId
|
||
updateQrcodeCoilId(newQrcodeId, newCoil.getCoilId());
|
||
}
|
||
} else if (isMerge) {
|
||
// 合卷:将bo作为合卷后的新钢卷,newCoils中的对象作为参与合卷的原始钢卷
|
||
// 1. 将参与合卷的原始钢卷的二维码标记为失效,并将钢卷标记为历史数据
|
||
for (WmsMaterialCoilBo originalCoilBo : bo.getNewCoils()) {
|
||
if (originalCoilBo.getCoilId() != null) {
|
||
WmsMaterialCoil originalCoil = baseMapper.selectById(originalCoilBo.getCoilId());
|
||
if (originalCoil != null) {
|
||
// 标记二维码为失效
|
||
if (originalCoil.getQrcodeRecordId() != null) {
|
||
WmsGenerateRecordBo oldQrBo = new WmsGenerateRecordBo();
|
||
oldQrBo.setRecordId(originalCoil.getQrcodeRecordId());
|
||
oldQrBo.setStatus(0); // 0=失效
|
||
generateRecordService.updateByBo(oldQrBo);
|
||
}
|
||
|
||
// 标记钢卷为历史数据
|
||
LambdaUpdateWrapper<WmsMaterialCoil> originalUpdateWrapper = new LambdaUpdateWrapper<>();
|
||
originalUpdateWrapper.eq(WmsMaterialCoil::getCoilId, originalCoilBo.getCoilId())
|
||
.set(WmsMaterialCoil::getDataType, 0); // 设置为历史数据
|
||
baseMapper.update(null, originalUpdateWrapper);
|
||
}
|
||
}
|
||
}
|
||
|
||
// 2. 生成合卷后的新钢卷二维码
|
||
Long mergedQrcodeId = generateQrcodeForMerge(bo, bo.getNewCoils());
|
||
|
||
// 3. 插入合卷后的新钢卷
|
||
WmsMaterialCoil newCoil = BeanUtil.toBean(bo, WmsMaterialCoil.class);
|
||
newCoil.setCoilId(null);
|
||
newCoil.setDataType(1);
|
||
|
||
// 从第一个参与合卷的原始钢卷获取基本信息
|
||
if (!bo.getNewCoils().isEmpty()) {
|
||
WmsMaterialCoil firstOriginalCoil = baseMapper.selectById(bo.getNewCoils().get(0).getCoilId());
|
||
if (firstOriginalCoil != null) {
|
||
// 继承基本信息
|
||
if (newCoil.getEnterCoilNo() == null) {
|
||
newCoil.setEnterCoilNo(firstOriginalCoil.getEnterCoilNo());
|
||
}
|
||
if (newCoil.getSupplierCoilNo() == null) {
|
||
newCoil.setSupplierCoilNo(firstOriginalCoil.getSupplierCoilNo()); // 保留厂家原料卷号
|
||
}
|
||
if (newCoil.getItemType() == null) {
|
||
newCoil.setItemType(firstOriginalCoil.getItemType());
|
||
}
|
||
if (newCoil.getItemId() == null) {
|
||
newCoil.setItemId(firstOriginalCoil.getItemId());
|
||
}
|
||
if (newCoil.getTeam() == null) {
|
||
newCoil.setTeam(firstOriginalCoil.getTeam());
|
||
}
|
||
}
|
||
}
|
||
newCoil.setQrcodeRecordId(mergedQrcodeId);
|
||
|
||
validEntityBeforeSave(newCoil);
|
||
baseMapper.insert(newCoil);
|
||
newCoils.add(newCoil);
|
||
|
||
// 更新二维码内容中的coilId
|
||
updateQrcodeCoilId(mergedQrcodeId, newCoil.getCoilId());
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
/**
|
||
* 为分卷生成新二维码(每个子钢卷一个)
|
||
*/
|
||
private Long generateQrcodeForSplit(WmsMaterialCoil oldCoil, WmsMaterialCoilBo newCoilBo, List<String> allNewCoilNos) {
|
||
try {
|
||
Map<String, Object> contentMap = new HashMap<>();
|
||
contentMap.put("enter_coil_no", oldCoil.getEnterCoilNo());
|
||
contentMap.put("current_coil_no", newCoilBo.getCurrentCoilNo());
|
||
contentMap.put("coil_id", String.valueOf(oldCoil.getCoilId())); // 初始钢卷ID(记录原钢卷的ID)
|
||
contentMap.put("current_coil_id", "null"); // 当前钢卷ID(分卷时暂时为null,插入后更新)
|
||
|
||
// 复制原钢卷的历史steps
|
||
List<Map<String, Object>> steps = new ArrayList<>();
|
||
if (oldCoil.getQrcodeRecordId() != null) {
|
||
WmsGenerateRecordVo oldRecord = generateRecordService.queryById(oldCoil.getQrcodeRecordId());
|
||
if (oldRecord != null) {
|
||
ObjectMapper objectMapper = new ObjectMapper();
|
||
@SuppressWarnings("unchecked")
|
||
Map<String, Object> oldContentMap = objectMapper.readValue(oldRecord.getContent(), Map.class);
|
||
@SuppressWarnings("unchecked")
|
||
List<Map<String, Object>> oldSteps = (List<Map<String, Object>>) oldContentMap.get("steps");
|
||
if (oldSteps != null) {
|
||
steps.addAll(oldSteps);
|
||
}
|
||
}
|
||
}
|
||
|
||
// 添加分卷步骤
|
||
Map<String, Object> splitStep = new HashMap<>();
|
||
splitStep.put("step", steps.size() + 1);
|
||
splitStep.put("action", "更新");
|
||
splitStep.put("operation", "分卷");
|
||
splitStep.put("old_current_coil_no", oldCoil.getCurrentCoilNo());
|
||
splitStep.put("old_coil_id", String.valueOf(oldCoil.getCoilId()));
|
||
splitStep.put("new_current_coil_nos", String.join(",", allNewCoilNos));
|
||
splitStep.put("child_coils", allNewCoilNos);
|
||
splitStep.put("operator", LoginHelper.getUsername()); // 操作者
|
||
steps.add(splitStep);
|
||
|
||
contentMap.put("steps", steps);
|
||
|
||
ObjectMapper objectMapper = new ObjectMapper();
|
||
String contentJson = objectMapper.writeValueAsString(contentMap);
|
||
|
||
WmsGenerateRecordBo recordBo = new WmsGenerateRecordBo();
|
||
recordBo.setContent(contentJson);
|
||
recordBo.setSerialNumber(oldCoil.getEnterCoilNo() + "-" + newCoilBo.getCurrentCoilNo());
|
||
recordBo.setQrcodeType(0L);
|
||
recordBo.setIsEnabled(0L);
|
||
recordBo.setSize(200L);
|
||
recordBo.setStatus(1); // 1=当前有效码
|
||
|
||
WmsGenerateRecordVo record = generateRecordService.insertByBo(recordBo);
|
||
return record.getRecordId();
|
||
} catch (Exception e) {
|
||
throw new RuntimeException("生成分卷二维码失败: " + e.getMessage());
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 为合卷生成新二维码(合并多个父钢卷的二维码信息)
|
||
*/
|
||
private Long generateQrcodeForMerge(WmsMaterialCoilBo mergedCoilBo, List<WmsMaterialCoilBo> originalCoils) {
|
||
try {
|
||
if (mergedCoilBo == null) {
|
||
throw new RuntimeException("合卷后的钢卷数据不能为空");
|
||
}
|
||
|
||
Map<String, Object> contentMap = new HashMap<>();
|
||
// 获取enterCoilNo,优先使用mergedCoilBo的,如果没有则从原始钢卷中获取
|
||
String enterCoilNo = mergedCoilBo.getEnterCoilNo();
|
||
if (enterCoilNo == null && originalCoils != null && !originalCoils.isEmpty()) {
|
||
WmsMaterialCoil firstOriginalCoil = baseMapper.selectById(originalCoils.get(0).getCoilId());
|
||
if (firstOriginalCoil != null) {
|
||
enterCoilNo = firstOriginalCoil.getEnterCoilNo();
|
||
}
|
||
}
|
||
contentMap.put("enter_coil_no", enterCoilNo);
|
||
contentMap.put("current_coil_no", mergedCoilBo.getCurrentCoilNo());
|
||
contentMap.put("coil_id", "null"); // 初始钢卷ID(合卷时为null)
|
||
contentMap.put("current_coil_id", "null"); // 当前钢卷ID(合卷时暂时为null,插入后更新)
|
||
|
||
// 合并所有参与合卷的原始钢卷的历史steps
|
||
List<Map<String, Object>> steps = new ArrayList<>();
|
||
|
||
// 从参与合卷的原始钢卷中获取二维码信息并合并
|
||
if (originalCoils != null && !originalCoils.isEmpty()) {
|
||
for (WmsMaterialCoilBo originalCoilBo : originalCoils) {
|
||
if (originalCoilBo.getCoilId() != null) {
|
||
// 查询原始钢卷的二维码信息
|
||
WmsMaterialCoil originalCoil = baseMapper.selectById(originalCoilBo.getCoilId());
|
||
if (originalCoil != null && originalCoil.getQrcodeRecordId() != null) {
|
||
WmsGenerateRecordVo originalQr = generateRecordService.queryById(originalCoil.getQrcodeRecordId());
|
||
if (originalQr != null) {
|
||
ObjectMapper objectMapper = new ObjectMapper();
|
||
@SuppressWarnings("unchecked")
|
||
Map<String, Object> originalContentMap = objectMapper.readValue(originalQr.getContent(), Map.class);
|
||
@SuppressWarnings("unchecked")
|
||
List<Map<String, Object>> originalSteps = (List<Map<String, Object>>) originalContentMap.get("steps");
|
||
if (originalSteps != null) {
|
||
steps.addAll(originalSteps);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 添加合卷步骤
|
||
Map<String, Object> mergeStep = new HashMap<>();
|
||
mergeStep.put("step", steps.size() + 1);
|
||
mergeStep.put("action", "更新");
|
||
mergeStep.put("operation", "合卷");
|
||
|
||
// 收集参与合卷的原始钢卷号和ID
|
||
List<String> originalCoilNos = new ArrayList<>();
|
||
List<String> originalCoilIds = new ArrayList<>();
|
||
if (originalCoils != null && !originalCoils.isEmpty()) {
|
||
for (WmsMaterialCoilBo originalCoilBo : originalCoils) {
|
||
if (originalCoilBo.getCurrentCoilNo() != null) {
|
||
originalCoilNos.add(originalCoilBo.getCurrentCoilNo());
|
||
}
|
||
if (originalCoilBo.getCoilId() != null) {
|
||
originalCoilIds.add(originalCoilBo.getCoilId().toString());
|
||
}
|
||
}
|
||
}
|
||
mergeStep.put("parent_coil_nos", String.join(",", originalCoilNos));
|
||
mergeStep.put("parent_coil_ids", String.join(",", originalCoilIds));
|
||
mergeStep.put("new_current_coil_no", mergedCoilBo.getCurrentCoilNo());
|
||
mergeStep.put("operator", LoginHelper.getUsername()); // 操作者
|
||
steps.add(mergeStep);
|
||
|
||
contentMap.put("steps", steps);
|
||
// 将父钢卷ID也存储到顶层,方便快速查询
|
||
contentMap.put("parent_coil_ids", String.join(",", originalCoilIds));
|
||
|
||
ObjectMapper objectMapper = new ObjectMapper();
|
||
String contentJson = objectMapper.writeValueAsString(contentMap);
|
||
|
||
WmsGenerateRecordBo recordBo = new WmsGenerateRecordBo();
|
||
recordBo.setContent(contentJson);
|
||
recordBo.setSerialNumber(enterCoilNo + "-" + mergedCoilBo.getCurrentCoilNo());
|
||
recordBo.setQrcodeType(0L);
|
||
recordBo.setIsEnabled(0L);
|
||
recordBo.setSize(200L);
|
||
recordBo.setStatus(1); // 1=当前有效码
|
||
|
||
WmsGenerateRecordVo record = generateRecordService.insertByBo(recordBo);
|
||
return record.getRecordId();
|
||
} catch (Exception e) {
|
||
throw new RuntimeException("生成合卷二维码失败: " + e.getMessage());
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 更新二维码内容中的coilId
|
||
*/
|
||
private void updateQrcodeCoilId(Long qrcodeRecordId, Long coilId) {
|
||
try {
|
||
// 获取二维码记录
|
||
WmsGenerateRecordVo record = generateRecordService.queryById(qrcodeRecordId);
|
||
if (record == null) {
|
||
throw new RuntimeException("二维码记录不存在");
|
||
}
|
||
|
||
// 解析现有content
|
||
ObjectMapper objectMapper = new ObjectMapper();
|
||
Map<String, Object> contentMap = objectMapper.readValue(record.getContent(), Map.class);
|
||
|
||
// 如果是第一次设置coilId(从"null"变为实际ID),则同时设置coil_id和current_coil_id
|
||
if ("null".equals(contentMap.get("coil_id"))) {
|
||
contentMap.put("coil_id", String.valueOf(coilId)); // 初始ID,不再改变
|
||
}
|
||
|
||
// 始终更新current_coil_id为最新的钢卷ID
|
||
contentMap.put("current_coil_id", String.valueOf(coilId));
|
||
|
||
// 更新二维码记录
|
||
String newContentJson = objectMapper.writeValueAsString(contentMap);
|
||
WmsGenerateRecordBo updateBo = new WmsGenerateRecordBo();
|
||
updateBo.setRecordId(qrcodeRecordId);
|
||
updateBo.setContent(newContentJson);
|
||
generateRecordService.updateByBo(updateBo);
|
||
} catch (Exception e) {
|
||
throw new RuntimeException("更新二维码coilId失败: " + e.getMessage());
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 更新二维码内容(正常更新,添加step)
|
||
* @param oldCoil 旧钢卷记录
|
||
* @param bo 更新数据
|
||
* @param newCoilId 新钢卷ID(如果创建了新记录)
|
||
*/
|
||
private void updateQrcodeContentForNormalUpdate(WmsMaterialCoil oldCoil, WmsMaterialCoilBo bo, Long newCoilId) {
|
||
try {
|
||
// 获取原二维码记录
|
||
WmsGenerateRecordVo oldRecord = generateRecordService.queryById(oldCoil.getQrcodeRecordId());
|
||
if (oldRecord == null) {
|
||
throw new RuntimeException("二维码记录不存在");
|
||
}
|
||
|
||
// 解析现有content
|
||
ObjectMapper objectMapper = new ObjectMapper();
|
||
@SuppressWarnings("unchecked")
|
||
Map<String, Object> contentMap = objectMapper.readValue(oldRecord.getContent(), Map.class);
|
||
|
||
// 获取现有steps
|
||
@SuppressWarnings("unchecked")
|
||
List<Map<String, Object>> steps = (List<Map<String, Object>>) contentMap.get("steps");
|
||
if (steps == null) {
|
||
steps = new ArrayList<>();
|
||
}
|
||
|
||
// 添加新的step,记录更新信息
|
||
Map<String, Object> newStep = new HashMap<>();
|
||
newStep.put("step", steps.size() + 1);
|
||
newStep.put("action", "更新");
|
||
newStep.put("operation", "信息更新");
|
||
newStep.put("old_current_coil_no", oldCoil.getCurrentCoilNo());
|
||
newStep.put("new_current_coil_no", bo.getCurrentCoilNo());
|
||
newStep.put("old_coil_id", String.valueOf(oldCoil.getCoilId()));
|
||
newStep.put("new_coil_id", String.valueOf(newCoilId));
|
||
newStep.put("operator", LoginHelper.getUsername());
|
||
|
||
// 记录具体的变更字段
|
||
List<String> changedFields = new ArrayList<>();
|
||
if (bo.getCurrentCoilNo() != null && !bo.getCurrentCoilNo().equals(oldCoil.getCurrentCoilNo())) {
|
||
changedFields.add("钢卷号: " + oldCoil.getCurrentCoilNo() + " → " + bo.getCurrentCoilNo());
|
||
}
|
||
if (bo.getTeam() != null && !bo.getTeam().equals(oldCoil.getTeam())) {
|
||
changedFields.add("班组: " + oldCoil.getTeam() + " → " + bo.getTeam());
|
||
}
|
||
if (bo.getWarehouseId() != null && !bo.getWarehouseId().equals(oldCoil.getWarehouseId())) {
|
||
changedFields.add("逻辑库区ID: " + oldCoil.getWarehouseId() + " → " + bo.getWarehouseId());
|
||
}
|
||
if (bo.getActualWarehouseId() != null && !bo.getActualWarehouseId().equals(oldCoil.getActualWarehouseId())) {
|
||
changedFields.add("真实库区ID: " + oldCoil.getActualWarehouseId() + " → " + bo.getActualWarehouseId());
|
||
}
|
||
if (bo.getGrossWeight() != null && !bo.getGrossWeight().equals(oldCoil.getGrossWeight())) {
|
||
changedFields.add("毛重: " + oldCoil.getGrossWeight() + " → " + bo.getGrossWeight());
|
||
}
|
||
if (bo.getNetWeight() != null && !bo.getNetWeight().equals(oldCoil.getNetWeight())) {
|
||
changedFields.add("净重: " + oldCoil.getNetWeight() + " → " + bo.getNetWeight());
|
||
}
|
||
if (bo.getRemark() != null && !bo.getRemark().equals(oldCoil.getRemark())) {
|
||
changedFields.add("备注: " + oldCoil.getRemark() + " → " + bo.getRemark());
|
||
}
|
||
if (bo.getQualityStatus() != null && !bo.getQualityStatus().equals(oldCoil.getQualityStatus())) {
|
||
changedFields.add("质量状态: " + oldCoil.getQualityStatus() + " → " + bo.getQualityStatus());
|
||
}
|
||
if (bo.getTrimmingRequirement() != null && !bo.getTrimmingRequirement().equals(oldCoil.getTrimmingRequirement())) {
|
||
changedFields.add("切边要求: " + oldCoil.getTrimmingRequirement() + " → " + bo.getTrimmingRequirement());
|
||
}
|
||
if (bo.getPackingStatus() != null && !bo.getPackingStatus().equals(oldCoil.getPackingStatus())) {
|
||
changedFields.add("打包状态: " + oldCoil.getPackingStatus() + " → " + bo.getPackingStatus());
|
||
}
|
||
if (bo.getPackagingRequirement() != null && !bo.getPackagingRequirement().equals(oldCoil.getPackagingRequirement())) {
|
||
changedFields.add("包装要求: " + oldCoil.getPackagingRequirement() + " → " + bo.getPackagingRequirement());
|
||
}
|
||
|
||
newStep.put("changed_fields", String.join("; ", changedFields));
|
||
newStep.put("update_time", new java.util.Date());
|
||
|
||
steps.add(newStep);
|
||
contentMap.put("steps", steps);
|
||
|
||
// 更新当前钢卷号
|
||
if (bo.getCurrentCoilNo() != null) {
|
||
contentMap.put("current_coil_no", bo.getCurrentCoilNo());
|
||
}
|
||
|
||
// 更新 current_coil_id 为新记录的ID
|
||
if (newCoilId != null) {
|
||
contentMap.put("current_coil_id", String.valueOf(newCoilId));
|
||
}
|
||
|
||
// 更新二维码记录
|
||
String newContentJson = objectMapper.writeValueAsString(contentMap);
|
||
WmsGenerateRecordBo updateBo = new WmsGenerateRecordBo();
|
||
updateBo.setRecordId(oldCoil.getQrcodeRecordId());
|
||
updateBo.setContent(newContentJson);
|
||
generateRecordService.updateByBo(updateBo);
|
||
} catch (Exception e) {
|
||
throw new RuntimeException("更新二维码失败: " + e.getMessage());
|
||
}
|
||
}
|
||
|
||
|
||
/**
|
||
* 保存前的数据校验
|
||
*/
|
||
private void validEntityBeforeSave(WmsMaterialCoil entity) {
|
||
//TODO 做一些数据校验,如唯一约束
|
||
}
|
||
|
||
/**
|
||
* 批量删除钢卷物料表
|
||
*/
|
||
@Override
|
||
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
|
||
if (isValid) {
|
||
//TODO 做一些业务上的校验,判断是否需要校验
|
||
}
|
||
return baseMapper.deleteBatchIds(ids) > 0;
|
||
}
|
||
|
||
/**
|
||
* 钢卷溯源查询
|
||
* 根据入场钢卷号查询二维码,解析content中的steps,然后根据steps中的钢卷号反向查询数据库
|
||
*
|
||
* @param enterCoilNo 入场钢卷号
|
||
* @param currentCoilNo 当前钢卷号(可选,用于查询特定子钢卷)
|
||
* @return 溯源结果(包含二维码信息和数据库记录)
|
||
*/
|
||
@Override
|
||
public Map<String, Object> queryTrace(String enterCoilNo, String currentCoilNo) {
|
||
try {
|
||
// 1. 查询所有相关的二维码记录(包括分卷后的独立二维码)
|
||
List<WmsGenerateRecordVo> allQrRecords = new ArrayList<>();
|
||
|
||
// 首先查询主二维码(以入场钢卷号为序列号的)
|
||
WmsGenerateRecordBo qrBo = new WmsGenerateRecordBo();
|
||
qrBo.setSerialNumber(enterCoilNo);
|
||
List<WmsGenerateRecordVo> mainQrRecords = generateRecordService.queryList(qrBo);
|
||
allQrRecords.addAll(mainQrRecords);
|
||
|
||
// 然后查询所有以该入场钢卷号开头的二维码(分卷后的二维码)
|
||
WmsGenerateRecordBo splitQrBo = new WmsGenerateRecordBo();
|
||
List<WmsGenerateRecordVo> allRecords = generateRecordService.queryList(splitQrBo);
|
||
for (WmsGenerateRecordVo record : allRecords) {
|
||
if (record.getSerialNumber() != null &&
|
||
record.getSerialNumber().startsWith(enterCoilNo + "-") &&
|
||
!allQrRecords.contains(record)) {
|
||
allQrRecords.add(record);
|
||
}
|
||
}
|
||
|
||
if (allQrRecords.isEmpty()) {
|
||
throw new RuntimeException("未找到对应的二维码记录");
|
||
}
|
||
|
||
// 2. 合并所有二维码的steps信息,去重并重新编号
|
||
Map<String, Map<String, Object>> uniqueSteps = new HashMap<>(); // 用于去重
|
||
Set<String> allCoilNos = new HashSet<>();
|
||
|
||
for (WmsGenerateRecordVo qrRecord : allQrRecords) {
|
||
ObjectMapper objectMapper = new ObjectMapper();
|
||
@SuppressWarnings("unchecked")
|
||
Map<String, Object> contentMap = objectMapper.readValue(qrRecord.getContent(), Map.class);
|
||
|
||
@SuppressWarnings("unchecked")
|
||
List<Map<String, Object>> steps = (List<Map<String, Object>>) contentMap.get("steps");
|
||
|
||
if (steps != null) {
|
||
for (Map<String, Object> step : steps) {
|
||
// 创建唯一标识:操作类型 + 相关钢卷号
|
||
String stepKey = createStepKey(step);
|
||
|
||
// 如果是新的步骤,添加到唯一步骤集合中
|
||
if (!uniqueSteps.containsKey(stepKey)) {
|
||
Map<String, Object> uniqueStep = new HashMap<>(step);
|
||
uniqueStep.put("qrcode_serial", qrRecord.getSerialNumber());
|
||
uniqueStep.put("qrcode_id", qrRecord.getRecordId());
|
||
uniqueSteps.put(stepKey, uniqueStep);
|
||
}
|
||
|
||
// 提取钢卷号
|
||
extractCoilNo(step, "current_coil_no", allCoilNos);
|
||
extractCoilNo(step, "new_current_coil_no", allCoilNos);
|
||
extractCoilNo(step, "old_current_coil_no", allCoilNos);
|
||
extractCoilNo(step, "new_current_coil_nos", allCoilNos);
|
||
extractCoilNo(step, "merged_from", allCoilNos);
|
||
extractCoilNo(step, "parent_coil_nos", allCoilNos);
|
||
extractCoilId(step, "coil_id", allCoilNos);
|
||
extractCoilId(step, "old_coil_id", allCoilNos);
|
||
extractCoilId(step, "parent_coil_ids", allCoilNos);
|
||
}
|
||
}
|
||
}
|
||
|
||
// 转换为列表并按原始步骤号排序(保持时间顺序)
|
||
List<Map<String, Object>> allSteps = new ArrayList<>(uniqueSteps.values());
|
||
|
||
// 按原始步骤号排序,保持实际操作的时间顺序
|
||
allSteps.sort((a, b) -> {
|
||
Integer stepA = (Integer) a.get("step");
|
||
Integer stepB = (Integer) b.get("step");
|
||
if (stepA == null) stepA = 0;
|
||
if (stepB == null) stepB = 0;
|
||
return stepA.compareTo(stepB);
|
||
});
|
||
|
||
// 重新编号(保持连续性)
|
||
for (int i = 0; i < allSteps.size(); i++) {
|
||
allSteps.get(i).put("display_step", i + 1);
|
||
// 保留原始步骤号用于调试
|
||
allSteps.get(i).put("original_step", allSteps.get(i).get("step"));
|
||
}
|
||
|
||
// 3. 如果指定了当前钢卷号,过滤出相关的钢卷号
|
||
Set<String> filteredCoilNos = allCoilNos;
|
||
if (currentCoilNo != null && !currentCoilNo.trim().isEmpty()) {
|
||
final String filterValue = currentCoilNo;
|
||
filteredCoilNos = allCoilNos.stream()
|
||
.filter(coilNo -> coilNo.contains(filterValue))
|
||
.collect(Collectors.toSet());
|
||
}
|
||
|
||
// 4. 根据提取的钢卷号反向查询数据库
|
||
List<WmsMaterialCoilVo> result = new ArrayList<>();
|
||
if (!filteredCoilNos.isEmpty()) {
|
||
LambdaQueryWrapper<WmsMaterialCoil> lqw = Wrappers.lambdaQuery();
|
||
lqw.eq(WmsMaterialCoil::getEnterCoilNo, enterCoilNo);
|
||
|
||
// 查询包含提取出的钢卷号的记录
|
||
final Set<String> finalCoilNos = filteredCoilNos;
|
||
lqw.and(wrapper -> {
|
||
int count = 0;
|
||
for (String coilNo : finalCoilNos) {
|
||
if (count == 0) {
|
||
wrapper.eq(WmsMaterialCoil::getCurrentCoilNo, coilNo);
|
||
} else {
|
||
wrapper.or().eq(WmsMaterialCoil::getCurrentCoilNo, coilNo);
|
||
}
|
||
count++;
|
||
}
|
||
});
|
||
|
||
lqw.orderByAsc(WmsMaterialCoil::getCreateTime);
|
||
result = baseMapper.selectVoList(lqw);
|
||
|
||
// 填充每个记录的关联对象信息(如库区)
|
||
for (WmsMaterialCoilVo vo : result) {
|
||
fillRelatedObjects(vo);
|
||
}
|
||
}
|
||
|
||
// 如果没有找到记录,尝试查询所有相关的钢卷(包括历史数据)
|
||
if (result.isEmpty()) {
|
||
LambdaQueryWrapper<WmsMaterialCoil> lqw = Wrappers.lambdaQuery();
|
||
lqw.eq(WmsMaterialCoil::getEnterCoilNo, enterCoilNo);
|
||
lqw.orderByAsc(WmsMaterialCoil::getCreateTime);
|
||
result = baseMapper.selectVoList(lqw);
|
||
|
||
// 填充每个记录的关联对象信息
|
||
for (WmsMaterialCoilVo vo : result) {
|
||
fillRelatedObjects(vo);
|
||
}
|
||
}
|
||
|
||
// 5. 构建返回结果
|
||
Map<String, Object> resultMap = new HashMap<>();
|
||
resultMap.put("qrcode", allQrRecords.get(0)); // 主二维码
|
||
resultMap.put("all_qrcodes", allQrRecords); // 所有相关二维码
|
||
resultMap.put("steps", allSteps); // 所有步骤
|
||
resultMap.put("records", result); // 所有钢卷记录
|
||
|
||
return resultMap;
|
||
} catch (Exception e) {
|
||
throw new RuntimeException("溯源查询失败: " + e.getMessage());
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 创建步骤唯一标识
|
||
*/
|
||
private String createStepKey(Map<String, Object> step) {
|
||
StringBuilder keyBuilder = new StringBuilder();
|
||
|
||
// 使用操作类型和主要标识符创建唯一key
|
||
String operation = (String) step.get("operation");
|
||
keyBuilder.append(operation).append("-");
|
||
|
||
// 根据操作类型使用不同的标识符
|
||
if ("分卷".equals(operation)) {
|
||
// 分卷:使用原钢卷号 + 分卷列表
|
||
keyBuilder.append(step.get("old_current_coil_no")).append("->");
|
||
keyBuilder.append(step.get("new_current_coil_nos"));
|
||
} else if ("合卷".equals(operation)) {
|
||
// 合卷:使用父钢卷列表 + 新钢卷号
|
||
keyBuilder.append(step.get("parent_coil_nos")).append("->");
|
||
keyBuilder.append(step.get("new_current_coil_no"));
|
||
} else if ("新增".equals(operation)) {
|
||
// 新增:使用当前钢卷号
|
||
keyBuilder.append(step.get("current_coil_no"));
|
||
} else {
|
||
// 其他更新:使用原钢卷号 -> 新钢卷号
|
||
keyBuilder.append(step.get("old_current_coil_no")).append("->");
|
||
keyBuilder.append(step.get("new_current_coil_no"));
|
||
}
|
||
|
||
return keyBuilder.toString();
|
||
}
|
||
|
||
|
||
/**
|
||
* 从step中提取钢卷号
|
||
*/
|
||
private void extractCoilNo(Map<String, Object> step, String fieldName, Set<String> coilNos) {
|
||
Object value = step.get(fieldName);
|
||
if (value != null) {
|
||
String strValue = value.toString();
|
||
if (strValue.contains(",")) {
|
||
// 如果是逗号分隔的多个钢卷号,分割后添加
|
||
String[] coilArray = strValue.split(",");
|
||
for (String coilNo : coilArray) {
|
||
coilNos.add(coilNo.trim());
|
||
}
|
||
} else {
|
||
coilNos.add(strValue.trim());
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 从step中提取钢卷ID
|
||
*/
|
||
private void extractCoilId(Map<String, Object> step, String fieldName, Set<String> coilNos) {
|
||
Object value = step.get(fieldName);
|
||
if (value != null) {
|
||
String strValue = value.toString();
|
||
if (strValue.contains(",")) {
|
||
// 如果是逗号分隔的多个钢卷ID,分割后添加
|
||
String[] coilArray = strValue.split(",");
|
||
for (String coilId : coilArray) {
|
||
coilNos.add(coilId.trim());
|
||
}
|
||
} else {
|
||
coilNos.add(strValue.trim());
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 查询各个库区中不同类型的钢卷分布情况
|
||
* 按库区分组,统计每种物品类型和物品ID的钢卷数量和重量
|
||
*
|
||
* @param itemType 物品类型(可选)
|
||
* @param itemId 物品ID(可选)
|
||
* @return 分布情况列表,包含库区信息、物品类型、物品ID、数量、重量等
|
||
*/
|
||
@Override
|
||
public List<WmsMaterialCoilVo> getDistributionByWarehouse(String itemType, Long itemId) {
|
||
List<Map<String, Object>> mapList = baseMapper.getDistributionByWarehouse(itemType, itemId);
|
||
return convertMapListToVoList(mapList);
|
||
}
|
||
|
||
@Override
|
||
public List<WmsMaterialCoilVo> getDistributionByActualWarehouse(String itemType, Long itemId) {
|
||
List<Map<String, Object>> mapList = baseMapper.getDistributionByActualWarehouse(itemType, itemId);
|
||
return convertMapListToVoListActual(mapList);
|
||
}
|
||
private List<WmsMaterialCoilVo> convertMapListToVoListActual(List<Map<String, Object>> mapList) {
|
||
List<WmsMaterialCoilVo> voList = new ArrayList<>();
|
||
for (Map<String, Object> map : mapList) {
|
||
WmsMaterialCoilVo vo = new WmsMaterialCoilVo();
|
||
vo.setActualWarehouseId(map.get("actual_warehouse_id") != null ? Long.valueOf(map.get("actual_warehouse_id").toString()) : null);
|
||
vo.setActualWarehouseName(map.get("actual_warehouse_name") != null ? map.get("actual_warehouse_name").toString() : null);
|
||
vo.setItemType(map.get("item_type") != null ? map.get("item_type").toString() : null);
|
||
vo.setItemId(map.get("item_id") != null ? Long.valueOf(map.get("item_id").toString()) : null);
|
||
vo.setCoilCount(map.get("coil_count") != null ? Long.valueOf(map.get("coil_count").toString()) : 0L);
|
||
vo.setTotalGrossWeight(map.get("total_gross_weight") != null ? new BigDecimal(map.get("total_gross_weight").toString()) : BigDecimal.ZERO);
|
||
vo.setTotalNetWeight(map.get("total_net_weight") != null ? new BigDecimal(map.get("total_net_weight").toString()) : BigDecimal.ZERO);
|
||
voList.add(vo);
|
||
}
|
||
return voList;
|
||
}
|
||
/**
|
||
* 查询不同类型的钢卷在不同库区的分布情况
|
||
* 按物品类型和物品ID分组,统计每个库区的钢卷数量和重量
|
||
*
|
||
* @param itemType 物品类型(可选)
|
||
* @param itemId 物品ID(可选)
|
||
* @return 分布情况列表,包含物品类型、物品ID、库区信息、数量、重量等
|
||
*/
|
||
@Override
|
||
public List<WmsMaterialCoilVo> getDistributionByItemType(String itemType, Long itemId) {
|
||
List<Map<String, Object>> mapList = baseMapper.getDistributionByItemType(itemType, itemId);
|
||
return convertMapListToVoList(mapList);
|
||
}
|
||
|
||
/**
|
||
* 将Map列表转换为WmsMaterialCoilVo列表
|
||
*/
|
||
private List<WmsMaterialCoilVo> convertMapListToVoList(List<Map<String, Object>> mapList) {
|
||
List<WmsMaterialCoilVo> voList = new ArrayList<>();
|
||
for (Map<String, Object> map : mapList) {
|
||
WmsMaterialCoilVo vo = new WmsMaterialCoilVo();
|
||
vo.setWarehouseId(map.get("warehouse_id") != null ? Long.valueOf(map.get("warehouse_id").toString()) : null);
|
||
vo.setWarehouseName(map.get("warehouse_name") != null ? map.get("warehouse_name").toString() : null);
|
||
vo.setItemType(map.get("item_type") != null ? map.get("item_type").toString() : null);
|
||
vo.setItemId(map.get("item_id") != null ? Long.valueOf(map.get("item_id").toString()) : null);
|
||
vo.setCoilCount(map.get("coil_count") != null ? Long.valueOf(map.get("coil_count").toString()) : 0L);
|
||
vo.setTotalGrossWeight(map.get("total_gross_weight") != null ? new BigDecimal(map.get("total_gross_weight").toString()) : BigDecimal.ZERO);
|
||
vo.setTotalNetWeight(map.get("total_net_weight") != null ? new BigDecimal(map.get("total_net_weight").toString()) : BigDecimal.ZERO);
|
||
voList.add(vo);
|
||
}
|
||
return voList;
|
||
}
|
||
}
|
||
|