
    pje                        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 d d	lm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Zd!dZdS )"    )annotations)IteratorN)Decimal)
Connection)
TestClient)get_db)
create_app)apply_migrationsreturnr   c                 ~    t          j        dd          } t           j        | _        |                     d           | S )Nz:memory:F)check_same_threadzPRAGMA foreign_keys = ON)sqlite3connectRowrow_factoryexecuteconns    /tests/unit/test_vue_dashboard_v12_acceptance.py_connectr      s8    ?:???D{DLL+,,,K    r   r   c                h     t                      }d fd}||j        t          <   t          |          S )Nr   Iterator[Connection]c               3     K    V  d S N r   s   r   override_dbz_client.<locals>.override_db   s      




r   )r   r   )r	   dependency_overridesr   r   )r   appr   s   `  r   _clientr       sE    
,,C      (3CV$c??r   Nonec                   d}|                      d|f           |                      d|f           |                      d|f           |                      d|f           |                      d|f           |                      d|f           |                      d|f           |                      d	|f           |                      d
|f           |                      d|f           |                      d|f           |                      d|f           |                      d|f           |                                  d S )N2026-05-16T12:00:00ZzINSERT INTO platforms(platform_id, name, platform_type, country, default_currency, created_at) VALUES ('p1', 'Raiffeisen', 'bank', 'CH', 'CHF', ?)zINSERT INTO platforms(platform_id, name, platform_type, country, default_currency, created_at) VALUES ('p2', 'PostFinance', 'broker', 'CH', 'CHF', ?)zINSERT INTO platforms(platform_id, name, platform_type, country, default_currency, created_at) VALUES ('p3', 'True Wealth', 'broker', 'CH', 'CHF', ?)zINSERT INTO accounts(account_id, platform_id, account_name, account_type, currency, created_at) VALUES ('cash1', 'p1', 'Privatkonto', 'cash', 'CHF', ?)zINSERT INTO accounts(account_id, platform_id, account_name, account_type, currency, created_at) VALUES ('broker1', 'p2', 'Depot', 'brokerage', 'CHF', ?)zINSERT INTO accounts(account_id, platform_id, account_name, account_type, currency, created_at) VALUES ('tw1', 'p3', 'Gesamtwert', 'managed_portfolio', 'CHF', ?)zINSERT INTO instruments(instrument_id, asset_class, name, ticker, isin, currency, created_at) VALUES ('usd1', 'etf', 'Vanguard Total Stock Market ETF', 'VTI', 'US9229087690', 'USD', ?)zINSERT INTO instruments(instrument_id, asset_class, name, ticker, isin, currency, created_at) VALUES ('chf1', 'stock', 'Swiss Demo', 'SWD', 'CH0000000000', 'CHF', ?)zINSERT INTO fx_rates(fx_rate_id, base_currency, quote_currency, rate_date, rate, provider, rate_type, quality_status, created_at) VALUES ('fx_usd', 'USD', 'CHF', '2026-05-16', '0.91', 'frankfurter', 'close', 'fresh', ?)zINSERT INTO fx_rates(fx_rate_id, base_currency, quote_currency, rate_date, rate, provider, rate_type, quality_status, created_at) VALUES ('fx_eur', 'EUR', 'CHF', '2026-05-16', '0.98', 'frankfurter', 'close', 'fresh', ?)zwINSERT INTO crypto_wallets(wallet_id, wallet_name, wallet_type, created_at) VALUES ('w1', 'Cold Wallet', 'hardware', ?)zINSERT INTO crypto_assets(asset_id, symbol, coin_name, coingecko_id, created_at) VALUES ('btc', 'BTC', 'Bitcoin', 'bitcoin', ?)zINSERT INTO crypto_holdings(crypto_holding_id, wallet_id, asset_id, quantity, verification_status, created_at) VALUES ('h1', 'w1', 'btc', '0.25', 'ok', ?))r   commit)r   nows     r   _seedr&       sa   
 CLL  f  il  hn  o  o  oLL  i  lo  kq  r  r  rLL  i  lo  kq  r  r  rLL  k  nq  ms  t  t  tLL  l  or  nt  u  u  uLL  u  x{  w}  ~  ~  ~LL  L  OR  NT  U  U  ULL  y  |  {A  B  B  BLL  o  ru  qw  x  x  xLL  o  ru  qw  x  x  xLL  K  NQ  MS  T  T  TLL  S  VY  U[  \  \  \LL  n  qt  pv  w  w  wKKMMMMMr   c            
        t                      } t          |            t          |            t          |           }ddddddddd	d
	}|                    d|                                          }|d         dk    sJ |d         dk    sJ |                    di ||d         dd                                          }|                     d|d         f                                          }|d         dk    sJ |d         dk    sJ |d         dk    sJ |                    d                                          }|d         dk    sJ |d         dk    sJ ddddd ddd!d"d
	}|                    d|                                          }|d         d#k    sJ |                    di ||d         dd                                          }	|                     d$|	d         f                                          }
|
d         dk    sJ |
d         d#k    sJ |                    d%                                          }|d         d#k    sJ d S )&Netfbroker1usd12USD
2026-05-16initial_snapshot100z
manual usd	asset_class
account_idinstrument_idquantitycurrency
trade_datetransaction_typecost_basis_originalnote/api/positions/previewjson	fx_statusok
amount_chfz91.00/api/positions/confirm
preview_idTrA   confirmzkSELECT fx_rate_to_chf, fx_status, gross_amount_chf, net_amount_chf FROM transactions WHERE transaction_id=?	entity_idfx_rate_to_chfz0.91gross_amount_chfz%/api/portfolio/positions/broker1:usd1statuszFX fehltstockchf11CHF10z
manual chf
not_neededzISELECT fx_rate_to_chf, fx_status FROM transactions WHERE transaction_id=?z%/api/portfolio/positions/broker1:chf1)	r   r
   r&   r    postr<   r   fetchoneget)r   clientreqpreview	confirmedtxdetailchfpreview_chfconfirmed_chftx_chf
detail_chfs               r   ;test_position_confirm_resolves_cached_fx_and_chf_not_neededr\   2   sS   ::D'---uT{{{T]]Fy6_bpu  FR  hz  SX  bn  o  oCkk2k==BBDDG;4''''< G++++4;xc;xQXYeQfsw;x;x;xyy~~  A  AI	  D  GP  Q\  G]  F_  
`  
`  
i  
i  
k  
kB6))))k?d"""" !W,,,,ZZ?@@EEGGF+$&&&&(z))))!Vadrw  HT  j|  UY  co  p  pC++6S+AAFFHHK{#|3333KK 8  @A#  @AU`amUn{  @A  @A  @AK  B  B  G  G  I  IM\\ehu  wB  iC  hE  F  F  O  O  Q  QF"#s****+,....CDDIIKKJk"l222222r   c            
        t                      } t          |            t          |            t          |           }|                    d                                          }t          d |D                       }|d         dk    sJ |d         dk    sJ |d         du sJ d	|d
         dddddddd	}|                    d|          }|j        dk    sJ d|j	        
                                v sd|j	        
                                v sJ |                    d|d
          ddddd                                          }|d         dk    sJ |                    d|d
          dddd|d          d!d"                                          }|d#         d$k    sJ |                     d%|d
         f                                          d&         d'k    sJ |                     d(|d
         f                                          d&         d'k    sJ |                    d)                                          }|d*         dk    sJ d+|v sJ d S ),Nz/api/reference/accountsc              3  .   K   | ]}d |d         v |V  dS )zTrue WealthlabelNr   ).0as     r   	<genexpr>zStest_truewealth_is_managed_total_value_account_not_equity_target.<locals>.<genexpr>U   s0      AAA]aj%@%@a%@%@%@%@AAr   valuation_modemanual_total_valueportfolio_bucket
