
    /&j5                       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mZmZmZmZmZmZmZmZmZ d dlmZ d d	lmZ d d
lmZ d dlmZ  G d d          Z G d d          Z G d d          Z  G d d          Z!d Z"d&dZ#d&dZ$d&dZ%d&dZ&d&dZ'd&dZ(d&dZ)d&dZ*d&dZ+d&d Z,d&d!Z-d&d"Z.d&d#Z/d&d$Z0d&d%Z1dS )'    )annotations)DecimalN)data)page_13_equity_manage)set_manual_fx_override)
LookupUnavailableProviderCandidate%dedupe_missing_provider_symbol_alertsexport_mapping_decision_packexport_mapping_review_templategenerate_mapping_candidatesrank_candidaterecalculate_candidate_rankingsreject_mapping_candidateselect_mapping_candidate)"ensure_instrument_metadata_quality)refresh_market_prices)connect_memory)apply_migrationsc                  &    e Zd ZdZddddZd ZdS )StaticLookupProviderstaticNFfailc               &    |pi | _         || _        d S N)candidates_by_isinr   )selfr   r   s      4tests/unit/test_true_wealth_mapping_candidates_c3.py__init__zStaticLookupProvider.__init__   s    "4":			    c               ~    | j         rt          d          t          | j                            |g                     S )Nzlookup down)r   r   listr   get)r   isinnametickerexchangecurrencys         r   lookupzStaticLookupProvider.lookup#   s;    9 	3#M222D+//b99:::r!   r   )__name__
__module____qualname__r&   r    r*    r!   r   r   r      sH        D     ; ; ; ; ;r!   r   c                      e Zd ZdZddZdS )RaisingPriceProviderraisingsymbolstrc                     t          d          )Nz>price provider should not be called without confirmed mappings)AssertionError)r   r2   s     r   	get_pricezRaisingPriceProvider.get_price,   s    ]^^^r!   N)r2   r3   )r+   r,   r-   r&   r6   r.   r!   r   r0   r0   )   s3        D_ _ _ _ _ _r!   r0   c                      e Zd Zd Zd ZdS )FakeTabc                    | S r   r.   )r   s    r   	__enter__zFakeTab.__enter__1   s    r!   c                    dS NFr.   )r   argss     r   __exit__zFakeTab.__exit__4   s    ur!   N)r+   r,   r-   r:   r>   r.   r!   r   r8   r8   0   s2              r!   r8   c                      e Zd Zd Zd Zd Zd Zd Zd Zd Z	d Z
d	 Zd
 Zd Zd Zd Zd Zd Zd Zd Zd Zd ZdS )FakeStc                    d S r   r.   r   r=   kwargss      r   titlezFakeSt.title9         r!   c                    d S r   r.   rB   s      r   captionzFakeSt.caption:   rE   r!   c                    d S r   r.   rB   s      r   warningzFakeSt.warning;   rE   r!   c                    d S r   r.   rB   s      r   	subheaderzFakeSt.subheader<   rE   r!   c                    d S r   r.   rB   s      r   writezFakeSt.write=   rE   r!   c                    d S r   r.   rB   s      r   successzFakeSt.success>   rE   r!   c                    d S r   r.   rB   s      r   errorzFakeSt.error?   rE   r!   c                    d S r   r.   rB   s      r   infozFakeSt.info@   rE   r!   c                    d S r   r.   rB   s      r   dividerzFakeSt.dividerA   rE   r!   c                    d S r   r.   rB   s      r   	dataframezFakeSt.dataframeB   rE   r!   c                    d S r   r.   rB   s      r   tablezFakeSt.tableC   rE   r!   c                    d |D             S )Nc                *    g | ]}t                      S r.   r8   ).0_s     r   
