Browse Source

跨区调拨

master
han\hanst 7 months ago
parent
commit
2de7b56a8d
  1. 155
      src/main/java/com/gaotao/modules/crossAreaTransfer/controller/CrossAreaTransferController.java
  2. 71
      src/main/java/com/gaotao/modules/crossAreaTransfer/dao/CrossAreaTransferMapper.java
  3. 101
      src/main/java/com/gaotao/modules/crossAreaTransfer/entity/CrossAreaTransferEntity.java
  4. 31
      src/main/java/com/gaotao/modules/crossAreaTransfer/service/CrossAreaTransferService.java
  5. 304
      src/main/java/com/gaotao/modules/crossAreaTransfer/service/impl/CrossAreaTransferServiceImpl.java
  6. 179
      src/main/java/com/gaotao/modules/labelSplitMerge/service/impl/LabelSplitMergeServiceImpl.java
  7. 108
      src/main/java/com/gaotao/modules/propertyChange/service/impl/PropertyChangeServiceImpl.java
  8. 7
      src/main/java/com/gaotao/modules/trans/service/impl/TransHeaderServiceImpl.java
  9. 97
      src/main/resources/mapper/crossAreaTransfer/CrossAreaTransferMapper.xml

155
src/main/java/com/gaotao/modules/crossAreaTransfer/controller/CrossAreaTransferController.java

@ -0,0 +1,155 @@
package com.gaotao.modules.crossAreaTransfer.controller;
import com.gaotao.common.utils.R;
import com.gaotao.modules.crossAreaTransfer.service.CrossAreaTransferService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.Map;
/**
* 跨区调拨控制器
*
* @author system
* @date 2025-01-01
*/
@Api(tags = "跨区调拨管理")
@RestController
@RequestMapping("/cross-area-transfer")
public class CrossAreaTransferController {
private static final Logger logger = LoggerFactory.getLogger(CrossAreaTransferController.class);
@Autowired
private CrossAreaTransferService crossAreaTransferService;
/**
* 获取跨区调拨信息
*
* @param params 查询参数
* @return 调拨信息
*/
@ApiOperation("获取跨区调拨信息")
@PostMapping("/getTransferInfo")
public R getTransferInfo(@RequestBody Map<String, Object> params) {
logger.info("获取跨区调拨信息接口调用,参数: {}", params);
try {
// 参数校验
String scanCode = (String) params.get("scanCode");
String transferMode = (String) params.get("transferMode");
String site = (String) params.get("site");
String warehouseId = (String) params.get("warehouseId");
if (scanCode == null || scanCode.trim().isEmpty()) {
return R.error("扫描码不能为空");
}
if (transferMode == null || transferMode.trim().isEmpty()) {
return R.error("调拨模式不能为空");
}
if (!"label".equals(transferMode) && !"location".equals(transferMode)) {
return R.error("调拨模式参数错误");
}
if (site == null || site.trim().isEmpty()) {
return R.error("站点不能为空");
}
if (warehouseId == null || warehouseId.trim().isEmpty()) {
return R.error("仓库ID不能为空");
}
Map<String, Object> result = crossAreaTransferService.getTransferInfo(params);
if ((Integer) result.get("code") == 0) {
return R.ok().put("data", result.get("data"));
} else {
return R.error((String) result.get("msg"));
}
} catch (Exception e) {
logger.error("获取跨区调拨信息失败", e);
return R.error("获取调拨信息失败: " + e.getMessage());
}
}
/**
* 保存跨区调拨
*
* @param params 调拨参数
* - scanCode: 扫描码
* - transferMode: 调拨模式
* - sourceLocation: 源库位
* - targetLocation: 目标库位
* - site: 站点
* - warehouseId: 仓库ID
* - operator: 操作员
* @return 操作结果
*/
@ApiOperation("保存跨区调拨")
@PostMapping("/saveTransfer")
public R saveTransfer(@RequestBody Map<String, Object> params) {
logger.info("保存跨区调拨接口调用,参数: {}", params);
try {
// 参数校验
String scanCode = (String) params.get("scanCode");
String transferMode = (String) params.get("transferMode");
String sourceLocation = (String) params.get("sourceLocation");
String targetLocation = (String) params.get("targetLocation");
String site = (String) params.get("site");
String warehouseId = (String) params.get("warehouseId");
String operator = (String) params.get("operator");
if (scanCode == null || scanCode.trim().isEmpty()) {
return R.error("扫描码不能为空");
}
if (transferMode == null || transferMode.trim().isEmpty()) {
return R.error("调拨模式不能为空");
}
if (!"label".equals(transferMode) && !"location".equals(transferMode)) {
return R.error("调拨模式参数错误");
}
if (sourceLocation == null || sourceLocation.trim().isEmpty()) {
return R.error("源库位不能为空");
}
if (targetLocation == null || targetLocation.trim().isEmpty()) {
return R.error("目标库位不能为空");
}
if (site == null || site.trim().isEmpty()) {
return R.error("站点不能为空");
}
if (warehouseId == null || warehouseId.trim().isEmpty()) {
return R.error("仓库ID不能为空");
}
if (operator == null || operator.trim().isEmpty()) {
return R.error("操作员不能为空");
}
boolean success = crossAreaTransferService.saveTransfer(params);
if (success) {
return R.ok("跨区调拨成功");
} else {
return R.error("跨区调拨失败");
}
} catch (Exception e) {
logger.error("保存跨区调拨失败", e);
return R.error("保存调拨失败: " + e.getMessage());
}
}
}

71
src/main/java/com/gaotao/modules/crossAreaTransfer/dao/CrossAreaTransferMapper.java

