
    /&j5                    v   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#Z1y)%    )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y)StaticLookupProviderstaticNFfailc               (    |xs i | _         || _        y N)candidates_by_isinr   )selfr   r   s      4tests/unit/test_true_wealth_mapping_candidates_c3.py__init__zStaticLookupProvider.__init__   s    "4":	    c               z    | j                   rt        d      t        | j                  j	                  |g             S )Nzlookup down)r   r   listr   get)r   isinnametickerexchangecurrencys         r   lookupzStaticLookupProvider.lookup#   s2    99#M22D++//b9::r!   r   )__name__
__module____qualname__r&   r    r*    r!   r   r   r      s    D ;r!   r   c                      e Zd ZdZddZy)RaisingPriceProviderraisingc                    t        d      )Nz>price provider should not be called without confirmed mappings)AssertionError)r   symbols     r   	get_pricezRaisingPriceProvider.get_price,   s    ]^^r!   N)r4   str)r+   r,   r-   r&   r5   r.   r!   r   r0   r0   )   s    D_r!   r0   c                      e Zd Zd Zd Zy)FakeTabc                    | S r   r.   )r   s    r   	__enter__zFakeTab.__enter__1   s    r!   c                     yNFr.   )r   argss     r   __exit__zFakeTab.__exit__4   s    r!   N)r+   r,   r-   r:   r>   r.   r!   r   r8   r8   0   s    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y)FakeStc                     y r   r.   r   r=   kwargss      r   titlezFakeSt.title9       r!   c                     y r   r.   rB   s      r   captionzFakeSt.caption:   rE   r!   c                     y r   r.   rB   s      r   warningzFakeSt.warning;   rE   r!   c                     y r   r.   rB   s      r   	subheaderzFakeSt.subheader<   rE   r!   c                     y r   r.   rB   s      r   writezFakeSt.write=   rE   r!   c                     y r   r.   rB   s      r   successzFakeSt.success>   rE   r!   c                     y r   r.   rB   s      r   errorzFakeSt.error?   rE   r!   c                     y r   r.   rB   s      r   infozFakeSt.info@   rE   r!   c                     y r   r.   rB   s      r   dividerzFakeSt.dividerA   rE   r!   c                     y r   r.   rB   s      r   	dataframezFakeSt.dataframeB   rE   r!   c                     y r   r.   rB   s      r   tablezFakeSt.tableC   rE   r!   c                <    |D cg c]  }t                c}S c c}w r   r8   )r   labels_s      r   tabszFakeSt.tabsD   s    v#>!GI#>>#>s   c                    |r|d   S d S )Nr   r.   )r   labeloptionsrC   s       r   	selectboxzFakeSt.selectboxE   s    '!*3YUY3Yr!   c                &    |j                  dd      S )Nvalue )r$   rB   s      r   
text_inputzFakeSt.text_inputF   s    &**Wb2I+Ir!   c                     y)Nre   r.   rB   s      r   	text_areazFakeSt.text_areaG   s    r!   c                     y)N
2025-12-31r.   rB   s      r   
date_inputzFakeSt.date_inputH   s    ,r!   c                     yr<   r.   rB   s      r   checkboxzFakeSt.checkboxI   s    r!   c                    t               S r   r[   rB   s      r   expanderzFakeSt.expanderJ   s	    	)9r!   c                     yr<   r.   rB   s      r   buttonzFakeSt.buttonK   s    er!   N)r+   r,   r-   rD   rG   rI   rK   rM   rO   rQ   rS   rU   rW   rY   r^   rb   rf   rh   rk   rm   ro   rq   r.   r!   r   r@   r@   8   s;    *,,.*,*),.*>YI3>593r!   r@   c                     t               } t        |        | j                  d       | j                  d       | j                  d       | j                  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_connrv   N   sc    DTLL  U  VLL  ]  ^LL  E  FLL  U  VKr!   c                    t               } t        dt        ddddddd      gi      }t        | |	      }| j	                  d
      j                         }| j	                  d      j                         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 y )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   )rv   r   r	   r   rs   fetchonecandidates_foundhigh_confidence)ru   r   resultrowmapping_counts        r   ?test_candidate_generator_creates_high_candidate_from_isin_matchr   X   s/   <D#*GYafqv  ~Q  Xf  zB  C  D% H )AF
