
    oj10                    
   d dl mZ d dlmZ d dl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 d d	lmZ d d
lmZmZmZ d dlmZ d dlmZ d Zd*d+dZ	 d,d-dZd.dZd/d!Zd0d"Zd0d#Z d0d$Z!d0d%Z"d0d&Z#d0d'Z$d0d(Z%d0d)Z&dS )1    )annotations)DecimalN)HTTPException)confirm_create_budget_account)confirm_create_category)%seed_credit_card_candidates_from_rows)get_budget_planning_matrix!get_category_forecast_explanationconfirm_budget_transaction)confirm_prior_year_actualsget_prior_year_actualspreview_prior_year_actuals)connect_memory)apply_migrationsc                 @    t                      } t          |            | S )N)r   r   )conns    .tests/unit/test_budget_planning_forecast_v1.pydbr      s     DTK    Essen & Haushaltnamestrc                p    t          | dddd          d         }t          | |dd          d         }||fS )NHaushaltcheckingCHF)r   account_typecurrency	entity_idexpenser   category_type)r   r   )r   r   
account_idcategory_ids       r   setup_categoryr&      sa    .ZUKK  J *	22  K {""r   r!   r$   r%   	booked_onamounttx_typec                6    t          | |||dd|d|dd	          S )Nzconfirmed bookingProviderr   manual)	r$   transaction_typetransaction_datedescriptionpayeeamount_originalcurrency_originalr%   source_typer   )r   r$   r%   r'   r(   r)   s         r   book_expenser4   +   s>     &$ ' ).%!&&#
	
 
	
  r   startendreturnNonec                n    |                      dd| d| ||df           |                                  d S )NzINSERT INTO budget_import_sessions(
             import_session_id,file_period_start,file_period_end,status,created_at,updated_at)
           VALUES (?,?,?,?,CURRENT_TIMESTAMP,CURRENT_TIMESTAMP)z	coverage--candidates_created)executecommit)r   r5   r6   s      r   mark_import_coverager>   C   sP    LL	C 
#U	"	"S	"	"E30DE	   	KKMMMMMr   yearvalueslist[dict[str, str | None]]c                T    t          | ||d          }t          | |d                   S )Nr?   r@   payload)r   r   )r   r?   r@   previews       r   save_prior_yearrF   M   s.    (/O/OPPG%dGI,>???r   c                    t                      } t          |           \  }}t          | ddd          d         }t          | d|dd|ddg          }t	          | d	          }d
 |d         D             }|d         dk    sJ ||         d         dk    sJ ||         d         dk    sJ ||         d         dk    sJ ||         d         dk    sJ |d         d         dk    sJ |d         d         dk    sJ |d         d         dk    sJ |d         d         dk    sJ |                     d                                          d         dk    sJ t          | d|d d|ddg           t	          | d	          }d |d         D             }||         d         J ||         d         J |d         d         dk    sJ |d         d         dk    sJ |d         d         dk    sJ d S )NFreizeitr!   r"   r    2025z1200.00r%   
amount_chf0.00r?   c                     i | ]}|d          |S r%    .0rows     r   
<dictcomp>z^test_prior_year_batch_keeps_blank_and_explicit_zero_distinct_and_auditable.<locals>.<dictcomp>b       @@@S@@@r   rowsstatus	confirmedannual_actual_chfmonthly_average_chf100.00totalsrecorded_category_count   missing_category_count   zFSELECT COUNT(*) FROM audit_log WHERE action='prior_year_actuals_saved'r   c                     i | ]}|d          |S rO   rP   rQ   s     r   rT   z^test_prior_year_batch_keeps_blank_and_explicit_zero_distinct_and_auditable.<locals>.<dictcomp>z   rU   r   )r   r&   r   rF   r   r<   fetchone)r   _accountfirstsecondresultactualsby_ids          r   Jtest_prior_year_batch_keeps_blank_and_explicit_zero_distinct_and_auditableri   R   s   44D$T**OHe$zI>> F !;;"&99	
 F %T777G@@@@@E({****<+,	9999<-.(::::=,-7777=./69999801Y>>>>823x????8671<<<<856!;;;;<<P hjj    !66"&99	
   %T777G@@@@@E<+,444<-.666801V;;;;8671<<<<856!;;;;;;r   c                    t                      } t          |           \  }}t          |           d         dk    sJ t          | d|ddg           dt          | d          d         v sJ t	          j        t          d	          5  t          | d
           d d d            n# 1 swxY w Y   t	          j        t          d	          5  t          | ddz  g d           d d d            n# 1 swxY w Y   t	          j        t          d	          5  t          | d|ddgd           d d d            d S # 1 swxY w Y   d S )Nr?   rI   2024z240.00rJ   rM   available_yearsz	past year)match99999i  rC   znon-negative CHF1e999999)r   r&   r   rF   pytestraisesr   r   )r   rc   r%   s      r   Ftest_default_and_additional_past_years_work_but_future_year_is_blockedrs      s7   44D*400Hk!$''/69999D&;h#W#W"XYYY+Dv>>>?PQQQQQ	}K	8	8	8 2 2t&11112 2 2 2 2 2 2 2 2 2 2 2 2 2 2	}K	8	8	8 M M"4#*)K)KLLLM M M M M M M M M M M M M M M	},>	?	?	? 
 
