Ë
    ž|Siû‹  ã                  ó.  — d Z ddlmZ ddlmZ ddlmZ ddlmZmZ ddl	m
Z
mZmZmZmZ ddlmZmZmZmZmZmZmZ dd	lmZmZmZ dd
lmZ ddlmZ ddlm Z  e
rddl!m"Z" ddl#m$Z$  ed¬«       G d„ d«      «       Z%e G d„ d«      «       Z& G d„ d«      Z'y)z&Wallet service for point transactions.é    )Úannotations)Ú	dataclass)Údatetime)ÚDecimalÚROUND_HALF_UP)ÚTYPE_CHECKINGÚAnyÚDictÚListÚOptionalé   )ÚHookExecutionErrorÚHookRejectionErrorÚInsufficientBalanceErrorÚInvalidParamsErrorÚInvalidPointTypeErrorÚUserNotFoundErrorÚWalletOperationError)ÚHookManagerÚHookTypeÚPostHookError)ÚHookContext)Úget_global_registry)Útransfer_completed)ÚModel)ÚWalletRepositoryProtocolT)Úfrozenc                  ó€   — e Zd ZU dZded<   ded<   ded<   ded<   ded	<   d
ed<   d
ed<   ded<   ded<   ded<   ded<   y)ÚTransactionRecordz'Represents a wallet transaction record.ú
int | NoneÚidÚstrÚwtypeÚintÚiidÚuidÚtyper   ÚamountÚbalanceÚ
trans_typeÚdescrÚcdateúDict[str, Any]Ú
extra_dataN)Ú__name__Ú
__module__Ú__qualname__Ú__doc__Ú__annotations__© ó    úN/home/cursorai/projects/django-wallet-utils/src/django_wallet_utils/service.pyr   r      s?   … á1àƒNØƒJØ	ƒHØ	ƒHØ
ƒIØƒOØÓØÓØƒJØƒJØÔr5   r   c                  ój   — e Zd ZU dZded<   dZded<   dZded<   dZded	<   dZd
ed<   dZ	ded<   dd„Z
y)ÚTransactionResultað  
    Result of a wallet transaction with hook execution status.

    Attributes:
        success: Whether the transaction was successful
        transaction_id: Transaction ID if successful
        error_code: Error code if transaction failed (PRE hook rejection or validation error)
        error_message: Human-readable error message if failed
        error_details: Additional error context if failed
        post_hook_errors: List of errors from POST hooks (transaction still successful)
    ÚboolÚsuccessNr    Útransaction_idú
str | NoneÚ
error_codeÚerror_messagezDict[str, Any] | NoneÚerror_detailszList[PostHookError] | NoneÚpost_hook_errorsc                ó\  — | j                   | j                  dœ}| j                  r+| j                  | j                  | j                  xs i dœ|d<   | j
                  rJ| j
                  D �cg c]1  }|j                  |j                  |j                  |j                  dœ‘Œ3 c}|d<   |S c c}w )z(Convert to dictionary for API responses.)r:   r;   ©ÚcodeÚmessageÚdetailsÚerror©ÚhookrC   rD   rE   Úwarnings)	r:   r;   r=   r>   r?   r@   Ú	hook_namerD   rE   )ÚselfÚresultÚerrs      r6   Úto_dictzTransactionResult.to_dictD   s°   € ð —|‘|Ø"×1Ñ1ñ
