Skip to content

Commit

Permalink
Merge pull request #24 from FITER1/MON-94
Browse files Browse the repository at this point in the history
MON-94 validate deposit period against frequency
  • Loading branch information
Napho authored Nov 16, 2022
2 parents cbc0913 + 93eb945 commit d9611ce
Show file tree
Hide file tree
Showing 12 changed files with 256 additions and 7 deletions.
1 change: 1 addition & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ FROM azul/zulu-openjdk:17 as fineract
#pentaho copy
COPY --from=builder /fineract/fineract-provider/pentahoReports/*.properties /root/.mifosx/pentahoReports/
COPY --from=builder /fineract/fineract-provider/pentahoReports/*.prpt /root/.mifosx/pentahoReports/
COPY --from=builder /fineract/fineract-provider/ff4j/*.yml /root/.fineract/ff4j/

COPY --from=builder /fineract/fineract-provider/build/libs/ /app
COPY --from=builder /app/libs /app/libs
Expand Down
11 changes: 10 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,13 @@ copy {
into pentahoReportDir
}

def ff4jConfigDir = System.properties['user.home'] + System.properties['file.separator'] + '.fineract' + System.properties['file.separator'] + 'ff4j'
copy {
from "fineract-provider/ff4j"
into ff4jConfigDir
}


allprojects {
group = 'org.apache.fineract'

Expand Down Expand Up @@ -179,6 +186,7 @@ allprojects {
"**/banner.txt",
"**/build.gradle.mustache",
"**/pom.mustache",
"**/io/fiter/ff4j/**",
])
strictCheck true
}
Expand Down Expand Up @@ -276,7 +284,8 @@ allprojects {
'**/*.prpt',
'**/*.properties',
'**/*.PROPERTIES',
'**/images/diag-*.svg'
'**/images/diag-*.svg',
'**/io/fiter/**',
]
}
}
Expand Down
1 change: 1 addition & 0 deletions fineract-provider/dependencies.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ dependencies {
include '*.jar' },
'org.openjdk.nashorn:nashorn-core',
'org.mapstruct:mapstruct',
'org.ff4j:ff4j-config-yaml:1.8.13'
)

