发布采购、拼车、预约及匹配端侧修复至灰度 #26
@@ -206,11 +206,36 @@ public class FleetTripService {
|
||||
try { if (bindings.insert(binding) != 1) throw conflict("排车单关联失败"); }
|
||||
catch (DuplicateKeyException duplicate) { throw conflict("排车单已关联其他车次,请刷新后重试"); }
|
||||
bookingReservations.bindIncoming(trip, dispatch, dispatches.sourceCargo(dispatch.dispatchNo()), operator);
|
||||
var route = matchedStops(response(trip).stops(), dispatches.manifest(dispatch.dispatchNo(), false).cargo());
|
||||
validatePlan(instant(trip.getPlannedDepartureAt()), instant(trip.getExpectedDriverEndAt()), route);
|
||||
bookingReservations.requireRoute(trip, route);
|
||||
trip.setStopsJson(write(route));
|
||||
dispatches.assign(dispatch, assignment(trip));
|
||||
persist(trip, request.recordVersion(), "BIND_DISPATCH", request.reason(), operator);
|
||||
return detail(trip);
|
||||
}
|
||||
|
||||
static List<FleetTripModels.Stop> matchedStops(List<FleetTripModels.Stop> existing, List<FleetExecutionModels.Cargo> cargo) {
|
||||
// Keep established stop indexes/order: confirmed bookings may refer to them.
|
||||
var result = new ArrayList<>(existing);
|
||||
boolean onlyPlaceholder = existing.size() == 2 && existing.get(1).destinationKey() == null
|
||||
&& existing.get(1).name().startsWith("待确定卸货点");
|
||||
if (onlyPlaceholder) result.remove(1);
|
||||
var keys = new HashSet<String>();
|
||||
for (var stop : result) if (stop.destinationKey() != null) keys.add(stop.destinationKey());
|
||||
for (var item : cargo) {
|
||||
if (item.destinationKey() == null || item.destinationKey().isBlank())
|
||||
throw conflict("排车货物目的地未确认,请先完善排车单目的地");
|
||||
if (keys.add(item.destinationKey())) {
|
||||
if (item.destinationLabel() == null || item.destinationLabel().isBlank())
|
||||
throw conflict("排车货物目的地名称缺失,请先完善排车单");
|
||||
result.add(new FleetTripModels.Stop(item.destinationLabel(), null, item.destinationKey()));
|
||||
}
|
||||
}
|
||||
if (result.size() < 2) throw conflict("排车单没有可用卸货目的地");
|
||||
return List.copyOf(result);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public FleetTripModels.Detail unbindDispatch(String tripNo, String operator, FleetTripModels.BindingCommand request) {
|
||||
var trip = planned(tripNo, request.recordVersion());
|
||||
|
||||
@@ -220,7 +220,7 @@ paths:
|
||||
parameters: [{$ref: '#/components/parameters/TripNo'}]
|
||||
post:
|
||||
summary: 将客户排车单关联到车次
|
||||
description: '权限:platform:fleet:trip:edit;按业务单号解析客户归属,同仓且未开工;关联和车/司机快照同步原子提交。'
|
||||
description: '权限:platform:fleet:trip:edit;按业务单号解析客户归属,同仓且未开工;关联、车/司机快照同步及按真实货物目的地标识补齐卸货站原子提交;目的地缺失拒绝关联,已有有效站点顺序与索引保留,初始默认占位站替换为真实目的地。'
|
||||
requestBody: {required: true, content: {application/json: {schema: {$ref: '#/components/schemas/BindingCommand'}}}}
|
||||
responses: {'200': {$ref: '#/components/responses/Detail'}}
|
||||
/api/platform/v1/last-leg/fleet/trips/{tripNo}/dispatches/unbind:
|
||||
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
package com.baiyue.lastleg.fleet.trip;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import java.util.List;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
class FleetTripMatchedStopsTest {
|
||||
private FleetExecutionModels.Cargo cargo(String key, String label) {
|
||||
return new FleetExecutionModels.Cargo("DP-1", "A", "1", "2", "PLT-1", 1, key, label);
|
||||
}
|
||||
@Test void replacesOnlyInitialPlaceholderAndDeduplicatesByIdentity() {
|
||||
var origin = new FleetTripModels.Stop("起运仓", null, null);
|
||||
var result = FleetTripService.matchedStops(List.of(origin, new FleetTripModels.Stop("待确定卸货点1", null, null)),
|
||||
List.of(cargo("FBA:ACY2", "ACY2"), cargo("FBA:ACY2", "ACY2")));
|
||||
assertThat(result).containsExactly(origin, new FleetTripModels.Stop("ACY2", null, "FBA:ACY2"));
|
||||
}
|
||||
@Test void preservesExistingStopIndexesAndAppendsDifferentIdentityEvenWhenNamesMatch() {
|
||||
var existing = List.of(new FleetTripModels.Stop("起点", null, null), new FleetTripModels.Stop("ACY2", null, "FBA:ACY2"));
|
||||
var result = FleetTripService.matchedStops(existing, List.of(cargo("PRIVATE:OTHER", "ACY2")));
|
||||
assertThat(result.subList(0,2)).isEqualTo(existing);
|
||||
assertThat(result.get(2).destinationKey()).isEqualTo("PRIVATE:OTHER");
|
||||
}
|
||||
@Test void rejectsMissingIdentityWithoutUsingDisplayNameAsKey() {
|
||||
assertThatThrownBy(() -> FleetTripService.matchedStops(List.of(new FleetTripModels.Stop("起点", null, null)), List.of(cargo(null,"ACY2"))))
|
||||
.hasMessageContaining("目的地未确认");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user