
    mjk                       d dl mZ d dlZd dlmc mZ d dlm	Z	 d dl
m
Z
mZ d dl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lmZ d dlmZm Z m!Z!m"Z"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- dZ.dNdOdZ/dPdZ0e.dddQd$Z1dRd%Z2ddddddd&dSd/Z3dRd0Z4dTdUd4Z5dVd6Z6dWd;Z7dXd<Z8dXd=Z9dXd>Z:dXd?Z;dXd@Z<dXdAZ=dYdBZ>dXdCZ?dPdDZ@dXdEZAdXdFZBdXdGZCdXdHZDdXdIZEdXdJZFdZdKZGdXdLZHdXdMZIdS )[    )annotationsN)ThreadPoolExecutor)datetime	timedelta)Path)
TestClient)run_postfinance_source_contract)+run_portfolio_market_analytics_v1_scenarios)#run_sprint9_fx_fmp_history_contract)get_db)
create_app)portfolio_data)build_portfolio_reconciliationconfirm_ingestioningestion_historylist_data_sourcespreview_ingestion)build_portfolio_performance)!set_performance_cashflow_coverage$set_performance_scope_classification)connect)MIGRATION_VERSIONapply_migrationsz2026-07-23T12:00:00+00:00pathPath | Nonereturnsqlite3.Connectionc                d    t          | pd          }t          |           t          |           |S )Nz:memory:)r   r   seed_registry)r   conns     c/home/agent/.hermes/repos/FinanceManager/tests/unit/test_portfolio_data_ingestion_reconciliation.pydatabaser"   $   s5    4%:&&DT$K    r    Nonec                   |                      dt          f           dD ]^\  }}}}|                      d|d||t          f           t          | |d|ddt                     t          | |d	d
dddt                     _|                      dt          f           |                      dt          f           |                                  d S )NzcINSERT INTO platforms(platform_id,name,platform_type,created_at) VALUES('p','Synthetic','broker',?)))azAKB Haushaltskonto	brokeragepostfinance_etrading_depot)bzRaiffeisen Transferkontor'   postfinance_etrading_cash)totalzSynthetic Totalwertrobo_advisorcrypto_portfoliozINSERT INTO accounts(account_id,platform_id,account_name,account_type,currency,performance_included,is_active,created_at)
               VALUES(?,?,?,?, 'CHF',0,1,?)pTsynthetic_test_fixturezNExplicit synthetic investment role; account names are intentionally irrelevant)
account_idincludedclassification_rolesourcenoteclassified_atz
1900-01-01z
2100-12-31completez#Complete synthetic cashflow history)r0   coverage_fromcoverage_tostatusr3   r4   recorded_atzINSERT INTO instruments(instrument_id,asset_class,name,ticker,isin,exchange,currency,is_active,created_at)
           VALUES('i','equity','Synthetic Asset','SYN','CH0000000001','SIX','CHF',1,?)zINSERT INTO instruments(instrument_id,asset_class,name,ticker,isin,exchange,currency,is_active,created_at)
           VALUES('eur','equity','Synthetic EUR Asset','EURX','CH0000000002','SIX','EUR',1,?))executeNOWr   r   commit)r    r0   nameaccount_typeroles        r!   r   r   +   s    LLvy|x~1 
 
,
D,
 	/1;S$VY0Z	
 	
 	
 	-! $+a	
 	
 	
 	
 	*!&$+6		
 		
 		
 		
 		
 	LL	Z\_[a   	LL	acfbh   	KKMMMMMr#   )createdupdatedsnapshot_idstraccountatvaluerA   rB   
str | Nonec          	     f    |                      d||||||f           |                                  d S )NzINSERT INTO account_value_snapshots(snapshot_id,account_id,valuation_date,total_value_chf,currency,source_type,quality_status,created_at,updated_at)
           VALUES(?,?,?,?,'CHF','manual_total_value','ok',?,?))r;   r=   )r    rC   rE   rF   rG   rA   rB   s          r!   
add_legacyrJ   T   sF    LL	BDOQXZ\^celnuCv   	KKMMMMMr#   c           	     p    |                      d|||||t          f           |                                  d S )NzINSERT INTO cash_account_snapshots(snapshot_id,account_id,snapshot_type,balance_date,amount_original,currency,amount_chf,source,created_at)
           VALUES(?,?, 'reconciliation', ?,?,'CHF',?,'manual',?)r;   r<   r=   r    rC   rE   rF   rG   s        r!   add_cashrN   \   sF    LL	DFQSZ\^`eglnqEr   	KKMMMMMr#   )
instrumentquantitygrossnetrow_hashtransfer_grouptransaction_idkindrO   rP   rQ   rR   rS   rT   c                   |                      d|||||||||||	pd| |
t          f           |                                  d S )Na  INSERT INTO transactions(transaction_id,transaction_type,activity_kind,account_id,instrument_id,trade_date,
             event_timestamp,quantity,gross_amount_original,net_amount_original,currency_original,fx_rate_to_chf,
             fx_status,source_type,source_id,row_hash,is_confirmed,quality_status,internal_transfer_group_id,created_at)
           VALUES(?,?,?,?,?,?,?,?,?,?,'CHF','1','ok','fixture','fixture',?,1,'ok',?,?)zhash-rL   )r    rU   rV   rE   rF   rO   rP   rQ   rR   rS   rT   s              r!   add_transactionrX   d   sq    
 	LL	Z 
tWj"b(ESVX`X|d|lzd|d|  M  OR  	S   	KKMMMMMr#   c           	     p    |                      d|||||t          f           |                                  d S )Nae  INSERT INTO portfolio_valuation_snapshots(snapshot_id,scope_kind,scope_id,account_id,value_original,currency,
             base_currency,fx_rate_to_base,fx_direction,valuation_at,source,captured_at,snapshot_version,quality_status,reason_codes_json)
           VALUES(?, 'account', ?, ?, ?, 'CHF','CHF','1','original_to_base',?,'fixture',?,1,'complete','[]')rL   rM   s        r!   add_canonical_valuationrZ   s   sC    LL	p 
gwr37	   	KKMMMMMr#   legacy_account_valuesr3   dict[str, object]c                    | dd ddt           dS )N	portfolio
2025-01-01
2025-12-31
source_key
scope_kindr0   period_from	period_todata_cutoff)r<   )r3   s    r!   requestrg   }   s,     4`l  |H  Y\  ]  ]  ]r#   previewc                H     i  fddD              fddD             ddiS )Nc                "    i | ]}||         S  rk   .0keyrh   s     r!   
<dictcomp>z#confirm_payload.<locals>.<dictcomp>   s    
~
~
~3
~
~
~r#   ra   c                "    i | ]}||         S rk   rk   rl   s     r!   ro   z#confirm_payload.<locals>.<dictcomp>   s1      Y  Y  Y3  Y  Y  Yr#   )
preview_idconfirmation_idpreview_created_atsource_revisioninput_fingerprintpayload_hashconfirmTrk   )rh   s   `r!   confirm_payloadrx      sp    
~
~
~
~(}
~
~
~ Y  Y  Y  Y  )X  Y  Y  Y 	4  r#   tmp_pathr   monkeypatchpytest.MonkeyPatchc           
     
   t                      }d}t          |k    }|st          j        d|fdt          |f          dt	          j                    v st          j        t                    rt          j        t                    ndt          j        |          dz  }dd|iz  }t          t          j	        |                    d x}}|
                    d                                          d	         }|t          k    }|st          j        d|fd
|t          f          t          j        |          dt	          j                    v st          j        t                    rt          j        t                    nddz  }dd|iz  }t          t          j	        |                    d x}}d |
                    d          D             }h d}||k    }|slt          j        d|fd||f          t          j        |          t          j        |          dz  }	dd|	iz  }
