浏览代码

feat(订单实时): lsy 订单状态两个收口点发布信号(构造器 5→6 参,波及 5 个测试类)

发布点只有两处,都是「行真的改了」之后:
- applyPayResult 的 rows==1 尾(建单尾/回调/轮询确认/关单拒绝/对账 9 个调用点全覆盖)
- applyRefundResult 的 rows==1 内(refunded_amount 与状态唯一收口)

守卫没命中的分支一行都没改,不发 —— 发了就是让三页白拉一次。
测试:LsyOrderServiceStateTest 加 4 例(两个 emit + 两个 verifyNoInteractions);
另外 4 个测试类只改构造点(@Mock + 实参尾追加 publisher),顺带订正它们
「构造器签名与 Task 5 一致(5 参),不要改」这句已失效的注释。
alphaH 1 周之前
父节点
当前提交
6dc88533c3

+ 6 - 0
java/src/main/java/com/payment/platform/module/payment/leshouying/service/LsyOrderService.java

@@ -12,6 +12,7 @@ import com.payment.platform.module.payment.leshouying.enums.LsyOrderStatus;
 import com.payment.platform.module.payment.leshouying.enums.LsyPayType;
 import com.payment.platform.module.payment.leshouying.mapper.LsyOrderMapper;
 import com.payment.platform.module.payment.leshouying.util.LsyLogSanitizer;
