1、OrderModelDO减少记录字段;2、组件业务数据拉取改动:反同步订单+板件/配件合为一个接口,暂时注释反同步板材(组件报错);

This commit is contained in:
gaoqr
2026-08-03 17:05:15 +08:00
parent 3fdaecf86a
commit ffc22b23b3
19 changed files with 407 additions and 102 deletions
@@ -22,6 +22,7 @@ import com.cf.imes.module.plan.service.customplateno.CustomPlateNoGenerateServic
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.dto.ProducingOrderExtraSyncRequest;
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;
@@ -128,16 +129,13 @@ public class ProducingOrderImportTransactionalService {
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);
producingOrderClient.updateOrderExtra(
request.getSourceOrderId(), token,
buildOrderExtraSyncRequest(
order, request.getSourceOrderId(), serialNoRequest));
logStage(request, "sync-order-extra-and-serial-no", stageStartedAt);
log.info("[producing-import-sync] sourceOrderId={} targetOrderId={} "
+ "blocksSubmitted={} partsSubmitted={} blocksUpdated={} partsUpdated={}",
request.getSourceOrderId(), request.getTargetOrderId(),
@@ -149,11 +147,28 @@ public class ProducingOrderImportTransactionalService {
elapsedMillis(totalStartedAt));
}
/**
* 组装单头与生产项外部序列号的一体化反向同步报文。
*
* <p>直接复用本次导入在内存中形成的映射,不重新查询数据库。</p>
*/
private ProducingOrderExtraSyncRequest buildOrderExtraSyncRequest(
OrderDO order,
String sourceOrderId,
ProducingOrderItemSerialNoUpdateRequest serialNoRequest) {
return ProducingOrderExtraSyncRequest.builder()
.extra(buildOrderExtraRequest(order, sourceOrderId))
.blocks(serialNoRequest.getBlocks())
.parts(serialNoRequest.getParts())
// .externalMaterialMapping(serialNoRequest.getExternalMaterialMapping())
.build();
}
/**
* 将 iMES 订单字段转换为对方完整订单单头。
*
* <p>{@code customSerialNo} 严格使用 {@code orders.custom_order_no}
* iMES 当前没有客户、经销商和人员业务 ID,因此嵌套对象 ID 传空字符串。</p>
* <p>{@code customSerialNo} 使用 {@code orders.custom_order_no}iMES 暂无对应的
* 联系人和人员业务 ID,因此嵌套对象 ID 按接口约定传空字符串。</p>
*/
private ProducingOrderExtraUpdateRequest buildOrderExtraRequest(
OrderDO order, String sourceOrderId) {
@@ -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.ProducingImportProcessGroup;
import com.cf.imes.module.plan.service.orderImport.producing.dto.ProducingImportData;
import com.cf.imes.module.plan.service.orderImport.producing.dto.ProducingExternalMaterial;
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.ordecomponent.OrderComponentDO;
@@ -183,6 +184,9 @@ public class ProducingOrderImportFactory {
// 对方 partsItems.idiMES 基础 order_item.id
private Map<String, String> partSerialNoMap = new LinkedHashMap<>();
// 对方 materials.idiMES 板材库/配件物料对象
private Map<String, ProducingExternalMaterial> externalMaterialMap = new LinkedHashMap<>();
private List<PlateDO> plateDOS = ListUtils.newArrayListWithExpectedSize(ORDER_PLATE_BATCH_THRESHOLD_NUMBER);
private List<OrderItemDO> orderItemDOS = ListUtils.newArrayListWithExpectedSize(ORDER_ITEM_BATCH_THRESHOLD_NUMBER);
private List<OrderPartsDO> orderPartsDOS = new ArrayList<>();
@@ -349,7 +353,8 @@ public class ProducingOrderImportFactory {
int itemRowsBeforeParts = itemBatchRows;
int partRowsBeforeParts = partBatchRows;
stageStartedAt = System.nanoTime();
analyzeParts(producingImportData.getParts());
analyzeParts(producingImportData.getParts(),
producingImportData.getStandaloneSealMaterials());
long partsElapsedNanos = System.nanoTime() - stageStartedAt;
logStage("parts", stageStartedAt);
logPartsPerformanceDetail(partsElapsedNanos,
@@ -397,7 +402,8 @@ public class ProducingOrderImportFactory {
return new ProducingOrderItemSerialNoUpdateRequest(
new LinkedHashMap<>(blockSerialNoMap),
new LinkedHashMap<>(partSerialNoMap));
new LinkedHashMap<>(partSerialNoMap),
new LinkedHashMap<>(externalMaterialMap));
} catch (Exception e) {
throw e;
} finally {
@@ -640,6 +646,11 @@ public class ProducingOrderImportFactory {
// 缓存goodCode和orderGoodsId的对应关系
materialMap.put(plateGoodsGoodsId, goodsDO);
}
if (StringUtils.isNotEmpty(materialReqVO.getSourceMaterialId())) {
externalMaterialMap.putIfAbsent(
materialReqVO.getSourceMaterialId(),
toExternalBlockMaterial(materialReqVO));
}
}
}
@@ -1314,7 +1325,6 @@ public class ProducingOrderImportFactory {
ProducingImportBlock.PointInfoDTO pointInfo = block.getPointInfo();
OrderModelDO orderModelDO = OrderModelDO.builder()
.plateId(plateDO.getId())
.texture(block.getTexture())
.typographicFace(block.getHoleArrange())
.openDoorType(block.getOpenDoorType())
@@ -1349,8 +1359,6 @@ public class ProducingOrderImportFactory {
}
orderModelDO.setPlateExtraRemark(plateExtraRemark);
orderModelDO.setGoodsId(block.getGoodsCode());
orderModelDO.setPlateGoodsId(plateDO.getGoodsId());
return orderModelDO;
}
@@ -1867,10 +1875,12 @@ public class ProducingOrderImportFactory {
/**
* 解析配件列表
*
* @param parts
* @param parts 有实际柜体归属的配件
* @param standaloneSealMaterials 仅由板件引用的订单级封边条物料
*/
private void analyzeParts(List<ProducingImportRoomTree> parts) {
if (ObjectUtil.isNull(parts)) {
private void analyzeParts(List<ProducingImportRoomTree> parts,
List<ProducingImportPart> standaloneSealMaterials) {
if (CollUtil.isEmpty(parts) && CollUtil.isEmpty(standaloneSealMaterials)) {
return;
}
log.debug("====================【cad拆单获取封边配置开始】====================");
@@ -1878,7 +1888,14 @@ public class ProducingOrderImportFactory {
getOrgSealEdgeConfig();
log.debug("====================【cad拆单获取封边配置结束】====================");
for (ProducingImportRoomTree room : parts) {
if (CollUtil.isNotEmpty(standaloneSealMaterials)) {
for (ProducingImportPart sealMaterial : standaloneSealMaterials) {
analyzeOrderPart(sealMaterial);
}
}
for (ProducingImportRoomTree room : parts == null
? Collections.<ProducingImportRoomTree>emptyList() : parts) {
// 房间名
String roomName = room.getName();
@@ -2217,6 +2234,67 @@ public class ProducingOrderImportFactory {
// orderpart id回显到配件
part.setImesPartsId(orderPartId);
}
if (StringUtils.isNotEmpty(part.getSourceMaterialId())) {
externalMaterialMap.putIfAbsent(
part.getSourceMaterialId(), toExternalPartMaterial(part));
}
}
/**
* 将前端映射后的 iMES 板材库属性转换为对方 ProductMaterial(type=1)。
*/
private ProducingExternalMaterial toExternalBlockMaterial(
ProducingImportMaterial material) {
return ProducingExternalMaterial.builder()
.id(material.getId())
.type(1)
.name(material.getName())
.remark(getEmpty(material.getRemark()))
.brand(material.getBrand())
.spec(material.getSpec())
.material(material.getMaterial())
.color(material.getColor())
.width(material.getWidth())
.length(material.getHeight())
.thickness(material.getThickness())
.hasWave(material.getTexture())
.build();
}
/**
* 将本次生成或复用的 iMES 配件属性转换为对方 ProductMaterial(type=2/3)。
*/
private ProducingExternalMaterial toExternalPartMaterial(ProducingImportPart part) {
boolean sealMaterial = PART_CATEGORY_ONE.equals(part.getType());
ProducingImportPart.GroupData groupData = part.getGroupData();
String material = sealMaterial && groupData != null
? groupData.getMaterial()
: StringUtils.isNotEmpty(part.getMaterial())
? part.getMaterial() : getFieldFromSpec(part.getSpec(), 1);
String color = sealMaterial && groupData != null
? groupData.getColor()
: StringUtils.isNotEmpty(part.getColor())
? part.getColor() : getFieldFromSpec(part.getSpec(), 2);
return ProducingExternalMaterial.builder()
.id(String.valueOf(part.getImesPartsId()))
.type(sealMaterial ? 3 : 2)
.name(part.getName())
.remark(getEmpty(part.getRemark()))
.factory(part.getFactory())
.brand(part.getBrand())
.spec(sealMaterial ? part.getSpec() : getFieldFromSpec(part.getSpec(), 0))
.material(getEmpty(material))
.color(getEmpty(color))
.model(part.getModel())
.width(sealMaterial ? nullableDouble(part.getWidth()) : null)
.size(sealMaterial && groupData != null && groupData.getSize() != null
? groupData.getSize().doubleValue() : null)
.build();
}
/** 将可空配件尺寸转换为数字,空值继续保持为空。 */
private Double nullableDouble(String value) {
return StringUtils.isEmpty(value) ? null : NumberUtil.parseDouble(value);
}
/**
@@ -2747,9 +2825,21 @@ public class ProducingOrderImportFactory {
} else {
ps.setNull(20, Types.INTEGER);
}
ps.setLong(21, item.getBodyId());
ps.setString(22, item.getBodyName());
ps.setString(23, item.getRoomName());
if (item.getBodyId() != null) {
ps.setLong(21, item.getBodyId());
} else {
ps.setNull(21, Types.BIGINT);
}
if (StringUtils.isNotEmpty(item.getBodyName())) {
ps.setString(22, item.getBodyName());
} else {
ps.setNull(22, Types.VARCHAR);
}
if (StringUtils.isNotEmpty(item.getRoomName())) {
ps.setString(23, item.getRoomName());
} else {
ps.setNull(23, Types.VARCHAR);
}
}
/** {@inheritDoc} */
@@ -2982,6 +3072,7 @@ public class ProducingOrderImportFactory {
componentGroupMap = null;
blockSerialNoMap = null;
partSerialNoMap = null;
externalMaterialMap = null;
plateDOS = null;
orderItemDOS = null;
@@ -1,9 +1,7 @@
package com.cf.imes.module.plan.service.orderImport.producing;
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.ProducingOrderExtraSyncRequest;
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.property.ProducingOrderImportProperties;
@@ -36,6 +34,11 @@ import static com.cf.imes.module.plan.enums.ErrorCodeConstants.PRODUCING_ORDER_S
@Slf4j
public class ProducingOrderClient {
/**
* 外部接口报文的最大日志长度,避免批量序列号同步失败时输出过大的日志。
*/
private static final int MAX_LOG_PAYLOAD_LENGTH = 16_384;
private final ProducingOrderImportProperties properties;
private final ObjectMapper objectMapper;
private final HttpClient httpClient;
@@ -107,68 +110,40 @@ public class ProducingOrderClient {
}
/**
* 用 iMES 订单信息完整替换对方订单单头
* 一次性完整替换对方订单单头,并回写板件、配件外部序列号
*
* @param orderId 对方组件生产系统订单 ID
* @param token MES JWT,不包含 {@code Bearer } 前缀
* @param request iMES 订单单头
* @param request iMES 订单单头及板件、配件映射
* @return 对方实际更新的板件和配件数量
*/
public void updateOrderExtra(String orderId,
String token,
ProducingOrderExtraUpdateRequest request) {
public ProducingOrderItemSerialNoUpdateResponse updateOrderExtra(
String orderId,
String token,
ProducingOrderExtraSyncRequest 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");
if (!StringUtils.hasText(response.body())) {
throw new ServiceException(PRODUCING_ORDER_SYNC_FAILED,
"order-extra: empty response");
}
try {
ProducingOrderApiResult result = objectMapper.readValue(
response.body(), ProducingOrderApiResult.class);
ProducingOrderItemSerialNoUpdateResponse result = objectMapper.readValue(
response.body(), ProducingOrderItemSerialNoUpdateResponse.class);
if (result == null || !result.isSuccess()) {
String message = result == null ? "empty response" : result.getMessage();
throw new ServiceException(PRODUCING_ORDER_SYNC_FAILED,
"order-extra: " + message);
}
return result;
} 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();
}
}
/**
* 序列化反向同步请求。
*/
@@ -200,23 +175,49 @@ public class ProducingOrderClient {
int maxAttempts = Math.max(1, properties.getNetworkRetryTimes() + 1);
IOException lastNetworkError = null;
for (int attempt = 1; attempt <= maxAttempts; attempt++) {
long startedAt = System.nanoTime();
log.info("[producing-order-http] operation={} method=PUT uri={} attempt={}/{} requestBytes={}",
operation, uri, attempt, maxAttempts, utf8Length(body));
log.debug("[producing-order-http-request] operation={} uri={} body={}",
operation, uri, logPayload(body));
try {
HttpResponse<String> response = httpClient.send(
request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8));
long elapsedMs = elapsedMillis(startedAt);
String responseBody = response.body();
if (response.statusCode() < 200 || response.statusCode() >= 300) {
log.error("[producing-order-http-error] operation={} method=PUT uri={} "
+ "attempt={}/{} status={} elapsedMs={} requestBody={} responseBody={}",
operation, uri, attempt, maxAttempts, response.statusCode(), elapsedMs,
logPayload(body), logPayload(responseBody));
throw new ServiceException(PRODUCING_ORDER_SYNC_FAILED,
operation + ": HTTP " + response.statusCode());
operation + ": HTTP " + response.statusCode()
+ ", response=" + logPayload(responseBody));
}
log.info("[producing-order-http] operation={} method=PUT uri={} attempt={}/{} "
+ "status={} elapsedMs={} responseBytes={}",
operation, uri, attempt, maxAttempts, response.statusCode(), elapsedMs,
utf8Length(responseBody));
log.debug("[producing-order-http-response] operation={} uri={} body={}",
operation, uri, logPayload(responseBody));
return response;
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
log.error("[producing-order-http-error] operation={} method=PUT uri={} "
+ "attempt={}/{} elapsedMs={} error=request-interrupted",
operation, uri, attempt, maxAttempts, elapsedMillis(startedAt));
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);
log.warn("[producing-order-http-error] operation={} method=PUT uri={} "
+ "attempt={}/{} elapsedMs={} retry=true",
operation, uri, attempt, maxAttempts, elapsedMillis(startedAt), ex);
} else {
log.error("[producing-order-http-error] operation={} method=PUT uri={} "
+ "attempt={}/{} elapsedMs={} retry=false",
operation, uri, attempt, maxAttempts, elapsedMillis(startedAt), ex);
}
}
}
@@ -225,4 +226,32 @@ public class ProducingOrderClient {
throw new ServiceException(PRODUCING_ORDER_SYNC_FAILED,
operation + ": " + message);
}
/**
* 将外部接口报文限制在可控的日志长度内;空响应使用明确占位符表示。
*/
private String logPayload(String payload) {
if (!StringUtils.hasText(payload)) {
return "<empty>";
}
if (payload.length() <= MAX_LOG_PAYLOAD_LENGTH) {
return payload;
}
return payload.substring(0, MAX_LOG_PAYLOAD_LENGTH)
+ "...<truncated,totalChars=" + payload.length() + ">";
}
/**
* 计算HTTP报文的UTF-8字节数。
*/
private int utf8Length(String payload) {
return payload == null ? 0 : payload.getBytes(StandardCharsets.UTF_8).length;
}
/**
* 将纳秒计时转换为毫秒。
*/
private long elapsedMillis(long startedAt) {
return (System.nanoTime() - startedAt) / 1_000_000;
}
}
@@ -23,6 +23,7 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -89,6 +90,7 @@ public class ProducingOrderConverter {
result.setCadViewFileId(cadViewFileId);
result.setUseConcreteProcessGroupName(true);
result.setMaterials(toMaterials(context, request.getMaterialMappings(), mappedPlateGoods));
result.setStandaloneSealMaterials(toStandaloneSealMaterials(context));
result.setProcessGroup(toProcessGroups(context));
result.setComponentGroup(toComponentGroups(context));
@@ -431,9 +433,11 @@ public class ProducingOrderConverter {
}
PlateGoodDO source = mappedPlateGoods.get(mapping.getSourceMaterialId());
ProducingImportMaterial target = new ProducingImportMaterial();
target.setSourceMaterialId(mapping.getSourceMaterialId());
target.setId(String.valueOf(source.getId()));
target.setGoodsId(source.getGoodsId());
target.setName(source.getGoodsName());
target.setRemark(source.getRemark());
target.setMaterial(source.getMaterial());
target.setColor(source.getColor());
target.setTexture(Boolean.TRUE.equals(source.getTexture()));
@@ -447,6 +451,68 @@ public class ProducingOrderConverter {
return result;
}
/**
* 将仅由板件 sealIds 引用的 type=3 物料转换为订单级封边条。
*
* <p>已经通过 partsItems 导入的封边条不重复创建;该列表只生成 order_parts
* 不生成没有实际归属关系的 order_item。</p>
*/
private List<ProducingImportPart> toStandaloneSealMaterials(Context context) {
Set<String> partMaterialIds = safe(context.order.getPartsItems()).stream()
.map(item -> context.parts.get(item.getRelationId()))
.filter(Objects::nonNull)
.map(ProducingOrderResponse.Part::getMaterialId)
.collect(Collectors.toSet());
Set<String> sealMaterialIds = safe(context.order.getBlockList()).stream()
.flatMap(block -> safe(block.getSealIds()).stream())
.filter(id -> !partMaterialIds.contains(id))
.collect(Collectors.toCollection(LinkedHashSet::new));
List<ProducingImportPart> result = new ArrayList<>();
for (String materialId : sealMaterialIds) {
ProducingOrderResponse.Material material = context.materials.get(materialId);
if (material == null || !Objects.equals(material.getType(), 3)) {
continue;
}
ProducingImportPart target = new ProducingImportPart();
target.setName(material.getName());
target.setType(SEAL_PART_GROUP);
target.setModel(empty(material.getModel()));
target.setSpec(empty(material.getSpec()));
target.setWidth(numberText(material.getWidth()));
target.setHeight("0");
target.setThickness(numberText(material.getSize()));
target.setMaterial(empty(material.getMaterial()));
target.setColor(sealPartColor(material));
target.setBrand(empty(material.getBrand()));
target.setFactory(empty(material.getFactory()));
target.setUnit("");
target.setNum(1D);
target.setIsComposite(false);
target.setRemark(empty(material.getRemark()));
target.setSourceMaterialId(material.getId());
ProducingImportPart.GroupData groupData = new ProducingImportPart.GroupData();
groupData.setSize(integerValue(material.getSize()));
groupData.setThickness(integerValue(material.getWidth()));
groupData.setMaterial(empty(material.getMaterial()));
groupData.setColor(sealPartColor(material));
groupData.setBoardName(material.getName());
target.setGroupData(groupData);
result.add(target);
}
return result;
}
/** 将可空数字转换为原拆单配件使用的字符串,缺失时按 0。 */
private String numberText(Double value) {
return String.valueOf(zero(value));
}
/** 将可空封边尺寸转换为原拆单结构使用的整数。 */
private Integer integerValue(Double value) {
return value == null ? 0 : value.intValue();
}
/**
* 将 type=3 加工组类型及其 type=4 加工组转换为原导入结构。
*/
@@ -991,6 +1057,7 @@ public class ProducingOrderConverter {
target.setRemark(remarksText(effectivePartRemarks(item, part)));
target.setObjectId(partCadViewId(context, part.getId()));
target.setSourcePartsItemId(item.getId());
target.setSourceMaterialId(part.getMaterialId());
target.setGroupIds(parseIds(item.getProcessGroupIds(), "process group"));
target.setComponentIds(isNoComponent(item.getComponentGroupId())
? new ArrayList<>()
@@ -999,8 +1066,8 @@ public class ProducingOrderConverter {
if (sealPart) {
ProducingImportPart.GroupData groupData =
new ProducingImportPart.GroupData();
groupData.setSize(0);
groupData.setThickness(0);
groupData.setSize(integerValue(material.getSize()));
groupData.setThickness(integerValue(material.getWidth()));
groupData.setMaterial(target.getMaterial());
groupData.setColor(sealPartColor(material));
groupData.setBoardName(material.getName());
@@ -0,0 +1,32 @@
package com.cf.imes.module.plan.service.orderImport.producing.dto;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Builder;
import lombok.Data;
/**
* 反向同步给组件系统的 iMES 物料对象。
*
* <p>字段遵循对方 ProductMaterial 结构:1=板材、2=五金、3=封边条。</p>
*/
@Data
@Builder
@JsonInclude(JsonInclude.Include.NON_NULL)
public class ProducingExternalMaterial {
private String id;
private Integer type;
private String name;
private String remark;
private String factory;
private String brand;
private String spec;
private String material;
private String color;
private String model;
private Double width;
private Double length;
private Double thickness;
private Double size;
private Boolean hasWave;
}
@@ -31,6 +31,11 @@ public class ProducingImportData {
@JsonProperty(value = "Parts")
private List<ProducingImportRoomTree> Parts;
/**
* 被板件 sealIds 引用、但没有对应 partsItems 的订单级封边条物料。
*/
private List<ProducingImportPart> standaloneSealMaterials;
@JsonProperty(value = "ProcessGroup")
@Valid
private List<ProducingImportProcessGroup> ProcessGroup;
@@ -28,12 +28,19 @@ public class ProducingImportMaterial {
private String name;
private String remark;
private boolean texture;
private String spec;
private String id;
/**
* 对方板材的 {@code materials[].id}。
*/
private String sourceMaterialId;
/**
* 获取板材纹理标识。
*
@@ -58,6 +58,11 @@ public class ProducingImportPart {
*/
private String sourcePartsItemId;
/**
* 对方配件或封边条的 {@code materials[].id}。
*/
private String sourceMaterialId;
private Long imesPartsId;
private List<Integer> groupIds = new ArrayList<>();
@@ -0,0 +1,40 @@
package com.cf.imes.module.plan.service.orderImport.producing.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* 组件生产单单头与生产项外部序列号的合并更新请求。
*
* <p>{@code extra} 使用完整替换语义;{@code blocks} 和 {@code parts} 的键分别为
* 对方 {@code blockItems.id}/{@code partsItems.id},值为 iMES 生成的板件号和配件短号。</p>
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ProducingOrderExtraSyncRequest {
/** 需要反向同步的 iMES 订单单头,接口必填。 */
private ProducingOrderExtraUpdateRequest extra;
/** 对方板件实例 ID 到 iMES 板件号的映射。 */
@Builder.Default
private Map<String, String> blocks = new LinkedHashMap<>();
/** 对方配件实例 ID 到 iMES 配件短号的映射。 */
@Builder.Default
private Map<String, String> parts = new LinkedHashMap<>();
/**
* 对方 materials.id 到 iMES 板材库/配件物料对象的映射,仅包含 type=1/2/3。
*/
@Builder.Default
private Map<String, ProducingExternalMaterial> externalMaterialMapping =
new LinkedHashMap<>();
}
@@ -27,4 +27,10 @@ public class ProducingOrderItemSerialNoUpdateRequest {
* 对方配件实例 ID 到 iMES 基础 {@code order_item.id} 的映射。
*/
private Map<String, String> parts = new LinkedHashMap<>();
/**
* 对方 materials.id 到 iMES 板材库/配件物料对象的映射。
*/
private Map<String, ProducingExternalMaterial> externalMaterialMapping =
new LinkedHashMap<>();
}
@@ -5,10 +5,10 @@ import com.fasterxml.jackson.databind.JsonNode;
import lombok.Data;
/**
* 对方批量更新生产项外部序列号的响应。
* 对方合并更新订单单头及生产项外部序列号的响应。
*
* <p>实际接口使用通用响应外壳,将更新数量放在 {@code data} 中;
* 同时保留对文档所示顶层更新数量字段的兼容。更新数量仅用于日志观测,
* <p>兼容接口文档所示的顶层更新数量,以及部署环境可能使用通用响应外壳
* 更新数量仅用于日志观测,
* 不作为本地事务提交条件。</p>
*/
@Data
@@ -2,6 +2,7 @@ package com.cf.imes.module.plan.service.orderImport.producing.dto;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonAlias;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.Data;
@@ -53,10 +54,12 @@ public class ProducingOrderResponse {
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonInclude(JsonInclude.Include.NON_NULL)
public static class Material {
private String id;
private Integer type;
private String name;
private String remark;
private String factory;
private String brand;
private String spec;
@@ -9,7 +9,7 @@ import java.time.Duration;
/**
* 组件生产单拉取及导入配置。
*
* <p>统一管理对方订单查询、单头回写、生产项编号回写接口,
* <p>统一管理对方订单查询、单头生产项编号合并回写接口,
* HTTP 超时和重试策略,以及单订单板件数量上限。</p>
*/
@Data
@@ -29,12 +29,6 @@ public class ProducingOrderImportProperties {
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 连接的超时时间。
*/
@@ -167,7 +167,6 @@ chenfeng:
producing-order:
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
read-timeout: 60s
sync-read-timeout: 10s
@@ -195,7 +195,6 @@ chenfeng:
producing-order:
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
read-timeout: 60s
sync-read-timeout: 10s