Files
saasshop/tests/Feature/AdminPlatformOrderExportTest.php

216 lines
7.9 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 AdminPlatformOrderExportTest 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_export_platform_orders_csv(): void
{
$this->loginAsPlatformAdmin();
$merchant = Merchant::query()->firstOrFail();
$plan = Plan::query()->create([
'code' => 'export_order_test',
'name' => '导出测试套餐',
'billing_cycle' => 'monthly',
'price' => 10,
'list_price' => 10,
'status' => 'active',
'sort' => 10,
'published_at' => now(),
]);
PlatformOrder::query()->create([
'merchant_id' => $merchant->id,
'plan_id' => $plan->id,
'order_no' => 'PO_EXPORT_0001',
'order_type' => 'new_purchase',
'status' => 'pending',
'payment_status' => 'unpaid',
'plan_name' => $plan->name,
'billing_cycle' => $plan->billing_cycle,
'period_months' => 1,
'quantity' => 1,
'payable_amount' => 10,
'paid_amount' => 0,
'placed_at' => now(),
'meta' => [
'subscription_activation_error' => [
'message' => '模拟失败',
'at' => now()->toDateTimeString(),
'admin_id' => 1,
],
],
]);
// batch_synced_24h 筛选导出:构造一条 24h 内、一条超 24h 的订单
PlatformOrder::query()->create([
'merchant_id' => $merchant->id,
'plan_id' => $plan->id,
'order_no' => 'PO_EXPORT_BATCH_RECENT',
'order_type' => 'renewal',
'status' => 'activated',
'payment_status' => 'paid',
'plan_name' => $plan->name,
'billing_cycle' => $plan->billing_cycle,
'period_months' => 1,
'quantity' => 1,
'payable_amount' => 10,
'paid_amount' => 10,
'placed_at' => now(),
'paid_at' => now(),
'activated_at' => now(),
'meta' => [
'batch_activation' => [
'at' => now()->toDateTimeString(),
'admin_id' => 1,
'scope' => 'filtered',
],
],
]);
PlatformOrder::query()->create([
'merchant_id' => $merchant->id,
'plan_id' => $plan->id,
'order_no' => 'PO_EXPORT_BATCH_OLD',
'order_type' => 'renewal',
'status' => 'activated',
'payment_status' => 'paid',
'plan_name' => $plan->name,
'billing_cycle' => $plan->billing_cycle,
'period_months' => 1,
'quantity' => 1,
'payable_amount' => 10,
'paid_amount' => 10,
'placed_at' => now()->subHours(30),
'paid_at' => now()->subHours(30),
'activated_at' => now()->subHours(30),
'meta' => [
'batch_activation' => [
'at' => now()->subHours(30)->toDateTimeString(),
'admin_id' => 1,
'scope' => 'filtered',
],
],
]);
$res = $this->get('/admin/platform-orders/export');
$res->assertOk();
$res->assertHeader('content-type', 'text/csv; charset=UTF-8');
// StreamedResponse 在测试环境下需用 streamedContent() 获取内容
$content = $res->streamedContent();
$this->assertStringContainsString('订单号', $content);
$this->assertStringContainsString('PO_EXPORT_0001', $content);
$this->assertStringContainsString('同步失败原因', $content);
$this->assertStringContainsString('订阅ID', $content);
$this->assertStringContainsString('BMPA失败原因', $content);
$this->assertStringContainsString('最近批量标记支付并生效时间', $content);
$this->assertStringContainsString('最近批量标记支付并生效管理员', $content);
$this->assertStringContainsString('最近批量生效时间', $content);
$this->assertStringContainsString('最近批量生效管理员', $content);
$this->assertStringContainsString('退款总额', $content);
// include_meta=1 时应包含 meta(JSON) 列
$res2 = $this->get('/admin/platform-orders/export?include_meta=1');
$res2->assertOk();
$content2 = $res2->streamedContent();
$this->assertStringContainsString('原始meta(JSON)', $content2);
$this->assertStringContainsString('subscription_activation_error', $content2);
// batch_synced_24h=1 导出应只包含 24h 内批量同步过的订单
$res3 = $this->get('/admin/platform-orders/export?batch_synced_24h=1');
$res3->assertOk();
$content3 = $res3->streamedContent();
$this->assertStringContainsString('PO_EXPORT_BATCH_RECENT', $content3);
$this->assertStringNotContainsString('PO_EXPORT_BATCH_OLD', $content3);
// site_subscription_id 精确过滤导出只导出订阅ID命中的订单
$sub = \App\Models\SiteSubscription::query()->create([
'merchant_id' => $merchant->id,
'plan_id' => $plan->id,
'status' => 'activated',
'source' => 'manual',
'subscription_no' => 'SUB_EXPORT_FILTER_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_EXPORT_SUB_FILTER_0001',
'order_type' => 'renewal',
'status' => 'activated',
'payment_status' => 'paid',
'plan_name' => $plan->name,
'billing_cycle' => $plan->billing_cycle,
'period_months' => 1,
'quantity' => 1,
'payable_amount' => 10,
'paid_amount' => 10,
'placed_at' => now(),
'paid_at' => now(),
'activated_at' => now(),
]);
PlatformOrder::query()->create([
'merchant_id' => $merchant->id,
'plan_id' => $plan->id,
'site_subscription_id' => null,
'order_no' => 'PO_EXPORT_SUB_FILTER_0002',
'order_type' => 'renewal',
'status' => 'activated',
'payment_status' => 'paid',
'plan_name' => $plan->name,
'billing_cycle' => $plan->billing_cycle,
'period_months' => 1,
'quantity' => 1,
'payable_amount' => 10,
'paid_amount' => 10,
'placed_at' => now(),
'paid_at' => now(),
'activated_at' => now(),
]);
$res4 = $this->get('/admin/platform-orders/export?site_subscription_id=' . $sub->id);
$res4->assertOk();
$content4 = $res4->streamedContent();
$this->assertStringContainsString('PO_EXPORT_SUB_FILTER_0001', $content4);
$this->assertStringNotContainsString('PO_EXPORT_SUB_FILTER_0002', $content4);
}
public function test_guest_cannot_export_platform_orders_csv(): void
{
$this->seed();
$this->get('/admin/platform-orders/export')
->assertRedirect('/admin/login');
}
}