
    0pjM                       d dl mZ d dlZd dlmZ d dlmZ d dlmZm	Z	m
Z
mZ d dlmZ d dlmZ d dlmZmZmZmZmZmZmZmZ d	d
dddd#dZd$dZd Zd Zd Zd Zd Zd Z d Z!d Z"d Z#d Z$d Z%d Z&d Z'd  Z(d! Z)d" Z*dS )%    )annotationsN)Decimal)SimpleNamespace)NOWadd_bank_rowdatabasepreview)_daily_source_exit_code)_statement_preview_payload)MODEL_SOURCE/build_truewealth_activation_performance_preview&build_truewealth_anchor_reconciliationbuild_truewealth_model_preview!build_truewealth_performance_viewrun_activated_daily_sourcerun_isolated_daily_sources)store_truewealth_modelled_daily_valuation
2026-07-271009010)daytotal
securitiescashr   
str | Nonec               f   |dnd}|,t          t          |          t          |          z
            n|}|                     ddt          f           |                     ddd|t          f           |                     d||||||t          f           t	          d	d          D ]Y\  }\  }}	}
|                     d
d| d| d| ||	|
t          f           |                     dd| d| |t          f           Z|                     d||t          f           |                                  d S )Nr      zINSERT INTO truewealth_portfolios(portfolio_id,account_id,source_reference_hash,label,portfolio_kind,base_currency,is_active,created_at) VALUES('twp','tw-total',?,'Free','free_assets','CHF',1,?)@ppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppa|  INSERT INTO truewealth_import_batches(batch_id,portfolio_id,account_id,file_sha256,filename_sha256,source_file_type,parser_id,parser_version,provenance,snapshot_date,page_count,archive_reference,status,audit_id,confirmed_at,confirmed_by) VALUES('twb','twp','tw-total',?,?,'application/pdf','test','1','truewealth_customer_export',?,1,'private','confirmed','audit-anchor',?,'user')@ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff@nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnna  INSERT INTO truewealth_snapshots(snapshot_id,portfolio_id,account_id,batch_id,snapshot_date,source_total_chf,securities_total_chf,cash_total_chf,components_total_chf,reconciliation_difference_chf,reconciliation_tolerance_chf,reconciliation_status,position_count,cash_count,completeness_status,reason_codes_json,created_at) VALUES('tws','twp','tw-total','twb',?,?,?,?,?,'0','1','matched',2,?,'complete','[]',?)))CH0001260)CH0002330zINSERT INTO truewealth_snapshot_positions(snapshot_position_id,snapshot_id,source_row_reference,instrument_name,isin,quantity,price_currency,source_price,source_value_chf,source_evidence_json,created_at) VALUES(?,'tws',?,?,? ,?,'CHF','30',?,'{}',?)ztwp-zrow-zFund z|INSERT INTO instruments(instrument_id,asset_class,name,isin,currency,is_active,created_at) VALUES(?, 'etf', ?, ?, 'CHF',1,?)inst-zINSERT INTO account_value_snapshots(snapshot_id,account_id,valuation_date,total_value_chf,currency,source_type,quality_status,created_at,source_reference,is_active) VALUES('official-anchor','tw-total',?,?,'CHF','truewealth_official_import','ok',?,'tws',1))strr   executer   	enumeratecommit)connr   r   r   r   
cash_countstored_cashindexisinquantitysource_values              1tests/unit/test_sprint20d_truewealth_valuation.pyadd_truewealth_anchorr5      s   lJ?C|#gennwz':'::;;;QUKLL  V  Ya  cf  Xg  h  h  hLL  T  W_  ai  kn  ps  Vt  u  u  uLL  q  tw  y~  @J  LW  Y^  `j  lo  sp  q  q  q1:;dfg1h1h H H--h  T  We  ^c  We  We  gu  ns  gu  gu  wF  D  wF  wF  HL  NV  Xd  fi  Vj  	k  	k  	k  X  [j  ch  [j  [j  l{  ty  l{  l{  }A  CF  ZG  	H  	H  	H  	HLL  W  Z]  ^c  dg  Yh  i  i  iKKMMMMM    
2026-07-28c           	         dD ].\  }}|                      dd| d| d| ||t          f           /|                                  d S )N))r   r'   )   r   zINSERT INTO market_prices(market_price_id,instrument_id,price_date,close,currency,provider,quality_status,created_at) VALUES(?,?,?,?,'CHF','test','fresh',?)zprice--r(   )r*   r   r,   )r-   r   r0   prices       r4   add_exact_pricesr<   $   s    + u uu  x  {Q  DI  {Q  {Q  LO  {Q  {Q  Sb  [`  Sb  Sb  dg  in  ps  zt  	u  	u  	u  	uKKMMMMMr6   c                    t                      } |                     dt          t          f           t          |            t	          |            |                     dt          f           |                                  t          | d          }|d         dk    sJ |d         dk    sJ |d	         d
k    sJ |d         dk    sJ |d         d         du sJ |                     d                                          d         dk    sJ d S )NINSERT INTO audit_log(audit_id,timestamp,source,action,entity_type,entity_id,old_values_json,new_values_json,created_by,created_at) VALUES('audit-anchor',?,'test','confirm','batch','twb','{}','{}','user',?)a  INSERT INTO transactions(transaction_id,transaction_type,activity_kind,account_id,trade_date,gross_amount_original,net_amount_original,currency_original,fx_rate_to_chf,fx_source,fx_status,gross_amount_chf,net_amount_chf,source_type,source_id,is_confirmed,quality_status,created_at) VALUES('deposit','external_deposit','external_deposit','tw-total','2026-07-28','20','20','CHF','1','identity','ok','20','20','test','test',1,'complete',?)r7   as_ofstatusreadyposition_value_chfz90.00unassigned_cash_chfz30.00modelled_value_chfz120.00anchorsource_total_is_control_onlyTzJSELECT COUNT(*) FROM transactions WHERE transaction_type IN ('buy','sell')r   )r   r*   r   r5   r<   r,   r   fetchoner-   results     r4   Rtest_modelled_value_uses_positions_and_cash_once_and_keeps_contribution_unassignedrK   *   sU   ::DLL  b  eh  il  dm  n  n  n$TLL  L  OR  NT  U  U  UKKMMM+DEEEF(w&&&&&'72222'(G3333&'83333(:;tCCCC<<deennppqrswxxxxxxxr6   c                 l   t                      } |                     dt          t          f           t          |            t	          |            |                     dt          f           |                                  t          | d          }|d         dk    sJ |d         J d|d	         v sJ d S )
Nr>   al  INSERT INTO transactions(transaction_id,transaction_type,activity_kind,account_id,trade_date,gross_amount_original,net_amount_original,currency_original,fx_status,source_type,source_id,is_confirmed,quality_status,created_at) VALUES('usd-deposit','external_deposit','external_deposit','tw-total','2026-07-28','100','100','USD','missing','test','test',1,'partial',?)r7   r?   rA   blockedrE   external_cashflow_chf_missingreason_codes)r   r*   r   r5   r<   r,   r   rI   s     r4   Dtest_non_chf_cashflow_without_canonical_amount_blocks_modelled_valuerP   <   s    ::DLL  b  eh  il  dm  n  n  n$TLL  D  GJ  FL  M  M  MKKMMM+DEEEF(y((((&'///*f^.DDDDDDDr6   c                 P   t                      } |                     dt          t          f           t          | d            t	          |            t          | d          }|d         dk    sJ |d         d         d	k    sJ |d         d
         dk    sJ |d         dk    sJ d S )Nr>   )r   r7   r?   rA   rB   rF   
cash_basis&source_total_minus_confirmed_positionscash_chf10.00rE   100.00)r   r*   r   r5   r<   r   rI   s     r4   =test_model_derives_cash_residual_when_anchor_has_no_cash_rowsrW   K   s    ::DLL  b  eh  il  dm  n  n  n$T****T+DEEEF(w&&&&(L)-UUUUU(J'72222&'8333333r6   c                    t                      } |                     dt          t          f           t          |            t	          | d          }|d         dk    sJ |d         J d|d         v sJ |d	         J d S )
Nr>   r7   r?   rA   rM   rE   exact_date_price_missingrO   latest_modelled_value)r   r*   r   r5   r   rI   s     r4   Jtest_missing_exact_price_blocks_new_day_without_faking_a_modelled_fallbackr[   Y   s    ::DLL  b  eh  il  dm  n  n  n$+DEEEF(y((((&'///%)?????)*22222r6   c                 6   t                      } |                     dt          t          f           t          |            t	          |            |                     dt          t          f           |                                  t          | d          }t          | d          }|d         dk    sJ |d         du sJ |                     d	t          f                                          }|d
         dk    sJ dt          j
        |d                   v sJ t          dk    sJ t          j
        |                     d                                          d                   }|d         dk    sJ |d         dk    sJ h dt          |          z  rJ d S )Nr>   a2  INSERT INTO audit_log(audit_id,timestamp,source,action,entity_type,entity_id,old_values_json,new_values_json,confirmed,created_by,created_at) VALUES('active',?,'performance_activation_v1','performance_source_activation_confirmed','performance_source','truewealth','{}','{"source":"truewealth"}',1,'user',?)r7   r?   valuation_storedr   
idempotentTzYSELECT quality_status,reason_codes_json FROM portfolio_valuation_snapshots WHERE source=?quality_statuspartialttwror_provisionalreason_codes_jsontruewealth_modelled_dailyz[SELECT new_values_json FROM audit_log WHERE action='truewealth_modelled_daily_value_stored'r   position_countr9   cashflow_count>   	cashflows	positions
provenancelatest_price_fx)r   r*   r   r5   r<   r,   r   r   rH   jsonloadsset)r-   storedrepeatedrowaudit_payloads        r4   Ttest_model_store_is_provisional_append_only_and_idempotent_after_separate_activationrq   f   s    ::DLL  b  eh  il  dm  n  n  n$TLL  N  QT  UX  PY  Z  Z  ZKKMMM6t<PPPF8\RRRH$%****L!T))))
,,r  vB  uD  E  E  N  N  P  PC I----4:c2E.F#G#GGGGG66666Ji	
 	

