@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\{DB,Schema};
|
||||
|
||||
return new class extends Migration {
|
||||
public function up():void
|
||||
{
|
||||
if(!in_array(DB::getDriverName(),['pgsql','sqlite'],true))throw new LogicException('SGF dispatch schema requires PostgreSQL/SQLite.');
|
||||
Schema::create('sgf_invoice_dispatches',function(Blueprint $t){
|
||||
$t->id();$t->foreignId('tenant_id')->constrained('tenants')->restrictOnDelete();
|
||||
$t->foreignId('supplier_id')->constrained('suppliers')->restrictOnDelete();
|
||||
$t->string('reference',120);$t->string('number',100);$t->string('connection_id',64);$t->string('mapping_id',64);
|
||||
$t->json('mapping_snapshot');$t->char('mapping_hash',64);$t->json('document');$t->text('reason');
|
||||
$t->unsignedInteger('source_version')->default(1);$t->unsignedInteger('version')->default(1);
|
||||
$t->string('phase',32)->default('draft');$t->boolean('ever_sending')->default(false);
|
||||
$t->text('state_ciphertext')->nullable();$t->char('approval_hash',64)->nullable();
|
||||
$t->foreignId('preview_actor_id')->nullable()->constrained('users')->restrictOnDelete();$t->char('source_context_hash',64)->nullable();
|
||||
$t->uuid('operation_key')->nullable()->unique();$t->uuid('lease_id')->nullable();$t->timestamp('lease_until')->nullable();
|
||||
$t->json('receipt')->nullable();$t->foreignId('created_by')->constrained('users')->restrictOnDelete();$t->timestamps();
|
||||
$t->unique(['tenant_id','reference']);$t->unique(['tenant_id','supplier_id','number'],'sgf_dispatch_document_unique');
|
||||
$t->index(['tenant_id','id']);$t->index(['tenant_id','phase','id']);
|
||||
});
|
||||
Schema::create('sgf_invoice_dispatch_events',function(Blueprint $t){
|
||||
$t->id();$t->foreignId('dispatch_id')->constrained('sgf_invoice_dispatches')->restrictOnDelete();
|
||||
$t->foreignId('tenant_id')->constrained('tenants')->restrictOnDelete();$t->unsignedInteger('version');
|
||||
$t->foreignId('actor_id')->constrained('users')->restrictOnDelete();$t->string('action',40);$t->text('reason');
|
||||
$t->json('before_state')->nullable();$t->json('after_state');$t->timestamp('created_at');
|
||||
$t->unique(['dispatch_id','version']);$t->index(['tenant_id','dispatch_id','id']);
|
||||
});
|
||||
if(DB::getDriverName()==='pgsql'){
|
||||
DB::unprepared("CREATE FUNCTION sgf_dispatch_preserve() RETURNS trigger LANGUAGE plpgsql AS \$\$ BEGIN RAISE EXCEPTION 'Preserve SGF dispatch audit/history'; END; \$\$;");
|
||||
DB::unprepared('CREATE TRIGGER sgf_dispatch_event_immutable BEFORE UPDATE OR DELETE ON sgf_invoice_dispatch_events FOR EACH ROW EXECUTE FUNCTION sgf_dispatch_preserve()');
|
||||
DB::unprepared('CREATE TRIGGER sgf_dispatch_no_delete BEFORE DELETE ON sgf_invoice_dispatches FOR EACH ROW EXECUTE FUNCTION sgf_dispatch_preserve()');
|
||||
}elseif(DB::getDriverName()==='sqlite'){
|
||||
foreach(['UPDATE','DELETE']as$action)DB::unprepared("CREATE TRIGGER sgf_dispatch_events_".strtolower($action)." BEFORE $action ON sgf_invoice_dispatch_events BEGIN SELECT RAISE(ABORT,'Preserve SGF dispatch audit'); END");
|
||||
DB::unprepared("CREATE TRIGGER sgf_dispatch_no_delete BEFORE DELETE ON sgf_invoice_dispatches BEGIN SELECT RAISE(ABORT,'Preserve SGF dispatch history'); END");
|
||||
}else throw new LogicException('SGF dispatch schema validated only for PostgreSQL/SQLite.');
|
||||
}
|
||||
public function down():void
|
||||
{
|
||||
Schema::dropIfExists('sgf_invoice_dispatch_events');Schema::dropIfExists('sgf_invoice_dispatches');
|
||||
if(DB::getDriverName()==='pgsql')DB::unprepared('DROP FUNCTION IF EXISTS sgf_dispatch_preserve()');
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user