diff --git a/fineract-investor/src/main/java/org/apache/fineract/investor/cob/loan/LoanAccountOwnerTransferBusinessStep.java b/fineract-investor/src/main/java/org/apache/fineract/investor/cob/loan/LoanAccountOwnerTransferBusinessStep.java
index 5e5ac6273..ff8a7aeb2 100644
--- a/fineract-investor/src/main/java/org/apache/fineract/investor/cob/loan/LoanAccountOwnerTransferBusinessStep.java
+++ b/fineract-investor/src/main/java/org/apache/fineract/investor/cob/loan/LoanAccountOwnerTransferBusinessStep.java
@@ -21,6 +21,7 @@ package org.apache.fineract.investor.cob.loan;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.List;
+import java.util.Objects;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.fineract.cob.loan.LoanCOBBusinessStep;
@@ -28,6 +29,7 @@ import org.apache.fineract.infrastructure.core.service.DateUtils;
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.ExternalAssetOwnerTransferDetails;
import org.apache.fineract.investor.domain.ExternalAssetOwnerTransferLoanMapping;
import org.apache.fineract.investor.domain.ExternalAssetOwnerTransferLoanMappingRepository;
import org.apache.fineract.investor.domain.ExternalAssetOwnerTransferRepository;
@@ -89,7 +91,7 @@ public class LoanAccountOwnerTransferBusinessStep implements LoanCOBBusinessStep
final ExternalAssetOwnerTransfer buybackExternalAssetOwnerTransfer) {
ExternalAssetOwnerTransfer activeExternalAssetOwnerTransfer = externalAssetOwnerTransferRepository
.findOne((root, query, criteriaBuilder) -> criteriaBuilder.and(criteriaBuilder.equal(root.get("loanId"), loan.getId()),
- criteriaBuilder.equal(root.get("ownerId"), buybackExternalAssetOwnerTransfer.getOwnerId()),
+ criteriaBuilder.equal(root.get("owner"), buybackExternalAssetOwnerTransfer.getOwner()),
criteriaBuilder.equal(root.get("status"), ExternalTransferStatus.ACTIVE),
criteriaBuilder.equal(root.get("effectiveDateTo"), FUTURE_DATE_9999_12_31)))
.orElseThrow();
@@ -102,11 +104,12 @@ public class LoanAccountOwnerTransferBusinessStep implements LoanCOBBusinessStep
ExternalAssetOwnerTransfer buybackExternalAssetOwnerTransfer, ExternalAssetOwnerTransfer activeExternalAssetOwnerTransfer) {
activeExternalAssetOwnerTransfer.setEffectiveDateTo(settlementDate);
buybackExternalAssetOwnerTransfer.setEffectiveDateTo(buybackExternalAssetOwnerTransfer.getEffectiveDateFrom());
+ buybackExternalAssetOwnerTransfer
+ .setExternalAssetOwnerTransferDetails(createAssetOwnerTransferDetails(loan, buybackExternalAssetOwnerTransfer));
externalAssetOwnerTransferRepository.save(activeExternalAssetOwnerTransfer);
buybackExternalAssetOwnerTransfer = externalAssetOwnerTransferRepository.save(buybackExternalAssetOwnerTransfer);
externalAssetOwnerTransferLoanMappingRepository.deleteByLoanIdAndOwnerTransfer(loan.getId(), activeExternalAssetOwnerTransfer);
// TODO: create asset ownership accounting entries
- // TODO: create asset ownership transaction entries
return buybackExternalAssetOwnerTransfer;
}
@@ -116,8 +119,9 @@ public class LoanAccountOwnerTransferBusinessStep implements LoanCOBBusinessStep
if (isTransferable(loan)) {
newExternalAssetOwnerTransfer = createActiveEntry(settlementDate, externalAssetOwnerTransfer);
createActiveMapping(loan.getId(), newExternalAssetOwnerTransfer);
+ newExternalAssetOwnerTransfer
+ .setExternalAssetOwnerTransferDetails(createAssetOwnerTransferDetails(loan, newExternalAssetOwnerTransfer));
// TODO: create asset ownership accounting entries
- // TODO: create asset ownership transaction entries
} else {
ExternalTransferSubStatus subStatus = ExternalTransferSubStatus.BALANCE_ZERO;
if (loan.getTotalOverpaid().compareTo(BigDecimal.ZERO) > 0) {
@@ -129,6 +133,23 @@ public class LoanAccountOwnerTransferBusinessStep implements LoanCOBBusinessStep
return newExternalAssetOwnerTransfer;
}
+ private ExternalAssetOwnerTransferDetails createAssetOwnerTransferDetails(Loan loan,
+ ExternalAssetOwnerTransfer externalAssetOwnerTransfer) {
+ ExternalAssetOwnerTransferDetails details = new ExternalAssetOwnerTransferDetails();
+ details.setExternalAssetOwnerTransfer(externalAssetOwnerTransfer);
+ details.setTotalOutstanding(Objects.requireNonNullElse(loan.getLoanSummary().getTotalOutstanding(), BigDecimal.ZERO));
+ details.setTotalPrincipalOutstanding(
+ Objects.requireNonNullElse(loan.getLoanSummary().getTotalPrincipalOutstanding(), BigDecimal.ZERO));
+ details.setTotalInterestOutstanding(
+ Objects.requireNonNullElse(loan.getLoanSummary().getTotalInterestOutstanding(), BigDecimal.ZERO));
+ details.setTotalFeeChargesOutstanding(
+ Objects.requireNonNullElse(loan.getLoanSummary().getTotalFeeChargesOutstanding(), BigDecimal.ZERO));
+ details.setTotalPenaltyChargesOutstanding(
+ Objects.requireNonNullElse(loan.getLoanSummary().getTotalPenaltyChargesOutstanding(), BigDecimal.ZERO));
+ details.setTotalOverpaid(Objects.requireNonNullElse(loan.getTotalOverpaid(), BigDecimal.ZERO));
+ return details;
+ }
+
private void createActiveMapping(Long loanId, ExternalAssetOwnerTransfer externalAssetOwnerTransfer) {
ExternalAssetOwnerTransferLoanMapping externalAssetOwnerTransferLoanMapping = new ExternalAssetOwnerTransferLoanMapping();
externalAssetOwnerTransferLoanMapping.setLoanId(loanId);
@@ -157,7 +178,6 @@ public class LoanAccountOwnerTransferBusinessStep implements LoanCOBBusinessStep
final ExternalTransferSubStatus subStatus, final LocalDate effectiveDateFrom, final LocalDate effectiveDateTo) {
ExternalAssetOwnerTransfer newExternalAssetOwnerTransfer = new ExternalAssetOwnerTransfer();
newExternalAssetOwnerTransfer.setOwner(externalAssetOwnerTransfer.getOwner());
- newExternalAssetOwnerTransfer.setOwnerId(externalAssetOwnerTransfer.getOwnerId());
newExternalAssetOwnerTransfer.setExternalId(externalAssetOwnerTransfer.getExternalId());
newExternalAssetOwnerTransfer.setStatus(status);
newExternalAssetOwnerTransfer.setSubStatus(subStatus);
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 ca1d1d878..9cbb0a539 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
@@ -27,6 +27,7 @@ public class ExternalTransferData {
private Long transferId;
private ExternalTransferOwnerData owner;
private ExternalTransferLoanMappingData loan;
+ private ExternalTransferDataDetails details;
private String transferExternalId;
private String purchasePriceRatio;
private LocalDate settlementDate;
diff --git a/fineract-investor/src/main/java/org/apache/fineract/investor/data/ExternalTransferDataDetails.java b/fineract-investor/src/main/java/org/apache/fineract/investor/data/ExternalTransferDataDetails.java
new file mode 100644
index 000000000..4dd5d551c
--- /dev/null
+++ b/fineract-investor/src/main/java/org/apache/fineract/investor/data/ExternalTransferDataDetails.java
@@ -0,0 +1,34 @@
+/**
+ * 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.math.BigDecimal;
+import lombok.Data;
+
+@Data
+public class ExternalTransferDataDetails {
+
+ private Long detailsId;
+ private BigDecimal totalOutstanding;
+ private BigDecimal totalPrincipalOutstanding;
+ private BigDecimal totalInterestOutstanding;
+ private BigDecimal totalFeeChargesOutstanding;
+ private BigDecimal totalPenaltyChargesOutstanding;
+ private BigDecimal totalOverpaid;
+}
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 d9735a1d3..ab9f7f671 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
@@ -18,12 +18,14 @@
*/
package org.apache.fineract.investor.domain;
+import jakarta.persistence.CascadeType;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
+import jakarta.persistence.OneToOne;
import jakarta.persistence.Table;
import java.time.LocalDate;
import lombok.Getter;
@@ -41,13 +43,13 @@ import org.apache.fineract.investor.data.ExternalTransferSubStatus;
@Entity
public class ExternalAssetOwnerTransfer extends AbstractAuditableWithUTCDateTimeCustom {
- @Column(name = "owner_id", nullable = false)
- private Long ownerId;
-
@ManyToOne
- @JoinColumn(name = "owner_id", insertable = false, updatable = false, nullable = false)
+ @JoinColumn(name = "owner_id", nullable = false)
private ExternalAssetOwner owner;
+ @OneToOne(mappedBy = "externalAssetOwnerTransfer", cascade = CascadeType.ALL)
+ private ExternalAssetOwnerTransferDetails externalAssetOwnerTransferDetails;
+
@Column(name = "external_id", length = 100, nullable = false)
private ExternalId externalId;
diff --git a/fineract-investor/src/main/java/org/apache/fineract/investor/domain/ExternalAssetOwnerTransferDetails.java b/fineract-investor/src/main/java/org/apache/fineract/investor/domain/ExternalAssetOwnerTransferDetails.java
new file mode 100644
index 000000000..badfa672d
--- /dev/null
+++ b/fineract-investor/src/main/java/org/apache/fineract/investor/domain/ExternalAssetOwnerTransferDetails.java
@@ -0,0 +1,61 @@
+/**
+ * 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.CascadeType;
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.OneToOne;
+import jakarta.persistence.Table;
+import java.math.BigDecimal;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDateTimeCustom;
+
+@Getter
+@Setter
+@Table(name = "m_external_asset_owner_transfer_details")
+@NoArgsConstructor
+@Entity
+public class ExternalAssetOwnerTransferDetails extends AbstractAuditableWithUTCDateTimeCustom {
+
+ @OneToOne(cascade = CascadeType.ALL)
+ @JoinColumn(name = "asset_owner_transfer_id", referencedColumnName = "id")
+ private ExternalAssetOwnerTransfer externalAssetOwnerTransfer;
+
+ @Column(name = "total_outstanding_derived", scale = 6, precision = 19, nullable = false)
+ private BigDecimal totalOutstanding;
+
+ @Column(name = "principal_outstanding_derived", scale = 6, precision = 19, nullable = false)
+ private BigDecimal totalPrincipalOutstanding;
+
+ @Column(name = "interest_outstanding_derived", scale = 6, precision = 19, nullable = false)
+ private BigDecimal totalInterestOutstanding;
+
+ @Column(name = "fee_charges_outstanding_derived", scale = 6, precision = 19, nullable = false)
+ private BigDecimal totalFeeChargesOutstanding;
+
+ @Column(name = "penalty_charges_outstanding_derived", scale = 6, precision = 19, nullable = false)
+ private BigDecimal totalPenaltyChargesOutstanding;
+
+ @Column(name = "total_overpaid_derived", scale = 6, precision = 19, nullable = false)
+ private BigDecimal totalOverpaid;
+}
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
index a29ba4167..094a60459 100644
--- 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
@@ -20,9 +20,11 @@ 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.ExternalTransferDataDetails;
import org.apache.fineract.investor.data.ExternalTransferOwnerData;
import org.apache.fineract.investor.domain.ExternalAssetOwner;
import org.apache.fineract.investor.domain.ExternalAssetOwnerTransfer;
+import org.apache.fineract.investor.domain.ExternalAssetOwnerTransferDetails;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
@@ -39,8 +41,12 @@ public interface ExternalAssetOwnersTransferMapper {
@Mapping(target = "purchasePriceRatio", source = "purchasePriceRatio")
@Mapping(target = "settlementDate", source = "settlementDate")
@Mapping(target = "status", source = "status")
+ @Mapping(target = "details", source = "externalAssetOwnerTransferDetails")
ExternalTransferData mapTransfer(ExternalAssetOwnerTransfer source);
ExternalTransferOwnerData mapOwner(ExternalAssetOwner source);
+ @Mapping(target = "detailsId", source = "id")
+ ExternalTransferDataDetails mapDetails(ExternalAssetOwnerTransferDetails details);
+
}
diff --git a/fineract-investor/src/main/java/org/apache/fineract/investor/service/ExternalAssetOwnersWriteServiceImpl.java b/fineract-investor/src/main/java/org/apache/fineract/investor/service/ExternalAssetOwnersWriteServiceImpl.java
index 25df924a7..4b1920f89 100644
--- a/fineract-investor/src/main/java/org/apache/fineract/investor/service/ExternalAssetOwnersWriteServiceImpl.java
+++ b/fineract-investor/src/main/java/org/apache/fineract/investor/service/ExternalAssetOwnersWriteServiceImpl.java
@@ -144,7 +144,7 @@ public class ExternalAssetOwnersWriteServiceImpl implements ExternalAssetOwnersW
ExternalAssetOwnerTransfer externalAssetOwnerTransfer = new ExternalAssetOwnerTransfer();
externalAssetOwnerTransfer.setExternalId(externalId);
- externalAssetOwnerTransfer.setOwnerId(effectiveTransfer.getOwnerId());
+ externalAssetOwnerTransfer.setOwner(effectiveTransfer.getOwner());
externalAssetOwnerTransfer.setStatus(ExternalTransferStatus.BUYBACK);
externalAssetOwnerTransfer.setLoanId(effectiveTransfer.getLoanId());
externalAssetOwnerTransfer.setExternalLoanId(effectiveTransfer.getExternalLoanId());
@@ -218,7 +218,6 @@ public class ExternalAssetOwnersWriteServiceImpl implements ExternalAssetOwnersW
final JsonElement json = fromApiJsonHelper.parse(apiRequestBodyAsJson);
ExternalAssetOwner owner = getOwner(json);
- externalAssetOwnerTransfer.setOwnerId(owner.getId());
externalAssetOwnerTransfer.setOwner(owner);
externalAssetOwnerTransfer.setExternalId(getTransferExternalIdFromJson(json));
externalAssetOwnerTransfer.setStatus(ExternalTransferStatus.PENDING);
diff --git a/fineract-investor/src/main/resources/db/changelog/tenant/module/investor/module-changelog-master.xml b/fineract-investor/src/main/resources/db/changelog/tenant/module/investor/module-changelog-master.xml
index 6ce35e811..e8df64dc0 100644
--- a/fineract-investor/src/main/resources/db/changelog/tenant/module/investor/module-changelog-master.xml
+++ b/fineract-investor/src/main/resources/db/changelog/tenant/module/investor/module-changelog-master.xml
@@ -28,4 +28,5 @@
+
diff --git a/fineract-investor/src/main/resources/db/changelog/tenant/module/investor/parts/0007_add_external_asset_owner_transfer_details.xml b/fineract-investor/src/main/resources/db/changelog/tenant/module/investor/parts/0007_add_external_asset_owner_transfer_details.xml
new file mode 100644
index 000000000..516b35315
--- /dev/null
+++ b/fineract-investor/src/main/resources/db/changelog/tenant/module/investor/parts/0007_add_external_asset_owner_transfer_details.xml
@@ -0,0 +1,118 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/fineract-investor/src/test/java/org/apache/fineract/investor/cob/loan/LoanAccountOwnerTransferBusinessStepTest.java b/fineract-investor/src/test/java/org/apache/fineract/investor/cob/loan/LoanAccountOwnerTransferBusinessStepTest.java
index 9492e630b..be1aa36d6 100644
--- a/fineract-investor/src/test/java/org/apache/fineract/investor/cob/loan/LoanAccountOwnerTransferBusinessStepTest.java
+++ b/fineract-investor/src/test/java/org/apache/fineract/investor/cob/loan/LoanAccountOwnerTransferBusinessStepTest.java
@@ -167,6 +167,8 @@ public class LoanAccountOwnerTransferBusinessStepTest {
// given
final Loan loanForProcessing = Mockito.mock(Loan.class);
when(loanForProcessing.getId()).thenReturn(1L);
+ LoanSummary loanSummary = Mockito.mock(LoanSummary.class);
+ when(loanForProcessing.getLoanSummary()).thenReturn(loanSummary);
ExternalAssetOwnerTransfer firstResponseItem = Mockito.mock(ExternalAssetOwnerTransfer.class);
ExternalAssetOwnerTransfer secondResponseItem = Mockito.mock(ExternalAssetOwnerTransfer.class);
when(firstResponseItem.getStatus()).thenReturn(ExternalTransferStatus.BUYBACK);
diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java
index 94ba578e0..ee278d5c1 100644
--- a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java
+++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java
@@ -3213,7 +3213,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
}
if (loanTransaction.isRecoveryRepayment()
- && loanTransaction.getAmount(loanCurrency()).getAmount().compareTo(getSummary().getTotalWrittenOff()) > 0) {
+ && loanTransaction.getAmount(loanCurrency()).getAmount().compareTo(getLoanSummary().getTotalWrittenOff()) > 0) {
final String errorMessage = "The transaction amount cannot greater than the remaining written off amount.";
throw new InvalidLoanStateTransitionException("transaction", "cannot.be.greater.than.total.written.off", errorMessage);
}
@@ -3884,13 +3884,13 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
addLoanTransaction(mapEntry.getValue());
}
updateLoanSummaryDerivedFields();
- LoanTransaction loanTransaction = findlatestTransaction();
+ LoanTransaction loanTransaction = getLatestTransaction();
doPostLoanTransactionChecks(loanTransaction.getTransactionDate(), loanLifecycleStateMachine);
}
return changedTransactionDetail;
}
- private LoanTransaction findlatestTransaction() {
+ public LoanTransaction getLatestTransaction() {
LoanTransaction transaction = null;
for (LoanTransaction loanTransaction : this.loanTransactions) {
if (!loanTransaction.isReversed()
@@ -4472,10 +4472,6 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
return this.loanOfficer;
}
- public LoanSummary getSummary() {
- return this.summary;
- }
-
public Set getCollateral() {
return this.collateral;
}
@@ -6511,7 +6507,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
public LoanRepaymentScheduleInstallment fetchLoanForeclosureDetail(final LocalDate closureDate) {
Money[] receivables = retriveIncomeOutstandingTillDate(closureDate);
- Money totalPrincipal = Money.of(getCurrency(), this.getSummary().getTotalPrincipalOutstanding());
+ Money totalPrincipal = Money.of(getCurrency(), this.getLoanSummary().getTotalPrincipalOutstanding());
totalPrincipal = totalPrincipal.minus(receivables[3]);
final Set compoundingDetails = null;
final LocalDate currentDate = DateUtils.getBusinessLocalDate();
diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransaction.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransaction.java
index 3e2393baa..9772541f8 100644
--- a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransaction.java
+++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransaction.java
@@ -249,25 +249,25 @@ public class LoanTransaction extends AbstractAuditableWithUTCDateTimeCustom {
public static LoanTransaction initiateTransfer(final Office office, final Loan loan, final LocalDate transferDate,
final ExternalId externalId) {
return new LoanTransaction(loan, office, LoanTransactionType.INITIATE_TRANSFER.getValue(), transferDate,
- loan.getSummary().getTotalOutstanding(), loan.getSummary().getTotalPrincipalOutstanding(),
- loan.getSummary().getTotalInterestOutstanding(), loan.getSummary().getTotalFeeChargesOutstanding(),
- loan.getSummary().getTotalPenaltyChargesOutstanding(), null, false, null, externalId);
+ loan.getLoanSummary().getTotalOutstanding(), loan.getLoanSummary().getTotalPrincipalOutstanding(),
+ loan.getLoanSummary().getTotalInterestOutstanding(), loan.getLoanSummary().getTotalFeeChargesOutstanding(),
+ loan.getLoanSummary().getTotalPenaltyChargesOutstanding(), null, false, null, externalId);
}
public static LoanTransaction approveTransfer(final Office office, final Loan loan, final LocalDate transferDate,
final ExternalId externalId) {
return new LoanTransaction(loan, office, LoanTransactionType.APPROVE_TRANSFER.getValue(), transferDate,
- loan.getSummary().getTotalOutstanding(), loan.getSummary().getTotalPrincipalOutstanding(),
- loan.getSummary().getTotalInterestOutstanding(), loan.getSummary().getTotalFeeChargesOutstanding(),
- loan.getSummary().getTotalPenaltyChargesOutstanding(), null, false, null, externalId);
+ loan.getLoanSummary().getTotalOutstanding(), loan.getLoanSummary().getTotalPrincipalOutstanding(),
+ loan.getLoanSummary().getTotalInterestOutstanding(), loan.getLoanSummary().getTotalFeeChargesOutstanding(),
+ loan.getLoanSummary().getTotalPenaltyChargesOutstanding(), null, false, null, externalId);
}
public static LoanTransaction withdrawTransfer(final Office office, final Loan loan, final LocalDate transferDate,
final ExternalId externalId) {
return new LoanTransaction(loan, office, LoanTransactionType.WITHDRAW_TRANSFER.getValue(), transferDate,
- loan.getSummary().getTotalOutstanding(), loan.getSummary().getTotalPrincipalOutstanding(),
- loan.getSummary().getTotalInterestOutstanding(), loan.getSummary().getTotalFeeChargesOutstanding(),
- loan.getSummary().getTotalPenaltyChargesOutstanding(), null, false, null, externalId);
+ loan.getLoanSummary().getTotalOutstanding(), loan.getLoanSummary().getTotalPrincipalOutstanding(),
+ loan.getLoanSummary().getTotalInterestOutstanding(), loan.getLoanSummary().getTotalFeeChargesOutstanding(),
+ loan.getLoanSummary().getTotalPenaltyChargesOutstanding(), null, false, null, externalId);
}
public static LoanTransaction refund(final Office office, final Money amount, final PaymentDetail paymentDetail,
diff --git a/fineract-provider/src/main/resources/jpa/persistence.xml b/fineract-provider/src/main/resources/jpa/persistence.xml
index 40eb0b48e..c4119fd3a 100644
--- a/fineract-provider/src/main/resources/jpa/persistence.xml
+++ b/fineract-provider/src/main/resources/jpa/persistence.xml
@@ -71,6 +71,7 @@
org.apache.fineract.investor.domain.ExternalAssetOwner
org.apache.fineract.investor.domain.ExternalAssetOwnerTransfer
org.apache.fineract.investor.domain.ExternalAssetOwnerTransferLoanMapping
+ org.apache.fineract.investor.domain.ExternalAssetOwnerTransferDetails
org.apache.fineract.portfolio.collateral.domain.LoanCollateral
org.apache.fineract.portfolio.collateralmanagement.domain.ClientCollateralManagement
diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/investor/externalassetowner/InitiateExternalAssetOwnerTransferTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/investor/externalassetowner/InitiateExternalAssetOwnerTransferTest.java
index a218ab0da..68b915d4d 100644
--- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/investor/externalassetowner/InitiateExternalAssetOwnerTransferTest.java
+++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/investor/externalassetowner/InitiateExternalAssetOwnerTransferTest.java
@@ -19,6 +19,8 @@
package org.apache.fineract.integrationtests.investor.externalassetowner;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -124,6 +126,13 @@ public class InitiateExternalAssetOwnerTransferTest {
JsonPath.from(loanDetails).get("netDisbursalAmount").toString());
LoanStatusChecker.verifyLoanIsActive(loanStatusHashMap);
+ // Add Charge Penalty
+ Integer penalty = ChargesHelper.createCharges(requestSpec, responseSpec,
+ ChargesHelper.getLoanSpecifiedDueDateJSON(ChargesHelper.CHARGE_CALCULATION_TYPE_FLAT, "10", true));
+ Integer penalty1LoanChargeId = this.loanTransactionHelper.addChargesForLoan(loanID,
+ LoanTransactionHelper.getSpecifiedDueDateChargesForLoanAsJSON(String.valueOf(penalty), "02 March 2020", "10"));
+ assertNotNull(penalty1LoanChargeId);
+
String transferExternalId = UUID.randomUUID().toString();
PostInitiateTransferResponse saleResponse = externalAssetOwnerHelper.initiateTransferByLoanId(loanID.longValue(), "sale",
new PostInitiateTransferRequest().settlementDate("2020-03-02").dateFormat("yyyy-MM-dd").locale("en")
@@ -154,12 +163,14 @@ public class InitiateExternalAssetOwnerTransferTest {
assertEquals(LocalDate.of(2020, 3, 2), externalTransferData.getSettlementDate());
assertEquals(LocalDate.of(2020, 3, 2), externalTransferData.getEffectiveFrom());
assertEquals(LocalDate.of(2020, 3, 2), externalTransferData.getEffectiveTo());
+ assertNull(externalTransferData.getDetails());
externalTransferData = retrieveResponse.getContent().get(1);
assertEquals(transferExternalId, externalTransferData.getTransferExternalId());
assertEquals(ExternalTransferData.StatusEnum.ACTIVE, externalTransferData.getStatus());
assertEquals(LocalDate.of(2020, 3, 2), externalTransferData.getSettlementDate());
assertEquals(LocalDate.of(2020, 3, 3), externalTransferData.getEffectiveFrom());
assertEquals(LocalDate.of(9999, 12, 31), externalTransferData.getEffectiveTo());
+ validateExternalTransferDataDetailsWithPenalty(externalTransferData);
String buybackTransferExternalId = "36efeb06-d835-48a1-99eb-09bd1d348c1e";
PostInitiateTransferResponse buybackResponse = externalAssetOwnerHelper.initiateTransferByLoanId(loanID.longValue(), "buyback",
@@ -177,18 +188,21 @@ public class InitiateExternalAssetOwnerTransferTest {
assertEquals(LocalDate.of(2020, 3, 2), externalTransferData.getSettlementDate());
assertEquals(LocalDate.of(2020, 3, 2), externalTransferData.getEffectiveFrom());
assertEquals(LocalDate.of(2020, 3, 2), externalTransferData.getEffectiveTo());
+ assertNull(externalTransferData.getDetails());
externalTransferData = retrieveResponse.getContent().get(1);
assertEquals(transferExternalId, externalTransferData.getTransferExternalId());
assertEquals(ExternalTransferData.StatusEnum.ACTIVE, externalTransferData.getStatus());
assertEquals(LocalDate.of(2020, 3, 2), externalTransferData.getSettlementDate());
assertEquals(LocalDate.of(2020, 3, 3), externalTransferData.getEffectiveFrom());
assertEquals(LocalDate.of(9999, 12, 31), externalTransferData.getEffectiveTo());
+ validateExternalTransferDataDetailsWithPenalty(externalTransferData);
externalTransferData = retrieveResponse.getContent().get(2);
assertEquals(buybackTransferExternalId, externalTransferData.getTransferExternalId());
assertEquals(ExternalTransferData.StatusEnum.BUYBACK, externalTransferData.getStatus());
assertEquals(LocalDate.of(2020, 3, 3), externalTransferData.getSettlementDate());
assertEquals(LocalDate.of(2020, 3, 3), externalTransferData.getEffectiveFrom());
assertEquals(LocalDate.of(9999, 12, 31), externalTransferData.getEffectiveTo());
+ assertNull(externalTransferData.getDetails());
BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, LocalDate.of(2020, 3, 4));
@@ -202,18 +216,21 @@ public class InitiateExternalAssetOwnerTransferTest {
assertEquals(LocalDate.of(2020, 3, 2), externalTransferData.getSettlementDate());
assertEquals(LocalDate.of(2020, 3, 2), externalTransferData.getEffectiveFrom());
assertEquals(LocalDate.of(2020, 3, 2), externalTransferData.getEffectiveTo());
+ assertNull(externalTransferData.getDetails());
externalTransferData = retrieveResponse.getContent().get(1);
assertEquals(transferExternalId, externalTransferData.getTransferExternalId());
assertEquals(ExternalTransferData.StatusEnum.ACTIVE, externalTransferData.getStatus());
assertEquals(LocalDate.of(2020, 3, 2), externalTransferData.getSettlementDate());
assertEquals(LocalDate.of(2020, 3, 3), externalTransferData.getEffectiveFrom());
assertEquals(LocalDate.of(2020, 3, 3), externalTransferData.getEffectiveTo());
+ validateExternalTransferDataDetailsWithPenalty(externalTransferData);
externalTransferData = retrieveResponse.getContent().get(2);
assertEquals(buybackTransferExternalId, externalTransferData.getTransferExternalId());
assertEquals(ExternalTransferData.StatusEnum.BUYBACK, externalTransferData.getStatus());
assertEquals(LocalDate.of(2020, 3, 3), externalTransferData.getSettlementDate());
assertEquals(LocalDate.of(2020, 3, 3), externalTransferData.getEffectiveFrom());
assertEquals(LocalDate.of(2020, 3, 3), externalTransferData.getEffectiveTo());
+ validateExternalTransferDataDetailsWithPenalty(externalTransferData);
} finally {
requestSpec = new RequestSpecBuilder().setContentType(ContentType.JSON).build();
requestSpec.header("Authorization", "Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey());
@@ -223,6 +240,16 @@ public class InitiateExternalAssetOwnerTransferTest {
}
}
+ private static void validateExternalTransferDataDetailsWithPenalty(ExternalTransferData externalTransferData) {
+ assertNotNull(externalTransferData.getDetails());
+ assertEquals(new BigDecimal("15767.420000"), externalTransferData.getDetails().getTotalOutstanding());
+ assertEquals(new BigDecimal("15000.000000"), externalTransferData.getDetails().getTotalPrincipalOutstanding());
+ assertEquals(new BigDecimal("757.420000"), externalTransferData.getDetails().getTotalInterestOutstanding());
+ assertEquals(new BigDecimal("10.000000"), externalTransferData.getDetails().getTotalPenaltyChargesOutstanding());
+ assertEquals(new BigDecimal("0.000000"), externalTransferData.getDetails().getTotalFeeChargesOutstanding());
+ assertEquals(new BigDecimal("0.000000"), externalTransferData.getDetails().getTotalOverpaid());
+ }
+
@Test
public void saleIsNotAllowedWhenTransferIsAlreadyPending() {
try {
@@ -386,12 +413,14 @@ public class InitiateExternalAssetOwnerTransferTest {
assertEquals(LocalDate.of(2020, 3, 2), externalTransferData.getSettlementDate());
assertEquals(LocalDate.of(2020, 3, 2), externalTransferData.getEffectiveFrom());
assertEquals(LocalDate.of(9999, 12, 31), externalTransferData.getEffectiveTo());
+ assertNull(externalTransferData.getDetails());
externalTransferData = retrieveResponse.getContent().get(1);
assertEquals(transferExternalId, externalTransferData.getTransferExternalId());
assertEquals(ExternalTransferData.StatusEnum.BUYBACK, externalTransferData.getStatus());
assertEquals(LocalDate.of(2020, 3, 2), externalTransferData.getSettlementDate());
assertEquals(LocalDate.of(2020, 3, 2), externalTransferData.getEffectiveFrom());
assertEquals(LocalDate.of(9999, 12, 31), externalTransferData.getEffectiveTo());
+ assertNull(externalTransferData.getDetails());
BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, LocalDate.of(2020, 3, 3));
final String jobName = "Loan COB";
@@ -405,24 +434,28 @@ public class InitiateExternalAssetOwnerTransferTest {
assertEquals(LocalDate.of(2020, 3, 2), externalTransferData.getSettlementDate());
assertEquals(LocalDate.of(2020, 3, 2), externalTransferData.getEffectiveFrom());
assertEquals(LocalDate.of(2020, 3, 2), externalTransferData.getEffectiveTo());
+ assertNull(externalTransferData.getDetails());
externalTransferData = retrieveResponse.getContent().get(1);
assertEquals(transferExternalId, externalTransferData.getTransferExternalId());
assertEquals(ExternalTransferData.StatusEnum.BUYBACK, externalTransferData.getStatus());
assertEquals(LocalDate.of(2020, 3, 2), externalTransferData.getSettlementDate());
assertEquals(LocalDate.of(2020, 3, 2), externalTransferData.getEffectiveFrom());
assertEquals(LocalDate.of(2020, 3, 2), externalTransferData.getEffectiveTo());
+ assertNull(externalTransferData.getDetails());
externalTransferData = retrieveResponse.getContent().get(2);
assertEquals(transferExternalId, externalTransferData.getTransferExternalId());
assertEquals(ExternalTransferData.StatusEnum.CANCELLED, externalTransferData.getStatus());
assertEquals(LocalDate.of(2020, 3, 2), externalTransferData.getSettlementDate());
assertEquals(LocalDate.of(2020, 3, 2), externalTransferData.getEffectiveFrom());
assertEquals(LocalDate.of(2020, 3, 2), externalTransferData.getEffectiveTo());
+ assertNull(externalTransferData.getDetails());
externalTransferData = retrieveResponse.getContent().get(3);
assertEquals(transferExternalId, externalTransferData.getTransferExternalId());
assertEquals(ExternalTransferData.StatusEnum.CANCELLED, externalTransferData.getStatus());
assertEquals(LocalDate.of(2020, 3, 2), externalTransferData.getSettlementDate());
assertEquals(LocalDate.of(2020, 3, 2), externalTransferData.getEffectiveFrom());
assertEquals(LocalDate.of(2020, 3, 2), externalTransferData.getEffectiveTo());
+ assertNull(externalTransferData.getDetails());
} finally {
requestSpec = new RequestSpecBuilder().setContentType(ContentType.JSON).build();
requestSpec.header("Authorization", "Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey());