diff --git a/nflg_project_dev/nflg-bom-new/src/main/java/com/nflg/product/bomnew/api/user/ProductionOrderApi.java b/nflg_project_dev/nflg-bom-new/src/main/java/com/nflg/product/bomnew/api/user/ProductionOrderApi.java index 2020ac23..996c009b 100644 --- a/nflg_project_dev/nflg-bom-new/src/main/java/com/nflg/product/bomnew/api/user/ProductionOrderApi.java +++ b/nflg_project_dev/nflg-bom-new/src/main/java/com/nflg/product/bomnew/api/user/ProductionOrderApi.java @@ -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> queryMaterials(@Valid @RequestBody @NotEmpty List query) { + return ResultVO.success(productionOrderService.queryMaterials(query)); + } + + /** + * 手动同步到SAP + * @return + */ + @PostMapping("sync2Sap") + @ApiOperation("手动同步到SAP") + public ResultVO sync2Sap(@RequestBody List rowIds) { + productionOrderService.sync2Sap(rowIds); + return ResultVO.success(); + } + } diff --git a/nflg_project_dev/nflg-bom-new/src/main/java/com/nflg/product/bomnew/job/SaticScheduleTask.java b/nflg_project_dev/nflg-bom-new/src/main/java/com/nflg/product/bomnew/job/SaticScheduleTask.java new file mode 100644 index 00000000..546e41c7 --- /dev/null +++ b/nflg_project_dev/nflg-bom-new/src/main/java/com/nflg/product/bomnew/job/SaticScheduleTask.java @@ -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); + } + +} diff --git a/nflg_project_dev/nflg-bom-new/src/main/java/com/nflg/product/bomnew/pojo/dto/sap/production/ProImportSapParamDTO.java b/nflg_project_dev/nflg-bom-new/src/main/java/com/nflg/product/bomnew/pojo/dto/sap/production/ProImportSapParamDTO.java new file mode 100644 index 00000000..fb0780e8 --- /dev/null +++ b/nflg_project_dev/nflg-bom-new/src/main/java/com/nflg/product/bomnew/pojo/dto/sap/production/ProImportSapParamDTO.java @@ -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 T1; +} diff --git a/nflg_project_dev/nflg-bom-new/src/main/java/com/nflg/product/bomnew/pojo/dto/sap/production/ProT1DTO.java b/nflg_project_dev/nflg-bom-new/src/main/java/com/nflg/product/bomnew/pojo/dto/sap/production/ProT1DTO.java new file mode 100644 index 00000000..238ac7ae --- /dev/null +++ b/nflg_project_dev/nflg-bom-new/src/main/java/com/nflg/product/bomnew/pojo/dto/sap/production/ProT1DTO.java @@ -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; +} diff --git a/nflg_project_dev/nflg-bom-new/src/main/java/com/nflg/product/bomnew/service/ProductionOrderService.java b/nflg_project_dev/nflg-bom-new/src/main/java/com/nflg/product/bomnew/service/ProductionOrderService.java index 3a6d6c58..7c092dd4 100644 --- a/nflg_project_dev/nflg-bom-new/src/main/java/com/nflg/product/bomnew/service/ProductionOrderService.java +++ b/nflg_project_dev/nflg-bom-new/src/main/java/com/nflg/product/bomnew/service/ProductionOrderService.java @@ -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 getListByPage(ProductionOrderQuery query){ - query.setSyncStatus(0); +// query.setSyncStatus(0); Page page = new Page<>(query.getPage(),query.getPageSize()); Page listByPage = this.getBaseMapper().getListByPage(page, query); if (CollUtil.isNotEmpty(listByPage.getRecords())) { @@ -158,7 +172,8 @@ public class ProductionOrderService extends ServiceImpl task1 = CompletableFuture.runAsync(() -> syncChange2Sap(rowId, SessionUtil.getUserCode())); + task1.join(); } } @@ -166,19 +181,117 @@ public class ProductionOrderService extends ServiceImpl itemList = this.productionOrderItemService.lambdaQuery() + .eq(ProductionOrderItemEntity::getOrderRowId, rowId) + .list(); + if (CollUtil.isNotEmpty(itemList)) { +// ProImportSapParamDTO sapParamDTO = new ProImportSapParamDTO(); + List proT1DTOS = new ArrayList<>(); +// sapParamDTO.setT1(proT1DTOS); +// sapParamDTO.setI_AUFNR("0000" + order.getProductionOrder()); + // SAP 原始数据 + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("order_row_id", rowId); + List sapItemList = this.productionOrderItemSapMapper.selectList(queryWrapper); + // 格式:项目号_物料号 + List itemNoMaterialNos = itemList.stream().map(item -> item.getItemNo() + "_" + item.getMaterialNo()).collect(Collectors.toList()); + List 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 intersection = new ArrayList<>(sapItemNoMaterialNos); + intersection.retainAll(itemNoMaterialNos); + // 旧版相对于新版的差集 -> [1,2] + List difference = new ArrayList<>(sapItemNoMaterialNos); + difference.removeAll(itemNoMaterialNos); + // 新版相对于旧版的差集 -> [6,7] + List 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 inputParams = new HashMap<>(); + inputParams.put("I_AUFNR", "0000" + order.getProductionOrder()); + sapReqParams.setInputParams(inputParams); + Map>> inputTables = new HashMap<>(); + List> t1List = new ArrayList<>(); + proT1DTOS.forEach(t1 -> { + t1List.add(Convert.convert(new TypeReference>() { + }, t1)); + }); + inputTables.put("T1", t1List); + sapReqParams.setInputTables(inputTables); + log.info("生产订单同步到SAP数据:{}", JSON.toJSONString(sapReqParams)); + } + return true; } /** @@ -354,4 +467,40 @@ public class ProductionOrderService extends ServiceImpl queryMaterials(List query) { + List datas = new ArrayList<>(); + List 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 rowIds) { + VUtils.isTure(CollUtil.isEmpty(rowIds)).throwMessage("请选择要同步数据"); + rowIds.forEach(rowId -> syncChange2Sap(rowId, SessionUtil.getUserCode())); + } }