t          t          j	        |
                    d x}x}}|j
        }d} ||          }|j        } |            }|sddt	          j                    v st          j        |          rt          j        |          ndt          j        |          t          j        |          t          j        |          t          j        |          t          j        |          dz  }t          t          j	        |                    d x}x}x}x}}t          |dddd           t          |t          t          |t!                                                    }t#          j        t&          j        d          5  |
                    d|d         f           d d d            n# 1 swxY w Y   t#          j        t&          j        d           5  |
                    d!|d         f           d d d            n# 1 swxY w Y   t#          j        t&          j        d"          5  |
                    d#|d         f           d d d            n# 1 swxY w Y   t#          j        t&          j        d$          5  |
                    d%|d         f           d d d            n# 1 swxY w Y   t+          | d&z             t-          | d'z  |           d S )(N1   ==z%(py0)s == %(py3)sr   py0py3assert %(py5)spy5z*SELECT MAX(version) FROM schema_migrationsr   )z%(py1)s == %(py3)s)py1r   c                    h | ]
}|d          S )   rk   rm   rows     r!   	<setcomp>z[test_migrations_41_to_43_are_additive_and_ingestion_history_is_immutable.<locals>.<setcomp>   s    [[[sCF[[[r#   z,PRAGMA table_info(instrument_price_mappings)>   source_venuesource_symbolsource_currency>=z%(py1)s >= %(py4)sr   py4assert %(py6)spy6zXSELECT name FROM sqlite_master WHERE type='table' AND name='portfolio_ingestion_batches'zassert %(py10)s
{%(py10)s = %(py8)s
{%(py8)s = %(py6)s
{%(py6)s = %(py2)s
{%(py2)s = %(py0)s.execute
}(%(py4)s)
}.fetchone
}()
}r    )r   py2r   r   py8py10legacyr&   r`   1000	immutablematchzJUPDATE portfolio_ingestion_batches SET status='confirmed' WHERE batch_id=?batch_idzcannot be deletedz6DELETE FROM portfolio_ingestion_items WHERE batch_id=?zaudit is immutablez7UPDATE audit_log SET action='changed' WHERE entity_id=?zaudit cannot be deletedz'DELETE FROM audit_log WHERE entity_id=?zmarket-analyticszsprint9-history)r"   r   
@pytest_ar_call_reprcompare@py_builtinslocals_should_repr_global_name	_safereprAssertionError_format_explanationr;   fetchonerJ   r   rx   r   rg   pytestraisessqlite3DatabaseErrorr
   r   )ry   rz   r    @py_assert2@py_assert1@py_format4@py_format6@py_assert0@py_assert3@py_format5@py_format7@py_assert5@py_assert7@py_assert9@py_format11results                   r!   Htest_migrations_41_to_43_are_additive_and_ingestion_history_is_immutabler      s    ::D """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""<<DEENNPPQRShSWhhhhhhhhhhhSWhhhhhhShhhhhhhhhhhWhhhhhhWhhhhhhhhhhhhhhhhhhhhhhhhhhhh[[dll+YZZ[[[  ` ` ` [ `        [ `     \   `                          <~r~<<rss~s|~||~~~~~~~~~~~~~~~4~~~~~4~~~~~~<~~~~r~~~~s~~~~|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~tXsL&999t_5FtWYY5W5W%X%XYYF	w,K	@	@	@ z zadjkudvcxyyyz z z z z z z z z z z z z z z	w,4G	H	H	H f fMPVWaPbOdeeef f f f f f f f f f f f f f f	w,4H	I	I	I g gNQWXbQcPefffg g g g g g g g g g g g g g g	w,4M	N	N	N W W>
AS@UVVVW W W W W W W W W W W W W W W/;M0MNNN'3D(DkRRRRRsH   (OOO=P''P+.P+Q<<R R 'SSSc                 
   t                      } t          | dddd           t          | dddd           t          | ddddt          	           | j        }t	          | t                                }| j        }||k    }|st          j        d
|fd||f          dt          j	                    v st          j
        |           rt          j        |           ndt          j        |          dt          j	                    v st          j
        |          rt          j        |          nddz  }dd|iz  }t          t          j        |                    d x}}|d         }dddddddd}||k    }|slt          j        d
|fd||f          t          j        |          t          j        |          dz  }dd|iz  }t          t          j        |                    d x}x}}|d         d         }d}||k    }|slt          j        d
|fd||f          t          j        |          t          j        |          dz  }dd|iz  }t          t          j        |                    d x}x}}|d         }t          |          }d}	||	k    }
|
st          j        d
|
fd||	f          dt          j	                    v st          j
        t                    rt          j        t                    ndt          j        |          t          j        |          t          j        |	          dz  }d d!|iz  }t          t          j        |                    d x}x}x}
}	d" |d#         D             }t          |          }|sd$d%t          j	                    v st          j
        t                    rt          j        t                    nd%t          j        |          t          j        |          dz  }t          t          j        |                    d x}}t!          | t#          |                    }|d&         }d}||k    }|slt          j        d
|fd||f          t          j        |          t          j        |          dz  }dd|iz  }t          t          j        |                    d x}x}}|                     d'|d(         f                                          d         }d}||k    }|slt          j        d
|fd||f          t          j        |          t          j        |          dz  }dd|iz  }t          t          j        |                    d x}x}}d S ))Noner&   r`   r   	duplicateblockedr)   900)rB   r~   )z5%(py2)s
{%(py2)s = %(py0)s.total_changes
} == %(py4)sr    before)r   r   r   r   r   countsr   r      )new	unchangedr   	ambiguousr   	versioned
discoveredz%(py1)s == %(py4)sr   quality_impactr9   partialrv   @   z0%(py4)s
{%(py4)s = %(py0)s(%(py2)s)
} == %(py7)slenr   r   r   py7assert %(py9)spy9c              3  *   K   | ]}d |d         vV  dS )/source_record_refNrk   rm   items     r!   	<genexpr>zbtest_preview_is_storage_free_and_classifies_new_duplicate_blocked_and_unchanged.<locals>.<genexpr>   s-      QQs$233QQQQQQr#   itemsz,assert %(py4)s
{%(py4)s = %(py0)s(%(py2)s)
}allwritten_recordsz?SELECT COUNT(*) FROM portfolio_ingestion_items WHERE batch_id=?r   )r"   rJ   r<   total_changesr   rg   r   r   r   r   r   r   r   r   r   r   r   rx   r;   r   )r    r   rh   r   r   r   r   r   r   @py_assert6r   @py_format8@py_format10	confirmeds                 r!   Otest_preview_is_storage_free_and_classifies_new_duplicate_blocked_and_unchangedr      s   ::DtUCv666t[#|V<<<tY\5#FFFFFgii00G'''''''''''''''''''''''4'''''4'''''''''''''''''''''''''''''''''''''''''''''''''8  JXYfgvw  HI  !J  !J  J  !J  J  J  J  J  J  J  J  J  J  J  !J  J  J  J  J  J  J  J  J  J  !J  J  J  J  J  J  J  J  J  J  J  J  J  J  J  J  J  J  J  J  J  J  J  J  J  J  J  J#$X.;);.);;;;;;;;;;.);;;;;.;;;;);;;;;;;;;;;;;;;;;;;;;;;;;;;~&-3&''-2-'2----------'2------------3-----3------&----'----2-----------------------------QQ@PQQQQ3QQQQQQQQQQQQQQQQ3QQQQQ3QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ!$(@(@AAI&',1,'1,,,,,,,,,,'1,,,,,',,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,<<Y\efp\q[stt}}  AB  C  H  GH  H  C  GH  H  H  H  H  H  H  H  H  H  H  C  GH  H  H  H  H  H  C  H  H  H  H  GH  H  H  H  H  H  H  H  H  H  H  H  H  H  H  H  H  H  H  H  H  H  H  H  H  H  H  H  H  Hr#   c                 X
   t                      } t          | dddd           t          | t                                }t	          |          }t          | |          }t          | |          }g }|d         }d}||u }|}	|r|d         }
