예제 #1
0
	def allocate_amounts(self, repayment_details):
		precision = cint(frappe.db.get_default("currency_precision")) or 2

		self.set('repayment_details', [])
		self.principal_amount_paid = 0
		total_interest_paid = 0
		interest_paid = self.amount_paid - self.penalty_amount

		if self.amount_paid - self.penalty_amount > 0:
			interest_paid = self.amount_paid - self.penalty_amount
			for lia, amounts in iteritems(repayment_details.get('pending_accrual_entries', [])):
				if amounts['interest_amount'] + amounts['payable_principal_amount'] <= interest_paid:
					interest_amount = amounts['interest_amount']
					paid_principal = amounts['payable_principal_amount']
					self.principal_amount_paid += paid_principal
					interest_paid -= (interest_amount + paid_principal)
				elif interest_paid:
					if interest_paid >= amounts['interest_amount']:
						interest_amount = amounts['interest_amount']
						paid_principal = interest_paid - interest_amount
						self.principal_amount_paid += paid_principal
						interest_paid = 0
					else:
						interest_amount = interest_paid
						interest_paid = 0
						paid_principal=0

				total_interest_paid += interest_amount
				self.append('repayment_details', {
					'loan_interest_accrual': lia,
					'paid_interest_amount': interest_amount,
					'paid_principal_amount': paid_principal
				})

		if repayment_details['unaccrued_interest'] and interest_paid:
			# no of days for which to accrue interest
			# Interest can only be accrued for an entire day and not partial
			if interest_paid > repayment_details['unaccrued_interest']:
				per_day_interest = flt(get_per_day_interest(self.pending_principal_amount,
					self.rate_of_interest, self.posting_date), precision)
				interest_paid -= repayment_details['unaccrued_interest']
				total_interest_paid += repayment_details['unaccrued_interest']
			else:
				# get no of days for which interest can be paid
				per_day_interest = flt(get_per_day_interest(self.pending_principal_amount,
					self.rate_of_interest, self.posting_date), precision)

				no_of_days = cint(interest_paid/per_day_interest)
				total_interest_paid += no_of_days * per_day_interest
				interest_paid -= no_of_days * per_day_interest

		self.total_interest_paid = total_interest_paid

		if interest_paid:
			self.principal_amount_paid += interest_paid
예제 #2
0
	def book_unaccrued_interest(self):
		precision = cint(frappe.db.get_default("currency_precision")) or 2
		if self.total_interest_paid > self.interest_payable:
			if not self.is_term_loan:
				# get last loan interest accrual date
				last_accrual_date = get_last_accrual_date(self.against_loan)

				# get posting date upto which interest has to be accrued
				per_day_interest = flt(get_per_day_interest(self.pending_principal_amount,
					self.rate_of_interest, self.posting_date), 2)

				no_of_days = flt(flt(self.total_interest_paid - self.interest_payable,
					precision)/per_day_interest, 0) - 1

				posting_date = add_days(last_accrual_date, no_of_days)

				# book excess interest paid
				process = process_loan_interest_accrual_for_demand_loans(posting_date=posting_date,
					loan=self.against_loan, accrual_type="Repayment")

				# get loan interest accrual to update paid amount
				lia = frappe.db.get_value('Loan Interest Accrual', {'process_loan_interest_accrual':
					process}, ['name', 'interest_amount', 'payable_principal_amount'], as_dict=1)

				self.append('repayment_details', {
					'loan_interest_accrual': lia.name,
					'paid_interest_amount': flt(self.total_interest_paid - self.interest_payable, precision),
					'paid_principal_amount': 0.0,
					'accrual_type': 'Repayment'
				})
예제 #3
0
    def book_unaccrued_interest(self):
        precision = cint(frappe.db.get_default("currency_precision")) or 2
        if flt(self.total_interest_paid, precision) > flt(
                self.interest_payable, precision):
            if not self.is_term_loan:
                # get last loan interest accrual date
                last_accrual_date = get_last_accrual_date(self.against_loan)

                # get posting date upto which interest has to be accrued
                per_day_interest = get_per_day_interest(
                    self.pending_principal_amount, self.rate_of_interest,
                    self.posting_date)

                no_of_days = (flt(
                    flt(self.total_interest_paid - self.interest_payable,
                        precision) / per_day_interest, 0) - 1)

                posting_date = add_days(last_accrual_date, no_of_days)

                # book excess interest paid
                process = process_loan_interest_accrual_for_demand_loans(
                    posting_date=posting_date,
                    loan=self.against_loan,
                    accrual_type="Repayment")

                # get loan interest accrual to update paid amount
                lia = frappe.db.get_value(
                    "Loan Interest Accrual",
                    {"process_loan_interest_accrual": process},
                    ["name", "interest_amount", "payable_principal_amount"],
                    as_dict=1,
                )

                if lia:
                    self.append(
                        "repayment_details",
                        {
                            "loan_interest_accrual":
                            lia.name,
                            "paid_interest_amount":
                            flt(
                                self.total_interest_paid -
                                self.interest_payable, precision),
                            "paid_principal_amount":
                            0.0,
                            "accrual_type":
                            "Repayment",
                        },
                    )