(**Q	 M
 )*a////)*a////KKKcR_N`N``aaaaar6   c                    t                      } |                     dt          t          f           |                     dt          f           |                                  t          | d          }|d         dk    sJ |d         dk    sJ |d	         g k    sJ |                     d
                                          d         dk    sJ d S )Na  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,source_reference,quality_status,reason_codes_json) VALUES('model-old','account','tw-total','tw-total','120','CHF','CHF','1','original_to_base','2026-07-28',?,?,1,'model-fp','partial','["modelled_valuation"]')a  INSERT INTO account_value_snapshots(snapshot_id,account_id,valuation_date,total_value_chf,currency,source_type,quality_status,created_at,source_reference,is_active) VALUES('official-new','tw-total','2026-07-29','123','CHF','truewealth_official_import','ok',?,'new-source',1)zofficial-new)official_snapshot_iddifference_chfz3.00historical_model_values_changedr   inferred_robo_transactionszVSELECT value_original FROM portfolio_valuation_snapshots WHERE snapshot_id='model-old'120)r   r*   r   r   r,   r   rH   rI   s     r4   Itest_new_official_anchor_reconciles_without_changing_or_inventing_historyrx      s   ::DLL  s  vB  CF  uG  H  H  HLL  j  mp  lr  s  s  sKKMMM3D~^^^F"#v----349999./25555<<pqqzz||}~  DI  I  I  I  I  I  Ir6   c                     t                      } dD ]%\  }}}|                     d|||t          f           &|                                  t	          | dd          }|d         ddd	k    sJ |d
         dk    sJ d S )N)a
