【生产订单管理】

This commit is contained in:
10001392 2024-09-04 16:42:44 +08:00
parent 6e9466004b
commit 8447cf9ad9
5 changed files with 275 additions and 15 deletions

View File

@ -4,6 +4,8 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
import com.nflg.product.base.core.api.BaseApi;
import com.nflg.product.bomnew.pojo.query.ProductionOrderQuery;
import com.nflg.product.bomnew.pojo.query.ProductionOrderSaveQuery;
import com.nflg.product.bomnew.pojo.query.QueryMaterialsQuery;
import com.nflg.product.bomnew.pojo.vo.EbomQueryMaterialsVO;
import com.nflg.product.bomnew.pojo.vo.ProductionOrderItemVO;
import com.nflg.product.bomnew.pojo.vo.ProductionOrderVO;
import com.nflg.product.bomnew.service.ProductionOrderService;
@ -14,6 +16,7 @@ import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.validation.Valid;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.List;
@ -113,4 +116,26 @@ public class ProductionOrderApi extends BaseApi {
return productionOrderService.syncProductionOrderFromSap(query);
}
/**
* 批量查询物料信息
* @param query query
* @return 物料信息
*/
@PostMapping("queryMaterials")
@ApiOperation("批量查询物料信息")
public ResultVO<List<EbomQueryMaterialsVO>> queryMaterials(@Valid @RequestBody @NotEmpty List<QueryMaterialsQuery> query) {
return ResultVO.success(productionOrderService.queryMaterials(query));
}
/**
* 手动同步到SAP
* @return
*/
@PostMapping("sync2Sap")
@ApiOperation("手动同步到SAP")
public ResultVO<String> sync2Sap(@RequestBody List<Long> rowIds) {
productionOrderService.sync2Sap(rowIds);
return ResultVO.success();
}
}

View File

@ -0,0 +1,35 @@
package com.nflg.product.bomnew.job;
import cn.hutool.core.date.LocalDateTimeUtil;
import com.nflg.product.bomnew.pojo.query.ProductionOrderQuery;
import com.nflg.product.bomnew.service.ProductionOrderService;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import javax.annotation.Resource;
import java.time.LocalDateTime;
/**
* 定时任务
*/
@Configuration
@EnableScheduling
public class SaticScheduleTask {
@Resource
private ProductionOrderService productionOrderService;
/**
* 每天2点自动同步前一天SAP生产订单
*/
@Scheduled(cron = "${bom.production.sync.sap.time:0 0 2 * * ?}")
public void syncProductionOrderFromSap() {
ProductionOrderQuery query = new ProductionOrderQuery();
String date = LocalDateTimeUtil.format(LocalDateTime.now().plusDays(-1), "yyyy-MM-dd");
query.setStartDate(date);
query.setEndDate(date);
productionOrderService.syncProductionOrderFromSap(query);
}
}

View File

@ -0,0 +1,15 @@
package com.nflg.product.bomnew.pojo.dto.sap.production;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.List;
@Data
public class ProImportSapParamDTO {
@ApiModelProperty("生产订单")
private String I_AUFNR;
@ApiModelProperty("详情")
private List<ProT1DTO> T1;
}

View File

@ -0,0 +1,36 @@
package com.nflg.product.bomnew.pojo.dto.sap.production;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
public class ProT1DTO {
/**
* 项目 POSNR
* 组件 MATNR
* 需求数量 BDMNG
* 单位 MEINS
* 存储地点 LGORT
* 反冲
* 操作类型 OTYPE
*/
@ApiModelProperty("项目")
private String POSNR;
@ApiModelProperty("组件")
private String MATNR;
@ApiModelProperty("需求数量")
private String BDMNG;
@ApiModelProperty("单位")
private String MEINS;
@ApiModelProperty("LGORT")
private String LGORT;
@ApiModelProperty("操作类型 0不变 1新增 2修改 3删除")
private String OTYPE;
}

View File

