table('fin_accounts')->insert([ 'company_name' => '朱俊祥', 'account_short' => '朱俊祥微信', 'account_type' => '个人微信', 'current_balance' => 0, ]); $connection->table('fin_transactions')->insert([ 'txn_date' => '2026-10-03', 'account_short' => '朱俊祥微信', 'detail' => '旧月份记录', 'income' => 1, 'expense' => 0, 'balance' => 101, 'source' => 'wechat-statement', 'source_value' => '朱俊祥微信', 'process_type' => '公司微信收支流水', 'row_key' => 'old-wechat-statement', ]); $file = $this->workbook([ ['日期', '简称', '收入', '支出', '余额'], [null, '朱俊祥微信', null, null, 100], ['10/4/2026', '朱俊祥微信', 20, null, 120], ['10/5/2026', '朱俊祥微信', null, 5, 115], ]); $this->artisan('finance-ledger:import-wechat-statement', [ 'path' => $file, '--dry-run' => true, ])->assertExitCode(0); $this->assertDatabaseHas('fin_transactions', [ 'row_key' => 'old-wechat-statement', ], 'business_mirror'); $this->artisan('finance-ledger:import-wechat-statement', [ 'path' => $file, ])->assertExitCode(0); $this->assertDatabaseMissing('fin_transactions', [ 'row_key' => 'old-wechat-statement', ], 'business_mirror'); $this->assertSame(2, $connection->table('fin_transactions') ->where('source', 'wechat-statement') ->where('account_short', '朱俊祥微信') ->count()); $this->assertDatabaseHas('fin_transactions', [ 'txn_date' => '2026-10-04', 'account_short' => '朱俊祥微信', 'income' => 20, 'balance' => 120, 'source' => 'wechat-statement', ], 'business_mirror'); $this->assertDatabaseHas('fin_transactions', [ 'txn_date' => '2026-10-05', 'account_short' => '朱俊祥微信', 'expense' => 5, 'balance' => 115, ], 'business_mirror'); $this->assertDatabaseHas('fin_account_opening', [ 'account_short' => '朱俊祥微信', 'opening_date' => '2026-10-01', 'opening_balance' => 100, ], 'business_mirror'); $this->assertDatabaseMissing('fin_daily_flows', [ 'account_short' => '朱俊祥微信', ], 'business_mirror'); $this->assertSame(0.0, (float) $connection->table('fin_accounts') ->where('account_short', '朱俊祥微信') ->value('current_balance')); } public function test_unbalanced_wechat_statement_keeps_existing_rows(): void { DB::connection('business_mirror')->table('fin_accounts')->insert([ 'company_name' => '朱俊祥', 'account_short' => '朱俊祥微信', ]); DB::connection('business_mirror')->table('fin_transactions')->insert([ 'txn_date' => '2026-10-03', 'account_short' => '朱俊祥微信', 'detail' => '应保留记录', 'income' => 1, 'expense' => 0, 'balance' => 101, 'source' => 'wechat-statement', 'source_value' => '朱俊祥微信', 'row_key' => 'wechat-unbalanced-existing', ]); $file = $this->workbook([ ['日期', '简称', '收入', '支出', '余额'], [null, '朱俊祥微信', null, null, 100], ['10/4/2026', '朱俊祥微信', 20, null, 125], ]); $this->withExceptionHandling()->artisan('finance-ledger:import-wechat-statement', [ 'path' => $file, ])->assertExitCode(1); $this->assertDatabaseHas('fin_transactions', [ 'row_key' => 'wechat-unbalanced-existing', ], 'business_mirror'); } /** @param list> $rows */ private function workbook(array $rows): string { $spreadsheet = new Spreadsheet(); $spreadsheet->getActiveSheet()->fromArray($rows, null, 'A1'); $path = tempnam(sys_get_temp_dir(), 'wechat-statement-') . '.xlsx'; (new Xlsx($spreadsheet))->save($path); $spreadsheet->disconnectWorksheets(); return $path; } }