成本领料、退料的SAP接口对接

This commit is contained in:
zhangke 2025-08-06 11:37:17 +08:00
parent 1207038de8
commit 1b081162c8
5 changed files with 276 additions and 72 deletions

View File

@ -21,7 +21,6 @@ import org.springframework.stereotype.Component;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;
@Slf4j
@Component
@ -35,6 +34,7 @@ public class SapService {
/**
* 生产订单查询
*
* @param no 生产订单号
*/
public ZWM00MB007DTO zwm00Mb007(String no) {
@ -62,6 +62,7 @@ public class SapService {
/**
* 生产订单收货
*
* @param no 生产订单号
* @param userName 用户名
* @param materials 入库物料列表
@ -104,6 +105,7 @@ public class SapService {
/**
* 查询采购单退库信息
*
* @param orderNo 采购单号
*/
public Zim001QueryResultDTO zim001query(String orderNo) {
@ -303,6 +305,7 @@ public class SapService {
/**
* 获取库存信息
*
* @param factory 工厂编号
* @param warehouseNo 仓库编号
* @param materialNo 物料编号
@ -442,7 +445,6 @@ public class SapService {
JCoTable tOut = function.getTableParameterList().getTable("T_OUT");
log.info("SAP返回: {}", tOut);
List<C_MaterialReturnQueryDTO> result = new ArrayList<>();
// if (out.getString("TYPE").equals("S")) {
for (int i = 0; i < tOut.getNumRows(); i++) {
tOut.setRow(i);
result.add(new C_MaterialReturnQueryDTO()
@ -458,66 +460,233 @@ public class SapService {
return result;
}
// 成本中心退库确认
/**
* 成本中心退库确认接口
* <p>
* 该方法用于调用 SAP RFC 函数 ZWM00_MB112执行成本中心物料退库操作
* 根据传入的请求参数构造输入表和字段并处理返回结果
*
* @param request 请求参数对象包含退库单据号用户信息及物料明细等
* @return C_MaterialReturnDTO 返回结果对象包含生成的物料凭证号MBLNR和年度MJAHR
*/
public C_MaterialReturnDTO zwm00_MB112(C_MaterialReturnQO request) {
// 参数校验
VUtil.trueThrowBusinessError(Objects.isNull(request)).throwMessage("请求参数不能为空");
VUtil.trueThrowBusinessError(CollectionUtil.isEmpty(request.getItems())).throwMessage("物料明细不能为空");
// 构造函数调用所需的输入参数
Map<String, Object> parameters = new HashMap<>();
parameters.put("I_RSNUM", request.getResbRsNum());
parameters.put("I_USNAM", UserUtil.getUserName());
List<C_MaterialReturnItemDTO> t_list1 = new ArrayList<>();
List<C_MaterialReturnSerialItemDTO> t_list2 = new ArrayList<>();
for (C_MaterialReturnItemQO item : request.getItems()) {
if (CollectionUtil.isNotEmpty(item.getScanCodes())) {
List<ScanCodeQO> scanCodeList = item.getScanCodes();
//合并批次数量
Map<String, BigDecimal> batchSummary = scanCodeList.stream()
.collect(Collectors.groupingBy(
ScanCodeQO::getBatchNumber,
Collectors.reducing(BigDecimal.ZERO, ScanCodeQO::getCodeNum, BigDecimal::add)
));
for (Map.Entry<String, BigDecimal> entry : batchSummary.entrySet()) {
t_list1.add(new C_MaterialReturnItemDTO()
.setMatnr(item.getResbMatnr())
.setRspos(item.getResbRspos())
.setLgort(item.getResbLgort())
.setMeins(item.getResbMeins())
.setWerks(item.getResbWerks())
.setCharg(entry.getKey())
.setErfmg(String.valueOf(entry.getValue()))
);
}
for (ScanCodeQO scanCode : scanCodeList) {
t_list2.add(new C_MaterialReturnSerialItemDTO()
.setRspos(item.getResbRspos())
.setSernr(scanCode.getSerialNumber())
.setFlag("X")
);
}
}
}
parameters.put("T_LIST1", t_list1);
parameters.put("T_LIST2", t_list2);
// 构造函数调用所需的输入表结构 T_LIST1 T_LIST2
List<Map<String, Object>> t_list1 = new ArrayList<>();
List<Map<String, Object>> t_list2 = new ArrayList<>();
JCoFunction function = exec("ZWM00_MB112", parameters, null);
JCoTable tOut = function.getTableParameterList().getTable("T_OUT");
log.info("SAP返回: {}", tOut);
// 遍历请求中的物料明细项填充表数据
request.getItems().forEach(item -> {
if (Objects.nonNull(item.getScanCodes()) && CollectionUtil.isNotEmpty(item.getScanCodes())) {
// 如果存在扫码信息则按扫码记录逐条构造表数据
item.getScanCodes().forEach(scanCode -> {
Map<String, Object> map = buildMb112TList1Map(item, scanCode.getCodeNum(), scanCode.getBatchNumber());
t_list1.add(map);
Map<String, Object> map1 = buildMb112TList2Map(item.getResbRspos(), scanCode.getSerialNumber());
t_list2.add(map1);
});
} else {
// 无扫码信息时使用默认值构造表数据
Map<String, Object> map = buildMb112TList1Map(item, item.getErfmg(), "");
t_list1.add(map);
}
});
// 将构造好的表数据放入输入参数中
Map<String, List<Map<String, Object>>> tables = new HashMap<>();
if (CollectionUtil.isNotEmpty(t_list1)) {
tables.put("T_LIST1", t_list1);
}
if (CollectionUtil.isNotEmpty(t_list2)) {
tables.put("T_LIST2", t_list2);
}
// 调用 SAP RFC 函数 ZWM00_MB112
JCoFunction function = exec("ZWM00_MB112", parameters, tables);
// 处理返回表 T_RETURN判断执行是否成功
JCoTable returnTable = function.getTableParameterList().getTable("T_RETURN");
VUtil.trueThrowBusinessError(returnTable.getNumRows() <= 0).throwMessage("获取Type信息有误");
returnTable.setRow(0);
VUtil.trueThrowBusinessError(StrUtil.equals(returnTable.getString("E_TYPE"), "E"))
.throwMessage(returnTable.getString("E_MSG"));
log.info("SAP返回: {}", returnTable);
// 获取导出参数构造返回结果对象
JCoParameterList exportParam = function.getExportParameterList();
VUtil.trueThrowBusinessError(Objects.isNull(exportParam)).throwMessage("无法获取到有效的物料凭证信息");
C_MaterialReturnDTO result = new C_MaterialReturnDTO()
.setEMblnr(tOut.getString("E_MBLNR"))
.setEMJahr(tOut.getString("E_MJAHR"));
.setEMblnr(exportParam.getString("E_MBLNR"))
.setEMJahr(exportParam.getString("E_MJAHR"));
return null;
log.info("SAP返回物料凭证信息: MBLNR={}, MJAHR={}", result.getEMblnr(), result.getEMJahr());
return result;
}
// 提取构造 T_LIST1 表项的方法
private Map<String, Object> buildMb112TList1Map(C_MaterialReturnItemQO item, BigDecimal erFmg, String charg) {
Map<String, Object> map = new HashMap<>(8); // 预设容量避免频繁扩容
map.put("RSPOS", item.getResbRspos());
map.put("MATNR", item.getResbMatnr());
map.put("ERFMG", erFmg);
map.put("MEINS", item.getResbMeins());
map.put("WERKS", item.getResbWerks());
map.put("LGORT", item.getResbLgort());
map.put("CHARG", charg);
return map;
}
// 提取构造 T_LIST2 表项的方法
private Map<String, Object> buildMb112TList2Map(String rspos, String sernr) {
Map<String, Object> map = new HashMap<>(4);
map.put("RSPOS", rspos);
map.put("SERNR", sernr);
map.put("FLAG", "X");
return map;
}
/**
* 成本中心领料查询接口
* <p>
* 根据预留单号resebRsNum调用SAP的RFC函数ZWM00_MB026查询对应的成本中心领料信息
* 包括领料主记录和明细清单并封装为C_MaterialOutboundQueryDTO对象返回
*
* @param resebRsNum 预留单号不能为空
* @return C_MaterialOutboundQueryDTO 领料查询结果数据传输对象包含主信息和明细列表
* @throws BusinessException 当参数为空或SAP返回数据异常时抛出业务异常
*/
//成本中心领料查询
public C_MaterialOutboundQueryDTO zwm00_MB026(String resebRsNum) {
// 参数校验
VUtil.trueThrowBusinessError(resebRsNum == null || resebRsNum.isEmpty()).throwMessage("请求参数不能为空");
Map<String, Object> parameters = new HashMap<>();
parameters.put("I_KOSTL", resebRsNum);
JCoFunction function = exec("ZWM00_MB026", parameters, null);
return null;
// 获取主信息表 T_OUT 并校验
JCoTable tOut = function.getTableParameterList().getTable("T_OUT");
VUtil.trueThrowBusinessError(tOut == null || tOut.getRow() <= 0).throwMessage("预留单号获取失败");
tOut.setRow(0);
C_MaterialOutboundQueryDTO result = new C_MaterialOutboundQueryDTO()
.setResbRsnum(tOut.getString("RSNUM"))
.setWempf(tOut.getString("WEMPF"));
// 获取领料清单表 T_LIST 并校验
JCoTable tList = function.getTableParameterList().getTable("T_LIST");
VUtil.trueThrowBusinessError(tList == null || tList.getRow() <= 0).throwMessage("领料清单获取失败");
log.info("SAP返回领料清单: {}", tList);
// 封装领料明细项列表
List<C_MaterialOutboundItemQueryDTO> outboundItems = new ArrayList<>();
for (int i = 0; i < tList.getNumRows(); i++) {
tList.setRow(i);
C_MaterialOutboundItemQueryDTO item = new C_MaterialOutboundItemQueryDTO()
.setResbRsnum(tList.getString("RSNUM"))
.setResbRspos(tList.getString("RSPOS"))
.setMaktx(tList.getString("MAKTX"))
.setResbMatnr(tList.getString("MATNR"))
.setWqyls(tList.getBigDecimal("WQYLS"))
.setResbWerks(tList.getString("WERKS"))
.setResbLgort(tList.getString("LGORT"))
.setResbMeins(tList.getString("MEINS"));
outboundItems.add(item);
}
result.setItems(outboundItems);
return result;
}
public C_MaterialOutboundDTO ZWM00_MB115(C_MaterialOutboundQO request) {
return null;
VUtil.trueThrowBusinessError(CollectionUtil.isEmpty(request.getItems())).throwMessage("物料明细不能为空");
// 构造函数调用所需的输入参数
Map<String, Object> parameters = new HashMap<>();
parameters.put("I_RSNUM", request.getResbRsNum());
parameters.put("I_USNAM", UserUtil.getUserName());
// 构造函数调用所需的输入表结构 T_LIST1 T_LIST2
List<Map<String, Object>> t_list1 = new ArrayList<>();
List<Map<String, Object>> t_list2 = new ArrayList<>();
// 遍历请求中的物料明细项填充表数据
request.getItems().forEach(item -> {
if (Objects.nonNull(item.getScanCodes()) && CollectionUtil.isNotEmpty(item.getScanCodes())) {
// 如果存在扫码信息则按扫码记录逐条构造表数据
item.getScanCodes().forEach(scanCode -> {
Map<String, Object> map = buildMb115TList1Map(item, scanCode.getCodeNum(), scanCode.getBatchNumber());
t_list1.add(map);
Map<String, Object> map1 = buildMb115TList2Map(item.getResbRspos(), scanCode.getSerialNumber());
t_list2.add(map1);
});
} else {
// 无扫码信息时使用默认值构造表数据
Map<String, Object> map = buildMb115TList1Map(item, item.getQty(), "");
t_list1.add(map);
}
});
// 将构造好的表数据放入输入参数中
Map<String, List<Map<String, Object>>> tables = new HashMap<>();
if (CollectionUtil.isNotEmpty(t_list1)) {
tables.put("T_LIST1", t_list1);
}
if (CollectionUtil.isNotEmpty(t_list2)) {
tables.put("T_LIST2", t_list2);
}
// 调用 SAP RFC 函数 ZWM00_MB112
JCoFunction function = exec("ZWM00_MB115", parameters, tables);
// 处理返回表 T_RETURN判断执行是否成功
JCoTable returnTable = function.getTableParameterList().getTable("T_RETURN");
VUtil.trueThrowBusinessError(returnTable.getNumRows() <= 0).throwMessage("获取Type信息有误");
returnTable.setRow(0);
VUtil.trueThrowBusinessError(StrUtil.equals(returnTable.getString("E_TYPE"), "E"))
.throwMessage(returnTable.getString("E_MSG"));
log.info("SAP返回: {}", returnTable);
// 获取导出参数构造返回结果对象
JCoParameterList exportParam = function.getExportParameterList();
VUtil.trueThrowBusinessError(Objects.isNull(exportParam)).throwMessage("无法获取到有效的物料凭证信息");
C_MaterialOutboundDTO result = new C_MaterialOutboundDTO()
.setEMblnr(exportParam.getString("E_MBLNR"))
.setEMJahr(exportParam.getString("E_MJAHR"));
log.info("SAP返回物料凭证信息: MBLNR={}, MJAHR={}", result.getEMblnr(), result.getEMJahr());
return result;
}
// 提取构造 T_LIST1 表项的方法
private Map<String, Object> buildMb115TList1Map(C_MaterialOutboundItemQO item, BigDecimal erFmg, String charg) {
Map<String, Object> map = new HashMap<>(8); // 预设容量避免频繁扩容
map.put("RSPOS", item.getResbRspos());
map.put("MATNR", item.getResbMatnr());
map.put("ERFMG", erFmg);
map.put("MEINS", item.getResbMeins());
map.put("WERKS", item.getResbWerks());
map.put("LGORT", item.getResbLgort());
map.put("CHARG", charg);
return map;
}
// 提取构造 T_LIST2 表项的方法
private Map<String, Object> buildMb115TList2Map(String rspos, String sernr) {
Map<String, Object> map = new HashMap<>(4);
map.put("RSPOS", rspos);
map.put("SERNR", sernr);
map.put("FLAG", "X");
return map;
}

View File

@ -20,4 +20,38 @@ public class SapMetaPrintTest {
public void ZWM00_MB107(){
sapService.printMeta("ZWM00_MB107");
}
@Test
public void ZWM00_MB017()
{
sapService.printMeta("ZWM00_MB017");
}
@Test
public void execZwm00_MB017()
{
sapService.zwm00_MB017("1309976");
}
@Test
public void ZWM00_MB112()
{
sapService.printMeta("ZWM00_MB112");
}
@Test
public void ZWM00_MB026()
{
sapService.printMeta("ZWM00_MB026");
}
@Test
public void ZWM00_MB115()
{
sapService.printMeta("ZWM00_MB115");
}
}

View File

@ -8,10 +8,14 @@ import java.util.List;
@Data
@Accessors(chain = true)
public class C_MaterialOutboundQueryDTO {
/**
* 预留/相关需求的编号
*/
private String resbRsnum;
// 预留项目号 RKPF-WEMPF
private String rkpfWempf;
/*** 预留项目号 RKPF-WEMPF*/
private String wempf;
//领料明细
private List<C_MaterialOutboundItemQueryDTO> items;

View File

@ -33,7 +33,7 @@ public class C_MaterialOutboundItemQO {
*/
private BigDecimal qty;
// 实际出库数量
// 出库需求数量
private BigDecimal resbErfmg;
//扫码信息

View File

@ -10,9 +10,6 @@ import java.util.List;
public class C_MaterialOutboundQO {
//预留号
private String resbRsNum;
// 工位
private String rkpfWempf;
// 预留单退料详情信息
private List<C_MaterialOutboundItemQO> items;
}