<listcomp>zFakeSt.tabs.<locals>.<listcomp>D   s    #>#>#>!GII#>#>#>r!   r.   )r   labelss     r   tabszFakeSt.tabsD   s    #>#>v#>#>#>>r!   c                    |r|d         nd S )Nr   r.   )r   labeloptionsrC   s       r   	selectboxzFakeSt.selectboxE   s    :Y'!**UY3Yr!   c                .    |                     dd          S )Nvalue )r$   rB   s      r   
text_inputzFakeSt.text_inputF   s    &**Wb2I2I+Ir!   c                    dS )Nrh   r.   rB   s      r   	text_areazFakeSt.text_areaG   s    r!   c                    dS )N
2025-12-31r.   rB   s      r   
date_inputzFakeSt.date_inputH   s    ,,r!   c                    dS r<   r.   rB   s      r   checkboxzFakeSt.checkboxI   s    r!   c                    t                      S r   r\   rB   s      r   expanderzFakeSt.expanderJ   s    		)9r!   c                    dS r<   r.   rB   s      r   buttonzFakeSt.buttonK   s    eer!   N)r+   r,   r-   rD   rG   rI   rK   rM   rO   rQ   rS   rU   rW   rY   ra   re   ri   rk   rn   rp   rr   rt   r.   r!   r   r@   r@   8   s        ***,,,,,,...***,,,***))),,,...***>>>YYYIII333>>>55599933333r!   r@   c                     t                      } t          |            |                     d           |                     d           |                     d           |                     d           | S )NzINSERT INTO platforms(platform_id,name,platform_type,default_currency,created_at) VALUES('p1','True Wealth','broker','CHF','now')zINSERT INTO accounts(account_id,platform_id,account_name,account_type,currency,created_at) VALUES('a1','p1','TW','brokerage','CHF','now')zINSERT INTO instruments(instrument_id,asset_class,name,ticker,isin,exchange,currency,created_at) VALUES('inst1','ETF','Global Equity ETF','GETF','CH0000000001',NULL,'USD','now')aA  INSERT INTO transactions(transaction_id,transaction_type,account_id,instrument_id,trade_date,quantity,currency_original,fx_status,source_type,is_confirmed,quality_status,created_at) VALUES('tx1','initial_position_snapshot','a1','inst1','2025-12-31','1','USD','missing','broker_import_reviewed_snapshot',1,'warning','now'))r   r   executeconns    r   
setup_connry   N   s    DTLL  U  V  V  VLL  ]  ^  ^  ^LL  E  F  F  FLL  U  V  V  VKr!   returnNonec                    t                      } t          dt          ddddddd          gi          }t          | |	          }|                     d
                                          }|                     d                                          d         }|j        dk    sJ |j        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k    sJ |dk    sJ d S )NCH0000000001stooqGETF.SWSWXUSDGlobal Equity ETFactiveproviderprovider_symbolr(   r)   r&   r%   instrument_statusr   zMSELECT * FROM instrument_price_mapping_candidates WHERE instrument_id='inst1'zQSELECT COUNT(*) AS c FROM instrument_price_mappings WHERE mapping_status='mapped'c   
confidencehighreview_statusproposedcandidate_asset_classetfcandidate_hedge_statusunknowncandidate_valuation_policy
live_pricer   )ry   r   r	   r   rv   fetchonecandidates_foundhigh_confidence)rx   r   resultrowmapping_counts        r   ?test_candidate_generator_creates_high_candidate_from_isin_matchr   X   so   <<D#*GYafqv  ~Q  Xf  zB  C  C  C  D%  H )AAAF
,,f
g
g
p
p
r
rCLL!tuu~~  A  A  BE  FM"a''''!Q&&&&|&&&&:----&'50000'(I5555+,<<<<Ar!   c                    t                      } t          dt          ddd          gi          }t          | |           |                     d                                          }|d         d	k    sJ |d
         dk    sJ d S )Nr}   manualUNKNOWNr   )r   r   r&   r   zHSELECT confidence,review_status FROM instrument_price_mapping_candidatesr   lowr   needs_manual_reviewry   r   r	   r   rv   r   )rx   r   r   s      r   :test_name_only_candidate_is_review_required_low_confidencer   j   s    <<D#^6GQYkt  |O  7P  7P  7P  6Q  %R  S  SHx8888
