Feat: Adds multi currency support (#88)
This commit is contained in:
@@ -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');
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user