2026-06-30150000)br   152845INSERT INTO account_value_snapshots(snapshot_id,account_id,valuation_date,total_value_chf,currency,source_type,quality_status,created_at,is_active) VALUES(?,'tw-total',?,?,'CHF','manual_total_value','ok',?,1)z
2025-08-03
2026-08-03requested_fromrequested_toavailable_periodr|   r   )fromtofirst_performance_anchor)r   r*   r   r,   r   r-   snapshot_idr   valuerJ   s        r4   Itest_requested_long_period_falls_back_to_distinct_available_anchor_periodr      s    ::D#\ J JS%  l  oz  {~  D  EH  nI  	J  	J  	J  	JKKMMM.tL_klllF$%<)P)PPPPP,-======r6   c                    t                      } dD ]%\  }}}|                     d|||t          f           &|                     dt          t          f           |                                  t          | dd          }d |d         D             d	d
gk    sJ |d         d         d	k    sJ |d         d         dk    sJ |d         d         d
k    sJ d S )Nrz   r   a  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,source_reference,quality_status,reason_codes_json) VALUES('model-after','account','tw-total','tw-total','153000','CHF','CHF','1','original_to_base','2026-07-28',?,?,1,'model-fp','partial','["modelled_valuation"]')
2026-07-01r   r   c                    g | ]
}|d          S )date .0ro   s     r4   
<listcomp>zVtest_view_filters_chart_period_and_never_labels_model_as_confirmed.<locals>.<listcomp>   s    444CCK444r6   pointsr   r7   latest_confirmed_valuer   kind	confirmedrZ   r   r*   r   r   r,   r   r   s        r4   Btest_view_filters_chart_period_and_never_labels_model_as_confirmedr      sD   ::D#\ J JS%  l  oz  {~  D  EH  nI  	J  	J  	J  	JLL  x  {G  HK  zL  M  M  MKKMMM.tL_klllF446(#3444|8TTTTT*+F3|CCCC*+F3{BBBB)*62lBBBBBBr6   c                 H   t                      } |                     dt          t          f           dD ].\  }}}}|                     d|||t          t          ||f           /|                                  t          | dd          }d |d         D             d	d
gk    sJ d S )Na|  INSERT INTO account_value_snapshots(snapshot_id,account_id,valuation_date,total_value_chf,
                   currency,source_type,quality_status,created_at,is_active)
           VALUES('official','tw-total','2026-07-02','110','CHF','truewealth_official_import','ok',?,1),
                 ('official-new','tw-total','2026-07-02','115','CHF','truewealth_official_import','ok',?,1)))zmodel-anchor-old