ˆð
 �?Š?àŸ™Ø×-Ñ-Ø×-Ñ-Ò3°ñˆF�7‰Oð × Ò ð  ×0Ò0ó"ñ 1�Cð  ŸM™MØŸN™NØ"Ÿ{™{Ø"Ÿ{™{ó	ð 1ñ"ˆF�:Ñð ˆùò"s   Á+6B))Úreturnr-   )r/   r0   r1   r2   r3   r;   r=   r>   r?   r@   rN   r4   r5   r6   r8   r8   /   sH   … ñ
ð ƒMØ!%€N�JÓ%Ø!€J�
Ó!Ø $€M�:Ó$Ø+/€MÐ(Ó/Ø37ÐÐ0Ó7ôr5   r8   c                  ó‚  — e Zd ZdZh d£Zddd„Z	 	 	 d	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 dd„Z	 	 	 	 d	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 dd„Z	 	 	 	 d	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 dd„Zdd„Z		 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 dd	„Z
	 	 	 	 	 	 	 	 	 d	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 dd
„Zdd„Z	 	 	 	 	 	 	 d	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 dd„Zedd„«       Zy)ÚWalletServicezè
    Python port of the legacy WalletPoint PHP class.

    The service works with a WalletRepositoryProtocol that only needs to define point types.
    All balance operations and transaction recording are handled automatically.
    >
   r!   r%   r&   r'   r,   r+   r#   r(   r)   r*   c                ód   — || _         || _        |rt        t        «       «      | _        yd| _        y)a  
        Initialize the wallet service.

        Args:
            repository: WalletRepositoryProtocol instance that defines point types and provides User model
            enable_hooks: Whether to enable hook execution (default: False for backward compatibility)
        N)Ú
repositoryÚenable_hooksr   r   Úhook_manager)rK   rS   rT   s      r6   Ú__init__zWalletService.__init__v   s.   € ð %ˆŒØ(ˆÔÙBNœKÔ(;Ó(=Ó>ˆÕÐTXˆÕr5   Nc                ó¤  — |€i }| j                  d|||||d|«       | j                  j                  «       }|j                  |d«      }	t	        dt        |	«      «      }	|j                  t        d«      |	z  t        ¬«      }
| j                  rX| j                  rL| j                  j                  ||«      }t        d|||
|||||¬«	      }	 | j                  j                  |«       	 | j                  j)                  |||
d¬
«      }t/        d|||d|
|||| j1                  «       |j                  di «      ¬«      }	 | j                  j3                  |«      }g }| j                  r>| j                  r2t        d|||
|||||d|i¬«
      }| j                  j5                  |«      }| j                  rt        d||r|¬«      S d¬«      S |S # t        $ r7}t        d|j                   |j"                  |j$                  ¬	«      cY d}~S d}~wt&        $ r ‚ w xY w# t*        $ r}t-        d|› �«      |‚d}~ww xY w# t*        $ r}t-        d|› �«      |‚d}~ww xY w)a¢  
        Add points to a user wallet balance.

        Args:
            user_id: The user ID
            point_type: The type of wallet to add to (e.g., "credit_balance")
            amount: The amount to add (must be positive)
            remarks: Description/remarks for the transaction
            trans_type: Transaction type code (integer constant, optional)
            params: Extra parameters dict with optional 'data' key for additional fields
            iid: Initiator ID - ID of the user who performed this transaction (-100 for system)

        Returns:
            The transaction ID (legacy behavior) or TransactionResult (if hooks are enabled)

        Raises:
            InvalidPointTypeError: If point type doesn't exist
            InvalidParamsError: If params are invalid
            WalletOperationError: If the operation fails
            HookRejectionError: If a PRE hook rejects the transaction
        NÚaddFé   r   ú0.1©Úrounding)	Ú	operationÚuser_idÚ
point_typer(   Úremarksr*   r%   ÚparamsÚcurrent_balance©r:   r=   r>   r?   ©Úallow_negativezError adding user point: ÚcÚdata©r!   r#   r%   r&   r'   r(   r)   r*   r+   r,   r.   ú#Error creating transaction record: r;   ©
r]   r^   r_   r(   r`   r*   r%   ra   rb   ÚmetadataT©r:   r;   r@   )Ú_validate_add_deduct_pointrS   Úget_point_typesÚgetÚmaxr$   Úquantizer   r   rT   rU   Úget_user_balancer   Úexecute_pre_hooksr   r8   r=   rD   rE   r   Úupdate_balanceÚ	Exceptionr   r   Ú_get_current_datetimeÚcreate_transaction_recordÚexecute_post_hooks)rK   r^   r_   r(   r`   r*   ra   r%   Úpoint_typesÚdecimal_placesÚamount_roundedrb   ÚcontextÚeÚbalance_afterÚrecordr;   r@   s                     r6   Ú	add_pointzWalletService.add_point‚   s™  € ð> ˆ>ØˆFà×'Ñ'Ø�7˜J¨°¸ÀUÈFô	
ð
 —o‘o×5Ñ5Ó7ˆØ$Ÿ™¨°QÓ7ˆÜ˜Q¤ NÓ 3Ó4ˆð  Ÿ™¬°«¸>Ñ)IÔTa˜Óbˆð ×Ò ×!2Ò!2Ø"Ÿo™o×>Ñ>¸wÈ
ÓSˆOÜ!ØØØ%Ø%ØØ%ØØØ /ô
ˆGð
Ø×!Ñ!×3Ñ3°GÔ<ð	OØ ŸO™O×:Ñ:¸7ÀJÐP^ÐotÐ:ÓuˆMô
 #ØØØØØØ!Ø!Ø!ØØ×,Ñ,Ó.Ø—z‘z &¨"Ó-ô
