[ 'driver' => 'sqlite', 'database' => ':memory:', 'prefix' => '', ], 'upstream_mirrors.connection' => 'business_mirror', 'app.timezone' => 'Asia/Shanghai', 'dingtalk.worklog.enabled' => true, 'dingtalk.worklog.template_name' => '财务日报', 'dingtalk.worklog.lookback_days' => 35, ]); DB::purge('business_mirror'); Schema::connection('business_mirror')->create('business_mirror_table_states', function (Blueprint $table): void { $table->string('dataset_key', 191)->primary(); $table->string('source_key', 64); $table->string('source_object', 191); $table->string('target_table', 64); $table->string('status', 24)->default('pending'); $table->string('run_mode', 24)->nullable(); $table->json('cursor')->nullable(); $table->json('high_watermark')->nullable(); $table->dateTime('window_started_at')->nullable(); $table->dateTime('window_ends_at')->nullable(); $table->dateTime('initial_completed_at')->nullable(); $table->dateTime('last_attempted_at')->nullable(); $table->dateTime('last_succeeded_at')->nullable(); $table->unsignedBigInteger('last_upserted_rows')->default(0); $table->unsignedBigInteger('mirror_row_count')->default(0); $table->string('last_error_code', 120)->nullable(); $table->timestamps(); }); (require base_path('database/migrations/2026_11_04_230000_create_ding_worklog_reports.php'))->up(); } public function test_command_stores_reports_under_the_correct_statistics_date(): void { Carbon::setTestNow(Carbon::parse('2026-11-05 13:00:00', 'Asia/Shanghai')); try { $client = Mockery::mock(DingTalkWorklogClient::class); $client->shouldReceive('isConfigured')->once()->andReturnTrue(); $client->shouldReceive('listReports')->once()->andReturn([ 'pages' => 1, 'reports' => [ [ 'report_id' => 'before-noon', 'creator_id' => 'user-a', 'creator_name' => '秋香', 'template_name' => '财务日报', 'create_time' => '2026-11-04 10:26:00', ], [ 'report_id' => 'last-minute', 'creator_id' => 'user-b', 'creator_name' => '李斯', 'template_name' => '财务日报', 'create_time' => '2026-11-05 11:59:59', ], [ 'report_id' => 'noon', 'creator_id' => 'user-c', 'creator_name' => '晨曦', 'template_name' => '财务日报', 'create_time' => '2026-11-05 12:00:00', ], ], ]); $this->app->instance(DingTalkWorklogClient::class, $client); $this->artisan('business-mirror:sync-ding-worklogs') ->expectsOutputToContain('写入/更新 3 条') ->assertSuccessful(); $rows = DB::connection('business_mirror') ->table('ding_worklog_reports') ->orderBy('report_id') ->get(['report_id', 'creator_userid', 'statistics_date']) ->map(static fn (object $row): array => (array) $row) ->all(); $this->assertSame([ [ 'report_id' => 'before-noon', 'creator_userid' => 'user-a', 'statistics_date' => '2026-11-03', ], [ 'report_id' => 'last-minute', 'creator_userid' => 'user-b', 'statistics_date' => '2026-11-04', ], [ 'report_id' => 'noon', 'creator_userid' => 'user-c', 'statistics_date' => '2026-11-05', ], ], $rows); } finally { Carbon::setTestNow(); } } }