|
|
@@ -211,6 +211,11 @@ public class FlashDeliveryApplicationService {
|
|
|
boolean pinRequired = request.getPinRequired() == null || request.getPinRequired();
|
|
|
String payType = normalizePayType(request.getPayType());
|
|
|
List<String> senderImages = validateProofUrls(request.getSenderImageUrls(), false);
|
|
|
+ if (!senderImages.isEmpty()) {
|
|
|
+ if (quote.pickups().size() != 1 || quote.pickups().get(0).getSenderImageUrls() != null
|
|
|
+ && !quote.pickups().get(0).getSenderImageUrls().isEmpty()) throw fail("flash.delivery.pickup.input.conflict");
|
|
|
+ quote.pickups().get(0).setSenderImageUrls(senderImages);
|
|
|
+ }
|
|
|
FlashDeliveryOrder order = new FlashDeliveryOrder();
|
|
|
order.setOrderNo(generateOrderNo());
|
|
|
order.setClientRequestId(requestId);
|
|
|
@@ -272,7 +277,6 @@ public class FlashDeliveryApplicationService {
|
|
|
}
|
|
|
}
|
|
|
saveStops(order, quote.pickups(), request.getDelivery(), now);
|
|
|
- saveImages(order.getId(), "SENDER", "USER", userId, senderImages, now);
|
|
|
writeLog(order.getId(), null, WAITING_ACCEPTANCE, "USER", userId, null, now);
|
|
|
if (Boolean.TRUE.equals(order.getIsDisplay())) {
|
|
|
notificationService.notifyAvailable(order);
|
|
|
@@ -349,6 +353,7 @@ public class FlashDeliveryApplicationService {
|
|
|
throw fail("flash.delivery.state.changed");
|
|
|
}
|
|
|
// 条件更新成功后持有订单行锁至提交,抢单不会读到仅修改一半的地址。
|
|
|
+ imageMapper.delete(new QueryWrapper<FlashDeliveryOrderImage>().eq("order_id", orderId).eq("proof_type", "SENDER"));
|
|
|
stopMapper.delete(new QueryWrapper<FlashDeliveryOrderStop>().eq("order_id", orderId));
|
|
|
saveStops(order, pickups, request.getDelivery(), now);
|
|
|
order.setVersion(order.getVersion() + 1);
|
|
|
@@ -430,7 +435,7 @@ public class FlashDeliveryApplicationService {
|
|
|
return view;
|
|
|
}
|
|
|
|
|
|
- /** v2 待接单改址报价;订单级物品、配送方式与原运价快照保持不变。 */
|
|
|
+ /** v2 待接单改址报价;逐站物品随完整站点提交,配送方式与原运价快照保持不变。 */
|
|
|
public FlashDeliveryQuoteView quoteAddressV2(Long userId, FlashDeliveryV2AddressChangeRequest request) {
|
|
|
if (request == null) throw fail("flash.delivery.request.required");
|
|
|
FlashDeliveryOrder order = requireEditableOrder(userId, request.getOrderId(), request.getOrderVersion());
|
|
|
@@ -451,8 +456,7 @@ public class FlashDeliveryApplicationService {
|
|
|
throw new FlashDeliveryQuoteChangedException(quote);
|
|
|
}
|
|
|
List<FlashDeliveryV2StopRequest> stops = normalizeV2Stops(request.getStops());
|
|
|
- FlashDeliveryV2QuoteRequest orderItems = v2OrderSnapshot(order, stops);
|
|
|
- copyPickupSummary(order, pickupAdapters(stops.stream().filter(s -> "PICKUP".equals(s.getType())).toList(), orderItems));
|
|
|
+ copyPickupSummary(order, pickupAdapters(stops.stream().filter(s -> "PICKUP".equals(s.getType())).toList()));
|
|
|
FlashDeliveryV2StopRequest firstDelivery = stops.stream().filter(s -> "DELIVERY".equals(s.getType())).findFirst().orElseThrow();
|
|
|
copyAddress(firstDelivery, order, false);
|
|
|
order.setReceiverUserId(resolveReceiverUserId(firstDelivery.getPhone()));
|
|
|
@@ -468,6 +472,7 @@ public class FlashDeliveryApplicationService {
|
|
|
if (orderMapper.updateWaitingAddress(order, request.getOrderVersion()) != 1) {
|
|
|
throw fail("flash.delivery.state.changed");
|
|
|
}
|
|
|
+ imageMapper.delete(new QueryWrapper<FlashDeliveryOrderImage>().eq("order_id", order.getId()).eq("proof_type", "SENDER"));
|
|
|
stopMapper.delete(new QueryWrapper<FlashDeliveryOrderStop>().eq("order_id", order.getId()));
|
|
|
saveStopsV2(order, stops, Boolean.TRUE.equals(order.getPinRequired()), now);
|
|
|
order.setVersion(order.getVersion() + 1);
|
|
|
@@ -480,7 +485,7 @@ public class FlashDeliveryApplicationService {
|
|
|
if (order.getDeliveryStopCount() == null) throw fail("flash.delivery.edit.not.allowed");
|
|
|
List<FlashDeliveryV2StopRequest> stops = normalizeV2Stops(request.getStops());
|
|
|
FlashDeliveryV2QuoteRequest orderItems = v2OrderSnapshot(order, stops);
|
|
|
- validateOrderLevelItem(orderItems);
|
|
|
+
|
|
|
FlashDeliveryPricing pricing = pricingSnapshot(order);
|
|
|
RouteDistance route = v2Route(stops, vehicleTypeOf(order));
|
|
|
FlashDeliveryPriceBreakdown breakdown;
|
|
|
@@ -491,7 +496,7 @@ public class FlashDeliveryApplicationService {
|
|
|
throw fail("flash.delivery.tip.invalid");
|
|
|
}
|
|
|
List<FlashDeliveryPickupRequest> pickups = pickupAdapters(stops.stream()
|
|
|
- .filter(s -> "PICKUP".equals(s.getType())).toList(), orderItems);
|
|
|
+ .filter(s -> "PICKUP".equals(s.getType())).toList());
|
|
|
FlashDeliveryQuoteView view = quoteView(quoteAdapter(orderItems),
|
|
|
new QuoteContext(pricing, route, breakdown, pickups));
|
|
|
view.setOrderVersion(order.getVersion());
|
|
|
@@ -790,9 +795,9 @@ public class FlashDeliveryApplicationService {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // ==== v2 多点取送统一契约(2026-10-14):统一 stops 数组、订单级物品、独立计价 ====
|
|
|
+ // ==== v2 多点取送统一契约(2026-10-14):统一 stops 数组、取货站独立物品、独立计价 ====
|
|
|
|
|
|
- /** v2 实时报价:统一站点数组顺序即路线顺序,物品主体在订单级,独立计价方法。 */
|
|
|
+ /** v2 实时报价:统一站点数组顺序即路线顺序,物品按取货站设置,独立计价方法。 */
|
|
|
public FlashDeliveryQuoteView quoteV2(FlashDeliveryV2QuoteRequest request) {
|
|
|
QuoteContext context = calculateQuoteV2(request);
|
|
|
return quoteView(quoteAdapter(request), context);
|
|
|
@@ -823,7 +828,6 @@ public class FlashDeliveryApplicationService {
|
|
|
validateSchedule(deliveryMode, request.getScheduledPickupStartAt(), request.getScheduledPickupEndAt(), now);
|
|
|
boolean pinRequired = request.getPinRequired() == null || request.getPinRequired();
|
|
|
String payType = normalizePayType(request.getPayType());
|
|
|
- List<String> senderImages = validateProofUrls(request.getSenderImageUrls(), false);
|
|
|
List<FlashDeliveryV2StopRequest> deliveries = stops.stream()
|
|
|
.filter(s -> "DELIVERY".equals(s.getType())).toList();
|
|
|
FlashDeliveryOrder order = new FlashDeliveryOrder();
|
|
|
@@ -888,7 +892,6 @@ public class FlashDeliveryApplicationService {
|
|
|
}
|
|
|
}
|
|
|
saveStopsV2(order, stops, pinRequired, now);
|
|
|
- saveImages(order.getId(), "SENDER", "USER", userId, senderImages, now);
|
|
|
writeLog(order.getId(), null, WAITING_ACCEPTANCE, "USER", userId, null, now);
|
|
|
if (Boolean.TRUE.equals(order.getIsDisplay())) {
|
|
|
notificationService.notifyAvailable(order);
|
|
|
@@ -896,16 +899,6 @@ public class FlashDeliveryApplicationService {
|
|
|
return participantDetail(order, true, false);
|
|
|
}
|
|
|
|
|
|
- /** v2 物品主体在订单级一次设置;校验规则与旧逐站物品一致。 */
|
|
|
- private void validateOrderLevelItem(FlashDeliveryV2QuoteRequest request) {
|
|
|
- if (!PACKAGE_TYPES.contains(Objects.toString(request.getPackageType(), ""))) {
|
|
|
- throw fail("flash.delivery.package.type.invalid");
|
|
|
- }
|
|
|
- if (request.getQuantity() == null || request.getQuantity() <= 0
|
|
|
- || hasText(request.getWeightRange()) && !WEIGHT_RANGES.contains(request.getWeightRange())
|
|
|
- || tooLong(request.getSpecification(), 255)) throw fail("flash.delivery.item.invalid");
|
|
|
- }
|
|
|
-
|
|
|
/** v2 报价核心:站点结构校验后命中运价,路线经点为全部取货站与收货站。 */
|
|
|
private QuoteContext calculateQuoteV2(FlashDeliveryV2QuoteRequest request) {
|
|
|
if (request == null) throw fail("flash.delivery.request.required");
|
|
|
@@ -913,7 +906,6 @@ public class FlashDeliveryApplicationService {
|
|
|
validateDeliveryType(request.getDeliveryType());
|
|
|
List<FlashDeliveryV2StopRequest> stops = normalizeV2Stops(request.getStops());
|
|
|
if (request.getTipAmount() == null || request.getTipAmount() < 0) throw fail("flash.delivery.tip.invalid");
|
|
|
- validateOrderLevelItem(request);
|
|
|
Date now = new Date();
|
|
|
String deliveryMode = normalizeDeliveryMode(request.getDeliveryMode());
|
|
|
validateSchedule(deliveryMode, request.getScheduledPickupStartAt(), request.getScheduledPickupEndAt(), now);
|
|
|
@@ -925,19 +917,14 @@ public class FlashDeliveryApplicationService {
|
|
|
route.distanceMeters(), request.getDeliveryType(), request.getTipAmount());
|
|
|
List<FlashDeliveryV2StopRequest> pickups = stops.stream()
|
|
|
.filter(s -> "PICKUP".equals(s.getType())).toList();
|
|
|
- return new QuoteContext(pricing, route, breakdown, pickupAdapters(pickups, request));
|
|
|
+ return new QuoteContext(pricing, route, breakdown, pickupAdapters(pickups));
|
|
|
}
|
|
|
|
|
|
- /** v2 物品主体在订单级;内部取货站适配器统一携带订单级物品供既有校验与摘要复用。 */
|
|
|
- private List<FlashDeliveryPickupRequest> pickupAdapters(List<FlashDeliveryV2StopRequest> pickups,
|
|
|
- FlashDeliveryV2QuoteRequest request) {
|
|
|
+ /** v2 取货站适配器携带本站独立物品和图片。 */
|
|
|
+ private List<FlashDeliveryPickupRequest> pickupAdapters(List<FlashDeliveryV2StopRequest> pickups) {
|
|
|
return pickups.stream().map(stop -> {
|
|
|
FlashDeliveryPickupRequest adapter = new FlashDeliveryPickupRequest();
|
|
|
BeanUtils.copyProperties(stop, adapter);
|
|
|
- adapter.setPackageType(request.getPackageType());
|
|
|
- adapter.setQuantity(request.getQuantity());
|
|
|
- adapter.setWeightRange(request.getWeightRange());
|
|
|
- adapter.setSpecification(request.getSpecification());
|
|
|
return adapter;
|
|
|
}).toList();
|
|
|
}
|
|
|
@@ -946,10 +933,22 @@ public class FlashDeliveryApplicationService {
|
|
|
private List<FlashDeliveryV2StopRequest> normalizeV2Stops(List<FlashDeliveryV2StopRequest> stops) {
|
|
|
if (stops == null || stops.isEmpty()) throw fail("flash.delivery.stops.required");
|
|
|
for (FlashDeliveryV2StopRequest stop : stops) {
|
|
|
- if (!"PICKUP".equals(stop.getType()) && !"DELIVERY".equals(stop.getType())) {
|
|
|
+ if (stop == null || !"PICKUP".equals(stop.getType()) && !"DELIVERY".equals(stop.getType())) {
|
|
|
throw fail("flash.delivery.stop.type.invalid");
|
|
|
}
|
|
|
validateAddress(stop);
|
|
|
+ if ("PICKUP".equals(stop.getType())) {
|
|
|
+ if (!PACKAGE_TYPES.contains(Objects.toString(stop.getPackageType(), ""))) {
|
|
|
+ throw fail("flash.delivery.package.type.invalid");
|
|
|
+ }
|
|
|
+ if (stop.getQuantity() == null || stop.getQuantity() <= 0
|
|
|
+ || hasText(stop.getWeightRange()) && !WEIGHT_RANGES.contains(stop.getWeightRange())
|
|
|
+ || tooLong(stop.getSpecification(), 255)) throw fail("flash.delivery.item.invalid");
|
|
|
+ validateProofUrls(stop.getSenderImageUrls(), false);
|
|
|
+ } else if (stop.getPackageType() != null || stop.getQuantity() != null || stop.getWeightRange() != null
|
|
|
+ || stop.getSpecification() != null || stop.getSenderImageUrls() != null && !stop.getSenderImageUrls().isEmpty()) {
|
|
|
+ throw fail("flash.delivery.item.invalid");
|
|
|
+ }
|
|
|
if (tooLong(stop.getRemark(), 200)) throw fail("flash.delivery.stop.remark.too.long");
|
|
|
}
|
|
|
List<FlashDeliveryV2StopRequest> pickups = stops.stream()
|
|
|
@@ -996,10 +995,6 @@ public class FlashDeliveryApplicationService {
|
|
|
adapter.setServiceType(request.getServiceType());
|
|
|
adapter.setDeliveryType(request.getDeliveryType());
|
|
|
adapter.setVehicleType(request.getVehicleType());
|
|
|
- adapter.setPackageType(request.getPackageType());
|
|
|
- adapter.setQuantity(request.getQuantity());
|
|
|
- adapter.setWeightRange(request.getWeightRange());
|
|
|
- adapter.setSpecification(request.getSpecification());
|
|
|
adapter.setTipAmount(request.getTipAmount());
|
|
|
adapter.setDeliveryMode(request.getDeliveryMode());
|
|
|
adapter.setScheduledPickupStartAt(request.getScheduledPickupStartAt());
|
|
|
@@ -1029,6 +1024,10 @@ public class FlashDeliveryApplicationService {
|
|
|
row.setHandoffMethod(trimToNull(stop.getHandoffMethod()));
|
|
|
row.setLongitude(stop.getLongitude()); row.setLatitude(stop.getLatitude());
|
|
|
row.setRemark(trimToNull(stop.getRemark()));
|
|
|
+ if ("PICKUP".equals(stop.getType())) {
|
|
|
+ row.setPackageType(stop.getPackageType()); row.setQuantity(stop.getQuantity());
|
|
|
+ row.setWeightRange(trimToNull(stop.getWeightRange())); row.setSpecification(trimToNull(stop.getSpecification()));
|
|
|
+ }
|
|
|
row.setOrderId(order.getId()); row.setStopType(stop.getType()); row.setStopOrder(i);
|
|
|
row.setStatus("PENDING"); row.setCreateTime(now);
|
|
|
if ("DELIVERY".equals(stop.getType())) {
|
|
|
@@ -1042,6 +1041,10 @@ public class FlashDeliveryApplicationService {
|
|
|
}
|
|
|
}
|
|
|
if (stopMapper.insert(row) != 1) throw fail("flash.delivery.state.changed");
|
|
|
+ if ("PICKUP".equals(stop.getType())) {
|
|
|
+ saveStationImages(order.getId(), row.getId(), "SENDER", "USER", order.getUserId(),
|
|
|
+ validateProofUrls(stop.getSenderImageUrls(), false), now);
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -1392,22 +1395,6 @@ public class FlashDeliveryApplicationService {
|
|
|
return value == null ? null : value.setScale(2, RoundingMode.HALF_UP);
|
|
|
}
|
|
|
|
|
|
- /** 状态、图片和日志处于同一事务;任一图片写入失败会回滚本次业务操作。 */
|
|
|
- private void saveImages(Long orderId, String proofType, String operatorType,
|
|
|
- Long operatorId, List<String> urls, Date now) {
|
|
|
- for (int index = 0; index < urls.size(); index++) {
|
|
|
- FlashDeliveryOrderImage image = new FlashDeliveryOrderImage();
|
|
|
- image.setOrderId(orderId);
|
|
|
- image.setProofType(proofType);
|
|
|
- image.setImageUrl(urls.get(index));
|
|
|
- image.setSortOrder(index);
|
|
|
- image.setOperatorType(operatorType);
|
|
|
- image.setOperatorId(operatorId);
|
|
|
- image.setCreateTime(now);
|
|
|
- imageMapper.insert(image);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
/** 校验凭证图片 URL:必填时 1 至 9 张,每项为合法 URI 且不超过 1000 字符。 */
|
|
|
private List<String> validateProofUrls(List<String> values, boolean required) {
|
|
|
if (values == null || values.isEmpty()) {
|
|
|
@@ -1532,10 +1519,9 @@ public class FlashDeliveryApplicationService {
|
|
|
}
|
|
|
|
|
|
/** 订单实体转骑手端任务卡片,可附带骑手到取件点的直线距离。 */
|
|
|
- /** 列表页一次 IN 批量取回 v2 多站点单的站点,避免逐单 N+1;单点单卡片不需要逐站展示。 */
|
|
|
+ /** 列表页一次 IN 批量取回所有闪送订单站点及货品,避免逐单 N+1。 */
|
|
|
private Map<Long, List<FlashDeliveryOrderStop>> stopRowsFor(List<FlashDeliveryOrder> records) {
|
|
|
List<Long> orderIds = records.stream()
|
|
|
- .filter(order -> order.getDeliveryStopCount() != null)
|
|
|
.map(FlashDeliveryOrder::getId).toList();
|
|
|
if (orderIds.isEmpty()) return Map.of();
|
|
|
return stopMapper.selectList(new QueryWrapper<FlashDeliveryOrderStop>()
|
|
|
@@ -1558,10 +1544,6 @@ public class FlashDeliveryApplicationService {
|
|
|
view.setDeliveryStopCount(expectedDeliveryStopCount(order));
|
|
|
view.setDeliveredStopCount(deliveredStopCount(order));
|
|
|
view.setCanUserCancel(canUserCancel(order));
|
|
|
- view.setPackageType(order.getPackageType());
|
|
|
- view.setQuantity(order.getQuantity());
|
|
|
- view.setWeightRange(order.getWeightRange());
|
|
|
- view.setSpecification(order.getSpecification());
|
|
|
view.setDeliveryMode(order.getDeliveryMode());
|
|
|
view.setScheduledPickupStartAt(order.getScheduledPickupStartAt());
|
|
|
view.setScheduledPickupEndAt(order.getScheduledPickupEndAt());
|
|
|
@@ -1585,8 +1567,8 @@ public class FlashDeliveryApplicationService {
|
|
|
view.setCreateTime(order.getCreateTime());
|
|
|
// 备注仅对中单骑手本人可见;newTask 待抢卡片保持脱敏为空。
|
|
|
view.setUserNote(Objects.equals(riderId, order.getRiderId()) ? order.getUserNote() : null);
|
|
|
- // v2 多站点单卡片逐站展示取送地址与状态;与详情同口径脱敏联系人、电话、坐标和凭证。
|
|
|
- if (order.getDeliveryStopCount() != null && stopRows != null && !stopRows.isEmpty()) {
|
|
|
+ // 闪送卡片逐站展示货品、取送地址与状态;与详情同口径脱敏联系人、电话、坐标和凭证。
|
|
|
+ if (stopRows != null && !stopRows.isEmpty()) {
|
|
|
view.setStops(stopViews(stopRows, false, List.of()));
|
|
|
}
|
|
|
return view;
|
|
|
@@ -1600,17 +1582,14 @@ public class FlashDeliveryApplicationService {
|
|
|
return view;
|
|
|
}
|
|
|
|
|
|
- /** 按凭证类型把图片分组为寄件、取件、送达三组 URL。 */
|
|
|
+ /** 按凭证类型汇总骑手取件、送达图片;商品图片按取货站返回。 */
|
|
|
private void groupImageUrls(FlashDeliveryOrderDetailView view, List<FlashDeliveryOrderImage> images) {
|
|
|
- List<String> sender = new ArrayList<>();
|
|
|
List<String> pickup = new ArrayList<>();
|
|
|
List<String> delivery = new ArrayList<>();
|
|
|
for (FlashDeliveryOrderImage image : images) {
|
|
|
- if ("SENDER".equals(image.getProofType())) sender.add(image.getImageUrl());
|
|
|
- else if ("PICKUP".equals(image.getProofType())) pickup.add(image.getImageUrl());
|
|
|
+ if ("PICKUP".equals(image.getProofType())) pickup.add(image.getImageUrl());
|
|
|
else if ("DELIVERY".equals(image.getProofType())) delivery.add(image.getImageUrl());
|
|
|
}
|
|
|
- view.setSenderImageUrls(sender);
|
|
|
view.setPickupImageUrls(pickup);
|
|
|
view.setDeliveryImageUrls(delivery);
|
|
|
}
|
|
|
@@ -1647,10 +1626,6 @@ public class FlashDeliveryApplicationService {
|
|
|
view.setDeliveryStopCount(expectedDeliveryStopCount(order));
|
|
|
view.setDeliveredStopCount(deliveredStopCount(order));
|
|
|
view.setCanUserCancel(canUserCancel(order));
|
|
|
- view.setPackageType(order.getPackageType());
|
|
|
- view.setQuantity(order.getQuantity());
|
|
|
- view.setWeightRange(order.getWeightRange());
|
|
|
- view.setSpecification(order.getSpecification());
|
|
|
view.setDeliveryMode(order.getDeliveryMode());
|
|
|
view.setScheduledPickupStartAt(order.getScheduledPickupStartAt());
|
|
|
view.setScheduledPickupEndAt(order.getScheduledPickupEndAt());
|
|
|
@@ -2046,9 +2021,9 @@ public class FlashDeliveryApplicationService {
|
|
|
FlashDeliveryPickupRequest pickup = new FlashDeliveryPickupRequest();
|
|
|
BeanUtils.copyProperties(pickups.get(0), pickup);
|
|
|
BeanUtils.copyProperties(request.getPickup(), pickup);
|
|
|
- // 站点不再保存逐站物品;单点改址回退时物品取订单级摘要,与统一契约一致。
|
|
|
- pickup.setPackageType(order.getPackageType()); pickup.setQuantity(order.getQuantity());
|
|
|
- pickup.setWeightRange(order.getWeightRange()); pickup.setSpecification(order.getSpecification());
|
|
|
+ pickup.setSenderImageUrls(imageMapper.selectList(new QueryWrapper<FlashDeliveryOrderImage>()
|
|
|
+ .eq("order_id", order.getId()).eq("stop_id", pickups.get(0).getId()).eq("proof_type", "SENDER")
|
|
|
+ .orderByAsc("sort_order", "id")).stream().map(FlashDeliveryOrderImage::getImageUrl).toList());
|
|
|
return List.of(pickup);
|
|
|
}
|
|
|
|
|
|
@@ -2067,6 +2042,7 @@ public class FlashDeliveryApplicationService {
|
|
|
if (pickup.getQuantity() == null || pickup.getQuantity() <= 0
|
|
|
|| hasText(pickup.getWeightRange()) && !WEIGHT_RANGES.contains(pickup.getWeightRange())
|
|
|
|| tooLong(pickup.getSpecification(), 255)) throw fail("flash.delivery.item.invalid");
|
|
|
+ validateProofUrls(pickup.getSenderImageUrls(), false);
|
|
|
if (sameAddressText(pickup, delivery)
|
|
|
|| pickup.getLatitude().compareTo(delivery.getLatitude()) == 0
|
|
|
&& pickup.getLongitude().compareTo(delivery.getLongitude()) == 0) {
|
|
|
@@ -2140,31 +2116,33 @@ public class FlashDeliveryApplicationService {
|
|
|
} catch (Exception ignored) { return null; }
|
|
|
}
|
|
|
|
|
|
- /** 订单旧字段仅维护首站兼容摘要,不代表全部站点物品。 */
|
|
|
+ /** 订单仅维护首站地址摘要,货品以取货站为准。 */
|
|
|
private void copyPickupSummary(FlashDeliveryOrder order, List<FlashDeliveryPickupRequest> pickups) {
|
|
|
FlashDeliveryPickupRequest first = pickups.get(0);
|
|
|
copyAddress(first, order, true);
|
|
|
- order.setPackageType(first.getPackageType()); order.setQuantity(first.getQuantity());
|
|
|
- order.setWeightRange(first.getWeightRange()); order.setSpecification(trimToNull(first.getSpecification()));
|
|
|
order.setPickupStopCount(pickups.size());
|
|
|
}
|
|
|
|
|
|
/** 调用方已创建订单或持有订单行锁,全部站点与订单在同一事务保存。 */
|
|
|
private void saveStops(FlashDeliveryOrder order, List<FlashDeliveryPickupRequest> pickups,
|
|
|
FlashDeliveryAddressRequest delivery, Date now) {
|
|
|
- for (int i = 0; i < pickups.size(); i++) insertStop(order.getId(), pickups.get(i), "PICKUP", i, now);
|
|
|
- insertStop(order.getId(), delivery, "DELIVERY", pickups.size(), now);
|
|
|
+ for (int i = 0; i < pickups.size(); i++) insertStop(order, pickups.get(i), "PICKUP", i, now);
|
|
|
+ insertStop(order, delivery, "DELIVERY", pickups.size(), now);
|
|
|
}
|
|
|
|
|
|
- private void insertStop(Long orderId, FlashDeliveryAddressRequest address, String type, int index, Date now) {
|
|
|
+ private void insertStop(FlashDeliveryOrder order, FlashDeliveryAddressRequest address, String type, int index, Date now) {
|
|
|
FlashDeliveryOrderStop stop = new FlashDeliveryOrderStop();
|
|
|
BeanUtils.copyProperties(address, stop);
|
|
|
stop.setName(address.getName().trim()); stop.setPhone(address.getPhone().trim());
|
|
|
stop.setAddress(address.getAddress().trim()); stop.setAddressDetail(trimToNull(address.getAddressDetail()));
|
|
|
stop.setHandoffMethod(trimToNull(address.getHandoffMethod()));
|
|
|
- stop.setOrderId(orderId); stop.setStopType(type); stop.setStopOrder(index);
|
|
|
+ stop.setOrderId(order.getId()); stop.setStopType(type); stop.setStopOrder(index);
|
|
|
stop.setStatus("PENDING"); stop.setCreateTime(now);
|
|
|
if (stopMapper.insert(stop) != 1) throw fail("flash.delivery.state.changed");
|
|
|
+ if (address instanceof FlashDeliveryPickupRequest pickup) {
|
|
|
+ saveStationImages(order.getId(), stop.getId(), "SENDER", "USER", order.getUserId(),
|
|
|
+ validateProofUrls(pickup.getSenderImageUrls(), false), now);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/** 事务内使用当前读,避免骑手资料查询建立的旧快照遮蔽锁等待期间的履约变化;GET 不加锁。 */
|
|
|
@@ -2373,6 +2351,10 @@ public class FlashDeliveryApplicationService {
|
|
|
FlashDeliveryStopView view = new FlashDeliveryStopView();
|
|
|
BeanUtils.copyProperties(stop, view);
|
|
|
view.setDeliveryPinCode(null);
|
|
|
+ if (sensitive && "PICKUP".equals(stop.getStopType())) {
|
|
|
+ view.setSenderImageUrls(images.stream().filter(i -> Objects.equals(i.getStopId(), stop.getId())
|
|
|
+ && "SENDER".equals(i.getProofType())).map(FlashDeliveryOrderImage::getImageUrl).toList());
|
|
|
+ }
|
|
|
if (sensitive) view.setImageUrls(images.stream().filter(i -> Objects.equals(i.getStopId(), stop.getId())
|
|
|
&& Objects.equals(i.getProofType(), stop.getStopType()))
|
|
|
.map(FlashDeliveryOrderImage::getImageUrl).toList());
|