ˆð	YØ!Ÿ_™_×FÑFÀvÓNˆNð
 ÐØ×Ò ×!2Ò!2Ü!ØØØ%Ø%ØØ%ØØØ -Ø*¨NÐ;ôˆGð  $×0Ñ0×CÑCÀGÓLÐð ×ÒÜ$ØØ-Ù5EÐ!1ôð ð LPôð ð Ðøôy &ò Ü(Ø!Ø Ÿ|™|Ø"#§)¡)Ø"#§)¡)ô	õ ûô &ò Øðûô ò 	OÜ&Ð)BÀ1À#Ð'FÓGÈQÐNûð	Oûô& ò 	YÜ&Ð)LÈQÈCÐ'PÓQÐWXÐXûð	YúsN   Ã
G Ã&H Ä:H2 Ç	HÇ,HÇ;HÈHÈ	H/ÈH*È*H/È2	IÈ;I
É
Ic	                ó²  — |€i }| j                  d|||||||«       | j                  j                  «       }	|	j                  |d«      }
t	        dt        |
«      «      }
|j                  t        d«      |
z  t        ¬«      }| j                  r[| j                  rO| j                  j                  ||«      }t        d||||||||d|i¬«
      }	 | j                  j                  |«       	 | j                  j)                  ||||¬«      \  }}|s~| j                  j                  ||«      }t/        |«      }t/        |«      }| j                  r"t        d	dd|d|
› d�›d|d|
› d�›�||dœ¬
«      S t1        d|d|
› d�›d|d|
› d�›�||¬«      ‚t3        d|||d||||| j5                  «       |j                  di «      ¬«      }	 | j                  j7                  |«      }g }| j                  r?| j                  r3t        d||||||||||dœ¬«
      }| j                  j9                  |«      }| j                  rt        d||r|¬«      S d¬«      S |S # t        $ r7}t        d	|j                   |j"                  |j$                  ¬
«      cY d}~S d}~wt&        $ r ‚ w xY w# t*        $ r}t-        d|› �«      |‚d}~ww xY w# t*        $ r}t-        d|› �«      |‚d}~ww xY w)a±  
        Deduct points from a user wallet balance using atomic SQL operation.

        Uses SQL WHERE clause to prevent race conditions and ensure balance sufficiency.

        Args:
            user_id: The user ID
            point_type: The type of wallet to deduct from
            amount: The amount to deduct (must be positive)
            remarks: Description/remarks for the transaction
            trans_type: Transaction type code (integer constant, optional)
            allow_negative: Whether to allow negative balance (default: False)
            params: Extra parameters dict with optional 'data' key for additional fields
            iid: Initiator ID - ID of the user who performed this transaction (-100 for system)

        Returns:
            The transaction ID (legacy behavior) or TransactionResult (if hooks are enabled)

        Raises:
            InsufficientBalanceError: If insufficient balance and allow_negative=False
            InvalidPointTypeError: If point type doesn't exist
            InvalidParamsError: If params are invalid
            WalletOperationError: If the operation fails
            HookRejectionError: If a PRE hook rejects the transaction
        NÚdeductrY   r   rZ   r[   re   rj   Frc   rd   zError deducting user point: ÚINSUFFICIENT_BALANCEz6Insufficient balance for this transaction. Available: Ú.Úfz, Requested: )Ú	availableÚ	requestedÚdrg   rh   ri   )r;   re   Trl   )rm   rS   rn   ro   rp   r$   rq   r   r   rT   rU   rr   r   rs   r   r8   r=   rD   rE   r   Údeduct_balance_atomicru   r   Úfloatr   r   rv   rw   rx   )rK   r^   r_   r(   r`   r*   re   ra   r%   ry   rz   r{   rb   r|   r}   r:   r~   r†   r‡   r   r;   r@   s                         r6   Údeduct_pointzWalletService.deduct_pointÿ   s…  € ðH ˆ>ØˆFà×'Ñ'Ø�g˜z¨6°7¸JÈÐX^ô	
ð
 —o‘o×5Ñ5Ó7ˆØ$Ÿ™¨°QÓ7ˆÜ˜Q¤ NÓ 3Ó4ˆð  Ÿ™¬°«¸>Ñ)IÔTa˜Óbˆð ×Ò ×!2Ò!2Ø"Ÿo™o×>Ñ>¸wÈ
ÓSˆOÜ!Ø"ØØ%Ø%ØØ%ØØØ /Ø*¨NÐ;ôˆGð
Ø×!Ñ!×3Ñ3°GÔ<ð	RØ%)§_¡_×%JÑ%JØ˜ ^ÀNð &Kó &Ñ"ˆG�]ñ à"Ÿo™o×>Ñ>¸wÈ
ÓSˆOÜ˜oÓ.ˆIÜ˜f›ˆIà× Ò Ü(Ø!Ø5Ø$ZÐ[dÐefÐguÐfvÐvwÐdwÐZxð y/Ø/8¸¸>Ð:JÈ!Ð8KÐ.Lð#Nð &/Ø%.ñ#ô	ð 	ô /ØLÈYÐWXÐYgÐXhÐhiÐViÐLjð k"Ø"+¨A¨nÐ-=¸QÐ+>Ð!?ðAà'Ø'ô	ð ô #ØØØØØØ!Ø!Ø!ØØ×,Ñ,Ó.Ø—z‘z &¨"Ó-ô
ˆð	YØ!Ÿ_™_×FÑFÀvÓNˆNð
 ÐØ×Ò ×!2Ò!2Ü!Ø"ØØ%Ø%ØØ%ØØØ -Ø,:ÈnÑ]ôˆGð  $×0Ñ0×CÑCÀGÓLÐð ×ÒÜ$ØØ-Ù5EÐ!1ôð ð LPôð ð Ðøôs &ò Ü(Ø!Ø Ÿ|™|Ø"#§)¡)Ø"#§)¡)ô	õ ûô &ò Øðûô ò 	RÜ&Ð)EÀaÀSÐ'IÓJÐPQÐQûð	RûôZ ò 	YÜ&Ð)LÈQÈCÐ'PÓQÐWXÐXûð	YúsN   ÃI Ã)"J Ç J9 É	JÉ,JÊJÊJÊ	J6Ê"J1Ê1J6Ê9	KËKËKc
                óX  — ddl m}
 ddlm} |€|}|sd}|dk  rt	        dd¬	«      ‚| j                  ||«       | j                  ||«       	 | j                  j                  |d
¬«       | j                  r`| j                  rT| j                  j                  ||«      }t!        d||||||	||d|xs i i|¬«      }	 | j                  j#                  |«       |xs i }| j                  }d
| _        	 |
j/                  «       5  di |¥d|i¥i}| j1                  ||||› d|› d�|d
||	¬«      }di |¥d|i¥i}| j3                  ||||› d|› d�|||	¬«      }| j                  j                  ||«      }| j                  j                  ||«      }| j5                  |«      }| j5                  |«      }ddd«       || _        › d› �}d||||||||dœ}|rˆ| j                  r|t!        d||||||	||d|i||||||dœ¬ «      }| j                  j7                  |«      }|r@|D �cg c]1  }|j8                  |j&                  |j(                  |j*                  d!œ‘Œ3 c}|d"<   t;        j<                  | j>                  |||||||¬#«
       |S # t        $ r8}dt        t        |«      j                  «      v rt        d|› d�|¬«      |‚‚ d}~ww xY w# t$        $ r1}d
|j&                  |j(                  |j*                  dœdœcY d}~S d}~wt,        $ r ‚ w xY w# 1 sw Y   �ŒexY w# || _        w xY wc c}w )$u³  
        Transfer points between two users atomically.

        The transfer is wrapped in a database transaction to ensure both deduction
        and addition succeed or fail together. Supports same-type transfers
        (e.g., cash â†’ cash) and cross-type transfers (e.g., cash â†’ credit).

        Args:
            from_user_id: The sender's user ID
            to_user_id: The recipient's user ID
            from_point_type: The point type to deduct from sender
            to_point_type: The point type to add to recipient
            amount: The amount to transfer (must be positive)
            remarks: Description for the transaction (default: "Point transfer")
            trans_type: Transaction type code (defaults to WALLET_TRANSFER)
            metadata: Optional metadata dict to attach to both transaction records
            iid: Initiator ID - ID of the user who performed this transaction (-100 for system)

        Returns:
            Dict with keys:
                - success: True if successful, False if rejected by hook
                - transfer_id: Unique transfer identifier (from_transaction_id:to_transaction_id)
                - from_transaction_id: Transaction ID for sender's deduction
                - to_transaction_id: Transaction ID for recipient's addition
                - from_user_id: Sender's user ID
                - to_user_id: Recipient's user ID
                - from_point_type: Sender's point type
                - to_point_type: Recipient's point type
                - amount: Transfer amount
                - from_balance: Sender's balance after transfer
                - to_balance: Recipient's balance after transfer
                - error: Error details if rejected (only if hooks enabled)
                - warnings: POST hook errors if any (only if hooks enabled)

        Raises:
            UserNotFoundError: If recipient doesn't exist
            InsufficientBalanceError: If sender has insufficient balance (only if hooks disabled)
            InvalidPointTypeError: If point type doesn't exist
            InvalidParamsError: If parameters are invalid
            WalletOperationError: If the transfer fails
            HookRejectionError: If a PRE hook rejects the transaction (only if hooks disabled)

        Example:
            # Same point type transfer
            result = service.transfer_points(
                from_user_id=1,
                to_user_id=2,
                from_point_type="cash_balance",
                to_point_type="cash_balance",
                amount=Decimal("100.00"),
                remarks="Transfer to friend",
            )

            # Cross-type transfer
            result = service.transfer_points(
                from_user_id=1,
                to_user_id=2,
                from_point_type="cash_balance",
                to_point_type="credit_balance",
                amount=Decimal("50.00"),
                remarks="Cash to credit conversion",
            )
        r   )Útransactionr   )ÚWALLET_TRANSFERNzPoint transferz Transfer amount must be positiveÚtransfer_points©ÚmethodF)Ú
