90 lines
2.3 KiB
TypeScript
90 lines
2.3 KiB
TypeScript
import { jsonError } from '@/lib/server/http';
|
|
import { recalculateHolding } from '@/lib/server/portfolio';
|
|
import { withStore } from '@/lib/server/store';
|
|
|
|
type Context = {
|
|
params: Promise<{ id: string }>;
|
|
};
|
|
|
|
function nowIso() {
|
|
return new Date().toISOString();
|
|
}
|
|
|
|
function asPositiveNumber(value: unknown) {
|
|
const parsed = typeof value === 'number' ? value : Number(value);
|
|
return Number.isFinite(parsed) && parsed > 0 ? parsed : null;
|
|
}
|
|
|
|
export async function PATCH(request: Request, context: Context) {
|
|
const { id } = await context.params;
|
|
const numericId = Number(id);
|
|
|
|
if (!Number.isInteger(numericId) || numericId <= 0) {
|
|
return jsonError('Invalid holding id');
|
|
}
|
|
|
|
const payload = await request.json() as {
|
|
shares?: number;
|
|
avgCost?: number;
|
|
currentPrice?: number;
|
|
};
|
|
|
|
let found = false;
|
|
let updated: unknown = null;
|
|
|
|
await withStore((store) => {
|
|
const index = store.holdings.findIndex((entry) => entry.id === numericId);
|
|
if (index < 0) {
|
|
return;
|
|
}
|
|
|
|
found = true;
|
|
const existing = store.holdings[index];
|
|
|
|
const shares = asPositiveNumber(payload.shares) ?? Number(existing.shares);
|
|
const avgCost = asPositiveNumber(payload.avgCost) ?? Number(existing.avg_cost);
|
|
const currentPrice = asPositiveNumber(payload.currentPrice) ?? Number(existing.current_price ?? existing.avg_cost);
|
|
|
|
const next = recalculateHolding({
|
|
...existing,
|
|
shares: shares.toFixed(6),
|
|
avg_cost: avgCost.toFixed(6),
|
|
current_price: currentPrice.toFixed(6),
|
|
updated_at: nowIso(),
|
|
last_price_at: nowIso()
|
|
});
|
|
|
|
store.holdings[index] = next;
|
|
updated = next;
|
|
});
|
|
|
|
if (!found) {
|
|
return jsonError('Holding not found', 404);
|
|
}
|
|
|
|
return Response.json({ holding: updated });
|
|
}
|
|
|
|
export async function DELETE(_request: Request, context: Context) {
|
|
const { id } = await context.params;
|
|
const numericId = Number(id);
|
|
|
|
if (!Number.isInteger(numericId) || numericId <= 0) {
|
|
return jsonError('Invalid holding id');
|
|
}
|
|
|
|
let removed = false;
|
|
|
|
await withStore((store) => {
|
|
const next = store.holdings.filter((holding) => holding.id !== numericId);
|
|
removed = next.length !== store.holdings.length;
|
|
store.holdings = next;
|
|
});
|
|
|
|
if (!removed) {
|
|
return jsonError('Holding not found', 404);
|
|
}
|
|
|
|
return Response.json({ success: true });
|
|
}
|