Exemple #1
0
 def test_calculate_principal_and_duration_raises_error(self):
     '''
         Test whether Loan Plan fields are missing
     '''
     params = (20000.0, '_Test Loan Plan 2', '2020-08-19')
     with self.assertRaises(ValueError):
         calculate_principal_and_duration(*params)
Exemple #2
0
 def test_calculate_principal_and_duration_raises_when_invalid_plan(self):
     '''
         Test for invalid Loan Plan dict
     '''
     params = (20000.0, 104, '2020-08-19')
     with self.assertRaises(ValueError):
         calculate_principal_and_duration(*params)
Exemple #3
0
    def validate(self):
        effective_date = frappe.get_value('Loan Plan', self.loan_plan,
                                          'date_effective_from')
        if effective_date and \
                getdate(effective_date) > getdate(self.posting_date):
            return None
        if self.stipulated_recovery_amount > self.loan_principal:
            frappe.throw("Recovery Amount cannot exceed Principal.")

        date_of_retirement, net_salary_amount = frappe.get_value(
            'Loanee Details', {'customer': self.customer},
            ['date_of_retirement', 'net_salary_amount'])
        force_duration, income_multiple, max_duration = frappe.get_value(
            'Loan Plan', self.loan_plan,
            ['force_duration', 'income_multiple', 'max_duration'])
        check = calculate_principal_and_duration(
            income=net_salary_amount,
            loan_plan={
                'force_duration': force_duration,
                'income_multiple': income_multiple,
                'max_duration': max_duration,
                'billing_day': getdate(self.billing_date).day,
                'rate_of_interest': self.rate_of_interest,
            },
            end_date=date_of_retirement,
            execution_date=self.posting_date)
        if self.loan_principal > flt(check.get('principal')):
            frappe.throw("Requested principal cannot exceed {}.".format(
                self.fmt_money(check.get('principal'))))
        if self.stipulated_recovery_amount < \
                self.loan_principal / check.get('duration'):
            frappe.throw("Recovery Amount can be less than {}.".format(
                self.fmt_money(self.loan_principal / check.get('duration'))))

        # possible heavy db queries ahead so check for outstanding is
        # positioned last
        outstanding_principal = reduce(
            (lambda a, x: a + get_outstanding_principal(
                x.name, self.posting_date)),
            frappe.get_all('Loan',
                           filters={
                               'customer':
                               self.customer,
                               'docstatus':
                               1,
                               'recovery_status':
                               ('in', 'Not Started, In Progress'),
                           }), 0)
        if self.loan_principal + outstanding_principal > \
                flt(check.get('principal')):
            frappe.throw("""
                    Customer has existing loans of outstanding {}.
                    Total principal should not exceed allowable principal {}.
                """.format(self.fmt_money(outstanding_principal),
                           self.fmt_money(check.get('principal'))))
        self.expected_end_date = check.get('expected_eta')
Exemple #4
0
 def test_calculate_principal_and_duration(self):
     '''Test calculate_principal_and_duration default case'''
     actual = calculate_principal_and_duration(
         20000.0,
         '_Test Loan Plan 1',
         '2030-08-19',
         '2017-12-12',
     )
     expected = {
         'principal': 480000.0,
         'expected_eta': '2023-01-04',
         'duration': 60,
         'recovery_amount': 8000.0,
         'initial_interest': 24000.0,
     }
     self.assertEqual(actual, expected)
Exemple #5
0
 def test_calculate_principal_force_duration(self):
     '''
         Test calculate_principal_and_duration when the end_date is ignored
         in Loan Plan.
     '''
     actual = calculate_principal_and_duration(
         20000.0,
         '_Test Loan Plan 3',
         '2020-08-19',
         '2017-12-12',
     )
     expected = {
         'principal': 480000.0,
         'expected_eta': '2023-01-04',
         'duration': 60,
         'recovery_amount': 8000.0,
         'initial_interest': 24000.0,
     }
     self.assertEqual(actual, expected)
Exemple #6
0
 def test_calculate_principal_and_duration_end_date_before_loan_plan_max_duration(
         self):
     '''
         Test calculate_principal_and_duration when the end_date is before
         Loan Plan.max duration.
     '''
     actual = calculate_principal_and_duration(
         20000.0,
         '_Test Loan Plan 1',
         '2020-08-19',
         '2017-12-12',
     )
     expected = {
         'principal': 248000.0,
         'expected_eta': '2020-08-04',
         'duration': 31,
         'recovery_amount': 8000.0,
         'initial_interest': 12500.0,
     }
     self.assertEqual(actual, expected)
Exemple #7
0
 def test_calculate_principal_and_duration_when_plan_is_dict(self):
     '''Test when loan_plan param is a dict'''
     actual = calculate_principal_and_duration(
         20000.0,
         {
             'income_multiple': 24,
             'max_duration': 60,
             'billing_day': 5,
             'rate_of_interest': 5.0,
         },
         '2020-08-19',
         '2017-12-12',
     )
     expected = {
         'principal': 248000.0,
         'expected_eta': '2020-08-04',
         'duration': 31,
         'recovery_amount': 8000.0,
         'initial_interest': 12400.0,
     }
     self.assertEqual(actual, expected)