
    PSi'P                        d 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 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  G d de      Z G d de      Z G d de	      Z G d de	      Zy)zDTests for investment start_date logic and reward calculation timing.    )annotations)date	timedelta)Decimal)TestCase)reverse)timezone)status)	APIClientAPITestCase)CalculateRewardsTask)
InvestmentReward)Userc                  0    e Zd ZdZddZd Zd Zd Zd Zy)	InvestmentStartDateTestszBStandard tests for investment start_date being created_at + 1 day.c                $   t         j                  j                  ddd      | _        t	        d      | j                  _        | j                  j                          t               | _        | j                  j                  | j                         y))Set up test user with sufficient balance.i  TestUsertestusertelegram_user_id
first_nameusernamez20000.00000000userN
r   objectscreate_userr   r   credit_balancesaver   clientforce_authenticateselfs    ]/home/cursorai/projects/telegram-earn/backend/apps/investments/tests/test_start_date_logic.pysetUpzInvestmentStartDateTests.setUp   j    LL,,!! - 
	
 $++;#<		 		k&&DII&6    c                    t        d      }t        j                         }| j                  j	                  |ddid      }| j                  |j                  t        j                         t        j                  j                  |j                  d         }|j                  t        d	      z   }t        |j                   |z
  j#                               }| j%                  |dd
       | j'                  |j                   |j                         y)z+Standard: start_date is created_at + 1 day.investment-listamount1000jsonformatidr1      daysz/start_date should be exactly created_at + 1 dayN)r   r	   nowr"   postassertEqualstatus_coder
   HTTP_201_CREATEDr   r   getdata
created_atr   abs
start_datetotal_seconds
assertLessassertGreater)r%   urlbefore_creationresponse
investmentexpected_start	time_diffs          r&   *test_start_date_is_next_day_after_creationzCInvestmentStartDateTests.test_start_date_is_next_day_after_creation"   s    '(",,.;;##C(F);F#K--v/F/FG''++x}}T/B+C
 $..1BB..?NNPQ		1&WX 	:00*2G2GHr)   c                   t        d      }| j                  j                  |ddid      }| j                  |j                  t
        j                         t        j                  j                  |j                  d         }|j                  t        |j                        z   }t        |j                  |z
  j!                               }| j#                  |d	d
       y)z0Standard: end_date = start_date + duration_days.r+   r,   r-   r.   r/   r1   r2   r4   r3   z-end_date should be start_date + duration_daysN)r   r"   r7   r8   r9   r
   r:   r   r   r;   r<   r?   r   duration_daysr>   end_dater@   rA   )r%   rC   rE   rF   expected_endrH   s         r&   )test_end_date_is_start_date_plus_durationzBInvestmentStartDateTests.test_end_date_is_start_date_plus_duration4   s    '(;;##C(F);F#K--v/F/FG''++x}}T/B+C
 ",,yj>V>V/WW,,|;JJLM		1&UVr)   c                   t        d      }| j                  j                  |ddid      }| j                  j                  |ddid      }| j                  j                  |ddid      }t        j                  j                  |j                  d   	      }t        j                  j                  |j                  d   	      }t        j                  j                  |j                  d   	      }|||fD ]S  }|j                  t        d
      z   }	t        |j                  |	z
  j                               }
| j                  |
d
       U y)zOStandard: Multiple investments created same day each get start_date = next day.r+   r,   100r.   r/   500r-   r1   r2   r3   r4   N)r   r"   r7   r   r   r;   r<   r=   r   r>   r?   r@   rA   )r%   rC   	response1	response2	response3inv1inv2inv3invrG   rH   s              r&   :test_multiple_investments_same_day_independent_start_dateszSInvestmentStartDateTests.test_multiple_investments_same_day_independent_start_datesA   s%   '( KK$$S8U*;F$K	KK$$S8U*;F$K	KK$$S8V*<V$L	!!%%)=%>!!%%)=%>!!%%)=%> $%C ^^iQ.??NS^^n<KKMNIOOIq) &r)   c           	     <   t        d      }g d}g d}t        ||      D ]  \  }}| j                  j                  |d|id      }| j	                  |j
                  t        j                  d| d|j                          t        j                  j                  |j                  d	   
      }| j	                  |j                  |       |j                  t        d      z   }t        |j                   |z
  j#                               }	| j%                  |	d        y)zCStandard: All tiers use same start_date logic regardless of amount.r+   )50r-   10000)r3         r,   r.   r/   z(Failed to create investment with amount z: r1   r2   r3   r4   N)r   zipr"   r7   r8   r9   r
   r:   r<   r   r   r;   tierr=   r   r>   r?   r@   rA   )