d}|
|k    }|}	|	st          j        d	|fd
||f          t          j        |          t          j        |          dz  }dd|iz  }|	                    |           |r`t          j        d|fd|
|f          t          j        |
          t          j        |          dz  }dd|iz  }|	                    |           t          j
        |d          i z  }dd|iz  }t          t          j        |                    d x}	x}x}x}x}x}
x}}|d         |d         dd}||k    }|st          j        d|fd||f          dt          j                    v st          j        |          rt          j        |          ndt          j        |          dz  }dd|iz  }t          t          j        |                    d x}}|                     d                                          d         }	d}|	|k    }|slt          j        d|fd |	|f          t          j        |	          t          j        |          d!z  }d"d#|iz  }t          t          j        |                    d x}	x}}|                     d$|d         f                                          d         }	d}|	|k    }|slt          j        d|fd |	|f          t          j        |	          t          j        |          d!z  }d"d#|iz  }t          t          j        |                    d x}	x}}t          | t                                }g }|d%         d&         }d}||k    }|}	|r|d%         d'         }
d}|
|k    }|}	|	st          j        d|fd(||f          t          j        |          t          j        |          dz  }dd|iz  }|	                    |           |r`t          j        d|fd|
|f          t          j        |
          t          j        |          dz  }dd|iz  }|	                    |           t          j
        |d          i z  }dd|iz  }t          t          j        |                    d x}	x}x}x}x}x}
x}}t%                       d S ))Nr   r&   r`   r   
idempotentFr   r   is)z%(py3)s is %(py6)s)r   r   z%(py8)sr   r~   )z%(py11)s == %(py14)s)py11py14z%(py16)spy16r   zassert %(py19)spy19r   audit_idTr   r   r   r   secondr   r   r   zaSELECT COUNT(*) FROM portfolio_valuation_snapshots WHERE source='ingestion:legacy_account_values'r   r   r   r   z0SELECT COUNT(*) FROM audit_log WHERE entity_id=?r   r   r   )z%(py3)s == %(py6)s)r"   rJ   r   rg   rx   r   r   r   r   append_format_boolopr   r   r   r   r   r;   r   r	   )r    rh   payloadfirstr   r   r   r   @py_assert4r   @py_assert10@py_assert13@py_assert12r   @py_format9@py_format15@py_format17@py_format18@py_format20r   r   r   r   freshs                           r!   Otest_confirm_is_atomic_audited_idempotent_and_second_fresh_preview_is_unchangedr      s   ::DtXsL&999gii00Gg&&GdG,,EtW--FII5I%I%'IIIIIE2C,DII,D,IIIIIIIIIIII%IIIIIIIII%IIIIIIIIIIIIIIIIIIIIIIIIIII,DIIIII,DIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII"'
"3zARbfggg6ggggggggggg6ggggggggggggg6ggggg6gggggggggggggggggggggggggggggggg<<{||  F  F  H  H  IJ  K  P  OP  P  K  OP  P  P  P  P  P  P  P  P  P  P  K  OP  P  P  P  P  P  K  P  P  P  P  OP  P  P  P  P  P  P  P  P  P  P  P  P  P  P  P  P  P  P  P  P  P  P  P  P  P  P  P<<JUS]M^L`aajjllmnotsttostttttttttttosttttttottttsttttttttttttttttttttttttttttdGII..ELL5?;'L1L'1,LLLLLx1GL1L1G11LLLLLLLLLLLL'1LLLLL'LLLL1LLLLLLLLLLLLLLLLLLLLLLLLLLL1G1LLLLL1GLLLL1LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#%%%%%r#   c                 p   t                      } t          | dddd           t          | t                                }t	          |          }t          | |           t          |          }d|d<   t          j        t          d          5  t          | |           d d d            n# 1 swxY w Y   t          | t                                }t          | d	d
ddd           t          j        t          d          5  t          | t	          |                     d d d            d S # 1 swxY w Y   d S )Nr   r&   r`   r   z
2025-02-01rd      verändertem Inhaltr   laterr)   5002026-01-01T00:00:00+00:00rA   zveraltet|Ausgangsrevision)
r"   rJ   r   rg   rx   r   dictr   r   
ValueError)r    rh   r   changedpreview2s        r!   Ltest_confirmation_identity_rejects_changed_payload_and_stale_source_revisionr     s   ::DtXsL&999gii00Gg&&GdG$$$7mmG)GM	z)>	?	?	? ) )$((() ) ) ) ) ) ) ) ) ) ) ) ) ) ) wyy11HtWc<@[\\\\	z)D	E	E	E ; ;$ 9 9:::; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;s$   B))B-0B- D++D/2D/c                 &   t                      } t          | dddd           t          | t                      d          }t	          j        t          d          5  t          | t          |                     d d d            d S # 1 swxY w Y   d S )	Nr   r&   r`   r   z2020-01-01T00:00:00+00:00)rs   
abgelaufenr   )	r"   rJ   r   rg   r   r   r  r   rx   )r    rh   s     r!    test_expired_preview_is_rejectedr     s    ::DtXsL&999giiD_```G	z	6	6	6 : :$ 8 8999: : : : : : : : : : : : : : : : : :s   BB
B
c            
        t                      } t          | ddddd           t          | t          t	          | t                                                     t          | ddddd	           t	          | t                                }|d
         d         }d}||k    }|slt          j        d|fd||f          t          j        |          t          j        |          dz  }dd|iz  }t          t          j
        |                    d x}x}}t          | t          |                     |                     d                                          }d |D             }ddg}||k    }|slt          j        d|fd||f          t          j        |          t          j        |          dz  }dd|iz  }t          t          j
        |                    d x}x}}|d         d         }d }||u}|slt          j        d|fd||f          t          j        |          t          j        |          dz  }dd|iz  }t          t          j
        |                    d x}x}}d S )Nv1r&   r`   r   r   r   v210102026-02-01T00:00:00+00:00r   r   r   r~   r   r   r   r   zSELECT snapshot_version,supersedes_snapshot_id,value_original FROM portfolio_valuation_snapshots WHERE source='ingestion:legacy_account_values' ORDER BY snapshot_versionc                .    g | ]}|d          |d         fS snapshot_versionvalue_originalrk   r   s     r!   
<listcomp>zJtest_snapshot_correction_creates_new_immutable_version.<locals>.<listcomp>   )    MMMS#$c*:&;<MMMr#   r   r      r  supersedes_snapshot_id)is not)z%(py1)s is not %(py4)s)r"   rJ   r   rx   r   rg   r   r   r   r   r   r;   fetchall)r    rh   r   r   r   r   r   rowss           r!   6test_snapshot_correction_creates_new_immutable_versionr     s   ::DtT3f>YZZZZdO,=dGII,N,NOOPPPtT3f>YZZZZgii00G8[).Q.)Q..........)Q.....)....Q...........................dOG44555<<  D  E  E  N  N  P  PDMMMMMkR]_jQkkMQkkkkkkkkkkkMQkkkkkkMkkkkQkkkkkkkkkkkkkkkkkkkkkkkkkkkk7+,8D8,D8888888888,D88888,8888D88888888888888888888888888888r#   c                    t                      } t          | dddddddd		  	         t          j        t          j        d
          5  t          | dddddddd		  	         d d d            n# 1 swxY w Y   t          | dddddd           t          | dddddd           t          | t          d                    }|d         d         }d}||k    }|slt          j	        d|fd||f          t          j
        |          t          j
        |          dz  }dd|iz  }t          t          j        |                    d x}x}}|d         d         }d}||k    }|slt          j	        d|fd||f          t          j
        |          t          j
        |          dz  }dd|iz  }t          t          j        |                    d x}x}}|d         d         }d}||k    }|slt          j	        d|fd||f          t          j
        |          t          j
        |          dz  }dd|iz  }t          t          j        |                    d x}x}}|d         d         }d}||k    }|slt          j	        d|fd||f          t          j
        |          t          j
        |          dz  }dd|iz  }t          t          j        |                    d x}x}}|d         }g }||k    }|slt          j	        d|fd||f          t          j
        |          t          j
        |          dz  }dd|iz  }t          t          j        |                    d x}x}}d S ) Nbuy1buyr&   r_   i1100same)rO   rP   rQ   rS   ztransactions.row_hashr   buy2r   z
2025-01-02)rP   rQ   r   option_exercisez
2025-01-03)rO   rP   canonical_transactionsr   r   r   r~   r   r   r   r   r   r   planned_activities)r"   rX   r   r   r   IntegrityErrorr   rg   r   r   r   r   r   )r    rh   r   r   r   r   r   s          r!   Ttest_canonical_activity_preview_handles_duplicates_ambiguity_and_unsupported_recordsr'     s   ::DD&%lsUX`epvwwww	w-5L	M	M	M | |feS,3Y\ditz{{{{| | | | | | | | | | | | | | |D+uc<#UZ[[[[D)%6\VYdghhhhg.F&G&GHHG8[).Q.)Q..........)Q.....)....Q...........................8[).Q.)Q..........)Q.....)....Q...........................8[).Q.)Q..........)Q.....)....Q...........................8Y',1,'1,,,,,,,,,,'1,,,,,',,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,'(.B.(B..........(B.....(....B.............................s   A,,A03A0c           	     F   | dz  t                    }t          |dddd           t          |t                                }t	          |          |                                 dfdt          d	
          5 }t          |                    fdt          d	                              }d d d            n# 1 swxY w Y   t                    }d |D             }t          |          }d}||k    }	|	st          j        d|	fd||f          dt          j                    v st          j        t                    rt          j        t                    ndt          j        |          t          j        |          t          j        |          dz  }
dd|
iz  }t%          t          j        |                    d x}x}x}	}|                    d                                          d         }d}||k    }|slt          j        d|fd||f          t          j        |          t          j        |          dz  }dd|iz  }t%          t          j        |                    d x}x}}|                    d                                          d         }d}||k    }|slt          j        d|fd||f          t          j        |          t          j        |          dz  }dd|iz  }t%          t          j        |                    d x}x}}d S )Nzparallel.sqlite3r   r&   r`   r   r   r\   c                     t                    } 	 t          |           |                                  S # |                                  w xY wN)r   r   close)localr   r   s    r!   r;   zOtest_parallel_confirmation_produces_one_batch_and_one_snapshot.<locals>.execute   sA    	$UG44KKMMMMEKKMMMMs	   6 Ar  )max_workersc                                 S r*  rk   )_r;   s    r!   <lambda>zPtest_parallel_confirmation_produces_one_batch_and_one_snapshot.<locals>.<lambda>  s    '')) r#   c              3  B   K   | ]}t          |d                     V  dS )r   N)bool)rm   r   s     r!   r   zQtest_parallel_confirmation_produces_one_batch_and_one_snapshot.<locals>.<genexpr>  s2      DD&4|,---DDDDDDr#   r   r~   r   sumr   r   r   z0SELECT COUNT(*) FROM portfolio_ingestion_batchesr   r   r   r   r   z2SELECT COUNT(*) FROM portfolio_valuation_snapshots)r   r\   )r"   rJ   r   rg   rx   r+  r   listmapranger   r3  r   r   r   r   r   r   r   r   r;   r   )ry   r    rh   poolresultsverifyr   r   r   r   r   r   r   r   r   r   r;   r   r   s                   @@@r!   >test_parallel_confirmation_produces_one_batch_and_one_snapshotr:     s   ((DD>>DtXsL&999gii00Gg&&GJJLLL       
	*	*	* @dtxx 3 3 3 3U1XX>>??@ @ @ @ @ @ @ @ @ @ @ @ @ @ @T]]FDDGDDDI3DDDIIDIIIIIIIIIIDIIIIIIIIIIII3IIIII3IIIIIIDIIIIDIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII>>LMMVVXXYZ[`_``[_```````````[_``````[````_````````````````````````````>>NOOXXZZ[\]babb]abbbbbbbbbbb]abbbbbb]bbbbabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbs   4CCCc            
        t                      } t          | dddd           t          | t          t	          | t                                                     t          |           }d |d         D             }h d}||k    }|slt          j        d|fd	||f          t          j	        |          t          j	        |          d
z  }dd|iz  }t          t          j        |                    d x}x}}t          | dd          }|d         }d}||k    }|slt          j        d|fd||f          t          j	        |          t          j	        |          d
z  }dd|iz  }t          t          j        |                    d x}x}}|d         d         d         }|j        }d} ||          }	|	ssdt          j	        |          t          j	        |          t          j	        |          t          j	        |	          dz  }
t          t          j        |
                    d x}x}x}}	d}t          |          }||v}|st          j        d|fd||f          t          j	        |          dt          j                    v st          j        t                    rt          j	        t                    nddt          j                    v st          j        |          rt          j	        |          ndt          j	        |          dz  }dd |iz  }t          t          j        |                    d x}x}}d S )!Nr   r&   r`   r   c                    h | ]
}|d          S )rb   rk   r   s     r!   r   zLtest_source_status_and_history_are_redacted_and_paginated.<locals>.<setcomp>  s    >>>4D>>>r#   sources>   fx_ratesmarket_pricesreported_positionsr[   r$  r   r   r   r   r   
   r   )limitoffsetr+   r   r~   r   r   r   zbatch-zLassert %(py7)s
{%(py7)s = %(py3)s
{%(py3)s = %(py1)s.startswith
}(%(py5)s)
}r   r   r   r   source_filename)not in)z4%(py1)s not in %(py6)s
{%(py6)s = %(py3)s(%(py4)s)
}rD   history)r   r   r   r   zassert %(py8)sr   )r"   rJ   r   rx   r   rg   r   r   r   r   r   r   r   
startswithrD   r   r   r   )r    r=  r   r   r   r   r   rG  r   r   r   r   r   s                r!   9test_source_status_and_history_are_redacted_and_paginatedrI    sV   ::DtXsL&999dO,=dGII,N,NOOPPP%%G>>79+=>>>  i  Ci  Ci  Ci  i>  Ci  i  i  i  i  i  i  i  i  i  i>  Ci  i  i  i  i  i>  i  i  i  i  Ci  i  i  i  i  i  i  i  i  i  i  i  i  i  i  i  i  i  i  i  i  i  i  i  i  i  i  iBq999G7 q q          q         q                           7Az*?*5?h?55h????????*????5????h????????????????????????????0CLL0L0000000000L0000000000000000C00000C000000000000000000000000L00000000000000000000000000000r#   c           
     d   t          | ddddddd           |                     dt          f           |                     d	t          f           t          | d
