mirror of
http://192.168.1.205:9980/cf_devdept2/cf_imes_server.git
synced 2026-08-12 21:02:08 +08:00
新增同步组件订单、同步组件板件/配件能力
This commit is contained in:
+5
@@ -88,6 +88,11 @@ public class OrderItemDO {
|
|||||||
*/
|
*/
|
||||||
private Integer cadViewId;
|
private Integer cadViewId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对方配件实例 {@code partsItems[].id}。
|
||||||
|
*/
|
||||||
|
private String sourcePartsItemId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 分堆状态
|
* 分堆状态
|
||||||
*/
|
*/
|
||||||
|
|||||||
+1
@@ -34,4 +34,5 @@ public class ErrorCodeConstants {
|
|||||||
public static final ErrorCode PRODUCING_ORDER_CAD_OBJECT_INVALID = new ErrorCode(1_005_000_024, "producing.order.cad_object.invalid");
|
public static final ErrorCode PRODUCING_ORDER_CAD_OBJECT_INVALID = new ErrorCode(1_005_000_024, "producing.order.cad_object.invalid");
|
||||||
public static final ErrorCode PRODUCING_ORDER_ENUM_INVALID = new ErrorCode(1_005_000_025, "producing.order.enum.invalid");
|
public static final ErrorCode PRODUCING_ORDER_ENUM_INVALID = new ErrorCode(1_005_000_025, "producing.order.enum.invalid");
|
||||||
public static final ErrorCode PRODUCING_ORDER_IMPORT_FAILED = new ErrorCode(1_005_000_026, "producing.order.import.failed");
|
public static final ErrorCode PRODUCING_ORDER_IMPORT_FAILED = new ErrorCode(1_005_000_026, "producing.order.import.failed");
|
||||||
|
public static final ErrorCode PRODUCING_ORDER_SYNC_FAILED = new ErrorCode(1_005_000_027, "producing.order.sync.failed");
|
||||||
}
|
}
|
||||||
|
|||||||
+5
@@ -83,4 +83,9 @@ public class OrderItemDO {
|
|||||||
* cad视图id
|
* cad视图id
|
||||||
*/
|
*/
|
||||||
private Integer cadViewId;
|
private Integer cadViewId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对方配件实例 {@code partsItems[].id}。
|
||||||
|
*/
|
||||||
|
private String sourcePartsItemId;
|
||||||
}
|
}
|
||||||
+4
-4
@@ -22,8 +22,8 @@ import static com.cf.imes.module.plan.enums.ErrorCodeConstants.PRODUCING_ORDER_I
|
|||||||
import static com.cf.imes.module.plan.enums.ErrorCodeConstants.WEBCAD_ORDER_IMPORT_ORGANID_EMPTY_ERROR;
|
import static com.cf.imes.module.plan.enums.ErrorCodeConstants.WEBCAD_ORDER_IMPORT_ORGANID_EMPTY_ERROR;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 编排组件生产单导入的事务外步骤:生成内部调用令牌、拉取并校验报文、登记图纸外链、
|
* 编排组件生产单导入:在事务外生成内部调用令牌、拉取并校验报文、登记图纸外链、
|
||||||
* 获取组织级导入锁,再进入数据库事务。
|
* 获取组织级导入锁,再进入数据库事务完成写库和反向同步。
|
||||||
*
|
*
|
||||||
* <p>图纸文件记录必须先创建;后续失败时仅做尽力补偿,补偿失败不覆盖原始导入异常。</p>
|
* <p>图纸文件记录必须先创建;后续失败时仅做尽力补偿,补偿失败不覆盖原始导入异常。</p>
|
||||||
*/
|
*/
|
||||||
@@ -52,7 +52,7 @@ public class ProducingOrderImportServiceImpl implements ProducingOrderImportServ
|
|||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*
|
*
|
||||||
* <p>数据库事务开始前完成远程报文拉取、完整校验和图纸地址登记,
|
* <p>数据库事务开始前完成远程报文拉取、完整校验和图纸地址登记,
|
||||||
* 避免把网络等待纳入订单写库事务。</p>
|
* 订单写库完成后在同一事务内反向同步组件系统;反向同步失败时回滚本次导入。</p>
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean importOrder(ProducingOrderImportReqVO request) {
|
public boolean importOrder(ProducingOrderImportReqVO request) {
|
||||||
@@ -97,7 +97,7 @@ public class ProducingOrderImportServiceImpl implements ProducingOrderImportServ
|
|||||||
}
|
}
|
||||||
|
|
||||||
stageStartedAt = System.nanoTime();
|
stageStartedAt = System.nanoTime();
|
||||||
transactionalService.importOrder(response, request, organId, fileId);
|
transactionalService.importOrder(response, request, organId, fileId, token);
|
||||||
logStage(request, "transaction", stageStartedAt);
|
logStage(request, "transaction", stageStartedAt);
|
||||||
log.info("[producing-import] sourceOrderId={} targetOrderId={} stage=total elapsedMs={}",
|
log.info("[producing-import] sourceOrderId={} targetOrderId={} stage=total elapsedMs={}",
|
||||||
request.getSourceOrderId(), request.getTargetOrderId(),
|
request.getSourceOrderId(), request.getTargetOrderId(),
|
||||||
|
|||||||
+100
-3
@@ -20,7 +20,11 @@ import com.cf.imes.module.plan.dal.mysql.orderBody.OrderBodyMapper;
|
|||||||
import com.cf.imes.module.plan.dal.mysql.plate.PlateMapper;
|
import com.cf.imes.module.plan.dal.mysql.plate.PlateMapper;
|
||||||
import com.cf.imes.module.plan.service.customplateno.CustomPlateNoGenerateService;
|
import com.cf.imes.module.plan.service.customplateno.CustomPlateNoGenerateService;
|
||||||
import com.cf.imes.module.plan.service.orderImport.factory.ProducingOrderImportFactory;
|
import com.cf.imes.module.plan.service.orderImport.factory.ProducingOrderImportFactory;
|
||||||
|
import com.cf.imes.module.plan.service.orderImport.producing.ProducingOrderClient;
|
||||||
import com.cf.imes.module.plan.service.orderImport.producing.ProducingOrderConverter;
|
import com.cf.imes.module.plan.service.orderImport.producing.ProducingOrderConverter;
|
||||||
|
import com.cf.imes.module.plan.service.orderImport.producing.dto.ProducingOrderExtraUpdateRequest;
|
||||||
|
import com.cf.imes.module.plan.service.orderImport.producing.dto.ProducingOrderItemSerialNoUpdateRequest;
|
||||||
|
import com.cf.imes.module.plan.service.orderImport.producing.dto.ProducingOrderItemSerialNoUpdateResponse;
|
||||||
import com.cf.imes.module.plan.service.orderImport.producing.dto.ProducingOrderResponse;
|
import com.cf.imes.module.plan.service.orderImport.producing.dto.ProducingOrderResponse;
|
||||||
import com.cf.imes.module.plan.service.orderImport.property.ProducingOrderImportProperties;
|
import com.cf.imes.module.plan.service.orderImport.property.ProducingOrderImportProperties;
|
||||||
import com.cf.imes.module.system.api.assemblyconfig.AssemblyConfigApi;
|
import com.cf.imes.module.system.api.assemblyconfig.AssemblyConfigApi;
|
||||||
@@ -31,18 +35,22 @@ import org.springframework.jdbc.core.JdbcTemplate;
|
|||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.ZoneOffset;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static com.cf.imes.module.plan.enums.ErrorCodeConstants.PRODUCING_ORDER_SYNC_FAILED;
|
||||||
import static com.cf.imes.module.plan.enums.ErrorCodeConstants.WEBCAD_ORDER_IMPORT_ORDER_PLATENUM_REACH_THRESHOLD_ERROR;
|
import static com.cf.imes.module.plan.enums.ErrorCodeConstants.WEBCAD_ORDER_IMPORT_ORDER_PLATENUM_REACH_THRESHOLD_ERROR;
|
||||||
import static com.cf.imes.module.plan.enums.ErrorCodeConstants.WEBCAD_ORDER_NOT_EXISTS_ERROR;
|
import static com.cf.imes.module.plan.enums.ErrorCodeConstants.WEBCAD_ORDER_NOT_EXISTS_ERROR;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 组件生产单的写库事务边界。
|
* 组件生产单的写库事务边界。
|
||||||
*
|
*
|
||||||
* <p>目标订单校验、报文转换、订单状态更新以及板件/配件/加工组/部件组入库任一步失败,
|
* <p>目标订单校验、报文转换、订单状态更新、板件/配件/加工组/部件组入库,
|
||||||
* 都会回滚本次数据库变更。</p>
|
* 以及事务末尾的组件系统反向同步任一步失败,都会回滚本次数据库变更。</p>
|
||||||
*/
|
*/
|
||||||
@Service
|
@Service
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@@ -72,6 +80,8 @@ public class ProducingOrderImportTransactionalService {
|
|||||||
private JdbcTemplate jdbcTemplate;
|
private JdbcTemplate jdbcTemplate;
|
||||||
@Resource
|
@Resource
|
||||||
private ProducingOrderConverter producingOrderConverter;
|
private ProducingOrderConverter producingOrderConverter;
|
||||||
|
@Resource
|
||||||
|
private ProducingOrderClient producingOrderClient;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 在一个事务内完成目标订单状态更新及全部拆单业务数据写入。
|
* 在一个事务内完成目标订单状态更新及全部拆单业务数据写入。
|
||||||
@@ -80,12 +90,14 @@ public class ProducingOrderImportTransactionalService {
|
|||||||
* @param request 本次导入请求
|
* @param request 本次导入请求
|
||||||
* @param organId 当前组织 ID
|
* @param organId 当前组织 ID
|
||||||
* @param cadViewFileId 事务外预先生成的图纸文件 ID
|
* @param cadViewFileId 事务外预先生成的图纸文件 ID
|
||||||
|
* @param token MES JWT,不包含 {@code Bearer } 前缀
|
||||||
*/
|
*/
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public void importOrder(ProducingOrderResponse response,
|
public void importOrder(ProducingOrderResponse response,
|
||||||
ProducingOrderImportReqVO request,
|
ProducingOrderImportReqVO request,
|
||||||
Long organId,
|
Long organId,
|
||||||
Long cadViewFileId) {
|
Long cadViewFileId,
|
||||||
|
String token) {
|
||||||
long totalStartedAt = System.nanoTime();
|
long totalStartedAt = System.nanoTime();
|
||||||
long stageStartedAt = System.nanoTime();
|
long stageStartedAt = System.nanoTime();
|
||||||
OrderDO order = getTargetOrder(request.getTargetOrderId(), organId);
|
OrderDO order = getTargetOrder(request.getTargetOrderId(), organId);
|
||||||
@@ -111,13 +123,98 @@ public class ProducingOrderImportTransactionalService {
|
|||||||
assemblyConfigApi, producingOrderImportProperties.getPlateNumThreshold(),
|
assemblyConfigApi, producingOrderImportProperties.getPlateNumThreshold(),
|
||||||
jdbcTemplate);
|
jdbcTemplate);
|
||||||
stageStartedAt = System.nanoTime();
|
stageStartedAt = System.nanoTime();
|
||||||
|
ProducingOrderItemSerialNoUpdateRequest serialNoRequest =
|
||||||
factory.analyzeTempData(producingImportData);
|
factory.analyzeTempData(producingImportData);
|
||||||
logStage(request, "factory", stageStartedAt);
|
logStage(request, "factory", stageStartedAt);
|
||||||
|
|
||||||
|
// 反向同步放在本地事务末尾:任一接口失败都会触发本地导入回滚。
|
||||||
|
stageStartedAt = System.nanoTime();
|
||||||
|
producingOrderClient.updateOrderExtra(
|
||||||
|
request.getSourceOrderId(), token,
|
||||||
|
buildOrderExtraRequest(order, request.getSourceOrderId()));
|
||||||
|
logStage(request, "sync-order-extra", stageStartedAt);
|
||||||
|
|
||||||
|
stageStartedAt = System.nanoTime();
|
||||||
|
ProducingOrderItemSerialNoUpdateResponse serialNoResponse =
|
||||||
|
producingOrderClient.updateItemSerialNos(token, serialNoRequest);
|
||||||
|
logStage(request, "sync-item-serial-no", stageStartedAt);
|
||||||
|
log.info("[producing-import-sync] sourceOrderId={} targetOrderId={} "
|
||||||
|
+ "blocksSubmitted={} partsSubmitted={} blocksUpdated={} partsUpdated={}",
|
||||||
|
request.getSourceOrderId(), request.getTargetOrderId(),
|
||||||
|
serialNoRequest.getBlocks().size(), serialNoRequest.getParts().size(),
|
||||||
|
serialNoResponse.getBlocksUpdated(), serialNoResponse.getPartsUpdated());
|
||||||
|
|
||||||
log.info("[producing-import-transaction] sourceOrderId={} targetOrderId={} stage=total elapsedMs={}",
|
log.info("[producing-import-transaction] sourceOrderId={} targetOrderId={} stage=total elapsedMs={}",
|
||||||
request.getSourceOrderId(), request.getTargetOrderId(),
|
request.getSourceOrderId(), request.getTargetOrderId(),
|
||||||
elapsedMillis(totalStartedAt));
|
elapsedMillis(totalStartedAt));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将 iMES 订单字段转换为对方完整订单单头。
|
||||||
|
*
|
||||||
|
* <p>{@code customSerialNo} 严格使用 {@code orders.custom_order_no};
|
||||||
|
* iMES 当前没有客户、经销商和人员业务 ID,因此嵌套对象 ID 传空字符串。</p>
|
||||||
|
*/
|
||||||
|
private ProducingOrderExtraUpdateRequest buildOrderExtraRequest(
|
||||||
|
OrderDO order, String sourceOrderId) {
|
||||||
|
ProducingOrderExtraUpdateRequest.Contact distributor =
|
||||||
|
ProducingOrderExtraUpdateRequest.Contact.builder()
|
||||||
|
.id("")
|
||||||
|
.name(empty(order.getDealer()))
|
||||||
|
.address("")
|
||||||
|
.phone(empty(order.getDealerPhoneNumber()))
|
||||||
|
.build();
|
||||||
|
ProducingOrderExtraUpdateRequest.Contact customer =
|
||||||
|
ProducingOrderExtraUpdateRequest.Contact.builder()
|
||||||
|
.id("")
|
||||||
|
.name(empty(order.getCustomer()))
|
||||||
|
.address(empty(order.getAddress()))
|
||||||
|
.phone(empty(order.getPhoneNumber()))
|
||||||
|
.build();
|
||||||
|
ProducingOrderExtraUpdateRequest.User createPerson =
|
||||||
|
ProducingOrderExtraUpdateRequest.User.builder()
|
||||||
|
.id("")
|
||||||
|
.name(empty(order.getCreator()))
|
||||||
|
.build();
|
||||||
|
ProducingOrderExtraUpdateRequest.User salePerson =
|
||||||
|
ProducingOrderExtraUpdateRequest.User.builder()
|
||||||
|
.id("")
|
||||||
|
.name(empty(order.getSalesman()))
|
||||||
|
.build();
|
||||||
|
return ProducingOrderExtraUpdateRequest.builder()
|
||||||
|
.id(sourceOrderId)
|
||||||
|
.remark(empty(order.getRemark()))
|
||||||
|
.customSerialNo(empty(order.getCustomOrderNo()))
|
||||||
|
.type(order.getOrderType())
|
||||||
|
.distributor(distributor)
|
||||||
|
.customer(customer)
|
||||||
|
.createPerson(createPerson)
|
||||||
|
.salePerson(salePerson)
|
||||||
|
.creationTime(toIsoTime(order.getCreateTime(), "create_time"))
|
||||||
|
.saleTime(toIsoTime(order.getOrderDate(), "order_date"))
|
||||||
|
.shippingTime(toIsoTime(order.getDeliveryDate(), "delivery_date"))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将 iMES 本地时间转换为带东八区偏移的 ISO 8601 字符串。
|
||||||
|
*/
|
||||||
|
private String toIsoTime(LocalDateTime value, String fieldName) {
|
||||||
|
if (value == null) {
|
||||||
|
throw new ServiceException(PRODUCING_ORDER_SYNC_FAILED,
|
||||||
|
"orders." + fieldName + " is null");
|
||||||
|
}
|
||||||
|
return value.atOffset(ZoneOffset.ofHours(8))
|
||||||
|
.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将可空订单文本转换为对方必填对象可接受的空字符串。
|
||||||
|
*/
|
||||||
|
private String empty(String value) {
|
||||||
|
return value == null ? "" : value;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 输出事务内各处理阶段耗时。
|
* 输出事务内各处理阶段耗时。
|
||||||
*/
|
*/
|
||||||
|
|||||||
+31
-2
@@ -32,6 +32,7 @@ import com.cf.imes.module.plan.service.orderImport.producing.dto.ProducingImport
|
|||||||
import com.cf.imes.module.plan.service.orderImport.producing.dto.ProducingImportPart;
|
import com.cf.imes.module.plan.service.orderImport.producing.dto.ProducingImportPart;
|
||||||
import com.cf.imes.module.plan.service.orderImport.producing.dto.ProducingImportProcessGroup;
|
import com.cf.imes.module.plan.service.orderImport.producing.dto.ProducingImportProcessGroup;
|
||||||
import com.cf.imes.module.plan.service.orderImport.producing.dto.ProducingImportData;
|
import com.cf.imes.module.plan.service.orderImport.producing.dto.ProducingImportData;
|
||||||
|
import com.cf.imes.module.plan.service.orderImport.producing.dto.ProducingOrderItemSerialNoUpdateRequest;
|
||||||
import com.cf.imes.module.plan.dal.dataobject.goods.GoodsDO;
|
import com.cf.imes.module.plan.dal.dataobject.goods.GoodsDO;
|
||||||
import com.cf.imes.module.plan.dal.dataobject.ordecomponent.OrderComponentDO;
|
import com.cf.imes.module.plan.dal.dataobject.ordecomponent.OrderComponentDO;
|
||||||
import com.cf.imes.module.plan.dal.dataobject.order.OrderDO;
|
import com.cf.imes.module.plan.dal.dataobject.order.OrderDO;
|
||||||
@@ -79,6 +80,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
@@ -165,6 +167,12 @@ public class ProducingOrderImportFactory {
|
|||||||
// 部件缓存:{cad groupId:imes部件id}
|
// 部件缓存:{cad groupId:imes部件id}
|
||||||
private Map<Integer, OrderComponentDO> componentGroupMap = new HashMap<>();
|
private Map<Integer, OrderComponentDO> componentGroupMap = new HashMap<>();
|
||||||
|
|
||||||
|
// 对方 blockItems.id:iMES plate_no
|
||||||
|
private Map<String, String> blockSerialNoMap = new LinkedHashMap<>();
|
||||||
|
|
||||||
|
// 对方 partsItems.id:iMES 基础 order_item.id
|
||||||
|
private Map<String, String> partSerialNoMap = new LinkedHashMap<>();
|
||||||
|
|
||||||
private List<PlateDO> plateDOS = new ArrayList<>();
|
private List<PlateDO> plateDOS = new ArrayList<>();
|
||||||
private List<OrderItemDO> orderItemDOS = new ArrayList<>();
|
private List<OrderItemDO> orderItemDOS = new ArrayList<>();
|
||||||
private List<OrderPartsDO> orderPartsDOS = new ArrayList<>();
|
private List<OrderPartsDO> orderPartsDOS = new ArrayList<>();
|
||||||
@@ -254,8 +262,10 @@ public class ProducingOrderImportFactory {
|
|||||||
* 调用方负责提供事务边界;无论成功或失败,本工厂都会在结束时清理本次导入缓存。</p>
|
* 调用方负责提供事务边界;无论成功或失败,本工厂都会在结束时清理本次导入缓存。</p>
|
||||||
*
|
*
|
||||||
* @param producingImportData 已完成字段转换和关联校验的导入数据
|
* @param producingImportData 已完成字段转换和关联校验的导入数据
|
||||||
|
* @return 本次实际生成的板件、配件外部序列号映射
|
||||||
*/
|
*/
|
||||||
public void analyzeTempData(ProducingImportData producingImportData) {
|
public ProducingOrderItemSerialNoUpdateRequest analyzeTempData(
|
||||||
|
ProducingImportData producingImportData) {
|
||||||
long totalStartedAt = System.nanoTime();
|
long totalStartedAt = System.nanoTime();
|
||||||
try {
|
try {
|
||||||
cadViewFileId = producingImportData.getCadViewFileId();
|
cadViewFileId = producingImportData.getCadViewFileId();
|
||||||
@@ -345,6 +355,9 @@ public class ProducingOrderImportFactory {
|
|||||||
log.warn(new ServiceException(WEBCAD_ORDER_IMPORT_ORDER_PLATENUM_REACH_THRESHOLD_ERROR, orderId, cadImportPlateNumThreshold).getMessage());
|
log.warn(new ServiceException(WEBCAD_ORDER_IMPORT_ORDER_PLATENUM_REACH_THRESHOLD_ERROR, orderId, cadImportPlateNumThreshold).getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return new ProducingOrderItemSerialNoUpdateRequest(
|
||||||
|
new LinkedHashMap<>(blockSerialNoMap),
|
||||||
|
new LinkedHashMap<>(partSerialNoMap));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw e;
|
throw e;
|
||||||
} finally {
|
} finally {
|
||||||
@@ -1154,6 +1167,7 @@ public class ProducingOrderImportFactory {
|
|||||||
plateDO.setModelData(JsonUtils.toJsonString(orderModelDO));
|
plateDO.setModelData(JsonUtils.toJsonString(orderModelDO));
|
||||||
|
|
||||||
plateDOS.add(plateDO);
|
plateDOS.add(plateDO);
|
||||||
|
blockSerialNoMap.put(block.getSourceBlockItemId(), plateDO.getPlateNo());
|
||||||
orderPlateBatchInsertWithinThreshold(plateDOS, false);
|
orderPlateBatchInsertWithinThreshold(plateDOS, false);
|
||||||
|
|
||||||
// 遍历加工组信息,生成对应的加工组和item
|
// 遍历加工组信息,生成对应的加工组和item
|
||||||
@@ -1932,6 +1946,7 @@ public class ProducingOrderImportFactory {
|
|||||||
.plateId(0L)
|
.plateId(0L)
|
||||||
.num(part.getNum())
|
.num(part.getNum())
|
||||||
.cadViewId(cadViewId)
|
.cadViewId(cadViewId)
|
||||||
|
.sourcePartsItemId(part.getSourcePartsItemId())
|
||||||
.organId(organId)
|
.organId(organId)
|
||||||
.build();
|
.build();
|
||||||
orderItemDOS.add(orderItemDO);
|
orderItemDOS.add(orderItemDO);
|
||||||
@@ -1949,9 +1964,12 @@ public class ProducingOrderImportFactory {
|
|||||||
.plateId(0L)
|
.plateId(0L)
|
||||||
.num(partNum)
|
.num(partNum)
|
||||||
.cadViewId(cadViewId)
|
.cadViewId(cadViewId)
|
||||||
|
.sourcePartsItemId(part.getSourcePartsItemId())
|
||||||
.groupId(0L) // 用于统计加工组下配件的总数
|
.groupId(0L) // 用于统计加工组下配件的总数
|
||||||
.organId(organId)
|
.organId(organId)
|
||||||
.build();
|
.build();
|
||||||
|
partSerialNoMap.put(
|
||||||
|
part.getSourcePartsItemId(), String.valueOf(orderItemDO.getId()));
|
||||||
orderItemDOS.add(orderItemDO);
|
orderItemDOS.add(orderItemDO);
|
||||||
orderItemBatchInsertWithinThreshold(orderItemDOS, false);
|
orderItemBatchInsertWithinThreshold(orderItemDOS, false);
|
||||||
} else {
|
} else {
|
||||||
@@ -1967,8 +1985,11 @@ public class ProducingOrderImportFactory {
|
|||||||
.plateId(0L)
|
.plateId(0L)
|
||||||
.num(part.getNum())
|
.num(part.getNum())
|
||||||
.cadViewId(cadViewId)
|
.cadViewId(cadViewId)
|
||||||
|
.sourcePartsItemId(part.getSourcePartsItemId())
|
||||||
.organId(organId)
|
.organId(organId)
|
||||||
.build();
|
.build();
|
||||||
|
partSerialNoMap.put(
|
||||||
|
part.getSourcePartsItemId(), String.valueOf(orderItemDO.getId()));
|
||||||
orderItemDOS.add(orderItemDO);
|
orderItemDOS.add(orderItemDO);
|
||||||
orderItemBatchInsertWithinThreshold(orderItemDOS, false);
|
orderItemBatchInsertWithinThreshold(orderItemDOS, false);
|
||||||
}
|
}
|
||||||
@@ -1989,6 +2010,7 @@ public class ProducingOrderImportFactory {
|
|||||||
.num(part.getNum())
|
.num(part.getNum())
|
||||||
.compId(partComponentId)
|
.compId(partComponentId)
|
||||||
.cadViewId(cadViewId)
|
.cadViewId(cadViewId)
|
||||||
|
.sourcePartsItemId(part.getSourcePartsItemId())
|
||||||
.organId(organId)
|
.organId(organId)
|
||||||
.build();
|
.build();
|
||||||
orderItemDOS.add(orderItemDO);
|
orderItemDOS.add(orderItemDO);
|
||||||
@@ -2368,7 +2390,7 @@ public class ProducingOrderImportFactory {
|
|||||||
// 达到批量的阈值就做一次插入
|
// 达到批量的阈值就做一次插入
|
||||||
if (CollUtil.isNotEmpty(list) && (list.size() >= BATCH_THRESHOLD_NUMBER || isLast)) {
|
if (CollUtil.isNotEmpty(list) && (list.size() >= BATCH_THRESHOLD_NUMBER || isLast)) {
|
||||||
|
|
||||||
String sql = "INSERT INTO order_item (id,order_id,type,room_id,body_id,package_id,group_id,plate_id,parts_id,num,organ_id,comp_id,cad_view_id) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)";
|
String sql = "INSERT INTO order_item (id,order_id,type,room_id,body_id,package_id,group_id,plate_id,parts_id,num,organ_id,comp_id,cad_view_id,source_parts_item_id) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?)";
|
||||||
jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() {
|
jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() {
|
||||||
/** {@inheritDoc} */
|
/** {@inheritDoc} */
|
||||||
@Override
|
@Override
|
||||||
@@ -2399,6 +2421,11 @@ public class ProducingOrderImportFactory {
|
|||||||
} else {
|
} else {
|
||||||
ps.setNull(13, Types.INTEGER);
|
ps.setNull(13, Types.INTEGER);
|
||||||
}
|
}
|
||||||
|
if (item.getSourcePartsItemId() != null) {
|
||||||
|
ps.setString(14, item.getSourcePartsItemId());
|
||||||
|
} else {
|
||||||
|
ps.setNull(14, Types.VARCHAR);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritDoc} */
|
/** {@inheritDoc} */
|
||||||
@@ -2809,6 +2836,8 @@ public class ProducingOrderImportFactory {
|
|||||||
existRoomIdMap = null;
|
existRoomIdMap = null;
|
||||||
orderPartMap = null;
|
orderPartMap = null;
|
||||||
componentGroupMap = null;
|
componentGroupMap = null;
|
||||||
|
blockSerialNoMap = null;
|
||||||
|
partSerialNoMap = null;
|
||||||
|
|
||||||
plateDOS = null;
|
plateDOS = null;
|
||||||
orderItemDOS = null;
|
orderItemDOS = null;
|
||||||
|
|||||||
+129
-3
@@ -1,6 +1,10 @@
|
|||||||
package com.cf.imes.module.plan.service.orderImport.producing;
|
package com.cf.imes.module.plan.service.orderImport.producing;
|
||||||
|
|
||||||
import com.cf.imes.framework.common.exception.ServiceException;
|
import com.cf.imes.framework.common.exception.ServiceException;
|
||||||
|
import com.cf.imes.module.plan.service.orderImport.producing.dto.ProducingOrderApiResult;
|
||||||
|
import com.cf.imes.module.plan.service.orderImport.producing.dto.ProducingOrderExtraUpdateRequest;
|
||||||
|
import com.cf.imes.module.plan.service.orderImport.producing.dto.ProducingOrderItemSerialNoUpdateRequest;
|
||||||
|
import com.cf.imes.module.plan.service.orderImport.producing.dto.ProducingOrderItemSerialNoUpdateResponse;
|
||||||
import com.cf.imes.module.plan.service.orderImport.producing.dto.ProducingOrderResponse;
|
import com.cf.imes.module.plan.service.orderImport.producing.dto.ProducingOrderResponse;
|
||||||
import com.cf.imes.module.plan.service.orderImport.property.ProducingOrderImportProperties;
|
import com.cf.imes.module.plan.service.orderImport.property.ProducingOrderImportProperties;
|
||||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||||
@@ -8,6 +12,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
|||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
@@ -19,12 +24,13 @@ import java.nio.charset.StandardCharsets;
|
|||||||
|
|
||||||
import static com.cf.imes.module.plan.enums.ErrorCodeConstants.PRODUCING_ORDER_PULL_FAILED;
|
import static com.cf.imes.module.plan.enums.ErrorCodeConstants.PRODUCING_ORDER_PULL_FAILED;
|
||||||
import static com.cf.imes.module.plan.enums.ErrorCodeConstants.PRODUCING_ORDER_RESPONSE_INVALID;
|
import static com.cf.imes.module.plan.enums.ErrorCodeConstants.PRODUCING_ORDER_RESPONSE_INVALID;
|
||||||
|
import static com.cf.imes.module.plan.enums.ErrorCodeConstants.PRODUCING_ORDER_SYNC_FAILED;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 组件生产系统订单查询客户端。
|
* 组件生产系统订单查询及反向同步客户端。
|
||||||
*
|
*
|
||||||
* <p>仅网络 I/O 异常按配置重试;HTTP 错误、业务错误和无法解析的报文直接失败,
|
* <p>查询订单以及回写订单单头、生产项外部序列号均使用后端生成的 MES JWT。
|
||||||
* 防止无意义的重复请求拉长同步导入事务外耗时。</p>
|
* 仅网络 I/O 异常按配置重试;HTTP 和业务错误直接失败。</p>
|
||||||
*/
|
*/
|
||||||
@Component
|
@Component
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@@ -99,4 +105,124 @@ public class ProducingOrderClient {
|
|||||||
String message = lastNetworkError == null ? "network error" : lastNetworkError.getMessage();
|
String message = lastNetworkError == null ? "network error" : lastNetworkError.getMessage();
|
||||||
throw new ServiceException(PRODUCING_ORDER_PULL_FAILED, message);
|
throw new ServiceException(PRODUCING_ORDER_PULL_FAILED, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用 iMES 订单信息完整替换对方订单单头。
|
||||||
|
*
|
||||||
|
* @param orderId 对方组件生产系统订单 ID
|
||||||
|
* @param token MES JWT,不包含 {@code Bearer } 前缀
|
||||||
|
* @param request iMES 订单单头
|
||||||
|
*/
|
||||||
|
public void updateOrderExtra(String orderId,
|
||||||
|
String token,
|
||||||
|
ProducingOrderExtraUpdateRequest request) {
|
||||||
|
String encodedOrderId = URLEncoder.encode(orderId, StandardCharsets.UTF_8);
|
||||||
|
URI uri = URI.create(properties.getOrderExtraUrl().replace("{id}", encodedOrderId));
|
||||||
|
HttpResponse<String> response = sendPut(
|
||||||
|
uri, token, serializeSyncRequest(request), "order-extra");
|
||||||
|
try {
|
||||||
|
ProducingOrderApiResult result = objectMapper.readValue(
|
||||||
|
response.body(), ProducingOrderApiResult.class);
|
||||||
|
if (result == null || !result.isSuccess()) {
|
||||||
|
String message = result == null ? "empty response" : result.getMessage();
|
||||||
|
throw new ServiceException(PRODUCING_ORDER_SYNC_FAILED,
|
||||||
|
"order-extra: " + message);
|
||||||
|
}
|
||||||
|
} catch (JsonProcessingException ex) {
|
||||||
|
throw new ServiceException(PRODUCING_ORDER_SYNC_FAILED,
|
||||||
|
"order-extra: invalid JSON response");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量回写板件编号和配件基础 {@code order_item.id}。
|
||||||
|
*
|
||||||
|
* <p>接口返回的实际更新数量仅用于日志,不参与事务成功判断。</p>
|
||||||
|
*
|
||||||
|
* @param token MES JWT,不包含 {@code Bearer } 前缀
|
||||||
|
* @param request 对方生产项 ID 与 iMES 编号的映射
|
||||||
|
* @return 对方返回的实际更新数量;响应体无法解析时返回空计数对象
|
||||||
|
*/
|
||||||
|
public ProducingOrderItemSerialNoUpdateResponse updateItemSerialNos(
|
||||||
|
String token,
|
||||||
|
ProducingOrderItemSerialNoUpdateRequest request) {
|
||||||
|
URI uri = URI.create(properties.getItemSerialNoUrl());
|
||||||
|
HttpResponse<String> response = sendPut(
|
||||||
|
uri, token, serializeSyncRequest(request), "item-serial-no");
|
||||||
|
if (!StringUtils.hasText(response.body())) {
|
||||||
|
return new ProducingOrderItemSerialNoUpdateResponse();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
ProducingOrderItemSerialNoUpdateResponse result = objectMapper.readValue(
|
||||||
|
response.body(), ProducingOrderItemSerialNoUpdateResponse.class);
|
||||||
|
if (result != null && !result.isSuccess()) {
|
||||||
|
throw new ServiceException(PRODUCING_ORDER_SYNC_FAILED,
|
||||||
|
"item-serial-no: " + result.getMessage());
|
||||||
|
}
|
||||||
|
return result == null
|
||||||
|
? new ProducingOrderItemSerialNoUpdateResponse() : result;
|
||||||
|
} catch (JsonProcessingException ex) {
|
||||||
|
// HTTP 已成功时不因观测字段无法解析而回滚,避免对方已更新、iMES 却回滚。
|
||||||
|
log.warn("Producing item serial number response cannot be parsed; "
|
||||||
|
+ "ignore update counts", ex);
|
||||||
|
return new ProducingOrderItemSerialNoUpdateResponse();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 序列化反向同步请求。
|
||||||
|
*/
|
||||||
|
private String serializeSyncRequest(Object request) {
|
||||||
|
try {
|
||||||
|
return objectMapper.writeValueAsString(request);
|
||||||
|
} catch (JsonProcessingException ex) {
|
||||||
|
throw new ServiceException(PRODUCING_ORDER_SYNC_FAILED,
|
||||||
|
"cannot serialize request");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送支持网络异常重试的 PUT 请求。
|
||||||
|
*
|
||||||
|
* <p>PUT 接口具有覆盖语义,网络异常时重复发送同一请求不会生成重复业务数据。</p>
|
||||||
|
*/
|
||||||
|
private HttpResponse<String> sendPut(URI uri,
|
||||||
|
String token,
|
||||||
|
String body,
|
||||||
|
String operation) {
|
||||||
|
HttpRequest request = HttpRequest.newBuilder(uri)
|
||||||
|
.timeout(properties.getSyncReadTimeout())
|
||||||
|
.header("Authorization", "Bearer " + token)
|
||||||
|
.header("Accept", "application/json")
|
||||||
|
.header("Content-Type", "application/json; charset=utf-8")
|
||||||
|
.PUT(HttpRequest.BodyPublishers.ofString(body, StandardCharsets.UTF_8))
|
||||||
|
.build();
|
||||||
|
int maxAttempts = Math.max(1, properties.getNetworkRetryTimes() + 1);
|
||||||
|
IOException lastNetworkError = null;
|
||||||
|
for (int attempt = 1; attempt <= maxAttempts; attempt++) {
|
||||||
|
try {
|
||||||
|
HttpResponse<String> response = httpClient.send(
|
||||||
|
request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8));
|
||||||
|
if (response.statusCode() < 200 || response.statusCode() >= 300) {
|
||||||
|
throw new ServiceException(PRODUCING_ORDER_SYNC_FAILED,
|
||||||
|
operation + ": HTTP " + response.statusCode());
|
||||||
|
}
|
||||||
|
return response;
|
||||||
|
} catch (InterruptedException ex) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
throw new ServiceException(PRODUCING_ORDER_SYNC_FAILED,
|
||||||
|
operation + ": request interrupted");
|
||||||
|
} catch (IOException ex) {
|
||||||
|
lastNetworkError = ex;
|
||||||
|
if (attempt < maxAttempts) {
|
||||||
|
log.warn("Producing order sync operation {} failed on attempt {}, retrying",
|
||||||
|
operation, attempt, ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String message = lastNetworkError == null
|
||||||
|
? "network error" : lastNetworkError.getMessage();
|
||||||
|
throw new ServiceException(PRODUCING_ORDER_SYNC_FAILED,
|
||||||
|
operation + ": " + message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
@@ -978,6 +978,7 @@ public class ProducingOrderConverter {
|
|||||||
// 实例级备注优先;对方暂未在 partsItems 返回 remarks 时,兼容读取配件定义备注。
|
// 实例级备注优先;对方暂未在 partsItems 返回 remarks 时,兼容读取配件定义备注。
|
||||||
target.setRemark(remarksText(effectivePartRemarks(item, part)));
|
target.setRemark(remarksText(effectivePartRemarks(item, part)));
|
||||||
target.setObjectId(partCadViewId(context, part.getId()));
|
target.setObjectId(partCadViewId(context, part.getId()));
|
||||||
|
target.setSourcePartsItemId(item.getId());
|
||||||
target.setGroupIds(parseIds(item.getProcessGroupIds(), "process group"));
|
target.setGroupIds(parseIds(item.getProcessGroupIds(), "process group"));
|
||||||
target.setComponentIds(isNoComponent(item.getComponentGroupId())
|
target.setComponentIds(isNoComponent(item.getComponentGroupId())
|
||||||
? new ArrayList<>()
|
? new ArrayList<>()
|
||||||
|
|||||||
+5
@@ -53,6 +53,11 @@ public class ProducingImportPart {
|
|||||||
|
|
||||||
private Integer objectId;
|
private Integer objectId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对方配件实例 {@code partsItems[].id}。
|
||||||
|
*/
|
||||||
|
private String sourcePartsItemId;
|
||||||
|
|
||||||
private Long imesPartsId;
|
private Long imesPartsId;
|
||||||
|
|
||||||
private List<Integer> groupIds = new ArrayList<>();
|
private List<Integer> groupIds = new ArrayList<>();
|
||||||
|
|||||||
+32
@@ -0,0 +1,32 @@
|
|||||||
|
package com.cf.imes.module.plan.service.orderImport.producing.dto;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 组件生产系统通用业务响应。
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
|
public class ProducingOrderApiResult {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 业务码;对方文档允许数字或数字字符串。
|
||||||
|
*/
|
||||||
|
private JsonNode code;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 业务提示。
|
||||||
|
*/
|
||||||
|
private String message;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断响应是否为成功业务码。
|
||||||
|
*
|
||||||
|
* @return {@code code=0} 时返回 {@code true}
|
||||||
|
*/
|
||||||
|
public boolean isSuccess() {
|
||||||
|
return code != null && code.asInt(Integer.MIN_VALUE) == 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
+124
@@ -0,0 +1,124 @@
|
|||||||
|
package com.cf.imes.module.plan.service.orderImport.producing.dto;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 组件生产系统订单单头更新请求。
|
||||||
|
*
|
||||||
|
* <p>对方接口采用完整替换语义,因此即使 iMES 没有对应的业务主键,
|
||||||
|
* 联系人和用户对象也需要保留,并将其 ID 写为空字符串。</p>
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class ProducingOrderExtraUpdateRequest {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对方组件生产系统订单 ID。
|
||||||
|
*/
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* iMES 订单备注。
|
||||||
|
*/
|
||||||
|
private String remark;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* iMES 自定义订单号。
|
||||||
|
*/
|
||||||
|
private String customSerialNo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* iMES 订单类型。
|
||||||
|
*/
|
||||||
|
private Integer type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 经销商信息。
|
||||||
|
*/
|
||||||
|
private Contact distributor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 客户信息。
|
||||||
|
*/
|
||||||
|
private Contact customer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 订单创建人。
|
||||||
|
*/
|
||||||
|
private User createPerson;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 销售业务员。
|
||||||
|
*/
|
||||||
|
private User salePerson;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* iMES 订单创建时间,使用 ISO 8601 时间字符串。
|
||||||
|
*/
|
||||||
|
private String creationTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* iMES 下单日期,使用 ISO 8601 时间字符串。
|
||||||
|
*/
|
||||||
|
private String saleTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* iMES 交付日期,使用 ISO 8601 时间字符串。
|
||||||
|
*/
|
||||||
|
private String shippingTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对方订单单头使用的联系人结构。
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public static class Contact {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* iMES 暂无对应联系人业务 ID,按接口约定传空字符串。
|
||||||
|
*/
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 联系人名称。
|
||||||
|
*/
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 联系地址。
|
||||||
|
*/
|
||||||
|
private String address;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 联系电话。
|
||||||
|
*/
|
||||||
|
private String phone;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对方订单单头使用的用户结构。
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public static class User {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* iMES 暂无对应人员业务 ID,按接口约定传空字符串。
|
||||||
|
*/
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 人员名称。
|
||||||
|
*/
|
||||||
|
private String name;
|
||||||
|
}
|
||||||
|
}
|
||||||
+30
@@ -0,0 +1,30 @@
|
|||||||
|
package com.cf.imes.module.plan.service.orderImport.producing.dto;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量更新组件生产项外部序列号的请求。
|
||||||
|
*
|
||||||
|
* <p>键为对方 {@code blockItems.id}/{@code partsItems.id},
|
||||||
|
* 值分别为 iMES 板件编号和基础配件 {@code order_item.id}。</p>
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class ProducingOrderItemSerialNoUpdateRequest {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对方板件实例 ID 到 iMES {@code order_plate.plate_no} 的映射。
|
||||||
|
*/
|
||||||
|
private Map<String, String> blocks = new LinkedHashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对方配件实例 ID 到 iMES 基础 {@code order_item.id} 的映射。
|
||||||
|
*/
|
||||||
|
private Map<String, String> parts = new LinkedHashMap<>();
|
||||||
|
}
|
||||||
+89
@@ -0,0 +1,89 @@
|
|||||||
|
package com.cf.imes.module.plan.service.orderImport.producing.dto;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对方批量更新生产项外部序列号的响应。
|
||||||
|
*
|
||||||
|
* <p>实际接口使用通用响应外壳,将更新数量放在 {@code data} 中;
|
||||||
|
* 同时保留对文档所示顶层更新数量字段的兼容。更新数量仅用于日志观测,
|
||||||
|
* 不作为本地事务提交条件。</p>
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
|
public class ProducingOrderItemSerialNoUpdateResponse {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 业务码;实际接口允许返回数字或数字字符串。
|
||||||
|
*/
|
||||||
|
private JsonNode code;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 业务提示。
|
||||||
|
*/
|
||||||
|
private String message;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 实际接口返回的更新数量对象。
|
||||||
|
*/
|
||||||
|
private UpdateCounts data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 兼容文档中直接放在响应顶层的板件更新数量。
|
||||||
|
*/
|
||||||
|
private Integer blocksUpdated;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 兼容文档中直接放在响应顶层的配件更新数量。
|
||||||
|
*/
|
||||||
|
private Integer partsUpdated;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断已解析响应是否返回成功业务码。
|
||||||
|
*
|
||||||
|
* <p>未返回 {@code code} 时按文档中的无外壳结构处理为成功。</p>
|
||||||
|
*
|
||||||
|
* @return {@code code} 缺失或等于 0 时返回 {@code true}
|
||||||
|
*/
|
||||||
|
public boolean isSuccess() {
|
||||||
|
return code == null || code.asInt(Integer.MIN_VALUE) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取对方实际更新的板件数量。
|
||||||
|
*
|
||||||
|
* @return 优先返回 {@code data.blocksUpdated},否则返回兼容的顶层字段
|
||||||
|
*/
|
||||||
|
public Integer getBlocksUpdated() {
|
||||||
|
return data == null ? blocksUpdated : data.getBlocksUpdated();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取对方实际更新的配件数量。
|
||||||
|
*
|
||||||
|
* @return 优先返回 {@code data.partsUpdated},否则返回兼容的顶层字段
|
||||||
|
*/
|
||||||
|
public Integer getPartsUpdated() {
|
||||||
|
return data == null ? partsUpdated : data.getPartsUpdated();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量更新数量。
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
|
public static class UpdateCounts {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对方实际更新的板件索引数量。
|
||||||
|
*/
|
||||||
|
private Integer blocksUpdated;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对方实际更新的配件索引数量。
|
||||||
|
*/
|
||||||
|
private Integer partsUpdated;
|
||||||
|
}
|
||||||
|
}
|
||||||
+19
-1
@@ -9,7 +9,8 @@ import java.time.Duration;
|
|||||||
/**
|
/**
|
||||||
* 组件生产单拉取及导入配置。
|
* 组件生产单拉取及导入配置。
|
||||||
*
|
*
|
||||||
* <p>统一管理对方订单接口地址、HTTP 超时和重试策略,以及单订单板件数量上限。</p>
|
* <p>统一管理对方订单查询、单头回写、生产项编号回写接口,
|
||||||
|
* HTTP 超时和重试策略,以及单订单板件数量上限。</p>
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
@Configuration
|
@Configuration
|
||||||
@@ -22,6 +23,18 @@ public class ProducingOrderImportProperties {
|
|||||||
private String orderUrl =
|
private String orderUrl =
|
||||||
"http://proc.mes.cf/api-branch=opt_split_order/api/v1/producing/order/{id}";
|
"http://proc.mes.cf/api-branch=opt_split_order/api/v1/producing/order/{id}";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 组件生产单订单单头更新地址,其中 {@code {id}} 会替换为来源订单 ID。
|
||||||
|
*/
|
||||||
|
private String orderExtraUrl =
|
||||||
|
"http://proc.mes.cf/api-branch=opt_split_order/api/v1/producing/order/{id}/extra";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量更新板件、配件外部序列号的接口地址。
|
||||||
|
*/
|
||||||
|
private String itemSerialNoUrl =
|
||||||
|
"http://proc.mes.cf/api-branch=opt_split_order/api/v1/producing/order/items/serial-no";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 建立 HTTP 连接的超时时间。
|
* 建立 HTTP 连接的超时时间。
|
||||||
*/
|
*/
|
||||||
@@ -32,6 +45,11 @@ public class ProducingOrderImportProperties {
|
|||||||
*/
|
*/
|
||||||
private Duration readTimeout = Duration.ofSeconds(60);
|
private Duration readTimeout = Duration.ofSeconds(60);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 事务内反向同步接口的读取超时时间。
|
||||||
|
*/
|
||||||
|
private Duration syncReadTimeout = Duration.ofSeconds(10);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 网络 I/O 失败后的重试次数;HTTP 或业务错误不重试。
|
* 网络 I/O 失败后的重试次数;HTTP 或业务错误不重试。
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -166,8 +166,11 @@ chenfeng:
|
|||||||
plan:
|
plan:
|
||||||
producing-order:
|
producing-order:
|
||||||
order-url: http://proc.mes.cf/api-branch=opt_split_order/api/v1/producing/order/{id}
|
order-url: http://proc.mes.cf/api-branch=opt_split_order/api/v1/producing/order/{id}
|
||||||
|
order-extra-url: http://proc.mes.cf/api-branch=opt_split_order/api/v1/producing/order/{id}/extra
|
||||||
|
item-serial-no-url: http://proc.mes.cf/api-branch=opt_split_order/api/v1/producing/order/items/serial-no
|
||||||
connect-timeout: 5s
|
connect-timeout: 5s
|
||||||
read-timeout: 60s
|
read-timeout: 60s
|
||||||
|
sync-read-timeout: 10s
|
||||||
network-retry-times: 1
|
network-retry-times: 1
|
||||||
plate-num-threshold: 20000
|
plate-num-threshold: 20000
|
||||||
webcad:
|
webcad:
|
||||||
|
|||||||
@@ -194,8 +194,11 @@ chenfeng:
|
|||||||
plan:
|
plan:
|
||||||
producing-order:
|
producing-order:
|
||||||
order-url: http://proc.mes.cf/api-branch=opt_split_order/api/v1/producing/order/{id}
|
order-url: http://proc.mes.cf/api-branch=opt_split_order/api/v1/producing/order/{id}
|
||||||
|
order-extra-url: http://proc.mes.cf/api-branch=opt_split_order/api/v1/producing/order/{id}/extra
|
||||||
|
item-serial-no-url: http://proc.mes.cf/api-branch=opt_split_order/api/v1/producing/order/items/serial-no
|
||||||
connect-timeout: 5s
|
connect-timeout: 5s
|
||||||
read-timeout: 60s
|
read-timeout: 60s
|
||||||
|
sync-read-timeout: 10s
|
||||||
network-retry-times: 1
|
network-retry-times: 1
|
||||||
plate-num-threshold: 20000
|
plate-num-threshold: 20000
|
||||||
webcad:
|
webcad:
|
||||||
|
|||||||
+1
@@ -40,3 +40,4 @@ producing.order.cad_view_path.empty=組件生產單缺少 CAD 圖紙地址
|
|||||||
producing.order.cad_object.invalid=組件生產單 CAD 物件映射無效:{0}
|
producing.order.cad_object.invalid=組件生產單 CAD 物件映射無效:{0}
|
||||||
producing.order.enum.invalid=組件生產單枚舉值無效:{0}
|
producing.order.enum.invalid=組件生產單枚舉值無效:{0}
|
||||||
producing.order.import.failed=組件生產單匯入失敗
|
producing.order.import.failed=組件生產單匯入失敗
|
||||||
|
producing.order.sync.failed=反向同步組件生產單失敗:{0}
|
||||||
|
|||||||
+1
@@ -40,3 +40,4 @@ producing.order.cad_view_path.empty=The producing order has no CAD view path
|
|||||||
producing.order.cad_object.invalid=Invalid CAD object mapping: {0}
|
producing.order.cad_object.invalid=Invalid CAD object mapping: {0}
|
||||||
producing.order.enum.invalid=Invalid producing order enum value: {0}
|
producing.order.enum.invalid=Invalid producing order enum value: {0}
|
||||||
producing.order.import.failed=Failed to import producing order
|
producing.order.import.failed=Failed to import producing order
|
||||||
|
producing.order.sync.failed=Failed to synchronize the producing order back: {0}
|
||||||
|
|||||||
+1
@@ -40,3 +40,4 @@ producing.order.cad_view_path.empty=组件生产单缺少 CAD 图纸地址
|
|||||||
producing.order.cad_object.invalid=组件生产单 CAD 对象映射无效:{0}
|
producing.order.cad_object.invalid=组件生产单 CAD 对象映射无效:{0}
|
||||||
producing.order.enum.invalid=组件生产单枚举值无效:{0}
|
producing.order.enum.invalid=组件生产单枚举值无效:{0}
|
||||||
producing.order.import.failed=组件生产单导入失败
|
producing.order.import.failed=组件生产单导入失败
|
||||||
|
producing.order.sync.failed=反向同步组件生产单失败:{0}
|
||||||
|
|||||||
Reference in New Issue
Block a user