Explorar o código

pms功能优化 功能优化

zhangcl hai 3 meses
pai
achega
a0464bb999
Modificáronse 43 ficheiros con 1271 adicións e 32 borrados
  1. 1 1
      yudao-module-pms/yudao-module-pms-api/src/main/java/cn/iocoder/yudao/module/pms/enums/ErrorCodeConstant.java
  2. 9 0
      yudao-module-pms/yudao-module-pms-biz/pom.xml
  3. 13 3
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotbom/IotBomController.java
  4. 4 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotbom/vo/IotBomRespVO.java
  5. 9 2
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotmainworkorder/IotMainWorkOrderController.java
  6. 93 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotsappickinglist/IotSapPickingListController.java
  7. 89 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotsappickinglist/vo/IotSapPickingListPageReqVO.java
  8. 108 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotsappickinglist/vo/IotSapPickingListRespVO.java
  9. 79 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotsappickinglist/vo/IotSapPickingListSaveReqVO.java
  10. 5 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotsapstock/vo/IotSapStockPageReqVO.java
  11. 1 3
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/stat/IotStaticController.java
  12. 117 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/dal/dataobject/iotsappickinglist/IotSapPickingListDO.java
  13. 4 2
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/dal/mysql/iotbom/IotBomMapper.java
  14. 12 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/dal/mysql/iotcommonbommaterial/IotCommonBomMaterialMapper.java
  15. 5 2
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/dal/mysql/iotdevicecategorytemplate/IotDeviceCategoryTemplateMapper.java
  16. 5 2
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/dal/mysql/iotmainworkorder/IotMainWorkOrderMapper.java
  17. 1 1
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/dal/mysql/iotmaterial/IotMaterialMapper.java
  18. 45 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/dal/mysql/iotsappickinglist/IotSapPickingListMapper.java
  19. 8 4
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/dal/mysql/iotsapstock/IotSapStockMapper.java
  20. 125 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/job/sap/SyncSapPickingListJob.java
  21. 18 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/sap/SapConfig.java
  22. 47 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/sap/SapConnector.java
  23. 214 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/sap/SapController.java
  24. 3 4
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/IotProductClassifyService.java
  25. 11 5
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotbom/IotBomServiceImpl.java
  26. 1 1
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotcommonbommaterial/IotCommonBomMaterialServiceImpl.java
  27. 15 1
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotdevicecategorytemplate/IotDeviceCategoryTemplateServiceImpl.java
  28. 8 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotmainworkorder/IotMainWorkOrderService.java
  29. 6 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotmainworkorder/IotMainWorkOrderServiceImpl.java
  30. 55 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotsappickinglist/IotSapPickingListService.java
  31. 71 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotsappickinglist/IotSapPickingListServiceImpl.java
  32. BIN=BIN
      yudao-module-pms/yudao-module-pms-biz/src/main/resources/lib/librfccm.so
  33. BIN=BIN
      yudao-module-pms/yudao-module-pms-biz/src/main/resources/lib/libsapjco3.so
  34. BIN=BIN
      yudao-module-pms/yudao-module-pms-biz/src/main/resources/lib/libsapjcorfc.so
  35. BIN=BIN
      yudao-module-pms/yudao-module-pms-biz/src/main/resources/lib/sapjco3.dll
  36. BIN=BIN
      yudao-module-pms/yudao-module-pms-biz/src/main/resources/lib/sapjco3.jar
  37. BIN=BIN
      yudao-module-pms/yudao-module-pms-biz/src/main/resources/lib/sapjcorfc.dll
  38. 12 0
      yudao-module-pms/yudao-module-pms-biz/src/main/resources/mapper/static/IotMainWorkOrderMapper.xml
  39. 2 0
      yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/saporg/SapOrgApi.java
  40. 6 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/saporg/SapOrgApiImpl.java
  41. 45 0
      yudao-server/pom.xml
  42. 12 0
      yudao-server/src/main/resources/application-dev.yaml
  43. 12 1
      yudao-server/src/main/resources/application-local.yaml

+ 1 - 1
yudao-module-pms/yudao-module-pms-api/src/main/java/cn/iocoder/yudao/module/pms/enums/ErrorCodeConstant.java

@@ -56,5 +56,5 @@ public interface ErrorCodeConstant{
     ErrorCode IOT_MAINTAIN_BOM_NOT_EXISTS = new ErrorCode(145, "维修工单对应维修项BOM不存在");
     ErrorCode THINGS_MODEL_NOT_EXISTS = new ErrorCode(146, "物模型不存在");
     ErrorCode IOT_MAINTAIN_BOMS_NOT_EXISTS = new ErrorCode(147, "请选择维修工单对应BOM");
-
+    ErrorCode IOT_SAP_PICKING_LIST_NOT_EXISTS = new ErrorCode(147, "PMS SAP 领料单不存在");
 }

+ 9 - 0
yudao-module-pms/yudao-module-pms-biz/pom.xml

@@ -67,6 +67,15 @@
             <scope>compile</scope>
         </dependency>
 
+        <!-- SAP接口相关 -->
+        <dependency>
+            <groupId>com.sap</groupId>
+            <artifactId>sapjco3</artifactId>
+            <version>3.0.12</version>
+            <scope>system</scope>
+            <systemPath>${project.basedir}/src/main/resources/lib/sapjco3.jar</systemPath>
+        </dependency>
+
         <!--TDEngine相关配置-->
         <!--pom.xml-->
         <dependency>

+ 13 - 3
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotbom/IotBomController.java

@@ -8,13 +8,14 @@ import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
 import cn.iocoder.yudao.framework.common.pojo.PageParam;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
 import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
 import cn.iocoder.yudao.module.pms.controller.admin.iotbom.vo.*;
 import cn.iocoder.yudao.module.pms.controller.admin.iotcommonbommaterial.vo.IotCommonBomMaterialSaveReqVO;
+import cn.iocoder.yudao.module.pms.dal.dataobject.IotProductClassifyDO;
 import cn.iocoder.yudao.module.pms.dal.dataobject.iotbom.IotBomDO;
 import cn.iocoder.yudao.module.pms.dal.dataobject.iotcommonbommaterial.IotCommonBomMaterialDO;
+import cn.iocoder.yudao.module.pms.service.IotProductClassifyService;
 import cn.iocoder.yudao.module.pms.service.iotbom.IotBomService;
 import cn.iocoder.yudao.module.pms.service.iotcommonbommaterial.IotCommonBomMaterialService;
 import io.swagger.v3.oas.annotations.Operation;
@@ -28,11 +29,15 @@ import javax.annotation.Resource;
 import javax.servlet.http.HttpServletResponse;
 import javax.validation.Valid;
 import java.io.IOException;
-import java.util.*;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 import java.util.stream.Collectors;
 
 import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
 
 @Tag(name = "管理后台 - PMS BOM 关系")
 @RestController
@@ -44,6 +49,8 @@ public class IotBomController {
     private IotBomService iotBomService;
     @Resource
     private IotCommonBomMaterialService iotCommonBomMaterialService;
+    @Resource
+    private IotProductClassifyService iotProductClassifyService;
 
     @PostMapping("/create")
     @Operation(summary = "创建PMS BOM 关系")
@@ -109,7 +116,6 @@ public class IotBomController {
         List<Long> bomNodeIds = list.stream()
                 .map(IotBomDO::getId)
                 .collect(Collectors.toList());
-
         IotCommonBomMaterialSaveReqVO bomMaterialSaveReqVO = new IotCommonBomMaterialSaveReqVO();
         bomMaterialSaveReqVO.setBomNodeIds(bomNodeIds);
         // 查询所有bom节点已经绑定的物料列表
@@ -124,9 +130,13 @@ public class IotBomController {
                 }
             });
         }
+        // 拼接所属 设备分类 名称
+        Map<Long, IotProductClassifyDO> deviceCategoryMap = iotProductClassifyService.getIotProductClassifyMap(
+                convertList(list, IotBomDO::getDeviceCategoryId));
         return success(BeanUtils.toBean(list, IotBomRespVO.class, bom -> {
             Integer materialCount = bomMaterialCount.getOrDefault(bom.getId(), 0);
             bom.setMaterials(materialCount);
+            bom.setDeviceCategoryName(deviceCategoryMap.get(bom.getDeviceCategoryId()).getName());
         }));
     }
 

+ 4 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotbom/vo/IotBomRespVO.java

@@ -86,4 +86,8 @@ public class IotBomRespVO {
      */
     @Schema(description = "已经绑定的物料数量")
     private Integer materials;
+
+    @Schema(description = "所属设备分类名称", example = "空压机")
+    @ExcelProperty("所属设备分类")
+    private String deviceCategoryName;
 }

+ 9 - 2
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotmainworkorder/IotMainWorkOrderController.java

@@ -1,6 +1,7 @@
 package cn.iocoder.yudao.module.pms.controller.admin.iotmainworkorder;
 
 import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.collection.CollectionUtil;
 import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
 import cn.iocoder.yudao.framework.common.pojo.PageParam;
@@ -13,9 +14,7 @@ import cn.iocoder.yudao.module.pms.controller.admin.iotmainworkorder.vo.IotMainW
 import cn.iocoder.yudao.module.pms.controller.admin.iotmainworkorder.vo.IotMainWorkOrderRespVO;
 import cn.iocoder.yudao.module.pms.controller.admin.iotmainworkorder.vo.IotMainWorkOrderSaveReqVO;
 import cn.iocoder.yudao.module.pms.controller.admin.iotmainworkorder.vo.IotMainWorkOrderSaveVO;