예제 #4
0
    def test_loan_topup_with_additional_pledge(self):
        pledge = [{
            "loan_security": "Test Security 1",
            "qty": 4000.00
        }]

        loan_application = create_loan_application(
            '_Test Company', self.applicant, 'Demand Loan', pledge)
        create_pledge(loan_application)

        loan = create_demand_loan(
            self.applicant, "Demand Loan", loan_application, posting_date='2019-10-01')
        loan.submit()

        self.assertEquals(loan.loan_amount, 1000000)

        first_date = '2019-10-01'
        last_date = '2019-10-30'

        # Disbursed 10,00,000 amount
        make_loan_disbursement_entry(
            loan.name, loan.loan_amount, disbursement_date=first_date)
        process_loan_interest_accrual_for_demand_loans(posting_date=last_date)
        amounts = calculate_amounts(loan.name, add_days(last_date, 1))

        previous_interest = amounts['interest_amount']

        pledge1 = [{
            "loan_security": "Test Security 1",
            "qty": 2000.00
        }]

        create_loan_security_pledge(self.applicant, pledge1, loan=loan.name)

        # Topup 500000
        make_loan_disbursement_entry(
            loan.name, 500000, disbursement_date=add_days(last_date, 1))
        process_loan_interest_accrual_for_demand_loans(
            posting_date=add_days(last_date, 15))
        amounts = calculate_amounts(loan.name, add_days(last_date, 15))

        per_day_interest = get_per_day_interest(1500000, 13.5, '2019-10-30')
        interest = per_day_interest * 15

        self.assertEquals(amounts['pending_principal_amount'], 1500000)
        self.assertEquals(amounts['interest_amount'],
                          flt(interest + previous_interest, 2))
예제 #5
0
    def allocate_excess_payment_for_demand_loans(self, interest_paid,
                                                 repayment_details):
        if repayment_details["unaccrued_interest"] and interest_paid > 0:
            # no of days for which to accrue interest
            # Interest can only be accrued for an entire day and not partial
            if interest_paid > repayment_details["unaccrued_interest"]:
                interest_paid -= repayment_details["unaccrued_interest"]
                self.total_interest_paid += repayment_details[
                    "unaccrued_interest"]
            else:
                # get no of days for which interest can be paid
                per_day_interest = get_per_day_interest(
                    self.pending_principal_amount, self.rate_of_interest,
                    self.posting_date)

                no_of_days = cint(interest_paid / per_day_interest)
                self.total_interest_paid += no_of_days * per_day_interest
                interest_paid -= no_of_days * per_day_interest

        if interest_paid > 0:
            self.principal_amount_paid += interest_paid
예제 #6
0
def get_amounts(amounts, against_loan, posting_date):
	precision = cint(frappe.db.get_default("currency_precision")) or 2

	against_loan_doc = frappe.get_doc("Loan", against_loan)
	loan_type_details = frappe.get_doc("Loan Type", against_loan_doc.loan_type)
	accrued_interest_entries = get_accrued_interest_entries(against_loan_doc.name)

	pending_accrual_entries = {}

	total_pending_interest = 0
	penalty_amount = 0
	payable_principal_amount = 0
	final_due_date = ''
	due_date = ''

	for entry in accrued_interest_entries:
		# Loan repayment due date is one day after the loan interest is accrued
		# no of late days are calculated based on loan repayment posting date
		# and if no_of_late days are positive then penalty is levied

		due_date = add_days(entry.posting_date, 1)
		no_of_late_days = date_diff(posting_date,
			add_days(due_date, loan_type_details.grace_period_in_days)) + 1

		if no_of_late_days > 0 and (not against_loan_doc.repay_from_salary) and entry.accrual_type == 'Regular':
			penalty_amount += (entry.interest_amount * (loan_type_details.penalty_interest_rate / 100) * no_of_late_days)

		total_pending_interest += entry.interest_amount
		payable_principal_amount += entry.payable_principal_amount

		pending_accrual_entries.setdefault(entry.name, {
			'interest_amount': flt(entry.interest_amount, precision),
			'payable_principal_amount': flt(entry.payable_principal_amount, precision)
		})

		if due_date and not final_due_date:
			final_due_date = add_days(due_date, loan_type_details.grace_period_in_days)

	if against_loan_doc.status in ('Disbursed', 'Loan Closure Requested', 'Closed'):
		pending_principal_amount = against_loan_doc.total_payment - against_loan_doc.total_principal_paid \
			- against_loan_doc.total_interest_payable - against_loan_doc.written_off_amount
	else:
		pending_principal_amount = against_loan_doc.disbursed_amount - against_loan_doc.total_principal_paid \
			- against_loan_doc.total_interest_payable - against_loan_doc.written_off_amount

	unaccrued_interest = 0
	if due_date:
		pending_days = date_diff(posting_date, due_date) + 1
	else:
		last_accrual_date = get_last_accrual_date(against_loan_doc.name)
		pending_days = date_diff(posting_date, last_accrual_date) + 1

	if pending_days > 0:
		principal_amount = flt(pending_principal_amount, precision)
		per_day_interest = get_per_day_interest(principal_amount, loan_type_details.rate_of_interest, posting_date)
		unaccrued_interest += (pending_days * flt(per_day_interest, precision))

	amounts["pending_principal_amount"] = flt(pending_principal_amount, precision)
	amounts["payable_principal_amount"] = flt(payable_principal_amount, precision)
	amounts["interest_amount"] = flt(total_pending_interest, precision)
	amounts["penalty_amount"] = flt(penalty_amount, precision)
	amounts["payable_amount"] = flt(payable_principal_amount + total_pending_interest + penalty_amount, precision)
	amounts["pending_accrual_entries"] = pending_accrual_entries
	amounts["unaccrued_interest"] = unaccrued_interest

	if final_due_date:
		amounts["due_date"] = final_due_date

	return amounts
예제 #7
0
def get_amounts(amounts, against_loan, posting_date):
    precision = cint(frappe.db.get_default("currency_precision")) or 2

    against_loan_doc = frappe.get_doc("Loan", against_loan)
    loan_type_details = frappe.get_doc("Loan Type", against_loan_doc.loan_type)
    accrued_interest_entries = get_accrued_interest_entries(
        against_loan_doc.name, posting_date)

    computed_penalty_date, pending_penalty_amount = get_penalty_details(
        against_loan)
    pending_accrual_entries = {}

    total_pending_interest = 0
    penalty_amount = 0
    payable_principal_amount = 0
    final_due_date = ""
    due_date = ""

    for entry in accrued_interest_entries:
        # Loan repayment due date is one day after the loan interest is accrued
        # no of late days are calculated based on loan repayment posting date
        # and if no_of_late days are positive then penalty is levied

        due_date = add_days(entry.posting_date, 1)
        due_date_after_grace_period = add_days(
            due_date, loan_type_details.grace_period_in_days)

        # Consider one day after already calculated penalty
        if computed_penalty_date and getdate(
                computed_penalty_date) >= due_date_after_grace_period:
            due_date_after_grace_period = add_days(computed_penalty_date, 1)

        no_of_late_days = date_diff(posting_date,
                                    due_date_after_grace_period) + 1

        if (no_of_late_days > 0 and (not against_loan_doc.repay_from_salary)
                and entry.accrual_type == "Regular"):
            penalty_amount += (
                entry.interest_amount *
                (loan_type_details.penalty_interest_rate / 100) *
                no_of_late_days)

        total_pending_interest += entry.interest_amount
        payable_principal_amount += entry.payable_principal_amount

        pending_accrual_entries.setdefault(
            entry.name,
            {
                "interest_amount":
                flt(entry.interest_amount, precision),
                "payable_principal_amount":
                flt(entry.payable_principal_amount, precision),
            },
        )

        if due_date and not final_due_date:
            final_due_date = add_days(due_date,
                                      loan_type_details.grace_period_in_days)

    pending_principal_amount = get_pending_principal_amount(against_loan_doc)

    unaccrued_interest = 0
    if due_date:
        pending_days = date_diff(posting_date, due_date) + 1
    else:
        last_accrual_date = get_last_accrual_date(against_loan_doc.name)
        pending_days = date_diff(posting_date, last_accrual_date) + 1

    if pending_days > 0:
        principal_amount = flt(pending_principal_amount, precision)
        per_day_interest = get_per_day_interest(
            principal_amount, loan_type_details.rate_of_interest, posting_date)
        unaccrued_interest += pending_days * per_day_interest

    amounts["pending_principal_amount"] = flt(pending_principal_amount,
                                              precision)
    amounts["payable_principal_amount"] = flt(payable_principal_amount,
                                              precision)
    amounts["interest_amount"] = flt(total_pending_interest, precision)
    amounts["penalty_amount"] = flt(penalty_amount + pending_penalty_amount,
                                    precision)
    amounts["payable_amount"] = flt(
        payable_principal_amount + total_pending_interest + penalty_amount,
        precision)
    amounts["pending_accrual_entries"] = pending_accrual_entries
    amounts["unaccrued_interest"] = flt(unaccrued_interest, precision)

    if final_due_date:
        amounts["due_date"] = final_due_date

    return amounts