ddd           t	          | dddd           t	          | dddd           t          | dddd           |                                  d S )Nr  r&   r_   r  10800rO   rP   rQ   INSERT INTO positions_snapshot(position_snapshot_id,snapshot_date,account_id,platform_id,instrument_id,quantity,market_value_chf,data_quality_status,created_at)
           VALUES('pos','2025-12-31','a','p','i','10','1000','ok',?)INSERT INTO market_prices(market_price_id,instrument_id,price_date,close,currency,provider,quality_status,created_at)
           VALUES('price','i','2025-12-31','100','CHF','fixture','ok',?)cashr`   r   ztotal-a1100z
total-onlyr+   5000zcanonical-total)rX   r;   r<   rN   rJ   rZ   r=   r    s    r!   seed_matched_reconciliationrT    s    D%\cTX`effffLL	HJM   	LL	LNQV   T63e444tY\6:::t\7L&AAAD"3WlFSSSKKMMMMMr#   c                 ^	   t                      } t          |            t          | dt                    }t	          d |d         D                       }|d         }ddddd	}||k    }|slt          j        d
|fd||f          t          j        |          t          j        |          dz  }dd|iz  }t          t          j	        |                    d x}x}}|d         d         }d}||k    }|slt          j        d
|fd||f          t          j        |          t          j        |          dz  }dd|iz  }t          t          j	        |                    d x}x}}t	          d |d         D                       }|d         }d}||k    }|slt          j        d
|fd||f          t          j        |          t          j        |          dz  }dd|iz  }t          t          j	        |                    d x}x}}|d         }d }||u }|slt          j        d|fd||f          t          j        |          t          j        |          dz  }dd|iz  }t          t          j	        |                    d x}x}}|d         d         d         }d}||k    }|slt          j        d
|fd||f          t          j        |          t          j        |          dz  }dd|iz  }t          t          j	        |                    d x}x}}|d         }	t          |	          }d}
||
k    }|st          j        d
|fd||
f          dt          j                    v st          j        t                    rt          j        t                    ndt          j        |	          t          j        |          t          j        |
          dz  }dd |iz  }t          t          j	        |                    d x}	x}x}}