@ -0,0 +1,71 @@
package com.gaotao.modules.crossAreaTransfer.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.gaotao.modules.crossAreaTransfer.entity.CrossAreaTransferEntity;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Map;
/**
* 跨区调拨Mapper
*
* @author system
* @date 2025-01-01
*/
@Mapper
public interface CrossAreaTransferMapper extends BaseMapper<CrossAreaTransferEntity> {
/**
* 根据标签条码获取库存信息
*
* @param labelCode 标签条码
* @param site 站点
* @param warehouseId 仓库ID
* @return 库存信息
*/
Map<String, Object> getStockInfoByLabelCode(@Param("labelCode") String labelCode,
@Param("site") String site,
@Param("warehouseId") String warehouseId);
/**
* 根据库位获取标签列表
*
* @param locationId 库位ID
* @param site 站点
* @param warehouseId 仓库ID
* @return 标签列表
*/
List<Map<String, Object>> getLabelsByLocation(@Param("locationId") String locationId,
@Param("site") String site,
@Param("warehouseId") String warehouseId);
/**
* 根据库位获取库存信息列表
*
* @param locationId 库位ID
* @param site 站点
* @param warehouseId 仓库ID
* @return 库存信息列表
*/
List<Map<String, Object>> getStockInfoByLocation(@Param("locationId") String locationId,
@Param("site") String site,
@Param("warehouseId") String warehouseId);
/**
* 更新库存表的库位和仓库信息按标签调拨
*
* @param params 更新参数
* @return 更新行数
*/
int updateStockLocationAndWarehouse(Map<String, Object> params);
/**
* 批量更新库存表的库位和仓库信息按库位调拨
*
* @param params 更新参数
* @return 更新行数
*/
int batchUpdateStockLocationAndWarehouse(Map<String, Object> params);
}

101
src/main/java/com/gaotao/modules/crossAreaTransfer/entity/CrossAreaTransferEntity.java

@ -0,0 +1,101 @@
package com.gaotao.modules.crossAreaTransfer.entity;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
/**
* 跨区调拨实体类
*
* @author system
* @date 2025-01-01
*/
@Data
@TableName("cross_area_transfer")
public class CrossAreaTransferEntity implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@TableId
private Long id;
/**
* 站点
*/
private String site;
/**
* 事业部
*/
private String buNo;
/**
* 仓库ID
*/
private String warehouseId;
/**
* 标签条码
*/
private String labelCode;
/**
* 物料编码
*/
private String partNo;
/**
* 批次号
*/
private String batchNo;
/**
* 调拨模式label-按标签调拨location-按库位调拨
*/
private String transferMode;
/**
* 源库位
*/
private String sourceLocation;
/**
* 目标库位
*/
private String targetLocation;
/**
* 数量
*/
private Float quantity;
/**
* 操作员
*/
private String operator;
/**
* 创建时间
*/
private Date createTime;
/**
* 事务单号
*/
private String transNo;
/**
* 状态0-待处理1-已完成2-已取消
*/
private Integer status;
/**
* 备注
*/
private String remark;
}

31
src/main/java/com/gaotao/modules/crossAreaTransfer/service/CrossAreaTransferService.java

@ -0,0 +1,31 @@
package com.gaotao.modules.crossAreaTransfer.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.gaotao.modules.crossAreaTransfer.entity.CrossAreaTransferEntity;
import java.util.Map;
/**
* 跨区调拨服务接口
*
* @author system
* @date 2025-01-01
*/
public interface CrossAreaTransferService extends IService<CrossAreaTransferEntity> {
/**
* 获取跨区调拨信息
*
* @param params 查询参数
* @return 调拨信息
*/
Map<String, Object> getTransferInfo(Map<String, Object> params);
/**
* 保存跨区调拨
*
* @param params 调拨参数
* @return 是否成功
*/
boolean saveTransfer(Map<String, Object> params);
}

304
src/main/java/com/gaotao/modules/crossAreaTransfer/service/impl/CrossAreaTransferServiceImpl.java

