mirror of
https://github.com/wahyd4/links.git
synced 2026-08-08 21:04:53 +10:00
86 lines
3.3 KiB
Python
86 lines
3.3 KiB
Python
"""Template views for the invest app."""
|
||
import logging
|
||
|
||
from django.shortcuts import render, get_object_or_404
|
||
from django.utils import timezone
|
||
|
||
from .models import Portfolio, Transaction
|
||
from .services import get_portfolio_value, get_weekly_overview, get_all_holdings, get_performance_chart_data
|
||
|
||
logger = logging.getLogger(__name__)
|
||
|
||
|
||
def dashboard(request):
|
||
"""Landing page: weekly snapshot overview + per-portfolio table."""
|
||
overview = get_weekly_overview()
|
||
|
||
# Determine current Australian financial year (Jul–Jun)
|
||
now = timezone.now()
|
||
fy_start = now.year if now.month >= 7 else now.year - 1
|
||
fy_label = f"FY {str(fy_start)[2:]}-{str(fy_start + 1)[2:]}"
|
||
|
||
last_week_date = overview.get('last_week_date')
|
||
all_holdings = get_all_holdings(reference_date=last_week_date)
|
||
# Merge snapshot data into each holdings group.
|
||
# Change is computed as (live total – last snapshot), so the card header and
|
||
# the change line are always consistent with the live holdings table.
|
||
rows_by_id = {row['portfolio'].id: row for row in overview.get('portfolio_rows', [])}
|
||
for group in all_holdings:
|
||
row = rows_by_id.get(group['portfolio'].id, {})
|
||
group['last_snapshot_value'] = row.get('last_week_value')
|
||
group['position_count'] = row.get('position_count', len(group['holdings']))
|
||
# Derive portfolio-level change by summing per-stock value changes,
|
||
# so the header is always consistent with the individual rows.
|
||
stock_changes = [s['value_change'] for s in group['holdings'] if s['value_change'] is not None]
|
||
if stock_changes:
|
||
total_change = sum(stock_changes)
|
||
ref_total = group['total_value'] - total_change
|
||
group['change'] = total_change
|
||
group['change_pct'] = round((total_change / ref_total) * 100, 2) if ref_total else None
|
||
else:
|
||
group['change'] = None
|
||
group['change_pct'] = None
|
||
|
||
recent_transactions = (
|
||
Transaction.objects
|
||
.select_related('portfolio')
|
||
.order_by('-date', '-created_at')[:100]
|
||
)
|
||
|
||
return render(request, 'invest/dashboard.html', {
|
||
'overview': overview,
|
||
'fy_label': fy_label,
|
||
'all_holdings': all_holdings,
|
||
'chart_data_json': get_performance_chart_data() or 'null',
|
||
'recent_transactions': recent_transactions,
|
||
})
|
||
|
||
|
||
def portfolio_detail(request, pk):
|
||
"""Portfolio detail: live holdings, no cost/P&L."""
|
||
portfolio = get_object_or_404(Portfolio, pk=pk)
|
||
try:
|
||
summary = get_portfolio_value(portfolio)
|
||
except Exception as exc:
|
||
logger.error("get_portfolio_value failed for %s: %s", pk, exc)
|
||
summary = {
|
||
'portfolio_id': portfolio.id,
|
||
'portfolio_name': portfolio.name,
|
||
'holdings': [],
|
||
'total_value': 0,
|
||
}
|
||
return render(request, 'invest/portfolio_detail.html', {
|
||
'portfolio': portfolio,
|
||
'summary': summary,
|
||
})
|
||
|
||
|
||
def portfolio_transactions(request, pk):
|
||
"""Transaction history for a portfolio."""
|
||
portfolio = get_object_or_404(Portfolio, pk=pk)
|
||
transactions = portfolio.transactions.all().order_by('-date', '-created_at')
|
||
return render(request, 'invest/transactions.html', {
|
||
'portfolio': portfolio,
|
||
'transactions': transactions,
|
||
})
|