blob: 10d966e4d8d7cd561261e5580d19cd2a347c162a [file] [log] [blame]
/**
* 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.loanaccount.loanschedule.domain;
import static java.math.BigDecimal.ZERO;
import static java.util.Collections.EMPTY_LIST;
import static org.apache.fineract.organisation.monetary.domain.MonetaryCurrency.fromApplicationCurrency;
import static org.apache.fineract.organisation.workingdays.domain.RepaymentRescheduleType.MOVE_TO_NEXT_WORKING_DAY;
import static org.apache.fineract.portfolio.calendar.service.CalendarUtils.FLOATING_TIMEZONE_PROPERTY_KEY;
import static org.apache.fineract.portfolio.common.domain.DayOfWeekType.INVALID;
import static org.apache.fineract.portfolio.common.domain.PeriodFrequencyType.MONTHS;
import static org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleType.CUMULATIVE;
import static org.apache.fineract.portfolio.loanproduct.domain.AmortizationMethod.EQUAL_PRINCIPAL;
import static org.apache.fineract.portfolio.loanproduct.domain.InterestCalculationPeriodMethod.SAME_AS_REPAYMENT_PERIOD;
import static org.apache.fineract.portfolio.loanproduct.domain.InterestMethod.FLAT;
import static org.apache.fineract.portfolio.loanproduct.domain.LoanPreClosureInterestCalculationStrategy.NONE;
import static org.apache.fineract.portfolio.loanproduct.domain.RepaymentStartDateType.DISBURSEMENT_DATE;
import static org.apache.fineract.util.TimeZoneConstants.ASIA_MANILA_ID;
import static org.apache.fineract.util.TimeZoneConstants.EUROPE_BERLIN_ID;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given;
import java.math.BigDecimal;
import java.time.LocalDate;
import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
import org.apache.fineract.junit.context.WithTenantContext;
import org.apache.fineract.junit.context.WithTenantContextExtension;
import org.apache.fineract.junit.system.WithSystemProperty;
import org.apache.fineract.junit.system.WithSystemPropertyExtension;
import org.apache.fineract.junit.timezone.WithSystemTimeZone;
import org.apache.fineract.junit.timezone.WithSystemTimeZoneExtension;
import org.apache.fineract.organisation.monetary.domain.ApplicationCurrency;
import org.apache.fineract.organisation.monetary.domain.Money;
import org.apache.fineract.organisation.monetary.domain.MoneyHelper;
import org.apache.fineract.organisation.workingdays.data.AdjustedDateDetailsDTO;
import org.apache.fineract.organisation.workingdays.domain.WorkingDays;
import org.apache.fineract.portfolio.common.domain.DaysInMonthType;
import org.apache.fineract.portfolio.common.domain.DaysInYearType;
import org.apache.fineract.portfolio.loanaccount.data.HolidayDetailDTO;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mockito;
import org.springframework.test.util.ReflectionTestUtils;
@ExtendWith({ WithSystemTimeZoneExtension.class, WithTenantContextExtension.class, WithSystemPropertyExtension.class })
public class DefaultScheduledDateGeneratorTest {
private DefaultScheduledDateGenerator underTest = new DefaultScheduledDateGenerator();
@BeforeEach
public void setUp() {
ConfigurationDomainService cds = Mockito.mock(ConfigurationDomainService.class);
given(cds.getRoundingMode()).willReturn(6); // default
MoneyHelper moneyHelper = new MoneyHelper();
ReflectionTestUtils.setField(moneyHelper, "configurationDomainService", cds);
moneyHelper.initialize();
}
@Test
@WithSystemTimeZone(EUROPE_BERLIN_ID)
@WithTenantContext(tenantTimeZoneId = EUROPE_BERLIN_ID)
@WithSystemProperty(key = FLOATING_TIMEZONE_PROPERTY_KEY, value = "true")
public void test_AdjustRepaymentDate_Works_WithSameTenant_And_SystemTimeZone() {
// given
HolidayDetailDTO holidayDetailDTO = createHolidayDTO();
LocalDate dueRepaymentPeriodDate = LocalDate.of(2023, 11, 26);
LoanApplicationTerms loanApplicationTerms = createLoanApplicationTerms(dueRepaymentPeriodDate, holidayDetailDTO);
// when
AdjustedDateDetailsDTO result = underTest.adjustRepaymentDate(dueRepaymentPeriodDate, loanApplicationTerms, holidayDetailDTO);
// then
assertThat(result.getChangedScheduleDate()).isEqualTo(LocalDate.of(2023, 11, 26));
assertThat(result.getChangedActualRepaymentDate()).isEqualTo(LocalDate.of(2023, 11, 26));
assertThat(result.getNextRepaymentPeriodDueDate()).isEqualTo(LocalDate.of(2023, 12, 26));
}
@Test
@WithSystemTimeZone(ASIA_MANILA_ID)
@WithTenantContext(tenantTimeZoneId = EUROPE_BERLIN_ID)
@WithSystemProperty(key = FLOATING_TIMEZONE_PROPERTY_KEY, value = "true")
public void test_AdjustRepaymentDate_Works_WithDifferentTenant_And_SystemTimeZone() {
// given
HolidayDetailDTO holidayDetailDTO = createHolidayDTO();
LocalDate dueRepaymentPeriodDate = LocalDate.of(2023, 11, 26);
LoanApplicationTerms loanApplicationTerms = createLoanApplicationTerms(dueRepaymentPeriodDate, holidayDetailDTO);
// when
AdjustedDateDetailsDTO result = underTest.adjustRepaymentDate(dueRepaymentPeriodDate, loanApplicationTerms, holidayDetailDTO);
// then
assertThat(result.getChangedScheduleDate()).isEqualTo(LocalDate.of(2023, 11, 26));
assertThat(result.getChangedActualRepaymentDate()).isEqualTo(LocalDate.of(2023, 11, 26));
assertThat(result.getNextRepaymentPeriodDueDate()).isEqualTo(LocalDate.of(2023, 12, 26));
}
private LoanApplicationTerms createLoanApplicationTerms(LocalDate dueRepaymentPeriodDate, HolidayDetailDTO holidayDetailDTO) {
ApplicationCurrency dollarCurrency = new ApplicationCurrency("USD", "US Dollar", 2, 0, "currency.USD", "$");
Money principalAmount = Money.of(fromApplicationCurrency(dollarCurrency), BigDecimal.valueOf(1000L));
LocalDate expectedDisbursementDate = LocalDate.of(2023, 10, 26);
LocalDate submittedOnDate = LocalDate.of(2023, 10, 24);
return LoanApplicationTerms.assembleFrom(dollarCurrency, 1, MONTHS, 1, 1, MONTHS, null, INVALID, EQUAL_PRINCIPAL, FLAT, ZERO,
MONTHS, ZERO, SAME_AS_REPAYMENT_PERIOD, false, principalAmount, expectedDisbursementDate, null, dueRepaymentPeriodDate,
null, null, null, null, null, Money.of(fromApplicationCurrency(dollarCurrency), ZERO), false, null, EMPTY_LIST,
BigDecimal.valueOf(36_000L), null, DaysInMonthType.ACTUAL, DaysInYearType.ACTUAL, false, null, null, null, null, null, ZERO,
null, NONE, null, ZERO, EMPTY_LIST, true, 0, false, holidayDetailDTO, false, false, false, null, false, false, null, false,
DISBURSEMENT_DATE, submittedOnDate, CUMULATIVE, LoanScheduleProcessingType.HORIZONTAL, null);
}
private HolidayDetailDTO createHolidayDTO() {
WorkingDays workingDays = new WorkingDays("FREQ=WEEKLY;INTERVAL=1;BYDAY=MO,TU,WE,TH,FR,SA,SU", MOVE_TO_NEXT_WORKING_DAY.getValue(),
false, false);
HolidayDetailDTO holidayDetailDTO = new HolidayDetailDTO(false, EMPTY_LIST, workingDays, false, false);
return holidayDetailDTO;
}
}