Ë
    }0=iÖI  ã                  óÈ   — 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 ddlmZmZmZmZ e
rdd	lmZ dd
lmZ  ed¬«       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ÚOptionalé   )ÚInsufficientBalanceErrorÚInvalidParamsErrorÚInvalidPointTypeErrorÚWalletOperationError)Ú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__© ó    úW/home/cursorai/projects/telegram-earn/packages/wallet_utils/src/wallet_utils/service.pyr   r      s?   … á1àƒNØƒJØ	ƒHØ	ƒHØ
ƒIØƒOØÓØÓØƒJØƒJØÔr+   r   c                  óH  — e Zd ZdZh d£Z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                ó   — || _         y)zª
        Initialize the wallet service.

        Args:
            repository: WalletRepositoryProtocol instance that defines point types and provides User model
        N)Ú
repository)Úselfr0   s     r,   Ú__init__zWalletService.__init__>   s   € ð %ˆ�r+   Nc                óf  — |€i }| j                  d|||||d|«       | j                  j                  «       }|j                  |d«      }	t	        dt        |	«      «      }	|j                  t        d«      |	z  t        ¬«      }
	 | j                  j                  |||
d¬«      }t        d|||d
|
|||| j                  «       |j                  di «      ¬«      }	 | j                  j                  |«      }|S # 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

        Raises:
            InvalidPointTypeError: If point type doesn't exist
            InvalidParamsError: If params are invalid
            WalletOperationError: If the operation fails
        NÚaddFé   r   ú0.1©Úrounding©Úallow_negativezError adding user point: ÚcÚdata©r   r   r   r   r   r   r   r    r!   r"   r$   ú#Error creating transaction record: )Ú_validate_add_deduct_pointr0   Úget_point_typesÚgetÚmaxr   Úquantizer   r   Úupdate_balanceÚ	Exceptionr   r   Ú_get_current_datetimeÚcreate_transaction_record)r1   Úuser_idÚ
point_typer   Úremarksr    Úparamsr   Úpoint_typesÚdecimal_placesÚamount_roundedÚbalance_afterÚeÚrecordÚtransaction_ids                  r,   Ú	add_pointzWalletService.add_pointG   sZ  € ð< ˆ>ØˆFà×'Ñ'Ø�7˜J¨°¸ÀUÈFô	
ð
 —o‘o×5Ñ5Ó7ˆØ$Ÿ™¨°QÓ7ˆÜ˜Q¤ NÓ 3Ó4ˆð  Ÿ™¬°«¸>Ñ)IÔTa˜Óbˆð	OØ ŸO™O×:Ñ:¸7ÀJÐP^ÐotÐ:ÓuˆMô
 #ØØØØØØ!Ø!Ø!ØØ×,Ñ,Ó.Ø—z‘z &¨"Ó-ô
ˆð	YØ!Ÿ_™_×FÑFÀvÓNˆNð Ðøô- ò 	OÜ&Ð)BÀ1À#Ð'FÓGÈQÐNûð	Oûô& ò 	YÜ&Ð)LÈQÈCÐ'PÓQÐWXÐXûð	Yús0   ÂC3 ÃD Ã3	DÃ<DÄDÄ	D0ÄD+Ä+D0c	                ó  — |€i }| j                  d|||||||«       | j                  j                  «       }	|	j                  |d«      }
t	        dt        |
«      «      }
|j                  t        d«      |
z  t        ¬«      }	 | j                  j                  ||||¬«      \  }}|sP| j                  j                  ||«      }t        |«      }t        |«      }t        d	|d
|
› d�›d|d
|
› d�›�||¬«      ‚t        d|||d||||| j!                  «       |j                  di «      ¬«      }	 | j                  j#                  |«      }|S # 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

        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
        NÚdeductr5   r   r6   r7   r9   zError deducting user point: z6Insufficient balance for this transaction. Available: Ú.Úfz, Requested: )Ú	availableÚ	requestedÚdr<   r=   r>   )r?   r0   r@   rA   rB   r   rC   r   r   Údeduct_balance_atomicrE   r   Úget_user_balanceÚfloatr   r   rF   rG   )r1   rH   rI   r   rJ   r    r:   rK   r   rL   rM   rN   ÚsuccessrO   rP   Úcurrent_balancerX   rY   rQ   rR   s                       r,   Údeduct_pointzWalletService.deduct_point�   sÝ  € ðF ˆ>ØˆFà×'Ñ'Ø�g˜z¨6°7¸JÈÐX^ô	
ð
 —o‘o×5Ñ5Ó7ˆØ$Ÿ™¨°QÓ7ˆÜ˜Q¤ NÓ 3Ó4ˆð  Ÿ™¬°«¸>Ñ)IÔTa˜Óbˆð	RØ%)§_¡_×%JÑ%JØ˜ ^ÀNð &Kó &Ñ"ˆG�]ñ à"Ÿo™o×>Ñ>¸wÈ