"S](^(^'_``	
 	
 	

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
s6   B%%B),B)C..C25C2D99D= D=c            	     t   t                      } t          |           \  }t          | dd           t          | dddg           t	          dd          D ]\  }}t          | |d	|d
d|           t          | |dd           t          | |ddd           t          | ddddgdd           t          | ddd          }t          fd|d         D                       }t          d          }t          d          |t          |d                   z  z   }|d         g d k    sJ |d!         dk    sJ |d"         dk    sJ |d#         |
                    t          d$                    d%k    sJ |d&         dk    sJ t          |d'                   t          |d#                   t          d          z
  k    sJ |d(         t          |d'                   t          d)          z  d*z  
                    t          d$                    d%k    sJ d+|d,         v sJ d-|d.         vsJ d S )/N
2026-01-01
2026-04-30rI   z2400.00rJ   )100200300400r`   r5   2026-02d-28z
2026-05-1550.00z
2026-05-16z999.00transfer)r)   zAbo-Kandidat)DatumBeschreibungBetragzvisa.csvF)source_file_labelmigros_covered20262026-05)r?   current_monthcomparison_yearc              3  4   K   | ]}|d          k    |V  dS r%   NrP   rR   itemr%   s     r   	<genexpr>zTtest_forecast_uses_confirmed_actuals_plus_deterministic_rest_only.<locals>.<genexpr>   2      UU$}2E2T2Tt2T2T2T2TUUr   rV   250.00z1050.00remaining_month_partscovered_complete_months)01020304actual_year_to_date_chfused_monthly_average_chfforecast_display_chf0.01z.2fcomparison_year_actual_chfdeviation_chfdeviation_percent2400d   zcomparison_year=2025data_explorer_urlAboforecast_basis)r   r&   r>   rF   	enumerater4   r   r	   nextr   quantize)	r   r$   monthr(   matrixrS   averageexpectedr%   s	           @r   Atest_forecast_uses_confirmed_actuals_plus_deterministic_rest_onlyr      s   44D,T22J|\:::D&;i#X#X"YZZZ"#?qIII T TvT:{4JE4J4J4J4JFSSSSz;gFFFz;hPZ[[[[)8	T	TU$	    (	  F UUUUvUUU
U
UChGy!!Ggc:Q6R.S.S$SSH()-E-E-EEEEE()Y6666)*h6666%&X->->wv-O-O*U*UUUUU+,	99993'((GC8N4O,P,PSZ[dSeSe,eeeee"#733G+H+H7SY??+Z]`+`*j*jkrsykzkz*{*{  (B  (B  B  B  B  B!S)<%=====,-------r   c                     t                      } t          |           \  }}t          | dd           t          dd          D ]}t	          | ||d|ddd           t          | |d	d
dddddd           t          | dd          }|d         d         dk    sJ |d         d         dk    sJ |d         d         dk    sJ |d         d         J |d         d         J |d         d         d         dk    sJ d S )Nru   
2026-03-31r`      r|   r}   z-20r   r!   z
2026-04-10Uncategorizedr[   r   r,   )r$   r-   r.   r/   r0   r1   r2   r3   r   2026-04r?   r   r\   r   r   unrepresented_actual_chfunrepresented_transaction_countforecast_year_chfr   quality_warningscode"expenses_outside_active_categories)r   r&   r>   ranger4   r   r	   )r   r$   r%   r   r   s        r   Htest_primary_totals_include_unrepresented_expenses_and_withhold_forecastr      sf   44D,T22J|\:::q! U UT:{4JE4J4J4J4JGTTTT$ ) ,*$'!&#		
 		
   (6SSSF(56(BBBB(678CCCC(=>!CCCC(/0888(O,444$%b)&15YYYYYYYr   c            	     n   t                      } t          |           \  }t          | dd           t          dd          D ]}t	          | |d|ddd           t          | d	d
          }t          fd|d         D                       }|d         g k    sJ |d         du sJ |d         J d S )Nz
