
    6Si'                     h   d dl 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
 d dlmZ d dlmZmZ d dlmZ d d	lmZmZ d d
lmZ d dlmZ d dlmZ  e j6                  e      Z ed      Z ed       ed       ed      dZdZ dZ! ede        G d de             Z" ede!       G d de             Z#y)    N)date	timedelta)DecimalROUND_HALF_UP)transaction)timezone)Q)CronTaskregister_task)CronExecution)
InvestmentReward)
Commission)Transaction)Userz
0.00000001z50.00z30.00z20.00)         R001D001zcalculate-rewardsc                   L    e Zd ZdZdedefdZdedefdZde	e
z  ez  de	fdZy	)
CalculateRewardsTaskz
    Phase 1: Calculate daily rewards.
    
    This task should be run for a specific date (e.g., Yesterday).
    It identifies active investments for that date and creates PENDING Reward records.
    r   returnc                 D    |}|}| j                  |      }dd| d| ddS )NFzCalculated z new rewards for .errormessage)_calculate_pending_rewards)selfr   target_datereward_daterewards_calculateds        L/home/cursorai/projects/telegram-earn/backend/apps/investments/cron_tasks.pyexecutezCalculateRewardsTask.execute%   sF     " "<<[I $%7$88I+VWX
 	
    r"   c           	         t         j                  j                  t         j                  t         j                  g||      j                         }d}t        j                         5  |D ]  }| j                  |j                  |j                  z  t        d      z        }t        j                  j                  |||dd      \  }}|j                  }|j                  t         j                  k(  rt         j                  }||j                  j!                         k\  rt         j"                  }|j                  |k7  r||_        |j%                  ddg	       |s|d
z  } 	 ddd       |S # 1 sw Y   |S xY w)z
        Identify eligible investments and create pending Reward records.
        
        reward_date: The date for which we're calculating rewards (typically yesterday).
        )
status__instart_date__date__ltend_date__date__gter   100N)amountdistributed_at)
investmentr"   defaultsstatus
updated_atupdate_fieldsr   )r   objectsfilterSTATUS_PENDINGSTATUS_ACTIVEselect_for_updater   atomic	_quantizer,   daily_reward_rater   r   get_or_creater0   end_dater   STATUS_COMPLETEDsave)	r    r"   eligible_investmentscountr.   reward_amountrewardcreated
new_statuss	            r$   r   z/CalculateRewardsTask._calculate_pending_rewards3   s_     *1188"11:3K3KL!, +  9  
 

	 	 !2
 $%%
(D(DDwu~U! #)..">">) +"/*. #? # (..
$$
(A(AA!+!9!9J*"5"5":":"<<!+!<!<J$$
2(2J%OO8\2JOKQJEA 3 "F G "F s   %C4E,E,,E6valuec                 J    t        |      j                  t        t              S N)roundingr   quantizeDECIMAL_QUANTIZEr   r    rF   s     r$   r:   zCalculateRewardsTask._quantizej       u~&&'7-&PPr&   N)__name__
__module____qualname____doc__r   dictr%   intr   r   floatr:    r&   r$   r   r      sM    
D 
T 
5d 5s 5nQw4 Q Qr&   r   zdistribute-rewardsc            
            e Zd ZdZdef fdZdedefdZdede	e
e
f   fdZded	ede
fd
Zdededededdf
dZdeez  e
z  defdZ xZS )DistributeRewardsTaskz
    Phase 2: Distribute rewards.
    
    DEPENDENCY: Depends on 'calculate-rewards' completing successfully for the same date.
    
    This task distributes the rewards calculated for the given date.
    r   c           	         t         |          syt        j                  j	                  t
        | j                  d      j                         }|s8t        j                  dt
         d| j                   d| j                   d       yy)z}
        Custom check: Ensure CalculateRewardsTask (INV001) completed successfully 
        for this execution date.
        FT)	task_codeexecution_datesuccesszDependency z not completed for z. Skipping r   )super
