added option to import payments from csv file

This commit is contained in:
Simon Pocrnjič
2025-10-02 22:09:05 +02:00
parent 971a9e89d1
commit 12de0186cf
21 changed files with 2828 additions and 824 deletions
@@ -0,0 +1,52 @@
<?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('payments', function (Blueprint $table): void {
// Add new decimal column next to amount_cents temporarily for safe backfill
if (! Schema::hasColumn('payments', 'amount')) {
$table->decimal('amount', 20, 4)->nullable()->after('account_id');
}
});
// Backfill amount from amount_cents if present
if (Schema::hasColumn('payments', 'amount_cents')) {
DB::statement('UPDATE payments SET amount = CASE WHEN amount_cents IS NOT NULL THEN amount_cents / 100.0 ELSE amount END');
}
// Make amount non-null if desired; keeping nullable to avoid breaking existing rows
// Drop amount_cents column
Schema::table('payments', function (Blueprint $table): void {
if (Schema::hasColumn('payments', 'amount_cents')) {
$table->dropColumn('amount_cents');
}
});
}
public function down(): void
{
// Recreate amount_cents and backfill from amount, then drop amount
Schema::table('payments', function (Blueprint $table): void {
if (! Schema::hasColumn('payments', 'amount_cents')) {
$table->integer('amount_cents')->nullable()->after('account_id');
}
});
if (Schema::hasColumn('payments', 'amount')) {
DB::statement('UPDATE payments SET amount_cents = CASE WHEN amount IS NOT NULL THEN ROUND(amount * 100) ELSE amount_cents END');
}
Schema::table('payments', function (Blueprint $table): void {
if (Schema::hasColumn('payments', 'amount')) {
$table->dropColumn('amount');
}
});
}
};
@@ -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('payments', function (Blueprint $table): void {
if (! Schema::hasColumn('payments', 'balance_before')) {
$table->decimal('balance_before', 20, 4)->nullable()->after('amount');
}
});
}
public function down(): void
{
Schema::table('payments', function (Blueprint $table): void {
if (Schema::hasColumn('payments', 'balance_before')) {
$table->dropColumn('balance_before');
}
});
}
};
@@ -0,0 +1,41 @@
<?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('payments', function (Blueprint $table): void {
if (! $this->hasUniqueIndex('payments', 'payments_account_id_reference_unique')) {
$table->unique(['account_id', 'reference'], 'payments_account_id_reference_unique');
}
});
}
public function down(): void
{
Schema::table('payments', function (Blueprint $table): void {
if ($this->hasUniqueIndex('payments', 'payments_account_id_reference_unique')) {
$table->dropUnique('payments_account_id_reference_unique');
}
});
}
private function hasUniqueIndex(string $table, string $indexName): bool
{
// Works for both SQLite and others by checking existing indexes from connection schema manager when available.
try {
$connection = Schema::getConnection();
$schemaManager = $connection->getDoctrineSchemaManager();
$indexes = $schemaManager->listTableIndexes($table);
return array_key_exists($indexName, $indexes);
} catch (\Throwable $e) {
// Fallback: attempt dropping/creating blindly in migration operations
return false;
}
}
};
@@ -0,0 +1,58 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
$driver = DB::getDriverName();
if ($driver === 'pgsql') {
// Drop constraint if exists (covers both constraint-created and index-created uniqueness)
try {
DB::statement('ALTER TABLE payments DROP CONSTRAINT IF EXISTS payments_account_id_reference_unique');
} catch (\Throwable $e) {
// ignore
}
// Drop index if exists
try {
DB::statement('DROP INDEX IF EXISTS payments_account_id_reference_unique');
} catch (\Throwable $e) {
// ignore
}
// Create a partial unique index that ignores soft-deleted rows, use a new name
DB::statement('CREATE UNIQUE INDEX IF NOT EXISTS uniq_payments_account_reference_not_deleted ON payments (account_id, reference) WHERE deleted_at IS NULL');
} else {
// Fallback for other drivers: ensure a regular unique index exists (no partial support)
Schema::table('payments', function ($table): void {
try {
$table->unique(['account_id', 'reference'], 'payments_account_id_reference_unique');
} catch (\Throwable $e) {
// ignore if already exists
}
});
}
}
public function down(): void
{
$driver = DB::getDriverName();
if ($driver === 'pgsql') {
DB::statement('DROP INDEX IF EXISTS uniq_payments_account_reference_not_deleted');
// Recreate a standard unique index (non-partial) with the original name
DB::statement('CREATE UNIQUE INDEX IF NOT EXISTS payments_account_id_reference_unique ON payments (account_id, reference)');
} else {
// For other drivers, nothing special beyond ensuring the standard index exists
Schema::table('payments', function ($table): void {
try {
$table->unique(['account_id', 'reference'], 'payments_account_id_reference_unique');
} catch (\Throwable $e) {
// ignore
}
});
}
}
};