{# Harvest plan-builder tile + re-rendered queue. Inputs: plan: HarvestPlan rows: list[HarvestOpportunity] (full pool) tax_saved_by_key: dict[(symbol, account_label), Decimal] selected_keys: set[(symbol, account_label)] (rows currently checked) mode: "auto" | "manual" | "custom" (current budget mode) custom_budget: str (last custom value or "") exclude_locked: bool has_tax_config: bool #}
{% include "_harvest_summary.html" %} {# B2: taxpayer-level offset caveat — shared partial. Rendered here because this fragment is loaded via HTMX into /positions?view=at-loss (the new home for the harvest plan after the Phase 1 IA move). The page-level copy in tax.html covers /tax routes; both call the same template so there's a single source of truth for the caveat copy. #} {% include "_taxpayer_caveat.html" %}
{% if rows %} {% for row in rows_page %} {% set _checked = (row.symbol, row.account_label) in selected_keys %} {% set _acct_slug = row.account_label|replace('/', '__')|replace(' ', '_') %} {% endfor %}
Symbol Loss LT/ST Account Lockout-clear Tax saved (est.) Actions
{{ row.symbol }} −${{ "%.2f"|format(row.loss|abs) }} {{ row.lt_st }} {{ row.account_label }} {% if row.lockout_clear %} {{ row.lockout_clear }} {% else %} clear {% endif %} {% if has_tax_config %} {% set _ts = tax_saved_by_key[(row.symbol, row.account_label)] %} ${{ "%.2f"|format(_ts|float) }} {% else %} {% endif %} Simulate harvest
{% set pick_qs = '' %} {% if picks %}{% for p in picks %}{% set pick_qs = pick_qs + '&pick=' + (p|urlencode) %}{% endfor %}{% endif %} {% set page_base_url = '/tax/harvest/plan' %} {% set page_extra_qs = pick_qs %} {% set page_target = '#harvest-queue-region' %} {% set page_swap = 'outerHTML' %} {% include "_pagination_footer.html" %} {% else %}

No harvestable candidates right now.

{% endif %}