truewealthallow_position_addsFr(   r2   r*   rJ   r,   r-   r.   rL   zmust be blockedr0   r:   r;   i  
gesamtwertzmanual total/api/accounts/z/value/previewz12345.67zmanual TW value)valuation_datetotal_value_chfr9   r=   rM   z/value/confirmrA   T)rj   rk   r9   rA   rC   rG   rT   z?SELECT COUNT(*) FROM account_value_snapshots WHERE account_id=?r      zSSELECT COUNT(*) FROM audit_log WHERE action='account_value_confirm' AND entity_id=?/api/overviewtruewealth_value_chfpostfinance_equity_value_chf)r   r
   r&   r    rP   r<   nextrN   status_codetextlowerr   rO   )	r   rQ   accountstwblocked_reqblockedrS   rT   overviews	            r   @test_truewealth_is_managed_total_value_account_not_equity_targetry   P   s`   ::D'---uT{{{T]]Fzz34499;;H	AAAAA	A	AB#77777 !\1111#$----"'r,7GZ`nq  @E  Ua  wI  bf  pA  B  BKkk2kEEG#%%%%7<--////>W\EWEWEYEY3Y3Y3YYkkK2l+;KKKeq  GQ  [l  Sm  Smk  n  n  s  s  u  uG;<////MR-=MMMgs  IS  ]n  ~E  FR  ~S  `d  Ue  Ue  f  f  k  k  m  mIX+----<<Y\^_k\l[nooxxzz{|}  BC  C  C  C  C<<mprs  qA  pC  D  D  M  M  O  O  PQ  R  VW  W  W  W  Wzz/**//11H*+z9999)X555555r   c                >   t                      }t          |           t          |           ddi G fdd          dd lmc m} |                     |dfd           t          |          }|                    d           d         dk    sJ |	                    dd	d
dd          
                                }d         dk    sJ |d         d         d         d
k    sJ |d         du sJ dt          |                                          vsJ d S )Ncountr   c                  &    e Zd ZdZddd	 fdZdS )
etest_provider_search_endpoint_returns_candidates_and_no_provider_call_on_render.<locals>.FakeProviderfake_providerNr1   querystrr1   
str | Nonec               `    dxx         dz  cc<   ddl m}  |d |pddddd	d
ddd
  
        gS )Nr{   rl   r   CatalogSearchResultr(   zVanguard Total StockUS9229087690VTINYSEARCAr,   r~   highfake)isintickerexchangetrading_currencyprovider
confidencesource"jarvis_finance.market_data.catalogr   )selfr   r1   r   calleds       r   searchzltest_provider_search_endpoint_returns_candidates_and_no_provider_call_on_render.<locals>.FakeProvider.searchq   s    7OOOq OOONNNNNN''k.BUDZaox}  IS  fk  vE  RX  ag  h  h  h  i  ir   r   r   r1   r   __name__
__module____qualname__namer   )r   s   r   FakeProviderr}   o   sO        BF 	i 	i 	i 	i 	i 	i 	i 	i 	i 	ir   r   _provider_search_providersc                                   gS r   r   )r   s   r   <lambda>zatest_provider_search_endpoint_returns_candidates_and_no_provider_call_on_render.<locals>.<lambda>w   s    LLNNCS r   rm    /api/instruments/provider-searchr(   r   r,   r1   r   r5   r;   rl   
candidatesr   selection_requiredTapi_key)r   r
   r&   ,jarvis_finance.services.manual_entry_serviceservicesmanual_entry_servicesetattrr    rP   rN   r<   r   rs   )monkeypatchr   svcrQ   payloadr   r   s        @@r   Otest_provider_search_endpoint_returns_candidates_and_no_provider_call_on_renderr   k   s   ::D'---uT{{{q\Fi i i i i i i i i i ?>>>>>>>>9;S;S;S;STTTT]]F
JJ'?akk<SXchv{C|C|k}}  C  C  E  EG'?a< #H-6666'(D0000CLL..00000000r   c                    t                      } t          |            t          |            d}|                     d|f           |                     d|f           |                     d|f           |                                  t          |           }|                    di                                           }|d         dk    sJ |d	         dk    sJ |d
         dk    sJ |                     d                                          d         dk    sJ |                    ddd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 S )Nr#   zINSERT INTO accounts(account_id, platform_id, account_name, account_type, currency, created_at) VALUES ('review_acc', 'p2', 'True Wealth Review Brokerage', 'brokerage', 'CHF', ?)a  INSERT INTO transactions(transaction_id, transaction_type, account_id, instrument_id, trade_date, quantity, gross_amount_original, net_amount_original, currency_original, source_type, is_confirmed, quality_status, notes, created_at) VALUES ('review_tx', 'initial_position_snapshot', 'review_acc', 'usd1', '2026-05-16', '1', '1', '1', 'USD', 'broker_import_reviewed_snapshot', 1, 'ok', 'review artifact', ?)a  INSERT INTO transactions(transaction_id, transaction_type, account_id, instrument_id, trade_date, quantity, gross_amount_original, net_amount_original, currency_original, source_type, is_confirmed, quality_status, notes, created_at) VALUES ('manual_tx', 'initial_position_snapshot', 'broker1', 'chf1', '2026-05-16', '1', '1', '1', 'CHF', 'vue_manual_position', 1, 'ok', 'real manual', ?)z%/api/cleanup/review-artifacts/previewr;   rt   rl   transactionsmanual_positions_preservedz<SELECT is_active FROM accounts WHERE account_id='review_acc'r   z%/api/cleanup/review-artifacts/confirmTzacceptance cleanuprC   r9   rG   rT   zCSELECT is_voided FROM transactions WHERE transaction_id='review_tx'zCSELECT is_voided FROM transactions WHERE transaction_id='manual_tx')	r   r
   r&   r   r$   r    rN   r<   rO   )r   r%   rQ   rS   rT   s        r   Vtest_cleanup_preview_and_confirm_archives_review_artifacts_preserving_manual_positionsr      s>   ::D'---uT{{{
 CLL  F  IL  HN  O  O  OLL  j  mp  lr  s  s  sLL  W  Z]  Y_  `  `  `KKMMMT]]FkkAkKKPPRRG:!####>"a''''/0A5555<<VWW``bbcdeijjjjjCVZdxJyJyzz  B  BIX+----<<VWW``bbcdeijjjjj<<]^^ggiijklpqqqqq<<]^^ggiijklpqqqqqqqr   c            
        t                      } t          |            t          |            t          |           }ddddddddd	d
	}|                    d|                                          }|                    di ||d         dd           |                    di                                           }|d         du sJ |                    ddddd                                          }|d         dk    sJ |                     d                                          d         dk    sJ |                     d                                          d         dk    sJ |                     d           |                                  |                    di                                           }|d         du sJ |                    dddd d                                          }|d         dk    sJ |                     d!           |                                  |                    di                                           }|d         du sJ |                    dddd"d                                          }	|	d         dk    sJ |                    d|                                          }
