|
|
@@ -38,6 +38,7 @@ import java.text.SimpleDateFormat;
|
|
|
import java.time.LocalDate;
|
|
|
import java.time.LocalTime;
|
|
|
import java.util.*;
|
|
|
+import java.util.function.Supplier;
|
|
|
import java.util.stream.Collectors;
|
|
|
|
|
|
@Slf4j
|
|
|
@@ -59,6 +60,7 @@ public class McYdServiceImpl implements McYdService {
|
|
|
|
|
|
@Autowired
|
|
|
private DDClient_Contacts ddClient_contacts;
|
|
|
+
|
|
|
@Override
|
|
|
@Async
|
|
|
public void updateFormDataVersion(Map map) {
|
|
|
@@ -344,6 +346,100 @@ public class McYdServiceImpl implements McYdService {
|
|
|
return McR.success();
|
|
|
}
|
|
|
|
|
|
+ @Override
|
|
|
+ public McR multiLocationOutboundAI(Map map) {
|
|
|
+ String formInstId = UtilMap.getString(map, "formInstId");
|
|
|
+ log.info("出库单实例id:" + formInstId);
|
|
|
+
|
|
|
+ // 查询出库单主数据(支持重试)
|
|
|
+ Map d = executeWithRetry(() -> ydClient.queryData(YDParam.builder()
|
|
|
+ .formInstId(formInstId)
|
|
|
+ .formUuid("FORM-3208DFE5463549A9A57FB94358A75E80PV5F")
|
|
|
+ .appType("APP_GNQ1RGK68X4JNZUEU8RQ")
|
|
|
+ .systemToken("XH866P81QDOTQ0218TGZM9WCNXOF24WIP488M7A5")
|
|
|
+ .userId("332051151139376769").build(),
|
|
|
+ YDConf.FORM_QUERY.retrieve_id).getFormData(),
|
|
|
+ "查询出库单主数据", 3, 1000);
|
|
|
+
|
|
|
+ System.out.println("出库单数据:" + d);
|
|
|
+ List<Map> mapList = (List<Map>) d.get("tableField_m8mo8506");
|
|
|
+ System.out.println("出库单明细数据:" + mapList);
|
|
|
+
|
|
|
+ for (Map map1 : mapList) {
|
|
|
+ String componentInstId = map1.get("textField_ma1usp6o").toString();
|
|
|
+ BigDecimal outQuantity = new BigDecimal(map1.get("numberField_m8mo8508").toString());
|
|
|
+ processOutboundComponent(componentInstId, map1, outQuantity);
|
|
|
+ }
|
|
|
+ return McR.success();
|
|
|
+ }
|
|
|
+
|
|
|
+ private void processOutboundComponent(String componentInstId, Map detailRow, BigDecimal outQuantity) {
|
|
|
+ String componentName = detailRow.get("textField_m99kztjo").toString();
|
|
|
+ executeWithRetry(() -> {
|
|
|
+ // 1. 查询零部件当前完整数据
|
|
|
+ Map partData = ydClient.queryData(YDParam.builder()
|
|
|
+ .formInstId(componentInstId)
|
|
|
+ .formUuid("FORM-2353BE632D97434DAD55AEBD0866C44DVAT5")
|
|
|
+ .appType("APP_GNQ1RGK68X4JNZUEU8RQ")
|
|
|
+ .systemToken("XH866P81QDOTQ0218TGZM9WCNXOF24WIP488M7A5")
|
|
|
+ .userId("332051151139376769").build(),
|
|
|
+ YDConf.FORM_QUERY.retrieve_id).getFormData();
|
|
|
+
|
|
|
+ // 2. 获取当前可用库存(正确字段:numberField_m8gz97nk)
|
|
|
+ BigDecimal currentAvailable = parseBigDecimal(partData.get("numberField_m8gz97nk"));
|
|
|
+ // 计算出库后数量(应该 = currentAvailable - outQuantity)
|
|
|
+ BigDecimal newAvailable = currentAvailable.subtract(outQuantity);
|
|
|
+ System.out.println("当前可用库存:" + currentAvailable + ",出库后数量:" + newAvailable);
|
|
|
+
|
|
|
+ // 3. 解析子表仓库信息(取第一条)
|
|
|
+ String subTableJson = partData.get("tableField_m96gje14").toString();
|
|
|
+ JSONArray subArray = JSON.parseArray(subTableJson);
|
|
|
+ if (subArray == null || subArray.isEmpty()) {
|
|
|
+ throw new RuntimeException("零部件[" + componentName + "]子表数据为空,无法更新库存");
|
|
|
+ }
|
|
|
+ JSONObject warehouseObj = subArray.getJSONObject(0);
|
|
|
+ String warehouse = warehouseObj.getString("selectField_m88f1qi8");
|
|
|
+ String warehouseLocation = warehouseObj.getString("textField_m8mnxgql");
|
|
|
+ String safetyValue = warehouseObj.getString("numberField_m8873fn4");
|
|
|
+ BigDecimal currentWarehouseQty = parseBigDecimal(warehouseObj.getString("numberField_m9c8n9go"));
|
|
|
+ BigDecimal newWarehouseQty = currentWarehouseQty.subtract(outQuantity);
|
|
|
+ System.out.println("当前仓库数量:" + currentWarehouseQty + ",出库后仓库数量:" + newWarehouseQty);
|
|
|
+
|
|
|
+ // 4. 获取冻结数量(字段:numberField_m8obn6wl)并计算新冻结数量
|
|
|
+ BigDecimal currentFreeze = parseBigDecimal(partData.get("numberField_m8obn6wl"));
|
|
|
+ BigDecimal newFreeze = currentFreeze.add(outQuantity);
|
|
|
+ System.out.println("当前冻结数量:" + currentFreeze + ",新冻结数量:" + newFreeze);
|
|
|
+
|
|
|
+ // 5. 构建子表更新数据(完整替换)
|
|
|
+ List<Map<String, Object>> newSubTable = new ArrayList<>();
|
|
|
+ Map<String, Object> newRow = new HashMap<>();
|
|
|
+ newRow.put("selectField_m88f1qi8", warehouse);
|
|
|
+ newRow.put("textField_m8mnxgql", warehouseLocation);
|
|
|
+ newRow.put("numberField_m8873fn4", safetyValue);
|
|
|
+ newRow.put("numberField_m9c8n9go", newWarehouseQty); // 仓库数量更新为出库后数量
|
|
|
+ newSubTable.add(newRow);
|
|
|
+
|
|
|
+ // 6. 构建主表更新字段
|
|
|
+ Map<String, Object> updateData = new HashMap<>();
|
|
|
+ updateData.put("tableField_m96gje14", newSubTable);
|
|
|
+ updateData.put("numberField_m8obn6wl", newFreeze); // 冻结数量累加
|
|
|
+ updateData.put("numberField_m8gz97nk", newAvailable); // 可用库存更新为出库后数量
|
|
|
+
|
|
|
+ // 7. 执行原子更新(一次调用同时修改主表和子表)
|
|
|
+ ydClient.operateData(YDParam.builder()
|
|
|
+ .formInstId(componentInstId)
|
|
|
+ .formUuid("FORM-2353BE632D97434DAD55AEBD0866C44DVAT5")
|
|
|
+ .appType("APP_GNQ1RGK68X4JNZUEU8RQ")
|
|
|
+ .systemToken("XH866P81QDOTQ0218TGZM9WCNXOF24WIP488M7A5")
|
|
|
+ .updateFormDataJson(JSONObject.toJSONString(updateData))
|
|
|
+ .userId("332051151139376769").build(),
|
|
|
+ YDConf.FORM_OPERATION.update);
|
|
|
+
|
|
|
+ System.out.println("----------------------零部件[" + componentName + "]主表及子表数据原子更新完毕!------------------");
|
|
|
+ return null;
|
|
|
+ }, "处理出库零部件[" + componentName + "]实例[" + componentInstId + "]", 3, 1000);
|
|
|
+ }
|
|
|
+
|
|
|
@Override
|
|
|
public McR WarehouseStorage(Map map) {
|
|
|
String formInstId = UtilMap.getString(map,"formInstId");//实例id(入库单)
|
|
|
@@ -420,6 +516,135 @@ public class McYdServiceImpl implements McYdService {
|
|
|
return McR.success();
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public McR WarehouseStorageAI(Map map) {
|
|
|
+ String formInstId = UtilMap.getString(map, "formInstId");
|
|
|
+ log.info("入库单实例id:" + formInstId);
|
|
|
+
|
|
|
+ Map d = executeWithRetry(() -> ydClient.queryData(YDParam.builder()
|
|
|
+ .formInstId(formInstId)
|
|
|
+ .formUuid("FORM-6DED8EB4CF0446DB8841C7798E106F2886OH")
|
|
|
+ .appType("APP_GNQ1RGK68X4JNZUEU8RQ")
|
|
|
+ .systemToken("XH866P81QDOTQ0218TGZM9WCNXOF24WIP488M7A5")
|
|
|
+ .userId("332051151139376769").build(),
|
|
|
+ YDConf.FORM_QUERY.retrieve_id).getFormData(),
|
|
|
+ "查询入库单主数据", 3, 1000);
|
|
|
+
|
|
|
+ System.out.println("入库单数据:" + d);
|
|
|
+ List<Map> mapList = (List<Map>) d.get("tableField_m8mseubi");
|
|
|
+ System.out.println("入库单明细数据:" + mapList);
|
|
|
+
|
|
|
+ for (Map map1 : mapList) {
|
|
|
+ String componentInstId = map1.get("textField_ma3jhnpr").toString();
|
|
|
+ BigDecimal inQuantity = new BigDecimal(map1.get("numberField_m8mseubm").toString());
|
|
|
+ processComponent(componentInstId, map1, inQuantity);
|
|
|
+ }
|
|
|
+ return McR.success();
|
|
|
+ }
|
|
|
+
|
|
|
+ private void processComponent(String componentInstId, Map detailRow, BigDecimal inQuantity) {
|
|
|
+ String componentName = detailRow.get("textField_m9b1vd2w").toString();
|
|
|
+ executeWithRetry(() -> {
|
|
|
+ Map partData = ydClient.queryData(YDParam.builder()
|
|
|
+ .formInstId(componentInstId)
|
|
|
+ .formUuid("FORM-2353BE632D97434DAD55AEBD0866C44DVAT5")
|
|
|
+ .appType("APP_GNQ1RGK68X4JNZUEU8RQ")
|
|
|
+ .systemToken("XH866P81QDOTQ0218TGZM9WCNXOF24WIP488M7A5")
|
|
|
+ .userId("332051151139376769").build(),
|
|
|
+ YDConf.FORM_QUERY.retrieve_id).getFormData();
|
|
|
+
|
|
|
+ String subTableJson = partData.get("tableField_m96gje14").toString();
|
|
|
+ JSONArray subArray = JSON.parseArray(subTableJson);
|
|
|
+ if (subArray == null || subArray.isEmpty()) {
|
|
|
+ // 改用 RuntimeException,此类业务错误不应重试
|
|
|
+ throw new RuntimeException("零部件[" + componentName + "]子表数据为空,无法更新库存");
|
|
|
+ }
|
|
|
+ JSONObject warehouseObj = subArray.getJSONObject(0);
|
|
|
+ String warehouse = warehouseObj.getString("selectField_m88f1qi8");
|
|
|
+ String warehouseLocation = warehouseObj.getString("textField_m8mnxgql");
|
|
|
+ String safetyValue = warehouseObj.getString("numberField_m8873fn4");
|
|
|
+ BigDecimal currentWarehouseQty = parseBigDecimal(warehouseObj.getString("numberField_m9c8n9go"));
|
|
|
+
|
|
|
+ BigDecimal currentVirtual = parseBigDecimal(partData.get("numberField_m8obn6wq"));
|
|
|
+ BigDecimal currentAvailable = parseBigDecimal(partData.get("numberField_m8gz97nk"));
|
|
|
+
|
|
|
+ BigDecimal newWarehouseQty = currentWarehouseQty.add(inQuantity);
|
|
|
+ BigDecimal newVirtual = currentVirtual.add(inQuantity);
|
|
|
+ BigDecimal newAvailable = currentAvailable.add(inQuantity);
|
|
|
+
|
|
|
+ List<Map<String, Object>> newSubTable = new ArrayList<>();
|
|
|
+ Map<String, Object> newRow = new HashMap<>();
|
|
|
+ newRow.put("selectField_m88f1qi8", warehouse);
|
|
|
+ newRow.put("textField_m8mnxgql", warehouseLocation);
|
|
|
+ newRow.put("numberField_m8873fn4", safetyValue);
|
|
|
+ newRow.put("numberField_m9c8n9go", newWarehouseQty);
|
|
|
+ newSubTable.add(newRow);
|
|
|
+
|
|
|
+ Map<String, Object> updateData = new HashMap<>();
|
|
|
+ updateData.put("tableField_m96gje14", newSubTable);
|
|
|
+ updateData.put("numberField_m8obn6wq", newVirtual);
|
|
|
+ updateData.put("numberField_m8gz97nk", newAvailable);
|
|
|
+
|
|
|
+ ydClient.operateData(YDParam.builder()
|
|
|
+ .formInstId(componentInstId)
|
|
|
+ .formUuid("FORM-2353BE632D97434DAD55AEBD0866C44DVAT5")
|
|
|
+ .appType("APP_GNQ1RGK68X4JNZUEU8RQ")
|
|
|
+ .systemToken("XH866P81QDOTQ0218TGZM9WCNXOF24WIP488M7A5")
|
|
|
+ .updateFormDataJson(JSONObject.toJSONString(updateData))
|
|
|
+ .userId("332051151139376769").build(),
|
|
|
+ YDConf.FORM_OPERATION.update);
|
|
|
+
|
|
|
+ System.out.println("----------------------零部件[" + componentName + "]主表及子表数据原子更新完毕!------------------");
|
|
|
+ return null;
|
|
|
+ }, "处理零部件[" + componentName + "]实例[" + componentInstId + "]", 3, 1000);
|
|
|
+ }
|
|
|
+
|
|
|
+ private <T> T executeWithRetry(Supplier<T> action, String operationName, int maxRetries, long initialDelayMs) {
|
|
|
+ int attempt = 0;
|
|
|
+ while (true) {
|
|
|
+ try {
|
|
|
+ return action.get();
|
|
|
+ } catch (McException e) {
|
|
|
+ boolean isTemporary = e.getMessage() != null && e.getMessage().contains("temporary failure");
|
|
|
+ if (!isTemporary || attempt >= maxRetries) {
|
|
|
+ log.error("操作[{}]失败,非临时异常或已达最大重试次数({}),异常信息:", operationName, maxRetries, e);
|
|
|
+ throw e;
|
|
|
+ }
|
|
|
+ attempt++;
|
|
|
+ long delay = initialDelayMs * (1L << (attempt - 1));
|
|
|
+ log.warn("操作[{}]遇到临时故障,第{}次重试,等待{}ms", operationName, attempt, delay);
|
|
|
+ try {
|
|
|
+ Thread.sleep(delay);
|
|
|
+ } catch (InterruptedException ie) {
|
|
|
+ Thread.currentThread().interrupt();
|
|
|
+ // 重试被中断,改为抛出 RuntimeException,避免编译错误
|
|
|
+ throw new RuntimeException("重试被中断", ie);
|
|
|
+ }
|
|
|
+ } catch (RuntimeException e) {
|
|
|
+ // 业务异常(如子表为空)直接抛出,不重试
|
|
|
+ log.error("操作[{}]遇到业务异常,不重试", operationName, e);
|
|
|
+ throw e;
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("操作[{}]遇到非McException异常,不重试", operationName, e);
|
|
|
+ throw e;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ private BigDecimal parseBigDecimal(Object value) {
|
|
|
+ if (value == null) return BigDecimal.ZERO;
|
|
|
+ String str = value.toString().trim();
|
|
|
+ if (str.isEmpty()) return BigDecimal.ZERO;
|
|
|
+ try {
|
|
|
+ return new BigDecimal(str);
|
|
|
+ } catch (NumberFormatException e) {
|
|
|
+ log.warn("解析BigDecimal失败,值:{},返回0", str);
|
|
|
+ return BigDecimal.ZERO;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
@Override
|
|
|
public McR ProductReturn(Map map) {
|
|
|
String formInstId = UtilMap.getString(map,"formInstId");//实例id(退货单)
|