table('fin_accounts')->insert([ 'company_name' => '测试公司', 'account_short' => '测试公司支付宝', 'account_no' => '18800000000', 'account_type' => '支付宝', 'current_balance' => 1000, ]); $connection->table('fin_account_opening')->insert([ 'account_short' => '测试公司支付宝', 'opening_date' => '2026-10-01', 'opening_balance' => 1000, ]); $file = $this->csvFile([ ['交易时间', '交易分类', '交易对方', '商品说明', '收/支', '金额', '交易状态', '交易订单号', '商家订单号', '备注'], ['2026-10-29 09:10:00', '转账', '甲公司', '货款', '收入', '100.00', '交易成功', 'ALI-1', 'M-1', '收款'], ['2026-10-29 10:20:00', '消费', '乙公司', '服务费', '支出', '20.00', '交易成功', 'ALI-2', 'M-2', '付款'], ['2026-10-29 11:30:00', '其他', '丙公司', '关闭订单', '收入', '999.00', '交易关闭', 'ALI-3', 'M-3', ''], ['2026-10-28 11:30:00', '其他', '丁公司', '前一日', '收入', '300.00', '交易成功', 'ALI-4', 'M-4', ''], ]); $this->artisan('finance-ledger:import-company-alipay', [ 'path' => $file, '--date' => '2026-10-29', '--account' => '18800000000', '--account-short' => '测试公司支付宝', ])->assertExitCode(0); $this->assertDatabaseCount('fin_transactions', 2, 'business_mirror'); $this->assertDatabaseHas('fin_transactions', [ 'txn_date' => '2026-10-29', 'account_short' => '测试公司支付宝', 'approval_no' => 'ALI-1', 'source' => CompanyAlipayBillImporter::SOURCE, 'source_value' => '18800000000', 'income' => 100, ], 'business_mirror'); $this->assertDatabaseHas('fin_transactions', [ 'approval_no' => 'ALI-2', 'expense' => 20, ], 'business_mirror'); $this->assertDatabaseMissing('fin_transactions', ['approval_no' => 'ALI-3'], 'business_mirror'); $this->assertDatabaseMissing('fin_transactions', ['approval_no' => 'ALI-4'], 'business_mirror'); $this->assertDatabaseHas('fin_account_map', [ 'source' => CompanyAlipayBillImporter::SOURCE, 'source_value' => '18800000000', 'account_short' => '测试公司支付宝', 'txn_count' => 2, 'income_sum' => 100, 'expense_sum' => 20, ], 'business_mirror'); $this->assertDatabaseHas('fin_daily_flows', [ 'flow_date' => '2026-10-29', 'account_short' => '测试公司支付宝', 'opening_balance' => 1000, 'inflow' => 100, 'outflow' => 20, 'closing_balance' => 1080, ], 'business_mirror'); $replacement = $this->csvFile([ ['交易时间', '交易对方', '商品说明', '收/支', '金额(元)', '交易状态', '交易号'], ['2026-10-29 10:20:00', '乙公司', '服务费', '支出', '50.00', '交易成功', 'ALI-2'], ]); $this->artisan('finance-ledger:import-company-alipay', [ 'path' => $replacement, '--date' => '2026-10-29', '--account' => '18800000000', ])->assertExitCode(0); $this->assertDatabaseCount('fin_transactions', 1, 'business_mirror'); $this->assertDatabaseHas('fin_transactions', [ 'approval_no' => 'ALI-2', 'expense' => 50, ], 'business_mirror'); $this->assertDatabaseHas('fin_daily_flows', [ 'flow_date' => '2026-10-29', 'account_short' => '测试公司支付宝', 'outflow' => 50, 'closing_balance' => 950, ], 'business_mirror'); } public function test_empty_or_unknown_account_keeps_existing_rows(): void { DB::connection('business_mirror')->table('fin_accounts')->insert([ 'company_name' => '测试公司', 'account_short' => '测试公司支付宝', 'account_no' => '18800000000', 'account_type' => '支付宝', ]); DB::connection('business_mirror')->table('fin_transactions')->insert([ 'txn_date' => '2026-10-29', 'account_short' => '测试公司支付宝', 'detail' => '原有记录', 'income' => 1, 'expense' => 0, 'source' => CompanyAlipayBillImporter::SOURCE, 'source_value' => '18800000000', 'process_type' => CompanyAlipayBillImporter::PROCESS_TYPE, 'row_key' => hash('sha256', 'existing-alipay-row'), ]); $empty = $this->csvFile([ ['交易时间', '交易对方', '商品说明', '收/支', '金额(元)', '交易状态', '交易号'], ['2026-10-28 10:00:00', '甲公司', '非目标日期', '收入', '10.00', '交易成功', 'OLD-1'], ]); $this->withExceptionHandling()->artisan('finance-ledger:import-company-alipay', [ 'path' => $empty, '--date' => '2026-10-29', '--account' => '18800000000', ])->assertExitCode(1); $this->assertDatabaseHas('fin_transactions', ['detail' => '原有记录'], 'business_mirror'); $this->withExceptionHandling()->artisan('finance-ledger:import-company-alipay', [ 'path' => $empty, '--date' => '2026-10-29', '--account' => '99999999999', ])->assertExitCode(1); $this->assertDatabaseHas('fin_transactions', ['detail' => '原有记录'], 'business_mirror'); } /** @param list> $rows */ private function csvFile(array $rows): string { $path = tempnam(sys_get_temp_dir(), 'company-alipay-') . '.csv'; $stream = fopen($path, 'wb'); if ($stream === false) { throw new \RuntimeException('无法创建测试 CSV。'); } foreach ($rows as $row) { fputcsv($stream, $row); } fclose($stream); return $path; } }