feat(system): 新增物料BOM相关功能

- 新增物料BOM校验逻辑
- 添加货主信息更新功能
- 实现安全库存更新
- 优化物料导入导出功能
- 新增双单位支持
This commit is contained in:
tzy 2025-03-20 08:41:48 +08:00
parent c57f04959c
commit 918935b13a
10 changed files with 441 additions and 32 deletions

View File

@ -94,20 +94,28 @@ public class WxRobotUtil {
*/
public void sendMarkdownMsgToWeChatGroup(String markdownMsg, String robotId) {
String messageContent = markdownMsg.toString();
if (messageContent.length() > 4096) {
messageContent = messageContent.substring(0, 4096); // 截断到最大长度
}
HashMap<String, Object> paramMap = new HashMap<>();
HashMap<String, Object> markdownMap = new HashMap<>();
markdownMap.put("content", markdownMsg);
markdownMap.put("content", messageContent);
paramMap.put("msgtype", "markdown");
paramMap.put("markdown", markdownMap);
String sendUrl = SEND_MESSAGE_URL + "?key=" + robotId;
log.info("发送URL: {}", sendUrl);
log.info("发送参数: {}", paramMap);
ResponseEntity<Object> result = httpRequestUtil.doPost(sendUrl, paramMap);
JSONObject dataObject = JSONObject.parseObject(JSONObject.toJSONString(result.getBody()));
Integer errcode = Integer.valueOf(dataObject.get("errcode").toString());
if (errcode.equals(0)) {
log.info("企业微信推送Markdown消息成功时间" + new Date());
} else {
log.error("企业微信推送Markdown消息失败时间" + new Date());
}
log.error("企业微信推送Markdown消息失败时间" + new Date() + ",错误信息:" + dataObject.toJSONString());
}
}
/**
@ -118,7 +126,7 @@ public class WxRobotUtil {
* @param picUrl 图片链接
* @param robotId 机器人ID
*/
public void sendNewsToWeChatGroup(String title, String description, String url, String picUrl, String robotId) {
public void sendNewsToWeChatGroup(String title, String description, String url, String picUrl, String robotId) {
HashMap<String, Object> paramMap = new HashMap<>();
// 创建文章对象

View File

@ -378,6 +378,7 @@ public class BomDetailsController extends BaseController {
public R updateFBMaterial(@RequestBody List<Map<String, String>> bomDetailParams) {
List<BomDetails> bomDetailsList = new ArrayList<>();
Set<String> processedMaterials = new HashSet<>(); // 用于跟踪已处理的物料编码
List<String> failedMaterials = new ArrayList<>(); // 用于跟踪处理失败的物料
// 遍历前端传来的数据
for (Map<String, String> param : bomDetailParams) {
@ -393,18 +394,21 @@ public class BomDetailsController extends BaseController {
for (BomDetails material : bomDetails) {
// 只在第一次遇到该物料时新增父级物料
if (!processedMaterials.contains(material.getFNumber())) {
try { log.info("开始新增不存在的物料 ==> 物料图号: {}, 物料名称: {}", material.getPartNumber(), material.getName());
try {
log.info("开始新增不存在的物料 ==> 物料图号: {}, 物料名称: {}", material.getPartNumber(), material.getName());
Double fbWorkTime = iProcessRouteService.getFaWorkTime(material);
JdUtil.loadChengPinMaterialPreservation(material,fbWorkTime);
JdUtil.loadChengPinMaterialPreservation(material, fbWorkTime);
processedMaterials.add(material.getFNumber()); // 标记为已处理
} catch (Exception e) {
log.error("新增父级物料失败: {}", e.getMessage());
failedMaterials.add(material.getPartNumber());
}
}
// 获取工艺表中的非委外工时
Double fbWorkTime = iProcessRouteService.getFbWorkTime(material);
if (material.getPartNumber() != null && material.getName() != null&& material.getUnitWeight().equals("")) {
if (material.getPartNumber() != null && material.getName() != null
&& material.getUnitWeight().equals("")) {
String state = determineState(material);
log.info("开始新增不存在的物料 ==> 物料图号: {}, 物料名称: {}", material.getPartNumber(), material.getName());
@ -414,29 +418,82 @@ public class BomDetailsController extends BaseController {
log.info("新增物料成功 ==> 物料图号: {}, 物料名称: {}", material.getPartNumber(), material.getName());
material.setUnitWeight("新增成功");
} else {
log.error("新增物料失败 ==> 物料图号: {}, 物料名称: {}", material.getPartNumber(),
material.getName());
log.error("新增物料失败 ==> 物料图号: {}, 物料名称: {}", material.getPartNumber(), material.getName());
failedMaterials.add(material.getPartNumber());
}
// 更新物料状态
iBomDetailsService.updateByBo(BeanUtil.toBean(material, BomDetailsBo.class));
} catch (Exception e) {
log.error("处理物料时发生异常: {}", e.getMessage());
failedMaterials.add(material.getPartNumber());
}
} else {
log.error("物料信息不完整,无法新增物料");
failedMaterials.add(material.getPartNumber());
}
}
//保存物料之前进行BOM校验
List<JDBom> selectBomList = JdUtil.getSelectBomList(fnumber);
// 保存物料清单之前进行BOM校验
if (!validateBOM(fnumber, bomDetails)) {
log.error("BOM校验失败物料编码: {}", fnumber);
failedMaterials.add(fnumber);
continue; // 跳过保存
}
// 物料清单保存方法
FBloadBillOfMaterialsPreservation(bomDetails);
bomDetailsList.addAll(bomDetails);
}
}
// 返回处理结果
return R.ok("成功", bomDetailsList);
}
// BOM 校验方法
private boolean validateBOM(String fnumber, List<BomDetails> bomDetails) {
List<BomDetails> JDBomList = JdUtil.getSelectBomList(fnumber);
// 1. 判断BOM是否为空
if (JDBomList == null || JDBomList.isEmpty()) {
log.error("BOM为空物料编码: {}", fnumber);
return false; // BOM校验失败
}
// 2. 检查子项数量是否一致
if (JDBomList.size() != bomDetails.size()) {
log.error("BOM子项数量不一致物料编码: {},金蝶子项数量: {},传入子项数量: {}",
fnumber, JDBomList.size(), bomDetails.size());
return false; // BOM校验失败
}
// 3. 比较每个子项的内容
for (int i = 0; i < JDBomList.size(); i++) {
BomDetails jdBomDetail = JDBomList.get(i);
BomDetails inputBomDetail = bomDetails.get(i);
// 比较物料编码和名称
if (!jdBomDetail.getFNumber().equals(inputBomDetail.getFNumber()) ||
!jdBomDetail.getName().equals(inputBomDetail.getName())) {
log.error("BOM子项内容不一致物料编码: {},金蝶物料: {},传入物料: {}",
fnumber, jdBomDetail.getFNumber(), inputBomDetail.getFNumber());
return false; // BOM校验失败
}
// 比较分子和分母假设有分子和分母字段
if (!jdBomDetail.getDenominator().equals(inputBomDetail.getDenominator()) ||
!jdBomDetail.getQuantity().equals(inputBomDetail.getQuantity())) {
log.error("BOM子项分子分母不一致物料编码: {},金蝶分子: {}, 分母: {},传入分子: {}, 分母: {}",
fnumber, jdBomDetail.getDenominator(), jdBomDetail.getDenominator(),
inputBomDetail.getDenominator(), inputBomDetail.getDenominator());
return false; // BOM校验失败
}
}
// 如果所有校验通过
log.info("BOM校验通过物料编码: {}", fnumber);
return true; // BOM校验成功
}
/*
* 物料清单保存方法
@ -671,10 +728,10 @@ public class BomDetailsController extends BaseController {
fTreeEntityItem.addProperty("FNUMERATOR", details.getQuantity());
fTreeEntityItem.addProperty("FDENOMINATOR", details.getDenominator());
//添加货主信息 查看这个bom中是否符合货主信息
// 添加货主信息 查看这个bom中是否符合货主信息
String materialCode = details.getPartNumber();
Boolean vmiByCode = iMaterialTotalService.getVMIByCode(materialCode);
if (vmiByCode){
if (vmiByCode) {
fTreeEntityItem.addProperty("FOWNERTYPEID", "BD_Supplier");
JsonObject FOWNERID = new JsonObject();
fTreeEntityItem.add("FOWNERID", FOWNERID);
@ -1318,7 +1375,7 @@ public class BomDetailsController extends BaseController {
// 添加Model字段
model.addProperty("FMATERIALID", 0);
if(!(bomDetails1.getDanzhong() ==null)){
if (!(bomDetails1.getDanzhong() == null)) {
model.addProperty("F_HBYT_DZ", bomDetails1.getDanzhong());
}
model.addProperty("FSpecification", bomDetails1.getRemarks());
@ -1366,8 +1423,23 @@ public class BomDetailsController extends BaseController {
// 创建FBaseUnitId对象并加入SubHeadEntity
JsonObject fBaseUnitId = new JsonObject();
fBaseUnitId.addProperty("FNumber", "jian");
subHeadEntity.add("FBaseUnitId", fBaseUnitId);
if (bomDetails1.getPartNumber().startsWith("015") || bomDetails1.getName().contains("磨光棒")) {
if (bomDetails1.getWareHouse() != null) {
if (bomDetails1.getWareHouse().equals("KG")) {
fBaseUnitId.addProperty("FNumber", "004");
}
if (bomDetails1.getWareHouse().equals("")) {
fBaseUnitId.addProperty("FNumber", "003");
}
if (bomDetails1.getWareHouse().equals("mm")) {
fBaseUnitId.addProperty("FNumber", "005");
}
}
} else {
fBaseUnitId.addProperty("FNumber", "jian");
}
if (states.equals("1")) {
subHeadEntity.addProperty("FIsPurchase", true);
subHeadEntity.addProperty("FIsSale", true);
@ -1385,8 +1457,24 @@ public class BomDetailsController extends BaseController {
JsonObject subHeadEntity1 = new JsonObject();
model.add("SubHeadEntity1", subHeadEntity1);
JsonObject fStoreUnitId = new JsonObject();
fStoreUnitId.addProperty("FNumber", "jian");
subHeadEntity1.add("FStoreUnitID", fStoreUnitId);
// 如果是原材料的话且
if (bomDetails1.getPartNumber().startsWith("015") || bomDetails1.getName().contains("磨光棒")) {
if (bomDetails1.getWareHouse() != null) {
if (bomDetails1.getWareHouse().equals("KG")) {
fStoreUnitId.addProperty("FNumber", "004");
}
if (bomDetails1.getWareHouse().equals("")) {
fStoreUnitId.addProperty("FNumber", "003");
}
if (bomDetails1.getWareHouse().equals("mm")) {
fStoreUnitId.addProperty("FNumber", "005");
}
}
} else {
fStoreUnitId.addProperty("FNumber", "jian");
}
subHeadEntity1.addProperty("FUnitConvertDir", "1");
// 创建FStockId对象并加入SubHeadEntity1
@ -1407,6 +1495,21 @@ public class BomDetailsController extends BaseController {
// 创建FPurchaseUnitId对象并加入SubHeadEntity1
JsonObject fPurchaseUnitId = new JsonObject();
fPurchaseUnitId.addProperty("FNumber", "jian");
if (bomDetails1.getPartNumber().startsWith("015") || bomDetails1.getName().contains("磨光棒")) {
if (bomDetails1.getWareHouse() != null) {
if (bomDetails1.getWareHouse().equals("KG")) {
fPurchaseUnitId.addProperty("FNumber", "004");
}
if (bomDetails1.getWareHouse().equals("")) {
fPurchaseUnitId.addProperty("FNumber", "003");
}
if (bomDetails1.getWareHouse().equals("mm")) {
fPurchaseUnitId.addProperty("FNumber", "005");
}
}
} else {
fPurchaseUnitId.addProperty("FNumber", "jian");
}
subHeadEntity1.add("FPurchaseUnitId", fPurchaseUnitId);
// 创建SubHeadEntity3对象并加入Model
@ -1416,6 +1519,22 @@ public class BomDetailsController extends BaseController {
// 创建FPurchasePriceUnitId对象并加入SubHeadEntity3
JsonObject fPurchasePriceUnitId = new JsonObject();
fPurchasePriceUnitId.addProperty("FNumber", "jian");
if (bomDetails1.getPartNumber().startsWith("015") || bomDetails1.getName().contains("磨光棒")) {
if (bomDetails1.getWareHouse() != null) {
if (bomDetails1.getWareHouse().equals("KG")) {
fPurchasePriceUnitId.addProperty("FNumber", "004");
}
if (bomDetails1.getWareHouse().equals("")) {
fPurchasePriceUnitId.addProperty("FNumber", "003");
}
if (bomDetails1.getWareHouse().equals("mm")) {
fPurchasePriceUnitId.addProperty("FNumber", "005");
}
}
} else {
fPurchasePriceUnitId.addProperty("FNumber", "jian");
}
subHeadEntity3.add("FPurchasePriceUnitId", fPurchasePriceUnitId);
subHeadEntity3.addProperty("FIsQuota", false);
@ -1450,6 +1569,21 @@ public class BomDetailsController extends BaseController {
// 创建FProduceUnitId对象并加入SubHeadEntity5
JsonObject fProduceUnitId = new JsonObject();
fProduceUnitId.addProperty("FNumber", "jian");
if (bomDetails1.getPartNumber().startsWith("015") || bomDetails1.getName().contains("磨光棒")) {
if (bomDetails1.getWareHouse() != null) {
if (bomDetails1.getWareHouse().equals("KG")) {
fProduceUnitId.addProperty("FNumber", "004");
}
if (bomDetails1.getWareHouse().equals("")) {
fProduceUnitId.addProperty("FNumber", "003");
}
if (bomDetails1.getWareHouse().equals("mm")) {
fProduceUnitId.addProperty("FNumber", "005");
}
}
} else {
fProduceUnitId.addProperty("FNumber", "jian");
}
subHeadEntity5.add("FProduceUnitId", fProduceUnitId);
// 实际作工时并加入SubHeadEntity5
@ -1461,7 +1595,24 @@ public class BomDetailsController extends BaseController {
// 创建FBOMUnitId对象并加入SubHeadEntity5
JsonObject fBOMUnitId = new JsonObject();
fBOMUnitId.addProperty("FNumber", "jian");
if (bomDetails1.getPartNumber().startsWith("015") || bomDetails1.getName().contains("磨光棒")) {
if (bomDetails1.getWareHouse() != null) {
if (bomDetails1.getWareHouse().equals("KG")) {
fBOMUnitId.addProperty("FNumber", "004");
}
if (bomDetails1.getWareHouse().equals("")) {
fBOMUnitId.addProperty("FNumber", "003");
}
if (bomDetails1.getWareHouse().equals("mm")) {
fBOMUnitId.addProperty("FNumber", "005");
}
}
} else {
fBOMUnitId.addProperty("FNumber", "jian");
}
subHeadEntity5.add("FBOMUnitId", fBOMUnitId);
if (states.equals("1")) {
subHeadEntity5.addProperty("FIsMainPrd", false);
} else {
@ -1880,11 +2031,7 @@ public class BomDetailsController extends BaseController {
break;
}
subHeadEntity5.add("FBOMUnitId", fBOMUnitId);
if (states.equals("1")) {
subHeadEntity5.addProperty("FIsMainPrd", false);
} else {
subHeadEntity5.addProperty("FIsMainPrd", true);
}
subHeadEntity5.addProperty("FIsMainPrd", !states.equals("1"));
subHeadEntity5.addProperty("FIssueType", "1");
// 创建FPickStockId对象并加入SubHeadEntity5

View File

@ -21,10 +21,17 @@ import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.google.gson.JsonObject;
import com.kingdee.bos.webapi.sdk.K3CloudApi;
import com.ruoyi.common.utils.HttpRequestUtil;
import com.ruoyi.common.utils.WxRobotUtil;
import com.ruoyi.system.domain.SafetyStock;
import com.ruoyi.system.domain.WlStockData;
import com.ruoyi.system.domain.vo.SafetyStockVo;
import com.ruoyi.system.domain.vo.WlStockDataVo;
import com.ruoyi.system.mapper.SafetyStockMapper;
import com.ruoyi.system.mapper.WlStockDataMapper;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.RequiredArgsConstructor;
@ -70,7 +77,7 @@ public class KingdeeWorkCenterDataController extends BaseController {
private final IKingdeeWorkCenterDataService iKingdeeWorkCenterDataService;
private final HttpRequestUtil httpRequestUtil;
private static final Logger log = LoggerFactory.getLogger(KingdeeWorkCenterDataController.class);
private final WlStockDataMapper baseMapper;;
/**
* 查询金蝶工段数据列表
*/
@ -263,7 +270,12 @@ public class KingdeeWorkCenterDataController extends BaseController {
"> 数量信息:计划<font color=\"comment\">1.00</font>,已转入<font color=\"comment\">1.00</font>,已转出<font color=\"comment\">0.00</font>\n\n"
+
"请相关部门负责人关注并及时处理!";
wxRobotUtil.sendMarkdownMsgToWeChatGroup(markdownMsg, robotId);
String messageContent = markdownMsg;
int maxLength = 4096;
for (int i = 0; i < messageContent.length(); i += maxLength) {
String part = messageContent.substring(i, Math.min(i + maxLength, messageContent.length()));
wxRobotUtil.sendMarkdownMsgToWeChatGroup(part, robotId);
}
return R.ok();
}
@ -336,7 +348,12 @@ public class KingdeeWorkCenterDataController extends BaseController {
// 添加结束语
markdownMsg.append("请相关部门负责人关注并及时处理!");
// 发送消息
wxRobotUtil.sendMarkdownMsgToWeChatGroup(markdownMsg.toString(), robotId);
String messageContent = markdownMsg.toString();
int maxLength = 4096;
for (int i = 0; i < messageContent.length(); i += maxLength) {
String part = messageContent.substring(i, Math.min(i + maxLength, messageContent.length()));
wxRobotUtil.sendMarkdownMsgToWeChatGroup(part, robotId);
}
return R.ok();
@ -556,5 +573,80 @@ public class KingdeeWorkCenterDataController extends BaseController {
return R.fail("发送工段数据失败:" + e.getMessage());
}
}
@SaCheckPermission("system:workCenterData:getKuCun")
@Log(title = "金蝶工段数据延期数据", businessType = BusinessType.DELETE)
@PostMapping("/getKuCun")
public R<Void> getKuCun() {
String robotId = "0d2390e0-3e74-49fc-bd02-900b86bf0f55";
StringBuilder markdownMsg = new StringBuilder();
// 获取今天的日期
Date today = new Date();
Date sixAM = DateUtil.parse(DateUtil.format(today, "yyyy-MM-dd") + " 06:00:00");
// 创建查询条件
LambdaQueryWrapper<WlStockData> safetyStockLambdaQueryWrapper = new LambdaQueryWrapper<>();
// 获取时间在今天6点以后的数据
safetyStockLambdaQueryWrapper.ge(WlStockData::getCreateTime, sixAM);
List<WlStockData> safetyStocks = baseMapper.selectList(safetyStockLambdaQueryWrapper);
try {
if (CollUtil.isEmpty(safetyStocks)) {
markdownMsg.append("## 🚀 安全库存提醒\n\n")
.append("今日暂无安全库存预警数据。");
} else {
markdownMsg.append("## 🚀 安全库存提醒\n\n")
.append("以下是今日的安全库存预警数据:\n\n");
// 只显示前三个安全库存数据
int count = Math.min(3, safetyStocks.size());
for (int i = 0; i < count; i++) {
WlStockData safetyStock = safetyStocks.get(i);
markdownMsg.append("### 物料信息\n")
.append("#### 物料编号: **").append(safetyStock.getMaterialCode()).append("**\n")
.append("> **物料名称:** ").append(safetyStock.getMaterialName()).append("\n")
.append("> **可用库存:** ").append(String.format("%.2f", safetyStock.getAvailableStock())).append("\n")
.append("> **当前库存:** ").append(String.format("%.2f", safetyStock.getCurrentStock())).append("\n")
.append("> **最大库存:** ").append(String.format("%.2f", safetyStock.getMaxsafetyStock())).append("\n")
.append("> **创建时间:** ").append(DateUtil.formatDateTime(safetyStock.getCreateTime())).append("\n")
.append("---\n"); // 添加分隔线
}
// 添加总数汇总
markdownMsg.append("### 总数汇总\n")
.append("> 今日安全库存预警数据总数: **").append(safetyStocks.size()).append("**\n");
}
// 生成Excel文件
String fileName = String.format("%s安全预警数据_%s.xlsx","企标", DateUtil.format(new Date(), "yyyyMMddHHmmss"));
String filePath = FileUtils.getTempDirectoryPath() + File.separator + fileName;
// 使用EasyExcel写入数据
EasyExcel.write(filePath, WlStockDataVo.class)
.sheet("工段数据")
.doWrite(BeanUtil.copyToList(safetyStocks, WlStockDataVo.class));
// 发送Excel文件
File excelFile = new File(filePath);
wxRobotUtil.sendFileToWeChatGroup(excelFile, robotId);
// 删除临时文件
FileUtils.deleteQuietly(excelFile);
markdownMsg.append("\n详细数据请查看发送的Excel文件");
String messageContent = markdownMsg.toString();
int maxLength = 1000;
for (int i = 0; i < messageContent.length(); i += maxLength) {
String part = messageContent.substring(i, Math.min(i + maxLength, messageContent.length()));
wxRobotUtil.sendMarkdownMsgToWeChatGroup(part, robotId);
}
return R.ok();
} catch (Exception e) {
markdownMsg.append("- ").append("安全库存").append(" (获取失败: ").append(e.getMessage()).append(")\n");
return R.fail("发送安全库存数据失败:" + e.getMessage());
}
}
}

View File

@ -101,7 +101,6 @@ public class WlStockDataController extends BaseController {
/**
* 删除安全库存单据
*
* @param ids 主键串
*/
@SaCheckPermission("system:stockData:remove")
@ -114,8 +113,6 @@ public class WlStockDataController extends BaseController {
/**
* 生成安全库存单据
*
* @return
*/
@SaCheckPermission("system:stockData:generateDoc")
@Log(title = "安全库存单据", businessType = BusinessType.OTHER)

View File

@ -45,7 +45,7 @@ import java.util.Map;
/**
* 工序任务
*
* @author ruoyi
* @author tzy
* @date 2024-06-27
*/
@Validated
@ -54,7 +54,7 @@ import java.util.Map;
@RequestMapping("/system/procedure")
public class WorkProcedureController extends BaseController {
private static final Logger log = LoggerFactory.getLogger(KingdeeWorkCenterDataController.class);
private static final Logger log = LoggerFactory.getLogger(WorkProcedureController.class);
private final IWorkProcedureService iWorkProcedureService;
private final IKingdeeWorkCenterDataService iKingdeeWorkCenterDataService;

View File

@ -14,6 +14,7 @@ public class ProductctionPlanGatteDto {
private String text;
private String start_date;
private String end_date;
//天数
private Long duration;
private Integer type;
private Boolean open;

View File

@ -50,4 +50,6 @@ public interface IWorkProcedureService {
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
List<ProductctionPlanGatteDto> getGongXuTasks(String text);
List<ProductctionPlanGatteDto> getAllTasks1();
}

View File

@ -145,7 +145,6 @@ public class EleMaterialsServiceImpl implements IEleMaterialsService {
@Override
public Boolean updateByBo(EleMaterialsBo bo) {
EleMaterials update = BeanUtil.toBean(bo, EleMaterials.class);
validEntityBeforeSave(update);
return baseMapper.updateById(update) > 0;
}

View File

@ -25,6 +25,7 @@ import com.ruoyi.system.mapper.SafetyStockMapper;
import com.ruoyi.system.mapper.WlStockDataMapper;
import com.ruoyi.system.runner.JdUtil;
import com.ruoyi.system.service.IWlStockDataService;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -229,7 +230,69 @@ public class WlStockDataServiceImpl implements IWlStockDataService {
}
}
}
@XxlJob("generateDoc2")
public List<WlStockData> generateDoc2() {
List<SafetyStock> safetyStocks = safetyStockMapper.selectList();
if (CollectionUtils.isEmpty(safetyStocks)) {
logger.warn("没有找到安全库存数据");
logMessages("没有找到安全库存数据");
return Collections.emptyList();
}
// 使用固定大小的线程池而不是CachedThreadPool避免创建过多线程
ExecutorService executor = Executors.newFixedThreadPool(THREAD_POOL_SIZE);
List<WlStockData> wlStockDataList = Collections.synchronizedList(new ArrayList<>());
try {
// 创建所有任务的Future列表
List<CompletableFuture<Void>> futures = safetyStocks.stream()
.map(safetyStock -> CompletableFuture
.supplyAsync(() -> processWithRetry(safetyStock), executor)
.thenAccept(wlStockData -> {
if (wlStockData != null) {
wlStockDataList.add(wlStockData);
}
})
.exceptionally(e -> {
logger.error("处理安全库存数据失败: {}", safetyStock.getMaterialCode(), e);
logMessages("处理安全库存数据失败: " + safetyStock.getMaterialCode());
return null;
}))
.collect(Collectors.toList());
// 等待所有任务完成
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
.get(5, TimeUnit.MINUTES); // 设置整体超时时间
// 批量保存数据
if (!wlStockDataList.isEmpty()) {
boolean success = baseMapper.insertBatch(wlStockDataList);
logger.info("批量插入{}条数据: {}", wlStockDataList.size(), success);
logMessages("批量插入" + wlStockDataList.size() + "条数据成功");
}
return wlStockDataList;
} catch (TimeoutException e) {
logger.error("生成文档操作超时", e);
logMessages("生成单据操作超时");
throw new ServiceException("操作超时,请稍后重试");
} catch (Exception e) {
logger.error("生成文档时发生错误", e);
logMessages("生成单据发生错误: " + e.getMessage());
throw new ServiceException("生成文档失败:" + e.getMessage());
} finally {
executor.shutdown();
try {
if (!executor.awaitTermination(30, TimeUnit.SECONDS)) {
executor.shutdownNow();
}
} catch (InterruptedException e) {
executor.shutdownNow();
Thread.currentThread().interrupt();
}
}
}
private WlStockData processWithRetry(SafetyStock safetyStock) {
int retryCount = 0;
while (retryCount < MAX_RETRIES) {
@ -356,11 +419,11 @@ public class WlStockDataServiceImpl implements IWlStockDataService {
wlStockData.setMaxsafetyStock(BigDecimal.valueOf(maxSafetyStock));
wlStockData.setSecAvbqty(BigDecimal.valueOf(fSecAVBQty));
wlStockData.setDocumentType(String.format("物料编码:%s||可用库存:%.2f||库存量:%.2f||生产订单:%.2f||" +
/* wlStockData.setDocumentType(String.format("物料编码:%s||可用库存:%.2f||库存量:%.2f||生产订单:%.2f||" +
"采购订单:%.2f||预留量:%.2f||最大库存:%.2f||最低库存:%.2f",
safetyStock.getMaterialCode(), availableStock, fSecAVBQty, productionQty,
purchaseQty, fSecQty, maxSafetyStock, minSafetyStock));
*/
return wlStockData;
}

View File

@ -1,11 +1,17 @@
package com.ruoyi.system.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.gson.JsonObject;
import com.kingdee.bos.webapi.sdk.K3CloudApi;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.domain.ProductionPlan;
@ -22,6 +28,7 @@ import org.springframework.stereotype.Service;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;
@ -130,6 +137,99 @@ public class WorkProcedureServiceImpl implements IWorkProcedureService {
return tasks;
}
public List<ProductctionPlanGatteDto> getAllTasks1() {
try {
K3CloudApi client = new K3CloudApi();
JsonObject parameter = new JsonObject();
parameter.addProperty("FWorkCenterName", "机一工段");
Object[] parameters = new Object[] { parameter.toString() };
String execute = client.execute(
"Ljint.Kingdee.YiTe.KanBan.WebApi.ProduceWebApi.ExecuteService,Ljint.Kingdee.YiTe.KanBan.WebApi",
parameters);
// 解析响应
JSONObject response = JSONObject.parseObject(execute);
if (!"true".equals(response.getString("IsSuccess"))) {
String errorMsg = response.getString("Message");
return null;
}
// 获取明天的日期字符串 (格式: yyyy-MM-dd)
String tomorrow = DateUtil.format(DateUtil.tomorrow().toLocalDateTime().plusDays(1), "yyyy-MM-dd");
// 获取数据数组
JSONArray dataArray = response.getJSONArray("data");
if (dataArray == null || dataArray.isEmpty()) {
return null;
}
List<ProductctionPlanGatteDto> tasks = new ArrayList<>();
DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
for (int i = 0; i < dataArray.size(); i++) {
JSONArray queryList = dataArray.getJSONObject(i).getJSONArray("QueryList");
for (int j = 0; j < queryList.size(); j++) {
JSONObject item = queryList.getJSONObject(j);
// 获取计划结束时间并转换为日期格式进行比较
String planFinishTime = item.getString("FOperPlanFinishTime2");
if (org.springframework.util.StringUtils.hasText(planFinishTime)) {
// 提取日期部分进行比较 (去掉时间部分)
String finishDate = planFinishTime.split(" ")[0];
// 只处理明天结束的工单
if (tomorrow.equals(finishDate)) {
// 转换为 ProductctionPlanGatteDto 对象
ProductctionPlanGatteDto task = new ProductctionPlanGatteDto();
task.setId(item.getLong("Id")); // 假设有 Id 字段
task.setText(item.getString("MoOrderNo"));
task.setToolTipsTxt(item.getString("FProcessName"));
task.setType(1);
LocalDate startDate = item.getDate("FOperPlanStartTime2").toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
LocalDate endDate = item.getDate("FOperPlanFinishTime2").toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
task.setStart_date(startDate.toString());
task.setEnd_date(endDate.toString());
long duration = ChronoUnit.DAYS.between(startDate, endDate);
task.setDuration(duration);
task.setOpen(true);
task.setProgress(1L);
task.setStatus("yellow");
task.setParent(null); // 父任务没有parent
tasks.add(task);
// 处理子任务
JSONArray subTasksArray = item.getJSONArray("SubTasks");
if (subTasksArray != null) {
for (int k = 0; k < subTasksArray.size(); k++) {
JSONObject subTaskItem = subTasksArray.getJSONObject(k);
ProductctionPlanGatteDto subTask = new ProductctionPlanGatteDto();
subTask.setId(subTaskItem.getLong("SubTaskId"));
subTask.setText(subTaskItem.getString("FProcessName"));
subTask.setToolTipsTxt(subTaskItem.getString("SubTaskProcessName"));
subTask.setStart_date(subTaskItem.getString("FOperPlanStartTime2"));
subTask.setEnd_date(subTaskItem.getString("FOperPlanFinishTime2"));
subTask.setDuration(subTaskItem.getLong("1"));
subTask.setOpen(true);
subTask.setProgress(1L);
subTask.setStatus("yellow");
subTask.setParent(task.getId()); // 设置父任务ID
tasks.add(subTask);
}
}
}
}
}
}
return tasks;
} catch (Exception e) {
return null;
}
}
/**
* 查询工序任务