
    0j#                     *   d Z ddlZddlmc mZ ddlZddlm	Z	 ddl
Z
ddlmZmZ ddlmZmZ dddd	d
dZ e	d      ZdefdZdedede	fdZdededej,                  fdZ G d d      Z G d d      Z G d d      Z G d d      Z G d d      Zy)ut   Plan monitor service tests — Story 7.1.

QA note: planned balances generated by calling amortization.py directly.
    N)Decimal)calculate_avalancheAmortizationResult)get_monitor_statusesCardMonitorStatus   Visaz2000.00z20.00z50.00)idnamebalanceaprmin_payment100.00returnc                  ,    t        t        gt              S )N)r   CARDEXTRA     A/var/www/html/financials/tests/test_services/test_plan_monitor.py_make_resultr      s    vu--r   resultmonthc                 z    | j                   d   d   }|D ]  }|d   |k(  st        |d         c S  t        d      S )zEHelper: get planned balance at a specific month number from schedule.r   scheduler   r   0)per_card_scheduler   r   r   r   rows       r   _result_balance_at_monthr       sM    ''*:6H +w<5 3y>**+ 3<r   c                     | j                   d   d   }|D ].  }|d   |k(  st        j                  j                  |d         c S  t        j                  j	                         S )z(Get the date of a specific schedule row.r   r   r   date)r   datetimer"   fromisoformattodayr   s       r   _reference_date_for_monthr&   !   s`    ''*:6H <w<5 ==..s6{;;< ==  r   c                   $    e Zd Zd Zd Zd Zd Zy)TestMonitorBasicStructurec                    t               }t        |g       }t        |t              }|sddt	        j
                         v st        j                  t              rt        j                  t              nddt	        j
                         v st        j                  |      rt        j                  |      nddt	        j
                         v st        j                  t              rt        j                  t              ndt        j                  |      dz  }t        t        j                  |            d }t        |      }d}||k(  }|st        j                  d|fd||f      d	t	        j
                         v st        j                  t              rt        j                  t              nd	dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      d
z  }dd|iz  }	t        t        j                  |	            d x}x}}y )N5assert %(py4)s
{%(py4)s = %(py0)s(%(py1)s, %(py2)s)
}
isinstancestatuseslistpy0py1py2py4r   ==)z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} == %(py6)slen)r/   r0   py3py6assert %(py8)spy8)r   r   r+   r-   @py_builtinslocals
@pytest_ar_should_repr_global_name	_safereprAssertionError_format_explanationr5   _call_reprcompare)
selfr   r,   @py_assert3@py_format5@py_assert2@py_assert5@py_assert4@py_format7@py_format9s
             r   test_returns_list_of_statusesz7TestMonitorBasicStructure.test_returns_list_of_statuses-   s)   '3(D))))))))z)))z))))))()))())))))D)))D))))))))))8}!!}!!!!}!!!!!!s!!!s!!!!!!8!!!8!!!}!!!!!!!!!!r   c                 n   t               }t        |g       d   }t        |t              }|sddt	        j
                         v st        j                  t              rt        j                  t              nddt	        j
                         v st        j                  |      rt        j                  |      nddt	        j
                         v st        j                  t              rt        j                  t              ndt        j                  |      dz  }t        t        j                  |            d }d}t        ||      }|sdd	t	        j
                         v st        j                  t              rt        j                  t              nd	dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      d
z  }t        t        j                  |            d x}}d}t        ||      }|sdd	t	        j
                         v st        j                  t              rt        j                  t              nd	dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      d
z  }t        t        j                  |            d x}}d}t        ||      }|sdd	t	        j
                         v st        j                  t              rt        j                  t              nd	dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      d
z  }t        t        j                  |            d x}}d}t        ||      }|sdd	t	        j
                         v st        j                  t              rt        j                  t              nd	dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      d
z  }t        t        j                  |            d x}}d}t        ||      }|sdd	t	        j
                         v st        j                  t              rt        j                  t              nd	dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      d
z  }t        t        j                  |            d x}}d}t        ||      }|sdd	t	        j
                         v st        j                  t              rt        j                  t              nd	dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      d