r%   rC   amountsexpected_tiersr,   expected_tierrE   rX   rG   rH   s
             r&   *test_different_tiers_same_start_date_logiczCInvestmentStartDateTests.test_different_tiers_same_start_date_logicT   s    '( *"%(.%A!FM{{''h-?'OHX1163J3JEfXRPXP]P]_a$$((HMM$,?(@CSXX}5 ^^iQ.??NS^^n<KKMNIOOIq) &Br)   NreturnNone)	__name__
__module____qualname____doc__r'   rI   rN   rY   rd    r)   r&   r   r      s     L
7I$W*&*r)   r   c                  0    e Zd ZdZddZd Zd Zd Zd Zy)	 InvestmentStartDateEdgeCaseTestsz0Edge case tests for investment start_date logic.c                $   t         j                  j                  ddd      | _        t	        d      | j                  _        | j                  j                          t               | _        | j                  j                  | j                         y)r   i  EdgeUseredgeuserr   10000.00000000r   Nr   r$   s    r&   r'   z&InvestmentStartDateEdgeCaseTests.setUpk   r(   r)   c                @   t        j                         j                  dddd      }t        j                  t        d            }t        j                  j                  | j                  t        d      |d   |d   |d   t        j                  |t        d      z   |t        d      z   t        |d         z   	      }||_        |j                          |t        d      z   }| j                  |j                  j                         |j                                y
)z-Edge: Investment created at exactly 00:00:00.r   hourminutesecondmicrosecondr-   r`   ratedurationr3   r4   r   r,   r`   daily_reward_raterK   r
   r?   rL   N)r	   r6   replacer   get_tier_infor   r   creater   STATUS_PENDINGr   r=   r!   r8   r?   r   )r%   midnight	tier_inforF   rG   s        r&   #test_investment_created_at_midnightzDInvestmentStartDateEdgeCaseTests.test_investment_created_at_midnightw   s     <<>))q1RS)T,,WV_=	''..6?6"'/#J/,,)"33	q 11I9ZCX4YY / 	

 !)
 "I1$55..335~7J7J7LMr)   c                   t        d      }| j                  j                  |ddid      }t        j                  j                  |j                  d         }|j                  t        d	      z   }t        |j                  |z
  j                               }| j                  |d       | j                  |j                  j                         |j                  j                                y
)z%Edge: Investment created at 23:59:59.r+   r,   r-   r.   r/   r1   r2   r3   r4   N)r   r"   r7   r   r   r;   r<   r=   r   r>   r?   r@   rA   assertNotEqualr   r%   rC   rE   rF   rG   rH   s         r&   ,test_investment_created_just_before_midnightzMInvestmentStartDateEdgeCaseTests.test_investment_created_just_before_midnight   s     '(;;##C(F);F#K''++x}}T/B+C
 $..1BB..?NNPQ		1% 	J11668*:O:O:T:T:VWr)   c                   t        d      }t        d      | j                  _        | j                  j	                          | j
                  j                  |ddid      }| j                  |j                  t        j                         t        j                  j                  |j                  d         }|j                  t!        d	
      z   }t#        |j$                  |z
  j'                               }| j)                  |d	       y)z:Edge: Minimum investment ($10) uses same start_date logic.r+   z10.00000000r,   10r.   r/   r1   r2   r3   r4   N)r   r   r   r    r!   r"   r7   r8   r9   r
   r:   r   r   r;   r<   r=   r   r>   r?   r@   rA   r   s         r&   )test_minimum_investment_amount_start_datezJInvestmentStartDateEdgeCaseTests.test_minimum_investment_amount_start_date   s    '(#*=#9		 		;;##C(D)9&#I--v/F/FG''++x}}T/B+C
#..1BB..?NNPQ		1%r)   c                   t        d      }| j                  j                  |ddid      }t        j                  j                  |j                  d         }| j                  |j                  d       |j                  t        d	
      z   }t        |j                  |z
  j                               }| j                  |d	       y)z;Edge: Large investment (tier 6) uses same start_date logic.r+   r,   r\   r.   r/   r1   r2   r^   r3   r4   N)r   r"   r7   r   r   r;   r<   r8   r`   r=   r   r>   r?   r@   rA   r   s         r&   'test_maximum_tier_investment_start_datezHInvestmentStartDateEdgeCaseTests.test_maximum_tier_investment_start_date   s    '(;;##C(G)<V#L''++x}}T/B+C
