From 9dc281f48ea3ebbf255057a1f8fdd8db52eee7c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=90=9D=E5=8D=9C?= Date: Mon, 16 Mar 2026 23:26:29 +0800 Subject: [PATCH] chore(governance): block batch mark activated when receipt none/refund has --- .../Admin/PlatformOrderController.php | 10 +++++ app/Support/PlatformOrderToolsGuard.php | 6 +++ ...kActivatedRefundStatusFilterFieldsTest.php | 8 +++- ...edShouldBlockWhenReceiptStatusNoneTest.php | 38 +++++++++++++++++++ ...atedShouldBlockWhenRefundStatusHasTest.php | 38 +++++++++++++++++++ ...ShouldDisableWhenReceiptStatusNoneTest.php | 37 ++++++++++++++++++ ...onShouldDisableWhenRefundStatusHasTest.php | 37 ++++++++++++++++++ 7 files changed, 172 insertions(+), 2 deletions(-) create mode 100644 tests/Feature/AdminPlatformOrderBatchMarkActivatedShouldBlockWhenReceiptStatusNoneTest.php create mode 100644 tests/Feature/AdminPlatformOrderBatchMarkActivatedShouldBlockWhenRefundStatusHasTest.php create mode 100644 tests/Feature/AdminPlatformOrderIndexBatchMarkActivatedButtonShouldDisableWhenReceiptStatusNoneTest.php create mode 100644 tests/Feature/AdminPlatformOrderIndexBatchMarkActivatedButtonShouldDisableWhenRefundStatusHasTest.php diff --git a/app/Http/Controllers/Admin/PlatformOrderController.php b/app/Http/Controllers/Admin/PlatformOrderController.php index 402beb7..18a377a 100644 --- a/app/Http/Controllers/Admin/PlatformOrderController.php +++ b/app/Http/Controllers/Admin/PlatformOrderController.php @@ -1885,6 +1885,16 @@ class PlatformOrderController extends Controller return redirect()->back()->with('warning', '当前已勾选「只看可同步」:该集合语义为“已生效(activated)+未同步”,与本动作处理的“待处理(pending)”互斥。请先取消只看可同步后再执行。'); } + // 治理优先:当用户显式筛选「无回执」时,不允许直接批量生效 + if ((string) ($filters['receipt_status'] ?? '') === 'none') { + return redirect()->back()->with('warning', '当前筛选为「无回执」订单集合。为保证收费闭环可治理,请先补齐支付回执留痕后再执行批量仅标记为已生效。'); + } + + // 治理优先:当用户显式筛选「有退款」时,不允许直接批量生效 + if ((string) ($filters['refund_status'] ?? '') === 'has') { + return redirect()->back()->with('warning', '当前筛选为「有退款」订单集合。为避免带退款订单直接批量生效,请先完成退款治理(核对退款回执/修正状态)后再执行。'); + } + // 治理优先:当筛选集合命中“对账不一致/退款不一致”时,不允许直接批量生效 if ((string) ($filters['reconcile_mismatch'] ?? '') === '1' || (string) ($filters['refund_inconsistent'] ?? '') === '1') { return redirect()->back()->with('warning', '当前筛选集合包含「对账不一致/退款不一致」订单,为避免带病推进,请先完成金额/状态治理(补回执/核对退款/修正状态)后再执行批量仅标记为已生效。'); diff --git a/app/Support/PlatformOrderToolsGuard.php b/app/Support/PlatformOrderToolsGuard.php index f64c346..1f9f71d 100644 --- a/app/Support/PlatformOrderToolsGuard.php +++ b/app/Support/PlatformOrderToolsGuard.php @@ -132,6 +132,12 @@ class PlatformOrderToolsGuard if ((string) ($filters['syncable_only'] ?? '') === '1') { return '当前已勾选「只看可同步」:该集合语义为“已生效(activated)+未同步”,与本动作处理的“待处理(pending)”互斥。请先取消只看可同步后再执行。'; } + if ((string) ($filters['receipt_status'] ?? '') === 'none') { + return '当前集合为「无回执」:为保证收费闭环可治理,建议先补齐支付回执留痕后再批量生效。'; + } + if ((string) ($filters['refund_status'] ?? '') === 'has') { + return '当前集合为「有退款」:为避免带退款订单直接批量生效,请先完成退款治理(核对退款回执/修正状态)后再执行。'; + } if (((string) ($filters['reconcile_mismatch'] ?? '') === '1') || ((string) ($filters['refund_inconsistent'] ?? '') === '1')) { return '当前集合包含「对账不一致/退款不一致」治理集合:建议先完成金额/状态治理(补回执/核对退款/修正状态)后再批量生效。'; } diff --git a/tests/Feature/AdminPlatformOrderBatchMarkActivatedRefundStatusFilterFieldsTest.php b/tests/Feature/AdminPlatformOrderBatchMarkActivatedRefundStatusFilterFieldsTest.php index 42553fc..69c836d 100644 --- a/tests/Feature/AdminPlatformOrderBatchMarkActivatedRefundStatusFilterFieldsTest.php +++ b/tests/Feature/AdminPlatformOrderBatchMarkActivatedRefundStatusFilterFieldsTest.php @@ -86,17 +86,21 @@ class AdminPlatformOrderBatchMarkActivatedRefundStatusFilterFieldsTest extends T $page->assertSee('name="refund_status"', false); $page->assertSee('value="none"', false); - $this->post('/admin/platform-orders/batch-mark-activated', [ + $res = $this->post('/admin/platform-orders/batch-mark-activated', [ 'scope' => 'filtered', 'payment_status' => 'paid', 'status' => 'pending', + 'sync_status' => 'unsynced', 'refund_status' => 'none', 'limit' => 50, - ])->assertRedirect(); + ]); + + $res->assertRedirect(); $a->refresh(); $b->refresh(); + // 口径升级:只允许在“无退款”集合上推进;因此 A 会被推进、B 保持 pending。 $this->assertSame('activated', $a->status); $this->assertSame('pending', $b->status); } diff --git a/tests/Feature/AdminPlatformOrderBatchMarkActivatedShouldBlockWhenReceiptStatusNoneTest.php b/tests/Feature/AdminPlatformOrderBatchMarkActivatedShouldBlockWhenReceiptStatusNoneTest.php new file mode 100644 index 0000000..62801df --- /dev/null +++ b/tests/Feature/AdminPlatformOrderBatchMarkActivatedShouldBlockWhenReceiptStatusNoneTest.php @@ -0,0 +1,38 @@ +seed(); + + $this->post('/admin/login', [ + 'email' => 'platform.admin@demo.local', + 'password' => 'Platform@123456', + ])->assertRedirect('/admin'); + } + + public function test_batch_mark_activated_should_block_when_receipt_status_none_is_set(): void + { + $this->loginAsPlatformAdmin(); + + $res = $this->post('/admin/platform-orders/batch-mark-activated', [ + 'scope' => 'filtered', + 'payment_status' => 'paid', + 'status' => 'pending', + 'sync_status' => 'unsynced', + 'receipt_status' => 'none', + 'limit' => 50, + ]); + + $res->assertRedirect(); + $res->assertSessionHas('warning'); + } +} diff --git a/tests/Feature/AdminPlatformOrderBatchMarkActivatedShouldBlockWhenRefundStatusHasTest.php b/tests/Feature/AdminPlatformOrderBatchMarkActivatedShouldBlockWhenRefundStatusHasTest.php new file mode 100644 index 0000000..815eb1d --- /dev/null +++ b/tests/Feature/AdminPlatformOrderBatchMarkActivatedShouldBlockWhenRefundStatusHasTest.php @@ -0,0 +1,38 @@ +seed(); + + $this->post('/admin/login', [ + 'email' => 'platform.admin@demo.local', + 'password' => 'Platform@123456', + ])->assertRedirect('/admin'); + } + + public function test_batch_mark_activated_should_block_when_refund_status_has_is_set(): void + { + $this->loginAsPlatformAdmin(); + + $res = $this->post('/admin/platform-orders/batch-mark-activated', [ + 'scope' => 'filtered', + 'payment_status' => 'paid', + 'status' => 'pending', + 'sync_status' => 'unsynced', + 'refund_status' => 'has', + 'limit' => 50, + ]); + + $res->assertRedirect(); + $res->assertSessionHas('warning'); + } +} diff --git a/tests/Feature/AdminPlatformOrderIndexBatchMarkActivatedButtonShouldDisableWhenReceiptStatusNoneTest.php b/tests/Feature/AdminPlatformOrderIndexBatchMarkActivatedButtonShouldDisableWhenReceiptStatusNoneTest.php new file mode 100644 index 0000000..a9cafa8 --- /dev/null +++ b/tests/Feature/AdminPlatformOrderIndexBatchMarkActivatedButtonShouldDisableWhenReceiptStatusNoneTest.php @@ -0,0 +1,37 @@ +seed(); + + $this->post('/admin/login', [ + 'email' => 'platform.admin@demo.local', + 'password' => 'Platform@123456', + ])->assertRedirect('/admin'); + } + + public function test_batch_mark_activated_button_should_disable_when_receipt_status_none_even_if_paid_pending(): void + { + $this->loginAsPlatformAdmin(); + + $res = $this->get('/admin/platform-orders?payment_status=paid&status=pending&sync_status=unsynced&receipt_status=none'); + $res->assertOk(); + + $html = (string) $res->getContent(); + + $this->assertStringContainsString('批量仅标记为已生效(当前筛选范围)', $html); + $this->assertStringContainsString('data-role="batch-mark-activated-blocked-hint"', $html); + $this->assertStringContainsString('无回执', $html); + + $this->assertTrue(str_contains($html, 'type="submit" disabled') || str_contains($html, 'disabled="disabled"')); + } +} diff --git a/tests/Feature/AdminPlatformOrderIndexBatchMarkActivatedButtonShouldDisableWhenRefundStatusHasTest.php b/tests/Feature/AdminPlatformOrderIndexBatchMarkActivatedButtonShouldDisableWhenRefundStatusHasTest.php new file mode 100644 index 0000000..55ac60f --- /dev/null +++ b/tests/Feature/AdminPlatformOrderIndexBatchMarkActivatedButtonShouldDisableWhenRefundStatusHasTest.php @@ -0,0 +1,37 @@ +seed(); + + $this->post('/admin/login', [ + 'email' => 'platform.admin@demo.local', + 'password' => 'Platform@123456', + ])->assertRedirect('/admin'); + } + + public function test_batch_mark_activated_button_should_disable_when_refund_status_has_even_if_paid_pending(): void + { + $this->loginAsPlatformAdmin(); + + $res = $this->get('/admin/platform-orders?payment_status=paid&status=pending&sync_status=unsynced&refund_status=has'); + $res->assertOk(); + + $html = (string) $res->getContent(); + + $this->assertStringContainsString('批量仅标记为已生效(当前筛选范围)', $html); + $this->assertStringContainsString('data-role="batch-mark-activated-blocked-hint"', $html); + $this->assertStringContainsString('有退款', $html); + + $this->assertTrue(str_contains($html, 'type="submit" disabled') || str_contains($html, 'disabled="disabled"')); + } +}