mirror of
https://github.com/henry4682/finance_app.git
synced 2026-07-16 00:10:00 +00:00
feat: 前端分離+功能api化
1. 新增資產管理CRUD、googleOAuth登入 2. 更改原記帳controller
This commit is contained in:
54
app/Models/Account.php
Normal file
54
app/Models/Account.php
Normal file
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Account extends Model
|
||||
{
|
||||
protected $fillable = [
|
||||
'user_id',
|
||||
'name',
|
||||
'type',
|
||||
'currency',
|
||||
'balance',
|
||||
'note',
|
||||
'billing_day',
|
||||
'payment_day',
|
||||
];
|
||||
|
||||
public function user()
|
||||
{
|
||||
return $this->belongsTo(User::class);
|
||||
}
|
||||
|
||||
public function holdings()
|
||||
{
|
||||
return $this->hasMany(InvestmentHolding::class);
|
||||
}
|
||||
|
||||
public function expenses()
|
||||
{
|
||||
return $this->hasMany(Expense::class);
|
||||
}
|
||||
|
||||
public function unpaidAmount()
|
||||
{
|
||||
$billingDay = $this->billing_day ?? 1;
|
||||
|
||||
$now = now();
|
||||
|
||||
// 如果今天還沒到結帳日,帳單週期是上個月結帳日到這個月結帳日
|
||||
if ($now->day < $billingDay) {
|
||||
$start = $now->copy()->subMonth()->setDay($billingDay);
|
||||
$end = $now->copy()->setDay($billingDay)->subDay();
|
||||
} else {
|
||||
$start = $now->copy()->setDay($billingDay);
|
||||
$end = $now->copy()->addMonth()->setDay($billingDay)->subDay();
|
||||
}
|
||||
|
||||
return $this->expenses()
|
||||
->whereBetween('date', [$start->toDateString(), $end->toDateString()])
|
||||
->sum('amount');
|
||||
}
|
||||
}
|
||||
10
app/Models/AccountRule.php
Normal file
10
app/Models/AccountRule.php
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class AccountRule extends Model
|
||||
{
|
||||
//
|
||||
}
|
||||
@@ -7,18 +7,18 @@ use Illuminate\Database\Eloquent\Model;
|
||||
class Expense extends Model
|
||||
{
|
||||
protected $fillable = [
|
||||
'user_id',
|
||||
'category_id',
|
||||
'subcategory_id',
|
||||
'type',
|
||||
'amount',
|
||||
'note',
|
||||
'date',
|
||||
'invoice_number',
|
||||
'seller_name',
|
||||
'item_name',
|
||||
'external_id',
|
||||
];
|
||||
'user_id',
|
||||
'amount',
|
||||
'category_id',
|
||||
'item_name',
|
||||
'date',
|
||||
'note',
|
||||
'seller_name',
|
||||
'account_id',
|
||||
'is_amortized',
|
||||
'period_start',
|
||||
'period_end',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'date' => 'date:Y-m-d',
|
||||
@@ -39,4 +39,9 @@ class Expense extends Model
|
||||
{
|
||||
return $this->belongsTo(Category::class, 'subcategory_id');
|
||||
}
|
||||
|
||||
public function account()
|
||||
{
|
||||
return $this->belongsTo(Account::class);
|
||||
}
|
||||
}
|
||||
|
||||
32
app/Models/InvestmentHolding.php
Normal file
32
app/Models/InvestmentHolding.php
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class InvestmentHolding extends Model
|
||||
{
|
||||
protected $fillable = [
|
||||
'account_id',
|
||||
'type',
|
||||
'symbol',
|
||||
'name',
|
||||
'shares',
|
||||
'avg_cost',
|
||||
];
|
||||
|
||||
public function account()
|
||||
{
|
||||
return $this->belongsTo(Account::class);
|
||||
}
|
||||
|
||||
public function transactions()
|
||||
{
|
||||
return $this->hasMany(InvestmentTransaction::class, 'holding_id');
|
||||
}
|
||||
|
||||
public function security()
|
||||
{
|
||||
return $this->hasOne(Security::class, 'code', 'symbol');
|
||||
}
|
||||
}
|
||||
30
app/Models/InvestmentTransaction.php
Normal file
30
app/Models/InvestmentTransaction.php
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class InvestmentTransaction extends Model
|
||||
{
|
||||
protected $fillable = [
|
||||
'holding_id',
|
||||
'action',
|
||||
'shares',
|
||||
'price',
|
||||
'fee',
|
||||
'tax',
|
||||
'traded_at',
|
||||
'note',
|
||||
'amount', // 實際投入金額(基金用)
|
||||
'nav', // 淨值(基金用)
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'traded_at' => 'date',
|
||||
];
|
||||
|
||||
public function holding()
|
||||
{
|
||||
return $this->belongsTo(InvestmentHolding::class, 'holding_id');
|
||||
}
|
||||
}
|
||||
33
app/Models/Security.php
Normal file
33
app/Models/Security.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Security extends Model
|
||||
{
|
||||
protected $fillable = [
|
||||
'code',
|
||||
'type',
|
||||
'source',
|
||||
'name',
|
||||
'latest_price',
|
||||
'latest_price_at',
|
||||
'change_amount',
|
||||
'change_rate',
|
||||
'meta',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'latest_price_at' => 'datetime',
|
||||
'latest_price' => 'decimal:4',
|
||||
'change_amount' => 'decimal:4',
|
||||
'change_rate' => 'decimal:4',
|
||||
'meta' => 'array',
|
||||
];
|
||||
|
||||
public function historicPrices()
|
||||
{
|
||||
return $this->hasMany(SecurityPriceHistories::class, 'security_id', 'id');
|
||||
}
|
||||
}
|
||||
29
app/Models/SecurityPriceHistories.php
Normal file
29
app/Models/SecurityPriceHistories.php
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class SecurityPriceHistories extends Model
|
||||
{
|
||||
protected $fillable = [
|
||||
'id',
|
||||
'security_id',
|
||||
'price_date',
|
||||
'price',
|
||||
'change_amount',
|
||||
'change_rate',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'price' => 'decimal:4',
|
||||
'price_date' => 'datetime',
|
||||
'change_amount' => 'decimal:4',
|
||||
'change_rate' => 'decimal:4',
|
||||
];
|
||||
|
||||
public function security()
|
||||
{
|
||||
return $this->belongsTo(Security::class, 'security_id', 'id');
|
||||
}
|
||||
}
|
||||
@@ -5,12 +5,14 @@ namespace App\Models;
|
||||
// use Illuminate\Contracts\Auth\MustVerifyEmail;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||
use App\Models\Account;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
use Laravel\Sanctum\HasApiTokens;
|
||||
|
||||
class User extends Authenticatable
|
||||
{
|
||||
/** @use HasFactory<\Database\Factories\UserFactory> */
|
||||
use HasFactory, Notifiable;
|
||||
use HasFactory, Notifiable, HasApiTokens;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
@@ -21,6 +23,11 @@ class User extends Authenticatable
|
||||
'name',
|
||||
'email',
|
||||
'password',
|
||||
'google_id',
|
||||
'avatar',
|
||||
'google_access_token',
|
||||
'google_refresh_token',
|
||||
'google_token_expires_at',
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -45,4 +52,9 @@ class User extends Authenticatable
|
||||
'password' => 'hashed',
|
||||
];
|
||||
}
|
||||
|
||||
public function accounts()
|
||||
{
|
||||
return $this->hasMany(Account::class);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user