t          | dt                    }|d         }|d         }||k    }|slt          j        d
|fd||f          t          j        |          t          j        |          dz  }dd|iz  }t          t          j	        |                    d x}x}}d S )!Nr`   as_ofrf   c              3  2   K   | ]}|d          dk    |V  dS instrument_labelzSynthetic AssetNrk   r   s     r!   r   zktest_reconciliation_matches_quantity_value_cash_and_total_value_account_without_holdings.<locals>.<genexpr>.  s3      nntEW@X\m@m@md@m@m@m@mnnr#   differencesrP   rK  0matched)ledgerreported
differencer9   r~   r   r   r   r   	valuationr9   c              3  *   K   | ]}|d          
|V  dS )total_value_onlyNrk   r   s     r!   r   zktest_reconciliation_matches_quantity_value_cash_and_total_value_account_without_holdings.<locals>.<genexpr>1  s-      \\t4HZC[\d\\\\\\r#   account_totalspositions_valuer   )z%(py1)s is %(py4)scoverage
activitiesratior  ru   r   r   r   r   r   r   )r"   rT  r   r<   nextr   r   r   r   r   r   r   r   r   )r    r   rO   r   r   r   r   r   
total_onlyr   r   r   r   r   repeateds                  r!   Xtest_reconciliation_matches_quantity_value_cash_and_total_value_account_without_holdingsrl  *  s   ::D%%%+DRUVVVFnnvm'<nnnnnJj!o$VYen%o%oo!%ooooooooooo!%oooooo!oooo%ooooooooooooooooooooooooooook"8,9	9,	9999999999,	99999,9999	999999999999999999999999999\\v.>'?\\\\\Jh,9,9,,,,,,,,,,9,,,,,,,,,9,,,,,,,,,,,,,,,,,,,,,,,,,,,'(0D0(D0000000000(D00000(0000D000000000000000000000000000*l+G4;;4;;;;;;;;;;4;;;;;4;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;)*13*++1r1+r1111111111+r1111111111113111113111111*1111+1111r11111111111111111111111111111-d,TWXXXH'(GF3F,GG(,GGGGGGGGGGG(,GGGGGG(GGGG,GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGr#   c                    t                      } t          |            |                     d           t          | dt                    }|d         d         d         d         }d}||k    }|slt          j        d	|fd
||f          t          j        |          t          j        |          dz  }dd|iz  }t          t          j	        |                    d x}x}}|                     d           t          | dt                    }d}|d         d         d         }||v }|slt          j        d|fd||f          t          j        |          t          j        |          dz  }dd|iz  }t          t          j	        |                    d x}x}}d}|d         d         d         }||v }|slt          j        d|fd||f          t          j        |          t          j        |          dz  }dd|iz  }t          t          j	        |                    d x}x}}|                     d           |                     dt          f           |                     dt          f           t          | dt                    }d}t          d |d         D                       d         }||v }|slt          j        d|fd||f          t          j        |          t          j        |          dz  }dd|iz  }t          t          j	        |                    d x}x}}|                     d           t          | dt                    }	d}t          d |	d         D                       d         }||v }|slt          j        d|fd||f          t          j        |          t          j        |          dz  }dd|iz  }t          t          j	        |                    d x}x}}d S )NzZUPDATE positions_snapshot SET market_value_chf='1000.005' WHERE position_snapshot_id='pos'r`   rV  r[  r   ra  r9   within_tolerancer~   r   r   r   r   zbUPDATE positions_snapshot SET quantity='9',market_value_chf='900' WHERE position_snapshot_id='pos'quantity_mismatchreason_codesinz%(py1)s in %(py4)svalue_mismatchzvUPDATE positions_snapshot SET instrument_id='eur',quantity='1',market_value_chf='100' WHERE position_snapshot_id='pos'a?  INSERT INTO transactions(transaction_id,transaction_type,activity_kind,account_id,instrument_id,trade_date,quantity,gross_amount_original,currency_original,source_type,source_id,row_hash,quality_status,created_at) VALUES('eur-buy','buy','buy','a','eur','2025-01-01','1','90','EUR','fixture','fixture','eur-hash','ok',?)INSERT INTO market_prices(market_price_id,instrument_id,price_date,close,currency,provider,quality_status,created_at) VALUES('eur-price','eur','2025-12-31','100','EUR','fixture','ok',?)
missing_fxc              3  2   K   | ]}|d          dk    |V  dS rZ  zSynthetic EUR AssetNrk   r   s     r!   r   z]test_reconciliation_distinguishes_tolerance_mismatch_missing_fx_and_cutoff.<locals>.<genexpr>H  s?         A   AdSeNfjNNNNNN   A   Ar#   YUPDATE positions_snapshot SET snapshot_date='2025-12-30' WHERE position_snapshot_id='pos'cutoff_mismatchc              3  2   K   | ]}|d          dk    |V  dS rx  rk   r   s     r!   r   z]test_reconciliation_distinguishes_tolerance_mismatch_missing_fx_and_cutoff.<locals>.<genexpr>K  s[        %B  %BdtTfOg  lA  PA  PAT  PA  PA  PA  PA  %B  %Br#   )r"   rT  r;   r   r<   r   r   r   r   r   ri  )
r    insider   r   r   r   r   mismatchrv  cutoffs
             r!   Jtest_reconciliation_distinguishes_tolerance_mismatch_missing_fx_and_cutoffr  :  sL   ::D%%%LLmnnn+DRUVVVF- #K0:P>PP:>PPPPPPPPPPP:>PPPPPP:PPPP>PPPPPPPPPPPPPPPPPPPPPPPPPPPPLLuvvv-d,TWXXXHL(="9!"<^"LL"LLLLLLLLLLL"LLLLLLLLLL"LLLLLLLLLLLLLLLLLLLLLLLLLLLLIx6q9.IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIILL  J  K  K  KLL  S  VY  U[  \  \  \LL  M  PS  OU  V  V  V/LVYZZZJ  Q4   A   AM1J   A   A   A  A  A  BP  Q  Q<  Q  Q  Q  Q  Q  Q  Q  Q  Q  Q  Q<  Q  Q  Q  Q  Q  Q<  Q  Q  Q  Q  Q  Q  Q  Q  Q  Q  Q  Q  Q  Q  Q  Q  Q  Q  Q  Q  Q  Q  Q  Q  Q  Q  Q  Q  Q  Q  Q  QLLlmmm+DRUVVVF  R  %B  %Bf]6K  %B  %B  %B  !B  !B  CQ  !R  R  !R  R  R  R  R  R  R  R  R  R  R  !R  R  R  R  R  R  R  R  R  R  !R  R  R  R  R  R  R  R  R  R  R  R  R  R  R  R  R  R  R  R  R  R  R  R  R  R  R  R  R  Rr#   c            	        t                      } t          | dddddd           t          | ddd	dd