|                    di ||
d         dd           |                     d#           |                                  |                    di                                           }|d         d$u sJ d S )%NrH   r)   rI   rJ   rK   r-   r.   rL   z	bad inputr0   r:   r;   r@   rA   TrB   z*/api/positions/broker1:chf1/remove/previewsafe_to_removez*/api/positions/broker1:chf1/remove/confirm	ENTFERNENzwrong position)rC   confirmation_textr9   rG   rT   zLSELECT COUNT(*) FROM transactions WHERE is_voided=1 AND instrument_id='chf1'r   rl   zESELECT COUNT(*) FROM audit_log WHERE action='position_remove_confirm'a  INSERT INTO transactions(transaction_id, transaction_type, account_id, instrument_id, trade_date, quantity, gross_amount_original, net_amount_original, currency_original, fx_rate_to_chf, fx_status, source_type, is_confirmed, quality_status, notes, created_at) VALUES ('legacy_snapshot', 'initial_snapshot', 'broker1', 'usd1', '2026-05-16', '1', '10', '10', 'USD', '0.91', 'ok', 'manual_initial_snapshot', 1, 'ok', 'legacy manual snapshot', '2026-05-16T12:00:00Z')z*/api/positions/broker1:usd1/remove/previewz*/api/positions/broker1:usd1/remove/confirmzlegacy cleanupa  INSERT INTO transactions(transaction_id, transaction_type, account_id, instrument_id, trade_date, quantity, gross_amount_original, net_amount_original, currency_original, fx_rate_to_chf, fx_status, source_type, is_confirmed, quality_status, notes, created_at) VALUES ('manual_adjustment_snapshot', 'manual_adjustment', 'broker1', 'usd1', '2026-05-16', '1', '10', '10', 'USD', '0.91', 'ok', 'manual_dashboard', 1, 'ok', 'manual adjustment snapshot', '2026-05-16T12:00:00Z')zmanual adjustment cleanupa~  INSERT INTO transactions(transaction_id, transaction_type, account_id, instrument_id, trade_date, quantity, gross_amount_original, net_amount_original, currency_original, source_type, is_confirmed, quality_status, notes, created_at) VALUES ('hist_tx', 'buy', 'broker1', 'chf1', '2026-05-17', '1', '10', '10', 'CHF', 'vue_manual_position', 1, 'ok', 'history', '2026-05-17T12:00:00Z')F)	r   r
   r&   r    rN   r<   r   rO   r$   )r   rQ   rR   rS   remove_previewdonelegacy_previewlegacy_doneadjustment_previewadjustment_donepreview2rw   s               r   Dtest_remove_position_voids_single_manual_snapshot_but_blocks_historyr      sE   ::D'---uT{{{T]]F!Vadrw  HT  j|  UY  cn  o  oCkk2k==BBDDG
