feat(commerce): B1-2 恢复购买/退款拒付回收/对账真实比对 + Apple 端口预留
为什么:风险清单 R-03 把"票据校验 + 对账打通"列为上线阻塞项。勘察发现 ReconcileService 与 /admin/reconcile 两个接口 B1 之前就已实现,真缺口是:对账没跟商店比对、差额用 0 兜底(违反 "取不到就用 null"的契约)、退款回收只有人工入口且不幂等。按实际缺口做,不重复造。 - 恢复购买:补专项测试(换设备重提同一票据 → 同一订单、原交付时间不改写、不新增流水); 补单能力沿用 B1-1 的服务端建单路径,恢复列表沿用 GET /app/orders,不新增接口 - 退款/拒付回收:GooglePlayPurchaseClient 增加 listVoidedPurchases(purchases.voidedpurchases, 带分页);新增 StoreRefundService 拉取并按 (platform, orderId) 幂等回收,本地无单计入差异; OrderService 增加 refundByStoreCallback(已退款直接返回,不二次回收/不写第二条流水), 人工 refund() 的既有契约(已退款报错)保持不变 - 对账:reconcile_task 增 store_amount_sum(可空)与 notes 两列(幂等 ALTER); run() 改为集合比对(本地缺票据 + 票据无本地单 + 商店已作废但本地无单),并在同一次 run 里 顺带执行退款回收;storeAmountSum 恒为 null 并在 notes 说明需从 Play Console 财务报告获取; 商店调用失败置 status=FAILED 且不写 SUCCESS+0 - Apple IAP:只留端口/枚举与明确提示,不实现真调用(B2 再实现) - 契约同步 docs/api-phase1.md §1.8/§2.6;新增测试 17 条(commerce 14 + admin-api 3) - 实测:mvn test 71 条全过(commerce 27 + admin-api 3 + app-api 41,B1-1 的 54 条未被打红); 两个入口 package 通过;端到端手动对账返回 storeAmountSum=null + notes 说明缺什么
This commit is contained in:
1 parent
db897d50d6
commit
1dc97b4bf6
17 files changed
+971
-21
No files matched your search
+10
@@ -3,8 +3,12 @@ package com.fruitshorts.app.support;
|
||||
|
||||
import com.fruitshorts.framework.log.AccessDeniedRecorder;
|
||||
import com.fruitshorts.framework.web.GlobalExceptionHandler;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
import com.fasterxml.jackson.databind.json.JsonMapper;
|
||||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
|
||||
@@ -28,6 +32,12 @@ public final class ControllerContractSupport {
|
||||
AccessDeniedRecorder recorder = new AccessDeniedRecorder(Mockito.mock(ObjectProvider.class));
|
||||
return MockMvcBuilders.standaloneSetup(controller)
|
||||
.setControllerAdvice(new GlobalExceptionHandler(recorder))
|
||||
// 与 Spring Boot 的 Jackson 配置对齐:时间按 ISO 字符串输出而不是数组,
|
||||
// 否则契约测试断言 LocalDate/LocalDateTime 时会看到 [2026,10,15] 这种形态。
|
||||
.setMessageConverters(new MappingJackson2HttpMessageConverter(JsonMapper.builder()
|
||||
.addModule(new JavaTimeModule())
|
||||
.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
|
||||
.build()))
|
||||
.build();
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user