-import cn.iocoder.yudao.module.pms.controller.admin.maintenance.vo.IotMaintenancePlanRespVO;
 import cn.iocoder.yudao.module.pms.dal.dataobject.iotmainworkorder.IotMainWorkOrderDO;
-import cn.iocoder.yudao.module.pms.dal.dataobject.maintenance.IotMaintenancePlanDO;
 import cn.iocoder.yudao.module.pms.service.iotmainworkorder.IotMainWorkOrderService;
 import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
 import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
@@ -107,6 +106,14 @@ public class IotMainWorkOrderController {
         return success(new PageResult<>(buildMainWorkOrderList(pageResult.getList()), pageResult.getTotal()));
     }
 
+    @GetMapping("/allWorkOrderCountByResult")
+    @Operation(summary = "根据保养结果查询工单数量")
+    @PreAuthorize("@ss.hasPermission('pms:iot-main-work-order:query')")
+    public CommonResult<List<Map<String, Integer>>> allWorkOrderCountByResult() {
+        List<Map<String, Integer>> workOrderCount = iotMainWorkOrderService.allWorkOrderCountByResult();
+        return success(CollectionUtil.isEmpty(workOrderCount) ? CollectionUtil.newArrayList() : workOrderCount);
+    }
+
     private List<IotMainWorkOrderRespVO> buildMainWorkOrderList(List<IotMainWorkOrderDO> orders) {
         if (CollUtil.isEmpty(orders)) {
             return Collections.emptyList();

+ 93 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotsappickinglist/IotSapPickingListController.java

@@ -0,0 +1,93 @@
+package cn.iocoder.yudao.module.pms.controller.admin.iotsappickinglist;
+
+import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
+import cn.iocoder.yudao.module.pms.controller.admin.iotsappickinglist.vo.IotSapPickingListPageReqVO;
+import cn.iocoder.yudao.module.pms.controller.admin.iotsappickinglist.vo.IotSapPickingListRespVO;
+import cn.iocoder.yudao.module.pms.controller.admin.iotsappickinglist.vo.IotSapPickingListSaveReqVO;
+import cn.iocoder.yudao.module.pms.dal.dataobject.iotsappickinglist.IotSapPickingListDO;
+import cn.iocoder.yudao.module.pms.service.iotsappickinglist.IotSapPickingListService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletResponse;
+import javax.validation.Valid;
+import java.io.IOException;
+import java.util.List;
+
+import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+
+@Tag(name = "管理后台 - PMS SAP 领料单")
+@RestController
+@RequestMapping("/pms/iot-sap-picking-list")
+@Validated
+public class IotSapPickingListController {
+
+    @Resource
+    private IotSapPickingListService iotSapPickingListService;
+
+    @PostMapping("/create")
+    @Operation(summary = "创建PMS SAP 领料单")
+    @PreAuthorize("@ss.hasPermission('pms:iot-sap-picking-list:create')")
+    public CommonResult<Long> createIotSapPickingList(@Valid @RequestBody IotSapPickingListSaveReqVO createReqVO) {
+        return success(iotSapPickingListService.createIotSapPickingList(createReqVO));
+    }
+
+    @PutMapping("/update")
+    @Operation(summary = "更新PMS SAP 领料单")
+    @PreAuthorize("@ss.hasPermission('pms:iot-sap-picking-list:update')")
+    public CommonResult<Boolean> updateIotSapPickingList(@Valid @RequestBody IotSapPickingListSaveReqVO updateReqVO) {
+        iotSapPickingListService.updateIotSapPickingList(updateReqVO);
+        return success(true);
+    }
+
+    @DeleteMapping("/delete")
+    @Operation(summary = "删除PMS SAP 领料单")
+    @Parameter(name = "id", description = "编号", required = true)
+    @PreAuthorize("@ss.hasPermission('pms:iot-sap-picking-list:delete')")
+    public CommonResult<Boolean> deleteIotSapPickingList(@RequestParam("id") Long id) {
+        iotSapPickingListService.deleteIotSapPickingList(id);
+        return success(true);
+    }
+
+    @GetMapping("/get")
+    @Operation(summary = "获得PMS SAP 领料单")
+    @Parameter(name = "id", description = "编号", required = true, example = "1024")
+    @PreAuthorize("@ss.hasPermission('pms:iot-sap-picking-list:query')")
+    public CommonResult<IotSapPickingListRespVO> getIotSapPickingList(@RequestParam("id") Long id) {
+        IotSapPickingListDO iotSapPickingList = iotSapPickingListService.getIotSapPickingList(id);
+        return success(BeanUtils.toBean(iotSapPickingList, IotSapPickingListRespVO.class));
+    }
+
+    @GetMapping("/page")
+    @Operation(summary = "获得PMS SAP 领料单分页")
+    @PreAuthorize("@ss.hasPermission('pms:iot-sap-picking-list:query')")
+    public CommonResult<PageResult<IotSapPickingListRespVO>> getIotSapPickingListPage(@Valid IotSapPickingListPageReqVO pageReqVO) {
+        PageResult<IotSapPickingListDO> pageResult = iotSapPickingListService.getIotSapPickingListPage(pageReqVO);
+        return success(BeanUtils.toBean(pageResult, IotSapPickingListRespVO.class));
+    }
+
+    @GetMapping("/export-excel")
+    @Operation(summary = "导出PMS SAP 领料单 Excel")
+    @PreAuthorize("@ss.hasPermission('pms:iot-sap-picking-list:export')")
+    @ApiAccessLog(operateType = EXPORT)
+    public void exportIotSapPickingListExcel(@Valid IotSapPickingListPageReqVO pageReqVO,
+              HttpServletResponse response) throws IOException {
+        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
+        List<IotSapPickingListDO> list = iotSapPickingListService.getIotSapPickingListPage(pageReqVO).getList();
+        // 导出 Excel
+        ExcelUtils.write(response, "PMS SAP 领料单.xls", "数据", IotSapPickingListRespVO.class,
+                        BeanUtils.toBean(list, IotSapPickingListRespVO.class));
+    }
+
+}

+ 89 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotsappickinglist/vo/IotSapPickingListPageReqVO.java

@@ -0,0 +1,89 @@
+package cn.iocoder.yudao.module.pms.controller.admin.iotsappickinglist.vo;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "管理后台 - PMS SAP 领料单分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class IotSapPickingListPageReqVO extends PageParam {
+
+    @Schema(description = "组织部门id", example = "24856")
+    private Long deptId;
+
+    @Schema(description = "SAP工厂id", example = "13133")
+    private Long factoryId;
+
+    @Schema(description = "工厂(SAP)")
+    private String factory;
+
+    @Schema(description = "成本中心id", example = "7415")
+    private Long costCenterId;
+
+    @Schema(description = "成本中心(SAP)")
+    private String costCenter;
+
+    @Schema(description = "库存地点id", example = "20261")
+    private Long storageLocationId;
+
+    @Schema(description = "库存地点")
+    private String storageLocation;
+
+    @Schema(description = "领料单号")
+    private String number;
+
+    @Schema(description = "物料编码")
+    private String materialCode;
+
+    @Schema(description = "物料名称", example = "张三")
+    private String materialName;
+
+    @Schema(description = "物料组", example = "赵六")
+    private String materialGroupName;
+
+    @Schema(description = "物料组id", example = "30688")
+    private Long materialGroupId;
+
+    @Schema(description = "数量")
+    private BigDecimal quantity;
+
+    @Schema(description = "单价", example = "14631")
+    private BigDecimal unitPrice;
+
+    @Schema(description = "单位")
+    private String unit;
+
+    @Schema(description = "同步状态 0未同步 1同步成功 2同步失败", example = "2")
+    private Integer syncStatus;
+
+    @Schema(description = "最后一次同步时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime[] syncTime;
+
+    @Schema(description = "同步失败时的错误信息")
+    private String syncError;
+
+    @Schema(description = "排序")
+    private Integer sort;
+
+    @Schema(description = "状态 0启用  1停用", example = "1")
+    private Integer status;
+
+    @Schema(description = "备注", example = "随便")
+    private String remark;
+
+    @Schema(description = "创建时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime[] createTime;
+
+}

+ 108 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotsappickinglist/vo/IotSapPickingListRespVO.java

@@ -0,0 +1,108 @@
+package cn.iocoder.yudao.module.pms.controller.admin.iotsappickinglist.vo;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+@Schema(description = "管理后台 - PMS SAP 领料单 Response VO")
+@Data
+@ExcelIgnoreUnannotated
+public class IotSapPickingListRespVO {
+
+    @Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "24628")
+    @ExcelProperty("主键")
+    private Long id;
+
+    @Schema(description = "组织部门id", example = "24856")
+    @ExcelProperty("组织部门id")
+    private Long deptId;
+
+    @Schema(description = "SAP工厂id", example = "13133")
+    @ExcelProperty("SAP工厂id")
+    private Long factoryId;
+
+    @Schema(description = "工厂(SAP)")
+    @ExcelProperty("工厂(SAP)")
+    private String factory;
+
+    @Schema(description = "成本中心id", example = "7415")
+    @ExcelProperty("成本中心id")
+    private Long costCenterId;
+
+    @Schema(description = "成本中心(SAP)")
+    @ExcelProperty("成本中心(SAP)")
+    private String costCenter;
+
+    @Schema(description = "库存地点id", example = "20261")
+    @ExcelProperty("库存地点id")
+    private Long storageLocationId;
+
+    @Schema(description = "库存地点")
+    @ExcelProperty("库存地点")
+    private String storageLocation;
+
+    @Schema(description = "领料单号")
+    @ExcelProperty("领料单号")
+    private String number;
+
+    @Schema(description = "物料编码")
+    @ExcelProperty("物料编码")
+    private String materialCode;
+
+    @Schema(description = "物料名称", example = "张三")
+    @ExcelProperty("物料名称")
+    private String materialName;
+
+    @Schema(description = "物料组", example = "赵六")
+    @ExcelProperty("物料组")
+    private String materialGroupName;
+
+    @Schema(description = "物料组id", example = "30688")
+    @ExcelProperty("物料组id")
+    private Long materialGroupId;
+
+    @Schema(description = "数量")
+    @ExcelProperty("数量")
+    private BigDecimal quantity;
+
+    @Schema(description = "单价", example = "14631")
+    @ExcelProperty("单价")
+    private BigDecimal unitPrice;
+
+    @Schema(description = "单位")
+    @ExcelProperty("单位")
+    private String unit;
+
+    @Schema(description = "同步状态 0未同步 1同步成功 2同步失败", example = "2")
+    @ExcelProperty("同步状态 0未同步 1同步成功 2同步失败")
+    private Integer syncStatus;
+
+    @Schema(description = "最后一次同步时间")
+    @ExcelProperty("最后一次同步时间")
+    private LocalDateTime syncTime;
+
+    @Schema(description = "同步失败时的错误信息")
+    @ExcelProperty("同步失败时的错误信息")
+    private String syncError;
+
+    @Schema(description = "排序")
+    @ExcelProperty("排序")
+    private Integer sort;
+
+    @Schema(description = "状态 0启用  1停用", example = "1")
+    @ExcelProperty("状态 0启用  1停用")
+    private Integer status;
+
+    @Schema(description = "备注", example = "随便")
+    @ExcelProperty("备注")
+    private String remark;
+
+    @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("创建时间")
+    private LocalDateTime createTime;
+
+}

+ 79 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotsappickinglist/vo/IotSapPickingListSaveReqVO.java

@@ -0,0 +1,79 @@
+package cn.iocoder.yudao.module.pms.controller.admin.iotsappickinglist.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+@Schema(description = "管理后台 - PMS SAP 领料单新增/修改 Request VO")
+@Data
+public class IotSapPickingListSaveReqVO {
+
+    @Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "24628")
+    private Long id;
+
+    @Schema(description = "组织部门id", example = "24856")
+    private Long deptId;
+
+    @Schema(description = "SAP工厂id", example = "13133")
+    private Long factoryId;
+
+    @Schema(description = "工厂(SAP)")
+    private String factory;
+
+    @Schema(description = "成本中心id", example = "7415")
+    private Long costCenterId;
+
+    @Schema(description = "成本中心(SAP)")
+    private String costCenter;
+
+    @Schema(description = "库存地点id", example = "20261")
+    private Long storageLocationId;
+
+    @Schema(description = "库存地点")
+    private String storageLocation;
+
+    @Schema(description = "领料单号")
+    private String number;
+
+    @Schema(description = "物料编码")
+    private String materialCode;
+
+    @Schema(description = "物料名称", example = "张三")
+    private String materialName;
+
+    @Schema(description = "物料组", example = "赵六")
+    private String materialGroupName;
+
+    @Schema(description = "物料组id", example = "30688")
+    private Long materialGroupId;
+
+    @Schema(description = "数量")
+    private BigDecimal quantity;
+
+    @Schema(description = "单价", example = "14631")
+    private BigDecimal unitPrice;
+
+    @Schema(description = "单位")
+    private String unit;
+
+    @Schema(description = "同步状态 0未同步 1同步成功 2同步失败", example = "2")
+    private Integer syncStatus;
+
+    @Schema(description = "最后一次同步时间")
+    private LocalDateTime syncTime;
+
+    @Schema(description = "同步失败时的错误信息")
+    private String syncError;
+
+    @Schema(description = "排序")
+    private Integer sort;
+
+    @Schema(description = "状态 0启用  1停用", example = "1")
+    private Integer status;
+
+    @Schema(description = "备注", example = "随便")
+    private String remark;
+
+}

+ 5 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotsapstock/vo/IotSapStockPageReqVO.java

@@ -92,4 +92,9 @@ public class IotSapStockPageReqVO extends PageParam {
     @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
     private LocalDateTime[] createTime;
 
+    /**
+     * 扩展字段
+     */
+    @Schema(description = "是否设置了安全库存 Y已设置 N未设置")
+    private String configFlag;
 }

+ 1 - 3
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/stat/IotStaticController.java

@@ -5,7 +5,6 @@ import cn.iocoder.yudao.framework.common.util.date.DateUtils;
 import cn.iocoder.yudao.module.pms.controller.admin.failure.vo.IotFailureReportPageReqVO;
 import cn.iocoder.yudao.module.pms.controller.admin.inspect.order.vo.IotInspectOrderPageReqVO;
 import cn.iocoder.yudao.module.pms.controller.admin.iotmainworkorder.vo.IotMainWorkOrderPageReqVO;
-import cn.iocoder.yudao.module.pms.controller.admin.iotmainworkorder.vo.IotMainWorkOrderSaveReqVO;
 import cn.iocoder.yudao.module.pms.controller.admin.maintain.vo.IotMaintainPageReqVO;
 import cn.iocoder.yudao.module.pms.dal.dataobject.failure.IotFailureReportDO;
 import cn.iocoder.yudao.module.pms.dal.dataobject.inspect.IotInspectOrderDO;
@@ -20,7 +19,6 @@ import com.alibaba.fastjson.JSON;
 import com.google.common.collect.ImmutableMap;
 import io.swagger.v3.oas.annotations.tags.Tag;
 import org.apache.commons.lang3.StringUtils;
-import org.jetbrains.annotations.NotNull;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.GetMapping;
@@ -302,6 +300,6 @@ public class IotStaticController {
             return null;
         }
 
-
+        return null;
     }
 }