2026-07-02105r   )zmodel-day-old
2026-07-03rw   r   )zmodel-day-latestr   125r9   a  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,source_reference,quality_status,reason_codes_json)
               VALUES(?,'account','tw-total','tw-total',?,'CHF','CHF','1','original_to_base',?,?,?,? ,?,
                      'partial','["modelled_valuation"]')r   z
2026-07-04r   c                <    g | ]}|d          |d         |d         fS )r   	value_chfr   r   r   s     r4   r   z_test_view_selects_one_latest_model_version_per_day_and_official_anchor_wins.<locals>.<listcomp>   s,    UUUSS[#k*CK8UUUr6   r   )r   115r   )r   r   modelledr   )r-   r   r   r   versionrJ   s         r4   Ktest_view_selects_one_latest_model_version_per_day_and_official_anchor_winsr      s    ::DLL	o 
c
  - 
 
(S%
 	?
 %lC+N	
 	
 	
 	
 	KKMMM.#!  F VUF8DTUUU*)Z      r6   c                 J   t                      } dD ]%\  }}}|                     d|||t          f           &t          | ddd           t	          |           }t          | |dd          }|d         d	k    sJ |d
         dk    sJ |d         dk    sJ |d         dk    sJ d S )Nrz   r   zbank-1r|   900r   bank_previewperiod_from	period_toinvestment_result_chfz1945.00deposit_total_chfz900.00xirr_readiness!ready_after_cashflow_confirmationttwror_readinessunavailable)r   r*   r   r   r	   r   )r-   r   r   r   bankrJ   s         r4   Ltest_activation_performance_preview_subtracts_deposit_from_investment_resultr      s   ::D#\ J JS%  l  oz  {~  D  EH  nI  	J  	J  	J  	Jh|E2224==D<TPTbn  {G  H  H  HF)*i7777%&(2222"#'JJJJJ$%666666r6   c                    t                      } dD ]%\  }}}|                     d|||t          f           &|                     dt          f           |                                  t	          | t          |           dd          }|d         dk    sJ |d	         d
k    sJ |d         dk    sJ t          |d                   dk    sJ d S )Nrz   zINSERT INTO account_value_snapshots(snapshot_id,account_id,valuation_date,total_value_chf,
                       currency,source_type,quality_status,created_at,is_active)
               VALUES(?,'tw-total',?,?,'CHF','manual_total_value','ok',?,1)aI  INSERT INTO transactions(transaction_id,transaction_type,activity_kind,account_id,trade_date,
                   gross_amount_original,net_amount_original,currency_original,fx_rate_to_chf,fx_source,fx_status,
                   gross_amount_chf,net_amount_chf,source_type,source_id,is_confirmed,quality_status,created_at)
           VALUES('withdrawal','external_withdrawal','external_withdrawal','tw-total','2026-07-15',
                  '-500','-500','CHF','1','identity','ok','-500','-500',
                  'truewealth_external_cashflow_v1','confirmed-withdrawal',1,'complete',?)r|   r   r   r   0.00withdrawal_total_chfz500.00r   z3345.00withdrawalsr   )r   r*   r   r,   r   r	   lenr   s        r4   Gtest_activation_performance_preview_uses_canonical_external_withdrawalsr      s   ::D$ 	
 	
S% 	O #uc*		
 	
 	
 	
 	LL	^ 
   	KKMMM<T]] 	  F %&&0000()X5555)*i7777vm$%%******r6   c                    t                      g fd} fd}fd}t          d| |fd|fg          }ddgk    sJ d |D             ddgk    sJ                     d	                                          d
         d