KK(/l#/lW\EZgk/l/l/lKmmm[[!MTV[WW\\^^N*+t3333;;CVZq|  GW  KX  KX;  Y  Y  ^  ^  `  `D>[((((<<fggpprrstuyzzzzz<<_``iikklmnrsssss 	LL  c  d  d  dKKMMM[[!MTV[WW\\^^N*+t3333++J]a  yD  N^  R_  R_+  `  `  e  e  g  gKx K//// 	LL  l  m  m  mKKMMM%QXZ[[``bb./47777kk"Nae  }H  Rm  Vn  Vnk  o  o  t  t  v  vO8$3333 {{3#{>>CCEEHv{{Sk  squx  sq  IQ  R^  I_  lp  sq  sq  sq{  Hr  Hr  HrLL  R  S  S  SKKMMMkkFRkPPUUWWG#$------r   c                    t                      } t          |            t          |            t          |           }|                    ddddd                                          }|                    dddd|d         d	d
                                          }|d         }|                    d| dd	dd                                          }|d                                                             d          sJ |                    dd	dd                                          }d|d                                         v sJ |                     d          	                                d         dk    sJ |                    ddddddd                                          }|                    dddddd|d         d	d                                          }|d         }	|                    d|	 d d	d!d                                          }
|
d"         d#k    sJ |                     d$          	                                d         d%k    sJ d S )&Nz/api/wallets/previewzEmpty Walletr   new)r   wallet_typer9   r;   z/api/wallets/confirmrA   T)r   r   r9   rA   rC   rD   z/api/wallets/z/delete/confirmemptyr   messageu   wallet gelöschtz/api/wallets/w1/delete/confirmarchivedeaktiviertz9SELECT is_active FROM crypto_wallets WHERE wallet_id='w1'r   z/api/accounts/previewzAnderes KontozManual Broker	brokeragerK   )platform_nameaccount_nameaccount_typer5   r9   z/api/accounts/confirm)r   r   r   r5   r9   rA   rC   ri   z/deactivate/confirmz
not neededrG   rT   zSELECT COUNT(*) FROM audit_log WHERE action IN ('wallet_create_confirm','wallet_delete_confirm','wallet_deactivate_confirm','account_create_confirm','account_deactivate_confirm')   )
r   r
   r&   r    rN   r<   rs   
startswithr   rO   )r   rQ   wallet_previewwalletwiddeletednonemptyaccount_previewaccountaiddeactivateds              r   Btest_wallet_and_account_create_deactivate_delete_rules_are_auditedr      sT   ::D'---uT{{{T]]F[[!7~fpz  ?A  ?A[  B  B  G  G  I  IN[[/~^hrw  HV  Wc  Hd  qu  7v  7v[  w  w  |  |  ~  ~F

