From fc895fce05d12b5fc3e4dcedf7b5dc15cdd8a07f Mon Sep 17 00:00:00 2001 From: Aleksandar Vidakovic Date: Wed, 26 Oct 2022 00:25:31 +0200 Subject: [PATCH] FINERACT-1783: Customizeable LoanRepaymentScheduleTransactionProcessor --- custom/acme/loan/cob/build.gradle | 4 +- .../loan/cob/AcmeNoopBusinessStep.java | 8 +- .../custom-changelog/0001_acme_loan_cob.xml | 32 + custom/acme/loan/processor/build.gradle | 25 + .../acme/loan/processor/dependencies.gradle | 10 +- ...RepaymentScheduleTransactionProcessor.java | 41 + custom/acme/loan/starter/build.gradle | 4 +- custom/acme/loan/starter/dependencies.gradle | 2 + .../starter/AcmeLoanAutoConfiguration.java | 18 +- custom/docker/build.gradle | 2 +- .../main/avro/loan/v1/LoanAccountDataV1.avsc | 4 +- .../main/avro/loan/v1/LoanProductDataV1.avsc | 4 +- .../bare-bones-demo/bk_bare_bones_demo.sql | 36 +- .../bk_mifostenant_default.sql | 36 +- .../ceda/bk_ceda_trial.sql | 38 +- .../ceda/bk_core_with_custom_and_coa.sql | 38 +- .../ceda/ceda-schema-customisations.sql | 2 - .../default-demo/bk_mifostenant-default.sql | 36 +- .../latam-demo/bk_latam.sql | 36 +- .../0001a-mifosplatform-core-ddl-latest.sql | 19 +- .../0002-mifosx-base-reference-data-utf8.sql | 8 - .../en/chapters/architecture/modules.adoc | 90 +- .../en/chapters/custom/business-step.adoc | 36 + .../chapters/custom/database-migration.adoc | 21 + .../docs/en/chapters/custom/deployment.adoc | 12 + .../src/docs/en/chapters/custom/index.adoc | 17 + .../src/docs/en/chapters/custom/intro.adoc | 47 + .../custom/loan-transaction-processor.adoc | 114 + .../src/docs/en/chapters/custom/outlook.adoc | 3 + .../docs/en/chapters/custom/service-note.adoc | 29 + .../src/docs/en/chapters/custom/service.adoc | 5 + fineract-doc/src/docs/en/colophon.adoc | 4 + .../multiple-batch-instances-diagram.png | Bin 0 -> 13644 bytes .../multiple-read-instances-diagram.png | Bin 0 -> 15903 bytes .../en/images/single-instance-diagram.png | Bin 0 -> 7235 bytes fineract-doc/src/docs/en/index.adoc | 2 + fineract-provider/build.gradle | 2 +- .../importhandler/loan/LoanImportHandler.java | 52 +- .../LoanComparatorByStatusActive.java | 4 +- .../guarantor/GuarantorWorkbookPopulator.java | 2 +- .../LoanRepaymentWorkbookPopulator.java | 12 +- .../core/serialization/FromJsonHelper.java | 2 + .../mapper/loan/LoanAccountDataMapper.java | 6 + .../portfolio/calendar/data/CalendarData.java | 89 +- .../loanaccount/api/LoanApiConstants.java | 3 +- .../loanaccount/api/LoansApiResource.java | 49 +- .../api/LoansApiResourceSwagger.java | 12 +- .../loanaccount/data/CollectionData.java | 54 +- .../loanaccount/data/LoanAccountData.java | 2278 ++++++----------- .../portfolio/loanaccount/domain/Loan.java | 120 +- ...ntScheduleTransactionProcessorFactory.java | 63 +- ...RepaymentScheduleTransactionProcessor.java | 5 + ...RepaymentScheduleTransactionProcessor.java | 6 + ...RepaymentScheduleTransactionProcessor.java | 14 + ...RepaymentScheduleTransactionProcessor.java | 14 + ...RepaymentScheduleTransactionProcessor.java | 14 + ...RepaymentScheduleTransactionProcessor.java | 14 + ...RepaymentScheduleTransactionProcessor.java | 14 + ...RepaymentScheduleTransactionProcessor.java | 14 + ...RepaymentScheduleTransactionProcessor.java | 14 + ...onProcessingStrategyNotFoundException.java | 6 +- ...nReschedulePreviewPlatformServiceImpl.java | 4 +- ...ateLoanScheduleQueryFromApiJsonHelper.java | 2 +- ...anApplicationCommandFromApiJsonHelper.java | 60 +- ...WritePlatformServiceJpaRepositoryImpl.java | 15 +- .../loanaccount/service/LoanAssembler.java | 32 +- .../service/LoanReadPlatformServiceImpl.java | 26 +- .../starter/LoanAccountAutoStarter.java | 88 + .../loanproduct/LoanProductConstants.java | 2 +- .../api/LoanProductsApiResource.java | 4 +- .../api/LoanProductsApiResourceSwagger.java | 14 +- .../loanproduct/data/LoanProductData.java | 28 +- .../TransactionProcessingStrategyData.java | 18 +- .../loanproduct/domain/LoanProduct.java | 46 +- .../LoanProductConfigurableAttributes.java | 22 +- .../LoanTransactionProcessingStrategy.java | 77 - .../LoanProductDataValidator.java | 41 +- .../LoanDropdownReadPlatformServiceImpl.java | 26 +- .../LoanProductReadPlatformServiceImpl.java | 9 +- ...WritePlatformServiceJpaRepositoryImpl.java | 63 +- .../loanaccount/api/SelfLoansApiResource.java | 4 +- .../api/SelfLoansApiResourceSwagger.java | 12 +- .../api/SelfLoanProductsApiResource.java | 2 +- .../src/main/resources/application.properties | 9 + .../db/changelog/tenant/changelog-tenant.xml | 1 + ...064_refactor_loan_transaction_strategy.xml | 129 + .../migrations/sample_data/barebones_db.sql | 30 +- .../sample_data/load_sample_data.sql | 34 +- .../resources/static/legacy-docs/apiLive.htm | 58 +- .../resources/application-test.properties | 9 + instancemode-tests/build.gradle | 2 +- integration-tests/build.gradle | 2 +- .../ClientLoanIntegrationTest.java | 4 +- .../integrationtests/common/BatchHelper.java | 5 +- .../loans/LoanApplicationTestBuilder.java | 14 +- .../common/loans/LoanProductTestBuilder.java | 16 +- .../common/loans/LoanTransactionHelper.java | 4 +- oauth2-tests/build.gradle | 2 +- twofactor-tests/build.gradle | 2 +- 99 files changed, 2015 insertions(+), 2547 deletions(-) create mode 100644 custom/acme/loan/cob/src/main/resources/db/custom-changelog/0001_acme_loan_cob.xml create mode 100644 custom/acme/loan/processor/build.gradle rename fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransactionProcessingStrategyRepository.java => custom/acme/loan/processor/dependencies.gradle (61%) create mode 100644 custom/acme/loan/processor/src/main/java/com/acme/fineract/loan/processor/AcmeLoanRepaymentScheduleTransactionProcessor.java create mode 100644 fineract-doc/src/docs/en/chapters/custom/business-step.adoc create mode 100644 fineract-doc/src/docs/en/chapters/custom/database-migration.adoc create mode 100644 fineract-doc/src/docs/en/chapters/custom/deployment.adoc create mode 100644 fineract-doc/src/docs/en/chapters/custom/index.adoc create mode 100644 fineract-doc/src/docs/en/chapters/custom/intro.adoc create mode 100644 fineract-doc/src/docs/en/chapters/custom/loan-transaction-processor.adoc create mode 100644 fineract-doc/src/docs/en/chapters/custom/outlook.adoc create mode 100644 fineract-doc/src/docs/en/chapters/custom/service-note.adoc create mode 100644 fineract-doc/src/docs/en/chapters/custom/service.adoc create mode 100644 fineract-doc/src/docs/en/images/multiple-batch-instances-diagram.png create mode 100644 fineract-doc/src/docs/en/images/multiple-read-instances-diagram.png create mode 100644 fineract-doc/src/docs/en/images/single-instance-diagram.png create mode 100644 fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/starter/LoanAccountAutoStarter.java delete mode 100644 fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanTransactionProcessingStrategy.java create mode 100644 fineract-provider/src/main/resources/db/changelog/tenant/parts/0064_refactor_loan_transaction_strategy.xml diff --git a/custom/acme/loan/cob/build.gradle b/custom/acme/loan/cob/build.gradle index 104d04edc..04ca760dc 100644 --- a/custom/acme/loan/cob/build.gradle +++ b/custom/acme/loan/cob/build.gradle @@ -18,8 +18,8 @@ */ description = 'ACME Corp.: Fineract COB Loan' -group = 'com.acme.fineract.cob' +group = 'com.acme.fineract' -archivesBaseName = 'acme-fineract-cob-loan' +archivesBaseName = 'acme-fineract-loan-cob' apply from: 'dependencies.gradle' diff --git a/custom/acme/loan/cob/src/main/java/com/acme/fineract/loan/cob/AcmeNoopBusinessStep.java b/custom/acme/loan/cob/src/main/java/com/acme/fineract/loan/cob/AcmeNoopBusinessStep.java index 85d271d51..2217466d0 100644 --- a/custom/acme/loan/cob/src/main/java/com/acme/fineract/loan/cob/AcmeNoopBusinessStep.java +++ b/custom/acme/loan/cob/src/main/java/com/acme/fineract/loan/cob/AcmeNoopBusinessStep.java @@ -31,6 +31,10 @@ import org.springframework.stereotype.Component; @RequiredArgsConstructor public class AcmeNoopBusinessStep implements LoanCOBBusinessStep, InitializingBean { + private static final String ENUM_STYLED_NAME = "ACME_LOAN_NOOP"; + + private static final String HUMAN_READABLE_NAME = "ACME Loan Noop"; + // NOTE: just to demonstrate that dependency injection is working private final LoanAccountDomainService loanAccountDomainService; @@ -46,11 +50,11 @@ public class AcmeNoopBusinessStep implements LoanCOBBusinessStep, InitializingBe @Override public String getEnumStyledName() { - return "ACME_LOAN_NOOP"; + return ENUM_STYLED_NAME; } @Override public String getHumanReadableName() { - return "ACME Loan Noop"; + return HUMAN_READABLE_NAME; } } diff --git a/custom/acme/loan/cob/src/main/resources/db/custom-changelog/0001_acme_loan_cob.xml b/custom/acme/loan/cob/src/main/resources/db/custom-changelog/0001_acme_loan_cob.xml new file mode 100644 index 000000000..bd63bdc41 --- /dev/null +++ b/custom/acme/loan/cob/src/main/resources/db/custom-changelog/0001_acme_loan_cob.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + diff --git a/custom/acme/loan/processor/build.gradle b/custom/acme/loan/processor/build.gradle new file mode 100644 index 000000000..c693255c9 --- /dev/null +++ b/custom/acme/loan/processor/build.gradle @@ -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. + */ +description = 'ACME Corp.: Fineract Loan Transaction Processors' + +group = 'com.acme.fineract' + +archivesBaseName = 'acme-fineract-loan-processor' + +apply from: 'dependencies.gradle' diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransactionProcessingStrategyRepository.java b/custom/acme/loan/processor/dependencies.gradle similarity index 61% rename from fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransactionProcessingStrategyRepository.java rename to custom/acme/loan/processor/dependencies.gradle index 49c875e08..59d668289 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransactionProcessingStrategyRepository.java +++ b/custom/acme/loan/processor/dependencies.gradle @@ -16,13 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.fineract.portfolio.loanaccount.domain; -import org.apache.fineract.portfolio.loanproduct.domain.LoanTransactionProcessingStrategy; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.JpaSpecificationExecutor; - -public interface LoanTransactionProcessingStrategyRepository - extends JpaRepository, JpaSpecificationExecutor { - // no added behaviour +dependencies { + implementation(project(':fineract-provider')) } diff --git a/custom/acme/loan/processor/src/main/java/com/acme/fineract/loan/processor/AcmeLoanRepaymentScheduleTransactionProcessor.java b/custom/acme/loan/processor/src/main/java/com/acme/fineract/loan/processor/AcmeLoanRepaymentScheduleTransactionProcessor.java new file mode 100644 index 000000000..f53a94458 --- /dev/null +++ b/custom/acme/loan/processor/src/main/java/com/acme/fineract/loan/processor/AcmeLoanRepaymentScheduleTransactionProcessor.java @@ -0,0 +1,41 @@ +/** + * 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 com.acme.fineract.loan.processor; + +import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.FineractStyleLoanRepaymentScheduleTransactionProcessor; +import org.springframework.stereotype.Component; + +@Component +public class AcmeLoanRepaymentScheduleTransactionProcessor extends FineractStyleLoanRepaymentScheduleTransactionProcessor { + + private static final String STRATEGY_CODE = "acme-standard-strategy"; + + private static final String STRATEGY_NAME = "ACME Corp.: standard loan transaction processing strategy"; + + @Override + public String getCode() { + return STRATEGY_CODE; + } + + @Override + public String getName() { + return STRATEGY_NAME; + } + +} diff --git a/custom/acme/loan/starter/build.gradle b/custom/acme/loan/starter/build.gradle index 31e39823f..8620f5bfd 100644 --- a/custom/acme/loan/starter/build.gradle +++ b/custom/acme/loan/starter/build.gradle @@ -18,8 +18,8 @@ */ description = 'ACME Corp.: Fineract COB Starter' -group = 'com.acme.fineract.cob' +group = 'com.acme.fineract' -archivesBaseName = 'acme-fineract-cob-starter' +archivesBaseName = 'acme-fineract-loan-starter' apply from: 'dependencies.gradle' diff --git a/custom/acme/loan/starter/dependencies.gradle b/custom/acme/loan/starter/dependencies.gradle index 6276b6322..11225f482 100644 --- a/custom/acme/loan/starter/dependencies.gradle +++ b/custom/acme/loan/starter/dependencies.gradle @@ -18,7 +18,9 @@ */ dependencies { + implementation(project(':fineract-provider')) implementation(project(':custom:acme:loan:cob')) + implementation(project(':custom:acme:loan:processor')) implementation('org.springframework.boot:spring-boot-starter') testImplementation(project(':fineract-provider')) testImplementation('org.springframework.boot:spring-boot-starter-jdbc') diff --git a/custom/acme/loan/starter/src/main/java/com/acme/fineract/loan/starter/AcmeLoanAutoConfiguration.java b/custom/acme/loan/starter/src/main/java/com/acme/fineract/loan/starter/AcmeLoanAutoConfiguration.java index 91dc820c0..8e4560a32 100644 --- a/custom/acme/loan/starter/src/main/java/com/acme/fineract/loan/starter/AcmeLoanAutoConfiguration.java +++ b/custom/acme/loan/starter/src/main/java/com/acme/fineract/loan/starter/AcmeLoanAutoConfiguration.java @@ -18,11 +18,25 @@ */ package com.acme.fineract.loan.starter; +import com.acme.fineract.loan.processor.AcmeLoanRepaymentScheduleTransactionProcessor; +import java.util.List; +import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleTransactionProcessorFactory; +import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.LoanRepaymentScheduleTransactionProcessor; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.ComponentScans; @AutoConfiguration -@ComponentScan("com.acme.fineract.loan.cob") +@ComponentScans({ @ComponentScan("com.acme.fineract.loan.cob"), @ComponentScan("com.acme.fineract.loan.processor") }) @ConditionalOnProperty("acme.loan.enabled") -public class AcmeLoanAutoConfiguration {} +public class AcmeLoanAutoConfiguration { + + @Bean + public LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory( + AcmeLoanRepaymentScheduleTransactionProcessor defaultLoanRepaymentScheduleTransactionProcessor, + List processors) { + return new LoanRepaymentScheduleTransactionProcessorFactory(defaultLoanRepaymentScheduleTransactionProcessor, processors); + } +} diff --git a/custom/docker/build.gradle b/custom/docker/build.gradle index 8d1a91711..98b65ed18 100644 --- a/custom/docker/build.gradle +++ b/custom/docker/build.gradle @@ -85,7 +85,7 @@ jib { } // NOTE: other custom dependencies implementation 'org.mariadb.jdbc:mariadb-java-client:3.0.7' - implementation 'mysql:mysql-connector-java:8.0.30' + implementation 'mysql:mysql-connector-java:8.0.31' implementation 'org.postgresql:postgresql:42.5.0' annotationProcessor('org.springframework.boot:spring-boot-autoconfigure-processor') annotationProcessor('org.springframework.boot:spring-boot-configuration-processor') diff --git a/fineract-avro-schemas/src/main/avro/loan/v1/LoanAccountDataV1.avsc b/fineract-avro-schemas/src/main/avro/loan/v1/LoanAccountDataV1.avsc index c8e925c9c..ad628df93 100644 --- a/fineract-avro-schemas/src/main/avro/loan/v1/LoanAccountDataV1.avsc +++ b/fineract-avro-schemas/src/main/avro/loan/v1/LoanAccountDataV1.avsc @@ -341,10 +341,10 @@ }, { "default": null, - "name": "transactionProcessingStrategyId", + "name": "transactionProcessingStrategyCode", "type": [ "null", - "long" + "string" ] }, { diff --git a/fineract-avro-schemas/src/main/avro/loan/v1/LoanProductDataV1.avsc b/fineract-avro-schemas/src/main/avro/loan/v1/LoanProductDataV1.avsc index 935c96906..35f6cff0b 100644 --- a/fineract-avro-schemas/src/main/avro/loan/v1/LoanProductDataV1.avsc +++ b/fineract-avro-schemas/src/main/avro/loan/v1/LoanProductDataV1.avsc @@ -341,10 +341,10 @@ }, { "default": null, - "name": "transactionProcessingStrategyId", + "name": "transactionProcessingStrategyCode", "type": [ "null", - "long" + "string" ] }, { diff --git a/fineract-db/multi-tenant-demo-backups/bare-bones-demo/bk_bare_bones_demo.sql b/fineract-db/multi-tenant-demo-backups/bare-bones-demo/bk_bare_bones_demo.sql index 4e810f636..0c34151db 100644 --- a/fineract-db/multi-tenant-demo-backups/bare-bones-demo/bk_bare_bones_demo.sql +++ b/fineract-db/multi-tenant-demo-backups/bare-bones-demo/bk_bare_bones_demo.sql @@ -1011,7 +1011,6 @@ CREATE TABLE `m_loan` ( KEY `FKB6F935D87179A0CB` (`client_id`), KEY `FKB6F935D8C8D4B434` (`product_id`), KEY `FK7C885877240145` (`fund_id`), - KEY `FK_loan_ltp_strategy` (`loan_transaction_strategy_id`), KEY `FK_m_loan_m_staff` (`loan_officer_id`), KEY `group_id` (`group_id`), KEY `FK_m_loanpurpose_codevalue` (`loanpurpose_cv_id`), @@ -1027,7 +1026,6 @@ CREATE TABLE `m_loan` ( CONSTRAINT `FK_approvedon_userid` FOREIGN KEY (`approvedon_userid`) REFERENCES `m_appuser` (`id`), CONSTRAINT `FK_closedon_userid` FOREIGN KEY (`closedon_userid`) REFERENCES `m_appuser` (`id`), CONSTRAINT `FK_disbursedon_userid` FOREIGN KEY (`disbursedon_userid`) REFERENCES `m_appuser` (`id`), - CONSTRAINT `FK_loan_ltp_strategy` FOREIGN KEY (`loan_transaction_strategy_id`) REFERENCES `ref_loan_transaction_processing_strategy` (`id`), CONSTRAINT `FK_m_loanpurpose_codevalue` FOREIGN KEY (`loanpurpose_cv_id`) REFERENCES `m_code_value` (`id`), CONSTRAINT `FK_m_loan_m_staff` FOREIGN KEY (`loan_officer_id`) REFERENCES `m_staff` (`id`), CONSTRAINT `FK_rejectedon_userid` FOREIGN KEY (`rejectedon_userid`) REFERENCES `m_appuser` (`id`), @@ -1506,9 +1504,7 @@ CREATE TABLE `m_product_loan` ( PRIMARY KEY (`id`), UNIQUE KEY `unq_name` (`name`), KEY `FKA6A8A7D77240145` (`fund_id`), - KEY `FK_ltp_strategy` (`loan_transaction_strategy_id`), - CONSTRAINT `FKA6A8A7D77240145` FOREIGN KEY (`fund_id`) REFERENCES `m_fund` (`id`), - CONSTRAINT `FK_ltp_strategy` FOREIGN KEY (`loan_transaction_strategy_id`) REFERENCES `ref_loan_transaction_processing_strategy` (`id`) + CONSTRAINT `FKA6A8A7D77240145` FOREIGN KEY (`fund_id`) REFERENCES `m_fund` (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=UTF8MB4; /*!40101 SET character_set_client = @saved_cs_client */; @@ -1770,36 +1766,6 @@ INSERT INTO `r_enum_value` VALUES ('amortization_method_enum',0,'Equal principle /*!40000 ALTER TABLE `r_enum_value` ENABLE KEYS */; UNLOCK TABLES; --- --- Table structure for table `ref_loan_transaction_processing_strategy` --- - -DROP TABLE IF EXISTS `ref_loan_transaction_processing_strategy`; -/*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = UTF8MB4 */; -CREATE TABLE `ref_loan_transaction_processing_strategy` ( - `id` BIGINT NOT NULL AUTO_INCREMENT, - `code` varchar(100) DEFAULT NULL, - `name` varchar(255) DEFAULT NULL, - `createdby_id` BIGINT DEFAULT NULL, - `created_date` datetime DEFAULT NULL, - `lastmodifiedby_id` BIGINT DEFAULT NULL, - `lastmodified_date` datetime DEFAULT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `ltp_strategy_code` (`code`) -) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=UTF8MB4; -/*!40101 SET character_set_client = @saved_cs_client */; - --- --- Dumping data for table `ref_loan_transaction_processing_strategy` --- - -LOCK TABLES `ref_loan_transaction_processing_strategy` WRITE; -/*!40000 ALTER TABLE `ref_loan_transaction_processing_strategy` DISABLE KEYS */; -INSERT INTO `ref_loan_transaction_processing_strategy` VALUES (1,'mifos-standard-strategy','Mifos style',NULL,NULL,NULL,NULL),(2,'heavensfamily-strategy','Heavensfamily',NULL,NULL,NULL,NULL),(3,'creocore-strategy','Creocore',NULL,NULL,NULL,NULL),(4,'rbi-india-strategy','RBI (India)',NULL,NULL,NULL,NULL); -/*!40000 ALTER TABLE `ref_loan_transaction_processing_strategy` ENABLE KEYS */; -UNLOCK TABLES; - -- -- Table structure for table `rpt_sequence` -- diff --git a/fineract-db/multi-tenant-demo-backups/bk_mifostenant_default.sql b/fineract-db/multi-tenant-demo-backups/bk_mifostenant_default.sql index 61da348c6..ef70237b6 100644 --- a/fineract-db/multi-tenant-demo-backups/bk_mifostenant_default.sql +++ b/fineract-db/multi-tenant-demo-backups/bk_mifostenant_default.sql @@ -1012,7 +1012,6 @@ CREATE TABLE `m_loan` ( KEY `FKB6F935D87179A0CB` (`client_id`), KEY `FKB6F935D8C8D4B434` (`product_id`), KEY `FK7C885877240145` (`fund_id`), - KEY `FK_loan_ltp_strategy` (`loan_transaction_strategy_id`), KEY `FK_m_loan_m_staff` (`loan_officer_id`), KEY `group_id` (`group_id`), KEY `FK_m_loanpurpose_codevalue` (`loanpurpose_cv_id`), @@ -1028,7 +1027,6 @@ CREATE TABLE `m_loan` ( CONSTRAINT `FK_approvedon_userid` FOREIGN KEY (`approvedon_userid`) REFERENCES `m_appuser` (`id`), CONSTRAINT `FK_closedon_userid` FOREIGN KEY (`closedon_userid`) REFERENCES `m_appuser` (`id`), CONSTRAINT `FK_disbursedon_userid` FOREIGN KEY (`disbursedon_userid`) REFERENCES `m_appuser` (`id`), - CONSTRAINT `FK_loan_ltp_strategy` FOREIGN KEY (`loan_transaction_strategy_id`) REFERENCES `ref_loan_transaction_processing_strategy` (`id`), CONSTRAINT `FK_m_loanpurpose_codevalue` FOREIGN KEY (`loanpurpose_cv_id`) REFERENCES `m_code_value` (`id`), CONSTRAINT `FK_m_loan_m_staff` FOREIGN KEY (`loan_officer_id`) REFERENCES `m_staff` (`id`), CONSTRAINT `FK_rejectedon_userid` FOREIGN KEY (`rejectedon_userid`) REFERENCES `m_appuser` (`id`), @@ -1507,9 +1505,7 @@ CREATE TABLE `m_product_loan` ( PRIMARY KEY (`id`), UNIQUE KEY `unq_name` (`name`), KEY `FKA6A8A7D77240145` (`fund_id`), - KEY `FK_ltp_strategy` (`loan_transaction_strategy_id`), - CONSTRAINT `FKA6A8A7D77240145` FOREIGN KEY (`fund_id`) REFERENCES `m_fund` (`id`), - CONSTRAINT `FK_ltp_strategy` FOREIGN KEY (`loan_transaction_strategy_id`) REFERENCES `ref_loan_transaction_processing_strategy` (`id`) + CONSTRAINT `FKA6A8A7D77240145` FOREIGN KEY (`fund_id`) REFERENCES `m_fund` (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=UTF8MB4; /*!40101 SET character_set_client = @saved_cs_client */; @@ -1771,36 +1767,6 @@ INSERT INTO `r_enum_value` VALUES ('amortization_method_enum',0,'Equal principle /*!40000 ALTER TABLE `r_enum_value` ENABLE KEYS */; UNLOCK TABLES; --- --- Table structure for table `ref_loan_transaction_processing_strategy` --- - -DROP TABLE IF EXISTS `ref_loan_transaction_processing_strategy`; -/*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = UTF8MB4 */; -CREATE TABLE `ref_loan_transaction_processing_strategy` ( - `id` BIGINT NOT NULL AUTO_INCREMENT, - `code` varchar(100) DEFAULT NULL, - `name` varchar(255) DEFAULT NULL, - `createdby_id` BIGINT DEFAULT NULL, - `created_date` datetime DEFAULT NULL, - `lastmodifiedby_id` BIGINT DEFAULT NULL, - `lastmodified_date` datetime DEFAULT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `ltp_strategy_code` (`code`) -) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=UTF8MB4; -/*!40101 SET character_set_client = @saved_cs_client */; - --- --- Dumping data for table `ref_loan_transaction_processing_strategy` --- - -LOCK TABLES `ref_loan_transaction_processing_strategy` WRITE; -/*!40000 ALTER TABLE `ref_loan_transaction_processing_strategy` DISABLE KEYS */; -INSERT INTO `ref_loan_transaction_processing_strategy` VALUES (1,'mifos-standard-strategy','Mifos style',NULL,NULL,NULL,NULL),(2,'heavensfamily-strategy','Heavensfamily',NULL,NULL,NULL,NULL),(3,'creocore-strategy','Creocore',NULL,NULL,NULL,NULL),(4,'rbi-india-strategy','RBI (India)',NULL,NULL,NULL,NULL); -/*!40000 ALTER TABLE `ref_loan_transaction_processing_strategy` ENABLE KEYS */; -UNLOCK TABLES; - -- -- Table structure for table `rpt_sequence` -- diff --git a/fineract-db/multi-tenant-demo-backups/ceda/bk_ceda_trial.sql b/fineract-db/multi-tenant-demo-backups/ceda/bk_ceda_trial.sql index 766a63645..5ed8ef07d 100644 --- a/fineract-db/multi-tenant-demo-backups/ceda/bk_ceda_trial.sql +++ b/fineract-db/multi-tenant-demo-backups/ceda/bk_ceda_trial.sql @@ -930,7 +930,6 @@ CREATE TABLE `m_loan` ( KEY `FKB6F935D87179A0CB` (`client_id`), KEY `FKB6F935D8C8D4B434` (`product_id`), KEY `FK7C885877240145` (`fund_id`), - KEY `FK_loan_ltp_strategy` (`loan_transaction_strategy_id`), KEY `FK_m_loan_m_staff` (`loan_officer_id`), KEY `group_id` (`group_id`), KEY `FK_m_loanpurpose_codevalue` (`loanpurpose_cv_id`), @@ -946,7 +945,6 @@ CREATE TABLE `m_loan` ( CONSTRAINT `FK_approvedon_userid` FOREIGN KEY (`approvedon_userid`) REFERENCES `m_appuser` (`id`), CONSTRAINT `FK_closedon_userid` FOREIGN KEY (`closedon_userid`) REFERENCES `m_appuser` (`id`), CONSTRAINT `FK_disbursedon_userid` FOREIGN KEY (`disbursedon_userid`) REFERENCES `m_appuser` (`id`), - CONSTRAINT `FK_loan_ltp_strategy` FOREIGN KEY (`loan_transaction_strategy_id`) REFERENCES `ref_loan_transaction_processing_strategy` (`id`), CONSTRAINT `FK_m_loanpurpose_codevalue` FOREIGN KEY (`loanpurpose_cv_id`) REFERENCES `m_code_value` (`id`), CONSTRAINT `FK_m_loan_m_staff` FOREIGN KEY (`loan_officer_id`) REFERENCES `m_staff` (`id`), CONSTRAINT `FK_rejectedon_userid` FOREIGN KEY (`rejectedon_userid`) REFERENCES `m_appuser` (`id`), @@ -1399,7 +1397,7 @@ CREATE TABLE `m_portfolio_command_source` ( LOCK TABLES `m_portfolio_command_source` WRITE; /*!40000 ALTER TABLE `m_portfolio_command_source` DISABLE KEYS */; -INSERT INTO `m_portfolio_command_source` VALUES (1,'CREATE','CLIENT',2,NULL,1,NULL,NULL,'/clients/template',1,NULL,'{\"officeId\":\"2\",\"firstname\":\"Test\",\"middlename\":\"\",\"lastname\":\"One\",\"fullname\":\"\",\"externalId\":\"\",\"dateFormat\":\"yyyy-MM-dd\",\"locale\":\"en\",\"joinedDate\":\"2011-02-01\"}',1,'2013-04-05 12:38:05',NULL,NULL,1),(2,'CREATE','LOAN',2,NULL,1,1,NULL,'/loans',1,NULL,'{\"clientId\":\"1\",\"dateFormat\":\"yyyy-MM-dd\",\"locale\":\"en\",\"productId\":\"1\",\"loanOfficerId\":\"2\",\"submittedOnDate\":\"2011-04-01\",\"loanPurposeId\":\"25\",\"principal\":\"1,000,000.00\",\"loanTermFrequency\":\"12\",\"loanTermFrequencyType\":\"2\",\"numberOfRepayments\":\"12\",\"repaymentEvery\":\"1\",\"repaymentFrequencyType\":\"2\",\"interestRatePerPeriod\":\"24\",\"interestRateFrequencyType\":\"3\",\"expectedDisbursementDate\":\"2011-04-01\",\"amortizationType\":\"1\",\"interestType\":\"1\",\"interestCalculationPeriodType\":\"1\",\"inArrearsTolerance\":\"\",\"transactionProcessingStrategyId\":\"2\",\"repaymentsStartingFromDate\":\"\",\"interestChargedFromDate\":\"\",\"charges\":[{\"chargeId\":\"1\",\"amount\":\"1,500\",\"dueDate\":\"2011-05-01\"},{\"chargeId\":\"1\",\"amount\":\"1,500\",\"dueDate\":\"2011-06-01\"},{\"chargeId\":\"1\",\"amount\":\"1,500\",\"dueDate\":\"2011-07-01\"},{\"chargeId\":\"1\",\"amount\":\"1,500\",\"dueDate\":\"2011-08-01\"},{\"chargeId\":\"1\",\"amount\":\"1,500\",\"dueDate\":\"2011-09-01\"},{\"chargeId\":\"1\",\"amount\":\"1,500\",\"dueDate\":\"2011-10-01\"},{\"chargeId\":\"1\",\"amount\":\"1,500\",\"dueDate\":\"2011-11-01\"},{\"chargeId\":\"1\",\"amount\":\"1,500\",\"dueDate\":\"2011-12-01\"},{\"chargeId\":\"1\",\"amount\":\"1,500\",\"dueDate\":\"2012-01-01\"},{\"chargeId\":\"1\",\"amount\":\"1,500\",\"dueDate\":\"2012-02-01\"},{\"chargeId\":\"1\",\"amount\":\"1,500\",\"dueDate\":\"2012-03-01\"},{\"chargeId\":\"1\",\"amount\":\"1,500\",\"dueDate\":\"2012-04-01\"}],\"collateral\":[{\"id\":\"\",\"type\":\"23\",\"description\":\" small description.\",\"value\":\"\"}]}',1,'2013-04-05 12:41:57',NULL,NULL,1),(3,'APPROVE','LOAN',2,NULL,1,1,NULL,'/loans/1',1,NULL,'{\"status\":{\"id\":200,\"code\":\"loanStatusType.approved\",\"value\":\"Approved\",\"pendingApproval\":false,\"waitingForDisbursal\":true,\"active\":false,\"closedObligationsMet\":false,\"closedWrittenOff\":false,\"closedRescheduled\":false,\"closed\":false,\"overpaid\":false},\"locale\":\"en\",\"dateFormat\":\"yyyy-MM-dd\",\"approvedOnDate\":\"2011-04-01\"}',1,'2013-04-05 12:42:09',NULL,NULL,1); +INSERT INTO `m_portfolio_command_source` VALUES (1,'CREATE','CLIENT',2,NULL,1,NULL,NULL,'/clients/template',1,NULL,'{\"officeId\":\"2\",\"firstname\":\"Test\",\"middlename\":\"\",\"lastname\":\"One\",\"fullname\":\"\",\"externalId\":\"\",\"dateFormat\":\"yyyy-MM-dd\",\"locale\":\"en\",\"joinedDate\":\"2011-02-01\"}',1,'2013-04-05 12:38:05',NULL,NULL,1),(2,'CREATE','LOAN',2,NULL,1,1,NULL,'/loans',1,NULL,'{\"clientId\":\"1\",\"dateFormat\":\"yyyy-MM-dd\",\"locale\":\"en\",\"productId\":\"1\",\"loanOfficerId\":\"2\",\"submittedOnDate\":\"2011-04-01\",\"loanPurposeId\":\"25\",\"principal\":\"1,000,000.00\",\"loanTermFrequency\":\"12\",\"loanTermFrequencyType\":\"2\",\"numberOfRepayments\":\"12\",\"repaymentEvery\":\"1\",\"repaymentFrequencyType\":\"2\",\"interestRatePerPeriod\":\"24\",\"interestRateFrequencyType\":\"3\",\"expectedDisbursementDate\":\"2011-04-01\",\"amortizationType\":\"1\",\"interestType\":\"1\",\"interestCalculationPeriodType\":\"1\",\"inArrearsTolerance\":\"\",\"transactionProcessingStrategy\":\"heavensfamily-strategy\",\"repaymentsStartingFromDate\":\"\",\"interestChargedFromDate\":\"\",\"charges\":[{\"chargeId\":\"1\",\"amount\":\"1,500\",\"dueDate\":\"2011-05-01\"},{\"chargeId\":\"1\",\"amount\":\"1,500\",\"dueDate\":\"2011-06-01\"},{\"chargeId\":\"1\",\"amount\":\"1,500\",\"dueDate\":\"2011-07-01\"},{\"chargeId\":\"1\",\"amount\":\"1,500\",\"dueDate\":\"2011-08-01\"},{\"chargeId\":\"1\",\"amount\":\"1,500\",\"dueDate\":\"2011-09-01\"},{\"chargeId\":\"1\",\"amount\":\"1,500\",\"dueDate\":\"2011-10-01\"},{\"chargeId\":\"1\",\"amount\":\"1,500\",\"dueDate\":\"2011-11-01\"},{\"chargeId\":\"1\",\"amount\":\"1,500\",\"dueDate\":\"2011-12-01\"},{\"chargeId\":\"1\",\"amount\":\"1,500\",\"dueDate\":\"2012-01-01\"},{\"chargeId\":\"1\",\"amount\":\"1,500\",\"dueDate\":\"2012-02-01\"},{\"chargeId\":\"1\",\"amount\":\"1,500\",\"dueDate\":\"2012-03-01\"},{\"chargeId\":\"1\",\"amount\":\"1,500\",\"dueDate\":\"2012-04-01\"}],\"collateral\":[{\"id\":\"\",\"type\":\"23\",\"description\":\" small description.\",\"value\":\"\"}]}',1,'2013-04-05 12:41:57',NULL,NULL,1),(3,'APPROVE','LOAN',2,NULL,1,1,NULL,'/loans/1',1,NULL,'{\"status\":{\"id\":200,\"code\":\"loanStatusType.approved\",\"value\":\"Approved\",\"pendingApproval\":false,\"waitingForDisbursal\":true,\"active\":false,\"closedObligationsMet\":false,\"closedWrittenOff\":false,\"closedRescheduled\":false,\"closed\":false,\"overpaid\":false},\"locale\":\"en\",\"dateFormat\":\"yyyy-MM-dd\",\"approvedOnDate\":\"2011-04-01\"}',1,'2013-04-05 12:42:09',NULL,NULL,1); /*!40000 ALTER TABLE `m_portfolio_command_source` ENABLE KEYS */; UNLOCK TABLES; @@ -1435,9 +1433,7 @@ CREATE TABLE `m_product_loan` ( PRIMARY KEY (`id`), UNIQUE KEY `unq_name` (`name`), KEY `FKA6A8A7D77240145` (`fund_id`), - KEY `FK_ltp_strategy` (`loan_transaction_strategy_id`), - CONSTRAINT `FKA6A8A7D77240145` FOREIGN KEY (`fund_id`) REFERENCES `m_fund` (`id`), - CONSTRAINT `FK_ltp_strategy` FOREIGN KEY (`loan_transaction_strategy_id`) REFERENCES `ref_loan_transaction_processing_strategy` (`id`) + CONSTRAINT `FKA6A8A7D77240145` FOREIGN KEY (`fund_id`) REFERENCES `m_fund` (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=UTF8MB4; /*!40101 SET character_set_client = @saved_cs_client */; @@ -1709,36 +1705,6 @@ INSERT INTO `r_enum_value` VALUES ('amortization_method_enum',0,'Equal principle /*!40000 ALTER TABLE `r_enum_value` ENABLE KEYS */; UNLOCK TABLES; --- --- Table structure for table `ref_loan_transaction_processing_strategy` --- - -DROP TABLE IF EXISTS `ref_loan_transaction_processing_strategy`; -/*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = UTF8MB4 */; -CREATE TABLE `ref_loan_transaction_processing_strategy` ( - `id` BIGINT NOT NULL AUTO_INCREMENT, - `code` varchar(100) DEFAULT NULL, - `name` varchar(255) DEFAULT NULL, - `createdby_id` BIGINT DEFAULT NULL, - `created_date` datetime DEFAULT NULL, - `lastmodifiedby_id` BIGINT DEFAULT NULL, - `lastmodified_date` datetime DEFAULT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `ltp_strategy_code` (`code`) -) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=UTF8MB4; -/*!40101 SET character_set_client = @saved_cs_client */; - --- --- Dumping data for table `ref_loan_transaction_processing_strategy` --- - -LOCK TABLES `ref_loan_transaction_processing_strategy` WRITE; -/*!40000 ALTER TABLE `ref_loan_transaction_processing_strategy` DISABLE KEYS */; -INSERT INTO `ref_loan_transaction_processing_strategy` VALUES (2,'heavensfamily-strategy','Heavensfamily',NULL,NULL,NULL,NULL); -/*!40000 ALTER TABLE `ref_loan_transaction_processing_strategy` ENABLE KEYS */; -UNLOCK TABLES; - -- -- Table structure for table `rpt_sequence` -- diff --git a/fineract-db/multi-tenant-demo-backups/ceda/bk_core_with_custom_and_coa.sql b/fineract-db/multi-tenant-demo-backups/ceda/bk_core_with_custom_and_coa.sql index 0628d7668..f4672ec00 100644 --- a/fineract-db/multi-tenant-demo-backups/ceda/bk_core_with_custom_and_coa.sql +++ b/fineract-db/multi-tenant-demo-backups/ceda/bk_core_with_custom_and_coa.sql @@ -930,7 +930,6 @@ CREATE TABLE `m_loan` ( KEY `FKB6F935D87179A0CB` (`client_id`), KEY `FKB6F935D8C8D4B434` (`product_id`), KEY `FK7C885877240145` (`fund_id`), - KEY `FK_loan_ltp_strategy` (`loan_transaction_strategy_id`), KEY `FK_m_loan_m_staff` (`loan_officer_id`), KEY `group_id` (`group_id`), KEY `FK_m_loanpurpose_codevalue` (`loanpurpose_cv_id`), @@ -946,7 +945,6 @@ CREATE TABLE `m_loan` ( CONSTRAINT `FK_approvedon_userid` FOREIGN KEY (`approvedon_userid`) REFERENCES `m_appuser` (`id`), CONSTRAINT `FK_closedon_userid` FOREIGN KEY (`closedon_userid`) REFERENCES `m_appuser` (`id`), CONSTRAINT `FK_disbursedon_userid` FOREIGN KEY (`disbursedon_userid`) REFERENCES `m_appuser` (`id`), - CONSTRAINT `FK_loan_ltp_strategy` FOREIGN KEY (`loan_transaction_strategy_id`) REFERENCES `ref_loan_transaction_processing_strategy` (`id`), CONSTRAINT `FK_m_loanpurpose_codevalue` FOREIGN KEY (`loanpurpose_cv_id`) REFERENCES `m_code_value` (`id`), CONSTRAINT `FK_m_loan_m_staff` FOREIGN KEY (`loan_officer_id`) REFERENCES `m_staff` (`id`), CONSTRAINT `FK_rejectedon_userid` FOREIGN KEY (`rejectedon_userid`) REFERENCES `m_appuser` (`id`), @@ -1399,7 +1397,7 @@ CREATE TABLE `m_portfolio_command_source` ( LOCK TABLES `m_portfolio_command_source` WRITE; /*!40000 ALTER TABLE `m_portfolio_command_source` DISABLE KEYS */; -INSERT INTO `m_portfolio_command_source` VALUES (1,'CREATE','CLIENT',2,NULL,1,NULL,NULL,'/clients/template',1,NULL,'{\"officeId\":\"2\",\"firstname\":\"Test\",\"middlename\":\"\",\"lastname\":\"One\",\"fullname\":\"\",\"externalId\":\"\",\"dateFormat\":\"yyyy-MM-dd\",\"locale\":\"en\",\"joinedDate\":\"2011-02-01\"}',1,'2013-04-05 12:38:05',NULL,NULL,1),(2,'CREATE','LOAN',2,NULL,1,1,NULL,'/loans',1,NULL,'{\"clientId\":\"1\",\"dateFormat\":\"yyyy-MM-dd\",\"locale\":\"en\",\"productId\":\"1\",\"loanOfficerId\":\"2\",\"submittedOnDate\":\"2011-04-01\",\"loanPurposeId\":\"25\",\"principal\":\"1,000,000.00\",\"loanTermFrequency\":\"12\",\"loanTermFrequencyType\":\"2\",\"numberOfRepayments\":\"12\",\"repaymentEvery\":\"1\",\"repaymentFrequencyType\":\"2\",\"interestRatePerPeriod\":\"24\",\"interestRateFrequencyType\":\"3\",\"expectedDisbursementDate\":\"2011-04-01\",\"amortizationType\":\"1\",\"interestType\":\"1\",\"interestCalculationPeriodType\":\"1\",\"inArrearsTolerance\":\"\",\"transactionProcessingStrategyId\":\"2\",\"repaymentsStartingFromDate\":\"\",\"interestChargedFromDate\":\"\",\"charges\":[{\"chargeId\":\"1\",\"amount\":\"1,500\",\"dueDate\":\"2011-05-01\"},{\"chargeId\":\"1\",\"amount\":\"1,500\",\"dueDate\":\"2011-06-01\"},{\"chargeId\":\"1\",\"amount\":\"1,500\",\"dueDate\":\"2011-07-01\"},{\"chargeId\":\"1\",\"amount\":\"1,500\",\"dueDate\":\"2011-08-01\"},{\"chargeId\":\"1\",\"amount\":\"1,500\",\"dueDate\":\"2011-09-01\"},{\"chargeId\":\"1\",\"amount\":\"1,500\",\"dueDate\":\"2011-10-01\"},{\"chargeId\":\"1\",\"amount\":\"1,500\",\"dueDate\":\"2011-11-01\"},{\"chargeId\":\"1\",\"amount\":\"1,500\",\"dueDate\":\"2011-12-01\"},{\"chargeId\":\"1\",\"amount\":\"1,500\",\"dueDate\":\"2012-01-01\"},{\"chargeId\":\"1\",\"amount\":\"1,500\",\"dueDate\":\"2012-02-01\"},{\"chargeId\":\"1\",\"amount\":\"1,500\",\"dueDate\":\"2012-03-01\"},{\"chargeId\":\"1\",\"amount\":\"1,500\",\"dueDate\":\"2012-04-01\"}],\"collateral\":[{\"id\":\"\",\"type\":\"23\",\"description\":\" small description.\",\"value\":\"\"}]}',1,'2013-04-05 12:41:57',NULL,NULL,1),(3,'APPROVE','LOAN',2,NULL,1,1,NULL,'/loans/1',1,NULL,'{\"status\":{\"id\":200,\"code\":\"loanStatusType.approved\",\"value\":\"Approved\",\"pendingApproval\":false,\"waitingForDisbursal\":true,\"active\":false,\"closedObligationsMet\":false,\"closedWrittenOff\":false,\"closedRescheduled\":false,\"closed\":false,\"overpaid\":false},\"locale\":\"en\",\"dateFormat\":\"yyyy-MM-dd\",\"approvedOnDate\":\"2011-04-01\"}',1,'2013-04-05 12:42:09',NULL,NULL,1); +INSERT INTO `m_portfolio_command_source` VALUES (1,'CREATE','CLIENT',2,NULL,1,NULL,NULL,'/clients/template',1,NULL,'{\"officeId\":\"2\",\"firstname\":\"Test\",\"middlename\":\"\",\"lastname\":\"One\",\"fullname\":\"\",\"externalId\":\"\",\"dateFormat\":\"yyyy-MM-dd\",\"locale\":\"en\",\"joinedDate\":\"2011-02-01\"}',1,'2013-04-05 12:38:05',NULL,NULL,1),(2,'CREATE','LOAN',2,NULL,1,1,NULL,'/loans',1,NULL,'{\"clientId\":\"1\",\"dateFormat\":\"yyyy-MM-dd\",\"locale\":\"en\",\"productId\":\"1\",\"loanOfficerId\":\"2\",\"submittedOnDate\":\"2011-04-01\",\"loanPurposeId\":\"25\",\"principal\":\"1,000,000.00\",\"loanTermFrequency\":\"12\",\"loanTermFrequencyType\":\"2\",\"numberOfRepayments\":\"12\",\"repaymentEvery\":\"1\",\"repaymentFrequencyType\":\"2\",\"interestRatePerPeriod\":\"24\",\"interestRateFrequencyType\":\"3\",\"expectedDisbursementDate\":\"2011-04-01\",\"amortizationType\":\"1\",\"interestType\":\"1\",\"interestCalculationPeriodType\":\"1\",\"inArrearsTolerance\":\"\",\"transactionProcessingStrategy\":\"heavensfamily-strategy\",\"repaymentsStartingFromDate\":\"\",\"interestChargedFromDate\":\"\",\"charges\":[{\"chargeId\":\"1\",\"amount\":\"1,500\",\"dueDate\":\"2011-05-01\"},{\"chargeId\":\"1\",\"amount\":\"1,500\",\"dueDate\":\"2011-06-01\"},{\"chargeId\":\"1\",\"amount\":\"1,500\",\"dueDate\":\"2011-07-01\"},{\"chargeId\":\"1\",\"amount\":\"1,500\",\"dueDate\":\"2011-08-01\"},{\"chargeId\":\"1\",\"amount\":\"1,500\",\"dueDate\":\"2011-09-01\"},{\"chargeId\":\"1\",\"amount\":\"1,500\",\"dueDate\":\"2011-10-01\"},{\"chargeId\":\"1\",\"amount\":\"1,500\",\"dueDate\":\"2011-11-01\"},{\"chargeId\":\"1\",\"amount\":\"1,500\",\"dueDate\":\"2011-12-01\"},{\"chargeId\":\"1\",\"amount\":\"1,500\",\"dueDate\":\"2012-01-01\"},{\"chargeId\":\"1\",\"amount\":\"1,500\",\"dueDate\":\"2012-02-01\"},{\"chargeId\":\"1\",\"amount\":\"1,500\",\"dueDate\":\"2012-03-01\"},{\"chargeId\":\"1\",\"amount\":\"1,500\",\"dueDate\":\"2012-04-01\"}],\"collateral\":[{\"id\":\"\",\"type\":\"23\",\"description\":\" small description.\",\"value\":\"\"}]}',1,'2013-04-05 12:41:57',NULL,NULL,1),(3,'APPROVE','LOAN',2,NULL,1,1,NULL,'/loans/1',1,NULL,'{\"status\":{\"id\":200,\"code\":\"loanStatusType.approved\",\"value\":\"Approved\",\"pendingApproval\":false,\"waitingForDisbursal\":true,\"active\":false,\"closedObligationsMet\":false,\"closedWrittenOff\":false,\"closedRescheduled\":false,\"closed\":false,\"overpaid\":false},\"locale\":\"en\",\"dateFormat\":\"yyyy-MM-dd\",\"approvedOnDate\":\"2011-04-01\"}',1,'2013-04-05 12:42:09',NULL,NULL,1); /*!40000 ALTER TABLE `m_portfolio_command_source` ENABLE KEYS */; UNLOCK TABLES; @@ -1435,9 +1433,7 @@ CREATE TABLE `m_product_loan` ( PRIMARY KEY (`id`), UNIQUE KEY `unq_name` (`name`), KEY `FKA6A8A7D77240145` (`fund_id`), - KEY `FK_ltp_strategy` (`loan_transaction_strategy_id`), - CONSTRAINT `FKA6A8A7D77240145` FOREIGN KEY (`fund_id`) REFERENCES `m_fund` (`id`), - CONSTRAINT `FK_ltp_strategy` FOREIGN KEY (`loan_transaction_strategy_id`) REFERENCES `ref_loan_transaction_processing_strategy` (`id`) + CONSTRAINT `FKA6A8A7D77240145` FOREIGN KEY (`fund_id`) REFERENCES `m_fund` (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=UTF8MB4; /*!40101 SET character_set_client = @saved_cs_client */; @@ -1709,36 +1705,6 @@ INSERT INTO `r_enum_value` VALUES ('amortization_method_enum',0,'Equal principle /*!40000 ALTER TABLE `r_enum_value` ENABLE KEYS */; UNLOCK TABLES; --- --- Table structure for table `ref_loan_transaction_processing_strategy` --- - -DROP TABLE IF EXISTS `ref_loan_transaction_processing_strategy`; -/*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = UTF8MB4 */; -CREATE TABLE `ref_loan_transaction_processing_strategy` ( - `id` BIGINT NOT NULL AUTO_INCREMENT, - `code` varchar(100) DEFAULT NULL, - `name` varchar(255) DEFAULT NULL, - `createdby_id` BIGINT DEFAULT NULL, - `created_date` datetime DEFAULT NULL, - `lastmodifiedby_id` BIGINT DEFAULT NULL, - `lastmodified_date` datetime DEFAULT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `ltp_strategy_code` (`code`) -) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=UTF8MB4; -/*!40101 SET character_set_client = @saved_cs_client */; - --- --- Dumping data for table `ref_loan_transaction_processing_strategy` --- - -LOCK TABLES `ref_loan_transaction_processing_strategy` WRITE; -/*!40000 ALTER TABLE `ref_loan_transaction_processing_strategy` DISABLE KEYS */; -INSERT INTO `ref_loan_transaction_processing_strategy` VALUES (2,'heavensfamily-strategy','Heavensfamily',NULL,NULL,NULL,NULL); -/*!40000 ALTER TABLE `ref_loan_transaction_processing_strategy` ENABLE KEYS */; -UNLOCK TABLES; - -- -- Table structure for table `rpt_sequence` -- diff --git a/fineract-db/multi-tenant-demo-backups/ceda/ceda-schema-customisations.sql b/fineract-db/multi-tenant-demo-backups/ceda/ceda-schema-customisations.sql index 7c30d33e2..324897f21 100644 --- a/fineract-db/multi-tenant-demo-backups/ceda/ceda-schema-customisations.sql +++ b/fineract-db/multi-tenant-demo-backups/ceda/ceda-schema-customisations.sql @@ -17,8 +17,6 @@ -- under the License. -- -DELETE FROM `ref_loan_transaction_processing_strategy` WHERE id in (1, 3, 4); - INSERT INTO `m_code` (`code_name`, `is_system_defined`) VALUES ('FieldOfEmployment', '0'), diff --git a/fineract-db/multi-tenant-demo-backups/default-demo/bk_mifostenant-default.sql b/fineract-db/multi-tenant-demo-backups/default-demo/bk_mifostenant-default.sql index 61da348c6..ef70237b6 100644 --- a/fineract-db/multi-tenant-demo-backups/default-demo/bk_mifostenant-default.sql +++ b/fineract-db/multi-tenant-demo-backups/default-demo/bk_mifostenant-default.sql @@ -1012,7 +1012,6 @@ CREATE TABLE `m_loan` ( KEY `FKB6F935D87179A0CB` (`client_id`), KEY `FKB6F935D8C8D4B434` (`product_id`), KEY `FK7C885877240145` (`fund_id`), - KEY `FK_loan_ltp_strategy` (`loan_transaction_strategy_id`), KEY `FK_m_loan_m_staff` (`loan_officer_id`), KEY `group_id` (`group_id`), KEY `FK_m_loanpurpose_codevalue` (`loanpurpose_cv_id`), @@ -1028,7 +1027,6 @@ CREATE TABLE `m_loan` ( CONSTRAINT `FK_approvedon_userid` FOREIGN KEY (`approvedon_userid`) REFERENCES `m_appuser` (`id`), CONSTRAINT `FK_closedon_userid` FOREIGN KEY (`closedon_userid`) REFERENCES `m_appuser` (`id`), CONSTRAINT `FK_disbursedon_userid` FOREIGN KEY (`disbursedon_userid`) REFERENCES `m_appuser` (`id`), - CONSTRAINT `FK_loan_ltp_strategy` FOREIGN KEY (`loan_transaction_strategy_id`) REFERENCES `ref_loan_transaction_processing_strategy` (`id`), CONSTRAINT `FK_m_loanpurpose_codevalue` FOREIGN KEY (`loanpurpose_cv_id`) REFERENCES `m_code_value` (`id`), CONSTRAINT `FK_m_loan_m_staff` FOREIGN KEY (`loan_officer_id`) REFERENCES `m_staff` (`id`), CONSTRAINT `FK_rejectedon_userid` FOREIGN KEY (`rejectedon_userid`) REFERENCES `m_appuser` (`id`), @@ -1507,9 +1505,7 @@ CREATE TABLE `m_product_loan` ( PRIMARY KEY (`id`), UNIQUE KEY `unq_name` (`name`), KEY `FKA6A8A7D77240145` (`fund_id`), - KEY `FK_ltp_strategy` (`loan_transaction_strategy_id`), - CONSTRAINT `FKA6A8A7D77240145` FOREIGN KEY (`fund_id`) REFERENCES `m_fund` (`id`), - CONSTRAINT `FK_ltp_strategy` FOREIGN KEY (`loan_transaction_strategy_id`) REFERENCES `ref_loan_transaction_processing_strategy` (`id`) + CONSTRAINT `FKA6A8A7D77240145` FOREIGN KEY (`fund_id`) REFERENCES `m_fund` (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=UTF8MB4; /*!40101 SET character_set_client = @saved_cs_client */; @@ -1771,36 +1767,6 @@ INSERT INTO `r_enum_value` VALUES ('amortization_method_enum',0,'Equal principle /*!40000 ALTER TABLE `r_enum_value` ENABLE KEYS */; UNLOCK TABLES; --- --- Table structure for table `ref_loan_transaction_processing_strategy` --- - -DROP TABLE IF EXISTS `ref_loan_transaction_processing_strategy`; -/*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = UTF8MB4 */; -CREATE TABLE `ref_loan_transaction_processing_strategy` ( - `id` BIGINT NOT NULL AUTO_INCREMENT, - `code` varchar(100) DEFAULT NULL, - `name` varchar(255) DEFAULT NULL, - `createdby_id` BIGINT DEFAULT NULL, - `created_date` datetime DEFAULT NULL, - `lastmodifiedby_id` BIGINT DEFAULT NULL, - `lastmodified_date` datetime DEFAULT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `ltp_strategy_code` (`code`) -) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=UTF8MB4; -/*!40101 SET character_set_client = @saved_cs_client */; - --- --- Dumping data for table `ref_loan_transaction_processing_strategy` --- - -LOCK TABLES `ref_loan_transaction_processing_strategy` WRITE; -/*!40000 ALTER TABLE `ref_loan_transaction_processing_strategy` DISABLE KEYS */; -INSERT INTO `ref_loan_transaction_processing_strategy` VALUES (1,'mifos-standard-strategy','Mifos style',NULL,NULL,NULL,NULL),(2,'heavensfamily-strategy','Heavensfamily',NULL,NULL,NULL,NULL),(3,'creocore-strategy','Creocore',NULL,NULL,NULL,NULL),(4,'rbi-india-strategy','RBI (India)',NULL,NULL,NULL,NULL); -/*!40000 ALTER TABLE `ref_loan_transaction_processing_strategy` ENABLE KEYS */; -UNLOCK TABLES; - -- -- Table structure for table `rpt_sequence` -- diff --git a/fineract-db/multi-tenant-demo-backups/latam-demo/bk_latam.sql b/fineract-db/multi-tenant-demo-backups/latam-demo/bk_latam.sql index daa11df0d..9900ab12f 100644 --- a/fineract-db/multi-tenant-demo-backups/latam-demo/bk_latam.sql +++ b/fineract-db/multi-tenant-demo-backups/latam-demo/bk_latam.sql @@ -859,7 +859,6 @@ CREATE TABLE `m_loan` ( KEY `FKB6F935D87179A0CB` (`client_id`), KEY `FKB6F935D8C8D4B434` (`product_id`), KEY `FK7C885877240145` (`fund_id`), - KEY `FK_loan_ltp_strategy` (`loan_transaction_strategy_id`), KEY `FK_m_loan_m_staff` (`loan_officer_id`), KEY `group_id` (`group_id`), KEY `FK_m_loan_guarantor` (`guarantor_id`), @@ -867,7 +866,6 @@ CREATE TABLE `m_loan` ( CONSTRAINT `FK7C885877240145` FOREIGN KEY (`fund_id`) REFERENCES `m_fund` (`id`), CONSTRAINT `FKB6F935D87179A0CB` FOREIGN KEY (`client_id`) REFERENCES `m_client` (`id`), CONSTRAINT `FKB6F935D8C8D4B434` FOREIGN KEY (`product_id`) REFERENCES `m_product_loan` (`id`), - CONSTRAINT `FK_loan_ltp_strategy` FOREIGN KEY (`loan_transaction_strategy_id`) REFERENCES `ref_loan_transaction_processing_strategy` (`id`), CONSTRAINT `FK_m_loan_m_staff` FOREIGN KEY (`loan_officer_id`) REFERENCES `m_staff` (`id`), CONSTRAINT `m_loan_ibfk_1` FOREIGN KEY (`group_id`) REFERENCES `m_group` (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=UTF8MB4; @@ -1343,9 +1341,7 @@ CREATE TABLE `m_product_loan` ( `loan_transaction_strategy_id` BIGINT DEFAULT NULL, PRIMARY KEY (`id`), KEY `FKA6A8A7D77240145` (`fund_id`), - KEY `FK_ltp_strategy` (`loan_transaction_strategy_id`), - CONSTRAINT `FKA6A8A7D77240145` FOREIGN KEY (`fund_id`) REFERENCES `m_fund` (`id`), - CONSTRAINT `FK_ltp_strategy` FOREIGN KEY (`loan_transaction_strategy_id`) REFERENCES `ref_loan_transaction_processing_strategy` (`id`) + CONSTRAINT `FKA6A8A7D77240145` FOREIGN KEY (`fund_id`) REFERENCES `m_fund` (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=UTF8MB4; /*!40101 SET character_set_client = @saved_cs_client */; @@ -1687,36 +1683,6 @@ INSERT INTO `r_enum_value` VALUES ('amortization_method_enum',0,'Equal principle /*!40000 ALTER TABLE `r_enum_value` ENABLE KEYS */; UNLOCK TABLES; --- --- Table structure for table `ref_loan_transaction_processing_strategy` --- - -DROP TABLE IF EXISTS `ref_loan_transaction_processing_strategy`; -/*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = UTF8MB4 */; -CREATE TABLE `ref_loan_transaction_processing_strategy` ( - `id` BIGINT NOT NULL AUTO_INCREMENT, - `code` varchar(100) DEFAULT NULL, - `name` varchar(255) DEFAULT NULL, - `createdby_id` BIGINT DEFAULT NULL, - `created_date` datetime DEFAULT NULL, - `lastmodifiedby_id` BIGINT DEFAULT NULL, - `lastmodified_date` datetime DEFAULT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `ltp_strategy_code` (`code`) -) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=UTF8MB4; -/*!40101 SET character_set_client = @saved_cs_client */; - --- --- Dumping data for table `ref_loan_transaction_processing_strategy` --- - -LOCK TABLES `ref_loan_transaction_processing_strategy` WRITE; -/*!40000 ALTER TABLE `ref_loan_transaction_processing_strategy` DISABLE KEYS */; -INSERT INTO `ref_loan_transaction_processing_strategy` VALUES (1,'mifos-standard-strategy','Mifos style',NULL,NULL,NULL,NULL),(2,'heavensfamily-strategy','Heavensfamily',NULL,NULL,NULL,NULL),(3,'creocore-strategy','Creocore',NULL,NULL,NULL,NULL),(4,'rbi-india-strategy','RBI (India)',NULL,NULL,NULL,NULL); -/*!40000 ALTER TABLE `ref_loan_transaction_processing_strategy` ENABLE KEYS */; -UNLOCK TABLES; - -- -- Table structure for table `rpt_sequence` -- diff --git a/fineract-db/old-schema-files/0001a-mifosplatform-core-ddl-latest.sql b/fineract-db/old-schema-files/0001a-mifosplatform-core-ddl-latest.sql index 9c5ba1890..a07826136 100644 --- a/fineract-db/old-schema-files/0001a-mifosplatform-core-ddl-latest.sql +++ b/fineract-db/old-schema-files/0001a-mifosplatform-core-ddl-latest.sql @@ -68,7 +68,6 @@ DROP TABLE IF EXISTS `m_savings_account`; DROP TABLE IF EXISTS `m_savings_account_transaction`; DROP TABLE IF EXISTS `m_savings_product`; DROP TABLE IF EXISTS `m_staff`; -DROP TABLE IF EXISTS `ref_loan_transaction_processing_strategy`; DROP TABLE IF EXISTS `x_registered_table`; -- drop reporting related tables @@ -102,18 +101,6 @@ CREATE TABLE `m_organisation_currency` ( PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=UTF8MB4; -CREATE TABLE `ref_loan_transaction_processing_strategy` ( - `id` BIGINT NOT NULL AUTO_INCREMENT, - `code` varchar(100) DEFAULT NULL, - `name` varchar(255) DEFAULT NULL, - `createdby_id` BIGINT DEFAULT NULL, - `created_date` datetime DEFAULT NULL, - `lastmodifiedby_id` BIGINT DEFAULT NULL, - `lastmodified_date` datetime DEFAULT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `ltp_strategy_code` (`code`) -) ENGINE=InnoDB DEFAULT CHARSET=UTF8MB4; - CREATE TABLE `c_configuration` ( `id` BIGINT NOT NULL AUTO_INCREMENT, `name` varchar(50) DEFAULT NULL, @@ -482,9 +469,7 @@ CREATE TABLE `m_product_loan` ( PRIMARY KEY (`id`), UNIQUE KEY `unq_name` (`name`), KEY `FKA6A8A7D77240145` (`fund_id`), - KEY `FK_ltp_strategy` (`loan_transaction_strategy_id`), - CONSTRAINT `FKA6A8A7D77240145` FOREIGN KEY (`fund_id`) REFERENCES `m_fund` (`id`), - CONSTRAINT `FK_ltp_strategy` FOREIGN KEY (`loan_transaction_strategy_id`) REFERENCES `ref_loan_transaction_processing_strategy` (`id`) + CONSTRAINT `FKA6A8A7D77240145` FOREIGN KEY (`fund_id`) REFERENCES `m_fund` (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=UTF8MB4; CREATE TABLE `m_product_loan_charge` ( @@ -575,7 +560,6 @@ CREATE TABLE `m_loan` ( KEY `FKB6F935D87179A0CB` (`client_id`), KEY `FKB6F935D8C8D4B434` (`product_id`), KEY `FK7C885877240145` (`fund_id`), - KEY `FK_loan_ltp_strategy` (`loan_transaction_strategy_id`), KEY `FK_m_loan_m_staff` (`loan_officer_id`), KEY `group_id` (`group_id`), KEY `FK_m_loanpurpose_codevalue` (`loanpurpose_cv_id`), @@ -591,7 +575,6 @@ CREATE TABLE `m_loan` ( CONSTRAINT `FK_approvedon_userid` FOREIGN KEY (`approvedon_userid`) REFERENCES `m_appuser` (`id`), CONSTRAINT `FK_closedon_userid` FOREIGN KEY (`closedon_userid`) REFERENCES `m_appuser` (`id`), CONSTRAINT `FK_disbursedon_userid` FOREIGN KEY (`disbursedon_userid`) REFERENCES `m_appuser` (`id`), - CONSTRAINT `FK_loan_ltp_strategy` FOREIGN KEY (`loan_transaction_strategy_id`) REFERENCES `ref_loan_transaction_processing_strategy` (`id`), CONSTRAINT `FK_m_loanpurpose_codevalue` FOREIGN KEY (`loanpurpose_cv_id`) REFERENCES `m_code_value` (`id`), CONSTRAINT `FK_m_loan_m_staff` FOREIGN KEY (`loan_officer_id`) REFERENCES `m_staff` (`id`), CONSTRAINT `FK_rejectedon_userid` FOREIGN KEY (`rejectedon_userid`) REFERENCES `m_appuser` (`id`), diff --git a/fineract-db/old-schema-files/0002-mifosx-base-reference-data-utf8.sql b/fineract-db/old-schema-files/0002-mifosx-base-reference-data-utf8.sql index 6795b0796..9810e799c 100644 --- a/fineract-db/old-schema-files/0002-mifosx-base-reference-data-utf8.sql +++ b/fineract-db/old-schema-files/0002-mifosx-base-reference-data-utf8.sql @@ -19,14 +19,6 @@ -- currency symbols may not apply through command line on windows so use a different client like mysql workbench -INSERT INTO `ref_loan_transaction_processing_strategy` -(`id`,`code`,`name`) -VALUES -(1, 'mifos-standard-strategy', 'Mifos style'), -(2, 'heavensfamily-strategy', 'Heavensfamily'), -(3, 'creocore-strategy', 'Creocore'), -(4, 'rbi-india-strategy', 'RBI (India)'); - INSERT INTO `c_configuration` (`name`, `enabled`) VALUES diff --git a/fineract-doc/src/docs/en/chapters/architecture/modules.adoc b/fineract-doc/src/docs/en/chapters/architecture/modules.adoc index 0349c060c..137e26ffa 100644 --- a/fineract-doc/src/docs/en/chapters/architecture/modules.adoc +++ b/fineract-doc/src/docs/en/chapters/architecture/modules.adoc @@ -1,91 +1,5 @@ = Modules -NOTE: Currently modules are a proof of concept feature in Fineract. +We are currently working towards a fully modular codebase and will publish more here when we are ready. -== Custom modules - -Creating customizations for Fineract services is easy. The method described here will work both with our future module guidelines (aka "clean room" modules) and with the intermediary solution we will put in place to avoid major refactorings. - -The folder structure for modules is based on a convention that ensures that your extensions don't clash with Fineract's internals. This is to make sure that your downstream forks of Fineract are easy to sync. In the past we had all kinds of strategies to add custom code - including editing existing sources in `fineract-provider`. This is not recommended. - -IMPORTANT: At the moment the only service(s) we prepared to be overridden/replaced are `org.apache.fineract.portfolio.note.service.NoteReadPlatformService` and `org.apache.fineract.portfolio.note.service.NoteWritePlatformService`. Please reach out on the developer mailing list if you need other services. - -The recommended folder structure is very simple. If you follow this recommendation you'll get some additional benefits, e. g. you don't even have to edit `settings.gradle` to include your new custom modules. Your modules will also be automatically included in a custom Fineract Docker image build that you can use for your production deployments. - -Let's assume your company/org is called "ACME Inc." and you are trying to (fully/partially) replace an existing Fineract service, let's say those in `org.apache.fineract.portfolio.note`. The recommended folder structure would then look something like this: - -[plantuml, format=svg] ----- -include::{diagramsdir}/custom-folder-structure.puml[] ----- - -As soon as we can publish Fineract module JARs to Maven Central you'll have more freedom to setup your projects (including to setup separate Git repos). But for now please follow these instructions: - -1. Create a folder under `custom` and name it according to your company/organisation (e. g. `acme` if your company is `ACME Inc.`); this way your custom modules can't clash even with other companies' modules -2. Under your company folder create a folder for the `category` or `domain` your module is targeting; e. g. "loan", "client", "account" etc. -3. Finally, setup `library` folders for the actual modules you want to create; usually that will be to replace/extend some existing service, so there could be a `service` folder, maybe even a `core` folder, e. g. if you want to add additional DTOs etc.; we have also an example for COB business steps -4. Per `category`/`domain` you should have a `starter` library; means: a Spring Boot auto-configuration setup that makes including your module in Fineract easier ("hands-free"); the necessary parts for a auto-configuration library are a Spring Java configuration class (annotated with `@Configuration`) and a text file at `META-INF/spring.factories` in your starter resource folder: -+ -[source,properties] ----- -include::{rootdir}/custom/acme/note/starter/src/main/resources/META-INF/spring.factories[] ----- -+ -Please make sure that your module libraries have proper `build.gradle` files: -+ -[source,groovy] ----- -include::{rootdir}/custom/acme/note/service/build.gradle[lines=19..] ----- -+ -NOTE: You don't need to edit `settings.gradle` to add your modules/libraries. If you follow above convention they'll get included automatically. -+ -5. The dependency.gradle file could look something like this: -[source,groovy] ----- -include::{rootdir}/custom/acme/note/service/dependencies.gradle[lines=19..] ----- - -NOTE: We've included by default some basic and useful dependencies for all custom modules, like Slf4j, Lombok, the usual testing frameworks (JUnit, Cucumber, Mockito etc.) - -IMPORTANT: Do not include your custom module in `fineract-provider`'s dependency.gradle file. This creates a circular dependency and will fail your build. - -=== Database Migrations - -If database migrations are needed as part of your customizations then you can add your own migration scripts. This is again based on conventions: - -1. Create folders `db/custom-changelog` in one of your `resources` folders; we recommend using the resources folder in your starter library, but actually any of your custom libs will do. -2. Under `db/custom-changelog` create an XML changelog file, e. g. `changelog-acme-note.xml`; you are free to choose a name for this file, but we recommend being consistent to avoid classpath conflicts. -3. Under `db/custom-changelog` create a folder `parts` for your specific changelogs - -[plantuml, format=svg] ----- -include::{diagramsdir}/custom-db-migration-folder-structure.puml[] ----- - -And here an example migration script: - -[source,xml] ----- -include::{rootdir}/custom/acme/note/starter/src/main/resources/db/custom-changelog/0001_acme_note_initial.xml[lines=22..] ----- - -IMPORTANT: By default custom database migration changelogs are executed in context `tenant_db`. That makes sure your changes will be applied to the tenant database (read: main database and not the tenant store database). In theory you could also target the tenant configuration database, but it's not recommended to do that. - -=== Deployment - -Custom modules (better: the JAR files) only need to be dropped in Fineract's `libs` folder if you run Fineract from the Spring Boot JAR file. Dynamic loading of external JARs is provided since Fineract version 1.5.0. For your convenience we've created a separate Docker image module that automatically includes your custom modules (see `custom/docker`). You can build this Docker image with - -[source,bash] ----- -./gradlew :custom:docker:jibDockerBuild ----- - -The Docker image with included custom modules is called `fineract-custom`. - -NOTE: We'll provide soon a way to customize the Docker image parameters (image name, JVM implementation, JVM args, ports etc.). - - -=== Outlook - -If this *proof of concept* is accepted we could prepare Fineract's services to be replaceable. This approach works already very well even if we don't have proper JAR libraries published on Maven Central. It's an important goal to separate customized code from Fineract's internals to have soon real modules. +NOTE: Even if we are not quite there yet with full modularity you can already create your own custom modules to extend Fineract. Please see chapter <<_custom_modules>>. \ No newline at end of file diff --git a/fineract-doc/src/docs/en/chapters/custom/business-step.adoc b/fineract-doc/src/docs/en/chapters/custom/business-step.adoc new file mode 100644 index 000000000..060bcdc49 --- /dev/null +++ b/fineract-doc/src/docs/en/chapters/custom/business-step.adoc @@ -0,0 +1,36 @@ += Custom Business Steps + +It very easy to add your own business steps to Fineract's default steps: + +1. Create a custom module (e. g. `custom/acme/steps`, follow the instructions on how to create a custom module) +2. Create a class that implements interace `org.apache.fineract.cob.COBBusinessStep` +3. Provide the custom database migration to add the necessary information about your business step in table `m_batch_business_steps` + +.Business Step Interface +[source,java] +---- +include::{rootdir}/fineract-provider/src/main/java/org/apache/fineract/cob/COBBusinessStep.java[lines=19..] +---- + +== Business Step Implementation + +.Custom Business Step Implementation Example +[source,java] +---- +include::{rootdir}/custom/acme/loan/cob/src/main/java/com/acme/fineract/loan/cob/AcmeNoopBusinessStep.java[lines=19..] +---- + +As you can see this implementation is very simple and doesn't do much. There are some simple conventions though that you should follow implementing your own business steps: + +1. Make sure the value returned by method `getEnumStyledName()` is unique; it's a good idea to choose a prefix that reflects the name of your organization (in this example `ACME_`) +2. You have more freedom for the value returned by `getHumanReadableName()`, but it's a good idea to keep this value as unique as possible + +== Business Step Database Migration + +.Business Step Database Migration Example +[source,xml] +---- +include::{rootdir}/custom/acme/loan/cob/src/main/resources/db/custom-changelog/0001_acme_loan_cob.xml[lines=22..] +---- + +NOTE: See also chapter about batch jobs in this documentation. \ No newline at end of file diff --git a/fineract-doc/src/docs/en/chapters/custom/database-migration.adoc b/fineract-doc/src/docs/en/chapters/custom/database-migration.adoc new file mode 100644 index 000000000..6fc0e7982 --- /dev/null +++ b/fineract-doc/src/docs/en/chapters/custom/database-migration.adoc @@ -0,0 +1,21 @@ += Custom Database Migration + +If database migrations are needed as part of your customizations then you can add your own migration scripts. This is again based on conventions: + +1. Create folders `db/custom-changelog` in one of your `resources` folders; we recommend using the resources folder in your starter library, but actually any of your custom libs will do. +2. Under `db/custom-changelog` create an XML changelog file, e. g. `changelog-acme-note.xml`; you are free to choose a name for this file, but we recommend being consistent to avoid classpath conflicts. +3. Under `db/custom-changelog` create a folder `parts` for your specific changelogs + +[plantuml, format=svg] +---- +include::{diagramsdir}/custom-db-migration-folder-structure.puml[] +---- + +And here an example migration script: + +[source,xml] +---- +include::{rootdir}/custom/acme/note/starter/src/main/resources/db/custom-changelog/0001_acme_note_initial.xml[lines=22..] +---- + +IMPORTANT: By default, custom database migration changelogs are executed in context `tenant_db`. That makes sure your changes will be applied to the tenant database (read: main database and not the tenant store database). In theory you could also target the tenant configuration database, but it's not recommended to do that. diff --git a/fineract-doc/src/docs/en/chapters/custom/deployment.adoc b/fineract-doc/src/docs/en/chapters/custom/deployment.adoc new file mode 100644 index 000000000..178e67ba4 --- /dev/null +++ b/fineract-doc/src/docs/en/chapters/custom/deployment.adoc @@ -0,0 +1,12 @@ += Deploying Custom Modules + +Custom modules (better: the JAR files) only need to be dropped in Fineract's `libs` folder if you run Fineract from the Spring Boot JAR file. Dynamic loading of external JARs is provided since Fineract version 1.5.0. For your convenience we've created a separate Docker image module that automatically includes your custom modules (see `custom/docker`). You can build this Docker image with + +[source,bash] +---- +./gradlew :custom:docker:jibDockerBuild +---- + +The Docker image with included custom modules is called `fineract-custom`. + +NOTE: We'll provide soon a way to customize the Docker image parameters (image name, JVM implementation, JVM args, ports etc.). diff --git a/fineract-doc/src/docs/en/chapters/custom/index.adoc b/fineract-doc/src/docs/en/chapters/custom/index.adoc new file mode 100644 index 000000000..12bd1eb08 --- /dev/null +++ b/fineract-doc/src/docs/en/chapters/custom/index.adoc @@ -0,0 +1,17 @@ += Custom Modules + +NOTE: Currently modules are a proof of concept feature in Fineract. + +include::intro.adoc[leveloffset=+1] + +include::service.adoc[leveloffset=+1] + +include::business-step.adoc[leveloffset=+1] + +include::loan-transaction-processor.adoc[leveloffset=+1] + +include::database-migration.adoc[leveloffset=+1] + +include::deployment.adoc[leveloffset=+1] + +include::outlook.adoc[leveloffset=+1] diff --git a/fineract-doc/src/docs/en/chapters/custom/intro.adoc b/fineract-doc/src/docs/en/chapters/custom/intro.adoc new file mode 100644 index 000000000..7be11de7f --- /dev/null +++ b/fineract-doc/src/docs/en/chapters/custom/intro.adoc @@ -0,0 +1,47 @@ += Introduction + +Creating customizations for Fineract services is easy. The method described here will work both with our future module guidelines (aka "clean room" modules) and with the intermediary solution we will put in place to avoid major refactorings. + +The folder structure for modules is based on a convention that ensures that your extensions don't clash with Fineract's internals. This is to make sure that your downstream forks of Fineract are easy to sync. In the past we had all kinds of strategies to add custom code - including editing existing sources in `fineract-provider`. This is not recommended. + +IMPORTANT: At the moment the only service(s) we prepared to be overridden/replaced are `org.apache.fineract.portfolio.note.service.NoteReadPlatformService` and `org.apache.fineract.portfolio.note.service.NoteWritePlatformService`. Please reach out on the developer mailing list if you need other services. + +The recommended folder structure is very simple. If you follow this recommendation you'll get some additional benefits, e. g. you don't even have to edit `settings.gradle` to include your new custom modules. Your modules will also be automatically included in a custom Fineract Docker image build that you can use for your production deployments. + +Let's assume your company/org is called "ACME Inc." and you are trying to (fully/partially) replace an existing Fineract service, let's say those in `org.apache.fineract.portfolio.note`. The recommended folder structure would then look something like this: + +[plantuml, format=svg] +---- +include::{diagramsdir}/custom-folder-structure.puml[] +---- + +As soon as we can publish Fineract module JARs to Maven Central you'll have more freedom to setup your projects (including to setup separate Git repos). But for now please follow these instructions: + +1. Create a folder under `custom` and name it according to your company/organisation (e. g. `acme` if your company is `ACME Inc.`); this way your custom modules can't clash even with other companies' modules +2. Under your company folder create a folder for the `category` or `domain` your module is targeting; e. g. "loan", "client", "account" etc. +3. Finally, setup `library` folders for the actual modules you want to create; usually that will be to replace/extend some existing service, so there could be a `service` folder, maybe even a `core` folder, e. g. if you want to add additional DTOs etc.; we have also an example for COB business steps +4. Per `category`/`domain` you should have a `starter` library; means: a Spring Boot auto-configuration setup that makes including your module in Fineract easier ("hands-free"); the necessary parts for a auto-configuration library are a Spring Java configuration class (annotated with `@Configuration`) and a text file at `META-INF/spring.factories` in your starter resource folder: ++ +[source,properties] +---- +include::{rootdir}/custom/acme/note/starter/src/main/resources/META-INF/spring.factories[] +---- ++ +Please make sure that your module libraries have proper `build.gradle` files: ++ +[source,groovy] +---- +include::{rootdir}/custom/acme/note/service/build.gradle[lines=19..] +---- ++ +NOTE: You don't need to edit `settings.gradle` to add your modules/libraries. If you follow above convention they'll get included automatically. ++ +5. The dependency.gradle file could look something like this: +[source,groovy] +---- +include::{rootdir}/custom/acme/note/service/dependencies.gradle[lines=19..] +---- + +NOTE: We've included by default some basic and useful dependencies for all custom modules, like Slf4j, Lombok, the usual testing frameworks (JUnit, Cucumber, Mockito etc.) + +IMPORTANT: Do not include your custom module in `fineract-provider`'s dependency.gradle file. This creates a circular dependency and will fail your build. diff --git a/fineract-doc/src/docs/en/chapters/custom/loan-transaction-processor.adoc b/fineract-doc/src/docs/en/chapters/custom/loan-transaction-processor.adoc new file mode 100644 index 000000000..175c50b64 --- /dev/null +++ b/fineract-doc/src/docs/en/chapters/custom/loan-transaction-processor.adoc @@ -0,0 +1,114 @@ += Custom Loan Transaction Processors + +Fineract has 7 built-in loan transaction processors: + +1. `org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.CreocoreLoanRepaymentScheduleTransactionProcessor` +2. `org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.EarlyPaymentLoanRepaymentScheduleTransactionProcessor` +3. `org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.FineractStyleLoanRepaymentScheduleTransactionProcessor` +4. `org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.HeavensFamilyLoanRepaymentScheduleTransactionProcessor` +5. `org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.InterestPrincipalPenaltyFeesOrderLoanRepaymentScheduleTransactionProcessor` +6. `org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.PrincipalInterestPenaltyFeesOrderLoanRepaymentScheduleTransactionProcessor` +7. `org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.RBILoanRepaymentScheduleTransactionProcessor` + +.Default Loan Transaction Processor configuration +[source,java] +---- +include::{rootdir}/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/starter/LoanAccountAutoStarter.java[lines=38..80] +---- + +All default processor implementations are enabled by default, but can also be prevented from being loaded into memory by a simple configuration in `application.properties`. Use the environment variables you see below in your Kubernetes and Docker Compose deployments to override the default behavior. + +.Default Loan Transaction Processor Application Properties +[source,properties] +---- +include::{rootdir}/fineract-provider/src/main/resources/application.properties[lines=64..70] +---- + +== Implement Processors + +.Loan Transaction Processor Interface +[source,java] +---- +include::{rootdir}/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/LoanRepaymentScheduleTransactionProcessor.java[lines=19..] +---- + +.Custom Loan Transaction Processor Example +[source,java] +---- +include::{rootdir}/custom/acme/loan/processor/src/main/java/com/acme/fineract/loan/processor/AcmeLoanRepaymentScheduleTransactionProcessor.java[lines=19..] +---- + +The example implementation doesn't do much. We are just overriding one of the default processor implementations `org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.FineractStyleLoanRepaymentScheduleTransactionProcessor` and give the custom processor it's own lookup code and name (descriptive text for display in UIs, e. g. when configuring a loan product). As usual it is a good idea to follow some simple conventions: + +1. Make sure the value returned by `getCode()` is unique. Prefixing it with characters that reflect your organization name (here `acme-`) is a good idea. +2. You have more freedom for the descriptive test returned by `getName()`, but it is still a good idea to keep the value unique to avoid confusion. + +=== Method `getCode()` + +Lookup value that is used to pick a loan transaction processor (see processor factory). + +=== Method `getName()` + +Descriptive text about the loan transaction processor that is mostly used in user interfaces. + +=== Method `handleTransaction()` + +TBD + +=== Method `handleWriteOff()` + +TBD + +=== Method `handleRepaymentSchedule()` + +TBD + +=== Method `isInterestFirstRepaymentScheduleTransactionProcessor()` + +TBD + +=== Method `handleRefund()` + +TBD + +=== Method `handleChargeback()` + +TBD + +=== Method `processTransactionsFromDerivedFields()` + +TBD + +== Override Processor Factory + +The processor factory has no reference to any specific implementation of the loan transaction processor interface. All avaible implementations will be injected here (internal default and custom implementations). Processor instances can be looked up via method `determineProcessor()`. You can pass either the code of the processor or the processor's name to look it up. If a matching processor can't be found then the factory function will either return the default instance or fails with an exception depending on the configuration in `application.properties`. + +IMPORTANT: It is preferable to use the processor code to lookup processor instances. Lookups via processor names are only done in the import service via Excel sheets (should be fixed). + +.Loan Transaction Processor Factory Implementation +[source,java] +---- +include::{rootdir}/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleTransactionProcessorFactory.java[lines=19..] +---- + +This is the default factory auto-configuration. + +.Loan Transaction Processor Factory Auto-Configuration +[source,java] +---- +include::{rootdir}/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/starter/LoanAccountAutoStarter.java[lines=81..87] +---- + +If you need then you can override this, e.g. because you want to set a different default processor then you can do so in your custom module's auto-configuration. + +.Custom Loan Transaction Processor Factory Auto-Configuration Example +[source,java] +---- +include::{rootdir}/custom/acme/loan/starter/src/main/java/com/acme/fineract/loan/starter/AcmeLoanAutoConfiguration.java[lines=36..41] +---- + +.Processor Lookup Failure Configuration Property +[source,properties] +---- +include::{rootdir}/fineract-provider/src/main/resources/application.properties[lines=71..71] +---- diff --git a/fineract-doc/src/docs/en/chapters/custom/outlook.adoc b/fineract-doc/src/docs/en/chapters/custom/outlook.adoc new file mode 100644 index 000000000..f53eb21e0 --- /dev/null +++ b/fineract-doc/src/docs/en/chapters/custom/outlook.adoc @@ -0,0 +1,3 @@ += Outlook + +If this *proof of concept* is accepted we could prepare more of Fineract's internal services to be replaceable. This approach works already very well even if we don't have proper JAR libraries published on Maven Central. It's an important goal to separate customized code from Fineract's internals to have soon real modules. diff --git a/fineract-doc/src/docs/en/chapters/custom/service-note.adoc b/fineract-doc/src/docs/en/chapters/custom/service-note.adoc new file mode 100644 index 000000000..c88fadd6c --- /dev/null +++ b/fineract-doc/src/docs/en/chapters/custom/service-note.adoc @@ -0,0 +1,29 @@ += Note Service + +The Note service is responsible for ... TBD + +NOTE: We chose the note service because it's interface is very simple and has not many cross dependencies. + +== Interfaces + +.Note Read Service Interface +[source,java] +---- +include::{rootdir}/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/service/NoteReadPlatformService.java[lines=19..] +---- + +.Note Write Service Interface +[source,java] +---- +include::{rootdir}/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/service/NoteReadPlatformService.java[lines=19..] +---- + +== Auto Start Configuration + +The rules to replace the Note services are very simple. If you provide an alternative implementation of the services then the default implementations will *not* be loaded. + +.Note Auto Starter Configuration +[source,java] +---- +include::{rootdir}/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/starter/NoteAutoConfiguration.java[lines=19..] +---- diff --git a/fineract-doc/src/docs/en/chapters/custom/service.adoc b/fineract-doc/src/docs/en/chapters/custom/service.adoc new file mode 100644 index 000000000..27045eac9 --- /dev/null +++ b/fineract-doc/src/docs/en/chapters/custom/service.adoc @@ -0,0 +1,5 @@ += Custom Services + +NOTE: We are still trying to figure out which internal services make most sense to be pluggable. Please join the discussion and let us know if you have a specific requirement. + +include::service-note.adoc[leveloffset=+1] diff --git a/fineract-doc/src/docs/en/colophon.adoc b/fineract-doc/src/docs/en/colophon.adoc index 3a0e713da..c9a917891 100644 --- a/fineract-doc/src/docs/en/colophon.adoc +++ b/fineract-doc/src/docs/en/colophon.adoc @@ -19,6 +19,7 @@ | Michael Vorburger | mailto:mike@vorburger.ch[] | Aleksandar Vidakovic | mailto:aleks@apache.org[] | Arnold Galovics | mailto:arnold@apache.org[] +| Adam Saghy | mailto:adamsaghy@gmail.com[] |=== //ifdef::backend-pdf[] @@ -34,7 +35,10 @@ | Arnold Galovics | Database architecture section | 2022-03-11 | 1.7.0 | Aleksandar Vidakovic | Module section | 2022-03-23 | 1.7.0 | Aleksandar Vidakovic | Release section, file re-organisation | 2022-04-18 | 1.7.0 +| Arnold Galovics | Spring Batch | 2022-03-11 | 1.7.0 | Aleksandar Vidakovic | AsciiDoc cheatsheet | 2022-05-09 | 1.7.0 +| Adam Saghy | Business data | 2022-06-13 | 1.7.0 +| Aleksandar Vidakovic | Custom modules and extensions | 2022-10-29 | 1.8.0 |=== toc::[] diff --git a/fineract-doc/src/docs/en/images/multiple-batch-instances-diagram.png b/fineract-doc/src/docs/en/images/multiple-batch-instances-diagram.png new file mode 100644 index 0000000000000000000000000000000000000000..c080858550034ee6e90d39c356b735e4eb66b95a GIT binary patch literal 13644 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 literal 0 HcmV?d00001 diff --git a/fineract-doc/src/docs/en/index.adoc b/fineract-doc/src/docs/en/index.adoc index 3cb04b341..b31430c7d 100644 --- a/fineract-doc/src/docs/en/index.adoc +++ b/fineract-doc/src/docs/en/index.adoc @@ -37,6 +37,8 @@ include::chapters/architecture/index.adoc[leveloffset=+1] include::chapters/development/index.adoc[leveloffset=+1] +include::chapters/custom/index.adoc[leveloffset=+1] + include::chapters/security/index.adoc[leveloffset=+1] include::chapters/testing/index.adoc[leveloffset=+1] diff --git a/fineract-provider/build.gradle b/fineract-provider/build.gradle index 51b2c12f6..8ccbed967 100644 --- a/fineract-provider/build.gradle +++ b/fineract-provider/build.gradle @@ -152,7 +152,7 @@ configurations { dependencies { driver 'org.mariadb.jdbc:mariadb-java-client:3.0.8' driver 'org.postgresql:postgresql:42.5.0' - driver 'mysql:mysql-connector-java:8.0.30' + driver 'mysql:mysql-connector-java:8.0.31' } URLClassLoader loader = GroovyObject.class.classLoader diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/importhandler/loan/LoanImportHandler.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/importhandler/loan/LoanImportHandler.java index 11ffbc05a..054846e20 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/importhandler/loan/LoanImportHandler.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/importhandler/loan/LoanImportHandler.java @@ -28,6 +28,8 @@ import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.Objects; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.apache.fineract.commands.domain.CommandWrapper; import org.apache.fineract.commands.service.CommandWrapperBuilder; import org.apache.fineract.commands.service.PortfolioCommandSourceWritePlatformService; @@ -48,28 +50,25 @@ import org.apache.fineract.portfolio.loanaccount.data.LoanChargeData; import org.apache.fineract.portfolio.loanaccount.data.LoanCollateralManagementData; import org.apache.fineract.portfolio.loanaccount.data.LoanTransactionData; import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge; +import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleTransactionProcessorFactory; +import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.LoanRepaymentScheduleTransactionProcessor; import org.apache.fineract.portfolio.loanaccount.exception.InvalidAmountOfCollateralQuantity; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.IndexedColors; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.Workbook; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +@Slf4j +@RequiredArgsConstructor @Service public class LoanImportHandler implements ImportHandler { public static final String EMPTY_STR = ""; - private static final Logger LOG = LoggerFactory.getLogger(LoanImportHandler.class); private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService; - @Autowired - public LoanImportHandler(final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService) { - this.commandsSourceWritePlatformService = commandsSourceWritePlatformService; - } + private final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory; @Override public Count process(final Workbook workbook, final String locale, final String dateFormat) { @@ -234,24 +233,17 @@ public class LoanImportHandler implements ImportHandler { if (ImportHandlerUtils.readAsDouble(LoanConstants.ARREARS_TOLERANCE_COL, row) != null) { arrearsTolerance = BigDecimal.valueOf(ImportHandlerUtils.readAsDouble(LoanConstants.ARREARS_TOLERANCE_COL, row)); } - String repaymentStrategy = ImportHandlerUtils.readAsString(LoanConstants.REPAYMENT_STRATEGY_COL, row); - Long repaymentStrategyId = null; - if (repaymentStrategy != null) { - if (repaymentStrategy.equalsIgnoreCase("Penalties, Fees, Interest, Principal order")) { - repaymentStrategyId = 1L; - } else if (repaymentStrategy.equalsIgnoreCase("HeavensFamily Unique")) { - repaymentStrategyId = 2L; - } else if (repaymentStrategy.equalsIgnoreCase("Creocore Unique")) { - repaymentStrategyId = 3L; - } else if (repaymentStrategy.equalsIgnoreCase("Overdue/Due Fee/Int,Principal")) { - repaymentStrategyId = 4L; - } else if (repaymentStrategy.equalsIgnoreCase("Principal, Interest, Penalties, Fees Order")) { - repaymentStrategyId = 5L; - } else if (repaymentStrategy.equalsIgnoreCase("Interest, Principal, Penalties, Fees Order")) { - repaymentStrategyId = 6L; - } else if (repaymentStrategy.equalsIgnoreCase("Early Repayment Strategy")) { - repaymentStrategyId = 7L; - } + + String loanRepaymentScheduleTransactionProcessorStrategy = ImportHandlerUtils.readAsString(LoanConstants.REPAYMENT_STRATEGY_COL, + row); + + LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = loanRepaymentScheduleTransactionProcessorFactory + .determineProcessor(loanRepaymentScheduleTransactionProcessorStrategy); + + String repaymentStrategyCode = "mifos-standard-strategy"; + + if (loanRepaymentScheduleTransactionProcessor != null) { + repaymentStrategyCode = loanRepaymentScheduleTransactionProcessor.getCode(); } Integer graceOnPrincipalPayment = ImportHandlerUtils.readAsInt(LoanConstants.GRACE_ON_PRINCIPAL_PAYMENT_COL, row); Integer graceOnInterestPayment = ImportHandlerUtils.readAsInt(LoanConstants.GRACE_ON_INTEREST_PAYMENT_COL, row); @@ -355,7 +347,7 @@ public class LoanImportHandler implements ImportHandler { return LoanAccountData.importInstanceIndividual(loanTypeEnumOption, clientId, productId, loanOfficerId, submittedOnDate, fundId, principal, numberOfRepayments, repaidEvery, repaidEveryFrequencyEnums, loanTerm, loanTermFrequencyEnum, nominalInterestRate, submittedOnDate, amortizationEnumOption, interestMethodEnum, interestCalculationPeriodEnum, - arrearsTolerance, repaymentStrategyId, graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, + arrearsTolerance, repaymentStrategyCode, graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, interestChargedFromDate, firstRepaymentOnDate, row.getRowNum(), externalId, null, charges, linkAccountId, locale, dateFormat, loanCollateralManagementData); } else if (loanType.equals("jlg")) { @@ -364,7 +356,7 @@ public class LoanImportHandler implements ImportHandler { return LoanAccountData.importInstanceIndividual(loanTypeEnumOption, clientId, productId, loanOfficerId, submittedOnDate, fundId, principal, numberOfRepayments, repaidEvery, repaidEveryFrequencyEnums, loanTerm, loanTermFrequencyEnum, nominalInterestRate, submittedOnDate, amortizationEnumOption, interestMethodEnum, interestCalculationPeriodEnum, - arrearsTolerance, repaymentStrategyId, graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, + arrearsTolerance, repaymentStrategyCode, graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, interestChargedFromDate, firstRepaymentOnDate, row.getRowNum(), externalId, groupId, charges, linkAccountId, locale, dateFormat, null); } else { @@ -373,7 +365,7 @@ public class LoanImportHandler implements ImportHandler { return LoanAccountData.importInstanceGroup(loanTypeEnumOption, groupIdforGroupLoan, productId, loanOfficerId, submittedOnDate, fundId, principal, numberOfRepayments, repaidEvery, repaidEveryFrequencyEnums, loanTerm, loanTermFrequencyEnum, nominalInterestRate, amortizationEnumOption, interestMethodEnum, - interestCalculationPeriodEnum, arrearsTolerance, repaymentStrategyId, graceOnPrincipalPayment, + interestCalculationPeriodEnum, arrearsTolerance, repaymentStrategyCode, graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, interestChargedFromDate, firstRepaymentOnDate, row.getRowNum(), externalId, linkAccountId, locale, dateFormat); } @@ -426,7 +418,7 @@ public class LoanImportHandler implements ImportHandler { statusCell.setCellStyle(ImportHandlerUtils.getCellStyle(workbook, IndexedColors.LIGHT_GREEN)); } catch (RuntimeException ex) { errorCount++; - LOG.error("Problem occurred in importEntity function", ex); + log.error("Problem occurred in importEntity function", ex); errorMessage = ImportHandlerUtils.getErrorMessage(ex); writeLoanErrorMessage(workbook, loanId, errorMessage, progressLevel, statusCell, errorReportCell, row); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/populator/comparator/LoanComparatorByStatusActive.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/populator/comparator/LoanComparatorByStatusActive.java index e046b015e..5bfc7721c 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/populator/comparator/LoanComparatorByStatusActive.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/populator/comparator/LoanComparatorByStatusActive.java @@ -30,8 +30,8 @@ public class LoanComparatorByStatusActive implements Comparator @Override public int compare(LoanAccountData o1, LoanAccountData o2) { - boolean isData1StatusActive = o1.getStatusStringValue().equals("Active"); - boolean isData2StatusActive = o2.getStatusStringValue().equals("Active"); + boolean isData1StatusActive = o1.getStatus() != null && o1.getStatus().getValue().equals("Active"); + boolean isData2StatusActive = o2.getStatus() != null && o2.getStatus().getValue().equals("Active"); // if both status active, these have the same rank if (isData1StatusActive && isData2StatusActive) { diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/populator/guarantor/GuarantorWorkbookPopulator.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/populator/guarantor/GuarantorWorkbookPopulator.java index 97b98f80d..a702d8b61 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/populator/guarantor/GuarantorWorkbookPopulator.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/populator/guarantor/GuarantorWorkbookPopulator.java @@ -156,7 +156,7 @@ public class GuarantorWorkbookPopulator extends AbstractWorkbookPopulator { } writeString(GuarantorConstants.LOOKUP_CLIENT_NAME_COL, row, loan.getClientName() + "(" + loan.getClientId() + ")"); writeString(GuarantorConstants.LOOKUP_ACCOUNT_NO_COL, row, - Long.parseLong(loan.getAccountNo()) + "-" + loan.getStatusStringValue()); + Long.parseLong(loan.getAccountNo()) + "-" + loan.getStatus().getValue()); } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/populator/loanrepayment/LoanRepaymentWorkbookPopulator.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/populator/loanrepayment/LoanRepaymentWorkbookPopulator.java index 84f5ea855..5ed83bc73 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/populator/loanrepayment/LoanRepaymentWorkbookPopulator.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/populator/loanrepayment/LoanRepaymentWorkbookPopulator.java @@ -234,15 +234,15 @@ public class LoanRepaymentWorkbookPopulator extends AbstractWorkbookPopulator { row = loanRepaymentSheet.createRow(rowIndex++); writeString(LoanRepaymentConstants.LOOKUP_CLIENT_NAME_COL, row, loan.getClientName() + "(" + loan.getClientId() + ")"); writeString(LoanRepaymentConstants.LOOKUP_CLIENT_EXTERNAL_ID, row, clientIdToClientExternalId.get(loan.getClientId())); - writeString(LoanRepaymentConstants.LOOKUP_ACCOUNT_NO_COL, row, loan.getAccountNo() + "-" + loan.getStatusStringValue()); + writeString(LoanRepaymentConstants.LOOKUP_ACCOUNT_NO_COL, row, loan.getAccountNo() + "-" + loan.getStatus().getValue()); writeString(LoanRepaymentConstants.LOOKUP_PRODUCT_COL, row, loan.getLoanProductName()); writeDouble(LoanRepaymentConstants.LOOKUP_PRINCIPAL_COL, row, loan.getPrincipal().doubleValue()); - if (loan.getTotalOutstandingAmount() != null) { - writeBigDecimal(LoanRepaymentConstants.LOOKUP_TOTAL_OUTSTANDING_AMOUNT_COL, row, loan.getTotalOutstandingAmount()); + if (loan.getSummary() != null && loan.getSummary().getTotalOutstanding() != null) { + writeBigDecimal(LoanRepaymentConstants.LOOKUP_TOTAL_OUTSTANDING_AMOUNT_COL, row, loan.getSummary().getTotalOutstanding()); } - if (loan.getDisbursementDate() != null) { - writeDate(LoanRepaymentConstants.LOOKUP_LOAN_DISBURSEMENT_DATE_COL, row, outputFormat.format(loan.getDisbursementDate()), - dateCellStyle, dateFormat); + if (loan.getTimeline() != null && loan.getTimeline().getDisbursementDate() != null) { + writeDate(LoanRepaymentConstants.LOOKUP_LOAN_DISBURSEMENT_DATE_COL, row, + outputFormat.format(loan.getTimeline().getDisbursementDate()), dateCellStyle, dateFormat); } } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/serialization/FromJsonHelper.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/serialization/FromJsonHelper.java index 68949c896..239276d0b 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/serialization/FromJsonHelper.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/serialization/FromJsonHelper.java @@ -37,12 +37,14 @@ import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; +import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.apache.fineract.infrastructure.core.exception.InvalidJsonException; import org.apache.fineract.infrastructure.core.exception.UnsupportedParameterException; import org.springframework.context.annotation.Primary; import org.springframework.stereotype.Component; +@Slf4j @Primary @Component public class FromJsonHelper { diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/mapper/loan/LoanAccountDataMapper.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/mapper/loan/LoanAccountDataMapper.java index dd6007a2e..752af6587 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/mapper/loan/LoanAccountDataMapper.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/mapper/loan/LoanAccountDataMapper.java @@ -22,9 +22,15 @@ import org.apache.fineract.avro.loan.v1.LoanAccountDataV1; import org.apache.fineract.infrastructure.event.external.service.serialization.mapper.support.AvroMapperConfig; import org.apache.fineract.portfolio.loanaccount.data.LoanAccountData; import org.mapstruct.Mapper; +import org.mapstruct.Mapping; @Mapper(config = AvroMapperConfig.class) public interface LoanAccountDataMapper { + // TODO: avoid prefix "is" in class attributes; I would recommend to fix this also in the Avro structures + @Mapping(source = "loanProductLinkedToFloatingRate", target = "isLoanProductLinkedToFloatingRate") + @Mapping(source = "floatingInterestRate", target = "isFloatingInterestRate") + @Mapping(source = "topup", target = "isTopup") + @Mapping(source = "interestRecalculationEnabled", target = "isInterestRecalculationEnabled") LoanAccountDataV1 map(LoanAccountData source); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/data/CalendarData.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/data/CalendarData.java index e1295063a..aba4e210e 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/data/CalendarData.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/data/CalendarData.java @@ -24,8 +24,9 @@ import java.time.LocalTime; import java.time.OffsetDateTime; import java.util.Collection; import java.util.List; -import lombok.EqualsAndHashCode; -import lombok.Getter; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; import org.apache.fineract.infrastructure.core.data.EnumOptionData; import org.apache.fineract.portfolio.calendar.domain.CalendarFrequencyType; import org.apache.fineract.portfolio.calendar.domain.CalendarRemindBy; @@ -35,57 +36,55 @@ import org.apache.fineract.portfolio.calendar.service.CalendarEnumerations; import org.apache.fineract.portfolio.calendar.service.CalendarUtils; import org.apache.fineract.portfolio.common.domain.NthDayType; -/** - * Immutable data object representing a Calendar. - */ -@Getter -@EqualsAndHashCode +@Data +@NoArgsConstructor +@Accessors(chain = true) public final class CalendarData implements Serializable { - private final Long id; - private final Long calendarInstanceId; - private final Long entityId; - private final EnumOptionData entityType; + private Long id; + private Long calendarInstanceId; + private Long entityId; + private EnumOptionData entityType; private String title; - private final String description; - private final String location; - private final LocalDate startDate; - private final LocalDate endDate; - private final LocalTime meetingTime; - private final Integer duration; - private final EnumOptionData type; - private final boolean repeating; - private final String recurrence; - private final EnumOptionData frequency; - private final Integer interval; - private final EnumOptionData repeatsOnDay; - private final EnumOptionData repeatsOnNthDayOfMonth; - private final EnumOptionData remindBy; - private final Integer firstReminder; - private final Integer secondReminder; - private final Collection recurringDates; - private final Collection nextTenRecurringDates; - private final String humanReadable; - private final LocalDate recentEligibleMeetingDate; + private String description; + private String location; + private LocalDate startDate; + private LocalDate endDate; + private LocalTime meetingTime; + private Integer duration; + private EnumOptionData type; + private boolean repeating; + private String recurrence; + private EnumOptionData frequency; + private Integer interval; + private EnumOptionData repeatsOnDay; + private EnumOptionData repeatsOnNthDayOfMonth; + private EnumOptionData remindBy; + private Integer firstReminder; + private Integer secondReminder; + private Collection recurringDates; + private Collection nextTenRecurringDates; + private String humanReadable; + private LocalDate recentEligibleMeetingDate; - private final OffsetDateTime createdDate; - private final OffsetDateTime lastUpdatedDate; - private final Long createdByUserId; - private final String createdByUsername; - private final Long lastUpdatedByUserId; - private final String lastUpdatedByUsername; - private final Integer repeatsOnDayOfMonth; + private OffsetDateTime createdDate; + private OffsetDateTime lastUpdatedDate; + private Long createdByUserId; + private String createdByUsername; + private Long lastUpdatedByUserId; + private String lastUpdatedByUsername; + private Integer repeatsOnDayOfMonth; // template related - final List entityTypeOptions; - final List calendarTypeOptions; - final List remindByOptions; - final List frequencyOptions; - final List repeatsOnDayOptions; - final List frequencyNthDayTypeOptions; + private List entityTypeOptions; + private List calendarTypeOptions; + private List remindByOptions; + private List frequencyOptions; + private List repeatsOnDayOptions; + private List frequencyNthDayTypeOptions; // import fields - private transient Integer rowIndex; + private Integer rowIndex; private String dateFormat; private String locale; private String centerId; diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanApiConstants.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanApiConstants.java index 087c80acf..82962c8c1 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanApiConstants.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanApiConstants.java @@ -49,7 +49,7 @@ public interface LoanApiConstants { String rejectedOnDateParameterName = "rejectedOnDate"; String withdrawnOnDateParameterName = "withdrawnOnDate"; - String transactionProcessingStrategyIdParameterName = "transactionProcessingStrategyId"; + String transactionProcessingStrategyCodeParameterName = "transactionProcessingStrategyCode"; String loanPurposeIdParameterName = "loanPurposeId"; String loanOfficerIdParameterName = "loanOfficerId"; String fundIdParameterName = "fundId"; @@ -69,6 +69,7 @@ public interface LoanApiConstants { String interestCalculationPeriodTypeParameterName = "interestCalculationPeriodType"; String interestTypeParameterName = "interestType"; String amortizationTypeParameterName = "amortizationType"; + String amortizationTypeOptionsParameterName = "amortizationTypeOptions"; String repaymentFrequencyTypeParameterName = "repaymentFrequencyType"; String loanTermFrequencyTypeParameterName = "loanTermFrequencyType"; String loanTermFrequencyParameterName = "loanTermFrequency"; diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResource.java index 87be8ea40..8468e2e01 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResource.java @@ -32,6 +32,7 @@ import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; import java.io.InputStream; +import java.math.BigDecimal; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -102,6 +103,7 @@ import org.apache.fineract.portfolio.charge.service.ChargeReadPlatformService; import org.apache.fineract.portfolio.client.data.ClientData; import org.apache.fineract.portfolio.collateralmanagement.data.LoanCollateralResponseData; import org.apache.fineract.portfolio.collateralmanagement.service.LoanCollateralManagementReadPlatformService; +import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType; import org.apache.fineract.portfolio.delinquency.api.DelinquencyApiResourceSwagger; import org.apache.fineract.portfolio.delinquency.data.LoanDelinquencyTagHistoryData; import org.apache.fineract.portfolio.delinquency.service.DelinquencyReadPlatformService; @@ -121,6 +123,7 @@ import org.apache.fineract.portfolio.loanaccount.data.LoanTermVariationsData; import org.apache.fineract.portfolio.loanaccount.data.LoanTransactionData; import org.apache.fineract.portfolio.loanaccount.data.PaidInAdvanceData; import org.apache.fineract.portfolio.loanaccount.data.RepaymentScheduleRelatedLoanData; +import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus; import org.apache.fineract.portfolio.loanaccount.domain.LoanTermVariationType; import org.apache.fineract.portfolio.loanaccount.exception.LoanTemplateTypeRequiredException; import org.apache.fineract.portfolio.loanaccount.exception.NotSupportedLoanTemplateTypeException; @@ -191,7 +194,7 @@ import org.springframework.util.CollectionUtils; + "Example Values: 0=Daily, 1=Same as repayment period\n" + "allowPartialPeriodInterestCalcualtion\n" + "This value will be supported along with interestCalculationPeriodType as Same as repayment period to calculate interest for partial periods. Example: Interest charged from is 5th of April , Principal is 10000 and interest is 1% per month then the interest will be (10000 * 1%)* (25/30) , it calculates for the month first then calculates exact periods between start date and end date(can be a decimal)\n" + "inArrearsTolerance\n" + "The amount that can be 'waived' at end of all loan payments because it is too small to worry about.\n" - + "This is also the tolerance amount assessed when determining if a loan is in arrears.\n" + "transactionProcessingStrategyId\n" + + "This is also the tolerance amount assessed when determining if a loan is in arrears.\n" + "transactionProcessingStrategyCode\n" + "An enumeration that indicates the type of transaction processing strategy to be used. This relates to functionality that is also known as Payment Application Logic.\n" + "A number of out of the box approaches exist, some are custom to specific MFIs, some are more general and indicate the order in which payments are processed.\n" + "\n" @@ -213,7 +216,7 @@ public class LoansApiResource { "clientId", "group", "loanProductId", "loanProductName", "loanProductDescription", "isLoanProductLinkedToFloatingRate", "fundId", "fundName", "loanPurposeId", "loanPurposeName", "loanOfficerId", "loanOfficerName", "currency", "principal", "totalOverpaid", "inArrearsTolerance", "termFrequency", "termPeriodFrequencyType", "numberOfRepayments", "repaymentEvery", - "interestRatePerPeriod", "annualInterestRate", "repaymentFrequencyType", "transactionProcessingStrategyId", + "interestRatePerPeriod", "annualInterestRate", "repaymentFrequencyType", "transactionProcessingStrategyCode", "transactionProcessingStrategyName", "interestRateFrequencyType", "amortizationType", "interestType", "interestCalculationPeriodType", LoanProductConstants.ALLOW_PARTIAL_PERIOD_INTEREST_CALCUALTION_PARAM_NAME, "expectedFirstRepaymentOnDate", "graceOnPrincipalPayment", "recurringMoratoriumOnPrincipalPeriods", "graceOnInterestPayment", @@ -345,11 +348,15 @@ public class LoansApiResource { if (templateType.equals("individual") || templateType.equals("jlg")) { if (clientId == null) { - newLoanAccount = newLoanAccount == null ? LoanAccountData.emptyTemplate() : newLoanAccount; + newLoanAccount = newLoanAccount == null ? LoanAccountData.collateralTemplate(null) : newLoanAccount; } else { final LoanAccountData loanAccountClientDetails = this.loanReadPlatformService.retrieveClientDetailsTemplate(clientId); - officeId = loanAccountClientDetails.officeId(); + officeId = loanAccountClientDetails.getClientOfficeId(); + + if (officeId == null && loanAccountClientDetails.getGroup() != null) { + officeId = loanAccountClientDetails.getGroup().getOfficeId(); + } newLoanAccount = newLoanAccount == null ? loanAccountClientDetails : LoanAccountData.populateClientDefaults(newLoanAccount, loanAccountClientDetails); } @@ -364,7 +371,7 @@ public class LoansApiResource { } else if (templateType.equals("group")) { final LoanAccountData loanAccountGroupData = this.loanReadPlatformService.retrieveGroupDetailsTemplate(groupId); - officeId = loanAccountGroupData.groupOfficeId(); + officeId = loanAccountGroupData.getGroup() != null ? loanAccountGroupData.getGroup().getOfficeId() : null; calendarOptions = this.loanReadPlatformService.retrieveCalendars(groupId); newLoanAccount = newLoanAccount == null ? loanAccountGroupData : LoanAccountData.populateGroupDefaults(newLoanAccount, loanAccountGroupData); @@ -373,7 +380,7 @@ public class LoansApiResource { } else if (templateType.equals("jlgbulk")) { // get group details along with members in that group final LoanAccountData loanAccountGroupData = this.loanReadPlatformService.retrieveGroupAndMembersDetailsTemplate(groupId); - officeId = loanAccountGroupData.groupOfficeId(); + officeId = loanAccountGroupData.getGroup() != null ? loanAccountGroupData.getGroup().getOfficeId() : null; calendarOptions = this.loanReadPlatformService.retrieveCalendars(groupId); newLoanAccount = newLoanAccount == null ? loanAccountGroupData : LoanAccountData.populateGroupDefaults(newLoanAccount, loanAccountGroupData); @@ -471,7 +478,8 @@ public class LoansApiResource { loanBasicDetails = LoanAccountData.withInterestRecalculationCalendarData(loanBasicDetails, calendarData, compoundingCalendarData); } - if (loanBasicDetails.isMonthlyRepaymentFrequencyType()) { + if (loanBasicDetails.getRepaymentFrequencyType() != null + && loanBasicDetails.getRepaymentFrequencyType().getId().intValue() == PeriodFrequencyType.MONTHS.getValue()) { Collection loanCalendarDatas = this.calendarReadPlatformService.retrieveCalendarsByEntity(loanId, CalendarEntityType.LOANS.getValue(), null); CalendarData calendarData = null; @@ -542,9 +550,13 @@ public class LoansApiResource { if (associationParameters.contains(DataTableApiConstant.repaymentScheduleAssociateParamName)) { mandatoryResponseParameters.add(DataTableApiConstant.repaymentScheduleAssociateParamName); - final RepaymentScheduleRelatedLoanData repaymentScheduleRelatedData = loanBasicDetails.repaymentScheduleRelatedData(); + final RepaymentScheduleRelatedLoanData repaymentScheduleRelatedData = loanBasicDetails.getTimeline() + .repaymentScheduleRelatedData(loanBasicDetails.getCurrency(), loanBasicDetails.getPrincipal(), + loanBasicDetails.getApprovedPrincipal(), loanBasicDetails.getInArrearsTolerance(), + loanBasicDetails.getFeeChargesAtDisbursementCharged()); repaymentSchedule = this.loanReadPlatformService.retrieveRepaymentSchedule(loanId, repaymentScheduleRelatedData, - disbursementData, loanBasicDetails.isInterestRecalculationEnabled(), loanBasicDetails.getTotalPaidFeeCharges()); + disbursementData, loanBasicDetails.isInterestRecalculationEnabled(), + loanBasicDetails.getSummary() != null ? loanBasicDetails.getSummary().getFeeChargesPaid() : BigDecimal.ZERO); if (associationParameters.contains(DataTableApiConstant.futureScheduleAssociateParamName) && loanBasicDetails.isInterestRecalculationEnabled()) { @@ -553,7 +565,8 @@ public class LoansApiResource { } if (associationParameters.contains(DataTableApiConstant.originalScheduleAssociateParamName) - && loanBasicDetails.isInterestRecalculationEnabled() && loanBasicDetails.isActive()) { + && loanBasicDetails.isInterestRecalculationEnabled() + && LoanStatus.fromInt(loanBasicDetails.getStatus().getId().intValue()).isActive()) { mandatoryResponseParameters.add(DataTableApiConstant.originalScheduleAssociateParamName); LoanScheduleData loanScheduleData = this.loanScheduleHistoryReadPlatformService.retrieveRepaymentArchiveSchedule(loanId, repaymentScheduleRelatedData, disbursementData); @@ -597,7 +610,7 @@ public class LoansApiResource { if (associationParameters.contains(DataTableApiConstant.collectionAssociateParamName)) { mandatoryResponseParameters.add(DataTableApiConstant.collectionAssociateParamName); - if (loanBasicDetails.isActive()) { + if (LoanStatus.fromInt(loanBasicDetails.getStatus().getId().intValue()).isActive()) { collectionData = this.loanReadPlatformService.retrieveLoanCollectionData(loanId); } } @@ -655,8 +668,12 @@ public class LoansApiResource { } chargeTemplate = this.loanChargeReadPlatformService.retrieveLoanChargeTemplate(); - allowedLoanOfficers = this.loanReadPlatformService.retrieveAllowedLoanOfficers(loanBasicDetails.officeId(), - staffInSelectedOfficeOnly); + Long officeId = loanBasicDetails.getClientOfficeId(); + + if (officeId == null && loanBasicDetails.getGroup() != null) { + officeId = loanBasicDetails.getGroup().getOfficeId(); + } + allowedLoanOfficers = this.loanReadPlatformService.retrieveAllowedLoanOfficers(officeId, staffInSelectedOfficeOnly); loanPurposeOptions = this.codeValueReadPlatformService.retrieveCodeValuesByCode("LoanPurpose"); loanCollateralOptions = this.codeValueReadPlatformService.retrieveCodeValuesByCode("LoanCollateral"); @@ -674,8 +691,8 @@ public class LoansApiResource { mandatoryResponseParameters.add(DataTableApiConstant.linkedAccountAssociateParamName); linkedAccount = this.accountAssociationsReadPlatformService.retriveLoanLinkedAssociation(loanId); } - if (loanBasicDetails.groupId() != null) { - calendarOptions = this.loanReadPlatformService.retrieveCalendars(loanBasicDetails.groupId()); + if (loanBasicDetails.getGroup() != null && loanBasicDetails.getGroup().getId() != null) { + calendarOptions = this.loanReadPlatformService.retrieveCalendars(loanBasicDetails.getGroup().getId()); } if (loanBasicDetails.getProduct().isCanUseForTopup() && loanBasicDetails.getClientId() != null) { @@ -745,7 +762,7 @@ public class LoansApiResource { @Produces({ MediaType.APPLICATION_JSON }) @Operation(summary = "Calculate loan repayment schedule | Submit a new Loan Application", description = "It calculates the loan repayment Schedule\n" + "Submits a new loan application\n" - + "Mandatory Fields: clientId, productId, principal, loanTermFrequency, loanTermFrequencyType, loanType, numberOfRepayments, repaymentEvery, repaymentFrequencyType, interestRatePerPeriod, amortizationType, interestType, interestCalculationPeriodType, transactionProcessingStrategyId, expectedDisbursementDate, submittedOnDate, loanType\n" + + "Mandatory Fields: clientId, productId, principal, loanTermFrequency, loanTermFrequencyType, loanType, numberOfRepayments, repaymentEvery, repaymentFrequencyType, interestRatePerPeriod, amortizationType, interestType, interestCalculationPeriodType, transactionProcessingStrategyCode, expectedDisbursementDate, submittedOnDate, loanType\n" + "Optional Fields: graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, linkAccountId, allowPartialPeriodInterestCalcualtion, fixedEmiAmount, maxOutstandingLoanBalance, disbursementData, graceOnArrearsAgeing, createStandingInstructionAtDisbursement (requires linkedAccountId if set to true)\n" + "Additional Mandatory Fields if interest recalculation is enabled for product and Rest frequency not same as repayment period: recalculationRestFrequencyDate\n" + "Additional Mandatory Fields if interest recalculation with interest/fee compounding is enabled for product and compounding frequency not same as repayment period: recalculationCompoundingFrequencyDate\n" diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResourceSwagger.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResourceSwagger.java index 00be3eb35..1049893b2 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResourceSwagger.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResourceSwagger.java @@ -958,8 +958,8 @@ final class LoansApiResourceSwagger { public BigDecimal fixedPrincipalPercentagePerInstallment; public GetLoansLoanIdInterestType interestType; public GetLoansLoanIdInterestCalculationPeriodType interestCalculationPeriodType; - @Schema(example = "2") - public Integer transactionProcessingStrategyId; + @Schema(example = "mifos-standard-strategy") + public String transactionProcessingStrategyCode; public GetLoansLoanIdTimeline timeline; public GetLoansLoanIdSummary summary; public GetLoansLoanIdRepaymentSchedule repaymentSchedule; @@ -1033,8 +1033,8 @@ final class LoansApiResourceSwagger { public Integer interestCalculationPeriodType; @Schema(example = "20 September 2011") public String expectedDisbursementDate; - @Schema(example = "2") - public Integer transactionProcessingStrategyId; + @Schema(example = "mifos-standard-strategy") + public String transactionProcessingStrategyCode; @Schema(example = "360", allowableValues = "1, 360, 364, 36") public Integer daysInYearType; @Schema(example = "individual") @@ -1155,8 +1155,8 @@ final class LoansApiResourceSwagger { public BigDecimal fixedPrincipalPercentagePerInstallment; @Schema(example = "04 March 2014") public String expectedDisbursementDate; - @Schema(example = "1") - public Integer transactionProcessingStrategyId; + @Schema(example = "mifos-standard-strategy") + public String transactionProcessingStrategyCode; @Schema(example = "1") public Long linkAccountId; @Schema(example = "true") diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/CollectionData.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/CollectionData.java index 35c685311..37882f00e 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/CollectionData.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/CollectionData.java @@ -20,17 +20,23 @@ package org.apache.fineract.portfolio.loanaccount.data; import java.math.BigDecimal; import java.time.LocalDate; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; +@Data +@NoArgsConstructor +@Accessors(chain = true) public final class CollectionData { - private final BigDecimal availableDisbursementAmount; - private final int pastDueDays; - private final LocalDate nextPaymentDueDate; - private final int delinquentDays; - private final LocalDate delinquentDate; - private final BigDecimal delinquentAmount; - private final LocalDate lastPaymentDate; - private final BigDecimal lastPaymentAmount; + private BigDecimal availableDisbursementAmount; + private int pastDueDays; + private LocalDate nextPaymentDueDate; + private int delinquentDays; + private LocalDate delinquentDate; + private BigDecimal delinquentAmount; + private LocalDate lastPaymentDate; + private BigDecimal lastPaymentAmount; private CollectionData(BigDecimal availableDisbursementAmount, int pastDueDays, LocalDate nextPaymentDueDate, int delinquentDays, LocalDate delinquentDate, BigDecimal delinquentAmount, LocalDate lastPaymentDate, BigDecimal lastPaymentAmount) { @@ -55,36 +61,4 @@ public final class CollectionData { final BigDecimal zero = BigDecimal.ZERO; return new CollectionData(zero, 0, null, 0, null, zero, null, zero); } - - public BigDecimal getAvailableDisbursementAmount() { - return availableDisbursementAmount; - } - - public int getPastDueDays() { - return pastDueDays; - } - - public LocalDate getNextPaymentDueDate() { - return nextPaymentDueDate; - } - - public int getDelinquentDays() { - return delinquentDays; - } - - public LocalDate getDelinquentDate() { - return delinquentDate; - } - - public BigDecimal getDelinquentAmount() { - return delinquentAmount; - } - - public LocalDate getLastPaymentDate() { - return lastPaymentDate; - } - - public BigDecimal getLastPaymentAmount() { - return lastPaymentAmount; - } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanAccountData.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanAccountData.java index 43c36eefb..98769f2bc 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanAccountData.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanAccountData.java @@ -28,7 +28,9 @@ import java.util.List; import java.util.Locale; import java.util.Map; import javax.persistence.Transient; -import lombok.Getter; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; import org.apache.fineract.infrastructure.codes.data.CodeValueData; import org.apache.fineract.infrastructure.core.data.EnumOptionData; import org.apache.fineract.infrastructure.dataqueries.data.DatatableData; @@ -38,12 +40,10 @@ import org.apache.fineract.portfolio.account.data.PortfolioAccountData; import org.apache.fineract.portfolio.accountdetails.data.LoanAccountSummaryData; import org.apache.fineract.portfolio.calendar.data.CalendarData; import org.apache.fineract.portfolio.charge.data.ChargeData; -import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType; import org.apache.fineract.portfolio.delinquency.data.DelinquencyRangeData; import org.apache.fineract.portfolio.floatingrates.data.InterestRatePeriodData; import org.apache.fineract.portfolio.fund.data.FundData; import org.apache.fineract.portfolio.group.data.GroupGeneralData; -import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus; import org.apache.fineract.portfolio.loanaccount.guarantor.data.GuarantorData; import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanScheduleData; import org.apache.fineract.portfolio.loanproduct.data.LoanProductBorrowerCycleVariationData; @@ -52,182 +52,186 @@ import org.apache.fineract.portfolio.loanproduct.data.TransactionProcessingStrat import org.apache.fineract.portfolio.loanproduct.domain.LoanProductValueConditionType; import org.apache.fineract.portfolio.note.data.NoteData; import org.apache.fineract.portfolio.rate.data.RateData; -import org.springframework.util.CollectionUtils; -/** - * Immutable data object representing loan account data. - */ -@Getter -public final class LoanAccountData { +@Data +@NoArgsConstructor +@Accessors(chain = true) +public class LoanAccountData { // basic loan details // identity - private final Long id; - private final String accountNo; - private final String externalId; + private Long id; + private String accountNo; + private String externalId; // status - private final LoanStatusEnumData status; - private final EnumOptionData subStatus; + private LoanStatusEnumData status; + private EnumOptionData subStatus; // related to - private final Long clientId; - private final String clientAccountNo; - private final String clientName; - private final String clientExternalId; - private final Long clientOfficeId; - private final GroupGeneralData group; - private final Long loanProductId; - private final String loanProductName; - private final String loanProductDescription; - private final boolean isLoanProductLinkedToFloatingRate; - private final Long fundId; - private final String fundName; - private final Long loanPurposeId; - private final String loanPurposeName; - private final Long loanOfficerId; - private final String loanOfficerName; - private final EnumOptionData loanType; + private Long clientId; + private String clientAccountNo; + private String clientName; + private String clientExternalId; + private Long clientOfficeId; + private GroupGeneralData group; + private Long loanProductId; + private String loanProductName; + private String loanProductDescription; + // TODO: avoid prefix "is" + private boolean isLoanProductLinkedToFloatingRate; + private Long fundId; + private String fundName; + private Long loanPurposeId; + private String loanPurposeName; + private Long loanOfficerId; + private String loanOfficerName; + private EnumOptionData loanType; // terms - private final CurrencyData currency; - private final BigDecimal principal; - private final BigDecimal approvedPrincipal; - private final BigDecimal proposedPrincipal; - private final BigDecimal netDisbursalAmount; + private CurrencyData currency; + private BigDecimal principal; + private BigDecimal approvedPrincipal; + private BigDecimal proposedPrincipal; + private BigDecimal netDisbursalAmount; - private final Integer termFrequency; - private final EnumOptionData termPeriodFrequencyType; - private final Integer numberOfRepayments; - private final Integer repaymentEvery; - private final EnumOptionData repaymentFrequencyType; - private final EnumOptionData repaymentFrequencyNthDayType; - private final EnumOptionData repaymentFrequencyDayOfWeekType; - private final BigDecimal interestRatePerPeriod; - private final EnumOptionData interestRateFrequencyType; - private final BigDecimal annualInterestRate; - private final boolean isFloatingInterestRate; - private final BigDecimal interestRateDifferential; + private Integer termFrequency; + private EnumOptionData termPeriodFrequencyType; + private Integer numberOfRepayments; + private Integer repaymentEvery; + private EnumOptionData repaymentFrequencyType; + private EnumOptionData repaymentFrequencyNthDayType; + private EnumOptionData repaymentFrequencyDayOfWeekType; + private BigDecimal interestRatePerPeriod; + private EnumOptionData interestRateFrequencyType; + private BigDecimal annualInterestRate; + // TODO: avoid prefix "is" + private boolean isFloatingInterestRate; + private BigDecimal interestRateDifferential; // settings - private final EnumOptionData amortizationType; - private final EnumOptionData interestType; - private final EnumOptionData interestCalculationPeriodType; - private final Boolean allowPartialPeriodInterestCalculation; - private final BigDecimal inArrearsTolerance; - private final Long transactionProcessingStrategyId; - private final String transactionProcessingStrategyName; - private final Integer graceOnPrincipalPayment; - private final Integer recurringMoratoriumOnPrincipalPeriods; - private final Integer graceOnInterestPayment; - private final Integer graceOnInterestCharged; - private final Integer graceOnArrearsAgeing; - private final LocalDate interestChargedFromDate; - private final LocalDate expectedFirstRepaymentOnDate; - private final Boolean syncDisbursementWithMeeting; - private final Boolean disallowExpectedDisbursements; + private EnumOptionData amortizationType; + private EnumOptionData interestType; + private EnumOptionData interestCalculationPeriodType; + private Boolean allowPartialPeriodInterestCalculation; + private BigDecimal inArrearsTolerance; + private String transactionProcessingStrategyCode; + private String transactionProcessingStrategyName; + private Integer graceOnPrincipalPayment; + private Integer recurringMoratoriumOnPrincipalPeriods; + private Integer graceOnInterestPayment; + private Integer graceOnInterestCharged; + private Integer graceOnArrearsAgeing; + private LocalDate interestChargedFromDate; + private LocalDate expectedFirstRepaymentOnDate; + private Boolean syncDisbursementWithMeeting; + private Boolean disallowExpectedDisbursements; // timeline - private final LoanApplicationTimelineData timeline; + private LoanApplicationTimelineData timeline; // totals - private final LoanSummaryData summary; + private LoanSummaryData summary; // associations - private final LoanScheduleData repaymentSchedule; - private final Collection transactions; - private final Collection charges; - private final Collection collateral; - private final Collection guarantors; - private final CalendarData meeting; - private final Collection notes; - private final Collection disbursementDetails; - private final LoanScheduleData originalSchedule; + private LoanScheduleData repaymentSchedule; + private Collection transactions; + private Collection charges; + private Collection collateral; + private Collection guarantors; + private CalendarData meeting; + private Collection notes; + private Collection disbursementDetails; + private LoanScheduleData originalSchedule; // template - private final Collection productOptions; - private final Collection loanOfficerOptions; - private final Collection loanPurposeOptions; - private final Collection fundOptions; - private final Collection termFrequencyTypeOptions; - private final Collection repaymentFrequencyTypeOptions; - private final Collection repaymentFrequencyNthDayTypeOptions; - private final Collection repaymentFrequencyDaysOfWeekTypeOptions; + private Collection productOptions; + private Collection loanOfficerOptions; + private Collection loanPurposeOptions; + private Collection fundOptions; + private Collection termFrequencyTypeOptions; + private Collection repaymentFrequencyTypeOptions; + private Collection repaymentFrequencyNthDayTypeOptions; + private Collection repaymentFrequencyDaysOfWeekTypeOptions; - private final Collection interestRateFrequencyTypeOptions; - private final Collection amortizationTypeOptions; - private final Collection interestTypeOptions; - private final Collection interestCalculationPeriodTypeOptions; - private final Collection transactionProcessingStrategyOptions; - private final Collection chargeOptions; - private final Collection loanCollateralOptions; - private final Collection calendarOptions; + private Collection interestRateFrequencyTypeOptions; + private Collection amortizationTypeOptions; + private Collection interestTypeOptions; + private Collection interestCalculationPeriodTypeOptions; + private Collection transactionProcessingStrategyOptions; + private Collection chargeOptions; + private Collection loanCollateralOptions; + private Collection calendarOptions; @Transient - private final BigDecimal feeChargesAtDisbursementCharged; - private final BigDecimal totalOverpaid; + private BigDecimal feeChargesAtDisbursementCharged; + private BigDecimal totalOverpaid; // loanCycle - private final Integer loanCounter; - private final Integer loanProductCounter; + private Integer loanCounter; + private Integer loanProductCounter; // linkable account details - private final PortfolioAccountData linkedAccount; - private final Collection accountLinkingOptions; + private PortfolioAccountData linkedAccount; + private Collection accountLinkingOptions; - private final Boolean multiDisburseLoan; + private Boolean multiDisburseLoan; - private final Boolean canDefineInstallmentAmount; + private Boolean canDefineInstallmentAmount; - private final BigDecimal fixedEmiAmount; + private BigDecimal fixedEmiAmount; - private final BigDecimal maxOutstandingLoanBalance; + private BigDecimal maxOutstandingLoanBalance; - private final Boolean canDisburse; + private Boolean canDisburse; - private final Collection emiAmountVariations; - private final Collection clientActiveLoanOptions; - private final Boolean canUseForTopup; - private final boolean isTopup; - private final boolean fraud; - private final Long closureLoanId; - private final String closureLoanAccountNo; - private final BigDecimal topupAmount; + private Collection emiAmountVariations; + private Collection clientActiveLoanOptions; + private Boolean canUseForTopup; + // TODO: avoid prefix "is" + private boolean isTopup; + private boolean fraud; + private Long closureLoanId; + private String closureLoanAccountNo; + private BigDecimal topupAmount; private LoanProductData product; - private final Map memberVariations; + private Map memberVariations; - private final Boolean inArrears; + private Boolean inArrears; + // TODO: avoid prefix "is" + private Boolean isNPA; + private Collection overdueCharges; - private final Boolean isNPA; + private EnumOptionData daysInMonthType; + private EnumOptionData daysInYearType; + // TODO: avoid prefix "is" + private boolean isInterestRecalculationEnabled; - private final Collection overdueCharges; - - private final EnumOptionData daysInMonthType; - private final EnumOptionData daysInYearType; - private final boolean isInterestRecalculationEnabled; - - private final LoanInterestRecalculationData interestRecalculationData; - private final Boolean createStandingInstructionAtDisbursement; + private LoanInterestRecalculationData interestRecalculationData; + private Boolean createStandingInstructionAtDisbursement; // Paid In Advance - private final PaidInAdvanceData paidInAdvance; + private PaidInAdvanceData paidInAdvance; - private final Collection interestRatesPeriods; + private Collection interestRatesPeriods; // VariableInstallments - private final Boolean isVariableInstallmentsAllowed; - private final Integer minimumGap; - private final Integer maximumGap; + // TODO: avoid prefix "is" + private Boolean isVariableInstallmentsAllowed; + private Integer minimumGap; + private Integer maximumGap; private List datatables = null; - private final Boolean isEqualAmortization; - private final BigDecimal fixedPrincipalPercentagePerInstallment; + // TODO: avoid prefix "is" + private Boolean isEqualAmortization; + private BigDecimal fixedPrincipalPercentagePerInstallment; // Rate - private final List rates; - private final Boolean isRatesEnabled; + private List rates; + // TODO: avoid prefix "is" + private Boolean isRatesEnabled; // import fields private String dateFormat; @@ -242,25 +246,32 @@ public final class LoanAccountData { private Long groupId; private LocalDate expectedDisbursementDate; - private final CollectionData delinquent; - private final DelinquencyRangeData delinquencyRange; + private CollectionData delinquent; + private DelinquencyRangeData delinquencyRange; public static LoanAccountData importInstanceIndividual(EnumOptionData loanTypeEnumOption, Long clientId, Long productId, Long loanOfficerId, LocalDate submittedOnDate, Long fundId, BigDecimal principal, Integer numberOfRepayments, Integer repaymentEvery, EnumOptionData repaidEveryFrequencyEnums, Integer loanTermFrequency, EnumOptionData loanTermFrequencyTypeEnum, BigDecimal nominalInterestRate, LocalDate expectedDisbursementDate, EnumOptionData amortizationEnumOption, EnumOptionData interestMethodEnum, EnumOptionData interestCalculationPeriodTypeEnum, - BigDecimal inArrearsTolerance, Long transactionProcessingStrategyId, Integer graceOnPrincipalPayment, + BigDecimal inArrearsTolerance, String transactionProcessingStrategyCode, Integer graceOnPrincipalPayment, Integer graceOnInterestPayment, Integer graceOnInterestCharged, LocalDate interestChargedFromDate, LocalDate repaymentsStartingFromDate, Integer rowIndex, String externalId, Long groupId, Collection charges, String linkAccountId, String locale, String dateFormat, List loanCollateralManagementData) { - return new LoanAccountData(loanTypeEnumOption, clientId, productId, loanOfficerId, submittedOnDate, fundId, principal, - numberOfRepayments, repaymentEvery, repaidEveryFrequencyEnums, loanTermFrequency, loanTermFrequencyTypeEnum, - nominalInterestRate, expectedDisbursementDate, amortizationEnumOption, interestMethodEnum, - interestCalculationPeriodTypeEnum, inArrearsTolerance, transactionProcessingStrategyId, graceOnPrincipalPayment, - graceOnInterestPayment, graceOnInterestCharged, interestChargedFromDate, repaymentsStartingFromDate, rowIndex, externalId, - null, charges, linkAccountId, locale, dateFormat, loanCollateralManagementData); + return new LoanAccountData().setLoanType(loanTypeEnumOption).setClientId(clientId).setProductId(productId) + .setLoanOfficerId(loanOfficerId).setSubmittedOnDate(submittedOnDate).setFundId(fundId).setPrincipal(principal) + .setNumberOfRepayments(numberOfRepayments).setRepaymentEvery(repaymentEvery) + .setRepaymentFrequencyType(repaidEveryFrequencyEnums).setLoanTermFrequency(loanTermFrequency) + .setLoanTermFrequencyType(loanTermFrequencyTypeEnum).setInterestRatePerPeriod(nominalInterestRate) + .setExpectedDisbursementDate(expectedDisbursementDate).setAmortizationType(amortizationEnumOption) + .setInterestType(interestMethodEnum).setInterestCalculationPeriodType(interestCalculationPeriodTypeEnum) + .setInArrearsTolerance(inArrearsTolerance).setTransactionProcessingStrategyCode(transactionProcessingStrategyCode) + .setGraceOnPrincipalPayment(graceOnPrincipalPayment).setGraceOnInterestPayment(graceOnInterestPayment) + .setGraceOnInterestCharged(graceOnInterestCharged).setInterestChargedFromDate(interestChargedFromDate) + .setRepaymentsStartingFromDate(repaymentsStartingFromDate).setRowIndex(rowIndex).setExternalId(externalId) + .setGroupId(groupId).setCharges(charges).setLinkAccountId(linkAccountId).setLocale(locale).setDateFormat(dateFormat) + .setCollateral(loanCollateralManagementData); } public static LoanAccountData importInstanceGroup(EnumOptionData loanTypeEnumOption, Long groupIdforGroupLoan, Long productId, @@ -268,334 +279,31 @@ public final class LoanAccountData { Integer repaidEvery, EnumOptionData repaidEveryFrequencyEnums, Integer loanTermFrequency, EnumOptionData loanTermFrequencyTypeEnum, BigDecimal nominalInterestRate, EnumOptionData amortizationEnumOption, EnumOptionData interestMethodEnum, EnumOptionData interestCalculationPeriodEnum, BigDecimal arrearsTolerance, - Long transactionProcessingStrategyId, Integer graceOnPrincipalPayment, Integer graceOnInterestPayment, + String transactionProcessingStrategyCode, Integer graceOnPrincipalPayment, Integer graceOnInterestPayment, Integer graceOnInterestCharged, LocalDate interestChargedFromDate, LocalDate repaymentsStartingFromDate, Integer rowIndex, String externalId, String linkAccountId, String locale, String dateFormat) { - return new LoanAccountData(loanTypeEnumOption, groupIdforGroupLoan, productId, loanOfficerId, submittedOnDate, fundId, principal, - numberOfRepayments, repaidEvery, repaidEveryFrequencyEnums, loanTermFrequency, loanTermFrequencyTypeEnum, - nominalInterestRate, null, amortizationEnumOption, interestMethodEnum, interestCalculationPeriodEnum, arrearsTolerance, - transactionProcessingStrategyId, graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, - interestChargedFromDate, repaymentsStartingFromDate, rowIndex, externalId, null, null, linkAccountId, locale, dateFormat, - null); + return new LoanAccountData().setLoanType(loanTypeEnumOption).setGroupId(groupIdforGroupLoan).setProductId(productId) + .setLoanOfficerId(loanOfficerId).setSubmittedOnDate(submittedOnDate).setFundId(fundId).setPrincipal(principal) + .setNumberOfRepayments(numberOfRepayments).setRepaymentEvery(repaidEvery) + .setRepaymentFrequencyType(repaidEveryFrequencyEnums).setLoanTermFrequency(loanTermFrequency) + .setLoanTermFrequencyType(loanTermFrequencyTypeEnum).setInterestRatePerPeriod(nominalInterestRate) + .setAmortizationTypeOptions(List.of(amortizationEnumOption)).setInterestType(interestMethodEnum) + .setInterestCalculationPeriodType(interestCalculationPeriodEnum).setInArrearsTolerance(arrearsTolerance) + .setTransactionProcessingStrategyCode(transactionProcessingStrategyCode).setGraceOnPrincipalPayment(graceOnPrincipalPayment) + .setGraceOnInterestPayment(graceOnInterestPayment).setGraceOnInterestCharged(graceOnInterestCharged) + .setInterestChargedFromDate(interestChargedFromDate).setRepaymentsStartingFromDate(repaymentsStartingFromDate) + .setRowIndex(rowIndex).setExternalId(externalId).setLinkAccountId(linkAccountId).setLocale(locale) + .setDateFormat(dateFormat); } - private LoanAccountData(EnumOptionData loanType, Long clientId, Long productId, Long loanOfficerId, LocalDate submittedOnDate, - Long fundId, BigDecimal principal, Integer numberOfRepayments, Integer repaymentEvery, EnumOptionData repaymentFrequencyType, - Integer loanTermFrequency, EnumOptionData loanTermFrequencyType, BigDecimal interestRatePerPeriod, - LocalDate expectedDisbursementDate, EnumOptionData amortizationType, EnumOptionData interestType, - EnumOptionData interestCalculationPeriodType, BigDecimal inArrearsTolerance, Long transactionProcessingStrategyId, - Integer graceOnPrincipalPayment, Integer graceOnInterestPayment, Integer graceOnInterestCharged, - LocalDate interestChargedFromDate, LocalDate repaymentsStartingFromDate, Integer rowIndex, String externalId, Long groupId, - Collection charges, String linkAccountId, String locale, String dateFormat, - Collection loanCollateralManagementData) { - this.dateFormat = dateFormat; - this.locale = locale; - this.rowIndex = rowIndex; - this.submittedOnDate = submittedOnDate; - this.productId = productId; - this.loanTermFrequency = loanTermFrequency; - this.loanTermFrequencyType = loanTermFrequencyType; - this.repaymentsStartingFromDate = repaymentsStartingFromDate; - this.linkAccountId = linkAccountId; - this.externalId = externalId; - this.clientId = clientId; - this.fundId = fundId; - this.loanOfficerId = loanOfficerId; - this.numberOfRepayments = numberOfRepayments; - this.loanType = loanType; - this.principal = principal; - this.repaymentEvery = repaymentEvery; - this.repaymentFrequencyType = repaymentFrequencyType; - this.interestRatePerPeriod = interestRatePerPeriod; - this.amortizationType = amortizationType; - this.interestType = interestType; - this.interestCalculationPeriodType = interestCalculationPeriodType; - this.inArrearsTolerance = inArrearsTolerance; - this.transactionProcessingStrategyId = transactionProcessingStrategyId; - this.graceOnInterestPayment = graceOnInterestPayment; - this.graceOnInterestCharged = graceOnInterestCharged; - this.graceOnPrincipalPayment = graceOnPrincipalPayment; - this.interestChargedFromDate = interestChargedFromDate; - this.groupId = groupId; - this.expectedDisbursementDate = expectedDisbursementDate; - this.charges = charges; - this.rates = null; - this.id = null; - this.accountNo = null; - - this.status = null; - this.subStatus = null; - - this.clientAccountNo = null; - this.clientName = null; - this.clientOfficeId = null; - this.clientExternalId = null; - this.group = null; - this.loanProductId = null; - this.loanProductName = null; - this.loanProductDescription = null; - this.isLoanProductLinkedToFloatingRate = false; - - this.fundName = null; - this.loanPurposeId = null; - this.loanPurposeName = null; - - this.loanOfficerName = null; - - this.currency = null; - - this.approvedPrincipal = null; - this.proposedPrincipal = null; - this.netDisbursalAmount = null; - this.termFrequency = null; - this.termPeriodFrequencyType = null; - - this.repaymentFrequencyNthDayType = null; - this.repaymentFrequencyDayOfWeekType = null; - - this.interestRateFrequencyType = null; - this.annualInterestRate = null; - this.isFloatingInterestRate = false; - this.interestRateDifferential = null; - - this.allowPartialPeriodInterestCalculation = null; - - this.transactionProcessingStrategyName = null; - - this.recurringMoratoriumOnPrincipalPeriods = null; - - this.graceOnArrearsAgeing = null; - - this.expectedFirstRepaymentOnDate = null; - this.syncDisbursementWithMeeting = null; - this.timeline = null; - this.summary = null; - this.repaymentSchedule = null; - this.transactions = null; - - this.collateral = loanCollateralManagementData; - this.guarantors = null; - this.meeting = null; - this.notes = null; - this.disbursementDetails = null; - this.originalSchedule = null; - this.productOptions = null; - this.loanOfficerOptions = null; - this.loanPurposeOptions = null; - this.fundOptions = null; - this.termFrequencyTypeOptions = null; - this.repaymentFrequencyTypeOptions = null; - this.repaymentFrequencyNthDayTypeOptions = null; - this.repaymentFrequencyDaysOfWeekTypeOptions = null; - this.interestRateFrequencyTypeOptions = null; - this.amortizationTypeOptions = null; - this.interestTypeOptions = null; - this.interestCalculationPeriodTypeOptions = null; - this.transactionProcessingStrategyOptions = null; - this.chargeOptions = null; - this.loanCollateralOptions = null; - this.calendarOptions = null; - this.feeChargesAtDisbursementCharged = null; - this.totalOverpaid = null; - this.loanCounter = null; - this.loanProductCounter = null; - this.linkedAccount = null; - this.accountLinkingOptions = null; - this.multiDisburseLoan = null; - this.canDefineInstallmentAmount = null; - this.fixedEmiAmount = null; - this.maxOutstandingLoanBalance = null; - this.canDisburse = null; - this.emiAmountVariations = null; - this.clientActiveLoanOptions = null; - this.canUseForTopup = null; - this.isTopup = false; - this.closureLoanId = null; - this.closureLoanAccountNo = null; - this.topupAmount = null; - this.memberVariations = null; - this.inArrears = null; - this.isNPA = null; - this.overdueCharges = null; - this.daysInMonthType = null; - this.daysInYearType = null; - this.isInterestRecalculationEnabled = false; - this.interestRecalculationData = null; - this.createStandingInstructionAtDisbursement = null; - this.paidInAdvance = null; - this.interestRatesPeriods = null; - this.isVariableInstallmentsAllowed = null; - this.minimumGap = null; - this.maximumGap = null; - this.isEqualAmortization = null; - this.isRatesEnabled = false; - this.fixedPrincipalPercentagePerInstallment = null; - this.delinquent = null; - this.delinquencyRange = null; - this.disallowExpectedDisbursements = false; - this.fraud = false; - } - - public static final Comparator ClientNameComparator = new Comparator() { - - @Override - public int compare(LoanAccountData loan1, LoanAccountData loan2) { - String clientOfLoan1 = loan1.getClientName().toUpperCase(Locale.ENGLISH); - String clientOfLoan2 = loan2.getClientName().toUpperCase(Locale.ENGLISH); - return clientOfLoan1.compareTo(clientOfLoan2); - } - }; - /** * Used to produce a {@link LoanAccountData} with only collateral options for now. */ public static LoanAccountData collateralTemplate(final Collection loanCollateralOptions) { - final Long id = null; - final String accountNo = null; - final LoanStatusEnumData status = null; - final EnumOptionData subStatus = null; - final String externalId = null; - final Long clientId = null; - final String clientName = null; - final String clientAccountNo = null; - final Long clientOfficeId = null; - final String clientExternalId = null; - final GroupGeneralData group = null; - final EnumOptionData loanType = null; - final Long loanProductId = null; - final String loanProductName = null; - final String loanProductDescription = null; - final boolean isLoanProductLinkedToFloatingRate = false; - final Long fundId = null; - final String fundName = null; - final Long loanPurposeId = null; - final String loanPurposeName = null; - final Long loanOfficerId = null; - final String loanOfficerName = null; - final CurrencyData currencyData = null; - final BigDecimal proposedPrincipal = null; - final BigDecimal principal = null; - final BigDecimal netDisbursalAmount = null; - final BigDecimal totalOverpaid = null; - final BigDecimal inArrearsTolerance = null; - final Integer termFrequency = null; - final EnumOptionData termPeriodFrequencyType = null; - final Integer numberOfRepayments = null; - final Integer repaymentEvery = null; - final EnumOptionData repaymentFrequencyType = null; - final EnumOptionData repaymentFrequencyNthDayType = null; - final EnumOptionData repaymentFrequencyDayOfWeekType = null; - final Long transactionProcessingStrategyId = null; - final String transactionProcessingStrategyName = null; - final EnumOptionData amortizationType = null; - final BigDecimal interestRatePerPeriod = null; - final EnumOptionData interestRateFrequencyType = null; - final BigDecimal annualInterestRate = null; - final EnumOptionData interestType = null; - final boolean isFloatingInterestRate = false; - final BigDecimal interestRateDifferential = null; - final EnumOptionData interestCalculationPeriodType = null; - final Boolean allowPartialPeriodInterestCalcualtion = null; - final LocalDate expectedFirstRepaymentOnDate = null; - final Integer graceOnPrincipalPayment = null; - final Integer recurringMoratoriumOnPrincipalPeriods = null; - final Integer graceOnInterestPayment = null; - final Integer graceOnInterestCharged = null; - final Integer graceOnArrearsAgeing = null; - final LocalDate interestChargedFromDate = null; - final LoanApplicationTimelineData timeline = null; - final LoanSummaryData summary = null; - final BigDecimal feeChargesDueAtDisbursementCharged = null; - final LoanScheduleData repaymentSchedule = null; - final Collection transactions = null; - final Collection charges = null; - final Collection collateral = null; - final Collection guarantors = null; - final Collection notes = null; - final CalendarData calendarData = null; - final Collection productOptions = null; - final Collection termFrequencyTypeOptions = null; - final Collection repaymentFrequencyTypeOptions = null; - final Collection repaymentFrequencyNthDayTypeOptions = null; - final Collection repaymentFrequencyDayOfWeekTypeOptions = null; - final Collection transactionProcessingStrategyOptions = null; - final Collection interestRateFrequencyTypeOptions = null; - final Collection amortizationTypeOptions = null; - final Collection interestTypeOptions = null; - final Collection interestCalculationPeriodTypeOptions = null; - final Collection fundOptions = null; - final Collection chargeOptions = null; - final ChargeData chargeTemplate = null; - final Collection loanOfficerOptions = null; - final Collection loanPurposeOptions = null; - final Collection calendarOptions = null; - final Boolean syncDisbursementWithMeeting = null; - final Integer loancounter = null; - final Integer loanProductCounter = null; - final Collection accountLinkingOptions = null; - final PortfolioAccountData linkedAccount = null; - final Collection disbursementData = null; - final Boolean multiDisburseLoan = null; - final Boolean canDefineInstallmentAmount = null; - final BigDecimal fixedEmiAmount = null; - final BigDecimal maxOutstandingLoanBalance = null; - final Collection emiAmountVariations = null; - final Map memberVariations = null; - final LoanProductData product = null; - final Boolean inArrears = null; - final Boolean isNPA = null; - final Collection overdueCharges = null; - - final EnumOptionData daysInMonthType = null; - final EnumOptionData daysInYearType = null; - final boolean isInterestRecalculationEnabled = false; - final LoanInterestRecalculationData interestRecalculationData = null; - final LoanScheduleData originalSchedule = null; - final Boolean createStandingInstructionAtDisbursement = null; - final PaidInAdvanceData paidInAdvance = null; - final Collection interestRatesPeriods = null; - final Boolean isVariableInstallmentsAllowed = Boolean.FALSE; - final Integer minimumGap = null; - final Integer maximumGap = null; - final Boolean canUseForTopup = null; - final Collection clientActiveLoanOptions = null; - final boolean isTopup = false; - final Long closureLoanId = null; - final String closureLoanAccountNo = null; - final BigDecimal topupAmount = null; - final boolean isEqualAmortization = false; - final List rates = null; - final Boolean isRatesEnabled = false; - final BigDecimal fixedPrincipalPercentagePerInstallment = null; - final CollectionData delinquent = CollectionData.template(); - final DelinquencyRangeData delinquencyRange = null; - final Boolean disallowExpectedDisbursements = false; - final boolean fraud = false; - - return new LoanAccountData(id, accountNo, status, externalId, clientId, clientAccountNo, clientName, clientOfficeId, - clientExternalId, group, loanType, loanProductId, loanProductName, loanProductDescription, - isLoanProductLinkedToFloatingRate, fundId, fundName, loanPurposeId, loanPurposeName, loanOfficerId, loanOfficerName, - currencyData, proposedPrincipal, principal, principal, netDisbursalAmount, totalOverpaid, inArrearsTolerance, termFrequency, - termPeriodFrequencyType, numberOfRepayments, repaymentEvery, repaymentFrequencyType, repaymentFrequencyNthDayType, - repaymentFrequencyDayOfWeekType, transactionProcessingStrategyId, transactionProcessingStrategyName, amortizationType, - interestRatePerPeriod, interestRateFrequencyType, annualInterestRate, interestType, isFloatingInterestRate, - interestRateDifferential, interestCalculationPeriodType, allowPartialPeriodInterestCalcualtion, - expectedFirstRepaymentOnDate, graceOnPrincipalPayment, recurringMoratoriumOnPrincipalPeriods, graceOnInterestPayment, - graceOnInterestCharged, interestChargedFromDate, timeline, summary, feeChargesDueAtDisbursementCharged, repaymentSchedule, - transactions, charges, collateral, guarantors, calendarData, productOptions, termFrequencyTypeOptions, - repaymentFrequencyTypeOptions, repaymentFrequencyNthDayTypeOptions, repaymentFrequencyDayOfWeekTypeOptions, - transactionProcessingStrategyOptions, interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions, - interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions, loanPurposeOptions, - loanCollateralOptions, calendarOptions, syncDisbursementWithMeeting, loancounter, loanProductCounter, notes, - accountLinkingOptions, linkedAccount, disbursementData, multiDisburseLoan, canDefineInstallmentAmount, fixedEmiAmount, - maxOutstandingLoanBalance, emiAmountVariations, memberVariations, product, inArrears, graceOnArrearsAgeing, overdueCharges, - isNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled, interestRecalculationData, originalSchedule, - createStandingInstructionAtDisbursement, paidInAdvance, interestRatesPeriods, isVariableInstallmentsAllowed, minimumGap, - maximumGap, subStatus, canUseForTopup, clientActiveLoanOptions, isTopup, closureLoanId, closureLoanAccountNo, topupAmount, - isEqualAmortization, rates, isRatesEnabled, fixedPrincipalPercentagePerInstallment, delinquent, delinquencyRange, - disallowExpectedDisbursements, fraud); + return new LoanAccountData().setIsVariableInstallmentsAllowed(false).setDelinquent(CollectionData.template()) + .setLoanCollateralOptions(loanCollateralOptions); } /** @@ -603,181 +311,72 @@ public final class LoanAccountData { */ public static LoanAccountData clientDefaults(final Long clientId, final String clientAccountNo, final String clientName, final Long clientOfficeId, final String clientExternalId, final LocalDate expectedDisbursementDate) { - final Long id = null; - final String accountNo = null; - final LoanStatusEnumData status = null; - final EnumOptionData subStatus = null; - final String externalId = null; - final GroupGeneralData group = null; - final EnumOptionData loanType = null; - final String groupName = null; - final Long loanProductId = null; - final String loanProductName = null; - final String loanProductDescription = null; - final boolean isLoanProductLinkedToFloatingRate = false; - final Long fundId = null; - final String fundName = null; - final Long loanPurposeId = null; - final String loanPurposeName = null; - final Long loanOfficerId = null; - final String loanOfficerName = null; - final CurrencyData currencyData = null; - final BigDecimal proposedPrincipal = null; - final BigDecimal principal = null; - final BigDecimal netDisbursalAmount = null; - final BigDecimal totalOverpaid = null; - final BigDecimal inArrearsTolerance = null; - final Integer termFrequency = null; - final EnumOptionData termPeriodFrequencyType = null; - final Integer numberOfRepayments = null; - final Integer repaymentEvery = null; - final EnumOptionData repaymentFrequencyType = null; - final EnumOptionData repaymentFrequencyNthDayType = null; - final EnumOptionData repaymentFrequencyDayOfWeekType = null; - final Long transactionProcessingStrategyId = null; - final String transactionProcessingStrategyName = null; - final EnumOptionData amortizationType = null; - final BigDecimal interestRatePerPeriod = null; - final EnumOptionData interestRateFrequencyType = null; - final BigDecimal annualInterestRate = null; - final EnumOptionData interestType = null; - final boolean isFloatingInterestRate = false; - final BigDecimal interestRateDifferential = null; - final EnumOptionData interestCalculationPeriodType = null; - final Boolean allowPartialPeriodInterestCalcualtion = null; - final LocalDate expectedFirstRepaymentOnDate = null; - final Integer graceOnPrincipalPayment = null; - final Integer recurringMoratoriumOnPrincipalPeriods = null; - final Integer graceOnInterestPayment = null; - final Integer graceOnArrearsAgeing = null; - final Integer graceOnInterestCharged = null; - final LocalDate interestChargedFromDate = null; - final LoanApplicationTimelineData timeline = LoanApplicationTimelineData.templateDefault(expectedDisbursementDate); - final LoanSummaryData summary = null; - final BigDecimal feeChargesDueAtDisbursementCharged = null; - final LoanScheduleData repaymentSchedule = null; - final Collection transactions = null; - final Collection charges = null; - final Collection collateral = null; - final Collection guarantors = null; - final Collection notes = null; - final CalendarData calendarData = null; - final Collection productOptions = null; - final Collection termFrequencyTypeOptions = null; - final Collection repaymentFrequencyTypeOptions = null; - final Collection repaymentFrequencyNthDayTypeOptions = null; - final Collection repaymentFrequencyDayOfWeekTypeOptions = null; - final Collection repaymentStrategyOptions = null; - final Collection interestRateFrequencyTypeOptions = null; - final Collection amortizationTypeOptions = null; - final Collection interestTypeOptions = null; - final Collection interestCalculationPeriodTypeOptions = null; - final Collection fundOptions = null; - final Collection chargeOptions = null; - final ChargeData chargeTemplate = null; - final Collection loanOfficerOptions = null; - final Collection loanPurposeOptions = null; - final Collection loanCollateralOptions = null; - final Collection calendarOptions = null; - final Boolean syncDisbursementWithMeeting = null; - final Integer loancounter = null; - final Integer loanProductCounter = null; - final Collection accountLinkingOptions = null; - final PortfolioAccountData linkedAccount = null; - final Collection disbursementData = null; - final Boolean multiDisburseLoan = null; - final Boolean canDefineInstallmentAmount = null; - final BigDecimal fixedEmiAmount = null; - final BigDecimal maxOutstandingLoanBalance = null; - final Collection emiAmountVariations = null; - final Map memberVariations = null; - final LoanProductData product = null; - final Boolean inArrears = null; - final Boolean isNPA = null; - final Collection overdueCharges = null; - - final EnumOptionData daysInMonthType = null; - final EnumOptionData daysInYearType = null; - final boolean isInterestRecalculationEnabled = false; - final LoanInterestRecalculationData interestRecalculationData = null; - final LoanScheduleData originalSchedule = null; - final Boolean createStandingInstructionAtDisbursement = null; - final PaidInAdvanceData paidInAdvance = null; - final Collection interestRatesPeriods = null; - - final Boolean isVariableInstallmentsAllowed = Boolean.FALSE; - final Integer minimumGap = null; - final Integer maximumGap = null; - final Boolean canUseForTopup = null; - final Collection clientActiveLoanOptions = null; - final boolean isTopup = false; - final Long closureLoanId = null; - final String closureLoanAccountNo = null; - final BigDecimal topupAmount = null; - final boolean isEqualAmortization = false; - final List rates = null; - final Boolean isRatesEnabled = false; - final BigDecimal fixedPrincipalPercentagePerInstallment = null; - final CollectionData delinquent = CollectionData.template(); - final DelinquencyRangeData delinquencyRange = null; - final Boolean disallowExpectedDisbursements = false; - final boolean fraud = false; - - return new LoanAccountData(id, accountNo, status, externalId, clientId, clientAccountNo, clientName, clientOfficeId, - clientExternalId, group, loanType, loanProductId, loanProductName, loanProductDescription, - isLoanProductLinkedToFloatingRate, fundId, fundName, loanPurposeId, loanPurposeName, loanOfficerId, loanOfficerName, - currencyData, proposedPrincipal, principal, principal, netDisbursalAmount, totalOverpaid, inArrearsTolerance, termFrequency, - termPeriodFrequencyType, numberOfRepayments, repaymentEvery, repaymentFrequencyType, repaymentFrequencyNthDayType, - repaymentFrequencyDayOfWeekType, transactionProcessingStrategyId, transactionProcessingStrategyName, amortizationType, - interestRatePerPeriod, interestRateFrequencyType, annualInterestRate, interestType, isFloatingInterestRate, - interestRateDifferential, interestCalculationPeriodType, allowPartialPeriodInterestCalcualtion, - expectedFirstRepaymentOnDate, graceOnPrincipalPayment, recurringMoratoriumOnPrincipalPeriods, graceOnInterestPayment, - graceOnInterestCharged, interestChargedFromDate, timeline, summary, feeChargesDueAtDisbursementCharged, repaymentSchedule, - transactions, charges, collateral, guarantors, calendarData, productOptions, termFrequencyTypeOptions, - repaymentFrequencyTypeOptions, repaymentFrequencyNthDayTypeOptions, repaymentFrequencyDayOfWeekTypeOptions, - repaymentStrategyOptions, interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions, - interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions, loanPurposeOptions, - loanCollateralOptions, calendarOptions, syncDisbursementWithMeeting, loancounter, loanProductCounter, notes, - accountLinkingOptions, linkedAccount, disbursementData, multiDisburseLoan, canDefineInstallmentAmount, fixedEmiAmount, - maxOutstandingLoanBalance, emiAmountVariations, memberVariations, product, inArrears, graceOnArrearsAgeing, overdueCharges, - isNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled, interestRecalculationData, originalSchedule, - createStandingInstructionAtDisbursement, paidInAdvance, interestRatesPeriods, isVariableInstallmentsAllowed, minimumGap, - maximumGap, subStatus, canUseForTopup, clientActiveLoanOptions, isTopup, closureLoanId, closureLoanAccountNo, topupAmount, - isEqualAmortization, rates, isRatesEnabled, fixedPrincipalPercentagePerInstallment, delinquent, delinquencyRange, - disallowExpectedDisbursements, fraud); + return new LoanAccountData().setTimeline(LoanApplicationTimelineData.templateDefault(expectedDisbursementDate)) + .setIsVariableInstallmentsAllowed(false).setDelinquent(CollectionData.template()).setClientId(clientId) + .setClientAccountNo(clientAccountNo).setClientName(clientName).setClientOfficeId(clientOfficeId) + .setClientExternalId(clientExternalId).setExpectedDisbursementDate(expectedDisbursementDate); } public static LoanAccountData populateClientDefaults(final LoanAccountData acc, final LoanAccountData clientAcc) { - return new LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, clientAcc.clientId, clientAcc.clientAccountNo, - clientAcc.clientName, clientAcc.clientOfficeId, acc.clientExternalId, acc.group, acc.loanType, acc.loanProductId, - acc.loanProductName, acc.loanProductDescription, acc.isLoanProductLinkedToFloatingRate, acc.fundId, acc.fundName, - acc.loanPurposeId, acc.loanPurposeName, acc.loanOfficerId, acc.loanOfficerName, acc.currency, acc.proposedPrincipal, - acc.principal, acc.approvedPrincipal, acc.netDisbursalAmount, acc.totalOverpaid, acc.inArrearsTolerance, acc.termFrequency, - acc.termPeriodFrequencyType, acc.numberOfRepayments, acc.repaymentEvery, acc.repaymentFrequencyType, - acc.repaymentFrequencyNthDayType, acc.repaymentFrequencyDayOfWeekType, acc.transactionProcessingStrategyId, - acc.transactionProcessingStrategyName, acc.amortizationType, acc.interestRatePerPeriod, acc.interestRateFrequencyType, - acc.annualInterestRate, acc.interestType, acc.isFloatingInterestRate, acc.interestRateDifferential, - acc.interestCalculationPeriodType, acc.allowPartialPeriodInterestCalculation, acc.expectedFirstRepaymentOnDate, - acc.graceOnPrincipalPayment, acc.recurringMoratoriumOnPrincipalPeriods, acc.graceOnInterestPayment, - acc.graceOnInterestCharged, acc.interestChargedFromDate, clientAcc.timeline, acc.summary, - acc.feeChargesAtDisbursementCharged, acc.repaymentSchedule, acc.transactions, acc.charges, acc.collateral, acc.guarantors, - acc.meeting, acc.productOptions, acc.termFrequencyTypeOptions, acc.repaymentFrequencyTypeOptions, - acc.repaymentFrequencyNthDayTypeOptions, acc.repaymentFrequencyDaysOfWeekTypeOptions, - acc.transactionProcessingStrategyOptions, acc.interestRateFrequencyTypeOptions, acc.amortizationTypeOptions, - acc.interestTypeOptions, acc.interestCalculationPeriodTypeOptions, acc.fundOptions, acc.chargeOptions, null, - acc.loanOfficerOptions, acc.loanPurposeOptions, acc.loanCollateralOptions, acc.calendarOptions, - acc.syncDisbursementWithMeeting, acc.loanCounter, acc.loanProductCounter, acc.notes, acc.accountLinkingOptions, - acc.linkedAccount, acc.disbursementDetails, acc.multiDisburseLoan, acc.canDefineInstallmentAmount, acc.fixedEmiAmount, - acc.maxOutstandingLoanBalance, acc.emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears, - acc.graceOnArrearsAgeing, acc.overdueCharges, acc.isNPA, acc.daysInMonthType, acc.daysInYearType, - acc.isInterestRecalculationEnabled, acc.interestRecalculationData, acc.originalSchedule, - acc.createStandingInstructionAtDisbursement, acc.paidInAdvance, acc.interestRatesPeriods, acc.isVariableInstallmentsAllowed, - acc.minimumGap, acc.maximumGap, acc.subStatus, acc.canUseForTopup, acc.clientActiveLoanOptions, acc.isTopup, - acc.closureLoanId, acc.closureLoanAccountNo, acc.topupAmount, acc.isEqualAmortization, acc.rates, acc.isRatesEnabled, - acc.fixedPrincipalPercentagePerInstallment, acc.delinquent, acc.delinquencyRange, acc.disallowExpectedDisbursements, - acc.fraud); + return new LoanAccountData().setId(acc.id).setAccountNo(acc.accountNo).setStatus(acc.status).setExternalId(acc.externalId) + .setClientId(clientAcc.clientId).setClientAccountNo(clientAcc.clientAccountNo).setClientName(clientAcc.clientName) + .setClientOfficeId(clientAcc.clientOfficeId).setClientExternalId(acc.clientExternalId).setGroup(acc.group) + .setLoanType(acc.loanType).setLoanProductId(acc.loanProductId).setLoanProductName(acc.loanProductName) + .setLoanProductDescription(acc.loanProductDescription) + .setLoanProductLinkedToFloatingRate(acc.isLoanProductLinkedToFloatingRate).setFundId(acc.fundId).setFundName(acc.fundName) + .setLoanPurposeId(acc.loanPurposeId).setLoanPurposeName(acc.loanPurposeName).setLoanOfficerId(acc.loanOfficerId) + .setLoanOfficerName(acc.loanOfficerName).setCurrency(acc.currency).setProposedPrincipal(acc.proposedPrincipal) + .setPrincipal(acc.principal).setApprovedPrincipal(acc.approvedPrincipal).setNetDisbursalAmount(acc.netDisbursalAmount) + .setTotalOverpaid(acc.totalOverpaid).setInArrearsTolerance(acc.inArrearsTolerance).setTermFrequency(acc.termFrequency) + .setTermPeriodFrequencyType(acc.termPeriodFrequencyType).setNumberOfRepayments(acc.numberOfRepayments) + .setRepaymentEvery(acc.repaymentEvery).setRepaymentFrequencyType(acc.repaymentFrequencyType) + .setRepaymentFrequencyNthDayType(acc.repaymentFrequencyNthDayType) + .setRepaymentFrequencyDayOfWeekType(acc.repaymentFrequencyDayOfWeekType) + .setTransactionProcessingStrategyCode(acc.transactionProcessingStrategyCode) + .setTransactionProcessingStrategyName(acc.transactionProcessingStrategyName).setAmortizationType(acc.amortizationType) + .setInterestRatePerPeriod(acc.interestRatePerPeriod).setInterestRateFrequencyType(acc.interestRateFrequencyType) + .setAnnualInterestRate(acc.annualInterestRate).setInterestType(acc.interestType) + .setFloatingInterestRate(acc.isFloatingInterestRate).setInterestRateDifferential(acc.interestRateDifferential) + .setInterestCalculationPeriodType(acc.interestCalculationPeriodType) + .setAllowPartialPeriodInterestCalculation(acc.allowPartialPeriodInterestCalculation) + .setExpectedFirstRepaymentOnDate(acc.expectedFirstRepaymentOnDate).setGraceOnPrincipalPayment(acc.graceOnPrincipalPayment) + .setRecurringMoratoriumOnPrincipalPeriods(acc.recurringMoratoriumOnPrincipalPeriods) + .setGraceOnInterestPayment(acc.graceOnInterestPayment).setGraceOnInterestCharged(acc.graceOnInterestCharged) + .setInterestChargedFromDate(acc.interestChargedFromDate).setTimeline(clientAcc.timeline).setSummary(acc.summary) + .setFeeChargesAtDisbursementCharged(acc.feeChargesAtDisbursementCharged).setRepaymentSchedule(acc.repaymentSchedule) + .setTransactions(acc.transactions).setCharges(acc.charges).setCollateral(acc.collateral).setGuarantors(acc.guarantors) + .setMeeting(acc.meeting).setProductOptions(acc.productOptions).setTermFrequencyTypeOptions(acc.termFrequencyTypeOptions) + .setRepaymentFrequencyTypeOptions(acc.repaymentFrequencyTypeOptions) + .setRepaymentFrequencyNthDayTypeOptions(acc.repaymentFrequencyNthDayTypeOptions) + .setRepaymentFrequencyDaysOfWeekTypeOptions(acc.repaymentFrequencyDaysOfWeekTypeOptions) + .setTransactionProcessingStrategyOptions(acc.transactionProcessingStrategyOptions) + .setInterestRateFrequencyTypeOptions(acc.interestRateFrequencyTypeOptions) + .setAmortizationTypeOptions(acc.amortizationTypeOptions).setInterestTypeOptions(acc.interestTypeOptions) + .setInterestCalculationPeriodTypeOptions(acc.interestCalculationPeriodTypeOptions).setFundOptions(acc.fundOptions) + .setChargeOptions(acc.chargeOptions).setLoanOfficerOptions(acc.loanOfficerOptions) + .setLoanPurposeOptions(acc.loanPurposeOptions).setLoanCollateralOptions(acc.loanCollateralOptions) + .setCalendarOptions(acc.calendarOptions).setSyncDisbursementWithMeeting(acc.syncDisbursementWithMeeting) + .setLoanCounter(acc.loanCounter).setLoanProductCounter(acc.loanProductCounter).setNotes(acc.notes) + .setAccountLinkingOptions(acc.accountLinkingOptions).setLinkedAccount(acc.linkedAccount) + .setDisbursementDetails(acc.disbursementDetails).setMultiDisburseLoan(acc.multiDisburseLoan) + .setCanDefineInstallmentAmount(acc.canDefineInstallmentAmount).setFixedEmiAmount(acc.fixedEmiAmount) + .setMaxOutstandingLoanBalance(acc.maxOutstandingLoanBalance).setEmiAmountVariations(acc.emiAmountVariations) + .setMemberVariations(acc.memberVariations).setProduct(acc.product).setInArrears(acc.inArrears) + .setGraceOnArrearsAgeing(acc.graceOnArrearsAgeing).setOverdueCharges(acc.overdueCharges).setIsNPA(acc.isNPA) + .setDaysInMonthType(acc.daysInMonthType).setDaysInYearType(acc.daysInYearType) + .setInterestRecalculationEnabled(acc.isInterestRecalculationEnabled) + .setInterestRecalculationData(acc.interestRecalculationData).setOriginalSchedule(acc.originalSchedule) + .setCreateStandingInstructionAtDisbursement(acc.createStandingInstructionAtDisbursement).setPaidInAdvance(acc.paidInAdvance) + .setInterestRatesPeriods(acc.interestRatesPeriods).setIsVariableInstallmentsAllowed(acc.isVariableInstallmentsAllowed) + .setMinimumGap(acc.minimumGap).setMaximumGap(acc.maximumGap).setSubStatus(acc.subStatus) + .setCanUseForTopup(acc.canUseForTopup).setClientActiveLoanOptions(acc.clientActiveLoanOptions).setTopup(acc.isTopup) + .setClosureLoanId(acc.closureLoanId).setClosureLoanAccountNo(acc.closureLoanAccountNo).setTopupAmount(acc.topupAmount) + .setIsEqualAmortization(acc.isEqualAmortization).setRates(acc.rates).setIsRatesEnabled(acc.isRatesEnabled) + .setFixedPrincipalPercentagePerInstallment(acc.fixedPrincipalPercentagePerInstallment).setDelinquent(acc.delinquent) + .setDelinquencyRange(acc.delinquencyRange).setDisallowExpectedDisbursements(acc.disallowExpectedDisbursements) + .setFraud(acc.fraud); } /** @@ -785,184 +384,70 @@ public final class LoanAccountData { */ public static LoanAccountData groupDefaults(final GroupGeneralData group, final LocalDate expectedDisbursementDate) { - final Long id = null; - final String accountNo = null; - final LoanStatusEnumData status = null; - final EnumOptionData subStatus = null; - final String externalId = null; - final Long clientId = null; - final String clientAccountNo = null; - final String clientName = null; - final Long clientOfficeId = null; - final String clientExternalId = null; - final EnumOptionData loanType = null; - final Long loanProductId = null; - final String loanProductName = null; - final String loanProductDescription = null; - final boolean isLoanProductLinkedToFloatingRate = false; - final Long fundId = null; - final String fundName = null; - final Long loanPurposeId = null; - final String loanPurposeName = null; - final Long loanOfficerId = null; - final String loanOfficerName = null; - final CurrencyData currencyData = null; - final BigDecimal proposedPrincipal = null; - final BigDecimal principal = null; - final BigDecimal netDisbursalAmount = null; - final BigDecimal totalOverpaid = null; - final BigDecimal inArrearsTolerance = null; - final Integer termFrequency = null; - final EnumOptionData termPeriodFrequencyType = null; - final Integer numberOfRepayments = null; - final Integer repaymentEvery = null; - final EnumOptionData repaymentFrequencyType = null; - final EnumOptionData repaymentFrequencyNthDayType = null; - final EnumOptionData repaymentFrequencyDayOfWeekType = null; - final Long transactionProcessingStrategyId = null; - final String transactionProcessingStrategyName = null; - final EnumOptionData amortizationType = null; - final BigDecimal interestRatePerPeriod = null; - final EnumOptionData interestRateFrequencyType = null; - final BigDecimal annualInterestRate = null; - final EnumOptionData interestType = null; - final boolean isFloatingInterestRate = false; - final BigDecimal interestRateDifferential = null; - final EnumOptionData interestCalculationPeriodType = null; - final Boolean allowPartialPeriodInterestCalcualtion = null; - final LocalDate expectedFirstRepaymentOnDate = null; - final Integer graceOnPrincipalPayment = null; - final Integer recurringMoratoriumOnPrincipalPeriods = null; - final Integer graceOnInterestPayment = null; - final Integer graceOnInterestCharged = null; - final Integer graceOnArrearsAgeing = null; - final LocalDate interestChargedFromDate = null; - final LoanApplicationTimelineData timeline = LoanApplicationTimelineData.templateDefault(expectedDisbursementDate); - final LoanSummaryData summary = null; - final BigDecimal feeChargesDueAtDisbursementCharged = null; - - final LoanScheduleData repaymentSchedule = null; - final Collection transactions = null; - final Collection charges = null; - final Collection collateral = null; - final Collection guarantors = null; - final Collection notes = null; - final CalendarData calendarData = null; - final Collection productOptions = null; - final Collection termFrequencyTypeOptions = null; - final Collection repaymentFrequencyTypeOptions = null; - final Collection repaymentFrequencyNthDayTypeOptions = null; - final Collection repaymentFrequencyDayOfWeekTypeOptions = null; - final Collection repaymentStrategyOptions = null; - final Collection interestRateFrequencyTypeOptions = null; - final Collection amortizationTypeOptions = null; - final Collection interestTypeOptions = null; - final Collection interestCalculationPeriodTypeOptions = null; - final Collection fundOptions = null; - final Collection chargeOptions = null; - final ChargeData chargeTemplate = null; - final Collection loanOfficerOptions = null; - final Collection loanPurposeOptions = null; - final Collection loanCollateralOptions = null; - final Collection calendarOptions = null; - final Boolean syncDisbursementWithMeeting = null; - final Integer loancounter = null; - final Integer loanProductCounter = null; - final Collection accountLinkingOptions = null; - final PortfolioAccountData linkedAccount = null; - final Collection disbursementData = null; - final Boolean multiDisburseLoan = null; - final Boolean canDefineInstallmentAmount = null; - final BigDecimal fixedEmiAmount = null; - final BigDecimal maxOutstandingBalance = null; - final Collection emiAmountVariations = null; - final Map memberVariations = null; - final LoanProductData product = null; - final Boolean inArrears = null; - final Boolean isNPA = null; - final Collection overdueCharges = null; - - final EnumOptionData daysInMonthType = null; - final EnumOptionData daysInYearType = null; - final boolean isInterestRecalculationEnabled = false; - final LoanInterestRecalculationData interestRecalculationData = null; - final LoanScheduleData originalSchedule = null; - final Boolean createStandingInstructionAtDisbursement = null; - final PaidInAdvanceData paidInAdvance = null; - final Collection interestRatesPeriods = null; - - final Boolean isVariableInstallmentsAllowed = Boolean.FALSE; - final Integer minimumGap = null; - final Integer maximumGap = null; - final Boolean canUseForTopup = null; - final Collection clientActiveLoanOptions = null; - final boolean isTopup = false; - final Long closureLoanId = null; - final String closureLoanAccountNo = null; - final BigDecimal topupAmount = null; - final boolean isEqualAmortization = false; - final List rates = null; - final Boolean isRatesEnabled = false; - final BigDecimal fixedPrincipalPercentagePerInstallment = null; - final CollectionData delinquent = CollectionData.template(); - final DelinquencyRangeData delinquencyRange = null; - final Boolean disallowExpectedDisbursements = false; - final Boolean fraud = false; - - return new LoanAccountData(id, accountNo, status, externalId, clientId, clientAccountNo, clientName, clientOfficeId, - clientExternalId, group, loanType, loanProductId, loanProductName, loanProductDescription, - isLoanProductLinkedToFloatingRate, fundId, fundName, loanPurposeId, loanPurposeName, loanOfficerId, loanOfficerName, - currencyData, proposedPrincipal, principal, principal, netDisbursalAmount, totalOverpaid, inArrearsTolerance, termFrequency, - termPeriodFrequencyType, numberOfRepayments, repaymentEvery, repaymentFrequencyType, repaymentFrequencyNthDayType, - repaymentFrequencyDayOfWeekType, transactionProcessingStrategyId, transactionProcessingStrategyName, amortizationType, - interestRatePerPeriod, interestRateFrequencyType, annualInterestRate, interestType, isFloatingInterestRate, - interestRateDifferential, interestCalculationPeriodType, allowPartialPeriodInterestCalcualtion, - expectedFirstRepaymentOnDate, graceOnPrincipalPayment, recurringMoratoriumOnPrincipalPeriods, graceOnInterestPayment, - graceOnInterestCharged, interestChargedFromDate, timeline, summary, feeChargesDueAtDisbursementCharged, repaymentSchedule, - transactions, charges, collateral, guarantors, calendarData, productOptions, termFrequencyTypeOptions, - repaymentFrequencyTypeOptions, repaymentFrequencyNthDayTypeOptions, repaymentFrequencyDayOfWeekTypeOptions, - repaymentStrategyOptions, interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions, - interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions, loanPurposeOptions, - loanCollateralOptions, calendarOptions, syncDisbursementWithMeeting, loancounter, loanProductCounter, notes, - accountLinkingOptions, linkedAccount, disbursementData, multiDisburseLoan, canDefineInstallmentAmount, fixedEmiAmount, - maxOutstandingBalance, emiAmountVariations, memberVariations, product, inArrears, graceOnArrearsAgeing, overdueCharges, - isNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled, interestRecalculationData, originalSchedule, - createStandingInstructionAtDisbursement, paidInAdvance, interestRatesPeriods, isVariableInstallmentsAllowed, minimumGap, - maximumGap, subStatus, canUseForTopup, clientActiveLoanOptions, isTopup, closureLoanId, closureLoanAccountNo, topupAmount, - isEqualAmortization, rates, isRatesEnabled, fixedPrincipalPercentagePerInstallment, delinquent, delinquencyRange, - disallowExpectedDisbursements, fraud); + return new LoanAccountData().setTimeline(LoanApplicationTimelineData.templateDefault(expectedDisbursementDate)) + .setIsVariableInstallmentsAllowed(false).setDelinquent(CollectionData.template()).setGroup(group) + .setExpectedDisbursementDate(expectedDisbursementDate); } public static LoanAccountData populateGroupDefaults(final LoanAccountData acc, final LoanAccountData groupAcc) { - return new LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, acc.clientId, acc.clientAccountNo, acc.clientName, - acc.clientOfficeId, acc.clientExternalId, groupAcc.group, acc.loanType, acc.loanProductId, acc.loanProductName, - acc.loanProductDescription, acc.isLoanProductLinkedToFloatingRate, acc.fundId, acc.fundName, acc.loanPurposeId, - acc.loanPurposeName, acc.loanOfficerId, acc.loanOfficerName, acc.currency, acc.proposedPrincipal, acc.principal, - acc.approvedPrincipal, acc.netDisbursalAmount, acc.totalOverpaid, acc.inArrearsTolerance, acc.termFrequency, - acc.termPeriodFrequencyType, acc.numberOfRepayments, acc.repaymentEvery, acc.repaymentFrequencyType, - acc.repaymentFrequencyNthDayType, acc.repaymentFrequencyDayOfWeekType, acc.transactionProcessingStrategyId, - acc.transactionProcessingStrategyName, acc.amortizationType, acc.interestRatePerPeriod, acc.interestRateFrequencyType, - acc.annualInterestRate, acc.interestType, acc.isFloatingInterestRate, acc.interestRateDifferential, - acc.interestCalculationPeriodType, acc.allowPartialPeriodInterestCalculation, acc.expectedFirstRepaymentOnDate, - acc.graceOnPrincipalPayment, acc.recurringMoratoriumOnPrincipalPeriods, acc.graceOnInterestPayment, - acc.graceOnInterestCharged, acc.interestChargedFromDate, groupAcc.timeline, acc.summary, - acc.feeChargesAtDisbursementCharged, acc.repaymentSchedule, acc.transactions, acc.charges, acc.collateral, acc.guarantors, - acc.meeting, acc.productOptions, acc.termFrequencyTypeOptions, acc.repaymentFrequencyTypeOptions, - acc.repaymentFrequencyNthDayTypeOptions, acc.repaymentFrequencyDaysOfWeekTypeOptions, - acc.transactionProcessingStrategyOptions, acc.interestRateFrequencyTypeOptions, acc.amortizationTypeOptions, - acc.interestTypeOptions, acc.interestCalculationPeriodTypeOptions, acc.fundOptions, acc.chargeOptions, null, - acc.loanOfficerOptions, acc.loanPurposeOptions, acc.loanCollateralOptions, acc.calendarOptions, - acc.syncDisbursementWithMeeting, acc.loanCounter, acc.loanProductCounter, acc.notes, acc.accountLinkingOptions, - acc.linkedAccount, acc.disbursementDetails, acc.multiDisburseLoan, acc.canDefineInstallmentAmount, acc.fixedEmiAmount, - acc.maxOutstandingLoanBalance, acc.emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears, - acc.graceOnArrearsAgeing, acc.overdueCharges, acc.isNPA, acc.daysInMonthType, acc.daysInYearType, - acc.isInterestRecalculationEnabled, acc.interestRecalculationData, acc.originalSchedule, - acc.createStandingInstructionAtDisbursement, acc.paidInAdvance, acc.interestRatesPeriods, acc.isVariableInstallmentsAllowed, - acc.minimumGap, acc.maximumGap, acc.subStatus, acc.canUseForTopup, acc.clientActiveLoanOptions, acc.isTopup, - acc.closureLoanId, acc.closureLoanAccountNo, acc.topupAmount, acc.isEqualAmortization, acc.rates, acc.isRatesEnabled, - acc.fixedPrincipalPercentagePerInstallment, acc.delinquent, acc.delinquencyRange, acc.disallowExpectedDisbursements, - acc.fraud); + return new LoanAccountData().setId(acc.id).setAccountNo(acc.accountNo).setStatus(acc.status).setExternalId(acc.externalId) + .setClientId(acc.clientId).setClientAccountNo(acc.clientAccountNo).setClientName(acc.clientName) + .setClientOfficeId(acc.clientOfficeId).setClientExternalId(acc.clientExternalId).setGroup(groupAcc.group) + .setLoanType(acc.loanType).setLoanProductId(acc.loanProductId).setLoanProductName(acc.loanProductName) + .setLoanProductDescription(acc.loanProductDescription) + .setLoanProductLinkedToFloatingRate(acc.isLoanProductLinkedToFloatingRate).setFundId(acc.fundId).setFundName(acc.fundName) + .setLoanPurposeId(acc.loanPurposeId).setLoanPurposeName(acc.loanPurposeName).setLoanOfficerId(acc.loanOfficerId) + .setLoanOfficerName(acc.loanOfficerName).setCurrency(acc.currency).setProposedPrincipal(acc.proposedPrincipal) + .setPrincipal(acc.principal).setApprovedPrincipal(acc.approvedPrincipal).setNetDisbursalAmount(acc.netDisbursalAmount) + .setTotalOverpaid(acc.totalOverpaid).setInArrearsTolerance(acc.inArrearsTolerance).setTermFrequency(acc.termFrequency) + .setTermPeriodFrequencyType(acc.termPeriodFrequencyType).setNumberOfRepayments(acc.numberOfRepayments) + .setRepaymentEvery(acc.repaymentEvery).setRepaymentFrequencyType(acc.repaymentFrequencyType) + .setRepaymentFrequencyNthDayType(acc.repaymentFrequencyNthDayType) + .setRepaymentFrequencyDayOfWeekType(acc.repaymentFrequencyDayOfWeekType) + .setTransactionProcessingStrategyCode(acc.transactionProcessingStrategyCode) + .setTransactionProcessingStrategyName(acc.transactionProcessingStrategyName).setAmortizationType(acc.amortizationType) + .setInterestRatePerPeriod(acc.interestRatePerPeriod).setInterestRateFrequencyType(acc.interestRateFrequencyType) + .setAnnualInterestRate(acc.annualInterestRate).setInterestType(acc.interestType) + .setFloatingInterestRate(acc.isFloatingInterestRate).setInterestRateDifferential(acc.interestRateDifferential) + .setInterestCalculationPeriodType(acc.interestCalculationPeriodType) + .setAllowPartialPeriodInterestCalculation(acc.allowPartialPeriodInterestCalculation) + .setExpectedFirstRepaymentOnDate(acc.expectedFirstRepaymentOnDate).setGraceOnPrincipalPayment(acc.graceOnPrincipalPayment) + .setRecurringMoratoriumOnPrincipalPeriods(acc.recurringMoratoriumOnPrincipalPeriods) + .setGraceOnInterestPayment(acc.graceOnInterestPayment).setGraceOnInterestCharged(acc.graceOnInterestCharged) + .setInterestChargedFromDate(acc.interestChargedFromDate).setTimeline(groupAcc.timeline).setSummary(acc.summary) + .setFeeChargesAtDisbursementCharged(acc.feeChargesAtDisbursementCharged).setRepaymentSchedule(acc.repaymentSchedule) + .setTransactions(acc.transactions).setCharges(acc.charges).setCollateral(acc.collateral).setGuarantors(acc.guarantors) + .setMeeting(acc.meeting).setProductOptions(acc.productOptions).setTermFrequencyTypeOptions(acc.termFrequencyTypeOptions) + .setRepaymentFrequencyTypeOptions(acc.repaymentFrequencyTypeOptions) + .setRepaymentFrequencyNthDayTypeOptions(acc.repaymentFrequencyNthDayTypeOptions) + .setRepaymentFrequencyDaysOfWeekTypeOptions(acc.repaymentFrequencyDaysOfWeekTypeOptions) + .setTransactionProcessingStrategyOptions(acc.transactionProcessingStrategyOptions) + .setInterestRateFrequencyTypeOptions(acc.interestRateFrequencyTypeOptions) + .setAmortizationTypeOptions(acc.amortizationTypeOptions).setInterestTypeOptions(acc.interestTypeOptions) + .setInterestCalculationPeriodTypeOptions(acc.interestCalculationPeriodTypeOptions).setFundOptions(acc.fundOptions) + .setChargeOptions(acc.chargeOptions).setLoanOfficerOptions(acc.loanOfficerOptions) + .setLoanPurposeOptions(acc.loanPurposeOptions).setLoanCollateralOptions(acc.loanCollateralOptions) + .setCalendarOptions(acc.calendarOptions).setSyncDisbursementWithMeeting(acc.syncDisbursementWithMeeting) + .setLoanCounter(acc.loanCounter).setLoanProductCounter(acc.loanProductCounter).setNotes(acc.notes) + .setAccountLinkingOptions(acc.accountLinkingOptions).setLinkedAccount(acc.linkedAccount) + .setDisbursementDetails(acc.disbursementDetails).setMultiDisburseLoan(acc.multiDisburseLoan) + .setCanDefineInstallmentAmount(acc.canDefineInstallmentAmount).setFixedEmiAmount(acc.fixedEmiAmount) + .setMaxOutstandingLoanBalance(acc.maxOutstandingLoanBalance).setEmiAmountVariations(acc.emiAmountVariations) + .setMemberVariations(acc.memberVariations).setProduct(acc.product).setInArrears(acc.inArrears) + .setGraceOnArrearsAgeing(acc.graceOnArrearsAgeing).setOverdueCharges(acc.overdueCharges).setIsNPA(acc.isNPA) + .setDaysInMonthType(acc.daysInMonthType).setDaysInYearType(acc.daysInYearType) + .setInterestRecalculationEnabled(acc.isInterestRecalculationEnabled) + .setInterestRecalculationData(acc.interestRecalculationData).setOriginalSchedule(acc.originalSchedule) + .setCreateStandingInstructionAtDisbursement(acc.createStandingInstructionAtDisbursement).setPaidInAdvance(acc.paidInAdvance) + .setInterestRatesPeriods(acc.interestRatesPeriods).setIsVariableInstallmentsAllowed(acc.isVariableInstallmentsAllowed) + .setMinimumGap(acc.minimumGap).setMaximumGap(acc.maximumGap).setSubStatus(acc.subStatus) + .setCanUseForTopup(acc.canUseForTopup).setClientActiveLoanOptions(acc.clientActiveLoanOptions).setTopup(acc.isTopup) + .setClosureLoanId(acc.closureLoanId).setClosureLoanAccountNo(acc.closureLoanAccountNo).setTopupAmount(acc.topupAmount) + .setIsEqualAmortization(acc.isEqualAmortization).setRates(acc.rates).setIsRatesEnabled(acc.isRatesEnabled) + .setFixedPrincipalPercentagePerInstallment(acc.fixedPrincipalPercentagePerInstallment).setDelinquent(acc.delinquent) + .setDelinquencyRange(acc.delinquencyRange).setDisallowExpectedDisbursements(acc.disallowExpectedDisbursements) + .setFraud(acc.fraud); } public static LoanAccountData loanProductWithTemplateDefaults(final LoanProductData product, @@ -976,45 +461,6 @@ public final class LoanAccountData { final Collection loanPurposeOptions, final Collection loanCollateralOptions, final Integer loanCycleNumber, final Collection clientActiveLoanOptions) { - final Long id = null; - final String accountNo = null; - final LoanStatusEnumData status = null; - final EnumOptionData subStatus = null; - final String externalId = null; - final Long clientId = null; - final String clientAccountNo = null; - final String clientName = null; - final Long clientOfficeId = null; - final String clientExternalId = null; - final GroupGeneralData group = null; - final EnumOptionData loanType = null; - final Long loanPurposeId = null; - final String loanPurposeName = null; - final Long loanOfficerId = null; - final String loanOfficerName = null; - - final BigDecimal totalOverpaid = null; - - final String transactionProcessingStrategyName = null; - - final LocalDate expectedFirstRepaymentOnDate = null; - final LocalDate interestChargedFromDate = null; - final LoanApplicationTimelineData timeline = null; - final LoanSummaryData summary = null; - final BigDecimal feeChargesDueAtDisbursementCharged = null; - final ChargeData chargeTemplate = null; - final Boolean syncDisbursementWithMeeting = null; - - final LoanScheduleData repaymentSchedule = null; - final Collection transactions = null; - final Collection collateral = null; - final Collection guarantors = null; - final Collection notes = null; - final CalendarData calendarData = null; - final Collection productOptions = null; - final Collection calendarOptions = null; - final Collection loanOfficerOptions = null; - final EnumOptionData termPeriodFrequencyType = product.getRepaymentFrequencyType(); final Collection charges = new ArrayList(); @@ -1024,17 +470,10 @@ public final class LoanAccountData { } } - final Integer loancounter = null; - final Integer loanProductCounter = null; - final PortfolioAccountData linkedAccount = null; - final Collection accountLinkingOptions = null; - final Collection disbursementData = null; - final Collection emiAmountVariations = null; BigDecimal principal = null; BigDecimal proposedPrincipal = null; - BigDecimal netDisbursalAmount = null; - BigDecimal interestRatePerPeriod = null; + Integer numberOfRepayments = null; if (product.isUseBorrowerCycle() && loanCycleNumber > 0) { Collection principalVariationsForBorrowerCycle = product @@ -1051,14 +490,16 @@ public final class LoanAccountData { numberOfRepayments = numberofRepaymentval.intValue(); } } + if (principal == null) { principal = product.getPrincipal(); proposedPrincipal = principal; } // Add net get net disbursal amount from charges and principal - netDisbursalAmount = principal; - if (charges != null && !charges.isEmpty()) { + BigDecimal netDisbursalAmount = principal; + + if (!charges.isEmpty()) { for (LoanChargeData charge : charges) { netDisbursalAmount = netDisbursalAmount.subtract(charge.getAmount()); } @@ -1071,80 +512,48 @@ public final class LoanAccountData { numberOfRepayments = product.getNumberOfRepayments(); } - final Integer termFrequency = numberOfRepayments * product.getRepaymentEvery(); - final BigDecimal fixedEmi = null; - Map memberVariations = null; - final Boolean inArrears = null; - final Boolean isNPA = null; - final LoanScheduleData originalSchedule = null; - final Boolean createStandingInstructionAtDisbursement = null; - final PaidInAdvanceData paidInAdvance = null; - final Collection interestRatesPeriods = null; - - final Boolean canUseForTopup = product.isCanUseForTopup(); - final boolean isTopup = false; - final Long closureLoanId = null; - final String closureLoanAccountNo = null; - final BigDecimal topupAmount = null; - final List rates = null; - final Boolean isRatesEnabled = false; - final CollectionData delinquent = CollectionData.template(); - final DelinquencyRangeData delinquencyRange = null; - final boolean fraud = false; - - return new LoanAccountData(id, accountNo, status, externalId, clientId, clientAccountNo, clientName, clientOfficeId, - clientExternalId, group, loanType, product.getId(), product.getName(), product.getDescription(), - product.isLinkedToFloatingInterestRates(), product.getFundId(), product.getFundName(), loanPurposeId, loanPurposeName, - loanOfficerId, loanOfficerName, product.getCurrency(), proposedPrincipal, principal, principal, netDisbursalAmount, - totalOverpaid, product.getInArrearsTolerance(), termFrequency, termPeriodFrequencyType, numberOfRepayments, - product.getRepaymentEvery(), product.getRepaymentFrequencyType(), null, null, product.getTransactionProcessingStrategyId(), - transactionProcessingStrategyName, product.getAmortizationType(), interestRatePerPeriod, - product.getInterestRateFrequencyType(), product.getAnnualInterestRate(), product.getInterestType(), - product.isFloatingInterestRateCalculationAllowed(), product.getDefaultDifferentialLendingRate(), - product.getInterestCalculationPeriodType(), product.isAllowPartialPeriodInterestCalculation(), expectedFirstRepaymentOnDate, - product.getGraceOnPrincipalPayment(), product.getRecurringMoratoriumOnPrincipalPeriods(), - product.getGraceOnInterestPayment(), product.getGraceOnInterestCharged(), interestChargedFromDate, timeline, summary, - feeChargesDueAtDisbursementCharged, repaymentSchedule, transactions, charges, collateral, guarantors, calendarData, - productOptions, termFrequencyTypeOptions, repaymentFrequencyTypeOptions, repaymentFrequencyNthDayTypeOptions, - repaymentFrequencyDayOfWeekTypeOptions, repaymentStrategyOptions, interestRateFrequencyTypeOptions, amortizationTypeOptions, - interestTypeOptions, interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions, - loanPurposeOptions, loanCollateralOptions, calendarOptions, syncDisbursementWithMeeting, loancounter, loanProductCounter, - notes, accountLinkingOptions, linkedAccount, disbursementData, product.getMultiDisburseLoan(), - product.isCanDefineInstallmentAmount(), fixedEmi, product.getOutstandingLoanBalance(), emiAmountVariations, - memberVariations, product, inArrears, product.getGraceOnArrearsAgeing(), product.overdueFeeCharges(), isNPA, - product.getDaysInMonthType(), product.getDaysInYearType(), product.isInterestRecalculationEnabled(), - product.toLoanInterestRecalculationData(), originalSchedule, createStandingInstructionAtDisbursement, paidInAdvance, - interestRatesPeriods, product.isAllowVariableInstallments(), product.getMinimumGap(), product.getMaximumGap(), subStatus, - canUseForTopup, clientActiveLoanOptions, isTopup, closureLoanId, closureLoanAccountNo, topupAmount, - product.isEqualAmortization(), rates, isRatesEnabled, product.getFixedPrincipalPercentagePerInstallment(), delinquent, - delinquencyRange, product.getDisallowExpectedDisbursements(), fraud); + return new LoanAccountData().setProductId(product.getId()).setLoanProductName(product.getName()) + .setLoanProductDescription(product.getDescription()) + .setLoanProductLinkedToFloatingRate(product.isLinkedToFloatingInterestRates()).setFundId(product.getFundId()) + .setFundName(product.getFundName()).setCurrency(product.getCurrency()).setProposedPrincipal(proposedPrincipal) + .setPrincipal(principal).setApprovedPrincipal(principal).setNetDisbursalAmount(netDisbursalAmount) + .setInArrearsTolerance(product.getInArrearsTolerance()).setTermFrequency(numberOfRepayments * product.getRepaymentEvery()) + .setTermPeriodFrequencyType(termPeriodFrequencyType).setNumberOfRepayments(numberOfRepayments) + .setRepaymentEvery(product.getRepaymentEvery()).setRepaymentFrequencyType(product.getRepaymentFrequencyType()) + .setTransactionProcessingStrategyCode(product.getTransactionProcessingStrategyCode()) + .setAmortizationType(product.getAmortizationType()).setInterestRatePerPeriod(interestRatePerPeriod) + .setInterestRateFrequencyType(product.getInterestRateFrequencyType()).setAnnualInterestRate(product.getAnnualInterestRate()) + .setInterestType(product.getInterestType()).setFloatingInterestRate(product.isFloatingInterestRateCalculationAllowed()) + .setInterestRateDifferential(product.getDefaultDifferentialLendingRate()) + .setInterestCalculationPeriodType(product.getInterestCalculationPeriodType()) + .setAllowPartialPeriodInterestCalculation(product.isAllowPartialPeriodInterestCalculation()) + .setGraceOnPrincipalPayment(product.getGraceOnPrincipalPayment()) + .setRecurringMoratoriumOnPrincipalPeriods(product.getRecurringMoratoriumOnPrincipalPeriods()) + .setGraceOnInterestPayment(product.getGraceOnInterestPayment()) + .setGraceOnInterestCharged(product.getGraceOnInterestCharged()).setCharges(charges) + .setTermFrequencyTypeOptions(termFrequencyTypeOptions).setRepaymentFrequencyTypeOptions(repaymentFrequencyTypeOptions) + .setRepaymentFrequencyDaysOfWeekTypeOptions(repaymentFrequencyDayOfWeekTypeOptions) + .setRepaymentFrequencyNthDayTypeOptions(repaymentFrequencyNthDayTypeOptions) + .setTransactionProcessingStrategyOptions(repaymentStrategyOptions) + .setInterestRateFrequencyTypeOptions(interestRateFrequencyTypeOptions).setAmortizationTypeOptions(amortizationTypeOptions) + .setInterestTypeOptions(interestTypeOptions).setInterestCalculationPeriodTypeOptions(interestCalculationPeriodTypeOptions) + .setFundOptions(fundOptions).setChargeOptions(chargeOptions).setLoanPurposeOptions(loanPurposeOptions) + .setLoanCollateralOptions(loanCollateralOptions).setMultiDisburseLoan(product.getMultiDisburseLoan()) + .setCanDefineInstallmentAmount(product.isCanDefineInstallmentAmount()) + .setMaxOutstandingLoanBalance(product.getOutstandingLoanBalance()).setProduct(product) + .setGraceOnArrearsAgeing(product.getGraceOnArrearsAgeing()).setOverdueCharges(product.overdueFeeCharges()) + .setDaysInMonthType(product.getDaysInMonthType()).setDaysInYearType(product.getDaysInYearType()) + .setInterestRecalculationEnabled(product.isInterestRecalculationEnabled()) + .setInterestRecalculationData(product.toLoanInterestRecalculationData()) + .setIsVariableInstallmentsAllowed(product.isAllowVariableInstallments()).setMinimumGap(product.getMinimumGap()) + .setMaximumGap(product.getMaximumGap()).setTopup(product.isCanUseForTopup()) + .setClientActiveLoanOptions(clientActiveLoanOptions).setIsEqualAmortization(product.isEqualAmortization()) + .setFixedPrincipalPercentagePerInstallment(product.getFixedPrincipalPercentagePerInstallment()) + .setDelinquent(CollectionData.template()).setDisallowExpectedDisbursements(product.getDisallowExpectedDisbursements()); } public static LoanAccountData populateLoanProductDefaults(final LoanAccountData acc, final LoanProductData product) { - final LoanScheduleData repaymentSchedule = null; - final Collection transactions = null; - final Collection collateral = null; - final Collection guarantors = null; - final Collection notes = null; - final CalendarData calendarData = null; - final Collection productOptions = null; - final Collection termFrequencyTypeOptions = null; - final Collection repaymentFrequencyTypeOptions = null; - final Collection repaymentStrategyOptions = null; - final Collection interestRateFrequencyTypeOptions = null; - final Collection amortizationTypeOptions = null; - final Collection interestTypeOptions = null; - final Collection interestCalculationPeriodTypeOptions = null; - final Collection fundOptions = null; - final Collection chargeOptions = null; - final ChargeData chargeTemplate = null; - final Collection loanOfficerOptions = null; - final Collection loanPurposeOptions = null; - final Collection loanCollateralOptions = null; - final Collection calendarOptions = null; - final PaidInAdvanceData paidInAdvance = null; - final Integer termFrequency = product.getNumberOfRepayments() * product.getRepaymentEvery(); final EnumOptionData termPeriodFrequencyType = product.getRepaymentFrequencyType(); @@ -1154,41 +563,58 @@ public final class LoanAccountData { } BigDecimal netDisbursalAmount = product.getPrincipal(); - if (charges != null && !charges.isEmpty()) { + if (!charges.isEmpty()) { for (LoanChargeData charge : charges) { netDisbursalAmount = netDisbursalAmount.subtract(charge.getAmount()); } } final CollectionData delinquent = CollectionData.template(); - final DelinquencyRangeData delinquencyRange = null; - return new LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, acc.clientId, acc.clientAccountNo, acc.clientName, - acc.clientOfficeId, acc.clientExternalId, acc.group, acc.loanType, product.getId(), product.getName(), - product.getDescription(), product.isLinkedToFloatingInterestRates(), product.getFundId(), product.getFundName(), - acc.loanPurposeId, acc.loanPurposeName, acc.loanOfficerId, acc.loanOfficerName, product.getCurrency(), - product.getPrincipal(), product.getPrincipal(), product.getPrincipal(), netDisbursalAmount, acc.totalOverpaid, - product.getInArrearsTolerance(), termFrequency, termPeriodFrequencyType, product.getNumberOfRepayments(), - product.getRepaymentEvery(), product.getRepaymentFrequencyType(), null, null, product.getTransactionProcessingStrategyId(), - product.getTransactionProcessingStrategyName(), product.getAmortizationType(), product.getInterestRatePerPeriod(), - product.getInterestRateFrequencyType(), product.getAnnualInterestRate(), product.getInterestType(), - product.isFloatingInterestRateCalculationAllowed(), product.getDefaultDifferentialLendingRate(), - product.getInterestCalculationPeriodType(), product.isAllowPartialPeriodInterestCalculation(), - acc.expectedFirstRepaymentOnDate, product.getGraceOnPrincipalPayment(), product.getRecurringMoratoriumOnPrincipalPeriods(), - product.getGraceOnInterestPayment(), product.getGraceOnInterestCharged(), acc.interestChargedFromDate, acc.timeline, - acc.summary, acc.feeChargesAtDisbursementCharged, repaymentSchedule, transactions, charges, collateral, guarantors, - calendarData, productOptions, termFrequencyTypeOptions, repaymentFrequencyTypeOptions, null, null, repaymentStrategyOptions, - interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions, - fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions, loanPurposeOptions, loanCollateralOptions, calendarOptions, - acc.syncDisbursementWithMeeting, acc.loanCounter, acc.loanProductCounter, notes, acc.accountLinkingOptions, - acc.linkedAccount, acc.disbursementDetails, product.getMultiDisburseLoan(), product.isCanDefineInstallmentAmount(), - acc.fixedEmiAmount, product.getOutstandingLoanBalance(), acc.emiAmountVariations, acc.memberVariations, product, - acc.inArrears, product.getGraceOnArrearsAgeing(), product.overdueFeeCharges(), acc.isNPA, product.getDaysInMonthType(), - product.getDaysInYearType(), product.isInterestRecalculationEnabled(), product.toLoanInterestRecalculationData(), - acc.originalSchedule, acc.createStandingInstructionAtDisbursement, paidInAdvance, acc.interestRatesPeriods, - product.isAllowVariableInstallments(), product.getMinimumGap(), product.getMaximumGap(), acc.subStatus, acc.canUseForTopup, - acc.clientActiveLoanOptions, acc.isTopup, acc.closureLoanId, acc.closureLoanAccountNo, acc.topupAmount, - product.isEqualAmortization(), acc.rates, acc.isRatesEnabled, product.getFixedPrincipalPercentagePerInstallment(), - delinquent, delinquencyRange, product.getDisallowExpectedDisbursements(), acc.fraud); + return new LoanAccountData().setId(acc.id).setAccountNo(acc.accountNo).setStatus(acc.status).setExternalId(acc.externalId) + .setClientId(acc.clientId).setClientAccountNo(acc.clientAccountNo).setClientName(acc.clientName) + .setClientOfficeId(acc.clientOfficeId).setClientExternalId(acc.clientExternalId).setGroup(acc.group) + .setLoanType(acc.loanType).setId(product.getId()).setLoanProductName(product.getName()) + .setLoanProductDescription(product.getDescription()) + .setLoanProductLinkedToFloatingRate(product.isLinkedToFloatingInterestRates()).setFundId(product.getFundId()) + .setFundName(product.getFundName()).setLoanPurposeId(acc.loanPurposeId).setLoanPurposeName(acc.loanPurposeName) + .setLoanOfficerId(acc.loanOfficerId).setLoanOfficerName(acc.loanOfficerName).setCurrency(product.getCurrency()) + .setPrincipal(product.getPrincipal()).setPrincipal(product.getPrincipal()).setPrincipal(product.getPrincipal()) + .setNetDisbursalAmount(netDisbursalAmount).setTotalOverpaid(acc.totalOverpaid) + .setInArrearsTolerance(product.getInArrearsTolerance()).setTermFrequency(termFrequency) + .setTermPeriodFrequencyType(termPeriodFrequencyType).setNumberOfRepayments(product.getNumberOfRepayments()) + .setRepaymentEvery(product.getRepaymentEvery()).setRepaymentFrequencyType(product.getRepaymentFrequencyType()) + .setTransactionProcessingStrategyCode(product.getTransactionProcessingStrategyCode()) + .setTransactionProcessingStrategyName(product.getTransactionProcessingStrategyName()) + .setAmortizationType(product.getAmortizationType()).setInterestRatePerPeriod(product.getInterestRatePerPeriod()) + .setInterestRateFrequencyType(product.getInterestRateFrequencyType()).setAnnualInterestRate(product.getAnnualInterestRate()) + .setInterestType(product.getInterestType()).setFloatingInterestRate(product.isFloatingInterestRateCalculationAllowed()) + .setInterestRateDifferential(product.getDefaultDifferentialLendingRate()) + .setInterestCalculationPeriodType(product.getInterestCalculationPeriodType()) + .setAllowPartialPeriodInterestCalculation(product.isAllowPartialPeriodInterestCalculation()) + .setExpectedFirstRepaymentOnDate(acc.expectedFirstRepaymentOnDate) + .setGraceOnPrincipalPayment(product.getGraceOnPrincipalPayment()) + .setRecurringMoratoriumOnPrincipalPeriods(product.getRecurringMoratoriumOnPrincipalPeriods()) + .setGraceOnInterestPayment(product.getGraceOnInterestPayment()) + .setGraceOnInterestCharged(product.getGraceOnInterestCharged()).setInterestChargedFromDate(acc.interestChargedFromDate) + .setTimeline(acc.timeline).setSummary(acc.summary).setFeeChargesAtDisbursementCharged(acc.feeChargesAtDisbursementCharged) + .setCharges(charges).setSyncDisbursementWithMeeting(acc.syncDisbursementWithMeeting).setLoanCounter(acc.loanCounter) + .setLoanProductCounter(acc.loanProductCounter).setAccountLinkingOptions(acc.accountLinkingOptions) + .setLinkedAccount(acc.linkedAccount).setDisbursementDetails(acc.disbursementDetails) + .setMultiDisburseLoan(product.getMultiDisburseLoan()).setCanDefineInstallmentAmount(product.isCanDefineInstallmentAmount()) + .setFixedEmiAmount(acc.fixedEmiAmount).setMaxOutstandingLoanBalance(product.getOutstandingLoanBalance()) + .setEmiAmountVariations(acc.emiAmountVariations).setMemberVariations(acc.memberVariations).setProduct(product) + .setInArrears(acc.inArrears).setGraceOnArrearsAgeing(product.getGraceOnArrearsAgeing()) + .setOverdueCharges(product.overdueFeeCharges()).setIsNPA(acc.isNPA).setDaysInMonthType(product.getDaysInMonthType()) + .setDaysInYearType(product.getDaysInYearType()).setInterestRecalculationEnabled(product.isInterestRecalculationEnabled()) + .setInterestRecalculationData(product.toLoanInterestRecalculationData()).setOriginalSchedule(acc.originalSchedule) + .setCreateStandingInstructionAtDisbursement(acc.createStandingInstructionAtDisbursement) + .setInterestRatesPeriods(acc.interestRatesPeriods).setIsVariableInstallmentsAllowed(product.isAllowVariableInstallments()) + .setMinimumGap(product.getMinimumGap()).setMaximumGap(product.getMaximumGap()).setSubStatus(acc.subStatus) + .setCanUseForTopup(acc.canUseForTopup).setClientActiveLoanOptions(acc.clientActiveLoanOptions).setTopup(acc.isTopup) + .setClosureLoanId(acc.closureLoanId).setClosureLoanAccountNo(acc.closureLoanAccountNo).setTopupAmount(acc.topupAmount) + .setIsEqualAmortization(product.isEqualAmortization()).setRates(acc.rates).setIsRatesEnabled(acc.isRatesEnabled) + .setFixedPrincipalPercentagePerInstallment(product.getFixedPrincipalPercentagePerInstallment()).setDelinquent(delinquent) + .setDisallowExpectedDisbursements(product.getDisallowExpectedDisbursements()).setFraud(acc.fraud); } /* @@ -1203,7 +629,7 @@ public final class LoanAccountData { final BigDecimal approvedPrincipal, final BigDecimal netDisbursalAmount, final BigDecimal totalOverpaid, final BigDecimal inArrearsTolerance, final Integer termFrequency, final EnumOptionData termPeriodFrequencyType, final Integer numberOfRepayments, final Integer repaymentEvery, final EnumOptionData repaymentFrequencyType, - EnumOptionData repaymentFrequencyNthDayType, EnumOptionData repaymentFrequencyDayOfWeekType, final Long transactionStrategyId, + EnumOptionData repaymentFrequencyNthDayType, EnumOptionData repaymentFrequencyDayOfWeekType, final String transactionStrategy, final String transactionStrategyName, final EnumOptionData amortizationType, final BigDecimal interestRatePerPeriod, final EnumOptionData interestRateFrequencyType, final BigDecimal annualInterestRate, final EnumOptionData interestType, final boolean isFloatingInterestRate, final BigDecimal interestRateDifferential, @@ -1222,67 +648,44 @@ public final class LoanAccountData { final BigDecimal topupAmount, final boolean isEqualAmortization, final BigDecimal fixedPrincipalPercentagePerInstallment, final DelinquencyRangeData delinquencyRange, final boolean disallowExpectedDisbursements, final boolean fraud) { - final LoanScheduleData repaymentSchedule = null; - final Collection transactions = null; - final Collection charges = null; - final Collection collateral = null; - final Collection guarantors = null; - final Collection notes = null; - final CalendarData calendarData = null; - final Collection productOptions = null; - final Collection termFrequencyTypeOptions = null; - final Collection repaymentFrequencyTypeOptions = null; - final Collection repaymentFrequencyNthDayTypeOptions = null; - final Collection repaymentFrequencyDayOfWeekTypeOptions = null; - final Collection repaymentStrategyOptions = null; - final Collection interestRateFrequencyTypeOptions = null; - final Collection amortizationTypeOptions = null; - final Collection interestTypeOptions = null; - final Collection interestCalculationPeriodTypeOptions = null; - final Collection fundOptions = null; - final Collection chargeOptions = null; - final ChargeData chargeTemplate = null; - final Collection loanOfficerOptions = null; - final Collection loanPurposeOptions = null; - final Collection loanCollateralOptions = null; - final Collection calendarOptions = null; - final Collection accountLinkingOptions = null; - final PortfolioAccountData linkedAccount = null; - final Collection disbursementData = null; - final Collection emiAmountVariations = null; - final Map memberVariations = null; - final LoanProductData product = null; - final Collection overdueCharges = null; - final LoanScheduleData originalSchedule = null; - final PaidInAdvanceData paidInAdvance = null; - final Collection interestRatesPeriods = null; - final Collection clientActiveLoanOptions = null; - final List rates = null; - final Boolean isRatesEnabled = false; final CollectionData delinquent = CollectionData.template(); - return new LoanAccountData(id, accountNo, status, externalId, clientId, clientAccountNo, clientName, clientOfficeId, - clientExternalId, group, loanType, loanProductId, loanProductName, loanProductDescription, - isLoanProductLinkedToFloatingRate, fundId, fundName, loanPurposeId, loanPurposeName, loanOfficerId, loanOfficerName, - currencyData, proposedPrincipal, principal, approvedPrincipal, netDisbursalAmount, totalOverpaid, inArrearsTolerance, - termFrequency, termPeriodFrequencyType, numberOfRepayments, repaymentEvery, repaymentFrequencyType, - repaymentFrequencyNthDayType, repaymentFrequencyDayOfWeekType, transactionStrategyId, transactionStrategyName, - amortizationType, interestRatePerPeriod, interestRateFrequencyType, annualInterestRate, interestType, - isFloatingInterestRate, interestRateDifferential, interestCalculationPeriodType, allowPartialPeriodInterestCalcualtion, - expectedFirstRepaymentOnDate, graceOnPrincipalPayment, recurringMoratoriumOnPrincipalPeriods, graceOnInterestPayment, - graceOnInterestCharged, interestChargedFromDate, timeline, loanSummary, feeChargesDueAtDisbursementCharged, - repaymentSchedule, transactions, charges, collateral, guarantors, calendarData, productOptions, termFrequencyTypeOptions, - repaymentFrequencyTypeOptions, repaymentFrequencyNthDayTypeOptions, repaymentFrequencyDayOfWeekTypeOptions, - repaymentStrategyOptions, interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions, - interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions, loanPurposeOptions, - loanCollateralOptions, calendarOptions, syncDisbursementWithMeeting, loanCounter, loanProductCounter, notes, - accountLinkingOptions, linkedAccount, disbursementData, multiDisburseLoan, canDefineInstallmentAmount, fixedEmiAmont, - outstandingLoanBalance, emiAmountVariations, memberVariations, product, inArrears, graceOnArrearsAgeing, overdueCharges, - isNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled, interestRecalculationData, originalSchedule, - createStandingInstructionAtDisbursement, paidInAdvance, interestRatesPeriods, isVariableInstallmentsAllowed, minimumGap, - maximumGap, subStatus, canUseForTopup, clientActiveLoanOptions, isTopup, closureLoanId, closureLoanAccountNo, topupAmount, - isEqualAmortization, rates, isRatesEnabled, fixedPrincipalPercentagePerInstallment, delinquent, delinquencyRange, - disallowExpectedDisbursements, fraud); + return new LoanAccountData().setId(id).setAccountNo(accountNo).setStatus(status).setExternalId(externalId).setClientId(clientId) + .setClientAccountNo(clientAccountNo).setClientName(clientName).setClientOfficeId(clientOfficeId) + .setClientExternalId(clientExternalId).setGroup(group).setLoanType(loanType).setLoanProductId(loanProductId) + .setLoanProductName(loanProductName).setLoanProductDescription(loanProductDescription) + .setLoanProductLinkedToFloatingRate(isLoanProductLinkedToFloatingRate).setFundId(fundId).setFundName(fundName) + .setLoanPurposeId(loanPurposeId).setLoanPurposeName(loanPurposeName).setLoanOfficerId(loanOfficerId) + .setLoanOfficerName(loanOfficerName).setCurrency(currencyData).setProposedPrincipal(proposedPrincipal) + .setPrincipal(principal).setApprovedPrincipal(approvedPrincipal).setNetDisbursalAmount(netDisbursalAmount) + .setTotalOverpaid(totalOverpaid).setInArrearsTolerance(inArrearsTolerance).setTermFrequency(termFrequency) + .setTermPeriodFrequencyType(termPeriodFrequencyType).setNumberOfRepayments(numberOfRepayments) + .setRepaymentEvery(repaymentEvery).setRepaymentFrequencyType(repaymentFrequencyType) + .setRepaymentFrequencyNthDayType(repaymentFrequencyNthDayType) + .setRepaymentFrequencyDayOfWeekType(repaymentFrequencyDayOfWeekType) + .setTransactionProcessingStrategyCode(transactionStrategy).setTransactionProcessingStrategyName(transactionStrategyName) + .setAmortizationType(amortizationType).setInterestRatePerPeriod(interestRatePerPeriod) + .setInterestRateFrequencyType(interestRateFrequencyType).setAnnualInterestRate(annualInterestRate) + .setInterestType(interestType).setFloatingInterestRate(isFloatingInterestRate) + .setInterestRateDifferential(interestRateDifferential).setInterestCalculationPeriodType(interestCalculationPeriodType) + .setAllowPartialPeriodInterestCalculation(allowPartialPeriodInterestCalcualtion) + .setExpectedFirstRepaymentOnDate(expectedFirstRepaymentOnDate).setGraceOnPrincipalPayment(graceOnPrincipalPayment) + .setRecurringMoratoriumOnPrincipalPeriods(recurringMoratoriumOnPrincipalPeriods) + .setGraceOnInterestPayment(graceOnInterestPayment).setGraceOnInterestCharged(graceOnInterestCharged) + .setInterestChargedFromDate(interestChargedFromDate).setTimeline(timeline).setSummary(loanSummary) + .setFeeChargesAtDisbursementCharged(feeChargesDueAtDisbursementCharged) + .setSyncDisbursementWithMeeting(syncDisbursementWithMeeting).setLoanCounter(loanCounter) + .setLoanProductCounter(loanProductCounter).setMultiDisburseLoan(multiDisburseLoan) + .setCanDefineInstallmentAmount(canDefineInstallmentAmount).setFixedEmiAmount(fixedEmiAmont) + .setMaxOutstandingLoanBalance(outstandingLoanBalance).setInArrears(inArrears).setGraceOnArrearsAgeing(graceOnArrearsAgeing) + .setIsNPA(isNPA).setDaysInMonthType(daysInMonthType).setDaysInYearType(daysInYearType) + .setInterestRecalculationEnabled(isInterestRecalculationEnabled).setInterestRecalculationData(interestRecalculationData) + .setCreateStandingInstructionAtDisbursement(createStandingInstructionAtDisbursement) + .setIsVariableInstallmentsAllowed(isVariableInstallmentsAllowed).setMinimumGap(minimumGap).setMaximumGap(maximumGap) + .setSubStatus(subStatus).setCanUseForTopup(canUseForTopup).setTopup(isTopup).setClosureLoanId(closureLoanId) + .setClosureLoanAccountNo(closureLoanAccountNo).setTopupAmount(topupAmount).setIsEqualAmortization(isEqualAmortization) + .setFixedPrincipalPercentagePerInstallment(fixedPrincipalPercentagePerInstallment).setDelinquent(delinquent) + .setDelinquencyRange(delinquencyRange).setDisallowExpectedDisbursements(disallowExpectedDisbursements).setFraud(fraud); } /* @@ -1308,36 +711,71 @@ public final class LoanAccountData { final Collection clientActiveLoanOptions, final List rates, final Boolean isRatesEnabled, final CollectionData delinquent) { - return new LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, acc.clientId, acc.clientAccountNo, acc.clientName, - acc.clientOfficeId, acc.clientExternalId, acc.group, acc.loanType, acc.loanProductId, acc.loanProductName, - acc.loanProductDescription, acc.isLoanProductLinkedToFloatingRate, acc.fundId, acc.fundName, acc.loanPurposeId, - acc.loanPurposeName, acc.loanOfficerId, acc.loanOfficerName, acc.currency, acc.proposedPrincipal, acc.principal, - acc.approvedPrincipal, acc.netDisbursalAmount, acc.totalOverpaid, acc.inArrearsTolerance, acc.termFrequency, - acc.termPeriodFrequencyType, acc.numberOfRepayments, acc.repaymentEvery, acc.repaymentFrequencyType, - acc.repaymentFrequencyNthDayType, acc.repaymentFrequencyDayOfWeekType, acc.transactionProcessingStrategyId, - acc.transactionProcessingStrategyName, acc.amortizationType, acc.interestRatePerPeriod, acc.interestRateFrequencyType, - acc.annualInterestRate, acc.interestType, acc.isFloatingInterestRate, acc.interestRateDifferential, - acc.interestCalculationPeriodType, acc.allowPartialPeriodInterestCalculation, acc.expectedFirstRepaymentOnDate, - acc.graceOnPrincipalPayment, acc.recurringMoratoriumOnPrincipalPeriods, acc.graceOnInterestPayment, - acc.graceOnInterestCharged, acc.interestChargedFromDate, acc.timeline, acc.summary, acc.feeChargesAtDisbursementCharged, - repaymentSchedule, transactions, charges, collateral, guarantors, calendarData, productOptions, termFrequencyTypeOptions, - repaymentFrequencyTypeOptions, repaymentFrequencyNthDayTypeOptions, repaymentFrequencyDayOfWeekTypeOptions, - transactionProcessingStrategyOptions, interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions, - interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions, loanPurposeOptions, - loanCollateralOptions, calendarOptions, acc.syncDisbursementWithMeeting, acc.loanCounter, acc.loanProductCounter, notes, - accountLinkingOptions, linkedAccount, disbursementDetails, acc.multiDisburseLoan, acc.canDefineInstallmentAmount, - acc.fixedEmiAmount, acc.maxOutstandingLoanBalance, emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears, - acc.graceOnArrearsAgeing, overdueCharges, acc.isNPA, acc.daysInMonthType, acc.daysInYearType, - acc.isInterestRecalculationEnabled, acc.interestRecalculationData, acc.originalSchedule, - acc.createStandingInstructionAtDisbursement, paidInAdvance, interestRatesPeriods, acc.isVariableInstallmentsAllowed, - acc.minimumGap, acc.maximumGap, acc.subStatus, acc.canUseForTopup, clientActiveLoanOptions, acc.isTopup, acc.closureLoanId, - acc.closureLoanAccountNo, acc.topupAmount, acc.isEqualAmortization, rates, isRatesEnabled, - acc.fixedPrincipalPercentagePerInstallment, delinquent, acc.delinquencyRange, acc.disallowExpectedDisbursements, acc.fraud); + // TODO: why are these variables 'calendarData', 'chargeTemplate' never used (see original private constructor) + + return new LoanAccountData().setId(acc.id).setAccountNo(acc.accountNo).setStatus(acc.status).setExternalId(acc.externalId) + .setClientId(acc.clientId).setClientAccountNo(acc.clientAccountNo).setClientName(acc.clientName) + .setClientOfficeId(acc.clientOfficeId).setClientExternalId(acc.clientExternalId).setGroup(acc.group) + .setLoanType(acc.loanType).setLoanProductId(acc.loanProductId).setLoanProductName(acc.loanProductName) + .setLoanProductDescription(acc.loanProductDescription) + .setLoanProductLinkedToFloatingRate(acc.isLoanProductLinkedToFloatingRate).setFundId(acc.fundId).setFundName(acc.fundName) + .setLoanPurposeId(acc.loanPurposeId).setLoanPurposeName(acc.loanPurposeName).setLoanOfficerId(acc.loanOfficerId) + .setLoanOfficerName(acc.loanOfficerName).setCurrency(acc.currency).setProposedPrincipal(acc.proposedPrincipal) + .setPrincipal(acc.principal).setApprovedPrincipal(acc.approvedPrincipal).setNetDisbursalAmount(acc.netDisbursalAmount) + .setTotalOverpaid(acc.totalOverpaid).setInArrearsTolerance(acc.inArrearsTolerance).setTermFrequency(acc.termFrequency) + .setTermPeriodFrequencyType(acc.termPeriodFrequencyType).setNumberOfRepayments(acc.numberOfRepayments) + .setRepaymentEvery(acc.repaymentEvery).setRepaymentFrequencyType(acc.repaymentFrequencyType) + .setRepaymentFrequencyNthDayType(acc.repaymentFrequencyNthDayType) + .setRepaymentFrequencyDayOfWeekType(acc.repaymentFrequencyDayOfWeekType) + .setTransactionProcessingStrategyCode(acc.transactionProcessingStrategyCode) + .setTransactionProcessingStrategyName(acc.transactionProcessingStrategyName).setAmortizationType(acc.amortizationType) + .setInterestRatePerPeriod(acc.interestRatePerPeriod).setInterestRateFrequencyType(acc.interestRateFrequencyType) + .setAnnualInterestRate(acc.annualInterestRate).setInterestType(acc.interestType) + .setFloatingInterestRate(acc.isFloatingInterestRate).setInterestRateDifferential(acc.interestRateDifferential) + .setInterestCalculationPeriodType(acc.interestCalculationPeriodType) + .setAllowPartialPeriodInterestCalculation(acc.allowPartialPeriodInterestCalculation) + .setExpectedFirstRepaymentOnDate(acc.expectedFirstRepaymentOnDate).setGraceOnPrincipalPayment(acc.graceOnPrincipalPayment) + .setRecurringMoratoriumOnPrincipalPeriods(acc.recurringMoratoriumOnPrincipalPeriods) + .setGraceOnInterestPayment(acc.graceOnInterestPayment).setGraceOnInterestCharged(acc.graceOnInterestCharged) + .setInterestChargedFromDate(acc.interestChargedFromDate).setTimeline(acc.timeline).setSummary(acc.summary) + .setFeeChargesAtDisbursementCharged(acc.feeChargesAtDisbursementCharged).setRepaymentSchedule(repaymentSchedule) + .setTransactions(transactions).setCharges(charges).setCollateral(collateral).setGuarantors(guarantors) + .setProductOptions(productOptions).setTermFrequencyTypeOptions(termFrequencyTypeOptions) + .setRepaymentFrequencyTypeOptions(repaymentFrequencyTypeOptions) + .setRepaymentFrequencyNthDayTypeOptions(repaymentFrequencyNthDayTypeOptions) + .setRepaymentFrequencyDaysOfWeekTypeOptions(repaymentFrequencyDayOfWeekTypeOptions) + .setTransactionProcessingStrategyOptions(transactionProcessingStrategyOptions) + .setInterestRateFrequencyTypeOptions(interestRateFrequencyTypeOptions).setAmortizationTypeOptions(amortizationTypeOptions) + .setInterestTypeOptions(interestTypeOptions).setInterestCalculationPeriodTypeOptions(interestCalculationPeriodTypeOptions) + .setFundOptions(fundOptions).setChargeOptions(chargeOptions).setLoanOfficerOptions(loanOfficerOptions) + .setLoanPurposeOptions(loanPurposeOptions).setLoanCollateralOptions(loanCollateralOptions) + // .setMeeting(calendarData) + .setCalendarOptions(calendarOptions).setSyncDisbursementWithMeeting(acc.syncDisbursementWithMeeting) + .setLoanCounter(acc.loanCounter).setLoanProductCounter(acc.loanProductCounter).setNotes(notes) + .setAccountLinkingOptions(accountLinkingOptions).setLinkedAccount(linkedAccount).setDisbursementDetails(disbursementDetails) + .setEmiAmountVariations(emiAmountVariations).setOverdueCharges(overdueCharges).setPaidInAdvance(paidInAdvance) + .setInterestRatesPeriods(interestRatesPeriods).setClientActiveLoanOptions(clientActiveLoanOptions).setRates(rates) + .setIsRatesEnabled(isRatesEnabled).setDelinquent(delinquent).setMultiDisburseLoan(acc.multiDisburseLoan) + .setCanDefineInstallmentAmount(acc.canDefineInstallmentAmount).setFixedEmiAmount(acc.fixedEmiAmount) + .setMaxOutstandingLoanBalance(acc.maxOutstandingLoanBalance).setMemberVariations(acc.memberVariations) + .setProduct(acc.product).setInArrears(acc.inArrears).setGraceOnArrearsAgeing(acc.graceOnArrearsAgeing).setIsNPA(acc.isNPA) + .setDaysInMonthType(acc.daysInMonthType).setDaysInYearType(acc.daysInYearType) + .setInterestRecalculationEnabled(acc.isInterestRecalculationEnabled) + .setInterestRecalculationData(acc.interestRecalculationData).setOriginalSchedule(acc.originalSchedule) + .setCreateStandingInstructionAtDisbursement(acc.createStandingInstructionAtDisbursement) + .setIsVariableInstallmentsAllowed(acc.isVariableInstallmentsAllowed).setMinimumGap(acc.minimumGap) + .setMaximumGap(acc.maximumGap).setSubStatus(acc.subStatus).setCanUseForTopup(acc.canUseForTopup).setTopup(acc.isTopup) + .setClosureLoanId(acc.closureLoanId).setClosureLoanAccountNo(acc.closureLoanAccountNo).setTopupAmount(acc.topupAmount) + .setIsEqualAmortization(acc.isEqualAmortization) + .setFixedPrincipalPercentagePerInstallment(acc.fixedPrincipalPercentagePerInstallment) + .setDelinquencyRange(acc.delinquencyRange).setDisallowExpectedDisbursements(acc.disallowExpectedDisbursements) + .setFraud(acc.fraud); } public static LoanAccountData associationsAndTemplate(final LoanAccountData acc, final Collection productOptions, final Collection allowedLoanOfficers, final Collection calendarOptions, final Collection accountLinkingOptions, final Boolean isRatesEnabled) { + return associationsAndTemplate(acc, acc.repaymentSchedule, acc.transactions, acc.charges, acc.collateral, acc.guarantors, acc.meeting, productOptions, acc.termFrequencyTypeOptions, acc.repaymentFrequencyTypeOptions, acc.repaymentFrequencyNthDayTypeOptions, acc.repaymentFrequencyDaysOfWeekTypeOptions, @@ -1350,33 +788,63 @@ public final class LoanAccountData { public static LoanAccountData associateGroup(final LoanAccountData acc, final GroupGeneralData group) { - return new LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, acc.clientId, acc.clientAccountNo, acc.clientName, - acc.clientOfficeId, acc.clientExternalId, group, acc.loanType, acc.loanProductId, acc.loanProductName, - acc.loanProductDescription, acc.isLoanProductLinkedToFloatingRate, acc.fundId, acc.fundName, acc.loanPurposeId, - acc.loanPurposeName, acc.loanOfficerId, acc.loanOfficerName, acc.currency, acc.proposedPrincipal, acc.principal, - acc.approvedPrincipal, acc.netDisbursalAmount, acc.totalOverpaid, acc.inArrearsTolerance, acc.termFrequency, - acc.termPeriodFrequencyType, acc.numberOfRepayments, acc.repaymentEvery, acc.repaymentFrequencyType, - acc.repaymentFrequencyNthDayType, acc.repaymentFrequencyDayOfWeekType, acc.transactionProcessingStrategyId, - acc.transactionProcessingStrategyName, acc.amortizationType, acc.interestRatePerPeriod, acc.interestRateFrequencyType, - acc.annualInterestRate, acc.interestType, acc.isFloatingInterestRate, acc.interestRateDifferential, - acc.interestCalculationPeriodType, acc.allowPartialPeriodInterestCalculation, acc.expectedFirstRepaymentOnDate, - acc.graceOnPrincipalPayment, acc.recurringMoratoriumOnPrincipalPeriods, acc.graceOnInterestPayment, - acc.graceOnInterestCharged, acc.interestChargedFromDate, acc.timeline, acc.summary, acc.feeChargesAtDisbursementCharged, - acc.repaymentSchedule, acc.transactions, acc.charges, acc.collateral, acc.guarantors, acc.meeting, acc.productOptions, - acc.termFrequencyTypeOptions, acc.repaymentFrequencyTypeOptions, acc.repaymentFrequencyNthDayTypeOptions, - acc.repaymentFrequencyDaysOfWeekTypeOptions, acc.transactionProcessingStrategyOptions, acc.interestRateFrequencyTypeOptions, - acc.amortizationTypeOptions, acc.interestTypeOptions, acc.interestCalculationPeriodTypeOptions, acc.fundOptions, - acc.chargeOptions, null, acc.loanOfficerOptions, acc.loanPurposeOptions, acc.loanCollateralOptions, acc.calendarOptions, - acc.syncDisbursementWithMeeting, acc.loanCounter, acc.loanProductCounter, acc.notes, acc.accountLinkingOptions, - acc.linkedAccount, acc.disbursementDetails, acc.multiDisburseLoan, acc.canDefineInstallmentAmount, acc.fixedEmiAmount, - acc.maxOutstandingLoanBalance, acc.emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears, - acc.graceOnArrearsAgeing, acc.overdueCharges, acc.isNPA, acc.daysInMonthType, acc.daysInYearType, - acc.isInterestRecalculationEnabled, acc.interestRecalculationData, acc.originalSchedule, - acc.createStandingInstructionAtDisbursement, acc.paidInAdvance, acc.interestRatesPeriods, acc.isVariableInstallmentsAllowed, - acc.minimumGap, acc.maximumGap, acc.subStatus, acc.canUseForTopup, acc.clientActiveLoanOptions, acc.isTopup, - acc.closureLoanId, acc.closureLoanAccountNo, acc.topupAmount, acc.isEqualAmortization, acc.rates, acc.isRatesEnabled, - acc.fixedPrincipalPercentagePerInstallment, acc.delinquent, acc.delinquencyRange, acc.disallowExpectedDisbursements, - acc.fraud); + return new LoanAccountData().setId(acc.id).setAccountNo(acc.accountNo).setStatus(acc.status).setExternalId(acc.externalId) + .setClientId(acc.clientId).setClientAccountNo(acc.clientAccountNo).setClientName(acc.clientName) + .setClientOfficeId(acc.clientOfficeId).setClientExternalId(acc.clientExternalId).setGroup(group).setLoanType(acc.loanType) + .setLoanProductId(acc.loanProductId).setLoanProductName(acc.loanProductName) + .setLoanProductDescription(acc.loanProductDescription) + .setLoanProductLinkedToFloatingRate(acc.isLoanProductLinkedToFloatingRate).setFundId(acc.fundId).setFundName(acc.fundName) + .setLoanPurposeId(acc.loanPurposeId).setLoanPurposeName(acc.loanPurposeName).setLoanOfficerId(acc.loanOfficerId) + .setLoanOfficerName(acc.loanOfficerName).setCurrency(acc.currency).setProposedPrincipal(acc.proposedPrincipal) + .setPrincipal(acc.principal).setApprovedPrincipal(acc.approvedPrincipal).setNetDisbursalAmount(acc.netDisbursalAmount) + .setTotalOverpaid(acc.totalOverpaid).setInArrearsTolerance(acc.inArrearsTolerance).setTermFrequency(acc.termFrequency) + .setTermPeriodFrequencyType(acc.termPeriodFrequencyType).setNumberOfRepayments(acc.numberOfRepayments) + .setRepaymentEvery(acc.repaymentEvery).setRepaymentFrequencyType(acc.repaymentFrequencyType) + .setRepaymentFrequencyNthDayType(acc.repaymentFrequencyNthDayType) + .setRepaymentFrequencyDayOfWeekType(acc.repaymentFrequencyDayOfWeekType) + .setTransactionProcessingStrategyCode(acc.transactionProcessingStrategyCode) + .setTransactionProcessingStrategyName(acc.transactionProcessingStrategyName).setAmortizationType(acc.amortizationType) + .setInterestRatePerPeriod(acc.interestRatePerPeriod).setInterestRateFrequencyType(acc.interestRateFrequencyType) + .setAnnualInterestRate(acc.annualInterestRate).setInterestType(acc.interestType) + .setFloatingInterestRate(acc.isFloatingInterestRate).setInterestRateDifferential(acc.interestRateDifferential) + .setInterestCalculationPeriodType(acc.interestCalculationPeriodType) + .setAllowPartialPeriodInterestCalculation(acc.allowPartialPeriodInterestCalculation) + .setExpectedFirstRepaymentOnDate(acc.expectedFirstRepaymentOnDate).setGraceOnPrincipalPayment(acc.graceOnPrincipalPayment) + .setRecurringMoratoriumOnPrincipalPeriods(acc.recurringMoratoriumOnPrincipalPeriods) + .setGraceOnInterestPayment(acc.graceOnInterestPayment).setGraceOnInterestCharged(acc.graceOnInterestCharged) + .setInterestChargedFromDate(acc.interestChargedFromDate).setTimeline(acc.timeline).setSummary(acc.summary) + .setFeeChargesAtDisbursementCharged(acc.feeChargesAtDisbursementCharged).setRepaymentSchedule(acc.repaymentSchedule) + .setTransactions(acc.transactions).setCharges(acc.charges).setCollateral(acc.collateral).setGuarantors(acc.guarantors) + .setMeeting(acc.meeting).setProductOptions(acc.productOptions).setTermFrequencyTypeOptions(acc.termFrequencyTypeOptions) + .setRepaymentFrequencyTypeOptions(acc.repaymentFrequencyTypeOptions) + .setRepaymentFrequencyNthDayTypeOptions(acc.repaymentFrequencyNthDayTypeOptions) + .setRepaymentFrequencyDaysOfWeekTypeOptions(acc.repaymentFrequencyDaysOfWeekTypeOptions) + .setTransactionProcessingStrategyOptions(acc.transactionProcessingStrategyOptions) + .setInterestRateFrequencyTypeOptions(acc.interestRateFrequencyTypeOptions) + .setAmortizationTypeOptions(acc.amortizationTypeOptions).setInterestTypeOptions(acc.interestTypeOptions) + .setInterestCalculationPeriodTypeOptions(acc.interestCalculationPeriodTypeOptions).setFundOptions(acc.fundOptions) + .setChargeOptions(acc.chargeOptions).setLoanOfficerOptions(acc.loanOfficerOptions) + .setLoanPurposeOptions(acc.loanPurposeOptions).setLoanCollateralOptions(acc.loanCollateralOptions) + .setCalendarOptions(acc.calendarOptions).setSyncDisbursementWithMeeting(acc.syncDisbursementWithMeeting) + .setLoanCounter(acc.loanCounter).setLoanProductCounter(acc.loanProductCounter).setNotes(acc.notes) + .setAccountLinkingOptions(acc.accountLinkingOptions).setLinkedAccount(acc.linkedAccount) + .setDisbursementDetails(acc.disbursementDetails).setMultiDisburseLoan(acc.multiDisburseLoan) + .setCanDefineInstallmentAmount(acc.canDefineInstallmentAmount).setFixedEmiAmount(acc.fixedEmiAmount) + .setMaxOutstandingLoanBalance(acc.maxOutstandingLoanBalance).setEmiAmountVariations(acc.emiAmountVariations) + .setMemberVariations(acc.memberVariations).setProduct(acc.product).setInArrears(acc.inArrears) + .setGraceOnArrearsAgeing(acc.graceOnArrearsAgeing).setOverdueCharges(acc.overdueCharges).setIsNPA(acc.isNPA) + .setDaysInMonthType(acc.daysInMonthType).setDaysInYearType(acc.daysInYearType) + .setInterestRecalculationEnabled(acc.isInterestRecalculationEnabled) + .setInterestRecalculationData(acc.interestRecalculationData).setOriginalSchedule(acc.originalSchedule) + .setCreateStandingInstructionAtDisbursement(acc.createStandingInstructionAtDisbursement).setPaidInAdvance(acc.paidInAdvance) + .setInterestRatesPeriods(acc.interestRatesPeriods).setIsVariableInstallmentsAllowed(acc.isVariableInstallmentsAllowed) + .setMinimumGap(acc.minimumGap).setMaximumGap(acc.maximumGap).setSubStatus(acc.subStatus) + .setCanUseForTopup(acc.canUseForTopup).setClientActiveLoanOptions(acc.clientActiveLoanOptions).setTopup(acc.isTopup) + .setClosureLoanId(acc.closureLoanId).setClosureLoanAccountNo(acc.closureLoanAccountNo).setTopupAmount(acc.topupAmount) + .setIsEqualAmortization(acc.isEqualAmortization).setRates(acc.rates).setIsRatesEnabled(acc.isRatesEnabled) + .setFixedPrincipalPercentagePerInstallment(acc.fixedPrincipalPercentagePerInstallment).setDelinquent(acc.delinquent) + .setDelinquencyRange(acc.delinquencyRange).setDisallowExpectedDisbursements(acc.disallowExpectedDisbursements) + .setFraud(acc.fraud); } public static LoanAccountData associateMemberVariations(final LoanAccountData acc, final Map memberLoanCycle) { @@ -1417,33 +885,63 @@ public final class LoanAccountData { memberVariations.put(clientId, borrowerCycleData); } - return new LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, acc.clientId, acc.clientAccountNo, acc.clientName, - acc.clientOfficeId, acc.clientExternalId, acc.group, acc.loanType, acc.loanProductId, acc.loanProductName, - acc.loanProductDescription, acc.isLoanProductLinkedToFloatingRate, acc.fundId, acc.fundName, acc.loanPurposeId, - acc.loanPurposeName, acc.loanOfficerId, acc.loanOfficerName, acc.currency, acc.proposedPrincipal, acc.principal, - acc.approvedPrincipal, acc.netDisbursalAmount, acc.totalOverpaid, acc.inArrearsTolerance, acc.termFrequency, - acc.termPeriodFrequencyType, acc.numberOfRepayments, acc.repaymentEvery, acc.repaymentFrequencyType, - acc.repaymentFrequencyNthDayType, acc.repaymentFrequencyDayOfWeekType, acc.transactionProcessingStrategyId, - acc.transactionProcessingStrategyName, acc.amortizationType, acc.interestRatePerPeriod, acc.interestRateFrequencyType, - acc.annualInterestRate, acc.interestType, acc.isFloatingInterestRate, acc.interestRateDifferential, - acc.interestCalculationPeriodType, acc.allowPartialPeriodInterestCalculation, acc.expectedFirstRepaymentOnDate, - acc.graceOnPrincipalPayment, acc.recurringMoratoriumOnPrincipalPeriods, acc.graceOnInterestPayment, - acc.graceOnInterestCharged, acc.interestChargedFromDate, acc.timeline, acc.summary, acc.feeChargesAtDisbursementCharged, - acc.repaymentSchedule, acc.transactions, acc.charges, acc.collateral, acc.guarantors, acc.meeting, acc.productOptions, - acc.termFrequencyTypeOptions, acc.repaymentFrequencyTypeOptions, acc.repaymentFrequencyNthDayTypeOptions, - acc.repaymentFrequencyDaysOfWeekTypeOptions, acc.transactionProcessingStrategyOptions, acc.interestRateFrequencyTypeOptions, - acc.amortizationTypeOptions, acc.interestTypeOptions, acc.interestCalculationPeriodTypeOptions, acc.fundOptions, - acc.chargeOptions, null, acc.loanOfficerOptions, acc.loanPurposeOptions, acc.loanCollateralOptions, acc.calendarOptions, - acc.syncDisbursementWithMeeting, acc.loanCounter, acc.loanProductCounter, acc.notes, acc.accountLinkingOptions, - acc.linkedAccount, acc.disbursementDetails, acc.multiDisburseLoan, acc.canDefineInstallmentAmount, acc.fixedEmiAmount, - acc.maxOutstandingLoanBalance, acc.emiAmountVariations, memberVariations, acc.product, acc.inArrears, - acc.graceOnArrearsAgeing, acc.overdueCharges, acc.isNPA, acc.daysInMonthType, acc.daysInYearType, - acc.isInterestRecalculationEnabled, acc.interestRecalculationData, acc.originalSchedule, - acc.createStandingInstructionAtDisbursement, acc.paidInAdvance, acc.interestRatesPeriods, acc.isVariableInstallmentsAllowed, - acc.minimumGap, acc.maximumGap, acc.subStatus, acc.canUseForTopup, acc.clientActiveLoanOptions, acc.isTopup, - acc.closureLoanId, acc.closureLoanAccountNo, acc.topupAmount, acc.isEqualAmortization, acc.rates, acc.isRatesEnabled, - acc.fixedPrincipalPercentagePerInstallment, acc.delinquent, acc.delinquencyRange, acc.disallowExpectedDisbursements, - acc.fraud); + return new LoanAccountData().setId(acc.id).setAccountNo(acc.accountNo).setStatus(acc.status).setExternalId(acc.externalId) + .setClientId(acc.clientId).setClientAccountNo(acc.clientAccountNo).setClientName(acc.clientName) + .setClientOfficeId(acc.clientOfficeId).setClientExternalId(acc.clientExternalId).setGroup(acc.group) + .setLoanType(acc.loanType).setLoanProductId(acc.loanProductId).setLoanProductName(acc.loanProductName) + .setLoanProductDescription(acc.loanProductDescription) + .setLoanProductLinkedToFloatingRate(acc.isLoanProductLinkedToFloatingRate).setFundId(acc.fundId).setFundName(acc.fundName) + .setLoanPurposeId(acc.loanPurposeId).setLoanPurposeName(acc.loanPurposeName).setLoanOfficerId(acc.loanOfficerId) + .setLoanOfficerName(acc.loanOfficerName).setCurrency(acc.currency).setProposedPrincipal(acc.proposedPrincipal) + .setPrincipal(acc.principal).setApprovedPrincipal(acc.approvedPrincipal).setNetDisbursalAmount(acc.netDisbursalAmount) + .setTotalOverpaid(acc.totalOverpaid).setInArrearsTolerance(acc.inArrearsTolerance).setTermFrequency(acc.termFrequency) + .setTermPeriodFrequencyType(acc.termPeriodFrequencyType).setNumberOfRepayments(acc.numberOfRepayments) + .setRepaymentEvery(acc.repaymentEvery).setRepaymentFrequencyType(acc.repaymentFrequencyType) + .setRepaymentFrequencyNthDayType(acc.repaymentFrequencyNthDayType) + .setRepaymentFrequencyDayOfWeekType(acc.repaymentFrequencyDayOfWeekType) + .setTransactionProcessingStrategyCode(acc.transactionProcessingStrategyCode) + .setTransactionProcessingStrategyName(acc.transactionProcessingStrategyName).setAmortizationType(acc.amortizationType) + .setInterestRatePerPeriod(acc.interestRatePerPeriod).setInterestRateFrequencyType(acc.interestRateFrequencyType) + .setAnnualInterestRate(acc.annualInterestRate).setInterestType(acc.interestType) + .setFloatingInterestRate(acc.isFloatingInterestRate).setInterestRateDifferential(acc.interestRateDifferential) + .setInterestCalculationPeriodType(acc.interestCalculationPeriodType) + .setAllowPartialPeriodInterestCalculation(acc.allowPartialPeriodInterestCalculation) + .setExpectedFirstRepaymentOnDate(acc.expectedFirstRepaymentOnDate).setGraceOnPrincipalPayment(acc.graceOnPrincipalPayment) + .setRecurringMoratoriumOnPrincipalPeriods(acc.recurringMoratoriumOnPrincipalPeriods) + .setGraceOnInterestPayment(acc.graceOnInterestPayment).setGraceOnInterestCharged(acc.graceOnInterestCharged) + .setInterestChargedFromDate(acc.interestChargedFromDate).setTimeline(acc.timeline).setSummary(acc.summary) + .setFeeChargesAtDisbursementCharged(acc.feeChargesAtDisbursementCharged).setRepaymentSchedule(acc.repaymentSchedule) + .setTransactions(acc.transactions).setCharges(acc.charges).setCollateral(acc.collateral).setGuarantors(acc.guarantors) + .setMeeting(acc.meeting).setProductOptions(acc.productOptions).setTermFrequencyTypeOptions(acc.termFrequencyTypeOptions) + .setRepaymentFrequencyTypeOptions(acc.repaymentFrequencyTypeOptions) + .setRepaymentFrequencyNthDayTypeOptions(acc.repaymentFrequencyNthDayTypeOptions) + .setRepaymentFrequencyDaysOfWeekTypeOptions(acc.repaymentFrequencyDaysOfWeekTypeOptions) + .setTransactionProcessingStrategyOptions(acc.transactionProcessingStrategyOptions) + .setInterestRateFrequencyTypeOptions(acc.interestRateFrequencyTypeOptions) + .setAmortizationTypeOptions(acc.amortizationTypeOptions).setInterestTypeOptions(acc.interestTypeOptions) + .setInterestCalculationPeriodTypeOptions(acc.interestCalculationPeriodTypeOptions).setFundOptions(acc.fundOptions) + .setChargeOptions(acc.chargeOptions).setLoanOfficerOptions(acc.loanOfficerOptions) + .setLoanPurposeOptions(acc.loanPurposeOptions).setLoanCollateralOptions(acc.loanCollateralOptions) + .setCalendarOptions(acc.calendarOptions).setSyncDisbursementWithMeeting(acc.syncDisbursementWithMeeting) + .setLoanCounter(acc.loanCounter).setLoanProductCounter(acc.loanProductCounter).setNotes(acc.notes) + .setAccountLinkingOptions(acc.accountLinkingOptions).setLinkedAccount(acc.linkedAccount) + .setDisbursementDetails(acc.disbursementDetails).setMultiDisburseLoan(acc.multiDisburseLoan) + .setCanDefineInstallmentAmount(acc.canDefineInstallmentAmount).setFixedEmiAmount(acc.fixedEmiAmount) + .setMaxOutstandingLoanBalance(acc.maxOutstandingLoanBalance).setEmiAmountVariations(acc.emiAmountVariations) + .setMemberVariations(memberVariations).setProduct(acc.product).setInArrears(acc.inArrears) + .setGraceOnArrearsAgeing(acc.graceOnArrearsAgeing).setOverdueCharges(acc.overdueCharges).setIsNPA(acc.isNPA) + .setDaysInMonthType(acc.daysInMonthType).setDaysInYearType(acc.daysInYearType) + .setInterestRecalculationEnabled(acc.isInterestRecalculationEnabled) + .setInterestRecalculationData(acc.interestRecalculationData).setOriginalSchedule(acc.originalSchedule) + .setCreateStandingInstructionAtDisbursement(acc.createStandingInstructionAtDisbursement).setPaidInAdvance(acc.paidInAdvance) + .setInterestRatesPeriods(acc.interestRatesPeriods).setIsVariableInstallmentsAllowed(acc.isVariableInstallmentsAllowed) + .setMinimumGap(acc.minimumGap).setMaximumGap(acc.maximumGap).setSubStatus(acc.subStatus) + .setCanUseForTopup(acc.canUseForTopup).setClientActiveLoanOptions(acc.clientActiveLoanOptions).setTopup(acc.isTopup) + .setClosureLoanId(acc.closureLoanId).setClosureLoanAccountNo(acc.closureLoanAccountNo).setTopupAmount(acc.topupAmount) + .setIsEqualAmortization(acc.isEqualAmortization).setRates(acc.rates).setIsRatesEnabled(acc.isRatesEnabled) + .setFixedPrincipalPercentagePerInstallment(acc.fixedPrincipalPercentagePerInstallment).setDelinquent(acc.delinquent) + .setDelinquencyRange(acc.delinquencyRange).setDisallowExpectedDisbursements(acc.disallowExpectedDisbursements) + .setFraud(acc.fraud); } public static LoanAccountData withInterestRecalculationCalendarData(final LoanAccountData acc, final CalendarData calendarData, @@ -1452,362 +950,189 @@ public final class LoanAccountData { final LoanInterestRecalculationData interestRecalculationData = LoanInterestRecalculationData .withCalendarData(acc.interestRecalculationData, calendarData, compoundingCalendarData); - return new LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, acc.clientId, acc.clientAccountNo, acc.clientName, - acc.clientOfficeId, acc.clientExternalId, acc.group, acc.loanType, acc.loanProductId, acc.loanProductName, - acc.loanProductDescription, acc.isLoanProductLinkedToFloatingRate, acc.fundId, acc.fundName, acc.loanPurposeId, - acc.loanPurposeName, acc.loanOfficerId, acc.loanOfficerName, acc.currency, acc.proposedPrincipal, acc.principal, - acc.approvedPrincipal, acc.netDisbursalAmount, acc.totalOverpaid, acc.inArrearsTolerance, acc.termFrequency, - acc.termPeriodFrequencyType, acc.numberOfRepayments, acc.repaymentEvery, acc.repaymentFrequencyType, - acc.repaymentFrequencyNthDayType, acc.repaymentFrequencyDayOfWeekType, acc.transactionProcessingStrategyId, - acc.transactionProcessingStrategyName, acc.amortizationType, acc.interestRatePerPeriod, acc.interestRateFrequencyType, - acc.annualInterestRate, acc.interestType, acc.isFloatingInterestRate, acc.interestRateDifferential, - acc.interestCalculationPeriodType, acc.allowPartialPeriodInterestCalculation, acc.expectedFirstRepaymentOnDate, - acc.graceOnPrincipalPayment, acc.recurringMoratoriumOnPrincipalPeriods, acc.graceOnInterestPayment, - acc.graceOnInterestCharged, acc.interestChargedFromDate, acc.timeline, acc.summary, acc.feeChargesAtDisbursementCharged, - acc.repaymentSchedule, acc.transactions, acc.charges, acc.collateral, acc.guarantors, acc.meeting, acc.productOptions, - acc.termFrequencyTypeOptions, acc.repaymentFrequencyTypeOptions, acc.repaymentFrequencyNthDayTypeOptions, - acc.repaymentFrequencyDaysOfWeekTypeOptions, acc.transactionProcessingStrategyOptions, acc.interestRateFrequencyTypeOptions, - acc.amortizationTypeOptions, acc.interestTypeOptions, acc.interestCalculationPeriodTypeOptions, acc.fundOptions, - acc.chargeOptions, null, acc.loanOfficerOptions, acc.loanPurposeOptions, acc.loanCollateralOptions, acc.calendarOptions, - acc.syncDisbursementWithMeeting, acc.loanCounter, acc.loanProductCounter, acc.notes, acc.accountLinkingOptions, - acc.linkedAccount, acc.disbursementDetails, acc.multiDisburseLoan, acc.canDefineInstallmentAmount, acc.fixedEmiAmount, - acc.maxOutstandingLoanBalance, acc.emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears, - acc.graceOnArrearsAgeing, acc.overdueCharges, acc.isNPA, acc.daysInMonthType, acc.daysInYearType, - acc.isInterestRecalculationEnabled, interestRecalculationData, acc.originalSchedule, - acc.createStandingInstructionAtDisbursement, acc.paidInAdvance, acc.interestRatesPeriods, acc.isVariableInstallmentsAllowed, - acc.minimumGap, acc.maximumGap, acc.subStatus, acc.canUseForTopup, acc.clientActiveLoanOptions, acc.isTopup, - acc.closureLoanId, acc.closureLoanAccountNo, acc.topupAmount, acc.isEqualAmortization, acc.rates, acc.isRatesEnabled, - acc.fixedPrincipalPercentagePerInstallment, acc.delinquent, acc.delinquencyRange, acc.disallowExpectedDisbursements, - acc.fraud); + return new LoanAccountData().setId(acc.id).setAccountNo(acc.accountNo).setStatus(acc.status).setExternalId(acc.externalId) + .setClientId(acc.clientId).setClientAccountNo(acc.clientAccountNo).setClientName(acc.clientName) + .setClientOfficeId(acc.clientOfficeId).setClientExternalId(acc.clientExternalId).setGroup(acc.group) + .setLoanType(acc.loanType).setLoanProductId(acc.loanProductId).setLoanProductName(acc.loanProductName) + .setLoanProductDescription(acc.loanProductDescription) + .setLoanProductLinkedToFloatingRate(acc.isLoanProductLinkedToFloatingRate).setFundId(acc.fundId).setFundName(acc.fundName) + .setLoanPurposeId(acc.loanPurposeId).setLoanPurposeName(acc.loanPurposeName).setLoanOfficerId(acc.loanOfficerId) + .setLoanOfficerName(acc.loanOfficerName).setCurrency(acc.currency).setProposedPrincipal(acc.proposedPrincipal) + .setPrincipal(acc.principal).setApprovedPrincipal(acc.approvedPrincipal).setNetDisbursalAmount(acc.netDisbursalAmount) + .setTotalOverpaid(acc.totalOverpaid).setInArrearsTolerance(acc.inArrearsTolerance).setTermFrequency(acc.termFrequency) + .setTermPeriodFrequencyType(acc.termPeriodFrequencyType).setNumberOfRepayments(acc.numberOfRepayments) + .setRepaymentEvery(acc.repaymentEvery).setRepaymentFrequencyType(acc.repaymentFrequencyType) + .setRepaymentFrequencyNthDayType(acc.repaymentFrequencyNthDayType) + .setRepaymentFrequencyDayOfWeekType(acc.repaymentFrequencyDayOfWeekType) + .setTransactionProcessingStrategyCode(acc.transactionProcessingStrategyCode) + .setTransactionProcessingStrategyName(acc.transactionProcessingStrategyName).setAmortizationType(acc.amortizationType) + .setInterestRatePerPeriod(acc.interestRatePerPeriod).setInterestRateFrequencyType(acc.interestRateFrequencyType) + .setAnnualInterestRate(acc.annualInterestRate).setInterestType(acc.interestType) + .setFloatingInterestRate(acc.isFloatingInterestRate).setInterestRateDifferential(acc.interestRateDifferential) + .setInterestCalculationPeriodType(acc.interestCalculationPeriodType) + .setAllowPartialPeriodInterestCalculation(acc.allowPartialPeriodInterestCalculation) + .setExpectedFirstRepaymentOnDate(acc.expectedFirstRepaymentOnDate).setGraceOnPrincipalPayment(acc.graceOnPrincipalPayment) + .setRecurringMoratoriumOnPrincipalPeriods(acc.recurringMoratoriumOnPrincipalPeriods) + .setGraceOnInterestPayment(acc.graceOnInterestPayment).setGraceOnInterestCharged(acc.graceOnInterestCharged) + .setInterestChargedFromDate(acc.interestChargedFromDate).setTimeline(acc.timeline).setSummary(acc.summary) + .setFeeChargesAtDisbursementCharged(acc.feeChargesAtDisbursementCharged).setRepaymentSchedule(acc.repaymentSchedule) + .setTransactions(acc.transactions).setCharges(acc.charges).setCollateral(acc.collateral).setGuarantors(acc.guarantors) + .setMeeting(acc.meeting).setProductOptions(acc.productOptions).setTermFrequencyTypeOptions(acc.termFrequencyTypeOptions) + .setRepaymentFrequencyTypeOptions(acc.repaymentFrequencyTypeOptions) + .setRepaymentFrequencyNthDayTypeOptions(acc.repaymentFrequencyNthDayTypeOptions) + .setRepaymentFrequencyDaysOfWeekTypeOptions(acc.repaymentFrequencyDaysOfWeekTypeOptions) + .setTransactionProcessingStrategyOptions(acc.transactionProcessingStrategyOptions) + .setInterestRateFrequencyTypeOptions(acc.interestRateFrequencyTypeOptions) + .setAmortizationTypeOptions(acc.amortizationTypeOptions).setInterestTypeOptions(acc.interestTypeOptions) + .setInterestCalculationPeriodTypeOptions(acc.interestCalculationPeriodTypeOptions).setFundOptions(acc.fundOptions) + .setChargeOptions(acc.chargeOptions).setLoanOfficerOptions(acc.loanOfficerOptions) + .setLoanPurposeOptions(acc.loanPurposeOptions).setLoanCollateralOptions(acc.loanCollateralOptions) + .setCalendarOptions(acc.calendarOptions).setSyncDisbursementWithMeeting(acc.syncDisbursementWithMeeting) + .setLoanCounter(acc.loanCounter).setLoanProductCounter(acc.loanProductCounter).setNotes(acc.notes) + .setAccountLinkingOptions(acc.accountLinkingOptions).setLinkedAccount(acc.linkedAccount) + .setDisbursementDetails(acc.disbursementDetails).setMultiDisburseLoan(acc.multiDisburseLoan) + .setCanDefineInstallmentAmount(acc.canDefineInstallmentAmount).setFixedEmiAmount(acc.fixedEmiAmount) + .setMaxOutstandingLoanBalance(acc.maxOutstandingLoanBalance).setEmiAmountVariations(acc.emiAmountVariations) + .setMemberVariations(acc.memberVariations).setProduct(acc.product).setInArrears(acc.inArrears) + .setGraceOnArrearsAgeing(acc.graceOnArrearsAgeing).setOverdueCharges(acc.overdueCharges).setIsNPA(acc.isNPA) + .setDaysInMonthType(acc.daysInMonthType).setDaysInYearType(acc.daysInYearType) + .setInterestRecalculationEnabled(acc.isInterestRecalculationEnabled).setInterestRecalculationData(interestRecalculationData) + .setOriginalSchedule(acc.originalSchedule) + .setCreateStandingInstructionAtDisbursement(acc.createStandingInstructionAtDisbursement).setPaidInAdvance(acc.paidInAdvance) + .setInterestRatesPeriods(acc.interestRatesPeriods).setIsVariableInstallmentsAllowed(acc.isVariableInstallmentsAllowed) + .setMinimumGap(acc.minimumGap).setMaximumGap(acc.maximumGap).setSubStatus(acc.subStatus) + .setCanUseForTopup(acc.canUseForTopup).setClientActiveLoanOptions(acc.clientActiveLoanOptions).setTopup(acc.isTopup) + .setClosureLoanId(acc.closureLoanId).setClosureLoanAccountNo(acc.closureLoanAccountNo).setTopupAmount(acc.topupAmount) + .setIsEqualAmortization(acc.isEqualAmortization).setRates(acc.rates).setIsRatesEnabled(acc.isRatesEnabled) + .setFixedPrincipalPercentagePerInstallment(acc.fixedPrincipalPercentagePerInstallment).setDelinquent(acc.delinquent) + .setDelinquencyRange(acc.delinquencyRange).setDisallowExpectedDisbursements(acc.disallowExpectedDisbursements) + .setFraud(acc.fraud); } public static LoanAccountData withLoanCalendarData(final LoanAccountData acc, final CalendarData calendarData) { - return new LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, acc.clientId, acc.clientAccountNo, acc.clientName, - acc.clientOfficeId, acc.clientExternalId, acc.group, acc.loanType, acc.loanProductId, acc.loanProductName, - acc.loanProductDescription, acc.isLoanProductLinkedToFloatingRate, acc.fundId, acc.fundName, acc.loanPurposeId, - acc.loanPurposeName, acc.loanOfficerId, acc.loanOfficerName, acc.currency, acc.proposedPrincipal, acc.principal, - acc.approvedPrincipal, acc.netDisbursalAmount, acc.totalOverpaid, acc.inArrearsTolerance, acc.termFrequency, - acc.termPeriodFrequencyType, acc.numberOfRepayments, acc.repaymentEvery, acc.repaymentFrequencyType, - calendarData.getRepeatsOnNthDayOfMonth(), calendarData.getRepeatsOnDay(), acc.transactionProcessingStrategyId, - acc.transactionProcessingStrategyName, acc.amortizationType, acc.interestRatePerPeriod, acc.interestRateFrequencyType, - acc.annualInterestRate, acc.interestType, acc.isFloatingInterestRate, acc.interestRateDifferential, - acc.interestCalculationPeriodType, acc.allowPartialPeriodInterestCalculation, acc.expectedFirstRepaymentOnDate, - acc.graceOnPrincipalPayment, acc.recurringMoratoriumOnPrincipalPeriods, acc.graceOnInterestPayment, - acc.graceOnInterestCharged, acc.interestChargedFromDate, acc.timeline, acc.summary, acc.feeChargesAtDisbursementCharged, - acc.repaymentSchedule, acc.transactions, acc.charges, acc.collateral, acc.guarantors, acc.meeting, acc.productOptions, - acc.termFrequencyTypeOptions, acc.repaymentFrequencyTypeOptions, acc.repaymentFrequencyNthDayTypeOptions, - acc.repaymentFrequencyDaysOfWeekTypeOptions, acc.transactionProcessingStrategyOptions, acc.interestRateFrequencyTypeOptions, - acc.amortizationTypeOptions, acc.interestTypeOptions, acc.interestCalculationPeriodTypeOptions, acc.fundOptions, - acc.chargeOptions, null, acc.loanOfficerOptions, acc.loanPurposeOptions, acc.loanCollateralOptions, acc.calendarOptions, - acc.syncDisbursementWithMeeting, acc.loanCounter, acc.loanProductCounter, acc.notes, acc.accountLinkingOptions, - acc.linkedAccount, acc.disbursementDetails, acc.multiDisburseLoan, acc.canDefineInstallmentAmount, acc.fixedEmiAmount, - acc.maxOutstandingLoanBalance, acc.emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears, - acc.graceOnArrearsAgeing, acc.overdueCharges, acc.isNPA, acc.daysInMonthType, acc.daysInYearType, - acc.isInterestRecalculationEnabled, acc.interestRecalculationData, acc.originalSchedule, - acc.createStandingInstructionAtDisbursement, acc.paidInAdvance, acc.interestRatesPeriods, acc.isVariableInstallmentsAllowed, - acc.minimumGap, acc.maximumGap, acc.subStatus, acc.canUseForTopup, acc.clientActiveLoanOptions, acc.isTopup, - acc.closureLoanId, acc.closureLoanAccountNo, acc.topupAmount, acc.isEqualAmortization, acc.rates, acc.isRatesEnabled, - acc.fixedPrincipalPercentagePerInstallment, acc.delinquent, acc.delinquencyRange, acc.disallowExpectedDisbursements, - acc.fraud); + return new LoanAccountData().setId(acc.id).setAccountNo(acc.accountNo).setStatus(acc.status).setExternalId(acc.externalId) + .setClientId(acc.clientId).setClientAccountNo(acc.clientAccountNo).setClientName(acc.clientName) + .setClientOfficeId(acc.clientOfficeId).setClientExternalId(acc.clientExternalId).setGroup(acc.group) + .setLoanType(acc.loanType).setLoanProductId(acc.loanProductId).setLoanProductName(acc.loanProductName) + .setLoanProductDescription(acc.loanProductDescription) + .setLoanProductLinkedToFloatingRate(acc.isLoanProductLinkedToFloatingRate).setFundId(acc.fundId).setFundName(acc.fundName) + .setLoanPurposeId(acc.loanPurposeId).setLoanPurposeName(acc.loanPurposeName).setLoanOfficerId(acc.loanOfficerId) + .setLoanOfficerName(acc.loanOfficerName).setCurrency(acc.currency).setProposedPrincipal(acc.proposedPrincipal) + .setPrincipal(acc.principal).setApprovedPrincipal(acc.approvedPrincipal).setNetDisbursalAmount(acc.netDisbursalAmount) + .setTotalOverpaid(acc.totalOverpaid).setInArrearsTolerance(acc.inArrearsTolerance).setTermFrequency(acc.termFrequency) + .setTermPeriodFrequencyType(acc.termPeriodFrequencyType).setNumberOfRepayments(acc.numberOfRepayments) + .setRepaymentEvery(acc.repaymentEvery).setRepaymentFrequencyType(acc.repaymentFrequencyType).setMeeting(calendarData) + .setTransactionProcessingStrategyCode(acc.transactionProcessingStrategyCode) + .setTransactionProcessingStrategyName(acc.transactionProcessingStrategyName).setAmortizationType(acc.amortizationType) + .setInterestRatePerPeriod(acc.interestRatePerPeriod).setInterestRateFrequencyType(acc.interestRateFrequencyType) + .setAnnualInterestRate(acc.annualInterestRate).setInterestType(acc.interestType) + .setFloatingInterestRate(acc.isFloatingInterestRate).setInterestRateDifferential(acc.interestRateDifferential) + .setInterestCalculationPeriodType(acc.interestCalculationPeriodType) + .setAllowPartialPeriodInterestCalculation(acc.allowPartialPeriodInterestCalculation) + .setExpectedFirstRepaymentOnDate(acc.expectedFirstRepaymentOnDate).setGraceOnPrincipalPayment(acc.graceOnPrincipalPayment) + .setRecurringMoratoriumOnPrincipalPeriods(acc.recurringMoratoriumOnPrincipalPeriods) + .setGraceOnInterestPayment(acc.graceOnInterestPayment).setGraceOnInterestCharged(acc.graceOnInterestCharged) + .setInterestChargedFromDate(acc.interestChargedFromDate).setTimeline(acc.timeline).setSummary(acc.summary) + .setFeeChargesAtDisbursementCharged(acc.feeChargesAtDisbursementCharged).setRepaymentSchedule(acc.repaymentSchedule) + .setTransactions(acc.transactions).setCharges(acc.charges).setCollateral(acc.collateral).setGuarantors(acc.guarantors) + .setMeeting(acc.meeting).setProductOptions(acc.productOptions).setTermFrequencyTypeOptions(acc.termFrequencyTypeOptions) + .setRepaymentFrequencyTypeOptions(acc.repaymentFrequencyTypeOptions) + .setRepaymentFrequencyNthDayTypeOptions(acc.repaymentFrequencyNthDayTypeOptions) + .setRepaymentFrequencyDaysOfWeekTypeOptions(acc.repaymentFrequencyDaysOfWeekTypeOptions) + .setTransactionProcessingStrategyOptions(acc.transactionProcessingStrategyOptions) + .setInterestRateFrequencyTypeOptions(acc.interestRateFrequencyTypeOptions) + .setAmortizationTypeOptions(acc.amortizationTypeOptions).setInterestTypeOptions(acc.interestTypeOptions) + .setInterestCalculationPeriodTypeOptions(acc.interestCalculationPeriodTypeOptions).setFundOptions(acc.fundOptions) + .setChargeOptions(acc.chargeOptions).setLoanOfficerOptions(acc.loanOfficerOptions) + .setLoanPurposeOptions(acc.loanPurposeOptions).setLoanCollateralOptions(acc.loanCollateralOptions) + .setCalendarOptions(acc.calendarOptions).setSyncDisbursementWithMeeting(acc.syncDisbursementWithMeeting) + .setLoanCounter(acc.loanCounter).setLoanProductCounter(acc.loanProductCounter).setNotes(acc.notes) + .setAccountLinkingOptions(acc.accountLinkingOptions).setLinkedAccount(acc.linkedAccount) + .setDisbursementDetails(acc.disbursementDetails).setMultiDisburseLoan(acc.multiDisburseLoan) + .setCanDefineInstallmentAmount(acc.canDefineInstallmentAmount).setFixedEmiAmount(acc.fixedEmiAmount) + .setMaxOutstandingLoanBalance(acc.maxOutstandingLoanBalance).setEmiAmountVariations(acc.emiAmountVariations) + .setMemberVariations(acc.memberVariations).setProduct(acc.product).setInArrears(acc.inArrears) + .setGraceOnArrearsAgeing(acc.graceOnArrearsAgeing).setOverdueCharges(acc.overdueCharges).setIsNPA(acc.isNPA) + .setDaysInMonthType(acc.daysInMonthType).setDaysInYearType(acc.daysInYearType) + .setInterestRecalculationEnabled(acc.isInterestRecalculationEnabled) + .setInterestRecalculationData(acc.interestRecalculationData).setOriginalSchedule(acc.originalSchedule) + .setCreateStandingInstructionAtDisbursement(acc.createStandingInstructionAtDisbursement).setPaidInAdvance(acc.paidInAdvance) + .setInterestRatesPeriods(acc.interestRatesPeriods).setIsVariableInstallmentsAllowed(acc.isVariableInstallmentsAllowed) + .setMinimumGap(acc.minimumGap).setMaximumGap(acc.maximumGap).setSubStatus(acc.subStatus) + .setCanUseForTopup(acc.canUseForTopup).setClientActiveLoanOptions(acc.clientActiveLoanOptions).setTopup(acc.isTopup) + .setClosureLoanId(acc.closureLoanId).setClosureLoanAccountNo(acc.closureLoanAccountNo).setTopupAmount(acc.topupAmount) + .setIsEqualAmortization(acc.isEqualAmortization).setRates(acc.rates).setIsRatesEnabled(acc.isRatesEnabled) + .setFixedPrincipalPercentagePerInstallment(acc.fixedPrincipalPercentagePerInstallment).setDelinquent(acc.delinquent) + .setDelinquencyRange(acc.delinquencyRange).setDisallowExpectedDisbursements(acc.disallowExpectedDisbursements) + .setFraud(acc.fraud); } public static LoanAccountData withOriginalSchedule(final LoanAccountData acc, final LoanScheduleData originalSchedule) { - return new LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, acc.clientId, acc.clientAccountNo, acc.clientName, - acc.clientOfficeId, acc.clientExternalId, acc.group, acc.loanType, acc.loanProductId, acc.loanProductName, - acc.loanProductDescription, acc.isLoanProductLinkedToFloatingRate, acc.fundId, acc.fundName, acc.loanPurposeId, - acc.loanPurposeName, acc.loanOfficerId, acc.loanOfficerName, acc.currency, acc.proposedPrincipal, acc.principal, - acc.approvedPrincipal, acc.netDisbursalAmount, acc.totalOverpaid, acc.inArrearsTolerance, acc.termFrequency, - acc.termPeriodFrequencyType, acc.numberOfRepayments, acc.repaymentEvery, acc.repaymentFrequencyType, - acc.repaymentFrequencyNthDayType, acc.repaymentFrequencyDayOfWeekType, acc.transactionProcessingStrategyId, - acc.transactionProcessingStrategyName, acc.amortizationType, acc.interestRatePerPeriod, acc.interestRateFrequencyType, - acc.annualInterestRate, acc.interestType, acc.isFloatingInterestRate, acc.interestRateDifferential, - acc.interestCalculationPeriodType, acc.allowPartialPeriodInterestCalculation, acc.expectedFirstRepaymentOnDate, - acc.graceOnPrincipalPayment, acc.recurringMoratoriumOnPrincipalPeriods, acc.graceOnInterestPayment, - acc.graceOnInterestCharged, acc.interestChargedFromDate, acc.timeline, acc.summary, acc.feeChargesAtDisbursementCharged, - acc.repaymentSchedule, acc.transactions, acc.charges, acc.collateral, acc.guarantors, acc.meeting, acc.productOptions, - acc.termFrequencyTypeOptions, acc.repaymentFrequencyTypeOptions, acc.repaymentFrequencyNthDayTypeOptions, - acc.repaymentFrequencyDaysOfWeekTypeOptions, acc.transactionProcessingStrategyOptions, acc.interestRateFrequencyTypeOptions, - acc.amortizationTypeOptions, acc.interestTypeOptions, acc.interestCalculationPeriodTypeOptions, acc.fundOptions, - acc.chargeOptions, null, acc.loanOfficerOptions, acc.loanPurposeOptions, acc.loanCollateralOptions, acc.calendarOptions, - acc.syncDisbursementWithMeeting, acc.loanCounter, acc.loanProductCounter, acc.notes, acc.accountLinkingOptions, - acc.linkedAccount, acc.disbursementDetails, acc.multiDisburseLoan, acc.canDefineInstallmentAmount, acc.fixedEmiAmount, - acc.maxOutstandingLoanBalance, acc.emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears, - acc.graceOnArrearsAgeing, acc.overdueCharges, acc.isNPA, acc.daysInMonthType, acc.daysInYearType, - acc.isInterestRecalculationEnabled, acc.interestRecalculationData, originalSchedule, - acc.createStandingInstructionAtDisbursement, acc.paidInAdvance, acc.interestRatesPeriods, acc.isVariableInstallmentsAllowed, - acc.minimumGap, acc.maximumGap, acc.subStatus, acc.canUseForTopup, acc.clientActiveLoanOptions, acc.isTopup, - acc.closureLoanId, acc.closureLoanAccountNo, acc.topupAmount, acc.isEqualAmortization, acc.rates, acc.isRatesEnabled, - acc.fixedPrincipalPercentagePerInstallment, acc.delinquent, acc.delinquencyRange, acc.disallowExpectedDisbursements, - acc.fraud); + return new LoanAccountData().setId(acc.id).setAccountNo(acc.accountNo).setStatus(acc.status).setExternalId(acc.externalId) + .setClientId(acc.clientId).setClientAccountNo(acc.clientAccountNo).setClientName(acc.clientName) + .setClientOfficeId(acc.clientOfficeId).setClientExternalId(acc.clientExternalId).setGroup(acc.group) + .setLoanType(acc.loanType).setLoanProductId(acc.loanProductId).setLoanProductName(acc.loanProductName) + .setLoanProductDescription(acc.loanProductDescription) + .setLoanProductLinkedToFloatingRate(acc.isLoanProductLinkedToFloatingRate).setFundId(acc.fundId).setFundName(acc.fundName) + .setLoanPurposeId(acc.loanPurposeId).setLoanPurposeName(acc.loanPurposeName).setLoanOfficerId(acc.loanOfficerId) + .setLoanOfficerName(acc.loanOfficerName).setCurrency(acc.currency).setProposedPrincipal(acc.proposedPrincipal) + .setPrincipal(acc.principal).setApprovedPrincipal(acc.approvedPrincipal).setNetDisbursalAmount(acc.netDisbursalAmount) + .setTotalOverpaid(acc.totalOverpaid).setInArrearsTolerance(acc.inArrearsTolerance).setTermFrequency(acc.termFrequency) + .setTermPeriodFrequencyType(acc.termPeriodFrequencyType).setNumberOfRepayments(acc.numberOfRepayments) + .setRepaymentEvery(acc.repaymentEvery).setRepaymentFrequencyType(acc.repaymentFrequencyType) + .setRepaymentFrequencyNthDayType(acc.repaymentFrequencyNthDayType) + .setRepaymentFrequencyDayOfWeekType(acc.repaymentFrequencyDayOfWeekType) + .setTransactionProcessingStrategyCode(acc.transactionProcessingStrategyCode) + .setTransactionProcessingStrategyName(acc.transactionProcessingStrategyName).setAmortizationType(acc.amortizationType) + .setInterestRatePerPeriod(acc.interestRatePerPeriod).setInterestRateFrequencyType(acc.interestRateFrequencyType) + .setAnnualInterestRate(acc.annualInterestRate).setInterestType(acc.interestType) + .setFloatingInterestRate(acc.isFloatingInterestRate).setInterestRateDifferential(acc.interestRateDifferential) + .setInterestCalculationPeriodType(acc.interestCalculationPeriodType) + .setAllowPartialPeriodInterestCalculation(acc.allowPartialPeriodInterestCalculation) + .setExpectedFirstRepaymentOnDate(acc.expectedFirstRepaymentOnDate).setGraceOnPrincipalPayment(acc.graceOnPrincipalPayment) + .setRecurringMoratoriumOnPrincipalPeriods(acc.recurringMoratoriumOnPrincipalPeriods) + .setGraceOnInterestPayment(acc.graceOnInterestPayment).setGraceOnInterestCharged(acc.graceOnInterestCharged) + .setInterestChargedFromDate(acc.interestChargedFromDate).setTimeline(acc.timeline).setSummary(acc.summary) + .setFeeChargesAtDisbursementCharged(acc.feeChargesAtDisbursementCharged).setRepaymentSchedule(acc.repaymentSchedule) + .setTransactions(acc.transactions).setCharges(acc.charges).setCollateral(acc.collateral).setGuarantors(acc.guarantors) + .setMeeting(acc.meeting).setProductOptions(acc.productOptions).setTermFrequencyTypeOptions(acc.termFrequencyTypeOptions) + .setRepaymentFrequencyTypeOptions(acc.repaymentFrequencyTypeOptions) + .setRepaymentFrequencyNthDayTypeOptions(acc.repaymentFrequencyNthDayTypeOptions) + .setRepaymentFrequencyDaysOfWeekTypeOptions(acc.repaymentFrequencyDaysOfWeekTypeOptions) + .setTransactionProcessingStrategyOptions(acc.transactionProcessingStrategyOptions) + .setInterestRateFrequencyTypeOptions(acc.interestRateFrequencyTypeOptions) + .setAmortizationTypeOptions(acc.amortizationTypeOptions).setInterestTypeOptions(acc.interestTypeOptions) + .setInterestCalculationPeriodTypeOptions(acc.interestCalculationPeriodTypeOptions).setFundOptions(acc.fundOptions) + .setChargeOptions(acc.chargeOptions).setLoanOfficerOptions(acc.loanOfficerOptions) + .setLoanPurposeOptions(acc.loanPurposeOptions).setLoanCollateralOptions(acc.loanCollateralOptions) + .setCalendarOptions(acc.calendarOptions).setSyncDisbursementWithMeeting(acc.syncDisbursementWithMeeting) + .setLoanCounter(acc.loanCounter).setLoanProductCounter(acc.loanProductCounter).setNotes(acc.notes) + .setAccountLinkingOptions(acc.accountLinkingOptions).setLinkedAccount(acc.linkedAccount) + .setDisbursementDetails(acc.disbursementDetails).setMultiDisburseLoan(acc.multiDisburseLoan) + .setCanDefineInstallmentAmount(acc.canDefineInstallmentAmount).setFixedEmiAmount(acc.fixedEmiAmount) + .setMaxOutstandingLoanBalance(acc.maxOutstandingLoanBalance).setEmiAmountVariations(acc.emiAmountVariations) + .setMemberVariations(acc.memberVariations).setProduct(acc.product).setInArrears(acc.inArrears) + .setGraceOnArrearsAgeing(acc.graceOnArrearsAgeing).setOverdueCharges(acc.overdueCharges).setIsNPA(acc.isNPA) + .setDaysInMonthType(acc.daysInMonthType).setDaysInYearType(acc.daysInYearType) + .setInterestRecalculationEnabled(acc.isInterestRecalculationEnabled) + .setInterestRecalculationData(acc.interestRecalculationData).setOriginalSchedule(originalSchedule) + .setCreateStandingInstructionAtDisbursement(acc.createStandingInstructionAtDisbursement).setPaidInAdvance(acc.paidInAdvance) + .setInterestRatesPeriods(acc.interestRatesPeriods).setIsVariableInstallmentsAllowed(acc.isVariableInstallmentsAllowed) + .setMinimumGap(acc.minimumGap).setMaximumGap(acc.maximumGap).setSubStatus(acc.subStatus) + .setCanUseForTopup(acc.canUseForTopup).setClientActiveLoanOptions(acc.clientActiveLoanOptions).setTopup(acc.isTopup) + .setClosureLoanId(acc.closureLoanId).setClosureLoanAccountNo(acc.closureLoanAccountNo).setTopupAmount(acc.topupAmount) + .setIsEqualAmortization(acc.isEqualAmortization).setRates(acc.rates).setIsRatesEnabled(acc.isRatesEnabled) + .setFixedPrincipalPercentagePerInstallment(acc.fixedPrincipalPercentagePerInstallment).setDelinquent(acc.delinquent) + .setDelinquencyRange(acc.delinquencyRange).setDisallowExpectedDisbursements(acc.disallowExpectedDisbursements) + .setFraud(acc.fraud); } - private LoanAccountData(final Long id, // - final String accountNo, // - final LoanStatusEnumData status, // - final String externalId, // - final Long clientId, final String clientAccountNo, final String clientName, final Long clientOfficeId, - final String clientExternalId, // - final GroupGeneralData group, final EnumOptionData loanType, final Long loanProductId, final String loanProductName, - final String loanProductDescription, // - final boolean isLoanProductLinkedToFloatingRate, final Long fundId, final String fundName, final Long loanPurposeId, - final String loanPurposeName, // - final Long loanOfficerId, final String loanOfficerName, // - final CurrencyData currency, BigDecimal proposedPrincipal, final BigDecimal principal, final BigDecimal approvedPrincipal, - final BigDecimal netDisbursalAmount, final BigDecimal totalOverpaid, // - final BigDecimal inArrearsTolerance, final Integer termFrequency, // - final EnumOptionData termPeriodFrequencyType, final Integer numberOfRepayments, final Integer repaymentEvery, - final EnumOptionData repaymentFrequencyType, // - final EnumOptionData repaymentFrequencyNthDayType, final EnumOptionData repaymentFrequencyDayOfWeekType, - final Long transactionProcessingStrategyId, final String transactionProcessingStrategyName, - final EnumOptionData amortizationType, final BigDecimal interestRatePerPeriod, final EnumOptionData interestRateFrequencyType, - final BigDecimal annualInterestRate, final EnumOptionData interestType, final boolean isFloatingInterestRate, - final BigDecimal interestRateDifferential, final EnumOptionData interestCalculationPeriodType, - final Boolean allowPartialPeriodInterestCalculation, final LocalDate expectedFirstRepaymentOnDate, - final Integer graceOnPrincipalPayment, final Integer recurringMoratoriumOnPrincipalPeriods, - final Integer graceOnInterestPayment, final Integer graceOnInterestCharged, final LocalDate interestChargedFromDate, - final LoanApplicationTimelineData timeline, final LoanSummaryData summary, final BigDecimal feeChargesDueAtDisbursementCharged, - final LoanScheduleData repaymentSchedule, final Collection transactions, - final Collection charges, final Collection collateral, - final Collection guarantors, final CalendarData meeting, final Collection productOptions, - final Collection termFrequencyTypeOptions, final Collection repaymentFrequencyTypeOptions, - final Collection repaymentFrequencyNthDayTypeOptions, - final Collection repaymentFrequencyDaysOfWeekTypeOptions, - final Collection transactionProcessingStrategyOptions, - final Collection interestRateFrequencyTypeOptions, final Collection amortizationTypeOptions, - final Collection interestTypeOptions, final Collection interestCalculationPeriodTypeOptions, - final Collection fundOptions, final Collection chargeOptions, final ChargeData chargeTemplate, - final Collection loanOfficerOptions, final Collection loanPurposeOptions, - final Collection loanCollateralOptions, final Collection calendarOptions, - final Boolean syncDisbursementWithMeeting, final Integer loanCounter, final Integer loanProductCounter, - final Collection notes, final Collection accountLinkingOptions, - final PortfolioAccountData linkedAccount, final Collection disbursementDetails, - final Boolean multiDisburseLoan, final Boolean canDefineInstallmentAmount, BigDecimal fixedEmiAmount, - final BigDecimal maxOutstandingLoanBalance, final Collection emiAmountVariations, - final Map memberVariations, final LoanProductData product, final Boolean inArrears, - final Integer graceOnArrearsAgeing, final Collection overdueCharges, final Boolean isNPA, - final EnumOptionData daysInMonthType, final EnumOptionData daysInYearType, final boolean isInterestRecalculationEnabled, - final LoanInterestRecalculationData interestRecalculationData, final LoanScheduleData originalSchedule, - final Boolean createStandingInstructionAtDisbursement, final PaidInAdvanceData paidInAdvance, - final Collection interestRatesPeriods, final Boolean isVariableInstallmentsAllowed, - final Integer minimumGap, final Integer maximumGap, final EnumOptionData subStatus, final Boolean canUseForTopup, - final Collection clientActiveLoanOptions, final boolean isTopup, final Long closureLoanId, - final String closureLoanAccountNo, final BigDecimal topupAmount, final boolean isEqualAmortization, final List rates, - final Boolean isRatesEnabled, final BigDecimal fixedPrincipalPercentagePerInstallment, final CollectionData delinquent, - final DelinquencyRangeData delinquencyRange, final Boolean disallowExpectedDisbursements, final Boolean fraud) { - - this.id = id; - this.accountNo = accountNo; - this.status = status; - this.subStatus = subStatus; - this.externalId = externalId; - this.clientId = clientId; - this.clientAccountNo = clientAccountNo; - this.clientName = clientName; - this.clientOfficeId = clientOfficeId; - this.clientExternalId = clientExternalId; - this.group = group; - this.loanType = loanType; - this.loanProductId = loanProductId; - this.loanProductName = loanProductName; - this.loanProductDescription = loanProductDescription; - this.isLoanProductLinkedToFloatingRate = isLoanProductLinkedToFloatingRate; - this.fundId = fundId; - this.fundName = fundName; - this.loanPurposeId = loanPurposeId; - this.loanPurposeName = loanPurposeName; - this.loanOfficerId = loanOfficerId; - this.loanOfficerName = loanOfficerName; - this.currency = currency; - this.proposedPrincipal = proposedPrincipal; - this.principal = principal; - this.approvedPrincipal = approvedPrincipal; - this.netDisbursalAmount = netDisbursalAmount; - this.totalOverpaid = totalOverpaid; - this.inArrearsTolerance = inArrearsTolerance; - this.termFrequency = termFrequency; - this.termPeriodFrequencyType = termPeriodFrequencyType; - this.numberOfRepayments = numberOfRepayments; - this.repaymentEvery = repaymentEvery; - this.repaymentFrequencyType = repaymentFrequencyType; - this.repaymentFrequencyNthDayType = repaymentFrequencyNthDayType; - this.repaymentFrequencyDayOfWeekType = repaymentFrequencyDayOfWeekType; - this.transactionProcessingStrategyId = transactionProcessingStrategyId; - this.transactionProcessingStrategyName = transactionProcessingStrategyName; - this.amortizationType = amortizationType; - this.interestRatePerPeriod = interestRatePerPeriod; - this.interestRateFrequencyType = interestRateFrequencyType; - this.annualInterestRate = annualInterestRate; - this.interestType = interestType; - this.isFloatingInterestRate = isFloatingInterestRate; - this.interestRateDifferential = interestRateDifferential; - this.interestCalculationPeriodType = interestCalculationPeriodType; - this.allowPartialPeriodInterestCalculation = allowPartialPeriodInterestCalculation; - this.expectedFirstRepaymentOnDate = expectedFirstRepaymentOnDate; - this.graceOnPrincipalPayment = graceOnPrincipalPayment; - this.recurringMoratoriumOnPrincipalPeriods = recurringMoratoriumOnPrincipalPeriods; - - this.graceOnInterestPayment = graceOnInterestPayment; - this.graceOnInterestCharged = graceOnInterestCharged; - this.interestChargedFromDate = interestChargedFromDate; - this.timeline = timeline; - this.feeChargesAtDisbursementCharged = feeChargesDueAtDisbursementCharged; - this.syncDisbursementWithMeeting = syncDisbursementWithMeeting; - - // totals - this.summary = summary; - - // associations - this.repaymentSchedule = repaymentSchedule; - this.transactions = transactions; - this.charges = charges; - this.collateral = collateral; - this.guarantors = guarantors; - this.meeting = meeting; - this.notes = notes; - - // template - this.productOptions = productOptions; - this.termFrequencyTypeOptions = termFrequencyTypeOptions; - this.repaymentFrequencyTypeOptions = repaymentFrequencyTypeOptions; - this.repaymentFrequencyNthDayTypeOptions = repaymentFrequencyNthDayTypeOptions; - this.repaymentFrequencyDaysOfWeekTypeOptions = repaymentFrequencyDaysOfWeekTypeOptions; - this.interestRateFrequencyTypeOptions = interestRateFrequencyTypeOptions; - this.amortizationTypeOptions = amortizationTypeOptions; - this.interestTypeOptions = interestTypeOptions; - this.interestCalculationPeriodTypeOptions = interestCalculationPeriodTypeOptions; - this.isRatesEnabled = isRatesEnabled; - - if (CollectionUtils.isEmpty(transactionProcessingStrategyOptions)) { - this.transactionProcessingStrategyOptions = null; - } else { - this.transactionProcessingStrategyOptions = transactionProcessingStrategyOptions; - } - - if (CollectionUtils.isEmpty(fundOptions)) { - this.fundOptions = null; - } else { - this.fundOptions = fundOptions; - } - - if (CollectionUtils.isEmpty(chargeOptions)) { - this.chargeOptions = null; - } else { - this.chargeOptions = chargeOptions; - } - - if (CollectionUtils.isEmpty(loanOfficerOptions)) { - this.loanOfficerOptions = null; - } else { - this.loanOfficerOptions = loanOfficerOptions; - } - - if (CollectionUtils.isEmpty(loanPurposeOptions)) { - this.loanPurposeOptions = null; - } else { - this.loanPurposeOptions = loanPurposeOptions; - } - - if (CollectionUtils.isEmpty(loanCollateralOptions)) { - this.loanCollateralOptions = null; - } else { - this.loanCollateralOptions = loanCollateralOptions; - } - - if (CollectionUtils.isEmpty(calendarOptions)) { - this.calendarOptions = null; - } else { - this.calendarOptions = calendarOptions; - } - - this.loanCounter = loanCounter; - this.loanProductCounter = loanProductCounter; - - this.linkedAccount = linkedAccount; - this.accountLinkingOptions = accountLinkingOptions; - this.disbursementDetails = disbursementDetails; - this.multiDisburseLoan = multiDisburseLoan; - - Boolean canDefineEMIAmount = canDefineInstallmentAmount; - if (canDefineInstallmentAmount == null) { - canDefineEMIAmount = multiDisburseLoan; - } else if (multiDisburseLoan != null) { - canDefineEMIAmount = canDefineInstallmentAmount || multiDisburseLoan; - } - this.canDefineInstallmentAmount = canDefineEMIAmount; - this.fixedEmiAmount = fixedEmiAmount; - this.maxOutstandingLoanBalance = maxOutstandingLoanBalance; - - if (this.status != null && LoanStatus.fromInt(this.status.getId().intValue()).isApproved()) { - this.canDisburse = true; - } else { - boolean canDisburse = false; - if (this.multiDisburseLoan != null && this.multiDisburseLoan && this.disbursementDetails != null) { - for (DisbursementData disbursementData : this.disbursementDetails) { - if (!disbursementData.isDisbursed()) { - canDisburse = true; - } - } - } - this.canDisburse = canDisburse; - } - this.emiAmountVariations = emiAmountVariations; - this.memberVariations = memberVariations; - this.product = product; - this.inArrears = inArrears; - this.graceOnArrearsAgeing = graceOnArrearsAgeing; - this.overdueCharges = overdueCharges; - this.isNPA = isNPA; - - this.daysInMonthType = daysInMonthType; - this.daysInYearType = daysInYearType; - this.isInterestRecalculationEnabled = isInterestRecalculationEnabled; - this.interestRecalculationData = interestRecalculationData; - this.originalSchedule = originalSchedule; - this.createStandingInstructionAtDisbursement = createStandingInstructionAtDisbursement; - this.paidInAdvance = paidInAdvance; - if (this.product != null) { - this.product.setLoanProductConfigurableAttributes(product.getAllowAttributeOverrides()); - } - this.interestRatesPeriods = interestRatesPeriods; - this.isVariableInstallmentsAllowed = isVariableInstallmentsAllowed; - this.minimumGap = minimumGap; - this.maximumGap = maximumGap; - this.canUseForTopup = canUseForTopup; - this.clientActiveLoanOptions = clientActiveLoanOptions; - this.isTopup = isTopup; - this.closureLoanId = closureLoanId; - this.closureLoanAccountNo = closureLoanAccountNo; - this.topupAmount = topupAmount; - this.isEqualAmortization = isEqualAmortization; - this.rates = rates; - this.fixedPrincipalPercentagePerInstallment = fixedPrincipalPercentagePerInstallment; - this.delinquent = delinquent; - this.delinquencyRange = delinquencyRange; - this.disallowExpectedDisbursements = disallowExpectedDisbursements; - this.fraud = fraud; - } - - public RepaymentScheduleRelatedLoanData repaymentScheduleRelatedData() { - return this.timeline.repaymentScheduleRelatedData(this.currency, this.principal, this.approvedPrincipal, this.inArrearsTolerance, - this.feeChargesAtDisbursementCharged); - } - - public Long officeId() { - Long officeId = this.clientOfficeId; - if (officeId == null) { - officeId = groupOfficeId(); - } - return officeId; - } - - public Long groupOfficeId() { - return this.group == null ? null : this.group.officeId(); - } - - public Long groupId() { - return this.group == null ? null : this.group.getId(); - } + public static final Comparator ClientNameComparator = (loan1, loan2) -> { + String clientOfLoan1 = loan1.getClientName().toUpperCase(Locale.ENGLISH); + String clientOfLoan2 = loan2.getClientName().toUpperCase(Locale.ENGLISH); + return clientOfLoan1.compareTo(clientOfLoan2); + }; private static BigDecimal fetchLoanCycleDefaultValue(Collection borrowerCycleVariationData, Integer loanCycleNumber) { @@ -1836,93 +1161,10 @@ public final class LoanAccountData { && data.getLoanProductValueConditionType().equals(LoanProductValueConditionType.EQUAL); } - public void setProduct(LoanProductData product) { - this.product = product; - } - - public BigDecimal getTotalOutstandingAmount() { - if (this.summary != null) { - return this.summary.getTotalOutstanding(); - } else { - return null; - } - } - - public boolean isIsInterestRecalculationEnabled() { - return this.isInterestRecalculationEnabled; - } - - public boolean isInterestRecalculationEnabled() { - return this.isInterestRecalculationEnabled; - } - public Long getInterestRecalculationDetailId() { if (isInterestRecalculationEnabled) { return this.interestRecalculationData.getId(); } return null; } - - public boolean isActive() { - return LoanStatus.fromInt(this.status.getId().intValue()).isActive(); - } - - public BigDecimal getTotalPaidFeeCharges() { - if (this.summary != null) { - return this.summary.getFeeChargesPaid(); - } - return BigDecimal.ZERO; - } - - public boolean isMonthlyRepaymentFrequencyType() { - return (this.repaymentFrequencyType.getId().intValue() == PeriodFrequencyType.MONTHS.getValue()); - } - - /** - * Used to produce a {@link LoanAccountData} with only collateral options for now. - * - * @return {@link LoanAccountData} object - */ - public static LoanAccountData emptyTemplate() { - final Collection loanCollateralOptions = null; - - return LoanAccountData.collateralTemplate(loanCollateralOptions); - } - - public boolean isIsLoanProductLinkedToFloatingRate() { - return this.isLoanProductLinkedToFloatingRate; - } - - public boolean isLoanProductLinkedToFloatingRate() { - return this.isLoanProductLinkedToFloatingRate; - } - - public LocalDate getDisbursementDate() { - return this.timeline.getDisbursementDate(); - } - - public boolean isFloatingInterestRate() { - return this.isFloatingInterestRate; - } - - public boolean isIsFloatingInterestRate() { - return this.isFloatingInterestRate; - } - - public void setDatatables(final List datatables) { - this.datatables = datatables; - } - - public String getStatusStringValue() { - return this.status.getValue(); - } - - public boolean isTopup() { - return isTopup; - } - - public boolean isIsTopup() { - return isTopup; - } - } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java index f7dc17113..ac3f0a932 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java @@ -133,7 +133,6 @@ import org.apache.fineract.portfolio.loanproduct.domain.InterestRecalculationCom import org.apache.fineract.portfolio.loanproduct.domain.LoanProduct; import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRelatedDetail; import org.apache.fineract.portfolio.loanproduct.domain.LoanRescheduleStrategyMethod; -import org.apache.fineract.portfolio.loanproduct.domain.LoanTransactionProcessingStrategy; import org.apache.fineract.portfolio.loanproduct.domain.RecalculationFrequencyType; import org.apache.fineract.portfolio.loanproduct.service.LoanEnumerations; import org.apache.fineract.portfolio.paymentdetail.domain.PaymentDetail; @@ -159,7 +158,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom { public static final String FUND_ID = "fundId"; public static final String LOAN_OFFICER_ID = "loanOfficerId"; public static final String LOAN_PURPOSE_ID = "loanPurposeId"; - public static final String TRANSACTION_PROCESSING_STRATEGY_ID = "transactionProcessingStrategyId"; + public static final String TRANSACTION_PROCESSING_STRATEGY_CODE = "transactionProcessingStrategyCode"; public static final String SUBMITTED_ON_DATE = "submittedOnDate"; public static final String DATE_FORMAT = "dateFormat"; public static final String LOCALE = "locale"; @@ -226,9 +225,11 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom { @JoinColumn(name = "loanpurpose_cv_id", nullable = true) private CodeValue loanPurpose; - @ManyToOne(fetch = FetchType.EAGER) - @JoinColumn(name = "loan_transaction_strategy_id", nullable = true) - private LoanTransactionProcessingStrategy transactionProcessingStrategy; + @Column(name = "loan_transaction_strategy_code", nullable = false) + private String transactionProcessingStrategyCode; + + @Column(name = "loan_transaction_strategy_name") + private String transactionProcessingStrategyName; @Embedded private LoanProductRelatedDetail loanRepaymentScheduleDetail; @@ -431,48 +432,41 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom { public static Loan newIndividualLoanApplication(final String accountNo, final Client client, final Integer loanType, final LoanProduct loanProduct, final Fund fund, final Staff officer, final CodeValue loanPurpose, - final LoanTransactionProcessingStrategy transactionProcessingStrategy, - final LoanProductRelatedDetail loanRepaymentScheduleDetail, final Set loanCharges, - final Set collateral, final BigDecimal fixedEmiAmount, + final String transactionProcessingStrategyCode, final LoanProductRelatedDetail loanRepaymentScheduleDetail, + final Set loanCharges, final Set collateral, final BigDecimal fixedEmiAmount, final List disbursementDetails, final BigDecimal maxOutstandingLoanBalance, final Boolean createStandingInstructionAtDisbursement, final Boolean isFloatingInterestRate, final BigDecimal interestRateDifferential, final List rates, final BigDecimal fixedPrincipalPercentagePerInstallment) { - final LoanStatus status = null; - final Group group = null; - final Boolean syncDisbursementWithMeeting = null; - return new Loan(accountNo, client, group, loanType, fund, officer, loanPurpose, transactionProcessingStrategy, loanProduct, - loanRepaymentScheduleDetail, status, loanCharges, collateral, syncDisbursementWithMeeting, fixedEmiAmount, - disbursementDetails, maxOutstandingLoanBalance, createStandingInstructionAtDisbursement, isFloatingInterestRate, - interestRateDifferential, rates, fixedPrincipalPercentagePerInstallment); + return new Loan(accountNo, client, null, loanType, fund, officer, loanPurpose, transactionProcessingStrategyCode, loanProduct, + loanRepaymentScheduleDetail, null, loanCharges, collateral, null, fixedEmiAmount, disbursementDetails, + maxOutstandingLoanBalance, createStandingInstructionAtDisbursement, isFloatingInterestRate, interestRateDifferential, rates, + fixedPrincipalPercentagePerInstallment); } public static Loan newGroupLoanApplication(final String accountNo, final Group group, final Integer loanType, final LoanProduct loanProduct, final Fund fund, final Staff officer, final CodeValue loanPurpose, - final LoanTransactionProcessingStrategy transactionProcessingStrategy, - final LoanProductRelatedDetail loanRepaymentScheduleDetail, final Set loanCharges, - final Set collateral, final Boolean syncDisbursementWithMeeting, final BigDecimal fixedEmiAmount, - final List disbursementDetails, final BigDecimal maxOutstandingLoanBalance, - final Boolean createStandingInstructionAtDisbursement, final Boolean isFloatingInterestRate, - final BigDecimal interestRateDifferential, final List rates, final BigDecimal fixedPrincipalPercentagePerInstallment) { - final LoanStatus status = null; - final Client client = null; - return new Loan(accountNo, client, group, loanType, fund, officer, loanPurpose, transactionProcessingStrategy, loanProduct, - loanRepaymentScheduleDetail, status, loanCharges, collateral, syncDisbursementWithMeeting, fixedEmiAmount, + final String transactionProcessingStrategyCode, final LoanProductRelatedDetail loanRepaymentScheduleDetail, + final Set loanCharges, final Set collateral, final Boolean syncDisbursementWithMeeting, + final BigDecimal fixedEmiAmount, final List disbursementDetails, + final BigDecimal maxOutstandingLoanBalance, final Boolean createStandingInstructionAtDisbursement, + final Boolean isFloatingInterestRate, final BigDecimal interestRateDifferential, final List rates, + final BigDecimal fixedPrincipalPercentagePerInstallment) { + return new Loan(accountNo, null, group, loanType, fund, officer, loanPurpose, transactionProcessingStrategyCode, loanProduct, + loanRepaymentScheduleDetail, null, loanCharges, collateral, syncDisbursementWithMeeting, fixedEmiAmount, disbursementDetails, maxOutstandingLoanBalance, createStandingInstructionAtDisbursement, isFloatingInterestRate, interestRateDifferential, rates, fixedPrincipalPercentagePerInstallment); } public static Loan newIndividualLoanApplicationFromGroup(final String accountNo, final Client client, final Group group, final Integer loanType, final LoanProduct loanProduct, final Fund fund, final Staff officer, final CodeValue loanPurpose, - final LoanTransactionProcessingStrategy transactionProcessingStrategy, - final LoanProductRelatedDetail loanRepaymentScheduleDetail, final Set loanCharges, - final Set collateral, final Boolean syncDisbursementWithMeeting, final BigDecimal fixedEmiAmount, - final List disbursementDetails, final BigDecimal maxOutstandingLoanBalance, - final Boolean createStandingInstructionAtDisbursement, final Boolean isFloatingInterestRate, - final BigDecimal interestRateDifferential, final List rates, final BigDecimal fixedPrincipalPercentagePerInstallment) { - final LoanStatus status = null; - return new Loan(accountNo, client, group, loanType, fund, officer, loanPurpose, transactionProcessingStrategy, loanProduct, - loanRepaymentScheduleDetail, status, loanCharges, collateral, syncDisbursementWithMeeting, fixedEmiAmount, + final String transactionProcessingStrategyCode, final LoanProductRelatedDetail loanRepaymentScheduleDetail, + final Set loanCharges, final Set collateral, final Boolean syncDisbursementWithMeeting, + final BigDecimal fixedEmiAmount, final List disbursementDetails, + final BigDecimal maxOutstandingLoanBalance, final Boolean createStandingInstructionAtDisbursement, + final Boolean isFloatingInterestRate, final BigDecimal interestRateDifferential, final List rates, + final BigDecimal fixedPrincipalPercentagePerInstallment) { + return new Loan(accountNo, client, group, loanType, fund, officer, loanPurpose, transactionProcessingStrategyCode, loanProduct, + loanRepaymentScheduleDetail, null, loanCharges, collateral, syncDisbursementWithMeeting, fixedEmiAmount, disbursementDetails, maxOutstandingLoanBalance, createStandingInstructionAtDisbursement, isFloatingInterestRate, interestRateDifferential, rates, fixedPrincipalPercentagePerInstallment); } @@ -482,7 +476,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom { } private Loan(final String accountNo, final Client client, final Group group, final Integer loanType, final Fund fund, - final Staff loanOfficer, final CodeValue loanPurpose, final LoanTransactionProcessingStrategy transactionProcessingStrategy, + final Staff loanOfficer, final CodeValue loanPurpose, final String transactionProcessingStrategyCode, final LoanProduct loanProduct, final LoanProductRelatedDetail loanRepaymentScheduleDetail, final LoanStatus loanStatus, final Set loanCharges, final Set collateral, final Boolean syncDisbursementWithMeeting, final BigDecimal fixedEmiAmount, final List disbursementDetails, @@ -509,7 +503,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom { this.loanOfficer = loanOfficer; this.loanPurpose = loanPurpose; - this.transactionProcessingStrategy = transactionProcessingStrategy; + this.transactionProcessingStrategyCode = transactionProcessingStrategyCode; this.loanProduct = loanProduct; if (loanStatus != null) { this.loanStatus = loanStatus.getValue(); @@ -677,7 +671,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom { public ChangedTransactionDetail reprocessTransactions() { ChangedTransactionDetail changedTransactionDetail = null; final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory - .determineProcessor(this.transactionProcessingStrategy); + .determineProcessor(this.transactionProcessingStrategyCode); final List allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement(); changedTransactionDetail = loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(), allNonContraTransactionsPostDisbursement, getCurrency(), getRepaymentScheduleInstallments(), getActiveCharges()); @@ -747,7 +741,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom { loanLifecycleStateMachine.transition(LoanEvent.LOAN_CHARGE_PAYMENT, this); final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory - .determineProcessor(this.transactionProcessingStrategy); + .determineProcessor(this.transactionProcessingStrategyCode); final List chargePaymentInstallments = new ArrayList<>(); LocalDate startDate = getDisbursementDate(); List installments = getRepaymentScheduleInstallments(); @@ -829,7 +823,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom { removeOrModifyTransactionAssociatedWithLoanChargeIfDueAtDisbursement(loanCharge); final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory - .determineProcessor(this.transactionProcessingStrategy); + .determineProcessor(this.transactionProcessingStrategyCode); if (!loanCharge.isDueAtDisbursement() && loanCharge.isPaidOrPartiallyPaid(loanCurrency())) { /**** * TODO Vishwas Currently we do not allow removing a loan charge after a loan is approved (hence there is no @@ -897,7 +891,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom { } final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory - .determineProcessor(this.transactionProcessingStrategy); + .determineProcessor(this.transactionProcessingStrategyCode); if (!loanCharge.isDueAtDisbursement()) { /**** * TODO Vishwas Currently we do not allow waiving updating loan charge after a loan is approved (hence there @@ -1084,7 +1078,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom { // Waive of charges whose due date falls after latest 'repayment' // transaction dont require entire loan schedule to be reprocessed. final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory - .determineProcessor(this.transactionProcessingStrategy); + .determineProcessor(this.transactionProcessingStrategyCode); if (!loanCharge.isDueAtDisbursement() && loanCharge.isPaidOrPartiallyPaid(loanCurrency())) { /**** * TODO Vishwas Currently we do not allow waiving fully paid loan charge and waiving partially paid loan @@ -1161,8 +1155,10 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom { this.loanOfficer = newLoanOfficer; } - public void updateTransactionProcessingStrategy(final LoanTransactionProcessingStrategy strategy) { - this.transactionProcessingStrategy = strategy; + public void updateTransactionProcessingStrategy(final String transactionProcessingStrategyCode, + final String transactionProcessingStrategyName) { + this.transactionProcessingStrategyCode = transactionProcessingStrategyCode; + this.transactionProcessingStrategyName = transactionProcessingStrategyName; } public void updateLoanCharges(final Set loanCharges) { @@ -1495,9 +1491,9 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom { actualChanges.put(LOAN_PURPOSE_ID, newValue); } - if (command.isChangeInLongParameterNamed(TRANSACTION_PROCESSING_STRATEGY_ID, this.transactionProcessingStrategy.getId())) { - final Long newValue = command.longValueOfParameterNamed(TRANSACTION_PROCESSING_STRATEGY_ID); - actualChanges.put(TRANSACTION_PROCESSING_STRATEGY_ID, newValue); + if (command.isChangeInStringParameterNamed(TRANSACTION_PROCESSING_STRATEGY_CODE, transactionProcessingStrategyCode)) { + final String newValue = command.stringValueOfParameterNamed(TRANSACTION_PROCESSING_STRATEGY_CODE); + actualChanges.put(TRANSACTION_PROCESSING_STRATEGY_CODE, newValue); } if (command.isChangeInLocalDateParameterNamed(SUBMITTED_ON_DATE, getSubmittedOnDate())) { @@ -2008,7 +2004,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom { } - existingLoanCollateral = loanCollateralList.toArray(new LoanCollateralManagementData[loanCollateralList.size()]); + existingLoanCollateral = loanCollateralList.toArray(new LoanCollateralManagementData[0]); return existingLoanCollateral; } @@ -2022,7 +2018,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom { loanChargesList.add(loanCharge.toCommand()); } - existingLoanCharges = loanChargesList.toArray(new LoanChargeCommand[loanChargesList.size()]); + existingLoanCharges = loanChargesList.toArray(new LoanChargeCommand[0]); return existingLoanCharges; } @@ -2641,7 +2637,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom { final List allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement(); if (!allNonContraTransactionsPostDisbursement.isEmpty()) { final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory - .determineProcessor(this.transactionProcessingStrategy); + .determineProcessor(this.transactionProcessingStrategyCode); changedTransactionDetail = loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(), allNonContraTransactionsPostDisbursement, getCurrency(), getRepaymentScheduleInstallments(), getActiveCharges()); for (final Map.Entry mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) { @@ -3221,7 +3217,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom { } final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory - .determineProcessor(this.transactionProcessingStrategy); + .determineProcessor(this.transactionProcessingStrategyCode); final LoanRepaymentScheduleInstallment currentInstallment = fetchLoanRepaymentScheduleInstallment( loanTransaction.getTransactionDate()); @@ -3649,7 +3645,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom { writeOffTransaction.reverse(); loanLifecycleStateMachine.transition(LoanEvent.WRITE_OFF_OUTSTANDING_UNDO, this); final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory - .determineProcessor(this.transactionProcessingStrategy); + .determineProcessor(this.transactionProcessingStrategyCode); final List allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement(); if (this.repaymentScheduleDetail().isInterestRecalculationEnabled()) { regenerateRepaymentScheduleWithInterestRecalculation(scheduleGeneratorDTO); @@ -3724,7 +3720,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom { final AppUser currentUser, final ScheduleGeneratorDTO scheduleGeneratorDTO) { final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory - .determineProcessor(this.transactionProcessingStrategy); + .determineProcessor(this.transactionProcessingStrategyCode); ChangedTransactionDetail changedTransactionDetail = closeDisbursements(scheduleGeneratorDTO, loanRepaymentScheduleTransactionProcessor); @@ -3846,7 +3842,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom { throw new InvalidLoanStateTransitionException("close", "cannot.be.a.future.date", errorMessage, closureDate); } final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory - .determineProcessor(this.transactionProcessingStrategy); + .determineProcessor(this.transactionProcessingStrategyCode); ChangedTransactionDetail changedTransactionDetail = closeDisbursements(scheduleGeneratorDTO, loanRepaymentScheduleTransactionProcessor); @@ -5133,7 +5129,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom { } final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory - .determineProcessor(this.transactionProcessingStrategy); + .determineProcessor(this.transactionProcessingStrategyCode); final List allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement(); ChangedTransactionDetail changedTransactionDetail = loanRepaymentScheduleTransactionProcessor.handleTransaction( getDisbursementDate(), allNonContraTransactionsPostDisbursement, getCurrency(), getRepaymentScheduleInstallments(), @@ -5269,7 +5265,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom { public ChangedTransactionDetail processTransactions() { final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory - .determineProcessor(this.transactionProcessingStrategy); + .determineProcessor(this.transactionProcessingStrategyCode); final List allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement(); ChangedTransactionDetail changedTransactionDetail = loanRepaymentScheduleTransactionProcessor.handleTransaction( getDisbursementDate(), allNonContraTransactionsPostDisbursement, getCurrency(), getRepaymentScheduleInstallments(), @@ -5498,7 +5494,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom { public void processPostDisbursementTransactions() { final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory - .determineProcessor(this.transactionProcessingStrategy); + .determineProcessor(this.transactionProcessingStrategyCode); final List allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement(); final List copyTransactions = new ArrayList<>(); if (!allNonContraTransactionsPostDisbursement.isEmpty()) { @@ -5526,7 +5522,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom { final LoanApplicationTerms loanApplicationTerms = constructLoanApplicationTerms(generatorDTO); final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory - .determineProcessor(this.transactionProcessingStrategy); + .determineProcessor(this.transactionProcessingStrategyCode); return loanScheduleGenerator.rescheduleNextInstallments(mc, loanApplicationTerms, this, generatorDTO.getHolidayDetailDTO(), loanRepaymentScheduleTransactionProcessor, generatorDTO.getRecalculateFrom()); @@ -5544,7 +5540,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom { final LoanScheduleGenerator loanScheduleGenerator = scheduleGeneratorDTO.getLoanScheduleFactory().create(interestMethod); final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory - .determineProcessor(this.transactionProcessingStrategy); + .determineProcessor(this.transactionProcessingStrategyCode); installment = loanScheduleGenerator.calculatePrepaymentAmount(getCurrency(), onDate, loanApplicationTerms, mc, this, scheduleGeneratorDTO.getHolidayDetailDTO(), loanRepaymentScheduleTransactionProcessor); } else { @@ -5687,8 +5683,8 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom { } } - public LoanTransactionProcessingStrategy transactionProcessingStrategy() { - return this.transactionProcessingStrategy; + public String transactionProcessingStrategy() { + return this.transactionProcessingStrategyCode; } public boolean isNpa() { @@ -6096,7 +6092,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom { } final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory - .determineProcessor(this.transactionProcessingStrategy); + .determineProcessor(this.transactionProcessingStrategyCode); // If is a refund if (adjustedTransaction == null) { @@ -6130,7 +6126,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom { } final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory - .determineProcessor(this.transactionProcessingStrategy); + .determineProcessor(this.transactionProcessingStrategyCode); final Money overpaidAmount = calculateTotalOverpayment(); // Before Transaction if (overpaidAmount.isGreaterThanZero()) { chargebackTransaction.setOverPayments(overpaidAmount); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleTransactionProcessorFactory.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleTransactionProcessorFactory.java index 23e6ccfb6..08afe83fb 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleTransactionProcessorFactory.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleTransactionProcessorFactory.java @@ -18,56 +18,39 @@ */ package org.apache.fineract.portfolio.loanaccount.domain; +import java.util.List; +import java.util.Optional; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.LoanRepaymentScheduleTransactionProcessor; -import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.CreocoreLoanRepaymentScheduleTransactionProcessor; -import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.EarlyPaymentLoanRepaymentScheduleTransactionProcessor; -import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.FineractStyleLoanRepaymentScheduleTransactionProcessor; -import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.HeavensFamilyLoanRepaymentScheduleTransactionProcessor; -import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.InterestPrincipalPenaltyFeesOrderLoanRepaymentScheduleTransactionProcessor; -import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.PrincipalInterestPenaltyFeesOrderLoanRepaymentScheduleTransactionProcessor; -import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.RBILoanRepaymentScheduleTransactionProcessor; -import org.apache.fineract.portfolio.loanproduct.domain.LoanTransactionProcessingStrategy; -import org.springframework.stereotype.Component; +import org.apache.fineract.portfolio.loanaccount.exception.LoanTransactionProcessingStrategyNotFoundException; +import org.apache.fineract.portfolio.loanproduct.data.TransactionProcessingStrategyData; +import org.springframework.beans.factory.annotation.Value; -@Component +@Slf4j +@RequiredArgsConstructor public class LoanRepaymentScheduleTransactionProcessorFactory { - public LoanRepaymentScheduleTransactionProcessor determineProcessor( - final LoanTransactionProcessingStrategy transactionProcessingStrategy) { + private final LoanRepaymentScheduleTransactionProcessor defaultLoanRepaymentScheduleTransactionProcessor; - LoanRepaymentScheduleTransactionProcessor processor = new PrincipalInterestPenaltyFeesOrderLoanRepaymentScheduleTransactionProcessor(); + private final List processors; - if (transactionProcessingStrategy != null) { + @Value("${fineract.loan.transactionprocessor.error-not-found-fail}") + private Boolean errorNotFoundFail; - if (transactionProcessingStrategy.isStandardStrategy()) { - processor = new FineractStyleLoanRepaymentScheduleTransactionProcessor(); - } + public LoanRepaymentScheduleTransactionProcessor determineProcessor(final String transactionProcessingStrategy) { - if (transactionProcessingStrategy.isHeavensfamilyStrategy()) { - processor = new HeavensFamilyLoanRepaymentScheduleTransactionProcessor(); - } + Optional processor = processors.stream() + .filter(p -> p.accept(transactionProcessingStrategy)).findFirst(); - if (transactionProcessingStrategy.isEarlyPaymentStrategy()) { - processor = new EarlyPaymentLoanRepaymentScheduleTransactionProcessor(); - } - - if (transactionProcessingStrategy.isCreocoreStrategy()) { - processor = new CreocoreLoanRepaymentScheduleTransactionProcessor(); - } - - if (transactionProcessingStrategy.isIndianRBIStrategy()) { - processor = new RBILoanRepaymentScheduleTransactionProcessor(); - } - - if (transactionProcessingStrategy.isPrincipalInterestPenaltiesFeesOrderStrategy()) { - processor = new PrincipalInterestPenaltyFeesOrderLoanRepaymentScheduleTransactionProcessor(); - } - - if (transactionProcessingStrategy.isInterestPrincipalPenaltiesFeesOrderStrategy()) { - processor = new InterestPrincipalPenaltyFeesOrderLoanRepaymentScheduleTransactionProcessor(); - } + if (processor.isEmpty() && Boolean.TRUE.equals(errorNotFoundFail)) { + throw new LoanTransactionProcessingStrategyNotFoundException(transactionProcessingStrategy); + } else { + return processor.orElse(defaultLoanRepaymentScheduleTransactionProcessor); } + } - return processor; + public List getStrategies() { + return processors.stream().map(p -> new TransactionProcessingStrategyData(null, p.getCode(), p.getName())).toList(); } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/AbstractLoanRepaymentScheduleTransactionProcessor.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/AbstractLoanRepaymentScheduleTransactionProcessor.java index 8e8ed91e3..b13780e34 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/AbstractLoanRepaymentScheduleTransactionProcessor.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/AbstractLoanRepaymentScheduleTransactionProcessor.java @@ -55,6 +55,11 @@ import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.imp */ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implements LoanRepaymentScheduleTransactionProcessor { + @Override + public boolean accept(String s) { + return getCode().equalsIgnoreCase(s) || getName().equalsIgnoreCase(s); + } + /** * Provides support for passing all {@link LoanTransaction}'s so it will completely re-process the entire loan * schedule. This is required in cases where the {@link LoanTransaction} being processed is in the past and falls diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/LoanRepaymentScheduleTransactionProcessor.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/LoanRepaymentScheduleTransactionProcessor.java index b65d2d28a..41b051283 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/LoanRepaymentScheduleTransactionProcessor.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/LoanRepaymentScheduleTransactionProcessor.java @@ -30,6 +30,12 @@ import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction; public interface LoanRepaymentScheduleTransactionProcessor { + String getCode(); + + String getName(); + + boolean accept(String s); + void handleTransaction(LoanTransaction loanTransaction, MonetaryCurrency currency, List installments, Set charges); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/CreocoreLoanRepaymentScheduleTransactionProcessor.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/CreocoreLoanRepaymentScheduleTransactionProcessor.java index f097a86b7..d00d6f3ed 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/CreocoreLoanRepaymentScheduleTransactionProcessor.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/CreocoreLoanRepaymentScheduleTransactionProcessor.java @@ -40,6 +40,20 @@ import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.Loa */ public class CreocoreLoanRepaymentScheduleTransactionProcessor extends AbstractLoanRepaymentScheduleTransactionProcessor { + private static final String STRATEGY_CODE = "creocore-strategy"; + + private static final String STRATEGY_NAME = "Creocore Unique"; + + @Override + public String getCode() { + return STRATEGY_CODE; + } + + @Override + public String getName() { + return STRATEGY_NAME; + } + /** * For creocore, early is defined as any date before the installment due date */ diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/EarlyPaymentLoanRepaymentScheduleTransactionProcessor.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/EarlyPaymentLoanRepaymentScheduleTransactionProcessor.java index 932f650f5..f569e7278 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/EarlyPaymentLoanRepaymentScheduleTransactionProcessor.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/EarlyPaymentLoanRepaymentScheduleTransactionProcessor.java @@ -34,6 +34,20 @@ import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.Loa */ public class EarlyPaymentLoanRepaymentScheduleTransactionProcessor extends AbstractLoanRepaymentScheduleTransactionProcessor { + public static final String STRATEGY_CODE = "early-repayment-strategy"; + + private static final String STRATEGY_NAME = "Early Repayment Strategy"; + + @Override + public String getCode() { + return STRATEGY_CODE; + } + + @Override + public String getName() { + return STRATEGY_NAME; + } + /** * For early/'in advance' repayments, pay off in the same way as on-time payments, interest first, principal, * penalties and charges. diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/FineractStyleLoanRepaymentScheduleTransactionProcessor.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/FineractStyleLoanRepaymentScheduleTransactionProcessor.java index 901f03853..b14158c23 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/FineractStyleLoanRepaymentScheduleTransactionProcessor.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/FineractStyleLoanRepaymentScheduleTransactionProcessor.java @@ -40,6 +40,20 @@ import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.Loa @SuppressWarnings("unused") public class FineractStyleLoanRepaymentScheduleTransactionProcessor extends AbstractLoanRepaymentScheduleTransactionProcessor { + private static final String STRATEGY_CODE = "mifos-standard-strategy"; + + private static final String STRATEGY_NAME = "Penalties, Fees, Interest, Principal order"; + + @Override + public String getCode() { + return STRATEGY_CODE; + } + + @Override + public String getName() { + return STRATEGY_NAME; + } + @Override protected boolean isTransactionInAdvanceOfInstallment(final int currentInstallmentIndex, final List installments, final LocalDate transactionDate, final Money transactionAmount) { diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/HeavensFamilyLoanRepaymentScheduleTransactionProcessor.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/HeavensFamilyLoanRepaymentScheduleTransactionProcessor.java index 495c52ee3..b752e0c97 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/HeavensFamilyLoanRepaymentScheduleTransactionProcessor.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/HeavensFamilyLoanRepaymentScheduleTransactionProcessor.java @@ -41,6 +41,20 @@ import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.Loa @SuppressWarnings("unused") public class HeavensFamilyLoanRepaymentScheduleTransactionProcessor extends AbstractLoanRepaymentScheduleTransactionProcessor { + private static final String STRATEGY_CODE = "heavensfamily-strategy"; + + private static final String STRATEGY_NAME = "HeavensFamily Unique"; + + @Override + public String getCode() { + return STRATEGY_CODE; + } + + @Override + public String getName() { + return STRATEGY_NAME; + } + /** * For late repayments, pay off in the same way as on-time payments, interest first then principal. */ diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/InterestPrincipalPenaltyFeesOrderLoanRepaymentScheduleTransactionProcessor.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/InterestPrincipalPenaltyFeesOrderLoanRepaymentScheduleTransactionProcessor.java index fa4245b31..23b9d9648 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/InterestPrincipalPenaltyFeesOrderLoanRepaymentScheduleTransactionProcessor.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/InterestPrincipalPenaltyFeesOrderLoanRepaymentScheduleTransactionProcessor.java @@ -35,6 +35,20 @@ import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.Loa public class InterestPrincipalPenaltyFeesOrderLoanRepaymentScheduleTransactionProcessor extends AbstractLoanRepaymentScheduleTransactionProcessor { + private static final String STRATEGY_CODE = "interest-principal-penalties-fees-order-strategy"; + + private static final String STRATEGY_NAME = "Interest, Principal, Penalties, Fees Order"; + + @Override + public String getCode() { + return STRATEGY_CODE; + } + + @Override + public String getName() { + return STRATEGY_NAME; + } + /** * For early/'in advance' repayments, pay off in the same way as on-time payments, interest first, principal, * penalties and charges. diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/PrincipalInterestPenaltyFeesOrderLoanRepaymentScheduleTransactionProcessor.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/PrincipalInterestPenaltyFeesOrderLoanRepaymentScheduleTransactionProcessor.java index 51208eb75..725b1f774 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/PrincipalInterestPenaltyFeesOrderLoanRepaymentScheduleTransactionProcessor.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/PrincipalInterestPenaltyFeesOrderLoanRepaymentScheduleTransactionProcessor.java @@ -35,6 +35,20 @@ import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.Loa public class PrincipalInterestPenaltyFeesOrderLoanRepaymentScheduleTransactionProcessor extends AbstractLoanRepaymentScheduleTransactionProcessor { + private static final String STRATEGY_CODE = "principal-interest-penalties-fees-order-strategy"; + + private static final String STRATEGY_NAME = "Principal, Interest, Penalties, Fees Order"; + + @Override + public String getCode() { + return STRATEGY_CODE; + } + + @Override + public String getName() { + return STRATEGY_NAME; + } + /** * For early/'in advance' repayments, pay off in the same way as on-time payments, interest first, principal, * penalties and charges. diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/RBILoanRepaymentScheduleTransactionProcessor.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/RBILoanRepaymentScheduleTransactionProcessor.java index b2ee29627..c09200357 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/RBILoanRepaymentScheduleTransactionProcessor.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/RBILoanRepaymentScheduleTransactionProcessor.java @@ -43,6 +43,20 @@ import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.Loa */ public class RBILoanRepaymentScheduleTransactionProcessor extends AbstractLoanRepaymentScheduleTransactionProcessor { + private static final String STRATEGY_CODE = "rbi-india-strategy"; + + private static final String STRATEGY_NAME = "Overdue/Due Fee/Int,Principal"; + + @Override + public String getCode() { + return STRATEGY_CODE; + } + + @Override + public String getName() { + return STRATEGY_NAME; + } + /** * For creocore, early is defined as any date before the installment due date */ diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/exception/LoanTransactionProcessingStrategyNotFoundException.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/exception/LoanTransactionProcessingStrategyNotFoundException.java index c445d7ffa..35745f1d8 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/exception/LoanTransactionProcessingStrategyNotFoundException.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/exception/LoanTransactionProcessingStrategyNotFoundException.java @@ -25,8 +25,8 @@ import org.apache.fineract.infrastructure.core.exception.AbstractPlatformResourc */ public class LoanTransactionProcessingStrategyNotFoundException extends AbstractPlatformResourceNotFoundException { - public LoanTransactionProcessingStrategyNotFoundException(final Long id) { - super("error.msg.transactions.processing.strategy.id.invalid", - "Loan transaction processing strategy with identifier " + id + " does not exist", id); + public LoanTransactionProcessingStrategyNotFoundException(final String code) { + super("error.msg.transactions.processing.strategy.code.invalid", + "Loan transaction processing strategy with code " + code + " does not exist", code); } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanReschedulePreviewPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanReschedulePreviewPlatformServiceImpl.java index 8443e888b..ac794d877 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanReschedulePreviewPlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanReschedulePreviewPlatformServiceImpl.java @@ -28,7 +28,6 @@ import org.apache.fineract.organisation.monetary.domain.MoneyHelper; import org.apache.fineract.portfolio.loanaccount.data.LoanTermVariationsData; import org.apache.fineract.portfolio.loanaccount.data.ScheduleGeneratorDTO; import org.apache.fineract.portfolio.loanaccount.domain.Loan; -import org.apache.fineract.portfolio.loanaccount.domain.LoanLifecycleStateMachine; import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleTransactionProcessorFactory; import org.apache.fineract.portfolio.loanaccount.domain.LoanRescheduleRequestToTermVariationMapping; import org.apache.fineract.portfolio.loanaccount.domain.LoanSummaryWrapper; @@ -132,8 +131,7 @@ public class LoanReschedulePreviewPlatformServiceImpl implements LoanRescheduleP final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.loanRepaymentScheduleTransactionProcessorFactory .determineProcessor(loan.transactionProcessingStrategy()); final LoanScheduleGenerator loanScheduleGenerator = this.loanScheduleFactory.create(loanApplicationTerms.getInterestMethod()); - final LoanLifecycleStateMachine loanLifecycleStateMachine = null; - loan.setHelpers(loanLifecycleStateMachine, this.loanSummaryWrapper, this.loanRepaymentScheduleTransactionProcessorFactory); + loan.setHelpers(null, this.loanSummaryWrapper, this.loanRepaymentScheduleTransactionProcessorFactory); final LoanScheduleDTO loanSchedule = loanScheduleGenerator.rescheduleNextInstallments(mathContext, loanApplicationTerms, loan, loanApplicationTerms.getHolidayDetailDTO(), loanRepaymentScheduleTransactionProcessor, rescheduleFromDate); final LoanScheduleModel loanScheduleModel = loanSchedule.getLoanScheduleModel(); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/serialization/CalculateLoanScheduleQueryFromApiJsonHelper.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/serialization/CalculateLoanScheduleQueryFromApiJsonHelper.java index 56e494661..0b9f35062 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/serialization/CalculateLoanScheduleQueryFromApiJsonHelper.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/serialization/CalculateLoanScheduleQueryFromApiJsonHelper.java @@ -48,7 +48,7 @@ public final class CalculateLoanScheduleQueryFromApiJsonHelper { LoanApiConstants.clientIdParameterName, LoanApiConstants.groupIdParameterName, LoanApiConstants.loanTypeParameterName, LoanApiConstants.calendarIdParameterName, LoanApiConstants.productIdParameterName, LoanApiConstants.accountNoParameterName, LoanApiConstants.externalIdParameterName, LoanApiConstants.fundIdParameterName, LoanApiConstants.loanOfficerIdParameterName, - LoanApiConstants.loanPurposeIdParameterName, LoanApiConstants.transactionProcessingStrategyIdParameterName, + LoanApiConstants.loanPurposeIdParameterName, LoanApiConstants.transactionProcessingStrategyCodeParameterName, LoanApiConstants.principalParamName, LoanApiConstants.inArrearsToleranceParameterName, LoanApiConstants.interestRatePerPeriodParameterName, LoanApiConstants.repaymentEveryParameterName, LoanApiConstants.numberOfRepaymentsParameterName, LoanApiConstants.loanTermFrequencyParameterName, diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/serialization/LoanApplicationCommandFromApiJsonHelper.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/serialization/LoanApplicationCommandFromApiJsonHelper.java index 8e2a9dac2..5afc20029 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/serialization/LoanApplicationCommandFromApiJsonHelper.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/serialization/LoanApplicationCommandFromApiJsonHelper.java @@ -32,6 +32,8 @@ import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.apache.fineract.infrastructure.core.data.ApiParameterError; import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder; @@ -46,18 +48,22 @@ import org.apache.fineract.portfolio.collateralmanagement.domain.ClientCollatera import org.apache.fineract.portfolio.loanaccount.api.LoanApiConstants; import org.apache.fineract.portfolio.loanaccount.domain.Loan; import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge; +import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleTransactionProcessorFactory; +import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.LoanRepaymentScheduleTransactionProcessor; import org.apache.fineract.portfolio.loanaccount.exception.InvalidAmountOfCollateralQuantity; import org.apache.fineract.portfolio.loanaccount.exception.InvalidAmountOfCollaterals; import org.apache.fineract.portfolio.loanproduct.LoanProductConstants; +import org.apache.fineract.portfolio.loanproduct.data.TransactionProcessingStrategyData; import org.apache.fineract.portfolio.loanproduct.domain.AmortizationMethod; import org.apache.fineract.portfolio.loanproduct.domain.InterestCalculationPeriodMethod; import org.apache.fineract.portfolio.loanproduct.domain.InterestMethod; import org.apache.fineract.portfolio.loanproduct.domain.LoanProduct; import org.apache.fineract.portfolio.loanproduct.exception.EqualAmortizationUnsupportedFeatureException; import org.apache.fineract.portfolio.savings.domain.SavingsAccount; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +@Slf4j +@RequiredArgsConstructor @Component public final class LoanApplicationCommandFromApiJsonHelper { @@ -72,8 +78,8 @@ public final class LoanApplicationCommandFromApiJsonHelper { LoanApiConstants.numberOfRepaymentsParameterName, LoanApiConstants.repaymentEveryParameterName, LoanApiConstants.repaymentFrequencyTypeParameterName, LoanApiConstants.repaymentFrequencyNthDayTypeParameterName, LoanApiConstants.repaymentFrequencyDayOfWeekTypeParameterName, LoanApiConstants.interestRatePerPeriodParameterName, - LoanApiConstants.amortizationTypeParameterName, LoanApiConstants.interestTypeParameterName, - LoanApiConstants.isFloatingInterestRate, LoanApiConstants.interestRateDifferential, + LoanApiConstants.amortizationTypeParameterName, LoanApiConstants.amortizationTypeOptionsParameterName, + LoanApiConstants.interestTypeParameterName, LoanApiConstants.isFloatingInterestRate, LoanApiConstants.interestRateDifferential, LoanApiConstants.interestCalculationPeriodTypeParameterName, LoanProductConstants.ALLOW_PARTIAL_PERIOD_INTEREST_CALCUALTION_PARAM_NAME, LoanApiConstants.interestRateFrequencyTypeParameterName, LoanApiConstants.expectedDisbursementDateParameterName, @@ -84,7 +90,7 @@ public final class LoanApplicationCommandFromApiJsonHelper { LoanApiConstants.externalIdParameterName, LoanApiConstants.fundIdParameterName, LoanApiConstants.loanOfficerIdParameterName, // optional LoanApiConstants.loanPurposeIdParameterName, LoanApiConstants.inArrearsToleranceParameterName, LoanApiConstants.chargesParameterName, LoanApiConstants.collateralParameterName, // optional - LoanApiConstants.transactionProcessingStrategyIdParameterName, // settings + LoanApiConstants.transactionProcessingStrategyCodeParameterName, // settings LoanApiConstants.calendarIdParameterName, // optional LoanApiConstants.syncDisbursementWithMeetingParameterName, // optional LoanApiConstants.linkAccountIdParameterName, LoanApiConstants.disbursementDataParameterName, @@ -102,14 +108,7 @@ public final class LoanApplicationCommandFromApiJsonHelper { private final CalculateLoanScheduleQueryFromApiJsonHelper apiJsonHelper; private final ClientCollateralManagementRepositoryWrapper clientCollateralManagementRepositoryWrapper; - @Autowired - public LoanApplicationCommandFromApiJsonHelper(final FromJsonHelper fromApiJsonHelper, - final CalculateLoanScheduleQueryFromApiJsonHelper apiJsonHelper, - final ClientCollateralManagementRepositoryWrapper clientCollateralManagementRepositoryWrapper) { - this.fromApiJsonHelper = fromApiJsonHelper; - this.apiJsonHelper = apiJsonHelper; - this.clientCollateralManagementRepositoryWrapper = clientCollateralManagementRepositoryWrapper; - } + private final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory; public void validateForCreate(final String json, final boolean isMeetingMandatoryForJLGLoans, final LoanProduct loanProduct) { if (StringUtils.isBlank(json)) { @@ -388,10 +387,19 @@ public final class LoanApplicationCommandFromApiJsonHelper { .notExceedingLengthOf(500); } - final Long transactionProcessingStrategyId = this.fromApiJsonHelper - .extractLongNamed(LoanApiConstants.transactionProcessingStrategyIdParameterName, element); - baseDataValidator.reset().parameter(LoanApiConstants.transactionProcessingStrategyIdParameterName) - .value(transactionProcessingStrategyId).notNull().integerGreaterThanZero(); + final String transactionProcessingStrategy = this.fromApiJsonHelper + .extractStringNamed(LoanApiConstants.transactionProcessingStrategyCodeParameterName, element); + baseDataValidator.reset().parameter(LoanApiConstants.transactionProcessingStrategyCodeParameterName) + .value(transactionProcessingStrategy).notNull(); + LoanRepaymentScheduleTransactionProcessor processor = loanRepaymentScheduleTransactionProcessorFactory + .determineProcessor(transactionProcessingStrategy); + + if (processor == null) { + Object[] values = loanRepaymentScheduleTransactionProcessorFactory.getStrategies().stream() + .map(TransactionProcessingStrategyData::getCode).toList().toArray(new String[0]); + + baseDataValidator.reset().parameter(LoanApiConstants.transactionProcessingStrategyCodeParameterName).isOneOfTheseValues(values); + } if (this.fromApiJsonHelper.parameterExists(LoanApiConstants.linkAccountIdParameterName, element)) { final Long linkAccountId = this.fromApiJsonHelper.extractLongNamed(LoanApiConstants.linkAccountIdParameterName, element); @@ -626,12 +634,22 @@ public final class LoanApplicationCommandFromApiJsonHelper { .integerGreaterThanZero(); } - if (this.fromApiJsonHelper.parameterExists(LoanApiConstants.transactionProcessingStrategyIdParameterName, element)) { + if (this.fromApiJsonHelper.parameterExists(LoanApiConstants.transactionProcessingStrategyCodeParameterName, element)) { atLeastOneParameterPassedForUpdate = true; - final Long transactionProcessingStrategyId = this.fromApiJsonHelper - .extractLongNamed(LoanApiConstants.transactionProcessingStrategyIdParameterName, element); - baseDataValidator.reset().parameter(LoanApiConstants.transactionProcessingStrategyIdParameterName) - .value(transactionProcessingStrategyId).notNull().integerGreaterThanZero(); + final String transactionProcessingStrategy = this.fromApiJsonHelper + .extractStringNamed(LoanApiConstants.transactionProcessingStrategyCodeParameterName, element); + baseDataValidator.reset().parameter(LoanApiConstants.transactionProcessingStrategyCodeParameterName) + .value(transactionProcessingStrategy).notNull(); + LoanRepaymentScheduleTransactionProcessor processor = loanRepaymentScheduleTransactionProcessorFactory + .determineProcessor(transactionProcessingStrategy); + + if (processor == null) { + Object[] values = loanRepaymentScheduleTransactionProcessorFactory.getStrategies().stream() + .map(TransactionProcessingStrategyData::getCode).toList().toArray(new String[0]); + + baseDataValidator.reset().parameter(LoanApiConstants.transactionProcessingStrategyCodeParameterName) + .isOneOfTheseValues(values); + } } BigDecimal principal = null; diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanApplicationWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanApplicationWritePlatformServiceJpaRepositoryImpl.java index 8b96e84a2..f3153e7d4 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanApplicationWritePlatformServiceJpaRepositoryImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanApplicationWritePlatformServiceJpaRepositoryImpl.java @@ -128,7 +128,6 @@ import org.apache.fineract.portfolio.loanproduct.data.LoanProductData; import org.apache.fineract.portfolio.loanproduct.domain.LoanProduct; import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRelatedDetail; import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRepository; -import org.apache.fineract.portfolio.loanproduct.domain.LoanTransactionProcessingStrategy; import org.apache.fineract.portfolio.loanproduct.domain.RecalculationFrequencyType; import org.apache.fineract.portfolio.loanproduct.exception.LinkedAccountRequiredException; import org.apache.fineract.portfolio.loanproduct.exception.LoanProductNotFoundException; @@ -605,7 +604,9 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa productRelatedDetail.setRepayEvery(loan.loanProduct().getLoanProductRelatedDetail().getRepayEvery()); } if (!transactionProcessingStrategy) { - loan.updateTransactionProcessingStrategy(loan.loanProduct().getRepaymentStrategy()); + loan.updateTransactionProcessingStrategy(loan.loanProduct().getRepaymentStrategy(), + this.loanRepaymentScheduleTransactionProcessorFactory.determineProcessor(loan.loanProduct().getRepaymentStrategy()) + .getName()); } } @@ -933,12 +934,12 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa existingLoanApplication.updateLoanOfficerOnLoanApplication(newValue); } - final String strategyIdParamName = "transactionProcessingStrategyId"; - if (changes.containsKey(strategyIdParamName)) { - final Long strategyId = command.longValueOfParameterNamed(strategyIdParamName); - final LoanTransactionProcessingStrategy strategy = this.loanAssembler.findStrategyByIdIfProvided(strategyId); + final String strategyCodeParamName = "transactionProcessingStrategyCode"; + if (changes.containsKey(strategyCodeParamName)) { + final String strategy = command.stringValueOfParameterNamed(strategyCodeParamName); - existingLoanApplication.updateTransactionProcessingStrategy(strategy); + existingLoanApplication.updateTransactionProcessingStrategy(strategy, + this.loanRepaymentScheduleTransactionProcessorFactory.determineProcessor(strategy).getName()); } /** diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAssembler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAssembler.java index 1b2b9d46c..9635efad6 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAssembler.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAssembler.java @@ -70,10 +70,8 @@ import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleTra import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper; import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus; import org.apache.fineract.portfolio.loanaccount.domain.LoanSummaryWrapper; -import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionProcessingStrategyRepository; import org.apache.fineract.portfolio.loanaccount.exception.ExceedingTrancheCountException; import org.apache.fineract.portfolio.loanaccount.exception.InvalidAmountOfCollaterals; -import org.apache.fineract.portfolio.loanaccount.exception.LoanTransactionProcessingStrategyNotFoundException; import org.apache.fineract.portfolio.loanaccount.exception.MultiDisbursementDataNotAllowedException; import org.apache.fineract.portfolio.loanaccount.exception.MultiDisbursementDataRequiredException; import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanApplicationTerms; @@ -82,7 +80,6 @@ import org.apache.fineract.portfolio.loanaccount.loanschedule.service.LoanSchedu import org.apache.fineract.portfolio.loanproduct.domain.LoanProduct; import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRelatedDetail; import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRepository; -import org.apache.fineract.portfolio.loanproduct.domain.LoanTransactionProcessingStrategy; import org.apache.fineract.portfolio.loanproduct.exception.InvalidCurrencyException; import org.apache.fineract.portfolio.loanproduct.exception.LinkedAccountRequiredException; import org.apache.fineract.portfolio.loanproduct.exception.LoanProductNotFoundException; @@ -100,7 +97,6 @@ public class LoanAssembler { private final ClientRepositoryWrapper clientRepository; private final GroupRepository groupRepository; private final FundRepository fundRepository; - private final LoanTransactionProcessingStrategyRepository loanTransactionProcessingStrategyRepository; private final StaffRepository staffRepository; private final CodeValueRepositoryWrapper codeValueRepository; private final LoanScheduleAssembler loanScheduleAssembler; @@ -143,7 +139,10 @@ public class LoanAssembler { final Long productId = this.fromApiJsonHelper.extractLongNamed("productId", element); final Long fundId = this.fromApiJsonHelper.extractLongNamed("fundId", element); final Long loanOfficerId = this.fromApiJsonHelper.extractLongNamed("loanOfficerId", element); - final Long transactionProcessingStrategyId = this.fromApiJsonHelper.extractLongNamed("transactionProcessingStrategyId", element); + final String transactionProcessingStrategyCode = this.fromApiJsonHelper.extractStringNamed("transactionProcessingStrategyCode", + element); + final String transactionProcessingStrategyName = this.loanRepaymentScheduleTransactionProcessorFactory + .determineProcessor(transactionProcessingStrategyCode).getName(); final Long loanPurposeId = this.fromApiJsonHelper.extractLongNamed("loanPurposeId", element); final Boolean syncDisbursementWithMeeting = this.fromApiJsonHelper.extractBooleanNamed("syncDisbursementWithMeeting", element); final Boolean createStandingInstructionAtDisbursement = this.fromApiJsonHelper @@ -155,8 +154,6 @@ public class LoanAssembler { .extractBigDecimalWithLocaleNamed(LoanApiConstants.disbursementPrincipalParameterName, element); final Fund fund = findFundByIdIfProvided(fundId); final Staff loanOfficer = findLoanOfficerByIdIfProvided(loanOfficerId); - final LoanTransactionProcessingStrategy loanTransactionProcessingStrategy = findStrategyByIdIfProvided( - transactionProcessingStrategyId); CodeValue loanPurpose = null; if (loanPurposeId != null) { loanPurpose = this.codeValueRepository.findOneWithNotFoundDetection(loanPurposeId); @@ -272,25 +269,25 @@ public class LoanAssembler { } loanApplication = Loan.newIndividualLoanApplicationFromGroup(accountNo, client, group, loanType.getId().intValue(), loanProduct, - fund, loanOfficer, loanPurpose, loanTransactionProcessingStrategy, loanProductRelatedDetail, loanCharges, null, + fund, loanOfficer, loanPurpose, transactionProcessingStrategyCode, loanProductRelatedDetail, loanCharges, null, syncDisbursementWithMeeting, fixedEmiAmount, disbursementDetails, maxOutstandingLoanBalance, createStandingInstructionAtDisbursement, isFloatingInterestRate, interestRateDifferential, rates, fixedPrincipalPercentagePerInstallment); - + loanApplication.updateTransactionProcessingStrategy(transactionProcessingStrategyCode, transactionProcessingStrategyName); } else if (group != null) { loanApplication = Loan.newGroupLoanApplication(accountNo, group, loanType.getId().intValue(), loanProduct, fund, loanOfficer, - loanPurpose, loanTransactionProcessingStrategy, loanProductRelatedDetail, loanCharges, null, + loanPurpose, transactionProcessingStrategyCode, loanProductRelatedDetail, loanCharges, null, syncDisbursementWithMeeting, fixedEmiAmount, disbursementDetails, maxOutstandingLoanBalance, createStandingInstructionAtDisbursement, isFloatingInterestRate, interestRateDifferential, rates, fixedPrincipalPercentagePerInstallment); - + loanApplication.updateTransactionProcessingStrategy(transactionProcessingStrategyCode, transactionProcessingStrategyName); } else if (client != null) { loanApplication = Loan.newIndividualLoanApplication(accountNo, client, loanType.getId().intValue(), loanProduct, fund, - loanOfficer, loanPurpose, loanTransactionProcessingStrategy, loanProductRelatedDetail, loanCharges, collateral, + loanOfficer, loanPurpose, transactionProcessingStrategyCode, loanProductRelatedDetail, loanCharges, collateral, fixedEmiAmount, disbursementDetails, maxOutstandingLoanBalance, createStandingInstructionAtDisbursement, isFloatingInterestRate, interestRateDifferential, rates, fixedPrincipalPercentagePerInstallment); - + loanApplication.updateTransactionProcessingStrategy(transactionProcessingStrategyCode, transactionProcessingStrategyName); } final String externalId = this.fromApiJsonHelper.extractStringNamed("externalId", element); @@ -354,15 +351,6 @@ public class LoanAssembler { return staff; } - public LoanTransactionProcessingStrategy findStrategyByIdIfProvided(final Long transactionProcessingStrategyId) { - LoanTransactionProcessingStrategy strategy = null; - if (transactionProcessingStrategyId != null) { - strategy = this.loanTransactionProcessingStrategyRepository.findById(transactionProcessingStrategyId) - .orElseThrow(() -> new LoanTransactionProcessingStrategyNotFoundException(transactionProcessingStrategyId)); - } - return strategy; - } - public void validateExpectedDisbursementForHolidayAndNonWorkingDay(final Loan loanApplication) { final boolean allowTransactionsOnHoliday = this.configurationDomainService.allowTransactionsOnHolidayEnabled(); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java index 26514e05e..1dced1891 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java @@ -609,8 +609,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService { + " l.amortization_method_enum as amortizationType, l.interest_method_enum as interestType, l.is_equal_amortization as isEqualAmortization, l.interest_calculated_in_period_enum as interestCalculationPeriodType," + " l.fixed_principal_percentage_per_installment fixedPrincipalPercentagePerInstallment, " + " l.allow_partial_period_interest_calcualtion as allowPartialPeriodInterestCalcualtion," - + " l.loan_status_id as lifeCycleStatusId, l.loan_transaction_strategy_id as transactionStrategyId, " - + " lps.name as transactionStrategyName, " + + " l.loan_status_id as lifeCycleStatusId, l.loan_transaction_strategy_code as transactionStrategyCode, " + + " l.loan_transaction_strategy_name as transactionStrategyName, " + " l.currency_code as currencyCode, l.currency_digits as currencyDigits, l.currency_multiplesof as inMultiplesOf, rc." + sqlGenerator.escape("name") + " as currencyName, rc.display_symbol as currencyDisplaySymbol, rc.internationalized_name_code as currencyNameCode, " @@ -676,7 +676,6 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService { + " left join m_appuser dbu on dbu.id = l.disbursedon_userid left join m_appuser cbu on cbu.id = l.closedon_userid" + " left join m_code_value cv on cv.id = l.loanpurpose_cv_id" + " left join m_code_value codev on codev.id = l.writeoff_reason_cv_id" - + " left join ref_loan_transaction_processing_strategy lps on lps.id = l.loan_transaction_strategy_id" + " left join m_product_loan_variable_installment_config lpvi on lpvi.loan_product_id = l.product_id" + " left join m_loan_topup as topup on l.id = topup.loan_id" + " left join m_loan as topuploan on topuploan.id = topup.closure_loan_id"; @@ -814,7 +813,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService { final int interestRateFrequencyTypeInt = JdbcSupport.getInteger(rs, "interestRateFrequencyType"); final EnumOptionData interestRateFrequencyType = LoanEnumerations.interestRateFrequencyType(interestRateFrequencyTypeInt); - final Long transactionStrategyId = JdbcSupport.getLong(rs, "transactionStrategyId"); + final String transactionStrategyCode = rs.getString("transactionStrategyCode"); final String transactionStrategyName = rs.getString("transactionStrategyName"); final int amortizationTypeInt = JdbcSupport.getInteger(rs, "amortizationType"); @@ -996,7 +995,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService { isLoanProductLinkedToFloatingRate, fundId, fundName, loanPurposeId, loanPurposeName, loanOfficerId, loanOfficerName, currencyData, proposedPrincipal, principal, approvedPrincipal, netDisbursalAmount, totalOverpaid, inArrearsTolerance, termFrequency, termPeriodFrequencyType, numberOfRepayments, repaymentEvery, repaymentFrequencyType, null, null, - transactionStrategyId, transactionStrategyName, amortizationType, interestRatePerPeriod, interestRateFrequencyType, + transactionStrategyCode, transactionStrategyName, amortizationType, interestRatePerPeriod, interestRateFrequencyType, annualInterestRate, interestType, isFloatingInterestRate, interestRateDifferential, interestCalculationPeriodType, allowPartialPeriodInterestCalcualtion, expectedFirstRepaymentOnDate, graceOnPrincipalPayment, recurringMoratoriumOnPrincipalPeriods, graceOnInterestPayment, graceOnInterestCharged, interestChargedFromDate, @@ -1932,14 +1931,13 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService { public LoanTransactionData retrieveLoanWriteoffTemplate(final Long loanId) { final LoanAccountData loan = this.retrieveOne(loanId); - final BigDecimal outstandingLoanBalance = null; final LoanTransactionEnumData transactionType = LoanEnumerations.transactionType(LoanTransactionType.WRITEOFF); - final BigDecimal unrecognizedIncomePortion = null; + final BigDecimal totalOutstanding = loan.getSummary() != null ? loan.getSummary().getTotalOutstanding() : null; final List writeOffReasonOptions = new ArrayList<>( this.codeValueReadPlatformService.retrieveCodeValuesByCode(LoanApiConstants.WRITEOFFREASONS)); LoanTransactionData loanTransactionData = new LoanTransactionData(null, null, null, transactionType, null, loan.getCurrency(), - DateUtils.getBusinessLocalDate(), loan.getTotalOutstandingAmount(), loan.getNetDisbursalAmount(), null, null, null, null, - null, null, null, null, outstandingLoanBalance, unrecognizedIncomePortion, false); + DateUtils.getBusinessLocalDate(), totalOutstanding, loan.getNetDisbursalAmount(), null, null, null, null, null, null, null, + null, null, null, false); loanTransactionData.setWriteOffReasonOptions(writeOffReasonOptions); return loanTransactionData; } @@ -2246,10 +2244,12 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService { final Collection intRates = this.floatingRatesReadPlatformService .retrieveInterestRatePeriods(loanData.getLoanProductId()); for (final InterestRatePeriodData rate : intRates) { - if (rate.getFromDate().compareTo(loanData.getDisbursementDate()) > 0 && loanData.isFloatingInterestRate()) { + if (loanData.getTimeline() != null && rate.getFromDate().compareTo(loanData.getTimeline().getDisbursementDate()) > 0 + && loanData.isFloatingInterestRate()) { updateInterestRatePeriodData(rate, loanData); intRatePeriodData.add(rate); - } else if (rate.getFromDate().compareTo(loanData.getDisbursementDate()) <= 0) { + } else if (loanData.getTimeline() != null + && rate.getFromDate().compareTo(loanData.getTimeline().getDisbursementDate()) <= 0) { updateInterestRatePeriodData(rate, loanData); intRatePeriodData.add(rate); break; @@ -2275,8 +2275,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService { } rate.setEffectiveInterestRate(effectiveInterestRate); - if (rate.getFromDate().compareTo(loan.getDisbursementDate()) < 0) { - rate.setFromDate(loan.getDisbursementDate()); + if (loan.getTimeline() != null && rate.getFromDate().compareTo(loan.getTimeline().getDisbursementDate()) < 0) { + rate.setFromDate(loan.getTimeline().getDisbursementDate()); } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/starter/LoanAccountAutoStarter.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/starter/LoanAccountAutoStarter.java new file mode 100644 index 000000000..be365229f --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/starter/LoanAccountAutoStarter.java @@ -0,0 +1,88 @@ +/** + * 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.starter; + +import java.util.List; +import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleTransactionProcessorFactory; +import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.LoanRepaymentScheduleTransactionProcessor; +import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.CreocoreLoanRepaymentScheduleTransactionProcessor; +import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.EarlyPaymentLoanRepaymentScheduleTransactionProcessor; +import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.FineractStyleLoanRepaymentScheduleTransactionProcessor; +import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.HeavensFamilyLoanRepaymentScheduleTransactionProcessor; +import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.InterestPrincipalPenaltyFeesOrderLoanRepaymentScheduleTransactionProcessor; +import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.PrincipalInterestPenaltyFeesOrderLoanRepaymentScheduleTransactionProcessor; +import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.RBILoanRepaymentScheduleTransactionProcessor; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class LoanAccountAutoStarter { + + @Bean + @ConditionalOnProperty("fineract.loan.transactionprocessor.creocore.enabled") + public CreocoreLoanRepaymentScheduleTransactionProcessor creocoreLoanRepaymentScheduleTransactionProcessor() { + return new CreocoreLoanRepaymentScheduleTransactionProcessor(); + } + + @Bean + @ConditionalOnProperty("fineract.loan.transactionprocessor.early-repayment.enabled") + public EarlyPaymentLoanRepaymentScheduleTransactionProcessor earlyPaymentLoanRepaymentScheduleTransactionProcessor() { + return new EarlyPaymentLoanRepaymentScheduleTransactionProcessor(); + } + + @Bean + @ConditionalOnProperty("fineract.loan.transactionprocessor.mifos-standard.enabled") + public FineractStyleLoanRepaymentScheduleTransactionProcessor fineractStyleLoanRepaymentScheduleTransactionProcessor() { + return new FineractStyleLoanRepaymentScheduleTransactionProcessor(); + } + + @Bean + @ConditionalOnProperty("fineract.loan.transactionprocessor.heavensfamily.enabled") + public HeavensFamilyLoanRepaymentScheduleTransactionProcessor heavensFamilyLoanRepaymentScheduleTransactionProcessor() { + return new HeavensFamilyLoanRepaymentScheduleTransactionProcessor(); + } + + @Bean + @ConditionalOnProperty("fineract.loan.transactionprocessor.interest-principal-penalties-fees.enabled") + public InterestPrincipalPenaltyFeesOrderLoanRepaymentScheduleTransactionProcessor interestPrincipalPenaltyFeesOrderLoanRepaymentScheduleTransactionProcessor() { + return new InterestPrincipalPenaltyFeesOrderLoanRepaymentScheduleTransactionProcessor(); + } + + @Bean + @ConditionalOnProperty("fineract.loan.transactionprocessor.principal-interest-penalties-fees.enabled") + public PrincipalInterestPenaltyFeesOrderLoanRepaymentScheduleTransactionProcessor principalInterestPenaltyFeesOrderLoanRepaymentScheduleTransactionProcessor() { + return new PrincipalInterestPenaltyFeesOrderLoanRepaymentScheduleTransactionProcessor(); + } + + @Bean + @ConditionalOnProperty("fineract.loan.transactionprocessor.rbi-india.enabled") + public RBILoanRepaymentScheduleTransactionProcessor rbiLoanRepaymentScheduleTransactionProcessor() { + return new RBILoanRepaymentScheduleTransactionProcessor(); + } + + @Bean + @ConditionalOnMissingBean(LoanRepaymentScheduleTransactionProcessorFactory.class) + public LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory( + PrincipalInterestPenaltyFeesOrderLoanRepaymentScheduleTransactionProcessor defaultLoanRepaymentScheduleTransactionProcessor, + List processors) { + return new LoanRepaymentScheduleTransactionProcessorFactory(defaultLoanRepaymentScheduleTransactionProcessor, processors); + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/LoanProductConstants.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/LoanProductConstants.java index a38dee9f2..e92f8d71c 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/LoanProductConstants.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/LoanProductConstants.java @@ -115,7 +115,7 @@ public interface LoanProductConstants { String allowAttributeOverridesParamName = "allowAttributeOverrides"; String amortizationTypeParamName = "amortizationType"; String interestTypeParamName = "interestType"; - String transactionProcessingStrategyIdParamName = "transactionProcessingStrategyId"; + String transactionProcessingStrategyCodeParamName = "transactionProcessingStrategyCode"; String interestCalculationPeriodTypeParamName = "interestCalculationPeriodType"; String inArrearsToleranceParamName = "inArrearsTolerance"; String repaymentEveryParamName = "repaymentEvery"; diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResource.java index 4fc7cc78d..a49e51f67 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResource.java @@ -99,7 +99,7 @@ public class LoanProductsApiResource { "recurringMoratoriumOnPrincipalPeriods", "graceOnInterestPayment", "graceOnInterestCharged", "interestRatePerPeriod", "minInterestRatePerPeriod", "maxInterestRatePerPeriod", "interestRateFrequencyType", "annualInterestRate", "amortizationType", "interestType", "interestCalculationPeriodType", LoanProductConstants.ALLOW_PARTIAL_PERIOD_INTEREST_CALCUALTION_PARAM_NAME, - "inArrearsTolerance", "transactionProcessingStrategyId", "transactionProcessingStrategyName", "charges", "accountingRule", + "inArrearsTolerance", "transactionProcessingStrategyCode", "transactionProcessingStrategyName", "charges", "accountingRule", "externalId", "accountingMappings", "paymentChannelToFundSourceMappings", "fundOptions", "paymentTypeOptions", "currencyOptions", "repaymentFrequencyTypeOptions", "interestRateFrequencyTypeOptions", "amortizationTypeOptions", "interestTypeOptions", "interestCalculationPeriodTypeOptions", "transactionProcessingStrategyOptions", "chargeOptions", @@ -178,7 +178,7 @@ public class LoanProductsApiResource { @Produces({ MediaType.APPLICATION_JSON }) @Operation(summary = "Create a Loan Product", description = "Depending of the Accounting Rule (accountingRule) selected, additional fields with details of the appropriate Ledger Account identifiers would need to be passed in.\n" + "\n" + "Refer MifosX Accounting Specs Draft for more details regarding the significance of the selected accounting rule\n\n" - + "Mandatory Fields: name, shortName, currencyCode, digitsAfterDecimal, inMultiplesOf, principal, numberOfRepayments, repaymentEvery, repaymentFrequencyType, interestRatePerPeriod, interestRateFrequencyType, amortizationType, interestType, interestCalculationPeriodType, transactionProcessingStrategyId, accountingRule, isInterestRecalculationEnabled, daysInYearType, daysInMonthType\n\n" + + "Mandatory Fields: name, shortName, currencyCode, digitsAfterDecimal, inMultiplesOf, principal, numberOfRepayments, repaymentEvery, repaymentFrequencyType, interestRatePerPeriod, interestRateFrequencyType, amortizationType, interestType, interestCalculationPeriodType, transactionProcessingStrategyCode, accountingRule, isInterestRecalculationEnabled, daysInYearType, daysInMonthType\n\n" + "Optional Fields: inArrearsTolerance, graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, graceOnArrearsAgeing, charges, paymentChannelToFundSourceMappings, feeToIncomeAccountMappings, penaltyToIncomeAccountMappings, includeInBorrowerCycle, useBorrowerCycle,principalVariationsForBorrowerCycle, numberOfRepaymentVariationsForBorrowerCycle, interestRateVariationsForBorrowerCycle, multiDisburseLoan,maxTrancheCount, outstandingLoanBalance,overdueDaysForNPA,holdGuaranteeFunds, principalThresholdForLastInstalment, accountMovesOutOfNPAOnlyOnArrearsCompletion, canDefineInstallmentAmount, installmentAmountInMultiplesOf, allowAttributeOverrides, allowPartialPeriodInterestCalcualtion\n\n" + "Additional Mandatory Fields for Cash(2) based accounting: fundSourceAccountId, loanPortfolioAccountId, interestOnLoanAccountId, incomeFromFeeAccountId, incomeFromPenaltyAccountId, writeOffAccountId, transfersInSuspenseAccountId, overpaymentLiabilityAccountId\n\n" + "Additional Mandatory Fields for periodic (3) and upfront (4)accrual accounting: fundSourceAccountId, loanPortfolioAccountId, interestOnLoanAccountId, incomeFromFeeAccountId, incomeFromPenaltyAccountId, writeOffAccountId, receivableInterestAccountId, receivableFeeAccountId, receivablePenaltyAccountId, transfersInSuspenseAccountId, overpaymentLiabilityAccountId\n\n" diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResourceSwagger.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResourceSwagger.java index 04d604094..d25930356 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResourceSwagger.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResourceSwagger.java @@ -109,8 +109,8 @@ final class LoanProductsApiResourceSwagger { public Integer interestType; @Schema(example = "1") public Integer interestCalculationPeriodType; - @Schema(example = "1") - public Long transactionProcessingStrategyId; + @Schema(example = "mifos-standard-strategy") + public String transactionProcessingStrategyCode; @Schema(example = "false") public Boolean isLinkedToFloatingInterestRates; @Schema(example = "false") @@ -227,7 +227,7 @@ final class LoanProductsApiResourceSwagger { @Schema(example = "true") public boolean interestType; @Schema(example = "true") - public boolean transactionProcessingStrategyId; + public boolean transactionProcessingStrategyCode; @Schema(example = "true") public boolean interestCalculationPeriodType; @Schema(example = "true") @@ -503,8 +503,8 @@ final class LoanProductsApiResourceSwagger { public BigDecimal fixedPrincipalPercentagePerInstallment; public GetLoanProductsInterestType interestType; public GetLoansProductsInterestCalculationPeriodType interestCalculationPeriodType; - @Schema(example = "1") - public Long transactionProcessingStrategyId; + @Schema(example = "mifos-standard-strategy") + public String transactionProcessingStrategy; @Schema(example = "Mifos style") public String transactionProcessingStrategyName; @Schema(example = "[]") @@ -1211,8 +1211,8 @@ final class LoanProductsApiResourceSwagger { public BigDecimal fixedPrincipalPercentagePerInstallment; public GetLoanProductsTemplateResponse.GetLoanProductsInterestTemplateType interestType; public GetLoanProductsResponse.GetLoansProductsInterestCalculationPeriodType interestCalculationPeriodType; - @Schema(example = "1") - public Long transactionProcessingStrategyId; + @Schema(example = "mifos-standard-strategy") + public String transactionProcessingStrategyCode; @Schema(example = "Mifos style") public String transactionProcessingStrategyName; @Schema(example = "[]") diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/data/LoanProductData.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/data/LoanProductData.java index ae969b411..91c52c59c 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/data/LoanProductData.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/data/LoanProductData.java @@ -107,7 +107,7 @@ public class LoanProductData implements Serializable { private final EnumOptionData interestCalculationPeriodType; private final Boolean allowPartialPeriodInterestCalculation; private final BigDecimal inArrearsTolerance; - private final Long transactionProcessingStrategyId; + private final String transactionProcessingStrategyCode; private final String transactionProcessingStrategyName; private final Integer graceOnPrincipalPayment; private final Integer recurringMoratoriumOnPrincipalPeriods; @@ -228,7 +228,7 @@ public class LoanProductData implements Serializable { final Boolean allowPartialPeriodInterestCalcualtion = null; final Long fundId = null; final String fundName = null; - final Long transactionProcessingStrategyId = null; + final String transactionProcessingStrategyCode = null; final String transactionProcessingStrategyName = null; final Integer graceOnPrincipalPayment = null; final Integer recurringMoratoriumOnPrincipalPeriods = null; @@ -281,7 +281,7 @@ public class LoanProductData implements Serializable { numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod, minInterestRatePerPeriod, maxInterestRatePerPeriod, annualInterestRate, repaymentFrequencyType, interestRateFrequencyType, amortizationType, interestType, interestCalculationPeriodType, allowPartialPeriodInterestCalcualtion, fundId, fundName, - transactionProcessingStrategyId, transactionProcessingStrategyName, graceOnPrincipalPayment, + transactionProcessingStrategyCode, transactionProcessingStrategyName, graceOnPrincipalPayment, recurringMoratoriumOnPrincipalPeriods, graceOnInterestPayment, graceOnInterestCharged, charges, accountingType, includeInBorrowerCycle, useBorrowerCycle, startDate, closeDate, status, externalId, principalVariations, interestRateVariations, numberOfRepaymentVariations, multiDisburseLoan, maxTrancheCount, outstandingLoanBalance, @@ -331,7 +331,7 @@ public class LoanProductData implements Serializable { final Boolean allowPartialPeriodInterestCalcualtion = null; final Long fundId = null; final String fundName = null; - final Long transactionProcessingStrategyId = null; + final String transactionProcessingStrategyCode = null; final String transactionProcessingStrategyName = null; final Integer graceOnPrincipalPayment = null; final Integer recurringMoratoriumOnPrincipalPeriods = null; @@ -386,7 +386,7 @@ public class LoanProductData implements Serializable { numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod, minInterestRatePerPeriod, maxInterestRatePerPeriod, annualInterestRate, repaymentFrequencyType, interestRateFrequencyType, amortizationType, interestType, interestCalculationPeriodType, allowPartialPeriodInterestCalcualtion, fundId, fundName, - transactionProcessingStrategyId, transactionProcessingStrategyName, graceOnPrincipalPayment, + transactionProcessingStrategyCode, transactionProcessingStrategyName, graceOnPrincipalPayment, recurringMoratoriumOnPrincipalPeriods, graceOnInterestPayment, graceOnInterestCharged, charges, accountingType, includeInBorrowerCycle, useBorrowerCycle, startDate, closeDate, status, externalId, principalVariations, interestRateVariations, numberOfRepaymentVariations, multiDisburseLoan, maxTrancheCount, outstandingLoanBalance, @@ -441,7 +441,7 @@ public class LoanProductData implements Serializable { final Boolean allowPartialPeriodInterestCalcualtion = null; final Long fundId = null; final String fundName = null; - final Long transactionProcessingStrategyId = null; + final String transactionProcessingStrategyCode = null; final String transactionProcessingStrategyName = null; final Integer graceOnPrincipalPayment = null; @@ -498,7 +498,7 @@ public class LoanProductData implements Serializable { numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod, minInterestRatePerPeriod, maxInterestRatePerPeriod, annualInterestRate, repaymentFrequencyType, interestRateFrequencyType, amortizationType, interestType, interestCalculationPeriodType, allowPartialPeriodInterestCalcualtion, fundId, fundName, - transactionProcessingStrategyId, transactionProcessingStrategyName, graceOnPrincipalPayment, + transactionProcessingStrategyCode, transactionProcessingStrategyName, graceOnPrincipalPayment, recurringMoratoriumOnPrincipalPeriods, graceOnInterestPayment, graceOnInterestCharged, charges, accountingType, includeInBorrowerCycle, useBorrowerCycle, startDate, closeDate, status, externalId, principalVariationsForBorrowerCycle, interestRateVariationsForBorrowerCycle, numberOfRepaymentVariationsForBorrowerCycle, multiDisburseLoan, maxTrancheCount, @@ -547,7 +547,7 @@ public class LoanProductData implements Serializable { final Boolean allowPartialPeriodInterestCalcualtion = null; final Long fundId = null; final String fundName = null; - final Long transactionProcessingStrategyId = null; + final String transactionProcessingStrategyCode = null; final String transactionProcessingStrategyName = null; final Integer graceOnPrincipalPayment = null; @@ -604,7 +604,7 @@ public class LoanProductData implements Serializable { numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod, minInterestRatePerPeriod, maxInterestRatePerPeriod, annualInterestRate, repaymentFrequencyType, interestRateFrequencyType, amortizationType, interestType, interestCalculationPeriodType, allowPartialPeriodInterestCalcualtion, fundId, fundName, - transactionProcessingStrategyId, transactionProcessingStrategyName, graceOnPrincipalPayment, + transactionProcessingStrategyCode, transactionProcessingStrategyName, graceOnPrincipalPayment, recurringMoratoriumOnPrincipalPeriods, graceOnInterestPayment, graceOnInterestCharged, charges, accountingType, includeInBorrowerCycle, useBorrowerCycle, startDate, closeDate, status, externalId, principalVariationsForBorrowerCycle, interestRateVariationsForBorrowerCycle, numberOfRepaymentVariationsForBorrowerCycle, multiDisburseLoan, maxTrancheCount, @@ -638,7 +638,7 @@ public class LoanProductData implements Serializable { final BigDecimal maxInterestRatePerPeriod, final BigDecimal annualInterestRate, final EnumOptionData repaymentFrequencyType, final EnumOptionData interestRateFrequencyType, final EnumOptionData amortizationType, final EnumOptionData interestType, final EnumOptionData interestCalculationPeriodType, final Boolean allowPartialPeriodInterestCalculation, final Long fundId, - final String fundName, final Long transactionProcessingStrategyId, final String transactionProcessingStrategyName, + final String fundName, final String transactionProcessingStrategyCode, final String transactionProcessingStrategyName, final Integer graceOnPrincipalPayment, final Integer recurringMoratoriumOnPrincipalPeriods, final Integer graceOnInterestPayment, final Integer graceOnInterestCharged, final Collection charges, final EnumOptionData accountingType, final boolean includeInBorrowerCycle, boolean useBorrowerCycle, final LocalDate startDate, @@ -703,7 +703,7 @@ public class LoanProductData implements Serializable { this.allowPartialPeriodInterestCalculation = allowPartialPeriodInterestCalculation; this.fundId = fundId; this.fundName = fundName; - this.transactionProcessingStrategyId = transactionProcessingStrategyId; + this.transactionProcessingStrategyCode = transactionProcessingStrategyCode; this.transactionProcessingStrategyName = transactionProcessingStrategyName; this.charges = charges; this.accountingRule = accountingType; @@ -858,10 +858,10 @@ public class LoanProductData implements Serializable { if (this.transactionProcessingStrategyOptions != null && this.transactionProcessingStrategyOptions.size() == 1) { final List listOfOptions = new ArrayList<>(this.transactionProcessingStrategyOptions); - this.transactionProcessingStrategyId = listOfOptions.get(0).id(); - this.transactionProcessingStrategyName = listOfOptions.get(0).name(); + this.transactionProcessingStrategyCode = listOfOptions.get(0).getCode(); + this.transactionProcessingStrategyName = listOfOptions.get(0).getName(); } else { - this.transactionProcessingStrategyId = productData.transactionProcessingStrategyId; + this.transactionProcessingStrategyCode = productData.transactionProcessingStrategyCode; this.transactionProcessingStrategyName = productData.transactionProcessingStrategyName; } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/data/TransactionProcessingStrategyData.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/data/TransactionProcessingStrategyData.java index 3f15fe8f8..479983b95 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/data/TransactionProcessingStrategyData.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/data/TransactionProcessingStrategyData.java @@ -19,28 +19,18 @@ package org.apache.fineract.portfolio.loanproduct.data; import java.io.Serializable; +import lombok.Getter; +import lombok.RequiredArgsConstructor; /** * Immutable data object representing a transaction strategy option for a loan. */ +@RequiredArgsConstructor +@Getter public final class TransactionProcessingStrategyData implements Serializable { private final Long id; @SuppressWarnings("unused") private final String code; private final String name; - - public TransactionProcessingStrategyData(final Long id, final String code, final String name) { - this.id = id; - this.code = code; - this.name = name; - } - - public Long id() { - return this.id; - } - - public String name() { - return this.name; - } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProduct.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProduct.java index 4ebe179aa..a28c66d2f 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProduct.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProduct.java @@ -82,9 +82,11 @@ public class LoanProduct extends AbstractPersistableCustom { @JoinColumn(name = "fund_id") private Fund fund; - @ManyToOne - @JoinColumn(name = "loan_transaction_strategy_id") - private LoanTransactionProcessingStrategy transactionProcessingStrategy; + @Column(name = "loan_transaction_strategy_code", nullable = false) + private String transactionProcessingStrategyCode; + + @Column(name = "loan_transaction_strategy_name") + private String transactionProcessingStrategyName; @Column(name = "name", nullable = false, unique = true) private String name; @@ -200,7 +202,7 @@ public class LoanProduct extends AbstractPersistableCustom { @JoinColumn(name = "delinquency_bucket_id") private DelinquencyBucket delinquencyBucket; - public static LoanProduct assembleFromJson(final Fund fund, final LoanTransactionProcessingStrategy loanTransactionProcessingStrategy, + public static LoanProduct assembleFromJson(final Fund fund, final String loanTransactionProcessingStrategy, final List productCharges, final JsonCommand command, final AprCalculator aprCalculator, FloatingRate floatingRate, final List productRates) { @@ -568,8 +570,8 @@ public class LoanProduct extends AbstractPersistableCustom { this.loanProductMinMaxConstraints = null; } - public LoanProduct(final Fund fund, final LoanTransactionProcessingStrategy transactionProcessingStrategy, final String name, - final String shortName, final String description, final MonetaryCurrency currency, final BigDecimal defaultPrincipal, + public LoanProduct(final Fund fund, final String transactionProcessingStrategyCode, final String name, final String shortName, + final String description, final MonetaryCurrency currency, final BigDecimal defaultPrincipal, final BigDecimal defaultMinPrincipal, final BigDecimal defaultMaxPrincipal, final BigDecimal defaultNominalInterestRatePerPeriod, final BigDecimal defaultMinNominalInterestRatePerPeriod, final BigDecimal defaultMaxNominalInterestRatePerPeriod, final PeriodFrequencyType interestPeriodFrequencyType, @@ -599,7 +601,7 @@ public class LoanProduct extends AbstractPersistableCustom { final boolean allowApprovedDisbursedAmountsOverApplied, final String overAppliedCalculationType, final Integer overAppliedNumber) { this.fund = fund; - this.transactionProcessingStrategy = transactionProcessingStrategy; + this.transactionProcessingStrategyCode = transactionProcessingStrategyCode; this.name = name.trim(); this.shortName = shortName.trim(); if (StringUtils.isNotBlank(description)) { @@ -743,12 +745,16 @@ public class LoanProduct extends AbstractPersistableCustom { this.fund = fund; } - public void update(final LoanTransactionProcessingStrategy strategy) { - this.transactionProcessingStrategy = strategy; + public void setTransactionProcessingStrategyCode(final String transactionProcessingStrategyCode) { + this.transactionProcessingStrategyCode = transactionProcessingStrategyCode; } - public LoanTransactionProcessingStrategy getRepaymentStrategy() { - return this.transactionProcessingStrategy; + public void setTransactionProcessingStrategyName(final String transactionProcessingStrategyName) { + this.transactionProcessingStrategyName = transactionProcessingStrategyName; + } + + public String getRepaymentStrategy() { + return this.transactionProcessingStrategyCode; } public boolean hasCurrencyCodeOf(final String currencyCode) { @@ -884,14 +890,10 @@ public class LoanProduct extends AbstractPersistableCustom { actualChanges.put(fundIdParamName, newValue); } - Long existingStrategyId = null; - if (this.transactionProcessingStrategy != null) { - existingStrategyId = this.transactionProcessingStrategy.getId(); - } - final String transactionProcessingStrategyParamName = "transactionProcessingStrategyId"; - if (command.isChangeInLongParameterNamed(transactionProcessingStrategyParamName, existingStrategyId)) { - final Long newValue = command.longValueOfParameterNamed(transactionProcessingStrategyParamName); - actualChanges.put(transactionProcessingStrategyParamName, newValue); + final String transactionProcessingStrategyCodeParamName = "transactionProcessingStrategyCode"; + if (command.isChangeInStringParameterNamed(transactionProcessingStrategyCodeParamName, this.transactionProcessingStrategyCode)) { + final String newValue = command.stringValueOfParameterNamed(transactionProcessingStrategyCodeParamName); + actualChanges.put(transactionProcessingStrategyCodeParamName, newValue); } final String chargesParamName = "charges"; @@ -1035,11 +1037,11 @@ public class LoanProduct extends AbstractPersistableCustom { } if (command.parsedJson().getAsJsonObject().getAsJsonObject(LoanProductConstants.allowAttributeOverridesParamName) - .getAsJsonPrimitive(LoanProductConstants.transactionProcessingStrategyIdParamName) + .getAsJsonPrimitive(LoanProductConstants.transactionProcessingStrategyCodeParamName) .getAsBoolean() != this.loanConfigurableAttributes.getTransactionProcessingStrategyBoolean()) { - this.loanConfigurableAttributes.setTransactionProcessingStrategyId( + this.loanConfigurableAttributes.setTransactionProcessingStrategyCode( command.parsedJson().getAsJsonObject().getAsJsonObject(LoanProductConstants.allowAttributeOverridesParamName) - .getAsJsonPrimitive(LoanProductConstants.transactionProcessingStrategyIdParamName).getAsBoolean()); + .getAsJsonPrimitive(LoanProductConstants.transactionProcessingStrategyCodeParamName).getAsBoolean()); } if (command.parsedJson().getAsJsonObject().getAsJsonObject(LoanProductConstants.allowAttributeOverridesParamName) diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProductConfigurableAttributes.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProductConfigurableAttributes.java index e3fec2f80..d2d1d4a08 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProductConfigurableAttributes.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProductConfigurableAttributes.java @@ -43,8 +43,8 @@ public class LoanProductConfigurableAttributes extends AbstractPersistableCustom @Column(name = "interest_method_enum") private Boolean interestType; - @Column(name = "loan_transaction_strategy_id") - private Boolean transactionProcessingStrategyId; + @Column(name = "loan_transaction_strategy_code") + private Boolean transactionProcessingStrategyCode; @Column(name = "interest_calculated_in_period_enum") private Boolean interestCalculationPeriodType; @@ -62,7 +62,7 @@ public class LoanProductConfigurableAttributes extends AbstractPersistableCustom private Boolean graceOnArrearsAgeing; private static final String[] supportedLoanConfigurableAttributes = { LoanProductConstants.amortizationTypeParamName, - LoanProductConstants.interestTypeParamName, LoanProductConstants.transactionProcessingStrategyIdParamName, + LoanProductConstants.interestTypeParamName, LoanProductConstants.transactionProcessingStrategyCodeParamName, LoanProductConstants.interestCalculationPeriodTypeParamName, LoanProductConstants.inArrearsToleranceParamName, LoanProductConstants.repaymentEveryParamName, LoanProductConstants.graceOnPrincipalAndInterestPaymentParamName, LoanProductConstants.GRACE_ON_ARREARS_AGEING_PARAMETER_NAME }; @@ -77,7 +77,7 @@ public class LoanProductConfigurableAttributes extends AbstractPersistableCustom .getAsJsonPrimitive(LoanProductConstants.interestTypeParamName).getAsBoolean(); final Boolean transactionProcessingStrategy = command.parsedJson().getAsJsonObject() .getAsJsonObject(LoanProductConstants.allowAttributeOverridesParamName) - .getAsJsonPrimitive(LoanProductConstants.transactionProcessingStrategyIdParamName).getAsBoolean(); + .getAsJsonPrimitive(LoanProductConstants.transactionProcessingStrategyCodeParamName).getAsBoolean(); final Boolean interestCalcPeriod = command.parsedJson().getAsJsonObject() .getAsJsonObject(LoanProductConstants.allowAttributeOverridesParamName) .getAsJsonPrimitive(LoanProductConstants.interestCalculationPeriodTypeParamName).getAsBoolean(); @@ -116,7 +116,7 @@ public class LoanProductConfigurableAttributes extends AbstractPersistableCustom arrearsTolerance, repaymentEvery, graceOnPrincipalAndInterestPayment, graceOnArrearsAging); } - public LoanProductConfigurableAttributes(Boolean amortization, Boolean interestMethod, Boolean transactionProcessingStrategy, + public LoanProductConfigurableAttributes(Boolean amortization, Boolean interestMethod, Boolean transactionProcessingStrategyCode, Boolean interestCalcPeriod, Boolean arrearsTolerance, Boolean repaymentEvery, Boolean graceOnPrincipalAndInterestPayment, Boolean graceOnArrearsAging) { this.amortizationType = amortization; @@ -126,7 +126,7 @@ public class LoanProductConfigurableAttributes extends AbstractPersistableCustom this.interestCalculationPeriodType = interestCalcPeriod; this.graceOnPrincipalAndInterestPayment = graceOnPrincipalAndInterestPayment; this.repaymentEvery = repaymentEvery; - this.transactionProcessingStrategyId = transactionProcessingStrategy; + this.transactionProcessingStrategyCode = transactionProcessingStrategyCode; } protected LoanProductConfigurableAttributes() { @@ -150,7 +150,7 @@ public class LoanProductConfigurableAttributes extends AbstractPersistableCustom } public Boolean getTransactionProcessingStrategyBoolean() { - return transactionProcessingStrategyId; + return transactionProcessingStrategyCode; } public Boolean getInterestCalcPeriodBoolean() { @@ -185,8 +185,8 @@ public class LoanProductConfigurableAttributes extends AbstractPersistableCustom this.interestType = interestType; } - public void setTransactionProcessingStrategyId(Boolean transactionProcessingStrategyId) { - this.transactionProcessingStrategyId = transactionProcessingStrategyId; + public void setTransactionProcessingStrategyCode(Boolean transactionProcessingStrategyCode) { + this.transactionProcessingStrategyCode = transactionProcessingStrategyCode; } public void setInterestCalculationPeriodType(Boolean interestCalculationPeriodType) { @@ -223,7 +223,7 @@ public class LoanProductConfigurableAttributes extends AbstractPersistableCustom return Objects.equals(loanProduct, that.loanProduct) && Objects.equals(amortizationType, that.amortizationType) && Objects.equals(interestType, that.interestType) - && Objects.equals(transactionProcessingStrategyId, that.transactionProcessingStrategyId) + && Objects.equals(transactionProcessingStrategyCode, that.transactionProcessingStrategyCode) && Objects.equals(interestCalculationPeriodType, that.interestCalculationPeriodType) && Objects.equals(inArrearsTolerance, that.inArrearsTolerance) && Objects.equals(repaymentEvery, that.repaymentEvery) && Objects.equals(graceOnPrincipalAndInterestPayment, that.graceOnPrincipalAndInterestPayment) @@ -232,7 +232,7 @@ public class LoanProductConfigurableAttributes extends AbstractPersistableCustom @Override public int hashCode() { - return Objects.hash(loanProduct, amortizationType, interestType, transactionProcessingStrategyId, interestCalculationPeriodType, + return Objects.hash(loanProduct, amortizationType, interestType, transactionProcessingStrategyCode, interestCalculationPeriodType, inArrearsTolerance, repaymentEvery, graceOnPrincipalAndInterestPayment, graceOnArrearsAgeing); } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanTransactionProcessingStrategy.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanTransactionProcessingStrategy.java deleted file mode 100644 index 606770ef5..000000000 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanTransactionProcessingStrategy.java +++ /dev/null @@ -1,77 +0,0 @@ -/** - * 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 javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.Table; -import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom; -import org.apache.fineract.portfolio.loanproduct.data.TransactionProcessingStrategyData; - -@Entity -@Table(name = "ref_loan_transaction_processing_strategy") -public class LoanTransactionProcessingStrategy extends AbstractPersistableCustom { - - @Column(name = "code", unique = true) - private String code; - - @Column(name = "name") - private String name; - - @Column(name = "sort_order") - private Integer sortOrder; // Don't change this name as this property name - // is used as sort order while retrieving this - // objects - - protected LoanTransactionProcessingStrategy() { - // - } - - public TransactionProcessingStrategyData toData() { - return new TransactionProcessingStrategyData(getId(), this.code, this.name); - } - - public boolean isStandardStrategy() { - return "mifos-standard-strategy".equalsIgnoreCase(this.code); - } - - public boolean isHeavensfamilyStrategy() { - return "heavensfamily-strategy".equalsIgnoreCase(this.code); - } - - public boolean isEarlyPaymentStrategy() { - return "early-repayment-strategy".equalsIgnoreCase(this.code); - } - - public boolean isCreocoreStrategy() { - return "creocore-strategy".equalsIgnoreCase(this.code); - } - - public boolean isIndianRBIStrategy() { - return "rbi-india-strategy".equalsIgnoreCase(this.code); - } - - public boolean isPrincipalInterestPenaltiesFeesOrderStrategy() { - return "principal-interest-penalties-fees-order-strategy".equalsIgnoreCase(this.code); - } - - public boolean isInterestPrincipalPenaltiesFeesOrderStrategy() { - return "interest-principal-penalties-fees-order-strategy".equalsIgnoreCase(this.code); - } -} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/serialization/LoanProductDataValidator.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/serialization/LoanProductDataValidator.java index de4d59eae..db87368d7 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/serialization/LoanProductDataValidator.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/serialization/LoanProductDataValidator.java @@ -32,6 +32,8 @@ import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.apache.fineract.accounting.common.AccountingConstants.LoanProductAccountingParams; import org.apache.fineract.accounting.common.AccountingRuleType; @@ -43,7 +45,10 @@ import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper; import org.apache.fineract.portfolio.calendar.service.CalendarUtils; import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType; import org.apache.fineract.portfolio.loanaccount.api.LoanApiConstants; +import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleTransactionProcessorFactory; +import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.LoanRepaymentScheduleTransactionProcessor; import org.apache.fineract.portfolio.loanproduct.LoanProductConstants; +import org.apache.fineract.portfolio.loanproduct.data.TransactionProcessingStrategyData; import org.apache.fineract.portfolio.loanproduct.domain.AmortizationMethod; import org.apache.fineract.portfolio.loanproduct.domain.InterestCalculationPeriodMethod; import org.apache.fineract.portfolio.loanproduct.domain.InterestMethod; @@ -53,9 +58,10 @@ import org.apache.fineract.portfolio.loanproduct.domain.LoanProduct; import org.apache.fineract.portfolio.loanproduct.domain.LoanProductValueConditionType; import org.apache.fineract.portfolio.loanproduct.domain.RecalculationFrequencyType; import org.apache.fineract.portfolio.loanproduct.exception.EqualAmortizationUnsupportedFeatureException; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +@Slf4j +@RequiredArgsConstructor @Component public final class LoanProductDataValidator { @@ -78,7 +84,7 @@ public final class LoanProductDataValidator { public static final String INTEREST_TYPE = "interestType"; public static final String INTEREST_CALCULATION_PERIOD_TYPE = "interestCalculationPeriodType"; public static final String IN_ARREARS_TOLERANCE = "inArrearsTolerance"; - public static final String TRANSACTION_PROCESSING_STRATEGY_ID = "transactionProcessingStrategyId"; + public static final String TRANSACTION_PROCESSING_STRATEGY_CODE = "transactionProcessingStrategyCode"; public static final String GRACE_ON_PRINCIPAL_PAYMENT = "graceOnPrincipalPayment"; public static final String GRACE_ON_INTEREST_PAYMENT = "graceOnInterestPayment"; public static final String GRACE_ON_INTEREST_CHARGED = "graceOnInterestCharged"; @@ -102,7 +108,7 @@ public final class LoanProductDataValidator { NUMBER_OF_REPAYMENTS, MIN_NUMBER_OF_REPAYMENTS, MAX_NUMBER_OF_REPAYMENTS, REPAYMENT_FREQUENCY_TYPE, INTEREST_RATE_PER_PERIOD, MIN_INTEREST_RATE_PER_PERIOD, MAX_INTEREST_RATE_PER_PERIOD, INTEREST_RATE_FREQUENCY_TYPE, AMORTIZATION_TYPE, INTEREST_TYPE, INTEREST_CALCULATION_PERIOD_TYPE, LoanProductConstants.ALLOW_PARTIAL_PERIOD_INTEREST_CALCUALTION_PARAM_NAME, - IN_ARREARS_TOLERANCE, TRANSACTION_PROCESSING_STRATEGY_ID, GRACE_ON_PRINCIPAL_PAYMENT, "recurringMoratoriumOnPrincipalPeriods", + IN_ARREARS_TOLERANCE, TRANSACTION_PROCESSING_STRATEGY_CODE, GRACE_ON_PRINCIPAL_PAYMENT, "recurringMoratoriumOnPrincipalPeriods", GRACE_ON_INTEREST_PAYMENT, GRACE_ON_INTEREST_CHARGED, "charges", ACCOUNTING_RULE, INCLUDE_IN_BORROWER_CYCLE, "startDate", "closeDate", "externalId", IS_LINKED_TO_FLOATING_INTEREST_RATES, FLOATING_RATES_ID, INTEREST_RATE_DIFFERENTIAL, MIN_DIFFERENTIAL_LENDING_RATE, DEFAULT_DIFFERENTIAL_LENDING_RATE, MAX_DIFFERENTIAL_LENDING_RATE, @@ -149,7 +155,7 @@ public final class LoanProductDataValidator { LoanProductConstants.OVER_APPLIED_NUMBER, LoanProductConstants.DELINQUENCY_BUCKET_PARAM_NAME)); private static final String[] SUPPORTED_LOAN_CONFIGURABLE_ATTRIBUTES = { LoanProductConstants.amortizationTypeParamName, - LoanProductConstants.interestTypeParamName, LoanProductConstants.transactionProcessingStrategyIdParamName, + LoanProductConstants.interestTypeParamName, LoanProductConstants.transactionProcessingStrategyCodeParamName, LoanProductConstants.interestCalculationPeriodTypeParamName, LoanProductConstants.inArrearsToleranceParamName, LoanProductConstants.repaymentEveryParamName, LoanProductConstants.graceOnPrincipalAndInterestPaymentParamName, LoanProductConstants.GRACE_ON_ARREARS_AGEING_PARAMETER_NAME }; @@ -161,10 +167,7 @@ public final class LoanProductDataValidator { private final FromJsonHelper fromApiJsonHelper; - @Autowired - public LoanProductDataValidator(final FromJsonHelper fromApiJsonHelper) { - this.fromApiJsonHelper = fromApiJsonHelper; - } + private final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory; public void validateForCreate(final String json) { if (StringUtils.isBlank(json)) { @@ -310,9 +313,19 @@ public final class LoanProductDataValidator { final BigDecimal inArrearsTolerance = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(IN_ARREARS_TOLERANCE, element); baseDataValidator.reset().parameter(IN_ARREARS_TOLERANCE).value(inArrearsTolerance).ignoreIfNull().zeroOrPositiveAmount(); - final Long transactionProcessingStrategyId = this.fromApiJsonHelper.extractLongNamed(TRANSACTION_PROCESSING_STRATEGY_ID, element); - baseDataValidator.reset().parameter(TRANSACTION_PROCESSING_STRATEGY_ID).value(transactionProcessingStrategyId).notNull() - .integerGreaterThanZero(); + final String transactionProcessingStrategyCode = this.fromApiJsonHelper.extractStringNamed(TRANSACTION_PROCESSING_STRATEGY_CODE, + element); + baseDataValidator.reset().parameter(TRANSACTION_PROCESSING_STRATEGY_CODE).value(transactionProcessingStrategyCode).notNull(); + + LoanRepaymentScheduleTransactionProcessor processor = loanRepaymentScheduleTransactionProcessorFactory + .determineProcessor(transactionProcessingStrategyCode); + + if (processor == null) { + Object[] values = loanRepaymentScheduleTransactionProcessorFactory.getStrategies().stream() + .map(TransactionProcessingStrategyData::getCode).toList().toArray(new String[0]); + + baseDataValidator.reset().parameter(TRANSACTION_PROCESSING_STRATEGY_CODE).isOneOfTheseValues(values); + } if (this.fromApiJsonHelper.parameterExists(LoanProductConstants.DELINQUENCY_BUCKET_PARAM_NAME, element)) { final Long delinquencyBucketId = this.fromApiJsonHelper.extractLongNamed(LoanProductConstants.DELINQUENCY_BUCKET_PARAM_NAME, @@ -1077,10 +1090,10 @@ public final class LoanProductDataValidator { baseDataValidator.reset().parameter(REPAYMENT_FREQUENCY_TYPE).value(repaymentFrequencyType).notNull().inMinMaxRange(0, 3); } - if (this.fromApiJsonHelper.parameterExists(TRANSACTION_PROCESSING_STRATEGY_ID, element)) { - final Long transactionProcessingStrategyId = this.fromApiJsonHelper.extractLongNamed(TRANSACTION_PROCESSING_STRATEGY_ID, + if (this.fromApiJsonHelper.parameterExists(TRANSACTION_PROCESSING_STRATEGY_CODE, element)) { + final String transactionProcessingStrategyCode = this.fromApiJsonHelper.extractStringNamed(TRANSACTION_PROCESSING_STRATEGY_CODE, element); - baseDataValidator.reset().parameter(TRANSACTION_PROCESSING_STRATEGY_ID).value(transactionProcessingStrategyId).notNull() + baseDataValidator.reset().parameter(TRANSACTION_PROCESSING_STRATEGY_CODE).value(transactionProcessingStrategyCode).notNull() .integerGreaterThanZero(); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanDropdownReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanDropdownReadPlatformServiceImpl.java index 4cb3b5833..c9659445e 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanDropdownReadPlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanDropdownReadPlatformServiceImpl.java @@ -34,15 +34,15 @@ import static org.apache.fineract.portfolio.loanproduct.service.LoanEnumerations import static org.apache.fineract.portfolio.loanproduct.service.LoanEnumerations.repaymentFrequencyType; import static org.apache.fineract.portfolio.loanproduct.service.LoanEnumerations.rescheduleStrategyType; -import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; +import lombok.RequiredArgsConstructor; import org.apache.fineract.infrastructure.core.data.EnumOptionData; import org.apache.fineract.portfolio.common.domain.DayOfWeekType; import org.apache.fineract.portfolio.common.domain.NthDayType; import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType; -import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionProcessingStrategyRepository; +import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleTransactionProcessorFactory; import org.apache.fineract.portfolio.loanproduct.data.TransactionProcessingStrategyData; import org.apache.fineract.portfolio.loanproduct.domain.AmortizationMethod; import org.apache.fineract.portfolio.loanproduct.domain.InterestCalculationPeriodMethod; @@ -51,22 +51,14 @@ import org.apache.fineract.portfolio.loanproduct.domain.InterestRecalculationCom import org.apache.fineract.portfolio.loanproduct.domain.LoanPreClosureInterestCalculationStrategy; import org.apache.fineract.portfolio.loanproduct.domain.LoanProductValueConditionType; import org.apache.fineract.portfolio.loanproduct.domain.LoanRescheduleStrategyMethod; -import org.apache.fineract.portfolio.loanproduct.domain.LoanTransactionProcessingStrategy; import org.apache.fineract.portfolio.loanproduct.domain.RecalculationFrequencyType; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; @Service +@RequiredArgsConstructor public class LoanDropdownReadPlatformServiceImpl implements LoanDropdownReadPlatformService { - private final LoanTransactionProcessingStrategyRepository loanTransactionProcessingStrategyRepository; - - @Autowired - public LoanDropdownReadPlatformServiceImpl( - final LoanTransactionProcessingStrategyRepository loanTransactionProcessingStrategyRepository) { - this.loanTransactionProcessingStrategyRepository = loanTransactionProcessingStrategyRepository; - } + private final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory; @Override public List retrieveLoanAmortizationTypeOptions() { @@ -125,15 +117,7 @@ public class LoanDropdownReadPlatformServiceImpl implements LoanDropdownReadPlat @Override public Collection retrieveTransactionProcessingStrategies() { - - final Collection strategyOptions = new ArrayList<>(); - Sort sort = Sort.by("sortOrder"); - final List strategies = this.loanTransactionProcessingStrategyRepository.findAll(sort); - for (final LoanTransactionProcessingStrategy strategy : strategies) { - strategyOptions.add(strategy.toData()); - } - - return strategyOptions; + return loanRepaymentScheduleTransactionProcessorFactory.getStrategies(); } @Override diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanProductReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanProductReadPlatformServiceImpl.java index 77c458b3d..3f966dc67 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanProductReadPlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanProductReadPlatformServiceImpl.java @@ -202,7 +202,7 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo } public String loanProductSchema() { - return "lp.id as id, lp.fund_id as fundId, f.name as fundName, lp.loan_transaction_strategy_id as transactionStrategyId, ltps.name as transactionStrategyName, " + return "lp.id as id, lp.fund_id as fundId, f.name as fundName, lp.loan_transaction_strategy_code as transactionStrategyCode, lp.loan_transaction_strategy_name as transactionStrategyName, " + "lp.name as name, lp.short_name as shortName, lp.description as description, " + "lp.principal_amount as principal, lp.min_principal_amount as minPrincipal, lp.max_principal_amount as maxPrincipal, lp.currency_code as currencyCode, lp.currency_digits as currencyDigits, lp.currency_multiplesof as inMultiplesOf, " + "lp.nominal_interest_rate_per_period as interestRatePerPeriod, lp.min_nominal_interest_rate_per_period as minInterestRatePerPeriod, lp.max_nominal_interest_rate_per_period as maxInterestRatePerPeriod, lp.interest_period_frequency_enum as interestRatePerPeriodFreq, " @@ -236,7 +236,7 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo + "lp.account_moves_out_of_npa_only_on_arrears_completion as accountMovesOutOfNPAOnlyOnArrearsCompletion, " + "curr.name as currencyName, curr.internationalized_name_code as currencyNameCode, curr.display_symbol as currencyDisplaySymbol, lp.external_id as externalId, " + "lca.id as lcaId, lca.amortization_method_enum as amortizationBoolean, lca.interest_method_enum as interestMethodConfigBoolean, " - + "lca.loan_transaction_strategy_id as transactionProcessingStrategyBoolean,lca.interest_calculated_in_period_enum as interestCalcPeriodBoolean, lca.arrearstolerance_amount as arrearsToleranceBoolean, " + + "lca.loan_transaction_strategy_code as transactionProcessingStrategyBoolean,lca.interest_calculated_in_period_enum as interestCalcPeriodBoolean, lca.arrearstolerance_amount as arrearsToleranceBoolean, " + "lca.repay_every as repaymentFrequencyBoolean, lca.moratorium as graceOnPrincipalAndInterestBoolean, lca.grace_on_arrears_ageing as graceOnArrearsAgingBoolean, " + "lp.is_linked_to_floating_interest_rates as isLinkedToFloatingInterestRates, " + "lfr.floating_rates_id as floatingRateId, " + "fr.name as floatingRateName, " @@ -251,7 +251,6 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo + " from m_product_loan lp " + " left join m_fund f on f.id = lp.fund_id " + " left join m_product_loan_recalculation_details lpr on lpr.product_id=lp.id " + " left join m_product_loan_guarantee_details lpg on lpg.loan_product_id=lp.id " - + " left join ref_loan_transaction_processing_strategy ltps on ltps.id = lp.loan_transaction_strategy_id" + " left join m_product_loan_configurable_attributes lca on lca.loan_product_id = lp.id " + " left join m_product_loan_floating_rates as lfr on lfr.loan_product_id = lp.id " + " left join m_floating_rates as fr on lfr.floating_rates_id = fr.id " @@ -270,7 +269,7 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo final String description = rs.getString("description"); final Long fundId = JdbcSupport.getLong(rs, "fundId"); final String fundName = rs.getString("fundName"); - final Long transactionStrategyId = JdbcSupport.getLong(rs, "transactionStrategyId"); + final String transactionStrategyCode = rs.getString("transactionStrategyCode"); final String transactionStrategyName = rs.getString("transactionStrategyName"); final String currencyCode = rs.getString("currencyCode"); @@ -487,7 +486,7 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod, minInterestRatePerPeriod, maxInterestRatePerPeriod, annualInterestRate, repaymentFrequencyType, interestRateFrequencyType, amortizationType, interestType, interestCalculationPeriodType, - allowPartialPeriodInterestCalcualtion, fundId, fundName, transactionStrategyId, transactionStrategyName, + allowPartialPeriodInterestCalcualtion, fundId, fundName, transactionStrategyCode, transactionStrategyName, graceOnPrincipalPayment, recurringMoratoriumOnPrincipalPeriods, graceOnInterestPayment, graceOnInterestCharged, this.charges, accountingRuleType, includeInBorrowerCycle, useBorrowerCycle, startDate, closeDate, status, externalId, principalVariationsForBorrowerCycle, interestRateVariationsForBorrowerCycle, diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanProductWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanProductWritePlatformServiceJpaRepositoryImpl.java index 32affda53..6cd832436 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanProductWritePlatformServiceJpaRepositoryImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanProductWritePlatformServiceJpaRepositoryImpl.java @@ -25,6 +25,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; import javax.persistence.PersistenceException; +import lombok.RequiredArgsConstructor; import org.apache.commons.lang3.exception.ExceptionUtils; import org.apache.fineract.accounting.producttoaccountmapping.service.ProductToGLAccountMappingWritePlatformService; import org.apache.fineract.infrastructure.core.api.JsonCommand; @@ -45,14 +46,12 @@ import org.apache.fineract.portfolio.floatingrates.domain.FloatingRateRepository import org.apache.fineract.portfolio.fund.domain.Fund; import org.apache.fineract.portfolio.fund.domain.FundRepository; import org.apache.fineract.portfolio.fund.exception.FundNotFoundException; +import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleTransactionProcessorFactory; import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper; -import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionProcessingStrategyRepository; -import org.apache.fineract.portfolio.loanaccount.exception.LoanTransactionProcessingStrategyNotFoundException; import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.AprCalculator; import org.apache.fineract.portfolio.loanproduct.LoanProductConstants; import org.apache.fineract.portfolio.loanproduct.domain.LoanProduct; import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRepository; -import org.apache.fineract.portfolio.loanproduct.domain.LoanTransactionProcessingStrategy; import org.apache.fineract.portfolio.loanproduct.exception.InvalidCurrencyException; import org.apache.fineract.portfolio.loanproduct.exception.LoanProductCannotBeModifiedDueToNonClosedLoansException; import org.apache.fineract.portfolio.loanproduct.exception.LoanProductDateException; @@ -62,13 +61,13 @@ import org.apache.fineract.portfolio.rate.domain.Rate; import org.apache.fineract.portfolio.rate.domain.RateRepositoryWrapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.DataIntegrityViolationException; import org.springframework.orm.jpa.JpaSystemException; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Service +@RequiredArgsConstructor public class LoanProductWritePlatformServiceJpaRepositoryImpl implements LoanProductWritePlatformService { private static final Logger LOG = LoggerFactory.getLogger(LoanProductWritePlatformServiceJpaRepositoryImpl.class); @@ -77,7 +76,6 @@ public class LoanProductWritePlatformServiceJpaRepositoryImpl implements LoanPro private final LoanProductRepository loanProductRepository; private final AprCalculator aprCalculator; private final FundRepository fundRepository; - private final LoanTransactionProcessingStrategyRepository loanTransactionProcessingStrategyRepository; private final ChargeRepositoryWrapper chargeRepository; private final RateRepositoryWrapper rateRepository; private final ProductToGLAccountMappingWritePlatformService accountMappingWritePlatformService; @@ -86,32 +84,7 @@ public class LoanProductWritePlatformServiceJpaRepositoryImpl implements LoanPro private final LoanRepositoryWrapper loanRepositoryWrapper; private final BusinessEventNotifierService businessEventNotifierService; private final DelinquencyBucketRepository delinquencyBucketRepository; - - @Autowired - public LoanProductWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, - final LoanProductDataValidator fromApiJsonDeserializer, final LoanProductRepository loanProductRepository, - final AprCalculator aprCalculator, final FundRepository fundRepository, - final LoanTransactionProcessingStrategyRepository loanTransactionProcessingStrategyRepository, - final ChargeRepositoryWrapper chargeRepository, final RateRepositoryWrapper rateRepository, - final ProductToGLAccountMappingWritePlatformService accountMappingWritePlatformService, - final FineractEntityAccessUtil fineractEntityAccessUtil, final FloatingRateRepositoryWrapper floatingRateRepository, - final LoanRepositoryWrapper loanRepositoryWrapper, final BusinessEventNotifierService businessEventNotifierService, - final DelinquencyBucketRepository delinquencyBucketRepository) { - this.context = context; - this.fromApiJsonDeserializer = fromApiJsonDeserializer; - this.loanProductRepository = loanProductRepository; - this.aprCalculator = aprCalculator; - this.fundRepository = fundRepository; - this.loanTransactionProcessingStrategyRepository = loanTransactionProcessingStrategyRepository; - this.chargeRepository = chargeRepository; - this.rateRepository = rateRepository; - this.accountMappingWritePlatformService = accountMappingWritePlatformService; - this.fineractEntityAccessUtil = fineractEntityAccessUtil; - this.floatingRateRepository = floatingRateRepository; - this.loanRepositoryWrapper = loanRepositoryWrapper; - this.businessEventNotifierService = businessEventNotifierService; - this.delinquencyBucketRepository = delinquencyBucketRepository; - } + private final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory; @Transactional @Override @@ -126,9 +99,7 @@ public class LoanProductWritePlatformServiceJpaRepositoryImpl implements LoanPro final Fund fund = findFundByIdIfProvided(command.longValueOfParameterNamed("fundId")); - final Long transactionProcessingStrategyId = command.longValueOfParameterNamed("transactionProcessingStrategyId"); - final LoanTransactionProcessingStrategy loanTransactionProcessingStrategy = findStrategyByIdIfProvided( - transactionProcessingStrategyId); + final String loanTransactionProcessingStrategyCode = command.stringValueOfParameterNamed("transactionProcessingStrategyCode"); final String currencyCode = command.stringValueOfParameterNamed("currencyCode"); final List charges = assembleListOfProductCharges(command, currencyCode); @@ -139,9 +110,11 @@ public class LoanProductWritePlatformServiceJpaRepositoryImpl implements LoanPro floatingRate = this.floatingRateRepository .findOneWithNotFoundDetection(command.longValueOfParameterNamed("floatingRatesId")); } - final LoanProduct loanProduct = LoanProduct.assembleFromJson(fund, loanTransactionProcessingStrategy, charges, command, + final LoanProduct loanProduct = LoanProduct.assembleFromJson(fund, loanTransactionProcessingStrategyCode, charges, command, this.aprCalculator, floatingRate, rates); loanProduct.updateLoanProductInRelatedClasses(); + loanProduct.setTransactionProcessingStrategyName( + loanRepaymentScheduleTransactionProcessorFactory.determineProcessor(loanTransactionProcessingStrategyCode).getName()); if (command.parameterExists("delinquencyBucketId")) { DelinquencyBucket delinquencyBucket = this.delinquencyBucketRepository @@ -177,15 +150,6 @@ public class LoanProductWritePlatformServiceJpaRepositoryImpl implements LoanPro } - private LoanTransactionProcessingStrategy findStrategyByIdIfProvided(final Long transactionProcessingStrategyId) { - LoanTransactionProcessingStrategy strategy = null; - if (transactionProcessingStrategyId != null) { - return this.loanTransactionProcessingStrategyRepository.findById(transactionProcessingStrategyId) - .orElseThrow(() -> new LoanTransactionProcessingStrategyNotFoundException(transactionProcessingStrategyId)); - } - return strategy; - } - private Fund findFundByIdIfProvided(final Long fundId) { Fund fund = null; if (fundId != null) { @@ -232,11 +196,12 @@ public class LoanProductWritePlatformServiceJpaRepositoryImpl implements LoanPro product.setDelinquencyBucket(delinquencyBucket); } - if (changes.containsKey("transactionProcessingStrategyId")) { - final Long transactionProcessingStrategyId = (Long) changes.get("transactionProcessingStrategyId"); - final LoanTransactionProcessingStrategy loanTransactionProcessingStrategy = findStrategyByIdIfProvided( - transactionProcessingStrategyId); - product.update(loanTransactionProcessingStrategy); + if (changes.containsKey("transactionProcessingStrategyCode")) { + final String transactionProcessingStrategyCode = (String) changes.get("transactionProcessingStrategyCode"); + final String transactionProcessingStrategyName = loanRepaymentScheduleTransactionProcessorFactory + .determineProcessor(transactionProcessingStrategyCode).getName(); + product.setTransactionProcessingStrategyCode(transactionProcessingStrategyCode); + product.setTransactionProcessingStrategyName(transactionProcessingStrategyName); } if (changes.containsKey("charges")) { diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/loanaccount/api/SelfLoansApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/loanaccount/api/SelfLoansApiResource.java index 993d0ad64..f763891b8 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/loanaccount/api/SelfLoansApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/loanaccount/api/SelfLoansApiResource.java @@ -204,9 +204,9 @@ public class SelfLoansApiResource { @Produces({ MediaType.APPLICATION_JSON }) @Operation(summary = "Calculate Loan Repayment Schedule | Submit a new Loan Application", description = "Calculate Loan Repayment Schedule:\n\n" + "Calculates Loan Repayment Schedule\n\n" - + "Mandatory Fields: productId, principal, loanTermFrequency, loanTermFrequencyType, numberOfRepayments, repaymentEvery, repaymentFrequencyType, interestRatePerPeriod, amortizationType, interestType, interestCalculationPeriodType, expectedDisbursementDate, transactionProcessingStrategyId\n\n" + + "Mandatory Fields: productId, principal, loanTermFrequency, loanTermFrequencyType, numberOfRepayments, repaymentEvery, repaymentFrequencyType, interestRatePerPeriod, amortizationType, interestType, interestCalculationPeriodType, expectedDisbursementDate, transactionProcessingStrategyCode\n\n" + "Submit a new Loan Application:\n\n" - + "Mandatory Fields: clientId, productId, principal, loanTermFrequency, loanTermFrequencyType, loanType, numberOfRepayments, repaymentEvery, repaymentFrequencyType, interestRatePerPeriod, amortizationType, interestType, interestCalculationPeriodType, transactionProcessingStrategyId, expectedDisbursementDate, submittedOnDate, loanType\n\n" + + "Mandatory Fields: clientId, productId, principal, loanTermFrequency, loanTermFrequencyType, loanType, numberOfRepayments, repaymentEvery, repaymentFrequencyType, interestRatePerPeriod, amortizationType, interestType, interestCalculationPeriodType, transactionProcessingStrategyCode, expectedDisbursementDate, submittedOnDate, loanType\n\n" + "Additional Mandatory Fields if interest recalculation is enabled for product and Rest frequency not same as repayment period: recalculationRestFrequencyDate\n\n" + "Additional Mandatory Fields if interest recalculation with interest/fee compounding is enabled for product and compounding frequency not same as repayment period: recalculationCompoundingFrequencyDate\n\n" + "Additional Mandatory Field if Entity-Datatable Check is enabled for the entity of type loan: datatables\n\n" diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/loanaccount/api/SelfLoansApiResourceSwagger.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/loanaccount/api/SelfLoansApiResourceSwagger.java index 40fe21e89..c00a3b6da 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/loanaccount/api/SelfLoansApiResourceSwagger.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/loanaccount/api/SelfLoansApiResourceSwagger.java @@ -482,8 +482,8 @@ final class SelfLoansApiResourceSwagger { public GetLoansLoanIdAmortizationType amortizationType; public GetLoansLoanIdInterestType interestType; public GetLoansLoanIdInterestCalculationPeriodType interestCalculationPeriodType; - @Schema(example = "2") - public Integer transactionProcessingStrategyId; + @Schema(example = "mifos-standard-strategy") + public String transactionProcessingStrategyCode; public GetLoansLoanIdTimeline timeline; public GetLoansLoanIdSummary summary; } @@ -694,8 +694,8 @@ final class SelfLoansApiResourceSwagger { public Integer interestType; @Schema(example = "1") public Integer interestCalculationPeriodType; - @Schema(example = "1") - public Integer transactionProcessingStrategyId; + @Schema(example = "mifos-standard-strategy") + public String transactionProcessingStrategyCode; @Schema(example = "10 Jun 2013") public String expectedDisbursementDate; @Schema(example = "10 Jun 2013") @@ -758,8 +758,8 @@ final class SelfLoansApiResourceSwagger { public Integer amortizationType; @Schema(example = "04 March 2014") public String expectedDisbursementDate; - @Schema(example = "1") - public Integer transactionProcessingStrategyId; + @Schema(example = "mifos-standard-strategy") + public String transactionProcessingStrategyCode; } @Schema(description = "PutSelfLoansLoanIdResponse") diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/products/api/SelfLoanProductsApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/products/api/SelfLoanProductsApiResource.java index 684a69fbe..8eab22e15 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/products/api/SelfLoanProductsApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/products/api/SelfLoanProductsApiResource.java @@ -72,7 +72,7 @@ import org.springframework.stereotype.Component; + "The minimum number of days allowed between a Loan disbursal and its first repayment.\n" + "principalThresholdForLastInstalment\n" + "Field represents percentage of current instalment principal amount for comparing against principal outstanding to add another repayment instalment. If the outstanding principal amount is less then calculated amount, remaining outstanding amount will be added to current instalment. Default value for multi disburse loan is 50% and non-multi disburse loan is 0%\n" + "canDefineInstallmentAmount\n" + "if provided as true, then fixed instalment amount can be provided from loan account.\n" - + "transactionProcessingStrategyId\n" + + "transactionProcessingStrategyCode\n" + "An enumeration that indicates the type of transaction processing strategy to be used. This relates to functionality that is also known as Payment Application Logic.\n" + "A number of out of the box approaches exist, some are custom to specific MFIs, some are more general and indicate the order in which payments are processed.\n" + "\n" diff --git a/fineract-provider/src/main/resources/application.properties b/fineract-provider/src/main/resources/application.properties index 03f3f4283..d04f98c19 100644 --- a/fineract-provider/src/main/resources/application.properties +++ b/fineract-provider/src/main/resources/application.properties @@ -61,6 +61,15 @@ fineract.events.external.producer.jms.broker-url=${FINERACT_EXTERNAL_EVENTS_PROD fineract.idempotency-key-header-name=${FINERACT_IDEMPOTENCY_KEY_HEADER_NAME:Idempotency-Key} +fineract.loan.transactionprocessor.creocore.enabled=${FINERACT_LOAN_TRANSACTIONPROCESSOR_CREOCORE_ENABLED:true} +fineract.loan.transactionprocessor.early-repayment.enabled=${FINERACT_LOAN_TRANSACTIONPROCESSOR_EARLY_REPAYMENT_ENABLED:true} +fineract.loan.transactionprocessor.mifos-standard.enabled=${FINERACT_LOAN_TRANSACTIONPROCESSOR_MIFOS_STANDARD_ENABLED:true} +fineract.loan.transactionprocessor.heavensfamily.enabled=${FINERACT_LOAN_TRANSACTIONPROCESSOR_HEAVENSFAMILY_ENABLED:true} +fineract.loan.transactionprocessor.interest-principal-penalties-fees.enabled=${FINERACT_LOAN_TRANSACTIONPROCESSOR_INTEREST_PRINCIPAL_PENALTIES_FEES_ENABLED:true} +fineract.loan.transactionprocessor.principal-interest-penalties-fees.enabled=${FINERACT_LOAN_TRANSACTIONPROCESSOR_PRINCIPAL_INTEREST_PENALTIES_FEES_ENABLED:true} +fineract.loan.transactionprocessor.rbi-india.enabled=${FINERACT_LOAN_TRANSACTIONPROCESSOR_RBI_INDIA_ENABLED:true} +fineract.loan.transactionprocessor.error-not-found-fail=${FINERACT_LOAN_TRANSACTIONPROCESSOR_ERROR_NOT_FOUND_FAIL:true} + # Logging pattern for the console logging.pattern.console=${CONSOLE_LOG_PATTERN:%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(%replace([%X{correlationId}]){'\\[\\]', ''}) %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:%wEx}} diff --git a/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml b/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml index 021e6e960..f652ebe41 100644 --- a/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml +++ b/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml @@ -83,4 +83,5 @@ + diff --git a/fineract-provider/src/main/resources/db/changelog/tenant/parts/0064_refactor_loan_transaction_strategy.xml b/fineract-provider/src/main/resources/db/changelog/tenant/parts/0064_refactor_loan_transaction_strategy.xml new file mode 100644 index 000000000..14acd66af --- /dev/null +++ b/fineract-provider/src/main/resources/db/changelog/tenant/parts/0064_refactor_loan_transaction_strategy.xml @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + loan_transaction_strategy_id = 1 + + + + + loan_transaction_strategy_id = 2 + + + + + loan_transaction_strategy_id = 3 + + + + + loan_transaction_strategy_id = 4 + + + + + loan_transaction_strategy_id = 5 + + + + + loan_transaction_strategy_id = 6 + + + + + loan_transaction_strategy_id = 7 + + + + + + + + + + + + + + + + + loan_transaction_strategy_id = 1 + + + + + loan_transaction_strategy_id = 2 + + + + + loan_transaction_strategy_id = 3 + + + + + loan_transaction_strategy_id = 4 + + + + + loan_transaction_strategy_id = 5 + + + + + loan_transaction_strategy_id = 6 + + + + + loan_transaction_strategy_id = 7 + + + + + + + + + diff --git a/fineract-provider/src/main/resources/sql/migrations/sample_data/barebones_db.sql b/fineract-provider/src/main/resources/sql/migrations/sample_data/barebones_db.sql index 0ef41e972..7ad6deb4c 100644 --- a/fineract-provider/src/main/resources/sql/migrations/sample_data/barebones_db.sql +++ b/fineract-provider/src/main/resources/sql/migrations/sample_data/barebones_db.sql @@ -2266,7 +2266,6 @@ CREATE TABLE IF NOT EXISTS `m_loan` ( KEY `FKB6F935D87179A0CB` (`client_id`), KEY `FKB6F935D8C8D4B434` (`product_id`), KEY `FK7C885877240145` (`fund_id`), - KEY `FK_loan_ltp_strategy` (`loan_transaction_strategy_id`), KEY `FK_m_loan_m_staff` (`loan_officer_id`), KEY `group_id` (`group_id`), KEY `FK_m_loanpurpose_codevalue` (`loanpurpose_cv_id`), @@ -2284,7 +2283,6 @@ CREATE TABLE IF NOT EXISTS `m_loan` ( CONSTRAINT `FK_approvedon_userid` FOREIGN KEY (`approvedon_userid`) REFERENCES `m_appuser` (`id`), CONSTRAINT `FK_closedon_userid` FOREIGN KEY (`closedon_userid`) REFERENCES `m_appuser` (`id`), CONSTRAINT `FK_disbursedon_userid` FOREIGN KEY (`disbursedon_userid`) REFERENCES `m_appuser` (`id`), - CONSTRAINT `FK_loan_ltp_strategy` FOREIGN KEY (`loan_transaction_strategy_id`) REFERENCES `ref_loan_transaction_processing_strategy` (`id`), CONSTRAINT `FK_m_loan_m_staff` FOREIGN KEY (`loan_officer_id`) REFERENCES `m_staff` (`id`), CONSTRAINT `FK_m_loanpurpose_codevalue` FOREIGN KEY (`loanpurpose_cv_id`) REFERENCES `m_code_value` (`id`), CONSTRAINT `FK_rejectedon_userid` FOREIGN KEY (`rejectedon_userid`) REFERENCES `m_appuser` (`id`), @@ -3971,9 +3969,7 @@ CREATE TABLE IF NOT EXISTS `m_product_loan` ( UNIQUE KEY `unq_short_name` (`short_name`), UNIQUE KEY `external_id_UNIQUE` (`external_id`), KEY `FKA6A8A7D77240145` (`fund_id`), - KEY `FK_ltp_strategy` (`loan_transaction_strategy_id`), - CONSTRAINT `FKA6A8A7D77240145` FOREIGN KEY (`fund_id`) REFERENCES `m_fund` (`id`), - CONSTRAINT `FK_ltp_strategy` FOREIGN KEY (`loan_transaction_strategy_id`) REFERENCES `ref_loan_transaction_processing_strategy` (`id`) + CONSTRAINT `FKA6A8A7D77240145` FOREIGN KEY (`fund_id`) REFERENCES `m_fund` (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=UTF8MB4; -- Dumping data for table fineract_default.m_product_loan: ~0 rows (approximately) @@ -5494,30 +5490,6 @@ INSERT INTO `ppi_scores` (`id`, `score_from`, `score_to`) VALUES /*!40000 ALTER TABLE `ppi_scores` ENABLE KEYS */; --- Dumping structure for table fineract_default.ref_loan_transaction_processing_strategy -DROP TABLE IF EXISTS `ref_loan_transaction_processing_strategy`; -CREATE TABLE IF NOT EXISTS `ref_loan_transaction_processing_strategy` ( - `id` BIGINT NOT NULL AUTO_INCREMENT, - `code` varchar(100) DEFAULT NULL, - `name` varchar(255) DEFAULT NULL, - `sort_order` INT DEFAULT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `ltp_strategy_code` (`code`) -) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=UTF8MB4; - --- Dumping data for table fineract_default.ref_loan_transaction_processing_strategy: ~7 rows (approximately) -/*!40000 ALTER TABLE `ref_loan_transaction_processing_strategy` DISABLE KEYS */; -INSERT INTO `ref_loan_transaction_processing_strategy` (`id`, `code`, `name`, `sort_order`) VALUES - (1, 'mifos-standard-strategy', 'Penalties, Fees, Interest, Principal order', 1), - (2, 'heavensfamily-strategy', 'HeavensFamily Unique', 6), - (3, 'creocore-strategy', 'Creocore Unique', 7), - (4, 'rbi-india-strategy', 'Overdue/Due Fee/Int,Principal', 2), - (5, 'principal-interest-penalties-fees-order-strategy', 'Principal, Interest, Penalties, Fees Order', 3), - (6, 'interest-principal-penalties-fees-order-strategy', 'Interest, Principal, Penalties, Fees Order', 4), - (7, 'early-repayment-strategy', 'Early Repayment Strategy', 5); -/*!40000 ALTER TABLE `ref_loan_transaction_processing_strategy` ENABLE KEYS */; - - -- Dumping structure for table fineract_default.rpt_sequence DROP TABLE IF EXISTS `rpt_sequence`; CREATE TABLE IF NOT EXISTS `rpt_sequence` ( diff --git a/fineract-provider/src/main/resources/sql/migrations/sample_data/load_sample_data.sql b/fineract-provider/src/main/resources/sql/migrations/sample_data/load_sample_data.sql index 4c3c13419..61e4fdf63 100644 --- a/fineract-provider/src/main/resources/sql/migrations/sample_data/load_sample_data.sql +++ b/fineract-provider/src/main/resources/sql/migrations/sample_data/load_sample_data.sql @@ -2406,7 +2406,6 @@ CREATE TABLE IF NOT EXISTS `m_loan` ( KEY `FKB6F935D87179A0CB` (`client_id`), KEY `FKB6F935D8C8D4B434` (`product_id`), KEY `FK7C885877240145` (`fund_id`), - KEY `FK_loan_ltp_strategy` (`loan_transaction_strategy_id`), KEY `FK_m_loan_m_staff` (`loan_officer_id`), KEY `group_id` (`group_id`), KEY `FK_m_loanpurpose_codevalue` (`loanpurpose_cv_id`), @@ -2424,7 +2423,6 @@ CREATE TABLE IF NOT EXISTS `m_loan` ( CONSTRAINT `FK_approvedon_userid` FOREIGN KEY (`approvedon_userid`) REFERENCES `m_appuser` (`id`), CONSTRAINT `FK_closedon_userid` FOREIGN KEY (`closedon_userid`) REFERENCES `m_appuser` (`id`), CONSTRAINT `FK_disbursedon_userid` FOREIGN KEY (`disbursedon_userid`) REFERENCES `m_appuser` (`id`), - CONSTRAINT `FK_loan_ltp_strategy` FOREIGN KEY (`loan_transaction_strategy_id`) REFERENCES `ref_loan_transaction_processing_strategy` (`id`), CONSTRAINT `FK_m_loan_m_staff` FOREIGN KEY (`loan_officer_id`) REFERENCES `m_staff` (`id`), CONSTRAINT `FK_m_loanpurpose_codevalue` FOREIGN KEY (`loanpurpose_cv_id`) REFERENCES `m_code_value` (`id`), CONSTRAINT `FK_rejectedon_userid` FOREIGN KEY (`rejectedon_userid`) REFERENCES `m_appuser` (`id`), @@ -4104,7 +4102,7 @@ INSERT INTO `m_portfolio_command_source` (`id`, `action_name`, `entity_name`, `o (24, 'CREATE', 'USER', 1, NULL, NULL, NULL, NULL, '/users/template', 5, NULL, '{"sendPasswordToEmail":true,"officeId":1,"username":"janej","firstname":"Jane","lastname":"J","email":"janej@123.com","roles":["1"]}', 1, '2014-03-07 20:07:48', NULL, NULL, 1, NULL, NULL), (25, 'CREATE', 'STAFF', 3, NULL, NULL, NULL, NULL, '/staff/template', 3, NULL, '{"isLoanOfficer":true,"officeId":3,"firstname":"John","lastname":"K"}', 1, '2014-03-07 20:08:28', NULL, NULL, 1, NULL, NULL), (26, 'CREATE', 'FUND', NULL, NULL, NULL, NULL, NULL, '/funds/template', 1, NULL, '{"name":"Loan from Central Bank"}', 1, '2014-03-10 10:11:50', NULL, NULL, 1, NULL, NULL), - (27, 'CREATE', 'LOANPRODUCT', NULL, NULL, NULL, NULL, NULL, '/loanproducts/template', 1, NULL, '{"currencyCode":"USD","includeInBorrowerCycle":"false","useBorrowerCycle":"false","digitsAfterDecimal":"2","inMultiplesOf":"0","repaymentFrequencyType":1,"interestRateFrequencyType":3,"amortizationType":1,"interestType":1,"interestCalculationPeriodType":1,"transactionProcessingStrategyId":1,"principalVariationsForBorrowerCycle":[],"interestRateVariationsForBorrowerCycle":[],"numberOfRepaymentVariationsForBorrowerCycle":[],"multiDisburseLoan":false,"fundSourceAccountId":31,"loanPortfolioAccountId":32,"transfersInSuspenseAccountId":33,"interestOnLoanAccountId":36,"incomeFromFeeAccountId":37,"incomeFromPenaltyAccountId":38,"writeOffAccountId":41,"overpaymentLiabilityAccountId":30,"accountingRule":"2","name":"Income Generating Loan","shortName":"IGL","fundId":1,"minPrincipal":"10000","principal":"10000","maxPrincipal":"10000","minNumberOfRepayments":"25","numberOfRepayments":"25","maxNumberOfRepayments":"25","repaymentEvery":"1","minInterestRatePerPeriod":"26","interestRatePerPeriod":"26","maxInterestRatePerPeriod":"26","paymentChannelToFundSourceMappings":[],"feeToIncomeAccountMappings":[],"penaltyToIncomeAccountMappings":[],"charges":[],"dateFormat":"dd MMMM yyyy","locale":"en","startDate":"01 January 2010"}', 1, '2014-03-10 10:16:39', NULL, NULL, 1, NULL, NULL), + (27, 'CREATE', 'LOANPRODUCT', NULL, NULL, NULL, NULL, NULL, '/loanproducts/template', 1, NULL, '{"currencyCode":"USD","includeInBorrowerCycle":"false","useBorrowerCycle":"false","digitsAfterDecimal":"2","inMultiplesOf":"0","repaymentFrequencyType":1,"interestRateFrequencyType":3,"amortizationType":1,"interestType":1,"interestCalculationPeriodType":1,"transactionProcessingStrategyCode":"mifos-standard-strategy","principalVariationsForBorrowerCycle":[],"interestRateVariationsForBorrowerCycle":[],"numberOfRepaymentVariationsForBorrowerCycle":[],"multiDisburseLoan":false,"fundSourceAccountId":31,"loanPortfolioAccountId":32,"transfersInSuspenseAccountId":33,"interestOnLoanAccountId":36,"incomeFromFeeAccountId":37,"incomeFromPenaltyAccountId":38,"writeOffAccountId":41,"overpaymentLiabilityAccountId":30,"accountingRule":"2","name":"Income Generating Loan","shortName":"IGL","fundId":1,"minPrincipal":"10000","principal":"10000","maxPrincipal":"10000","minNumberOfRepayments":"25","numberOfRepayments":"25","maxNumberOfRepayments":"25","repaymentEvery":"1","minInterestRatePerPeriod":"26","interestRatePerPeriod":"26","maxInterestRatePerPeriod":"26","paymentChannelToFundSourceMappings":[],"feeToIncomeAccountMappings":[],"penaltyToIncomeAccountMappings":[],"charges":[],"dateFormat":"dd MMMM yyyy","locale":"en","startDate":"01 January 2010"}', 1, '2014-03-10 10:16:39', NULL, NULL, 1, NULL, NULL), (28, 'CREATE', 'SAVINGSPRODUCT', NULL, NULL, NULL, NULL, NULL, '/savingsproducts/template', 1, NULL, '{"currencyCode":"USD","digitsAfterDecimal":2,"interestCompoundingPeriodType":1,"interestPostingPeriodType":4,"interestCalculationType":1,"interestCalculationDaysInYearType":365,"savingsReferenceAccountId":31,"overdraftPortfolioControlId":32,"savingsControlAccountId":30,"incomeFromFeeAccountId":36,"incomeFromPenaltyAccountId":37,"incomeFromInterestId":38,"interestOnSavingsAccountId":41,"writeOffAccountId":42,"accountingRule":"2","name":"Voluntary savings","shortName":"VS","description":"Save money","inMultiplesOf":"0","nominalAnnualInterestRate":"9.5","minRequiredOpeningBalance":"1000","lockinPeriodFrequency":"1","lockinPeriodFrequencyType":1,"withdrawalFeeForTransfers":"false","paymentChannelToFundSourceMappings":[],"feeToIncomeAccountMappings":[],"penaltyToIncomeAccountMappings":[],"charges":[],"locale":"en","transfersInSuspenseAccountId":30}', 1, '2014-03-10 10:21:16', NULL, NULL, 1, NULL, NULL), (29, 'UPDATE', 'SAVINGSPRODUCT', NULL, NULL, NULL, NULL, NULL, '/savingsproducts/1', 1, NULL, '{"shortName":"VS","penaltyToIncomeAccountMappings":"[]","paymentChannelToFundSourceMappings":"[]","feeToIncomeAccountMappings":"[]"}', 1, '2014-03-10 10:21:51', NULL, NULL, 1, NULL, NULL), (30, 'CREATE', 'CODEVALUE', NULL, NULL, NULL, NULL, NULL, '/codes/3/codevalues/template', 10, NULL, '{"name":"Cattle Rearing","position":"104"}', 1, '2014-03-10 10:27:02', NULL, NULL, 1, NULL, NULL), @@ -4145,7 +4143,7 @@ INSERT INTO `m_portfolio_command_source` (`id`, `action_name`, `entity_name`, `o (65, 'UPDATE', 'GLACCOUNT', NULL, NULL, NULL, NULL, NULL, '/glaccounts/2', 2, NULL, '{"usage":1}', 1, '2014-05-01 16:25:56', NULL, NULL, 1, NULL, NULL), (66, 'UPDATE', 'LOANPRODUCT', NULL, NULL, NULL, NULL, NULL, '/loanproducts/1', 1, NULL, '{"inMultiplesOf":0,"penaltyToIncomeAccountMappings":"[]","paymentChannelToFundSourceMappings":"[]","feeToIncomeAccountMappings":"[]"}', 1, '2014-05-01 16:26:06', NULL, NULL, 1, NULL, NULL), (67, 'UPDATE', 'LOANPRODUCT', NULL, NULL, NULL, NULL, NULL, '/loanproducts/1', 1, NULL, '{"inMultiplesOf":0,"overpaymentLiabilityAccountId":2,"penaltyToIncomeAccountMappings":"[]","paymentChannelToFundSourceMappings":"[]","transfersInSuspenseAccountId":17,"feeToIncomeAccountMappings":"[]"}', 1, '2014-05-01 16:26:37', NULL, NULL, 1, NULL, NULL), - (68, 'CREATE', 'LOAN', 2, NULL, 8, 1, NULL, '/loans', 1, NULL, '{"clientId":"8","productId":1,"disbursementData":[],"fundId":1,"principal":10000,"loanTermFrequency":25,"loanTermFrequencyType":1,"numberOfRepayments":25,"repaymentEvery":1,"repaymentFrequencyType":1,"interestRatePerPeriod":26,"amortizationType":1,"interestType":1,"interestCalculationPeriodType":1,"transactionProcessingStrategyId":1,"locale":"en","dateFormat":"dd MMMM yyyy","loanType":"individual","expectedDisbursementDate":"16 June 2014","submittedOnDate":"02 June 2014","charges":[{"chargeId":1,"amount":500}]}', 1, '2014-06-11 09:17:45', NULL, NULL, 1, NULL, NULL), + (68, 'CREATE', 'LOAN', 2, NULL, 8, 1, NULL, '/loans', 1, NULL, '{"clientId":"8","productId":1,"disbursementData":[],"fundId":1,"principal":10000,"loanTermFrequency":25,"loanTermFrequencyType":1,"numberOfRepayments":25,"repaymentEvery":1,"repaymentFrequencyType":1,"interestRatePerPeriod":26,"amortizationType":1,"interestType":1,"interestCalculationPeriodType":1,"transactionProcessingStrategyCode":"mifos-standard-strategy","locale":"en","dateFormat":"dd MMMM yyyy","loanType":"individual","expectedDisbursementDate":"16 June 2014","submittedOnDate":"02 June 2014","charges":[{"chargeId":1,"amount":500}]}', 1, '2014-06-11 09:17:45', NULL, NULL, 1, NULL, NULL), (69, 'APPROVE', 'LOAN', 2, NULL, 8, 1, NULL, '/loans/1', 1, NULL, '{"status":{"id":200,"code":"loanStatusType.approved","value":"Approved","pendingApproval":false,"waitingForDisbursal":true,"active":false,"closedObligationsMet":false,"closedWrittenOff":false,"closedRescheduled":false,"closed":false,"overpaid":false},"locale":"en","dateFormat":"dd MMMM yyyy","approvedOnDate":"11 June 2014"}', 1, '2014-06-11 09:18:16', NULL, NULL, 1, NULL, NULL), (70, 'CREATE', 'FINANCIALACTIVITYACCOUNT', NULL, NULL, NULL, NULL, NULL, '/organizationglaccounts/template', 2, NULL, '{"financialActivityId":100,"glAccountId":33}', 1, '2014-06-16 16:54:20', NULL, NULL, 1, NULL, NULL), (71, 'UPDATE', 'FINANCIALACTIVITYACCOUNT', NULL, NULL, NULL, NULL, NULL, '/organizationglaccounts/2', 2, NULL, '{"glAccountId":32}', 1, '2014-06-16 16:57:17', NULL, NULL, 1, NULL, NULL), @@ -4216,9 +4214,7 @@ CREATE TABLE IF NOT EXISTS `m_product_loan` ( UNIQUE KEY `unq_short_name` (`short_name`), UNIQUE KEY `external_id_UNIQUE` (`external_id`), KEY `FKA6A8A7D77240145` (`fund_id`), - KEY `FK_ltp_strategy` (`loan_transaction_strategy_id`), - CONSTRAINT `FKA6A8A7D77240145` FOREIGN KEY (`fund_id`) REFERENCES `m_fund` (`id`), - CONSTRAINT `FK_ltp_strategy` FOREIGN KEY (`loan_transaction_strategy_id`) REFERENCES `ref_loan_transaction_processing_strategy` (`id`) + CONSTRAINT `FKA6A8A7D77240145` FOREIGN KEY (`fund_id`) REFERENCES `m_fund` (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=UTF8MB4; -- Dumping data for table mifostenant-reference.m_product_loan: ~1 rows (approximately) @@ -5751,30 +5747,6 @@ INSERT INTO `ppi_scores` (`id`, `score_from`, `score_to`) VALUES /*!40000 ALTER TABLE `ppi_scores` ENABLE KEYS */; --- Dumping structure for table mifostenant-reference.ref_loan_transaction_processing_strategy -DROP TABLE IF EXISTS `ref_loan_transaction_processing_strategy`; -CREATE TABLE IF NOT EXISTS `ref_loan_transaction_processing_strategy` ( - `id` BIGINT NOT NULL AUTO_INCREMENT, - `code` varchar(100) DEFAULT NULL, - `name` varchar(255) DEFAULT NULL, - `sort_order` INT DEFAULT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `ltp_strategy_code` (`code`) -) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=UTF8MB4; - --- Dumping data for table mifostenant-reference.ref_loan_transaction_processing_strategy: ~7 rows (approximately) -/*!40000 ALTER TABLE `ref_loan_transaction_processing_strategy` DISABLE KEYS */; -INSERT INTO `ref_loan_transaction_processing_strategy` (`id`, `code`, `name`, `sort_order`) VALUES - (1, 'mifos-standard-strategy', 'Penalties, Fees, Interest, Principal order', 1), - (2, 'heavensfamily-strategy', 'HeavensFamily Unique', 6), - (3, 'creocore-strategy', 'Creocore Unique', 7), - (4, 'rbi-india-strategy', 'Overdue/Due Fee/Int,Principal', 2), - (5, 'principal-interest-penalties-fees-order-strategy', 'Principal, Interest, Penalties, Fees Order', 3), - (6, 'interest-principal-penalties-fees-order-strategy', 'Interest, Principal, Penalties, Fees Order', 4), - (7, 'early-repayment-strategy', 'Early Repayment Strategy', 5); -/*!40000 ALTER TABLE `ref_loan_transaction_processing_strategy` ENABLE KEYS */; - - -- Dumping structure for table mifostenant-reference.rpt_sequence DROP TABLE IF EXISTS `rpt_sequence`; CREATE TABLE IF NOT EXISTS `rpt_sequence` ( diff --git a/fineract-provider/src/main/resources/static/legacy-docs/apiLive.htm b/fineract-provider/src/main/resources/static/legacy-docs/apiLive.htm index 2c8c5833b..7efe917f9 100644 --- a/fineract-provider/src/main/resources/static/legacy-docs/apiLive.htm +++ b/fineract-provider/src/main/resources/static/legacy-docs/apiLive.htm @@ -4740,7 +4740,7 @@ Content-Type: application/json Request Body: \"amortizationType\": 1, \"interestType\": 0, \"interestCalculationPeriodType\": 1, - \"transactionProcessingStrategyId\": 1, + \"transactionProcessingStrategyCode\": \"mifos-standard-strategy\", \"expectedDisbursementDate\": \"10 Jun 2013\", \"submittedOnDate\": \"10 Jun 2013\" }" @@ -10339,7 +10339,7 @@ GET https://DomainName/fineract-provider/api/v1/groups/{groupId}/glimaccounts - transactionProcessingStrategyId + transactionProcessingStrategyCode @@ -10541,7 +10541,7 @@ GET https://DomainName/api/v1/loans/template?templateType=individual&clientId=1& "code": "interestCalculationPeriodType.same.as.repayment.period", "value": "Same as repayment period" }, - "transactionProcessingStrategyId": 2, + "transactionProcessingStrategyCode": "mifos-standard-strategy", "timeline": { "expectedDisbursementDate": [ 2013, @@ -10973,7 +10973,7 @@ GET https://DomainName/api/v1/loans/{loanId} "code": "interestCalculationPeriodType.same.as.repayment.period", "value": "Same as repayment period" }, - "transactionProcessingStrategyId": 2, + "transactionProcessingStrategyCode": "mifos-standard-strategy", "timeline": { "submittedOnDate": [ 2012, @@ -11265,7 +11265,7 @@ GET https://DomainName/fineract-provider/api/v1/loans "code": "interestCalculationPeriodType.same.as.repayment.period", "value": "Same as repayment period" }, - "transactionProcessingStrategyId": 2, + "transactionProcessingStrategyCode": "mifos-standard-strategy", "timeline": { "submittedOnDate": [ 2012, @@ -11417,7 +11417,7 @@ No Request Body: "interestCalculationPeriodType": 0, "amortizationType": 1, "expectedDisbursementDate": "04 March 2014", - "transactionProcessingStrategyId": 1 + "transactionProcessingStrategyCode": "mifos-standard-strategy" } @@ -11449,7 +11449,7 @@ No Request Body: repaymentFrequencyType, interestRatePerPeriod, amortizationType, interestType, interestCalculationPeriodType, expectedDisbursementDate, - transactionProcessingStrategyId + transactionProcessingStrategyCode @@ -11476,7 +11476,7 @@ Request Body: "interestType": 0, "interestCalculationPeriodType": 1, "expectedDisbursementDate": "20 September 2011", - "transactionProcessingStrategyId": 2 + "transactionProcessingStrategyCode": "mifos-standard-strategy" } @@ -11598,7 +11598,7 @@ Request Body: loanTermFrequencyType, loanType, numberOfRepayments, repaymentEvery, repaymentFrequencyType, interestRatePerPeriod, amortizationType, interestType, - interestCalculationPeriodType, transactionProcessingStrategyId, + interestCalculationPeriodType, transactionProcessingStrategyCode, expectedDisbursementDate, submittedOnDate, loanType @@ -11663,7 +11663,7 @@ Request Body: "amortizationType": 1, "interestType": 0, "interestCalculationPeriodType": 1, - "transactionProcessingStrategyId": 1, + "transactionProcessingStrategyCode": "mifos-standard-strategy", "expectedDisbursementDate": "10 Jun 2013", "submittedOnDate": "10 Jun 2013", "linkAccountId" : "1", @@ -12222,7 +12222,7 @@ Content-Type: application/json interestRatePerPeriod, expectedDisbursementDate, clientId, groupId, productId, totalLoan, loanType, interestType, - principal, charges, transactionProcessingStrategyId, submittedOnDate, amortizationType, repaymentFrequencyType, + principal, charges, transactionProcessingStrategyCode, submittedOnDate, amortizationType, repaymentFrequencyType, loanTermFrequencyType, loanTermFrequency, repaymentEvery, numberOfRepayments, interestCalculationPeriodType, isParentAccount, locale,dateFormat @@ -12250,7 +12250,7 @@ Request Body: "locale":"en_GB", "principal":"1000.00", "charges":[], - "transactionProcessingStrategyId":"1", + "transactionProcessingStrategyCode":"mifos-standard-strategy", "submittedOnDate":"10 June 2020", "amortizationType":"1", "repaymentFrequencyType":"2", @@ -15740,7 +15740,7 @@ Request Body: - transactionProcessingStrategyId + transactionProcessingStrategyCode @@ -15986,7 +15986,7 @@ GET https://DomainName/api/v1/loanproducts "code": "interestCalculationPeriodType.same.as.repayment.period", "value": "Same as repayment period" }, - "transactionProcessingStrategyId": 1, + "transactionProcessingStrategyCode": "mifos-standard-strategy", "transactionProcessingStrategyName": "Mifos style", "principalVariationsForBorrowerCycle": [], "interestRateVariationsForBorrowerCycle": [], @@ -16989,7 +16989,7 @@ GET https://DomainName/api/v1/loanproducts/{productId} "code": "interestCalculationPeriodType.same.as.repayment.period", "value": "Same as repayment period" }, - "transactionProcessingStrategyId": 1, + "transactionProcessingStrategyCode": "mifos-standard-strategy", "transactionProcessingStrategyName": "Mifos style", "charges": [], "principalVariationsForBorrowerCycle": [ @@ -17162,7 +17162,7 @@ GET https://DomainName/api/v1/loanproducts/{productId} name, shortName, currencyCode, digitsAfterDecimal, inMultiplesOf, principal, numberOfRepayments, repaymentEvery, repaymentFrequencyType, interestRatePerPeriod, interestRateFrequencyType, amortizationType, interestType, - interestCalculationPeriodType, transactionProcessingStrategyId, + interestCalculationPeriodType, transactionProcessingStrategyCode, accountingRule, isInterestRecalculationEnabled, daysInYearType, daysInMonthType @@ -17277,7 +17277,7 @@ Request Body: "amortizationType":1, "interestType":0, "interestCalculationPeriodType":1, -"transactionProcessingStrategyId":1, +"transactionProcessingStrategyCode":"mifos-standard-strategy", "principalVariationsForBorrowerCycle":[], "interestRateVariationsForBorrowerCycle":[], "numberOfRepaymentVariationsForBorrowerCycle":[ @@ -17299,7 +17299,7 @@ Request Body: "allowAttributeOverrides": {amortizationType : true, interestType : true, - transactionProcessingStrategyId : false, + transactionProcessingStrategyCode : false, interestCalculationPeriodType : true, inArrearsTolerance : false, repaymentEvery : true, @@ -17355,7 +17355,7 @@ Request Body: "numberOfRepayments": "12", "repaymentEvery": "1", "repaymentFrequencyType": 2, - "transactionProcessingStrategyId": 1, + "transactionProcessingStrategyCode": "mifos-standard-strategy", "interestRatePerPeriod": "1.75", "interestRateFrequencyType": 2, "amortizationType": 1, @@ -17422,7 +17422,7 @@ Request Body: "numberOfRepayments": "12", "repaymentEvery": "1", "repaymentFrequencyType": 2, - "transactionProcessingStrategyId": 1, + "transactionProcessingStrategyCode": "mifos-standard-strategy", "interestRatePerPeriod": "1.75", "interestRateFrequencyType": 2, "amortizationType": 1, @@ -47942,7 +47942,7 @@ GET https://DomainName/api/v1/self/loans/template?templateType=individual&client "code": "interestCalculationPeriodType.same.as.repayment.period", "value": "Same as repayment period" }, - "transactionProcessingStrategyId": 2, + "transactionProcessingStrategyCode": "mifos-standard-strategy", "timeline": { "expectedDisbursementDate": [ 2013, @@ -48192,7 +48192,7 @@ GET https://DomainName/api/v1/self/loans/template?templateType=individual&client repaymentFrequencyType, interestRatePerPeriod, amortizationType, interestType, interestCalculationPeriodType, expectedDisbursementDate, - transactionProcessingStrategyId + transactionProcessingStrategyCode @@ -48219,7 +48219,7 @@ Request Body: "interestType": 0, "interestCalculationPeriodType": 1, "expectedDisbursementDate": "20 September 2011", - "transactionProcessingStrategyId": 2 + "transactionProcessingStrategyCode": "mifos-standard-strategy" } @@ -48343,7 +48343,7 @@ Request Body: loanTermFrequencyType, loanType, numberOfRepayments, repaymentEvery, repaymentFrequencyType, interestRatePerPeriod, amortizationType, interestType, - interestCalculationPeriodType, transactionProcessingStrategyId, + interestCalculationPeriodType, transactionProcessingStrategyCode, expectedDisbursementDate, submittedOnDate, loanType @@ -48400,7 +48400,7 @@ Request Body: "amortizationType": 1, "interestType": 0, "interestCalculationPeriodType": 1, - "transactionProcessingStrategyId": 1, + "transactionProcessingStrategyCode": "mifos-standard-strategy", "expectedDisbursementDate": "10 Jun 2013", "submittedOnDate": "10 Jun 2013", "linkAccountId" : "1", @@ -48553,7 +48553,7 @@ GET https://DomainName/api/v1/self/loans/{loanId} "code": "interestCalculationPeriodType.same.as.repayment.period", "value": "Same as repayment period" }, - "transactionProcessingStrategyId": 2, + "transactionProcessingStrategyCode": "mifos-standard-strategy", "timeline": { "submittedOnDate": [ 2012, @@ -48722,7 +48722,7 @@ No Request Body: "interestCalculationPeriodType": 0, "amortizationType": 1, "expectedDisbursementDate": "04 March 2014", - "transactionProcessingStrategyId": 1 + "transactionProcessingStrategyCode": "mifos-standard-strategy" } @@ -51635,7 +51635,7 @@ No Request Body: - transactionProcessingStrategyId + transactionProcessingStrategyCode @@ -51929,7 +51929,7 @@ GET https://DomainName/api/v1/self/loanproducts/{productId}?clientId={clientId} "code": "interestCalculationPeriodType.same.as.repayment.period", "value": "Same as repayment period" }, - "transactionProcessingStrategyId": 1, + "transactionProcessingStrategyCode": "mifos-standard-strategy", "transactionProcessingStrategyName": "Mifos style", "charges": [], "principalVariationsForBorrowerCycle": [ diff --git a/fineract-provider/src/test/resources/application-test.properties b/fineract-provider/src/test/resources/application-test.properties index b43d7260b..0247e9519 100644 --- a/fineract-provider/src/test/resources/application-test.properties +++ b/fineract-provider/src/test/resources/application-test.properties @@ -51,6 +51,15 @@ fineract.events.external.producer.jms.enabled=${FINERACT_EXTERNAL_EVENTS_PRODUCE fineract.events.external.producer.jms.event-queue-name=${FINERACT_EXTERNAL_EVENTS_PRODUCER_JMS_QUEUE_NAME:JMS-event-queue} fineract.events.external.producer.jms.broker-url=${FINERACT_EXTERNAL_EVENTS_PRODUCER_JMS_BROKER_URL:tcp://127.0.0.1:61616} +fineract.loan.transactionprocessor.creocore.enabled=true +fineract.loan.transactionprocessor.early-repayment.enabled=true +fineract.loan.transactionprocessor.mifos-standard.enabled=true +fineract.loan.transactionprocessor.heavensfamily.enabled=true +fineract.loan.transactionprocessor.interest-principal-penalties-fees.enabled=true +fineract.loan.transactionprocessor.principal-interest-penalties-fees.enabled=true +fineract.loan.transactionprocessor.rbi-india.enabled=true +fineract.loan.transactionprocessor.error-not-found-fail=true + management.health.jms.enabled=false diff --git a/instancemode-tests/build.gradle b/instancemode-tests/build.gradle index d7e977980..4660b829f 100644 --- a/instancemode-tests/build.gradle +++ b/instancemode-tests/build.gradle @@ -37,7 +37,7 @@ configurations { driver } dependencies { - driver 'mysql:mysql-connector-java:8.0.30' + driver 'mysql:mysql-connector-java:8.0.31' } cargo { diff --git a/integration-tests/build.gradle b/integration-tests/build.gradle index 8e737ae6a..e1969a2ca 100644 --- a/integration-tests/build.gradle +++ b/integration-tests/build.gradle @@ -37,7 +37,7 @@ configurations { driver } dependencies { - driver 'mysql:mysql-connector-java:8.0.30' + driver 'mysql:mysql-connector-java:8.0.31' } cargo { diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanIntegrationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanIntegrationTest.java index ac4913248..54276d6c0 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanIntegrationTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanIntegrationTest.java @@ -6299,7 +6299,7 @@ public class ClientLoanIntegrationTest { private void validateIfValuesAreNotOverridden(Integer loanID, Integer loanProductID) { String loanProductDetails = this.loanTransactionHelper.getLoanProductDetails(this.requestSpec, this.responseSpec, loanProductID); String loanDetails = this.loanTransactionHelper.getLoanDetails(this.requestSpec, this.responseSpec, loanID); - List comparisonAttributes = Arrays.asList("amortizationType", "interestType", "transactionProcessingStrategyId", + List comparisonAttributes = Arrays.asList("amortizationType", "interestType", "transactionProcessingStrategyCode", "interestCalculationPeriodType", "repaymentFrequencyType", "graceOnPrincipalPayment", "graceOnInterestPayment", "inArrearsTolerance", "graceOnArrearsAgeing"); @@ -6313,7 +6313,7 @@ public class ClientLoanIntegrationTest { private JsonObject createLoanProductConfigurationDetail(JsonObject loanProductConfiguration, Boolean bool) { loanProductConfiguration.addProperty("amortizationType", bool); loanProductConfiguration.addProperty("interestType", bool); - loanProductConfiguration.addProperty("transactionProcessingStrategyId", bool); + loanProductConfiguration.addProperty("transactionProcessingStrategyCode", bool); loanProductConfiguration.addProperty("interestCalculationPeriodType", bool); loanProductConfiguration.addProperty("inArrearsTolerance", bool); loanProductConfiguration.addProperty("repaymentEvery", bool); diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/BatchHelper.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/BatchHelper.java index a80158fd5..50f373570 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/BatchHelper.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/BatchHelper.java @@ -275,7 +275,8 @@ public final class BatchHelper { + "\"loanTermFrequencyType\": 2, \"loanType\": \"individual\", \"numberOfRepayments\": 10," + "\"repaymentEvery\": 1, \"repaymentFrequencyType\": 2, \"interestRatePerPeriod\": 10," + "\"amortizationType\": 1, \"interestType\": 0, \"interestCalculationPeriodType\": 1," - + "\"transactionProcessingStrategyId\": 1, \"expectedDisbursementDate\": \"" + dateString + "\","; + + "\"transactionProcessingStrategyCode\": \"mifos-standard-strategy\", \"expectedDisbursementDate\": \"" + dateString + + "\","; if (clientCollateralId != null) { body = body + "\"collateral\": [{\"clientCollateralId\": \"" + clientCollateralId + "\", \"quantity\": \"1\"}],"; @@ -313,7 +314,7 @@ public final class BatchHelper { + "\"loanTermFrequencyType\": 2, \"loanType\": \"individual\", \"numberOfRepayments\": 10," + "\"repaymentEvery\": 1, \"repaymentFrequencyType\": 2, \"interestRatePerPeriod\": 10," + "\"amortizationType\": 1, \"interestType\": 0, \"interestCalculationPeriodType\": 1," - + "\"transactionProcessingStrategyId\": 1, \"expectedDisbursementDate\": \"10 Jun 2013\"," + + "\"transactionProcessingStrategyCode\": \"mifos-standard-strategy\", \"expectedDisbursementDate\": \"10 Jun 2013\"," + "\"submittedOnDate\": \"10 Jun 2013\"}", clientId, productId); br.setBody(body); diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanApplicationTestBuilder.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanApplicationTestBuilder.java index 94ae8bf60..ab21bb1d5 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanApplicationTestBuilder.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanApplicationTestBuilder.java @@ -39,9 +39,9 @@ public class LoanApplicationTestBuilder { private static final String EQUAL_INSTALLMENTS = "1"; private static final String CALCULATION_PERIOD_SAME_AS_REPAYMENT_PERIOD = "1"; private static final String LOCALE = "en_GB"; - public static final String DEFAULT_STRATEGY = "1"; - public static final String RBI_INDIA_STRATEGY = "4"; - public static final String INTEREST_PRINCIPAL_PENALTIES_FEES_ORDER_STRATEGY = "6"; + public static final String DEFAULT_STRATEGY = "mifos-standard-strategy"; + public static final String RBI_INDIA_STRATEGY = "rbi-india-strategy"; + public static final String INTEREST_PRINCIPAL_PENALTIES_FEES_ORDER_STRATEGY = "interest-principal-penalties-fees-order-strategy"; private String externalId = null; private String principal = "10,000"; @@ -56,7 +56,7 @@ public class LoanApplicationTestBuilder { private String interestType = FLAT_BALANCE; private String amortizationType = EQUAL_PRINCIPAL_PAYMENTS; private String interestCalculationPeriodType = CALCULATION_PERIOD_SAME_AS_REPAYMENT_PERIOD; - private String transactionProcessingID = DEFAULT_STRATEGY; + private String transactionProcessingCode = DEFAULT_STRATEGY; private String expectedDisbursmentDate = ""; private String submittedOnDate = ""; private String loanType = "individual"; @@ -147,7 +147,7 @@ public class LoanApplicationTestBuilder { map.put("fixedPrincipalPercentagePerInstallment", fixedPrincipalPercentagePerInstallment); map.put("interestType", this.interestType); map.put("interestCalculationPeriodType", this.interestCalculationPeriodType); - map.put("transactionProcessingStrategyId", this.transactionProcessingID); + map.put("transactionProcessingStrategyCode", this.transactionProcessingCode); map.put("expectedDisbursementDate", this.expectedDisbursmentDate); map.put("submittedOnDate", this.submittedOnDate); map.put("loanType", this.loanType); @@ -335,8 +335,8 @@ public class LoanApplicationTestBuilder { return this; } - public LoanApplicationTestBuilder withRepaymentStrategy(final String transactionProcessingStrategy) { - this.transactionProcessingID = transactionProcessingStrategy; + public LoanApplicationTestBuilder withRepaymentStrategy(final String transactionProcessingStrategyCode) { + this.transactionProcessingCode = transactionProcessingStrategyCode; return this; } diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanProductTestBuilder.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanProductTestBuilder.java index 39ec5f627..d7251c427 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanProductTestBuilder.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanProductTestBuilder.java @@ -40,11 +40,11 @@ public class LoanProductTestBuilder { private static final String EQUAL_INSTALLMENTS = "1"; private static final String DECLINING_BALANCE = "0"; private static final String FLAT_BALANCE = "1"; - public static final String DEFAULT_STRATEGY = "1"; - public static final String INTEREST_PRINCIPAL_PENALTIES_FEES_ORDER_STRATEGY = "6"; - // private static final String HEAVENS_FAMILY_STRATEGY ="2"; - // private static final String CREO_CORE_STRATEGY ="3"; - public static final String RBI_INDIA_STRATEGY = "4"; + public static final String DEFAULT_STRATEGY = "mifos-standard-strategy"; + public static final String INTEREST_PRINCIPAL_PENALTIES_FEES_ORDER_STRATEGY = "interest-principal-penalties-fees-order-strategy"; + // private static final String HEAVENS_FAMILY_STRATEGY ="heavensfamily-strategy"; + // private static final String CREO_CORE_STRATEGY ="creocore-strategy"; + public static final String RBI_INDIA_STRATEGY = "rbi-india-strategy"; public static final String RECALCULATION_FREQUENCY_TYPE_SAME_AS_REPAYMENT_PERIOD = "1"; public static final String RECALCULATION_FREQUENCY_TYPE_DAILY = "2"; @@ -83,7 +83,7 @@ public class LoanProductTestBuilder { private String overdueDaysForNPA = "5"; private String interestCalculationPeriodType = CALCULATION_PERIOD_SAME_AS_REPAYMENT_PERIOD; private String inArrearsTolerance = "0"; - private String transactionProcessingStrategy = DEFAULT_STRATEGY; + private String transactionProcessingStrategyCode = DEFAULT_STRATEGY; private String accountingRule = NONE; private final String currencyCode = USD; private String amortizationType = EQUAL_INSTALLMENTS; @@ -166,7 +166,7 @@ public class LoanProductTestBuilder { map.put("interestType", this.interestType); map.put("interestCalculationPeriodType", this.interestCalculationPeriodType); map.put("inArrearsTolerance", this.inArrearsTolerance); - map.put("transactionProcessingStrategyId", this.transactionProcessingStrategy); + map.put("transactionProcessingStrategyCode", this.transactionProcessingStrategyCode); map.put("accountingRule", this.accountingRule); map.put("minPrincipal", this.minPrincipal); map.put("maxPrincipal", this.maxPrincipal); @@ -488,7 +488,7 @@ public class LoanProductTestBuilder { } public LoanProductTestBuilder withRepaymentStrategy(final String transactionProcessingStrategy) { - this.transactionProcessingStrategy = transactionProcessingStrategy; + this.transactionProcessingStrategyCode = transactionProcessingStrategy; return this; } diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanTransactionHelper.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanTransactionHelper.java index 15bc47d88..df68df1c1 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanTransactionHelper.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanTransactionHelper.java @@ -22,8 +22,8 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; +import com.google.common.reflect.TypeToken; import com.google.gson.Gson; -import com.linecorp.armeria.internal.shaded.guava.reflect.TypeToken; import io.restassured.specification.RequestSpecification; import io.restassured.specification.ResponseSpecification; import java.io.ByteArrayInputStream; @@ -850,7 +850,7 @@ public class LoanTransactionHelper { map.put("interestType", "0"); map.put("interestCalculationPeriodType", "1"); map.put("expectedDisbursementDate", "20 September 2011"); - map.put("transactionProcessingStrategyId", "1"); + map.put("transactionProcessingStrategyCode", "mifos-standard-strategy"); return new Gson().toJson(map); } diff --git a/oauth2-tests/build.gradle b/oauth2-tests/build.gradle index 678975a46..91a1027d1 100644 --- a/oauth2-tests/build.gradle +++ b/oauth2-tests/build.gradle @@ -37,7 +37,7 @@ configurations { driver } dependencies { - driver 'mysql:mysql-connector-java:8.0.30' + driver 'mysql:mysql-connector-java:8.0.31' } cargo { diff --git a/twofactor-tests/build.gradle b/twofactor-tests/build.gradle index 22ee0e3b2..74daf9e0e 100644 --- a/twofactor-tests/build.gradle +++ b/twofactor-tests/build.gradle @@ -37,7 +37,7 @@ configurations { driver } dependencies { - driver 'mysql:mysql-connector-java:8.0.30' + driver 'mysql:mysql-connector-java:8.0.31' } cargo {