implementation ('org.apache.commons:commons-email') {
Expand Down
44 changes: 44 additions & 0 deletions fineract-provider/ff4j/ff4j-feature-moniafrica.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#
# 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.
#

ff4j:
autocreate: false
audit: false
features:
- uid: savings.rd.minimumduration_mon94
enable: true
description: >-
When frequency is set as daily, minimum duration is 1 month. When set as
weekly, monthly, bi-weekly minimum is 3 months.
custom-properties:
- name: daily
type: org.ff4j.property.PropertyInt
value: 1
- name: weekly
type: org.ff4j.property.PropertyInt
value: 3
- name: bi-weekly
type: org.ff4j.property.PropertyInt
value: 3
- name: monthly
type: org.ff4j.property.PropertyInt
value: 3
- name: other
type: org.ff4j.property.PropertyInt
value: 3
44 changes: 44 additions & 0 deletions fineract-provider/ff4j/ff4j-feature-template.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#
# 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.
#

ff4j:
autocreate: false
audit: false
features:
- uid: savings.rd.minimumduration_mon94
enable: false
description: >-
When frequency is set as daily, minimum duration is 1 month. When set as
weekly, monthly, bi-weekly minimum is 3 months.
custom-properties:
- name: daily
type: org.ff4j.property.PropertyInt
value: 1
- name: weekly
type: org.ff4j.property.PropertyInt
value: 3
- name: bi-weekly
type: org.ff4j.property.PropertyInt
value: 3
- name: monthly
type: org.ff4j.property.PropertyInt
value: 3
- name: other
type: org.ff4j.property.PropertyInt
value: 3
61 changes: 61 additions & 0 deletions fineract-provider/src/main/java/io/fiter/ff4j/FF4JConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package io.fiter.ff4j;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import lombok.SneakyThrows;
import org.apache.fineract.infrastructure.documentmanagement.contentrepository.FileSystemContentRepository;
import org.ff4j.FF4j;
import org.ff4j.audit.repository.EventRepository;
import org.ff4j.audit.repository.InMemoryEventRepository;
import org.ff4j.conf.FF4jConfiguration;
import org.ff4j.core.FeatureStore;
import org.ff4j.parser.yaml.YamlParser;
import org.ff4j.property.store.InMemoryPropertyStore;
import org.ff4j.property.store.PropertyStore;
import org.ff4j.store.InMemoryFeatureStore;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class FF4JConfig {

@Value("${fiter.features.ff4j}")
private String ff4jFileName;

@SneakyThrows
@Bean
public FF4j getFF4j() {

final String templateRepository = FileSystemContentRepository.FINERACT_BASE_DIR + File.separator + "ff4j" + File.separator
+ this.ff4jFileName;
final File configFile = new File(templateRepository);
InputStream targetStream = null;
try {
targetStream = new FileInputStream(configFile);
} catch (IOException ex) {
throw ex;
}
// We imported ff4j-config-yaml to have this
FF4jConfiguration initConfig = new YamlParser().parseConfigurationFile(targetStream);
// LOGGER.info("Default features have been loaded {}", initConfig.getFeatures().keySet());

// 1. Define the store you want for Feature, Properties, Audit among 20 tech
FeatureStore featureStore = new InMemoryFeatureStore(initConfig);
PropertyStore propertyStore = new InMemoryPropertyStore(initConfig);
EventRepository logsAudit = new InMemoryEventRepository();

// 2. Build FF4j
FF4j ff4jBean = new FF4j();
ff4jBean.setPropertiesStore(propertyStore);
ff4jBean.setFeatureStore(featureStore);
ff4jBean.setEventRepository(logsAudit);

// 3. Complete setup
ff4jBean.setEnableAudit(false);
ff4jBean.setAutocreate(true);
return ff4jBean;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package io.fiter.ff4j.validators;

public class FeatureList {

private FeatureList() {}

protected static final String MINIMUM_RD_PERIOD = "savings.rd.minimumduration_mon94";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package io.fiter.ff4j.validators;

import static org.apache.fineract.portfolio.savings.DepositsApiConstants.depositPeriodFrequencyIdParamName;
import static org.apache.fineract.portfolio.savings.DepositsApiConstants.depositPeriodParamName;
import static org.apache.fineract.portfolio.savings.DepositsApiConstants.minDepositTermParamName;
import static org.apache.fineract.portfolio.savings.DepositsApiConstants.minDepositTermTypeIdParamName;

import com.google.gson.JsonElement;
import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
import org.apache.fineract.portfolio.savings.DepositAccountType;
import org.apache.fineract.portfolio.savings.SavingsPeriodFrequencyType;
import org.ff4j.FF4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class SavingsAccountFeatureValidator {

private final FF4j ff4j;
private final FromJsonHelper fromApiJsonHelper;

@Autowired
public SavingsAccountFeatureValidator(FF4j ff4j, FromJsonHelper fromApiJsonHelper) {
this.ff4j = ff4j;
this.fromApiJsonHelper = fromApiJsonHelper;
}

public void validateDepositDetailsForUpdate(final JsonElement element, final DataValidatorBuilder baseDataValidator,
DepositAccountType depositAccountType) {

if (ff4j.check(FeatureList.MINIMUM_RD_PERIOD) && depositAccountType.equals(DepositAccountType.RECURRING_DEPOSIT)) {

Integer minDepositTermType = null;

if (fromApiJsonHelper.parameterExists(minDepositTermTypeIdParamName, element)) {
minDepositTermType = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(minDepositTermTypeIdParamName, element);
}

Integer minTerm = null;
if (fromApiJsonHelper.parameterExists(minDepositTermParamName, element)) {
minTerm = fromApiJsonHelper.extractIntegerSansLocaleNamed(minDepositTermParamName, element);
}

if (fromApiJsonHelper.parameterExists(depositPeriodParamName, element)) {
minTerm = fromApiJsonHelper.extractIntegerSansLocaleNamed(depositPeriodParamName, element);

}

if (fromApiJsonHelper.parameterExists(depositPeriodFrequencyIdParamName, element)) {
minDepositTermType = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(depositPeriodFrequencyIdParamName, element);
}

if (minDepositTermType != null && minTerm != null) {

Integer minDurationAllowed = 0;
if (minDepositTermType.equals(SavingsPeriodFrequencyType.DAYS.getValue())) {
minDurationAllowed = ff4j.getFeature(FeatureList.MINIMUM_RD_PERIOD).getCustomProperties().get("daily").asInt();
} else {
minDurationAllowed = ff4j.getFeature(FeatureList.MINIMUM_RD_PERIOD).getCustomProperties().get("other").asInt();
}

if (minDurationAllowed > minTerm) {
baseDataValidator.reset().parameter(minDepositTermTypeIdParamName).failWithCodeNoParameterAddedToErrorCode(
"period.not.allowed", "Period less than minimum allowed for term type");
}
}

}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
@EnableTransactionManagement
@EnableWebSecurity
@EnableConfigurationProperties({ FineractProperties.class, LiquibaseProperties.class })
@ComponentScan(basePackages = "org.apache.fineract.**")
@ComponentScan(basePackages = { "org.apache.fineract.**", "io.fiter.**" })
public abstract class AbstractApplicationConfiguration {

}
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,11 @@ public enum ChargeTimeType {
// loan
SHAREACCOUNT_ACTIVATION(13, "chargeTimeType.activation"), // only for loan
SHARE_PURCHASE(14, "chargeTimeType.sharespurchase"), SHARE_REDEEM(15, "chargeTimeType.sharesredeem"),

SAVINGS_NOACTIVITY_FEE(16, "chargeTimeType.savingsNoActivityFee"), DISBURSE_TO_SAVINGS(17,
"chargeTimeType.disburseToSavings"), FDA_PRE_CLOSURE_FEE(18,
"chargeTimeType.fdaPreclosureFee"), FDA_PARTIAL_LIQUIDATION_FEE(19, "chargeTimeType.fdaPartialLiquidationFee");


private final Integer value;
private final String code;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.reflect.TypeToken;
import io.fiter.ff4j.validators.SavingsAccountFeatureValidator;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.time.LocalDate;
Expand Down Expand Up @@ -99,11 +100,18 @@ public class DepositAccountDataValidator {

private final FromJsonHelper fromApiJsonHelper;
private final DepositProductDataValidator productDataValidator;
/**
*
* This is a fiter only feature, it should not be committed in the event that it this is merged upstream
*/
private final SavingsAccountFeatureValidator featureValidator;

@Autowired
public DepositAccountDataValidator(final FromJsonHelper fromApiJsonHelper, final DepositProductDataValidator productDataValidator) {
public DepositAccountDataValidator(final FromJsonHelper fromApiJsonHelper, final DepositProductDataValidator productDataValidator,
final SavingsAccountFeatureValidator featureValidator) {
this.fromApiJsonHelper = fromApiJsonHelper;
this.productDataValidator = productDataValidator;
this.featureValidator = featureValidator;
}

public void validateFixedDepositForSubmit(final String json) {
Expand Down Expand Up @@ -172,7 +180,7 @@ public void validateRecurringDepositForSubmit(final String json) {
validateRecurringDetailForSubmit(element, baseDataValidator);
validateSavingsCharges(element, baseDataValidator);
validateWithHoldTax(element, baseDataValidator);

featureValidator.validateDepositDetailsForUpdate(element, baseDataValidator, DepositAccountType.RECURRING_DEPOSIT);
throwExceptionIfValidationWarningsExist(dataValidationErrors);
}

Expand All @@ -196,7 +204,7 @@ public void validateRecurringDepositForUpdate(final String json) {
validateRecurringDetailForUpdate(element, baseDataValidator);
// validateSavingsCharges(element, baseDataValidator);
validateWithHoldTax(element, baseDataValidator);

featureValidator.validateDepositDetailsForUpdate(element, baseDataValidator, DepositAccountType.RECURRING_DEPOSIT);
throwExceptionIfValidationWarningsExist(dataValidationErrors);

}
Expand Down
2 changes: 2 additions & 0 deletions fineract-provider/src/main/resources/application.properties
Original file line number Diff line number Diff line change
Expand Up @@ -136,3 +136,5 @@ springdoc.show-actuator=${SPRINGDOC_SHOW_ACTUATOR:false}
spring.web.resources.static-locations=classpath:/static/

spring.main.allow-bean-definition-overriding=true

fiter.features.ff4j=${FF4J_FILE_NAME:ff4j-feature-template.yml}

0 comments on commit d9611ce

Please sign in to comment.