
    1j3&                       d Z ddlmZ ddlZddlmZmZ ddlmZ ddl	m
Z
 ddlmZ ddlmZ dd	lmZ dd
lmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlm Z  ddl!m"Z"m#Z#m$Z$m%Z%m&Z& ddl'm(Z( e"e#e$e%dZ)e G d d             Z*e G d d             Z+e G d d             Z,e G d d             Z-	 	 	 	 	 	 	 	 	 	 ddZ.y)u  
Dashboard summary service.

Boundary 1 (Flask/Service) & Boundary 5 (Analytics+Insights/Flask) enforced:
no Flask context, no direct DB session — all inputs are plain parameters.
All aggregations use SQL func.sum — no Python loops over transaction rows.
    )annotationsN)	dataclassfield)Decimal)Any)func)db)Budget)Category)Transaction)Bill)Debt)PaydownPlan)PaydownPlanCard)Account)PaydownBalanceUpdate)calculate_avalanchecalculate_snowballcalculate_highest_balancecalculate_proportionalcalculate_custom)get_monitor_statuses)	avalanchesnowballhighest_balanceproportionalc                  T    e Zd ZU ded<   ded<   ded<   ded<   ded<   ded	<   d
ed<   y)BudgetBurnRowstrcategory_namer   budgetedspent	remainingintpctstatebool
has_budgetN__name__
__module____qualname____annotations__     0/var/www/html/financials/app/services/summary.pyr   r   *   s)    N	HJr/   r   c                  J    e Zd ZU ded<   ded<   ded<   ded<   ded<   ded	<   y
)UpcomingBillRowr   namer   amountdue_dater$   days_until_duestatus	item_typeNr)   r.   r/   r0   r2   r2   5   s!    
IOMKNr/   r2   c                  6    e Zd ZU ded<   ded<   ded<   ded<   y)RecentTransactionr   datemerchantr   r4   r    Nr)   r.   r/   r0   r:   r:   ?   s    
IMOr/   r:   c                      e Zd ZU ded<   ded<   ded<   ded<   ded<   d	ed
<   ded<   ded<   ded<   ded<   ded<   ded<   y)DashboardDatazlist[BudgetBurnRow]budget_burn_rowsr   current_month_totalprior_month_totalmonth_deltazlist[UpcomingBillRow]upcoming_billszlist[RecentTransaction]recent_transactionsz	list[Any]paydown_statusesz
Any | Noneactive_planr'   has_budgets	has_billshas_transactionshas_active_planNr)   r.   r/   r0   r>   r>   G   sU     *) !  *) 10   Or/   r>   c                R   t         j                  j                         }|  d|dd}t        j                  | |d      t        j                  d      z
  }|j                   d|j
                  dd}t        j                  j                  d      j                  t        j                        j                         }t        j                  j                  ||       j                         D 	ci c]  }	|	j                  |	 }
}	t        j                  j                  t         j                  t#        j$                  t         j&                        j)                  d	            j+                  t         j                  j-                  |      t         j.                  d
k(        j1                  t         j                        j                         }|D ci c]  }|j                  |j2                   }}g }|D ]  }|
j5                  |j6                        }|r|j&                  n
t9        d      }|j5                  |j6                  t9        d            }||z
  }|dkD  rt;        ||z  dz        nd}|dk\  rdn|dk\  rdnd}|j=                  t?        |j                  ||||||du              tA        d |D              }t        j                  j                  t#        j$                  t         j&                              j+                  t         j                  j-                  |      t         j.                  d
k(        jC                         }t9        tE        |xs d            }t        j                  j                  t#        j$                  t         j&                              j+                  t         j                  j-                  |      t         j.                  d
k(        jC                         }t9        tE        |xs d            }||z
  }t         j                  jG                         dkD  }|t        j                  d      z   jI                         }tJ        j                  j                  d      j                         }tL        j                  j                  d      j                         }g } |D ]  }!|!jN                  s|!jN                  |kD  r t         j                  jQ                  |!jN                        |z
  jR                  }"|"dk  rd}#n
|"dk(  rd}#nd}#| j=                  tU        |!j                  |!j&                  |!jN                  |"|#d              |D ]  }$|$jN                  s|$jN                  |kD  r t         j                  jQ                  |$jN                        |z
  jR                  }"|"dk  rd}#n
