Feat: Repayment With Post Dated Checks
This commit is contained in:
@@ -106,9 +106,9 @@ import org.apache.fineract.client.services.ReportsApi;
|
||||
import org.apache.fineract.client.services.RolesApi;
|
||||
import org.apache.fineract.client.services.RunReportsApi;
|
||||
import org.apache.fineract.client.services.SavingsAccountApi;
|
||||
import org.apache.fineract.client.services.SavingsAccountTransactionsApi;
|
||||
import org.apache.fineract.client.services.SavingsChargesApi;
|
||||
import org.apache.fineract.client.services.SavingsProductApi;
|
||||
import org.apache.fineract.client.services.SavingsAccountTransactionsApi;
|
||||
import org.apache.fineract.client.services.SchedulerApi;
|
||||
import org.apache.fineract.client.services.ScoreCardApi;
|
||||
import org.apache.fineract.client.services.SearchApiApi;
|
||||
|
||||
+27
@@ -896,6 +896,33 @@ public class CommandWrapperBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommandWrapperBuilder updatePostDatedCheck(final Long id, final Long loanId) {
|
||||
this.actionName = "UPDATE";
|
||||
this.entityName = "REPAYMENT_WITH_POSTDATEDCHECKS";
|
||||
this.entityId = id;
|
||||
this.loanId = loanId;
|
||||
this.href = "/loans/" + loanId + "/repaymentwithpostdatedchecks/" + id;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommandWrapperBuilder bouncedCheck(final Long id, final Long loanId) {
|
||||
this.actionName = "BOUNCE";
|
||||
this.entityName = "REPAYMENT_WITH_POSTDATEDCHECKS";
|
||||
this.entityId = id;
|
||||
this.loanId = loanId;
|
||||
this.href = "/loans/" + loanId + "/repaymentwithpostdatedchecks/" + id;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommandWrapperBuilder deletePostDatedCheck(final Long id, final Long loanId) {
|
||||
this.actionName = "DELETE";
|
||||
this.entityName = "REPAYMENT_WITH_POSTDATEDCHECKS";
|
||||
this.entityId = id;
|
||||
this.loanId = loanId;
|
||||
this.href = "/loans/" + loanId + "/repaymentwithpostdatedchecks/" + id;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommandWrapperBuilder updateLoanApplication(final Long loanId) {
|
||||
this.actionName = "UPDATE";
|
||||
this.entityName = "LOAN";
|
||||
|
||||
+1
@@ -433,6 +433,7 @@ public class LoanImportHandler implements ImportHandler {
|
||||
gsonBuilder.registerTypeAdapter(LocalDate.class, new DateSerializer(dateFormat));
|
||||
JsonObject loanRepaymentJsonob = gsonBuilder.create().toJsonTree(loanRepayments.get(rowIndex)).getAsJsonObject();
|
||||
loanRepaymentJsonob.remove("manuallyReversed");
|
||||
loanRepaymentJsonob.remove("numberOfRepayments");
|
||||
String payload = loanRepaymentJsonob.toString();
|
||||
final CommandWrapper commandRequest = new CommandWrapperBuilder() //
|
||||
.loanRepaymentTransaction(result.getLoanId()) //
|
||||
|
||||
+1
@@ -32,6 +32,7 @@ public interface LoanApiConstants {
|
||||
String principalDisbursedParameterName = "transactionAmount";
|
||||
String chargesParameterName = "charges";
|
||||
String loanIdTobeApproved = "loanId";
|
||||
String postDatedChecks = "postDatedChecks";
|
||||
|
||||
String approvedLoanAmountParameterName = "approvedLoanAmount";
|
||||
String approvedOnDateParameterName = "approvedOnDate";
|
||||
|
||||
+6
@@ -30,6 +30,7 @@ import java.time.LocalDate;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.GET;
|
||||
@@ -54,6 +55,7 @@ import org.apache.fineract.infrastructure.core.serialization.ApiRequestJsonSeria
|
||||
import org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSerializer;
|
||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.LoanRepaymentScheduleInstallmentData;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.LoanTransactionData;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanChargePaidByReadPlatformService;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanReadPlatformService;
|
||||
@@ -132,6 +134,10 @@ public class LoanTransactionsApiResource {
|
||||
transactionData = this.loanReadPlatformService.retrieveNewClosureDetails();
|
||||
} else if (is(commandParam, "disburse")) {
|
||||
transactionData = this.loanReadPlatformService.retrieveDisbursalTemplate(loanId, true);
|
||||
transactionData.setNumberOfRepayments(this.loanReadPlatformService.retrieveNumberOfRepayments(loanId));
|
||||
final List<LoanRepaymentScheduleInstallmentData> loanRepaymentScheduleInstallmentData = this.loanReadPlatformService
|
||||
.getRepaymentDataResponse(loanId);
|
||||
transactionData.setLoanRepaymentScheduleInstallments(loanRepaymentScheduleInstallmentData);
|
||||
} else if (is(commandParam, "disburseToSavings")) {
|
||||
transactionData = this.loanReadPlatformService.retrieveDisbursalTemplate(loanId, false);
|
||||
} else if (is(commandParam, "recoverypayment")) {
|
||||
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* 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.portfolio.loanaccount.data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
|
||||
public final class LoanRepaymentScheduleInstallmentData {
|
||||
|
||||
private Long id;
|
||||
|
||||
private Integer installmentId;
|
||||
|
||||
private LocalDate date;
|
||||
|
||||
private BigDecimal amount;
|
||||
|
||||
private LoanRepaymentScheduleInstallmentData(final Long id, final Integer installmentId, final LocalDate date,
|
||||
final BigDecimal amount) {
|
||||
this.amount = amount;
|
||||
this.date = date;
|
||||
this.installmentId = installmentId;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public static LoanRepaymentScheduleInstallmentData instanceOf(final Long id, final Integer installmentId, final LocalDate date,
|
||||
final BigDecimal amount) {
|
||||
return new LoanRepaymentScheduleInstallmentData(id, installmentId, date, amount);
|
||||
}
|
||||
|
||||
}
|
||||
+12
@@ -21,6 +21,7 @@ package org.apache.fineract.portfolio.loanaccount.data;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import org.apache.fineract.infrastructure.codes.data.CodeValueData;
|
||||
import org.apache.fineract.organisation.monetary.data.CurrencyData;
|
||||
import org.apache.fineract.portfolio.account.data.AccountTransferData;
|
||||
@@ -66,6 +67,8 @@ public class LoanTransactionData {
|
||||
|
||||
private Collection<CodeValueData> writeOffReasonOptions = null;
|
||||
|
||||
private Integer numberOfRepayments = 0;
|
||||
|
||||
// import fields
|
||||
private transient Integer rowIndex;
|
||||
private String dateFormat;
|
||||
@@ -80,6 +83,7 @@ public class LoanTransactionData {
|
||||
private Integer bankNumber;
|
||||
private transient Long accountId;
|
||||
private transient String transactionType;
|
||||
private List<LoanRepaymentScheduleInstallmentData> loanRepaymentScheduleInstallments;
|
||||
|
||||
public static LoanTransactionData importInstance(BigDecimal repaymentAmount, LocalDate lastRepaymentDate, Long repaymentTypeId,
|
||||
Integer rowIndex, String locale, String dateFormat) {
|
||||
@@ -167,6 +171,14 @@ public class LoanTransactionData {
|
||||
this.writeOffReasonOptions = null;
|
||||
}
|
||||
|
||||
public void setNumberOfRepayments(Integer numberOfRepayments) {
|
||||
this.numberOfRepayments = numberOfRepayments;
|
||||
}
|
||||
|
||||
public void setLoanRepaymentScheduleInstallments(final List<LoanRepaymentScheduleInstallmentData> loanRepaymentScheduleInstallments) {
|
||||
this.loanRepaymentScheduleInstallments = loanRepaymentScheduleInstallments;
|
||||
}
|
||||
|
||||
public Long getAccountId() {
|
||||
return accountId;
|
||||
}
|
||||
|
||||
+22
-1
@@ -143,6 +143,7 @@ import org.apache.fineract.portfolio.loanproduct.domain.RecalculationFrequencyTy
|
||||
import org.apache.fineract.portfolio.loanproduct.service.LoanEnumerations;
|
||||
import org.apache.fineract.portfolio.paymentdetail.domain.PaymentDetail;
|
||||
import org.apache.fineract.portfolio.rate.domain.Rate;
|
||||
import org.apache.fineract.portfolio.repaymentwithpostdatedchecks.domain.PostDatedChecks;
|
||||
import org.apache.fineract.useradministration.domain.AppUser;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -322,7 +323,7 @@ public class Loan extends AbstractPersistableCustom {
|
||||
private Set<LoanOfficerAssignmentHistory> loanOfficerHistory;
|
||||
|
||||
@OrderBy(value = "installmentNumber")
|
||||
@OneToMany(cascade = CascadeType.ALL, mappedBy = "loan", orphanRemoval = true, fetch = FetchType.LAZY)
|
||||
@OneToMany(cascade = CascadeType.ALL, mappedBy = "loan", orphanRemoval = true, fetch = FetchType.EAGER)
|
||||
private List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments = new ArrayList<>();
|
||||
|
||||
@OrderBy(value = "dateOf, id")
|
||||
@@ -358,6 +359,9 @@ public class Loan extends AbstractPersistableCustom {
|
||||
@OrderBy(value = "expectedDisbursementDate, id")
|
||||
private List<LoanDisbursementDetails> disbursementDetails = new ArrayList<>();
|
||||
|
||||
@OneToMany(cascade = CascadeType.ALL, mappedBy = "loan", orphanRemoval = true, fetch = FetchType.EAGER)
|
||||
private List<PostDatedChecks> postDatedChecks = new ArrayList<>();
|
||||
|
||||
@OrderBy(value = "termApplicableFrom, id")
|
||||
@OneToMany(cascade = CascadeType.ALL, mappedBy = "loan", orphanRemoval = true, fetch = FetchType.LAZY)
|
||||
private List<LoanTermVariations> loanTermVariations = new ArrayList<>();
|
||||
@@ -528,6 +532,10 @@ public class Loan extends AbstractPersistableCustom {
|
||||
|
||||
}
|
||||
|
||||
public Integer getNumberOfRepayments() {
|
||||
return this.loanRepaymentScheduleDetail.getNumberOfRepayments();
|
||||
}
|
||||
|
||||
private LoanSummary updateSummaryWithTotalFeeChargesDueAtDisbursement(final BigDecimal feeChargesDueAtDisbursement) {
|
||||
if (this.summary == null) {
|
||||
this.summary = LoanSummary.create(feeChargesDueAtDisbursement);
|
||||
@@ -2821,6 +2829,11 @@ public class Loan extends AbstractPersistableCustom {
|
||||
return chargesPayment;
|
||||
}
|
||||
|
||||
public void removePostDatedChecks() {
|
||||
List<PostDatedChecks> postDatedChecks = new ArrayList<>();
|
||||
this.postDatedChecks = postDatedChecks;
|
||||
}
|
||||
|
||||
public Map<String, Object> undoDisbursal(final ScheduleGeneratorDTO scheduleGeneratorDTO, final List<Long> existingTransactionIds,
|
||||
final List<Long> existingReversedTransactionIds, AppUser currentUser) {
|
||||
|
||||
@@ -6267,6 +6280,14 @@ public class Loan extends AbstractPersistableCustom {
|
||||
return amount;
|
||||
}
|
||||
|
||||
public void updatePostDatedChecks(final List<PostDatedChecks> postDatedChecks) {
|
||||
this.postDatedChecks = postDatedChecks;
|
||||
}
|
||||
|
||||
public List<PostDatedChecks> getPostDatedChecks() {
|
||||
return this.postDatedChecks;
|
||||
}
|
||||
|
||||
public void updateWriteOffReason(CodeValue writeOffReason) {
|
||||
this.writeOffReason = writeOffReason;
|
||||
}
|
||||
|
||||
+37
-2
@@ -57,6 +57,7 @@ import org.apache.fineract.portfolio.account.domain.AccountTransferStandingInstr
|
||||
import org.apache.fineract.portfolio.account.domain.AccountTransferTransaction;
|
||||
import org.apache.fineract.portfolio.account.domain.StandingInstructionRepository;
|
||||
import org.apache.fineract.portfolio.account.domain.StandingInstructionStatus;
|
||||
import org.apache.fineract.portfolio.accountdetails.domain.AccountType;
|
||||
import org.apache.fineract.portfolio.client.domain.Client;
|
||||
import org.apache.fineract.portfolio.client.exception.ClientNotActiveException;
|
||||
import org.apache.fineract.portfolio.common.BusinessEventNotificationConstants.BusinessEntity;
|
||||
@@ -74,6 +75,9 @@ import org.apache.fineract.portfolio.loanaccount.service.LoanUtilService;
|
||||
import org.apache.fineract.portfolio.note.domain.Note;
|
||||
import org.apache.fineract.portfolio.note.domain.NoteRepository;
|
||||
import org.apache.fineract.portfolio.paymentdetail.domain.PaymentDetail;
|
||||
import org.apache.fineract.portfolio.repaymentwithpostdatedchecks.data.PostDatedChecksStatus;
|
||||
import org.apache.fineract.portfolio.repaymentwithpostdatedchecks.domain.PostDatedChecks;
|
||||
import org.apache.fineract.portfolio.repaymentwithpostdatedchecks.domain.PostDatedChecksRepository;
|
||||
import org.apache.fineract.useradministration.domain.AppUser;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.dao.DataIntegrityViolationException;
|
||||
@@ -102,6 +106,7 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
|
||||
private final BusinessEventNotifierService businessEventNotifierService;
|
||||
private final LoanUtilService loanUtilService;
|
||||
private final StandingInstructionRepository standingInstructionRepository;
|
||||
private final PostDatedChecksRepository postDatedChecksRepository;
|
||||
private final LoanCollateralManagementRepository loanCollateralManagementRepository;
|
||||
|
||||
@Autowired
|
||||
@@ -116,10 +121,9 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
|
||||
final LoanRepaymentScheduleInstallmentRepository repaymentScheduleInstallmentRepository,
|
||||
final LoanAccrualPlatformService loanAccrualPlatformService, final PlatformSecurityContext context,
|
||||
final BusinessEventNotifierService businessEventNotifierService, final LoanUtilService loanUtilService,
|
||||
final StandingInstructionRepository standingInstructionRepository,
|
||||
final StandingInstructionRepository standingInstructionRepository, final PostDatedChecksRepository postDatedChecksRepository,
|
||||
final LoanCollateralManagementRepository loanCollateralManagementRepository) {
|
||||
this.loanAccountAssembler = loanAccountAssembler;
|
||||
this.loanRepositoryWrapper = loanRepositoryWrapper;
|
||||
this.loanTransactionRepository = loanTransactionRepository;
|
||||
this.noteRepository = noteRepository;
|
||||
this.configurationDomainService = configurationDomainService;
|
||||
@@ -135,7 +139,9 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
|
||||
this.businessEventNotifierService = businessEventNotifierService;
|
||||
this.loanUtilService = loanUtilService;
|
||||
this.standingInstructionRepository = standingInstructionRepository;
|
||||
this.postDatedChecksRepository = postDatedChecksRepository;
|
||||
this.loanCollateralManagementRepository = loanCollateralManagementRepository;
|
||||
this.loanRepositoryWrapper = loanRepositoryWrapper;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@@ -246,6 +252,35 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
|
||||
builderResult.withEntityId(newRepaymentTransaction.getId()).withOfficeId(loan.getOfficeId()).withClientId(loan.getClientId())
|
||||
.withGroupId(loan.getGroupId());
|
||||
|
||||
if (AccountType.fromInt(loan.getLoanType()).isIndividualAccount()) {
|
||||
// Mark Post Dated Check as paid.
|
||||
final Set<LoanTransactionToRepaymentScheduleMapping> loanTransactionToRepaymentScheduleMappings = newRepaymentTransaction
|
||||
.getLoanTransactionToRepaymentScheduleMappings();
|
||||
|
||||
if (loanTransactionToRepaymentScheduleMappings != null) {
|
||||
for (LoanTransactionToRepaymentScheduleMapping loanTransactionToRepaymentScheduleMapping : loanTransactionToRepaymentScheduleMappings) {
|
||||
LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment = loanTransactionToRepaymentScheduleMapping
|
||||
.getLoanRepaymentScheduleInstallment();
|
||||
if (loanRepaymentScheduleInstallment != null) {
|
||||
final boolean isPaid = loanRepaymentScheduleInstallment.isNotFullyPaidOff();
|
||||
PostDatedChecks postDatedChecks = this.postDatedChecksRepository
|
||||
.getPendingPostDatedCheck(loanRepaymentScheduleInstallment);
|
||||
|
||||
if (postDatedChecks != null) {
|
||||
if (!isPaid) {
|
||||
postDatedChecks.setStatus(PostDatedChecksStatus.POST_DATED_CHECKS_PAID);
|
||||
} else {
|
||||
postDatedChecks.setStatus(PostDatedChecksStatus.POST_DATED_CHECKS_PENDING);
|
||||
}
|
||||
this.postDatedChecksRepository.saveAndFlush(postDatedChecks);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return newRepaymentTransaction;
|
||||
}
|
||||
|
||||
|
||||
+12
@@ -39,6 +39,7 @@ import org.apache.fineract.infrastructure.core.domain.AbstractAuditableCustom;
|
||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.apache.fineract.organisation.monetary.domain.Money;
|
||||
import org.apache.fineract.portfolio.repaymentwithpostdatedchecks.domain.PostDatedChecks;
|
||||
|
||||
@Entity
|
||||
@Table(name = "m_loan_repayment_schedule")
|
||||
@@ -137,6 +138,9 @@ public final class LoanRepaymentScheduleInstallment extends AbstractAuditableCus
|
||||
@JoinColumn(name = "loan_repayment_schedule_id", referencedColumnName = "id", nullable = false)
|
||||
private Set<LoanInterestRecalcualtionAdditionalDetails> loanCompoundingDetails = new HashSet<>();
|
||||
|
||||
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER, mappedBy = "loanRepaymentScheduleInstallment")
|
||||
private Set<PostDatedChecks> postDatedChecks;
|
||||
|
||||
LoanRepaymentScheduleInstallment() {
|
||||
this.installmentNumber = null;
|
||||
this.fromDate = null;
|
||||
@@ -212,6 +216,14 @@ public final class LoanRepaymentScheduleInstallment extends AbstractAuditableCus
|
||||
return fromLocalDate;
|
||||
}
|
||||
|
||||
public void setPostDatedChecksToNull() {
|
||||
this.postDatedChecks = null;
|
||||
}
|
||||
|
||||
public Set<PostDatedChecks> getPostDatedCheck() {
|
||||
return this.postDatedChecks;
|
||||
}
|
||||
|
||||
public LocalDate getDueDate() {
|
||||
return LocalDate.ofInstant(this.dueDate.toInstant(), DateUtils.getDateTimeZoneOfTenant());
|
||||
}
|
||||
|
||||
+10
@@ -111,6 +111,16 @@ public class LoanRepositoryWrapper {
|
||||
return this.repository.getMaxClientOrJLGLoanCounter(clientId);
|
||||
}
|
||||
|
||||
public List<LoanRepaymentScheduleInstallment> getLoanRepaymentScheduleInstallments(final Long loanId) {
|
||||
final Loan loan = this.repository.findById(loanId).orElseThrow(() -> new LoanNotFoundException(loanId));
|
||||
final List<LoanRepaymentScheduleInstallment> loanRepaymentScheduleInstallments = loan.getRepaymentScheduleInstallments();
|
||||
return loanRepaymentScheduleInstallments;
|
||||
}
|
||||
|
||||
public Integer getNumberOfRepayments(final Long loanId) {
|
||||
return this.repository.findById(loanId).orElseThrow(() -> new LoanNotFoundException(loanId)).getNumberOfRepayments();
|
||||
}
|
||||
|
||||
public Integer getMaxClientOrJLGLoanProductCounter(@Param("productId") Long productId, @Param("clientId") Long clientId) {
|
||||
return this.repository.getMaxClientOrJLGLoanProductCounter(productId, clientId);
|
||||
}
|
||||
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* 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.portfolio.loanaccount.exception;
|
||||
|
||||
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformResourceNotFoundException;
|
||||
|
||||
public class LoanRepaymentScheduleNotFoundException extends AbstractPlatformResourceNotFoundException {
|
||||
|
||||
public LoanRepaymentScheduleNotFoundException(final Integer id) {
|
||||
super("error.msg.loan.repayment.installment.id.invalid", "Loan repayment with installment identifier " + id + " does not exist",
|
||||
id);
|
||||
}
|
||||
|
||||
public LoanRepaymentScheduleNotFoundException(final Long id) {
|
||||
super("error.msg.loan.repayment.id.invalid", "Loan repayment with identifier " + id + " does not exist", id);
|
||||
}
|
||||
|
||||
public LoanRepaymentScheduleNotFoundException(final Long id, final Integer loan) {
|
||||
super("error.msg.loan.id" + id + ".not.contains.repayment.schedule", "Loan does not have repayment scheduled", loan);
|
||||
}
|
||||
|
||||
}
|
||||
+60
-2
@@ -18,7 +18,9 @@
|
||||
*/
|
||||
package org.apache.fineract.portfolio.loanaccount.serialization;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import java.lang.reflect.Type;
|
||||
import java.math.BigDecimal;
|
||||
@@ -30,18 +32,25 @@ import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.fineract.infrastructure.core.data.ApiParameterError;
|
||||
import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
|
||||
import org.apache.fineract.infrastructure.core.exception.InvalidJsonException;
|
||||
import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
|
||||
import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException;
|
||||
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
|
||||
import org.apache.fineract.portfolio.calendar.domain.Calendar;
|
||||
import org.apache.fineract.portfolio.calendar.domain.CalendarInstance;
|
||||
import org.apache.fineract.portfolio.calendar.exception.NotValidRecurringDateException;
|
||||
import org.apache.fineract.portfolio.calendar.service.CalendarUtils;
|
||||
import org.apache.fineract.portfolio.loanaccount.api.LoanApiConstants;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanDisbursementDetails;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
|
||||
import org.apache.fineract.portfolio.loanaccount.exception.LoanNotFoundException;
|
||||
import org.apache.fineract.portfolio.loanaccount.exception.LoanRepaymentScheduleNotFoundException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@@ -50,12 +59,14 @@ public final class LoanEventApiJsonValidator {
|
||||
|
||||
private final FromJsonHelper fromApiJsonHelper;
|
||||
private final LoanApplicationCommandFromApiJsonHelper fromApiJsonDeserializer;
|
||||
private final LoanRepository loanRepository;
|
||||
|
||||
@Autowired
|
||||
public LoanEventApiJsonValidator(final FromJsonHelper fromApiJsonHelper,
|
||||
final LoanApplicationCommandFromApiJsonHelper fromApiJsonDeserializer) {
|
||||
final LoanApplicationCommandFromApiJsonHelper fromApiJsonDeserializer, final LoanRepository loanRepository) {
|
||||
this.fromApiJsonHelper = fromApiJsonHelper;
|
||||
this.fromApiJsonDeserializer = fromApiJsonDeserializer;
|
||||
this.loanRepository = loanRepository;
|
||||
}
|
||||
|
||||
private void throwExceptionIfValidationWarningsExist(final List<ApiParameterError> dataValidationErrors) {
|
||||
@@ -79,7 +90,8 @@ public final class LoanEventApiJsonValidator {
|
||||
} else {
|
||||
disbursementParameters = new HashSet<>(Arrays.asList("actualDisbursementDate", "externalId", "note", "locale", "dateFormat",
|
||||
"paymentTypeId", "accountNumber", "checkNumber", "routingCode", "receiptNumber", "bankNumber", "adjustRepaymentDate",
|
||||
LoanApiConstants.principalDisbursedParameterName, LoanApiConstants.emiAmountParameterName));
|
||||
LoanApiConstants.principalDisbursedParameterName, LoanApiConstants.emiAmountParameterName,
|
||||
LoanApiConstants.postDatedChecks));
|
||||
}
|
||||
|
||||
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
|
||||
@@ -110,6 +122,52 @@ public final class LoanEventApiJsonValidator {
|
||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
}
|
||||
|
||||
public void validateDisbursementWithPostDatedChecks(final String json, final Long loanId) {
|
||||
final JsonElement jsonElement = this.fromApiJsonHelper.parse(json);
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("loan.disbursement");
|
||||
final Loan loan = this.loanRepository.findById(loanId).orElseThrow(() -> new LoanNotFoundException(loanId));
|
||||
final List<LoanRepaymentScheduleInstallment> loanRepaymentScheduleInstallment = loan.getRepaymentScheduleInstallments();
|
||||
|
||||
JsonObject jsonObject = jsonElement.getAsJsonObject();
|
||||
final Locale locale = this.fromApiJsonHelper.extractLocaleParameter(jsonObject);
|
||||
if (jsonObject.has("postDatedChecks") && jsonObject.get("postDatedChecks").isJsonArray()) {
|
||||
JsonArray postDatedChecks = jsonObject.get("postDatedChecks").getAsJsonArray();
|
||||
for (int i = 0; i < postDatedChecks.size(); i++) {
|
||||
final JsonObject postDatedCheck = postDatedChecks.get(i).getAsJsonObject();
|
||||
|
||||
final String name = this.fromApiJsonHelper.extractStringNamed("name", postDatedCheck);
|
||||
baseDataValidator.reset().parameter("name").value(name).notNull();
|
||||
|
||||
final BigDecimal amount = this.fromApiJsonHelper.extractBigDecimalNamed("amount", postDatedCheck, locale);
|
||||
baseDataValidator.reset().parameter("amount").value(amount).notNull().positiveAmount();
|
||||
|
||||
final Long accountNo = this.fromApiJsonHelper.extractLongNamed("accountNo", postDatedCheck);
|
||||
baseDataValidator.reset().parameter("accountNo").value(accountNo).notNull().positiveAmount();
|
||||
|
||||
final Long checkNo = this.fromApiJsonHelper.extractLongNamed("checkNo", postDatedCheck);
|
||||
baseDataValidator.reset().parameter("checkNo").value(checkNo).notNull().positiveAmount();
|
||||
|
||||
final Integer installmentId = this.fromApiJsonHelper.extractIntegerNamed("installmentId", postDatedCheck, locale);
|
||||
final List<LoanRepaymentScheduleInstallment> installmentList = loanRepaymentScheduleInstallment.stream().filter(
|
||||
repayment -> repayment.getInstallmentNumber().equals(installmentId) && repayment.getLoan().getId().equals(loanId))
|
||||
.collect(Collectors.toList());
|
||||
if (installmentList.size() > 1) {
|
||||
throw new PlatformDataIntegrityException("error.repayment.redundancy", "Multiple installment data found",
|
||||
"postDatedChecks");
|
||||
} else if (installmentList.size() == 0) {
|
||||
throw new LoanRepaymentScheduleNotFoundException(installmentId);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!dataValidationErrors.isEmpty()) {
|
||||
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.",
|
||||
dataValidationErrors);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void validateDisbursementDateWithMeetingDate(final LocalDate actualDisbursementDate, final CalendarInstance calendarInstance,
|
||||
Boolean isSkipRepaymentOnFirstMonth, Integer numberOfDays) {
|
||||
if (null != calendarInstance) {
|
||||
|
||||
+5
@@ -31,6 +31,7 @@ import org.apache.fineract.portfolio.floatingrates.data.InterestRatePeriodData;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.DisbursementData;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.LoanAccountData;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.LoanApprovalData;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.LoanRepaymentScheduleInstallmentData;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.LoanScheduleAccrualData;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.LoanTermVariationsData;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.LoanTransactionData;
|
||||
@@ -140,6 +141,10 @@ public interface LoanReadPlatformService {
|
||||
|
||||
Integer retrieveNumberOfActiveLoans();
|
||||
|
||||
Integer retrieveNumberOfRepayments(Long loanId);
|
||||
|
||||
List<LoanAccountData> retrieveGLIMChildLoansByGLIMParentAccount(String parentloanAccountNumber);
|
||||
|
||||
List<LoanRepaymentScheduleInstallmentData> getRepaymentDataResponse(Long loanId);
|
||||
|
||||
}
|
||||
|
||||
+28
@@ -86,6 +86,7 @@ import org.apache.fineract.portfolio.loanaccount.data.LoanAccountData;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.LoanApplicationTimelineData;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.LoanApprovalData;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.LoanInterestRecalculationData;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.LoanRepaymentScheduleInstallmentData;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.LoanScheduleAccrualData;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.LoanStatusEnumData;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.LoanSummaryData;
|
||||
@@ -105,6 +106,7 @@ import org.apache.fineract.portfolio.loanaccount.domain.LoanTermVariationType;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType;
|
||||
import org.apache.fineract.portfolio.loanaccount.exception.LoanNotFoundException;
|
||||
import org.apache.fineract.portfolio.loanaccount.exception.LoanRepaymentScheduleNotFoundException;
|
||||
import org.apache.fineract.portfolio.loanaccount.exception.LoanTransactionNotFoundException;
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanScheduleData;
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanSchedulePeriodData;
|
||||
@@ -535,12 +537,38 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
if (paymentDetailsRequired) {
|
||||
paymentOptions = this.paymentTypeReadPlatformService.retrieveAllPaymentTypes();
|
||||
}
|
||||
|
||||
return LoanTransactionData.loanTransactionDataForDisbursalTemplate(transactionType,
|
||||
loan.getExpectedDisbursedOnLocalDateForTemplate(), loan.getDisburseAmountForTemplate(), paymentOptions,
|
||||
loan.retriveLastEmiAmount(), loan.getNextPossibleRepaymentDateForRescheduling());
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer retrieveNumberOfRepayments(final Long loanId) {
|
||||
this.context.authenticatedUser();
|
||||
return this.loanRepositoryWrapper.getNumberOfRepayments(loanId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<LoanRepaymentScheduleInstallmentData> getRepaymentDataResponse(final Long loanId) {
|
||||
this.context.authenticatedUser();
|
||||
final List<LoanRepaymentScheduleInstallment> loanRepaymentScheduleInstallments = this.loanRepositoryWrapper
|
||||
.getLoanRepaymentScheduleInstallments(loanId);
|
||||
List<LoanRepaymentScheduleInstallmentData> loanRepaymentScheduleInstallmentData = new ArrayList<>();
|
||||
|
||||
if (loanRepaymentScheduleInstallments == null || loanRepaymentScheduleInstallments.size() == 0) {
|
||||
throw new LoanRepaymentScheduleNotFoundException(loanId, Integer.valueOf(0));
|
||||
}
|
||||
for (LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment : loanRepaymentScheduleInstallments) {
|
||||
loanRepaymentScheduleInstallmentData.add(LoanRepaymentScheduleInstallmentData.instanceOf(
|
||||
loanRepaymentScheduleInstallment.getId(), loanRepaymentScheduleInstallment.getInstallmentNumber(),
|
||||
loanRepaymentScheduleInstallment.getDueDate(), loanRepaymentScheduleInstallment
|
||||
.getTotalOutstanding(loanRepaymentScheduleInstallment.getLoan().getCurrency()).getAmount()));
|
||||
}
|
||||
return loanRepaymentScheduleInstallmentData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoanTransactionData retrieveLoanTransaction(final Long loanId, final Long transactionId) {
|
||||
this.context.authenticatedUser();
|
||||
|
||||
+30
-1
@@ -193,6 +193,9 @@ import org.apache.fineract.portfolio.note.domain.Note;
|
||||
import org.apache.fineract.portfolio.note.domain.NoteRepository;
|
||||
import org.apache.fineract.portfolio.paymentdetail.domain.PaymentDetail;
|
||||
import org.apache.fineract.portfolio.paymentdetail.service.PaymentDetailWritePlatformService;
|
||||
import org.apache.fineract.portfolio.repaymentwithpostdatedchecks.domain.PostDatedChecks;
|
||||
import org.apache.fineract.portfolio.repaymentwithpostdatedchecks.domain.PostDatedChecksRepository;
|
||||
import org.apache.fineract.portfolio.repaymentwithpostdatedchecks.service.RepaymentWithPostDatedChecksAssembler;
|
||||
import org.apache.fineract.portfolio.savings.domain.SavingsAccount;
|
||||
import org.apache.fineract.portfolio.transfer.api.TransferApiConstants;
|
||||
import org.apache.fineract.useradministration.domain.AppUser;
|
||||
@@ -249,6 +252,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
private final CashierTransactionDataValidator cashierTransactionDataValidator;
|
||||
private final GLIMAccountInfoRepository glimRepository;
|
||||
private final LoanRepository loanRepository;
|
||||
private final RepaymentWithPostDatedChecksAssembler repaymentWithPostDatedChecksAssembler;
|
||||
private final PostDatedChecksRepository postDatedChecksRepository;
|
||||
private final LoanChargePaidByRepository loanChargePaidByRepository;
|
||||
|
||||
@Autowired
|
||||
@@ -279,7 +284,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
final LoanRepaymentScheduleTransactionProcessorFactory transactionProcessingStrategy,
|
||||
final CodeValueRepositoryWrapper codeValueRepository, final LoanRepositoryWrapper loanRepositoryWrapper,
|
||||
final CashierTransactionDataValidator cashierTransactionDataValidator, final GLIMAccountInfoRepository glimRepository,
|
||||
final LoanRepository loanRepository, final LoanChargePaidByRepository loanChargePaidByRepository) {
|
||||
final LoanRepository loanRepository, final RepaymentWithPostDatedChecksAssembler repaymentWithPostDatedChecksAssembler,
|
||||
final PostDatedChecksRepository postDatedChecksRepository, final LoanChargePaidByRepository loanChargePaidByRepository) {
|
||||
this.context = context;
|
||||
this.loanEventApiJsonValidator = loanEventApiJsonValidator;
|
||||
this.loanAssembler = loanAssembler;
|
||||
@@ -320,6 +326,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
this.cashierTransactionDataValidator = cashierTransactionDataValidator;
|
||||
this.loanRepository = loanRepository;
|
||||
this.glimRepository = glimRepository;
|
||||
this.repaymentWithPostDatedChecksAssembler = repaymentWithPostDatedChecksAssembler;
|
||||
this.postDatedChecksRepository = postDatedChecksRepository;
|
||||
this.loanChargePaidByRepository = loanChargePaidByRepository;
|
||||
}
|
||||
|
||||
@@ -359,6 +367,11 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
|
||||
this.loanEventApiJsonValidator.validateDisbursement(command.json(), isAccountTransfer);
|
||||
|
||||
if (command.parameterExists("postDatedChecks")) {
|
||||
// validate with post dated checks for the disbursement
|
||||
this.loanEventApiJsonValidator.validateDisbursementWithPostDatedChecks(command.json(), loanId);
|
||||
}
|
||||
|
||||
final Loan loan = this.loanAssembler.assembleFrom(loanId);
|
||||
|
||||
// Get disbursedAmount
|
||||
@@ -541,6 +554,14 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
|
||||
updateRecurringCalendarDatesForInterestRecalculation(loan);
|
||||
this.loanAccountDomainService.recalculateAccruals(loan);
|
||||
|
||||
// Post Dated Checks
|
||||
if (command.parameterExists("postDatedChecks")) {
|
||||
// get repayment with post dates checks to update
|
||||
Set<PostDatedChecks> postDatedChecks = this.repaymentWithPostDatedChecksAssembler.fromParsedJson(command.json(), loan);
|
||||
updatePostDatedChecks(postDatedChecks);
|
||||
}
|
||||
|
||||
this.businessEventNotifierService.notifyBusinessEventWasExecuted(BusinessEvents.LOAN_DISBURSAL,
|
||||
constructEntityMap(BusinessEntity.LOAN, loan));
|
||||
return new CommandProcessingResultBuilder() //
|
||||
@@ -554,6 +575,10 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
.build();
|
||||
}
|
||||
|
||||
private void updatePostDatedChecks(Set<PostDatedChecks> postDatedChecks) {
|
||||
this.postDatedChecksRepository.saveAll(postDatedChecks);
|
||||
}
|
||||
|
||||
private void createAndSaveLoanScheduleArchive(final Loan loan, ScheduleGeneratorDTO scheduleGeneratorDTO) {
|
||||
LoanRescheduleRequest loanRescheduleRequest = null;
|
||||
LoanScheduleModel loanScheduleModel = loan.regenerateScheduleModel(scheduleGeneratorDTO);
|
||||
@@ -623,6 +648,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
try {
|
||||
List<LoanRepaymentScheduleInstallment> installments = loan.getRepaymentScheduleInstallments();
|
||||
for (LoanRepaymentScheduleInstallment installment : installments) {
|
||||
// installment.setPostDatedChecksToNull();
|
||||
if (installment.getId() == null) {
|
||||
this.repaymentScheduleInstallmentRepository.save(installment);
|
||||
}
|
||||
@@ -840,6 +866,9 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
loan.setActualDisbursementDate(null);
|
||||
ScheduleGeneratorDTO scheduleGeneratorDTO = this.loanUtilService.buildScheduleGeneratorDTO(loan, recalculateFrom);
|
||||
|
||||
// Remove post dated checks if added.
|
||||
loan.removePostDatedChecks();
|
||||
|
||||
final Map<String, Object> changes = loan.undoDisbursal(scheduleGeneratorDTO, existingTransactionIds, existingReversedTransactionIds,
|
||||
currentUser);
|
||||
|
||||
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
/**
|
||||
* 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.portfolio.repaymentwithpostdatedchecks.api;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
|
||||
final class PostDatedChecksApiResourceSwagger {
|
||||
|
||||
private PostDatedChecksApiResourceSwagger() {}
|
||||
|
||||
@Schema(description = "GetPostDatedChecks")
|
||||
public static final class GetPostDatedChecks {
|
||||
|
||||
private GetPostDatedChecks() {}
|
||||
|
||||
@Schema(example = "1")
|
||||
public Long id;
|
||||
@Schema(example = "1")
|
||||
public Integer installmentId;
|
||||
@Schema(example = "AMANA")
|
||||
public String name;
|
||||
@Schema(example = "900800200300")
|
||||
public Long accountNo;
|
||||
@Schema(example = "100000")
|
||||
public BigDecimal amount;
|
||||
@Schema(example = "2021-07-18")
|
||||
public LocalDate date;
|
||||
|
||||
}
|
||||
|
||||
@Schema(description = "UpdatePostDatedCheckRequest")
|
||||
public static final class UpdatePostDatedCheckRequest {
|
||||
|
||||
private UpdatePostDatedCheckRequest() {}
|
||||
|
||||
@Schema(example = "en")
|
||||
public String locale;
|
||||
@Schema(example = "10000")
|
||||
public BigDecimal amount;
|
||||
@Schema(example = "900800300400")
|
||||
public Long accountNo;
|
||||
@Schema(example = "2021-07-19")
|
||||
public LocalDate repaymentDate;
|
||||
@Schema(example = "AMANA")
|
||||
public String name;
|
||||
@Schema(example = "dd MM YYYY")
|
||||
public String dateFormat;
|
||||
@Schema(example = "2021-08-10")
|
||||
public LocalDate date;
|
||||
}
|
||||
|
||||
@Schema(description = "UpdatePostDatedCheckResponse")
|
||||
public static final class UpdatePostDatedCheckResponse {
|
||||
|
||||
private UpdatePostDatedCheckResponse() {}
|
||||
|
||||
@Schema(example = "12")
|
||||
public Integer resourceId;
|
||||
public UpdateChangesResponse changes;
|
||||
|
||||
static final class UpdateChangesResponse {
|
||||
|
||||
private UpdateChangesResponse() {}
|
||||
|
||||
@Schema(example = "10000")
|
||||
public BigDecimal amount;
|
||||
@Schema(example = "AMANA")
|
||||
public String bankName;
|
||||
@Schema(example = "900800500600")
|
||||
public Long accountNo;
|
||||
@Schema(example = "2021-08-10")
|
||||
public LocalDate date;
|
||||
}
|
||||
}
|
||||
|
||||
@Schema(description = "DeletePostDatedCheck")
|
||||
public static final class DeletePostDatedCheck {
|
||||
|
||||
private DeletePostDatedCheck() {}
|
||||
|
||||
@Schema(example = "1")
|
||||
public Long loanId;
|
||||
@Schema(example = "2")
|
||||
public Long resourceId;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+147
@@ -0,0 +1,147 @@
|
||||
/**
|
||||
* 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.portfolio.repaymentwithpostdatedchecks.api;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.media.ArraySchema;
|
||||
import io.swagger.v3.oas.annotations.media.Content;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.parameters.RequestBody;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import java.util.List;
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DELETE;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.PUT;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import org.apache.fineract.commands.domain.CommandWrapper;
|
||||
import org.apache.fineract.commands.service.CommandWrapperBuilder;
|
||||
import org.apache.fineract.commands.service.PortfolioCommandSourceWritePlatformService;
|
||||
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSerializer;
|
||||
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
|
||||
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
|
||||
import org.apache.fineract.portfolio.repaymentwithpostdatedchecks.data.PostDatedChecksData;
|
||||
import org.apache.fineract.portfolio.repaymentwithpostdatedchecks.service.RepaymentWithPostDatedChecksReadPlatformService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Path("/loans/{loanId}/postdatedchecks")
|
||||
@Component
|
||||
@Scope("singleton")
|
||||
@Tag(name = "repayment with post dated checks", description = "Repay with post dated checks")
|
||||
public class RepaymentWithPostDatedChecksApiResource {
|
||||
|
||||
private final PlatformSecurityContext context;
|
||||
private final FromJsonHelper fromJsonHelper;
|
||||
private final DefaultToApiJsonSerializer<PostDatedChecksData> apiJsonSerializer;
|
||||
private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService;
|
||||
private final RepaymentWithPostDatedChecksReadPlatformService repaymentWithPostDatedChecksReadPlatformService;
|
||||
|
||||
@Autowired
|
||||
public RepaymentWithPostDatedChecksApiResource(final PlatformSecurityContext context, final FromJsonHelper fromJsonHelper,
|
||||
final DefaultToApiJsonSerializer<PostDatedChecksData> apiJsonSerializer,
|
||||
final PortfolioCommandSourceWritePlatformService portfolioCommandSourceWritePlatformService,
|
||||
final RepaymentWithPostDatedChecksReadPlatformService repaymentWithPostDatedChecksReadPlatformService) {
|
||||
this.context = context;
|
||||
this.fromJsonHelper = fromJsonHelper;
|
||||
this.apiJsonSerializer = apiJsonSerializer;
|
||||
this.commandsSourceWritePlatformService = portfolioCommandSourceWritePlatformService;
|
||||
this.repaymentWithPostDatedChecksReadPlatformService = repaymentWithPostDatedChecksReadPlatformService;
|
||||
}
|
||||
|
||||
@GET
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
@Operation(summary = "Get All Post Dated Checks", description = "Get All Post dated Checks")
|
||||
@ApiResponses({
|
||||
@ApiResponse(responseCode = "200", description = "OK", content = @Content(array = @ArraySchema(schema = @Schema(implementation = PostDatedChecksApiResourceSwagger.GetPostDatedChecks.class)))) })
|
||||
public String getPostDatedChecks(@PathParam("loanId") @Parameter(description = "loanId") final Long loanId) {
|
||||
this.context.authenticatedUser();
|
||||
final List<PostDatedChecksData> postDatedChecksDataList = this.repaymentWithPostDatedChecksReadPlatformService
|
||||
.getPostDatedChecks(loanId);
|
||||
return this.apiJsonSerializer.serialize(postDatedChecksDataList);
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("{installmentId}")
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
@Operation(summary = "Get Post Dated Check", description = "Get Post Dated Check")
|
||||
@ApiResponses({
|
||||
@ApiResponse(responseCode = "200", description = "OK", content = @Content(array = @ArraySchema(schema = @Schema(implementation = PostDatedChecksApiResourceSwagger.GetPostDatedChecks.class)))) })
|
||||
public String getPostDatedCheck(@PathParam("installmentId") @Parameter(description = "installmentId") final Integer installmentId,
|
||||
@PathParam("loanId") @Parameter(description = "loanId") final Long loanId) {
|
||||
this.context.authenticatedUser();
|
||||
final PostDatedChecksData postDatedChecksData = this.repaymentWithPostDatedChecksReadPlatformService
|
||||
.getPostDatedCheckByInstallmentId(installmentId, loanId);
|
||||
return this.apiJsonSerializer.serialize(postDatedChecksData);
|
||||
}
|
||||
|
||||
@PUT
|
||||
@Path("{postDatedCheckId}")
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
@Operation(summary = "Update Post Dated Check, Bounced Check", description = "Update Post Dated Check, Bounced Check")
|
||||
@RequestBody(required = true, content = @Content(schema = @Schema(implementation = PostDatedChecksApiResourceSwagger.UpdatePostDatedCheckRequest.class)))
|
||||
@ApiResponses({
|
||||
@ApiResponse(responseCode = "200", description = "OK", content = @Content(array = @ArraySchema(schema = @Schema(implementation = PostDatedChecksApiResourceSwagger.UpdatePostDatedCheckResponse.class)))) })
|
||||
public String updatePostDatedChecks(@PathParam("postDatedCheckId") @Parameter(description = "postDatedCheckId") final Long id,
|
||||
@PathParam("loanId") @Parameter(description = "loanId") final Long loanId,
|
||||
@Parameter(hidden = true) final String apiRequestBodyAsJson,
|
||||
@QueryParam("editType") @Parameter(description = "editType") final String type) {
|
||||
|
||||
CommandWrapper commandRequest = null;
|
||||
|
||||
if ("update".equals(type)) {
|
||||
commandRequest = new CommandWrapperBuilder().updatePostDatedCheck(id, loanId).withJson(apiRequestBodyAsJson).build();
|
||||
} else if ("bounced".equals(type)) {
|
||||
commandRequest = new CommandWrapperBuilder().bouncedCheck(id, loanId).withJson(apiRequestBodyAsJson).build();
|
||||
}
|
||||
|
||||
final CommandProcessingResult commandProcessingResult = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
||||
|
||||
return this.apiJsonSerializer.serialize(commandProcessingResult);
|
||||
}
|
||||
|
||||
@DELETE
|
||||
@Path("{postDatedCheckId}")
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
@Operation(summary = "Delete Post Dated Check", description = "Delete Post Dated Check")
|
||||
@ApiResponses({
|
||||
@ApiResponse(responseCode = "200", description = "OK", content = @Content(array = @ArraySchema(schema = @Schema(implementation = PostDatedChecksApiResourceSwagger.DeletePostDatedCheck.class)))) })
|
||||
public String deletePostDatedCheck(@PathParam("postDatedCheckId") @Parameter(description = "postDatedCheckId") final Long id,
|
||||
@PathParam("loanId") @Parameter(description = "loanId") final Long loanId) {
|
||||
final CommandWrapper commandRequest = new CommandWrapperBuilder().deletePostDatedCheck(id, loanId).build();
|
||||
|
||||
final CommandProcessingResult commandProcessingResult = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
||||
|
||||
return this.apiJsonSerializer.serialize(commandProcessingResult);
|
||||
}
|
||||
|
||||
}
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* 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.portfolio.repaymentwithpostdatedchecks.data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
|
||||
public final class PostDatedChecksData {
|
||||
|
||||
private final Long id;
|
||||
|
||||
private final Integer installmentId;
|
||||
|
||||
private final String name;
|
||||
|
||||
private final Long accountNo;
|
||||
|
||||
private final BigDecimal amount;
|
||||
|
||||
private final LocalDate installmentDate;
|
||||
|
||||
private final Long checkNo;
|
||||
|
||||
private final Integer status;
|
||||
|
||||
private PostDatedChecksData(final LocalDate installmentDate, final Long id, final Integer installmentId, final Long accountNo,
|
||||
final BigDecimal amount, final String name, final Long checkNo, final Integer status) {
|
||||
this.accountNo = accountNo;
|
||||
this.amount = amount;
|
||||
this.name = name;
|
||||
this.id = id;
|
||||
this.installmentDate = installmentDate;
|
||||
this.installmentId = installmentId;
|
||||
this.checkNo = checkNo;
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public static PostDatedChecksData from(final LocalDate installmentDate, final Long id, final Integer installmentId,
|
||||
final Long accountNo, final BigDecimal amount, final String name, final Long checkNo, final Integer status) {
|
||||
return new PostDatedChecksData(installmentDate, id, installmentId, accountNo, amount, name, checkNo, status);
|
||||
}
|
||||
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.portfolio.repaymentwithpostdatedchecks.data;
|
||||
|
||||
public interface PostDatedChecksStatus {
|
||||
|
||||
Integer POST_DATED_CHECKS_BOUNCED = 1;
|
||||
Integer POST_DATED_CHECKS_PAID = 2;
|
||||
Integer POST_DATED_CHECKS_PENDING = 0;
|
||||
}
|
||||
+150
@@ -0,0 +1,150 @@
|
||||
/**
|
||||
* 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.portfolio.repaymentwithpostdatedchecks.domain;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.OneToOne;
|
||||
import javax.persistence.Table;
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
||||
|
||||
@Entity
|
||||
@Table(name = "m_repayment_with_post_dated_checks")
|
||||
public class PostDatedChecks extends AbstractPersistableCustom {
|
||||
|
||||
@ManyToOne(optional = false)
|
||||
@JoinColumn(name = "loan_id", referencedColumnName = "id", nullable = false)
|
||||
private Loan loan;
|
||||
@OneToOne(optional = false)
|
||||
@JoinColumn(name = "repayment_id", referencedColumnName = "id", nullable = false)
|
||||
private LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment;
|
||||
@Column(name = "account_no", nullable = false, length = 10)
|
||||
private Long accountNo;
|
||||
@Column(name = "bank_name", nullable = false, length = 100)
|
||||
private String bankName;
|
||||
@Column(name = "amount", scale = 6, precision = 19)
|
||||
private BigDecimal amount;
|
||||
@Column(name = "repayment_date", nullable = false)
|
||||
private Date repaymentDate;
|
||||
@Column(name = "status", columnDefinition = "0")
|
||||
private Integer status;
|
||||
@Column(name = "check_no", nullable = false, unique = true)
|
||||
private Long checkNo;
|
||||
|
||||
public PostDatedChecks() {}
|
||||
|
||||
private PostDatedChecks(final Long accountNo, final String bankName, final BigDecimal amount,
|
||||
final LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment, final Date date, final Loan loan, final Long checkNo) {
|
||||
this.bankName = bankName;
|
||||
this.accountNo = accountNo;
|
||||
this.amount = amount;
|
||||
this.loanRepaymentScheduleInstallment = loanRepaymentScheduleInstallment;
|
||||
this.repaymentDate = date;
|
||||
this.loan = loan;
|
||||
this.checkNo = checkNo;
|
||||
}
|
||||
|
||||
public static PostDatedChecks instanceOf(final Long accountNo, final String bankName, final BigDecimal amount,
|
||||
final LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment, final Loan loan, final Long checkNo) {
|
||||
return new PostDatedChecks(accountNo, bankName, amount, loanRepaymentScheduleInstallment,
|
||||
Date.from(loanRepaymentScheduleInstallment.getDueDate().atStartOfDay(DateUtils.getDateTimeZoneOfTenant()).toInstant()),
|
||||
loan, checkNo);
|
||||
}
|
||||
|
||||
public void setLoan(Loan loan) {
|
||||
this.loan = loan;
|
||||
}
|
||||
|
||||
public void setLoanRepaymentScheduleInstallment(final LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment) {
|
||||
this.loanRepaymentScheduleInstallment = loanRepaymentScheduleInstallment;
|
||||
}
|
||||
|
||||
public Map<String, Object> updatePostDatedChecks(JsonCommand command) {
|
||||
final Map<String, Object> changes = new HashMap<>();
|
||||
|
||||
if (command.isChangeInBigDecimalParameterNamed("amount", this.amount)) {
|
||||
final BigDecimal newAmount = command.bigDecimalValueOfParameterNamed("amount");
|
||||
this.amount = newAmount;
|
||||
changes.put("amount", newAmount);
|
||||
}
|
||||
|
||||
if (command.isChangeInStringParameterNamed("name", this.bankName)) {
|
||||
final String newName = command.stringValueOfParameterNamed("name");
|
||||
this.bankName = newName;
|
||||
changes.put("bankName", newName);
|
||||
}
|
||||
|
||||
if (command.isChangeInLongParameterNamed("accountNo", this.accountNo)) {
|
||||
final Long newAccountNo = command.longValueOfParameterNamed("accountNo");
|
||||
this.accountNo = newAccountNo;
|
||||
changes.put("accountNo", newAccountNo);
|
||||
}
|
||||
|
||||
if (command.isChangeInLongParameterNamed("checkNo", this.accountNo)) {
|
||||
final Long newCheckNo = command.longValueOfParameterNamed("checkNo");
|
||||
this.checkNo = newCheckNo;
|
||||
changes.put("checkNo", newCheckNo);
|
||||
}
|
||||
|
||||
return changes;
|
||||
}
|
||||
|
||||
public Loan getLoan() {
|
||||
return this.loan;
|
||||
}
|
||||
|
||||
public LoanRepaymentScheduleInstallment getLoanRepaymentScheduleInstallment() {
|
||||
return this.loanRepaymentScheduleInstallment;
|
||||
}
|
||||
|
||||
public void setStatus(Integer status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public String getBankName() {
|
||||
return this.bankName;
|
||||
}
|
||||
|
||||
public Long getCheckNo() {
|
||||
return this.checkNo;
|
||||
}
|
||||
|
||||
public Long getAccountNo() {
|
||||
return this.accountNo;
|
||||
}
|
||||
|
||||
public BigDecimal getAmount() {
|
||||
return this.amount;
|
||||
}
|
||||
|
||||
public Integer getStatus() {
|
||||
return this.status;
|
||||
}
|
||||
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* 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.portfolio.repaymentwithpostdatedchecks.domain;
|
||||
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
public interface PostDatedChecksRepository extends JpaRepository<PostDatedChecks, Long>, JpaSpecificationExecutor<PostDatedChecks> {
|
||||
|
||||
@Query("select pdc from PostDatedChecks pdc where pdc.status = 0 and pdc.loanRepaymentScheduleInstallment = :loanRepaymentScheduleInstallment")
|
||||
PostDatedChecks getPendingPostDatedCheck(
|
||||
@Param("loanRepaymentScheduleInstallment") LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment);
|
||||
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.portfolio.repaymentwithpostdatedchecks.exception;
|
||||
|
||||
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformDomainRuleException;
|
||||
|
||||
public class PostDatedCheckBouncedCheckInvalid extends AbstractPlatformDomainRuleException {
|
||||
|
||||
public PostDatedCheckBouncedCheckInvalid(final String defaultUserMessage, final Object... defaultUserMessageArgs) {
|
||||
super("error.msg.post.dated.checkNo..invalid", defaultUserMessage, defaultUserMessageArgs);
|
||||
}
|
||||
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* 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.portfolio.repaymentwithpostdatedchecks.exception;
|
||||
|
||||
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformResourceNotFoundException;
|
||||
|
||||
public class PostDatedCheckNotFoundException extends AbstractPlatformResourceNotFoundException {
|
||||
|
||||
public PostDatedCheckNotFoundException(final Long id) {
|
||||
super("error.msg.post.dated.check.id.invalid", "Post Dated Check with identifier " + id + " does not exist", id);
|
||||
}
|
||||
|
||||
public PostDatedCheckNotFoundException(final Long id, final Integer installmentNo) {
|
||||
super("error.msg.post.dated.check.for.installment.not.found",
|
||||
"Post Dated Check for loan id " + id + " and installment number " + installmentNo + " does not exist");
|
||||
}
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* 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.portfolio.repaymentwithpostdatedchecks.handler;
|
||||
|
||||
import org.apache.fineract.commands.annotation.CommandType;
|
||||
import org.apache.fineract.commands.handler.NewCommandSourceHandler;
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.apache.fineract.portfolio.repaymentwithpostdatedchecks.service.RepaymentWithPostDatedChecksWritePlatformService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Service
|
||||
@CommandType(entity = "REPAYMENT_WITH_POSTDATEDCHECKS", action = "BOUNCE")
|
||||
public class BouncePostDatedCheckHandler implements NewCommandSourceHandler {
|
||||
|
||||
private final RepaymentWithPostDatedChecksWritePlatformService repaymentWithPostDatedChecksWritePlatformService;
|
||||
|
||||
@Autowired
|
||||
public BouncePostDatedCheckHandler(
|
||||
final RepaymentWithPostDatedChecksWritePlatformService repaymentWithPostDatedChecksWritePlatformService) {
|
||||
this.repaymentWithPostDatedChecksWritePlatformService = repaymentWithPostDatedChecksWritePlatformService;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult processCommand(final JsonCommand command) {
|
||||
return this.repaymentWithPostDatedChecksWritePlatformService.bouncePostDatedChecks(command);
|
||||
}
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* 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.portfolio.repaymentwithpostdatedchecks.handler;
|
||||
|
||||
import org.apache.fineract.commands.annotation.CommandType;
|
||||
import org.apache.fineract.commands.handler.NewCommandSourceHandler;
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.apache.fineract.portfolio.repaymentwithpostdatedchecks.service.RepaymentWithPostDatedChecksWritePlatformService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Service
|
||||
@CommandType(entity = "REPAYMENT_WITH_POSTDATEDCHECKS", action = "DELETE")
|
||||
public class DeletePostDatedChecksHandler implements NewCommandSourceHandler {
|
||||
|
||||
private final RepaymentWithPostDatedChecksWritePlatformService repaymentWithPostDatedChecksWritePlatformService;
|
||||
|
||||
@Autowired
|
||||
public DeletePostDatedChecksHandler(
|
||||
final RepaymentWithPostDatedChecksWritePlatformService repaymentWithPostDatedChecksWritePlatformService) {
|
||||
this.repaymentWithPostDatedChecksWritePlatformService = repaymentWithPostDatedChecksWritePlatformService;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult processCommand(final JsonCommand command) {
|
||||
return this.repaymentWithPostDatedChecksWritePlatformService.deletePostDatedChecks(command);
|
||||
}
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* 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.portfolio.repaymentwithpostdatedchecks.handler;
|
||||
|
||||
import org.apache.fineract.commands.annotation.CommandType;
|
||||
import org.apache.fineract.commands.handler.NewCommandSourceHandler;
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.apache.fineract.portfolio.repaymentwithpostdatedchecks.service.RepaymentWithPostDatedChecksWritePlatformService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Service
|
||||
@CommandType(entity = "REPAYMENT_WITH_POSTDATEDCHECKS", action = "UPDATE")
|
||||
public class EditPostDatedChecksHandler implements NewCommandSourceHandler {
|
||||
|
||||
private final RepaymentWithPostDatedChecksWritePlatformService repaymentWithPostDatedChecksWritePlatformService;
|
||||
|
||||
@Autowired
|
||||
public EditPostDatedChecksHandler(
|
||||
final RepaymentWithPostDatedChecksWritePlatformService repaymentWithPostDatedChecksWritePlatformService) {
|
||||
this.repaymentWithPostDatedChecksWritePlatformService = repaymentWithPostDatedChecksWritePlatformService;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult processCommand(final JsonCommand command) {
|
||||
return this.repaymentWithPostDatedChecksWritePlatformService.updatePostDatedChecks(command);
|
||||
}
|
||||
}
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
/**
|
||||
* 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.portfolio.repaymentwithpostdatedchecks.service;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
||||
import org.apache.fineract.portfolio.repaymentwithpostdatedchecks.domain.PostDatedChecks;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class RepaymentWithPostDatedChecksAssembler {
|
||||
|
||||
private final FromJsonHelper fromApiJsonHelper;
|
||||
|
||||
@Autowired
|
||||
public RepaymentWithPostDatedChecksAssembler(final FromJsonHelper fromJsonHelper) {
|
||||
this.fromApiJsonHelper = fromJsonHelper;
|
||||
}
|
||||
|
||||
public Set<PostDatedChecks> fromParsedJson(final String json, final Loan loan) {
|
||||
final Set<PostDatedChecks> postDatedChecks = new HashSet<>();
|
||||
final JsonElement jsonElement = this.fromApiJsonHelper.parse(json);
|
||||
final List<LoanRepaymentScheduleInstallment> loanRepaymentScheduleInstallments = loan.getRepaymentScheduleInstallments();
|
||||
|
||||
JsonObject jsonObject = jsonElement.getAsJsonObject();
|
||||
final Locale locale = this.fromApiJsonHelper.extractLocaleParameter(jsonObject);
|
||||
if (jsonObject.has("postDatedChecks") && jsonObject.get("postDatedChecks").isJsonArray()) {
|
||||
JsonArray postDatedCheckArray = jsonObject.get("postDatedChecks").getAsJsonArray();
|
||||
for (int i = 0; i < postDatedCheckArray.size(); i++) {
|
||||
final JsonObject postDatedCheck = postDatedCheckArray.get(i).getAsJsonObject();
|
||||
if (postDatedCheck == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final String name = this.fromApiJsonHelper.extractStringNamed("name", postDatedCheck);
|
||||
|
||||
final BigDecimal amount = this.fromApiJsonHelper.extractBigDecimalNamed("amount", postDatedCheck, locale);
|
||||
|
||||
final Integer installmentId = this.fromApiJsonHelper.extractIntegerNamed("installmentId", postDatedCheck, locale);
|
||||
final List<LoanRepaymentScheduleInstallment> installmentList = loanRepaymentScheduleInstallments.stream()
|
||||
.filter(repayment -> repayment.getInstallmentNumber().equals(installmentId)).collect(Collectors.toList());
|
||||
final Long accountNo = this.fromApiJsonHelper.extractLongNamed("accountNo", postDatedCheck);
|
||||
final Long checkNo = this.fromApiJsonHelper.extractLongNamed("checkNo", postDatedCheck);
|
||||
|
||||
postDatedChecks.add(PostDatedChecks.instanceOf(accountNo, name, amount, installmentList.get(0), loan, checkNo));
|
||||
}
|
||||
}
|
||||
|
||||
return postDatedChecks;
|
||||
}
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.portfolio.repaymentwithpostdatedchecks.service;
|
||||
|
||||
import java.util.List;
|
||||
import org.apache.fineract.portfolio.repaymentwithpostdatedchecks.data.PostDatedChecksData;
|
||||
|
||||
public interface RepaymentWithPostDatedChecksReadPlatformService {
|
||||
|
||||
List<PostDatedChecksData> getPostDatedChecks(Long id);
|
||||
|
||||
PostDatedChecksData getPostDatedCheck(Long id);
|
||||
|
||||
PostDatedChecksData getPostDatedCheckByInstallmentId(Integer id, Long loanId);
|
||||
|
||||
}
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
/**
|
||||
* 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.portfolio.repaymentwithpostdatedchecks.service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallmentRepository;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
|
||||
import org.apache.fineract.portfolio.loanaccount.exception.LoanNotFoundException;
|
||||
import org.apache.fineract.portfolio.repaymentwithpostdatedchecks.data.PostDatedChecksData;
|
||||
import org.apache.fineract.portfolio.repaymentwithpostdatedchecks.data.PostDatedChecksStatus;
|
||||
import org.apache.fineract.portfolio.repaymentwithpostdatedchecks.domain.PostDatedChecks;
|
||||
import org.apache.fineract.portfolio.repaymentwithpostdatedchecks.domain.PostDatedChecksRepository;
|
||||
import org.apache.fineract.portfolio.repaymentwithpostdatedchecks.exception.PostDatedCheckNotFoundException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class RepaymentWithPostDatedChecksReadPlatformServiceImpl implements RepaymentWithPostDatedChecksReadPlatformService {
|
||||
|
||||
private final PostDatedChecksRepository postDatedChecksRepository;
|
||||
private final LoanRepository loanRepository;
|
||||
private final LoanRepaymentScheduleInstallmentRepository loanRepaymentScheduleInstallmentRepository;
|
||||
|
||||
@Autowired
|
||||
public RepaymentWithPostDatedChecksReadPlatformServiceImpl(final PostDatedChecksRepository postDatedChecksRepository,
|
||||
final LoanRepository loanRepository,
|
||||
final LoanRepaymentScheduleInstallmentRepository loanRepaymentScheduleInstallmentRepository) {
|
||||
this.postDatedChecksRepository = postDatedChecksRepository;
|
||||
this.loanRepository = loanRepository;
|
||||
this.loanRepaymentScheduleInstallmentRepository = loanRepaymentScheduleInstallmentRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PostDatedChecksData> getPostDatedChecks(final Long id) {
|
||||
final Loan loan = this.loanRepository.findById(id).orElseThrow(() -> new LoanNotFoundException(id));
|
||||
final List<PostDatedChecks> postDatedChecks = loan.getPostDatedChecks();
|
||||
List<PostDatedChecksData> postDatedChecksDataList = new ArrayList<>();
|
||||
for (PostDatedChecks postDatedCheckObject : postDatedChecks) {
|
||||
// Avoid bounced checks
|
||||
if (!PostDatedChecksStatus.POST_DATED_CHECKS_BOUNCED.equals(postDatedCheckObject.getStatus())) {
|
||||
postDatedChecksDataList.add(PostDatedChecksData.from(
|
||||
postDatedCheckObject.getLoanRepaymentScheduleInstallment().getDueDate(), postDatedCheckObject.getId(),
|
||||
postDatedCheckObject.getLoanRepaymentScheduleInstallment().getInstallmentNumber(),
|
||||
postDatedCheckObject.getAccountNo(), postDatedCheckObject.getAmount(), postDatedCheckObject.getBankName(),
|
||||
postDatedCheckObject.getCheckNo(), postDatedCheckObject.getStatus()));
|
||||
}
|
||||
}
|
||||
return postDatedChecksDataList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PostDatedChecksData getPostDatedCheck(final Long id) {
|
||||
final PostDatedChecks postDatedChecks = this.postDatedChecksRepository.findById(id)
|
||||
.orElseThrow(() -> new PostDatedCheckNotFoundException(id));
|
||||
|
||||
return PostDatedChecksData.from(postDatedChecks.getLoanRepaymentScheduleInstallment().getDueDate(), postDatedChecks.getId(),
|
||||
postDatedChecks.getLoanRepaymentScheduleInstallment().getInstallmentNumber(), postDatedChecks.getAccountNo(),
|
||||
postDatedChecks.getAmount(), postDatedChecks.getBankName(), postDatedChecks.getCheckNo(), postDatedChecks.getStatus());
|
||||
}
|
||||
|
||||
@Override
|
||||
public PostDatedChecksData getPostDatedCheckByInstallmentId(final Integer id, final Long loanId) {
|
||||
final Loan loan = this.loanRepository.findById(loanId).orElseThrow(() -> new LoanNotFoundException(loanId));
|
||||
final List<PostDatedChecks> postDatedChecks = loan.getPostDatedChecks();
|
||||
|
||||
if (postDatedChecks == null || postDatedChecks.size() == 0) {
|
||||
throw new PostDatedCheckNotFoundException(loanId, id);
|
||||
}
|
||||
|
||||
final PostDatedChecks postDatedChecksData = postDatedChecks.stream()
|
||||
.filter((postDatedCheck) -> postDatedCheck.getLoanRepaymentScheduleInstallment().getInstallmentNumber().equals(id)
|
||||
&& !PostDatedChecksStatus.POST_DATED_CHECKS_BOUNCED.equals(postDatedCheck.getStatus()))
|
||||
.collect(Collectors.toList()).get(0);
|
||||
return PostDatedChecksData.from(postDatedChecksData.getLoanRepaymentScheduleInstallment().getDueDate(), postDatedChecksData.getId(),
|
||||
postDatedChecksData.getLoanRepaymentScheduleInstallment().getInstallmentNumber(), postDatedChecksData.getAccountNo(),
|
||||
postDatedChecksData.getAmount(), postDatedChecksData.getBankName(), postDatedChecksData.getCheckNo(),
|
||||
postDatedChecksData.getStatus());
|
||||
}
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.portfolio.repaymentwithpostdatedchecks.service;
|
||||
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
|
||||
|
||||
public interface RepaymentWithPostDatedChecksWritePlatformService {
|
||||
|
||||
CommandProcessingResult deletePostDatedChecks(JsonCommand command);
|
||||
|
||||
CommandProcessingResult updatePostDatedChecks(JsonCommand command);
|
||||
|
||||
CommandProcessingResult bouncePostDatedChecks(JsonCommand command);
|
||||
}
|
||||
+227
@@ -0,0 +1,227 @@
|
||||
/**
|
||||
* 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.portfolio.repaymentwithpostdatedchecks.service;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import java.lang.reflect.Type;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
import org.apache.fineract.infrastructure.core.data.ApiParameterError;
|
||||
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder;
|
||||
import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
|
||||
import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
|
||||
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
|
||||
import org.apache.fineract.portfolio.loanaccount.exception.LoanNotFoundException;
|
||||
import org.apache.fineract.portfolio.repaymentwithpostdatedchecks.data.PostDatedChecksStatus;
|
||||
import org.apache.fineract.portfolio.repaymentwithpostdatedchecks.domain.PostDatedChecks;
|
||||
import org.apache.fineract.portfolio.repaymentwithpostdatedchecks.domain.PostDatedChecksRepository;
|
||||
import org.apache.fineract.portfolio.repaymentwithpostdatedchecks.exception.PostDatedCheckNotFoundException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.dao.DataIntegrityViolationException;
|
||||
import org.springframework.orm.jpa.JpaSystemException;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Service
|
||||
public class RepaymentWithPostDatedChecksWritePlatformServiceImpl implements RepaymentWithPostDatedChecksWritePlatformService {
|
||||
|
||||
private final PostDatedChecksRepository postDatedChecksRepository;
|
||||
private final FromJsonHelper fromApiJsonHelper;
|
||||
private final LoanRepository loanRepository;
|
||||
/**
|
||||
* The parameters supported for this command.
|
||||
*/
|
||||
private final Set<String> supportedParametersForUpdate = new HashSet<>(Arrays.asList("name", "amount", "accountNo", "locale"));
|
||||
private final Set<String> supportedParametersForBounce = new HashSet<>(
|
||||
Arrays.asList("name", "amount", "accountNo", "checkNo", "locale", "installmentId"));
|
||||
|
||||
@Autowired
|
||||
public RepaymentWithPostDatedChecksWritePlatformServiceImpl(final PostDatedChecksRepository postDatedChecksRepository,
|
||||
final FromJsonHelper fromApiJsonHelper, final LoanRepository loanRepository) {
|
||||
this.postDatedChecksRepository = postDatedChecksRepository;
|
||||
this.fromApiJsonHelper = fromApiJsonHelper;
|
||||
this.loanRepository = loanRepository;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult updatePostDatedChecks(JsonCommand command) {
|
||||
validateForUpdate(command);
|
||||
final PostDatedChecks postDatedChecks = this.postDatedChecksRepository.findById(command.entityId())
|
||||
.orElseThrow(() -> new PostDatedCheckNotFoundException(command.entityId()));
|
||||
Map<String, Object> changes = postDatedChecks.updatePostDatedChecks(command);
|
||||
this.postDatedChecksRepository.saveAndFlush(postDatedChecks);
|
||||
return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(command.entityId()).with(changes)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult bouncePostDatedChecks(JsonCommand command) {
|
||||
validateForBounce(command);
|
||||
|
||||
final PostDatedChecks postDatedCheck = this.postDatedChecksRepository.findById(command.entityId())
|
||||
.orElseThrow(() -> new PostDatedCheckNotFoundException(command.entityId()));
|
||||
postDatedCheck.setStatus(PostDatedChecksStatus.POST_DATED_CHECKS_BOUNCED);
|
||||
|
||||
final Loan loan = this.loanRepository.findById(command.getLoanId())
|
||||
.orElseThrow(() -> new LoanNotFoundException(command.getLoanId()));
|
||||
|
||||
final JsonElement jsonElement = this.fromApiJsonHelper.parse(command.json());
|
||||
|
||||
JsonObject jsonObject = jsonElement.getAsJsonObject();
|
||||
final Locale locale = this.fromApiJsonHelper.extractLocaleParameter(jsonObject);
|
||||
|
||||
final String name = this.fromApiJsonHelper.extractStringNamed("name", jsonObject);
|
||||
|
||||
final BigDecimal amount = this.fromApiJsonHelper.extractBigDecimalNamed("amount", jsonObject, locale);
|
||||
|
||||
final Integer installmentId = this.fromApiJsonHelper.extractIntegerNamed("installmentId", jsonObject, locale);
|
||||
|
||||
final Long accountNo = this.fromApiJsonHelper.extractLongNamed("accountNo", jsonObject);
|
||||
final Long checkNo = this.fromApiJsonHelper.extractLongNamed("checkNo", jsonObject);
|
||||
|
||||
final List<LoanRepaymentScheduleInstallment> loanRepaymentScheduleInstallments = loan.getRepaymentScheduleInstallments();
|
||||
|
||||
final List<LoanRepaymentScheduleInstallment> installmentList = loanRepaymentScheduleInstallments.stream()
|
||||
.filter(repayment -> repayment.getInstallmentNumber().equals(installmentId)).collect(Collectors.toList());
|
||||
|
||||
final PostDatedChecks postDatedChecks = PostDatedChecks.instanceOf(accountNo, name, amount, installmentList.get(0), loan, checkNo);
|
||||
try {
|
||||
this.postDatedChecksRepository.saveAndFlush(postDatedChecks);
|
||||
} catch (final JpaSystemException | DataIntegrityViolationException e) {
|
||||
final Throwable realCause = e.getCause();
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("postdatedChecks");
|
||||
if (realCause.getMessage().toLowerCase().contains("transaction has been rolled back")) {
|
||||
baseDataValidator.reset().parameter("checkNo").failWithCode("value.must.be.unique");
|
||||
}
|
||||
if (!dataValidationErrors.isEmpty()) {
|
||||
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.",
|
||||
dataValidationErrors, e);
|
||||
}
|
||||
}
|
||||
|
||||
return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(Integer.toUnsignedLong(installmentId))
|
||||
.withLoanId(postDatedChecks.getLoan().getId()).build();
|
||||
}
|
||||
|
||||
private void validateForBounce(JsonCommand command) {
|
||||
final JsonElement jsonElement = this.fromApiJsonHelper.parse(command.json());
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
||||
|
||||
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
|
||||
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, command.json(), this.supportedParametersForBounce);
|
||||
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
||||
.resource("repayment-with-post-dated-checks");
|
||||
|
||||
if (!command.parameterExists("locale")) {
|
||||
baseDataValidator.reset().parameter("locale").notNull().failWithCode("locale.not.exists");
|
||||
} else {
|
||||
final String locale = this.fromApiJsonHelper.extractStringNamed("locale", jsonElement);
|
||||
baseDataValidator.reset().parameter("locale").value(locale).notNull();
|
||||
}
|
||||
|
||||
if (command.parameterExists("amount")) {
|
||||
final BigDecimal amount = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed("amount", jsonElement);
|
||||
baseDataValidator.reset().parameter("amount").value(amount).notNull().positiveAmount();
|
||||
}
|
||||
|
||||
if (command.parameterExists("accountNo")) {
|
||||
final Long accountNo = this.fromApiJsonHelper.extractLongNamed("accountNo", jsonElement);
|
||||
baseDataValidator.reset().parameter("accountNo").value(accountNo).notNull().positiveAmount();
|
||||
}
|
||||
|
||||
if (command.parameterExists("name")) {
|
||||
final String name = this.fromApiJsonHelper.extractStringNamed("name", jsonElement);
|
||||
baseDataValidator.reset().parameter("name").value(name).notNull();
|
||||
}
|
||||
|
||||
if (command.parameterExists("checkNo")) {
|
||||
final Long checkNo = this.fromApiJsonHelper.extractLongNamed("checkNo", jsonElement);
|
||||
baseDataValidator.reset().parameter("checkNo").value(checkNo).notNull().longGreaterThanZero();
|
||||
}
|
||||
|
||||
if (!dataValidationErrors.isEmpty()) {
|
||||
throw new PlatformApiDataValidationException(dataValidationErrors);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void validateForUpdate(JsonCommand command) {
|
||||
final JsonElement jsonElement = this.fromApiJsonHelper.parse(command.json());
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
||||
|
||||
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
|
||||
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, command.json(), this.supportedParametersForUpdate);
|
||||
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
||||
.resource("repayment-with-post-dated-checks");
|
||||
|
||||
if (!command.parameterExists("locale")) {
|
||||
baseDataValidator.reset().parameter("locale").notNull().failWithCode("locale.not.exists");
|
||||
} else {
|
||||
final String locale = this.fromApiJsonHelper.extractStringNamed("locale", jsonElement);
|
||||
baseDataValidator.reset().parameter("locale").value(locale).notNull();
|
||||
}
|
||||
|
||||
if (command.parameterExists("amount")) {
|
||||
final BigDecimal amount = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed("amount", jsonElement);
|
||||
baseDataValidator.reset().parameter("amount").value(amount).notNull().positiveAmount();
|
||||
}
|
||||
|
||||
if (command.parameterExists("accountNo")) {
|
||||
final Long accountNo = this.fromApiJsonHelper.extractLongNamed("accountNo", jsonElement);
|
||||
baseDataValidator.reset().parameter("accountNo").value(accountNo).notNull().positiveAmount();
|
||||
}
|
||||
|
||||
if (command.parameterExists("name")) {
|
||||
final String name = this.fromApiJsonHelper.extractStringNamed("name", jsonElement);
|
||||
baseDataValidator.reset().parameter("name").value(name).notNull();
|
||||
}
|
||||
|
||||
if (!dataValidationErrors.isEmpty()) {
|
||||
throw new PlatformApiDataValidationException(dataValidationErrors);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult deletePostDatedChecks(final JsonCommand command) {
|
||||
this.postDatedChecksRepository.deleteById(command.entityId());
|
||||
return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withLoanId(command.getLoanId())
|
||||
.withEntityId(command.entityId()).build();
|
||||
}
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
--
|
||||
-- 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.
|
||||
--
|
||||
|
||||
-- create m_repayment_with_post_dated_checks management
|
||||
CREATE TABLE `m_repayment_with_post_dated_checks` (
|
||||
`id` bigint(20) NOT NULL AUTO_INCREMENT,
|
||||
`check_no` bigint(20) NOT NULL UNIQUE,
|
||||
`amount` decimal(20,5) NOT NULL,
|
||||
`loan_id` bigint(20) DEFAULT NULL,
|
||||
`repayment_id` bigint(20) DEFAULT NULL,
|
||||
`account_no` bigint(20) NOT NULL,
|
||||
`bank_name` VARCHAR(200) NOT NULL,
|
||||
`repayment_date` DATE NOT NULL,
|
||||
`status` SMALLINT(1) DEFAULT 0,
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
CONSTRAINT `fkloanrepayment` FOREIGN KEY (`loan_id`) REFERENCES `m_loan` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
CONSTRAINT `fkrepaymentwithpostdated` FOREIGN KEY (`repayment_id`) REFERENCES `m_loan_repayment_schedule` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
INSERT INTO `m_permission`
|
||||
(`grouping`,`code`,`entity_name`,`action_name`,`can_maker_checker`) VALUES
|
||||
('portfolio', 'UPDATE_REPAYMENT_WITH_POSTDATEDCHECKS', 'REPAYMENT_WITH_POSTDATEDCHECKS', 'UPDATE', '0'),
|
||||
('portfolio', 'DELETE_REPAYMENT_WITH_POSTDATEDCHECKS', 'REPAYMENT_WITH_POSTDATEDCHECKS', 'DELETE', '0'),
|
||||
('portfolio', 'BOUNCE_REPAYMENT_WITH_POSTDATEDCHECKS', 'REPAYMENT_WITH_POSTDATEDCHECKS', 'BOUNCE', '0');
|
||||
+183
@@ -0,0 +1,183 @@
|
||||
/**
|
||||
* 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.integrationtests;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import io.restassured.builder.RequestSpecBuilder;
|
||||
import io.restassured.builder.ResponseSpecBuilder;
|
||||
import io.restassured.http.ContentType;
|
||||
import io.restassured.specification.RequestSpecification;
|
||||
import io.restassured.specification.ResponseSpecification;
|
||||
import java.math.BigDecimal;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import org.apache.fineract.integrationtests.common.ClientHelper;
|
||||
import org.apache.fineract.integrationtests.common.CollateralManagementHelper;
|
||||
import org.apache.fineract.integrationtests.common.PaymentTypeDomain;
|
||||
import org.apache.fineract.integrationtests.common.PaymentTypeHelper;
|
||||
import org.apache.fineract.integrationtests.common.Utils;
|
||||
import org.apache.fineract.integrationtests.common.loans.LoanApplicationTestBuilder;
|
||||
import org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder;
|
||||
import org.apache.fineract.integrationtests.common.loans.LoanStatusChecker;
|
||||
import org.apache.fineract.integrationtests.common.loans.LoanTransactionHelper;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class RepaymentWithPostDatedChecksTest {
|
||||
|
||||
private ResponseSpecification responseSpec;
|
||||
private RequestSpecification requestSpec;
|
||||
private final SimpleDateFormat dateFormatterStandard = new SimpleDateFormat("dd MMMM yyyy");
|
||||
private LoanTransactionHelper loanTransactionHelper;
|
||||
|
||||
@BeforeEach
|
||||
public void setup() {
|
||||
Utils.initializeRESTAssured();
|
||||
this.requestSpec = new RequestSpecBuilder().setContentType(ContentType.JSON).build();
|
||||
this.requestSpec.header("Authorization", "Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey());
|
||||
this.responseSpec = new ResponseSpecBuilder().expectStatusCode(200).build();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRepaymentWithPostDatedChecks() {
|
||||
this.loanTransactionHelper = new LoanTransactionHelper(requestSpec, responseSpec);
|
||||
|
||||
Calendar meetingCalendar = Calendar.getInstance();
|
||||
meetingCalendar.set(2012, 3, 4);
|
||||
|
||||
final String disbursalDate = this.dateFormatterStandard.format(meetingCalendar.getTime());
|
||||
|
||||
final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec);
|
||||
Assertions.assertNotNull(clientID);
|
||||
ClientHelper.verifyClientCreatedOnServer(this.requestSpec, this.responseSpec, clientID);
|
||||
|
||||
final Integer loanProductID = this.loanTransactionHelper.getLoanProductId(new LoanProductTestBuilder().build(null));
|
||||
Assertions.assertNotNull(loanProductID, "Could not create Loan Product");
|
||||
|
||||
final Integer loanID = applyForLoanApplication(clientID, loanProductID, "8000");
|
||||
Assertions.assertNotNull(loanID, "Could not create Loan Account");
|
||||
|
||||
HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(this.requestSpec, this.responseSpec, loanID);
|
||||
|
||||
LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
|
||||
|
||||
// Test for loan account is created, can be approved
|
||||
this.loanTransactionHelper.approveLoan(disbursalDate, loanID);
|
||||
loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(this.requestSpec, this.responseSpec, loanID);
|
||||
LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap);
|
||||
|
||||
// Get repayments
|
||||
final ArrayList<HashMap> installmentData = this.loanTransactionHelper.getRepayments(loanID);
|
||||
Assertions.assertNotNull(installmentData, "Empty Installment Data");
|
||||
List<HashMap> postDatedChecks = new ArrayList<>();
|
||||
Gson gson = new Gson();
|
||||
|
||||
DateFormat dateFormat = new SimpleDateFormat("dd MMMM yyyy");
|
||||
dateFormat.setTimeZone(Utils.getTimeZoneOfTenant());
|
||||
|
||||
// Get the first installment date
|
||||
ArrayList installmentDate = (ArrayList) installmentData.get(0).get("date");
|
||||
Assertions.assertNotNull(installmentDate);
|
||||
Assertions.assertEquals(3, installmentDate.size());
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.set((Integer) installmentDate.get(0), (Integer) installmentDate.get(1) - 1, (Integer) installmentDate.get(2));
|
||||
final String LOAN_REPAYMENT_DATE = dateFormat.format(calendar.getTime());
|
||||
Float firstInstallmentAmount = (Float) installmentData.get(0).get("amount");
|
||||
|
||||
for (int i = 0; i < installmentData.size(); i++) {
|
||||
String result = gson.toJson(installmentData.get(i));
|
||||
JsonObject reportObject = JsonParser.parseString(result).getAsJsonObject();
|
||||
final Integer installmentId = reportObject.get("installmentId").getAsInt();
|
||||
final BigDecimal amount = reportObject.get("amount").getAsBigDecimal();
|
||||
postDatedChecks.add(postDatedCheck(installmentId, amount));
|
||||
}
|
||||
|
||||
Assertions.assertNotNull(postDatedChecks);
|
||||
|
||||
// Test for loan account approved can be disbursed
|
||||
this.loanTransactionHelper.disburseLoanWithPostDatedChecks(disbursalDate, loanID, BigDecimal.valueOf(8000), postDatedChecks);
|
||||
loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(this.requestSpec, this.responseSpec, loanID);
|
||||
LoanStatusChecker.verifyLoanIsActive(loanStatusHashMap);
|
||||
|
||||
// Create payment type PDC - Post Dated Checks
|
||||
String name = "PDC";
|
||||
String description = PaymentTypeHelper.randomNameGenerator("PDC", 15);
|
||||
Boolean isCashPayment = false;
|
||||
Integer position = 1;
|
||||
|
||||
Integer paymentTypeId = PaymentTypeHelper.createPaymentType(requestSpec, responseSpec, name, description, isCashPayment, position);
|
||||
Assertions.assertNotNull(paymentTypeId);
|
||||
PaymentTypeHelper.verifyPaymentTypeCreatedOnServer(requestSpec, responseSpec, paymentTypeId);
|
||||
PaymentTypeDomain paymentTypeResponse = PaymentTypeHelper.retrieveById(requestSpec, responseSpec, paymentTypeId);
|
||||
Assertions.assertEquals(name, paymentTypeResponse.getName());
|
||||
|
||||
// Repay for the installment 1 using post dated check
|
||||
HashMap postDatedCheck = this.loanTransactionHelper.getPostDatedCheck(loanID, Integer.valueOf(1));
|
||||
Assertions.assertNotNull(postDatedCheck);
|
||||
Assertions.assertNotNull(Float.parseFloat(String.valueOf(postDatedCheck.get("amount"))));
|
||||
|
||||
this.loanTransactionHelper.makeRepaymentWithPDC(LOAN_REPAYMENT_DATE, firstInstallmentAmount, loanID, paymentTypeId);
|
||||
}
|
||||
|
||||
private Integer applyForLoanApplication(final Integer clientID, final Integer loanProductID, final String proposedAmount) {
|
||||
List<HashMap> collaterals = new ArrayList<>();
|
||||
final Integer collateralId = CollateralManagementHelper.createCollateralProduct(this.requestSpec, this.responseSpec);
|
||||
Assertions.assertNotNull(collateralId);
|
||||
final Integer clientCollateralId = CollateralManagementHelper.createClientCollateral(this.requestSpec, this.responseSpec,
|
||||
clientID.toString(), collateralId);
|
||||
Assertions.assertNotNull(clientCollateralId);
|
||||
addCollaterals(collaterals, clientCollateralId, BigDecimal.valueOf(1));
|
||||
final String loanApplication = new LoanApplicationTestBuilder().withPrincipal(proposedAmount).withLoanTermFrequency("5")
|
||||
.withLoanTermFrequencyAsMonths().withNumberOfRepayments("5").withRepaymentEveryAfter("1")
|
||||
.withRepaymentFrequencyTypeAsMonths().withInterestRatePerPeriod("2").withExpectedDisbursementDate("04 April 2012")
|
||||
.withCollaterals(collaterals).withSubmittedOnDate("02 April 2012")
|
||||
.build(clientID.toString(), loanProductID.toString(), null);
|
||||
return this.loanTransactionHelper.getLoanId(loanApplication);
|
||||
}
|
||||
|
||||
private void addCollaterals(List<HashMap> collaterals, Integer collateralId, BigDecimal quantity) {
|
||||
collaterals.add(collaterals(collateralId, quantity));
|
||||
}
|
||||
|
||||
private HashMap<String, String> collaterals(Integer collateralId, BigDecimal quantity) {
|
||||
HashMap<String, String> collateral = new HashMap<String, String>(2);
|
||||
collateral.put("clientCollateralId", collateralId.toString());
|
||||
collateral.put("quantity", quantity.toString());
|
||||
return collateral;
|
||||
}
|
||||
|
||||
private HashMap<String, String> postDatedCheck(final Integer installmentId, final BigDecimal amount) {
|
||||
HashMap<String, String> map = new HashMap<String, String>();
|
||||
map.put("installmentId", installmentId.toString());
|
||||
map.put("name", "AMANA BANK");
|
||||
map.put("amount", amount.toString());
|
||||
map.put("accountNo", "900400500621");
|
||||
map.put("checkNo", Utils.randomNumberGenerator(12).toString());
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
}
|
||||
+51
@@ -28,6 +28,7 @@ import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
@@ -165,6 +166,12 @@ public class LoanTransactionHelper {
|
||||
return Utils.performServerGet(requestSpec, responseSpec, GET_LOAN_CHARGES_URL, "");
|
||||
}
|
||||
|
||||
public ArrayList<HashMap> getRepayments(final Integer loanId) {
|
||||
final String GET_REPAYMENTS_URL = "/fineract-provider/api/v1/loans/" + loanId + "/transactions/template?command=disburse&"
|
||||
+ Utils.TENANT_IDENTIFIER;
|
||||
return Utils.performServerGet(requestSpec, responseSpec, GET_REPAYMENTS_URL, "loanRepaymentScheduleInstallments");
|
||||
}
|
||||
|
||||
public HashMap approveLoan(final String approvalDate, final Integer loanID) {
|
||||
String loanApprovalCommand = createLoanOperationURL(APPROVE_LOAN_COMMAND, loanID);
|
||||
String loanApprovalRequest = getApproveLoanAsJSON(approvalDate);
|
||||
@@ -203,6 +210,28 @@ public class LoanTransactionHelper {
|
||||
return performLoanTransaction(createLoanOperationURL(DISBURSE_LOAN_COMMAND, loanID), getDisburseLoanAsJSON(date, null));
|
||||
}
|
||||
|
||||
public HashMap disburseLoanWithPostDatedChecks(final String date, final Integer loanId, final BigDecimal transactionAmount,
|
||||
final List<HashMap> postDatedChecks) {
|
||||
return performLoanTransaction(createLoanOperationURL(DISBURSE_LOAN_COMMAND, loanId),
|
||||
getDisburseLoanWithPostDatedChecksAsJSON(date, transactionAmount.toString(), postDatedChecks));
|
||||
}
|
||||
|
||||
private String getDisburseLoanWithPostDatedChecksAsJSON(final String actualDisbursementDate, final String transactionAmount,
|
||||
final List<HashMap> postDatedChecks) {
|
||||
final HashMap<String, Object> map = new HashMap<String, Object>();
|
||||
map.put("locale", "en");
|
||||
map.put("dateFormat", "dd MMMM yyyy");
|
||||
map.put("actualDisbursementDate", actualDisbursementDate);
|
||||
map.put("note", "DISBURSE NOTE");
|
||||
if (transactionAmount != null) {
|
||||
map.put("transactionAmount", transactionAmount);
|
||||
}
|
||||
|
||||
map.put("postDatedChecks", postDatedChecks);
|
||||
LOG.info("Loan Application disburse request : {} ", map);
|
||||
return new Gson().toJson(map);
|
||||
}
|
||||
|
||||
public HashMap disburseLoanWithRepaymentReschedule(final String date, final Integer loanID, String adjustRepaymentDate) {
|
||||
return performLoanTransaction(createLoanOperationURL(DISBURSE_LOAN_COMMAND, loanID),
|
||||
getDisburseLoanWithRepaymentRescheduleAsJSON(date, null, adjustRepaymentDate));
|
||||
@@ -291,6 +320,11 @@ public class LoanTransactionHelper {
|
||||
getRepaymentBodyAsJSON(date, amountToBePaid), "");
|
||||
}
|
||||
|
||||
public HashMap makeRepaymentWithPDC(final String date, final Float amountToBePaid, final Integer loanID, final Integer paymentType) {
|
||||
return (HashMap) performLoanTransaction(createLoanTransactionURL(MAKE_REPAYMENT_COMMAND, loanID),
|
||||
getRepaymentWithPDCBodyAsJSON(date, amountToBePaid, paymentType), "");
|
||||
}
|
||||
|
||||
public HashMap forecloseLoan(final String transactionDate, final Integer loanID) {
|
||||
return (HashMap) performLoanTransaction(createLoanTransactionURL(FORECLOSURE_COMMAND, loanID),
|
||||
getForeclosureBodyAsJSON(transactionDate, loanID), "");
|
||||
@@ -367,6 +401,12 @@ public class LoanTransactionHelper {
|
||||
return Utils.performServerGet(requestSpec, responseSpec, GET_LOAN_CHARGES_URL, "");
|
||||
}
|
||||
|
||||
public HashMap getPostDatedCheck(final Integer loanId, final Integer installmentId) {
|
||||
final String GET_POST_DATED_TRANS_URL = "/fineract-provider/api/v1/loans/" + loanId + "/postdatedchecks/" + installmentId + "?"
|
||||
+ Utils.TENANT_IDENTIFIER;
|
||||
return Utils.performServerGet(requestSpec, responseSpec, GET_POST_DATED_TRANS_URL, "");
|
||||
}
|
||||
|
||||
private String getDisburseLoanAsJSON(final String actualDisbursementDate, final String transactionAmount) {
|
||||
final HashMap<String, String> map = new HashMap<>();
|
||||
map.put("locale", "en");
|
||||
@@ -444,6 +484,17 @@ public class LoanTransactionHelper {
|
||||
return new Gson().toJson(map);
|
||||
}
|
||||
|
||||
private String getRepaymentWithPDCBodyAsJSON(final String transactionDate, final Float transactionAmount, final Integer paymentTypeId) {
|
||||
final HashMap<String, String> map = new HashMap<>();
|
||||
map.put("locale", "en");
|
||||
map.put("paymentTypeId", paymentTypeId.toString());
|
||||
map.put("dateFormat", "dd MMMM yyyy");
|
||||
map.put("transactionDate", transactionDate);
|
||||
map.put("transactionAmount", transactionAmount.toString());
|
||||
map.put("note", "Repayment Made!!!");
|
||||
return new Gson().toJson(map);
|
||||
}
|
||||
|
||||
private String getForeclosureBodyAsJSON(final String transactionDate, final Integer loanId) {
|
||||
final HashMap<String, Object> map = new HashMap<>();
|
||||
map.put("locale", "en");
|
||||
|
||||
Reference in New Issue
Block a user