+ 117 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/dal/dataobject/iotsappickinglist/IotSapPickingListDO.java

@@ -0,0 +1,117 @@
+package cn.iocoder.yudao.module.pms.dal.dataobject.iotsappickinglist;
+
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.*;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+/**
+ * PMS SAP 领料单 DO
+ *
+ * @author ruiqi
+ */
+@TableName("rq_iot_sap_picking_list")
+@KeySequence("rq_iot_sap_picking_list_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class IotSapPickingListDO extends BaseDO {
+
+    /**
+     * 主键
+     */
+    @TableId
+    private Long id;
+    /**
+     * 组织部门id
+     */
+    private Long deptId;
+    /**
+     * SAP工厂id
+     */
+    private Long factoryId;
+    /**
+     * 工厂(SAP)
+     */
+    private String factory;
+    /**
+     * 成本中心id
+     */
+    private Long costCenterId;
+    /**
+     * 成本中心(SAP)
+     */
+    private String costCenter;
+    /**
+     * 库存地点id
+     */
+    private Long storageLocationId;
+    /**
+     * 库存地点
+     */
+    private String storageLocation;
+    /**
+     * 领料单号
+     */
+    private String number;
+    /**
+     * 物料编码
+     */
+    private String materialCode;
+    /**
+     * 物料名称
+     */
+    private String materialName;
+    /**
+     * 物料组
+     */
+    private String materialGroupName;
+    /**
+     * 物料组id
+     */
+    private Long materialGroupId;
+    /**
+     * 数量
+     */
+    private BigDecimal quantity;
+    /**
+     * 单价
+     */
+    private BigDecimal unitPrice;
+    /**
+     * 单位
+     */
+    private String unit;
+    /**
+     * 同步状态 0未同步 1同步成功 2同步失败
+     */
+    private Integer syncStatus;
+    /**
+     * 最后一次同步时间
+     */
+    private LocalDateTime syncTime;
+    /**
+     * 同步失败时的错误信息
+     */
+    private String syncError;
+    /**
+     * 排序
+     */
+    private Integer sort;
+    /**
+     * 状态 0启用  1停用
+     */
+    private Integer status;
+    /**
+     * 备注
+     */
+    private String remark;
+
+}

+ 4 - 2
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/dal/mysql/iotbom/IotBomMapper.java

@@ -14,6 +14,7 @@ import org.apache.ibatis.annotations.Mapper;
 
 import java.util.Collection;
 import java.util.List;
