Mager updated
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('accounts', function (Blueprint $table) {
|
||||
$table->decimal("initial_amount", 20, 4)->default(0);
|
||||
$table->decimal("balance_amount", 20, 4)->default(0);
|
||||
$table->date("promise_date")->nullable();
|
||||
$table->index('balance_amount');
|
||||
$table->index('promise_date');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
//
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('object_types', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('name',50);
|
||||
$table->string('description',125)->nullable();
|
||||
$table->softDeletes();
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
Schema::create('objects', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('reference', 125)->nullable();
|
||||
$table->string('name', 255);
|
||||
$table->string('description', 255)->nullable();
|
||||
// If you keep the column name as 'type_id', specify the table explicitly
|
||||
$table->foreignId('type_id')->constrained('object_types')->nullOnDelete();
|
||||
// Indexes for faster lookups
|
||||
$table->softDeletes();
|
||||
$table->timestamps();
|
||||
|
||||
$table->index('reference');
|
||||
$table->index('type_id');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('objects');
|
||||
Schema::dropIfExists('object_types');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration {
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('bank_accounts', function (Blueprint $table) {
|
||||
$table->id();
|
||||
// Ownership (Person-specific). Change to your actual Person table name.
|
||||
$table->foreignId('person_id')->constrained('person')->cascadeOnDelete();
|
||||
// Account details
|
||||
$table->string('bank_name', 100);
|
||||
$table->string('iban', 34)->nullable();
|
||||
$table->string('bic_swift', 11)->nullable();
|
||||
$table->string('account_number', 34)->nullable();
|
||||
$table->string('routing_number', 20)->nullable();
|
||||
$table->char('currency', 3)->default('EUR');
|
||||
$table->char('country_code', 2)->nullable();
|
||||
$table->string('holder_name', 125)->nullable();
|
||||
|
||||
// Status and lifecycle
|
||||
$table->boolean('is_active')->default(true);
|
||||
|
||||
// Misc
|
||||
$table->text('notes')->nullable();
|
||||
$table->json('meta')->nullable();
|
||||
|
||||
// Indexes
|
||||
$table->index('person_id');
|
||||
$table->index('iban');
|
||||
$table->softDeletes();
|
||||
$table->timestamps();
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('bank_accounts');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('emails', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('person_id')->constrained('person')->cascadeOnDelete();
|
||||
// The email address
|
||||
$table->string('value', 255);
|
||||
// Optional label like "work", "home", etc.
|
||||
$table->string('label', 50)->nullable();
|
||||
// Mark a preferred email for the person (enforce at most one in app logic)
|
||||
$table->boolean('is_primary')->default(false);
|
||||
// Whether this email is considered currently active/usable
|
||||
$table->boolean('is_active')->default(true);
|
||||
// Whether validation checks passed (syntax/deliverability)
|
||||
$table->boolean('valid')->default(true);
|
||||
// When the email was verified (e.g., via confirmation link)
|
||||
$table->timestamp('verified_at')->nullable();
|
||||
// JSON columns for notification preferences and arbitrary metadata
|
||||
$table->json('preferences')->nullable();
|
||||
$table->json('meta')->nullable();
|
||||
// Soft delete support
|
||||
$table->softDeletes();
|
||||
// Avoid duplicate emails per person among non-deleted records
|
||||
$table->unique(['person_id', 'value', 'deleted_at'], 'emails_person_value_unique');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('emails');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('imports', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->uuid('uuid')->unique();
|
||||
|
||||
// Who initiated the import
|
||||
$table->foreignId('user_id')->nullable()->constrained('users')->nullOnDelete();
|
||||
|
||||
// Optional template applied to this import (FK added in a later migration to avoid ordering issues)
|
||||
$table->foreignId('import_template_id')->nullable();
|
||||
|
||||
// Optional client this import is for (many imports per client)
|
||||
$table->foreignId('client_id')->nullable()->constrained('clients')->nullOnDelete();
|
||||
|
||||
// File/source metadata
|
||||
$table->string('source_type', 12); // csv|xml|xls|xlsx|json
|
||||
$table->string('file_name', 255);
|
||||
$table->string('original_name', 255)->nullable();
|
||||
$table->string('disk', 50)->default('local');
|
||||
$table->string('path', 2048);
|
||||
$table->unsignedBigInteger('size')->nullable(); // bytes
|
||||
$table->string('sheet_name', 64)->nullable(); // for Excel
|
||||
|
||||
// Progress/status
|
||||
$table->string('status', 20)->default('uploaded'); // uploaded|parsing|parsed|validating|importing|completed|failed
|
||||
$table->unsignedInteger('total_rows')->default(0);
|
||||
$table->unsignedInteger('valid_rows')->default(0);
|
||||
$table->unsignedInteger('invalid_rows')->default(0);
|
||||
$table->unsignedInteger('imported_rows')->default(0);
|
||||
$table->timestamp('started_at')->nullable();
|
||||
$table->timestamp('finished_at')->nullable();
|
||||
$table->timestamp('failed_at')->nullable();
|
||||
|
||||
// Diagnostics and flexibility
|
||||
$table->json('error_summary')->nullable();
|
||||
$table->json('meta')->nullable();
|
||||
|
||||
// Helpful indexes
|
||||
$table->index('user_id');
|
||||
$table->index('import_template_id');
|
||||
$table->index('status');
|
||||
$table->index('client_id');
|
||||
$table->index('source_type');
|
||||
$table->index(['disk', 'path']);
|
||||
|
||||
$table->timestamps();
|
||||
$table->softDeletes();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('imports');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('import_rows', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('import_id')->constrained('imports')->cascadeOnDelete();
|
||||
|
||||
$table->unsignedInteger('row_number');
|
||||
$table->string('sheet_name', 64)->nullable();
|
||||
|
||||
// Type of record represented in this row (person, account, etc.)
|
||||
$table->string('record_type', 50)->nullable();
|
||||
|
||||
// Data and results
|
||||
$table->json('raw_data')->nullable();
|
||||
$table->json('mapped_data')->nullable();
|
||||
$table->string('status', 20)->default('pending'); // pending|valid|invalid|imported|skipped
|
||||
$table->json('errors')->nullable();
|
||||
$table->json('warnings')->nullable();
|
||||
|
||||
// Link to created entity (optional, polymorphic)
|
||||
$table->nullableMorphs('entity'); // entity_type + entity_id
|
||||
|
||||
// Dedup/trace
|
||||
$table->string('fingerprint', 64)->nullable()->index();
|
||||
|
||||
// Helpful indexes
|
||||
$table->index(['import_id', 'status']);
|
||||
$table->index(['import_id', 'row_number']);
|
||||
$table->index('record_type');
|
||||
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('import_rows');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('import_mappings', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('import_id')->constrained('imports')->cascadeOnDelete();
|
||||
|
||||
// Column/header from the source file and the target field in the system
|
||||
$table->string('source_column', 255);
|
||||
$table->string('target_field', 255)->nullable();
|
||||
$table->string('transform', 50)->nullable(); // e.g., trim|upper|date:dd.MM.yyyy
|
||||
$table->json('options')->nullable(); // any extra config for mapping/transforms
|
||||
|
||||
// Indexes
|
||||
$table->index(['import_id', 'source_column']);
|
||||
$table->index(['import_id', 'target_field']);
|
||||
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('import_mappings');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('import_events', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('import_id')->constrained('imports')->cascadeOnDelete();
|
||||
$table->foreignId('user_id')->nullable()->constrained('users')->nullOnDelete();
|
||||
|
||||
// Event details
|
||||
$table->string('event', 50); // created|parsing_started|parsed|validating|importing|completed|failed|retry|...
|
||||
$table->string('level', 10)->default('info'); // info|warning|error
|
||||
$table->text('message')->nullable();
|
||||
$table->json('context')->nullable();
|
||||
|
||||
// An optional pointer to a specific row related to the event
|
||||
$table->foreignId('import_row_id')->nullable()->constrained('import_rows')->nullOnDelete();
|
||||
|
||||
// Indexes
|
||||
$table->index(['import_id', 'event']);
|
||||
$table->index(['import_id', 'level']);
|
||||
$table->index('user_id');
|
||||
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('import_events');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('import_templates', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->uuid('uuid')->unique();
|
||||
|
||||
$table->string('name', 100);
|
||||
$table->string('description', 255)->nullable();
|
||||
|
||||
// What kind of source this template is for (csv|xml|xls|xlsx|json)
|
||||
$table->string('source_type', 12)->default('csv');
|
||||
|
||||
// Defaults for records handled by this template (e.g., person, account)
|
||||
$table->string('default_record_type', 50)->nullable();
|
||||
|
||||
// Optional sample header row for UI assistance
|
||||
$table->json('sample_headers')->nullable();
|
||||
|
||||
// Ownership and lifecycle
|
||||
$table->foreignId('user_id')->nullable()->constrained('users')->nullOnDelete();
|
||||
$table->boolean('is_active')->default(true);
|
||||
$table->json('meta')->nullable();
|
||||
|
||||
$table->timestamps();
|
||||
$table->softDeletes();
|
||||
|
||||
$table->index(['source_type', 'is_active']);
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('import_templates');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('import_template_mappings', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('import_template_id')->constrained('import_templates')->cascadeOnDelete();
|
||||
|
||||
$table->string('source_column', 255);
|
||||
$table->string('target_field', 255)->nullable();
|
||||
$table->string('transform', 50)->nullable();
|
||||
$table->json('options')->nullable();
|
||||
|
||||
$table->unsignedInteger('position')->nullable(); // order in the header
|
||||
|
||||
$table->timestamps();
|
||||
|
||||
$table->index(['import_template_id', 'source_column']);
|
||||
$table->index(['import_template_id', 'position']);
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('import_template_mappings');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('import_templates', function (Blueprint $table) {
|
||||
$table->foreignId('client_id')->nullable()->constrained('clients')->nullOnDelete()->after('user_id');
|
||||
$table->index('client_id');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('import_templates', function (Blueprint $table) {
|
||||
if (Schema::hasColumn('import_templates', 'client_id')) {
|
||||
$table->dropForeign(['client_id']);
|
||||
$table->dropIndex(['client_id']);
|
||||
$table->dropColumn('client_id');
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
// People: unique by (tax_number, social_security_number, deleted_at)
|
||||
Schema::table('person', function (Blueprint $table) {
|
||||
if (!self::hasIndex('person', 'person_identity_unique')) {
|
||||
$table->unique(['tax_number', 'social_security_number', 'deleted_at'], 'person_identity_unique');
|
||||
}
|
||||
});
|
||||
|
||||
// Phones: unique by (person_id, nu, country_code, deleted_at)
|
||||
Schema::table('person_phones', function (Blueprint $table) {
|
||||
if (!self::hasIndex('person_phones', 'person_phones_unique')) {
|
||||
$table->unique(['person_id', 'nu', 'country_code', 'deleted_at'], 'person_phones_unique');
|
||||
}
|
||||
});
|
||||
|
||||
// Addresses: unique by (person_id, address, country, deleted_at)
|
||||
Schema::table('person_addresses', function (Blueprint $table) {
|
||||
if (!self::hasIndex('person_addresses', 'person_addresses_unique')) {
|
||||
$table->unique(['person_id', 'address', 'country', 'deleted_at'], 'person_addresses_unique');
|
||||
}
|
||||
});
|
||||
|
||||
// Contracts: unique by (client_case_id, reference, deleted_at)
|
||||
Schema::table('contracts', function (Blueprint $table) {
|
||||
if (!self::hasIndex('contracts', 'contracts_reference_unique')) {
|
||||
$table->unique(['client_case_id', 'reference', 'deleted_at'], 'contracts_reference_unique');
|
||||
}
|
||||
});
|
||||
|
||||
// Accounts: unique by (contract_id, reference, deleted_at)
|
||||
Schema::table('accounts', function (Blueprint $table) {
|
||||
if (!self::hasIndex('accounts', 'accounts_reference_unique')) {
|
||||
$table->unique(['contract_id', 'reference', 'deleted_at'], 'accounts_reference_unique');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('person', function (Blueprint $table) {
|
||||
$table->dropUnique('person_identity_unique');
|
||||
});
|
||||
Schema::table('person_phones', function (Blueprint $table) {
|
||||
$table->dropUnique('person_phones_unique');
|
||||
});
|
||||
Schema::table('person_addresses', function (Blueprint $table) {
|
||||
$table->dropUnique('person_addresses_unique');
|
||||
});
|
||||
Schema::table('contracts', function (Blueprint $table) {
|
||||
$table->dropUnique('contracts_reference_unique');
|
||||
});
|
||||
Schema::table('accounts', function (Blueprint $table) {
|
||||
$table->dropUnique('accounts_reference_unique');
|
||||
});
|
||||
}
|
||||
|
||||
private static function hasIndex(string $table, string $index): bool
|
||||
{
|
||||
// Attempt to detect index presence; if not supported, return false to try creating
|
||||
try {
|
||||
$connection = Schema::getConnection();
|
||||
$schemaManager = $connection->getDoctrineSchemaManager();
|
||||
$doctrineTable = $schemaManager->listTableDetails($table);
|
||||
return $doctrineTable->hasIndex($index);
|
||||
} catch (\Throwable $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('import_template_mappings', function (Blueprint $table) {
|
||||
$table->string('apply_mode', 10)->default('both')->after('transform'); // insert|update|both
|
||||
$table->index(['import_template_id', 'apply_mode']);
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('import_template_mappings', function (Blueprint $table) {
|
||||
if (Schema::hasColumn('import_template_mappings', 'apply_mode')) {
|
||||
$table->dropIndex(['import_template_id', 'apply_mode']);
|
||||
$table->dropColumn('apply_mode');
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('import_mappings', function (Blueprint $table) {
|
||||
$table->string('apply_mode', 10)->default('both')->after('transform');
|
||||
$table->index(['import_id', 'apply_mode']);
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('import_mappings', function (Blueprint $table) {
|
||||
if (Schema::hasColumn('import_mappings', 'apply_mode')) {
|
||||
$table->dropIndex(['import_id', 'apply_mode']);
|
||||
$table->dropColumn('apply_mode');
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('accounts', function (Blueprint $table) {
|
||||
|
||||
if (!Schema::hasColumn('accounts', 'balance_amount')) {
|
||||
|
||||
$table->decimal('balance_amount', 18, 4)->nullable()->after('description');
|
||||
$table->index('balance_amount');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('accounts', function (Blueprint $table) {
|
||||
if (Schema::hasColumn('accounts', 'balance_amount')) {
|
||||
$table->dropIndex(['balance_amount']);
|
||||
$table->dropColumn('balance_amount');
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('imports', function (Blueprint $table) {
|
||||
if (!Schema::hasColumn('imports', 'import_template_id')) {
|
||||
$table->foreignId('import_template_id')->nullable();
|
||||
}
|
||||
// Add foreign key if not exists (Postgres will error if duplicate, so wrap in try/catch in runtime, but Schema builder doesn't support conditional FKs)
|
||||
$table->foreign('import_template_id', 'imports_import_template_id_foreign')
|
||||
->references('id')->on('import_templates')->nullOnDelete();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('imports', function (Blueprint $table) {
|
||||
$table->dropForeign('imports_import_template_id_foreign');
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
// Change column type to text/longer string temporarily (nullable) to allow backfill without truncation
|
||||
$driver = DB::connection()->getDriverName();
|
||||
if ($driver === 'pgsql') {
|
||||
DB::statement('ALTER TABLE person ALTER COLUMN nu DROP NOT NULL');
|
||||
DB::statement('ALTER TABLE person ALTER COLUMN nu TYPE TEXT USING nu::text');
|
||||
} elseif ($driver === 'mysql') {
|
||||
DB::statement('ALTER TABLE person MODIFY nu VARCHAR(32) NULL');
|
||||
} else {
|
||||
// Fallback: try schema change (may require doctrine/dbal)
|
||||
Schema::table('person', function (Blueprint $table) {
|
||||
$table->string('nu', 32)->nullable()->change();
|
||||
});
|
||||
}
|
||||
|
||||
// Backfill unique 6-char alphanumeric 'nu' values
|
||||
$rows = DB::table('person')->select('id', 'nu')->orderBy('id')->get();
|
||||
$used = [];
|
||||
foreach ($rows as $row) {
|
||||
if (is_string($row->nu) && preg_match('/^[A-Za-z0-9]{6}$/', $row->nu)) {
|
||||
if (!isset($used[$row->nu])) {
|
||||
$used[$row->nu] = true;
|
||||
continue;
|
||||
}
|
||||
// duplicate will be regenerated below
|
||||
}
|
||||
// mark to regenerate
|
||||
$used[$row->nu] = false;
|
||||
}
|
||||
|
||||
$updates = [];
|
||||
foreach ($rows as $row) {
|
||||
$needsNew = true;
|
||||
if (is_string($row->nu) && preg_match('/^[A-Za-z0-9]{6}$/', $row->nu) && ($used[$row->nu] === true)) {
|
||||
// valid and unique
|
||||
$needsNew = false;
|
||||
}
|
||||
if ($needsNew) {
|
||||
do {
|
||||
$nu = Str::random(6); // [A-Za-z0-9]
|
||||
} while (isset($used[$nu]));
|
||||
$used[$nu] = true;
|
||||
$updates[] = ['id' => $row->id, 'nu' => $nu];
|
||||
}
|
||||
}
|
||||
|
||||
// Apply updates in chunks
|
||||
foreach (array_chunk($updates, 500) as $chunk) {
|
||||
foreach ($chunk as $u) {
|
||||
DB::table('person')->where('id', $u['id'])->update(['nu' => $u['nu']]);
|
||||
}
|
||||
}
|
||||
|
||||
// Add unique index and then narrow type to VARCHAR(6) and make not nullable
|
||||
Schema::table('person', function (Blueprint $table) {
|
||||
$table->unique('nu');
|
||||
});
|
||||
if ($driver === 'pgsql') {
|
||||
DB::statement('ALTER TABLE person ALTER COLUMN nu TYPE VARCHAR(6) USING nu::varchar(6)');
|
||||
DB::statement('ALTER TABLE person ALTER COLUMN nu SET NOT NULL');
|
||||
} elseif ($driver === 'mysql') {
|
||||
DB::statement('ALTER TABLE person MODIFY nu VARCHAR(6) NOT NULL');
|
||||
} else {
|
||||
Schema::table('person', function (Blueprint $table) {
|
||||
$table->string('nu', 6)->nullable(false)->change();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
// Drop unique and revert to integer (best-effort)
|
||||
Schema::table('person', function (Blueprint $table) {
|
||||
$table->dropUnique(['nu']);
|
||||
});
|
||||
$driver = DB::connection()->getDriverName();
|
||||
// Coerce values back to numeric to avoid issues on some DBs
|
||||
DB::table('person')->update(['nu' => '0']);
|
||||
if ($driver === 'pgsql') {
|
||||
DB::statement('ALTER TABLE person ALTER COLUMN nu TYPE BIGINT USING nu::bigint');
|
||||
DB::statement('ALTER TABLE person ALTER COLUMN nu SET DEFAULT 0');
|
||||
DB::statement('ALTER TABLE person ALTER COLUMN nu SET NOT NULL');
|
||||
} elseif ($driver === 'mysql') {
|
||||
DB::statement('ALTER TABLE person MODIFY nu BIGINT UNSIGNED NOT NULL DEFAULT 0');
|
||||
} else {
|
||||
Schema::table('person', function (Blueprint $table) {
|
||||
$table->unsignedBigInteger('nu')->default(0)->change();
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('documents', function (Blueprint $table) {
|
||||
$table->string('preview_path', 2048)->nullable()->after('path');
|
||||
$table->string('preview_mime', 100)->nullable()->after('preview_path');
|
||||
$table->timestamp('preview_generated_at')->nullable()->after('preview_mime');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('documents', function (Blueprint $table) {
|
||||
$table->dropColumn(['preview_path', 'preview_mime', 'preview_generated_at']);
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('import_mappings', function (Blueprint $table) {
|
||||
if (!Schema::hasColumn('import_mappings', 'position')) {
|
||||
$table->unsignedInteger('position')->nullable()->after('options');
|
||||
}
|
||||
$table->index(['import_id', 'position']);
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('import_mappings', function (Blueprint $table) {
|
||||
if (Schema::hasColumn('import_mappings', 'position')) {
|
||||
$table->dropIndex(['import_id', 'position']);
|
||||
$table->dropColumn('position');
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('import_mappings', function (Blueprint $table) {
|
||||
if (!Schema::hasColumn('import_mappings', 'entity')) {
|
||||
$table->string('entity', 64)->nullable()->after('import_id');
|
||||
}
|
||||
$table->index(['import_id', 'entity']);
|
||||
});
|
||||
|
||||
// Backfill entity from target_field's first segment where possible
|
||||
DB::table('import_mappings')->orderBy('id')->chunkById(1000, function ($rows) {
|
||||
foreach ($rows as $row) {
|
||||
if (!empty($row->entity)) continue;
|
||||
$entity = null;
|
||||
if (!empty($row->target_field)) {
|
||||
$parts = explode('.', $row->target_field);
|
||||
$record = $parts[0] ?? null;
|
||||
if ($record) {
|
||||
// Map record segment to UI entity key
|
||||
$map = [
|
||||
'person' => 'person',
|
||||
'address' => 'person_addresses',
|
||||
'phone' => 'person_phones',
|
||||
'email' => 'emails',
|
||||
'account' => 'accounts',
|
||||
'contract' => 'contracts',
|
||||
];
|
||||
$entity = $map[$record] ?? $record;
|
||||
}
|
||||
}
|
||||
if ($entity) {
|
||||
DB::table('import_mappings')->where('id', $row->id)->update(['entity' => $entity]);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('import_mappings', function (Blueprint $table) {
|
||||
if (Schema::hasColumn('import_mappings', 'entity')) {
|
||||
// drop composite index if exists
|
||||
try { $table->dropIndex(['import_id', 'entity']); } catch (\Throwable $e) { /* ignore */ }
|
||||
$table->dropColumn('entity');
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('import_template_mappings', function (Blueprint $table) {
|
||||
if (!Schema::hasColumn('import_template_mappings', 'entity')) {
|
||||
$table->string('entity', 64)->nullable()->after('import_template_id');
|
||||
}
|
||||
$table->index(['import_template_id', 'entity']);
|
||||
});
|
||||
|
||||
// Backfill entity from target_field first segment
|
||||
DB::table('import_template_mappings')->orderBy('id')->chunkById(1000, function ($rows) {
|
||||
foreach ($rows as $row) {
|
||||
if (!empty($row->entity)) continue;
|
||||
$entity = null;
|
||||
if (!empty($row->target_field)) {
|
||||
$parts = explode('.', $row->target_field);
|
||||
$record = $parts[0] ?? null;
|
||||
if ($record) {
|
||||
$map = [
|
||||
'person' => 'person',
|
||||
'address' => 'person_addresses',
|
||||
'phone' => 'person_phones',
|
||||
'email' => 'emails',
|
||||
'account' => 'accounts',
|
||||
'contract' => 'contracts',
|
||||
];
|
||||
$entity = $map[$record] ?? $record;
|
||||
}
|
||||
}
|
||||
if ($entity) {
|
||||
DB::table('import_template_mappings')->where('id', $row->id)->update(['entity' => $entity]);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('import_template_mappings', function (Blueprint $table) {
|
||||
if (Schema::hasColumn('import_template_mappings', 'entity')) {
|
||||
try { $table->dropIndex(['import_template_id', 'entity']); } catch (\Throwable $e) { /* ignore */ }
|
||||
$table->dropColumn('entity');
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user