@ -0,0 +1,304 @@
package com.gaotao.modules.crossAreaTransfer.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gaotao.modules.crossAreaTransfer.dao.CrossAreaTransferMapper;
import com.gaotao.modules.crossAreaTransfer.entity.CrossAreaTransferEntity;
import com.gaotao.modules.crossAreaTransfer.service.CrossAreaTransferService;
import com.gaotao.modules.inboundNotification.dao.InboundNotificationHeadMapper;
import com.gaotao.modules.trans.entity.TransDetail;
import com.gaotao.modules.trans.entity.TransDetailDto;
import com.gaotao.modules.trans.entity.TransHeader;
import com.gaotao.modules.trans.service.TransDetailService;
import com.gaotao.modules.trans.service.TransHeaderService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 跨区调拨服务实现类
*
* @author system
* @date 2025-01-01
*/
@Service
public class CrossAreaTransferServiceImpl extends ServiceImpl<CrossAreaTransferMapper, CrossAreaTransferEntity> implements CrossAreaTransferService {
private static final Logger logger = LoggerFactory.getLogger(CrossAreaTransferServiceImpl.class);
@Autowired
private CrossAreaTransferMapper crossAreaTransferMapper;
@Autowired
private TransHeaderService transHeaderService;
@Autowired
private TransDetailService transDetailService;
@Autowired
private InboundNotificationHeadMapper headMapper;
@Override
public Map<String, Object> getTransferInfo(Map<String, Object> params) {
logger.info("获取跨区调拨信息,参数: {}", params);
String scanCode = (String) params.get("scanCode");
String transferMode = (String) params.get("transferMode");
String site = (String) params.get("site");
String warehouseId = (String) params.get("warehouseId");
Map<String, Object> result = new HashMap<>();
try {
if ("label".equals(transferMode)) {
// 按标签调拨获取标签信息
Map<String, Object> stockInfo = crossAreaTransferMapper.getStockInfoByLabelCode(scanCode, site, warehouseId);
if (stockInfo == null) {
logger.warn("未找到标签库存信息,标签条码: {}", scanCode);
result.put("code", 1);
result.put("msg", "未找到该标签的库存信息");
return result;
}
// 格式化返回数据
Map<String, Object> labelInfo = new HashMap<>();
labelInfo.put("labelCode", stockInfo.get("label_code"));
labelInfo.put("quantity", stockInfo.get("quantity"));
labelInfo.put("warehouseName", stockInfo.get("warehouse_name"));
labelInfo.put("locationId", stockInfo.get("location_id"));
labelInfo.put("status", stockInfo.get("status"));
labelInfo.put("productionDate", stockInfo.get("production_date"));
labelInfo.put("expiryDate", stockInfo.get("expiry_date"));
labelInfo.put("orderRef1", stockInfo.get("order_ref1"));
labelInfo.put("orderRef2", stockInfo.get("order_ref2"));
labelInfo.put("batchNo", stockInfo.get("batch_no"));
labelInfo.put("buNo", stockInfo.get("buNo"));
result.put("code", 0);
result.put("data", labelInfo);
} else if ("location".equals(transferMode)) {
// 按库位调拨获取库位下的所有标签
List<Map<String, Object>> labels = crossAreaTransferMapper.getLabelsByLocation(scanCode, site, warehouseId);
if (labels == null || labels.isEmpty()) {
logger.warn("该库位下未找到标签,库位: {}", scanCode);
result.put("code", 1);
result.put("msg", "该库位下未找到标签");
return result;
}
result.put("code", 0);
result.put("data", labels);
}
logger.info("获取跨区调拨信息成功,模式: {}, 扫描码: {}", transferMode, scanCode);
return result;
} catch (Exception e) {
logger.error("获取跨区调拨信息失败", e);
result.put("code", 1);
result.put("msg", "查询失败: " + e.getMessage());
return result;
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean saveTransfer(Map<String, Object> params) {
logger.info("开始保存跨区调拨,参数: {}", params);
try {
String scanCode = (String) params.get("scanCode");
String transferMode = (String) params.get("transferMode");
String sourceLocation = (String) params.get("sourceLocation");
String targetLocation = (String) params.get("targetLocation");
String site = (String) params.get("site");
String buNo = (String) params.get("buNo");
String warehouseId = (String) params.get("warehouseId");
String operator = (String) params.get("operator");
// 1. 验证库位是否存在且可用
Map<String, Object> locationInfo = headMapper.validateLocation(targetLocation, site);
if (locationInfo == null || locationInfo.isEmpty()) {
throw new RuntimeException("该库位不存在,请检查");
}
String locationStatus = (String) locationInfo.get("status");
if (!"Y".equals(locationStatus)) {
throw new RuntimeException("该库位已停用,请检查");
}
// 2. 根据源库位查询库存信息
List<Map<String, Object>> stockInfoList = new ArrayList<>();
if ("label".equals(transferMode)) {
// 按标签调拨查询单个标签的库存信息
Map<String, Object> stockInfo = crossAreaTransferMapper.getStockInfoByLabelCode(scanCode, site, warehouseId);
if (stockInfo != null) {
stockInfoList.add(stockInfo);
}
} else {
// 按库位调拨查询库位下所有标签的库存信息
stockInfoList = crossAreaTransferMapper.getStockInfoByLocation(sourceLocation, site, warehouseId);
}
if (stockInfoList.isEmpty()) {
logger.error("未找到库存信息,源库位: {}", sourceLocation);
return false;
}
// 根据库位获取实际的仓库ID
String actualWarehouseId = (String) locationInfo.get("warehouseId");
if (actualWarehouseId != null && !actualWarehouseId.trim().isEmpty()) {
warehouseId = actualWarehouseId;
logger.info("根据库位号 {} 获取到仓库ID: {}", targetLocation, warehouseId);
}
// 3. 更新库存表 - 根据源库位更新到目标库位和仓库
Map<String, Object> updateParams = new HashMap<>();
updateParams.put("site", site);
updateParams.put("sourceLocation", sourceLocation);
updateParams.put("targetLocation", targetLocation);
updateParams.put("targetWarehouseId", warehouseId); // 目标仓库ID
updateParams.put("operator", operator);
updateParams.put("updateTime", new Date());
int updateCount = 0;
if ("label".equals(transferMode)) {
// 按标签调拨更新单个标签的库位和仓库
updateParams.put("labelCode", scanCode);
updateCount = crossAreaTransferMapper.updateStockLocationAndWarehouse(updateParams);
} else {
// 按库位调拨更新整个库位下所有标签的库位和仓库
updateCount = crossAreaTransferMapper.batchUpdateStockLocationAndWarehouse(updateParams);
}
if (updateCount == 0) {
logger.error("更新库存失败,未找到匹配的库存记录");
return false;
}
// 5. 生成标签变动事务记录
generateTransferTransaction(site, warehouseId, scanCode, transferMode, buNo, stockInfoList);
logger.info("跨区调拨保存成功,模式: {}, 扫描码: {}, 目标库位: {}", transferMode, scanCode, targetLocation);
return true;
} catch (Exception e) {
logger.error("保存跨区调拨失败", e);
throw new RuntimeException("保存跨区调拨失败: " + e.getMessage());
}
}
/**
* 生成跨区调拨事务记录
*/
private void generateTransferTransaction(String site, String warehouseId, String scanCode, String transferMode, String buNo, List<Map<String, Object>> stockInfoList) {
logger.info("开始生成跨区调拨事务记录,扫描码: {}", scanCode);
try {
// 构建TransDetailDto对象
TransDetailDto transDetailDto = new TransDetailDto();
transDetailDto.setSite(site);
transDetailDto.setRemark("跨区调拨 - " + transferMode);
transDetailDto.setOrderref1(scanCode); // 扫描码标签或库位
transDetailDto.setOrderref2(transferMode); // 调拨模式
transDetailDto.setOrderref3(warehouseId); // 仓库ID
// 使用TransHeaderService的genTrans方法生成事务头
// CAT = Cross Area Transfer 跨区调拨
TransHeader transHeader = transHeaderService.genTrans(transDetailDto, "CAT", warehouseId, buNo);
if (transHeader == null) {
throw new RuntimeException("生成跨区调拨事务头记录失败");
}
logger.info("跨区调拨事务头记录生成成功,事务单号: {}", transHeader.getTransno());
// 生成事务明细记录
generateTransactionDetails(transHeader.getTransno(), stockInfoList, site);
logger.info("跨区调拨事务记录生成完成,事务单号: {}, 扫描码: {}, 明细记录数: {}",
transHeader.getTransno(), scanCode, stockInfoList.size());
} catch (Exception e) {
logger.error("生成跨区调拨事务记录失败", e);
// 不抛出异常避免影响主流程
}
}
/**
* 生成事务明细记录
*/
private void generateTransactionDetails(String transNo, List<Map<String, Object>> stockInfoList, String site) {
logger.info("开始生成跨区调拨事务明细记录,事务单号: {}, 明细数量: {}", transNo, stockInfoList.size());
List<TransDetail> transDetailList = new ArrayList<>();
double itemNo = 1.0; // 行号从1开始
for (Map<String, Object> stockInfo : stockInfoList) {
String labelCode = (String) stockInfo.get("label_code");
String partNo = (String) stockInfo.get("part_no");
String batchNo = (String) stockInfo.get("batch_no");
Object quantityObj = stockInfo.get("quantity");
// 转换数量
BigDecimal quantity = convertToDecimal(quantityObj);
// 构建事务明细记录
TransDetail transDetail = new TransDetail();
transDetail.setSite(site);
transDetail.setTransno(transNo);
transDetail.setItemno(itemNo);
transDetail.setPartno(partNo);
transDetail.setTransqty(quantity);
transDetail.setBatchno(batchNo);
transDetail.setDirection("-"); // 调拨方向
transDetail.setOrderref1(labelCode); // 标签条码
transDetail.setOrderref2(partNo); // 物料编码
transDetail.setOrderref3(batchNo); // 批次号
transDetail.setRemark("跨区调拨 - 标签: " + labelCode);
transDetailList.add(transDetail);
itemNo += 1.0; // 行号递增
}
// 批量保存事务明细记录
if (!transDetailList.isEmpty()) {
boolean success = transDetailService.saveBatch(transDetailList);
if (!success) {
throw new RuntimeException("跨区调拨事务明细记录保存失败");
}
logger.info("跨区调拨事务明细记录生成成功,共生成 {} 条明细记录", transDetailList.size());
}
}
/**
* 转换数量为BigDecimal
*/
private BigDecimal convertToDecimal(Object quantityObj) {
if (quantityObj == null) {
return BigDecimal.ZERO;
}
if (quantityObj instanceof BigDecimal) {
return (BigDecimal) quantityObj;
} else if (quantityObj instanceof Number) {
return new BigDecimal(quantityObj.toString());
} else {
try {
return new BigDecimal(quantityObj.toString());
} catch (NumberFormatException e) {
logger.warn("数量转换失败,使用默认值0,原值: {}", quantityObj);
return BigDecimal.ZERO;
}
}
}
}

179
src/main/java/com/gaotao/modules/labelSplitMerge/service/impl/LabelSplitMergeServiceImpl.java

@ -4,9 +4,11 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gaotao.modules.labelSplitMerge.dao.LabelSplitMergeMapper;
import com.gaotao.modules.labelSplitMerge.entity.LabelSplitMergeEntity;
import com.gaotao.modules.labelSplitMerge.service.LabelSplitMergeService;
import com.gaotao.modules.trans.entity.TransDetail;
import com.gaotao.modules.trans.entity.TransDetailDto;
import com.gaotao.modules.trans.entity.TransHeader;
import com.gaotao.modules.trans.entity.TransNoControl;
import com.gaotao.modules.trans.service.TransDetailService;
import com.gaotao.modules.trans.service.TransHeaderService;
import com.gaotao.modules.trans.service.TransNoControlService;
import org.slf4j.Logger;
@ -15,8 +17,11 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
@ -36,6 +41,9 @@ public class LabelSplitMergeServiceImpl extends ServiceImpl<LabelSplitMergeMappe
@Autowired
private TransHeaderService transHeaderService;
@Autowired
private TransDetailService transDetailService;
@Autowired
private TransNoControlService transNoControlService;
@ -136,8 +144,7 @@ public class LabelSplitMergeServiceImpl extends ServiceImpl<LabelSplitMergeMappe
}
// 5. 生成标签变动事务记录
generatePropertyChangeTransaction(site, buNo, warehouseId, originalLabelCode, partNo,
"标签拆分: 原标签[" + originalLabelCode + "]拆分出新标签[" + newLabelCode + "], 拆分数量: " + splitQuantity,"CF");
generateSplitTransaction(site, buNo, warehouseId, originalLabelCode, newLabelCode, partNo, batchNo, splitQuantity, remainingQuantity);
Map<String, Object> result = new HashMap<>();
result.put("newLabelCode", newLabelCode);
@ -202,8 +209,7 @@ public class LabelSplitMergeServiceImpl extends ServiceImpl<LabelSplitMergeMappe
}
// 4. 生成标签变动事务记录
generatePropertyChangeTransaction(site, buNo, warehouseId, sourceLabelCode, partNo,
"标签合并: 源标签[" + sourceLabelCode + "]合并到目标标签[" + targetLabelCode + "], 合并数量: " + sourceQuantity,"HB");
generateMergeTransaction(site, buNo, warehouseId, sourceLabelCode, targetLabelCode, partNo, batchNo, sourceQuantity, targetQuantity, mergedQuantity);
logger.info("标签合并成功,源标签: {}, 目标标签: {}, 合并数量: {}", sourceLabelCode, targetLabelCode, sourceQuantity);
return true;
@ -215,33 +221,176 @@ public class LabelSplitMergeServiceImpl extends ServiceImpl<LabelSplitMergeMappe
}
/**
* 生成标签变动事务记录
* 生成标签拆分事务记录
*/
private void generateSplitTransaction(String site, String buNo, String warehouseId, String originalLabelCode,
String newLabelCode, String partNo, String batchNo, Float splitQuantity, Float remainingQuantity) {
logger.info("开始生成标签拆分事务记录,原标签: {}, 新标签: {}", originalLabelCode, newLabelCode);
try {
// 构建TransDetailDto对象
TransDetailDto transDetailDto = new TransDetailDto();
transDetailDto.setSite(site);
transDetailDto.setRemark("标签拆分 - 原标签: " + originalLabelCode + ", 新标签: " + newLabelCode);
transDetailDto.setOrderref1(originalLabelCode); // 原标签条码
transDetailDto.setOrderref2(newLabelCode); // 新标签条码
transDetailDto.setOrderref3(warehouseId); // 仓库ID
// 使用TransHeaderService的genTrans方法生成事务头
// CF = 拆分 (Cha Fen)
TransHeader transHeader = transHeaderService.genTrans(transDetailDto, "CF", warehouseId, buNo);
if (transHeader == null) {
throw new RuntimeException("生成标签拆分事务头记录失败");
}
logger.info("标签拆分事务头记录生成成功,事务单号: {}", transHeader.getTransno());
// 生成事务明细记录
generateSplitTransactionDetails(transHeader.getTransno(), originalLabelCode, newLabelCode, partNo, batchNo, splitQuantity, remainingQuantity, site);
logger.info("标签拆分事务记录生成完成,事务单号: {}, 原标签: {}, 新标签: {}",
transHeader.getTransno(), originalLabelCode, newLabelCode);
} catch (Exception e) {
logger.error("生成标签拆分事务记录失败", e);
// 不抛出异常避免影响主流程
}
}
/**
* 生成标签合并事务记录
*/
private void generatePropertyChangeTransaction(String site, String buNo, String warehouseId,
String labelCode, String partNo, String remark,String transType) {
logger.info("开始生成标签变动事务记录,标签条码: {}", labelCode);
private void generateMergeTransaction(String site, String buNo, String warehouseId, String sourceLabelCode,
String targetLabelCode, String partNo, String batchNo, Float sourceQuantity, Float targetQuantity, Float mergedQuantity) {
logger.info("开始生成标签合并事务记录,源标签: {}, 目标标签: {}", sourceLabelCode, targetLabelCode);
try {
// 构建TransDetailDto对象
TransDetailDto transDetailDto = new TransDetailDto();
transDetailDto.setSite(site);
transDetailDto.setRemark(remark);
transDetailDto.setOrderref1(labelCode); // 标签条码
transDetailDto.setOrderref2(partNo); // 物料编码
transDetailDto.setRemark("标签合并 - 源标签: " + sourceLabelCode + ", 目标标签: " + targetLabelCode);
transDetailDto.setOrderref1(sourceLabelCode); // 标签条码
transDetailDto.setOrderref2(targetLabelCode); // 目标标签条
transDetailDto.setOrderref3(warehouseId); // 仓库ID
// 使用TransHeaderService的genTrans方法生成事务头
TransHeader transHeader = transHeaderService.genTrans(transDetailDto, transType, warehouseId, buNo);
// HB = 合并 (He Bing)
TransHeader transHeader = transHeaderService.genTrans(transDetailDto, "HB", warehouseId, buNo);
if (transHeader == null) {
throw new RuntimeException("生成标签变动事务头记录失败");
throw new RuntimeException("生成标签合并事务头记录失败");
}
logger.info("标签变动事务记录生成成功,事务单号: {}, 标签条码: {}", transHeader.getTransno(), labelCode);
logger.info("标签合并事务头记录生成成功,事务单号: {}", transHeader.getTransno());
// 生成事务明细记录
generateMergeTransactionDetails(transHeader.getTransno(), sourceLabelCode, targetLabelCode, partNo, batchNo, sourceQuantity, targetQuantity, mergedQuantity, site);
logger.info("标签合并事务记录生成完成,事务单号: {}, 源标签: {}, 目标标签: {}",
transHeader.getTransno(), sourceLabelCode, targetLabelCode);
} catch (Exception e) {
logger.error("生成标签变动事务记录失败", e);
logger.error("生成标签合并事务记录失败", e);
// 不抛出异常避免影响主流程
}
}
/**
* 生成标签拆分事务明细记录
*/
private void generateSplitTransactionDetails(String transNo, String originalLabelCode, String newLabelCode,
String partNo, String batchNo, Float splitQuantity, Float remainingQuantity, String site) {
logger.info("开始生成标签拆分事务明细记录,事务单号: {}", transNo);
List<TransDetail> transDetailList = new ArrayList<>();
// 原标签明细记录减少数量
TransDetail originalDetail = new TransDetail();
originalDetail.setSite(site);
originalDetail.setTransno(transNo);
originalDetail.setItemno(1.0);
originalDetail.setPartno(partNo);
originalDetail.setTransqty(new BigDecimal(splitQuantity.toString()));
originalDetail.setBatchno(batchNo);
originalDetail.setDirection("-"); // 减少方向
originalDetail.setOrderref1(originalLabelCode); // 原标签条码
originalDetail.setOrderref2(partNo); // 物料编码
originalDetail.setOrderref3(batchNo); // 批次号
originalDetail.setRemark("标签拆分 - 原标签减少数量: " + splitQuantity);
transDetailList.add(originalDetail);
// 新标签明细记录增加数量
TransDetail newDetail = new TransDetail();
newDetail.setSite(site);
newDetail.setTransno(transNo);
newDetail.setItemno(2.0);
newDetail.setPartno(partNo);
newDetail.setTransqty(new BigDecimal(splitQuantity.toString()));
newDetail.setBatchno(batchNo);
newDetail.setDirection("+"); // 增加方向
newDetail.setOrderref1(newLabelCode); // 新标签条码
newDetail.setOrderref2(partNo); // 物料编码
newDetail.setOrderref3(batchNo); // 批次号
newDetail.setRemark("标签拆分 - 新标签增加数量: " + splitQuantity);
transDetailList.add(newDetail);
// 批量保存事务明细记录
if (!transDetailList.isEmpty()) {
boolean success = transDetailService.saveBatch(transDetailList);
if (!success) {
throw new RuntimeException("标签拆分事务明细记录保存失败");
}
logger.info("标签拆分事务明细记录生成成功,共生成 {} 条明细记录", transDetailList.size());
}
}
/**
* 生成标签合并事务明细记录
*/
private void generateMergeTransactionDetails(String transNo, String sourceLabelCode, String targetLabelCode,
String partNo, String batchNo, Float sourceQuantity, Float targetQuantity, Float mergedQuantity, String site) {
logger.info("开始生成标签合并事务明细记录,事务单号: {}", transNo);
List<TransDetail> transDetailList = new ArrayList<>();
// 目标标签明细记录减少数量 - 被合并掉
TransDetail targetDetail = new TransDetail();
targetDetail.setSite(site);
targetDetail.setTransno(transNo);
targetDetail.setItemno(1.0);
targetDetail.setPartno(partNo);
targetDetail.setTransqty(new BigDecimal(targetQuantity.toString()));
targetDetail.setBatchno(batchNo);
targetDetail.setDirection("-"); // 减少方向
targetDetail.setOrderref1(targetLabelCode); // 目标标签条码
targetDetail.setOrderref2(partNo); // 物料编码
targetDetail.setOrderref3(batchNo); // 批次号
targetDetail.setRemark("标签合并 - 目标标签被合并,数量: " + targetQuantity);
transDetailList.add(targetDetail);
// 源标签明细记录增加合并后的总数量
TransDetail sourceDetail = new TransDetail();
sourceDetail.setSite(site);
sourceDetail.setTransno(transNo);
sourceDetail.setItemno(2.0);
sourceDetail.setPartno(partNo);
sourceDetail.setTransqty(new BigDecimal(mergedQuantity.toString()));
sourceDetail.setBatchno(batchNo);
sourceDetail.setDirection("+"); // 增加方向
sourceDetail.setOrderref1(sourceLabelCode); // 源标签条码
sourceDetail.setOrderref2(partNo); // 物料编码
sourceDetail.setOrderref3(batchNo); // 批次号
sourceDetail.setRemark("标签合并 - 源标签获得合并后总数量: " + mergedQuantity);
transDetailList.add(sourceDetail);
// 批量保存事务明细记录
if (!transDetailList.isEmpty()) {
boolean success = transDetailService.saveBatch(transDetailList);
if (!success) {
throw new RuntimeException("标签合并事务明细记录保存失败");
}
logger.info("标签合并事务明细记录生成成功,共生成 {} 条明细记录", transDetailList.size());
}
}
}