,,a
b
b
k
k
m
mC|%%%%#8888888r!   c            
        t                      } t          dt          dddd          t          dddd          gi          }t          | |          }d |                     d	                                          D             }|j        d
k    sJ |dhk    sJ |                     d                                          d         d
k    sJ d S )Nr}   r~   r   r   r   r   r(   r%   yahoor   c                    h | ]
}|d          S )r   r.   )r]   rs     r   	<setcomp>zItest_multiple_candidates_are_manual_review_and_alerted.<locals>.<setcomp>z   s/      F  F  Fq/"  F  F  Fr!   z=SELECT review_status FROM instrument_price_mapping_candidatesr   r   z_SELECT COUNT(*) AS c FROM alerts WHERE rule_id='ambiguous_provider_mapping' AND status='active'r   )ry   r   r	   r   rv   fetchallambiguous_provider_mappingr   )rx   r   r   statusess       r   6test_multiple_candidates_are_manual_review_and_alertedr   s   s6   <<D#^7IPU\jkkk7IPU\jkkk6 %  H )AAAF F  FDLL9x,y,y  -C  -C  -E  -E  F  F  FH,1111-.....<<yzz  D  D  F  F  GJ  K  OP  P  P  P  P  P  Pr!   c                     t                      } t          | t          i                     }|j        dk    sJ |                     d                                          d         dk    sJ d S )Nr   r   \SELECT COUNT(*) AS c FROM alerts WHERE rule_id='missing_provider_symbol' AND status='active'r   )ry   r   r   instruments_without_candidaterv   r   rx   r   s     r   6test_no_candidate_keeps_missing_provider_symbol_activer      s    <<D(8LR8P8PQQQF/14444<<vww  A  A  C  C  DG  H  LM  M  M  M  M  M  Mr!   c                    t                      } t          | d           |                     d                                          d         dk    sJ |                     d                                          d         dk    sJ d S )Ninst1)instrument_idzYSELECT COUNT(*) AS c FROM alerts WHERE rule_id='hedge_status_unknown' AND status='active'r   r   z^SELECT COUNT(*) AS c FROM alerts WHERE rule_id='instrument_status_unknown' AND status='active')ry   r   rv   r   rw   s    r   /test_hedge_and_instrument_status_unknown_alertsr      s    <<D&t7CCCC<<stt}}  AD  E  IJ  J  J  J  J<<xyy  C  C  E  E  FI  J  NO  O  O  O  O  O  Or!   c                    t                      } t          dt          ddddddd          gi          }t          | |	           |                     d
                                          }|                     d                                          }|d         dk    sJ |d         dk    sJ |d         dk    sJ |d         dk    sJ d S )Nr}   r~   r   r   CHFzGlobal Equity ETF CHF Hedgedr   r   r   znSELECT candidate_is_hedged,candidate_hedged_to_currency,review_status FROM instrument_price_mapping_candidatesz@SELECT hedge_status FROM instruments WHERE instrument_id='inst1'candidate_is_hedgedr   candidate_hedged_to_currencyr   r   hedge_statusr   r   )rx   r   r   insts       r   :test_chf_hedged_candidate_remains_proposed_until_confirmedr      s-   <<D#^6GQXjs  D  OT  [y  @N  bj  7k  7k  7k  6l  %m  n  nHx8888