should_runr   r4   r5   CALCULATE_TASK_CODEr[   existsloggerwarningrZ   )r    dependency_completed	__class__s     r$   r^   z DistributeRewardsTask.should_runx   s     w!#  -44;;)..  <  
 &(	 	 $NN122EdFYFYEZ [ NN+1. r&   r   c                 v    |}t        j                         }| j                  ||      \  }}dd| d| d| ddS )NFzDistributed z rewards and z commissions for r   r   )r   now_distribute_rewards)r    r   r!   rf   rewards_distributedcommissions_createds         r$   r%   zDistributeRewardsTask.execute   s]    lln 483K3KKY\3]00 %&9%:-H[G\\mnymzz{|
 	
r&   r!   c           
         t         j                  j                  d|      j                  dd      j	                         }d}d}t        j                         5  |D ]{  }| j                  |j                  j                  |j                  t        j                  |j                  j                  |j                  d       t        j                  j	                         j                  |j                  j                        }| j!                  |j"                  |j                  z         |_        |j                  dkD  r9| j!                  |j"                  |j                  z  t%        d	      z        |_        |j)                  g d
       ||_        |j)                  dg       |dz  }| j-                  ||j                  j                  |      }||z  }~ 	 d d d        ||fS # 1 sw Y   ||fS xY w)NT)distributed_at__isnullr"   r.   investment__userr   )investment_id	reward_iduserr,   tx_typemetadatapkr+   )roi_total_amountroi_total_percentr1   r2   r-   r   )r   r4   r5   select_relatedr8   r   r9   _credit_userr.   rp   r,   r   TYPE_REWARDidr   getr:   ru   r   rv   r?   r-   _create_commissions)	r    r!   rf   pending_rewardsreward_countcommission_countrC   r.   c_counts	            r$   rg   z)DistributeRewardsTask._distribute_rewards   s    !..//#'# 0 
 .'9
:;L;L;N 	
 !)!!**//!=='33/5/@/@/C/CRXR[R[\	 "  (//AACGG6K\K\K_K_G`
.2nnZ=X=X[a[h[h=h.i
+$$q(37>>#44z7H7HHGTYNZ4J0 .ef ),%+;*<=! 2266;L;L;Q;QSVW G+ 3 * "8 ---9 "8 ---s   FG''G3rC   downline_userc                 T   d}g }|j                   }|r<t        |      dk  r.|j                  |       |j                   }|rt        |      dk  r.t        |      D ]  \  }}|dz   }	t        j                  |	      }
|
s |S | j                  |j                  |
z  t        d      z        }t        j                  j                  ||	|||
|t        j                  |d      \  }}|s|dz  }| j                  ||t        j                  |j                   |j                   |	d        |S )	Nr   r   r   r+   )r   commission_rater,   r0   r-   )rC   levelupline_userr/   )rn   downline_user_idr   ro   )referred_bylenappend	enumerateCOMMISSION_RATESr{   r:   r,   r   r   r4   r<   STATUS_DISTRIBUTEDrx   r   TYPE_COMMISSIONrz   )r    rC   r   rf   r   uplinescurrent_userir   r   rater,   
commissionrD   s                 r$   r|   z)DistributeRewardsTask._create_commissions   sD    !$00s7|a/NN<('33L s7|a/ (0NA{EE#''.D<  9 ^^FMMD$875>$IJF","4"4"B"B'%2'+$(;;&)	 #C #J  A% !!$!'77%+YY,9,<,<!&	 " 	/ 1D  r&   rp   r,   rq   rr   Nc           	      `   t         j                  j                         j                  |j                        }|j
                  }| j                  ||z         |_        |j                  dg       t        j                  j                  |||t        j                  ||j
                  |       y)z;Credit a user's balance and log the transaction atomically.rs   credit_balancer2   )rp   transaction_typer,   r0   balance_beforebalance_afterdataN)r   r4   r8   r{   rt   r   r:   r?   r   creater>   )r    rp   r,   rq   rr   user_lockedr   s          r$   rx   z"DistributeRewardsTask._credit_user   s     ll446::dgg:F$33%)^^NV4K%L"(8'9:""$//)%44 	# 	
r&   rF   c                 J    t        |      j                  t        t              S rH   rJ   rM   s     r$   r:   zDistributeRewardsTask._quantize	  rN   r&   )rO   rP   rQ   rR   boolr^   r   rS   r%   tuplerT   rg   r   r   r|   r   strrx   rU   r:   __classcell__)rd   s   @r$   rX   rX   n   s    D 2
D 
T 
(.t (.U38_ (.T, & ,  , s , \

")
47
CG
	
&Qw4 Q Qr&   rX   )$loggingdatetimer   r   decimalr   r   	django.dbr   django.utilsr   django.db.modelsr	   django_cronjob_utilsr
   r   django_cronjob_utils.modelsr   apps.investments.modelsr   r   apps.referrals.modelsr   apps.transactions.modelsr   apps.users.modelsr   	getLoggerrO   ra   rL   r   r_   DISTRIBUTE_TASK_CODEr   rX   rV   r&   r$   <module>r      s     $ * ! !  8 5 6 , 0 "			8	$<( www    "$78NQ8 NQ 9NQb #%9:[QH [Q ;[Qr&   