feat: Add financial models and seeders
This commit is contained in:
parent
04230e5d1b
commit
635cde021b
|
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
|
||||
namespace App\Enums;
|
||||
|
||||
enum AccountType: string
|
||||
{
|
||||
case Checking = 'checking';
|
||||
case CreditCard = 'credit_card';
|
||||
case Loan = 'loan';
|
||||
case Savings = 'savings';
|
||||
case Others = 'others';
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
|
||||
namespace App\Enums;
|
||||
|
||||
enum AccountType: string
|
||||
{
|
||||
case Checking = 'checking';
|
||||
case CreditCard = 'credit_card';
|
||||
case Loan = 'loan';
|
||||
case Savings = 'savings';
|
||||
case Others = 'others';
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Enums\AccountType;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
class Account extends Model
|
||||
{
|
||||
/** @use HasFactory<\Database\Factories\AccountFactory> */
|
||||
use HasFactory, SoftDeletes;
|
||||
|
||||
protected $fillable = [
|
||||
'user_id',
|
||||
'name',
|
||||
'name_iv',
|
||||
'bank_id',
|
||||
'currency_code',
|
||||
'type',
|
||||
];
|
||||
|
||||
protected function casts(): array
|
||||
{
|
||||
return [
|
||||
'type' => AccountType::class,
|
||||
];
|
||||
}
|
||||
|
||||
public function user(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class);
|
||||
}
|
||||
|
||||
public function bank(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Bank::class);
|
||||
}
|
||||
|
||||
public function transactions(): HasMany
|
||||
{
|
||||
return $this->hasMany(Transaction::class);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
class Bank extends Model
|
||||
{
|
||||
/** @use HasFactory<\Database\Factories\BankFactory> */
|
||||
use HasFactory, SoftDeletes;
|
||||
|
||||
protected $fillable = [
|
||||
'name',
|
||||
'name_iv',
|
||||
'logo',
|
||||
];
|
||||
|
||||
public function accounts(): HasMany
|
||||
{
|
||||
return $this->hasMany(Account::class);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
class Category extends Model
|
||||
{
|
||||
/** @use HasFactory<\Database\Factories\CategoryFactory> */
|
||||
use HasFactory, SoftDeletes;
|
||||
|
||||
protected $fillable = [
|
||||
'name',
|
||||
'icon',
|
||||
'color',
|
||||
'user_id',
|
||||
];
|
||||
|
||||
public function user(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class);
|
||||
}
|
||||
|
||||
public function transactions(): HasMany
|
||||
{
|
||||
return $this->hasMany(Transaction::class);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class Transaction extends Model
|
||||
{
|
||||
/** @use HasFactory<\Database\Factories\TransactionFactory> */
|
||||
use HasFactory;
|
||||
|
||||
protected $fillable = [
|
||||
'user_id',
|
||||
'account_id',
|
||||
'category_id',
|
||||
'description',
|
||||
'description_iv',
|
||||
'transaction_date',
|
||||
'amount',
|
||||
'currency_code',
|
||||
'notes',
|
||||
'notes_iv',
|
||||
];
|
||||
|
||||
protected function casts(): array
|
||||
{
|
||||
return [
|
||||
'transaction_date' => 'date',
|
||||
'amount' => 'decimal:2',
|
||||
];
|
||||
}
|
||||
|
||||
public function user(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class);
|
||||
}
|
||||
|
||||
public function account(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Account::class);
|
||||
}
|
||||
|
||||
public function category(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Category::class);
|
||||
}
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@ namespace App\Models;
|
|||
|
||||
// use Illuminate\Contracts\Auth\MustVerifyEmail;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Database\Eloquent\Relations\HasOne;
|
||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
|
|
@ -56,4 +57,19 @@ class User extends Authenticatable
|
|||
{
|
||||
return $this->hasOne(EncryptedMessage::class);
|
||||
}
|
||||
|
||||
public function transactions(): HasMany
|
||||
{
|
||||
return $this->hasMany(Transaction::class);
|
||||
}
|
||||
|
||||
public function accounts(): HasMany
|
||||
{
|
||||
return $this->hasMany(Account::class);
|
||||
}
|
||||
|
||||
public function categories(): HasMany
|
||||
{
|
||||
return $this->hasMany(Category::class);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Enums\AccountType;
|
||||
use App\Models\Bank;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Account>
|
||||
*/
|
||||
class AccountFactory extends Factory
|
||||
{
|
||||
/**
|
||||
* Define the model's default state.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
'user_id' => User::factory(),
|
||||
'name' => fake()->words(2, true).' Account',
|
||||
'name_iv' => fake()->regexify('[A-Za-z0-9]{16}'),
|
||||
'bank_id' => Bank::factory(),
|
||||
'currency_code' => fake()->randomElement(['USD', 'EUR', 'GBP', 'JPY']),
|
||||
'type' => fake()->randomElement(AccountType::cases()),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Bank>
|
||||
*/
|
||||
class BankFactory extends Factory
|
||||
{
|
||||
/**
|
||||
* Define the model's default state.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
'name' => fake()->company(),
|
||||
'name_iv' => fake()->regexify('[A-Za-z0-9]{16}'),
|
||||
'logo' => fake()->imageUrl(200, 200, 'business'),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Category>
|
||||
*/
|
||||
class CategoryFactory extends Factory
|
||||
{
|
||||
/**
|
||||
* Define the model's default state.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
'name' => fake()->randomElement(['Food', 'Transport', 'Entertainment', 'Shopping', 'Healthcare', 'Utilities', 'Travel', 'Education']),
|
||||
'icon' => fake()->randomElement(['🍔', '🚗', '🎮', '🛒', '💊', '💡', '✈️', '📚']),
|
||||
'color' => fake()->hexColor(),
|
||||
'user_id' => User::factory(),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\Account;
|
||||
use App\Models\Category;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Transaction>
|
||||
*/
|
||||
class TransactionFactory extends Factory
|
||||
{
|
||||
/**
|
||||
* Define the model's default state.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
'user_id' => User::factory(),
|
||||
'account_id' => Account::factory(),
|
||||
'category_id' => Category::factory(),
|
||||
'description' => fake()->sentence(),
|
||||
'description_iv' => fake()->regexify('[A-Za-z0-9]{16}'),
|
||||
'transaction_date' => fake()->dateTimeBetween('-1 year', 'now'),
|
||||
'amount' => fake()->randomFloat(2, -1000, 1000),
|
||||
'currency_code' => fake()->randomElement(['USD', 'EUR', 'GBP', 'JPY']),
|
||||
'notes' => fake()->optional()->paragraph(),
|
||||
'notes_iv' => fake()->optional()->regexify('[A-Za-z0-9]{16}'),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
<?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('banks', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->text('name');
|
||||
$table->string('name_iv', 16);
|
||||
$table->string('logo')->nullable();
|
||||
$table->timestamps();
|
||||
$table->softDeletes();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('banks');
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
<?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('accounts', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('user_id')->constrained()->onDelete('cascade');
|
||||
$table->text('name');
|
||||
$table->string('name_iv', 16);
|
||||
$table->foreignId('bank_id')->constrained()->onDelete('cascade');
|
||||
$table->string('currency_code', 3);
|
||||
$table->string('type');
|
||||
$table->timestamps();
|
||||
$table->softDeletes();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('accounts');
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
<?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('categories', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('name');
|
||||
$table->string('icon')->nullable();
|
||||
$table->string('color')->nullable();
|
||||
$table->foreignId('user_id')->constrained()->onDelete('cascade');
|
||||
$table->timestamps();
|
||||
$table->softDeletes();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('categories');
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
<?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('transactions', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('user_id')->constrained()->onDelete('cascade');
|
||||
$table->foreignId('account_id')->constrained()->onDelete('cascade');
|
||||
$table->foreignId('category_id')->constrained()->onDelete('cascade');
|
||||
$table->text('description');
|
||||
$table->string('description_iv', 16);
|
||||
$table->date('transaction_date');
|
||||
$table->decimal('amount', 15, 2);
|
||||
$table->string('currency_code', 3);
|
||||
$table->text('notes')->nullable();
|
||||
$table->string('notes_iv', 16)->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('transactions');
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Enums\AccountType;
|
||||
use App\Models\Account;
|
||||
use App\Models\Bank;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class AccountSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
$users = User::all();
|
||||
$banks = Bank::all();
|
||||
|
||||
if ($users->isEmpty() || $banks->isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($users as $user) {
|
||||
Account::create([
|
||||
'user_id' => $user->id,
|
||||
'name' => 'Main Checking',
|
||||
'name_iv' => fake()->regexify('[A-Za-z0-9]{16}'),
|
||||
'bank_id' => $banks->random()->id,
|
||||
'currency_code' => 'USD',
|
||||
'type' => AccountType::Checking,
|
||||
]);
|
||||
|
||||
Account::create([
|
||||
'user_id' => $user->id,
|
||||
'name' => 'Savings Account',
|
||||
'name_iv' => fake()->regexify('[A-Za-z0-9]{16}'),
|
||||
'bank_id' => $banks->random()->id,
|
||||
'currency_code' => 'USD',
|
||||
'type' => AccountType::Savings,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Models\Bank;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class BankSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
$banks = [
|
||||
['name' => 'Chase', 'logo' => null],
|
||||
['name' => 'Bank of America', 'logo' => null],
|
||||
['name' => 'Wells Fargo', 'logo' => null],
|
||||
['name' => 'Citibank', 'logo' => null],
|
||||
['name' => 'US Bank', 'logo' => null],
|
||||
];
|
||||
|
||||
foreach ($banks as $bank) {
|
||||
Bank::create([
|
||||
'name' => $bank['name'],
|
||||
'name_iv' => fake()->regexify('[A-Za-z0-9]{16}'),
|
||||
'logo' => $bank['logo'],
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Models\Category;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class CategorySeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
$users = User::all();
|
||||
|
||||
if ($users->isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$categories = [
|
||||
['name' => 'Food & Dining', 'icon' => '🍔', 'color' => '#FF6B6B'],
|
||||
['name' => 'Transportation', 'icon' => '🚗', 'color' => '#4ECDC4'],
|
||||
['name' => 'Entertainment', 'icon' => '🎮', 'color' => '#95E1D3'],
|
||||
['name' => 'Shopping', 'icon' => '🛒', 'color' => '#F38181'],
|
||||
['name' => 'Healthcare', 'icon' => '💊', 'color' => '#AA96DA'],
|
||||
['name' => 'Utilities', 'icon' => '💡', 'color' => '#FCBAD3'],
|
||||
['name' => 'Travel', 'icon' => '✈️', 'color' => '#FFFFD2'],
|
||||
['name' => 'Education', 'icon' => '📚', 'color' => '#A8D8EA'],
|
||||
];
|
||||
|
||||
foreach ($users as $user) {
|
||||
foreach ($categories as $category) {
|
||||
Category::create([
|
||||
'name' => $category['name'],
|
||||
'icon' => $category['icon'],
|
||||
'color' => $category['color'],
|
||||
'user_id' => $user->id,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Models\Account;
|
||||
use App\Models\Category;
|
||||
use App\Models\Transaction;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class TransactionSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
$users = User::all();
|
||||
$accounts = Account::all();
|
||||
$categories = Category::all();
|
||||
|
||||
if ($users->isEmpty() || $accounts->isEmpty() || $categories->isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($accounts->take(5) as $account) {
|
||||
for ($i = 0; $i < 10; $i++) {
|
||||
Transaction::create([
|
||||
'user_id' => $users->random()->id,
|
||||
'account_id' => $account->id,
|
||||
'category_id' => $categories->random()->id,
|
||||
'description' => fake()->sentence(),
|
||||
'description_iv' => fake()->regexify('[A-Za-z0-9]{16}'),
|
||||
'transaction_date' => fake()->dateTimeBetween('-3 months', 'now'),
|
||||
'amount' => fake()->randomFloat(2, -500, 500),
|
||||
'currency_code' => 'USD',
|
||||
'notes' => fake()->optional(0.3)->paragraph(),
|
||||
'notes_iv' => fake()->optional(0.3)->regexify('[A-Za-z0-9]{16}'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue