FINERACT-1926: Fineract Asset Externalization new asset events
- [x] Add LoanOwnershipTransferBusinessEvent - [x] Add LoanAccountSnapshotBusinessEvent - [x] Move packages to the right packages - [X] Implement LoanOwnershipTransferBusinessEvent serializer - [x] Call cancel/buyback/sale event - [x] Unit tests
This commit is contained in:
committed by
Arnold Gálovics
parent
d37c0e1de2
commit
25d7a9228a
@@ -0,0 +1,158 @@
|
|||||||
|
{
|
||||||
|
"name": "LoanOwnershipTransferDataV1",
|
||||||
|
"namespace": "org.apache.fineract.avro.loan.v1",
|
||||||
|
"type": "record",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"name": "loanId",
|
||||||
|
"type": ["long"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": null,
|
||||||
|
"name": "loanExternalId",
|
||||||
|
"type": [
|
||||||
|
"null",
|
||||||
|
"string"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": null,
|
||||||
|
"name": "type",
|
||||||
|
"type": [
|
||||||
|
"null",
|
||||||
|
"string"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": null,
|
||||||
|
"name": "transferExternalId",
|
||||||
|
"type": [
|
||||||
|
"null",
|
||||||
|
"string"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": null,
|
||||||
|
"name": "submittedDate",
|
||||||
|
"type": [
|
||||||
|
"null",
|
||||||
|
"string"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": null,
|
||||||
|
"name": "assetOwnerExternalId",
|
||||||
|
"type": [
|
||||||
|
"null",
|
||||||
|
"string"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": null,
|
||||||
|
"name": "currency",
|
||||||
|
"type": [
|
||||||
|
"null",
|
||||||
|
"org.apache.fineract.avro.generic.v1.CurrencyDataV1"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": null,
|
||||||
|
"name": "totalOutstandingBalanceAmount",
|
||||||
|
"type": [
|
||||||
|
"null",
|
||||||
|
"bigdecimal"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": null,
|
||||||
|
"name": "outstandingPrincipalPortion",
|
||||||
|
"type": [
|
||||||
|
"null",
|
||||||
|
"bigdecimal"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": null,
|
||||||
|
"name": "outstandingFeePortion",
|
||||||
|
"type": [
|
||||||
|
"null",
|
||||||
|
"bigdecimal"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": null,
|
||||||
|
"name": "outstandingPenaltyPortion",
|
||||||
|
"type": [
|
||||||
|
"null",
|
||||||
|
"bigdecimal"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": null,
|
||||||
|
"name": "outstandingInterestPortion",
|
||||||
|
"type": [
|
||||||
|
"null",
|
||||||
|
"bigdecimal"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": null,
|
||||||
|
"name": "overPaymentPortion",
|
||||||
|
"type": [
|
||||||
|
"null",
|
||||||
|
"bigdecimal"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": null,
|
||||||
|
"name": "unrecognizedIncomePortion",
|
||||||
|
"type": [
|
||||||
|
"null",
|
||||||
|
"bigdecimal"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": null,
|
||||||
|
"name": "unpaidChargeData",
|
||||||
|
"type": [
|
||||||
|
"null",
|
||||||
|
{
|
||||||
|
"type": "array",
|
||||||
|
"items": "org.apache.fineract.avro.loan.v1.UnpaidChargeDataV1"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": null,
|
||||||
|
"name": "transferStatus",
|
||||||
|
"type": [
|
||||||
|
"null",
|
||||||
|
"string"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": null,
|
||||||
|
"name": "transferStatusReason",
|
||||||
|
"type": [
|
||||||
|
"null",
|
||||||
|
"string"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": null,
|
||||||
|
"name": "settlementDate",
|
||||||
|
"type": [
|
||||||
|
"null",
|
||||||
|
"string"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": null,
|
||||||
|
"name": "purchasePriceRatio",
|
||||||
|
"type": [
|
||||||
|
"null",
|
||||||
|
"string"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -28,7 +28,6 @@ dependencies {
|
|||||||
)
|
)
|
||||||
|
|
||||||
// implementation dependencies are directly used (compiled against) in src/main (and src/test)
|
// implementation dependencies are directly used (compiled against) in src/main (and src/test)
|
||||||
//
|
|
||||||
implementation(
|
implementation(
|
||||||
'org.springframework.boot:spring-boot-starter-web',
|
'org.springframework.boot:spring-boot-starter-web',
|
||||||
'org.springframework.boot:spring-boot-starter-security',
|
'org.springframework.boot:spring-boot-starter-security',
|
||||||
@@ -127,4 +126,8 @@ dependencies {
|
|||||||
exclude group: 'com.zaxxer', module: 'HikariCP-java7'
|
exclude group: 'com.zaxxer', module: 'HikariCP-java7'
|
||||||
}
|
}
|
||||||
testImplementation ('org.mockito:mockito-inline')
|
testImplementation ('org.mockito:mockito-inline')
|
||||||
|
implementation('org.apache.avro:avro')
|
||||||
|
implementation(
|
||||||
|
project(path: ':fineract-avro-schemas')
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -20,10 +20,11 @@ package org.apache.fineract.infrastructure.core.config;
|
|||||||
|
|
||||||
import org.apache.fineract.infrastructure.event.external.service.serialization.mapper.support.ExternalIdMapper;
|
import org.apache.fineract.infrastructure.event.external.service.serialization.mapper.support.ExternalIdMapper;
|
||||||
import org.mapstruct.Builder;
|
import org.mapstruct.Builder;
|
||||||
|
import org.mapstruct.InjectionStrategy;
|
||||||
import org.mapstruct.MapperConfig;
|
import org.mapstruct.MapperConfig;
|
||||||
import org.mapstruct.MappingConstants;
|
import org.mapstruct.MappingConstants;
|
||||||
import org.mapstruct.ReportingPolicy;
|
import org.mapstruct.ReportingPolicy;
|
||||||
|
|
||||||
@MapperConfig(componentModel = MappingConstants.ComponentModel.SPRING, unmappedTargetPolicy = ReportingPolicy.ERROR, builder = @Builder(disableBuilder = true), uses = {
|
@MapperConfig(componentModel = MappingConstants.ComponentModel.SPRING, unmappedTargetPolicy = ReportingPolicy.ERROR, builder = @Builder(disableBuilder = true), uses = {
|
||||||
ExternalIdMapper.class })
|
ExternalIdMapper.class }, injectionStrategy = InjectionStrategy.CONSTRUCTOR)
|
||||||
public class MapstructMapperConfig {}
|
public class MapstructMapperConfig {}
|
||||||
|
|||||||
+2
-1
@@ -19,10 +19,11 @@
|
|||||||
package org.apache.fineract.infrastructure.event.external.service.serialization.mapper.support;
|
package org.apache.fineract.infrastructure.event.external.service.serialization.mapper.support;
|
||||||
|
|
||||||
import org.mapstruct.Builder;
|
import org.mapstruct.Builder;
|
||||||
|
import org.mapstruct.InjectionStrategy;
|
||||||
import org.mapstruct.MapperConfig;
|
import org.mapstruct.MapperConfig;
|
||||||
import org.mapstruct.MappingConstants;
|
import org.mapstruct.MappingConstants;
|
||||||
import org.mapstruct.ReportingPolicy;
|
import org.mapstruct.ReportingPolicy;
|
||||||
|
|
||||||
@MapperConfig(componentModel = MappingConstants.ComponentModel.SPRING, unmappedTargetPolicy = ReportingPolicy.ERROR, builder = @Builder(disableBuilder = true), uses = {
|
@MapperConfig(componentModel = MappingConstants.ComponentModel.SPRING, unmappedTargetPolicy = ReportingPolicy.ERROR, builder = @Builder(disableBuilder = true), uses = {
|
||||||
AvroDateTimeMapper.class, AvroMonthDayMapper.class, ExternalIdMapper.class })
|
AvroDateTimeMapper.class, AvroMonthDayMapper.class, ExternalIdMapper.class }, injectionStrategy = InjectionStrategy.CONSTRUCTOR)
|
||||||
public class AvroMapperConfig {}
|
public class AvroMapperConfig {}
|
||||||
|
|||||||
+14
-5
@@ -26,6 +26,8 @@ import lombok.RequiredArgsConstructor;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.fineract.cob.loan.LoanCOBBusinessStep;
|
import org.apache.fineract.cob.loan.LoanCOBBusinessStep;
|
||||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
|
import org.apache.fineract.infrastructure.event.business.domain.loan.LoanAccountSnapshotBusinessEvent;
|
||||||
|
import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService;
|
||||||
import org.apache.fineract.investor.config.InvestorModuleIsEnabledCondition;
|
import org.apache.fineract.investor.config.InvestorModuleIsEnabledCondition;
|
||||||
import org.apache.fineract.investor.data.ExternalTransferStatus;
|
import org.apache.fineract.investor.data.ExternalTransferStatus;
|
||||||
import org.apache.fineract.investor.data.ExternalTransferSubStatus;
|
import org.apache.fineract.investor.data.ExternalTransferSubStatus;
|
||||||
@@ -34,6 +36,7 @@ import org.apache.fineract.investor.domain.ExternalAssetOwnerTransferDetails;
|
|||||||
import org.apache.fineract.investor.domain.ExternalAssetOwnerTransferLoanMapping;
|
import org.apache.fineract.investor.domain.ExternalAssetOwnerTransferLoanMapping;
|
||||||
import org.apache.fineract.investor.domain.ExternalAssetOwnerTransferLoanMappingRepository;
|
import org.apache.fineract.investor.domain.ExternalAssetOwnerTransferLoanMappingRepository;
|
||||||
import org.apache.fineract.investor.domain.ExternalAssetOwnerTransferRepository;
|
import org.apache.fineract.investor.domain.ExternalAssetOwnerTransferRepository;
|
||||||
|
import org.apache.fineract.investor.domain.LoanOwnershipTransferBusinessEvent;
|
||||||
import org.apache.fineract.investor.service.AccountingService;
|
import org.apache.fineract.investor.service.AccountingService;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||||
import org.springframework.context.annotation.Conditional;
|
import org.springframework.context.annotation.Conditional;
|
||||||
@@ -50,6 +53,7 @@ public class LoanAccountOwnerTransferBusinessStep implements LoanCOBBusinessStep
|
|||||||
private final ExternalAssetOwnerTransferRepository externalAssetOwnerTransferRepository;
|
private final ExternalAssetOwnerTransferRepository externalAssetOwnerTransferRepository;
|
||||||
private final ExternalAssetOwnerTransferLoanMappingRepository externalAssetOwnerTransferLoanMappingRepository;
|
private final ExternalAssetOwnerTransferLoanMappingRepository externalAssetOwnerTransferLoanMappingRepository;
|
||||||
private final AccountingService accountingService;
|
private final AccountingService accountingService;
|
||||||
|
private final BusinessEventNotifierService businessEventNotifierService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Loan execute(Loan loan) {
|
public Loan execute(Loan loan) {
|
||||||
@@ -73,7 +77,7 @@ public class LoanAccountOwnerTransferBusinessStep implements LoanCOBBusinessStep
|
|||||||
throw new IllegalStateException(String.format("Illegal transfer found. Expected %s and %s, found: %s and %s",
|
throw new IllegalStateException(String.format("Illegal transfer found. Expected %s and %s, found: %s and %s",
|
||||||
ExternalTransferStatus.PENDING, ExternalTransferStatus.BUYBACK, firstTransferStatus, secondTransferStatus));
|
ExternalTransferStatus.PENDING, ExternalTransferStatus.BUYBACK, firstTransferStatus, secondTransferStatus));
|
||||||
}
|
}
|
||||||
handleSameDaySaleAndBuyback(settlementDate, transferDataList);
|
handleSameDaySaleAndBuyback(settlementDate, transferDataList, loan);
|
||||||
} else if (size == 1) {
|
} else if (size == 1) {
|
||||||
ExternalAssetOwnerTransfer transfer = transferDataList.get(0);
|
ExternalAssetOwnerTransfer transfer = transferDataList.get(0);
|
||||||
if (ExternalTransferStatus.PENDING.equals(transfer.getStatus())) {
|
if (ExternalTransferStatus.PENDING.equals(transfer.getStatus())) {
|
||||||
@@ -89,7 +93,8 @@ public class LoanAccountOwnerTransferBusinessStep implements LoanCOBBusinessStep
|
|||||||
|
|
||||||
private void handleSale(final Loan loan, final LocalDate settlementDate, final ExternalAssetOwnerTransfer externalAssetOwnerTransfer) {
|
private void handleSale(final Loan loan, final LocalDate settlementDate, final ExternalAssetOwnerTransfer externalAssetOwnerTransfer) {
|
||||||
ExternalAssetOwnerTransfer newExternalAssetOwnerTransfer = sellAsset(loan, settlementDate, externalAssetOwnerTransfer);
|
ExternalAssetOwnerTransfer newExternalAssetOwnerTransfer = sellAsset(loan, settlementDate, externalAssetOwnerTransfer);
|
||||||
// TODO: trigger asset loan transfer executed event
|
businessEventNotifierService.notifyPostBusinessEvent(new LoanOwnershipTransferBusinessEvent(newExternalAssetOwnerTransfer, loan));
|
||||||
|
businessEventNotifierService.notifyPostBusinessEvent(new LoanAccountSnapshotBusinessEvent(loan));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleBuyback(final Loan loan, final LocalDate settlementDate,
|
private void handleBuyback(final Loan loan, final LocalDate settlementDate,
|
||||||
@@ -102,7 +107,8 @@ public class LoanAccountOwnerTransferBusinessStep implements LoanCOBBusinessStep
|
|||||||
.orElseThrow();
|
.orElseThrow();
|
||||||
ExternalAssetOwnerTransfer newExternalAssetOwnerTransfer = buybackAsset(loan, settlementDate, buybackExternalAssetOwnerTransfer,
|
ExternalAssetOwnerTransfer newExternalAssetOwnerTransfer = buybackAsset(loan, settlementDate, buybackExternalAssetOwnerTransfer,
|
||||||
activeExternalAssetOwnerTransfer);
|
activeExternalAssetOwnerTransfer);
|
||||||
// TODO: trigger asset loan transfer executed event
|
businessEventNotifierService.notifyPostBusinessEvent(new LoanOwnershipTransferBusinessEvent(newExternalAssetOwnerTransfer, loan));
|
||||||
|
businessEventNotifierService.notifyPostBusinessEvent(new LoanAccountSnapshotBusinessEvent(loan));
|
||||||
}
|
}
|
||||||
|
|
||||||
private ExternalAssetOwnerTransfer buybackAsset(final Loan loan, final LocalDate settlementDate,
|
private ExternalAssetOwnerTransfer buybackAsset(final Loan loan, final LocalDate settlementDate,
|
||||||
@@ -166,10 +172,13 @@ public class LoanAccountOwnerTransferBusinessStep implements LoanCOBBusinessStep
|
|||||||
return loan.getLoanSummary().getTotalOutstanding().compareTo(BigDecimal.ZERO) > 0;
|
return loan.getLoanSummary().getTotalOutstanding().compareTo(BigDecimal.ZERO) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleSameDaySaleAndBuyback(final LocalDate settlementDate, final List<ExternalAssetOwnerTransfer> transferDataList) {
|
private void handleSameDaySaleAndBuyback(final LocalDate settlementDate, final List<ExternalAssetOwnerTransfer> transferDataList,
|
||||||
|
Loan loan) {
|
||||||
ExternalAssetOwnerTransfer cancelledPendingTransfer = cancelTransfer(settlementDate, transferDataList.get(0));
|
ExternalAssetOwnerTransfer cancelledPendingTransfer = cancelTransfer(settlementDate, transferDataList.get(0));
|
||||||
ExternalAssetOwnerTransfer cancelledBuybackTransfer = cancelTransfer(settlementDate, transferDataList.get(1));
|
ExternalAssetOwnerTransfer cancelledBuybackTransfer = cancelTransfer(settlementDate, transferDataList.get(1));
|
||||||
// TODO: trigger asset loan transfer cancel events
|
businessEventNotifierService.notifyPostBusinessEvent(new LoanOwnershipTransferBusinessEvent(cancelledPendingTransfer, loan));
|
||||||
|
businessEventNotifierService.notifyPostBusinessEvent(new LoanOwnershipTransferBusinessEvent(cancelledBuybackTransfer, loan));
|
||||||
|
businessEventNotifierService.notifyPostBusinessEvent(new LoanAccountSnapshotBusinessEvent(loan));
|
||||||
}
|
}
|
||||||
|
|
||||||
private ExternalAssetOwnerTransfer cancelTransfer(final LocalDate settlementDate,
|
private ExternalAssetOwnerTransfer cancelTransfer(final LocalDate settlementDate,
|
||||||
|
|||||||
+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 lombok.Getter;
|
||||||
|
import org.apache.fineract.infrastructure.event.business.domain.AbstractBusinessEvent;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public abstract class InvestorBusinessEvent extends AbstractBusinessEvent<ExternalAssetOwnerTransfer> {
|
||||||
|
|
||||||
|
private final Loan loan;
|
||||||
|
private static final String CATEGORY = "Investor";
|
||||||
|
|
||||||
|
public InvestorBusinessEvent(ExternalAssetOwnerTransfer value, Loan loan) {
|
||||||
|
super(value);
|
||||||
|
this.loan = loan;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getCategory() {
|
||||||
|
return CATEGORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Long getAggregateRootId() {
|
||||||
|
return get().getId();
|
||||||
|
}
|
||||||
|
}
|
||||||
+35
@@ -0,0 +1,35 @@
|
|||||||
|
/**
|
||||||
|
* 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.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||||
|
|
||||||
|
public class LoanOwnershipTransferBusinessEvent extends InvestorBusinessEvent {
|
||||||
|
|
||||||
|
private static final String TYPE = "LoanOwnershipTransferBusinessEvent";
|
||||||
|
|
||||||
|
public LoanOwnershipTransferBusinessEvent(ExternalAssetOwnerTransfer value, Loan loan) {
|
||||||
|
super(value, loan);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getType() {
|
||||||
|
return TYPE;
|
||||||
|
}
|
||||||
|
}
|
||||||
+5
@@ -30,4 +30,9 @@ public class ExternalAssetOwnerTransferNotFoundException extends AbstractPlatfor
|
|||||||
externalTransferStatus),
|
externalTransferStatus),
|
||||||
externalId.getValue(), externalTransferStatus);
|
externalId.getValue(), externalTransferStatus);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ExternalAssetOwnerTransferNotFoundException(Long id) {
|
||||||
|
super("error.msg.external.asset.owner.transfer.id", String.format("External asset owner transfer with id: %s does not found", id),
|
||||||
|
id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
@@ -28,6 +28,8 @@ public interface ExternalAssetOwnersReadService {
|
|||||||
Page<ExternalTransferData> retrieveTransferData(Long loanId, String externalLoanId, String transferExternalId, Integer offset,
|
Page<ExternalTransferData> retrieveTransferData(Long loanId, String externalLoanId, String transferExternalId, Integer offset,
|
||||||
Integer limit);
|
Integer limit);
|
||||||
|
|
||||||
|
ExternalTransferData retrieveTransferData(Long transferExternalId);
|
||||||
|
|
||||||
ExternalTransferData retrieveActiveTransferData(Long loanId, String externalLoanId, String transferExternalId);
|
ExternalTransferData retrieveActiveTransferData(Long loanId, String externalLoanId, String transferExternalId);
|
||||||
|
|
||||||
ExternalOwnerTransferJournalEntryData retrieveJournalEntriesOfTransfer(Long transferId, Integer offset, Integer limit);
|
ExternalOwnerTransferJournalEntryData retrieveJournalEntriesOfTransfer(Long transferId, Integer offset, Integer limit);
|
||||||
|
|||||||
+7
@@ -33,6 +33,7 @@ import org.apache.fineract.investor.domain.ExternalAssetOwnerTransferJournalEntr
|
|||||||
import org.apache.fineract.investor.domain.ExternalAssetOwnerTransferLoanMapping;
|
import org.apache.fineract.investor.domain.ExternalAssetOwnerTransferLoanMapping;
|
||||||
import org.apache.fineract.investor.domain.ExternalAssetOwnerTransferLoanMappingRepository;
|
import org.apache.fineract.investor.domain.ExternalAssetOwnerTransferLoanMappingRepository;
|
||||||
import org.apache.fineract.investor.domain.ExternalAssetOwnerTransferRepository;
|
import org.apache.fineract.investor.domain.ExternalAssetOwnerTransferRepository;
|
||||||
|
import org.apache.fineract.investor.exception.ExternalAssetOwnerTransferNotFoundException;
|
||||||
import org.springframework.data.domain.Page;
|
import org.springframework.data.domain.Page;
|
||||||
import org.springframework.data.domain.PageRequest;
|
import org.springframework.data.domain.PageRequest;
|
||||||
import org.springframework.data.domain.Sort;
|
import org.springframework.data.domain.Sort;
|
||||||
@@ -122,4 +123,10 @@ public class ExternalAssetOwnersReadServiceImpl implements ExternalAssetOwnersRe
|
|||||||
return PageRequest.of(offset, limit, Sort.by("id"));
|
return PageRequest.of(offset, limit, Sort.by("id"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ExternalTransferData retrieveTransferData(Long externalTransferId) {
|
||||||
|
return externalAssetOwnerTransferRepository.findById(externalTransferId).map(mapper::mapTransfer)
|
||||||
|
.orElseThrow(() -> new ExternalAssetOwnerTransferNotFoundException(externalTransferId));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+145
@@ -0,0 +1,145 @@
|
|||||||
|
/**
|
||||||
|
* 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.serialization.serializer.investor;
|
||||||
|
|
||||||
|
import static org.apache.fineract.infrastructure.core.service.DateUtils.DEFAULT_DATE_FORMATTER;
|
||||||
|
import static org.apache.fineract.investor.data.ExternalTransferStatus.ACTIVE;
|
||||||
|
import static org.apache.fineract.investor.data.ExternalTransferStatus.BUYBACK;
|
||||||
|
import static org.apache.fineract.investor.data.ExternalTransferStatus.CANCELLED;
|
||||||
|
import static org.apache.fineract.investor.data.ExternalTransferStatus.DECLINED;
|
||||||
|
import static org.apache.fineract.investor.data.ExternalTransferSubStatus.BALANCE_NEGATIVE;
|
||||||
|
import static org.apache.fineract.investor.data.ExternalTransferSubStatus.BALANCE_ZERO;
|
||||||
|
import static org.apache.fineract.investor.data.ExternalTransferSubStatus.SAMEDAY_TRANSFERS;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.apache.avro.generic.GenericContainer;
|
||||||
|
import org.apache.fineract.avro.generator.ByteBufferSerializable;
|
||||||
|
import org.apache.fineract.avro.generic.v1.CurrencyDataV1;
|
||||||
|
import org.apache.fineract.avro.loan.v1.LoanOwnershipTransferDataV1;
|
||||||
|
import org.apache.fineract.avro.loan.v1.UnpaidChargeDataV1;
|
||||||
|
import org.apache.fineract.infrastructure.event.business.domain.BusinessEvent;
|
||||||
|
import org.apache.fineract.infrastructure.event.external.service.serialization.serializer.BusinessEventSerializer;
|
||||||
|
import org.apache.fineract.investor.data.ExternalTransferData;
|
||||||
|
import org.apache.fineract.investor.data.ExternalTransferStatus;
|
||||||
|
import org.apache.fineract.investor.domain.ExternalAssetOwnerTransfer;
|
||||||
|
import org.apache.fineract.investor.domain.InvestorBusinessEvent;
|
||||||
|
import org.apache.fineract.investor.service.ExternalAssetOwnersReadService;
|
||||||
|
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class InvestorBusinessEventSerializer implements BusinessEventSerializer {
|
||||||
|
|
||||||
|
private final ExternalAssetOwnersReadService externalAssetOwnersReadService;
|
||||||
|
|
||||||
|
private static CurrencyDataV1 getCurrencyFromEvent(InvestorBusinessEvent event) {
|
||||||
|
MonetaryCurrency loanCurrency = event.getLoan().getCurrency();
|
||||||
|
CurrencyDataV1 currency = CurrencyDataV1.newBuilder().setCode(loanCurrency.getCode())
|
||||||
|
.setDecimalPlaces(loanCurrency.getDigitsAfterDecimal()).setInMultiplesOf(loanCurrency.getCurrencyInMultiplesOf()).build();
|
||||||
|
return currency;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> boolean canSerialize(BusinessEvent<T> event) {
|
||||||
|
return event instanceof InvestorBusinessEvent;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<? extends GenericContainer> getSupportedSchema() {
|
||||||
|
return LoanOwnershipTransferDataV1.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> ByteBufferSerializable toAvroDTO(BusinessEvent<T> rawEvent) {
|
||||||
|
InvestorBusinessEvent event = (InvestorBusinessEvent) rawEvent;
|
||||||
|
ExternalTransferData transferData = externalAssetOwnersReadService.retrieveTransferData(event.get().getId());
|
||||||
|
|
||||||
|
LoanOwnershipTransferDataV1.Builder builder = LoanOwnershipTransferDataV1.newBuilder().setLoanId(transferData.getLoan().getLoanId())
|
||||||
|
.setLoanExternalId(transferData.getLoan().getExternalId()).setTransferExternalId(transferData.getTransferExternalId())
|
||||||
|
.setAssetOwnerExternalId(transferData.getOwner().getExternalId())
|
||||||
|
.setPurchasePriceRatio(transferData.getPurchasePriceRatio()).setCurrency(getCurrencyFromEvent(event))
|
||||||
|
.setSettlementDate(transferData.getSettlementDate().format(DEFAULT_DATE_FORMATTER))
|
||||||
|
.setSubmittedDate(transferData.getSettlementDate().format(DEFAULT_DATE_FORMATTER))
|
||||||
|
.setType(transferData.getStatus() == BUYBACK ? "BUYBACK" : "SALE").setTransferStatus(getStatus(event.get()))
|
||||||
|
.setTransferStatusReason(getTransferStatusReason(event.get()).orElse(null));
|
||||||
|
|
||||||
|
if (transferData.getDetails() != null) {
|
||||||
|
builder.setTotalOutstandingBalanceAmount(transferData.getDetails().getTotalOutstanding())
|
||||||
|
.setOutstandingPrincipalPortion(transferData.getDetails().getTotalPrincipalOutstanding())
|
||||||
|
.setOutstandingInterestPortion(transferData.getDetails().getTotalInterestOutstanding())
|
||||||
|
.setOutstandingFeePortion(transferData.getDetails().getTotalFeeChargesOutstanding())
|
||||||
|
.setOutstandingPenaltyPortion(transferData.getDetails().getTotalPenaltyChargesOutstanding())
|
||||||
|
.setUnpaidChargeData(getUnpaidChargeData(event)).setOverPaymentPortion(transferData.getDetails().getTotalOverpaid());
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<UnpaidChargeDataV1> getUnpaidChargeData(InvestorBusinessEvent event) {
|
||||||
|
java.util.Map<Long, UnpaidChargeDataV1> map = new HashMap<>();
|
||||||
|
event.getLoan().getLoanCharges().forEach(loanCharge -> addToMap(map, loanCharge));
|
||||||
|
return map.values().stream().toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addToMap(Map<Long, UnpaidChargeDataV1> map, LoanCharge loanCharge) {
|
||||||
|
if (loanCharge.amountOutstanding().compareTo(BigDecimal.ZERO) > 0) {
|
||||||
|
UnpaidChargeDataV1 toAdd = new UnpaidChargeDataV1(loanCharge.getCharge().getId(), loanCharge.name(),
|
||||||
|
loanCharge.amountOutstanding());
|
||||||
|
UnpaidChargeDataV1 unpaidChargeDataV1 = map.get(loanCharge.getCharge().getId());
|
||||||
|
if (unpaidChargeDataV1 == null) {
|
||||||
|
map.put(toAdd.getChargeId(), toAdd);
|
||||||
|
} else {
|
||||||
|
unpaidChargeDataV1.setOutstandingAmount(unpaidChargeDataV1.getOutstandingAmount().add(toAdd.getOutstandingAmount()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getStatus(ExternalAssetOwnerTransfer externalAssetOwnerTransfer) {
|
||||||
|
ExternalTransferStatus status = externalAssetOwnerTransfer.getStatus();
|
||||||
|
if (ACTIVE.equals(status) || BUYBACK.equals(status)) {
|
||||||
|
return "EXECUTED";
|
||||||
|
} else if (DECLINED.equals(status)) {
|
||||||
|
return "DECLINED";
|
||||||
|
} else if (CANCELLED.equals(status)) {
|
||||||
|
return "CANCELLED";
|
||||||
|
} else {
|
||||||
|
return "UNKNOWN";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Optional<String> getTransferStatusReason(ExternalAssetOwnerTransfer externalAssetOwnerTransfer) {
|
||||||
|
ExternalTransferStatus status = externalAssetOwnerTransfer.getStatus();
|
||||||
|
if (DECLINED.equals(status) && BALANCE_ZERO.equals(externalAssetOwnerTransfer.getSubStatus())) {
|
||||||
|
return Optional.of("BALANCE ZERO");
|
||||||
|
} else if (DECLINED.equals(status) && BALANCE_NEGATIVE.equals(externalAssetOwnerTransfer.getSubStatus())) {
|
||||||
|
return Optional.of("BALANCE NEGATIV");
|
||||||
|
} else if (CANCELLED.equals(status) && SAMEDAY_TRANSFERS.equals(externalAssetOwnerTransfer.getSubStatus())) {
|
||||||
|
return Optional.of("SAMEDAY TRANSFER");
|
||||||
|
} else {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
@@ -30,4 +30,5 @@
|
|||||||
<include relativeToChangelogFile="true" file="parts/0006_asset_schemas.xml"/>
|
<include relativeToChangelogFile="true" file="parts/0006_asset_schemas.xml"/>
|
||||||
<include relativeToChangelogFile="true" file="parts/0007_add_external_asset_owner_transfer_details.xml"/>
|
<include relativeToChangelogFile="true" file="parts/0007_add_external_asset_owner_transfer_details.xml"/>
|
||||||
<include relativeToChangelogFile="true" file="parts/0008_add_mappings.xml"/>
|
<include relativeToChangelogFile="true" file="parts/0008_add_mappings.xml"/>
|
||||||
|
<include relativeToChangelogFile="true" file="parts/0009_add_loan_ownership_transfer_events.xml"/>
|
||||||
</databaseChangeLog>
|
</databaseChangeLog>
|
||||||
|
|||||||
+37
@@ -0,0 +1,37 @@
|
|||||||
|
<?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">
|
||||||
|
<insert tableName="m_external_event_configuration">
|
||||||
|
<column name="type" value="LoanOwnershipTransferBusinessEvent"/>
|
||||||
|
<column name="enabled" valueBoolean="false"/>
|
||||||
|
</insert>
|
||||||
|
<insert tableName="m_external_event_configuration">
|
||||||
|
<column name="type" value="LoanAccountSnapshotBusinessEvent"/>
|
||||||
|
<column name="enabled" valueBoolean="false"/>
|
||||||
|
</insert>
|
||||||
|
</changeSet>
|
||||||
|
|
||||||
|
</databaseChangeLog>
|
||||||
+66
-1
@@ -21,10 +21,12 @@ package org.apache.fineract.investor.cob.loan;
|
|||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.ArgumentMatchers.eq;
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
import static org.mockito.Mockito.times;
|
import static org.mockito.Mockito.times;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.verifyNoInteractions;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
@@ -38,15 +40,20 @@ import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
|
|||||||
import org.apache.fineract.infrastructure.core.domain.ActionContext;
|
import org.apache.fineract.infrastructure.core.domain.ActionContext;
|
||||||
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
|
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
|
||||||
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
|
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
|
||||||
|
import org.apache.fineract.infrastructure.event.business.domain.BusinessEvent;
|
||||||
|
import org.apache.fineract.infrastructure.event.business.domain.loan.LoanAccountSnapshotBusinessEvent;
|
||||||
|
import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService;
|
||||||
import org.apache.fineract.investor.data.ExternalTransferStatus;
|
import org.apache.fineract.investor.data.ExternalTransferStatus;
|
||||||
import org.apache.fineract.investor.data.ExternalTransferSubStatus;
|
import org.apache.fineract.investor.data.ExternalTransferSubStatus;
|
||||||
import org.apache.fineract.investor.domain.ExternalAssetOwnerTransfer;
|
import org.apache.fineract.investor.domain.ExternalAssetOwnerTransfer;
|
||||||
import org.apache.fineract.investor.domain.ExternalAssetOwnerTransferLoanMapping;
|
import org.apache.fineract.investor.domain.ExternalAssetOwnerTransferLoanMapping;
|
||||||
import org.apache.fineract.investor.domain.ExternalAssetOwnerTransferLoanMappingRepository;
|
import org.apache.fineract.investor.domain.ExternalAssetOwnerTransferLoanMappingRepository;
|
||||||
import org.apache.fineract.investor.domain.ExternalAssetOwnerTransferRepository;
|
import org.apache.fineract.investor.domain.ExternalAssetOwnerTransferRepository;
|
||||||
|
import org.apache.fineract.investor.domain.LoanOwnershipTransferBusinessEvent;
|
||||||
import org.apache.fineract.investor.service.AccountingService;
|
import org.apache.fineract.investor.service.AccountingService;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanSummary;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanSummary;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
@@ -66,6 +73,10 @@ public class LoanAccountOwnerTransferBusinessStepTest {
|
|||||||
private ExternalAssetOwnerTransferRepository externalAssetOwnerTransferRepository;
|
private ExternalAssetOwnerTransferRepository externalAssetOwnerTransferRepository;
|
||||||
@Mock
|
@Mock
|
||||||
private ExternalAssetOwnerTransferLoanMappingRepository externalAssetOwnerTransferLoanMappingRepository;
|
private ExternalAssetOwnerTransferLoanMappingRepository externalAssetOwnerTransferLoanMappingRepository;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private BusinessEventNotifierService businessEventNotifierService;
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
private AccountingService accountingService;
|
private AccountingService accountingService;
|
||||||
private LoanAccountOwnerTransferBusinessStep underTest;
|
private LoanAccountOwnerTransferBusinessStep underTest;
|
||||||
@@ -76,7 +87,7 @@ public class LoanAccountOwnerTransferBusinessStepTest {
|
|||||||
ThreadLocalContextUtil.setActionContext(ActionContext.DEFAULT);
|
ThreadLocalContextUtil.setActionContext(ActionContext.DEFAULT);
|
||||||
ThreadLocalContextUtil.setBusinessDates(new HashMap<>(Map.of(BusinessDateType.BUSINESS_DATE, actualDate)));
|
ThreadLocalContextUtil.setBusinessDates(new HashMap<>(Map.of(BusinessDateType.BUSINESS_DATE, actualDate)));
|
||||||
underTest = new LoanAccountOwnerTransferBusinessStep(externalAssetOwnerTransferRepository,
|
underTest = new LoanAccountOwnerTransferBusinessStep(externalAssetOwnerTransferRepository,
|
||||||
externalAssetOwnerTransferLoanMappingRepository, accountingService);
|
externalAssetOwnerTransferLoanMappingRepository, accountingService, businessEventNotifierService);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -89,6 +100,7 @@ public class LoanAccountOwnerTransferBusinessStepTest {
|
|||||||
final Loan processedLoan = underTest.execute(loanForProcessing);
|
final Loan processedLoan = underTest.execute(loanForProcessing);
|
||||||
// then
|
// then
|
||||||
verify(externalAssetOwnerTransferRepository, times(1)).findAll(any(Specification.class), eq(Sort.by(Sort.Direction.ASC, "id")));
|
verify(externalAssetOwnerTransferRepository, times(1)).findAll(any(Specification.class), eq(Sort.by(Sort.Direction.ASC, "id")));
|
||||||
|
verifyNoInteractions(businessEventNotifierService);
|
||||||
assertEquals(processedLoan, loanForProcessing);
|
assertEquals(processedLoan, loanForProcessing);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,6 +121,7 @@ public class LoanAccountOwnerTransferBusinessStepTest {
|
|||||||
// then
|
// then
|
||||||
assertEquals("Illegal transfer found. Expected PENDING and BUYBACK, found: PENDING and ACTIVE", exception.getMessage());
|
assertEquals("Illegal transfer found. Expected PENDING and BUYBACK, found: PENDING and ACTIVE", exception.getMessage());
|
||||||
verify(externalAssetOwnerTransferRepository, times(1)).findAll(any(Specification.class), eq(Sort.by(Sort.Direction.ASC, "id")));
|
verify(externalAssetOwnerTransferRepository, times(1)).findAll(any(Specification.class), eq(Sort.by(Sort.Direction.ASC, "id")));
|
||||||
|
verifyNoInteractions(businessEventNotifierService);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -118,6 +131,15 @@ public class LoanAccountOwnerTransferBusinessStepTest {
|
|||||||
when(loanForProcessing.getId()).thenReturn(1L);
|
when(loanForProcessing.getId()).thenReturn(1L);
|
||||||
ExternalAssetOwnerTransfer firstResponseItem = Mockito.mock(ExternalAssetOwnerTransfer.class);
|
ExternalAssetOwnerTransfer firstResponseItem = Mockito.mock(ExternalAssetOwnerTransfer.class);
|
||||||
ExternalAssetOwnerTransfer secondResponseItem = Mockito.mock(ExternalAssetOwnerTransfer.class);
|
ExternalAssetOwnerTransfer secondResponseItem = Mockito.mock(ExternalAssetOwnerTransfer.class);
|
||||||
|
|
||||||
|
ExternalAssetOwnerTransfer firstSaveResult = Mockito.mock(ExternalAssetOwnerTransfer.class);
|
||||||
|
ExternalAssetOwnerTransfer secondSaveResult = Mockito.mock(ExternalAssetOwnerTransfer.class);
|
||||||
|
ExternalAssetOwnerTransfer thirdSaveResult = Mockito.mock(ExternalAssetOwnerTransfer.class);
|
||||||
|
ExternalAssetOwnerTransfer fourthSaveResult = Mockito.mock(ExternalAssetOwnerTransfer.class);
|
||||||
|
|
||||||
|
when(externalAssetOwnerTransferRepository.save(any(ExternalAssetOwnerTransfer.class))).thenReturn(firstSaveResult)
|
||||||
|
.thenReturn(secondSaveResult).thenReturn(thirdSaveResult).thenReturn(fourthSaveResult);
|
||||||
|
|
||||||
when(firstResponseItem.getStatus()).thenReturn(ExternalTransferStatus.PENDING);
|
when(firstResponseItem.getStatus()).thenReturn(ExternalTransferStatus.PENDING);
|
||||||
when(secondResponseItem.getStatus()).thenReturn(ExternalTransferStatus.BUYBACK);
|
when(secondResponseItem.getStatus()).thenReturn(ExternalTransferStatus.BUYBACK);
|
||||||
List<ExternalAssetOwnerTransfer> response = List.of(firstResponseItem, secondResponseItem);
|
List<ExternalAssetOwnerTransfer> response = List.of(firstResponseItem, secondResponseItem);
|
||||||
@@ -163,6 +185,11 @@ public class LoanAccountOwnerTransferBusinessStepTest {
|
|||||||
assertEquals(actualDate, externalAssetOwnerTransferArgumentCaptor.getAllValues().get(3).getEffectiveDateTo());
|
assertEquals(actualDate, externalAssetOwnerTransferArgumentCaptor.getAllValues().get(3).getEffectiveDateTo());
|
||||||
|
|
||||||
assertEquals(processedLoan, loanForProcessing);
|
assertEquals(processedLoan, loanForProcessing);
|
||||||
|
|
||||||
|
ArgumentCaptor<BusinessEvent<?>> businessEventArgumentCaptor = verifyBusinessEvents(3);
|
||||||
|
verifyLoanTransferBusinessEvent(businessEventArgumentCaptor, 0, loanForProcessing, secondSaveResult);
|
||||||
|
verifyLoanTransferBusinessEvent(businessEventArgumentCaptor, 1, loanForProcessing, fourthSaveResult);
|
||||||
|
verifyLoanAccountSnapshotBusinessEvent(businessEventArgumentCaptor, 2, loanForProcessing);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -193,6 +220,10 @@ public class LoanAccountOwnerTransferBusinessStepTest {
|
|||||||
verify(externalAssetOwnerTransferLoanMappingRepository, times(1)).deleteByLoanIdAndOwnerTransfer(1L, secondResponseItem);
|
verify(externalAssetOwnerTransferLoanMappingRepository, times(1)).deleteByLoanIdAndOwnerTransfer(1L, secondResponseItem);
|
||||||
|
|
||||||
assertEquals(processedLoan, loanForProcessing);
|
assertEquals(processedLoan, loanForProcessing);
|
||||||
|
|
||||||
|
ArgumentCaptor<BusinessEvent<?>> businessEventArgumentCaptor = verifyBusinessEvents(2);
|
||||||
|
verifyLoanTransferBusinessEvent(businessEventArgumentCaptor, 0, loanForProcessing, firstResponseItem);
|
||||||
|
verifyLoanAccountSnapshotBusinessEvent(businessEventArgumentCaptor, 1, loanForProcessing);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -238,6 +269,10 @@ public class LoanAccountOwnerTransferBusinessStepTest {
|
|||||||
assertEquals(1L, externalAssetOwnerTransferLoanMappingArgumentCaptor.getValue().getLoanId());
|
assertEquals(1L, externalAssetOwnerTransferLoanMappingArgumentCaptor.getValue().getLoanId());
|
||||||
assertEquals(newTransfer, externalAssetOwnerTransferLoanMappingArgumentCaptor.getValue().getOwnerTransfer());
|
assertEquals(newTransfer, externalAssetOwnerTransferLoanMappingArgumentCaptor.getValue().getOwnerTransfer());
|
||||||
assertEquals(processedLoan, loanForProcessing);
|
assertEquals(processedLoan, loanForProcessing);
|
||||||
|
|
||||||
|
ArgumentCaptor<BusinessEvent<?>> businessEventArgumentCaptor = verifyBusinessEvents(2);
|
||||||
|
verifyLoanTransferBusinessEvent(businessEventArgumentCaptor, 0, loanForProcessing, newTransfer);
|
||||||
|
verifyLoanAccountSnapshotBusinessEvent(businessEventArgumentCaptor, 1, loanForProcessing);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -278,6 +313,10 @@ public class LoanAccountOwnerTransferBusinessStepTest {
|
|||||||
assertEquals(actualDate, externalAssetOwnerTransferArgumentCaptor.getAllValues().get(1).getEffectiveDateFrom());
|
assertEquals(actualDate, externalAssetOwnerTransferArgumentCaptor.getAllValues().get(1).getEffectiveDateFrom());
|
||||||
assertEquals(actualDate, externalAssetOwnerTransferArgumentCaptor.getAllValues().get(1).getEffectiveDateTo());
|
assertEquals(actualDate, externalAssetOwnerTransferArgumentCaptor.getAllValues().get(1).getEffectiveDateTo());
|
||||||
assertEquals(processedLoan, loanForProcessing);
|
assertEquals(processedLoan, loanForProcessing);
|
||||||
|
|
||||||
|
ArgumentCaptor<BusinessEvent<?>> businessEventArgumentCaptor = verifyBusinessEvents(2);
|
||||||
|
verifyLoanTransferBusinessEvent(businessEventArgumentCaptor, 0, loanForProcessing, newTransfer);
|
||||||
|
verifyLoanAccountSnapshotBusinessEvent(businessEventArgumentCaptor, 1, loanForProcessing);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -318,6 +357,10 @@ public class LoanAccountOwnerTransferBusinessStepTest {
|
|||||||
assertEquals(actualDate, externalAssetOwnerTransferArgumentCaptor.getAllValues().get(1).getEffectiveDateFrom());
|
assertEquals(actualDate, externalAssetOwnerTransferArgumentCaptor.getAllValues().get(1).getEffectiveDateFrom());
|
||||||
assertEquals(actualDate, externalAssetOwnerTransferArgumentCaptor.getAllValues().get(1).getEffectiveDateTo());
|
assertEquals(actualDate, externalAssetOwnerTransferArgumentCaptor.getAllValues().get(1).getEffectiveDateTo());
|
||||||
assertEquals(processedLoan, loanForProcessing);
|
assertEquals(processedLoan, loanForProcessing);
|
||||||
|
|
||||||
|
ArgumentCaptor<BusinessEvent<?>> businessEventArgumentCaptor = verifyBusinessEvents(2);
|
||||||
|
verifyLoanTransferBusinessEvent(businessEventArgumentCaptor, 0, loanForProcessing, newTransfer);
|
||||||
|
verifyLoanAccountSnapshotBusinessEvent(businessEventArgumentCaptor, 1, loanForProcessing);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -333,4 +376,26 @@ public class LoanAccountOwnerTransferBusinessStepTest {
|
|||||||
assertNotNull(actualEnumName);
|
assertNotNull(actualEnumName);
|
||||||
assertEquals("Execute external asset owner transfer", actualEnumName);
|
assertEquals("Execute external asset owner transfer", actualEnumName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private ArgumentCaptor<BusinessEvent<?>> verifyBusinessEvents(int expectedBusinessEvents) {
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
ArgumentCaptor<BusinessEvent<?>> businessEventArgumentCaptor = ArgumentCaptor.forClass(BusinessEvent.class);
|
||||||
|
verify(businessEventNotifierService, times(expectedBusinessEvents)).notifyPostBusinessEvent(businessEventArgumentCaptor.capture());
|
||||||
|
return businessEventArgumentCaptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void verifyLoanTransferBusinessEvent(ArgumentCaptor<BusinessEvent<?>> businessEventArgumentCaptor, int index, Loan expectedLoan,
|
||||||
|
ExternalAssetOwnerTransfer expectedAssetOwnerTransfer) {
|
||||||
|
assertTrue(businessEventArgumentCaptor.getAllValues().get(index) instanceof LoanOwnershipTransferBusinessEvent);
|
||||||
|
assertEquals(expectedLoan, ((LoanOwnershipTransferBusinessEvent) businessEventArgumentCaptor.getAllValues().get(index)).getLoan());
|
||||||
|
assertEquals(expectedAssetOwnerTransfer,
|
||||||
|
((LoanOwnershipTransferBusinessEvent) businessEventArgumentCaptor.getAllValues().get(index)).get());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void verifyLoanAccountSnapshotBusinessEvent(ArgumentCaptor<BusinessEvent<?>> businessEventArgumentCaptor, int index,
|
||||||
|
Loan expectedLoan) {
|
||||||
|
assertTrue(businessEventArgumentCaptor.getAllValues().get(index) instanceof LoanAccountSnapshotBusinessEvent);
|
||||||
|
assertEquals(expectedLoan, ((LoanAccountSnapshotBusinessEvent) businessEventArgumentCaptor.getAllValues().get(index)).get());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+200
@@ -0,0 +1,200 @@
|
|||||||
|
/**
|
||||||
|
* 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.serialization.serializer.investor;
|
||||||
|
|
||||||
|
import static org.apache.fineract.investor.data.ExternalTransferStatus.ACTIVE;
|
||||||
|
import static org.apache.fineract.investor.data.ExternalTransferStatus.BUYBACK;
|
||||||
|
import static org.apache.fineract.investor.data.ExternalTransferStatus.CANCELLED;
|
||||||
|
import static org.apache.fineract.investor.data.ExternalTransferStatus.DECLINED;
|
||||||
|
import static org.apache.fineract.investor.data.ExternalTransferSubStatus.BALANCE_NEGATIVE;
|
||||||
|
import static org.apache.fineract.investor.data.ExternalTransferSubStatus.BALANCE_ZERO;
|
||||||
|
import static org.apache.fineract.investor.data.ExternalTransferSubStatus.SAMEDAY_TRANSFERS;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import org.apache.fineract.avro.generator.ByteBufferSerializable;
|
||||||
|
import org.apache.fineract.avro.loan.v1.LoanOwnershipTransferDataV1;
|
||||||
|
import org.apache.fineract.avro.loan.v1.UnpaidChargeDataV1;
|
||||||
|
import org.apache.fineract.investor.data.ExternalTransferData;
|
||||||
|
import org.apache.fineract.investor.data.ExternalTransferDataDetails;
|
||||||
|
import org.apache.fineract.investor.data.ExternalTransferLoanData;
|
||||||
|
import org.apache.fineract.investor.data.ExternalTransferOwnerData;
|
||||||
|
import org.apache.fineract.investor.data.ExternalTransferStatus;
|
||||||
|
import org.apache.fineract.investor.data.ExternalTransferSubStatus;
|
||||||
|
import org.apache.fineract.investor.domain.ExternalAssetOwnerTransfer;
|
||||||
|
import org.apache.fineract.investor.domain.LoanOwnershipTransferBusinessEvent;
|
||||||
|
import org.apache.fineract.investor.service.ExternalAssetOwnersReadService;
|
||||||
|
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
||||||
|
import org.apache.fineract.portfolio.charge.domain.Charge;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.mockito.Mockito;
|
||||||
|
|
||||||
|
public class InvestorBusinessEventSerializerTest {
|
||||||
|
|
||||||
|
public static final long LOAN_ID = 222L;
|
||||||
|
public static final String ASSET_OWNER_EXTERNAL_ID = "1ad87015-8b05-49de-9ed8-e9c214fda7eb";
|
||||||
|
public static final String LOAN_EXTERNAL_ID = "29641fe0-0ac6-409a-bb8b-24fdf08d2891";
|
||||||
|
public static final String TRANSFER_EXTERNAL_ID = "ac303982-46a5-4cea-9f71-67b69063a2b7";
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSerializationSellOK() {
|
||||||
|
doTest(ACTIVE, null, "SALE", "EXECUTED", null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSerializationBuybackOK() {
|
||||||
|
doTest(BUYBACK, null, "BUYBACK", "EXECUTED", null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSerializationDeclinedNegativeBalance() {
|
||||||
|
doTest(DECLINED, BALANCE_NEGATIVE, "SALE", "DECLINED", "BALANCE NEGATIV");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSerializationDeclinedBalanceZero() {
|
||||||
|
doTest(DECLINED, BALANCE_ZERO, "SALE", "DECLINED", "BALANCE ZERO");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSerializationCancelledSameDayTransfer() {
|
||||||
|
doTest(CANCELLED, SAMEDAY_TRANSFERS, "SALE", "CANCELLED", "SAMEDAY TRANSFER");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doTest(ExternalTransferStatus status, ExternalTransferSubStatus subStatus, String expectedType, String expectedStatus,
|
||||||
|
String expectedReason) {
|
||||||
|
// given
|
||||||
|
ExternalAssetOwnersReadService mockReadService = Mockito.mock(ExternalAssetOwnersReadService.class);
|
||||||
|
when(mockReadService.retrieveTransferData(123L)).thenReturn(createTransferData(status));
|
||||||
|
Loan loan = Mockito.mock(Loan.class);
|
||||||
|
when(loan.getCurrency()).thenReturn(new MonetaryCurrency("EUR", 2, 1));
|
||||||
|
List<LoanCharge> loanCharges = createMockCharges();
|
||||||
|
when(loan.getLoanCharges()).thenReturn(loanCharges);
|
||||||
|
LoanOwnershipTransferBusinessEvent loanOwnershipTransferBusinessEvent = new LoanOwnershipTransferBusinessEvent(
|
||||||
|
createExternalAssetOwnerTransfer(status, subStatus), loan);
|
||||||
|
|
||||||
|
// when
|
||||||
|
InvestorBusinessEventSerializer serializer = new InvestorBusinessEventSerializer(mockReadService);
|
||||||
|
ByteBufferSerializable byteBufferSerializable = serializer.toAvroDTO(loanOwnershipTransferBusinessEvent);
|
||||||
|
|
||||||
|
// then
|
||||||
|
verifyFields(byteBufferSerializable, expectedType, expectedStatus, expectedReason);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<LoanCharge> createMockCharges() {
|
||||||
|
List<LoanCharge> loanCharges = new ArrayList<>();
|
||||||
|
loanCharges.add(loanCharge(1L, "charge a", new BigDecimal("10.00000")));
|
||||||
|
loanCharges.add(loanCharge(1L, "charge a", new BigDecimal("15.00000")));
|
||||||
|
loanCharges.add(loanCharge(2L, "charge b", BigDecimal.ZERO));
|
||||||
|
loanCharges.add(loanCharge(3L, "charge c", new BigDecimal("12.00000")));
|
||||||
|
return loanCharges;
|
||||||
|
}
|
||||||
|
|
||||||
|
private LoanCharge loanCharge(Long chargeId, String name, BigDecimal amountOutstanding) {
|
||||||
|
LoanCharge loanCharge = mock(LoanCharge.class);
|
||||||
|
Charge charge = mock(Charge.class);
|
||||||
|
when(charge.getId()).thenReturn(chargeId);
|
||||||
|
when(charge.getName()).thenReturn(name);
|
||||||
|
when(loanCharge.name()).thenReturn(name);
|
||||||
|
when(loanCharge.getCharge()).thenReturn(charge);
|
||||||
|
when(loanCharge.amountOutstanding()).thenReturn(amountOutstanding);
|
||||||
|
return loanCharge;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void verifyFields(ByteBufferSerializable byteBufferSerializable, String type, String status, String statusReason) {
|
||||||
|
assertTrue(byteBufferSerializable instanceof LoanOwnershipTransferDataV1);
|
||||||
|
LoanOwnershipTransferDataV1 result = (LoanOwnershipTransferDataV1) byteBufferSerializable;
|
||||||
|
assertEquals(LOAN_ID, result.getLoanId());
|
||||||
|
assertEquals("EUR", result.getCurrency().getCode());
|
||||||
|
assertEquals(2, result.getCurrency().getDecimalPlaces());
|
||||||
|
assertEquals(1, result.getCurrency().getInMultiplesOf());
|
||||||
|
assertEquals("1.0", result.getPurchasePriceRatio());
|
||||||
|
assertEquals(ASSET_OWNER_EXTERNAL_ID, result.getAssetOwnerExternalId());
|
||||||
|
assertEquals(LOAN_EXTERNAL_ID, result.getLoanExternalId());
|
||||||
|
assertEquals(TRANSFER_EXTERNAL_ID, result.getTransferExternalId());
|
||||||
|
assertEquals(LOAN_ID, result.getLoanId());
|
||||||
|
assertEquals(new BigDecimal("1108.00000"), result.getTotalOutstandingBalanceAmount());
|
||||||
|
assertEquals(new BigDecimal("100.00000"), result.getOutstandingInterestPortion());
|
||||||
|
assertEquals(new BigDecimal("1000.00000"), result.getOutstandingPrincipalPortion());
|
||||||
|
assertEquals(new BigDecimal("5.00000"), result.getOutstandingFeePortion());
|
||||||
|
assertEquals(new BigDecimal("3.00000"), result.getOutstandingPenaltyPortion());
|
||||||
|
assertEquals(BigDecimal.ZERO, result.getOverPaymentPortion());
|
||||||
|
assertEquals("2023-06-11", result.getSettlementDate());
|
||||||
|
assertEquals("2023-06-11", result.getSubmittedDate());
|
||||||
|
assertEquals(status, result.getTransferStatus());
|
||||||
|
assertEquals(statusReason, result.getTransferStatusReason());
|
||||||
|
assertEquals(type, result.getType());
|
||||||
|
verifyUnpaidCharges(result.getUnpaidChargeData());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void verifyUnpaidCharges(List<UnpaidChargeDataV1> unpaidChargeData) {
|
||||||
|
assertEquals(2, unpaidChargeData.size());
|
||||||
|
Map<Long, UnpaidChargeDataV1> map = unpaidChargeData.stream()
|
||||||
|
.collect(Collectors.toMap(UnpaidChargeDataV1::getChargeId, Function.identity()));
|
||||||
|
assertEquals("charge a", map.get(1L).getChargeName());
|
||||||
|
assertEquals(new BigDecimal("25.00000"), map.get(1L).getOutstandingAmount());
|
||||||
|
assertEquals("charge c", map.get(3L).getChargeName());
|
||||||
|
assertEquals(new BigDecimal("12.00000"), map.get(3L).getOutstandingAmount());
|
||||||
|
}
|
||||||
|
|
||||||
|
private ExternalAssetOwnerTransfer createExternalAssetOwnerTransfer(ExternalTransferStatus status,
|
||||||
|
ExternalTransferSubStatus subStatus) {
|
||||||
|
ExternalAssetOwnerTransfer mock = Mockito.mock(ExternalAssetOwnerTransfer.class);
|
||||||
|
when(mock.getStatus()).thenReturn(status);
|
||||||
|
when(mock.getSubStatus()).thenReturn(subStatus);
|
||||||
|
when(mock.getId()).thenReturn(123L);
|
||||||
|
return mock;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ExternalTransferData createTransferData(ExternalTransferStatus status) {
|
||||||
|
ExternalTransferDataDetails details = new ExternalTransferDataDetails();
|
||||||
|
details.setDetailsId(444L);
|
||||||
|
details.setTotalOutstanding(new BigDecimal("1108.00000"));
|
||||||
|
details.setTotalInterestOutstanding(new BigDecimal("100.00000"));
|
||||||
|
details.setTotalPrincipalOutstanding(new BigDecimal("1000.00000"));
|
||||||
|
details.setTotalFeeChargesOutstanding(new BigDecimal("5.00000"));
|
||||||
|
details.setTotalPenaltyChargesOutstanding(new BigDecimal("3.00000"));
|
||||||
|
details.setTotalOverpaid(BigDecimal.ZERO);
|
||||||
|
|
||||||
|
ExternalTransferData data = new ExternalTransferData();
|
||||||
|
data.setOwner(new ExternalTransferOwnerData(ASSET_OWNER_EXTERNAL_ID));
|
||||||
|
data.setStatus(status);
|
||||||
|
data.setTransferId(123L);
|
||||||
|
data.setLoan(new ExternalTransferLoanData(LOAN_ID, LOAN_EXTERNAL_ID));
|
||||||
|
data.setEffectiveFrom(LocalDate.of(2023, 6, 10));
|
||||||
|
data.setEffectiveTo(LocalDate.of(9999, 12, 31));
|
||||||
|
data.setSettlementDate(LocalDate.of(2023, 6, 11));
|
||||||
|
data.setPurchasePriceRatio("1.0");
|
||||||
|
data.setTransferExternalId(TRANSFER_EXTERNAL_ID);
|
||||||
|
data.setDetails(details);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+35
@@ -0,0 +1,35 @@
|
|||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.fineract.infrastructure.event.business.domain.loan;
|
||||||
|
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||||
|
|
||||||
|
public class LoanAccountSnapshotBusinessEvent extends LoanBusinessEvent {
|
||||||
|
|
||||||
|
private static final String TYPE = "LoanAccountSnapshotBusinessEvent";
|
||||||
|
|
||||||
|
public LoanAccountSnapshotBusinessEvent(Loan value) {
|
||||||
|
super(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getType() {
|
||||||
|
return TYPE;
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
-2
@@ -96,7 +96,7 @@ public class ExternalEventConfigurationValidationServiceTest {
|
|||||||
"LoanChargeAdjustmentPostBusinessEvent", "LoanChargeAdjustmentPreBusinessEvent", "LoanDelinquencyRangeChangeBusinessEvent",
|
"LoanChargeAdjustmentPostBusinessEvent", "LoanChargeAdjustmentPreBusinessEvent", "LoanDelinquencyRangeChangeBusinessEvent",
|
||||||
"LoanAccountsStayedLockedBusinessEvent", "MockBusinessEvent", "LoanChargeOffPreBusinessEvent",
|
"LoanAccountsStayedLockedBusinessEvent", "MockBusinessEvent", "LoanChargeOffPreBusinessEvent",
|
||||||
"LoanChargeOffPostBusinessEvent", "LoanUndoChargeOffBusinessEvent", "LoanAccrualTransactionCreatedBusinessEvent",
|
"LoanChargeOffPostBusinessEvent", "LoanUndoChargeOffBusinessEvent", "LoanAccrualTransactionCreatedBusinessEvent",
|
||||||
"LoanRescheduledDueAdjustScheduleBusinessEvent");
|
"LoanRescheduledDueAdjustScheduleBusinessEvent", "LoanOwnershipTransferBusinessEvent", "LoanAccountSnapshotBusinessEvent");
|
||||||
|
|
||||||
List<FineractPlatformTenant> tenants = Arrays
|
List<FineractPlatformTenant> tenants = Arrays
|
||||||
.asList(new FineractPlatformTenant(1L, "default", "Default Tenant", "Europe/Budapest", null));
|
.asList(new FineractPlatformTenant(1L, "default", "Default Tenant", "Europe/Budapest", null));
|
||||||
@@ -174,7 +174,7 @@ public class ExternalEventConfigurationValidationServiceTest {
|
|||||||
"LoanChargeAdjustmentPostBusinessEvent", "LoanChargeAdjustmentPreBusinessEvent", "LoanDelinquencyRangeChangeBusinessEvent",
|
"LoanChargeAdjustmentPostBusinessEvent", "LoanChargeAdjustmentPreBusinessEvent", "LoanDelinquencyRangeChangeBusinessEvent",
|
||||||
"LoanAccountsStayedLockedBusinessEvent", "LoanChargeOffPreBusinessEvent", "LoanChargeOffPostBusinessEvent",
|
"LoanAccountsStayedLockedBusinessEvent", "LoanChargeOffPreBusinessEvent", "LoanChargeOffPostBusinessEvent",
|
||||||
"LoanUndoChargeOffBusinessEvent", "LoanAccrualTransactionCreatedBusinessEvent",
|
"LoanUndoChargeOffBusinessEvent", "LoanAccrualTransactionCreatedBusinessEvent",
|
||||||
"LoanRescheduledDueAdjustScheduleBusinessEvent");
|
"LoanRescheduledDueAdjustScheduleBusinessEvent", "LoanOwnershipTransferBusinessEvent", "LoanAccountSnapshotBusinessEvent");
|
||||||
|
|
||||||
List<FineractPlatformTenant> tenants = Arrays
|
List<FineractPlatformTenant> tenants = Arrays
|
||||||
.asList(new FineractPlatformTenant(1L, "default", "Default Tenant", "Europe/Budapest", null));
|
.asList(new FineractPlatformTenant(1L, "default", "Default Tenant", "Europe/Budapest", null));
|
||||||
|
|||||||
+1
-1
@@ -105,7 +105,7 @@ public class LoanAccountDelinquencyRangeEventSerializerTest {
|
|||||||
// given
|
// given
|
||||||
LoanDelinquencyRangeChangeBusinessEventSerializer serializer = new LoanDelinquencyRangeChangeBusinessEventSerializer(
|
LoanDelinquencyRangeChangeBusinessEventSerializer serializer = new LoanDelinquencyRangeChangeBusinessEventSerializer(
|
||||||
loanReadPlatformService, new LoanDelinquencyRangeDataMapperImpl(), loanChargeReadPlatformService,
|
loanReadPlatformService, new LoanDelinquencyRangeDataMapperImpl(), loanChargeReadPlatformService,
|
||||||
delinquencyReadPlatformService, new LoanChargeDataMapperImpl(), new CurrencyDataMapperImpl(), mapper);
|
delinquencyReadPlatformService, new LoanChargeDataMapperImpl(null, null, null), new CurrencyDataMapperImpl(), mapper);
|
||||||
|
|
||||||
Loan loanForProcessing = Mockito.mock(Loan.class);
|
Loan loanForProcessing = Mockito.mock(Loan.class);
|
||||||
LoanAccountData loanAccountData = mock(LoanAccountData.class);
|
LoanAccountData loanAccountData = mock(LoanAccountData.class);
|
||||||
|
|||||||
+10
@@ -470,6 +470,16 @@ public class ExternalEventConfigurationHelper {
|
|||||||
loanRescheduledDueAdjustScheduleBusinessEvent.put("enabled", false);
|
loanRescheduledDueAdjustScheduleBusinessEvent.put("enabled", false);
|
||||||
defaults.add(loanRescheduledDueAdjustScheduleBusinessEvent);
|
defaults.add(loanRescheduledDueAdjustScheduleBusinessEvent);
|
||||||
|
|
||||||
|
Map<String, Object> loanOwnershipTransferBusinessEvent = new HashMap<>();
|
||||||
|
loanOwnershipTransferBusinessEvent.put("type", "LoanOwnershipTransferBusinessEvent");
|
||||||
|
loanOwnershipTransferBusinessEvent.put("enabled", false);
|
||||||
|
defaults.add(loanOwnershipTransferBusinessEvent);
|
||||||
|
|
||||||
|
Map<String, Object> loanAccountSnapshotBusinessEvent = new HashMap<>();
|
||||||
|
loanAccountSnapshotBusinessEvent.put("type", "LoanAccountSnapshotBusinessEvent");
|
||||||
|
loanAccountSnapshotBusinessEvent.put("enabled", false);
|
||||||
|
defaults.add(loanAccountSnapshotBusinessEvent);
|
||||||
|
|
||||||
return defaults;
|
return defaults;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user