Feat: Adds multi currency support (#88)

This commit is contained in:
hackerESQ
2025-04-09 19:25:15 -05:00
committed by GitHub
parent 6d6f968f42
commit eae345f243
100 changed files with 17735 additions and 35761 deletions
@@ -21,6 +21,7 @@ return new class extends Migration
$table->string('password');
$table->rememberToken();
$table->string('profile_photo_path', 2048)->nullable();
$table->boolean('admin')->nullable();
$table->timestamps();
});
@@ -38,6 +39,5 @@ return new class extends Migration
{
Schema::dropIfExists('users');
Schema::dropIfExists('password_reset_tokens');
Schema::dropIfExists('sessions');
}
};
@@ -2,10 +2,8 @@
declare(strict_types=1);
use Database\Seeders\MarketDataSeeder;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Schema;
class CreateMarketDataTable extends Migration
@@ -34,10 +32,6 @@ class CreateMarketDataTable extends Migration
$table->timestamps();
});
Artisan::call('db:seed', [
'--class' => MarketDataSeeder::class,
'--force' => true,
]);
}
/**
@@ -20,10 +20,6 @@ class CreateDailyChangeTable extends Migration
$table->date('date');
$table->foreignIdFor(Portfolio::class, 'portfolio_id')->constrained()->onDelete('cascade');
$table->float('total_market_value', 12, 4)->nullable();
$table->float('total_cost_basis', 12, 4)->nullable();
$table->float('total_gain', 12, 4)->nullable();
$table->float('total_dividends_earned', 12, 4)->nullable();
$table->float('realized_gains', 12, 4)->nullable();
$table->text('annotation')->nullable();
$table->primary(['date', 'portfolio_id']);
@@ -1,30 +0,0 @@
<?php
declare(strict_types=1);
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('users', function (Blueprint $table) {
$table->boolean('admin')->nullable()->after('profile_photo_path');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('users', function (Blueprint $table) {
$table->dropColumn('admin');
});
}
};
@@ -0,0 +1,164 @@
<?php
declare(strict_types=1);
use App\Models\CurrencyRate;
use App\Models\Transaction;
use Database\Seeders\CurrencySeeder;
use Database\Seeders\MarketDataSeeder;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
/**
* Add options column to users table
*/
Schema::table('users', function (Blueprint $table) {
$table->json('options')->default(json_encode([
'locale' => config('app.locale', 'en'),
'display_currency' => config('investbrain.base_currency', 'USD'),
]))->after('profile_photo_path');
});
/**
* Add _base and currency column to market_data table
*/
Schema::table('market_data', function (Blueprint $table) {
$table->float('market_value_base', 12, 4)->nullable()->after('market_value');
$table->string('currency', 3)->default(config('investbrain.base_currency'))->after('market_value');
});
DB::table('market_data')->update([
'market_value_base' => DB::raw('market_value'),
]);
/**
* Add _base columns to transactions table
*/
Schema::table('transactions', function (Blueprint $table) {
$table->float('cost_basis_base', 12, 4)->nullable()->after('sale_price');
$table->float('sale_price_base', 12, 4)->nullable()->after('cost_basis_base');
});
DB::table('transactions')->update([
'cost_basis_base' => DB::raw('cost_basis'),
'sale_price_base' => DB::raw('sale_price'),
]);
Schema::table('transactions', function (Blueprint $table) {
$table->float('cost_basis_base', 12, 4)->nullable(false)->change();
});
/**
* Add _base columns to dividends table
*/
Schema::table('dividends', function (Blueprint $table) {
$table->float('dividend_amount_base', 12, 4)->nullable()->after('dividend_amount');
});
DB::table('dividends')->update([
'dividend_amount_base' => DB::raw('dividend_amount'),
]);
Schema::table('dividends', function (Blueprint $table) {
$table->float('dividend_amount_base', 12, 4)->nullable(false)->change();
});
/**
* Creates currencies table
*/
Schema::create('currencies', function (Blueprint $table) {
$table->string('currency', 3)->primary(); // ISO 4217
$table->string('label');
$table->timestamps();
});
/**
* Creates currency rates table
*/
Schema::create('currency_rates', function (Blueprint $table) {
$table->date('date');
$table->string('currency', 3);
$table->float('rate', 12, 4);
$table->timestamps();
$table->primary(['date', 'currency']);
});
if (config('app.env') != 'testing') {
Artisan::call('db:seed', [
'--class' => CurrencySeeder::class,
'--force' => true,
]);
CurrencyRate::timeSeriesRates(
'', // use fake currency to force
Transaction::min('date')
);
CurrencyRate::refreshCurrencyData();
Artisan::call('db:seed', [
'--class' => MarketDataSeeder::class,
'--force' => true,
]);
}
/**
* Cleanup daily change table
*/
if (Schema::hasColumn('daily_change', 'total_cost_basis')) {
Schema::table('daily_change', function (Blueprint $table) {
$table->dropColumn('total_cost_basis');
});
}
if (Schema::hasColumn('daily_change', 'total_gain')) {
Schema::table('daily_change', function (Blueprint $table) {
$table->dropColumn('total_gain');
});
}
if (Schema::hasColumn('daily_change', 'total_dividends_earned')) {
Schema::table('daily_change', function (Blueprint $table) {
$table->dropColumn('total_dividends_earned');
});
}
if (Schema::hasColumn('daily_change', 'realized_gains')) {
Schema::table('daily_change', function (Blueprint $table) {
$table->dropColumn('realized_gains');
});
}
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('users', function (Blueprint $table) {
$table->dropColumn('options');
});
Schema::table('market_data', function (Blueprint $table) {
$table->dropColumn('currency');
$table->dropColumn('market_value_base');
});
Schema::table('transactions', function (Blueprint $table) {
$table->dropColumn('cost_basis_base');
$table->dropColumn('sale_price_base');
});
Schema::table('dividends', function (Blueprint $table) {
$table->dropColumn('dividend_amount_base');
});
Schema::dropIfExists('currencies');
Schema::dropIfExists('currency_rates');
}
};