z  }t        t        j                  |            d x}}y )Nr   r*   r+   statusr   r.   
account_idz5assert %(py5)s
{%(py5)s = %(py0)s(%(py1)s, %(py3)s)
}hasattr)r/   r0   r6   py5planned_balanceactual_balancevariance	is_behindis_stale)r   r   r+   r   r:   r;   r<   r=   r>   r?   r@   rN   )rB   r   rL   rC   rD   rE   rG   @py_format6s           r   test_status_has_required_fieldsz9TestMonitorBasicStructure.test_status_has_required_fields3   s   %fb1!4&"344444444z444z444444&444&444444"3444"34444444444+,wv|,,,,,,,,w,,,w,,,,,,v,,,v,,,|,,,,,,,,,,01wv011111111w111w111111v111v11101111111111/0wv/00000000w000w000000v000v000/0000000000)*wvz********w***w******v***v***z***********+wv{++++++++w+++w++++++v+++v+++{++++++++++)*wvz********w***w******v***v***z**********r   c                    t               }t        |g       d   }|j                  }d}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}}y )	Nr   r   r3   )z2%(py2)s
{%(py2)s = %(py0)s.account_id
} == %(py5)srL   r/   r1   rO   assert %(py7)spy7)r   r   rM   r<   rA   r:   r;   r=   r>   r?   r@   rB   r   rL   @py_assert1rG   rC   rU   @py_format8s           r   test_account_id_matches_cardz6TestMonitorBasicStructure.test_account_id_matches_card>   s    %fb1!4  %A% A%%%% A%%%%%%v%%%v%%% %%%A%%%%%%%r   c                    t               }t        |g       d   }|j                  }d}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}}y )	Nr   r	   r3   )z4%(py2)s
{%(py2)s = %(py0)s.account_name
} == %(py5)srL   rX   rY   rZ   )r   r   account_namer<   rA   r:   r;   r=   r>   r?   r@   r[   s           r   test_account_name_matches_cardz8TestMonitorBasicStructure.test_account_name_matches_cardC   s    %fb1!4"",f,"f,,,,"f,,,,,,v,,,v,,,",,,f,,,,,,,r   N)__name__
__module____qualname__rJ   rV   r^   ra   r   r   r   r(   r(   ,   s    "	+&
-r   r(   c                   $    e Zd Zd Zd Zd Zd Zy)TestDeviationDetectionc                 p   t               }t        |d      }t        |d      }ddlm} |t        d      z  j                  t        d      |      }d|t        j                  j                  |t        j                               dg}t        |||	      }|d   }|j                  }	d
}
|	|
u }|st        j                  d|fd|	|
f      t        j                  |      t        j                  |	      t        j                  |
      dz  }dd|iz  }t        t        j                   |            dx}x}	x}}
y)u9   Exactly 5% over is NOT behind — requires strictly > 5%.   r   )
ROUND_DOWNz1.050.01)roundingr   rM   r   
updated_atreference_dateFisz1%(py3)s
{%(py3)s = %(py1)s.is_behind
} is %(py6)sr0   r6   r7   r8   r9   N)r   r&   r    decimalri   r   quantizer#   combinetimer   rS   r<   rA   r>   r?   r@   )rB   r   ref_dateplannedri   exactly_5pctupdatesr,   @py_assert0rE   rF   rG   rH   rI   s                 r   %test_exactly_at_5_percent_not_flaggedz<TestDeviationDetection.test_exactly_at_5_percent_not_flaggedL   s    ,VQ7*615 	''&/1;;GFOV`;a"#"*"3"3";";Hhmmo"VX Y'Q{-{$$--$----$---{---$----------r   c                 `   t               }t        |d      }t        |d      }|t        d      z  j	                  t        d            }d|t
        j
                  j                  |t        j                               dg}t        |||      }|d   }|j                  }d}	||	u }
|
st        j                  d	|
fd
||	f      t        j                  |      t        j                  |      t        j                  |	      dz  }dd|iz  }t        t        j                  |            dx}x}x}
}	y)z5.01% over IS behind.rh   z1.0501rj   r   rl   rn   r   Trp   rr   rs   r8   r9   Nr   r&   r    r   ru   r#   rv   rw   r   rS   r<   rA   r>   r?   r@   )rB   r   rx   ry   	over_5pctr{   r,   r|   rE   rF   rG   rH   rI   s                r   #test_just_over_5_percent_is_flaggedz:TestDeviationDetection.test_just_over_5_percent_is_flaggedZ   s    ,VQ7*615wx00::76?K	"#	"*"3"3";";Hhmmo"VX Y'Q{,{$$,,$,,,,$,,,{,,,$,,,,,,,,,,r   c                 `   t               }t        |d      }t        |d      }|t        d      z  j	                  t        d            }d|t
        j
                  j                  |t        j                               dg}t        |||      }|d   }|j                  }d}	||	u }
