package com.baiyue.lastleg.service; import com.baomidou.mybatisplus.core.toolkit.IdWorker; import com.baiyue.common.event.EventEnvelope; import com.baiyue.common.event.EventIdentifiers; import com.baiyue.common.event.EventPayloadCanonicalizer; import com.baiyue.common.event.EventPayloadHash; import com.baiyue.common.event.EventTypes; import com.baiyue.common.event.OverseasInboundOrderDetainedChangedV1; import com.baiyue.common.event.RegionCode; import com.baiyue.lastleg.entity.LastlegEventOutbox; import com.baiyue.lastleg.entity.LastlegOrder; import com.baiyue.lastleg.mapper.LastlegEventOutboxMapper; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import jakarta.annotation.Resource; import org.springframework.stereotype.Service; import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneOffset; /** 在尾程业务事务内冻结按来源入仓单回传国内的暂扣状态事件。 */ @Service public class InboundOrderDetainedOutboxService { @Resource private LastlegEventOutboxMapper mapper; @Resource private ObjectMapper objectMapper; public void publish(LastlegOrder order, boolean detained, String reason, String operatorId, String operatorName, Instant changedAt, long changeVersion) { requireText(order.getSourceInboundId(), "sourceInboundId"); requireText(order.getInboundCode(), "inboundCode"); requireText(order.getCustomerId(), "customerId"); var payload = new OverseasInboundOrderDetainedChangedV1(order.getSourceInboundId(), order.getInboundCode(), String.valueOf(order.getId()), order.getOrderNo(), detained, reason, operatorId, operatorName, changedAt); JsonNode payloadNode = objectMapper.valueToTree(payload); String eventKey = EventTypes.OVERSEAS_INBOUND_ORDER_DETAINED_CHANGED + ':' + order.getSourceInboundId() + ':' + changeVersion; String causationId = EventIdentifiers.isSupported(order.getSourceEventId()) ? order.getSourceEventId() : null; EventEnvelope envelope = new EventEnvelope(EventIdentifiers.newUuid(), EventTypes.OVERSEAS_INBOUND_ORDER_DETAINED_CHANGED, 1, changedAt, RegionCode.OVERSEAS, RegionCode.CN, order.getCustomerId(), "INBOUND_ORDER", order.getSourceInboundId(), changeVersion, 1L, EventIdentifiers.newUuid(), eventKey, causationId, payloadNode, EventPayloadHash.sha256(EventPayloadCanonicalizer.canonicalize(payloadNode))).requireValid(); LastlegEventOutbox event = new LastlegEventOutbox(); event.setId(IdWorker.getId()); event.setCustomerId(order.getCustomerId()); event.setAggregateType(envelope.aggregateType()); event.setAggregateId(envelope.aggregateId()); event.setEventType(envelope.eventType()); event.setEventVersion(envelope.eventVersion()); event.setEventKey(eventKey); event.setPayloadJson(json(envelope)); event.setStatus("PENDING"); event.setRetryCount(0); event.setCreatedAt(LocalDateTime.ofInstant(changedAt, ZoneOffset.UTC)); mapper.insert(event); } private static void requireText(String value, String field) { if (value == null || value.isBlank()) throw new IllegalStateException(field + " is required"); } private String json(Object value) { try { return objectMapper.writeValueAsString(value); } catch (JsonProcessingException exception) { throw new IllegalStateException("Cannot serialize inbound detained event", exception); } } }