[FINERACT-1926] POST API for asset externalization

This commit is contained in:
taskain7
2023-05-24 11:26:54 +02:00
committed by Adam Saghy
parent fd27401de4
commit 045f0ec121
40 changed files with 1257 additions and 25 deletions
@@ -16,16 +16,13 @@
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.infrastructure.core.service;
package org.apache.fineract.cob.data;
import org.apache.commons.lang3.StringUtils;
import org.apache.fineract.infrastructure.core.domain.ExternalId;
public final class CommandParameterUtil {
public interface LoanIdAndExternalId {
private CommandParameterUtil() {}
public static boolean is(final String commandParam, final String commandValue) {
return StringUtils.isNotBlank(commandParam) && commandParam.trim().equalsIgnoreCase(commandValue);
}
Long getId();
ExternalId getExternalId();
}
@@ -1,33 +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.commands.service;
import org.apache.fineract.commands.domain.CommandWrapper;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
public interface PortfolioCommandSourceWritePlatformService {
CommandProcessingResult logCommandSource(CommandWrapper commandRequest);
CommandProcessingResult approveEntry(Long id);
Long rejectEntry(Long id);
Long deleteEntry(Long makerCheckerId);
}
@@ -1,79 +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.infrastructure.cache.domain;
import java.util.HashMap;
import java.util.Map;
public enum CacheType {
INVALID(0, "cacheType.invalid"), //
NO_CACHE(1, "cacheType.noCache"), //
SINGLE_NODE(2, "cacheType.singleNode"), //
MULTI_NODE(3, "cacheType.multiNode");
private final Integer value;
private final String code;
private static final Map<Integer, CacheType> intToEnumMap = new HashMap<>();
static {
for (final CacheType type : CacheType.values()) {
intToEnumMap.put(type.value, type);
}
}
public static CacheType fromInt(final Integer value) {
CacheType type = intToEnumMap.get(value);
if (type == null) {
type = INVALID;
}
return type;
}
CacheType(final Integer value, final String code) {
this.value = value;
this.code = code;
}
@Override
public String toString() {
return name().toString().replaceAll("_", " ");
}
public Integer getValue() {
return this.value;
}
public String getCode() {
return this.code;
}
public boolean isNoCache() {
return NO_CACHE.getValue().equals(this.value);
}
public boolean isEhcache() {
return SINGLE_NODE.getValue().equals(this.value);
}
public boolean isDistributedCache() {
return MULTI_NODE.getValue().equals(this.value);
}
}
@@ -1,142 +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.infrastructure.configuration.domain;
import java.time.LocalDate;
import org.apache.fineract.infrastructure.cache.domain.CacheType;
public interface ConfigurationDomainService {
boolean isMakerCheckerEnabledForTask(String taskPermissionCode);
boolean isAmazonS3Enabled();
boolean isRescheduleFutureRepaymentsEnabled();
boolean isRescheduleRepaymentsOnHolidaysEnabled();
boolean allowTransactionsOnHolidayEnabled();
boolean allowTransactionsOnNonWorkingDayEnabled();
boolean isConstraintApproachEnabledForDatatables();
boolean isEhcacheEnabled();
void updateCache(CacheType cacheType);
Long retrievePenaltyWaitPeriod();
boolean isPasswordForcedResetEnable();
Long retrievePasswordLiveTime();
Long retrieveGraceOnPenaltyPostingPeriod();
Long retrieveOpeningBalancesContraAccount();
boolean isSavingsInterestPostingAtCurrentPeriodEnd();
Integer retrieveFinancialYearBeginningMonth();
Integer retrieveMinAllowedClientsInGroup();
Integer retrieveMaxAllowedClientsInGroup();
boolean isMeetingMandatoryForJLGLoans();
int getRoundingMode();
boolean isBackdatePenaltiesEnabled();
boolean isOrganisationstartDateEnabled();
LocalDate retrieveOrganisationStartDate();
boolean isPaymentTypeApplicableForDisbursementCharge();
boolean isInterestChargedFromDateSameAsDisbursementDate();
boolean isSkippingMeetingOnFirstDayOfMonthEnabled();
boolean isInterestToBeRecoveredFirstWhenGreaterThanEMI();
boolean isPrincipalCompoundingDisabledForOverdueLoans();
Long retreivePeroidInNumberOfDaysForSkipMeetingDate();
boolean isChangeEmiIfRepaymentDateSameAsDisbursementDateEnabled();
boolean isDailyTPTLimitEnabled();
Long getDailyTPTLimit();
void removeGlobalConfigurationPropertyDataFromCache(String propertyName);
boolean isSMSOTPDeliveryEnabled();
boolean isEmailOTPDeliveryEnabled();
Integer retrieveOTPCharacterLength();
Integer retrieveOTPLiveTime();
boolean isSubRatesEnabled();
boolean isFirstRepaymentDateAfterRescheduleAllowedOnHoliday();
String getAccountMappingForPaymentType();
String getAccountMappingForCharge();
boolean isNextDayFixedDepositInterestTransferEnabledForPeriodEnd();
boolean retrievePivotDateConfig();
boolean isRelaxingDaysConfigForPivotDateEnabled();
Long retrieveRelaxingDaysConfigForPivotDate();
boolean isBusinessDateEnabled();
boolean isCOBDateAdjustmentEnabled();
boolean isReversalTransactionAllowed();
Long retrieveExternalEventsPurgeDaysCriteria();
Long retrieveProcessedCommandsPurgeDaysCriteria();
Long retrieveRepaymentDueDays();
Long retrieveRepaymentOverdueDays();
boolean isExternalIdAutoGenerationEnabled();
boolean isAddressEnabled();
boolean isCOBBulkEventEnabled();
Long retrieveExternalEventBatchSize();
String retrieveReportExportS3FolderName();
String getAccrualDateConfigForCharge();
}
@@ -60,7 +60,12 @@ public class CustomAuditingHandler extends AuditingHandler {
}
private DateTimeProvider fetchDateTimeProvider(Object bean) {
return bean instanceof AbstractAuditableWithUTCDateTimeCustom ? CustomDateTimeProvider.TENANT : CustomDateTimeProvider.INSTANCE;
if (bean instanceof AbstractAuditableWithUTCDateTimeCustom
|| bean instanceof org.apache.fineract.investor.domain.AbstractAuditableWithUTCDateTimeCustom) {
return CustomDateTimeProvider.TENANT;
} else {
return CustomDateTimeProvider.INSTANCE;
}
}
/**
@@ -1,145 +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.infrastructure.core.data;
import java.util.Map;
import org.apache.fineract.infrastructure.core.domain.ExternalId;
/**
* Represents the successful result of an REST API call that results in processing a command.
*/
public class CommandProcessingResultBuilder {
private Long commandId;
private Long officeId;
private Long groupId;
private Long clientId;
private Long loanId;
private Long savingsId;
private String resourceIdentifier;
private Long entityId;
private Long subEntityId;
private Long gsimId;
private Long glimId;
private String transactionId;
private Map<String, Object> changes;
private Map<String, Object> creditBureauReportData;
private Long productId;
private boolean rollbackTransaction = false;
private ExternalId entityExternalId = ExternalId.empty();
private ExternalId subEntityExternalId = ExternalId.empty();
public CommandProcessingResult build() {
return CommandProcessingResult.fromDetails(this.commandId, this.officeId, this.groupId, this.clientId, this.loanId, this.savingsId,
this.resourceIdentifier, this.entityId, this.gsimId, this.glimId, this.creditBureauReportData, this.transactionId,
this.changes, this.productId, this.rollbackTransaction, this.subEntityId, this.entityExternalId, this.subEntityExternalId);
}
public CommandProcessingResultBuilder withCommandId(final Long withCommandId) {
this.commandId = withCommandId;
return this;
}
public CommandProcessingResultBuilder with(final Map<String, Object> withChanges) {
this.changes = withChanges;
return this;
}
public CommandProcessingResultBuilder withResourceIdAsString(final String withResourceIdentifier) {
this.resourceIdentifier = withResourceIdentifier;
return this;
}
public CommandProcessingResultBuilder withEntityId(final Long withEntityId) {
this.entityId = withEntityId;
return this;
}
public CommandProcessingResultBuilder withSubEntityId(final Long withSubEntityId) {
this.subEntityId = withSubEntityId;
return this;
}
public CommandProcessingResultBuilder withOfficeId(final Long withOfficeId) {
this.officeId = withOfficeId;
return this;
}
public CommandProcessingResultBuilder withClientId(final Long withClientId) {
this.clientId = withClientId;
return this;
}
public CommandProcessingResultBuilder withGroupId(final Long withGroupId) {
this.groupId = withGroupId;
return this;
}
public CommandProcessingResultBuilder withLoanId(final Long withLoanId) {
this.loanId = withLoanId;
return this;
}
public CommandProcessingResultBuilder withSavingsId(final Long withSavingsId) {
this.savingsId = withSavingsId;
return this;
}
public CommandProcessingResultBuilder withTransactionId(final String withTransactionId) {
this.transactionId = withTransactionId;
return this;
}
public CommandProcessingResultBuilder withProductId(final Long productId) {
this.productId = productId;
return this;
}
public CommandProcessingResultBuilder withGsimId(final Long gsimId) {
this.gsimId = gsimId;
return this;
}
public CommandProcessingResultBuilder withGlimId(final Long glimId) {
this.glimId = glimId;
return this;
}
public CommandProcessingResultBuilder withCreditReport(final Map<String, Object> withCreditReport) {
this.creditBureauReportData = withCreditReport;
return this;
}
public CommandProcessingResultBuilder setRollbackTransaction(final boolean rollbackTransaction) {
this.rollbackTransaction = this.rollbackTransaction || rollbackTransaction;
return this;
}
public CommandProcessingResultBuilder withEntityExternalId(final ExternalId entityExternalId) {
this.entityExternalId = entityExternalId;
return this;
}
public CommandProcessingResultBuilder withSubEntityExternalId(final ExternalId subEntityExternalId) {
this.subEntityExternalId = subEntityExternalId;
return this;
}
}
@@ -21,6 +21,7 @@ package org.apache.fineract.infrastructure.core.domain;
import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
import org.apache.commons.lang3.StringUtils;
import org.apache.fineract.infrastructure.core.service.ExternalIdFactory;
@Converter(autoApply = true)
public class ExternalIdConverter implements AttributeConverter<ExternalId, String> {
@@ -32,7 +33,7 @@ public class ExternalIdConverter implements AttributeConverter<ExternalId, Strin
@Override
public ExternalId convertToEntityAttribute(String externalId) {
return StringUtils.isBlank(externalId) ? ExternalId.empty() : new ExternalId(externalId);
return StringUtils.isBlank(externalId) ? ExternalId.empty() : ExternalIdFactory.produce(externalId);
}
}
@@ -1,44 +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.infrastructure.core.exception;
public class UnrecognizedQueryParamException extends RuntimeException {
private final String queryParamKey;
private final String queryParamValue;
private final Object[] supportedParams;
public UnrecognizedQueryParamException(final String queryParamKey, final String queryParamValue, final Object... supportedParams) {
this.queryParamKey = queryParamKey;
this.queryParamValue = queryParamValue;
this.supportedParams = supportedParams;
}
public String getQueryParamKey() {
return this.queryParamKey;
}
public String getQueryParamValue() {
return this.queryParamValue;
}
public Object[] getSupportedParams() {
return this.supportedParams;
}
}
@@ -1,60 +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.infrastructure.core.service;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.domain.ExternalId;
import org.springframework.stereotype.Component;
@Component
@RequiredArgsConstructor
public class ExternalIdFactory {
private final ConfigurationDomainService configurationDomainService;
public static ExternalId produce(String value) {
return StringUtils.isBlank(value) ? ExternalId.empty() : new ExternalId(value);
}
public ExternalId createFromCommand(JsonCommand command, final String externalIdKey) {
String externalIdStr = null;
if (command.parsedJson() != null) {
externalIdStr = command.stringValueOfParameterNamedAllowingNull(externalIdKey);
}
return create(externalIdStr);
}
public ExternalId create(String externalIdStr) {
if (StringUtils.isBlank(externalIdStr)) {
if (configurationDomainService.isExternalIdAutoGenerationEnabled()) {
return ExternalId.generate();
} else {
return ExternalId.empty();
}
}
return new ExternalId(externalIdStr);
}
public ExternalId create() {
return create(null);
}
}
@@ -85,6 +85,11 @@ public interface LoanRepository extends JpaRepository<Loan, Long>, JpaSpecificat
String FIND_BY_ACCOUNT_NUMBER = "select loan from Loan loan where loan.accountNumber = :accountNumber";
String GET_NON_CLOSED_LOAN_BY_LOAN_ID = "select loan from Loan loan where loan.id = :loanId and loan.loanStatus in (100,200,300,"
+ "303,304)";
String EXISTS_NON_CLOSED_BY_EXTERNAL_LOAN_ID = "select case when (count (loan) > 0) then 'true' else 'false' end from Loan loan where loan.externalId = :externalLoanId and loan.loanStatus in (100,200,300,303,304)";
String FIND_ID_BY_EXTERNAL_ID = "SELECT loan.id FROM Loan loan WHERE loan.externalId = :externalId";
// should follow the logic of `FIND_ALL_NON_CLOSED_LOANS_BY_LAST_CLOSED_BUSINESS_DATE` query
@@ -191,6 +196,12 @@ public interface LoanRepository extends JpaRepository<Loan, Long>, JpaSpecificat
@Query(FIND_BY_ACCOUNT_NUMBER)
Loan findLoanAccountByAccountNumber(@Param("accountNumber") String accountNumber);
@Query(GET_NON_CLOSED_LOAN_BY_LOAN_ID)
Loan getNonClosedLoanIdAndExternalIdByLoanId(@Param("loanId") Long loanId);
@Query(EXISTS_NON_CLOSED_BY_EXTERNAL_LOAN_ID)
boolean existsNonClosedLoanByExternalLoanId(@Param("externalLoanId") ExternalId externalLoanId);
boolean existsByExternalId(@Param("externalId") ExternalId externalId);
@Query(FIND_ALL_NON_CLOSED)
@@ -262,4 +262,8 @@ public class LoanRepositoryWrapper {
public List<Long> findLoanIdsByStatusId(Integer statusId) {
return repository.findLoanIdByStatusId(statusId);
}
public Loan getNonClosedLoanIdAndExternalIdByLoanId(Long loanId) {
return repository.getNonClosedLoanIdAndExternalIdByLoanId(loanId);
}
}
@@ -41,6 +41,7 @@ import org.apache.fineract.infrastructure.codes.data.CodeValueData;
import org.apache.fineract.infrastructure.codes.service.CodeValueReadPlatformService;
import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
import org.apache.fineract.infrastructure.core.data.LoanIdAndExternalIdData;
import org.apache.fineract.infrastructure.core.domain.ExternalId;
import org.apache.fineract.infrastructure.core.domain.JdbcSupport;
import org.apache.fineract.infrastructure.core.service.DateUtils;
@@ -144,7 +145,7 @@ import org.springframework.util.CollectionUtils;
@AllArgsConstructor
@Service
@Transactional(readOnly = true)
public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
public class LoanReadPlatformServiceImpl implements LoanReadPlatformService, LoanReadPlatformServiceCommon {
private static final String ACCRUAL_ON_CHARGE_SUBMITTED_ON_DATE = "submitted-date";
private final JdbcTemplate jdbcTemplate;
@@ -591,6 +592,17 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
}
}
@Override
public LoanIdAndExternalIdData getTransferableLoanIdAndExternalId(Long loanId) {
Loan loan = loanRepositoryWrapper.getNonClosedLoanIdAndExternalIdByLoanId(loanId);
return new LoanIdAndExternalIdData(loan.getId(), loan.getExternalId());
}
@Override
public Long getLoanIdByLoanExternalId(String externalId) {
return loanRepositoryWrapper.findIdByExternalId(ExternalIdFactory.produce(externalId));
}
private static final class LoanMapper implements RowMapper<LoanAccountData> {
private final DatabaseSpecificSQLGenerator sqlGenerator;