k    sJ                     d                                          d
         dk    sJ d S )Nc                                           d                               d                               dt          f           t          d          )NpostfinanceBEGIN IMMEDIATEzcINSERT INTO platforms(platform_id,name,platform_type,created_at) VALUES('failed','Failed','bank',?)boom)appendr*   r   RuntimeErrorcallsr-   s   r4   failzStest_daily_sources_are_isolated_and_failed_transaction_is_rolled_back.<locals>.fail   s`    ]###&'''z  ~A  }C  	D  	D  	D6"""r6   c                 B     j         r                                  d S d S )N)in_transactionrollback)r-   s   r4   r   zWtest_daily_sources_are_isolated_and_failed_transaction_is_rolled_back.<locals>.rollback  s)     	MMOOOOO	 	r6   c                                           d                               d                               dt          f                                            dddS )N
truewealthr   zeINSERT INTO platforms(platform_id,name,platform_type,created_at) VALUES('success','Success','bank',?)completer   )rA   r]   )r   r*   r   r,   r   s   r4   succeedzVtest_daily_sources_are_isolated_and_failed_transaction_is_rolled_back.<locals>.succeed  sm    \"""&'''|  @C  E  	F  	F  	F#q999r6   r   r   c                *    g | ]}|j         |j        fS r   )sourcerA   r   s     r4   r   zYtest_daily_sources_are_isolated_and_failed_transaction_is_rolled_back.<locals>.<listcomp>  s!    777SZ
#777r6   )r   failed)r   r   z9SELECT COUNT(*) FROM platforms WHERE platform_id='failed'r   z:SELECT COUNT(*) FROM platforms WHERE platform_id='success'r   )r   r   r*   rH   )r   r   r   resultsr   r-   s       @@r4   Etest_daily_sources_are_isolated_and_failed_transaction_is_rolled_backr      s,   ::DE# # # # # #
    : : : : : : )=h*GV]H^)_``G]<0000077w777<TUn;ooooo<<STT]]__`abfggggg<<TUU^^``abcghhhhhhhr6   c                     t          t          d          t          d          g          dk    sJ t          t          d          t          d          g          dk    sJ d S )Nr   )rA   rM   r   not_activatedr   )r
   r   r   r6   r4   @test_daily_cli_exit_code_is_nonzero_for_activated_blocked_sourcer     s    "	
	+	+	+_I-N-N-NO 	
    #		0	0	0/2T2T2TU 	
     r6   c                 |    t                      } g t          | dfd          }|d         dk    sJ g k    sJ d S )Nr   c                 .                          d          S )Nzprovider-called)r   )r   s   r4   <lambda>zMtest_unactivated_daily_source_never_invokes_provider_worker.<locals>.<lambda>%  s    .// r6   rA   r   )r   r   )r-   rJ   r   s     @r4   ;test_unactivated_daily_source_never_invokes_provider_workerr     s[    ::DE'//// F (....B;;;;;;r6   c                 N   t          t          d          t          d          t          d          t          d          g g dd d dd          } t          | d          }|d	         d
k    sJ |d         dk    sJ |d         dk    sJ |d         dk    sJ |d         dk    sJ d S )Nr   r   0r   r    r   source_total_chfsecurities_total_chfcash_total_chfcomponents_total_chfr   rg   statement_dater   r   file_sha256
page_counttax.pdfr   rU   rR   rS   r   rV   reconciliation_difference_chfr   cash_derivation_statusconfirmed_or_derivedr   r   r   	statementpayloads     r4   Ntest_statement_without_cash_derives_residual_without_adding_source_total_twicer   ,  s     $T]]s||$T]]#  I )I>>G#$////< $LLLLL)*h666623v====+,0FFFFFFFr6   c                     t          t          d          t          d          t          d          t          d          g g dd d dd          } t          | d          }|d	         d
k    sJ |d         dk    sJ d S )N80r   r   r   r    r   r   r   r   z-10.00r   rM   r   r   s     r4   0test_statement_negative_cash_residual_is_blockedr   D  s     $T]]s||$T]]#  I )I>>G#$0000+,	999999r6   )r   r   )r7   )+
__future__r   rj   decimalr   typesr   (test_sprint20d_truewealth_productizationr   r   r   r	   jarvis_finance.cli.mainr
   *jarvis_finance.services.truewealth_servicer   ,jarvis_finance.services.truewealth_valuationr   r   r   r   r   r   r   r   r5   r<   rK   rP   rW   r[   rq   rx   r   r   r   r   r   r   r   r   r   r   r   r6   r4   <module>r      s?   " " " " " "        ! ! ! ! ! ! Y Y Y Y Y Y Y Y Y Y Y Y ; ; ; ; ; ; Q Q Q Q Q Q	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 (45Tfj 
 
 
 
 
 
   y y y$E E E4 4 4
3 
3 
3b b b6I I I> > >C C C! ! !H
7 
7 
7!+ !+ !+Hi i i0    G G G0: : : : :r6   