,,f
g
p
p
rCLL!tu~~  A  BE  FM""a'''!!Q&&&|&&&:---&'5000'(I555+,<<<Ar!   c                     t               } t        dt        ddd      gi      }t        | |       | j	                  d      j                         }|d   d	k(  sJ |d
   dk(  sJ y )Nrx   manualUNKNOWNr}   )r   r   r&   r   zHSELECT confidence,review_status FROM instrument_price_mapping_candidatesr   lowr   needs_manual_reviewrv   r   r	   r   rs   r   )ru   r   r   s      r   :test_name_only_candidate_is_review_required_low_confidencer   j   s    <D#^6GQYkt  |O  7P  6Q  %R  SHx8
,,a
b
k
k
mC|%%%#8888r!   c            
     l   t               } t        dt        dddd      t        dddd      gi      }t        | |      }| j	                  d      j                         D ch c]  }|d	   	 }}|j                  d
k(  sJ |dhk(  sJ | j	                  d      j                         d   d
k(  sJ y c c}w )Nrx   ry   rz   r{   r   r   r(   r%   yahoor   z=SELECT review_status FROM instrument_price_mapping_candidatesr   r   r   z_SELECT COUNT(*) AS c FROM alerts WHERE rule_id='ambiguous_provider_mapping' AND status='active'r   )rv   r   r	   r   rs   fetchallambiguous_provider_mappingr   )ru   r   r   rstatusess        r   6test_multiple_candidates_are_manual_review_and_alertedr   s   s    <D#^7IPU\jk7IPU\jk6 % H )AF,0LL9x,y  -C  -C  -E  Fq/"  FH  F,,111-....<<yz  D  D  F  GJ  K  OP  P  P  P Fs   "B1c                     t               } t        | t        i             }|j                  dk(  sJ | j	                  d      j                         d   dk(  sJ y )Nr   r   \SELECT COUNT(*) AS c FROM alerts WHERE rule_id='missing_provider_symbol' AND status='active'r   )rv   r   r   instruments_without_candidaters   r   ru   r   s     r   6test_no_candidate_keeps_missing_provider_symbol_activer      st    <D(8LR8PQF//1444<<vw  A  A  C  DG  H  LM  M  M  Mr!   c                     t               } t        | d       | j                  d      j                         d   dk(  sJ | j                  d      j                         d   dk(  sJ y )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')rv   r   rs   r   rt   s    r   /test_hedge_and_instrument_status_unknown_alertsr      s    <D&t7C<<st}}  AD  E  IJ  J  J  J<<xy  C  C  E  FI  J  NO  O  O  Or!   c                 :   t               } t        dt        ddddddd      gi      }t        | |	       | j	                  d
      j                         }| j	                  d      j                         }|d   dk(  sJ |d   dk(  sJ |d   dk(  sJ |d   dk(  sJ y )Nrx   ry   rz   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   )ru   r   r   insts       r   :test_chf_hedged_candidate_remains_proposed_until_confirmedr      s    <D#^6GQXjs  D  OT  [y  @N  bj  7k  6l  %m  nHx8
,,  H  I  R  R  TC<<Z[ddfD$%***-.%777#88889,,,r!   c                     t               } t        | t        d            }|j                  dk(  sJ | j	                  d      j                         d   dk(  sJ y )NTr   r   r   z`SELECT COUNT(*) AS c FROM alerts WHERE rule_id='provider_lookup_unavailable' AND status='active'r   )rv   r   r   provider_lookup_unavailablers   r   r   s     r   )test_provider_lookup_error_does_not_crashr      su    <D(8LRV8WXF--222<<z{  E  E  G  HK  L  PQ  Q  Q  Qr!   c                    t               } | j                  d       t        dt        dddddd      gi      }t	        | |	       | j                  d
      j                         d   }t        | |d      }|sJ | j                  d      j                         d   dk\  sJ | j                  d      j                         d   dk(  sJ y )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')rx   ry   rz   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   )rv   rs   r   r	   r   r   r   )ru   r   r   
mapping_ids       r   Htest_mapping_selection_writes_audit_and_resolves_missing_provider_symbolr      s/   <DLL  h  i#^6GQXjs  D  OT  [i  }E  7F  6G  %H  IHx8<< ^_hhjkyzL)$\PefJ:<<  N  O  X  X  Z  [^  _  cd  d  d  d<<vw  A  A  C  DG  H  LM  M  M  Mr!   c            
        t               } | j                  d       t        j                  t              5  t        | dddt        d      d       d d d        t        | dddt        d      d       | j                  d	      j                         d
   dk(  sJ | j                  d      j                         d
   dk(  sJ y # 1 sw Y   rxY w)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   rj   z0.9re   )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   )rv   rs   pytestraises
ValueErrorr   r   r   rt   s    r   6test_fx_override_requires_note_and_resolves_missing_fxr      s    <DLL  S  T	z	" Ft5Zfmtuzm{  CE  	FF4uUVbipqviw  Q  R<<_`iikloptuuuu<<ijssuvyz~	F Fs   CC
c                     t               } t        | t               ddd      }|j                  dk(  sJ |j                  dk(  sJ y )Nr      T)r   asset_classlimitdry_runr   )rv   r   r0   total_mappingsupdated_countr   s     r   Jtest_market_price_dry_run_without_confirmed_mapping_does_not_call_providerr      sJ    <D"42F2HV[cdnrsF  A%%%1$$$r!   c                 T    t               } t        j                  t               |        y r   )rv   r   renderr@   rt   s    r   1test_dashboard_review_ui_renders_without_live_apir      s    <D  40r!   c                     t               } | j                  d       | j                  d       t        |       }|dk(  sJ | j                  d      j                         d   dk(  sJ y )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   )rv   rs   r
   r   )ru   resolveds     r   8test_missing_provider_symbol_dedupes_per_instrument_onlyr      s    <DLL  i  jLL  i  j4T:Hq==<<vw  A  A  C  DG  H  LM  M  M  Mr!   c           
         t               }t        dt        ddddd      gi      }t        ||       | dz  }t	        ||	      }|j                  d
      }|d   dk(  sJ |d   dk(  sJ d|v sJ d|v sJ y )Nrx   ry   rz   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)rv   r   r	   r   r   	read_text)tmp_pathru   r   outsummarytexts         r   /test_mapping_template_contains_candidate_fieldsr      s    <D#^6GQXjs  D  OT  [i  7j  6k  %l  mHx8
+
+C,TsCG=='=*D%&!+++#$))) i  mq  q  q  q,444r!   c            
     (   t               } t        dt        dddd      t        dddd      gi      }t        | |       t	        j
                  |       D ci c]  }|d   |
 }}|d	   d
   dk(  sJ |d   d
   dk(  sJ |d   d
   dk(  sJ y c c}w )Nrx   ry   rz   r{   r   r   r   checku   Mapping-Kandidaten unbestätigtcount2z+Instrumente mit mehreren Mapping-Kandidaten1r   )rv   r   r	   r   r   get_data_quality)ru   r   r   checkss       r   4test_data_quality_center_shows_candidate_review_needr      s    <D#^7IPU\jk7IPU\jk6 % H  x8+/+@+@+FGCc'lCGFG34W=DDD?@ISPPP./8C??? Hs   Bc            
        t               } t        | t        i              | j                  d      j	                         d   dk(  sJ t        dt        dddd	d
      gi      }t        | |       | j                  d      j	                         d   dk(  sJ | j                  d      j	                         d   }t        | |d       | j                  d      j	                         d   dk(  sJ y )Nr   r   r   r   rx   ry   rz   r{   r|   r   r   r   r   r   r   )rv   r   r   rs   r   r	   r   )ru   r   r   s      r   Ctest_missing_provider_symbol_not_resolved_until_candidate_confirmedr      sZ   <D/CB/GH<<vw  A  A  C  DG  H  LM  M  M  M#^6GQXjs  D  OT  [i  7j  6k  %l  mHx8<<vw  A  A  C  DG  H  LM  M  M  M<< ^_hhjkyzLTCXY<<vw  A  A  C  DG  H  LM  M  M  Mr!   )returnNone)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@   rv   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r.   r!   r   <module>r      s    "   ) @ >   V C : >
; 
;_ _ 4 4,$9
PMO	-Q	M@%1
M
5
@	Mr!   