Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.workingcapitalloanproduct.calc;

import java.math.BigDecimal;
import java.math.MathContext;
import java.time.LocalDate;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Component;

/**
* Default implementation of {@link ProjectedAmortizationScheduleCalculator}. Delegates to
* {@link ProjectedAmortizationScheduleModel} methods.
*/
@Component
public final class DefaultProjectedAmortizationScheduleCalculator implements ProjectedAmortizationScheduleCalculator {

@Override
@NonNull
public ProjectedAmortizationScheduleModel generateModel(@NonNull final BigDecimal principalAmount,
@NonNull final BigDecimal discountAmount, @NonNull final BigDecimal netAmount, @NonNull final BigDecimal totalPaymentValue,
@NonNull final BigDecimal periodPaymentRate, final int npvDayCount, @NonNull final LocalDate startDate,
@NonNull final MathContext mc) {
return ProjectedAmortizationScheduleModel.generate(principalAmount, discountAmount, netAmount, totalPaymentValue, periodPaymentRate,
npvDayCount, startDate, mc);
}

@Override
@NonNull
public ProjectedAmortizationScheduleModel addDisbursement(@NonNull final ProjectedAmortizationScheduleModel model,
@NonNull final BigDecimal newPrincipalAmount, @NonNull final BigDecimal newDiscountAmount,
@NonNull final BigDecimal newNetAmount, @NonNull final LocalDate newStartDate) {
return model.regenerate(newPrincipalAmount, newDiscountAmount, newNetAmount, newStartDate);
}

@Override
public void applyPayment(@NonNull final ProjectedAmortizationScheduleModel model, @NonNull final LocalDate paymentDate,
@NonNull final BigDecimal paymentAmount) {
model.applyPayment(paymentDate, paymentAmount);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.workingcapitalloanproduct.calc;

import java.math.BigDecimal;
import java.time.LocalDate;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.experimental.Accessors;

/**
* Single installment of a Working Capital loan's projected amortization schedule.
*
* <p>
* TODO: migrate monetary fields to Money wrapper
*/
@Getter
@Accessors(fluent = true)
@AllArgsConstructor
public class ProjectedAmortizationInstallment {

/** 1-based installment number (0 = disbursement row). */
private final int installmentNo;

private final LocalDate installmentDate;

/** Exponent for discount factor: {@code DF = 1/(1+EIR)^daysLeft}. Zero for paid periods. */
private final long daysLeft;

/** {@code (TPV × periodRate) / dayCount}; negated disbursement for row 0. */
private final BigDecimal expectedPaymentAmount;

/** Actual if paid, expected if unpaid (adjusted for excess); {@code null} for row 0. */
private final BigDecimal forecastPaymentAmount;

/** {@code 1 / (1 + EIR)^daysLeft} */
private final BigDecimal discountFactor;

/** {@code forecastPayment × discountFactor} */
private final BigDecimal npvValue;

/** {@code balance[i] = balance[i-1] × (1+EIR) - expectedPayment} */
private final BigDecimal balance;

/** {@code balance[i] + expectedPayment - balance[i-1]} (equivalent to {@code prevBalance × EIR}) */
private final BigDecimal expectedAmortizationAmount;

/** First paid: sum of all NPV values; subsequent: {@code netAmort[i-1] - actualAmort[i-1]}. */
private final BigDecimal netAmortizationAmount;

private final BigDecimal actualPaymentAmount;

/** Cursor-based consumption of expected amortization proportional to payment ratio. */
private final BigDecimal actualAmortizationAmount;

/** {@code actualAmortization - expectedAmortization} */
private final BigDecimal incomeModification;

/** {@code deferredBalance[i-1] - actualAmortization[i]} */
private final BigDecimal deferredBalance;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.workingcapitalloanproduct.calc;

import java.math.BigDecimal;
import java.math.MathContext;
import java.time.LocalDate;
import org.springframework.lang.NonNull;

/**
* Calculator service for Working Capital loan projected amortization schedule. Analogous to {@code EMICalculator} for
* progressive loans, but with a minimal API: generation, disbursement and payment.
*/
public interface ProjectedAmortizationScheduleCalculator {

/**
* Creates an initial projected amortization schedule model (at loan creation).
*
* @return model with no payments applied
*/
@NonNull
ProjectedAmortizationScheduleModel generateModel(@NonNull BigDecimal principalAmount, @NonNull BigDecimal discountAmount,
@NonNull BigDecimal netAmount, @NonNull BigDecimal totalPaymentValue, @NonNull BigDecimal periodPaymentRate, int npvDayCount,
@NonNull LocalDate startDate, @NonNull MathContext mc);

/**
* Recalculates the model with updated financial parameters (at approval or disbursement). Preserves already applied
* payments on the model.
*
* @param model
* current model (may have payments)
* @param newPrincipalAmount
* approved or disbursed principal
* @param newDiscountAmount
* approved or disbursed discount
* @param newNetAmount
* approved or actual net amount
* @param newStartDate
* actual start date
* @return new model with recalculated schedule
*/
@NonNull
ProjectedAmortizationScheduleModel addDisbursement(@NonNull ProjectedAmortizationScheduleModel model,
@NonNull BigDecimal newPrincipalAmount, @NonNull BigDecimal newDiscountAmount, @NonNull BigDecimal newNetAmount,
@NonNull LocalDate newStartDate);

/**
* Applies a payment to the model. The model is mutated in place; callers can read the updated installment directly
* from the model.
*
* @param model
* current model (mutated in place)
* @param paymentDate
* the date when payment was made
* @param paymentAmount
* actual payment amount
*/
void applyPayment(@NonNull ProjectedAmortizationScheduleModel model, @NonNull LocalDate paymentDate, @NonNull BigDecimal paymentAmount);
}
Loading
Loading