FINERACT-2081: Ability to assign settlement information to loan product when asset is externally owned
This commit is contained in:
committed by
Arnold Gálovics
parent
3481761e74
commit
d2bdbf843a
@@ -610,6 +610,9 @@ configure(project.fineractJavaProjects) {
|
||||
'com.google.truth:truth',
|
||||
'com.google.truth.extensions:truth-java8-extension'
|
||||
)
|
||||
|
||||
testCompileOnly 'org.projectlombok:lombok'
|
||||
testAnnotationProcessor 'org.projectlombok:lombok'
|
||||
}
|
||||
|
||||
test {
|
||||
|
||||
@@ -65,6 +65,7 @@ import org.apache.fineract.client.services.DelinquencyRangeAndBucketsManagementA
|
||||
import org.apache.fineract.client.services.DocumentsApiFixed;
|
||||
import org.apache.fineract.client.services.EntityDataTableApi;
|
||||
import org.apache.fineract.client.services.EntityFieldConfigurationApi;
|
||||
import org.apache.fineract.client.services.ExternalAssetOwnerLoanProductAttributesApi;
|
||||
import org.apache.fineract.client.services.ExternalAssetOwnersApi;
|
||||
import org.apache.fineract.client.services.ExternalEventConfigurationApi;
|
||||
import org.apache.fineract.client.services.ExternalServicesApi;
|
||||
@@ -291,6 +292,7 @@ public final class FineractClient {
|
||||
public final WorkingDaysApi workingDays;
|
||||
|
||||
public final ExternalAssetOwnersApi externalAssetOwners;
|
||||
public final ExternalAssetOwnerLoanProductAttributesApi externalAssetOwnerLoanProductAttributes;
|
||||
public final LoanAccountLockApi loanAccountLockApi;
|
||||
|
||||
private FineractClient(OkHttpClient okHttpClient, Retrofit retrofit) {
|
||||
@@ -299,6 +301,7 @@ public final class FineractClient {
|
||||
|
||||
loanAccountLockApi = retrofit.create(LoanAccountLockApi.class);
|
||||
externalAssetOwners = retrofit.create(ExternalAssetOwnersApi.class);
|
||||
externalAssetOwnerLoanProductAttributes = retrofit.create(ExternalAssetOwnerLoanProductAttributesApi.class);
|
||||
glClosures = retrofit.create(AccountingClosureApi.class);
|
||||
accountingRules = retrofit.create(AccountingRulesApi.class);
|
||||
accountNumberFormats = retrofit.create(AccountNumberFormatApi.class);
|
||||
|
||||
+17
@@ -3644,6 +3644,23 @@ public class CommandWrapperBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommandWrapperBuilder createExternalAssetOwnerLoanProductAttribute(final Long loanProductId) {
|
||||
this.actionName = "CREATE";
|
||||
this.entityName = "EXTERNAL_ASSET_OWNER_LOAN_PRODUCT_ATTRIBUTE";
|
||||
this.productId = loanProductId;
|
||||
this.href = "/external-asset-owners/loan-product/" + loanProductId + "/attributes";
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommandWrapperBuilder updateExternalAssetOwnerLoanProductAttribute(final Long loanProductId, final Long attributeId) {
|
||||
this.actionName = "UPDATE";
|
||||
this.entityName = "EXTERNAL_ASSET_OWNER_LOAN_PRODUCT_ATTRIBUTE";
|
||||
this.productId = loanProductId;
|
||||
this.entityId = attributeId;
|
||||
this.href = "/external-asset-owners/loan-product/" + loanProductId + "/attributes/" + attributeId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommandWrapperBuilder saleLoanToExternalAssetOwner(final Long loanId) {
|
||||
this.actionName = "SALE";
|
||||
this.entityName = "LOAN";
|
||||
|
||||
+6
@@ -29,6 +29,7 @@ import org.apache.fineract.client.services.CurrencyApi;
|
||||
import org.apache.fineract.client.services.DataTablesApi;
|
||||
import org.apache.fineract.client.services.DefaultApi;
|
||||
import org.apache.fineract.client.services.DelinquencyRangeAndBucketsManagementApi;
|
||||
import org.apache.fineract.client.services.ExternalAssetOwnerLoanProductAttributesApi;
|
||||
import org.apache.fineract.client.services.ExternalAssetOwnersApi;
|
||||
import org.apache.fineract.client.services.ExternalEventConfigurationApi;
|
||||
import org.apache.fineract.client.services.FundsApi;
|
||||
@@ -214,6 +215,11 @@ public class ApiConfiguration {
|
||||
return fineractClient.createService(ExternalAssetOwnersApi.class);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ExternalAssetOwnerLoanProductAttributesApi externalAssetOwnerLoanProductAttributesApi() {
|
||||
return fineractClient.createService(ExternalAssetOwnerLoanProductAttributesApi.class);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public BusinessStepConfigurationApi businessStepConfigurationApi() {
|
||||
return fineractClient.createService(BusinessStepConfigurationApi.class);
|
||||
|
||||
@@ -36,6 +36,7 @@ dependencies {
|
||||
implementation(
|
||||
'org.springframework.boot:spring-boot-starter-web',
|
||||
'org.springframework.boot:spring-boot-starter-security',
|
||||
'org.springframework.boot:spring-boot-starter-cache',
|
||||
'jakarta.ws.rs:jakarta.ws.rs-api',
|
||||
'org.glassfish.jersey.media:jersey-media-multipart',
|
||||
|
||||
@@ -55,6 +56,7 @@ dependencies {
|
||||
'org.mapstruct:mapstruct',
|
||||
|
||||
'io.github.resilience4j:resilience4j-spring-boot3',
|
||||
'org.reflections:reflections:0.10.2',
|
||||
)
|
||||
compileOnly 'org.projectlombok:lombok'
|
||||
annotationProcessor 'org.projectlombok:lombok'
|
||||
|
||||
+44
@@ -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.
|
||||
*/
|
||||
package org.apache.fineract.investor.api;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import org.apache.fineract.investor.domain.ExternalAssetOwnerLoanProductAttributes;
|
||||
|
||||
public final class ExternalAssetOwnerLoanProductAttributesApiConstants {
|
||||
|
||||
private ExternalAssetOwnerLoanProductAttributesApiConstants() {
|
||||
|
||||
}
|
||||
|
||||
// parameters
|
||||
private static final String loanProductIdParamName = "loanProductId";
|
||||
private static final String attributeKeyParamName = "attributeKey";
|
||||
private static final String attributeValueParamName = "attributeValue";
|
||||
private static final String id = "id";
|
||||
|
||||
/**
|
||||
* These parameters will match the class level parameters of {@link ExternalAssetOwnerLoanProductAttributes}. Where
|
||||
* possible, we try to get response parameters to match those of request parameters.
|
||||
*/
|
||||
static final Set<String> RESPONSE_DATA_PARAMETERS = new HashSet<>(
|
||||
Arrays.asList(id, loanProductIdParamName, attributeKeyParamName, attributeValueParamName));
|
||||
}
|
||||
+131
@@ -0,0 +1,131 @@
|
||||
/**
|
||||
* 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.investor.api;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.media.Content;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.parameters.RequestBody;
|
||||
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 jakarta.ws.rs.Consumes;
|
||||
import jakarta.ws.rs.GET;
|
||||
import jakarta.ws.rs.POST;
|
||||
import jakarta.ws.rs.PUT;
|
||||
import jakarta.ws.rs.Path;
|
||||
import jakarta.ws.rs.PathParam;
|
||||
import jakarta.ws.rs.Produces;
|
||||
import jakarta.ws.rs.QueryParam;
|
||||
import jakarta.ws.rs.core.Context;
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
import jakarta.ws.rs.core.UriInfo;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.fineract.commands.domain.CommandWrapper;
|
||||
import org.apache.fineract.commands.service.CommandWrapperBuilder;
|
||||
import org.apache.fineract.commands.service.PortfolioCommandSourceWritePlatformService;
|
||||
import org.apache.fineract.infrastructure.core.api.ApiRequestParameterHelper;
|
||||
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSerializer;
|
||||
import org.apache.fineract.infrastructure.core.service.Page;
|
||||
import org.apache.fineract.infrastructure.security.service.PlatformUserRightsContext;
|
||||
import org.apache.fineract.investor.config.InvestorModuleIsEnabledCondition;
|
||||
import org.apache.fineract.investor.data.ExternalTransferLoanProductAttributesData;
|
||||
import org.apache.fineract.investor.service.ExternalAssetOwnerLoanProductAttributesReadService;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Path("/v1/external-asset-owners/loan-product")
|
||||
@Component
|
||||
@Tag(name = "External Asset Owner Loan Product Attributes", description = "External Asset Owner Loan Product Attributes")
|
||||
@RequiredArgsConstructor
|
||||
@Conditional(InvestorModuleIsEnabledCondition.class)
|
||||
public class ExternalAssetOwnerLoanProductAttributesApiResource {
|
||||
|
||||
private final PlatformUserRightsContext platformUserRightsContext;
|
||||
private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService;
|
||||
private final ExternalAssetOwnerLoanProductAttributesReadService externalAssetOwnerLoanProductAttributesReadService;
|
||||
private final ApiRequestParameterHelper apiRequestParameterHelper;
|
||||
private final DefaultToApiJsonSerializer<ExternalTransferLoanProductAttributesData> toApiJsonSerializer;
|
||||
|
||||
@POST
|
||||
@Path("/{loanProductId}/attributes")
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
@RequestBody(required = true, content = @Content(schema = @Schema(implementation = ExternalAssetOwnerLoanProductAttributesApiResourceSwagger.PostExternalAssetOwnerLoanProductAttributeRequest.class)))
|
||||
@ApiResponses({ @ApiResponse(responseCode = "200", description = "OK"),
|
||||
@ApiResponse(responseCode = "400", description = "Invalid Request"),
|
||||
@ApiResponse(responseCode = "403", description = "Resource Already Exists"),
|
||||
@ApiResponse(responseCode = "404", description = "Not Found"),
|
||||
@ApiResponse(responseCode = "500", description = "Internal Server Error") })
|
||||
public CommandProcessingResult postExternalAssetOwnerLoanProductAttribute(
|
||||
@PathParam("loanProductId") @Parameter(description = "loanProductId") final Long loanProductId,
|
||||
@Parameter(hidden = true) final String apiRequestBodyAsJson) {
|
||||
platformUserRightsContext.isAuthenticated();
|
||||
final CommandWrapperBuilder builder = new CommandWrapperBuilder().withJson(apiRequestBodyAsJson);
|
||||
CommandWrapper request = builder.createExternalAssetOwnerLoanProductAttribute(loanProductId).build();
|
||||
|
||||
return commandsSourceWritePlatformService.logCommandSource(request);
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/{loanProductId}/attributes")
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
@Operation(tags = {
|
||||
"External Asset Owner Loan Product Attributes" }, summary = "Retrieve All Loan Product Attributes", description = "Retrieves all Loan Product Attributes with a given loanProductId", parameters = {
|
||||
@Parameter(name = "loanProductId", description = "loanProductId"),
|
||||
@Parameter(name = "attributeKey", description = "attributeKey") })
|
||||
@ApiResponses({ @ApiResponse(responseCode = "200", description = "A paginated group of loan product attributes is returned"),
|
||||
@ApiResponse(responseCode = "404", description = "Not Found"),
|
||||
@ApiResponse(responseCode = "500", description = "Internal Server Error") })
|
||||
public Page<ExternalTransferLoanProductAttributesData> getExternalAssetOwnerLoanProductAttributes(@Context final UriInfo uriInfo,
|
||||
@PathParam("loanProductId") @Parameter(description = "loanProductId") final Long loanProductId,
|
||||
@QueryParam("attributeKey") @Parameter(description = "attributeKey") final String attributeKey) {
|
||||
platformUserRightsContext.isAuthenticated();
|
||||
|
||||
return externalAssetOwnerLoanProductAttributesReadService.retrieveAllLoanProductAttributesByLoanProductId(loanProductId,
|
||||
attributeKey);
|
||||
}
|
||||
|
||||
@PUT
|
||||
@Path("/{loanProductId}/attributes/{id}")
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
@RequestBody(required = true, content = @Content(schema = @Schema(implementation = ExternalAssetOwnerLoanProductAttributesApiResourceSwagger.PutExternalAssetOwnerLoanProductAttributeRequest.class)))
|
||||
@Operation(tags = {
|
||||
"External Asset Owner Loan Product Attributes" }, summary = "Update a Loan Product Attribute", description = "Updates a loan product attribute with a given loan product id and attribute id", parameters = {
|
||||
@Parameter(name = "loanProductId", description = "loanProductId"),
|
||||
@Parameter(name = "attributeId", description = "attributeId") })
|
||||
@ApiResponses({ @ApiResponse(responseCode = "200", description = "A loan product attribute filtered by id is returned"),
|
||||
@ApiResponse(responseCode = "404", description = "Not Found"),
|
||||
@ApiResponse(responseCode = "500", description = "Internal Server Error") })
|
||||
public CommandProcessingResult updateLoanProductAttribute(
|
||||
@PathParam("loanProductId") @Parameter(description = "loanProductId") final Long loanProductId,
|
||||
@PathParam("id") @Parameter(description = "attributeId") final Long attributeId,
|
||||
@Parameter(hidden = true) final String apiRequestBodyAsJson) {
|
||||
platformUserRightsContext.isAuthenticated();
|
||||
final CommandWrapperBuilder builder = new CommandWrapperBuilder().withJson(apiRequestBodyAsJson);
|
||||
CommandWrapper request = builder.updateExternalAssetOwnerLoanProductAttribute(loanProductId, attributeId).build();
|
||||
|
||||
return commandsSourceWritePlatformService.logCommandSource(request);
|
||||
}
|
||||
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* 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.investor.api;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
|
||||
@SuppressWarnings({ "MemberName" })
|
||||
final class ExternalAssetOwnerLoanProductAttributesApiResourceSwagger {
|
||||
|
||||
private ExternalAssetOwnerLoanProductAttributesApiResourceSwagger() {}
|
||||
|
||||
@Schema(description = "PostExternalAssetOwnerLoanProductAttributeRequest")
|
||||
public static final class PostExternalAssetOwnerLoanProductAttributeRequest {
|
||||
|
||||
private PostExternalAssetOwnerLoanProductAttributeRequest() {}
|
||||
|
||||
@Schema(example = "SETTLEMENT_MODEL")
|
||||
public String attributeKey;
|
||||
|
||||
@Schema(example = "DELAYED_SETTLEMENT")
|
||||
public String attributeValue;
|
||||
}
|
||||
|
||||
@Schema(description = "PutExternalAssetOwnerLoanProductAttributeRequest")
|
||||
public static final class PutExternalAssetOwnerLoanProductAttributeRequest {
|
||||
|
||||
private PutExternalAssetOwnerLoanProductAttributeRequest() {}
|
||||
|
||||
@Schema(example = "SETTLEMENT_MODEL")
|
||||
public String attributeKey;
|
||||
|
||||
@Schema(example = "DELAYED_SETTLEMENT_DISABLED")
|
||||
public String attributeValue;
|
||||
}
|
||||
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* 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.investor.data;
|
||||
|
||||
public final class ExternalAssetOwnerLoanProductAttributeRequestParameters {
|
||||
|
||||
private ExternalAssetOwnerLoanProductAttributeRequestParameters() {}
|
||||
|
||||
public static final String ATTRIBUTE_KEY = "attributeKey";
|
||||
public static final String ATTRIBUTE_VALUE = "attributeValue";
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* 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.investor.data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* Data object representing an external transfer loan product attribute
|
||||
*/
|
||||
|
||||
@Data
|
||||
@Getter
|
||||
public class ExternalTransferLoanProductAttributesData implements Serializable {
|
||||
|
||||
private Long attributeId;
|
||||
private Long loanProductId;
|
||||
private String attributeKey;
|
||||
private String attributeValue;
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* 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.investor.data.attribute;
|
||||
|
||||
public interface ExternalAssetOwnerLoanProductAttribute {
|
||||
|
||||
String getAttributeKey();
|
||||
|
||||
String getAttributeValue();
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* 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.investor.data.attribute;
|
||||
|
||||
public enum SettlementModelExternalAssetOwnerLoanProductAttribute implements ExternalAssetOwnerLoanProductAttribute {
|
||||
|
||||
DEFAULT_SETTLEMENT("DEFAULT_SETTLEMENT"), DELAYED_SETTLEMENT("DELAYED_SETTLEMENT"),;
|
||||
|
||||
private final String attributeKey;
|
||||
private final String attributeValue;
|
||||
|
||||
SettlementModelExternalAssetOwnerLoanProductAttribute(String attributeValue) {
|
||||
this.attributeKey = "SETTLEMENT_MODEL";
|
||||
this.attributeValue = attributeValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAttributeKey() {
|
||||
return attributeKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAttributeValue() {
|
||||
return attributeValue;
|
||||
}
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* 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.investor.domain;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Table;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDateTimeCustom;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@Entity
|
||||
@NoArgsConstructor
|
||||
@Table(name = "m_external_asset_owner_loan_product_configurable_attributes")
|
||||
public class ExternalAssetOwnerLoanProductAttributes extends AbstractAuditableWithUTCDateTimeCustom<Long> {
|
||||
|
||||
@Column(name = "loan_product_id", nullable = false)
|
||||
private Long loanProductId;
|
||||
|
||||
@Column(name = "attribute_key", nullable = false)
|
||||
private String attributeKey;
|
||||
|
||||
@Column(name = "attribute_value", nullable = false)
|
||||
private String attributeValue;
|
||||
|
||||
}
|
||||
+31
@@ -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.investor.domain;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
public interface ExternalAssetOwnerLoanProductAttributesRepository extends JpaRepository<ExternalAssetOwnerLoanProductAttributes, Long>,
|
||||
JpaSpecificationExecutor<ExternalAssetOwnerLoanProductAttributes> {
|
||||
|
||||
@Query("SELECT CASE WHEN COUNT(attribute)>0 THEN TRUE ELSE FALSE END FROM ExternalAssetOwnerLoanProductAttributes attribute WHERE attribute.loanProductId =:loanProductId AND attribute.attributeKey =:attributeKey")
|
||||
boolean existsByLoanProductIdAndKey(@Param("loanProductId") Long loanProductId, @Param("attributeKey") String attributeKey);
|
||||
}
|
||||
+31
@@ -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.investor.exception;
|
||||
|
||||
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformDomainRuleException;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
public class ExternalAssetOwnerLoanProductAttributeAlreadyExistsException extends AbstractPlatformDomainRuleException {
|
||||
|
||||
private static final String errorCode = "error.msg.externalAssetOwnerLoanProductAttribute.exists";
|
||||
|
||||
public ExternalAssetOwnerLoanProductAttributeAlreadyExistsException(String errorMessage) {
|
||||
super(errorCode, errorMessage, HttpStatus.FORBIDDEN);
|
||||
}
|
||||
}
|
||||
+31
@@ -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.investor.exception;
|
||||
|
||||
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformDomainRuleException;
|
||||
|
||||
public class ExternalAssetOwnerLoanProductAttributeInvalidSettlementAttributeException extends AbstractPlatformDomainRuleException {
|
||||
|
||||
private static final String errorCode = "error.msg.externalAssetOwnerLoanProductAttribute.invalidSettlementAttribute";
|
||||
|
||||
public ExternalAssetOwnerLoanProductAttributeInvalidSettlementAttributeException(String errorMessage) {
|
||||
super(errorCode, errorMessage);
|
||||
}
|
||||
|
||||
}
|
||||
+31
@@ -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.investor.exception;
|
||||
|
||||
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformResourceNotFoundException;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
public class ExternalAssetOwnerLoanProductAttributeNotFoundException extends AbstractPlatformResourceNotFoundException {
|
||||
|
||||
private static final String errorCode = "error.msg.externalAssetOwnerLoanProductAttribute.nonExistentAttribute";
|
||||
|
||||
public ExternalAssetOwnerLoanProductAttributeNotFoundException(final Long attributeId) {
|
||||
super(errorCode, "Loan product attribute with id " + attributeId + " was not found", HttpStatus.NOT_FOUND);
|
||||
}
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* 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.investor.exception;
|
||||
|
||||
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformDomainRuleException;
|
||||
|
||||
public class ExternalAssetOwnerLoanProductAttributesException extends AbstractPlatformDomainRuleException {
|
||||
|
||||
private static final String errorCode = "error.msg.externalAssetOwnerLoanProductAttributes.general";
|
||||
|
||||
public ExternalAssetOwnerLoanProductAttributesException(String errorMessage) {
|
||||
super(errorCode, errorMessage);
|
||||
}
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* 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.investor.service;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.fineract.commands.annotation.CommandType;
|
||||
import org.apache.fineract.commands.handler.NewCommandSourceHandler;
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
@CommandType(entity = "EXTERNAL_ASSET_OWNER_LOAN_PRODUCT_ATTRIBUTE", action = "CREATE")
|
||||
public class CreateExternalAssetOwnerLoanProductAttributeHandler implements NewCommandSourceHandler {
|
||||
|
||||
private final ExternalAssetOwnerLoanProductAttributesWriteService externalAssetOwnerLoanProductAttributesWriteService;
|
||||
|
||||
@Override
|
||||
public CommandProcessingResult processCommand(JsonCommand command) {
|
||||
return externalAssetOwnerLoanProductAttributesWriteService.createExternalAssetOwnerLoanProductAttribute(command);
|
||||
}
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* 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.investor.service;
|
||||
|
||||
import org.apache.fineract.infrastructure.core.config.MapstructMapperConfig;
|
||||
import org.apache.fineract.investor.data.ExternalTransferLoanProductAttributesData;
|
||||
import org.apache.fineract.investor.domain.ExternalAssetOwnerLoanProductAttributes;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
|
||||
@Mapper(config = MapstructMapperConfig.class)
|
||||
public interface ExternalAssetOwnerLoanProductAttributesMapper {
|
||||
|
||||
@Mapping(target = "attributeId", source = "id")
|
||||
ExternalTransferLoanProductAttributesData mapLoanProductAttributes(ExternalAssetOwnerLoanProductAttributes attributes);
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* 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.investor.service;
|
||||
|
||||
import org.apache.fineract.infrastructure.core.service.Page;
|
||||
import org.apache.fineract.investor.data.ExternalTransferLoanProductAttributesData;
|
||||
|
||||
public interface ExternalAssetOwnerLoanProductAttributesReadService {
|
||||
|
||||
Page<ExternalTransferLoanProductAttributesData> retrieveAllLoanProductAttributesByLoanProductId(Long loanProductId,
|
||||
String attributeKey);
|
||||
|
||||
}
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
/**
|
||||
* 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.investor.service;
|
||||
|
||||
import jakarta.persistence.criteria.Predicate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.fineract.infrastructure.core.service.Page;
|
||||
import org.apache.fineract.investor.data.ExternalTransferLoanProductAttributesData;
|
||||
import org.apache.fineract.investor.domain.ExternalAssetOwnerLoanProductAttributes;
|
||||
import org.apache.fineract.investor.domain.ExternalAssetOwnerLoanProductAttributesRepository;
|
||||
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRepository;
|
||||
import org.apache.fineract.portfolio.loanproduct.exception.LoanProductNotFoundException;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@Transactional(readOnly = true)
|
||||
public class ExternalAssetOwnerLoanProductAttributesReadServiceImpl implements ExternalAssetOwnerLoanProductAttributesReadService {
|
||||
|
||||
private final ExternalAssetOwnerLoanProductAttributesRepository externalAssetOwnerLoanProductAttributesRepository;
|
||||
private final LoanProductRepository loanProductRepository;
|
||||
private final ExternalAssetOwnerLoanProductAttributesMapper mapper;
|
||||
|
||||
@Override
|
||||
@Cacheable(cacheNames = "externalAssetOwnerLoanProductAttributes", key = "T(org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil).getTenant().getTenantIdentifier().concat(#loanProductId.toString() + #attributeKey)", unless = "#attributeKey == null")
|
||||
public Page<ExternalTransferLoanProductAttributesData> retrieveAllLoanProductAttributesByLoanProductId(final Long loanProductId,
|
||||
final String attributeKey) {
|
||||
validateLoanProduct(loanProductId);
|
||||
|
||||
PageRequest pageRequest = PageRequest.of(0, 100, Sort.by("id"));
|
||||
|
||||
org.springframework.data.domain.Page<ExternalAssetOwnerLoanProductAttributes> pageOfAttributeData = externalAssetOwnerLoanProductAttributesRepository
|
||||
.findAll(retrieveLoanProductAttributesByLoanProductIdAndAttributeKeySpecification(loanProductId, attributeKey),
|
||||
pageRequest);
|
||||
|
||||
return new Page<>(pageOfAttributeData.getContent().stream().map(mapper::mapLoanProductAttributes).toList(),
|
||||
pageOfAttributeData.getNumberOfElements());
|
||||
}
|
||||
|
||||
private void validateLoanProduct(final Long loanProductId) {
|
||||
if (loanProductId == null) {
|
||||
throw new IllegalArgumentException("At least one of the following parameters must be provided: loanProductId");
|
||||
}
|
||||
if (!loanProductRepository.existsById(loanProductId)) {
|
||||
throw new LoanProductNotFoundException(loanProductId);
|
||||
}
|
||||
}
|
||||
|
||||
public static Specification<ExternalAssetOwnerLoanProductAttributes> retrieveLoanProductAttributesByLoanProductIdAndAttributeKeySpecification(
|
||||
final Long loanProductId, final String attributeKey) {
|
||||
return (root, query, cb) -> {
|
||||
List<Predicate> predicates = new ArrayList<>();
|
||||
predicates.add(cb.equal(root.get("loanProductId"), loanProductId));
|
||||
|
||||
if (StringUtils.isNotBlank(attributeKey)) {
|
||||
predicates.add(cb.equal(root.get("attributeKey"), attributeKey));
|
||||
}
|
||||
|
||||
return cb.and(predicates.toArray(new Predicate[0]));
|
||||
};
|
||||
}
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* 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.investor.service;
|
||||
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
|
||||
|
||||
public interface ExternalAssetOwnerLoanProductAttributesWriteService {
|
||||
|
||||
CommandProcessingResult createExternalAssetOwnerLoanProductAttribute(JsonCommand command);
|
||||
|
||||
CommandProcessingResult updateExternalAssetOwnerLoanProductAttribute(JsonCommand command);
|
||||
|
||||
}
|
||||
+193
@@ -0,0 +1,193 @@
|
||||
/**
|
||||
* 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.investor.service;
|
||||
|
||||
import static org.reflections.scanners.Scanners.SubTypes;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import jakarta.transaction.Transactional;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
import org.apache.fineract.infrastructure.core.data.ApiParameterError;
|
||||
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder;
|
||||
import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
|
||||
import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
|
||||
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
|
||||
import org.apache.fineract.investor.data.ExternalAssetOwnerLoanProductAttributeRequestParameters;
|
||||
import org.apache.fineract.investor.data.attribute.ExternalAssetOwnerLoanProductAttribute;
|
||||
import org.apache.fineract.investor.domain.ExternalAssetOwnerLoanProductAttributes;
|
||||
import org.apache.fineract.investor.domain.ExternalAssetOwnerLoanProductAttributesRepository;
|
||||
import org.apache.fineract.investor.exception.ExternalAssetOwnerLoanProductAttributeAlreadyExistsException;
|
||||
import org.apache.fineract.investor.exception.ExternalAssetOwnerLoanProductAttributeInvalidSettlementAttributeException;
|
||||
import org.apache.fineract.investor.exception.ExternalAssetOwnerLoanProductAttributeNotFoundException;
|
||||
import org.apache.fineract.investor.exception.ExternalAssetOwnerLoanProductAttributesException;
|
||||
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRepository;
|
||||
import org.apache.fineract.portfolio.loanproduct.exception.LoanProductNotFoundException;
|
||||
import org.reflections.Reflections;
|
||||
import org.springframework.cache.annotation.CacheEvict;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@Transactional
|
||||
public class ExternalAssetOwnerLoanProductAttributesWriteServiceImpl implements ExternalAssetOwnerLoanProductAttributesWriteService {
|
||||
|
||||
private static final String INVESTOR_PATH = "org.apache.fineract.investor";
|
||||
|
||||
private final FromJsonHelper fromApiJsonHelper;
|
||||
private final ExternalAssetOwnerLoanProductAttributesRepository externalAssetOwnerLoanProductAttributesRepository;
|
||||
private final LoanProductRepository loanProductRepository;
|
||||
private final Set<Class<?>> implementingClasses = new Reflections(INVESTOR_PATH)
|
||||
.get(SubTypes.of(ExternalAssetOwnerLoanProductAttribute.class).asClass());
|
||||
|
||||
@Override
|
||||
public CommandProcessingResult createExternalAssetOwnerLoanProductAttribute(JsonCommand command) {
|
||||
final JsonElement json = fromApiJsonHelper.parse(command.json());
|
||||
String attributeKey = fromApiJsonHelper.extractStringNamed(ExternalAssetOwnerLoanProductAttributeRequestParameters.ATTRIBUTE_KEY,
|
||||
json);
|
||||
String attributeValue = fromApiJsonHelper
|
||||
.extractStringNamed(ExternalAssetOwnerLoanProductAttributeRequestParameters.ATTRIBUTE_VALUE, json);
|
||||
Long loanProductId = command.getProductId();
|
||||
validateLoanProductAttributeRequest(command.json(), attributeKey, attributeValue);
|
||||
validateExternalAssetOwnerLoanProductAttribute(attributeKey, attributeValue);
|
||||
validateLoanProductExistsAndAttributeDoesNotExist(loanProductId, attributeKey);
|
||||
ExternalAssetOwnerLoanProductAttributes newAttribute = createExternalAssetOwnerLoanProductAttribute(loanProductId, attributeKey,
|
||||
attributeValue);
|
||||
externalAssetOwnerLoanProductAttributesRepository.saveAndFlush(newAttribute);
|
||||
return buildResponseData(newAttribute);
|
||||
}
|
||||
|
||||
@Override
|
||||
@CacheEvict(cacheNames = "externalAssetOwnerLoanProductAttributes", key = "T(org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil).getTenant().getTenantIdentifier().concat(#command.getProductId().toString() + #attributeKey)")
|
||||
public CommandProcessingResult updateExternalAssetOwnerLoanProductAttribute(JsonCommand command) {
|
||||
final JsonElement json = fromApiJsonHelper.parse(command.json());
|
||||
String attributeKey = fromApiJsonHelper.extractStringNamed(ExternalAssetOwnerLoanProductAttributeRequestParameters.ATTRIBUTE_KEY,
|
||||
json);
|
||||
String attributeValue = fromApiJsonHelper
|
||||
.extractStringNamed(ExternalAssetOwnerLoanProductAttributeRequestParameters.ATTRIBUTE_VALUE, json);
|
||||
|
||||
Long loanProductId = command.getProductId();
|
||||
Long attributeId = command.entityId();
|
||||
validateLoanProductAttributeRequest(command.json(), attributeKey, attributeValue);
|
||||
validateExternalAssetOwnerLoanProductAttribute(attributeKey, attributeValue);
|
||||
validateLoanProductExists(loanProductId);
|
||||
ExternalAssetOwnerLoanProductAttributes attributeToUpdate = getLoanProductAttribute(attributeId);
|
||||
validateLoanProductAttributeKeysMatch(attributeKey, attributeToUpdate.getAttributeKey());
|
||||
if (!attributeToUpdate.getAttributeValue().equals(attributeValue)) {
|
||||
attributeToUpdate.setAttributeValue(attributeValue);
|
||||
externalAssetOwnerLoanProductAttributesRepository.saveAndFlush(attributeToUpdate);
|
||||
}
|
||||
return buildResponseData(attributeToUpdate);
|
||||
}
|
||||
|
||||
private void validateLoanProductAttributeRequest(String apiRequestBodyAsJson, String attributeKey, String attributeValue) {
|
||||
final Set<String> requestParameters = new HashSet<>(
|
||||
Arrays.asList(ExternalAssetOwnerLoanProductAttributeRequestParameters.ATTRIBUTE_KEY,
|
||||
ExternalAssetOwnerLoanProductAttributeRequestParameters.ATTRIBUTE_VALUE));
|
||||
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
|
||||
fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, apiRequestBodyAsJson, requestParameters);
|
||||
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("loanproductattribute");
|
||||
|
||||
baseDataValidator.reset().parameter(ExternalAssetOwnerLoanProductAttributeRequestParameters.ATTRIBUTE_KEY).value(attributeKey)
|
||||
.notBlank().notExceedingLengthOf(255);
|
||||
|
||||
baseDataValidator.reset().parameter(ExternalAssetOwnerLoanProductAttributeRequestParameters.ATTRIBUTE_VALUE).value(attributeValue)
|
||||
.notBlank().notExceedingLengthOf(255);
|
||||
|
||||
if (!dataValidationErrors.isEmpty()) {
|
||||
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.",
|
||||
dataValidationErrors);
|
||||
}
|
||||
}
|
||||
|
||||
private void validateLoanProductExistsAndAttributeDoesNotExist(Long loanProductId, String attributeKey) {
|
||||
validateLoanProductExists(loanProductId);
|
||||
validateLoanProductAttributeDoesNotExist(loanProductId, attributeKey);
|
||||
}
|
||||
|
||||
private void validateLoanProductExists(Long loanProductId) {
|
||||
if (!loanProductRepository.existsById(loanProductId)) {
|
||||
throw new LoanProductNotFoundException(loanProductId);
|
||||
}
|
||||
}
|
||||
|
||||
private void validateLoanProductAttributeDoesNotExist(Long loanProductId, String attributeKey) {
|
||||
if (externalAssetOwnerLoanProductAttributesRepository.existsByLoanProductIdAndKey(loanProductId, attributeKey)) {
|
||||
throw new ExternalAssetOwnerLoanProductAttributeAlreadyExistsException(
|
||||
"attributeKey already exists for the loanProductId: " + loanProductId + ". Use PUT call to UPDATE the attribute.");
|
||||
}
|
||||
}
|
||||
|
||||
private void validateLoanProductAttributeKeysMatch(String attributeKeyFromRequest, String attributeKeyFromDB) {
|
||||
if (!attributeKeyFromRequest.equals(attributeKeyFromDB)) {
|
||||
throw new ExternalAssetOwnerLoanProductAttributesException(
|
||||
"The attribute key of requested update attribute does not match the attribute key from database.");
|
||||
}
|
||||
}
|
||||
|
||||
private void validateExternalAssetOwnerLoanProductAttribute(String attributeKey, String attributeValue) {
|
||||
for (Class<?> implementingClass : implementingClasses) {
|
||||
if (implementingClass.isEnum()) {
|
||||
for (Object obj : implementingClass.getEnumConstants()) {
|
||||
ExternalAssetOwnerLoanProductAttribute objEnum = (ExternalAssetOwnerLoanProductAttribute) obj;
|
||||
if (objEnum.getAttributeKey().equals(attributeKey)
|
||||
&& objEnum.getAttributeValue().equals(attributeValue.toUpperCase())) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new ExternalAssetOwnerLoanProductAttributeInvalidSettlementAttributeException(
|
||||
"The given attribute key or attribute value is not valid.");
|
||||
}
|
||||
|
||||
private ExternalAssetOwnerLoanProductAttributes getLoanProductAttribute(Long attributeId) {
|
||||
Optional<ExternalAssetOwnerLoanProductAttributes> loanProductAttribute = externalAssetOwnerLoanProductAttributesRepository
|
||||
.findById(attributeId);
|
||||
if (loanProductAttribute.isEmpty()) {
|
||||
throw new ExternalAssetOwnerLoanProductAttributeNotFoundException(attributeId);
|
||||
}
|
||||
return loanProductAttribute.get();
|
||||
}
|
||||
|
||||
private ExternalAssetOwnerLoanProductAttributes createExternalAssetOwnerLoanProductAttribute(Long loanProductId, String attributeKey,
|
||||
String attributeValue) {
|
||||
ExternalAssetOwnerLoanProductAttributes attribute = new ExternalAssetOwnerLoanProductAttributes();
|
||||
attribute.setLoanProductId(loanProductId);
|
||||
attribute.setAttributeKey(attributeKey);
|
||||
attribute.setAttributeValue(attributeValue);
|
||||
return attribute;
|
||||
}
|
||||
|
||||
private CommandProcessingResult buildResponseData(ExternalAssetOwnerLoanProductAttributes savedAttribute) {
|
||||
return new CommandProcessingResultBuilder().withEntityId(savedAttribute.getLoanProductId()).build();
|
||||
}
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* 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.investor.service;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.fineract.commands.annotation.CommandType;
|
||||
import org.apache.fineract.commands.handler.NewCommandSourceHandler;
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
@CommandType(entity = "EXTERNAL_ASSET_OWNER_LOAN_PRODUCT_ATTRIBUTE", action = "UPDATE")
|
||||
public class UpdateExternalAssetOwnerLoanProductAttributeHandler implements NewCommandSourceHandler {
|
||||
|
||||
private final ExternalAssetOwnerLoanProductAttributesWriteService externalAssetOwnerLoanProductAttributesWriteService;
|
||||
|
||||
@Override
|
||||
public CommandProcessingResult processCommand(JsonCommand command) {
|
||||
return externalAssetOwnerLoanProductAttributesWriteService.updateExternalAssetOwnerLoanProductAttribute(command);
|
||||
}
|
||||
}
|
||||
+1
@@ -35,4 +35,5 @@
|
||||
<include relativeToChangelogFile="true" file="parts/0011_set_datetime_precision.xml"/>
|
||||
<include relativeToChangelogFile="true" file="parts/0012_add_external_asset_owner_transfer_index.xml"/>
|
||||
<include relativeToChangelogFile="true" file="parts/0013_add_additional_asset_owner_indices.xml"/>
|
||||
<include relativeToChangelogFile="true" file="parts/0014_add_external_asset_owner_loan_product_configurable_attributes.xml"/>
|
||||
</databaseChangeLog>
|
||||
|
||||
+112
@@ -0,0 +1,112 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
|
||||
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.
|
||||
|
||||
-->
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.1.xsd">
|
||||
|
||||
<changeSet author="fineract" id="1" context="postgresql">
|
||||
<!-- Create the m_external_asset_owner_loan_product_configurable_attributes table -->
|
||||
<createTable tableName="m_external_asset_owner_loan_product_configurable_attributes">
|
||||
|
||||
<column autoIncrement="true" name="id" type="BIGINT" remarks="Internal ID">
|
||||
<constraints nullable="false" primaryKey="true"/>
|
||||
</column>
|
||||
<column name="loan_product_id" type="BIGINT">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="attribute_key" type="VARCHAR(255)">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="attribute_value" type="VARCHAR(255)">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
|
||||
<column name="created_by" type="BIGINT"/>
|
||||
<column name="created_on_utc" type="TIMESTAMP WITH TIME ZONE"/>
|
||||
<column name="last_modified_by" type="BIGINT"/>
|
||||
<column name="last_modified_on_utc" type="TIMESTAMP WITH TIME ZONE"/>
|
||||
</createTable>
|
||||
</changeSet>
|
||||
<changeSet author="fineract" id="1" context="mysql">
|
||||
<!-- Create the m_external_asset_owner_loan_product_configurable_attributes table -->
|
||||
<createTable tableName="m_external_asset_owner_loan_product_configurable_attributes">
|
||||
<column autoIncrement="true" name="id" type="BIGINT" remarks="Internal ID">
|
||||
<constraints nullable="false" primaryKey="true"/>
|
||||
</column>
|
||||
<column name="loan_product_id" type="BIGINT">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="attribute_key" type="VARCHAR(255)">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="attribute_value" type="VARCHAR(255)">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
|
||||
<column name="created_by" type="BIGINT"/>
|
||||
<column name="created_on_utc" type="DATETIME"/>
|
||||
<column name="last_modified_by" type="BIGINT"/>
|
||||
<column name="last_modified_on_utc" type="DATETIME"/>
|
||||
</createTable>
|
||||
</changeSet>
|
||||
|
||||
<changeSet author="fineract" id="2">
|
||||
<addForeignKeyConstraint baseColumnNames="created_by"
|
||||
baseTableName="m_external_asset_owner_loan_product_configurable_attributes"
|
||||
constraintName="FK_ext_asset_owner_lp_conf_attr_created_by"
|
||||
deferrable="false"
|
||||
initiallyDeferred="false"
|
||||
onDelete="RESTRICT" onUpdate="RESTRICT" referencedColumnNames="id"
|
||||
referencedTableName="m_appuser" validate="true"/>
|
||||
<addForeignKeyConstraint baseColumnNames="last_modified_by"
|
||||
baseTableName="m_external_asset_owner_loan_product_configurable_attributes"
|
||||
constraintName="FK_ext_asset_owner_lp_conf_attr_modified_by"
|
||||
deferrable="false"
|
||||
initiallyDeferred="false"
|
||||
onDelete="RESTRICT" onUpdate="RESTRICT" referencedColumnNames="id"
|
||||
referencedTableName="m_appuser" validate="true"/>
|
||||
<addForeignKeyConstraint baseColumnNames="loan_product_id"
|
||||
baseTableName="m_external_asset_owner_loan_product_configurable_attributes"
|
||||
constraintName="FK_ext_asset_owner_lp_conf_attr_loan_product_id"
|
||||
deferrable="false"
|
||||
initiallyDeferred="false"
|
||||
onDelete="RESTRICT" onUpdate="RESTRICT" referencedColumnNames="id"
|
||||
referencedTableName="m_product_loan" validate="true"/>
|
||||
</changeSet>
|
||||
|
||||
<changeSet author="fineract" id="3">
|
||||
<insert tableName="m_permission">
|
||||
<column name="grouping" value="loan_product_attribute"/>
|
||||
<column name="code" value="CREATE_EXTERNAL_ASSET_OWNER_LOAN_PRODUCT_ATTRIBUTE"/>
|
||||
<column name="entity_name" value="EXTERNAL_ASSET_OWNER_LOAN_PRODUCT_ATTRIBUTE"/>
|
||||
<column name="action_name" value="CREATE"/>
|
||||
<column name="can_maker_checker" valueBoolean="false"/>
|
||||
</insert>
|
||||
<insert tableName="m_permission">
|
||||
<column name="grouping" value="loan_product_attribute"/>
|
||||
<column name="code" value="UPDATE_EXTERNAL_ASSET_OWNER_LOAN_PRODUCT_ATTRIBUTE"/>
|
||||
<column name="entity_name" value="EXTERNAL_ASSET_OWNER_LOAN_PRODUCT_ATTRIBUTE"/>
|
||||
<column name="action_name" value="UPDATE"/>
|
||||
<column name="can_maker_checker" valueBoolean="false"/>
|
||||
</insert>
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
||||
+164
@@ -0,0 +1,164 @@
|
||||
/**
|
||||
* 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.investor.service;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
import org.apache.fineract.infrastructure.core.service.Page;
|
||||
import org.apache.fineract.investor.data.ExternalTransferLoanProductAttributesData;
|
||||
import org.apache.fineract.investor.domain.ExternalAssetOwnerLoanProductAttributes;
|
||||
import org.apache.fineract.investor.domain.ExternalAssetOwnerLoanProductAttributesRepository;
|
||||
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRepository;
|
||||
import org.apache.fineract.portfolio.loanproduct.exception.LoanProductNotFoundException;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.springframework.data.domain.PageImpl;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
public class ExternalAssetOwnerLoanProductAttributesReadServiceTest {
|
||||
|
||||
@Mock
|
||||
private ExternalAssetOwnerLoanProductAttributesRepository externalAssetOwnerLoanProductAttributesRepository;
|
||||
|
||||
@Mock
|
||||
private LoanProductRepository loanProductRepository;
|
||||
|
||||
@Mock
|
||||
private ExternalAssetOwnerLoanProductAttributesMapper mapper;
|
||||
|
||||
private ExternalAssetOwnerLoanProductAttributesReadService underTest;
|
||||
|
||||
private int offset = 0;
|
||||
|
||||
private int limit = 100;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
underTest = new ExternalAssetOwnerLoanProductAttributesReadServiceImpl(externalAssetOwnerLoanProductAttributesRepository,
|
||||
loanProductRepository, mapper);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("testRetrieveAllLoanProductAttributesByLoanProductIdDataProvider")
|
||||
public void testRetrieveAllLoanProductAttributesByLoanProductId(Long loanProductId, String attributeKey) {
|
||||
// given
|
||||
ExternalAssetOwnerLoanProductAttributes attributes = Mockito.mock(ExternalAssetOwnerLoanProductAttributes.class);
|
||||
ExternalTransferLoanProductAttributesData data = Mockito.mock(ExternalTransferLoanProductAttributesData.class);
|
||||
PageRequest pageRequest = PageRequest.of(offset, limit, Sort.by("id").ascending());
|
||||
org.springframework.data.domain.Page<ExternalAssetOwnerLoanProductAttributes> attributesPage = new PageImpl<>(List.of(attributes),
|
||||
pageRequest, 1);
|
||||
|
||||
when(externalAssetOwnerLoanProductAttributesRepository.findAll(any(Specification.class), eq(pageRequest)))
|
||||
.thenReturn(attributesPage);
|
||||
when(loanProductRepository.existsById(loanProductId)).thenReturn(true);
|
||||
when(mapper.mapLoanProductAttributes(attributes)).thenReturn(data);
|
||||
|
||||
// when
|
||||
Page<ExternalTransferLoanProductAttributesData> result = underTest.retrieveAllLoanProductAttributesByLoanProductId(loanProductId,
|
||||
attributeKey);
|
||||
|
||||
// then
|
||||
assertEquals(1, result.getTotalFilteredRecords());
|
||||
assertEquals(data, result.getPageItems().get(0));
|
||||
verify(loanProductRepository, times(1)).existsById(loanProductId);
|
||||
verify(mapper, times(1)).mapLoanProductAttributes(attributes);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRetrieveAllLoanProductAttributesByLoanProductIdAndInvalidAttributeKey() {
|
||||
// given
|
||||
Long loanProductId = 1L;
|
||||
ExternalAssetOwnerLoanProductAttributes attributes = Mockito.mock(ExternalAssetOwnerLoanProductAttributes.class);
|
||||
PageRequest pageRequest = PageRequest.of(offset, limit, Sort.by("id").ascending());
|
||||
org.springframework.data.domain.Page<ExternalAssetOwnerLoanProductAttributes> attributesPage = new PageImpl<>(List.of(attributes),
|
||||
pageRequest, 0);
|
||||
|
||||
when(externalAssetOwnerLoanProductAttributesRepository.findAll(any(Specification.class), eq(pageRequest)))
|
||||
.thenReturn(attributesPage);
|
||||
when(loanProductRepository.existsById(loanProductId)).thenReturn(true);
|
||||
when(mapper.mapLoanProductAttributes(attributes)).thenReturn(null);
|
||||
|
||||
// when
|
||||
Page<ExternalTransferLoanProductAttributesData> result = underTest.retrieveAllLoanProductAttributesByLoanProductId(loanProductId,
|
||||
"BAD_KEY");
|
||||
|
||||
// then
|
||||
assertEquals(1, result.getTotalFilteredRecords());
|
||||
assertNull(result.getPageItems().get(0));
|
||||
verify(externalAssetOwnerLoanProductAttributesRepository, times(1)).findAll(any(Specification.class), eq(pageRequest));
|
||||
verify(loanProductRepository, times(1)).existsById(loanProductId);
|
||||
verify(mapper, times(1)).mapLoanProductAttributes(attributes);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRetrieveLoanProductAttributesDataByLoanProductIdIllegalArgument() {
|
||||
// given
|
||||
|
||||
// when
|
||||
IllegalArgumentException exception = assertThrows(IllegalArgumentException.class,
|
||||
() -> underTest.retrieveAllLoanProductAttributesByLoanProductId(null, null));
|
||||
|
||||
// then
|
||||
assertEquals("At least one of the following parameters must be provided: loanProductId", exception.getMessage());
|
||||
verifyNoInteractions(externalAssetOwnerLoanProductAttributesRepository);
|
||||
verifyNoInteractions(loanProductRepository);
|
||||
verifyNoInteractions(mapper);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRetrieveLoanProductAttributesDataByLoanProductIdNotFound() {
|
||||
// given
|
||||
Long loanProductId = 1L;
|
||||
when(loanProductRepository.existsById(loanProductId)).thenReturn(false);
|
||||
|
||||
// when
|
||||
LoanProductNotFoundException exception = assertThrows(LoanProductNotFoundException.class,
|
||||
() -> underTest.retrieveAllLoanProductAttributesByLoanProductId(loanProductId, null));
|
||||
|
||||
// then
|
||||
assertEquals("Loan product with identifier 1 does not exist", exception.getMessage());
|
||||
verify(loanProductRepository, times(1)).existsById(loanProductId);
|
||||
verifyNoInteractions(externalAssetOwnerLoanProductAttributesRepository);
|
||||
verifyNoInteractions(mapper);
|
||||
}
|
||||
|
||||
private static Stream<Arguments> testRetrieveAllLoanProductAttributesByLoanProductIdDataProvider() {
|
||||
return Stream.of(Arguments.of(1L, "SETTLEMENT_MODEL"), Arguments.of(1L, null));
|
||||
}
|
||||
}
|
||||
+391
@@ -0,0 +1,391 @@
|
||||
/**
|
||||
* 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.investor.service;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Stream;
|
||||
import lombok.Setter;
|
||||
import org.apache.commons.lang3.RandomStringUtils;
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
|
||||
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
|
||||
import org.apache.fineract.investor.data.ExternalAssetOwnerLoanProductAttributeRequestParameters;
|
||||
import org.apache.fineract.investor.domain.ExternalAssetOwnerLoanProductAttributes;
|
||||
import org.apache.fineract.investor.domain.ExternalAssetOwnerLoanProductAttributesRepository;
|
||||
import org.apache.fineract.investor.exception.ExternalAssetOwnerLoanProductAttributeAlreadyExistsException;
|
||||
import org.apache.fineract.investor.exception.ExternalAssetOwnerLoanProductAttributeInvalidSettlementAttributeException;
|
||||
import org.apache.fineract.investor.exception.ExternalAssetOwnerLoanProductAttributeNotFoundException;
|
||||
import org.apache.fineract.investor.exception.ExternalAssetOwnerLoanProductAttributesException;
|
||||
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRepository;
|
||||
import org.apache.fineract.portfolio.loanproduct.exception.LoanProductNotFoundException;
|
||||
import org.junit.Assert;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
public class ExternalAssetOwnerLoanProductAttributesWriteServiceImplTest {
|
||||
|
||||
@Test
|
||||
public void testCreateExternalAssetOwnerLoanProductAttributeHappyPath() {
|
||||
TestContext testContext = new TestContext();
|
||||
ArgumentCaptor<ExternalAssetOwnerLoanProductAttributes> loanProductAttributeArgumentCaptor = ArgumentCaptor
|
||||
.forClass(ExternalAssetOwnerLoanProductAttributes.class);
|
||||
|
||||
// given
|
||||
final JsonCommand command = createJsonCommand(testContext.jsonCommandString, testContext.loanProductId, null);
|
||||
when(testContext.externalAssetOwnerLoanProductAttributesRepository.existsByLoanProductIdAndKey(testContext.loanProductId,
|
||||
testContext.attributeKey)).thenReturn(false);
|
||||
when(testContext.loanProductRepository.existsById(testContext.loanProductId)).thenReturn(true);
|
||||
|
||||
// when
|
||||
testContext.externalAssetOwnerLoanProductAttributesWriteService.createExternalAssetOwnerLoanProductAttribute(command);
|
||||
|
||||
// then
|
||||
verify(testContext.externalAssetOwnerLoanProductAttributesRepository).existsByLoanProductIdAndKey(any(), any());
|
||||
verify(testContext.externalAssetOwnerLoanProductAttributesRepository).saveAndFlush(loanProductAttributeArgumentCaptor.capture());
|
||||
verify(testContext.loanProductRepository).existsById(testContext.loanProductId);
|
||||
assertLoanProductAttributeValues(testContext, loanProductAttributeArgumentCaptor.getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateExternalAssetOwnerLoanProductAttributeHappyPath() {
|
||||
TestContext testContext = new TestContext();
|
||||
ArgumentCaptor<ExternalAssetOwnerLoanProductAttributes> loanProductAttributeArgumentCaptor = ArgumentCaptor
|
||||
.forClass(ExternalAssetOwnerLoanProductAttributes.class);
|
||||
|
||||
ExternalAssetOwnerLoanProductAttributes attributeInDB = new ExternalAssetOwnerLoanProductAttributes();
|
||||
attributeInDB.setLoanProductId(testContext.loanProductId);
|
||||
attributeInDB.setAttributeKey(testContext.attributeKey);
|
||||
attributeInDB.setAttributeValue("DIFFERENT_VALUE");
|
||||
attributeInDB.setId(1L);
|
||||
|
||||
// given
|
||||
final JsonCommand command = createJsonCommand(testContext.jsonCommandString, testContext.loanProductId, attributeInDB.getId());
|
||||
when(testContext.loanProductRepository.existsById(testContext.loanProductId)).thenReturn(true);
|
||||
when(testContext.externalAssetOwnerLoanProductAttributesRepository.findById(command.entityId()))
|
||||
.thenReturn(Optional.of(attributeInDB));
|
||||
|
||||
testContext.externalAssetOwnerLoanProductAttributesWriteService.updateExternalAssetOwnerLoanProductAttribute(command);
|
||||
|
||||
// then
|
||||
verify(testContext.loanProductRepository).existsById(testContext.loanProductId);
|
||||
verify(testContext.externalAssetOwnerLoanProductAttributesRepository).findById(eq(command.entityId()));
|
||||
verify(testContext.externalAssetOwnerLoanProductAttributesRepository).saveAndFlush(loanProductAttributeArgumentCaptor.capture());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateExternalAssetOwnerLoanProductAttributeUpdateNotRequired() {
|
||||
TestContext testContext = new TestContext();
|
||||
ArgumentCaptor<ExternalAssetOwnerLoanProductAttributes> loanProductAttributeArgumentCaptor = ArgumentCaptor
|
||||
.forClass(ExternalAssetOwnerLoanProductAttributes.class);
|
||||
|
||||
ExternalAssetOwnerLoanProductAttributes attributeInDB = new ExternalAssetOwnerLoanProductAttributes();
|
||||
attributeInDB.setLoanProductId(testContext.loanProductId);
|
||||
attributeInDB.setAttributeKey(testContext.attributeKey);
|
||||
attributeInDB.setAttributeValue(testContext.attributeValue);
|
||||
attributeInDB.setId(1L);
|
||||
|
||||
// given
|
||||
final JsonCommand command = createJsonCommand(testContext.jsonCommandString, testContext.loanProductId, attributeInDB.getId());
|
||||
when(testContext.loanProductRepository.existsById(testContext.loanProductId)).thenReturn(true);
|
||||
when(testContext.externalAssetOwnerLoanProductAttributesRepository.findById(command.entityId()))
|
||||
.thenReturn(Optional.of(attributeInDB));
|
||||
|
||||
testContext.externalAssetOwnerLoanProductAttributesWriteService.updateExternalAssetOwnerLoanProductAttribute(command);
|
||||
|
||||
// then
|
||||
verify(testContext.loanProductRepository).existsById(testContext.loanProductId);
|
||||
verify(testContext.externalAssetOwnerLoanProductAttributesRepository).findById(eq(command.entityId()));
|
||||
verify(testContext.externalAssetOwnerLoanProductAttributesRepository, times(0))
|
||||
.saveAndFlush(loanProductAttributeArgumentCaptor.capture());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateExternalAssetOwnerLoanProductAttributeOnAttributeThatDoesNotExist() {
|
||||
TestContext testContext = new TestContext();
|
||||
ArgumentCaptor<ExternalAssetOwnerLoanProductAttributes> loanProductAttributeArgumentCaptor = ArgumentCaptor
|
||||
.forClass(ExternalAssetOwnerLoanProductAttributes.class);
|
||||
|
||||
// given
|
||||
final JsonCommand command = createJsonCommand(testContext.jsonCommandString, testContext.loanProductId, 1L);
|
||||
when(testContext.loanProductRepository.existsById(testContext.loanProductId)).thenReturn(true);
|
||||
when(testContext.externalAssetOwnerLoanProductAttributesRepository.findById(1L)).thenReturn(Optional.empty());
|
||||
|
||||
ExternalAssetOwnerLoanProductAttributeNotFoundException thrownException = Assert.assertThrows(
|
||||
ExternalAssetOwnerLoanProductAttributeNotFoundException.class,
|
||||
() -> testContext.externalAssetOwnerLoanProductAttributesWriteService
|
||||
.updateExternalAssetOwnerLoanProductAttribute(command));
|
||||
|
||||
// then
|
||||
verify(testContext.loanProductRepository).existsById(testContext.loanProductId);
|
||||
verify(testContext.externalAssetOwnerLoanProductAttributesRepository).findById(eq(1L));
|
||||
verify(testContext.externalAssetOwnerLoanProductAttributesRepository, times(0))
|
||||
.saveAndFlush(loanProductAttributeArgumentCaptor.capture());
|
||||
Assertions.assertEquals(thrownException.getMessage(), "Loan product attribute with id " + 1L + " was not found");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateExternalAssetOwnerLoanProductAttributeOnAttributeWithDifferentKeyValue() {
|
||||
TestContext testContext = new TestContext();
|
||||
ArgumentCaptor<ExternalAssetOwnerLoanProductAttributes> loanProductAttributeArgumentCaptor = ArgumentCaptor
|
||||
.forClass(ExternalAssetOwnerLoanProductAttributes.class);
|
||||
|
||||
ExternalAssetOwnerLoanProductAttributes attributeInDB = new ExternalAssetOwnerLoanProductAttributes();
|
||||
attributeInDB.setLoanProductId(testContext.loanProductId);
|
||||
attributeInDB.setAttributeKey("DIFFERENT_KEY");
|
||||
attributeInDB.setAttributeValue(testContext.attributeValue);
|
||||
attributeInDB.setId(1L);
|
||||
|
||||
// given
|
||||
final JsonCommand command = createJsonCommand(testContext.jsonCommandString, testContext.loanProductId, attributeInDB.getId());
|
||||
when(testContext.loanProductRepository.existsById(testContext.loanProductId)).thenReturn(true);
|
||||
when(testContext.externalAssetOwnerLoanProductAttributesRepository.findById(command.entityId()))
|
||||
.thenReturn(Optional.of(attributeInDB));
|
||||
|
||||
ExternalAssetOwnerLoanProductAttributesException thrownException = Assert.assertThrows(
|
||||
ExternalAssetOwnerLoanProductAttributesException.class,
|
||||
() -> testContext.externalAssetOwnerLoanProductAttributesWriteService
|
||||
.updateExternalAssetOwnerLoanProductAttribute(command));
|
||||
|
||||
// then
|
||||
verify(testContext.loanProductRepository).existsById(testContext.loanProductId);
|
||||
verify(testContext.externalAssetOwnerLoanProductAttributesRepository).findById(eq(command.entityId()));
|
||||
verify(testContext.externalAssetOwnerLoanProductAttributesRepository, times(0))
|
||||
.saveAndFlush(loanProductAttributeArgumentCaptor.capture());
|
||||
Assertions.assertEquals(thrownException.getMessage(),
|
||||
"The attribute key of requested update attribute does not match the attribute key from database.");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateExternalAssetOwnerLoanProductAttributeUsingDefaultSettlementValue() {
|
||||
TestContext testContext = new TestContext();
|
||||
ArgumentCaptor<ExternalAssetOwnerLoanProductAttributes> loanProductAttributeArgumentCaptor = ArgumentCaptor
|
||||
.forClass(ExternalAssetOwnerLoanProductAttributes.class);
|
||||
|
||||
// given
|
||||
final JsonElement jsonCommandElement = testContext.fromJsonHelper.parse(testContext.jsonCommandString);
|
||||
final JsonCommand command = createJsonCommand(testContext.jsonCommandString, testContext.loanProductId, null);
|
||||
when(testContext.externalAssetOwnerLoanProductAttributesRepository.existsByLoanProductIdAndKey(testContext.loanProductId,
|
||||
testContext.attributeKey)).thenReturn(false);
|
||||
when(testContext.loanProductRepository.existsById(testContext.loanProductId)).thenReturn(true);
|
||||
when(testContext.fromApiJsonHelper.extractStringNamed(ExternalAssetOwnerLoanProductAttributeRequestParameters.ATTRIBUTE_VALUE,
|
||||
jsonCommandElement)).thenReturn("DEFAULT_SETTLEMENT");
|
||||
testContext.setAttributeValue("DEFAULT_SETTLEMENT");
|
||||
|
||||
// when
|
||||
testContext.externalAssetOwnerLoanProductAttributesWriteService.createExternalAssetOwnerLoanProductAttribute(command);
|
||||
|
||||
// then
|
||||
verify(testContext.externalAssetOwnerLoanProductAttributesRepository).existsByLoanProductIdAndKey(any(), any());
|
||||
verify(testContext.externalAssetOwnerLoanProductAttributesRepository).saveAndFlush(loanProductAttributeArgumentCaptor.capture());
|
||||
verify(testContext.loanProductRepository).existsById(testContext.loanProductId);
|
||||
assertLoanProductAttributeValues(testContext, loanProductAttributeArgumentCaptor.getValue());
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("externalAssetOwnerLoanProductAttributeApiRequestDataValidationErrors")
|
||||
public void testExternalAssetOwnerLoanProductAttributeRequestWithApiDataValidationErrors(String testName, String attributeKey,
|
||||
String attributeValue, String expectedErrorString) {
|
||||
TestContext testContext = new TestContext();
|
||||
final JsonElement jsonCommandElement = testContext.fromJsonHelper.parse(testContext.jsonCommandString);
|
||||
final JsonCommand command = createJsonCommand(testContext.jsonCommandString, testContext.loanProductId, null);
|
||||
when(testContext.fromApiJsonHelper.extractStringNamed(ExternalAssetOwnerLoanProductAttributeRequestParameters.ATTRIBUTE_KEY,
|
||||
jsonCommandElement)).thenReturn(attributeKey);
|
||||
when(testContext.fromApiJsonHelper.extractStringNamed(ExternalAssetOwnerLoanProductAttributeRequestParameters.ATTRIBUTE_VALUE,
|
||||
jsonCommandElement)).thenReturn(attributeValue);
|
||||
|
||||
PlatformApiDataValidationException thrownException = Assert.assertThrows(PlatformApiDataValidationException.class,
|
||||
() -> testContext.externalAssetOwnerLoanProductAttributesWriteService
|
||||
.createExternalAssetOwnerLoanProductAttribute(command));
|
||||
|
||||
verify(testContext.externalAssetOwnerLoanProductAttributesRepository, times(0)).saveAndFlush(any());
|
||||
verify(testContext.externalAssetOwnerLoanProductAttributesRepository, times(0)).existsByLoanProductIdAndKey(any(), any());
|
||||
verify(testContext.loanProductRepository, times(0)).existsById(testContext.loanProductId);
|
||||
Assertions.assertEquals(thrownException.getMessage(), expectedErrorString);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateLoanProductAttributeExternalAssetOwnerExternalAssetOwnerLoanProductNotFound() {
|
||||
TestContext testContext = new TestContext();
|
||||
final JsonCommand command = createJsonCommand(testContext.jsonCommandString, testContext.loanProductId, null);
|
||||
|
||||
when(testContext.loanProductRepository.existsById(testContext.loanProductId)).thenReturn(false);
|
||||
|
||||
LoanProductNotFoundException thrownException = Assert.assertThrows(LoanProductNotFoundException.class,
|
||||
() -> testContext.externalAssetOwnerLoanProductAttributesWriteService
|
||||
.createExternalAssetOwnerLoanProductAttribute(command));
|
||||
|
||||
verify(testContext.externalAssetOwnerLoanProductAttributesRepository, times(0)).saveAndFlush(any());
|
||||
verify(testContext.externalAssetOwnerLoanProductAttributesRepository, times(0)).existsByLoanProductIdAndKey(any(), any());
|
||||
verify(testContext.loanProductRepository, times(1)).existsById(testContext.loanProductId);
|
||||
Assertions.assertEquals(thrownException.getMessage(),
|
||||
"Loan product with identifier " + testContext.loanProductId + " does not exist");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateLoanProductAttributeExternalAssetOwnerExternalAssetOwnerLoanProductAlreadyHasAttribute() {
|
||||
TestContext testContext = new TestContext();
|
||||
final JsonCommand command = createJsonCommand(testContext.jsonCommandString, testContext.loanProductId, null);
|
||||
|
||||
when(testContext.externalAssetOwnerLoanProductAttributesRepository.existsByLoanProductIdAndKey(testContext.loanProductId,
|
||||
testContext.attributeKey)).thenReturn(true);
|
||||
when(testContext.loanProductRepository.existsById(testContext.loanProductId)).thenReturn(true);
|
||||
|
||||
ExternalAssetOwnerLoanProductAttributeAlreadyExistsException thrownException = Assert.assertThrows(
|
||||
ExternalAssetOwnerLoanProductAttributeAlreadyExistsException.class,
|
||||
() -> testContext.externalAssetOwnerLoanProductAttributesWriteService
|
||||
.createExternalAssetOwnerLoanProductAttribute(command));
|
||||
|
||||
verify(testContext.externalAssetOwnerLoanProductAttributesRepository, times(0)).saveAndFlush(any());
|
||||
verify(testContext.externalAssetOwnerLoanProductAttributesRepository, times(1)).existsByLoanProductIdAndKey(any(), any());
|
||||
verify(testContext.loanProductRepository, times(1)).existsById(testContext.loanProductId);
|
||||
Assertions.assertEquals(thrownException.getMessage(), "attributeKey already exists for the loanProductId: "
|
||||
+ testContext.loanProductId + ". Use PUT call to UPDATE the attribute.");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExternalAssetOwnerLoanProductAttributeInvalidKey() {
|
||||
TestContext testContext = new TestContext();
|
||||
|
||||
final JsonCommand command = createJsonCommand(testContext.jsonCommandString, testContext.loanProductId, null);
|
||||
|
||||
final JsonElement jsonCommandElement = testContext.fromJsonHelper.parse(testContext.jsonCommandString);
|
||||
when(testContext.fromApiJsonHelper.extractStringNamed(ExternalAssetOwnerLoanProductAttributeRequestParameters.ATTRIBUTE_KEY,
|
||||
jsonCommandElement)).thenReturn("BAD_KEY");
|
||||
ExternalAssetOwnerLoanProductAttributeInvalidSettlementAttributeException thrownException = Assert.assertThrows(
|
||||
ExternalAssetOwnerLoanProductAttributeInvalidSettlementAttributeException.class,
|
||||
() -> testContext.externalAssetOwnerLoanProductAttributesWriteService
|
||||
.createExternalAssetOwnerLoanProductAttribute(command));
|
||||
|
||||
verify(testContext.externalAssetOwnerLoanProductAttributesRepository, times(0)).saveAndFlush(any());
|
||||
verify(testContext.externalAssetOwnerLoanProductAttributesRepository, times(0)).existsByLoanProductIdAndKey(any(), any());
|
||||
verify(testContext.loanProductRepository, times(0)).existsById(testContext.loanProductId);
|
||||
Assertions.assertEquals(thrownException.getMessage(), "The given attribute key or attribute value is not valid.");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExternalAssetOwnerLoanProductAttributeInvalidValue() {
|
||||
TestContext testContext = new TestContext();
|
||||
|
||||
final JsonCommand command = createJsonCommand(testContext.jsonCommandString, testContext.loanProductId, null);
|
||||
|
||||
final JsonElement jsonCommandElement = testContext.fromJsonHelper.parse(testContext.jsonCommandString);
|
||||
when(testContext.fromApiJsonHelper.extractStringNamed(ExternalAssetOwnerLoanProductAttributeRequestParameters.ATTRIBUTE_VALUE,
|
||||
jsonCommandElement)).thenReturn("BAD_VALUE");
|
||||
ExternalAssetOwnerLoanProductAttributeInvalidSettlementAttributeException thrownException = Assert.assertThrows(
|
||||
ExternalAssetOwnerLoanProductAttributeInvalidSettlementAttributeException.class,
|
||||
() -> testContext.externalAssetOwnerLoanProductAttributesWriteService
|
||||
.createExternalAssetOwnerLoanProductAttribute(command));
|
||||
|
||||
verify(testContext.externalAssetOwnerLoanProductAttributesRepository, times(0)).saveAndFlush(any());
|
||||
verify(testContext.externalAssetOwnerLoanProductAttributesRepository, times(0)).existsByLoanProductIdAndKey(any(), any());
|
||||
verify(testContext.loanProductRepository, times(0)).existsById(testContext.loanProductId);
|
||||
Assertions.assertEquals(thrownException.getMessage(), "The given attribute key or attribute value is not valid.");
|
||||
}
|
||||
|
||||
private static Stream<Arguments> externalAssetOwnerLoanProductAttributeApiRequestDataValidationErrors() {
|
||||
|
||||
return Stream.of(Arguments.of("blankAttributeValue", "SETTLEMENT_MODEL", "", "Validation errors exist."),
|
||||
Arguments.of("blankAttributeKey", "", "DELAYED_SETTLEMENT", "Validation errors exist."));
|
||||
}
|
||||
|
||||
private void assertLoanProductAttributeValues(final TestContext testContext,
|
||||
final ExternalAssetOwnerLoanProductAttributes loanProductAttribute) {
|
||||
Assertions.assertEquals(testContext.loanProductId, loanProductAttribute.getLoanProductId());
|
||||
Assertions.assertEquals(testContext.attributeKey, loanProductAttribute.getAttributeKey());
|
||||
Assertions.assertEquals(testContext.attributeValue, loanProductAttribute.getAttributeValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to create {@link JsonCommand} object from json command string.
|
||||
*
|
||||
* @param jsonCommand
|
||||
* the json command string
|
||||
* @param loanProductId
|
||||
* the loanProductId
|
||||
* @return the {@link JsonCommand} object.
|
||||
*/
|
||||
private JsonCommand createJsonCommand(final String jsonCommand, final Long loanProductId, final Long resourceId) {
|
||||
return new JsonCommand(null, jsonCommand, null, null, null, resourceId, null, null, null, null, null, null, null, loanProductId,
|
||||
null, null, null, null);
|
||||
}
|
||||
|
||||
@SuppressFBWarnings({ "VA_FORMAT_STRING_USES_NEWLINE" })
|
||||
static class TestContext {
|
||||
|
||||
@Mock
|
||||
private FromJsonHelper fromApiJsonHelper;
|
||||
|
||||
@Mock
|
||||
private ExternalAssetOwnerLoanProductAttributesRepository externalAssetOwnerLoanProductAttributesRepository;
|
||||
|
||||
@Mock
|
||||
private LoanProductRepository loanProductRepository;
|
||||
|
||||
@InjectMocks
|
||||
private ExternalAssetOwnerLoanProductAttributesWriteServiceImpl externalAssetOwnerLoanProductAttributesWriteService;
|
||||
|
||||
private final FromJsonHelper fromJsonHelper = new FromJsonHelper();
|
||||
private final Long loanProductId = Long.valueOf(RandomStringUtils.randomNumeric(2));
|
||||
@Setter
|
||||
private String attributeKey = "SETTLEMENT_MODEL";
|
||||
@Setter
|
||||
private String attributeValue = "DELAYED_SETTLEMENT";
|
||||
|
||||
private String jsonCommandString = String.format("""
|
||||
{
|
||||
"attributeKey": "%s",
|
||||
"attributeValue": "%s"
|
||||
}
|
||||
""", attributeKey, attributeValue);
|
||||
|
||||
@SuppressFBWarnings("CT_CONSTRUCTOR_THROW")
|
||||
TestContext() {
|
||||
MockitoAnnotations.openMocks(this);
|
||||
stubFromApiJsonHelper();
|
||||
}
|
||||
|
||||
private void stubFromApiJsonHelper() {
|
||||
final JsonElement jsonCommandElement = fromJsonHelper.parse(jsonCommandString);
|
||||
when(fromApiJsonHelper.parse(anyString())).thenReturn(jsonCommandElement);
|
||||
when(fromApiJsonHelper.extractStringNamed(ExternalAssetOwnerLoanProductAttributeRequestParameters.ATTRIBUTE_KEY,
|
||||
jsonCommandElement)).thenReturn(attributeKey);
|
||||
when(fromApiJsonHelper.extractStringNamed(ExternalAssetOwnerLoanProductAttributeRequestParameters.ATTRIBUTE_VALUE,
|
||||
jsonCommandElement)).thenReturn(attributeValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
+5
@@ -21,6 +21,7 @@ package org.apache.fineract.portfolio.loanproduct.domain;
|
||||
import java.util.List;
|
||||
import org.apache.fineract.infrastructure.core.domain.ExternalId;
|
||||
import org.apache.fineract.portfolio.delinquency.domain.DelinquencyBucket;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
@@ -36,4 +37,8 @@ public interface LoanProductRepository extends JpaRepository<LoanProduct, Long>,
|
||||
List<LoanProduct> findByDelinquencyBucketNotNull();
|
||||
|
||||
LoanProduct findByExternalId(ExternalId externalId);
|
||||
|
||||
@Override
|
||||
@Query("SELECT CASE WHEN COUNT(loanProduct)>0 THEN TRUE ELSE FALSE END FROM LoanProduct loanProduct WHERE loanProduct.id = :loanProductId")
|
||||
boolean existsById(@NotNull @Param("loanProductId") Long loanProductId);
|
||||
}
|
||||
|
||||
+5
-5
@@ -126,10 +126,10 @@ public class TwoFactorAuthenticationTest {
|
||||
|
||||
@Test
|
||||
public void testTwofactorLogin() throws IOException, MessagingException {
|
||||
assertEquals(greenMail.getReceivedMessages().length, 0);
|
||||
assertEquals(0, greenMail.getReceivedMessages().length);
|
||||
performServerPost(requestSpec, responseSpec,
|
||||
"/fineract-provider/api/v1/twofactor?deliveryMethod=email&extendedToken=false&" + TENANT_IDENTIFIER, "", "");
|
||||
assertEquals(greenMail.getReceivedMessages().length, 1);
|
||||
assertEquals(1, greenMail.getReceivedMessages().length);
|
||||
|
||||
Pattern p = Pattern.compile("token is (.+).");
|
||||
Matcher m = p.matcher((CharSequence) greenMail.getReceivedMessages()[0].getContent());
|
||||
@@ -161,10 +161,10 @@ public class TwoFactorAuthenticationTest {
|
||||
|
||||
@Test
|
||||
public void testTfaConfigSettings() throws IOException, MessagingException {
|
||||
assertEquals(greenMail.getReceivedMessages().length, 0);
|
||||
assertEquals(0, greenMail.getReceivedMessages().length);
|
||||
performServerPost(requestSpec, responseSpec,
|
||||
"/fineract-provider/api/v1/twofactor?deliveryMethod=email&extendedToken=false&" + TENANT_IDENTIFIER, "", "");
|
||||
assertEquals(greenMail.getReceivedMessages().length, 1);
|
||||
assertEquals(1, greenMail.getReceivedMessages().length);
|
||||
|
||||
Pattern p = Pattern.compile("token is (.+).");
|
||||
Matcher m = p.matcher((CharSequence) greenMail.getReceivedMessages()[0].getContent());
|
||||
@@ -202,7 +202,7 @@ public class TwoFactorAuthenticationTest {
|
||||
// Login again
|
||||
performServerPost(requestSpec, responseSpec,
|
||||
"/fineract-provider/api/v1/twofactor?deliveryMethod=email&extendedToken=false&" + TENANT_IDENTIFIER, "", "");
|
||||
assertEquals(greenMail.getReceivedMessages().length, 2);
|
||||
assertEquals(2, greenMail.getReceivedMessages().length);
|
||||
|
||||
Matcher m2 = p.matcher((CharSequence) greenMail.getReceivedMessages()[1].getContent());
|
||||
|
||||
|
||||
Reference in New Issue
Block a user