|
|
@ -1,8 +1,13 @@ |
|
|
package com.gaotao.modules.warehouse.service.impl; |
|
|
package com.gaotao.modules.warehouse.service.impl; |
|
|
|
|
|
|
|
|
|
|
|
import com.alibaba.excel.EasyExcel; |
|
|
|
|
|
import com.alibaba.excel.context.AnalysisContext; |
|
|
|
|
|
import com.alibaba.excel.read.listener.ReadListener; |
|
|
import com.baomidou.mybatisplus.core.metadata.IPage; |
|
|
import com.baomidou.mybatisplus.core.metadata.IPage; |
|
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
|
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
|
|
import com.gaotao.common.utils.PageUtils; |
|
|
import com.gaotao.common.utils.PageUtils; |
|
|
|
|
|
import com.gaotao.modules.factory.dao.PartAttributeMapper; |
|
|
|
|
|
import com.gaotao.modules.factory.entity.PartAttribute; |
|
|
import com.gaotao.modules.handlingunit.entity.HandlingUnit; |
|
|
import com.gaotao.modules.handlingunit.entity.HandlingUnit; |
|
|
import com.gaotao.modules.handlingunit.service.HandlingUnitIdGeneratorService; |
|
|
import com.gaotao.modules.handlingunit.service.HandlingUnitIdGeneratorService; |
|
|
import com.gaotao.modules.handlingunit.service.HandlingUnitService; |
|
|
import com.gaotao.modules.handlingunit.service.HandlingUnitService; |
|
|
@ -13,15 +18,18 @@ import com.gaotao.modules.warehouse.entity.dto.CreateHuRequestDto; |
|
|
import com.gaotao.modules.warehouse.entity.dto.BatchCreateHuRequestDto; |
|
|
import com.gaotao.modules.warehouse.entity.dto.BatchCreateHuRequestDto; |
|
|
import com.gaotao.modules.warehouse.service.IfsInventoryInitService; |
|
|
import com.gaotao.modules.warehouse.service.IfsInventoryInitService; |
|
|
import com.gaotao.modules.warehouse.service.InventoryStockService; |
|
|
import com.gaotao.modules.warehouse.service.InventoryStockService; |
|
|
|
|
|
import org.apache.commons.lang.StringUtils; |
|
|
import org.springframework.beans.factory.annotation.Autowired; |
|
|
import org.springframework.beans.factory.annotation.Autowired; |
|
|
|
|
|
import org.springframework.jdbc.core.JdbcTemplate; |
|
|
import org.springframework.stereotype.Service; |
|
|
import org.springframework.stereotype.Service; |
|
|
import org.springframework.transaction.annotation.Transactional; |
|
|
import org.springframework.transaction.annotation.Transactional; |
|
|
import lombok.extern.slf4j.Slf4j; |
|
|
import lombok.extern.slf4j.Slf4j; |
|
|
|
|
|
import org.springframework.web.multipart.MultipartFile; |
|
|
|
|
|
|
|
|
|
|
|
import java.io.InputStream; |
|
|
import java.math.BigDecimal; |
|
|
import java.math.BigDecimal; |
|
|
import java.util.ArrayList; |
|
|
|
|
|
import java.util.Date; |
|
|
|
|
|
import java.util.List; |
|
|
|
|
|
|
|
|
import java.text.SimpleDateFormat; |
|
|
|
|
|
import java.util.*; |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* IFS库存初始化服务实现类 |
|
|
* IFS库存初始化服务实现类 |
|
|
@ -42,6 +50,12 @@ public class IfsInventoryInitServiceImpl implements IfsInventoryInitService { |
|
|
@Autowired |
|
|
@Autowired |
|
|
private InventoryStockMapper inventoryStockMapper; |
|
|
private InventoryStockMapper inventoryStockMapper; |
|
|
|
|
|
|
|
|
|
|
|
@Autowired |
|
|
|
|
|
private JdbcTemplate jdbcTemplate; |
|
|
|
|
|
|
|
|
|
|
|
@Autowired |
|
|
|
|
|
private PartAttributeMapper partAttributeMapper; |
|
|
|
|
|
|
|
|
@Override |
|
|
@Override |
|
|
public PageUtils getInventoryStockList(InventoryStock data) { |
|
|
public PageUtils getInventoryStockList(InventoryStock data) { |
|
|
IPage<InventoryStock> ipage = warehouseMapper.getIfsInventoryStockList( |
|
|
IPage<InventoryStock> ipage = warehouseMapper.getIfsInventoryStockList( |
|
|
@ -512,4 +526,470 @@ public class IfsInventoryInitServiceImpl implements IfsInventoryInitService { |
|
|
throw new RuntimeException("批量创建HU失败: " + e.getMessage()); |
|
|
throw new RuntimeException("批量创建HU失败: " + e.getMessage()); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* 导入IFS库存Excel数据到inventory_stock_ifs表和part_attribute表 |
|
|
|
|
|
* <p><b>Excel列对应关系(inventory_stock_ifs表):</b></p> |
|
|
|
|
|
* <ul> |
|
|
|
|
|
* <li>A列: Site -> site</li> |
|
|
|
|
|
* <li>B列: Warehouse Part No -> warehouse_id</li> |
|
|
|
|
|
* <li>C列: Part No -> part_no</li> |
|
|
|
|
|
* <li>D列: Part Description -> description</li> |
|
|
|
|
|
* <li>E列: UoM -> umid</li> |
|
|
|
|
|
* <li>F列: Lot/Batch No -> batch_no</li> |
|
|
|
|
|
* <li>G列: W/D/R -> wdr</li> |
|
|
|
|
|
* <li>H列: Location No -> location_id</li> |
|
|
|
|
|
* <li>I列: Receipt Date -> manufacture_date</li> |
|
|
|
|
|
* <li>J列: Expiration Date -> expired_date</li> |
|
|
|
|
|
* <li>K列: Qty On Hand -> qty_on_hand</li> |
|
|
|
|
|
* </ul> |
|
|
|
|
|
* <p><b>Excel列对应关系(part_attribute表):</b></p> |
|
|
|
|
|
* <ul> |
|
|
|
|
|
* <li>L列: is_zin_eh -> is_in_wh(是否进立库)</li> |
|
|
|
|
|
* <li>M列: is_zxbp_eh -> is_robot_pick(是否机械手臂拣选)</li> |
|
|
|
|
|
* <li>N列: weight -> weight(重量kg)</li> |
|
|
|
|
|
* <li>O列: length -> length(长度mm)</li> |
|
|
|
|
|
* <li>P列: width -> width(宽度mm)</li> |
|
|
|
|
|
* <li>Q列: 毫米(mm) -> height(高度mm)</li> |
|
|
|
|
|
* <li>R列: 最大直径max -> diameter(直径mm)</li> |
|
|
|
|
|
* <li>S列: HU -> handling_unit_flag(HU标志)</li> |
|
|
|
|
|
* <li>T列: 密封性 -> is_commonly_used(是否常用)</li> |
|
|
|
|
|
* <li>U列: A02型号 -> (暂不处理)</li> |
|
|
|
|
|
* </ul> |
|
|
|
|
|
* <p><b>默认值:</b>print_qty=0, inventory_stock_ifs.length=0, inventory_stock_ifs.width=0</p> |
|
|
|
|
|
* <p><b>注意:</b></p> |
|
|
|
|
|
* <ul> |
|
|
|
|
|
* <li>inventory_stock_ifs表:只插入不更新,记录已存在则报错</li> |
|
|
|
|
|
* <li>part_attribute表:记录已存在则跳过,不报错</li> |
|
|
|
|
|
* </ul> |
|
|
|
|
|
* |
|
|
|
|
|
* @param file Excel文件 |
|
|
|
|
|
* @param site 站点 |
|
|
|
|
|
* @param uploadBy 上传人 |
|
|
|
|
|
* @return 导入结果统计 |
|
|
|
|
|
*/ |
|
|
|
|
|
@Override |
|
|
|
|
|
@Transactional |
|
|
|
|
|
public Map<String, Object> importIfsInventoryExcel(MultipartFile file, String site, String uploadBy) throws Exception { |
|
|
|
|
|
log.info("=== 开始解析IFS库存Excel === 站点: {}, 操作人: {}", site, uploadBy); |
|
|
|
|
|
|
|
|
|
|
|
List<String> errorMessages = new ArrayList<>(); |
|
|
|
|
|
List<Map<String, Object>> successList = new ArrayList<>(); |
|
|
|
|
|
|
|
|
|
|
|
try (InputStream inputStream = file.getInputStream()) { |
|
|
|
|
|
// 使用EasyExcel读取数据 |
|
|
|
|
|
EasyExcel.read(inputStream, new ReadListener<Map<Integer, String>>() { |
|
|
|
|
|
private int currentRow = 0; |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
|
public void invoke(Map<Integer, String> data, AnalysisContext context) { |
|
|
|
|
|
currentRow++; |
|
|
|
|
|
|
|
|
|
|
|
log.info("开始处理第{}行数据", currentRow); |
|
|
|
|
|
|
|
|
|
|
|
// 跳过表头行 |
|
|
|
|
|
/*if (currentRow == 1) { |
|
|
|
|
|
log.info("第{}行是表头行,跳过", currentRow); |
|
|
|
|
|
return; |
|
|
|
|
|
}*/ |
|
|
|
|
|
|
|
|
|
|
|
try { |
|
|
|
|
|
// 解析Excel行数据 - inventory_stock_ifs表字段 |
|
|
|
|
|
String rowSite = getValue(data, 0); // A列: Site |
|
|
|
|
|
String warehouseId = getValue(data, 1); // B列: Warehouse Part No |
|
|
|
|
|
String partNo = getValue(data, 2); // C列: Part No |
|
|
|
|
|
String description = getValue(data, 3); // D列: Part Description |
|
|
|
|
|
String umid = getValue(data, 4); // E列: UoM |
|
|
|
|
|
String batchNo = getValue(data, 5); // F列: Lot/Batch No |
|
|
|
|
|
String wdr = getValue(data, 6); // G列: W/D/R |
|
|
|
|
|
String locationId = getValue(data, 7); // H列: Location No |
|
|
|
|
|
String receiptDateStr = getValue(data, 8); // I列: Receipt Date |
|
|
|
|
|
String expirationDateStr = getValue(data, 9); // J列: Expiration Date |
|
|
|
|
|
String qtyOnHandStr = getValue(data, 10); // K列: Qty On Hand |
|
|
|
|
|
|
|
|
|
|
|
// 解析Excel行数据 - part_attribute表字段(L-U列,10列) |
|
|
|
|
|
String isInWh = getValue(data, 11); // L列: is_zin_eh |
|
|
|
|
|
String isRobotPick = getValue(data, 12); // M列: is_zxbp_eh |
|
|
|
|
|
String weightStr = getValue(data, 13); // N列: weight |
|
|
|
|
|
String lengthStr = getValue(data, 14); // O列: length |
|
|
|
|
|
String widthStr = getValue(data, 15); // P列: width |
|
|
|
|
|
String heightStr = getValue(data, 16); // Q列: 毫米(mm) |
|
|
|
|
|
String diameterStr = getValue(data, 17); // R列: 最大直径max |
|
|
|
|
|
String handlingUnitFlag = getValue(data, 18); // S列: HU |
|
|
|
|
|
String isCommonlyUsed = getValue(data, 19); // T列: 密封性 |
|
|
|
|
|
// U列(20): A02型号 - 暂不处理 |
|
|
|
|
|
|
|
|
|
|
|
// 检查是否为空行(所有必填字段都为空) |
|
|
|
|
|
if (StringUtils.isBlank(rowSite) && StringUtils.isBlank(partNo) |
|
|
|
|
|
&& StringUtils.isBlank(batchNo) && StringUtils.isBlank(locationId)) { |
|
|
|
|
|
log.info("第{}行为空行,跳过", currentRow); |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 验证必填字段 |
|
|
|
|
|
if (StringUtils.isBlank(rowSite)) { |
|
|
|
|
|
String error = "第" + currentRow + "行: Site不能为空"; |
|
|
|
|
|
log.warn(error); |
|
|
|
|
|
errorMessages.add(error); |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
if (StringUtils.isBlank(partNo)) { |
|
|
|
|
|
String error = "第" + currentRow + "行: Part No不能为空"; |
|
|
|
|
|
log.warn(error); |
|
|
|
|
|
errorMessages.add(error); |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
if (StringUtils.isBlank(batchNo)) { |
|
|
|
|
|
String error = "第" + currentRow + "行: Lot/Batch No不能为空"; |
|
|
|
|
|
log.warn(error); |
|
|
|
|
|
errorMessages.add(error); |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
if (StringUtils.isBlank(locationId)) { |
|
|
|
|
|
String error = "第" + currentRow + "行: Location No不能为空"; |
|
|
|
|
|
log.warn(error); |
|
|
|
|
|
errorMessages.add(error); |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
if (StringUtils.isBlank(qtyOnHandStr)) { |
|
|
|
|
|
String error = "第" + currentRow + "行: Qty On Hand不能为空"; |
|
|
|
|
|
log.warn(error); |
|
|
|
|
|
errorMessages.add(error); |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 解析数量 |
|
|
|
|
|
BigDecimal qtyOnHand; |
|
|
|
|
|
try { |
|
|
|
|
|
qtyOnHand = new BigDecimal(qtyOnHandStr); |
|
|
|
|
|
} catch (NumberFormatException e) { |
|
|
|
|
|
errorMessages.add("第" + currentRow + "行: Qty On Hand格式不正确: " + qtyOnHandStr); |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 解析日期 |
|
|
|
|
|
Date manufactureDate = parseDate(receiptDateStr); |
|
|
|
|
|
Date expiredDate = parseDate(expirationDateStr); |
|
|
|
|
|
|
|
|
|
|
|
// 构建inventory_stock_ifs数据Map |
|
|
|
|
|
Map<String, Object> rowData = new HashMap<>(); |
|
|
|
|
|
rowData.put("site", rowSite); |
|
|
|
|
|
rowData.put("warehouse_id", warehouseId); |
|
|
|
|
|
rowData.put("part_no", partNo); |
|
|
|
|
|
rowData.put("description", description); |
|
|
|
|
|
rowData.put("umid", umid); |
|
|
|
|
|
rowData.put("batch_no", batchNo); |
|
|
|
|
|
rowData.put("wdr", wdr); |
|
|
|
|
|
rowData.put("location_id", locationId); |
|
|
|
|
|
rowData.put("manufacture_date", manufactureDate); |
|
|
|
|
|
rowData.put("expired_date", expiredDate); |
|
|
|
|
|
rowData.put("qty_on_hand", qtyOnHand); |
|
|
|
|
|
rowData.put("print_qty", BigDecimal.ZERO); // 默认0 |
|
|
|
|
|
rowData.put("length", BigDecimal.ZERO); // 默认0 |
|
|
|
|
|
rowData.put("width", BigDecimal.ZERO); // 默认0 |
|
|
|
|
|
rowData.put("rowNumber", currentRow); |
|
|
|
|
|
|
|
|
|
|
|
// 构建part_attribute数据(仅当有数据时才创建) |
|
|
|
|
|
boolean hasPartAttributeData = StringUtils.isNotBlank(isInWh) |
|
|
|
|
|
|| StringUtils.isNotBlank(isRobotPick) |
|
|
|
|
|
|| StringUtils.isNotBlank(weightStr) |
|
|
|
|
|
|| StringUtils.isNotBlank(lengthStr) |
|
|
|
|
|
|| StringUtils.isNotBlank(widthStr) |
|
|
|
|
|
|| StringUtils.isNotBlank(heightStr) |
|
|
|
|
|
|| StringUtils.isNotBlank(diameterStr) |
|
|
|
|
|
|| StringUtils.isNotBlank(isCommonlyUsed); |
|
|
|
|
|
|
|
|
|
|
|
if (hasPartAttributeData) { |
|
|
|
|
|
PartAttribute partAttribute = new PartAttribute(); |
|
|
|
|
|
partAttribute.setSite(rowSite); |
|
|
|
|
|
partAttribute.setPartNo(partNo); |
|
|
|
|
|
partAttribute.setIsInWh(normalizeYN(isInWh)); |
|
|
|
|
|
partAttribute.setIsRobotPick(normalizeYN(isRobotPick)); |
|
|
|
|
|
partAttribute.setWeight(parseBigDecimal(weightStr)); |
|
|
|
|
|
partAttribute.setLength(parseBigDecimal(lengthStr)); |
|
|
|
|
|
partAttribute.setWidth(parseBigDecimal(widthStr)); |
|
|
|
|
|
partAttribute.setHeight(parseBigDecimal(heightStr)); |
|
|
|
|
|
partAttribute.setDiameter(parseBigDecimal(diameterStr)); |
|
|
|
|
|
partAttribute.setIsCommonlyUsed(normalizeYN(isCommonlyUsed)); |
|
|
|
|
|
|
|
|
|
|
|
rowData.put("part_attribute", partAttribute); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
successList.add(rowData); |
|
|
|
|
|
log.info("第{}行数据解析成功: partNo={}, batchNo={}, locationId={}, qtyOnHand={}, hasPartAttribute={}", |
|
|
|
|
|
currentRow, partNo, batchNo, locationId, qtyOnHand, hasPartAttributeData); |
|
|
|
|
|
|
|
|
|
|
|
} catch (Exception e) { |
|
|
|
|
|
log.error("第{}行数据处理失败: {}", currentRow, e.getMessage(), e); |
|
|
|
|
|
errorMessages.add("第" + currentRow + "行: 数据处理失败 - " + e.getMessage()); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
|
public void doAfterAllAnalysed(AnalysisContext context) { |
|
|
|
|
|
log.info("Excel解析完成,共读取 {} 行(包含表头),成功解析 {} 行数据", currentRow, successList.size()); |
|
|
|
|
|
} |
|
|
|
|
|
}).sheet().doRead(); |
|
|
|
|
|
|
|
|
|
|
|
// 批量插入数据到数据库 |
|
|
|
|
|
int successCount = 0; |
|
|
|
|
|
int failCount = 0; |
|
|
|
|
|
int partAttributeSkipped = 0; |
|
|
|
|
|
int partAttributeSaved = 0; |
|
|
|
|
|
|
|
|
|
|
|
for (Map<String, Object> rowData : successList) { |
|
|
|
|
|
try { |
|
|
|
|
|
// 1. 插入或更新inventory_stock_ifs表 |
|
|
|
|
|
insertOrUpdateIfsInventory(rowData); |
|
|
|
|
|
|
|
|
|
|
|
// 2. 插入part_attribute表(如果已存在则跳过) |
|
|
|
|
|
PartAttribute partAttribute = (PartAttribute) rowData.get("part_attribute"); |
|
|
|
|
|
if (partAttribute != null) { |
|
|
|
|
|
boolean saved = insertPartAttributeIfNotExists(partAttribute); |
|
|
|
|
|
if (saved) { |
|
|
|
|
|
partAttributeSaved++; |
|
|
|
|
|
} else { |
|
|
|
|
|
partAttributeSkipped++; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
successCount++; |
|
|
|
|
|
} catch (Exception e) { |
|
|
|
|
|
failCount++; |
|
|
|
|
|
int rowNumber = (int) rowData.get("rowNumber"); |
|
|
|
|
|
log.error("第{}行数据插入失败: {}", rowNumber, e.getMessage(), e); |
|
|
|
|
|
errorMessages.add("第" + rowNumber + "行: 数据库插入失败 - " + e.getMessage()); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
log.info("=== part_attribute表处理统计 === 新增: {}, 跳过: {}", partAttributeSaved, partAttributeSkipped); |
|
|
|
|
|
|
|
|
|
|
|
log.info("=== IFS库存Excel导入完成 === 成功: {}, 失败: {}", successCount, failCount); |
|
|
|
|
|
|
|
|
|
|
|
Map<String, Object> result = new HashMap<>(); |
|
|
|
|
|
result.put("successCount", successCount); |
|
|
|
|
|
result.put("failCount", failCount); |
|
|
|
|
|
result.put("errorMessages", errorMessages); |
|
|
|
|
|
|
|
|
|
|
|
return result; |
|
|
|
|
|
|
|
|
|
|
|
} catch (Exception e) { |
|
|
|
|
|
log.error("Excel文件读取失败: {}", e.getMessage(), e); |
|
|
|
|
|
throw new RuntimeException("Excel文件读取失败: " + e.getMessage()); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* 从Map中安全获取字符串值 |
|
|
|
|
|
*/ |
|
|
|
|
|
private String getValue(Map<Integer, String> data, int index) { |
|
|
|
|
|
String value = data.get(index); |
|
|
|
|
|
return value != null ? value.trim() : ""; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* 标准化Y/N值 |
|
|
|
|
|
* 如果是Y则返回Y,如果是N则返回N,其他值返回N |
|
|
|
|
|
*/ |
|
|
|
|
|
private String normalizeYN(String value) { |
|
|
|
|
|
if (StringUtils.isBlank(value)) { |
|
|
|
|
|
return "N"; |
|
|
|
|
|
} |
|
|
|
|
|
value = value.trim().toUpperCase(); |
|
|
|
|
|
return "Y".equals(value) ? "Y" : "N"; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* 解析BigDecimal值 |
|
|
|
|
|
*/ |
|
|
|
|
|
private BigDecimal parseBigDecimal(String value) { |
|
|
|
|
|
if (StringUtils.isBlank(value)) { |
|
|
|
|
|
return null; |
|
|
|
|
|
} |
|
|
|
|
|
try { |
|
|
|
|
|
return new BigDecimal(value.trim()); |
|
|
|
|
|
} catch (NumberFormatException e) { |
|
|
|
|
|
log.warn("无法解析数字: {}", value); |
|
|
|
|
|
return null; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* 插入part_attribute记录(如果不存在) |
|
|
|
|
|
* @param partAttribute 料件属性对象 |
|
|
|
|
|
* @return true=成功插入,false=已存在跳过 |
|
|
|
|
|
*/ |
|
|
|
|
|
private boolean insertPartAttributeIfNotExists(PartAttribute partAttribute) { |
|
|
|
|
|
try { |
|
|
|
|
|
// 检查是否已存在 |
|
|
|
|
|
PartAttribute existing = partAttributeMapper.getPartAttributeByKey( |
|
|
|
|
|
partAttribute.getSite(), |
|
|
|
|
|
partAttribute.getPartNo() |
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
if (existing != null) { |
|
|
|
|
|
log.debug("料件属性已存在,跳过: site={}, partNo={}", |
|
|
|
|
|
partAttribute.getSite(), partAttribute.getPartNo()); |
|
|
|
|
|
return false; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 插入新记录 |
|
|
|
|
|
partAttributeMapper.insert(partAttribute); |
|
|
|
|
|
log.debug("料件属性新增成功: site={}, partNo={}", |
|
|
|
|
|
partAttribute.getSite(), partAttribute.getPartNo()); |
|
|
|
|
|
return true; |
|
|
|
|
|
|
|
|
|
|
|
} catch (Exception e) { |
|
|
|
|
|
log.error("料件属性插入异常: site={}, partNo={}, error={}", |
|
|
|
|
|
partAttribute.getSite(), partAttribute.getPartNo(), e.getMessage()); |
|
|
|
|
|
// 不抛出异常,允许继续处理其他数据 |
|
|
|
|
|
return false; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* 解析日期字符串 |
|
|
|
|
|
* 支持格式:YYYY/M/D, YYYY-MM-DD |
|
|
|
|
|
*/ |
|
|
|
|
|
private Date parseDate(String dateStr) { |
|
|
|
|
|
if (StringUtils.isBlank(dateStr)) { |
|
|
|
|
|
return null; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
try { |
|
|
|
|
|
// 尝试多种日期格式 |
|
|
|
|
|
String[] formats = { |
|
|
|
|
|
"yyyy/M/d", |
|
|
|
|
|
"yyyy-MM-dd", |
|
|
|
|
|
"yyyy/MM/dd", |
|
|
|
|
|
"yyyy-M-d", |
|
|
|
|
|
"M/d/yyyy", |
|
|
|
|
|
"MM/dd/yyyy" |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
for (String format : formats) { |
|
|
|
|
|
try { |
|
|
|
|
|
SimpleDateFormat sdf = new SimpleDateFormat(format); |
|
|
|
|
|
sdf.setLenient(false); |
|
|
|
|
|
return sdf.parse(dateStr); |
|
|
|
|
|
} catch (Exception e) { |
|
|
|
|
|
// 继续尝试下一个格式 |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
log.warn("无法解析日期: {}", dateStr); |
|
|
|
|
|
return null; |
|
|
|
|
|
} catch (Exception e) { |
|
|
|
|
|
log.error("日期解析异常: {}", dateStr, e); |
|
|
|
|
|
return null; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* 批量删除IFS库存数据(真实删除) |
|
|
|
|
|
* |
|
|
|
|
|
* @param items 删除项列表 |
|
|
|
|
|
* @return 删除的记录数 |
|
|
|
|
|
*/ |
|
|
|
|
|
@Override |
|
|
|
|
|
@Transactional |
|
|
|
|
|
public int batchDeleteInventory(List<Map<String, String>> items) { |
|
|
|
|
|
log.info("=== 开始批量删除IFS库存 === 删除项数量: {}", items.size()); |
|
|
|
|
|
|
|
|
|
|
|
int deletedCount = 0; |
|
|
|
|
|
|
|
|
|
|
|
for (Map<String, String> item : items) { |
|
|
|
|
|
try { |
|
|
|
|
|
String site = item.get("site"); |
|
|
|
|
|
String warehouseId = item.get("warehouseId"); |
|
|
|
|
|
String partNo = item.get("partNo"); |
|
|
|
|
|
String batchNo = item.get("batchNo"); |
|
|
|
|
|
String locationId = item.get("locationId"); |
|
|
|
|
|
String wdr = item.get("wdr"); |
|
|
|
|
|
|
|
|
|
|
|
log.info("删除记录: site={}, warehouse={}, partNo={}, batchNo={}, location={}, wdr={}", |
|
|
|
|
|
site, warehouseId, partNo, batchNo, locationId, wdr); |
|
|
|
|
|
|
|
|
|
|
|
// 执行删除 |
|
|
|
|
|
String deleteSql = "DELETE FROM inventory_stock_ifs " + |
|
|
|
|
|
"WHERE site = ? AND ISNULL(warehouse_id, '') = ISNULL(?, '') AND part_no = ? " + |
|
|
|
|
|
"AND batch_no = ? AND location_id = ? AND ISNULL(wdr, '') = ISNULL(?, '')"; |
|
|
|
|
|
|
|
|
|
|
|
int rows = jdbcTemplate.update(deleteSql, |
|
|
|
|
|
site, |
|
|
|
|
|
warehouseId, |
|
|
|
|
|
partNo, |
|
|
|
|
|
batchNo, |
|
|
|
|
|
locationId, |
|
|
|
|
|
wdr |
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
deletedCount += rows; |
|
|
|
|
|
log.debug("删除成功: 影响行数={}", rows); |
|
|
|
|
|
|
|
|
|
|
|
} catch (Exception e) { |
|
|
|
|
|
log.error("删除记录失败: {}", e.getMessage(), e); |
|
|
|
|
|
throw new RuntimeException("删除失败: " + e.getMessage()); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
log.info("=== 批量删除完成 === 总删除记录数: {}", deletedCount); |
|
|
|
|
|
return deletedCount; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* 插入IFS库存数据(仅插入,不更新) |
|
|
|
|
|
* 如果记录已存在(基于site, warehouse_id, part_no, batch_no, location_id, wdr),则抛出异常 |
|
|
|
|
|
*/ |
|
|
|
|
|
private void insertOrUpdateIfsInventory(Map<String, Object> data) { |
|
|
|
|
|
// 1. 先检查记录是否已存在 |
|
|
|
|
|
String checkSql = "SELECT COUNT(*) FROM inventory_stock_ifs " + |
|
|
|
|
|
"WHERE site = ? AND ISNULL(warehouse_id, '') = ISNULL(?, '') AND part_no = ? " + |
|
|
|
|
|
"AND batch_no = ? AND location_id = ? AND ISNULL(wdr, '') = ISNULL(?, '')"; |
|
|
|
|
|
|
|
|
|
|
|
Integer count = jdbcTemplate.queryForObject(checkSql, Integer.class, |
|
|
|
|
|
data.get("site"), |
|
|
|
|
|
data.get("warehouse_id"), |
|
|
|
|
|
data.get("part_no"), |
|
|
|
|
|
data.get("batch_no"), |
|
|
|
|
|
data.get("location_id"), |
|
|
|
|
|
data.get("wdr") |
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
// 2. 如果记录已存在,则抛出异常 |
|
|
|
|
|
if (count != null && count > 0) { |
|
|
|
|
|
throw new RuntimeException(String.format( |
|
|
|
|
|
"库存记录已存在:Site=%s, Warehouse=%s, PartNo=%s, BatchNo=%s, Location=%s, WDR=%s", |
|
|
|
|
|
data.get("site"), |
|
|
|
|
|
data.get("warehouse_id"), |
|
|
|
|
|
data.get("part_no"), |
|
|
|
|
|
data.get("batch_no"), |
|
|
|
|
|
data.get("location_id"), |
|
|
|
|
|
data.get("wdr") |
|
|
|
|
|
)); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 3. 插入新记录 |
|
|
|
|
|
String insertSql = "INSERT INTO inventory_stock_ifs " + |
|
|
|
|
|
"(site, warehouse_id, part_no, description, umid, batch_no, wdr, location_id, " + |
|
|
|
|
|
"manufacture_date, expired_date, qty_on_hand, print_qty, length, width) " + |
|
|
|
|
|
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; |
|
|
|
|
|
|
|
|
|
|
|
jdbcTemplate.update(insertSql, |
|
|
|
|
|
data.get("site"), |
|
|
|
|
|
data.get("warehouse_id"), |
|
|
|
|
|
data.get("part_no"), |
|
|
|
|
|
data.get("description"), |
|
|
|
|
|
data.get("umid"), |
|
|
|
|
|
data.get("batch_no"), |
|
|
|
|
|
data.get("wdr"), |
|
|
|
|
|
data.get("location_id"), |
|
|
|
|
|
data.get("manufacture_date"), |
|
|
|
|
|
data.get("expired_date"), |
|
|
|
|
|
data.get("qty_on_hand"), |
|
|
|
|
|
data.get("print_qty"), |
|
|
|
|
|
data.get("length"), |
|
|
|
|
|
data.get("width") |
|
|
|
|
|
); |
|
|
|
|
|
} |
|
|
} |
|
|
} |