[ 'driver' => 'sqlite', 'database' => ':memory:', 'prefix' => '', ], 'upstream_mirrors.connection' => 'business_mirror', ]); DB::purge('business_mirror'); $migration = require base_path( 'database/migrations/2026_10_05_000000_create_business_internal_flow_records_table.php' ); $migration->up(); } public function testImportKeepsWorkbookValuesAndSkipsTotalRows(): void { $path = $this->writeWorkbook($this->dataRows()); try { $result = app(InternalFlowWorkbookImporter::class)->import($path); } finally { @unlink($path); } $this->assertSame(3, $result['imported']); $this->assertSame(1, $result['skipped']); $rows = DB::connection('business_mirror') ->table(InternalFlowWorkbookImporter::TABLE) ->orderBy('sort_order') ->get(); $this->assertCount(3, $rows); $this->assertSame('示例甲供应链有限公司', $rows[0]->company_name); $this->assertSame('1', (string) $rows[0]->tag); $this->assertSame('1', $rows[0]->invoicing_ratio); $this->assertEqualsWithDelta(1200000.0, (float) $rows[0]->projected_sales, 0.000001); $this->assertSame(1, (int) $rows[0]->sort_order); $this->assertSame('示例乙电子商务有限公司', $rows[1]->company_name); $this->assertEqualsWithDelta(512345.6789, (float) $rows[1]->internal_invoiced, 0.000001); $this->assertEqualsWithDelta(1833433.2211, (float) $rows[1]->required_input_cost, 0.000001); $this->assertEqualsWithDelta(300000.5, (float) $rows[1]->internal_transfer_1, 0.000001); $this->assertEqualsWithDelta(1200000.5, (float) $rows[1]->receipt_total, 0.000001); $this->assertSame('0.42', $rows[1]->invoicing_ratio); $this->assertSame('示例丙家居有限公司', $rows[2]->company_name); $this->assertNull($rows[2]->invoiced_to_buyer); $this->assertEqualsWithDelta(220000.11, (float) $rows[2]->receipt_total, 0.000001); $this->assertSame('/', $rows[2]->invoicing_ratio); $this->assertSame(basename($path), $rows[0]->source_file); $this->assertSame( 0, DB::connection('business_mirror') ->table(InternalFlowWorkbookImporter::TABLE) ->where('company_name', '合计') ->count(), ); } public function testImportReplacesPreviousDatasetAndCommandReportsCounts(): void { $first = $this->writeWorkbook($this->dataRows()); app(InternalFlowWorkbookImporter::class)->import($first); @unlink($first); $second = $this->writeWorkbook([ ['示例乙电子商务有限公司', 2, 2345678.9, 456789.12, 512345.6789, 1833433.2211, 900000, null, null, 300000.5, 0, 0, 1200000.5, 633432.7211, 0.42], ]); try { $this->artisan('internal-flow:import', ['path' => $second]) ->expectsOutputToContain('明细 1 行') ->assertSuccessful(); } finally { @unlink($second); } $rows = DB::connection('business_mirror') ->table(InternalFlowWorkbookImporter::TABLE) ->get(); $this->assertCount(1, $rows); $this->assertSame('示例乙电子商务有限公司', $rows[0]->company_name); } public function testRepositoryFiltersSortsAndPaginates(): void { $path = $this->writeWorkbook($this->dataRows()); app(InternalFlowWorkbookImporter::class)->import($path); @unlink($path); $repository = app(InternalFlowReportRepository::class); $this->assertTrue($repository->ready()); $all = $repository->paginate(1, 50); $this->assertSame(3, $all['total']); $this->assertSame('示例甲供应链有限公司', $all['data'][0]['company_name']); $filtered = $repository->paginate(1, 50, ['company_name' => '示例乙']); $this->assertSame(1, $filtered['total']); $this->assertSame('示例乙电子商务有限公司', $filtered['data'][0]['company_name']); $tagged = $repository->paginate(1, 50, ['tag' => '4']); $this->assertSame(1, $tagged['total']); $this->assertSame('示例丙家居有限公司', $tagged['data'][0]['company_name']); $sorted = $repository->paginate(1, 50, [], 'projected_sales', 'desc'); $this->assertSame('示例乙电子商务有限公司', $sorted['data'][0]['company_name']); $unknownSort = $repository->paginate(1, 50, [], 'company_name; drop table users', 'desc'); $this->assertSame(3, $unknownSort['total']); $this->assertSame('示例甲供应链有限公司', $unknownSort['data'][0]['company_name']); $paged = $repository->paginate(2, 2); $this->assertSame(3, $paged['total']); $this->assertCount(1, $paged['data']); $this->assertSame('示例丙家居有限公司', $paged['data'][0]['company_name']); } /** * @return list> */ private function dataRows(): array { return [ ['示例甲供应链有限公司', 1, 1200000, 0, 1200000, 0, null, null, null, 0, 0, 0, 0, 0, 1], ['示例乙电子商务有限公司', 2, 2345678.9, 456789.12, 512345.6789, 1833433.2211, 900000, null, null, 300000.5, 0, 0, 1200000.5, 633432.7211, 0.42], ['示例丙家居有限公司', 4, 123456.78, null, null, 987654.32, null, null, null, 0, 0, 220000.11, 220000.11, 767654.21, '/'], ['合计', null, 3679135.68, 456789.12, 1712345.6789, 2821087.5411, 900000, 0, null, 300000.5, 0, 0, 1420000.61, 1401086.9311, '/'], [null, null, null, null, null, null, null, null, null, null, null, null, null, null, null], ]; } /** * @param list> $dataRows */ private function writeWorkbook(array $dataRows): string { $temporary = tempnam(sys_get_temp_dir(), 'internal-flow-'); $path = dirname($temporary) . DIRECTORY_SEPARATOR . 'internal-flow-' . basename($temporary) . '.xlsx'; rename($temporary, $path); $spreadsheet = new Spreadsheet(); $sheet = $spreadsheet->getActiveSheet(); $sheet->setTitle(InternalFlowWorkbookImporter::SHEET_TITLE); $sheet->fromArray([ ['抬头', '标签', '预计9月销量', '开票', null, '所需进项成本', '收票', null, null, null, null, null, null, '剩余缺口', '开票比例'], [null, null, null, null, null, null, '供应商', '索菲亚', '顾家', '内部流转(来源)', null, null, '合计', null, null], [null, null, null, '给买家开票', '内部开票', null, null, null, null, '1', '2', '3', null, null, null], ...$dataRows, ], null, 'A1'); foreach (['A1:A3', 'B1:B3', 'C1:C3', 'D1:E2', 'F1:F3', 'G1:M1', 'H2:H3', 'I2:I3', 'J2:L2', 'M2:M3', 'N1:N3', 'O1:O3'] as $range) { $sheet->mergeCells($range); } (new Xlsx($spreadsheet))->save($path); $spreadsheet->disconnectWorksheets(); return $path; } }