for_updateÚDoesNotExistzRecipient user with ID z does not exist)r^   Útransferrg   )r]   r^   r_   r(   r`   r*   r%   Ú
to_user_idÚto_point_typera   rb   rB   )r:   rF   Útransfer_toz
 (to user Ú))r^   r_   r(   r`   r*   re   ra   r%   Útransfer_fromz (from user )r^   r_   r(   r`   r*   ra   r%   Ú:T)r:   Útransfer_idÚfrom_transaction_idÚto_transaction_idÚfrom_user_idr•   Úfrom_point_typer–   r(   Úfrom_balanceÚ
to_balance)r›   rœ   r�   r    r¡   )r]   r^   r_   r(   r`   r*   r%   r•   r–   ra   rb   rk   rG   rI   )
Úsenderr›   rž   r•   rŸ   r–   r(   Úfrom_recordÚ	to_recordrk   ) Ú	django.dbr�   Útransaction_typesrŽ   r   Ú_validate_user_point_typerS   Ú_get_balance_objectru   r"   r'   r/   r   rT   rU   rr   r   rs   r   r=   rD   rE   r   Úatomicr‹   r€   Úget_transaction_by_idrx   rJ   r   ÚsendÚ	__class__)rK   rž   r•   rŸ   r–   r(   r`   r*   rk   r%   Údb_transactionrŽ   r}   rb   r|   Útransfer_metadataÚoriginal_enable_hooksÚfrom_paramsrœ   Ú	to_paramsr�   r    r¡   r£   r¤   r›   rL   r@   rM   s                                r6   r�   zWalletService.transfer_pointsŸ  s  € õV 	<Ý6ð ÐØ(ˆJñ Ø&ˆGð �QŠ;Ü$Ð%GÐPaÔbÐbð 	×&Ñ& |°_ÔEØ×&Ñ& z°=ÔAð	Ø�O‰O×/Ñ/°
ÀuÐ/ÔMð ×Ò ×!2Ò!2Ø"Ÿo™o×>Ñ>¸|È_Ó]ˆOÜ!Ø$Ø$Ø*ØØØ%ØØ%Ø+Ø ¢¨BÐ/Ø /ôˆGðØ×!Ñ!×3Ñ3°GÔ<ð %šN¨Ðð !%× 1Ñ 1ÐØ!ˆÔð%	6à×&Ñ&Õ(à%Ð'WÐ*;Ð'W¸]ÈJÑ'WÐX�Ø&*×&7Ñ&7Ø(Ø.Ø!Ø&˜i z°*°¸QÐ?Ø)Ø#(Ø&Øð '8ó 	'Ð#ð $Ð%YÐ(9Ð%Y¸?ÈLÑ%YÐZ�	Ø$(§N¡NØ&Ø,Ø!Ø&˜i |°L°>ÀÐCØ)Ø$Øð %3ó %Ð!ð  $Ÿ™×?Ñ?ÀÈoÓ^�Ø!Ÿ_™_×=Ñ=¸jÈ-ÓX�
ð #×8Ñ8Ð9LÓM�Ø ×6Ñ6Ð7HÓI�	÷A )ðF !6ˆDÔð -Ð-¨QÐ/@Ð.AÐBˆð Ø&Ø#6Ø!2Ø(Ø$Ø.Ø*ØØ(Ø$ñ
ˆñ ! T×%6Ò%6Ü!Ø$Ø$Ø*ØØØ%ØØ%Ø+ØÐ 1Ð2Ø ,à#.Ø+>Ø):Ø$0Ø",ñôˆGð(  $×0Ñ0×CÑCÀGÓLÐáñ  0ó&ñ  0˜ð !$§¡Ø #§¡Ø#&§;¡;Ø#&§;¡;ó	ð  0ñ&��zÑ"ô 	×ÑØ—>‘>Ø#Ø%Ø!Ø+Ø'ØØ#ØØ&õ	
ð ˆøôq ò 	Ø¤¤T¨!£W×%5Ñ%5Ó!6Ñ6Ü'Ø-¨j¨\¸ÐIØ&ôð ðð ûð	ûô6 &ò à$à !§¡Ø#$§9¡9Ø#$§9¡9ññõ ûô &ò Øðú÷ )Ñ(ûðF !6ˆDÕüòZ&sa   ÁJ Â:K Ã/L Ã?B,LÆ+L È6L'Ê	KÊ3K Ë KË	LË&K=Ë7LË=LÌLÌL Ì	L$c                ób   — | j                   j                  «       }||vrt        d|› d�|¬«      ‚y)z‘
        Validate whether the given point type is valid.

        Raises:
            InvalidPointTypeError: If point type doesn't exist
        úNo such point (ú	) exists!©r_   N)rS   rn   r   )rK   r^   r_   Úvalid_typess       r6   r§   z'WalletService._validate_user_point_typeš  s>   € ð —o‘o×5Ñ5Ó7ˆØ˜[Ñ(Ü'Ø! * ¨YÐ7ÀJôð ð )r5   c	                óœ  — | j                  ||«       |dk(  rdnd}	t        |t        «      st        d|	› d�|	¬«      ‚d|v rŒ|d   r†t        |d   t        «      st        d|	› d�|	¬«      ‚g }