ÓSˆOÜ˜oÓ.ˆIÜ˜f›ˆIÜ*ØHÈÐSTÐUcÐTdÐdeÐReÐHfð gØ'¨¨.Ð)9¸Ð':Ð;ð=à#Ø#ô	ð ô #ØØØØØØ!Ø!Ø!ØØ×,Ñ,Ó.Ø—z‘z &¨"Ó-ô
ˆð	YØ!Ÿ_™_×FÑFÀvÓNˆNð ÐøôG ò 	RÜ&Ð)EÀaÀSÐ'IÓJÐPQÐQûð	Rûô@ ò 	YÜ&Ð)LÈQÈCÐ'PÓQÐWXÐXûð	Yús0   Â"E Ä+E( Å	E%ÅE Å E%Å(	FÅ1F Æ F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!©rI   N)r0   r@   r   )r1   rH   rI   Úvalid_typess       r,   Ú_validate_user_point_typez'WalletService._validate_user_point_typeì   s>   € ð —o‘o×5Ñ5Ó7ˆØ˜[Ñ(Ü'Ø! * ¨YÐ7ÀJôð ð )r+   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
        r4   rS   r`   zInvalid params for z(), it must be a dict!)Úmethodr<   zInvalid params["data"] for z, z-(), some of the data parameters are invalid: Ú!N)rf   Ú
isinstanceÚdictr   ÚkeysÚRESERVED_FIELDSÚappendÚjoin)r1   Ú
add_deductrH   rI   r   rJ   r    r:   rK   rh   Úinvalid_fieldsÚfieldÚ
fields_strs                r,   r?   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Ø!ôð ð ð !/Ðr+   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 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   rb   rc   rd   ©r   ©r    ©r;   rZ   úInvalid transaction_type: ú&. Must be 'c' (credit) or 'd' (debit).©r   ©r   ©Ú
cdate__gte©Ú
cdate__ltez-cdater   Ú	isoformatr=   )r0   Úget_wallet_modelÚobjectsÚallÚfilterr@   r   r   rj   r   r   ÚfromisoformatÚorder_byr   r   r   r   r   r   r   r   r    r!   Úhasattrr"   r�   r$   rn   )r1   rH   rI   r    Útransaction_typer   Ú
start_dateÚend_dateÚlimitÚoffsetÚwallet_modelÚquerysetre   ÚrecordsÚobjrQ   s                   r,   Ú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Õ"ð ð  ˆr+   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�   r=   N)r0   r‚   rƒ   rA   r   r   r   r   r   r   r   r   r    r!   rˆ   r"   r�   r   r$   ÚDoesNotExist)r1   rR   rŽ   r‘   s       r,   Úget_transaction_by_idz#WalletService.get_transaction_by_id¢  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
        ru   rb   rc   rd   rv   rw   rx   ry   rz   r{   r|   r}   r   )r0   r‚   rƒ   r„   r…   r@   r   r   rj   r   r   r†   Úcount)r1   rH   rI   r    r‰   r   rŠ   r‹   rŽ   r�   re   s              r,   Úcount_transactionsz WalletService.count_transactions¿  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à�~‰~ÓÐr+   c                 óF   — t        j                  «       j                  «       S )z*Get current datetime as ISO format string.)r   Únowr�   r*   r+   r,   rF   z#WalletService._get_current_datetime  s   € ô �|‰|‹~×'Ñ'Ó)Ð)r+   )r0   z'WalletRepositoryProtocol')NNéœÿÿÿ)rH   r   rI   r   r   r   rJ   r   r    r   rK   úOptional[Dict[str, Any]]r   r   Úreturnr   )NFNr›   )rH   r   rI   r   r   r   rJ   r   r    r   r:   ÚboolrK   rœ   r   r   r�   r   )rH   r   rI   r   r�   ÚNone)rp   r   rH   r   rI   r   r   r   rJ   r   r    r   r:   rž   rK   r#   r�   rŸ   )	NNNNNNNNr   )rH   r   rI   ú
str | Noner    r   r‰   r    r   r   rŠ   údatetime | str | Noner‹   r¡   rŒ   r   r�   r   r�   zlist[TransactionRecord])rR   r   r�   zTransactionRecord | None)NNNNNNN)rH   r   rI   r    r    r   r‰   r    r   r   rŠ   r¡   r‹   r¡   r�   r   )r�   r   )r%   r&   r'   r(   rm   r2   rS   r`   rf   r?   r’   r•   r˜   ÚstaticmethodrF   r*   r+   r,   r.   r.   (   sq  „ ñò€Oó%ð "&Ø+/ØðFàðFð ðFð ð	Fð
 ðFð ðFð )ðFð ðFð 
óFð\ "&Ø$Ø+/Øð[àð[ð ð[ð ð	[ð
 ð[ð ð[ð ð[ð )ð[ð ð[ð 
ó[ózð)àð)ð ð)ð ð	)ð
 ð)ð ð)ð ð)ð ð)ð ð)ð 
ó)ðZ #Ø!%Ø!%Ø'+ØØ,0Ø*.Ø Øð|àð|ð ð|ð ð	|ð
 %ð|ð ð|ð *ð|ð (ð|ð ð|ð ð|ð 
!ó|ó|ð> #Ø!%Ø!%Ø'+ØØ,0Ø*.ð@ àð@ ð ð@ ð ð	@ ð
 %ð@ ð ð@ ð *ð@ ð (ð@ ð 
ó@ ðD ò*ó ñ*r+   r.   N)r(   Ú
__future__r   Údataclassesr   r   Údecimalr   r   Útypingr   r	   r
   r   Ú
exceptionsr   r   r   r   Údjango.db.modelsr   r0   r   r   r.   r*   r+   r,   Ú<module>r©      sY   ðÙ ,å "å !Ý ß *ß 5Ó 5÷ó ñ Ý&å4ñ �$Ô÷ð ó ð÷ \*ò \*r+   