|"dk(  rd}#nd}#| j=                  tU        |$j                  |$jV                  |$jN                  |"|#d              | jY                  d        t[        |       }%|D &ci c]  }&|&j6                  |&j                   }'}&t         j                  j                  t         j                  j]                         t         j6                  j]                               j_                  d      j                         }(|(D )cg c]I  })ta        |)j                  |)jb                  |)j&                  |'j5                  |)j                  d             K }*})d}+g },d
}-|r/td        j                  j                  |d!"      jg                         }+|+rd}-|+jh                  D .cg c]  }.|.jj                   }/}.tl        j                  j+                  tl        j6                  jo                  |/            j                         }0|0D &cg c]c  }&|&j6                  |&j                  |&jp                  xs t9        d      |&jr                  xs t9        d      |&jV                  xs t9        d      d#e }1}&tt        j5                  |+jv                        }2|2r |2|1|+jx                        }3nt{        |1i       }3t|        j                  j+                  t|        jj                  jo                  |/            j                         }4|4D 5cg c]&  }5|5jj                  |5j~                  |5j                  d$( }6}5t        |3|6      },t        ||||| |*|,|+||%||-%      S c c}	w c c}w c c}&w c c})w c c}.w c c}&w c c}5w )&u  
    Collect all dashboard data in a single pass.

    Parameters extracted at the route layer:
        year, month — current month for budget/spending
        active_plan_id — Settings-agnostic plan reference
        monthly_income — from Settings, passed as plain value
    -02dz-%   )daysT)	is_active)monthyeartotalF0r   d   dangerP   warningsafeN)r    r!   r"   r#   r%   r&   r(   c              3  4   K   | ]  }|j                     y wN)r(   ).0rs     r0   	<genexpr>z%get_dashboard_data.<locals>.<genexpr>   s     =qall=s      Overduez	Due TodayUpcomingbill)r3   r4   r5   r6   r7   r8   debtc                    | j                   S r[   )r5   )xs    r0   <lambda>z$get_dashboard_data.<locals>.<lambda>   s
    ajj r/   )key
   u   —)r;   r<   r4   r    active)idr7   )rj   r3   balanceaprmin_payment)
account_idrk   
updated_at)r?   r@   rA   rB   rC   rD   rE   rF   rG   rH   rI   rJ   )Cdatetimer;   today	timedeltarR   rQ   r   query	filter_byorder_byr3   allr
   category_idr	   sessionr   r   sumr4   labelfilterlike	is_creditgroup_byrS   getrj   r   r$   appendr   anyscalarr   count	isoformatr   r   r5   fromisoformatrO   r2   rm   sortr'   desclimitr:   merchant_normalizedr   firstcardsrn   r   in_current_balancerl   _STRATEGY_CALCstrategyextra_monthlyr   r   rk   ro   r   r>   )7rR   rQ   active_plan_idmonthly_incomerq   month_prefixprior_monthprior_prefixactive_categoriesbbudgets
spent_rowsr]   actualsr?   catbudgetr!   r"   r#   r%   r&   rG   current_sum_rowr@   prior_sum_rowrA   rB   rI   cutoffactive_billsactive_debtsrC   rb   deltar7   rc   rH   c	cat_namesrecent_txns_rawtrD   rF   rE   rJ   pcplan_card_idsr   
card_dictsfnresultupdates_rawuupdate_dictss7                                                          r0   get_dashboard_datar   b   s    MM!EV1U3Kr*L--eQ/(2D2D!2LLK!&&'q):):3(?rBL 	  4 099(--HLLN 
 ''e$'?CCE 	
qG 
 	

00$((;;M;M2N2T2TU\2]^	  %%l3[5J5Je5S	T	+))	*		  0::!q}}agg%:G:  SVV$$*6==CFFGCL1u$	-5\c%("S()q3J#)Y((T)!
 	" =,<==K 	

+"4"456	  %%l3[5J5Je5S	T	 
 "#o&:";< 	

+"4"456	  %%l3[5J5Je5S	T	 
  M$6Q 78%(99K"((..014 h((b11<<>F::''$'7;;=L::''$'7;;=L,.N }}==6!,,T]];eCII19FaZ FFo;;]] 
 	*  }}==6!,,T]];eCII19FaZ FFo##]] 
 	* 01^$I (99!qvv9I9	+""'');>>+>+>+@	A	r		  !  	**88#--u=		
  KO!''11^H1U[[]1<1B1BC2CC$$WZZ^^M%BCGGI 	
  dd,,<uu, }}<	

 	
  4 45
K$=$=>F%j"5F !&&V(3377FGSU 	 !
 <<AIIQ\\Z
 
 0E)/+%/))' } ;x :( D	
*
s,   /dd'd Add=A(d6+d$)
rR   r$   rQ   r$   r   z
int | Noner   zDecimal | Nonereturnr>   )/__doc__
__future__r   rp   dataclassesr   r   decimalr   typingr   
sqlalchemyr   app.extensionsr	   app.models.budgetr
   app.models.categoryr   app.models.transactionr   app.models.billr   app.models.debtr   app.models.paydown_planr   app.models.paydown_plan_cardr   app.models.accountr   !app.models.paydown_balance_updater   app.services.amortizationr   r   r   r   r   app.services.plan_monitorr   r   r   r2   r:   r>   r   r.   r/   r0   <module>r      s    #  (     $ ( .     / 8 & B  ; +)0-	            4B
BB B #	B
 Br/   