|d   j	                  «       D ]"  }|| j
                  v sŒ|
j                  |«       Œ$ |
r%d	j                  |
«      }t        d|	› d
|› d�|	¬«      ‚yyy)zÌ
        Validate parameters for add/deduct point operations.

        Raises:
            InvalidPointTypeError: If point type doesn't exist
            InvalidParamsError: If params are invalid
        rX   r€   r‹   zInvalid params for z(), it must be a dict!r�   rg   zInvalid params["data"] for z, z-(), some of the data parameters are invalid: Ú!N)r§   Ú
isinstanceÚdictr   ÚkeysÚRESERVED_FIELDSÚappendÚjoin)rK   Ú
add_deductr^   r_   r(   r`   r*   re   ra   r‘   Úinvalid_fieldsÚfieldÚ
fields_strs                r6   rm   z(WalletService._validate_add_deduct_point§  sþ   € ð$ 	×&Ñ& w°
Ô;à *¨eÒ 3‘¸ˆä˜&¤$Ô'Ü$Ð':¸6¸(ÐBXÐ%YÐbhÔiÐià�VÑ  v¢Ü˜f V™n¬dÔ3Ü(Ø1°&°Ð9OÐPÐY_ôð ð  ˆNØ ™×,Ñ,Ö.�Ø˜D×0Ñ0Ò0Ø"×)Ñ)¨%Õ0ð /ñ Ø!ŸY™Y ~Ó6�
Ü(Ø1°&°Ð9fÐgqÐfrÐrsÐtØ!ôð ð ð !/Ðr5   c
                ó˜  — | j                   j                  «       }
|
j                  j                  «       }|�|j	                  |¬«      }|�A| j                   j                  «       }||vrt        d|› d�|¬«      ‚|j	                  |¬«      }|�|j	                  |¬«      }|�%|dvrt        d	|› d
�«      ‚|j	                  |¬«      }|�|j	                  |¬«      }|�7t        |t        «      rt        j                  |«      }|j	                  |¬«      }|�7t        |t        «      rt        j                  |«      }|j	                  |¬«      }|j                  d«      }|	dkD  r||	d }|�|d| }g }|D ]Ô  }t        |j                  |j                  |j                   |j"                  |j$                  |j&                  |j(                  |j*                  |j,                  t/        |j0                  d«      r|j0                  j3                  «       nt        |j0                  «      |j4                  xs i ¬«      }|j7                  |«       ŒÖ |S )a¦  
        Retrieve wallet transaction history with various filters.
        
        Args:
            user_id: Filter by user ID (uid field)
            point_type: Filter by wallet/point type (wtype field)
            trans_type: Filter by transaction type code (trans_type field, integer constant)
            transaction_type: Filter by transaction type ('c' for credit, 'd' for debit) (type field)
            iid: Filter by initiator ID (iid field) - user who performed the transaction (-100 for system)
            start_date: Filter transactions from this date (inclusive) (cdate field)
            end_date: Filter transactions until this date (inclusive) (cdate field)
            limit: Maximum number of records to return
            offset: Number of records to skip (for pagination)
        
        Returns:
            List of TransactionRecord objects
        
        Example:
            # Get all transactions for a user
            transactions = service.get_transaction_history(user_id=123)
            
            # Get credit transactions for a specific point type
            transactions = service.get_transaction_history(
                user_id=123,
                point_type="credit_balance",
                transaction_type="c",
            )
            
            # Get transactions by transaction type code
            from django_wallet_utils.transaction_types import WALLET_DEPOSIT
            transactions = service.get_transaction_history(
                user_id=123,
                trans_type=WALLET_DEPOSIT,
            )
            
            # Get transactions in date range
            from datetime import datetime, timedelta
            end = datetime.now()
            start = end - timedelta(days=30)
            transactions = service.get_transaction_history(
                user_id=123,
                start_date=start,
                end_date=end,
                limit=100,
            )
        N©r&   r³   r´   rµ   ©r#   ©r*   ©rf   rˆ   úInvalid transaction_type: ú&. Must be 'c' (credit) or 'd' (debit).©r'   ©r%   ©Ú
cdate__gte©Ú
cdate__ltez-cdater   Ú	isoformatrh   )rS   Úget_wallet_modelÚobjectsÚallÚfilterrn   r   r   r¹   r"   r   ÚfromisoformatÚorder_byr   r!   r#   r%   r&   r'   r(   r)   r*   r+   Úhasattrr,   rÐ   r.   r½   )rK   r^   r_   r*   Útransaction_typer%   Ú
start_dateÚend_dateÚlimitÚoffsetÚwallet_modelÚquerysetr¶   ÚrecordsÚobjr   s                   r6   Úget_transaction_historyz%WalletService.get_transaction_historyÒ  s8  € ðt —‘×7Ñ7Ó9ˆØ×'Ñ'×+Ñ+Ó-ˆð ÐØ—‘¨7�Ó3ˆHàÐ!àŸ/™/×9Ñ9Ó;ˆKØ Ñ,Ü+Ø% j \°Ð;È
ôð ð  —‘¨Z�Ó8ˆHàÐ!Ø—‘°*�Ó=ˆHàÐ'Ø zÑ1Ü(Ø0Ð1AÐ0BÐBhÐióð ð  —‘Ð,<�Ó=ˆHàˆ?Ø—‘¨3�Ó/ˆHàÐ!Ü˜*¤cÔ*Ü%×3Ñ3°JÓ?�
Ø—‘°*�Ó=ˆHàÐÜ˜(¤CÔ(Ü#×1Ñ1°(Ó;�Ø—‘°(�Ó;ˆHð ×$Ñ$ XÓ.ˆð �AŠ:Ø  Ð(ˆHØÐØ  Ð'ˆHð ˆÛˆCÜ&Ø—6‘6Ø—i‘iØ—G‘GØ—G‘GØ—X‘XØ—z‘zØŸ™ØŸ>™>Ø—i‘iÜ/6°s·y±yÀ+Ô/N�c—i‘i×)Ñ)Ô+ÔTWÐX[×XaÑXaÓTbØŸ>™>Ò/¨RôˆFð �N‰N˜6Õ"ð ð  ˆr5   c                ó  — | j                   j                  «       }	 |j                  j                  |¬«      }t	        |j
                  |j                  |j                  |j                  |j                  |j                  |j                  |j                  |j                  t        |j                  d«      r|j                  j!                  «       nt#        |j                  «      |j$                  xs i ¬«      S # |j&                  $ r Y yw xY w)zÌ
        Get a single transaction by its ID.
        
        Args:
            transaction_id: The transaction ID
        
        Returns:
            TransactionRecord if found, None otherwise
        )r!   rÐ   rh   N)rS   rÑ   rÒ   ro   r   r!   r#   r%   r&   r'   r(   r)   r*   r+   r×   r,   rÐ   r"   r.   r“   )rK   r;   rÝ   rà   s       r6   rª   z#WalletService.get_transaction_by_idP  sÒ   € ð —‘×7Ñ7Ó9ˆð	Ø×&Ñ&×*Ñ*¨nÐ*Ó=ˆCÜ$Ø—6‘6Ø—i‘iØ—G‘GØ—G‘GØ—X‘XØ—z‘zØŸ™ØŸ>™>Ø—i‘iÜ/6°s·y±yÀ+Ô/N�c—i‘i×)Ñ)Ô+ÔTWÐX[×XaÑXaÓTbØŸ>™>Ò/¨Rôð øð ×(Ñ(ò 	Ùð	ús   œCC9 Ã9DÄ
Dc                óº  — | j                   j                  «       }|j                  j                  «       }	|�|	j	                  |¬«      }	|�A| j                   j                  «       }
||
vrt        d|› d�|¬«      ‚|	j	                  |¬«      }	|�|	j	                  |¬«      }	|�%|dvrt        d|› d	�«      ‚|	j	                  |¬
«      }	|�|	j	                  |¬«      }	|�7t        |t        «      rt        j                  |«      }|	j	                  |¬«      }	|�7t        |t        «      rt        j                  |«      }|	j	                  |¬«      }	|	j                  «       S )aõ  
        Count transactions matching the given filters.
        
        Args:
            user_id: Filter by user ID (uid field)
            point_type: Filter by wallet/point type (wtype field)
            trans_type: Filter by transaction type code (trans_type field, integer constant)
            transaction_type: Filter by transaction type ('c' for credit, 'd' for debit) (type field)
            iid: Filter by initiator ID (iid field) - user who performed the transaction (-100 for system)
            start_date: Filter transactions from this date (inclusive) (cdate field)
            end_date: Filter transactions until this date (inclusive) (cdate field)
        
        Returns:
            Number of transactions matching the filters
        rÄ   r³   r´   rµ   rÅ   rÆ   rÇ   rÈ   rÉ   rÊ   rË   rÌ   rÎ   )rS   rÑ   rÒ   rÓ   rÔ   rn   r   r   r¹   r"   r   rÕ   Úcount)rK   r^   r_   r*   rØ   r%   rÙ   rÚ   rÝ   rÞ   r¶   s              r6   Úcount_transactionsz WalletService.count_transactionsm  sd  € ð2 —‘×7Ñ7Ó9ˆØ×'Ñ'×+Ñ+Ó-ˆð ÐØ—‘¨7�Ó3ˆHàÐ!àŸ/™/×9Ñ9Ó;ˆKØ Ñ,Ü+Ø% j \°Ð;È
ôð ð  —‘¨Z�Ó8ˆHàÐ!Ø—‘°*�Ó=ˆHàÐ'Ø zÑ1Ü(Ø0Ð1AÐ0BÐBhÐióð ð  —‘Ð,<�Ó=ˆHàˆ?Ø—‘¨3�Ó/ˆHàÐ!Ü˜*¤cÔ*Ü%×3Ñ3°JÓ?�
Ø—‘°*�Ó=ˆHàÐÜ˜(¤CÔ(Ü#×1Ñ1°(Ó;�Ø—‘°(�Ó;ˆHà�~‰~ÓÐr5   c                 óF   — t        j                  «       j                  «       S )z*Get current datetime as ISO format string.)r   ÚnowrÐ   r4   r5   r6   rv   z#WalletService._get_current_datetime¯  s   € ô �|‰|‹~×'Ñ'Ó)Ð)r5   )F)rS   z'WalletRepositoryProtocol'rT   r9   )NNéœÿÿÿ)r^   r$   r_   r"   r(   r   r`   r"   r*   r    ra   úOptional[Dict[str, Any]]r%   r$   rO   úint | TransactionResult)NFNrè   )r^   r$   r_   r"   r(   r   r`   r"   r*   r    re   r9   ra   ré   r%   r$   rO   rê   )Ú NNrè   )rž   r$   r•   r$   rŸ   r"   r–   r"   r(   r   r`   r"   r*   r    rk   ré   r%   r$   rO   r-   )r^   r$   r_   r"   rO   ÚNone)r¿   r"   r^   r$   r_   r"   r(   r   r`   r"   r*   r    re   r9   ra   r-   rO   rì   )	NNNNNNNNr   )r^   r    r_   r<   r*   r    rØ   r<   r%   r    rÙ   údatetime | str | NonerÚ   rí   rÛ   r    rÜ   r$   rO   zlist[TransactionRecord])r;   r$   rO   zTransactionRecord | None)NNNNNNN)r^   r    r_   r<   r*   r    rØ   r<   r%   r    rÙ   rí   rÚ   rí   rO   r$   )rO   r"   )r/   r0   r1   r2   r¼   rV   r€   r‹   r�   r§   rm   rá   rª   rå   Ústaticmethodrv   r4   r5   r6   rQ   rQ   `   só  „ ñò€Oô
Yð$ "&Ø+/Øð{àð{ð ð{ð ð	{ð
 ð{ð ð{ð )ð{ð ð{ð 
!ó{ðF "&Ø$Ø+/Øð^àð^ð ð^ð ð	^ð
 ð^ð ð^ð ð^ð )ð^ð ð^ð 
!ó^ðN Ø!%Ø-1Øðyàðyð ðyð ð	yð
 ðyð ðyð ðyð ðyð +ðyð ðyð 
óyóvð)àð)ð ð)ð ð	)ð
 ð)ð ð)ð ð)ð ð)ð ð)ð 
ó)ðZ #Ø!%Ø!%Ø'+ØØ,0Ø*.Ø Øð|àð|ð ð|ð ð	|ð
 %ð|ð ð|ð *ð|ð (ð|ð ð|ð ð|ð 
!ó|ó|ð> #Ø!%Ø!%Ø'+ØØ,0Ø*.ð@ àð@ ð ð@ ð ð	@ ð
 %ð@ ð ð@ ð *ð@ ð (ð@ ð 
ó@ ðD ò*ó ñ*r5   rQ   N)(r2   Ú
__future__r   Údataclassesr   r   Údecimalr   r   Útypingr   r	   r
   r   r   Ú
exceptionsr   r   r   r   r   r   r   Údjango_package_hooksr   r   r   Úhooksr   rë   r   Úsignalsr   Údjango.db.modelsr   rS   r   r   r8   rQ   r4   r5   r6   Ú<module>rø      sˆ   ðÙ ,å "å !Ý ß *ß ;Õ ;÷÷ ñ ÷ FÑ EÝ Ý !Ý 'áÝ&å4ñ �$Ô÷ð ó ðð  ÷-ð -ó ð-÷`R*ò R*r5   