d           ddd                                D ]5\  }}t          dd|          D ]\  }}}t	          | | d| |||           6t          | ddt                    }t          | dddt                    }|d         }g }||k    }	|	slt          j        d|	fd||f          t          j	        |          t          j	        |          dz  }
dd|
iz  }t          t          j        |                    d x}x}	}|d         }ddddg}||k    }	|	slt          j        d|	fd||f          t          j	        |          t          j	        |          dz  }
dd|
iz  }t          t          j        |                    d x}x}	}d S )Nztransfer-outinternal_transferr&   2025-06-01T00:00:00+00:00z-100zraiffeisen-akb)rR   rT   ztransfer-inr)   r   )r   r   r   )r   r   rQ  )r&   r)   )openflowr+  )r_   r  r`   -r_   r`   )	from_dateto_daterf   )r  r  r0   rf   external_cashflowsr~   r   r   r   r   external_withdrawal)rF   rV   amount)r"   rX   r   ziprZ   r   r<   r   r   r   r   r   )r    rE   valuessuffixrF   rG   r^   r   r   r   r   r   s               r!   [test_scope_aware_raiffeisen_akb_transfer_is_internal_for_portfolio_and_external_for_accountr  N  sA   ::DD.*=sD_ek  }M  N  N  N  ND-)<cC^di  {K  L  L  L  L!8?WXX^^`` U U!$%>@y  |B  "C  "C 	U 	UFB#DW*?*?v*?*?"eTTTT	U+DLR^lopppI)$,P\ilz}~~~G)*0b0*b0000000000*b00000*0000b000000000000000000000000000'(  C4OYn  {A  .B  .B  -C  C(  -C  C  C  C  C  C  C  C  C  C  C(  -C  C  C  C  C  C(  C  C  C  C  -C  C  C  C  C  C  C  C  C  C  C  C  C  C  C  C  C  C  C  C  C  C  C  C  C  C  C  C  C  Cr#   c                     t                       t                      t          d          }  fd| j        t          <   t          |           }|j        }d} ||          }|j        }d}||k    }|st          j	        d|fd||f          dt          j                    v st          j        |          rt          j        |          ndt          j        |          t          j        |          t          j        |          t          j        |          t          j        |          d	z  }d
d|iz  }	t          t          j        |	                    d x}x}x}x}x}}|j        }d} ||          }|j        }d}||k    }|st          j	        d|fd||f          dt          j                    v st          j        |          rt          j        |          ndt          j        |          t          j        |          t          j        |          t          j        |          t          j        |          d	z  }d
d|iz  }	t          t          j        |	                    d x}x}x}x}x}}|                    dt#                                }
|
j        }d}||k    }|st          j	        d|fd||f          dt          j                    v st          j        |
          rt          j        |
          ndt          j        |          t          j        |          dz  }dd|iz  }t          t          j        |                    d x}x}}|                    dt%          |
                                                    }|j        }d}||k    }|st          j	        d|fd||f          dt          j                    v st          j        |          rt          j        |          ndt          j        |          t          j        |          dz  }dd|iz  }t          t          j        |                    d x}x}}|                    d          }|j        }d}||k    }|st          j	        d|fd||f          dt          j                    v st          j        |          rt          j        |          ndt          j        |          t          j        |          dz  }dd|iz  }t          t          j        |                    d x}x}}|                                d         }d}||k    }|slt          j	        d|fd||f          t          j        |          t          j        |          dz  }dd|iz  }t          t          j        |                    d x}x}}|                                 d         }|d         }t+          |          }dh}||k    }|st          j	        d|fd ||f          d!t          j                    v st          j        t*                    rt          j        t*                    nd!t          j        |          t          j        |          t          j        |          d"z  }d#d$|iz  }t          t          j        |                    d x}x}x}}|d         }t+          |          }d%h}||k    }|st          j	        d|fd ||f          d!t          j                    v st          j        t*                    rt          j        t*                    nd!t          j        |          t          j        |          t          j        |          d"z  }d#d$|iz  }t          t          j        |                    d x}x}x}}|d         }t+          |          }d%h}||k    }|st          j	        d|fd ||f          d!t          j                    v st          j        t*                    rt          j        t*                    nd!t          j        |          t          j        |          t          j        |          d"z  }d#d$|iz  }t          t          j        |                    d x}x}x}}|d&         }t+          |          }dh}||k    }|st          j	        d|fd ||f          d!t          j                    v st          j        t*                    rt          j        t*                    nd!t          j        |          t          j        |          t          j        |          d"z  }d#d$|iz  }t          t          j        |                    d x}x}x}}|d'         }t+          |          }dh}||k    }|st          j	        d|fd ||f          d!t          j                    v st          j        t*                    rt          j        t*                    nd!t          j        |          t          j        |          t          j        |          d"z  }d#d$|iz  }t          t          j        |                    d x}x}x}}|d         d%         d(         d)         d*         }d+}||k    }|slt          j	        d|fd||f          t          j        |          t          j        |          dz  }dd|iz  }t          t          j        |                    d x}x}}t          d,          } fd-|j        t          <   t          |d./          }|j        }d}t#                      } |||          }|j        }d}||k    }|s>t          j	        d|fd0||f          d1t          j                    v st          j        |          rt          j        |          nd1t          j        |          t          j        |          d2t          j                    v st          j        t"                    rt          j        t"                    nd2t          j        |          t          j        |          t          j        |          t          j        |          d3z  }d4d5|iz  }t          t          j        |                    d x}x}x}x}x}x}}|j        }d}i } |||          }|j        }d6}||k    }|st          j	        d|fd7||f          d1t          j                    v st          j        |          rt          j        |          nd1t          j        |          t          j        |          t          j        |          t          j        |          t          j        |          t          j        |          d8z  }	d9d:|	iz  }t          t          j        |                    d x}x}x}x}x}x}}d S );Ntest)
write_modec                      S r*  rk   rS  s   r!   r0  zAtest_api_openapi_write_security_and_read_routes.<locals>.<lambda>_  s    t r#   z/api/portfolio/data-sources   r~   )zk%(py8)s
{%(py8)s = %(py6)s
{%(py6)s = %(py2)s
{%(py2)s = %(py0)s.get
}(%(py4)s)
}.status_code
} == %(py11)sclient)r   r   r   r   r   r   zassert %(py13)spy13z\/api/portfolio/reconciliation?as_of=2025-12-31&data_cutoff=2026-07-23T12%3A00%3A00%2B00%3A00z /api/portfolio/ingestion/preview)json)z3%(py2)s
{%(py2)s = %(py0)s.status_code
} == %(py5)spreview_response)r   r   r   zassert %(py7)sr   z /api/portfolio/ingestion/confirmconfirm_responsez2/api/portfolio/ingestion/history?limit=20&offset=0history_responser+   r   r   r   r   r   pathsgetr   setr   r   r   postz /api/portfolio/ingestion/historyz/api/portfolio/reconciliation	responses409descriptionu$   Abgelaufene oder veränderte Previewdisabledc                      S r*  rk   rS  s   r!   r0  zAtest_api_openapi_write_security_and_read_routes.<locals>.<lambda>r  s    t r#   )z100.64.0.10iP  )r  )z%(py11)s
{%(py11)s = %(py9)s
{%(py9)s = %(py2)s
{%(py2)s = %(py0)s.post
}(%(py4)s, json=%(py7)s
{%(py7)s = %(py5)s()
})
}.status_code
} == %(py14)sr   rg   )r   r   r   r   r   r   r   r   zassert %(py16)sr   i  )z|%(py10)s
{%(py10)s = %(py8)s
{%(py8)s = %(py2)s
{%(py2)s = %(py0)s.post
}(%(py4)s, json=%(py6)s)
}.status_code
} == %(py13)s)r   r   r   r   r   r   r  zassert %(py15)spy15)r"   rT  r   dependency_overridesr   r   r  status_coder   r   r   r   r   r   r   r   r  rg   rx   r  openapir  )!appr  r   r   r   r   r   r   @py_format12@py_format14r  r   r   r   r  r  r   r   r   r   r  r   r   blocked_appr   @py_assert8r   r   r   r   @py_assert11@py_format16r    s!                                   @r!   /test_api_openapi_write_security_and_read_routesr  [  sy   ::D%%%

