diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/MapstructMapperConfig.java b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/config/MapstructMapperConfig.java similarity index 86% rename from fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/MapstructMapperConfig.java rename to fineract-core/src/main/java/org/apache/fineract/infrastructure/core/config/MapstructMapperConfig.java index 653659c2d..705d5f6a6 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/MapstructMapperConfig.java +++ b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/config/MapstructMapperConfig.java @@ -18,10 +18,12 @@ */ package org.apache.fineract.infrastructure.core.config; +import org.apache.fineract.infrastructure.event.external.service.serialization.mapper.support.ExternalIdMapper; import org.mapstruct.Builder; import org.mapstruct.MapperConfig; import org.mapstruct.MappingConstants; import org.mapstruct.ReportingPolicy; -@MapperConfig(componentModel = MappingConstants.ComponentModel.SPRING, unmappedTargetPolicy = ReportingPolicy.ERROR, builder = @Builder(disableBuilder = true)) +@MapperConfig(componentModel = MappingConstants.ComponentModel.SPRING, unmappedTargetPolicy = ReportingPolicy.ERROR, builder = @Builder(disableBuilder = true), uses = { + ExternalIdMapper.class }) public class MapstructMapperConfig {} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/mapper/support/AvroExternalIdMapper.java b/fineract-core/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/mapper/support/ExternalIdMapper.java similarity index 97% rename from fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/mapper/support/AvroExternalIdMapper.java rename to fineract-core/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/mapper/support/ExternalIdMapper.java index 6900a92d3..0bb3354ad 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/mapper/support/AvroExternalIdMapper.java +++ b/fineract-core/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/mapper/support/ExternalIdMapper.java @@ -22,7 +22,7 @@ import org.apache.fineract.infrastructure.core.domain.ExternalId; import org.springframework.stereotype.Component; @Component -public class AvroExternalIdMapper { +public class ExternalIdMapper { public String mapExternalId(ExternalId source) { if (source == null) { diff --git a/fineract-investor/src/main/java/org/apache/fineract/investor/api/ExternalAssetOwnersApiResource.java b/fineract-investor/src/main/java/org/apache/fineract/investor/api/ExternalAssetOwnersApiResource.java index 09744ce19..6c9f55bac 100644 --- a/fineract-investor/src/main/java/org/apache/fineract/investor/api/ExternalAssetOwnersApiResource.java +++ b/fineract-investor/src/main/java/org/apache/fineract/investor/api/ExternalAssetOwnersApiResource.java @@ -18,8 +18,14 @@ */ 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.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; +import java.util.List; import javax.ws.rs.Consumes; import javax.ws.rs.GET; import javax.ws.rs.POST; @@ -27,10 +33,17 @@ import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; +import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.UriInfo; import lombok.RequiredArgsConstructor; import org.apache.commons.lang3.NotImplementedException; +import org.apache.fineract.infrastructure.core.api.ApiRequestParameterHelper; +import org.apache.fineract.infrastructure.core.serialization.ApiRequestJsonSerializationSettings; +import org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSerializer; import org.apache.fineract.infrastructure.security.service.PlatformUserRightsContext; +import org.apache.fineract.investor.data.ExternalTransferData; +import org.apache.fineract.investor.service.ExternalAssetOwnersReadService; import org.springframework.stereotype.Component; @Path("/v1/external-asset-owners") @@ -40,6 +53,9 @@ import org.springframework.stereotype.Component; public class ExternalAssetOwnersApiResource { private final PlatformUserRightsContext platformUserRightsContext; + private final ExternalAssetOwnersReadService externalAssetOwnersReadService; + private final ApiRequestParameterHelper apiRequestParameterHelper; + private final DefaultToApiJsonSerializer apiJsonSerializerService; @POST @Path("/transfers/loans/{loanId}") @@ -54,7 +70,7 @@ public class ExternalAssetOwnersApiResource { } @POST - @Path("/transfers/loans//external-id/{loanExternalId}") + @Path("/transfers/loans/external-id/{loanExternalId}") @Consumes({ MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON }) public String transferRequestWithLoanExternalId(@PathParam("loanExternalId") final Long loanId, @@ -68,12 +84,19 @@ public class ExternalAssetOwnersApiResource { @GET @Path("/transfers") @Produces({ MediaType.APPLICATION_JSON }) + @Operation(tags = { + "External Asset Owners" }, summary = "Retrieve External Asset Owner Transfers", description = "Retrieve External Asset Owner Transfer items by transferExternalId, loanId or loanExternalId") + @ApiResponses({ + @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = ExternalAssetOwnersApiResourceSwagger.GetExternalTransferResponse.class))) }) public String getTransfer( @QueryParam("transferExternalId") @Parameter(description = "transferExternalId") final String transferExternalId, - @QueryParam("loanId") @Parameter(description = "loanId") final String loanId, - @QueryParam("loanExternalId") @Parameter(description = "loanExternalId") final String loanExternalId) { + @QueryParam("loanId") @Parameter(description = "loanId") final Long loanId, + @QueryParam("loanExternalId") @Parameter(description = "loanExternalId") final String loanExternalId, + @Context final UriInfo uriInfo) { platformUserRightsContext.isAuthenticated(); - - throw new NotImplementedException("Not implemented yet"); + List transferDataList = externalAssetOwnersReadService.retrieveTransferData(loanId, loanExternalId, + transferExternalId); + ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters()); + return apiJsonSerializerService.serialize(settings, transferDataList); } } diff --git a/fineract-investor/src/main/java/org/apache/fineract/investor/api/ExternalAssetOwnersApiResourceSwagger.java b/fineract-investor/src/main/java/org/apache/fineract/investor/api/ExternalAssetOwnersApiResourceSwagger.java new file mode 100644 index 000000000..43976241e --- /dev/null +++ b/fineract-investor/src/main/java/org/apache/fineract/investor/api/ExternalAssetOwnersApiResourceSwagger.java @@ -0,0 +1,90 @@ +/** + * 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; +import java.math.BigDecimal; +import java.time.LocalDate; +import java.util.Set; +import org.apache.fineract.investor.data.ExternalTransferStatus; + +@SuppressWarnings({ "MemberName" }) +final class ExternalAssetOwnersApiResourceSwagger { + + private ExternalAssetOwnersApiResourceSwagger() {} + + @Schema(description = "ExternalTransferResponse") + public static final class GetExternalTransferResponse { + + private GetExternalTransferResponse() {} + + static final class GetExternalTransferPageItems { + + private GetExternalTransferPageItems() {} + + static final class GetExternalTransferOwner { + + private GetExternalTransferOwner() {} + + @Schema(example = "e1156fbe-38bb-42f8-b491-fca02075f40e") + public String externalId; + } + + static final class GetExternalTransferLoan { + + private GetExternalTransferLoan() {} + + @Schema(example = "1") + public Long loanId; + + @Schema(example = "e1156fbe-38bb-42f8-b491-fca02075f40e") + public String externalId; + } + + @Schema(example = "1") + public Long transferId; + + public GetExternalTransferOwner owner; + + public GetExternalTransferLoan loan; + + @Schema(example = "e1156fbe-38bb-42f8-b491-fca02075f40e") + public String transferExternalId; + + @Schema(example = "1") + public BigDecimal purchasePriceRatio; + + @Schema(example = "[2023, 5, 23]") + public LocalDate settlementDate; + + @Schema(example = "PENDING") + public ExternalTransferStatus status; + + @Schema(example = "[2023, 5, 1]") + public LocalDate effectiveFrom; + + @Schema(example = "[2023, 5, 23]") + public LocalDate effectiveTo; + } + + @Schema(example = "20") + public Integer totalFilteredRecords; + public Set pageItems; + } +} diff --git a/fineract-investor/src/main/java/org/apache/fineract/investor/data/ExternalTransferData.java b/fineract-investor/src/main/java/org/apache/fineract/investor/data/ExternalTransferData.java index 83dec6e34..23f2bb861 100644 --- a/fineract-investor/src/main/java/org/apache/fineract/investor/data/ExternalTransferData.java +++ b/fineract-investor/src/main/java/org/apache/fineract/investor/data/ExternalTransferData.java @@ -25,15 +25,13 @@ import lombok.Data; @Data public class ExternalTransferData { - private final Long transferId; - private final ExternalTransferOwnerData owner; - private final ExternalTransferLoanMappingData loan; - private final String transferExternalId; - private final BigDecimal purchasePriceRatio; - private final LocalDate settlementDate; - private final ExternalTransferStatus status; - private final LocalDate effectiveFrom; - private final LocalDate effectiveTo; - private final String dateFormat; - private final String locale; + private Long transferId; + private ExternalTransferOwnerData owner; + private ExternalTransferLoanMappingData loan; + private String transferExternalId; + private BigDecimal purchasePriceRatio; + private LocalDate settlementDate; + private ExternalTransferStatus status; + private LocalDate effectiveFrom; + private LocalDate effectiveTo; } diff --git a/fineract-investor/src/main/java/org/apache/fineract/investor/domain/ExternalAssetOwner.java b/fineract-investor/src/main/java/org/apache/fineract/investor/domain/ExternalAssetOwner.java index 774018991..fd7c4d3de 100644 --- a/fineract-investor/src/main/java/org/apache/fineract/investor/domain/ExternalAssetOwner.java +++ b/fineract-investor/src/main/java/org/apache/fineract/investor/domain/ExternalAssetOwner.java @@ -25,6 +25,7 @@ import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; +import org.apache.fineract.infrastructure.core.domain.ExternalId; @Getter @Setter @@ -34,6 +35,6 @@ import lombok.Setter; public class ExternalAssetOwner extends AbstractAuditableWithUTCDateTimeCustom { @Column(name = "external_id", nullable = false, length = 100, unique = true) - private String externalId; + private ExternalId externalId; } diff --git a/fineract-investor/src/main/java/org/apache/fineract/investor/domain/ExternalAssetOwnerTransfer.java b/fineract-investor/src/main/java/org/apache/fineract/investor/domain/ExternalAssetOwnerTransfer.java index 10108fcba..e292ba6c0 100644 --- a/fineract-investor/src/main/java/org/apache/fineract/investor/domain/ExternalAssetOwnerTransfer.java +++ b/fineract-investor/src/main/java/org/apache/fineract/investor/domain/ExternalAssetOwnerTransfer.java @@ -29,6 +29,7 @@ import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; +import org.apache.fineract.infrastructure.core.domain.ExternalId; @Getter @Setter @@ -45,7 +46,7 @@ public class ExternalAssetOwnerTransfer extends AbstractAuditableWithUTCDateTime private ExternalAssetOwner owner; @Column(name = "external_id", length = 100) - private String externalId; + private ExternalId externalId; @Column(name = "status", length = 50) private String status; @@ -62,4 +63,10 @@ public class ExternalAssetOwnerTransfer extends AbstractAuditableWithUTCDateTime @Column(name = "effective_date_to") private LocalDate effectiveDateTo; + @Column(name = "loan_id", nullable = false) + private Long loanId; + + @Column(name = "external_loan_id", length = 100) + private ExternalId externalLoanId; + } diff --git a/fineract-investor/src/main/java/org/apache/fineract/investor/domain/ExternalAssetOwnerTransferLoanMapping.java b/fineract-investor/src/main/java/org/apache/fineract/investor/domain/ExternalAssetOwnerTransferLoanMapping.java index 86aea1f14..c0add21d2 100644 --- a/fineract-investor/src/main/java/org/apache/fineract/investor/domain/ExternalAssetOwnerTransferLoanMapping.java +++ b/fineract-investor/src/main/java/org/apache/fineract/investor/domain/ExternalAssetOwnerTransferLoanMapping.java @@ -39,7 +39,7 @@ public class ExternalAssetOwnerTransferLoanMapping extends AbstractAuditableWith private Long loanId; @ManyToOne - @JoinColumn(name = "owner_transfer_id", insertable = false, updatable = false) + @JoinColumn(name = "owner_transfer_id") private ExternalAssetOwnerTransfer ownerTransfer; } diff --git a/fineract-investor/src/main/java/org/apache/fineract/investor/domain/ExternalAssetOwnerTransferRepository.java b/fineract-investor/src/main/java/org/apache/fineract/investor/domain/ExternalAssetOwnerTransferRepository.java index 68675d870..556c33fe6 100644 --- a/fineract-investor/src/main/java/org/apache/fineract/investor/domain/ExternalAssetOwnerTransferRepository.java +++ b/fineract-investor/src/main/java/org/apache/fineract/investor/domain/ExternalAssetOwnerTransferRepository.java @@ -18,10 +18,16 @@ */ package org.apache.fineract.investor.domain; +import java.util.List; 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 ExternalAssetOwnerTransferRepository extends JpaRepository, JpaSpecificationExecutor { + @Query("select e from ExternalAssetOwnerTransfer e where (:loanId is null or e.loanId = :loanId) and (:loanExternalId is null or e.externalLoanId = :loanExternalId) and (:transferExternalId is null or e.externalId = :transferExternalId)") + List findAllByIncomingId(@Param("loanId") Long loanId, @Param("loanExternalId") String loanExternalId, + @Param("transferExternalId") String transferExternalId); } diff --git a/fineract-investor/src/main/java/org/apache/fineract/investor/service/ExternalAssetOwnersReadService.java b/fineract-investor/src/main/java/org/apache/fineract/investor/service/ExternalAssetOwnersReadService.java new file mode 100644 index 000000000..8f5f56d85 --- /dev/null +++ b/fineract-investor/src/main/java/org/apache/fineract/investor/service/ExternalAssetOwnersReadService.java @@ -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.service; + +import java.util.List; +import org.apache.fineract.investor.data.ExternalTransferData; + +public interface ExternalAssetOwnersReadService { + + List retrieveTransferData(Long loanId, String externalLoanId, String transferExternalId); +} diff --git a/fineract-investor/src/main/java/org/apache/fineract/investor/service/ExternalAssetOwnersReadServiceImpl.java b/fineract-investor/src/main/java/org/apache/fineract/investor/service/ExternalAssetOwnersReadServiceImpl.java new file mode 100644 index 000000000..b5b61db38 --- /dev/null +++ b/fineract-investor/src/main/java/org/apache/fineract/investor/service/ExternalAssetOwnersReadServiceImpl.java @@ -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.service; + +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.apache.fineract.investor.data.ExternalTransferData; +import org.apache.fineract.investor.domain.ExternalAssetOwnerTransfer; +import org.apache.fineract.investor.domain.ExternalAssetOwnerTransferRepository; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class ExternalAssetOwnersReadServiceImpl implements ExternalAssetOwnersReadService { + + private final ExternalAssetOwnerTransferRepository externalAssetOwnerTransferRepository; + private final ExternalAssetOwnersTransferMapper mapper; + private final ExternalAssetOwnersTransferMapper externalAssetOwnersTransferMapper; + + @Override + public List retrieveTransferData(Long loanId, String externalLoanId, String transferExternalId) { + List result = externalAssetOwnerTransferRepository.findAllByIncomingId(loanId, externalLoanId, + transferExternalId); + return result.stream().map(mapper::mapTransfer).toList(); + } +} diff --git a/fineract-investor/src/main/java/org/apache/fineract/investor/service/ExternalAssetOwnersTransferMapper.java b/fineract-investor/src/main/java/org/apache/fineract/investor/service/ExternalAssetOwnersTransferMapper.java new file mode 100644 index 000000000..a29ba4167 --- /dev/null +++ b/fineract-investor/src/main/java/org/apache/fineract/investor/service/ExternalAssetOwnersTransferMapper.java @@ -0,0 +1,46 @@ +/** + * 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.ExternalTransferData; +import org.apache.fineract.investor.data.ExternalTransferOwnerData; +import org.apache.fineract.investor.domain.ExternalAssetOwner; +import org.apache.fineract.investor.domain.ExternalAssetOwnerTransfer; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; + +@Mapper(config = MapstructMapperConfig.class) +public interface ExternalAssetOwnersTransferMapper { + + @Mapping(target = "transferId", source = "id") + @Mapping(target = "owner", source = "owner") + @Mapping(target = "loan.loanId", source = "loanId") + @Mapping(target = "loan.externalId", source = "externalLoanId") + @Mapping(target = "transferExternalId", source = "externalId") + @Mapping(target = "effectiveFrom", source = "effectiveDateFrom") + @Mapping(target = "effectiveTo", source = "effectiveDateTo") + @Mapping(target = "purchasePriceRatio", source = "purchasePriceRatio") + @Mapping(target = "settlementDate", source = "settlementDate") + @Mapping(target = "status", source = "status") + ExternalTransferData mapTransfer(ExternalAssetOwnerTransfer source); + + ExternalTransferOwnerData mapOwner(ExternalAssetOwner source); + +} diff --git a/fineract-investor/src/main/resources/db/changelog/tenant/module/investor/parts/0003_asset_schemas.xml b/fineract-investor/src/main/resources/db/changelog/tenant/module/investor/parts/0003_asset_schemas.xml new file mode 100644 index 000000000..bd12acd21 --- /dev/null +++ b/fineract-investor/src/main/resources/db/changelog/tenant/module/investor/parts/0003_asset_schemas.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/mapper/support/AvroMapperConfig.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/mapper/support/AvroMapperConfig.java index 8ee66be99..7de3ca674 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/mapper/support/AvroMapperConfig.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/mapper/support/AvroMapperConfig.java @@ -24,5 +24,5 @@ import org.mapstruct.MappingConstants; import org.mapstruct.ReportingPolicy; @MapperConfig(componentModel = MappingConstants.ComponentModel.SPRING, unmappedTargetPolicy = ReportingPolicy.ERROR, builder = @Builder(disableBuilder = true), uses = { - AvroDateTimeMapper.class, AvroMonthDayMapper.class, AvroExternalIdMapper.class }) + AvroDateTimeMapper.class, AvroMonthDayMapper.class, ExternalIdMapper.class }) public class AvroMapperConfig {}