originalConnection = DB::getDefaultConnection(); config()->set('database.connections.refund_migration_test', [ 'driver' => 'sqlite', 'database' => ':memory:', 'prefix' => '', 'foreign_key_constraints' => true, ]); DB::setDefaultConnection('refund_migration_test'); Schema::create('compra_items', function (Blueprint $table): void { $table->id(); $table->decimal('precio_unitario', 10, 2); $table->decimal('total', 10, 2); $table->decimal('refunded_amount', 10, 2)->default(0); }); Schema::create('tickets', function (Blueprint $table): void { $table->id(); $table->foreignId('source_purchase_item_id')->nullable(); $table->dateTime('refunded_at')->nullable(); }); Schema::create('ticket_refunds', function (Blueprint $table): void { $table->id(); $table->foreignId('ticket_id')->unique(); $table->foreignId('purchase_item_id'); $table->foreignId('created_by_user_id')->nullable(); $table->string('type', 16); $table->decimal('amount', 10, 2); $table->timestamps(); }); } protected function tearDown(): void { DB::purge('refund_migration_test'); DB::setDefaultConnection($this->originalConnection); parent::tearDown(); } public function test_it_backfills_a_refund_created_before_ticket_refunds_existed(): void { DB::table('compra_items')->insert([ 'id' => 254, 'precio_unitario' => '100.00', 'total' => '100.00', 'refunded_amount' => '40.00', ]); DB::table('tickets')->insert([ 'id' => 501, 'source_purchase_item_id' => 254, 'refunded_at' => '2026-09-13 18:30:00', ]); $this->migration()->up(); $this->assertFalse(Schema::hasColumn('compra_items', 'refunded_amount')); $this->assertDatabaseHas('ticket_refunds', [ 'ticket_id' => 501, 'purchase_item_id' => 254, 'created_by_user_id' => null, 'type' => 'partial', 'amount' => 40, 'created_at' => '2026-09-13 18:30:00', ]); } public function test_it_only_backfills_the_amount_not_already_in_ticket_refunds(): void { DB::table('compra_items')->insert([ 'id' => 254, 'precio_unitario' => '100.00', 'total' => '200.00', 'refunded_amount' => '140.00', ]); DB::table('tickets')->insert([ [ 'id' => 501, 'source_purchase_item_id' => 254, 'refunded_at' => '2026-09-13 18:30:00', ], [ 'id' => 502, 'source_purchase_item_id' => 254, 'refunded_at' => '2026-09-14 10:00:00', ], ]); DB::table('ticket_refunds')->insert([ 'ticket_id' => 502, 'purchase_item_id' => 254, 'created_by_user_id' => 7, 'type' => 'total', 'amount' => '100.00', 'created_at' => '2026-09-14 10:00:00', 'updated_at' => '2026-09-14 10:00:00', ]); $this->migration()->up(); $this->assertDatabaseHas('ticket_refunds', [ 'ticket_id' => 501, 'purchase_item_id' => 254, 'created_by_user_id' => null, 'type' => 'partial', 'amount' => 40, ]); $this->assertSame(2, DB::table('ticket_refunds')->count()); } public function test_it_still_refuses_to_drop_an_amount_without_a_refunded_ticket(): void { DB::table('compra_items')->insert([ 'id' => 254, 'precio_unitario' => '100.00', 'total' => '100.00', 'refunded_amount' => '40.00', ]); try { $this->migration()->up(); $this->fail('The migration should preserve an amount that cannot be backfilled.'); } catch (RuntimeException $exception) { $this->assertStringContainsString('ítem 254', $exception->getMessage()); $this->assertTrue(Schema::hasColumn('compra_items', 'refunded_amount')); } } private function migration(): object { return require database_path( 'migrations/2026_09_14_040000_remove_refunded_amount_from_purchase_items.php' ); } }