+import com.payment.platform.module.payment.stream.OrderEventPublisher;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
@@ -42,6 +43,9 @@ public class LsyOrderService {
     private final LeshouyingResponseParser parser;
     private final LeshouyingProperties props;
     private final LsyQueryService queryService;
+    /** 订单信号发布(SSE):只在**真的改了行**之后发 —— 守卫没命中的分支一行都没变,
+     *  发了就是让三页白拉一次。 */
+    private final OrderEventPublisher publisher;
 
     private static final Set<String> TERMINAL = Set.of(
             "SUCCESS", "FAIL", "CANCELED", "CLOSED", "EXPIRED", "REFUNDED");
@@ -152,6 +156,7 @@ public class LsyOrderService {
             if (patch.getUpstreamResultCode() != null) {
                 order.setUpstreamResultCode(patch.getUpstreamResultCode());
             }
+            publisher.changed(OrderEventPublisher.CHANNEL_LSY_ORDER, order.getTenantId());
             return true;
         }
         log.info("支付回写未命中(重复或状态不符): orderId={}, currentStatus={}, target={}",
@@ -177,6 +182,7 @@ public class LsyOrderService {
         if (rows == 1) {
             order.setStatus(newStatus);
             order.setRefundedAmount(accumulated);
+            publisher.changed(OrderEventPublisher.CHANNEL_LSY_ORDER, order.getTenantId());
             return true;
         }
         log.info("退款回写未命中: orderId={}, currentStatus={}", order.getId(), order.getStatus());

+ 4 - 2
java/src/test/java/com/payment/platform/module/payment/leshouying/service/LsyBarcodePayTest.java

@@ -6,6 +6,7 @@ import com.payment.platform.module.payment.leshouying.config.LeshouyingPropertie
 import com.payment.platform.module.payment.leshouying.dto.LsyPayResultDTO;
 import com.payment.platform.module.payment.leshouying.entity.LsyOrderEntity;
 import com.payment.platform.module.payment.leshouying.mapper.LsyOrderMapper;
+import com.payment.platform.module.payment.stream.OrderEventPublisher;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
@@ -25,6 +26,7 @@ class LsyBarcodePayTest {
     @Mock private LeshouyingClient client;
     @Mock private LsyOrderMapper orderMapper;
     @Mock private LsyQueryService queryService;
+    @Mock private OrderEventPublisher publisher;
     private LsyOrderService orderService;
     private LeshouyingProperties props;
 
@@ -33,9 +35,9 @@ class LsyBarcodePayTest {
         props = new LeshouyingProperties();
         props.setSyncPollTimes(3);
         props.setSyncPollIntervalMs(0);   // 测试里不真的睡
-        // 构造器签名与 Task 5 一致(5 参),不要改
+        // 构造器签名固定为 6 参(2026-10-05 加 OrderEventPublisher)—— 后续新增下单方法时不要改它
         orderService = new LsyOrderService(orderMapper, client,
-                new LeshouyingResponseParser(), props, queryService);
+                new LeshouyingResponseParser(), props, queryService, publisher);
     }
 
     private LsyOrderEntity order() {

+ 4 - 2
java/src/test/java/com/payment/platform/module/payment/leshouying/service/LsyH5PayTest.java

@@ -6,6 +6,7 @@ import com.payment.platform.module.payment.leshouying.config.LeshouyingPropertie
 import com.payment.platform.module.payment.leshouying.dto.LsyPayResultDTO;
 import com.payment.platform.module.payment.leshouying.entity.LsyOrderEntity;
 import com.payment.platform.module.payment.leshouying.mapper.LsyOrderMapper;
+import com.payment.platform.module.payment.stream.OrderEventPublisher;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
@@ -25,6 +26,7 @@ class LsyH5PayTest {
     @Mock private LeshouyingClient client;
     @Mock private LsyOrderMapper orderMapper;
     @Mock private LsyQueryService queryService;
+    @Mock private OrderEventPublisher publisher;
     private LsyOrderService orderService;
     private LeshouyingProperties props;
 
@@ -33,9 +35,9 @@ class LsyH5PayTest {
         props = new LeshouyingProperties();
         props.setSyncPollTimes(3);
         props.setSyncPollIntervalMs(0);
-        // 构造器签名与 Task 5 一致(5 参)
+        // 构造器签名固定为 6 参(2026-10-05 加 OrderEventPublisher)
         orderService = new LsyOrderService(orderMapper, client,
-                new LeshouyingResponseParser(), props, queryService);
+                new LeshouyingResponseParser(), props, queryService, publisher);
     }
 
     private LsyOrderEntity order() {

+ 45 - 2
java/src/test/java/com/payment/platform/module/payment/leshouying/service/LsyOrderServiceStateTest.java

@@ -10,6 +10,7 @@ import com.payment.platform.module.payment.leshouying.client.LeshouyingResponseP
 import com.payment.platform.module.payment.leshouying.config.LeshouyingProperties;
 import com.payment.platform.module.payment.leshouying.entity.LsyOrderEntity;
 import com.payment.platform.module.payment.leshouying.mapper.LsyOrderMapper;
+import com.payment.platform.module.payment.stream.OrderEventPublisher;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
@@ -33,15 +34,16 @@ class LsyOrderServiceStateTest {
     @Mock private LsyOrderMapper orderMapper;
     @Mock private LeshouyingClient client;
     @Mock private LsyQueryService queryService;
+    @Mock private OrderEventPublisher publisher;
     private LsyOrderService service;
     private LeshouyingProperties props;
 
     @BeforeEach
     void setUp() {
         props = new LeshouyingProperties();
-        // 构造器签名固定为 5 参 —— 后续任务新增下单方法时不要改动它
+        // 构造器签名固定为 6 参(2026-10-05 加 OrderEventPublisher)—— 后续新增下单方法时不要改它
         service = new LsyOrderService(orderMapper, client,
-                new LeshouyingResponseParser(), props, queryService);
+                new LeshouyingResponseParser(), props, queryService, publisher);
     }
 
     private LsyOrderEntity order(String status) {
@@ -231,6 +233,47 @@ class LsyOrderServiceStateTest {
         assertFalse(service.isTerminal("PARTIAL_REFUNDED"));
     }
 
+    @Test
+    void applyPayResult_affectedRowIsOne_emitsLsyOrderSignal() {
+        when(orderMapper.update(any(), any(UpdateWrapper.class))).thenReturn(1);
+        LsyOrderEntity o = order("PAYING");
+        o.setTenantId(2L);
+
+        assertTrue(service.applyPayResult(o, "SUCCESS", patch("T1")));
+
+        verify(publisher).changed(OrderEventPublisher.CHANNEL_LSY_ORDER, 2L);
+    }
+
+    @Test
+    void applyPayResult_affectedRowIsZero_emitsNothing() {
+        when(orderMapper.update(any(), any(UpdateWrapper.class))).thenReturn(0);
+
+        assertFalse(service.applyPayResult(order("SUCCESS"), "SUCCESS", patch("T1")));
+
+        // 重复通知(条件更新未命中)一行都没改 —— 发了就是让三页白拉一次
+        verifyNoInteractions(publisher);
+    }
+
+    @Test
+    void applyRefundResult_settledRow_emitsLsyOrderSignal() {
+        when(orderMapper.update(any(), any(UpdateWrapper.class))).thenReturn(1);
+        LsyOrderEntity o = order("SUCCESS");
+        o.setTenantId(2L);
+
+        service.applyRefundResult(o, 100L, "REFUNDED");
+
+        verify(publisher).changed(OrderEventPublisher.CHANNEL_LSY_ORDER, 2L);
+    }
+
+    @Test
+    void applyRefundResult_zeroRows_emitsNothing() {
+        when(orderMapper.update(any(), any(UpdateWrapper.class))).thenReturn(0);
+
+        service.applyRefundResult(order("CANCELED"), 100L, "REFUNDED");
+
+        verifyNoInteractions(publisher);
+    }
+
     /** 与 LsyNotifyServiceTest 同款(本仓库按测试文件各自持有一份,不抽公共类)。 */
     private static void withLogCapture(Class<?> type, Consumer<List<ILoggingEvent>> body) {
         Logger logger = (Logger) LoggerFactory.getLogger(type);

+ 3 - 1
java/src/test/java/com/payment/platform/module/payment/leshouying/service/LsyOrderUpstreamRejectTest.java

@@ -6,6 +6,7 @@ import com.payment.platform.module.payment.leshouying.client.LeshouyingResponseP
 import com.payment.platform.module.payment.leshouying.config.LeshouyingProperties;
 import com.payment.platform.module.payment.leshouying.entity.LsyOrderEntity;
 import com.payment.platform.module.payment.leshouying.mapper.LsyOrderMapper;
+import com.payment.platform.module.payment.stream.OrderEventPublisher;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
@@ -41,6 +42,7 @@ class LsyOrderUpstreamRejectTest {
     @Mock private LeshouyingClient client;
     @Mock private LsyOrderMapper orderMapper;
     @Mock private LsyQueryService queryService;
+    @Mock private OrderEventPublisher publisher;
     private LsyOrderService orderService;
     private LeshouyingProperties props;
 
@@ -51,7 +53,7 @@ class LsyOrderUpstreamRejectTest {
         props.setSyncPollTimes(3);
         props.setSyncPollIntervalMs(0);   // 测试里不真的睡
         orderService = new LsyOrderService(orderMapper, client,
-                new LeshouyingResponseParser(), props, queryService);
+                new LeshouyingResponseParser(), props, queryService, publisher);
     }
 
     private LsyOrderEntity order(long id, String outTradeNo, String payScene) {

+ 4 - 2
java/src/test/java/com/payment/platform/module/payment/leshouying/service/LsyQrPayTest.java

@@ -10,6 +10,7 @@ import com.payment.platform.module.payment.leshouying.config.LeshouyingPropertie
 import com.payment.platform.module.payment.leshouying.dto.LsyPayResultDTO;
 import com.payment.platform.module.payment.leshouying.entity.LsyOrderEntity;
 import com.payment.platform.module.payment.leshouying.mapper.LsyOrderMapper;
+import com.payment.platform.module.payment.stream.OrderEventPublisher;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
@@ -32,6 +33,7 @@ class LsyQrPayTest {
     @Mock private LeshouyingClient client;
     @Mock private LsyOrderMapper orderMapper;
     @Mock private LsyQueryService queryService;
+    @Mock private OrderEventPublisher publisher;
     private LsyOrderService orderService;
     private LeshouyingProperties props;
 
@@ -39,9 +41,9 @@ class LsyQrPayTest {
     void setUp() {
         props = new LeshouyingProperties();
         props.setDefaultQrExpireMinutes(15);
-        // 构造器签名与 Task 5 一致(5 参)
+        // 构造器签名固定为 6 参(2026-10-05 加 OrderEventPublisher)
         orderService = new LsyOrderService(orderMapper, client,
-                new LeshouyingResponseParser(), props, queryService);
+                new LeshouyingResponseParser(), props, queryService, publisher);
     }
 
     private LsyOrderEntity order() {