,,  H  I  I  R  R  T  TC<<Z[[ddffD$%****-.%7777#888889,,,,,,r!   c                     t                      } t          | t          d                    }|j        dk    sJ |                     d                                          d         dk    sJ d S )NTr   r   r   z`SELECT COUNT(*) AS c FROM alerts WHERE rule_id='provider_lookup_unavailable' AND status='active'r   )ry   r   r   provider_lookup_unavailablerv   r   r   s     r   )test_provider_lookup_error_does_not_crashr      s    <<D(8LRV8W8W8WXXXF-2222<<z{{  E  E  G  G  HK  L  PQ  Q  Q  Q  Q  Q  Qr!   c                 
   t                      } |                     d           t          dt          dddddd          gi          }t	          | |	           |                     d
                                          d         }t          | |d          }|sJ |                     d                                          d         dk    sJ |                     d                                          d         dk    sJ d S )NzINSERT INTO alerts(alert_id,priority,category,entity_type,entity_id,rule_id,message,status,created_at) VALUES('mps','warnung','market_data','instrument','inst1','missing_provider_symbol','missing','active','now')r}   r~   r   r   r   r   )r   r   r(   r)   r%   r   r   <SELECT candidate_id FROM instrument_price_mapping_candidatescandidate_idmanual confirmationr   notezsSELECT COUNT(*) AS c FROM audit_log WHERE action IN ('confirm_instrument_price_mapping','select_mapping_candidate')r      r   r   )ry   rv   r   r	   r   r   r   )rx   r   r   
mapping_ids       r   Htest_mapping_selection_writes_audit_and_resolves_missing_provider_symbolr      s   <<DLL  h  i  i  i#^6GQXjs  D  OT  [i  }E  7F  7F  7F  6G  %H  I  IHx8888<< ^__hhjjkyzL)$\PefffJ:<<  N  O  O  X  X  Z  Z  [^  _  cd  d  d  d  d<<vww  A  A  C  C  DG  H  LM  M  M  M  M  M  Mr!   c            
        t                      } |                     d           t          j        t                    5  t          | dddt          d          d           d d d            n# 1 swxY w Y   t          | dddt          d          d           |                     d	                                          d
         dk    sJ |                     d                                          d
         dk    sJ d S )NzINSERT INTO alerts(alert_id,priority,category,entity_type,entity_id,rule_id,message,status,created_at) VALUES('fx1','kritisch','fx','instrument','inst1','missing_fx','missing','active','now')r   r   rm   z0.9rh   )base_currencyquote_currency	rate_daterater   zstatement sourcezESELECT COUNT(*) AS c FROM audit_log WHERE action='manual_fx_override'r   r   zOSELECT COUNT(*) AS c FROM alerts WHERE rule_id='missing_fx' AND status='active'r   )ry   rv   pytestraises
ValueErrorr   r   r   rw   s    r   6test_fx_override_requires_note_and_resolves_missing_fxr      sv   <<DLL  S  T  T  T	z	"	" F Ft5Zfmtuzm{m{  CE  	F  	F  	F  	FF F F F F F F F F F F F F F F4uUVbipqviwiw  Q  R  R  R  R<<_``iikkloptuuuuu<<ijjssuuvyz~s   #A,,A03A0c                     t                      } t          | t                      ddd          }|j        dk    sJ |j        dk    sJ d S )Nr      T)r   asset_classlimitdry_runr   )ry   r   r0   total_mappingsupdated_countr   s     r   Jtest_market_price_dry_run_without_confirmed_mapping_does_not_call_providerr      s[    <<D"42F2H2HV[cdnrsssF A%%%%1$$$$$$r!   c                 d    t                      } t          j        t                      |            d S r   )ry   r   renderr@   rw   s    r   1test_dashboard_review_ui_renders_without_live_apir      s(    <<D 400000r!   c                 
   t                      } |                     d           |                     d           t          |           }|dk    sJ |                     d                                          d         dk    sJ d S )NzINSERT INTO alerts(alert_id,priority,category,entity_type,entity_id,rule_id,message,status,created_at) VALUES('mps1','warnung','market_data','instrument','inst1','missing_provider_symbol','missing','active','now')zINSERT INTO alerts(alert_id,priority,category,entity_type,entity_id,rule_id,message,status,created_at) VALUES('mps2','warnung','market_data','instrument','inst1','missing_provider_symbol','missing','active','now')r   r   r   )ry   rv   r
   r   )rx   resolveds     r   8test_missing_provider_symbol_dedupes_per_instrument_onlyr      s    <<DLL  i  j  j  jLL  i  j  j  j4T::Hq====<<vww  A  A  C  C  DG  H  LM  M  M  M  M  M  Mr!   c           
     4   t                      }t          dt          ddddd          gi          }t          ||           | dz  }t	          ||	          }|                    d
          }|d         dk    sJ |d         dk    sJ d|v sJ d|v sJ d S )Nr}   r~   r   r   r   r   r   r(   r)   r%   r   zmapping_template.csv)output_pathzutf-8)encodinginstrument_countr   candidate_rowszcandidate_provider,candidate_provider_symbol,candidate_exchange,candidate_currency,confidence,ranking_score,ranking_reason,risk_flags,recommended_action,hedge_status_candidate,instrument_status_candidate,evidence_sourcezreviewer_decision,reviewer_note)ry   r   r	   r   r   	read_text)tmp_pathrx   r   outsummarytexts         r   /test_mapping_template_contains_candidate_fieldsr      s   <<D#^6GQXjs  D  OT  [i  7j  7j  7j  6k  %l  m  mHx8888