|
st        j                  d	|
fd
||	f      t        j                  |      t        j                  |      t        j                  |	      dz  }dd|iz  }t        t        j                  |            dx}x}x}
}	y)u5   Actual balance below planned is good — not flagged.rh   z0.90rj   r   rl   rn   r   Frp   rr   rs   r8   r9   Nr   )rB   r   rx   ry   
below_planr{   r,   r|   rE   rF   rG   rH   rI   s                r   test_below_plan_not_flaggedz2TestDeviationDetection.test_below_plan_not_flaggedf   s    ,VQ7*615/99'&/J
"#
"*"3"3";";Hhmmo"VX Y'Q{-{$$--$----$---{---$----------r   c                 r   t               }t        |g       }|d   }|j                  }d}||u }|st        j                  d|fd||f      t        j
                  |      t        j
                  |      t        j
                  |      dz  }dd|iz  }t        t        j                  |            dx}x}x}}y)	z<No balance updates: no deviation flag (unknown, not behind).r   Frp   rr   rs   r8   r9   N)r   r   rS   r<   rA   r>   r?   r@   	rB   r   r,   r|   rE   rF   rG   rH   rI   s	            r   test_no_updates_not_flaggedz2TestDeviationDetection.test_no_updates_not_flaggedr   s|    '3{-{$$--$----$---{---$----------r   N)rb   rc   rd   r}   r   r   r   r   r   r   rf   rf   K   s    .
-
..r   rf   c                   $    e Zd Zd Zd Zd Zd Zy)TestStaleDatac                 r   t               }t        |g       }|d   }|j                  }d}||u }|st        j                  d|fd||f      t        j
                  |      t        j
                  |      t        j
                  |      dz  }dd|iz  }t        t        j                  |            d x}x}x}}y )Nr   Trp   z0%(py3)s
{%(py3)s = %(py1)s.is_stale
} is %(py6)srs   r8   r9   )r   r   rT   r<   rA   r>   r?   r@   r   s	            r   test_no_updates_is_stalez&TestStaleData.test_no_updates_is_stale|   s|    '3{+{##+t+#t++++#t+++{+++#+++t+++++++r   c                 .   t               }t        j                  j                         }dt	        d      t        j                  j                  |t        j                               dg}t        ||      }|d   }|j                  }d}||u }|st        j                  d|fd||f      t        j                  |      t        j                  |      t        j                  |      dz  }	d	d
|	iz  }
t        t        j                  |
            d x}x}x}}y )Nr   1000.00rl   r   Frp   r   rs   r8   r9   )r   r#   r"   r%   r   rv   rw   r   rT   r<   rA   r>   r?   r@   )rB   r   r%   r{   r,   r|   rE   rF   rG   rH   rI   s              r   test_recent_update_is_not_stalez-TestStaleData.test_recent_update_is_not_stale   s    ##%"#	0B"*"3"3";";E8==?"SU V'8{,{##,u,#u,,,,#u,,,{,,,#,,,u,,,,,,,r   c                 \   t               }t        j                  j                         t        j                  d      z
  }dt        d      t        j                  j                  |t        j                               dg}t        ||      }|d   }|j                  }d}||u }|st        j                  d|fd	||f      t        j                  |      t        j                  |      t        j                  |      d
z  }	dd|	iz  }
t        t        j                  |
            d x}x}x}}y )N   daysr   r   rl   r   Trp   r   rs   r8   r9   r   r#   r"   r%   	timedeltar   rv   rw   r   rT   r<   rA   r>   r?   r@   )rB   r   old_dater{   r,   r|   rE   rF   rG   rH   rI   s              r   !test_update_over_30_days_is_stalez/TestStaleData.test_update_over_30_days_is_stale   s    ==&&(8+=+=2+FF"#	0B"*"3"3";";Hhmmo"VX Y'8{+{##+t+#t++++#t+++{+++#+++t+++++++r   c                 \   t               }t        j                  j                         t        j                  d      z
  }dt        d      t        j                  j                  |t        j                               dg}t        ||      }|d   }|j                  }d}||u }|st        j                  d|fd	||f      t        j                  |      t        j                  |      t        j                  |      d
z  }	dd|	iz  }
t        t        j                  |
            d x}x}x}}y )N   r   r   r   rl   r   Frp   r   rs   r8   r9   r   )rB   r   thirty_days_agor{   r,   r|   rE   rF   rG   rH   rI   s              r   %test_update_exactly_30_days_not_stalez3TestStaleData.test_update_exactly_30_days_not_stale   s    "----/(2D2D"2MM"#	0B"*"3"3";";OX]]_"]_ `'8{,{##,u,#u,,,,#u,,,{,,,#,,,u,,,,,,,r   N)rb   rc   rd   r   r   r   r   r   r   r   r   r   {   s    ,