Ckk>#>>>QU_fEgEgkhhmmooG9##%%001CDDDDD{{;d\eBfBf{ggllnnHHY/55777777<<STT]]__`abfgggggkk"9Ra  tC  U`  ns  }B  AC  ACk  D  D  I  I  K  KOkk1/kz  MX  fk  uz  JY  Zf  Jg  tx  9y  9yk  z  z      A  AG
+
C++GsGGGZ^htNuNu+vv{{}}Kx K////<<  M  N  N  W  W  Y  Y  Z[  \  `a  a  a  a  a  a  ar   c                4   t                      }t          |           t          |            G d d           G d d          dd lmc m} |                     |dfd           t          |          }|                    dd	d
dddddd          	                                }t          |d                   dk    sJ |d         d         }|d         d
k    sJ |d         dk    sJ |d         dk    sJ |d         sJ |d         dk    sJ |d         dk    sJ |d         dk    sJ |d         dk    sJ |d         sJ |d         dk    sJ |d          d!k    sJ |d"         d#k    sJ d$|d%         v r
d&|d%         v sJ |d'         d(v sJ d S ))Nc                       e Zd ZdZddd	dZdS )
Xtest_provider_search_deduplicates_enriches_filters_and_ranks_goog.<locals>.FakeProviderAopenfigiNr   r   r   r1   r   c                   ddl m}  |di dddddd	d
ddddddd	dddddddddddddddddd d!d" |d d#d$d%dd&d'dd(d&d)ddd*d*+          gS ),Nr   r   )NrH   zALPHABET INC-CL Cr   US02079K1079r   GOOGr   NASDAQr   r,   r   r   provider_symbolBBG009S3NB30provider_marketcountryUSr   mediumr   evidence_notezprimary listing
last_price175.12price_currency
price_dater-   security_typeCommon Stockexchange_namezNasdaq Global SelectmicXNASrH   zALPHABET INC - CDRCA02079K3055NEOCADBBGCDRCACDR)r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r1   r   s       r   r   z_test_provider_search_deduplicates_enriches_filters_and_ranks_goog.<locals>.FakeProviderA.search   s   NNNNNN##  Q  Q  Q^^  Qdjdj  Qu}u}  Q  QV  QV  Q  ak  ak  Q  }K  }K  Q  ]e  ]e  Q  os  os  Q  @H  @H  Q  Q[  Q[  Q  k|  k|  Q  IQ  IQ  Q  bg  bg  Q  t@  t@  Q  P^  P^  Q  nD  nD  Q  JP  JP  Q##D'3Gnekv{  OT  _i  {C  UZ  dh  u}  FP  `e  uz  {  {  { r   r   r   r   r   r   FakeProviderAr      s:        BF 	 	 	 	 	 	 	 	r   r   c                       e Zd ZdZddd	dZdS )
Xtest_provider_search_deduplicates_enriches_filters_and_ranks_goog.<locals>.FakeProviderBfinnhubNr   r   r   r1   r   c                   ddl m}  |di dddddd	d
ddddddd	ddddddddddddddddddd d! |d d"d#d$d%d&dd'd(dd)*          gS )+Nr   r   )NrH   Alphabet Inc Class Cr   r   r   r   r   r   r   r,   r   r   r   r   r   r   r   r   r   r   zsymbol lookupr   z175.10r   r   r-   r   r   r   Nasdaqr   r   rH   zGoogol Technology Co Ltd8118HKEXHKDHKlowzweak name match)r   r   r   r   r   r   r   r   r   r   s       r   r   z_test_provider_search_deduplicates_enriches_filters_and_ranks_goog.<locals>.FakeProviderB.search   s   NNNNNN##  z  z  zP^P^  zgmgm  z  yA  yA  z  TY  TY  z  dm  dm  z  E  E  z  W_  W_  z  im  im  z  zB  zB  z  KT  KT  z  ds  ds  z  @H  @H  z  Y^  Y^  z  kw  kw  z  GU  GU  z  em  em  z  sy  sy  z##D'3MV\gm  AF  QZ  dh  uz  CL  \m  n  n  n r   r   r   r   r   r   FakeProviderBr      s:        BF 	 	 	 	 	 	 	 	r   r  r   r   c                 ,                               gS r   r   )r   r  s   r   r   zStest_provider_search_deduplicates_enriches_filters_and_ranks_goog.<locals>.<lambda>   s    MMOOUbUbUdUdCe r   r   rH   r   r,   r   r   T)r1   r   r5   r   r   main_listing_onlyhide_cdr_adr_derivativesr;   r   rl   r   r   r   r   r   r   r   r5   r   r   r   r   r   r   r-   r   r   r   r   r   confidence_label>   	EindeutigWahrscheinlich)r   r
   r&   r   r   r   r   r    rN   r<   len)r   r   r   rQ   r   googr   r  s         @@r   Atest_provider_search_deduplicates_enriches_filters_and_ranks_googr
     s   ::D'---uT{{{               ?>>>>>>>>9;e;e;e;e;efffT]]Fkk<SZeky~  MU  bf  }A  _c  Dd  Ddk  e  e  j  j  l  lGw|$%%****< #D>V####<>))))
