[ 'driver' => 'sqlite', 'database' => ':memory:', 'prefix' => '', ], 'upstream_mirrors.connection' => 'business_mirror', ]); DB::purge('business_mirror'); (require database_path('migrations/2026_11_06_170000_create_douyin_opening_balance_snapshots.php'))->up(); } protected function tearDown(): void { foreach ($this->files as $path) { @unlink($path); } parent::tearDown(); } public function test_it_imports_the_ending_balance_column_instead_of_platform_actual_ending(): void { $spreadsheet = new Spreadsheet(); $spreadsheet->getActiveSheet()->fromArray([ ['平台', '来源', '店铺', '期初余额', '本期收入', '本期支出', '期末余额', '平台实际期末余额', '状态'], ['头条放心购', '资金流水', '抖音-测试店', 100, 30, 5, 125, 999, '空'], ['头条放心购', '资金流水', '抖音-二号店', 50, 0, 0, 50, 0, '空'], ['拼多多', '资金流水', '拼多多-其他店', 10, 0, 0, 10, 10, '空'], ]); $path = tempnam(sys_get_temp_dir(), 'douyin-opening-'); unlink($path); $path .= '.xlsx'; (new Xlsx($spreadsheet))->save($path); $spreadsheet->disconnectWorksheets(); $this->files[] = $path; $result = app(DouyinOpeningBalanceImporter::class)->import($path, '2026-06-30'); $this->assertSame(2, $result['total']); $this->assertSame('175.00', $result['balance_total']); $rows = DB::connection('business_mirror') ->table('douyin_opening_balance_snapshots') ->orderBy('normalized_store_name') ->get(['store_name', 'normalized_store_name', 'balance']); $this->assertCount(2, $rows); $this->assertSame('二号店', $rows[0]->normalized_store_name); $this->assertSame(50.0, (float) $rows[0]->balance); $this->assertSame('测试店', $rows[1]->normalized_store_name); $this->assertSame(125.0, (float) $rows[1]->balance); } public function test_it_rejects_a_non_month_end_period(): void { $this->expectException(\InvalidArgumentException::class); app(DouyinOpeningBalanceImporter::class)->periodEnd('2026-06-29'); } }