+import java.util.Set;
 
 /**
  * PMS BOM 关系 Mapper
@@ -41,10 +42,11 @@ public interface IotBomMapper extends BaseMapperX<IotBomDO> {
                 .orderByDesc(IotBomDO::getId));
     }
 
-    default List<IotBomDO> selectList(IotBomListReqVO reqVO) {
+    default List<IotBomDO> selectList(IotBomListReqVO reqVO, Set<Long> ids) {
         return selectList(new LambdaQueryWrapperX<IotBomDO>()
                 .likeIfPresent(IotBomDO::getName, reqVO.getName())
-                .eqIfPresent(IotBomDO::getDeviceCategoryId, reqVO.getDeviceCategoryId())
+                // .eqIfPresent(IotBomDO::getDeviceCategoryId, reqVO.getDeviceCategoryId())
+                .inIfPresent(IotBomDO::getDeviceCategoryId, ids)
                 .eqIfPresent(IotBomDO::getStatus, reqVO.getStatus()));
     }
 

+ 12 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/dal/mysql/iotcommonbommaterial/IotCommonBomMaterialMapper.java

@@ -1,11 +1,15 @@
 package cn.iocoder.yudao.module.pms.dal.mysql.iotcommonbommaterial;
 
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjectUtil;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
+import cn.iocoder.yudao.framework.mybatis.core.query.MPJLambdaWrapperX;
 import cn.iocoder.yudao.module.pms.controller.admin.iotcommonbommaterial.vo.IotCommonBomMaterialPageReqVO;
 import cn.iocoder.yudao.module.pms.controller.admin.iotcommonbommaterial.vo.IotCommonBomMaterialSaveReqVO;
 import cn.iocoder.yudao.module.pms.dal.dataobject.iotcommonbommaterial.IotCommonBomMaterialDO;
+import cn.iocoder.yudao.module.pms.dal.dataobject.iotmaterial.IotMaterialDO;
 import org.apache.ibatis.annotations.Mapper;
 
 import java.util.List;
@@ -40,4 +44,12 @@ public interface IotCommonBomMaterialMapper extends BaseMapperX<IotCommonBomMate
                 .eqIfPresent(IotCommonBomMaterialDO::getMaterialId, reqVO.getMaterialId()));
     }
 
+    default List<IotCommonBomMaterialDO> selectList1(IotCommonBomMaterialSaveReqVO reqVO) {
+        MPJLambdaWrapperX<IotCommonBomMaterialDO> query = new MPJLambdaWrapperX<IotCommonBomMaterialDO>();
+        query.innerJoin(IotMaterialDO.class, IotMaterialDO::getId, IotCommonBomMaterialDO::getMaterialId)
+                .eq(ObjectUtil.isNotEmpty(reqVO.getDeviceCategoryId()), IotCommonBomMaterialDO::getDeviceCategoryId, reqVO.getDeviceCategoryId())
+                .in(CollUtil.isNotEmpty(reqVO.getBomNodeIds()), IotCommonBomMaterialDO::getBomNodeId, reqVO.getBomNodeIds());
+        return selectJoinList(IotCommonBomMaterialDO.class, query);
+    }
+
 }

+ 5 - 2
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/dal/mysql/iotdevicecategorytemplate/IotDeviceCategoryTemplateMapper.java

@@ -7,6 +7,8 @@ import cn.iocoder.yudao.module.pms.controller.admin.iotdevicecategorytemplate.vo
 import cn.iocoder.yudao.module.pms.dal.dataobject.iotdevicecategorytemplate.IotDeviceCategoryTemplateDO;
 import org.apache.ibatis.annotations.Mapper;
 
+import java.util.Set;
+
 /**
  * 设备分类属性公用模板 Mapper
  *
@@ -15,9 +17,10 @@ import org.apache.ibatis.annotations.Mapper;
 @Mapper
 public interface IotDeviceCategoryTemplateMapper extends BaseMapperX<IotDeviceCategoryTemplateDO> {
 
-    default PageResult<IotDeviceCategoryTemplateDO> selectPage(IotDeviceCategoryTemplatePageReqVO reqVO) {
+    default PageResult<IotDeviceCategoryTemplateDO> selectPage(IotDeviceCategoryTemplatePageReqVO reqVO, Set<Long> ids) {
         return selectPage(reqVO, new LambdaQueryWrapperX<IotDeviceCategoryTemplateDO>()
-                .eqIfPresent(IotDeviceCategoryTemplateDO::getDeviceCategoryId, reqVO.getDeviceCategoryId())
+                // .eqIfPresent(IotDeviceCategoryTemplateDO::getDeviceCategoryId, reqVO.getDeviceCategoryId())
+                .inIfPresent(IotDeviceCategoryTemplateDO::getDeviceCategoryId, ids)
                 .likeIfPresent(IotDeviceCategoryTemplateDO::getName, reqVO.getName())
                 .eqIfPresent(IotDeviceCategoryTemplateDO::getCode, reqVO.getCode())
                 .eqIfPresent(IotDeviceCategoryTemplateDO::getAttrs, reqVO.getAttrs())

+ 5 - 2
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/dal/mysql/iotmainworkorder/IotMainWorkOrderMapper.java

@@ -3,13 +3,13 @@ package cn.iocoder.yudao.module.pms.dal.mysql.iotmainworkorder;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
-import cn.iocoder.yudao.module.pms.controller.admin.inspect.order.vo.IotInspectOrderPageReqVO;
 import cn.iocoder.yudao.module.pms.controller.admin.iotmainworkorder.vo.IotMainWorkOrderPageReqVO;
-import cn.iocoder.yudao.module.pms.dal.dataobject.inspect.IotInspectOrderDO;
 import cn.iocoder.yudao.module.pms.dal.dataobject.iotmainworkorder.IotMainWorkOrderDO;
+import org.apache.ibatis.annotations.MapKey;
 import org.apache.ibatis.annotations.Mapper;
 
 import java.util.List;
+import java.util.Map;
 
 /**
  * 保养工单 Mapper
@@ -57,4 +57,7 @@ public interface IotMainWorkOrderMapper extends BaseMapperX<IotMainWorkOrderDO>
                 .betweenIfPresent(IotMainWorkOrderDO::getCreateTime, reqVO.getCreateTime())
                 .orderByAsc(IotMainWorkOrderDO::getCreateTime));
     }
+
+    @MapKey("result")
+    List<Map<String, Integer>> allWorkOrderCountByResult();
 }

+ 1 - 1
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/dal/mysql/iotmaterial/IotMaterialMapper.java

@@ -26,7 +26,7 @@ public interface IotMaterialMapper extends BaseMapperX<IotMaterialDO> {
                 .eqIfPresent(IotMaterialDO::getMaterialGroupId, reqVO.getMaterialGroupId())
                 .eqIfPresent(IotMaterialDO::getBomId, reqVO.getBomId())
                 .eqIfPresent(IotMaterialDO::getType, reqVO.getType())
-                .eqIfPresent(IotMaterialDO::getCode, reqVO.getCode())
+                .likeIfPresent(IotMaterialDO::getCode, reqVO.getCode())
                 .likeIfPresent(IotMaterialDO::getName, reqVO.getName())
                 .eqIfPresent(IotMaterialDO::getModel, reqVO.getModel())
                 .eqIfPresent(IotMaterialDO::getUnit, reqVO.getUnit())

+ 45 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/dal/mysql/iotsappickinglist/IotSapPickingListMapper.java

@@ -0,0 +1,45 @@
+package cn.iocoder.yudao.module.pms.dal.mysql.iotsappickinglist;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
+import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
+import cn.iocoder.yudao.module.pms.controller.admin.iotsappickinglist.vo.IotSapPickingListPageReqVO;
+import cn.iocoder.yudao.module.pms.dal.dataobject.iotsappickinglist.IotSapPickingListDO;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * PMS SAP 领料单 Mapper
+ *
+ * @author ruiqi
+ */
+@Mapper
+public interface IotSapPickingListMapper extends BaseMapperX<IotSapPickingListDO> {
+
+    default PageResult<IotSapPickingListDO> selectPage(IotSapPickingListPageReqVO reqVO) {
+        return selectPage(reqVO, new LambdaQueryWrapperX<IotSapPickingListDO>()
+                .eqIfPresent(IotSapPickingListDO::getDeptId, reqVO.getDeptId())
+                .eqIfPresent(IotSapPickingListDO::getFactoryId, reqVO.getFactoryId())
+                .eqIfPresent(IotSapPickingListDO::getFactory, reqVO.getFactory())
+                .eqIfPresent(IotSapPickingListDO::getCostCenterId, reqVO.getCostCenterId())
+                .eqIfPresent(IotSapPickingListDO::getCostCenter, reqVO.getCostCenter())
+                .eqIfPresent(IotSapPickingListDO::getStorageLocationId, reqVO.getStorageLocationId())
+                .eqIfPresent(IotSapPickingListDO::getStorageLocation, reqVO.getStorageLocation())
+                .eqIfPresent(IotSapPickingListDO::getNumber, reqVO.getNumber())
+                .eqIfPresent(IotSapPickingListDO::getMaterialCode, reqVO.getMaterialCode())
+                .likeIfPresent(IotSapPickingListDO::getMaterialName, reqVO.getMaterialName())
+                .likeIfPresent(IotSapPickingListDO::getMaterialGroupName, reqVO.getMaterialGroupName())
+                .eqIfPresent(IotSapPickingListDO::getMaterialGroupId, reqVO.getMaterialGroupId())
+                .eqIfPresent(IotSapPickingListDO::getQuantity, reqVO.getQuantity())
+                .eqIfPresent(IotSapPickingListDO::getUnitPrice, reqVO.getUnitPrice())
+                .eqIfPresent(IotSapPickingListDO::getUnit, reqVO.getUnit())
+                .eqIfPresent(IotSapPickingListDO::getSyncStatus, reqVO.getSyncStatus())
+                .betweenIfPresent(IotSapPickingListDO::getSyncTime, reqVO.getSyncTime())
+                .eqIfPresent(IotSapPickingListDO::getSyncError, reqVO.getSyncError())
+                .eqIfPresent(IotSapPickingListDO::getSort, reqVO.getSort())
+                .eqIfPresent(IotSapPickingListDO::getStatus, reqVO.getStatus())
+                .eqIfPresent(IotSapPickingListDO::getRemark, reqVO.getRemark())
+                .betweenIfPresent(IotSapPickingListDO::getCreateTime, reqVO.getCreateTime())
+                .orderByDesc(IotSapPickingListDO::getId));
+    }
+
+}

+ 8 - 4
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/dal/mysql/iotsapstock/IotSapStockMapper.java

