From d7876df11a6c3e6e0f36c273dfe4b14814600490 Mon Sep 17 00:00:00 2001 From: fiter-julius-oketayot <140818859+fiter-julius-oketayot@users.noreply.github.com> Date: Wed, 18 Oct 2023 18:38:38 +0300 Subject: [PATCH] Feature/FBR-335: Buro check integration (#224) Co-authored-by: Julius Peter Oketayot --- .../service/ExternalServicesConstants.java | 1 + ...icesPropertiesReadPlatformServiceImpl.java | 4 + .../infrastructure/core/config/JPAConfig.java | 2 + .../domain/BuroCheckClassification.java | 59 +++++++++++++ .../exception/DpiBuroChequeException.java | 31 +++++++ ...eauValidationWritePlatformServiceImpl.java | 83 +++++++++++++++++-- ...equalificationReadPlatformServiceImpl.java | 7 +- ...rt_buro_check_external_service_configs.sql | 53 ++++++++++++ .../0085_FBR_306_add_check_migrations.xml | 9 ++ 9 files changed, 237 insertions(+), 12 deletions(-) create mode 100644 fineract-provider/src/main/java/org/apache/fineract/organisation/prequalification/domain/BuroCheckClassification.java create mode 100644 fineract-provider/src/main/java/org/apache/fineract/organisation/prequalification/exception/DpiBuroChequeException.java create mode 100644 fineract-provider/src/main/resources/db/changelog/tenant/commands/insert_buro_check_external_service_configs.sql diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/service/ExternalServicesConstants.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/service/ExternalServicesConstants.java index 20666cd08e9..8bfec796c59 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/service/ExternalServicesConstants.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/service/ExternalServicesConstants.java @@ -49,6 +49,7 @@ private ExternalServicesConstants() { public static final String NOTIFICATION_SERVICE_NAME = "NOTIFICATION"; public static final String GUARANTEE_SERVICE_NAME = "GUARANTEE"; + public static final String DPI_BURO_CHECK_SERVICE_NAME = "DPI_BURO_CHECK"; public static final String NOTIFICATION_SERVER_KEY = "server_key"; public static final String NOTIFICATION_GCM_END_POINT = "gcm_end_point"; public static final String NOTIFICATION_FCM_END_POINT = "fcm_end_point"; diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/service/ExternalServicesPropertiesReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/service/ExternalServicesPropertiesReadPlatformServiceImpl.java index 07857524969..608922801bb 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/service/ExternalServicesPropertiesReadPlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/service/ExternalServicesPropertiesReadPlatformServiceImpl.java @@ -193,6 +193,10 @@ public Collection retrieveOne(String serviceName serviceNameToUse = ExternalServicesConstants.GUARANTEE_SERVICE_NAME; break; + case "DPI_BURO_CHECK": + serviceNameToUse = ExternalServicesConstants.DPI_BURO_CHECK_SERVICE_NAME; + break; + default: throw new ExternalServiceConfigurationNotFoundException(serviceName); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/JPAConfig.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/JPAConfig.java index 9af44b9d5cc..ebcf948c726 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/JPAConfig.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/JPAConfig.java @@ -28,6 +28,7 @@ import org.apache.fineract.infrastructure.core.service.database.DatabaseTypeResolver; import org.eclipse.persistence.config.PersistenceUnitProperties; import org.springframework.beans.factory.ObjectProvider; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.orm.jpa.EntityManagerFactoryBuilderCustomizer; import org.springframework.boot.autoconfigure.orm.jpa.JpaBaseConfiguration; import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties; @@ -52,6 +53,7 @@ import org.springframework.transaction.support.TransactionTemplate; @Configuration +@ConditionalOnMissingBean(name = { "jpaAuditingHandler" }) @EnableJpaAuditing @EnableJpaRepositories(basePackages = "org.apache.fineract.**.domain") @EnableConfigurationProperties(JpaProperties.class) diff --git a/fineract-provider/src/main/java/org/apache/fineract/organisation/prequalification/domain/BuroCheckClassification.java b/fineract-provider/src/main/java/org/apache/fineract/organisation/prequalification/domain/BuroCheckClassification.java new file mode 100644 index 00000000000..a3288dd7014 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/organisation/prequalification/domain/BuroCheckClassification.java @@ -0,0 +1,59 @@ +/** + * 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.organisation.prequalification.domain; + +import java.util.Arrays; +import java.util.Objects; +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.apache.fineract.infrastructure.core.data.EnumOptionData; + +@AllArgsConstructor +@Getter +public enum BuroCheckClassification { + + CLASSIFICATION_X(0, "Sin Categoria", "buro.check.classification.grey"), CLASSIFICATION_A(1, "A", + "buro.check.classification.green"), CLASSIFICATION_B(2, "B", "buro.check.classification.yellow"), CLASSIFICATION_C(3, "C", + "buro.check.classification.orange"), CLASSIFICATION_D(4, "D", "buro.check.classification.red"); + + private final Integer id; + private final String letter; + private final String color; + + public static BuroCheckClassification fromInt(final Integer id) { + return Arrays.stream(values()).filter(classification -> Objects.equals(classification.id, id)).findFirst() + .orElse(BuroCheckClassification.CLASSIFICATION_X); + } + + public static BuroCheckClassification fromLetter(final String letter) { + return Arrays.stream(values()).filter(classification -> Objects.equals(classification.letter, letter)).findFirst() + .orElse(BuroCheckClassification.CLASSIFICATION_X); + } + + public static BuroCheckClassification fromColor(final String color) { + return Arrays.stream(values()).filter(classification -> Objects.equals(classification.color, color)).findFirst() + .orElse(BuroCheckClassification.CLASSIFICATION_X); + } + + public static EnumOptionData status(final Integer statusInt) { + BuroCheckClassification buroCheckClassification = BuroCheckClassification.fromInt(statusInt); + return new EnumOptionData(buroCheckClassification.id.longValue(), buroCheckClassification.letter, buroCheckClassification.color); + } + +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/organisation/prequalification/exception/DpiBuroChequeException.java b/fineract-provider/src/main/java/org/apache/fineract/organisation/prequalification/exception/DpiBuroChequeException.java new file mode 100644 index 00000000000..410a697e690 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/organisation/prequalification/exception/DpiBuroChequeException.java @@ -0,0 +1,31 @@ +/** + * 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.organisation.prequalification.exception; + +import org.apache.fineract.infrastructure.core.exception.AbstractPlatformResourceNotFoundException; + +/** + * A {@link RuntimeException} thrown when client is already blacklisted. + */ +public class DpiBuroChequeException extends AbstractPlatformResourceNotFoundException { + + public DpiBuroChequeException(final String dpi) { + super("error.msg.group.prequalification.dpi.not.found", "DPI with " + dpi + " buro check not found!"); + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/organisation/prequalification/service/BureauValidationWritePlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/organisation/prequalification/service/BureauValidationWritePlatformServiceImpl.java index 0e4d18be72c..4bde877d623 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/organisation/prequalification/service/BureauValidationWritePlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/organisation/prequalification/service/BureauValidationWritePlatformServiceImpl.java @@ -18,25 +18,44 @@ */ package org.apache.fineract.organisation.prequalification.service; +import com.google.gson.JsonElement; +import java.nio.charset.Charset; +import java.util.Collection; import java.util.List; +import org.apache.commons.codec.binary.Base64; +import org.apache.fineract.infrastructure.configuration.data.ExternalServicesPropertiesData; +import org.apache.fineract.infrastructure.configuration.service.ExternalServicesConstants; +import org.apache.fineract.infrastructure.configuration.service.ExternalServicesPropertiesReadPlatformService; import org.apache.fineract.infrastructure.core.api.JsonCommand; import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder; +import org.apache.fineract.infrastructure.core.data.EnumOptionData; +import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException; +import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper; import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; +import org.apache.fineract.organisation.prequalification.domain.BuroCheckClassification; import org.apache.fineract.organisation.prequalification.domain.PreQualificationMemberRepository; import org.apache.fineract.organisation.prequalification.domain.PreQualificationStatusLogRepository; import org.apache.fineract.organisation.prequalification.domain.PrequalificationGroup; import org.apache.fineract.organisation.prequalification.domain.PrequalificationGroupMember; import org.apache.fineract.organisation.prequalification.domain.PrequalificationGroupRepositoryWrapper; -import org.apache.fineract.organisation.prequalification.domain.PrequalificationMemberIndication; import org.apache.fineract.organisation.prequalification.domain.PrequalificationStatus; import org.apache.fineract.organisation.prequalification.domain.PrequalificationStatusLog; import org.apache.fineract.organisation.prequalification.domain.ValidationChecklistResultRepository; +import org.apache.fineract.organisation.prequalification.exception.DpiBuroChequeException; import org.apache.fineract.useradministration.domain.AppUser; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Service; +import org.springframework.web.client.ResourceAccessException; +import org.springframework.web.client.RestTemplate; @Service public class BureauValidationWritePlatformServiceImpl implements BureauValidationWritePlatformService { @@ -49,13 +68,17 @@ public class BureauValidationWritePlatformServiceImpl implements BureauValidatio private final ValidationChecklistResultRepository validationChecklistResultRepository; private final PlatformSecurityContext platformSecurityContext; private final JdbcTemplate jdbcTemplate; + private final RestTemplate restTemplate = new RestTemplate(); + private final ExternalServicesPropertiesReadPlatformService externalServicePropertiesReadPlatformService; + private final FromJsonHelper fromApiJsonHelper; public BureauValidationWritePlatformServiceImpl(PlatformSecurityContext context, final PreQualificationMemberRepository preQualificationMemberRepository, PrequalificationGroupRepositoryWrapper prequalificationGroupRepositoryWrapper, final PreQualificationStatusLogRepository preQualificationStatusLogRepository, ValidationChecklistResultRepository validationChecklistResultRepository, PlatformSecurityContext platformSecurityContext, - JdbcTemplate jdbcTemplate) { + JdbcTemplate jdbcTemplate, ExternalServicesPropertiesReadPlatformService externalServicePropertiesReadPlatformService, + FromJsonHelper fromApiJsonHelper) { this.context = context; this.prequalificationGroupRepositoryWrapper = prequalificationGroupRepositoryWrapper; this.validationChecklistResultRepository = validationChecklistResultRepository; @@ -63,24 +86,26 @@ public BureauValidationWritePlatformServiceImpl(PlatformSecurityContext context, this.preQualificationMemberRepository = preQualificationMemberRepository; this.preQualificationStatusLogRepository = preQualificationStatusLogRepository; this.jdbcTemplate = jdbcTemplate; + this.externalServicePropertiesReadPlatformService = externalServicePropertiesReadPlatformService; + this.fromApiJsonHelper = fromApiJsonHelper; } @Override public CommandProcessingResult validatePrequalificationWithBureau(Long prequalificationId, JsonCommand command) { - PrequalificationGroup prequalificationGroup = this.prequalificationGroupRepositoryWrapper .findOneWithNotFoundDetection(prequalificationId); Integer fromStatus = prequalificationGroup.getStatus(); AppUser addedBy = this.context.getAuthenticatedUserIfPresent(); - // TODO --PROCESS THE PREQUALIFICATION GROUP WITH THE BUREAU AND UPDATE MEMBERS WITH THE RESULTS List members = this.preQualificationMemberRepository .findAllByPrequalificationGroup(prequalificationGroup); for (PrequalificationGroupMember member : members) { - // TODO --PROCESS THE MEMBER WITH THE BUREAU AND UPDATE THE RESULTS - // TODO --UPDATE THE MEMBER WITH THE RESULTS - member.updateBuroCheckStatus(PrequalificationMemberIndication.BUREAU_AVAILABLE.getValue()); + EnumOptionData enumOptionData = this.makeBureauCheckApiCall(member.getDpi()); + if (enumOptionData == null) { + throw new DpiBuroChequeException(member.getDpi()); + } + member.updateBuroCheckStatus(enumOptionData.getId().intValue()); this.preQualificationMemberRepository.save(member); } prequalificationGroup.updateStatus(PrequalificationStatus.BURO_CHECKED); @@ -97,4 +122,48 @@ public CommandProcessingResult validatePrequalificationWithBureau(Long prequalif .withEntityId(prequalificationGroup.getId()) // .build(); } + + private EnumOptionData makeBureauCheckApiCall(final String dpi) { + EnumOptionData enumOptionData = null; + final Collection externalServicesPropertiesDatas = this.externalServicePropertiesReadPlatformService + .retrieveOne(ExternalServicesConstants.DPI_BURO_CHECK_SERVICE_NAME); + String dpiBuroCheckApiUsername = null; + String dpiBuroCheckApiPassword = null; + String dpiBuroCheckApiHost = null; + for (final ExternalServicesPropertiesData externalServicesPropertiesData : externalServicesPropertiesDatas) { + if ("dpiBuroCheckApiUsername".equalsIgnoreCase(externalServicesPropertiesData.getName())) { + dpiBuroCheckApiUsername = externalServicesPropertiesData.getValue(); + } else if ("dpiBuroCheckApiPassword".equalsIgnoreCase(externalServicesPropertiesData.getName())) { + dpiBuroCheckApiPassword = externalServicesPropertiesData.getValue(); + } else if ("dpiBuroCheckApiHost".equalsIgnoreCase(externalServicesPropertiesData.getName())) { + dpiBuroCheckApiHost = externalServicesPropertiesData.getValue(); + } + } + final String credentials = dpiBuroCheckApiUsername + ":" + dpiBuroCheckApiPassword; + final String basicAuth = new String(Base64.encodeBase64(credentials.getBytes(Charset.defaultCharset())), Charset.defaultCharset()); + final HttpHeaders httpHeaders = new HttpHeaders(); + httpHeaders.setContentType(MediaType.APPLICATION_JSON); + httpHeaders.setAccept(List.of(MediaType.ALL)); + httpHeaders.add("Authorization", "Basic " + basicAuth); + final String url = dpiBuroCheckApiHost + "?DPI=" + dpi; + ResponseEntity responseEntity = null; + try { + responseEntity = restTemplate.exchange(url, HttpMethod.POST, new HttpEntity<>(httpHeaders), String.class); + } catch (ResourceAccessException ex) { + LOG.debug("DPI Buro Check Provider {} not available", url, ex); + } + + if (responseEntity == null || !responseEntity.getStatusCode().equals(HttpStatus.OK)) { + throw new PlatformDataIntegrityException("error.msg.mobile.service.provider.not.available", "DPI Buro Check Provider."); + } + if (responseEntity.hasBody()) { + final JsonElement jsonElement = this.fromApiJsonHelper.parse(responseEntity.getBody()); + if (jsonElement.isJsonObject()) { + final String classificationLetter = this.fromApiJsonHelper.extractStringNamed("Clasificacion", jsonElement); + enumOptionData = BuroCheckClassification.status(BuroCheckClassification.fromLetter(classificationLetter).getId()); + } + } + + return enumOptionData; + } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/organisation/prequalification/service/PrequalificationReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/organisation/prequalification/service/PrequalificationReadPlatformServiceImpl.java index 58901019bee..67406d55e43 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/organisation/prequalification/service/PrequalificationReadPlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/organisation/prequalification/service/PrequalificationReadPlatformServiceImpl.java @@ -40,6 +40,7 @@ import org.apache.fineract.organisation.prequalification.command.PrequalificationDataValidator; import org.apache.fineract.organisation.prequalification.data.GroupPrequalificationData; import org.apache.fineract.organisation.prequalification.data.MemberPrequalificationData; +import org.apache.fineract.organisation.prequalification.domain.BuroCheckClassification; import org.apache.fineract.organisation.prequalification.domain.PreQualificationMemberRepository; import org.apache.fineract.organisation.prequalification.domain.PreQualificationsEnumerations; import org.apache.fineract.organisation.prequalification.domain.PreQualificationsMemberEnumerations; @@ -552,12 +553,8 @@ public MemberPrequalificationData mapRow(final ResultSet rs, final int rowNum) t final Integer statusEnum = JdbcSupport.getInteger(rs, "status"); final EnumOptionData status = PreQualificationsMemberEnumerations.status(statusEnum); - EnumOptionData bureauCheckStatus = null; final Integer bureauStatus = rs.getInt("buroCheckStatus"); - if (bureauStatus != null) { - bureauCheckStatus = PreQualificationsMemberEnumerations.status(bureauStatus.intValue()); - } - + EnumOptionData bureauCheckStatus = BuroCheckClassification.status(BuroCheckClassification.fromInt(bureauStatus).getId()); final Long id = JdbcSupport.getLong(rs, "id"); final String name = rs.getString("name"); ; diff --git a/fineract-provider/src/main/resources/db/changelog/tenant/commands/insert_buro_check_external_service_configs.sql b/fineract-provider/src/main/resources/db/changelog/tenant/commands/insert_buro_check_external_service_configs.sql new file mode 100644 index 00000000000..ec3fb584b65 --- /dev/null +++ b/fineract-provider/src/main/resources/db/changelog/tenant/commands/insert_buro_check_external_service_configs.sql @@ -0,0 +1,53 @@ +-- +-- 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. +-- + +-- liquibase formatted sql +-- changeset fineract:1 +-- MySQL dump 10.13 Distrib 5.1.60, for Win32 (ia32) +-- +-- Host: localhost Database: fineract_default +-- ------------------------------------------------------ +-- Server version 5.1.60-community + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES UTF8MB4 */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; + +INSERT INTO c_external_service (name) +VALUES('DPI_BURO_CHECK'); + +INSERT INTO c_external_service_properties +(name, value, external_service_id) +VALUES('dpiBuroCheckApiHost', '###############', (SELECT id FROM c_external_service WHERE name='DPI_BURO_CHECK')); + +INSERT INTO c_external_service_properties +(name, value, external_service_id) +VALUES('dpiBuroCheckApiUsername', '###############', (SELECT id FROM c_external_service WHERE name='DPI_BURO_CHECK')); + + +INSERT INTO c_external_service_properties +(name, value, external_service_id) +VALUES('dpiBuroCheckApiPassword', '###############', (SELECT id FROM c_external_service WHERE name='DPI_BURO_CHECK')); diff --git a/fineract-provider/src/main/resources/db/changelog/tenant/parts/0085_FBR_306_add_check_migrations.xml b/fineract-provider/src/main/resources/db/changelog/tenant/parts/0085_FBR_306_add_check_migrations.xml index 16f4a07f54a..e01026481e9 100644 --- a/fineract-provider/src/main/resources/db/changelog/tenant/parts/0085_FBR_306_add_check_migrations.xml +++ b/fineract-provider/src/main/resources/db/changelog/tenant/parts/0085_FBR_306_add_check_migrations.xml @@ -571,4 +571,13 @@ + + + +