'
'
'C'3|||CV$__F:G3G::344G4@GCG@CGGGGGGGGGG@CGGGGGGGGGGGG6GGGGG6GGGGGG:GGGG3GGGG4GGGG@GGGGCGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG:  It  I::tuu  Iu  B  I  FI  I  B  FI  I  I  I  I  I  I  I  I  I  I  B  FI  I  I  I  I  I  I  I  I  I  I  I  I6  I  I  I  I  I6  I  I  I  I  I  I:  I  I  I  It  I  I  I  Iu  I  I  I  I  B  I  I  I  I  FI  I  I  I  I  I  I  I  I  I  I  I  I  I  I  I  I  I  I  I  I  I  I  I  I  I  I  I  I  I  I  I  I  I{{#EGII{VV'.3.'3..........'3.......................'....3...........................{{#EO\l\q\q\s\sLtLt{uu'.3.'3..........'3.......................'....3...........................zz"VWW'.3.'3..........'3.......................'....3...........................  ""7+0q0+q0000000000+q00000+0000q000000000000000000000000000KKMM'"E23?3344??4??????????4????????????3?????3??????3????4?????????????????????????????????78E3899EfXE9XEEEEEEEEEE9XEEEEEEEEEEEE3EEEEE3EEEEEE8EEEE9EEEEXEEEEEEEEEEEEEEEEEEEEEEEEEEEEE78E3899EfXE9XEEEEEEEEEE9XEEEEEEEEEEEE3EEEEE3EEEEEE8EEEE9EEEEXEEEEEEEEEEEEEEEEEEEEEEEEEEEEE78D3899DeWD9WDDDDDDDDDD9WDDDDDDDDDDDD3DDDDD3DDDDDD8DDDD9DDDDW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45A3566A5'A6'AAAAAAAAAA6'AAAAAAAAAAAA3AAAAA3AAAAAA5AAAA6AAAA'AAAAAAAAAAAAAAAAAAAAAAAAAAAAA34V<[I%PQ^_  J  dJ  J_  dJ  J  J  J  J  J  J  J  J  J  J_  dJ  J  J  J  J  J_  J  J  J  J  dJ  J  J  J  J  J  J  J  J  J  J  J  J  J  J  J  J  J  J  J  J  J  J  J  J  J  J  J
333K/;|||K$V,-CDDDG<^:^^<<:KKK^KW^[^^W[^^^^^^^^^^^W[^^^^^^^^^^^^^7^^^^^7^^^^^^<^^^^:^^^^^^^^^^^^^^^^^^^^^^^^^^K^^^^W^^^^[^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^<W:WW<<:DDDWDPWTWWPTWWWWWWWWWWWPTWWWWWWWWWWWWW7WWWWW7WWWWWW<WWWW:WWWWWWWWDWWWWPWWWWTWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWr#   c                 6   t                      } t          j        t          d          5  t	          | i t                      ddi           d d d            n# 1 swxY w Y   t          j        t          d          5  t	          | i t                      ddi           d d d            n# 1 swxY w Y   t          j        t          d          5  t	          | i t                      d	d
i           d d d            n# 1 swxY w Y   t          j        t          d          5  t          | dd           d d d            n# 1 swxY w Y   t          j        t          d          5  t          | dd           d d d            d S # 1 swxY w Y   d S )NDatenqueller   rb   bank_scraperZeitraumrd   z
2026-01-01zeindeutige Zeitzonerf   z2026-07-23T12:00:00zausschliesslich CHFr`   EUR)rW  base_currencyzDecimal-Textg?)rW  absolute_tolerance)r"   r   r   r  r   rg   r   rS  s    r!   #test_invalid_parameters_fail_closedr  x  s   ::D	z	7	7	7 M M$ K799 KlN K KLLLM M M M M M M M M M M M M M M	z	4	4	4 L L$ J799 Jm\ J JKKKL L L L L L L L L L L L L L L	z)>	?	?	? U U$ S799 Sm=R S STTTU U U U U U U U U U U U U U U	z)>	?	?	? V V&t<uUUUUV V V V V V V V V V V V V V V	z	8	8	8 Y Y&t<TWXXXXY Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y YsY   #AA A?#B..B25B2#DD
D)EEE.FFFc                    t                      } t          | ddddd           t          | ddddd	           t          | t                                }|d
         d         }d}||k    }|slt	          j        d|fd||f          t	          j        |          t	          j        |          dz  }dd|iz  }t          t	          j        |                    d x}x}}|d
         d         }d}||k    }|slt	          j        d|fd||f          t	          j        |          t	          j        |          dz  }dd|iz  }t          t	          j        |                    d x}x}}t          | t          |                    }|d         }d}||k    }|slt	          j        d|fd||f          t	          j        |          t	          j        |          dz  }dd|iz  }t          t	          j        |                    d x}x}}|                     d                                          }d |D             }ddg}||k    }|slt	          j        d|fd||f          t	          j        |          t	          j        |          dz  }dd|iz  }t          t	          j        |                    d x}x}}|d         d         }|d         d         }||k    }|slt	          j        d|fd||f          t	          j        |          t	          j        |          dz  }dd|iz  }t          t	          j        |                    d x}x}}d S )Nr	  r&   r`   r   r   r   r
  r  r  r   r   r   r~   r   r   r   r   r   r   r  zSELECT snapshot_id,snapshot_version,supersedes_snapshot_id,value_original
           FROM portfolio_valuation_snapshots ORDER BY snapshot_versionc                .    g | ]}|d          |d         fS r  rk   r   s     r!   r  zZtest_multiple_same_day_values_receive_sequential_versions_in_one_batch.<locals>.<listcomp>  r  r#   r  r  r  r   rC   )r"   rJ   r   rg   r   r   r   r   r   r   rx   r;   r  )	r    rh   r   r   r   r   r   r   r  s	            r!   Ftest_multiple_same_day_values_receive_sequential_versions_in_one_batchr    s   ::DtT3f>YZZZZtT3f>YZZZZgii00G8U#(q(#q((((((((((#q(((((#((((q(((((((((((((((((((((((((((8[).Q.)Q..........)Q.....)....Q...........................t_W%=%=>>F#$))$))))))))))$)))))$)))))))))))))))))))))))))))))))<<	K  hjj 	 NMMMMkR]_jQkkMQkkkkkkkkkkkMQkkkkkkMkkkkQkkkkkkkkkkkkkkkkkkkkkkkkkkkk7+,FQ0FF,0FFFFFFFFFFF,0FFFFFF,FFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFr#   c                   t                      }t          |dddd           t          |t                                }t	          |          }t          ||          }t          j        t          |d                             | 	                    t          dfd           t          ||          }|d         |d	         d
d}||k    }|st          j        d|fd||f          dt          j                    v st          j        |          rt          j        |          ndt          j        |          dz  }dd|iz  }	t#          t          j        |	                    d x}}t'          |          }
t)          d          z                                   |
d<   t-          j        t0          d          5  t          ||
           d d d            d S # 1 swxY w Y   d S )Nr   r&   r`   r   rs   _nowc                 *     t          d          z   S )Nr   )hours)r   r   s   r!   r0  zbtest_preview_timestamp_is_hash_bound_and_expired_idempotent_retry_still_succeeds.<locals>.<lambda>  s    )RSBTBTBT8T r#   r   r   Tr   r~   r   retryr   r   r   r   )daysr   r   )r"   rJ   r   rg   rx   r   r   fromisoformatrD   setattrr   r   r   r   r   r   r   r   r   r   r   	isoformatr   r   r  )rz   r    rh   r   r   r  r   r   r   r   tamperedrA   s              @r!   Ptest_preview_timestamp_is_hash_bound_and_expired_idempotent_retry_still_succeedsr    s6   ::DtXsL&999gii00Gg&&GdG,,E$S1E)F%G%GHHG0T0T0T0TUUUdG,,E!&z!2j@Qaefff5fffffffffff5fffffffffffff5fffff5ffffffffffffffffffffffffffffffffG}}H&-	q0A0A0A&A%L%L%N%NH!"	z)>	?	?	? * *$)))* * * * * * * * * * * * * * * * * *s   ;GG Gc            
        t                      } t          | ddddddd           |                     d	t          f           |                     d