+
+C,TsCCCG=='=**D%&!++++#$)))) i  mq  q  q  q  q,444444r!   c            
     b   t                      } t          dt          dddd          t          dddd          gi          }t          | |           d t	          j        |           D             }|d	         d
         dk    sJ |d         d
         dk    sJ |d         d
         dk    sJ d S )Nr}   r~   r   r   r   r   r   c                     i | ]}|d          |S )checkr.   )r]   r   s     r   
<dictcomp>zHtest_data_quality_center_shows_candidate_review_need.<locals>.<dictcomp>   s    GGGCc'lCGGGr!   u   Mapping-Kandidaten unbestätigtcount2z+Instrumente mit mehreren Mapping-Kandidaten1r   )ry   r   r	   r   r   get_data_quality)rx   r   checkss      r   4test_data_quality_center_shows_candidate_review_needr      s    <<D#^7IPU\jkkk7IPU\jkkk6 %  H  x8888GG4+@+F+FGGGF34W=DDDD?@ISPPPP./8C??????r!   c            
     x   t                      } t          | t          i                      |                     d                                          d         dk    sJ t          dt          dddd	d
          gi          }t          | |           |                     d                                          d         dk    sJ |                     d                                          d         }t          | |d           |                     d                                          d         dk    sJ d S )Nr   r   r   r   r}   r~   r   r   r   r   r   r   r   r   r   )ry   r   r   rv   r   r	   r   )rx   r   r   s      r   Ctest_missing_provider_symbol_not_resolved_until_candidate_confirmedr      s   <<D/CB/G/GHHHH<<vww  A  A  C  C  DG  H  LM  M  M  M  M#^6GQXjs  D  OT  [i  7j  7j  7j  6k  %l  m  mHx8888<<vww  A  A  C  C  DG  H  LM  M  M  M  M<< ^__hhjjkyzLTCXYYYY<<vww  A  A  C  C  DG  H  LM  M  M  M  M  M  Mr!   )rz   r{   )2
__future__r   decimalr   r   jarvis_finance.dashboardr   jarvis_finance.dashboard.pagesr   jarvis_finance.fx.overridesr   %jarvis_finance.market_data.candidatesr   r	   r
   r   r   r   r   r   r   r   &jarvis_finance.market_data.instrumentsr   !jarvis_finance.market_data.pricesr   jarvis_finance.storage.databaser   !jarvis_finance.storage.migrationsr   r   r0   r8   r@   ry   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r.   r!   r   <module>r     s>   " " " " " "        ) ) ) ) ) ) @ @ @ @ @ @ > > > > > >                        V U U U U U C C C C C C : : : : : : > > > > > >
; 
; 
; 
; 
; 
; 
; 
;_ _ _ _ _ _ _ _       4 4 4 4 4 4 4 4,     $9 9 9 9
P 
P 
P 
PM M M MO O O O	- 	- 	- 	-Q Q Q Q	M 	M 	M 	M@ @ @ @% % % %1 1 1 1
M M M M
5 
5 
5 
5
@ 
@ 
@ 
@	M 	M 	M 	M 	M 	Mr!   