Files
saasshop/tests/Feature/AdminPlatformOrderTest.php

460 lines
16 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
namespace Tests\Feature;
use App\Models\Merchant;
use App\Models\Plan;
use App\Models\PlatformOrder;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class AdminPlatformOrderTest extends TestCase
{
use RefreshDatabase;
protected function loginAsPlatformAdmin(): void
{
$this->seed();
$this->post('/admin/login', [
'email' => 'platform.admin@demo.local',
'password' => 'Platform@123456',
])->assertRedirect('/admin');
}
public function test_platform_admin_can_open_platform_orders_page(): void
{
$this->loginAsPlatformAdmin();
$this->get('/admin/platform-orders')
->assertOk()
->assertSee('平台订单')
->assertSee('筛选条件')
->assertSee('平台订单列表')
->assertSee('失败原因')
->assertSee('最近批量同步')
->assertSee('最近24小时批量同步过')
->assertSee('可同步订单')
->assertSee('近24小时批量同步')
->assertSee('快捷筛选')
->assertSee('待支付')
->assertSee('待生效')
->assertSee('可同步订阅');
}
public function test_guest_cannot_open_platform_orders_page(): void
{
$this->get('/admin/platform-orders')
->assertRedirect('/admin/login');
}
public function test_platform_orders_page_can_filter_by_status_and_payment_status(): void
{
$this->loginAsPlatformAdmin();
$merchant = Merchant::query()->firstOrFail();
$plan = Plan::query()->create([
'code' => 'pro_monthly_test',
'name' => '专业版(月付)',
'billing_cycle' => 'monthly',
'price' => 199,
'list_price' => 199,
'status' => 'active',
'sort' => 10,
'published_at' => now(),
]);
PlatformOrder::query()->create([
'merchant_id' => $merchant->id,
'plan_id' => $plan->id,
'order_no' => 'PO202603100101',
'order_type' => 'new_purchase',
'status' => 'activated',
'payment_status' => 'paid',
'plan_name' => '专业版(月付)',
'billing_cycle' => 'monthly',
'period_months' => 1,
'quantity' => 1,
'list_amount' => 199,
'discount_amount' => 0,
'payable_amount' => 199,
'paid_amount' => 199,
'placed_at' => now()->subHour(),
'paid_at' => now()->subMinutes(30),
'activated_at' => now()->subMinutes(20),
]);
PlatformOrder::query()->create([
'merchant_id' => $merchant->id,
'plan_id' => $plan->id,
'order_no' => 'PO202603100102',
'order_type' => 'renewal',
'status' => 'pending',
'payment_status' => 'unpaid',
'plan_name' => '专业版(月付)',
'billing_cycle' => 'monthly',
'period_months' => 1,
'quantity' => 1,
'list_amount' => 199,
'discount_amount' => 0,
'payable_amount' => 199,
'paid_amount' => 0,
'placed_at' => now()->subMinutes(10),
]);
$this->get('/admin/platform-orders?status=activated&payment_status=paid')
->assertOk()
->assertSee('PO202603100101')
->assertDontSee('PO202603100102')
->assertSee('专业版(月付)');
// 只看同步失败:构造一条带有 subscription_activation_error 的订单
PlatformOrder::query()->where('order_no', 'PO202603100102')->update([
'meta' => [
'subscription_activation_error' => [
'message' => '模拟失败',
'at' => now()->toDateTimeString(),
'admin_id' => 1,
],
],
]);
// 额外构造一条同原因失败,用于失败原因聚合统计
PlatformOrder::query()->create([
'merchant_id' => $merchant->id,
'plan_id' => $plan->id,
'order_no' => 'PO202603100104',
'order_type' => 'renewal',
'status' => 'pending',
'payment_status' => 'unpaid',
'plan_name' => '专业版(月付)',
'billing_cycle' => 'monthly',
'period_months' => 1,
'quantity' => 1,
'payable_amount' => 199,
'paid_amount' => 0,
'placed_at' => now()->subMinutes(9),
'meta' => [
'subscription_activation_error' => [
'message' => '模拟失败',
'at' => now()->toDateTimeString(),
'admin_id' => 1,
],
],
]);
// 再构造一条不同原因失败
PlatformOrder::query()->create([
'merchant_id' => $merchant->id,
'plan_id' => $plan->id,
'order_no' => 'PO202603100105',
'order_type' => 'renewal',
'status' => 'pending',
'payment_status' => 'unpaid',
'plan_name' => '专业版(月付)',
'billing_cycle' => 'monthly',
'period_months' => 1,
'quantity' => 1,
'payable_amount' => 199,
'paid_amount' => 0,
'placed_at' => now()->subMinutes(8),
'meta' => [
'subscription_activation_error' => [
'message' => '余额不足',
'at' => now()->toDateTimeString(),
'admin_id' => 1,
],
],
]);
$this->get('/admin/platform-orders?fail_only=1')
->assertOk()
->assertSee('PO202603100102')
->assertDontSee('PO202603100101');
// 失败原因聚合Top5应可见
$this->get('/admin/platform-orders')
->assertOk()
->assertSee('同步失败原因 TOP5')
->assertSee('模拟失败')
->assertSee('余额不足');
// 订阅号列应可点击进入订阅详情(提升治理联动效率)
$sub = \App\Models\SiteSubscription::query()->create([
'merchant_id' => $merchant->id,
'plan_id' => $plan->id,
'status' => 'activated',
'source' => 'manual',
'subscription_no' => 'SUB_LINK_0001',
'plan_name' => $plan->name,
'billing_cycle' => $plan->billing_cycle,
'period_months' => 1,
'amount' => 10,
'starts_at' => now()->subDay(),
'ends_at' => now()->addMonth(),
'activated_at' => now()->subDay(),
]);
PlatformOrder::query()->create([
'merchant_id' => $merchant->id,
'plan_id' => $plan->id,
'site_subscription_id' => $sub->id,
'order_no' => 'PO_SUB_LINK_0001',
'order_type' => 'renewal',
'status' => 'activated',
'payment_status' => 'paid',
'plan_name' => '专业版(月付)',
'billing_cycle' => 'monthly',
'period_months' => 1,
'quantity' => 1,
'payable_amount' => 199,
'paid_amount' => 199,
'placed_at' => now()->subMinutes(2),
'paid_at' => now()->subMinutes(1),
'activated_at' => now(),
]);
$this->get('/admin/platform-orders?keyword=PO_SUB_LINK_0001')
->assertOk()
->assertSee('SUB_LINK_0001')
->assertSee('/admin/site-subscriptions/' . $sub->id)
->assertSee('订阅ID')
->assertSee('/admin/platform-orders?site_subscription_id=' . $sub->id);
// 只看已同步:构造一条带有 subscription_activation 的订单 + 批量同步审计(用于列表展示)
PlatformOrder::query()->where('order_no', 'PO202603100101')->update([
'meta' => [
'subscription_activation' => [
'subscription_id' => 123,
'synced_at' => now()->toDateTimeString(),
'admin_id' => 1,
],
'audit' => [
[
'action' => 'batch_activate_subscription',
'scope' => 'filtered',
'at' => '2026-03-10 00:00:00',
'admin_id' => 1,
],
],
],
]);
$this->get('/admin/platform-orders')
->assertOk()
->assertSee('2026-03-10 00:00:00')
->assertSee('管理员1');
// 最近24小时批量同步筛选构造一条近24h一条超过24h
PlatformOrder::query()->create([
'merchant_id' => $merchant->id,
'plan_id' => $plan->id,
'order_no' => 'PO202603100107',
'order_type' => 'renewal',
'status' => 'activated',
'payment_status' => 'paid',
'plan_name' => '专业版(月付)',
'billing_cycle' => 'monthly',
'period_months' => 1,
'quantity' => 1,
'payable_amount' => 199,
'paid_amount' => 199,
'placed_at' => now()->subMinutes(3),
'paid_at' => now()->subMinutes(2),
'activated_at' => now()->subMinutes(1),
'meta' => [
'batch_activation' => [
'at' => now()->subHours(1)->format('Y-m-d H:i:s'),
'admin_id' => 1,
'scope' => 'filtered',
],
],
]);
PlatformOrder::query()->create([
'merchant_id' => $merchant->id,
'plan_id' => $plan->id,
'order_no' => 'PO202603100108',
'order_type' => 'renewal',
'status' => 'activated',
'payment_status' => 'paid',
'plan_name' => '专业版(月付)',
'billing_cycle' => 'monthly',
'period_months' => 1,
'quantity' => 1,
'payable_amount' => 199,
'paid_amount' => 199,
'placed_at' => now()->subMinutes(13),
'paid_at' => now()->subMinutes(12),
'activated_at' => now()->subMinutes(11),
'meta' => [
'batch_activation' => [
'at' => now()->subHours(30)->format('Y-m-d H:i:s'),
'admin_id' => 1,
'scope' => 'filtered',
],
],
]);
$this->get('/admin/platform-orders?batch_synced_24h=1')
->assertOk()
->assertSee('PO202603100107')
->assertDontSee('PO202603100108');
$this->get('/admin/platform-orders?synced_only=1')
->assertOk()
->assertSee('PO202603100101')
->assertDontSee('PO202603100102');
// sync_status 下拉筛选synced / failed / unsynced
$this->get('/admin/platform-orders?sync_status=synced')
->assertOk()
->assertSee('PO202603100101')
->assertDontSee('PO202603100102');
$this->get('/admin/platform-orders?sync_status=failed')
->assertOk()
->assertSee('PO202603100102')
->assertDontSee('PO202603100101');
// unsynced构造一条既无 subscription_activation 也无 error 的订单
PlatformOrder::query()->create([
'merchant_id' => $merchant->id,
'plan_id' => $plan->id,
'order_no' => 'PO202603100103',
'order_type' => 'renewal',
'status' => 'pending',
'payment_status' => 'unpaid',
'plan_name' => '专业版(月付)',
'billing_cycle' => 'monthly',
'period_months' => 1,
'quantity' => 1,
'payable_amount' => 199,
'paid_amount' => 0,
'placed_at' => now()->subMinutes(5),
]);
$this->get('/admin/platform-orders?sync_status=unsynced')
->assertOk()
->assertSee('PO202603100103')
->assertDontSee('PO202603100101')
->assertDontSee('PO202603100102');
// 只看可同步:已支付 + 已生效 + 未同步
PlatformOrder::query()->create([
'merchant_id' => $merchant->id,
'plan_id' => $plan->id,
'order_no' => 'PO202603100106',
'order_type' => 'renewal',
'status' => 'activated',
'payment_status' => 'paid',
'plan_name' => '专业版(月付)',
'billing_cycle' => 'monthly',
'period_months' => 1,
'quantity' => 1,
'payable_amount' => 199,
'paid_amount' => 199,
'placed_at' => now()->subMinutes(4),
'paid_at' => now()->subMinutes(3),
'activated_at' => now()->subMinutes(2),
]);
$this->get('/admin/platform-orders?syncable_only=1')
->assertOk()
->assertSee('PO202603100106')
->assertDontSee('PO202603100101')
->assertDontSee('PO202603100102');
}
public function test_platform_orders_page_can_filter_by_site_subscription_id(): void
{
$this->loginAsPlatformAdmin();
$merchant = \App\Models\Merchant::query()->firstOrFail();
$plan = \App\Models\Plan::query()->create([
'code' => 'po_subid_test',
'name' => '订阅ID筛选测试套餐',
'billing_cycle' => 'monthly',
'price' => 10,
'list_price' => 10,
'status' => 'active',
'sort' => 10,
'published_at' => now(),
]);
$sub1 = \App\Models\SiteSubscription::query()->create([
'merchant_id' => $merchant->id,
'plan_id' => $plan->id,
'status' => 'activated',
'source' => 'manual',
'subscription_no' => 'SUB_FILTER_0001',
'plan_name' => $plan->name,
'billing_cycle' => 'monthly',
'period_months' => 1,
'amount' => 10,
'starts_at' => now()->subDay(),
'ends_at' => now()->addMonth(),
'activated_at' => now()->subDay(),
]);
$sub2 = \App\Models\SiteSubscription::query()->create([
'merchant_id' => $merchant->id,
'plan_id' => $plan->id,
'status' => 'activated',
'source' => 'manual',
'subscription_no' => 'SUB_FILTER_0002',
'plan_name' => $plan->name,
'billing_cycle' => 'monthly',
'period_months' => 1,
'amount' => 10,
'starts_at' => now()->subDay(),
'ends_at' => now()->addMonth(),
'activated_at' => now()->subDay(),
]);
\App\Models\PlatformOrder::query()->create([
'merchant_id' => $merchant->id,
'plan_id' => $plan->id,
'site_subscription_id' => $sub1->id,
'order_no' => 'PO_SUBID_0001',
'order_type' => 'renewal',
'status' => 'activated',
'payment_status' => 'paid',
'plan_name' => $plan->name,
'billing_cycle' => 'monthly',
'period_months' => 1,
'quantity' => 1,
'payable_amount' => 10,
'paid_amount' => 10,
'placed_at' => now()->subMinutes(2),
'paid_at' => now()->subMinute(),
'activated_at' => now(),
]);
\App\Models\PlatformOrder::query()->create([
'merchant_id' => $merchant->id,
'plan_id' => $plan->id,
'site_subscription_id' => $sub2->id,
'order_no' => 'PO_SUBID_0002',
'order_type' => 'renewal',
'status' => 'activated',
'payment_status' => 'paid',
'plan_name' => $plan->name,
'billing_cycle' => 'monthly',
'period_months' => 1,
'quantity' => 1,
'payable_amount' => 10,
'paid_amount' => 10,
'placed_at' => now()->subMinutes(2),
'paid_at' => now()->subMinute(),
'activated_at' => now(),
]);
$this->get('/admin/platform-orders?site_subscription_id=' . $sub1->id)
->assertOk()
->assertSee('PO_SUBID_0001')
->assertDontSee('PO_SUBID_0002');
}
}