-,-r   r   c                       e Zd Zd Zy)TestMidMonthUpdatec                    t               }t        j                  j                         }|t        j                  d      z
  }dt        d      t        j                  j                  |t        j                               ddt        d      t        j                  j                  |t        j                               dg}t        ||      }|d   }|j                  }d}t        |      }	||	k(  }
|
st        j                  d|
fd||	f      t        j                  |      t        j                  |      d	t        j                         v st        j                  t
              rt        j                  t
              nd	t        j                  |      t        j                  |	      d
z  }dd|iz  }t!        t        j"                  |            dx}x}x}
x}}	y)z>When multiple updates exist, only the most recent one is used.r   r   z1500.00rl   z1200.00r   r3   )zT%(py3)s
{%(py3)s = %(py1)s.actual_balance
} == %(py9)s
{%(py9)s = %(py5)s(%(py7)s)
}r   r0   r6   rO   rZ   py9assert %(py11)spy11N)r   r#   r"   r%   r   r   rv   rw   r   rQ   r<   rA   r>   r:   r;   r=   r?   r@   )rB   r   r%   	yesterdayr{   r,   r|   rE   @py_assert6@py_assert8rG   @py_format10@py_format12s                r   0test_most_recent_update_used_when_multiple_existzCTestMidMonthUpdate.test_most_recent_update_used_when_multiple_exist   s>   ##%H..A66	);#,,44YPR);#,,44UHMMOLN
 (8{?{))?Y?WY-??)-?????)-????{???)??????W???W???Y???-?????????r   N)rb   rc   rd   r   r   r   r   r   r      s    @r   r   c                       e Zd Zd Zd Zy)TestVarianceCalculationc                    t               }t        |d      }t        |d      }|t        d      z   }d|t        j                  j                  |t	        j                               dg}t        |||      }|d   }|j                  }d}	t        |	      }
||
k(  }|st        j                  d|fd||
f      t        j                  |      t        j                  |      d	t        j                         v st        j                  t              rt        j                  t              nd	t        j                  |	      t        j                  |
      d
z  }dd|iz  }t        t        j                   |            d x}x}x}x}	}
y )N   r   r   rl   rn   r   r3   )zN%(py3)s
{%(py3)s = %(py1)s.variance
} == %(py9)s
{%(py9)s = %(py5)s(%(py7)s)
}r   r   r   r   )r   r&   r    r   r#   rv   rw   r   rR   r<   rA   r>   r:   r;   r=   r?   r@   rB   r   rx   ry   actualr{   r,   r|   rE   r   r   rG   r   r   s                 r   %test_variance_is_actual_minus_plannedz=TestVarianceCalculation.test_variance_is_actual_minus_planned   s   ,VQ7*61578,,"#"*"3"3";";Hhmmo"VX Y'Q{8{##8x8wx'88#'88888#'8888{888#888888w888w888x888'888888888r   c                 ,   t               }t        |d      }t        |d      }|t        d      z
  }dt	        |t        d            t
        j
                  j                  |t        j                               dg}t        |||      }|d   }|j                  }d}	t        |	      }
||
k  }|st        j                  d|fd	||
f      t        j                  |      t        j                  |      d
t        j                         v st        j                  t              rt        j                  t              nd
t        j                  |	      t        j                  |
      dz  }dd|iz  }t!        t        j"                  |            d x}x}x}x}	}
y )Nr   r   r   r   rl   rn   r   )<)zM%(py3)s
{%(py3)s = %(py1)s.variance
} < %(py9)s
{%(py9)s = %(py5)s(%(py7)s)
}r   r   r   r   )r   r&   r    r   maxr#   rv   rw   r   rR   r<   rA   r>   r:   r;   r=   r?   r@   r   s                 r   &test_negative_variance_when_below_planz>TestVarianceCalculation.test_negative_variance_when_below_plan   s   ,VQ7*61578,,"#FGCL0I"*"3"3";";Hhmmo"VX Y'Q{2{##2c2gcl2#l2222#l222{222#222222g222g222c222l22222222r   N)rb   rc   rd   r   r   r   r   r   r   r      s    93r   r   )__doc__builtinsr:   _pytest.assertion.rewrite	assertionrewriter<   r#   rt   r   pytestapp.services.amortizationr   r   app.services.plan_monitorr   r   r   r   r   intr    r"   r&   r(   rf   r   r   r   r   r   r   <module>r      s        M M
 IgV]^.( .%7   !&8 ! ! !- ->+. +.`- -B@ @$3 3r   