Skip to content

Commit

Permalink
Feature/FBR-335: Buro check integration (#224)
Browse files Browse the repository at this point in the history
Co-authored-by: Julius Peter Oketayot <[email protected]>
  • Loading branch information
fiter-julius-oketayot and Julius Peter Oketayot authored Oct 18, 2023
1 parent 7e42871 commit d7876df
Show file tree
Hide file tree
Showing 9 changed files with 237 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,10 @@ public Collection<ExternalServicesPropertiesData> 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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -52,6 +53,7 @@
import org.springframework.transaction.support.TransactionTemplate;

@Configuration
@ConditionalOnMissingBean(name = { "jpaAuditingHandler" })
@EnableJpaAuditing
@EnableJpaRepositories(basePackages = "org.apache.fineract.**.domain")
@EnableConfigurationProperties(JpaProperties.class)
Expand Down
Original file line number Diff line number Diff line change
@@ -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);
}

}
Original file line number Diff line number Diff line change
@@ -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!");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -49,38 +68,44 @@ 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;
this.platformSecurityContext = platformSecurityContext;
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<PrequalificationGroupMember> 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);
Expand All @@ -97,4 +122,48 @@ public CommandProcessingResult validatePrequalificationWithBureau(Long prequalif
.withEntityId(prequalificationGroup.getId()) //
.build();
}

private EnumOptionData makeBureauCheckApiCall(final String dpi) {
EnumOptionData enumOptionData = null;
final Collection<ExternalServicesPropertiesData> 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<String> 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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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");
;
Expand Down
Original file line number Diff line number Diff line change
@@ -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'));
Original file line number Diff line number Diff line change
Expand Up @@ -571,4 +571,13 @@
</addColumn>
</changeSet>

<changeSet author="fineract" id="49">
<sqlFile
encoding="utf8"
path="db/changelog/tenant/commands/insert_buro_check_external_service_configs.sql"
relativeToChangelogFile="false"
splitStatements="true"
stripComments="true"/>
</changeSet>

</databaseChangeLog>

0 comments on commit d7876df

Please sign in to comment.