feat(ft546): adapt existing WMS contract to WCS core

This commit is contained in:
zgw
2026-08-11 14:46:36 +08:00
parent e5f91de1a0
commit 3e704d0b10
6 changed files with 556 additions and 35 deletions

View File

@@ -5,6 +5,8 @@ import com.ruoyi.api.domain.wcs2wms.JobParam;
import com.ruoyi.api.domain.wcs2wms.ReceiveJob;
import com.ruoyi.api.service.IApiService;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.project.ft546.config.Ft546WcsProperties;
import com.ruoyi.project.ft546.wms.Ft546WmsAdapterService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.web.bind.annotation.PostMapping;
@@ -15,9 +17,18 @@ import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/wcs2Wms/api")
public class Wcs2WmsController {
private final IApiService apiService;
private final Ft546WmsAdapterService standardAdapter;
private final Ft546WcsProperties properties;
@Autowired
private IApiService apiService;
public Wcs2WmsController(IApiService apiService,
Ft546WmsAdapterService standardAdapter,
Ft546WcsProperties properties) {
this.apiService = apiService;
this.standardAdapter = standardAdapter;
this.properties = properties;
}
/**
* 接收出库任务
@@ -27,7 +38,10 @@ public class Wcs2WmsController {
*/
@PostMapping("/receiveOutMydoJob")
public AjaxResult receiveOutMydoJob(@RequestBody ReceiveJob receiveOutJob) {
return apiService.receiveOutMydoJob(receiveOutJob);
return isStandard()
? AjaxResult.success(
standardAdapter.receiveOutMydoJob(receiveOutJob))
: apiService.receiveOutMydoJob(receiveOutJob);
}
/**
@@ -38,7 +52,10 @@ public class Wcs2WmsController {
*/
@PostMapping("/receiveInMydoJob")
public AjaxResult receiveInMydoJob(@RequestBody ReceiveJob receiveInJob) {
return apiService.receiveInMydoJob(receiveInJob);
return isStandard()
? AjaxResult.success(
standardAdapter.receiveInMydoJob(receiveInJob))
: apiService.receiveInMydoJob(receiveInJob);
}
@@ -50,13 +67,23 @@ public class Wcs2WmsController {
*/
@PostMapping("/cancelMydoJob")
public AjaxResult cancelMydoJob(@RequestBody JobParam jobParam) {
return apiService.cancelMydoJob(jobParam);
return isStandard()
? AjaxResult.success(standardAdapter.cancelMydoJob(
jobParam == null ? null : jobParam.getTaskNo()))
: apiService.cancelMydoJob(jobParam);
}
/** Return a read-only snapshot of all S-RGV vehicles. */
@PostMapping("/tidyVehicleSnapshot")
public AjaxResult tidyVehicleSnapshot() {
return apiService.tidyVehicleSnapshot();
return isStandard()
? AjaxResult.success(standardAdapter.tidyVehicleSnapshot())
: apiService.tidyVehicleSnapshot();
}
private boolean isStandard() {
return properties.getRuntimeMode()
== Ft546WcsProperties.RuntimeMode.STANDARD;
}

View File

@@ -27,6 +27,7 @@ import com.ruoyi.job.domain.MydoJob;
import com.ruoyi.job.service.IMydoJobService;
import com.ruoyi.queue.agv.domain.AgvQueue;
import com.ruoyi.queue.agv.service.IAgvQueueService;
import com.ruoyi.project.ft546.wms.Ft546WmsAdapterService;
import com.ruoyi.system.domain.AgvContainerTask;
import com.ruoyi.system.service.IAgvContainerTaskService;
import lombok.extern.slf4j.Slf4j;
@@ -60,6 +61,8 @@ public class ApiServiceImpl implements IApiService {
private IAgvContainerTaskService agvContainerTaskService;
@Autowired
private DeviceSrgvMapper deviceSrgvMapper;
@Autowired
private Ft546WmsAdapterService ft546WmsAdapterService;
/**
@@ -520,36 +523,8 @@ public class ApiServiceImpl implements IApiService {
@Override
public AjaxResult tidyVehicleSnapshot() {
List<DeviceSrgv> vehicles = deviceSrgvMapper.selectDeviceSrgvList(new DeviceSrgv());
List<SrgvVehicleSnapshot> snapshots = new ArrayList<>();
for (DeviceSrgv vehicle : vehicles) {
boolean online = "1".equals(vehicle.getAgvStatus());
boolean healthy = online && value(vehicle.getAlarm()) <= 1 && value(vehicle.getErrMsg()) == 0;
boolean idle = healthy && value(vehicle.getTaskNo()) == 0
&& value(vehicle.getLocked()) == 0 && value(vehicle.getChargeFlag()) == 0;
SrgvVehicleSnapshot snapshot = new SrgvVehicleSnapshot();
snapshot.setGuid(vehicle.getGuid());
snapshot.setDeviceId(vehicle.getDeviceId());
snapshot.setDeviceName(vehicle.getDeviceName());
snapshot.setAgvStatus(vehicle.getAgvStatus());
snapshot.setOnline(online);
snapshot.setHealthy(healthy);
snapshot.setIdle(idle);
snapshot.setTaskNo(vehicle.getTaskNo());
snapshot.setAlarm(vehicle.getAlarm());
snapshot.setErrMsg(vehicle.getErrMsg());
snapshot.setChargeFlag(vehicle.getChargeFlag());
snapshot.setLocked(vehicle.getLocked());
snapshot.setBattery(vehicle.getBattery());
snapshot.setCurrSite(vehicle.getCurrSite());
snapshot.setCurrFloor(vehicle.getCurrFloor());
snapshots.add(snapshot);
}
return AjaxResult.success(snapshots);
}
private int value(Integer number) {
return number == null ? 0 : number;
return AjaxResult.success(ft546WmsAdapterService
.tidyVehicleSnapshot());
}
}

View File

@@ -0,0 +1,104 @@
package com.ruoyi.project.ft546.wms;
import com.ruoyi.api.domain.wcs2wms.ReceiveJob;
import com.ruoyi.api.domain.wcs2wms.SrgvVehicleSnapshot;
import com.ruoyi.device.srgv.domain.DeviceSrgv;
import com.ruoyi.device.srgv.mapper.DeviceSrgvMapper;
import com.ruoyi.wcs.application.task.TransportOrderResult;
import com.ruoyi.wcs.port.in.TransportOrderUseCase;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
@Service
public class Ft546WmsAdapterService {
private final TransportOrderUseCase orderUseCase;
private final VehicleSnapshotProvider vehicleSnapshotProvider;
private final Ft546WmsOrderMapper mapper = new Ft546WmsOrderMapper();
@Autowired
public Ft546WmsAdapterService(TransportOrderUseCase orderUseCase,
DeviceSrgvMapper deviceMapper) {
this(orderUseCase, () -> snapshots(deviceMapper));
}
public Ft546WmsAdapterService(TransportOrderUseCase orderUseCase,
VehicleSnapshotProvider snapshotProvider) {
this.orderUseCase = Objects.requireNonNull(orderUseCase,
"orderUseCase");
this.vehicleSnapshotProvider = Objects.requireNonNull(
snapshotProvider, "snapshotProvider");
}
public TransportOrderResult receiveOutMydoJob(ReceiveJob job) {
return orderUseCase.create(mapper.outbound(job));
}
public TransportOrderResult receiveInMydoJob(ReceiveJob job) {
return orderUseCase.create(mapper.inbound(job));
}
public TransportOrderResult cancelMydoJob(String taskNo) {
return orderUseCase.cancel(requireText(taskNo, "taskNo"));
}
public List<?> tidyVehicleSnapshot() {
List<?> snapshots = Objects.requireNonNull(
vehicleSnapshotProvider.load(), "vehicle snapshots");
return Collections.unmodifiableList(new ArrayList<Object>(snapshots));
}
private static List<SrgvVehicleSnapshot> snapshots(
DeviceSrgvMapper mapper) {
List<DeviceSrgv> vehicles = Objects.requireNonNull(mapper,
"deviceMapper").selectDeviceSrgvList(new DeviceSrgv());
List<SrgvVehicleSnapshot> snapshots =
new ArrayList<SrgvVehicleSnapshot>();
for (DeviceSrgv vehicle : vehicles) {
boolean online = "1".equals(vehicle.getAgvStatus());
boolean healthy = online && value(vehicle.getAlarm()) <= 1
&& value(vehicle.getErrMsg()) == 0;
boolean idle = healthy && value(vehicle.getTaskNo()) == 0
&& value(vehicle.getLocked()) == 0
&& value(vehicle.getChargeFlag()) == 0;
SrgvVehicleSnapshot snapshot = new SrgvVehicleSnapshot();
snapshot.setGuid(vehicle.getGuid());
snapshot.setDeviceId(vehicle.getDeviceId());
snapshot.setDeviceName(vehicle.getDeviceName());
snapshot.setAgvStatus(vehicle.getAgvStatus());
snapshot.setOnline(online);
snapshot.setHealthy(healthy);
snapshot.setIdle(idle);
snapshot.setTaskNo(vehicle.getTaskNo());
snapshot.setAlarm(vehicle.getAlarm());
snapshot.setErrMsg(vehicle.getErrMsg());
snapshot.setChargeFlag(vehicle.getChargeFlag());
snapshot.setLocked(vehicle.getLocked());
snapshot.setBattery(vehicle.getBattery());
snapshot.setCurrSite(vehicle.getCurrSite());
snapshot.setCurrFloor(vehicle.getCurrFloor());
snapshots.add(snapshot);
}
return snapshots;
}
private static int value(Integer number) {
return number == null ? 0 : number;
}
private static String requireText(String value, String field) {
if (value == null || value.trim().isEmpty()) {
throw new IllegalArgumentException(field + " must not be blank");
}
return value.trim();
}
@FunctionalInterface
public interface VehicleSnapshotProvider {
List<?> load();
}
}

View File

@@ -0,0 +1,68 @@
package com.ruoyi.project.ft546.wms;
import cn.hutool.json.JSONUtil;
import com.ruoyi.api.domain.RequestLog;
import com.ruoyi.api.service.IRequestLogService;
import com.ruoyi.wcs.port.out.WmsNotification;
import com.ruoyi.wcs.port.out.WmsNotificationGateway;
import com.ruoyi.wcs.port.out.WmsNotificationReceipt;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
import static com.ruoyi.common.Constant.JOB_FINISH_URL;
@Component
public final class Ft546WmsNotificationGateway
implements WmsNotificationGateway {
private static final java.util.Set<String> SUPPORTED_EVENTS =
new java.util.HashSet<String>(Arrays.asList("OrderCompleted",
"OrderFailed", "OrderCancelled"));
private final IRequestLogService requestLogService;
public Ft546WmsNotificationGateway(
IRequestLogService requestLogService) {
this.requestLogService = Objects.requireNonNull(requestLogService,
"requestLogService");
}
@Override
public WmsNotificationReceipt notify(WmsNotification notification) {
Objects.requireNonNull(notification, "notification");
if (!SUPPORTED_EVENTS.contains(notification.getEventType())) {
return new WmsNotificationReceipt(
WmsNotificationReceipt.Status.PERMANENT_FAILURE,
"unsupported FT546 notification event");
}
Map<String, Object> payload = new LinkedHashMap<String, Object>();
payload.put("eventId", notification.getEventId());
payload.put("jobId", context(notification, "jobId",
notification.getOrderId()));
payload.put("taskNo", notification.getExternalRequestId());
payload.put("wmsType", context(notification, "inOrOut", "UNKNOWN"));
payload.put("eventType", notification.getEventType());
payload.put("resultCode", notification.getResultCode());
payload.put("resultMessage", notification.getResultMessage());
RequestLog result = requestLogService.getRequestLog(JOB_FINISH_URL,
"WCS标准任务结果回传", JSONUtil.toJsonStr(payload));
if (result != null && "1".equals(result.getIsSuccessful())) {
return new WmsNotificationReceipt(
WmsNotificationReceipt.Status.DELIVERED,
notification.getEventId());
}
return new WmsNotificationReceipt(
WmsNotificationReceipt.Status.RETRYABLE_FAILURE,
result == null ? "callback returned no result"
: result.getErrorDetails());
}
private static String context(WmsNotification notification, String key,
String fallback) {
String value = notification.getContext().get(key);
return value == null || value.trim().isEmpty()
? fallback : value.trim();
}
}

View File

@@ -0,0 +1,82 @@
package com.ruoyi.project.ft546.wms;
import com.ruoyi.api.domain.wcs2wms.ReceiveJob;
import com.ruoyi.wcs.application.task.CreateTransportOrderCommand;
import com.ruoyi.wcs.domain.task.TransportOrderType;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
public final class Ft546WmsOrderMapper {
public CreateTransportOrderCommand inbound(ReceiveJob job) {
ReceiveJob request = Objects.requireNonNull(job, "job");
return command(request, TransportOrderType.INBOUND,
firstText(request.getEntranceId(), request.getExitId()),
requireText(request.getCargoSpaceId(), "cargoSpaceId"));
}
public CreateTransportOrderCommand outbound(ReceiveJob job) {
ReceiveJob request = Objects.requireNonNull(job, "job");
return command(request, TransportOrderType.OUTBOUND,
requireText(request.getCargoSpaceId(), "cargoSpaceId"),
firstText(request.getExitId(),
request.getTargetCargoSpaceId()));
}
private static CreateTransportOrderCommand command(
ReceiveJob job, TransportOrderType type, String source,
String destination) {
String taskNo = requireText(job.getTaskNo(), "taskNo");
Map<String, String> attributes = new LinkedHashMap<String, String>();
put(attributes, "legacyTaskNo", taskNo);
put(attributes, "jobId", job.getJobId());
put(attributes, "inOrOut", job.getInOrOut());
put(attributes, "roadwayId", job.getRoadwayId());
put(attributes, "classId", job.getClassId());
put(attributes, "entranceId", job.getEntranceId());
put(attributes, "exitId", job.getExitId());
put(attributes, "cargoSpaceId", job.getCargoSpaceId());
put(attributes, "targetCargoSpaceId",
job.getTargetCargoSpaceId());
return new CreateTransportOrderCommand(taskNo, type,
textOrNull(job.getTrayCode()), source, destination,
priority(job.getPriority()), null, attributes);
}
private static int priority(Long value) {
if (value == null) {
return 0;
}
if (value < Integer.MIN_VALUE || value > Integer.MAX_VALUE) {
throw new IllegalArgumentException("priority is out of range");
}
return value.intValue();
}
private static void put(Map<String, String> target, String key,
String value) {
String text = textOrNull(value);
if (text != null) {
target.put(key, text);
}
}
private static String firstText(String first, String second) {
String value = textOrNull(first);
return value != null ? value : requireText(second, "location");
}
private static String textOrNull(String value) {
return value == null || value.trim().isEmpty()
? null : value.trim();
}
private static String requireText(String value, String field) {
String text = textOrNull(value);
if (text == null) {
throw new IllegalArgumentException(field + " must not be blank");
}
return text;
}
}

View File

@@ -0,0 +1,265 @@
package com.ruoyi.project.ft546.wms;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.ruoyi.api.controller.Wcs2WmsController;
import com.ruoyi.api.domain.RequestLog;
import com.ruoyi.api.domain.wcs2wms.JobParam;
import com.ruoyi.api.domain.wcs2wms.ReceiveJob;
import com.ruoyi.api.service.IApiService;
import com.ruoyi.api.service.impl.RequestLogServiceImpl;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.project.ft546.config.Ft546WcsProperties;
import com.ruoyi.wcs.application.task.CreateTransportOrderCommand;
import com.ruoyi.wcs.application.task.TransportOrderResult;
import com.ruoyi.wcs.domain.task.TransportOrder;
import com.ruoyi.wcs.domain.task.TransportOrderType;
import com.ruoyi.wcs.port.in.TransportOrderUseCase;
import com.ruoyi.wcs.port.out.WmsNotification;
import com.ruoyi.wcs.port.out.WmsNotificationReceipt;
import org.junit.jupiter.api.Test;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
class Ft546WmsAdapterServiceTest {
private static final Instant NOW = Instant.parse("2026-08-11T06:00:00Z");
@Test
void mapsExistingInboundRequestToCanonicalOrder() {
Ft546WmsOrderMapper mapper = new Ft546WmsOrderMapper();
ReceiveJob job = job("TASK-1");
job.setEntranceId("PORT-1");
job.setCargoSpaceId("SPACE-9");
CreateTransportOrderCommand command = mapper.inbound(job);
assertEquals("TASK-1", command.getExternalRequestId());
assertEquals(TransportOrderType.INBOUND, command.getOrderType());
assertEquals("PORT-1", command.getSourceCode());
assertEquals("SPACE-9", command.getDestinationCode());
assertEquals("TRAY-1", command.getLoadId());
assertEquals("JOB-1", command.getAttributes().get("jobId"));
assertEquals("TASK-1",
command.getAttributes().get("legacyTaskNo"));
}
@Test
void mapsExistingOutboundRequestToCanonicalOrder() {
Ft546WmsOrderMapper mapper = new Ft546WmsOrderMapper();
ReceiveJob job = job("TASK-2");
job.setCargoSpaceId("SPACE-9");
job.setExitId("PORT-2");
CreateTransportOrderCommand command = mapper.outbound(job);
assertEquals(TransportOrderType.OUTBOUND, command.getOrderType());
assertEquals("SPACE-9", command.getSourceCode());
assertEquals("PORT-2", command.getDestinationCode());
}
@Test
void duplicateWmsRequestReturnsTheSameOrder() {
FakeTransportOrderUseCase useCase = new FakeTransportOrderUseCase();
Ft546WmsAdapterService service = new Ft546WmsAdapterService(useCase,
() -> Collections.singletonList("SNAPSHOT"));
ReceiveJob job = job("TASK-1");
job.setEntranceId("PORT-1");
job.setCargoSpaceId("SPACE-9");
TransportOrderResult first = service.receiveInMydoJob(job);
TransportOrderResult duplicate = service.receiveInMydoJob(job);
assertEquals(first.getOrderId(), duplicate.getOrderId());
assertEquals(2, useCase.createCommands.size());
assertEquals("TASK-1", useCase.createCommands.get(1)
.getExternalRequestId());
}
@Test
void controllerUsesStandardAdapterOnlyInStandardMode() {
IApiService legacy = mock(IApiService.class);
AjaxResult legacyResult = AjaxResult.success("legacy");
ReceiveJob job = job("TASK-1");
job.setEntranceId("PORT-1");
job.setCargoSpaceId("SPACE-9");
when(legacy.receiveInMydoJob(job)).thenReturn(legacyResult);
FakeTransportOrderUseCase useCase = new FakeTransportOrderUseCase();
Ft546WmsAdapterService standard = new Ft546WmsAdapterService(useCase,
() -> Collections.singletonList("SNAPSHOT"));
Ft546WcsProperties properties = new Ft546WcsProperties();
Wcs2WmsController controller = new Wcs2WmsController(legacy,
standard, properties);
assertSame(legacyResult, controller.receiveInMydoJob(job));
verify(legacy).receiveInMydoJob(job);
properties.setRuntimeMode(Ft546WcsProperties.RuntimeMode.STANDARD);
AjaxResult standardResult = controller.receiveInMydoJob(job);
assertTrue(standardResult.isSuccess());
assertTrue(standardResult.get(AjaxResult.DATA_TAG)
instanceof TransportOrderResult);
assertEquals(1, useCase.createCommands.size());
}
@Test
void controllerDelegatesCancelAndSnapshotWithoutLegacyWritesInStandard() {
IApiService legacy = mock(IApiService.class);
FakeTransportOrderUseCase useCase = new FakeTransportOrderUseCase();
Ft546WmsAdapterService standard = new Ft546WmsAdapterService(useCase,
() -> Arrays.asList("S1", "S2"));
Ft546WcsProperties properties = new Ft546WcsProperties();
properties.setRuntimeMode(Ft546WcsProperties.RuntimeMode.STANDARD);
Wcs2WmsController controller = new Wcs2WmsController(legacy,
standard, properties);
JobParam cancel = new JobParam("JOB-1", "TRAY-1", "TASK-1");
AjaxResult cancelResult = controller.cancelMydoJob(cancel);
AjaxResult snapshotResult = controller.tidyVehicleSnapshot();
assertTrue(cancelResult.isSuccess());
assertEquals(Arrays.asList("S1", "S2"),
snapshotResult.get(AjaxResult.DATA_TAG));
assertEquals(Collections.singletonList("TASK-1"),
useCase.cancelledExternalIds);
verify(legacy, never()).cancelMydoJob(any(JobParam.class));
verify(legacy, never()).tidyVehicleSnapshot();
}
@Test
void notificationUsesEventIdAsLegacyCallbackIdempotencyKey() {
FakeRequestLogService requestLogs = new FakeRequestLogService();
Ft546WmsNotificationGateway gateway =
new Ft546WmsNotificationGateway(requestLogs);
Map<String, String> context = new LinkedHashMap<String, String>();
context.put("jobId", "JOB-1");
context.put("inOrOut", "10");
WmsNotification notification = new WmsNotification("EVENT-1",
"TASK-1", "ORDER-1", NOW, "OrderCompleted", "OK",
"completed", context);
WmsNotificationReceipt receipt = gateway.notify(notification);
assertEquals(WmsNotificationReceipt.Status.DELIVERED,
receipt.getStatus());
JSONObject payload = JSONUtil.parseObj(requestLogs.requestBody);
assertEquals("EVENT-1", payload.getStr("eventId"));
assertEquals("JOB-1", payload.getStr("jobId"));
assertEquals("TASK-1", payload.getStr("taskNo"));
assertEquals("10", payload.getStr("wmsType"));
assertEquals("OrderCompleted", payload.getStr("eventType"));
}
@Test
void notificationTransportFailureRemainsRetryable() {
FakeRequestLogService requestLogs = new FakeRequestLogService();
requestLogs.success = false;
Ft546WmsNotificationGateway gateway =
new Ft546WmsNotificationGateway(requestLogs);
WmsNotification notification = new WmsNotification("EVENT-2",
"TASK-2", "ORDER-2", NOW, "OrderFailed", "FAILED",
"fault", Collections.<String, String>emptyMap());
WmsNotificationReceipt receipt = gateway.notify(notification);
assertEquals(WmsNotificationReceipt.Status.RETRYABLE_FAILURE,
receipt.getStatus());
}
private static ReceiveJob job(String taskNo) {
ReceiveJob job = new ReceiveJob();
job.setTaskNo(taskNo);
job.setJobId("JOB-1");
job.setTrayCode("TRAY-1");
job.setInOrOut("10");
job.setRoadwayId("R1");
job.setClassId("7");
job.setPriority(5L);
return job;
}
private static final class FakeTransportOrderUseCase
implements TransportOrderUseCase {
private final Map<String, TransportOrderResult> orders =
new LinkedHashMap<String, TransportOrderResult>();
private final List<CreateTransportOrderCommand> createCommands =
new ArrayList<CreateTransportOrderCommand>();
private final List<String> cancelledExternalIds =
new ArrayList<String>();
@Override
public TransportOrderResult create(CreateTransportOrderCommand command) {
createCommands.add(command);
TransportOrderResult existing = orders.get(
command.getExternalRequestId());
if (existing != null) {
return existing;
}
TransportOrder order = TransportOrder.accept(
"ORDER-" + command.getExternalRequestId(),
command.getExternalRequestId(), command.getOrderType(),
command.getLoadId(), command.getSourceCode(),
command.getDestinationCode(), command.getPriority(), NOW);
order.plan("WORKFLOW-" + command.getExternalRequestId());
TransportOrderResult result = TransportOrderResult.from(order);
orders.put(command.getExternalRequestId(), result);
return result;
}
@Override
public TransportOrderResult cancel(String externalRequestId) {
cancelledExternalIds.add(externalRequestId);
TransportOrderResult existing = orders.get(externalRequestId);
if (existing != null) {
return existing;
}
CreateTransportOrderCommand command =
new CreateTransportOrderCommand(externalRequestId,
TransportOrderType.INBOUND, null, "UNKNOWN-SOURCE",
"UNKNOWN-TARGET", 0, null,
Collections.<String, String>emptyMap());
return create(command);
}
@Override
public TransportOrderResult suspend(String orderId, String reason) {
throw new UnsupportedOperationException();
}
@Override
public TransportOrderResult resume(String orderId) {
throw new UnsupportedOperationException();
}
}
private static final class FakeRequestLogService
extends RequestLogServiceImpl {
private boolean success = true;
private String requestBody;
@Override
public RequestLog getRequestLog(String url, String endpoint,
String body) {
this.requestBody = body;
RequestLog log = new RequestLog();
log.setIsSuccessful(success ? "1" : "0");
log.setErrorDetails(success ? null : "injected failure");
return log;
}
}
}