x''''    ;&    
u$$$$	?d"""" N2222 !U****----!"n4444j)))i4
;K.K.K.KK"#'FFFFFFFr   c                   t                      }t          |           t          |            G d d           G d d          dd lmc m} |                     |dfd           t          |          }|                    dd	d
dd          	                                }|d         sJ |d         dgk    sJ dt          |          vsJ dt          |          vsJ d S )Nc                       e Zd ZdZddd	dZdS )
btest_provider_search_suppresses_raw_provider_errors_when_candidate_exists.<locals>.WorkingProviderr   Nr   r   r   r1   r   c               B    ddl m}  |d |pddddddd	dd
dd	          gS )Nr   r   rH   r   r   r   r   r,   r   r   r   )	r   r   r   r   r   r   r   r   r   r   r   s       r   r   zitest_provider_search_suppresses_raw_provider_errors_when_candidate_exists.<locals>.WorkingProvider.search  s    NNNNNN''k.DWF\cq  {A  LT  gl  wA  SY  cg  tz  CM  N  N  N  O  Or   r   r   r   r   r   WorkingProviderr    sB        BF 	O 	O 	O 	O 	O 	O 	O 	Or   r  c                       e Zd ZdZddd	dZdS )
atest_provider_search_suppresses_raw_provider_errors_when_candidate_exists.<locals>.BrokenProviderbroken_providerNr   r   r   r1   r   c                    t          d          )Nz1upstream HTTP 500 secret-ish raw provider failure)RuntimeErrorr   r   r1   s      r   r   zhtest_provider_search_suppresses_raw_provider_errors_when_candidate_exists.<locals>.BrokenProvider.search  s    RSSSr   r   r   r   r   r   BrokenProviderr    sB         BF 	T 	T 	T 	T 	T 	T 	T 	Tr   r  r   r   c                 ,                               gS r   r   )r  r  s   r   r   z[test_provider_search_suppresses_raw_provider_errors_when_candidate_exists.<locals>.<lambda>  s    OODUDUWeWeWgWgCh r   r   rH   r   r,   r   r;   r   warningsue   Datenquelle teilweise eingeschränkt: Ein Provider lieferte keine Daten; Treffer stammt aus openfigi.zHTTP 500zraw provider failure)r   r
   r&   r   r   r   r   r    rN   r<   r   )r   r   r   rQ   r   r  r  s        @@r   Itest_provider_search_suppresses_raw_provider_errors_when_candidate_existsr    s   ::D'---uT{{{O O O O O O O OT T T T T T T T
 ?>>>>>>>>9;h;h;h;h;hiiiT]]Fkk<SZeky~CCk  A  A  F  F  H  HG<    :  $K  #L  L  L  L  LS\\))))!W555555r   c                p   t                      }t          |           t          |            G d d          dd lmc m} |                     |dfd           t          |          }|                    dddd	
          	                                }|d         g k    sJ |d         dgk    sJ d S )Nc                       e Zd ZdZddd	dZdS )
Ptest_provider_search_no_candidates_has_clear_user_warning.<locals>.EmptyProviderempty_providerNr   r   r   r1   r   c                   g S r   r   r  s      r   r   zWtest_provider_search_no_candidates_has_clear_user_warning.<locals>.EmptyProvider.search"  s    Ir   r   r   r   r   r   EmptyProviderr     s:        BF 	 	 	 	 	 	 	 	r   r  r   r   c                                   gS r   r   )r  s   r   r   zKtest_provider_search_no_candidates_has_clear_user_warning.<locals>.<lambda>&  s    MMOOCT r   r   rH   DOESNOTEXIST)r1   r   r;   r   r  u,   Keine verlässlichen Providerdaten gefunden.)
r   r
   r&   r   r   r   r   r    rN   r<   )r   r   r   rQ   r   r  s        @r   9test_provider_search_no_candidates_has_clear_user_warningr"    s    ::D'---uT{{{       
 ?>>>>>>>>9;T;T;T;TUUUT]]Fkk<SZesCtCtkuuzz||G< B&&&&:#Q"RRRRRRRr   c            
        t                      } t          |            t          |            d}|                     d||f           |                                  t          |           }ddddddd	d
dd	}|                     d                                          d         }|                    d|                                          }|d         	                    d          sJ |                     d                                          d         |k    sJ |                    di ||d         dd                                          }|                     d|d         f                                          }|d         dk    sJ |                     d|d         f                                          }t          |          dddddd d!k    sJ |                     d"|d         f                                          }	|	d#         d$k    sJ |	d%         dk    sJ |	d&         d k    sJ |                    d'                                          }
t          d( |
D                       }|d%         dk    sJ |d)         d*k    sJ |d+         J |                     d,                                          d         d-k    sJ d S ).Nr#   a  
        INSERT INTO instrument_catalog_entries(catalog_entry_id, asset_class, name, normalized_name, isin, ticker, exchange, trading_currency, instrument_currency, provider, provider_symbol, provider_market, country, source, source_confidence, last_price, price_currency, price_date, created_at, updated_at)
        VALUES ('cat_goog', 'stock', 'ALPHABET INC-CL C', 'alphabet inc cl c', 'US02079K1079', 'GOOG', 'NASDAQ', 'USD', 'USD', 'openfigi', 'BBG009S3NB30', 'NASDAQ', 'US', 'openfigi', 'high', '175.12', 'USD', '2026-05-16', ?, ?)
    rH   r)   cat_googr+   r,   r-   r.   r/   zprovider candidate)	r1   r2   candidate_idr4   r5   r6   r7   r8   r9   z:SELECT COUNT(*) FROM instruments WHERE isin='US02079K1079'r   r:   r;   summaryALPHABETr@   rA   TrB   zPSELECT instrument_id, currency_original FROM transactions WHERE transaction_id=?rD   currency_originalzvSELECT ticker, isin, exchange, currency, provider_symbol, data_provider_primary FROM instruments WHERE instrument_id=?r3   r   r   r   r   r   )r   r   r   r5   r   data_provider_primaryzISELECT close, currency, provider FROM market_prices WHERE instrument_id=?closer   r5   r   z/api/equity/positionsc              3  2   K   | ]}|d          dk    |V  dS )r   r   Nr   )r`   rows     r   rb   z\test_provider_candidate_preview_confirm_materializes_instrument_and_audit.<locals>.<genexpr>I  s0      EECS]f-D-DC-D-D-D-DEEr   rG   Bewertetmarket_value_chfz>SELECT COUNT(*) FROM audit_log WHERE action='position_confirm'rl   )r   r
   r&   r   r$   r    rO   rN   r<   r   dictrP   rp   )r   r%   rQ   rR   beforerS   rT   rU   instpriceequitygoog_rows               r   Itest_provider_candidate_preview_confirm_materializes_instrument_and_auditr5  /  s   ::D'---uT{{{
 CLL  s   	KKMMMT]]F!Jdguz  KW  m  X]  g{  |  |C\\VWW``bbcdeFkk2k==BBDDG9((44444<<TUU^^``abcgmmmmm4;xc;xQXYeQfsw;x;x;xyy~~  A  AI	hkt  vA  lB  kD  
E  
E  
N  
N  
P  
PB!"e++++<<  Q  TV  Wf  Tg  Si  j  j  s  s  u  uD::FNPXfk  AO  jt  u  u  u  u  u  uLLdgijygzf|}}  G  G  I  IE>X%%%%%%%%
****ZZ/005577FEE6EEEEEHJ5((((H++++&'333<<XYYbbddefgklllllllr   c                    t                      } t          |            t          |            |                     dd           |                     d           |                                  t          |           }|                    d                                          }|d         d         dk    sJ |d         d         d	k    sJ |d
                             d          sJ d S )N5UPDATE crypto_assets SET notes=? WHERE asset_id='btc')z{"coingecko": {"market_cap_rank": 1, "market_cap": "2000000000000", "volume_24h": "50000000000", "change_24h_pct": "2.50", "change_7d_pct": "5.00", "homepage": "https://bitcoin.org", "image_url": "https://example.test/btc.png"}}zINSERT INTO crypto_prices(crypto_price_id, asset_id, coingecko_id, price_currency, price, provider, fetched_at, quality_status) VALUES ('cp1', 'btc', 'bitcoin', 'CHF', '80000', 'coingecko_cache', '2026-05-16T12:00:00Z', 'fresh')/api/crypto/positions/btccoingecko_infomarket_cap_rankrl   homepagezhttps://bitcoin.orgread_only_notezLive-Modus optional)	r   r
   r&   r   r$   r    rP   r<   r   r   rQ   rV   s      r   Ftest_crypto_detail_exposes_cached_coingecko_info_without_provider_callr>  P  s    ::D'---uT{{{LLH  Kt  u  u  uLL  x  y  y  yKKMMMT]]FZZ34499;;F"#$56!;;;;"#J/3HHHHH"#../DEEEEEEEr   c                 ^   t                      } t          |            t          |            |                     dd           |                                  t          |           }|                    d                                          }|d         d         J |d         d         J d S )Nr7  )zZ{"coingecko": {"homepage": "javascript:alert(1)", "image_url": "data:image/svg+xml,evil"}}r8  r9  r;  	image_url)r   r
   r&   r   r$   r    rP   r<   r=  s      r   2test_crypto_detail_sanitizes_cached_coingecko_urlsrA  _  s    ::D'---uT{{{LLH  Kj  k  k  kKKMMMT]]FZZ34499;;F"#J/777"#K088888r   )r   r   )r   r   r   r   )r   r   r   r!   )r   r!   )
__future__r   collections.abcr   r   decimalr   r   fastapi.testclientr   jarvis_finance.api.dependenciesr   jarvis_finance.api.mainr	   !jarvis_finance.storage.migrationsr
   r   r    r&   r\   ry   r   r   r   r   r
  r  r"  r5  r>  rA  r   r   r   <module>rI     s   " " " " " " $ $ $ $ $ $              ) ) ) ) ) ) 2 2 2 2 2 2 . . . . . . > > > > > >         $3 3 3 3<6 6 6 661 1 1 10r r r r,#. #. #. #.La a a a.*G *G *G *GZ6 6 6 64S S S S$m m m mBF F F F	9 	9 	9 	9 	9 	9r   