@ -5,7 +5,10 @@ import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.convert.Converter;
import cn.hutool.core.lang.TypeReference;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
@ -14,30 +17,41 @@ import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.nflg.product.base.core.conmon.util.SessionUtil;
import com.nflg.product.bomnew.mapper.master.MaterialMainMapper;
import com.nflg.product.bomnew.mapper.master.ProductionOrderItemSapMapper;
import com.nflg.product.bomnew.mapper.master.ProductionOrderMapper;
import com.nflg.product.bomnew.mapper.master.ProductionOrderSapMapper;
import com.nflg.product.bomnew.pojo.dto.sap.SapReqParams;
import com.nflg.product.bomnew.pojo.dto.sap.SapResult;
import com.nflg.product.bomnew.pojo.dto.sap.production.ProImportSapParamDTO;
import com.nflg.product.bomnew.pojo.dto.sap.production.ProT1DTO;
import com.nflg.product.bomnew.pojo.entity.ProductionOrderEntity;
import com.nflg.product.bomnew.pojo.entity.ProductionOrderItemEntity;
import com.nflg.product.bomnew.pojo.entity.ProductionOrderItemSapEntity;
import com.nflg.product.bomnew.pojo.entity.ProductionOrderSapEntity;
import com.nflg.product.bomnew.pojo.query.ProductionOrderQuery;
import com.nflg.product.bomnew.pojo.query.ProductionOrderSaveQuery;
import com.nflg.product.bomnew.pojo.query.QueryMaterialsQuery;
import com.nflg.product.bomnew.pojo.vo.BaseMaterialVO;
import com.nflg.product.bomnew.pojo.vo.EbomQueryMaterialsVO;
import com.nflg.product.bomnew.pojo.vo.ProductionOrderItemVO;
import com.nflg.product.bomnew.pojo.vo.ProductionOrderVO;
import com.nflg.product.bomnew.util.VUtils;
import lombok.extern.slf4j.Slf4j;
import nflg.product.common.constant.STATE;
import nflg.product.common.vo.ResultVO;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.stream.Collectors;
@ -60,7 +74,7 @@ public class ProductionOrderService extends ServiceImpl<ProductionOrderMapper, P
private ProductionOrderItemSapMapper productionOrderItemSapMapper;
public IPage<ProductionOrderVO> getListByPage(ProductionOrderQuery query){
query.setSyncStatus(0);
// query.setSyncStatus(0);
Page<ProductionOrderQuery> page = new Page<>(query.getPage(),query.getPageSize());
Page<ProductionOrderVO> listByPage = this.getBaseMapper().getListByPage(page, query);
if (CollUtil.isNotEmpty(listByPage.getRecords())) {
@ -158,7 +172,8 @@ public class ProductionOrderService extends ServiceImpl<ProductionOrderMapper, P
this.updateById(updateEntity);
// 计划已确认自动提交到AP
if (confirmStatus == 3) {
syncChange2Sap(rowId);
CompletableFuture<Void> task1 = CompletableFuture.runAsync(() -> syncChange2Sap(rowId, SessionUtil.getUserCode()));
task1.join();
}
}
@ -166,13 +181,14 @@ public class ProductionOrderService extends ServiceImpl<ProductionOrderMapper, P
* 生产订单变更提交到SAP
* @param rowId
*/
private void syncChange2Sap(Long rowId) {
// TODO
@Transactional(rollbackFor = Exception.class)
public void syncChange2Sap(Long rowId, String updateBy) {
if (doSyncChange2Sap(rowId)) {
ProductionOrderEntity updateEntity = new ProductionOrderEntity();
updateEntity.setRowId(rowId);
updateEntity.setEditStatus(2);
updateEntity.setSyncStatus(1); // 已同步
updateEntity.setUpdatedBy(SessionUtil.getUserCode());
updateEntity.setUpdatedBy(updateBy);
updateEntity.setUpdatedTime(LocalDateTime.now());
this.updateById(updateEntity);
ProductionOrderSapEntity updateSapEntity = new ProductionOrderSapEntity();
@ -180,6 +196,103 @@ public class ProductionOrderService extends ServiceImpl<ProductionOrderMapper, P
updateSapEntity.setSyncStatus(1); // 已同步
this.productionOrderSapMapper.updateById(updateSapEntity);
}
}
private boolean doSyncChange2Sap(Long rowId) {
ProductionOrderEntity order = this.getById(rowId);
if (ObjectUtil.isEmpty(order)) {
return false;
}
List<ProductionOrderItemEntity> itemList = this.productionOrderItemService.lambdaQuery()
.eq(ProductionOrderItemEntity::getOrderRowId, rowId)
.list();
if (CollUtil.isNotEmpty(itemList)) {
// ProImportSapParamDTO sapParamDTO = new ProImportSapParamDTO();
List<ProT1DTO> proT1DTOS = new ArrayList<>();
// sapParamDTO.setT1(proT1DTOS);
// sapParamDTO.setI_AUFNR("0000" + order.getProductionOrder());
// SAP 原始数据
QueryWrapper<ProductionOrderItemSapEntity> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("order_row_id", rowId);
List<ProductionOrderItemSapEntity> sapItemList = this.productionOrderItemSapMapper.selectList(queryWrapper);
// 格式项目号_物料号
List<String> itemNoMaterialNos = itemList.stream().map(item -> item.getItemNo() + "_" + item.getMaterialNo()).collect(Collectors.toList());
List<String> sapItemNoMaterialNos = sapItemList.stream().map(item -> item.getPOSNR() + "_" + item.getMATNR().replaceAll("^0+", "")).collect(Collectors.toList());
// 假设旧版 [1,2,3,4,5] 新版 [3,4,5,6,7]
// 旧版和新版的交集 -> [3,4,5]
List<String> intersection = new ArrayList<>(sapItemNoMaterialNos);
intersection.retainAll(itemNoMaterialNos);
// 旧版相对于新版的差集 -> [1,2]
List<String> difference = new ArrayList<>(sapItemNoMaterialNos);
difference.removeAll(itemNoMaterialNos);
// 新版相对于旧版的差集 -> [6,7]
List<String> difference2 = new ArrayList<>(itemNoMaterialNos);
difference2.removeAll(sapItemNoMaterialNos);
// SAP物料操作类型有4种0不变 1新增 2修改 3删除
// 两个差集认为 difference2 的物料是增加difference 的物料是减少
for (String add : difference2) {
ProductionOrderItemEntity addItem = itemList.stream().filter(item -> add.equals(item.getItemNo() + "_" + item.getMaterialNo())).findFirst().orElse(null);
if (ObjectUtil.isNotEmpty(addItem)) {
ProT1DTO proT1DTO = new ProT1DTO();
proT1DTO.setPOSNR(addItem.getItemNo());
proT1DTO.setMATNR("00000000" + addItem.getMaterialNo());
proT1DTO.setBDMNG(addItem.getCommandNum().toString());
proT1DTO.setMEINS(addItem.getUnit());
proT1DTO.setLGORT(addItem.getStorage());
proT1DTO.setOTYPE("1");
proT1DTOS.add(proT1DTO);
}
}
for (String remove : difference) {
ProductionOrderItemSapEntity removeItem = sapItemList.stream().filter(item -> remove.equals(item.getPOSNR() + "_" + item.getMATNR().replaceAll("^0+", ""))).findFirst().orElse(null);
if (ObjectUtil.isNotEmpty(removeItem)) {
ProT1DTO proT1DTO = new ProT1DTO();
proT1DTO.setPOSNR(removeItem.getPOSNR());
proT1DTO.setMATNR(removeItem.getMATNR());
proT1DTO.setBDMNG(removeItem.getBDMNG());
proT1DTO.setMEINS(removeItem.getMEINS());
proT1DTO.setLGORT(removeItem.getLGORT());
proT1DTO.setOTYPE("3");
proT1DTOS.add(proT1DTO);
}
}
// 遍历交集如果旧版和新版物料的 需求数量单位存储地点反冲 有一个字段值不一致则认为是物料修改否则是物料不变
for (String entity : intersection) {
ProductionOrderItemEntity dbItem = itemList.stream().filter(item -> entity.equals(item.getItemNo() + "_" + item.getMaterialNo())).findFirst().orElse(null);
ProductionOrderItemSapEntity sapItem = sapItemList.stream().filter(item -> entity.equals(item.getPOSNR() + "_" + item.getMATNR().replaceAll("^0+", ""))).findFirst().orElse(null);
ProT1DTO proT1DTO = new ProT1DTO();
proT1DTO.setPOSNR(dbItem.getItemNo());
proT1DTO.setMATNR("00000000" + dbItem.getMaterialNo());
proT1DTO.setBDMNG(dbItem.getCommandNum().toString());
proT1DTO.setMEINS(dbItem.getUnit());
proT1DTO.setLGORT(dbItem.getStorage());
proT1DTO.setOTYPE("0");
if (dbItem.getCommandNum().compareTo(new BigDecimal(sapItem.getBDMNG())) != 0
|| !dbItem.getUnit().equals(sapItem.getMEINS())
|| !dbItem.getStorage().equals(sapItem.getLGORT())
// || TODO 反冲
) {
proT1DTO.setOTYPE("2");
}
proT1DTOS.add(proT1DTO);
}
SapReqParams sapReqParams = new SapReqParams();
sapReqParams.setFunName("");
Map<String, Object> inputParams = new HashMap<>();
inputParams.put("I_AUFNR", "0000" + order.getProductionOrder());
sapReqParams.setInputParams(inputParams);
Map<String, List<Map<String, String>>> inputTables = new HashMap<>();
List<Map<String, String>> t1List = new ArrayList<>();
proT1DTOS.forEach(t1 -> {
t1List.add(Convert.convert(new TypeReference<Map<String, String>>() {
}, t1));
});
inputTables.put("T1", t1List);
sapReqParams.setInputTables(inputTables);
log.info("生产订单同步到SAP数据{}", JSON.toJSONString(sapReqParams));
}
return true;
}
/**
* 从SAP获取生产订单
@ -354,4 +467,40 @@ public class ProductionOrderService extends ServiceImpl<ProductionOrderMapper, P
}
return ResultVO.success();
}
public List<EbomQueryMaterialsVO> queryMaterials(List<QueryMaterialsQuery> query) {
List<BaseMaterialVO> datas = new ArrayList<>();
List<String> keys = query.stream().map(QueryMaterialsQuery::getMaterialNo)
.filter(StrUtil::isNotBlank)
.distinct()
.collect(Collectors.toList());
if (CollUtil.isNotEmpty(keys)) {
datas.addAll(SpringUtil.getBean(MaterialMainMapper.class).getMaterialBaseInfo(keys));
}
return query.stream().map(q -> {
BaseMaterialVO mVO = datas.stream()
.filter(m -> StrUtil.isNotBlank(q.getMaterialNo()) ? StrUtil.equals(m.getMaterialNo(), q.getMaterialNo())
: StrUtil.equals(m.getDrawingNo(), q.getDrawingNo()))
.findFirst()
.orElse(null);
EbomQueryMaterialsVO vo = new EbomQueryMaterialsVO();
vo.setOrderNumber(q.getOrderNumber());
vo.setMaterialNo(q.getMaterialNo());
if (Objects.nonNull(mVO)) {
vo.setMaterialNo(mVO.getMaterialNo());
vo.setMaterialName(mVO.getMaterialName());
vo.setMaterialDesc(mVO.getMaterialDesc());
}
return vo;
}).collect(Collectors.toList());
}
/**
* 手动同步到SAP
* @param rowIds
*/
public void sync2Sap(List<Long> rowIds) {
VUtils.isTure(CollUtil.isEmpty(rowIds)).throwMessage("请选择要同步数据");
rowIds.forEach(rowId -> syncChange2Sap(rowId, SessionUtil.getUserCode()));
}
}