From 07122fd10ae838f5edc6bd96888ae30d98310b10 Mon Sep 17 00:00:00 2001 From: Janos Haber Date: Thu, 10 Aug 2023 19:25:47 +0200 Subject: [PATCH] FINERACT-1968: Advanced repayment allocation strategy - data model - [x] m_loan_product_payment_allocation_rule table created - [x] m_loan_payment_allocation_rule table created - [x] LoanProductPaymentAllocationRule entity - [x] LoanPaymentAllocationRule entity - [x] List of enum converter to String converter to use `AllocationType` list --- .../core/data/GenericEnumListConverter.java | 66 ++++++++ .../domain/LoanPaymentAllocationRule.java | 66 ++++++++ .../loanproduct/domain/AllocationType.java | 26 ++++ .../domain/AllocationTypeListConverter.java | 36 +++++ .../portfolio/loanproduct/domain/DueType.java | 25 ++++ .../FutureInstallmentAllocationRule.java | 25 ++++ .../LoanProductPaymentAllocationRule.java | 63 ++++++++ .../PaymentAllocationTransactionType.java | 33 ++++ .../domain/PaymentAllocationType.java | 52 +++++++ .../module/loan/module-changelog-master.xml | 1 + .../1002_add_payment_allocation_rule.xml | 141 ++++++++++++++++++ .../src/main/resources/jpa/persistence.xml | 8 + 12 files changed, 542 insertions(+) create mode 100644 fineract-core/src/main/java/org/apache/fineract/infrastructure/core/data/GenericEnumListConverter.java create mode 100644 fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanPaymentAllocationRule.java create mode 100644 fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/AllocationType.java create mode 100644 fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/AllocationTypeListConverter.java create mode 100644 fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/DueType.java create mode 100644 fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/FutureInstallmentAllocationRule.java create mode 100644 fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProductPaymentAllocationRule.java create mode 100644 fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/PaymentAllocationTransactionType.java create mode 100644 fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/PaymentAllocationType.java create mode 100644 fineract-loan/src/main/resources/db/changelog/tenant/module/loan/parts/1002_add_payment_allocation_rule.xml diff --git a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/data/GenericEnumListConverter.java b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/data/GenericEnumListConverter.java new file mode 100644 index 000000000..a8f5f99e9 --- /dev/null +++ b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/data/GenericEnumListConverter.java @@ -0,0 +1,66 @@ +/** + * 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.infrastructure.core.data; + +import jakarta.persistence.AttributeConverter; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import org.apache.commons.lang3.StringUtils; + +public abstract class GenericEnumListConverter> implements AttributeConverter, String> { + + private static final String SPLIT_CHAR = ","; + + private final Class clazz; + + protected boolean isUnique() { + return false; + } + + protected GenericEnumListConverter(Class clazz) { + this.clazz = clazz; + } + + @Override + public String convertToDatabaseColumn(List values) { + if (values.isEmpty()) { + return null; + } + Stream valueStream; + if (isUnique()) { + valueStream = values.stream().distinct(); + } else { + valueStream = values.stream(); + } + return valueStream.map(Enum::name).collect(Collectors.joining(SPLIT_CHAR)); + } + + @Override + public List convertToEntityAttribute(String string) { + if (StringUtils.isBlank(string)) { + return List.of(); + } + Stream stream = Stream.of(string.split(SPLIT_CHAR)).map(e -> Enum.valueOf(clazz, e)); + if (isUnique()) { + return stream.distinct().toList(); + } + return stream.toList(); + } +} diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanPaymentAllocationRule.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanPaymentAllocationRule.java new file mode 100644 index 000000000..a16b80f50 --- /dev/null +++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanPaymentAllocationRule.java @@ -0,0 +1,66 @@ +/** + * 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.domain; + +import jakarta.persistence.Column; +import jakarta.persistence.ElementCollection; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.FetchType; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; +import jakarta.persistence.UniqueConstraint; +import java.util.List; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDateTimeCustom; +import org.apache.fineract.portfolio.loanproduct.domain.FutureInstallmentAllocationRule; +import org.apache.fineract.portfolio.loanproduct.domain.PaymentAllocationTransactionType; +import org.apache.fineract.portfolio.loanproduct.domain.PaymentAllocationType; + +@Getter +@Setter +@Entity +@Table(name = "m_loan_payment_allocation", uniqueConstraints = { + @UniqueConstraint(columnNames = { "loan_id", "transaction_type" }, name = "uq_m_loan_payment_allocation_rule") }) +@AllArgsConstructor +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class LoanPaymentAllocationRule extends AbstractAuditableWithUTCDateTimeCustom { + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "loan_id", nullable = false) + private Loan loan; + + @Column(name = "transaction_type", nullable = false) + @Enumerated(EnumType.STRING) + private PaymentAllocationTransactionType transactionType; + + @ElementCollection(fetch = FetchType.EAGER) + @Column(name = "allocation_types", nullable = false) + private List allocationTypes; + + @Column(name = "future_installment_allocation_rule", nullable = false) + @Enumerated(EnumType.STRING) + private FutureInstallmentAllocationRule futureInstallmentAllocationRule; +} diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/AllocationType.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/AllocationType.java new file mode 100644 index 000000000..af9d894d4 --- /dev/null +++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/AllocationType.java @@ -0,0 +1,26 @@ +/** + * 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.loanproduct.domain; + +public enum AllocationType { + PENALTY, // + FEE, // + PRINCIPAL, // + INTEREST // +} diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/AllocationTypeListConverter.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/AllocationTypeListConverter.java new file mode 100644 index 000000000..580590e01 --- /dev/null +++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/AllocationTypeListConverter.java @@ -0,0 +1,36 @@ +/** + * 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.loanproduct.domain; + +import jakarta.persistence.Converter; +import org.apache.fineract.infrastructure.core.data.GenericEnumListConverter; + +@Converter(autoApply = true) +public class AllocationTypeListConverter extends GenericEnumListConverter { + + @Override + protected boolean isUnique() { + return true; + } + + protected AllocationTypeListConverter() { + super(PaymentAllocationType.class); + } + +} diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/DueType.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/DueType.java new file mode 100644 index 000000000..493f6e6e8 --- /dev/null +++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/DueType.java @@ -0,0 +1,25 @@ +/** + * 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.loanproduct.domain; + +public enum DueType { + PAST_DUE, // + DUE, // + IN_ADVANCE // +} diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/FutureInstallmentAllocationRule.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/FutureInstallmentAllocationRule.java new file mode 100644 index 000000000..3fbe4ab83 --- /dev/null +++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/FutureInstallmentAllocationRule.java @@ -0,0 +1,25 @@ +/** + * 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.loanproduct.domain; + +public enum FutureInstallmentAllocationRule { + NEXT_INSTALLMENT, // + LAST_INSTALLMENT, // + REAMORTIZATION // +} diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProductPaymentAllocationRule.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProductPaymentAllocationRule.java new file mode 100644 index 000000000..7a33f0973 --- /dev/null +++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProductPaymentAllocationRule.java @@ -0,0 +1,63 @@ +/** + * 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.loanproduct.domain; + +import jakarta.persistence.Column; +import jakarta.persistence.ElementCollection; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.FetchType; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; +import jakarta.persistence.UniqueConstraint; +import java.util.List; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDateTimeCustom; + +@Getter +@Setter +@Entity +@Table(name = "m_loan_product_payment_allocation", uniqueConstraints = { + @UniqueConstraint(columnNames = { "loan_product_id", "transaction_type" }, name = "uq_m_loan_product_payment_allocation_rule") }) +@AllArgsConstructor +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class LoanProductPaymentAllocationRule extends AbstractAuditableWithUTCDateTimeCustom { + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "loan_product_id", nullable = false) + private LoanProduct loanProduct; + + @Column(name = "transaction_type", nullable = false) + @Enumerated(EnumType.STRING) + private PaymentAllocationTransactionType transactionType; + + @ElementCollection(fetch = FetchType.EAGER) + @Column(name = "allocation_types", nullable = false) + private List allocationTypes; + + @Enumerated(EnumType.STRING) + @Column(name = "future_installment_allocation_rule", nullable = false) + private FutureInstallmentAllocationRule futureInstallmentAllocationRule; +} diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/PaymentAllocationTransactionType.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/PaymentAllocationTransactionType.java new file mode 100644 index 000000000..ba0493a53 --- /dev/null +++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/PaymentAllocationTransactionType.java @@ -0,0 +1,33 @@ +/** + * 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.loanproduct.domain; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType; + +@Getter +@RequiredArgsConstructor +public enum PaymentAllocationTransactionType { + + DEFAULT(null), // + REPAYMENT(LoanTransactionType.REPAYMENT); // + + private final LoanTransactionType loanTransactionType; +} diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/PaymentAllocationType.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/PaymentAllocationType.java new file mode 100644 index 000000000..2ddca9dbb --- /dev/null +++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/PaymentAllocationType.java @@ -0,0 +1,52 @@ +/** + * 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.loanproduct.domain; + +import static org.apache.fineract.portfolio.loanproduct.domain.AllocationType.FEE; +import static org.apache.fineract.portfolio.loanproduct.domain.AllocationType.INTEREST; +import static org.apache.fineract.portfolio.loanproduct.domain.AllocationType.PENALTY; +import static org.apache.fineract.portfolio.loanproduct.domain.AllocationType.PRINCIPAL; +import static org.apache.fineract.portfolio.loanproduct.domain.DueType.DUE; +import static org.apache.fineract.portfolio.loanproduct.domain.DueType.IN_ADVANCE; +import static org.apache.fineract.portfolio.loanproduct.domain.DueType.PAST_DUE; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +@RequiredArgsConstructor +public enum PaymentAllocationType { + + PAST_DUE_PENALTY(PAST_DUE, PENALTY), // + PAST_DUE_FEE(PAST_DUE, FEE), // + PAST_DUE_PRINCIPAL(PAST_DUE, PRINCIPAL), // + PAST_DUE_INTEREST(PAST_DUE, INTEREST), // + DUE_PENALTY(DUE, PENALTY), // + DUE_FEE(DUE, FEE), // + DUE_PRINCIPAL(DUE, PRINCIPAL), // + DUE_INTEREST(DUE, INTEREST), // + IN_ADVANCE_PENALTY(IN_ADVANCE, PENALTY), // + IN_ADVANCE_FEE(IN_ADVANCE, FEE), // + IN_ADVANCE_PRINCIPAL(IN_ADVANCE, PRINCIPAL), // + IN_ADVANCE_INTEREST(IN_ADVANCE, INTEREST); // + + private final DueType dueType; + private final AllocationType allocationType; + +} diff --git a/fineract-loan/src/main/resources/db/changelog/tenant/module/loan/module-changelog-master.xml b/fineract-loan/src/main/resources/db/changelog/tenant/module/loan/module-changelog-master.xml index 77aacf807..ca7acea64 100644 --- a/fineract-loan/src/main/resources/db/changelog/tenant/module/loan/module-changelog-master.xml +++ b/fineract-loan/src/main/resources/db/changelog/tenant/module/loan/module-changelog-master.xml @@ -24,4 +24,5 @@ xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.1.xsd"> + diff --git a/fineract-loan/src/main/resources/db/changelog/tenant/module/loan/parts/1002_add_payment_allocation_rule.xml b/fineract-loan/src/main/resources/db/changelog/tenant/module/loan/parts/1002_add_payment_allocation_rule.xml new file mode 100644 index 000000000..ae59865f1 --- /dev/null +++ b/fineract-loan/src/main/resources/db/changelog/tenant/module/loan/parts/1002_add_payment_allocation_rule.xml @@ -0,0 +1,141 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/fineract-provider/src/main/resources/jpa/persistence.xml b/fineract-provider/src/main/resources/jpa/persistence.xml index f901e617d..b1fba72c9 100644 --- a/fineract-provider/src/main/resources/jpa/persistence.xml +++ b/fineract-provider/src/main/resources/jpa/persistence.xml @@ -106,6 +106,14 @@ org.apache.fineract.portfolio.loanproduct.domain.LoanProductInterestRecalculationDetails org.apache.fineract.portfolio.loanproduct.domain.LoanProductVariableInstallmentConfig org.apache.fineract.portfolio.repaymentwithpostdatedchecks.domain.PostDatedChecks + org.apache.fineract.portfolio.loanproduct.domain.PaymentAllocationType + org.apache.fineract.portfolio.loanproduct.domain.DueType + org.apache.fineract.portfolio.loanproduct.domain.AllocationType + org.apache.fineract.portfolio.loanproduct.domain.FutureInstallmentAllocationRule + org.apache.fineract.portfolio.loanproduct.domain.PaymentAllocationTransactionType + org.apache.fineract.portfolio.loanproduct.domain.AllocationTypeListConverter + org.apache.fineract.portfolio.loanproduct.domain.LoanProductPaymentAllocationRule + org.apache.fineract.portfolio.loanaccount.domain.LoanPaymentAllocationRule false