Compare commits

...
Author SHA1 Message Date
QiuSW 9eb28c225c fix(android): reconcile folded order details (#192) 2026-09-01 17:07:51 +08:00
2 changed files with 56 additions and 14 deletions
@@ -162,24 +162,28 @@ class PurchaseLiveAutomation(
return unknown("PURCHASE_ORDER_UNEXPECTED_APP", "核单期间出现未授权应用")
}
if (restoredFromWechat) pddObservedAfterWechatRestore = true
val paymentVisible = isKnownPddPaymentActivity(snapshot) ||
currentLabels.any { label -> PAYMENT_MARKERS.any(label::contains) }
val paymentVisible = isKnownPddPaymentActivity(snapshot)
val orderContextVisible = currentLabels.any { label -> ORDER_CONTEXT_MARKERS.any(label::contains) }
if (!paymentVisible && !orderContextVisible) {
val unpaidContextVisible = currentLabels.any { label -> UNPAID_MARKERS.any(label::contains) }
if (paymentVisible) {
if (!backedOutOfPayment) {
backedOutOfPayment = true
if (!driver.backPurchase()) {
return unknown("PURCHASE_ORDER_PAYMENT_BACK_FAILED", "支付页无法安全返回订单详情")
}
pause(500)
} else {
return unknown("PURCHASE_ORDER_PAYMENT_REPEATED", "支付页重复出现,已停止自动核单")
}
return@repeat
}
if (!orderContextVisible && !unpaidContextVisible) {
pause(ORDER_RESULT_SAMPLE_INTERVAL_MS)
return@repeat
}
currentLabels.forEach(labels::add)
parseOrderEvidence(labels)?.let { return it }
if (paymentVisible && !backedOutOfPayment) {
backedOutOfPayment = true
if (!driver.backPurchase()) {
return unknown("PURCHASE_ORDER_PAYMENT_BACK_FAILED", "支付页无法安全返回订单详情")
}
pause(500)
} else if (paymentVisible) {
return unknown("PURCHASE_ORDER_PAYMENT_REPEATED", "支付页重复出现,已停止自动核单")
} else if (index > 0 && index % 15 == 0) {
if (index > 0 && index % ORDER_RESULT_SCROLL_SAMPLE_INTERVAL == 0) {
driver.swipePurchase(SwipeDirection.UP, 400)
}
pause(ORDER_RESULT_SAMPLE_INTERVAL_MS)
@@ -435,6 +439,7 @@ class PurchaseLiveAutomation(
const val ORDER_RESULT_MAX_SAMPLES = 60
const val ORDER_RESULT_MAX_EMPTY_SAMPLES = 15
const val ORDER_RESULT_WECHAT_RESTORE_MAX_SAMPLES = 15
const val ORDER_RESULT_SCROLL_SAMPLE_INTERVAL = 15
const val ORDER_RESULT_SAMPLE_INTERVAL_MS = 200L
}
}
@@ -120,6 +120,37 @@ class PurchaseLiveAutomationTest {
assertFalse(driver.clicked.any { it.startsWith("微信") || it.contains("支付") })
}
@Test
fun `payment page returns to folded unpaid order detail and scrolls to read evidence`() {
val driver = LiveDriver(chooserAfterSubmit = true, orderEvidenceBelowFold = true)
val automation = PurchaseLiveAutomation(driver, pause = {})
val address = automation.updateShippingAddress("_cg54")
automation.finalConfirmation(input().copy(addressSuffix = "_cg54"), address)
automation.submitOrderOnce()
val order = automation.readOrderResult()
assertEquals("PDD-202608210001", order?.orderNo)
assertEquals(2, driver.postSubmitBackCount)
assertEquals(1, driver.genericSwipes)
assertFalse(driver.clicked.any { it.contains("支付") })
}
@Test
fun `repeated known payment activity still stops without scrolling or payment clicks`() {
val driver = LiveDriver(postSubmitCaptureSequence = listOf("payment", "payment"))
val automation = PurchaseLiveAutomation(driver, pause = {})
val address = automation.updateShippingAddress("_cg55")
automation.finalConfirmation(input().copy(addressSuffix = "_cg55"), address)
automation.submitOrderOnce()
assertEquals(null, automation.readOrderResult())
assertEquals("PURCHASE_ORDER_PAYMENT_REPEATED", automation.lastOrderReadFailure?.code)
assertEquals(1, driver.postSubmitBackCount)
assertEquals(0, driver.genericSwipes)
assertFalse(driver.clicked.any { it.contains("支付") })
}
@Test
fun `WeChat login is not touched and PDD is restored once before reading order detail`() {
val driver = LiveDriver(wechatLoginAfterSubmit = true)
@@ -310,6 +341,7 @@ class PurchaseLiveAutomationTest {
private val savedTransitionHidesSuffix: Boolean = false,
private val wechatLoginAfterSubmit: Boolean = false,
private val wechatRestoreStuck: Boolean = false,
private val orderEvidenceBelowFold: Boolean = false,
postSubmitCaptureSequence: List<String> = emptyList(),
) : PurchaseUiDriver {
private var page = "confirmation"
@@ -359,6 +391,7 @@ class PurchaseLiveAutomationTest {
node("address-summary", if (savedTransitionHidesSuffix) "已保存的收货信息" else address.substring(address.lastIndexOf("_cg"))),
))
"order" -> snapshot(listOf(node("status", "待付款"), node("order", "订单号:PDD-202608210001"), node("time", "下单时间:2026-08-21 10:30:00"), node("pay", "立即支付", clickable = true)))
"order-folded" -> snapshot(listOf(node("status", "待付款"), node("pay", "立即支付", clickable = true)))
"order-no-time" -> snapshot(listOf(node("status", "待付款"), node("order", "订单号:PDD-202608210001"), node("pay", "去支付", clickable = true)))
"chooser" -> UiSnapshot(if (trustedChooser) "android" else "example.untrusted", "com.android.internal.app.ChooserActivity", listOf(
node("chooser-title", "选择要使用的应用"), node("wechat-1", "微信"), node("wechat-2", "微信分身"),
@@ -428,7 +461,11 @@ class PurchaseLiveAutomationTest {
address = value
return FreshActionResult.SUCCESS
}
override fun swipePurchase(direction: SwipeDirection, durationMs: Long): Boolean { genericSwipes++; return true }
override fun swipePurchase(direction: SwipeDirection, durationMs: Long): Boolean {
genericSwipes++
if (page == "order-folded" && direction == SwipeDirection.UP) page = "order"
return true
}
override fun swipePurchaseIn(target: SnapshotNode, direction: SwipeDirection, durationMs: Long): Boolean {
scopedSwipes++
if (target.path == "panel" && direction == SwipeDirection.DOWN) addressVisible = true
@@ -439,7 +476,7 @@ class PurchaseLiveAutomationTest {
if (page == "chooser" || page == "payment") postSubmitBackCount++
page = when (page) {
"chooser" -> "payment"
"payment" -> "order"
"payment" -> if (orderEvidenceBelowFold) "order-folded" else "order"
else -> "confirmation"
}
return true