2026-01-10z
2026-03-20r`   r   r|   r}   z-15r[   r   r   r   c              3  4   K   | ]}|d          k    |V  dS r   rP   r   s     r   r   zUtest_partial_import_ranges_never_count_as_complete_forecast_months.<locals>.<genexpr>   r   r   rV   r   forecast_reliableFr   )r   r&   r>   r   r4   r	   r   )r   r$   r   r   rS   r%   s        @r   Btest_partial_import_ranges_never_count_as_complete_forecast_monthsr      s    44D,T22J|\:::q! V VT:{4JE4J4J4J4JHUUUU'6SSSF
UUUUvUUU
U
UC()R////"#u,,,,%&.....r   c                    t                      } t          |           \  }t          | |dd           t          | |dd           t          | dd          }t	          fd|d	         D                       }|d
         du sJ |d         J |d         J |d         J |d         dk    sJ |d         d         J d S )Nz
2026-01-31r[   z
2026-02-15r   r   z2026-02r   c              3  4   K   | ]}|d          k    |V  dS r   rP   r   s     r   r   z]test_forecast_is_missing_until_three_complete_months_and_never_zero_filled.<locals>.<genexpr>   r   r   rV   r   Fr   r   r   
evaluationu+   Vergleichswert für 2025 noch nicht erfasstr\   r   )r   r&   r4   r	   r   )r   r$   r   rS   r%   s       @r   Jtest_forecast_is_missing_until_three_complete_months_and_never_zero_filledr      s   44D,T22Jz;hGGGz;gFFF'6SSSF
UUUUvUUU
U
UC"#u,,,,%&...'''"#+++| MMMMM(/088888r   c            	        t                      } t          |           \  }t          | dd           t          | ddd          d         fd|                     d                                          D             }t          | d	|           t          d
d          D ]2}t          | |d|ddd           t          | |d|ddd           3t          | |dd           t          | dd          }|d         }t          |d                   t          |d                   z  t          d          z                      t          d                    }t          |d                   |k    sJ d S )Nru   rv   rH   r!   r"   r    c                    g | ]P}t          |d                    t          |d                    k    rdnt          |d                    k    rdnddQS )r%   1000.00z3000.00rL   rJ   )r   )rR   rS   rd   re   s     r   
<listcomp>zUtest_total_percent_comes_from_total_sums_not_category_percentages.<locals>.<listcomp>   s     6 6 6  s=122 s=)**e33 	 s=)**f44 Y		
 		
6 6 6r   zWSELECT category_id FROM budget_categories WHERE is_active=1 AND category_type='expense'rI   r`      r|   r}   r~   r[   z200.00z
2026-05-31r   r   r   r\   r   r   rw   r   r   )r   r&   r>   r   r<   fetchallrF   r   r4   r	   r   r   )	r   r$   comparison_valuesr   r   r\   expected_percentrd   re   s	          @@r   Atest_total_percent_comes_from_total_sums_not_category_percentagesr      s   44D&t,,J|\:::$zI>> F6 6 6 6 6 <<e
 

(**6 6 6 D&"3444q! Q QT:u.De.D.D.D.DhOOOT:v/Eu/E/E/E/ExPPPPz5,AAA'6SSSFHF'((
&56
7
7	8
%..	 hwv	 
 6-.//3CCCCCCCr   c            	     ^   t                      } t          |           \  }}t          | dd           t          | d|ddg           t	          dd          D ]\  }}t          | ||d	|d
d|           t          | ||dd           t          | |dd          }t          |d                   t          |d                   z   }|t          |d                   k    sJ |d         dk    sJ |d         dk    sJ |d         dk    sJ t          d |d         D                       sJ d S )Nru   r   rI   r   rJ   )33.00r   z34.00r`   r{   r|   r}   r~   z
2026-04-15z1.00r   )r%   r?   r   r   forecast_remaining_chfr   covered_complete_month_count   confirmed_transaction_countr   excluded_transfer_countr   c              3     K   | ]}d |v V  	dS )	RecurringNrP   )rR   r   s     r   r   zWtest_explorer_explanation_reconciles_exactly_with_displayed_forecast.<locals>.<genexpr>0  s'      IIt{d"IIIIIIr   
exclusions)	r   r&   r>   rF   r   r4   r
   r   any)r   r$   r%   r   r(   explanation
reconcileds          r   Dtest_explorer_explanation_reconciles_exactly_with_displayed_forecastr     s   44D,T22J|\:::D&;i#X#X"YZZZ"#>aHHH T TvT:{4JE4J4J4J4JFSSSSz;fEEE3+FF  K %>?@@7,-D D J -@!ABBBBBB56!;;;;45::::01Q6666II{</HIIIIIIIIIIr   )r   )r   r   )r!   )
r$   r   r%   r   r'   r   r(   r   r)   r   )r5   r   r6   r   r7   r8   )r?   r   r@   rA   )r7   r8   )'
__future__r   decimalr   rq   fastapir   'jarvis_finance.services.budget_accountsr   )jarvis_finance.services.budget_categoriesr   &jarvis_finance.services.budget_importsr   'jarvis_finance.services.budget_planningr	   r
   +jarvis_finance.services.budget_transactionsr   *jarvis_finance.services.prior_year_actualsr   r   r   jarvis_finance.storage.databaser   !jarvis_finance.storage.migrationsr   r   r&   r4   r>   rF   ri   rs   r   r   r   r   r   r   rP   r   r   <module>r      s<   " " " " " "        ! ! ! ! ! ! Q Q Q Q Q Q M M M M M M X X X X X X        S R R R R R         
 ; : : : : : > > > > > >  	# 	# 	# 	# 	#$     0   @ @ @ @
-< -< -< -<`
 
 
 
"". ". ". ".JZ Z Z Z</ / / /9 9 9 9"#D #D #D #DLJ J J J J Jr   