108
src/main/java/com/gaotao/modules/propertyChange/service/impl/PropertyChangeServiceImpl.java

@ -5,8 +5,10 @@ import com.gaotao.common.utils.DateUtils;
import com.gaotao.modules.propertyChange.dao.PropertyChangeMapper;
import com.gaotao.modules.propertyChange.entity.PropertyChangeEntity;
import com.gaotao.modules.propertyChange.service.PropertyChangeService;
import com.gaotao.modules.trans.entity.TransDetail;
import com.gaotao.modules.trans.entity.TransDetailDto;
import com.gaotao.modules.trans.entity.TransHeader;
import com.gaotao.modules.trans.service.TransDetailService;
import com.gaotao.modules.trans.service.TransHeaderService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -14,10 +16,13 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
@ -37,6 +42,9 @@ public class PropertyChangeServiceImpl extends ServiceImpl<PropertyChangeMapper,
@Autowired
private TransHeaderService transHeaderService;
@Autowired
private TransDetailService transDetailService;
private final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
@Override
@ -106,7 +114,8 @@ public class PropertyChangeServiceImpl extends ServiceImpl<PropertyChangeMapper,
}
// 3. 生成标签变动事务记录
generatePropertyChangeTransaction(site, buNo, warehouseId, labelCode, partNo);
generatePropertyChangeTransaction(site, buNo, warehouseId, labelCode, partNo, batchNo, quantity,
oldLocationId, newLocationId, oldProductionDateStr, newProductionDateStr, oldExpiryDateStr, newExpiryDateStr);
logger.info("属性变动保存成功,标签条码: {}", labelCode);
return true;
@ -119,29 +128,122 @@ public class PropertyChangeServiceImpl extends ServiceImpl<PropertyChangeMapper,
/**
* 生成属性变动事务记录
*/
private void generatePropertyChangeTransaction(String site, String buNo, String warehouseId, String labelCode, String partNo) {
private void generatePropertyChangeTransaction(String site, String buNo, String warehouseId, String labelCode, String partNo, String batchNo, Float quantity,
String oldLocationId, String newLocationId, String oldProductionDate, String newProductionDate, String oldExpiryDate, String newExpiryDate) {
logger.info("开始生成属性变动事务记录,标签条码: {}", labelCode);
try {
// 构建变动描述
StringBuilder changeDesc = new StringBuilder("属性变动: ");
if (newLocationId != null && !newLocationId.equals(oldLocationId)) {
changeDesc.append("库位[").append(oldLocationId).append("→").append(newLocationId).append("] ");
}
if (newProductionDate != null && !newProductionDate.equals(oldProductionDate)) {
changeDesc.append("生产日期[").append(oldProductionDate).append("→").append(newProductionDate).append("] ");
}
if (newExpiryDate != null && !newExpiryDate.equals(oldExpiryDate)) {
changeDesc.append("有效期[").append(oldExpiryDate).append("→").append(newExpiryDate).append("] ");
}
// 构建TransDetailDto对象
TransDetailDto transDetailDto = new TransDetailDto();
transDetailDto.setSite(site);
transDetailDto.setRemark(changeDesc.toString());
transDetailDto.setOrderref1(labelCode); // 标签条码
transDetailDto.setOrderref2(partNo); // 物料编码
transDetailDto.setOrderref3(warehouseId); // 仓库ID
// 使用TransHeaderService的genTrans方法生成事务头
// PC = Property Change 属性变动
TransHeader transHeader = transHeaderService.genTrans(transDetailDto, "PC", warehouseId, buNo);
if (transHeader == null) {
throw new RuntimeException("生成属性变动事务头记录失败");
}
logger.info("属性变动事务记录生成成功,事务单号: {}, 标签条码: {}", transHeader.getTransno(), labelCode);
logger.info("属性变动事务头记录生成成功,事务单号: {}", transHeader.getTransno());
// 生成事务明细记录
generatePropertyChangeTransactionDetails(transHeader.getTransno(), labelCode, partNo, batchNo, quantity,
oldLocationId, newLocationId, oldProductionDate, newProductionDate, oldExpiryDate, newExpiryDate, site);
logger.info("属性变动事务记录生成完成,事务单号: {}, 标签条码: {}",
transHeader.getTransno(), labelCode);
} catch (Exception e) {
logger.error("生成属性变动事务记录失败", e);
// 不抛出异常避免影响主流程
}
}
/**
* 生成属性变动事务明细记录
*/
private void generatePropertyChangeTransactionDetails(String transNo, String labelCode, String partNo, String batchNo, Float quantity,
String oldLocationId, String newLocationId, String oldProductionDate, String newProductionDate, String oldExpiryDate, String newExpiryDate, String site) {
logger.info("开始生成属性变动事务明细记录,事务单号: {}", transNo);
List<TransDetail> transDetailList = new ArrayList<>();
double itemNo = 1.0; // 行号从1开始
// 库位变动明细
if (newLocationId != null && !newLocationId.equals(oldLocationId)) {
TransDetail locationDetail = new TransDetail();
locationDetail.setSite(site);
locationDetail.setTransno(transNo);
locationDetail.setItemno(itemNo++);
locationDetail.setPartno(partNo);
locationDetail.setTransqty(new BigDecimal(quantity.toString()));
locationDetail.setBatchno(batchNo);
locationDetail.setDirection("M"); // 移动方向
locationDetail.setOrderref1(labelCode); // 标签条码
locationDetail.setOrderref2("LOCATION"); // 变动类型
locationDetail.setOrderref3(oldLocationId + "→" + newLocationId); // 变动内容
locationDetail.setRemark("库位变动: " + oldLocationId + " → " + newLocationId);
transDetailList.add(locationDetail);
}
// 生产日期变动明细
if (newProductionDate != null && !newProductionDate.equals(oldProductionDate)) {
TransDetail productionDateDetail = new TransDetail();
productionDateDetail.setSite(site);
productionDateDetail.setTransno(transNo);
productionDateDetail.setItemno(itemNo++);
productionDateDetail.setPartno(partNo);
productionDateDetail.setTransqty(new BigDecimal(quantity.toString()));
productionDateDetail.setBatchno(batchNo);
productionDateDetail.setDirection("M"); // 移动方向
productionDateDetail.setOrderref1(labelCode); // 标签条码
productionDateDetail.setOrderref2("PROD_DATE"); // 变动类型
productionDateDetail.setOrderref3((oldProductionDate != null ? oldProductionDate : "空") + "→" + newProductionDate); // 变动内容
productionDateDetail.setRemark("生产日期变动: " + (oldProductionDate != null ? oldProductionDate : "空") + " → " + newProductionDate);
transDetailList.add(productionDateDetail);
}
// 有效期变动明细
if (newExpiryDate != null && !newExpiryDate.equals(oldExpiryDate)) {
TransDetail expiryDateDetail = new TransDetail();
expiryDateDetail.setSite(site);
expiryDateDetail.setTransno(transNo);
expiryDateDetail.setItemno(itemNo++);
expiryDateDetail.setPartno(partNo);
expiryDateDetail.setTransqty(new BigDecimal(quantity.toString()));
expiryDateDetail.setBatchno(batchNo);
expiryDateDetail.setDirection("M"); // 移动方向
expiryDateDetail.setOrderref1(labelCode); // 标签条码
expiryDateDetail.setOrderref2("EXPIRY_DATE"); // 变动类型
expiryDateDetail.setOrderref3((oldExpiryDate != null ? oldExpiryDate : "空") + "→" + newExpiryDate); // 变动内容
expiryDateDetail.setRemark("有效期变动: " + (oldExpiryDate != null ? oldExpiryDate : "空") + " → " + newExpiryDate);
transDetailList.add(expiryDateDetail);
}
// 批量保存事务明细记录
if (!transDetailList.isEmpty()) {
boolean success = transDetailService.saveBatch(transDetailList);
if (!success) {
throw new RuntimeException("属性变动事务明细记录保存失败");
}
logger.info("属性变动事务明细记录生成成功,共生成 {} 条明细记录", transDetailList.size());
}
}
}

