[ 'driver' => 'sqlite', 'database' => ':memory:', 'prefix' => '', ], 'upstream_mirrors.connection' => 'business_mirror', 'finance_ledger.opening_date' => '2026-10-17', ]); DB::purge('business_mirror'); $schema = Schema::connection('business_mirror'); $schema->create('fin_accounts', function (Blueprint $table): void { $table->increments('id'); $table->string('company_name'); $table->string('account_short'); $table->decimal('current_balance', 18, 2)->default(0); $table->decimal('blocked_amount', 18, 2)->default(0); $table->decimal('daily_available', 18, 2)->default(0); $table->timestamp('updated_at')->nullable(); }); $schema->create('fin_account_opening', function (Blueprint $table): void { $table->increments('id'); $table->string('account_short'); $table->date('opening_date'); $table->decimal('opening_balance', 18, 2)->default(0); $table->timestamp('updated_at')->nullable(); }); $schema->create('fin_transactions', function (Blueprint $table): void { $table->increments('id'); $table->date('txn_date'); $table->string('account_short')->nullable(); $table->string('source'); $table->string('source_value')->nullable(); $table->decimal('income', 18, 2)->default(0); $table->decimal('expense', 18, 2)->default(0); }); $schema->create('fin_account_map', function (Blueprint $table): void { $table->increments('id'); $table->string('source'); $table->string('source_value'); $table->string('account_short')->nullable(); }); $schema->create('fin_daily_flows', function (Blueprint $table): void { $table->increments('id'); $table->date('flow_date'); $table->string('company_name')->nullable(); $table->string('account_short'); $table->decimal('opening_balance', 18, 2)->default(0); $table->decimal('inflow', 18, 2)->default(0); $table->decimal('outflow', 18, 2)->default(0); $table->decimal('closing_balance', 18, 2)->default(0); $table->string('remark')->nullable(); $table->timestamps(); }); $schema->create('fin_shops', function (Blueprint $table): void { $table->increments('id'); $table->string('company_name'); $table->decimal('shop_balance', 18, 2)->default(0); $table->timestamp('updated_at')->nullable(); }); $db = DB::connection('business_mirror'); $db->table('fin_accounts')->insert([ ['company_name' => '公司A', 'account_short' => '账户A', 'blocked_amount' => 0], ['company_name' => '公司B', 'account_short' => '账户B', 'blocked_amount' => 0], ]); $db->table('fin_account_opening')->insert([ ['account_short' => '账户A', 'opening_date' => '2026-10-17', 'opening_balance' => 1000], ['account_short' => '账户B', 'opening_date' => '2026-10-17', 'opening_balance' => 500], ]); $db->table('fin_transactions')->insert([ ['txn_date' => '2026-10-17', 'account_short' => '', 'source' => 'shop', 'source_value' => '店铺A', 'income' => 100, 'expense' => 0], ['txn_date' => '2026-10-18', 'account_short' => '账户A', 'source' => 'shop', 'source_value' => '店铺A', 'income' => 0, 'expense' => 50], ]); $db->table('fin_account_map')->insert([ ['source' => 'shop', 'source_value' => '店铺A', 'account_short' => '账户A'], ]); $db->table('fin_shops')->insert([ ['company_name' => '公司A', 'shop_balance' => 0], ]); } protected function tearDown(): void { DB::purge('business_mirror'); parent::tearDown(); } public function test_daily_flows_roll_forward_from_opening_and_merge_opening_day(): void { $result = app(FinanceLedgerCalculator::class)->recalculate(); $rows = DB::connection('business_mirror')->table('fin_daily_flows') ->orderBy('account_short')->orderBy('flow_date')->get(); $this->assertSame(3, $result['flows']); $this->assertSame(['账户A', '账户A', '账户B'], $rows->pluck('account_short')->all()); $this->assertEqualsWithDelta(1000.00, (float) $rows[0]->opening_balance, 0.001); $this->assertEqualsWithDelta(100.00, (float) $rows[0]->inflow, 0.001); $this->assertEqualsWithDelta(1100.00, (float) $rows[0]->closing_balance, 0.001); $this->assertEqualsWithDelta(1100.00, (float) $rows[1]->opening_balance, 0.001); $this->assertEqualsWithDelta(50.00, (float) $rows[1]->outflow, 0.001); $this->assertEqualsWithDelta(1050.00, (float) $rows[1]->closing_balance, 0.001); $this->assertEqualsWithDelta(500.00, (float) $rows[2]->closing_balance, 0.001); $accounts = DB::connection('business_mirror')->table('fin_accounts')->pluck('current_balance', 'account_short'); $this->assertEqualsWithDelta(1050.00, (float) $accounts['账户A'], 0.001); $this->assertEqualsWithDelta(500.00, (float) $accounts['账户B'], 0.001); $this->assertEqualsWithDelta(1050.00, (float) DB::connection('business_mirror')->table('fin_shops')->value('shop_balance'), 0.001); } }