
    Pkjj}8                        d dl mZ d dlZd dlZd dlZd dlmZmZmZ d dlm	Z	m
Z
 d dlmZmZ d dlmZ d dlmZ h dZh d	Zd,dZd-dZd.dZd/dZd0dZd1dZd2dZddd d3d%Zd2d&Zd4d'Zd5d(Zd6d*Zd4d+Z dS )7    )annotationsN)UTCdatedatetime)DecimalInvalidOperation)
ConnectionIntegrityError)Any)record_audit_event>   cashothercryptoequity>   CHFEURUSDreturnstrc                 X    t          j        t                                                    S )N)r   nowr   	isoformat     /src/jarvis_finance/services/portfolio_policy.py_nowr      s    <&&(((r   valueobjectfielderrors	list[str]Decimal | Nonec                   | dv rd S t          | t                    r|                    | d           d S 	 t          t	          |                                                     }n0# t          t          f$ r |                    | d           Y d S w xY w|                                r|dk     r|                    | d           d S |S )N)N z0: muss als exakter Decimal-Text angegeben werdenu   : ungültiger Zahlenwertr   z.: muss eine endliche, nicht-negative Zahl sein)	
isinstancefloatappendr   r   stripr   
ValueError	is_finite)r   r   r    results       r   _decimalr,      s    
t% PPPQQQtU))++,,j)   888999tt  !NNNOOOtMs   .A& &)BB
str | Nonec                N    | d n!t          |                                 d          S )Nf)format	normalize)r   s    r   _decimal_textr2   &   s$    =44fU__->->&D&DDr   payloaddict[str, Any]c                    i }dD ]$}|                      |          }|dv r|g n|||<   %t          d |                      d          pg D             d           |d<   |S )zIReturn the exact, JSON-stable policy content that a confirmation commits.)base_currencyeffective_fromhorizon	objectiveliquidity_reservemonthly_contributionmax_single_position_pctmax_crypto_pctrebalance_tolerance_pctmin_transaction_amount
benchmarksrestrictions>   r@   rA   Nc                    g | ]y}t          |t                    t          |                    d           pd          |                    d          |                    d          |                    d          dzS )asset_classr$   
target_pct	lower_pct	upper_pctrC   rD   rE   rF   )r%   dictr   get.0rows     r   
<listcomp>z&_canonical_payload.<locals>.<listcomp>5   s     		
 		
 		
 #t$$		
"377=#9#9#?R@@!ggl33 WW[11 WW[11	 		
 		
 		
r   allocationsc                ,    t          | d                   S NrC   )r   rL   s    r   <lambda>z$_canonical_payload.<locals>.<lambda>?   s    C.// r   key)rI   sorted)r3   r+   rT   r   s       r   _canonical_payloadrV   *   s    F _ _
 C  #AAAembbY^s"		
 		
  M228b		
 		
 		
 0/  F= Mr   c                    t          j        t          j        | dd                                                                                    S )NT),:)	sort_keys
separators)hashlibsha256jsondumpsencode	hexdigest)r3   s    r   _payload_hashrb   D   s?    >
7dzBBBIIKK ikkr   &tuple[list[str], list[dict[str, str]]]c           	     ~
   g }|                      d          t          vr|                    d           	 t          j        t          |                      d          pd                     n%# t          $ r |                    d           Y nw xY w|                      d          pg }t          |t                    r|s|                    d           g }t                      }t          d          }g }|D ]}t          |t                    s|                    d	           .t          |                     d
          pd          }|t          vs||v r|                    d           u|                    |           t          |                     d          | d|          }t          |                     d          | d|          }	t          |                     d          | d|          }
||	|
|                    | d           t          d ||	|
fD                       r|                    | d           |	|k    s||
k    r|                    | d           ||z  }|                    |t!          |          pdt!          |	          pdt!          |
          pdd           |r(|t          d          k    r|                    d           t#          d |D             d           }t          |                      d          d|          }|(|t          d          k    r|                    d           |r0|.t          |d                   |k    r|                    d           dD ]&}t          |                      |          ||           'dD ]S}t          |                      |          ||          }|+|t          d          k    r|                    | d            T|                      d!          pg }t          |t                    s|                    d"           nt%          |d#$          D ]\  }}d%| }t          |t                    s|                    | d&           8t          |          d'd(hz
  }|r|                    | d)           |                     d'          }t          |t
                    r|                                s|                    | d*           d(|v r|                    | d+           |t)          |d, -          fS ).Nr6   u   Basiswährung ist ungültigr7   r$   u1   Gültigkeitsdatum muss ISO-8601 (YYYY-MM-DD) seinrN   z/Mindestens eine Zielallokation ist erforderlich0z(Jede Zielallokation muss ein Objekt seinrC   u&   Assetklasse ist ungültig oder doppeltrD   z	 ZielwertrE   z UntergrenzerF   z Obergrenzez2: Zielwert und beide Bandgrenzen sind erforderlichc              3  <   K   | ]}|t          d           k    V  dS )100N)r   )rK   r   s     r   	<genexpr>z_validate.<locals>.<genexpr>h   s-      JJ%uwu~~%JJJJJJr   u7   : Prozentwerte dürfen 100 Prozent nicht überschreitenz0: Zielwert muss innerhalb der Bandgrenzen liegenrG   rg   u2   Zielallokationen müssen exakt 100 Prozent ergebenc              3  2   K   | ]}|d          dk    |V  dS )rC   r   Nr   rJ   s     r   rh   z_validate.<locals>.<genexpr>p   s1      OO3M0Bh0N0N30N0N0N0NOOr   r=   zMaximale Crypto-Quoteu;   Maximale Crypto-Quote darf 100 Prozent nicht überschreitenu>   Crypto-Zielallokation überschreitet die maximale Crypto-Quote)r:   r;   r?   )r<   r>   u'   : darf 100 Prozent nicht überschreitenr@   u-   Benchmarks müssen als Liste angegeben werden   )startz
Benchmark z: muss ein Objekt sein	referenceweightu%   : enthält nicht unterstützte Felderz: Referenz ist erforderlichu$   : Gewichte werden nicht unterstütztc                    | d         S rP   r   rQ   s    r   rR   z_validate.<locals>.<lambda>   s    c-6H r   rS   )rI   VALID_CURRENCIESr'   r   fromisoformatr   r)   r%   listsetr   rH   VALID_CLASSESaddr,   anyr2   next	enumerater(   rU   )r3   r    rowsseentotal
normalizedrL   assettargetlowerupperr   capr   r   r@   index	benchmark
unexpectedrl   s                       r   	_validater   J   s   F{{?##+;;;3444K3w{{+;<<BCCDDDD K K KIJJJJJK;;}%%+DdD!!  GHHHUUDCLLE')J r r#t$$ 	MMDEEECGGM**0b11%%$MMBCCC#'',//E1D1D1DfMM--%/E/E/EvNN--%/D/D/DfMM>U]emMMUVVVWWWJJFE53IJJJJJ 	]MMU[[[\\\6>>Ve^^MMUTTTUUU%}V?T?T?[X[jwx}j~j~  kF  CF  Ub  ch  Ui  Ui  Up  mp  q  q  	r  	r  	r  	r L''JKKKOO*OOOQUVVF
7;;/002I6
R
RC
3//STTT X#/gf\.B&C&Cc&I&IVWWWX 4 4U##UF3333G M MU++UF;;!7!7MMUKKKLLL\**0bJj$'' NEFFFF )*A > > > 	N 	NE9(((Ei.. >>>???Y;*AAJ OMMMNNN!k22Ii-- EY__5F5F ECCCDDD9$$LLLMMM6**H*HIIIIIs   6A, ,BBconnr	   c                    ~ t          |          }t          |          \  }}||d<   dt          |          d d         z   dt          j                    j        z   | |||sdnddS )NrN   zpolicy-preview-   zpolicy-confirm-u   Policy kann bestätigt werdenu"   Policy enthält Validierungsfehler)
preview_idconfirmation_idvalidr    rN   summary)rV   r   rb   uuiduuid4hex)r   r3   	canonicalr    rN   s        r   preview_policyr      s    "7++I#I..FK*Im'-	*B*B3B3*GG,tz||/??":@j22Fj  r   Tactive_only	policy_idr   boolr   dict[str, Any] | Nonec                  |r*|                      d|f                                          }n1|rdnd}|                      d| d                                          }|sd S t          |          }dD ]A}t          j        |                    |          pd          ||                    d          <   Bt          |d	                   |d	<   d
 |                      d|d         f                                          D             |d<   |S )Nz2SELECT * FROM portfolio_policies WHERE policy_id=?zWHERE is_active=1r$   z!SELECT * FROM portfolio_policies z ORDER BY version DESC LIMIT 1)benchmarks_jsonrestrictions_jsonz[]_json	is_activec                ,    g | ]}t          |          S r   )rH   )rK   items     r   rM   z _load_policy.<locals>.<listcomp>   s0      c  c  cDT$ZZ  c  c  cr   z}SELECT asset_class, target_pct, lower_pct, upper_pct FROM portfolio_policy_allocations WHERE policy_id=? ORDER BY asset_classr   rN   )	executefetchonerH   r^   loadspopremovesuffixr   fetchall)r   r   r   rL   wherer+   rT   s          r   _load_policyr      sU    qllOR[Q]^^ggii'2:##lldudddeennpp t#YYF7 P P,0Jvzz#7N$,O,Os(())vk233F; c  cDLL  BA  DG  HS  DT  CV  5W  5W  5`  5`  5b  5b  c  c  cF=Mr   c                   |                     d          durt          d          t          |          }t          | |          }|d         s(t          d                    |d                             |                     d          |d         k    rt          d          |d	         |d	<   t          |                     d
          pd          }|st          d          t          |          }	 |                     d           |                     d|f                                          }|rH|d         |k    rt          d          | 	                                 |d         |d         |d         ddS |                     d                                          }t          |r|d         nd          dz   }dt          j                    j         }	t                      }
|r|                     d|d         f           t          | ddd|	||r|d         nd ddd          }|                     d |	|d|d!         |r|d         nd |d"         |d#         |d$         |d%         |d&         |d'         |d(         |d)         |d*         t!          j        |d+         d,          t!          j        |d-         d,          |||||
f           |d	         D ]O}|                     d.d/t          j                    j         |	|d0         |d1         |d2         |d3         f           P|                                  n# t&          $ r}| 	                                 |                     d|f                                          }|r:|d         |k    rt          d          ||d         |d         |d         ddcY d }~S t          d4          |d }~wt(          $ r | 	                                  w xY w|	||d5dS )6NconfirmTu'   Explizite Bestätigung ist erforderlichr   z; r    r   u3   Vorschau stimmt nicht mit der Bestätigung übereinrN   r   r$   u   Bestätigungskennung fehltzBEGIN IMMEDIATEzpSELECT policy_id, version, audit_id, payload_hash
               FROM portfolio_policies WHERE confirmation_id=?payload_hashuB   Bestätigungskennung wurde mit verändertem Inhalt wiederverwendetr   versionaudit_id)r   r   r   
idempotentzaSELECT policy_id, version FROM portfolio_policies WHERE is_active=1 ORDER BY version DESC LIMIT 1r   rj   zpolicy-z;UPDATE portfolio_policies SET is_active=0 WHERE policy_id=?portfolio_policy_apiportfolio_policy_confirmedportfolio_policy)r   previous_policy_iduser)sourceactionentity_type	entity_id
new_values	confirmed
created_bya  INSERT INTO portfolio_policies(policy_id, version, is_active, effective_from, previous_policy_id, base_currency, horizon, objective, liquidity_reserve, monthly_contribution, max_single_position_pct, max_crypto_pct, rebalance_tolerance_pct, min_transaction_amount, benchmarks_json, restrictions_json, request_fingerprint, confirmation_id, payload_hash, audit_id, created_at)
               VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)r7   r6   r8   r9   r:   r;   r<   r=   r>   r?   r@   )rZ   rA   zINSERT INTO portfolio_policy_allocations(
                       allocation_id, policy_id, asset_class, target_pct, lower_pct, upper_pct
                   ) VALUES (?,?,?,?,?,?)zalloc-rC   rD   rE   rF   z-Policy konnte nicht atomar gespeichert werdenF)rI   r)   rV   r   joinr   rb   r   r   rollbackintr   r   r   r   r   r^   r_   commitr
   	Exception)r   r3   r   previewr   fingerprintexistingpriorr   r   r   r   rL   excs                 r   confirm_policyr      s   {{9T))BCCC"7++IT9--G7 778#455666{{<  GL$999NOOO&}5Im'++&788>B??O 75666	**KM&'''<<B
 
 (**	 	
  	N';66 !efffMMOOO!)+!68ICVdlmwdx  IM  N  N  N  A  B  B  K  K  M  M%6eI&&Q77!;0djll.00	ff 	LLM{#%   &)/*"<A&KeK&8&8t  
 
 
 	E 7Ay1A'B&+5k""y7Q)$i&<-.	:P0Q34i@P6Q34i@X6Y
9\2dCCC
9^4EEE+x
	
 	
 	
 ]+ 		 		CLL- 0TZ\\-//C<N%s;'7[9I	    	 S S S<<B
 
 (**	 	
  	N';66 X  "*+!68ICVdlmwdx  IM  N  N  N  N  N  N  N  NHIIsR    #wH\abbbs-   4BL= <G L= =
O3A3O:O3 O#O3c                .    t          |           }|d u|dS )N)
configuredpolicyr   r   r   s     r   active_policyr     s"    $F ,???r   c                &    t          | d|          S )zALoad one immutable policy version without changing storage state.Fr   r   )r   r   s     r   policy_detailr     s    %9EEEEr   list[dict[str, Any]]c                h    |                      d                                          }d |D             S )NzSELECT policy_id, version, is_active, effective_from, previous_policy_id, base_currency, horizon, objective, created_at, audit_id FROM portfolio_policies ORDER BY version DESCc                ^    g | ]*}i t          |          d t          |d                    i+S )r   )rH   r   rJ   s     r   rM   z"policy_history.<locals>.<listcomp>  s;    OOO3>tCyy>+tC,<'='=>>OOOr   )r   r   )r   rx   s     r   policy_historyr     sI    <<  J  K  K  T  T  V  VDOO$OOOOr   c                |    t          |           }|sddg ddS d|d         |d         dd	 |d
         D             ddS )NFunavailablez&Anlagestrategie ist nicht konfiguriert)r   data_quality_statusrx   reasonTr   r7   partialc                "    g | ]}i |d dddS )Nnot_assessableuJ   Aktuelle Werte sind noch nicht vollständig klassifiziert und vergleichbar)current_pctstatusr   r   )rK   