!,#..1BB..?NNPQ		1%r)   Nre   )	rh   ri   rj   rk   r'   r   r   r   r   rl   r)   r&   rn   rn   h   s     :
7N.X &
&r)   rn   c                  0    e Zd ZdZddZd Zd Zd Zd Zy)	RewardCalculationTimingTestsz:Standard tests for reward calculation based on start_date.c                    t         j                  j                  ddd      | _        t	        d      | j                  _        | j                  j                          y)z Set up test user and investment.i  
RewardUser
rewarduserr   rr   Nr   r   r   r   r   r    r!   r$   s    r&   r'   z"RewardCalculationTimingTests.setUp   sH    LL,,!#! - 
	
 $++;#<		 		r)   c                   t        j                         }|j                  dddd      }t        j                  t        d            }t        j                  j                  | j                  t        d      |d   |d   |d   t        j                  |t        d	      z   |t        d	      z   t        |d   	      z   
      }||_        |j                          |j                         }t        |      }|j                  |      }| j!                  |d       | j!                  t"        j                  j%                  |      j'                         d       y)zCStandard: No rewards calculated for investment on its creation day.   r   rt   r-   r`   ry   rz   r3   r4   r{   rF   Nr	   r6   r}   r   r~   r   r   r   r   r   r   r=   r!   r   r   _calculate_pending_rewardsr8   r   filtercount)r%   r6   creation_dater   rF   target_datetaskr   s           r&   test_no_reward_on_creation_dayz;RewardCalculationTimingTests.test_no_reward_on_creation_day   s(    llnAaQO,,WV_=	''..6?6"'/#J/,,$ya'88"YA%66	R\H]9^^ / 	

 !.
 $((*#K0//< 	"..*.EKKMqQr)   c                t   t        j                         }|j                  dddd      }|t        d      z   }t	        j
                  t        d            }t        j                  j                  | j                  t        d      |d   |d   |d	   t        j                  ||t        |d	         z   
      }||_        |j                          |j                         }t        |      }|j                  |      }| j!                  |d       |t        d      z   j                         }t        |      }|j                  |      }| j!                  |d       t"        j                  j%                  |      }	| j!                  |	j&                  |       | j!                  |	j(                  t        d             y)z;Standard: First reward calculated the day AFTER start_date.r   r   rt   r3   r4   r-   r`   ry   rz   r{   r   z20.00000000N)r	   r6   r}   r   r   r~   r   r   r   r   r   r=   r!   r   r   r   r8   r   r;   reward_dater,   )
r%   r6   r   r?   r   rF   r   r   r   rewards
             r&   test_first_reward_on_start_datez<RewardCalculationTimingTests.test_first_reward_on_start_date   s}    llnAaQO"YA%66
