mirror of
https://github.com/henry4682/finance_app.git
synced 2026-07-16 08:20:00 +00:00
feat: 前端分離+功能api化
1. 新增資產管理CRUD、googleOAuth登入 2. 更改原記帳controller
This commit is contained in:
98
app/Http/Controllers/Api/InvestmentTransactionController.php
Normal file
98
app/Http/Controllers/Api/InvestmentTransactionController.php
Normal file
@@ -0,0 +1,98 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\InvestmentHolding;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class InvestmentTransactionController extends Controller
|
||||
{
|
||||
public function index(Request $request, string $holdingId)
|
||||
{
|
||||
$holding = InvestmentHolding::whereHas('account', function ($q) use ($request) {
|
||||
$q->where('user_id', $request->user()->id);
|
||||
})->findOrFail($holdingId);
|
||||
|
||||
return response()->json($holding->transactions()->orderBy('traded_at', 'desc')->get());
|
||||
}
|
||||
|
||||
public function store(Request $request, string $holdingId)
|
||||
{
|
||||
$holding = InvestmentHolding::whereHas('account', function ($q) use ($request) {
|
||||
$q->where('user_id', $request->user()->id);
|
||||
})->findOrFail($holdingId);
|
||||
|
||||
$validated = $request->validate([
|
||||
'action' => 'required|in:buy,sell',
|
||||
'shares' => 'nullable|numeric|min:0',
|
||||
'price' => 'nullable|numeric|min:0',
|
||||
'fee' => 'nullable|numeric|min:0',
|
||||
'tax' => 'nullable|numeric|min:0',
|
||||
'traded_at' => 'required|date',
|
||||
'note' => 'nullable|string',
|
||||
'amount' => 'nullable|numeric|min:0', // 實際投入金額(基金用)
|
||||
'nav' => 'nullable|numeric|min:0', // 淨值(基金用)
|
||||
]);
|
||||
|
||||
$transaction = $holding->transactions()->create($validated);
|
||||
|
||||
// 更新持倉的 shares 和 avg_cost
|
||||
$this->recalculateHolding($holding);
|
||||
|
||||
return response()->json($transaction, 201);
|
||||
}
|
||||
|
||||
public function destroy(Request $request, string $holdingId, string $id)
|
||||
{
|
||||
$holding = InvestmentHolding::whereHas('account', function ($q) use ($request) {
|
||||
$q->where('user_id', $request->user()->id);
|
||||
})->findOrFail($holdingId);
|
||||
|
||||
$transaction = $holding->transactions()->findOrFail($id);
|
||||
$transaction->delete();
|
||||
|
||||
$this->recalculateHolding($holding);
|
||||
|
||||
return response()->json(null, 204);
|
||||
}
|
||||
|
||||
// 每次買賣後重新計算平均成本和持有股數
|
||||
private function recalculateHolding(InvestmentHolding $holding): void
|
||||
{
|
||||
$transactions = $holding->transactions()->orderBy('traded_at')->get();
|
||||
|
||||
$totalUnits = 0;
|
||||
$totalCost = 0;
|
||||
$presentUnits = 0;
|
||||
|
||||
|
||||
foreach ($transactions as $tx) {
|
||||
if ($tx->action === 'buy') {
|
||||
if ($holding->type === 'fund') {
|
||||
$units = $tx->nav > 0 ? $tx->amount / $tx->nav : 0;
|
||||
$totalCost += $tx->amount + $tx->fee;
|
||||
$presentUnits += $units;
|
||||
$totalUnits += $units;
|
||||
} else {
|
||||
$totalCost += $tx->shares * $tx->price + $tx->fee;
|
||||
$presentUnits += $tx->shares;
|
||||
$totalUnits += $tx->shares;
|
||||
}
|
||||
} else {
|
||||
if ($holding->type === 'fund') {
|
||||
$units = $tx->nav > 0 ? $tx->amount / $tx->nav : 0;
|
||||
$totalUnits -= $units;
|
||||
} else {
|
||||
$totalUnits -= $tx->shares;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$holding->update([
|
||||
'shares' => max(0, $totalUnits), // 總持有股數
|
||||
'avg_cost' => $presentUnits > 0 ? $totalCost / $presentUnits : 0,
|
||||
]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user