t          f           |                     dt          f           |                                  t          | t          d                    }|d         d         }d}||k    }|slt          j        d|fd||f          t          j	        |          t          j	        |          dz  }dd|iz  }t          t          j        |                    d x}x}}t          | dt                    }|d         d         }|d         d         }d}||k    }|slt          j        d|fd||f          t          j	        |          t          j	        |          dz  }dd|iz  }t          t          j        |                    d x}x}}|d         d         }d}||k    }|slt          j        d|fd||f          t          j	        |          t          j	        |          dz  }dd|iz  }t          t          j        |                    d x}x}}d S )Nr   r  r&   r_   r  rK  rL  rM  ar  INSERT INTO transactions(transaction_id,transaction_type,activity_kind,account_id,instrument_id,trade_date,
             quantity,gross_amount_original,currency_original,source_type,source_id,row_hash,is_confirmed,quality_status,created_at)
           VALUES('unconfirmed','buy','buy','a','i','2025-01-02','5','400','CHF','fixture','fixture','unconfirmed-hash',0,'ok',?)rN  rO  r$  r   r   r   r~   r   r   r   r   r`   rV  r[  r   rP   r^  r9   r]  )r"   rX   r;   r<   r=   r   rg   r   r   r   r   r   r   )	r    rh   r   r   r   r   r   reconciliationr   s	            r!   Ltest_unconfirmed_transactions_are_excluded_from_ingestion_and_reconciliationr    s   ::DD+uc<CZ^fkllllLL	E 
	   	LL	H	  
 	LL	L	  
 	KKMMMg.F&G&GHHG8\*/a/*a//////////*a/////*////a///////////////////////////3DZ]^^^N-(+D
H%--%----------%-----%-------------------------------
H%22%2222222222%22222%222222222222222222222222222222222r#   c            
        t                      } t          |            |                     d           |                     d           t          | dt                    }t          d |d         D                       }|d         d         }d	}||k    }|slt          j        d
|fd||f          t          j        |          t          j        |          dz  }dd|iz  }t          t          j
        |                    d x}x}}|d         d         }d	}||k    }|slt          j        d
|fd||f          t          j        |          t          j        |          dz  }dd|iz  }t          t          j
        |                    d x}x}}ddh}|d         }t          |          }	||	k    }|st          j        d|fd||	f          t          j        |          dt          j                    v st          j        t                    rt          j        t                    ndt          j        |          t          j        |	          dz  }
dd|
iz  }t          t          j
        |                    d x}x}x}}	|d         }d	}||k    }|slt          j        d
|fd||f          t          j        |          t          j        |          dz  }dd|iz  }t          t          j
        |                    d x}x}}|d         d         d         }d}||k    }|slt          j        d
|fd||f          t          j        |          t          j        |          dz  }dd|iz  }t          t          j
        |                    d x}x}}|                     d           |                     d           t          | dd d!d"d#d$d%&           |                     d'           |                     d(t          f           |                     d)t          f           |                                  t          | dt                    }t          d* |d         D                       }|d         d         }d	}||k    }|slt          j        d
|fd||f          t          j        |          t          j        |          dz  }dd|iz  }t          t          j
        |                    d x}x}}d+}|d         }||v }|slt          j        d,|fd-||f          t          j        |          t          j        |          dz  }dd|iz  }t          t          j
        |                    d x}x}}|d         d.         d         }d}||k    }|slt          j        d
|fd||f          t          j        |          t          j        |          dz  }dd|iz  }t          t          j
        |                    d x}x}}d S )/Nry  zNUPDATE market_prices SET price_date='2025-12-30' WHERE market_price_id='price'r`   rV  c              3  2   K   | ]}|d          dk    |V  dS rY  rk   r   s     r!   r   zatest_stale_position_price_and_fx_inputs_are_not_comparable_and_reduce_coverage.<locals>.<genexpr>  s3      gg>P9QUf9f9f9f9f9f9fggr#   r[  rP   r9   not_comparabler~   r   r   r   r   ra  stale_snapshotstale_pricerp  )<=)z0%(py1)s <= %(py7)s
{%(py7)s = %(py3)s(%(py5)s)
}r  rD  r   r   rf  pricescoveredr   zUPDATE positions_snapshot SET instrument_id='eur',snapshot_date='2025-12-31',quantity='1',market_value_chf='100' WHERE position_snapshot_id='pos'z3DELETE FROM transactions WHERE transaction_id='buy'zeur-buyr  r&   r_   eurr  90rM  zDELETE FROM market_pricesru  zINSERT INTO fx_rates(fx_rate_id,base_currency,quote_currency,rate_date,rate,provider,rate_type,quality_status,created_at) VALUES('eur-fx','EUR','CHF','2025-12-30','1','fixture','close','ok',?)c              3  2   K   | ]}|d          dk    |V  dS rx  rk   r   s     r!   r   zatest_stale_position_price_and_fx_inputs_are_not_comparable_and_reduce_coverage.<locals>.<genexpr>  s3      mm4@R;SWl;l;lt;l;l;l;lmmr#   stale_fxrq  rs  fx)r"   rT  r;   r   r<   ri  r   r   r   r   r   r  r   r   r   rX   r=   )r    staler   r   r   r   r   r   r   r   r   r   r  r  s                 r!   Ntest_stale_position_price_and_fx_inputs_are_not_comparable_and_reduce_coverager    sZ   ::D%%%LLlmmmLLabbb*4|QTUUUEgg}!5gggggD
H%9)99%)99999999999%)999999%9999)9999999999999999999999999999X&:*::&*:::::::::::&*::::::&::::*::::::::::::::::::::::::::::m,ID4HI4H0I0II,0IIIIIIIIIII,0IIIIII,IIIIIIIIIIIIIIIIIIIIII4HIIII0IIIIIIIIIIIIIIIIIIIIIIIIIIIIII?...?...........?......?................................X&y16Q61Q66666666661Q6666616666Q666666666666666666666666666LL  e  f  f  fLLFGGGD)UC%Z]eijjjjLL,---LL  M  PS  OU  V  V  VLL  T  WZ  V\  ]  ]  ]KKMMM-d,TWXXXH
mm 7mmm
m
mC{H%9)99%)99999999999%)999999%9999)9999999999999999999999999999,^,,:,,,,,,,,,,,:,,,,,,:,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,J%i05A50A55555555550A5555505555A55555555555555555555555555555r#   r*  )r   r   r   r   )r    r   r   r$   )r    r   rC   rD   rE   rD   rF   rD   rG   rD   rA   rD   rB   rH   r   r$   )r    r   rC   rD   rE   rD   rF   rD   rG   rD   r   r$   )r    r   rU   rD   rV   rD   rE   rD   rF   rD   rO   rH   rP   rH   rQ   rH   rR   rH   rS   rH   rT   rH   r   r$   )r[   )r3   rD   r   r\   )rh   r\   r   r\   )ry   r   rz   r{   r   r$   )r   r$   )ry   r   r   r$   )rz   r{   r   r$   )J
__future__r   builtinsr   _pytest.assertion.rewrite	assertionrewriter   concurrent.futuresr   r   r   r   pathlibr   r   fastapi.testclientr   !test_postfinance_portfolio_sourcer	   "test_portfolio_market_analytics_v1r
   test_sprint9_fx_fmp_historyr   jarvis_finance.api.dependenciesr   jarvis_finance.api.mainr   jarvis_finance.servicesr   &jarvis_finance.services.portfolio_datar   r   r   r   r   -jarvis_finance.services.portfolio_performancer   )jarvis_finance.services.performance_scoper   r   jarvis_finance.storage.databaser   !jarvis_finance.storage.migrationsr   r   r<   r"   r   rJ   rN   rX   rZ   rg   rx   r   r   r   r  r  r  r'  r:  rI  rT  rl  r  r  r  r  r  r  r  r  rk   r#   r!   <module>r     s@   " " " " " "               1 1 1 1 1 1 ( ( ( ( ( ( ( (         ) ) ) ) ) ) M M M M M M Z Z Z Z Z Z K K K K K K 2 2 2 2 2 2 . . . . . . 2 2 2 2 2 2              V U U U U U        4 3 3 3 3 3 Q Q Q Q Q Q Q Q!    & & & &R qt  LP          !%TW[4VZ        ] ] ] ] ]   S S S S0H H H H"& & & & ; ; ; ; : : : :
9 
9 
9 
9/ / / /c c c c.	1 	1 	1 	1   "H H H H R R R R(
C 
C 
C 
CX X X X:Y Y Y YG G G G"* * * * 3 3 3 386 6 6 6 6 6r#   