diff --git a/database/migrations/2026_06_25_120000_make_inspection_templates_global_with_pivot.php b/database/migrations/2026_06_25_120000_make_inspection_templates_global_with_pivot.php index 43f82bb..f4e7e08 100644 --- a/database/migrations/2026_06_25_120000_make_inspection_templates_global_with_pivot.php +++ b/database/migrations/2026_06_25_120000_make_inspection_templates_global_with_pivot.php @@ -15,14 +15,17 @@ return new class extends Migration */ public function up(): void { - // Pivot template ↔ project - Schema::create('inspection_template_project', function (Blueprint $table) { - $table->id(); - $table->foreignId('inspection_template_id')->constrained()->cascadeOnDelete(); - $table->foreignId('project_id')->constrained()->cascadeOnDelete(); - $table->timestamps(); - $table->unique(['inspection_template_id', 'project_id'], 'itp_template_project_unique'); - }); + // Pivot template ↔ project (idempotente: si el up() falló a mitad la primera + // vez, la tabla puede existir ya; en ese caso saltamos su creación). + if (! Schema::hasTable('inspection_template_project')) { + Schema::create('inspection_template_project', function (Blueprint $table) { + $table->id(); + $table->foreignId('inspection_template_id')->constrained()->cascadeOnDelete(); + $table->foreignId('project_id')->constrained()->cascadeOnDelete(); + $table->timestamps(); + $table->unique(['inspection_template_id', 'project_id'], 'itp_template_project_unique'); + }); + } // Migrar la asignación existente (project_id en inspection_templates → pivot) $rows = DB::table('inspection_templates')->whereNotNull('project_id')->get(['id', 'project_id']); @@ -37,12 +40,16 @@ return new class extends Migration ); } - // Drop columna phase_id (la asociación a fase deja de existir) + // Drop columna phase_id (la asociación a fase deja de existir). + // ORDEN IMPORTANTE en MySQL: primero FK, luego índice, luego columna. if (Schema::hasColumn('inspection_templates', 'phase_id')) { Schema::table('inspection_templates', function (Blueprint $table) { - // Algunos motores (SQLite) requieren dropear el índice antes de la columna. + // 1) FK primero: si no la dropeamos, MySQL rechaza soltar el índice + // que la sustenta ("needed in a foreign key constraint"). + try { $table->dropForeign(['phase_id']); } catch (\Throwable $e) { /* sqlite sin FKs / ya inexistente */ } + // 2) Índice después (nombre por convención de Laravel). try { $table->dropIndex('inspection_templates_phase_id_index'); } catch (\Throwable $e) { /* ya no existe */ } - try { $table->dropForeign(['phase_id']); } catch (\Throwable $e) { /* sqlite sin FKs */ } + // 3) Columna al final. $table->dropColumn('phase_id'); }); }