diff --git a/app/Http/Controllers/Business/Pages.php b/app/Http/Controllers/Business/Pages.php index 00e095b3..df0ca982 100644 --- a/app/Http/Controllers/Business/Pages.php +++ b/app/Http/Controllers/Business/Pages.php @@ -812,22 +812,22 @@ class Pages extends Controller : '(未匹配)'; fputcsv($csv, [ - $this->csvText($approvalNumber), + $this->csvIdentifier($approvalNumber), $this->csvText($workflow['title'] ?? ''), $this->csvText($row['status_label'] ?? ''), $this->csvText($originator), $this->csvText($row['payee_name'] ?? ''), - $this->csvText($row['product_id'] ?? ''), + $this->csvIdentifier($row['product_id'] ?? ''), $this->csvText($productName), $this->csvText($row['shop_name'] ?? ''), - $this->csvText($row['daifa_trade_no'] ?? ''), - $this->csvText($row['shop_trade_no'] ?? ''), + $this->csvIdentifier($row['daifa_trade_no'] ?? ''), + $this->csvIdentifier($row['shop_trade_no'] ?? ''), $row['ship_qty'] ?? null, $row['paid_amount'] ?? null, $row['daifa_amount'] ?? null, $row['price_diff'] ?? null, $this->csvText($row['supplier_name'] ?? ''), - $this->csvText($row['material_no'] ?? ''), + $this->csvIdentifier($row['material_no'] ?? ''), $this->csvText($row['workflow_created_at'] ?? ''), ]); } @@ -2076,6 +2076,22 @@ class Pages extends Controller return preg_match('/^[=+\-@]/u', $text) === 1 ? "'" . $text : $text; } + /** + * Export identifiers as text so Excel does not round or truncate long IDs. + * Keep the formula-injection guard from csvText for values beginning with a + * formula marker. + */ + private function csvIdentifier(mixed $value): string + { + $text = $this->csvText($value); + + if ($text === '' || str_starts_with($text, "'")) { + return $text; + } + + return "'" . $text; + } + private function emptyProductCatalogContent( array $filters, int $limit, diff --git a/database/migrations/2026_09_09_130000_add_daifa_material_no_index.php b/database/migrations/2026_09_09_130000_add_daifa_material_no_index.php new file mode 100644 index 00000000..a7ef1d83 --- /dev/null +++ b/database/migrations/2026_09_09_130000_add_daifa_material_no_index.php @@ -0,0 +1,51 @@ +environment('testing') + || (string) config('system_database.mode', 'bootstrap') === 'bootstrap') { + return; + } + + $schema = Schema::connection($this->connection()); + if (! $schema->hasTable(self::TABLE) || $schema->hasIndex(self::TABLE, self::INDEX)) { + return; + } + + $schema->table(self::TABLE, function (Blueprint $table): void { + $table->index('material_no', self::INDEX); + }); + } + + public function down(): void + { + if (app()->environment('testing') + || (string) config('system_database.mode', 'bootstrap') === 'bootstrap') { + return; + } + + $schema = Schema::connection($this->connection()); + if (! $schema->hasTable(self::TABLE) || ! $schema->hasIndex(self::TABLE, self::INDEX)) { + return; + } + + $schema->table(self::TABLE, function (Blueprint $table): void { + $table->dropIndex(self::INDEX); + }); + } +}; diff --git a/tests/Feature/Business/OnlineDaifaPricePageTest.php b/tests/Feature/Business/OnlineDaifaPricePageTest.php index 59ffab9d..b39e821a 100644 --- a/tests/Feature/Business/OnlineDaifaPricePageTest.php +++ b/tests/Feature/Business/OnlineDaifaPricePageTest.php @@ -155,9 +155,9 @@ class OnlineDaifaPricePageTest extends FeatureTestCase $repository->shouldReceive('exportRows')->once()->with($filters)->andReturn((static function (): \Generator { yield [ 'process_instance_id' => 'PROCESS-001', - 'product_id' => 'PRODUCT-001', - 'daifa_trade_no' => 'DAIFA-001', - 'shop_trade_no' => 'SHOP-001', + 'product_id' => '3821829253650055444', + 'daifa_trade_no' => '6927049845766979458', + 'shop_trade_no' => '6927049845766979459', 'shop_name' => '抖音旗舰店', 'payee_name' => '宁波顾家望业家居有限公司', 'supplier_name' => '@新北供应商', @@ -190,6 +190,9 @@ class OnlineDaifaPricePageTest extends FeatureTestCase $this->assertStringContainsString("'=APPROVAL-001", $content); $this->assertStringContainsString("'+扬灵", $content); $this->assertStringContainsString("'@新北供应商", $content); + $this->assertStringContainsString("'3821829253650055444", $content); + $this->assertStringContainsString("'6927049845766979458", $content); + $this->assertStringContainsString("'6927049845766979459", $content); $this->assertStringContainsString('MAT-001', $content); }