@@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.pms.dal.mysql.iotsapstock;
 
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
-import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
+import cn.iocoder.yudao.framework.mybatis.core.query.MPJLambdaWrapperX;
 import cn.iocoder.yudao.module.pms.controller.admin.iotsapstock.vo.IotSapStockPageReqVO;
 import cn.iocoder.yudao.module.pms.dal.dataobject.iotsapstock.IotSapStockDO;
 import org.apache.ibatis.annotations.Mapper;
@@ -16,8 +16,8 @@ import org.apache.ibatis.annotations.Mapper;
 public interface IotSapStockMapper extends BaseMapperX<IotSapStockDO> {
 
     default PageResult<IotSapStockDO> selectPage(IotSapStockPageReqVO reqVO) {
-        return selectPage(reqVO, new LambdaQueryWrapperX<IotSapStockDO>()
-                .eqIfPresent(IotSapStockDO::getDeptId, reqVO.getDeptId())
+        MPJLambdaWrapperX<IotSapStockDO> query = new MPJLambdaWrapperX<IotSapStockDO>();
+        query.eqIfPresent(IotSapStockDO::getDeptId, reqVO.getDeptId())
                 .eqIfPresent(IotSapStockDO::getFactoryId, reqVO.getFactoryId())
                 .eqIfPresent(IotSapStockDO::getFactory, reqVO.getFactory())
                 .eqIfPresent(IotSapStockDO::getStorageLocationId, reqVO.getStorageLocationId())
@@ -41,7 +41,11 @@ public interface IotSapStockMapper extends BaseMapperX<IotSapStockDO> {
                 .eqIfPresent(IotSapStockDO::getStatus, reqVO.getStatus())
                 .eqIfPresent(IotSapStockDO::getRemark, reqVO.getRemark())
                 .betweenIfPresent(IotSapStockDO::getCreateTime, reqVO.getCreateTime())
-                .orderByDesc(IotSapStockDO::getId));
+                .orderByDesc(IotSapStockDO::getId);
+        if ("Y".equals(reqVO.getConfigFlag())) {
+            query.gt(IotSapStockDO::getSafetyStock, 0);
+        }
+        return selectJoinPage(reqVO, IotSapStockDO.class, query);
     }
 
 }

+ 125 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/job/sap/SyncSapPickingListJob.java

@@ -0,0 +1,125 @@
+package cn.iocoder.yudao.module.pms.job.sap;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.util.ObjUtil;
+import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler;
+import cn.iocoder.yudao.framework.tenant.core.job.TenantJob;
+import cn.iocoder.yudao.module.pms.sap.SapConnector;
+import cn.iocoder.yudao.module.system.api.saporg.SapOrgApi;
+import cn.iocoder.yudao.module.system.api.saporg.dto.SapOrgRespDTO;
+import com.sap.conn.jco.*;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+@Component
+@Slf4j
+public class SyncSapPickingListJob implements JobHandler {
+    @Autowired
+    private SapConnector sapConnector;
+    @Autowired
+    private SapOrgApi sapOrgApi;
+
+    @Override
+    @TenantJob
+    public String execute(String param) throws Exception {
+        List<String> factoryCodes = factoryCodes();
+        if (CollUtil.isEmpty(factoryCodes)) {
+            return "No SAP Factory";
+        }
+        try {
+            JCoDestination destination = sapConnector.getDestination();
+            JCoFunction function = destination.getRepository().getFunction("ZPMS_006");
+            if (ObjUtil.isEmpty(function)) {
+                return "No SAP Function";
+            }
+            // 设置输入参数
+            JCoParameterList input = function.getImportParameterList();
+            input.setValue("I_WERKS", "6011");
+            // 暂时只设置同步 2025年后的 领料单 2025年之前的领料单 手动入库
+            input.setValue("I_DATUM_F", "20250101"); // 开始日期
+            // input.setValue("I_DATUM_T", "20251231"); // 结束日期
+
+            // 执行 RFC 调用
+            function.execute(destination);
+
+            // 获取输出参数
+            JCoParameterList output = function.getTableParameterList();
+            JCoTable headTable = function.getTableParameterList().getTable("T_HEAD");
+            // JCoParameterList output = function.getExportParameterList();
+            if (CollUtil.isNotEmpty(output)) {
+                output.forEach(material -> {
+                    // System.out.println(material.getName());
+                });
+            }
+            if (headTable != null && headTable.getNumRows() > 0) {
+                for (int i = 0; i < headTable.getNumRows(); i++) {
+                    headTable.setRow(i);
+                    System.out.println(String.format("行号 %d: 工厂=%s, 名称 1=%s, 领料/退料编号=%s, ZLLLX=%s, " +
+                                    "日期=%tT, 项目定义=%s, WBS 元素=%s, 描述=%s, 所属项目部=%s, 描述=%s, 成本中心=%s, 描述=%s\n",
+                            i,
+                            headTable.getString("WERKS"),
+                            headTable.getString("TXTMD"),
+                            headTable.getString("ZLTNO"),
+                            headTable.getString("ZLLLX"),
+                            headTable.getDate("DATUM"),
+                            headTable.getString("PSPID"),
+                            headTable.getString("POSID"),
+                            headTable.getString("POST1"),
+                            headTable.getString("ZSSXMB"),
+                            headTable.getString("LGOBE"),
+                            headTable.getString("KOSTL"),
+                            headTable.getString("LTEXT")
+                    ));
+                }
+            }
+            // 清空函数继续下次请求
+            JCoTable itemTable = function.getTableParameterList().getTable("T_ITEM");
+            if (itemTable != null && itemTable.getNumRows() > 0) {
+                for (int i = 0; i < itemTable.getNumRows(); i++) {
+                    itemTable.setRow(i);
+                    System.out.println(String.format("行号 %d: 物料=%s, 描述=%s, 数量=%f, " +
+                                    "基本单位=%s, 特殊库存=%s, 移动原因=%s, 原因=%s, 库存地点=%s, 描述=%s, 库存仓位=%s, 批次=%s, 转入工厂=%s, BEIZHU=%s\n",
+                            i,
+                            itemTable.getInt("ZNUMC"),
+                            itemTable.getString("MATNR"),
+                            itemTable.getString("MAKTX"),
+                            itemTable.getDouble("MENGE"),
+                            itemTable.getString("MEINS"),
+                            itemTable.getString("SOBKZ"),
+                            itemTable.getInt("GRUND"),
+                            itemTable.getString("GRTXT"),
+                            itemTable.getString("LGORT"),
+                            itemTable.getString("LGOBE"),
+                            itemTable.getString("LGPBE"),
+                            itemTable.getString("CHARG"),
+                            itemTable.getString("WERKS_ZR"),
+                            itemTable.getString("BEIZHU")
+                    ));
+                }
+            }
+
+            return "Material Info: " + output.getString("T_HEAD");
+        } catch (JCoException e) {
+            return "Error calling SAP Picking List: " + e.getMessage();
+        }
+    }
+
+    /**
+     * 查询所有SAP工厂
+     */
+    private List<String> factoryCodes(){
+        List<SapOrgRespDTO> sapOrgs = sapOrgApi.getSapOrgByType(1);
+        if (CollUtil.isEmpty(sapOrgs)) {
+            return CollectionUtil.newArrayList();
+        }
+        List<String> factoryCodes = sapOrgs.stream()
+                .map(SapOrgRespDTO::getFactoryCode)
+                .collect(Collectors.toList());
+        return CollUtil.isEmpty(factoryCodes) ? CollUtil.empty(String.class) : factoryCodes;
+    }
+}

+ 18 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/sap/SapConfig.java

@@ -0,0 +1,18 @@
+package cn.iocoder.yudao.module.pms.sap;
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+@ConfigurationProperties(prefix = "sap.jco")
+@Data
+public class SapConfig {
+    private String ashost;
+    private String sysnr;
+    private String client;
+    private String user;
+    private String passwd;
+    private String lang;
+    private int poolCapacity;
+    private int peakLimit;
+}

+ 47 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/sap/SapConnector.java

@@ -0,0 +1,47 @@
+package cn.iocoder.yudao.module.pms.sap;
+
+import com.sap.conn.jco.*;
+import com.sap.conn.jco.ext.DestinationDataProvider;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.util.Properties;
+
+@Component
+public class SapConnector {
+    private static final String DEST_NAME = "SAP_DEST";
+    @Value("${sap.jco.ashost}") private String ashost;
+    @Value("${sap.jco.sysnr}") private String sysnr;
+    @Value("${sap.jco.client}") private String client;
+    @Value("${sap.jco.user}") private String user;
+    @Value("${sap.jco.passwd}") private String passwd;
+    @Value("${sap.jco.lang}") private String lang;
+    @Value("${sap.jco.pool-capacity}") private String poolCapacity;
+    @Value("${sap.jco.peak-limit}") private String peakLimit;
+
+    public JCoDestination getDestination() throws JCoException {
+        Properties props = new Properties();
+        props.setProperty(DestinationDataProvider.JCO_ASHOST, ashost);
+        props.setProperty(DestinationDataProvider.JCO_SYSNR, sysnr);
+        props.setProperty(DestinationDataProvider.JCO_CLIENT, client);
+        props.setProperty(DestinationDataProvider.JCO_USER, user);
+        props.setProperty(DestinationDataProvider.JCO_PASSWD, passwd);
+        props.setProperty(DestinationDataProvider.JCO_LANG, lang);
+        props.setProperty(DestinationDataProvider.JCO_POOL_CAPACITY, poolCapacity);
+        props.setProperty(DestinationDataProvider.JCO_PEAK_LIMIT, peakLimit);
+
+        // 生成连接配置文件
+        createDestinationFile(DEST_NAME, props);
+        return JCoDestinationManager.getDestination(DEST_NAME);
+    }
+
+    private void createDestinationFile(String destName, Properties props) {
+        File destFile = new File(destName + ".jcoDestination");
+        try (FileOutputStream fos = new FileOutputStream(destFile)) {
+            props.store(fos, "SAP Connection Config");
+        } catch (Exception e) {
+            throw new RuntimeException("Failed to create SAP destination file", e);
+        }
+    }
+}

+ 214 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/sap/SapController.java

@@ -0,0 +1,214 @@
+package cn.iocoder.yudao.module.pms.sap;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjUtil;
+import cn.iocoder.yudao.module.system.api.saporg.SapOrgApi;
+import cn.iocoder.yudao.module.system.api.saporg.dto.SapOrgRespDTO;
+import com.sap.conn.jco.*;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+@Tag(name = "管理后台 - SAP同步接口 物料主数据 领料单 SAP库存")
+@RequestMapping("/pms/sapSync")
+@RestController
+@Validated
+public class SapController {
+    @Autowired
+    private SapConnector sapConnector;
+    @Autowired
+    private SapOrgApi sapOrgApi;
+
+    @GetMapping("/callSapStock")
+    @Operation(summary = "同步sap 库存接口")
+    public String callSapStock() {
+        try {
+            JCoDestination destination = sapConnector.getDestination();
+            JCoFunction function = destination.getRepository().getFunction("ZPMS_002");
+
+            // 设置输入参数
+            JCoParameterList input = function.getImportParameterList();
+            input.setValue("IV_WERKS", "6011");
+
+            // 执行 RFC 调用
+            function.execute(destination);
+
+            // 获取输出参数
+
+            JCoParameterList output = function.getTableParameterList();
+            JCoTable etStockTable = function.getTableParameterList().getTable("ET_STOCK");
+            // JCoParameterList output = function.getExportParameterList();
+            if (CollUtil.isNotEmpty(output)) {
+                output.forEach(material -> {
+                    System.out.println(material.getName());
+                });
+            }
+            if (etStockTable != null && etStockTable.getNumRows() > 0) {
+                for (int i = 0; i < etStockTable.getNumRows(); i++) {
+                    etStockTable.setRow(i);
+                    System.out.println(String.format("行号 %d: 工厂=%s, 物料=%s, 数量=%s\n",
+                            i,
+                            etStockTable.getString("WERKS"),
+                            etStockTable.getString("MATNR"),
+                            etStockTable.getString("LABST")
+                    ));
+                }
+            }
+            return "Material Info: " + output.getString("ET_STOCK");
+        } catch (JCoException e) {
+            return "Error calling SAP Stock: " + e.getMessage();
+        }
+    }
+
+    /**
+     * 同步SAP领料单 数据只有新增的情况
+     * @return
+     */
+    @GetMapping("/callSapPickingList")
+    @Operation(summary = "同步sap 领料单接口")
+    public String callSapPickingList() {
+        List<String> factoryCodes = factoryCodes();
+        if (CollUtil.isEmpty(factoryCodes)) {
+            return "No SAP Factory";
+        }
+        try {
+            JCoDestination destination = sapConnector.getDestination();
+            JCoFunction function = destination.getRepository().getFunction("ZPMS_006");
+            if (ObjUtil.isEmpty(function)) {
+                return "No SAP Function";
+            }
+            // 设置输入参数
+            JCoParameterList input = function.getImportParameterList();
+            input.setValue("I_WERKS", "6011");
+            // 暂时只设置同步 2025年后的 领料单 2025年之前的领料单 手动入库
+            input.setValue("I_DATUM_F", "20250101"); // 开始日期
+            // input.setValue("I_DATUM_T", "20251231"); // 结束日期
+
+            // 执行 RFC 调用
+            function.execute(destination);
+
+            // 获取输出参数
+            JCoParameterList output = function.getTableParameterList();
+            JCoTable headTable = function.getTableParameterList().getTable("T_HEAD");
+            // JCoParameterList output = function.getExportParameterList();
+            if (CollUtil.isNotEmpty(output)) {
+                output.forEach(material -> {
+                    // System.out.println(material.getName());
+                });
+            }
+            if (headTable != null && headTable.getNumRows() > 0) {
+                for (int i = 0; i < headTable.getNumRows(); i++) {
+                    headTable.setRow(i);
+                    System.out.println(String.format("行号 %d: 工厂=%s, 名称 1=%s, 领料/退料编号=%s, ZLLLX=%s, " +
+                                    "日期=%tT, 项目定义=%s, WBS 元素=%s, 描述=%s, 所属项目部=%s, 描述=%s, 成本中心=%s, 描述=%s\n",
+                            i,
+                            headTable.getString("WERKS"),
+                            headTable.getString("TXTMD"),
+                            headTable.getString("ZLTNO"),
+                            headTable.getString("ZLLLX"),
+                            headTable.getString("DATUM"),
+                            headTable.getString("PSPID"),
+                            headTable.getString("POSID"),
+                            headTable.getString("POST1"),
+                            headTable.getString("ZSSXMB"),
+                            headTable.getString("LGOBE"),
+                            headTable.getString("KOSTL"),
+                            headTable.getString("LTEXT")
+                    ));
+                }
+            }
+
+            JCoTable itemTable = function.getTableParameterList().getTable("T_ITEM");
+            if (itemTable != null && itemTable.getNumRows() > 0) {
+                for (int i = 0; i < itemTable.getNumRows(); i++) {
+                    itemTable.setRow(i);
+                    System.out.println(String.format("行号 %d: ZNUMC=%s, 物料=%s, 描述=%s, 数量=%f, " +
+                                    "基本单位=%s, 特殊库存=%s, 移动原因=%s, 原因=%s, 库存地点=%s, 描述=%s, 库存仓位=%s, 批次=%s, 转入工厂=%s, BEIZHU=%s\n",
+                            i,
+                            headTable.getString("ZNUMC"),
+                            headTable.getString("MATNR"),
+                            headTable.getString("MAKTX"),
+                            headTable.getString("MENGE"),
+                            headTable.getString("MEINS"),
+                            headTable.getString("SOBKZ"),
+                            headTable.getString("GRUND"),
+                            headTable.getString("GRTXT"),
+                            headTable.getString("LGORT"),
+                            headTable.getString("LGOBE"),
+                            headTable.getString("LGPBE"),
+                            headTable.getString("CHARG"),
+                            headTable.getString("WERKS_ZR"),
+                            headTable.getString("BEIZHU")
+                    ));
+                }
+            }
+
+            return "Material Info: " + output.getString("T_HEAD");
+        } catch (JCoException e) {
+            return "Error calling SAP Picking List: " + e.getMessage();
+        }
+    }
+
+    @GetMapping("/callSapMaterialMasterData")
+    @Operation(summary = "同步sap 物料主数据接口")
+    public String callSapMaterialMasterData() {
+        //
+        try {
+            JCoDestination destination = sapConnector.getDestination();
+            JCoFunction function = destination.getRepository().getFunction("ZPMS_002");
+
+            // 设置输入参数
+            JCoParameterList input = function.getImportParameterList();
+            input.setValue("IV_WERKS", "6011");
+
+            // 执行 RFC 调用
+            function.execute(destination);
+
+            // 获取输出参数
+
+            JCoParameterList output = function.getTableParameterList();
+            JCoTable etStockTable = function.getTableParameterList().getTable("ET_STOCK");
+            // JCoParameterList output = function.getExportParameterList();
+            if (CollUtil.isNotEmpty(output)) {
+                output.forEach(material -> {
+                    System.out.println(material.getName());
+                });
+            }
+            if (etStockTable != null && etStockTable.getNumRows() > 0) {
+                for (int i = 0; i < etStockTable.getNumRows(); i++) {
+                    etStockTable.setRow(i);
+                    System.out.println(String.format("行号 %d: 工厂=%s, 物料=%s, 数量=%s\n",
+                            i,
+                            etStockTable.getString("WERKS"),
+                            etStockTable.getString("MATNR"),
+                            etStockTable.getString("LABST")
+                    ));
+                }
+            }
+            return "Material Info: " + output.getString("ET_STOCK");
+        } catch (JCoException e) {
+            return "Error calling SAP Material Master Data: " + e.getMessage();
+        }
+    }
+
+    /**
+     * 查询所有SAP工厂
+     */
+    private List<String> factoryCodes(){
+        List<SapOrgRespDTO> sapOrgs = sapOrgApi.getSapOrgByType(1);
+        if (CollUtil.isEmpty(sapOrgs)) {
+            return CollUtil.empty(String.class);
+        }
+        List<String> factoryCodes = sapOrgs.stream()
+                .map(SapOrgRespDTO::getFactoryCode)
+                .collect(Collectors.toList());
+        return CollUtil.isEmpty(factoryCodes) ? CollUtil.empty(String.class) : factoryCodes;
+    }
+}

+ 3 - 4
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/IotProductClassifyService.java

@@ -4,8 +4,6 @@ import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
 import cn.iocoder.yudao.module.pms.controller.admin.vo.IotProductClassifyListReqVO;
 import cn.iocoder.yudao.module.pms.controller.admin.vo.IotProductClassifySaveReqVO;
 import cn.iocoder.yudao.module.pms.dal.dataobject.IotProductClassifyDO;
-import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptListReqVO;
-import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
 
 import java.util.*;
 
@@ -79,8 +77,9 @@ public interface IotProductClassifyService {
      * @param id 产品分类编号
      * @return 子产品分类列表
      */
-    default List<IotProductClassifyDO> getChildIotProductClassifyList(Long id) {
-        return getChildIotProductClassifyList(Collections.singleton(id));
+    default Set<Long> getChildIotProductClassifyList(Long id) {
+        List<IotProductClassifyDO> deviceCategories = getChildIotProductClassifyList(Collections.singleton(id));
+        return CollectionUtils.convertSet(deviceCategories, IotProductClassifyDO::getId);
     }
 
     /**

+ 11 - 5
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotbom/IotBomServiceImpl.java

@@ -8,15 +8,13 @@ import cn.iocoder.yudao.module.pms.controller.admin.iotbom.vo.IotBomPageReqVO;
 import cn.iocoder.yudao.module.pms.controller.admin.iotbom.vo.IotBomSaveReqVO;
 import cn.iocoder.yudao.module.pms.dal.dataobject.iotbom.IotBomDO;
 import cn.iocoder.yudao.module.pms.dal.mysql.iotbom.IotBomMapper;
+import cn.iocoder.yudao.module.pms.service.IotProductClassifyService;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.validation.annotation.Validated;
 
 import javax.annotation.Resource;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
+import java.util.*;
 
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 import static cn.iocoder.yudao.module.pms.enums.ErrorCodeConstant.IOT_BOM_NOT_EXISTS;
@@ -32,6 +30,8 @@ public class IotBomServiceImpl implements IotBomService {
 
     @Resource
     private IotBomMapper iotBomMapper;
+    @Resource
+    private IotProductClassifyService iotProductClassifyService;
 
     @Override
     @Transactional(rollbackFor = Exception.class)
@@ -86,7 +86,13 @@ public class IotBomServiceImpl implements IotBomService {
 
     @Override
     public List<IotBomDO> getBomList(IotBomListReqVO reqVO) {
-        List<IotBomDO> list = iotBomMapper.selectList(reqVO);
+        // 查询当前设备分类及子设备分类的所有BOM
+        Set<Long> ids = new HashSet<>();
+        if (Objects.nonNull(reqVO.getDeviceCategoryId())) {
+            ids = iotProductClassifyService.getChildIotProductClassifyList(reqVO.getDeviceCategoryId());
+            ids.add(reqVO.getDeviceCategoryId());
+        }
+        List<IotBomDO> list = iotBomMapper.selectList(reqVO, ids);
         list.sort(Comparator.comparing(IotBomDO::getSort));
         return list;
     }

+ 1 - 1
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotcommonbommaterial/IotCommonBomMaterialServiceImpl.java

@@ -79,7 +79,7 @@ public class IotCommonBomMaterialServiceImpl implements IotCommonBomMaterialServ
 
     @Override
     public List<IotCommonBomMaterialDO> getIotCommonBomMaterials(IotCommonBomMaterialSaveReqVO reqVO) {
-        return iotCommonBomMaterialMapper.selectList(reqVO);
+        return iotCommonBomMaterialMapper.selectList1(reqVO);
     }
 
 }

+ 15 - 1
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotdevicecategorytemplate/IotDeviceCategoryTemplateServiceImpl.java

@@ -6,11 +6,16 @@ import cn.iocoder.yudao.module.pms.controller.admin.iotdevicecategorytemplate.vo
 import cn.iocoder.yudao.module.pms.controller.admin.iotdevicecategorytemplate.vo.IotDeviceCategoryTemplateSaveReqVO;
 import cn.iocoder.yudao.module.pms.dal.dataobject.iotdevicecategorytemplate.IotDeviceCategoryTemplateDO;
 import cn.iocoder.yudao.module.pms.dal.mysql.iotdevicecategorytemplate.IotDeviceCategoryTemplateMapper;
+import cn.iocoder.yudao.module.pms.service.IotProductClassifyService;
 import org.springframework.stereotype.Service;
 import org.springframework.validation.annotation.Validated;
 
 import javax.annotation.Resource;
 
+import java.util.HashSet;
+import java.util.Objects;
+import java.util.Set;
+
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 import static cn.iocoder.yudao.module.pms.enums.ErrorCodeConstant.IOT_DEVICE_CATEGORY_TEMPLATE_NOT_EXISTS;
 
@@ -26,6 +31,9 @@ public class IotDeviceCategoryTemplateServiceImpl implements IotDeviceCategoryTe
     @Resource
     private IotDeviceCategoryTemplateMapper iotDeviceCategoryTemplateMapper;
 
+    @Resource
+    private IotProductClassifyService iotProductClassifyService;
+
     @Override
     public Long createIotDeviceCategoryTemplate(IotDeviceCategoryTemplateSaveReqVO createReqVO) {
         // 插入
@@ -65,7 +73,13 @@ public class IotDeviceCategoryTemplateServiceImpl implements IotDeviceCategoryTe
 
     @Override
     public PageResult<IotDeviceCategoryTemplateDO> getIotDeviceCategoryTemplatePage(IotDeviceCategoryTemplatePageReqVO pageReqVO) {
-        return iotDeviceCategoryTemplateMapper.selectPage(pageReqVO);
+        // 查询当前设备分类及子设备分类的所有BOM
+        Set<Long> ids = new HashSet<>();
+        if (Objects.nonNull(pageReqVO.getDeviceCategoryId())) {
+            ids = iotProductClassifyService.getChildIotProductClassifyList(pageReqVO.getDeviceCategoryId());
+            ids.add(pageReqVO.getDeviceCategoryId());
+        }
+        return iotDeviceCategoryTemplateMapper.selectPage(pageReqVO, ids);
     }
 
     @Override

+ 8 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotmainworkorder/IotMainWorkOrderService.java

@@ -8,6 +8,7 @@ import cn.iocoder.yudao.module.pms.dal.dataobject.iotmainworkorder.IotMainWorkOr
 
 import javax.validation.Valid;
 import java.util.List;
+import java.util.Map;
 
 /**
  * 保养工单 Service 接口
@@ -88,4 +89,11 @@ public interface IotMainWorkOrderService {
      * @return
      */
     void addWorkOrder(IotMainWorkOrderSaveVO saveVO);
+
+    /**
+     * 根据 保养结果 统计工单数量
+     *
+     * @return
+     */
+    List<Map<String, Integer>> allWorkOrderCountByResult();
 }

+ 6 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotmainworkorder/IotMainWorkOrderServiceImpl.java

@@ -24,6 +24,7 @@ import org.springframework.validation.annotation.Validated;
 import javax.annotation.Resource;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
 
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 import static cn.iocoder.yudao.module.pms.enums.ErrorCodeConstant.IOT_MAIN_WORK_ORDER_NOT_EXISTS;
@@ -193,4 +194,9 @@ public class IotMainWorkOrderServiceImpl implements IotMainWorkOrderService {
         // todo 处理库存减少
     }
 
+    @Override
+    public List<Map<String, Integer>> allWorkOrderCountByResult() {
+        return iotMainWorkOrderMapper.allWorkOrderCountByResult();
+    }
+
 }

+ 55 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotsappickinglist/IotSapPickingListService.java

@@ -0,0 +1,55 @@
+package cn.iocoder.yudao.module.pms.service.iotsappickinglist;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.pms.controller.admin.iotsappickinglist.vo.IotSapPickingListPageReqVO;
+import cn.iocoder.yudao.module.pms.controller.admin.iotsappickinglist.vo.IotSapPickingListSaveReqVO;
+import cn.iocoder.yudao.module.pms.dal.dataobject.iotsappickinglist.IotSapPickingListDO;
+
+import javax.validation.Valid;
+
+/**
+ * PMS SAP 领料单 Service 接口
+ *
+ * @author ruiqi
+ */
+public interface IotSapPickingListService {
+
+    /**
+     * 创建PMS SAP 领料单
+     *
+     * @param createReqVO 创建信息
+     * @return 编号
+     */
+    Long createIotSapPickingList(@Valid IotSapPickingListSaveReqVO createReqVO);
+
+    /**
+     * 更新PMS SAP 领料单
+     *
+     * @param updateReqVO 更新信息
+     */
+    void updateIotSapPickingList(@Valid IotSapPickingListSaveReqVO updateReqVO);
+
+    /**
+     * 删除PMS SAP 领料单
+     *
+     * @param id 编号
+     */
+    void deleteIotSapPickingList(Long id);
+
+    /**
+     * 获得PMS SAP 领料单
+     *
+     * @param id 编号
+     * @return PMS SAP 领料单
+     */
+    IotSapPickingListDO getIotSapPickingList(Long id);
+
+    /**
+     * 获得PMS SAP 领料单分页
+     *
+     * @param pageReqVO 分页查询
+     * @return PMS SAP 领料单分页
+     */
+    PageResult<IotSapPickingListDO> getIotSapPickingListPage(IotSapPickingListPageReqVO pageReqVO);
+
+}

+ 71 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotsappickinglist/IotSapPickingListServiceImpl.java

@@ -0,0 +1,71 @@
+package cn.iocoder.yudao.module.pms.service.iotsappickinglist;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.pms.controller.admin.iotsappickinglist.vo.IotSapPickingListPageReqVO;
+import cn.iocoder.yudao.module.pms.controller.admin.iotsappickinglist.vo.IotSapPickingListSaveReqVO;
+import cn.iocoder.yudao.module.pms.dal.dataobject.iotsappickinglist.IotSapPickingListDO;
+import cn.iocoder.yudao.module.pms.dal.mysql.iotsappickinglist.IotSapPickingListMapper;
+import org.springframework.stereotype.Service;
+import org.springframework.validation.annotation.Validated;
+
+import javax.annotation.Resource;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.pms.enums.ErrorCodeConstant.IOT_SAP_PICKING_LIST_NOT_EXISTS;
+
+/**
+ * PMS SAP 领料单 Service 实现类
+ *
+ * @author ruiqi
+ */
+@Service
+@Validated
+public class IotSapPickingListServiceImpl implements IotSapPickingListService {
+
+    @Resource
+    private IotSapPickingListMapper iotSapPickingListMapper;
+
+    @Override
+    public Long createIotSapPickingList(IotSapPickingListSaveReqVO createReqVO) {
+        // 插入
+        IotSapPickingListDO iotSapPickingList = BeanUtils.toBean(createReqVO, IotSapPickingListDO.class);
+        iotSapPickingListMapper.insert(iotSapPickingList);
+        // 返回
+        return iotSapPickingList.getId();
+    }
+
+    @Override
+    public void updateIotSapPickingList(IotSapPickingListSaveReqVO updateReqVO) {
+        // 校验存在
+        validateIotSapPickingListExists(updateReqVO.getId());
+        // 更新
+        IotSapPickingListDO updateObj = BeanUtils.toBean(updateReqVO, IotSapPickingListDO.class);
+        iotSapPickingListMapper.updateById(updateObj);
+    }
+
+    @Override
+    public void deleteIotSapPickingList(Long id) {
+        // 校验存在
+        validateIotSapPickingListExists(id);
+        // 删除
+        iotSapPickingListMapper.deleteById(id);
+    }
+
+    private void validateIotSapPickingListExists(Long id) {
+        if (iotSapPickingListMapper.selectById(id) == null) {
+            throw exception(IOT_SAP_PICKING_LIST_NOT_EXISTS);
+        }
+    }
+
+    @Override
+    public IotSapPickingListDO getIotSapPickingList(Long id) {
+        return iotSapPickingListMapper.selectById(id);
+    }
+
+    @Override
+    public PageResult<IotSapPickingListDO> getIotSapPickingListPage(IotSapPickingListPageReqVO pageReqVO) {
+        return iotSapPickingListMapper.selectPage(pageReqVO);
+    }
+
+}

BIN=BIN
yudao-module-pms/yudao-module-pms-biz/src/main/resources/lib/librfccm.so


BIN=BIN
yudao-module-pms/yudao-module-pms-biz/src/main/resources/lib/libsapjco3.so


BIN=BIN
yudao-module-pms/yudao-module-pms-biz/src/main/resources/lib/libsapjcorfc.so


BIN=BIN
yudao-module-pms/yudao-module-pms-biz/src/main/resources/lib/sapjco3.dll


BIN=BIN
yudao-module-pms/yudao-module-pms-biz/src/main/resources/lib/sapjco3.jar


BIN=BIN
yudao-module-pms/yudao-module-pms-biz/src/main/resources/lib/sapjcorfc.dll


+ 12 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/resources/mapper/static/IotMainWorkOrderMapper.xml

@@ -0,0 +1,12 @@
+<?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="cn.iocoder.yudao.module.pms.dal.mysql.iotmainworkorder.IotMainWorkOrderMapper">
+
+    <select id="allWorkOrderCountByResult" resultType="java.util.Map">
+        SELECT 'all' result, COUNT(1) num FROM rq_iot_main_work_order
+        UNION ALL
+        SELECT 'todo' result, COUNT(1) num FROM rq_iot_main_work_order WHERE result=1
+        UNION ALL
+        SELECT 'done' result, COUNT(1) num FROM rq_iot_main_work_order WHERE result=2;
+    </select>
+</mapper>

+ 2 - 0
yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/saporg/SapOrgApi.java

@@ -16,6 +16,8 @@ public interface SapOrgApi {
 
     SapOrgRespDTO getSapOrg(Long id);
 
+    List<SapOrgRespDTO> getSapOrgByType(Integer type);
+
     /**
      * 获得 sap org 信息数组
      *

+ 6 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/saporg/SapOrgApiImpl.java

@@ -27,6 +27,12 @@ public class SapOrgApiImpl implements SapOrgApi {
         return BeanUtils.toBean(sapOrg, SapOrgRespDTO.class);
     }
 
+    @Override
+    public List<SapOrgRespDTO> getSapOrgByType(Integer type) {
+        List<SapOrgDO> orgs = sapOrgService.getSapOrgList(null, type, null);
+        return BeanUtils.toBean(orgs, SapOrgRespDTO.class);
+    }
+
     @Override
     public List<SapOrgRespDTO> getSapOrgList(Collection<Long> ids) {
         List<SapOrgDO> sapOrgs = sapOrgService.getSapOrgList(ids);

+ 45 - 0
yudao-server/pom.xml

@@ -147,13 +147,58 @@
     <build>
         <!-- 设置构建的 jar 包名 -->
         <finalName>${project.artifactId}</finalName>
+        <!--
+        <resources>
+            <resource>
+                <directory>src/main/resources/lib</directory>
+                <targetPath>BOOT-INF/lib</targetPath>
+                <filtering>false</filtering>
+                <includes>
+                    <include>sapjco3.jar</include>
+                </includes>
+            </resource>
+        </resources> -->
+
         <plugins>
+            <!-- 依赖复制插件
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-dependency-plugin</artifactId>
+                <version>3.3.0</version>
+                <executions>
+                    <execution>
+                        <id>copy-sapjco</id>
+                        <phase>prepare-package</phase>
+                        <goals>
+                            <goal>copy</goal>
+                        </goals>
+                        <configuration>
+                            <artifactItems>
+                                <artifactItem>
+                                    <groupId>com.sap</groupId>
+                                    <artifactId>sapjco3</artifactId>
+                                    <version>3.0.12</version>
+                                    <outputDirectory>${project.build.directory}/BOOT-INF/lib</outputDirectory>
+                                    <destFileName>sapjco3.jar</destFileName>
+                                </artifactItem>
+                            </artifactItems>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin> -->
             <!-- 打包 -->
             <plugin>
                 <groupId>org.springframework.boot</groupId>
                 <artifactId>spring-boot-maven-plugin</artifactId>
                 <version>${spring.boot.version}</version>
                 <configuration>
+                    <!--
+                    <excludes>
+                        <exclude>
+                            <groupId>com.sap</groupId>
+                            <artifactId>sapjco3</artifactId>
+                        </exclude>
+                    </excludes> -->
                     <includeSystemScope>true</includeSystemScope>
                 </configuration>
                 <executions>

+ 12 - 0
yudao-server/src/main/resources/application-dev.yaml

@@ -175,6 +175,18 @@ dingtalk:
   URL_GET_SEND_MESSAGE: https://oapi.dingtalk.com/topapi/message/corpconversation/asyncsend_v2 # 发送钉钉工作消息
   URL_GET_USERINFO_BYMOBILE: https://oapi.dingtalk.com/topapi/v2/user/getbymobile # 根据用户手机号获取钉钉用户信息 url
 
+--- #################### SAP相关配置 ####################
+sap:
+  jco:
+    ashost: 172.17.25.120
+    sysnr: 00
+    client: 901
+    user: ZPMS
+    passwd: Kr2024.0
+    lang: zh
+    pool_capacity: 10
+    peak_limit: 20
+
 --- #################### 微信公众号相关配置 ####################
 wx: # 参见 https://github.com/Wechat-Group/WxJava/blob/develop/spring-boot-starters/wx-java-mp-spring-boot-starter/README.md 文档
   mp:

+ 12 - 1
yudao-server/src/main/resources/application-local.yaml

@@ -6,7 +6,7 @@ spring:
   autoconfigure:
     exclude:
       - com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure # 排除 Druid 的自动配置,使用 dynamic-datasource-spring-boot-starter 配置多数据源
-      - org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration # 默认 local 环境,不开启 Quartz 的自动配置
+      # - org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration # 默认 local 环境,不开启 Quartz 的自动配置
       - de.codecentric.boot.admin.server.config.AdminServerAutoConfiguration # 禁用 Spring Boot Admin 的 Server 的自动配置
       - de.codecentric.boot.admin.server.ui.config.AdminServerUiAutoConfiguration # 禁用 Spring Boot Admin 的 Server UI 的自动配置
       - de.codecentric.boot.admin.client.config.SpringBootAdminClientAutoConfiguration # 禁用 Spring Boot Admin 的 Client 的自动配置
@@ -203,6 +203,17 @@ dingtalk:
   URL_GET_SEND_MESSAGE: https://oapi.dingtalk.com/topapi/message/corpconversation/asyncsend_v2 # 发送钉钉工作消息
   URL_GET_USERINFO_BYMOBILE: https://oapi.dingtalk.com/topapi/v2/user/getbymobile # 根据用户手机号获取钉钉用户信息 url
 
+--- #################### SAP相关配置 ####################
+sap:
+  jco:
+    ashost: 172.17.25.120
+    sysnr: 00
+    client: 901
+    user: ZPMS
+    passwd: Kr2024.0
+    lang: zh
+    pool_capacity: 10
+    peak_limit: 20
 --- #################### 微信公众号、小程序相关配置 ####################
 wx:
   mp: # 公众号配置(必填),参见 https://github.com/Wechat-Group/WxJava/blob/develop/spring-boot-starters/wx-java-mp-spring-boot-starter/README.md 文档