7
src/main/java/com/gaotao/modules/trans/service/impl/TransHeaderServiceImpl.java

@ -27,7 +27,6 @@ public class TransHeaderServiceImpl extends ServiceImpl<TransHeaderMapper, Trans
@Transactional
public TransHeader genTrans(TransDetailDto inData,String transType,String warehouseId,String buNo) {
SysUserEntity currentUser = (SysUserEntity) SecurityUtils.getSubject().getPrincipal();
//String transType = "CRT";
// 获取流水号,出错不回滚
TransNoControl transNo = transNoService.getTransNo(inData.getSite(),transType,buNo);
TransHeader transHeader = new TransHeader();
@ -35,15 +34,11 @@ public class TransHeaderServiceImpl extends ServiceImpl<TransHeaderMapper, Trans
transHeader.setTransno(transNo.getNewTransNo());
transHeader.setTransdate(new Date());
transHeader.setTranstypeDb(transType);
// 仓库ID 从哪来
//transHeader.setw(warehouseId);
transHeader.setUserid(currentUser.getUserId().toString());
transHeader.setUsername(currentUser.getUserDisplay());
transHeader.setRemark(inData.getRemark());
transHeader.setOrderref1(inData.getOrderref1());
// 待定 待检验的出入库记录状态为待检验
transHeader.setStatus("C");
//transHeader.setStatus("C");
transHeader.setStatus("已录入");
transHeader.setOrderref2(inData.getOrderref2());
transHeader.setOrderref3(inData.getOrderref3());
transHeader.setEnterdate(new Date());

97
src/main/resources/mapper/crossAreaTransfer/CrossAreaTransferMapper.xml

@ -0,0 +1,97 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.gaotao.modules.crossAreaTransfer.dao.CrossAreaTransferMapper">
<!-- 根据标签条码获取库存信息 -->
<select id="getStockInfoByLabelCode" resultType="map">
SELECT
s.roll_no as label_code,
s.part_no,
s.batch_no,
s.bu_no as buNo,
s.qty_on_hand as quantity,
s.location_id,
s.manufacture_date as production_date,
s.expired_date as expiry_date,
s.orderref1 as order_ref1,
s.orderref2 as order_ref2,
s.status,
w.WareHouseName as warehouse_name
FROM inventory_stock s
LEFT JOIN warehouse w ON s.warehouse_id = w.WareHouseID AND s.site = w.site
WHERE s.roll_no = #{labelCode}
AND s.site = #{site}
AND s.warehouse_id = #{warehouseId}
AND s.status = '在库'
AND s.qty_on_hand > 0
</select>
<!-- 根据库位获取标签列表 -->
<select id="getLabelsByLocation" resultType="map">
SELECT
s.roll_no AS labelCode,
s.part_no AS partNo,
s.bu_no as buNo,
s.qty_on_hand AS quantity,
p.UMID as unit
FROM inventory_stock s
LEFT JOIN Part p ON s.part_no = p.PartNo AND s.site = p.site and s.bu_no = p.bu_no
WHERE s.location_id = #{locationId}
AND s.site = #{site}
AND s.warehouse_id = #{warehouseId}
AND s.status = '在库'
AND s.qty_on_hand > 0
ORDER BY s.roll_no
</select>
<!-- 根据库位获取库存信息列表 -->
<select id="getStockInfoByLocation" resultType="map">
SELECT
s.roll_no as label_code,
s.part_no,
s.batch_no,
s.qty_on_hand as quantity,
s.location_id,
s.manufacture_date as production_date,
s.expired_date as expiry_date,
s.orderref1 as order_ref1,
s.orderref2 as order_ref2,
s.status,
w.WareHouseName as warehouse_name
FROM inventory_stock s
LEFT JOIN warehouse w ON s.warehouse_id = w.WareHouseID AND s.site = w.site
WHERE s.location_id = #{locationId}
AND s.site = #{site}
AND s.warehouse_id = #{warehouseId}
AND s.status = '在库'
AND s.qty_on_hand > 0
ORDER BY s.roll_no
</select>
<!-- 更新库存表的库位和仓库信息(按标签调拨) -->
<update id="updateStockLocationAndWarehouse">
UPDATE inventory_stock
SET location_id = #{targetLocation},
warehouse_id = #{targetWarehouseId},
latest_in_date = #{updateTime}
WHERE roll_no = #{labelCode}
AND location_id = #{sourceLocation}
AND site = #{site}
AND status = '在库'
AND qty_on_hand > 0
</update>
<!-- 批量更新库存表的库位和仓库信息(按库位调拨) -->
<update id="batchUpdateStockLocationAndWarehouse">
UPDATE inventory_stock
SET location_id = #{targetLocation},
warehouse_id = #{targetWarehouseId},
latest_in_date = #{updateTime}
WHERE location_id = #{sourceLocation}
AND site = #{site}
AND status = '在库'
AND qty_on_hand > 0
</update>
</mapper>
Loading…
Cancel
Save