,,WV_=	''..6?6"'/#J/,,!):1F"GG / 	

 !.
 !oo'#K0//<" "I1$55;;=#K0//<"##z#:++[9(>?r)   c                j   t        j                         j                  dddd      }t        j                  t        d            }t        j                  j                  | j                  t        d      |d   |d   |d   t        j                  |t        d	      z   |t        d	      z   t        |d   	      z   
      }||_        |j                          t        |j                               }|j                  |j                               }| j!                  |d       |t        d	      z   j                         }t        |      }|j                  |      }| j!                  |d       | j!                  t"        j                  j%                  |      j'                         d       |t        d	      z   j                         }t        |      }|j                  |      }| j!                  |d       | j!                  t"        j                  j%                  |      j'                         d       y)z@Standard: Complete workflow from creation through multiple days.r   r   rt   r-   r`   ry   rz   r3   r4   r{   r      N)r	   r6   r}   r   r~   r   r   r   r   r   r   r=   r!   r   r   r   r8   r   r   r   )r%   	base_timer   rF   r   r   	day2_date	day3_dates           r&    test_reward_calculation_workflowz=RewardCalculationTimingTests.test_reward_calculation_workflow  s    LLN**1QTU*V	,,WV_=	''..6?6"'/#J/,, 9!#44!22YIjDY5ZZ / 	

 !*
 $INN$45//	0@A" !2288:	#I.//	:"..*.EKKMqQ !2288:	#I.//	:"..*.EKKMqQr)   c                j   t        j                         j                  dddd      }t        j                  t        d            }t        j                  j                  | j                  t        d      |d   |d   |d   t        j                  |t        d	      z   |t        d	      z   t        |d   	      z   
      }||_        |j                          t        j                  t        d            }t        j                  j                  | j                  t        d      |d   |d   |d   t        j                  |t        d	      z   |t        d	      z   t        |d   	      z   
      }|t        d	      z   |_        |j                          |t        d	      z   j                         }t        |      }|j                  |       | j!                  t"        j                  j%                  |      j'                         d       | j!                  t"        j                  j%                  |      j'                         d       |t        d	      z   j                         }t        |      }|j                  |       | j!                  t"        j                  j%                  |      j'                         d       | j!                  t"        j                  j%                  |      j'                         d       |t        d	      z   j                         }	t        |	      }|j                  |	       | j!                  t"        j                  j%                  |      j'                         d       | j!                  t"        j                  j%                  |      j'                         d       y)zMStandard: Multiple investments created on different days calculate correctly.r   r   rt   rQ   r`   ry   rz   r3   r4   r{   r-   r]   r   r   Nr   )
r%   r   r   rU   
tier_info2rV   day1r   day2day3s
             r&   (test_multiple_investments_correct_timingzERewardCalculationTimingTests.test_multiple_investments_correct_timing.  s   LLN**1QTU*V	 ,,WU^<	!!((5>6"'/#J/,, 9!#44!22YIjDY5ZZ ) 	
 $		  --gfo>
!!((6?F#(0$Z0,, 9!#44!22YJzDZ5[[ ) 	
 $iQ&77		 I1--335#D)''-..$.?EEGK..$.?EEGK I1--335#D)''-..$.?EEGK..$.?EEGK I1--335#D)''-..$.?EEGK..$.?EEGKr)   Nre   )	rh   ri   rj   rk   r'   r   r   r   r   rl   r)   r&   r   r      s$    DR:"@H$RL7Lr)   r   c                  *    e Zd ZdZddZd Zd Zd Zy)RewardCalculationEdgeCaseTestsz.Edge case tests for reward calculation timing.c                    t         j                  j                  ddd      | _        t	        d      | j                  _        | j                  j                          y)zSet up test user.i  EdgeRewardUseredgerewarduserr   rr   Nr   r$   s    r&   r'   z$RewardCalculationEdgeCaseTests.setUpk  sH    LL,,!'% - 
	
 $++;#<		 		r)   c                0   t        j                         }t        j                  t	        d            }t        j
                  j                  | j                  t	        d      |d   |d   dt        j                  ||t        d      z         }|j                         }t        |      }|j                  |      }| j                  |d       |t        d      z   j                         }t        |      }|j                  |      }| j                  |d       y)	zOEdge: Investment with 1-day duration gets 1 reward on the day after start_date.r-   r`   ry   r3   r4   r{   r   N)r	   r6   r   r~   r   r   r   r   r   r   r   r   r   r8   )r%   r6   r   rF   r   r   r   end_target_dates           r&   $test_investment_expiring_on_last_dayzCRewardCalculationEdgeCaseTests.test_investment_expiring_on_last_dayu  s    lln,,WV_=	
  ''..6?6"'/,,9!,, / 	

 hhj#K0//<" !2288:#O4//@"r)   c                   t        j                         }|t        d      z
  }t        j                  t        d            }t        j                  j                  | j                  t        d      |d   |d   dt        j                  ||t        d      z         }|j                         }t        |      }|j                  |      }| j                  |d       y	)
z8Edge: Investment past end_date doesn't generate rewards.
   r4   r-   r`   ry      r{   r   N)r	   r6   r   r   r~   r   r   r   r   STATUS_ACTIVEr   r   r   r8   )r%   r6   	past_dater   rF   r   r   r   s           r&   )test_investment_beyond_end_date_no_rewardzHRewardCalculationEdgeCaseTests.test_investment_beyond_end_date_no_reward  s    lln),,	,,WV_=	  ''..6?6"'/++ !22 / 	

 hhj#K0//< 	"r)   c                   t        j                         }|j                  dddd      }|j                         }t	        j
                  t        d            }t        j                  j                  | j                  t        d      |d   |d   |d   t        j                  ||t        |d         z         }t        |      }|j                  |      }| j                  |d       |t        d	      z   j                         }t        |      }|j                  |      }| j                  |d	       t        j                  j!                  |
      }	| j                  |	j"                  |       y)zPEdge: Boundary condition where start_date.date() == target_date - no reward yet.r   rt   r-   r`   ry   rz   r4   r{   r3   r   N)r	   r6   r}   r   r   r~   r   r   r   r   r   r   r   r   r8   r   r;   r   )
r%   r6   start_datetimer   r   rF   r   r   	next_dater   s
             r&   +test_start_date_equals_target_date_boundaryzJRewardCalculationEdgeCaseTests.test_start_date_equals_target_date_boundary  sA   lln!AaQO$))+,,WV_=	''..6?6"'/#J/,,%#iYz5J&KK / 	

 $K0//<" $iQ&77==?	#I.//	:"##z#:++Y7r)   Nre   )rh   ri   rj   rk   r'   r   r   r   rl   r)   r&   r   r   h  s    8#>#48r)   r   N)rk   
__future__r   datetimer   r   decimalr   django.testr   django.urlsr   django.utilsr	   rest_frameworkr
   rest_framework.testr   r   apps.investments.cron_tasksr   apps.investments.modelsr   r   apps.users.modelsr   r   rn   r   r   rl   r)   r&   <module>r      sf    J " $     ! ! 6 < 6 "R*{ R*jO&{ O&dkL8 kL\d8X d8r)   