allocations     r   rM   z#evaluate_policy.<locals>.<listcomp>#  sr      UV  UV  UV  r|  Vm  Yc  Vm  tx  DT  `l  Vm  Vm  Vm  UV  UV  UVr   rN   uB   Keine definitive Policy-Einhaltung bei unvollständigem Datenstand)r   r   r7   r   rx   r   r   r   s     r   evaluate_policyr     s    $F K#MSU  bJ  K  K  	K 6)+<PVWgPh  BK  UV  UV  @F  GT  @U  UV  UV  UV  bf  g  g  gr   )r   r   )r   r   r   r   r    r!   r   r"   )r   r"   r   r-   )r3   r4   r   r4   )r3   r4   r   r   )r3   r4   r   rc   )r   r	   r3   r4   r   r4   )r   r	   r   r   r   r-   r   r   )r   r	   r   r4   )r   r	   r   r   r   r   )r   r	   r   r   )!
__future__r   r\   r^   r   r   r   r   decimalr   r   sqlite3r	   r
   typingr   jarvis_finance.audit.logr   rs   ro   r   r,   r2   rV   rb   r   r   r   r   r   r   r   r   r   r   r   <module>r      s   " " " " " "    ( ( ( ( ( ( ( ( ( ( - - - - - - - - . . . . . . . .       7 7 7 7 7 7555((( ) ) ) )   "E E E E   4   CJ CJ CJ CJL    ;?X\       \c \c \c \c~@ @ @ @
F F F F
P P P P
g g g g g gr   