first version

This commit is contained in:
liu
2026-07-23 20:41:25 +08:00
parent 00a0938a1b
commit 10cff754a4
211 changed files with 11577 additions and 842 deletions
+121
View File
@@ -0,0 +1,121 @@
<?php
namespace Tests\Feature;
use App\Exports\PurchaseOrderExport;
use App\Models\CustomerLevelModel;
use App\Models\ProductCategoryModel;
use App\Models\ProductModel;
use App\Models\ProductPriceModel;
use App\Models\PurchaseOrderModel;
use App\Models\StoreModel;
use App\Models\UserModel;
use Maatwebsite\Excel\Facades\Excel;
/**
* 采购单导出:xlsx Content-Type / 蔬果分类过滤 / PDF / format 非法拒绝 / 权限拦截 /
* 中文文件名 RFC 5987 编码
*/
class ExportTest extends ProcurementTestCase
{
/**
* 构造含蔬果 + 肉禽两类商品的采购单(下单 → 汇总生成)
*/
private function buildPurchaseWithItems(): PurchaseOrderModel
{
$vegRoot = ProductCategoryModel::create(['name' => '蔬菜', 'parent_id' => 0, 'sort' => 0, 'status' => 1]);
$meatRoot = ProductCategoryModel::create(['name' => '肉禽蛋', 'parent_id' => 0, 'sort' => 1, 'status' => 1]);
$level = CustomerLevelModel::factory()->create();
$store = StoreModel::factory()->create(['level_id' => $level->id]);
$veg = ProductModel::factory()->create(['status' => ProductModel::STATUS_ON, 'category_id' => $vegRoot->id]);
$meat = ProductModel::factory()->create(['status' => ProductModel::STATUS_ON, 'category_id' => $meatRoot->id]);
ProductPriceModel::factory()->create(['product_id' => $veg->id, 'level_id' => $level->id, 'price' => '5.00']);
ProductPriceModel::factory()->create(['product_id' => $meat->id, 'level_id' => $level->id, 'price' => '20.00']);
$this->actingAsMiniUser(UserModel::factory()->forStore($store->id)->create());
$this->postJson('/mini/order', ['items' => [
['product_id' => $veg->id, 'quantity' => 2],
['product_id' => $meat->id, 'quantity' => 1],
]])->assertJsonPath('success', true);
$this->actingAsSysUser();
$this->postJson('/purchase/order/generate', ['purchase_date' => now()->toDateString()])
->assertJsonPath('success', true);
return PurchaseOrderModel::first();
}
/** xlsx 导出:正确 Content-Type + 中文文件名 RFC 5987 编码 */
public function test_export_xlsx_with_encoded_chinese_filename(): void
{
$purchase = $this->buildPurchaseWithItems();
$this->actingAsSysUser();
$response = $this->get("/purchase/order/{$purchase->id}/export?type=all&format=xlsx");
$response->assertOk();
$this->assertStringContainsString(
'spreadsheetml',
(string) $response->headers->get('Content-Type'),
'xlsx 应返回电子表格 Content-Type'
);
$disposition = (string) $response->headers->get('Content-Disposition');
// Symfony 输出小写 utf-8''RFC 5987),大小写不敏感断言
$this->assertMatchesRegularExpression("/filename\*=utf-8''/i", $disposition, '中文文件名应走 RFC 5987 编码');
$this->assertStringContainsString(rawurlencode('采购单'), $disposition);
}
/** 蔬果分类过滤:type=category 仅导出蔬菜/水果顶级分类商品 */
public function test_export_category_filters_to_vegetables(): void
{
$purchase = $this->buildPurchaseWithItems();
$this->actingAsSysUser();
Excel::fake();
$this->get("/purchase/order/{$purchase->id}/export?type=category&format=xlsx")->assertOk();
Excel::assertDownloaded(
$purchase->purchase_no . '_采购单.xlsx',
static function (PurchaseOrderExport $export): bool {
$items = $export->collection();
// 仅蔬菜商品一行,肉禽被过滤
return $items->count() === 1;
}
);
}
/** PDF 导出:application/pdf */
public function test_export_pdf(): void
{
$purchase = $this->buildPurchaseWithItems();
$this->actingAsSysUser();
$response = $this->get("/purchase/order/{$purchase->id}/export?format=pdf");
$response->assertOk();
$this->assertStringContainsString('application/pdf', (string) $response->headers->get('Content-Type'));
$this->assertStringStartsWith('%PDF', (string) $response->getContent());
}
/** format 参数非法 → 拒绝 */
public function test_export_invalid_format_rejected(): void
{
$purchase = $this->buildPurchaseWithItems();
$this->actingAsSysUser();
$this->get("/purchase/order/{$purchase->id}/export?format=doc")
->assertJsonPath('success', false);
}
/** 无 purchase.order.export 权限点 → 拦截 */
public function test_export_requires_export_permission(): void
{
$purchase = $this->buildPurchaseWithItems();
// 仅持有查询权限的用户
$this->actingAsSysUser(['purchase.order.query']);
$response = $this->get("/purchase/order/{$purchase->id}/export?format=xlsx");
$this->assertFalse($response->json('success'), '缺少权限点应被拦截');
}
}