Просмотр исходного кода

闪送改地址按定价时点最新运价重算,保存时同步刷新运价快照(快照=金额最后计算依据,恒可复算)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
qmj 5 дней назад
Родитель
Сommit
50fb778ad9

+ 17 - 13
ruoyi-admin/src/main/java/com/ruoyi/app/flashdelivery/service/FlashDeliveryApplicationService.java

@@ -269,6 +269,17 @@ public class FlashDeliveryApplicationService {
         order.setDistanceMeters(quote.getDistanceMeters());
         order.setDistanceSource(quote.getDistanceSource());
         order.setEstimatedDurationSeconds(quote.getEstimatedDurationSeconds());
+        // 运价快照与金额同事务刷新为本次计价依据(快照=金额的最后一次计算依据,而非最初依据)
+        order.setPricingId(quote.getPricingId());
+        order.setPricingVersion(quote.getPricingVersion());
+        order.setPricingStartTime(quote.getStartTime());
+        order.setPricingEndTime(quote.getEndTime());
+        order.setStartingDistance(quote.getStartingDistance());
+        order.setStartingFare(quote.getStartingFare());
+        order.setDistance(quote.getDistance());
+        order.setFreight(quote.getFreight());
+        order.setUrgentRate(quote.getUrgentRate());
+        order.setMinimumUrgentFee(quote.getMinimumUrgentFee());
         order.setDistanceFee(quote.getDistanceFee());
         order.setBaseDeliveryFee(quote.getBaseDeliveryFee());
         order.setUrgentFee(quote.getUrgentFee());
@@ -342,18 +353,11 @@ public class FlashDeliveryApplicationService {
                 new GeoPoint(request.getPickup().getLatitude(), request.getPickup().getLongitude()),
                 new GeoPoint(request.getDelivery().getLatitude(), request.getDelivery().getLongitude()));
         if (route.distanceMeters() > MAX_DISTANCE_METERS) throw fail("flash.delivery.distance.too.far");
-        // 沿用订单快照,避免地址编辑顺带切换运价或重验已经到时的预约单。
-        FlashDeliveryPricing pricing = new FlashDeliveryPricing();
-        pricing.setId(order.getPricingId());
-        pricing.setConfigVersion(order.getPricingVersion());
-        pricing.setStartTime(order.getPricingStartTime());
-        pricing.setEndTime(order.getPricingEndTime());
-        pricing.setStartingDistance(order.getStartingDistance());
-        pricing.setStartingFare(order.getStartingFare());
-        pricing.setDistance(order.getDistance());
-        pricing.setFreight(order.getFreight());
-        pricing.setUrgentRate(order.getUrgentRate());
-        pricing.setMinimumUrgentFee(order.getMinimumUrgentFee());
+        // 待接单尚未成交,改址按"订单定价时点"的最新运价重算(预约单取预约取件时刻、
+        // 立即单取当前),管理员调价对未接单的改址立即生效;时段语义保住,预约单不会用到错误时段的价格。
+        Date pricingDate = "SCHEDULED".equals(order.getDeliveryMode())
+                ? order.getScheduledPickupStartAt() : new Date();
+        FlashDeliveryPricing pricing = findPricingAt(pricingTargetTime(pricingDate));
         FlashDeliveryPriceBreakdown breakdown;
         try {
             breakdown = pricingCalculator.calculateBreakdown(pricing, route.distanceMeters(),
@@ -569,7 +573,7 @@ public class FlashDeliveryApplicationService {
                                                  String serviceType, String orderNo,
                                                  Long userId, Long riderId) {
         validateOptionalServiceType(serviceType);
-        QueryWrapper<FlashDeliveryOrder> query = new QueryWrapper<FlashDeliveryOrder>().orderByDesc("create_time");
+        QueryWrapper<FlashDeliveryOrder> query = new QueryWrapper<FlashDeliveryOrder>().orderByDesc("id");
         optionalEq(query, "status", status);
         optionalEq(query, "service_type", serviceType);
         if (hasText(orderNo)) query.like("order_no", orderNo.trim());

+ 6 - 3
ruoyi-admin/src/test/java/com/ruoyi/app/flashdelivery/service/FlashDeliveryApplicationServiceTest.java

@@ -1111,10 +1111,10 @@ class FlashDeliveryApplicationServiceTest {
     }
 
     @Test
-    void addressQuoteUsesOrderPricingSnapshotAndDoesNotWrite() {
+    void addressQuoteUsesLatestPricingForSlotTimeAndDoesNotWrite() {
         Fixture fixture = new Fixture();
         FlashDeliveryOrder order = editableOrder(fixture);
-        // 已到预约时间也允许待接单订单改地址,不重新验证创建时的预约窗口
+        // 已到预约时间也允许待接单订单改地址;报价读取该时点的最新运价而非订单旧快照
         order.setDeliveryMode("SCHEDULED");
         order.setScheduledPickupStartAt(new Date(1));
         order.setScheduledPickupEndAt(new Date(1800001));
@@ -1128,7 +1128,8 @@ class FlashDeliveryApplicationServiceTest {
         assertEquals(2, quote.getOrderVersion());
         assertEquals(1, quote.getPricingVersion());
         assertEquals("pickup road", order.getPickupAddress());
-        verify(fixture.pricingMapper, never()).selectAtTime(anyString());
+        // 改址报价必须查询运价表(按定价时点取最新),不再沿用订单快照
+        verify(fixture.pricingMapper).selectAtTime(anyString());
         verify(fixture.orderMapper, never()).updateWaitingAddress(any(), any());
         verify(fixture.logMapper, never()).insert(any(com.ruoyi.system.domain.flash.FlashDeliveryOrderLog.class));
     }
@@ -1359,6 +1360,8 @@ class FlashDeliveryApplicationServiceTest {
         order.setFreight(15L);
         when(fixture.orderMapper.selectById(10L)).thenReturn(order);
         when(fixture.routeService.calculate(any(), any())).thenReturn(new RouteDistance(4500, 900, "GOOGLE"));
+        // 031 后改址按订单定价时点读最新运价:stub 与订单快照同值,金额断言维持不变
+        when(fixture.pricingMapper.selectAtTime(anyString())).thenReturn(List.of(pricing()));
         return order;
     }
 

+ 1 - 1
ruoyi-system/src/main/java/com/ruoyi/system/domain/flash/FlashDeliveryOrder.java

@@ -75,7 +75,7 @@ public class FlashDeliveryOrder {
     private String distanceSource;
     private Integer estimatedDurationSeconds;
 
-    /** 下单时的金额和计价配置快照,后续后台调价不会修改这些字段。 */
+    /** 最近一次定价(下单或待接单改址)的金额与计价配置快照;快照+距离恒可复算出金额,后台调价只影响之后的定价。 */
     private Long amount;
     private String currency;
     /** 支付方式与主订单系统同域:4=现金、6=线下转账;闪送款项直达骑手,仅允许线下方式,下单时锁定。 */

+ 5 - 0
ruoyi-system/src/main/resources/mapper/flash/FlashDeliveryOrderMapper.xml

@@ -100,6 +100,11 @@
             receiver_user_id = #{order.receiverUserId},
             distance_meters = #{order.distanceMeters}, distance_source = #{order.distanceSource},
             estimated_duration_seconds = #{order.estimatedDurationSeconds},
+            pricing_id = #{order.pricingId}, pricing_version = #{order.pricingVersion},
+            pricing_start_time = #{order.pricingStartTime}, pricing_end_time = #{order.pricingEndTime},
+            starting_distance = #{order.startingDistance}, starting_fare = #{order.startingFare},
+            distance = #{order.distance}, freight = #{order.freight},
+            urgent_rate = #{order.urgentRate}, minimum_urgent_fee = #{order.minimumUrgentFee},
             distance_fee = #{order.distanceFee}, base_delivery_fee = #{order.baseDeliveryFee},
             urgent_fee = #{order.urgentFee}, amount = #{order.amount},
             update_time = #{order.updateTime}, version = version + 1