FINERACT-1734: New business events and refactorings
This commit is contained in:
committed by
Arnold Gálovics
parent
d06c3655af
commit
130d9c0c3d
@@ -524,17 +524,6 @@
|
||||
"org.apache.fineract.avro.portfolio.v1.PortfolioAccountDataV1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"default": null,
|
||||
"name": "accountLinkingOptions",
|
||||
"type": [
|
||||
"null",
|
||||
{
|
||||
"type": "array",
|
||||
"items": "org.apache.fineract.avro.portfolio.v1.PortfolioAccountDataV1"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"default": null,
|
||||
"name": "multiDisburseLoan",
|
||||
@@ -637,6 +626,14 @@
|
||||
"bigdecimal"
|
||||
]
|
||||
},
|
||||
{
|
||||
"default": null,
|
||||
"name": "product",
|
||||
"type": [
|
||||
"null",
|
||||
"org.apache.fineract.avro.loan.v1.LoanProductDataV1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"default": null,
|
||||
"name": "inArrears",
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"name": "LoanChargeDeletedV1",
|
||||
"namespace": "org.apache.fineract.avro.loan.v1",
|
||||
"type": "record",
|
||||
"fields": [
|
||||
{
|
||||
"default": null,
|
||||
"name": "id",
|
||||
"type": [
|
||||
"null",
|
||||
"long"
|
||||
]
|
||||
},
|
||||
{
|
||||
"default": null,
|
||||
"name": "chargeId",
|
||||
"type": [
|
||||
"null",
|
||||
"long"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"name": "LoanTransactionWithLoanV1",
|
||||
"namespace": "org.apache.fineract.avro.loan.v1",
|
||||
"type": "record",
|
||||
"fields": [
|
||||
{
|
||||
"default": null,
|
||||
"name": "loan",
|
||||
"type": [
|
||||
"null",
|
||||
"org.apache.fineract.avro.loan.v1.LoanAccountDataV1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"default": null,
|
||||
"name": "loanTransaction",
|
||||
"type": [
|
||||
"null",
|
||||
"org.apache.fineract.avro.loan.v1.LoanTransactionDataV1"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -29,3 +29,5 @@ include::technology.adoc[leveloffset=+1]
|
||||
include::modules.adoc[leveloffset=+1]
|
||||
|
||||
include::business-date.adoc[leveloffset=+1]
|
||||
|
||||
include::reliable-event-framework.adoc[leveloffset=+1]
|
||||
|
||||
+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.infrastructure.event.business.domain.loan;
|
||||
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
|
||||
public class LoanRescheduledDueCalendarChangeBusinessEvent extends LoanBusinessEvent {
|
||||
|
||||
public LoanRescheduledDueCalendarChangeBusinessEvent(Loan value) {
|
||||
super(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return "LoanRescheduledDueCalendarChangeBusinessEvent";
|
||||
}
|
||||
}
|
||||
+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.infrastructure.event.business.domain.loan;
|
||||
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
|
||||
public class LoanRescheduledDueHolidayBusinessEvent extends LoanBusinessEvent {
|
||||
|
||||
public LoanRescheduledDueHolidayBusinessEvent(Loan value) {
|
||||
super(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return "LoanRescheduledDueHolidayBusinessEvent";
|
||||
}
|
||||
}
|
||||
+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.infrastructure.event.business.domain.loan;
|
||||
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
|
||||
public class LoanScheduleVariationsAddedBusinessEvent extends LoanBusinessEvent {
|
||||
|
||||
public LoanScheduleVariationsAddedBusinessEvent(Loan value) {
|
||||
super(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return "LoanScheduleVariationsAddedBusinessEvent";
|
||||
}
|
||||
}
|
||||
+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.infrastructure.event.business.domain.loan;
|
||||
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
|
||||
public class LoanScheduleVariationsDeletedBusinessEvent extends LoanBusinessEvent {
|
||||
|
||||
public LoanScheduleVariationsDeletedBusinessEvent(Loan value) {
|
||||
super(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return "LoanScheduleVariationsDeletedBusinessEvent";
|
||||
}
|
||||
}
|
||||
+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.infrastructure.event.business.domain.loan;
|
||||
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
|
||||
public class LoanStatusChangedBusinessEvent extends LoanBusinessEvent {
|
||||
|
||||
public LoanStatusChangedBusinessEvent(Loan value) {
|
||||
super(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return "LoanStatusChangedBusinessEvent";
|
||||
}
|
||||
}
|
||||
+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.infrastructure.event.business.domain.loan;
|
||||
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
|
||||
public class LoanUpdateDisbursementDataBusinessEvent extends LoanBusinessEvent {
|
||||
|
||||
public LoanUpdateDisbursementDataBusinessEvent(Loan value) {
|
||||
super(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return "LoanUpdateDisbursementDataBusinessEvent";
|
||||
}
|
||||
}
|
||||
+14
@@ -19,6 +19,8 @@
|
||||
package org.apache.fineract.infrastructure.event.external.service;
|
||||
|
||||
import java.io.IOException;
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.PersistenceContext;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.fineract.infrastructure.event.business.domain.BusinessEvent;
|
||||
import org.apache.fineract.infrastructure.event.external.repository.ExternalEventRepository;
|
||||
@@ -38,6 +40,8 @@ public class ExternalEventService {
|
||||
private final ExternalEventIdempotencyKeyGenerator idempotencyKeyGenerator;
|
||||
private final BusinessEventSerializerFactory serializerFactory;
|
||||
|
||||
private EntityManager entityManager;
|
||||
|
||||
public <T> void postEvent(BusinessEvent<T> event) {
|
||||
if (event == null) {
|
||||
throw new IllegalArgumentException("event cannot be null");
|
||||
@@ -48,6 +52,7 @@ public class ExternalEventService {
|
||||
try {
|
||||
BusinessEventSerializer serializer = serializerFactory.create(event);
|
||||
String schema = serializer.getSupportedSchema().getName();
|
||||
flushChangesBeforeSerialization();
|
||||
byte[] data = serializer.serialize(event);
|
||||
ExternalEvent externalEvent = new ExternalEvent(eventType, schema, data, idempotencyKey);
|
||||
|
||||
@@ -57,4 +62,13 @@ public class ExternalEventService {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void flushChangesBeforeSerialization() {
|
||||
entityManager.flush();
|
||||
}
|
||||
|
||||
@PersistenceContext
|
||||
public void setEntityManager(EntityManager entityManager) {
|
||||
this.entityManager = entityManager;
|
||||
}
|
||||
}
|
||||
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.infrastructure.event.external.service.serialization.serializer.loan;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.avro.generic.GenericContainer;
|
||||
import org.apache.fineract.avro.loan.v1.LoanChargeDeletedV1;
|
||||
import org.apache.fineract.infrastructure.event.business.domain.BusinessEvent;
|
||||
import org.apache.fineract.infrastructure.event.business.domain.loan.charge.LoanDeleteChargeBusinessEvent;
|
||||
import org.apache.fineract.infrastructure.event.external.service.serialization.serializer.BusinessEventSerializer;
|
||||
import org.apache.fineract.infrastructure.event.external.service.support.ByteBufferConverter;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
@Order(Ordered.LOWEST_PRECEDENCE - 1)
|
||||
public class LoanChargeDeletedBusinessEventSerializer implements BusinessEventSerializer {
|
||||
|
||||
private final ByteBufferConverter byteBufferConverter;
|
||||
|
||||
@Override
|
||||
public <T> boolean canSerialize(BusinessEvent<T> event) {
|
||||
return event instanceof LoanDeleteChargeBusinessEvent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> byte[] serialize(BusinessEvent<T> rawEvent) throws IOException {
|
||||
LoanDeleteChargeBusinessEvent event = (LoanDeleteChargeBusinessEvent) rawEvent;
|
||||
LoanCharge loanCharge = event.get();
|
||||
Long id = loanCharge.getId();
|
||||
Long chargeId = loanCharge.getCharge().getId();
|
||||
LoanChargeDeletedV1 avroDto = new LoanChargeDeletedV1(id, chargeId);
|
||||
ByteBuffer buffer = avroDto.toByteBuffer();
|
||||
return byteBufferConverter.convert(buffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends GenericContainer> getSupportedSchema() {
|
||||
return LoanChargeDeletedV1.class;
|
||||
}
|
||||
}
|
||||
+13
-3
@@ -22,12 +22,16 @@ import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.avro.generic.GenericContainer;
|
||||
import org.apache.fineract.avro.loan.v1.LoanAccountDataV1;
|
||||
import org.apache.fineract.avro.loan.v1.LoanTransactionDataV1;
|
||||
import org.apache.fineract.avro.loan.v1.LoanTransactionWithLoanV1;
|
||||
import org.apache.fineract.infrastructure.event.business.domain.BusinessEvent;
|
||||
import org.apache.fineract.infrastructure.event.business.domain.loan.transaction.LoanTransactionBusinessEvent;
|
||||
import org.apache.fineract.infrastructure.event.external.service.serialization.mapper.loan.LoanAccountDataMapper;
|
||||
import org.apache.fineract.infrastructure.event.external.service.serialization.mapper.loan.LoanTransactionDataMapper;
|
||||
import org.apache.fineract.infrastructure.event.external.service.serialization.serializer.BusinessEventSerializer;
|
||||
import org.apache.fineract.infrastructure.event.external.service.support.ByteBufferConverter;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.LoanAccountData;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.LoanTransactionData;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanReadPlatformService;
|
||||
import org.springframework.stereotype.Component;
|
||||
@@ -37,7 +41,8 @@ import org.springframework.stereotype.Component;
|
||||
public class LoanTransactionBusinessEventSerializer implements BusinessEventSerializer {
|
||||
|
||||
private final LoanReadPlatformService service;
|
||||
private final LoanTransactionDataMapper mapper;
|
||||
private final LoanAccountDataMapper loanMapper;
|
||||
private final LoanTransactionDataMapper loanTransactionMapper;
|
||||
private final ByteBufferConverter byteBufferConverter;
|
||||
|
||||
@Override
|
||||
@@ -48,8 +53,13 @@ public class LoanTransactionBusinessEventSerializer implements BusinessEventSeri
|
||||
@Override
|
||||
public <T> byte[] serialize(BusinessEvent<T> rawEvent) throws IOException {
|
||||
LoanTransactionBusinessEvent event = (LoanTransactionBusinessEvent) rawEvent;
|
||||
LoanTransactionData data = service.retrieveLoanTransaction(event.get().getLoan().getId(), event.get().getId());
|
||||
LoanTransactionDataV1 avroDto = mapper.map(data);
|
||||
Long loanId = event.get().getLoan().getId();
|
||||
LoanAccountData loanData = service.retrieveOne(loanId);
|
||||
LoanAccountDataV1 loanAvroDto = loanMapper.map(loanData);
|
||||
Long loanTransactionId = event.get().getId();
|
||||
LoanTransactionData transactionData = service.retrieveLoanTransaction(loanId, loanTransactionId);
|
||||
LoanTransactionDataV1 loanTransactionAvroDto = loanTransactionMapper.map(transactionData);
|
||||
LoanTransactionWithLoanV1 avroDto = new LoanTransactionWithLoanV1(loanAvroDto, loanTransactionAvroDto);
|
||||
ByteBuffer buffer = avroDto.toByteBuffer();
|
||||
return byteBufferConverter.convert(buffer);
|
||||
}
|
||||
|
||||
+18
@@ -18,13 +18,22 @@
|
||||
*/
|
||||
package org.apache.fineract.portfolio.loanaccount.domain;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.fineract.infrastructure.event.business.domain.loan.LoanStatusChangedBusinessEvent;
|
||||
import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService;
|
||||
|
||||
// TODO: introduce tests for the state machine
|
||||
@RequiredArgsConstructor
|
||||
public class DefaultLoanLifecycleStateMachine implements LoanLifecycleStateMachine {
|
||||
|
||||
private final List<LoanStatus> allowedLoanStatuses;
|
||||
private final BusinessEventNotifierService businessEventNotifierService;
|
||||
|
||||
public DefaultLoanLifecycleStateMachine(LoanStatus[] allowedLoanStatuses, BusinessEventNotifierService businessEventNotifierService) {
|
||||
this(Arrays.asList(allowedLoanStatuses), businessEventNotifierService);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoanStatus dryTransition(final LoanEvent loanEvent, final Loan loan) {
|
||||
@@ -35,6 +44,15 @@ public class DefaultLoanLifecycleStateMachine implements LoanLifecycleStateMachi
|
||||
public void transition(final LoanEvent loanEvent, final Loan loan) {
|
||||
LoanStatus newState = getNextState(loanEvent, loan);
|
||||
loan.setLoanStatus(newState.getValue());
|
||||
|
||||
if (isNotLoanCreation(loanEvent)) {
|
||||
// in case of Loan creation, a LoanCreatedBusinessEvent is also raised, no need to send a status change
|
||||
businessEventNotifierService.notifyPostBusinessEvent(new LoanStatusChangedBusinessEvent(loan));
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isNotLoanCreation(LoanEvent loanEvent) {
|
||||
return !LoanEvent.LOAN_CREATED.equals(loanEvent);
|
||||
}
|
||||
|
||||
private LoanStatus getNextState(LoanEvent loanEvent, Loan loan) {
|
||||
|
||||
+4
-83
@@ -122,12 +122,10 @@ import org.apache.fineract.portfolio.loanaccount.exception.MultiDisbursementData
|
||||
import org.apache.fineract.portfolio.loanaccount.exception.UndoLastTrancheDisbursementException;
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanScheduleDTO;
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.AprCalculator;
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.DefaultScheduledDateGenerator;
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanApplicationTerms;
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleGenerator;
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModel;
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModelPeriod;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanUtilService;
|
||||
import org.apache.fineract.portfolio.loanproduct.domain.AmortizationMethod;
|
||||
import org.apache.fineract.portfolio.loanproduct.domain.InterestCalculationPeriodMethod;
|
||||
import org.apache.fineract.portfolio.loanproduct.domain.InterestMethod;
|
||||
@@ -2406,12 +2404,8 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
||||
public ChangedTransactionDetail disburse(final AppUser currentUser, final JsonCommand command, final Map<String, Object> actualChanges,
|
||||
final ScheduleGeneratorDTO scheduleGeneratorDTO, final PaymentDetail paymentDetail) {
|
||||
|
||||
this.loanLifecycleStateMachine.transition(LoanEvent.LOAN_DISBURSED, this);
|
||||
|
||||
final LocalDate actualDisbursementDate = command.localDateValueOfParameterNamed("actualDisbursementDate");
|
||||
|
||||
actualChanges.put("status", LoanEnumerations.status(this.loanStatus));
|
||||
|
||||
this.disbursedBy = currentUser;
|
||||
updateLoanScheduleDependentDerivedFields();
|
||||
|
||||
@@ -2446,7 +2440,10 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
||||
addLoanTransaction(interestAppliedTransaction);
|
||||
}
|
||||
|
||||
return reprocessTransactionForDisbursement();
|
||||
ChangedTransactionDetail result = reprocessTransactionForDisbursement();
|
||||
this.loanLifecycleStateMachine.transition(LoanEvent.LOAN_DISBURSED, this);
|
||||
actualChanges.put("status", LoanEnumerations.status(this.loanStatus));
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
@@ -4597,82 +4594,6 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
||||
// startDate
|
||||
}
|
||||
|
||||
public void applyHolidayToRepaymentScheduleDates(final Holiday holiday, final LoanUtilService loanUtilService) {
|
||||
final DefaultScheduledDateGenerator scheduledDateGenerator = new DefaultScheduledDateGenerator();
|
||||
ScheduleGeneratorDTO scheduleGeneratorDTO = loanUtilService.buildScheduleGeneratorDTO(this, holiday.getFromDateLocalDate());
|
||||
final LoanApplicationTerms loanApplicationTerms = this.constructLoanApplicationTerms(scheduleGeneratorDTO);
|
||||
|
||||
// LocalDate rescheduleFromDate = holiday.getFromDateLocalDate();
|
||||
LocalDate adjustedRescheduleToDate = null;
|
||||
|
||||
if (holiday.getReScheduleType().isResheduleToNextRepaymentDate()) {
|
||||
final LocalDate rescheduleToDate = holiday.getToDateLocalDate();
|
||||
for (final LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment : this.getRepaymentScheduleInstallments()) {
|
||||
if (rescheduleToDate.isEqual(loanRepaymentScheduleInstallment.getDueDate())) {
|
||||
adjustedRescheduleToDate = rescheduleToDate;
|
||||
break;
|
||||
} else {
|
||||
// Account for a Bimonthly Loan Product
|
||||
// if (loanApplicationTerms.getRepaymentPeriodFrequencyType().isSemiMonthly()) {
|
||||
// if (rescheduleToDate.isAfter(loanRepaymentScheduleInstallment.getDueDate())
|
||||
// && rescheduleToDate.isBefore(loanRepaymentScheduleInstallment.getDueDate().plusDays(15))) {
|
||||
// adjustedRescheduleToDate = loanRepaymentScheduleInstallment.getDueDate();
|
||||
// break;
|
||||
// }
|
||||
// } else {
|
||||
// // Once Bimonthly product implemented, Replace the `Standard Monthly Loan Holiday check` below
|
||||
// HERE
|
||||
// if (rescheduleToDate.isAfter(loanRepaymentScheduleInstallment.getDueDate())
|
||||
// && rescheduleToDate.isBefore(loanRepaymentScheduleInstallment.getDueDate().plusDays(30))) {
|
||||
// adjustedRescheduleToDate = loanRepaymentScheduleInstallment.getDueDate();
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
|
||||
// Standard Monthly Loan Holiday check
|
||||
if (rescheduleToDate.isAfter(loanRepaymentScheduleInstallment.getDueDate())
|
||||
&& rescheduleToDate.isBefore(loanRepaymentScheduleInstallment.getDueDate().plusDays(30))) {
|
||||
adjustedRescheduleToDate = loanRepaymentScheduleInstallment.getDueDate();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
adjustedRescheduleToDate = holiday.getRepaymentsRescheduledToLocalDate();
|
||||
}
|
||||
|
||||
// first repayment's from date is same as disbursement date.
|
||||
LocalDate tmpFromDate = getDisbursementDate();
|
||||
|
||||
// Loop through all loanRepayments
|
||||
List<LoanRepaymentScheduleInstallment> installments = getRepaymentScheduleInstallments();
|
||||
for (final LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment : installments) {
|
||||
|
||||
if (adjustedRescheduleToDate == null) {
|
||||
break;
|
||||
}
|
||||
|
||||
final LocalDate oldDueDate = loanRepaymentScheduleInstallment.getDueDate();
|
||||
|
||||
// update from date if it's not same as previous installament's due
|
||||
// date.
|
||||
if (!loanRepaymentScheduleInstallment.getFromDate().isEqual(tmpFromDate)) {
|
||||
loanRepaymentScheduleInstallment.updateFromDate(tmpFromDate);
|
||||
}
|
||||
|
||||
if (oldDueDate.equals(holiday.getFromDateLocalDate()) || oldDueDate.isAfter(holiday.getFromDateLocalDate())) {
|
||||
// FIXME: AA do we need to apply non-working days.
|
||||
// Assuming holiday's repayment reschedule to date cannot be
|
||||
// created on a non-working day.
|
||||
|
||||
adjustedRescheduleToDate = scheduledDateGenerator.generateNextRepaymentDate(adjustedRescheduleToDate, loanApplicationTerms,
|
||||
false);
|
||||
loanRepaymentScheduleInstallment.updateDueDate(adjustedRescheduleToDate);
|
||||
}
|
||||
tmpFromDate = loanRepaymentScheduleInstallment.getDueDate();
|
||||
}
|
||||
}
|
||||
|
||||
private void validateDisbursementDateIsOnNonWorkingDay(final WorkingDays workingDays, final boolean allowTransactionsOnNonWorkingDay) {
|
||||
if (!allowTransactionsOnNonWorkingDay) {
|
||||
if (!WorkingDaysUtil.isWorkingDay(workingDays, getDisbursementDate())) {
|
||||
|
||||
+1
-3
@@ -21,7 +21,6 @@ package org.apache.fineract.portfolio.loanaccount.domain;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
@@ -425,8 +424,7 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
|
||||
}
|
||||
|
||||
private LoanLifecycleStateMachine defaultLoanLifecycleStateMachine() {
|
||||
final List<LoanStatus> allowedLoanStatuses = Arrays.asList(LoanStatus.values());
|
||||
return new DefaultLoanLifecycleStateMachine(allowedLoanStatuses);
|
||||
return new DefaultLoanLifecycleStateMachine(LoanStatus.values(), businessEventNotifierService);
|
||||
}
|
||||
|
||||
private void checkClientOrGroupActive(final Loan loan) {
|
||||
|
||||
+5
-22
@@ -18,11 +18,7 @@
|
||||
*/
|
||||
package org.apache.fineract.portfolio.loanaccount.jobs.applyholidaystoloans;
|
||||
|
||||
import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
|
||||
import org.apache.fineract.infrastructure.jobs.service.JobName;
|
||||
import org.apache.fineract.organisation.holiday.domain.HolidayRepositoryWrapper;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanUtilService;
|
||||
import org.springframework.batch.core.Job;
|
||||
import org.springframework.batch.core.Step;
|
||||
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
|
||||
@@ -40,28 +36,15 @@ public class ApplyHolidaysToLoansConfig {
|
||||
|
||||
@Autowired
|
||||
private StepBuilderFactory steps;
|
||||
@Autowired
|
||||
private ConfigurationDomainService configurationDomainService;
|
||||
@Autowired
|
||||
private HolidayRepositoryWrapper holidayRepository;
|
||||
@Autowired
|
||||
private LoanRepositoryWrapper loanRepositoryWrapper;
|
||||
@Autowired
|
||||
private LoanUtilService loanUtilService;
|
||||
|
||||
@Bean
|
||||
protected Step applyHolidaysToLoansStep() {
|
||||
return steps.get(JobName.APPLY_HOLIDAYS_TO_LOANS.name()).tasklet(applyHolidaysToLoansTasklet()).build();
|
||||
protected Step applyHolidaysToLoansStep(ApplyHolidaysToLoansTasklet applyHolidaysToLoansTasklet) {
|
||||
return steps.get(JobName.APPLY_HOLIDAYS_TO_LOANS.name()).tasklet(applyHolidaysToLoansTasklet).build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Job applyHolidaysToLoansJob() {
|
||||
return jobs.get(JobName.APPLY_HOLIDAYS_TO_LOANS.name()).start(applyHolidaysToLoansStep()).incrementer(new RunIdIncrementer())
|
||||
.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ApplyHolidaysToLoansTasklet applyHolidaysToLoansTasklet() {
|
||||
return new ApplyHolidaysToLoansTasklet(configurationDomainService, holidayRepository, loanRepositoryWrapper, loanUtilService);
|
||||
public Job applyHolidaysToLoansJob(ApplyHolidaysToLoansTasklet applyHolidaysToLoansTasklet) {
|
||||
return jobs.get(JobName.APPLY_HOLIDAYS_TO_LOANS.name()).start(applyHolidaysToLoansStep(applyHolidaysToLoansTasklet))
|
||||
.incrementer(new RunIdIncrementer()).build();
|
||||
}
|
||||
}
|
||||
|
||||
+87
-1
@@ -18,6 +18,7 @@
|
||||
*/
|
||||
package org.apache.fineract.portfolio.loanaccount.jobs.applyholidaystoloans;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
@@ -26,26 +27,35 @@ import java.util.Set;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
|
||||
import org.apache.fineract.infrastructure.event.business.domain.loan.LoanRescheduledDueHolidayBusinessEvent;
|
||||
import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService;
|
||||
import org.apache.fineract.organisation.holiday.domain.Holiday;
|
||||
import org.apache.fineract.organisation.holiday.domain.HolidayRepositoryWrapper;
|
||||
import org.apache.fineract.organisation.office.domain.Office;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.ScheduleGeneratorDTO;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus;
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.DefaultScheduledDateGenerator;
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanApplicationTerms;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanUtilService;
|
||||
import org.springframework.batch.core.StepContribution;
|
||||
import org.springframework.batch.core.scope.context.ChunkContext;
|
||||
import org.springframework.batch.core.step.tasklet.Tasklet;
|
||||
import org.springframework.batch.repeat.RepeatStatus;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@Component
|
||||
public class ApplyHolidaysToLoansTasklet implements Tasklet {
|
||||
|
||||
private final ConfigurationDomainService configurationDomainService;
|
||||
private final HolidayRepositoryWrapper holidayRepository;
|
||||
private final LoanRepositoryWrapper loanRepositoryWrapper;
|
||||
private final LoanUtilService loanUtilService;
|
||||
private final BusinessEventNotifierService businessEventNotifierService;
|
||||
|
||||
@Override
|
||||
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
|
||||
@@ -72,7 +82,7 @@ public class ApplyHolidaysToLoansTasklet implements Tasklet {
|
||||
loans.addAll(loanRepositoryWrapper.findByGroupOfficeIdsAndLoanStatus(officeIds, loanStatuses));
|
||||
|
||||
for (final Loan loan : loans) {
|
||||
loan.applyHolidayToRepaymentScheduleDates(holiday, loanUtilService);
|
||||
applyHolidayToRepaymentScheduleDates(loan, holiday);
|
||||
}
|
||||
loanRepositoryWrapper.save(loans);
|
||||
holiday.processed();
|
||||
@@ -80,4 +90,80 @@ public class ApplyHolidaysToLoansTasklet implements Tasklet {
|
||||
holidayRepository.save(holidays);
|
||||
return RepeatStatus.FINISHED;
|
||||
}
|
||||
|
||||
public void applyHolidayToRepaymentScheduleDates(Loan loan, Holiday holiday) {
|
||||
LocalDate adjustedRescheduleToDate = null;
|
||||
if (holiday.getReScheduleType().isResheduleToNextRepaymentDate()) {
|
||||
adjustedRescheduleToDate = getNextRepaymentDate(loan, holiday);
|
||||
} else {
|
||||
adjustedRescheduleToDate = holiday.getRepaymentsRescheduledToLocalDate();
|
||||
}
|
||||
|
||||
if (isRepaymentScheduleAdjustmentNeeded(adjustedRescheduleToDate)) {
|
||||
adjustRepaymentSchedules(loan, holiday, adjustedRescheduleToDate);
|
||||
businessEventNotifierService.notifyPostBusinessEvent(new LoanRescheduledDueHolidayBusinessEvent(loan));
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isRepaymentScheduleAdjustmentNeeded(LocalDate adjustedRescheduleToDate) {
|
||||
return adjustedRescheduleToDate != null;
|
||||
}
|
||||
|
||||
private void adjustRepaymentSchedules(Loan loan, Holiday holiday, LocalDate adjustedRescheduleToDate) {
|
||||
final DefaultScheduledDateGenerator scheduledDateGenerator = new DefaultScheduledDateGenerator();
|
||||
ScheduleGeneratorDTO scheduleGeneratorDTO = loanUtilService.buildScheduleGeneratorDTO(loan, holiday.getFromDateLocalDate());
|
||||
final LoanApplicationTerms loanApplicationTerms = loan.constructLoanApplicationTerms(scheduleGeneratorDTO);
|
||||
|
||||
// first repayment's from date is same as disbursement date.
|
||||
LocalDate tmpFromDate = loan.getDisbursementDate();
|
||||
|
||||
// Loop through all loanRepayments
|
||||
List<LoanRepaymentScheduleInstallment> installments = loan.getRepaymentScheduleInstallments();
|
||||
for (final LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment : installments) {
|
||||
|
||||
final LocalDate oldDueDate = loanRepaymentScheduleInstallment.getDueDate();
|
||||
|
||||
// update from date if it's not same as previous installment's due
|
||||
// date.
|
||||
if (!loanRepaymentScheduleInstallment.getFromDate().isEqual(tmpFromDate)) {
|
||||
loanRepaymentScheduleInstallment.updateFromDate(tmpFromDate);
|
||||
}
|
||||
|
||||
if (oldDueDate.equals(holiday.getFromDateLocalDate()) || oldDueDate.isAfter(holiday.getFromDateLocalDate())) {
|
||||
// FIXME: AA do we need to apply non-working days.
|
||||
// Assuming holiday's repayment reschedule to date cannot be
|
||||
// created on a non-working day.
|
||||
|
||||
adjustedRescheduleToDate = scheduledDateGenerator.generateNextRepaymentDate(adjustedRescheduleToDate, loanApplicationTerms,
|
||||
false);
|
||||
loanRepaymentScheduleInstallment.updateDueDate(adjustedRescheduleToDate);
|
||||
}
|
||||
tmpFromDate = loanRepaymentScheduleInstallment.getDueDate();
|
||||
}
|
||||
}
|
||||
|
||||
private LocalDate getNextRepaymentDate(Loan loan, Holiday holiday) {
|
||||
LocalDate adjustedRescheduleToDate = null;
|
||||
final LocalDate rescheduleToDate = holiday.getToDateLocalDate();
|
||||
for (final LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment : loan.getRepaymentScheduleInstallments()) {
|
||||
if (rescheduleToDate.isEqual(loanRepaymentScheduleInstallment.getDueDate())) {
|
||||
adjustedRescheduleToDate = rescheduleToDate;
|
||||
break;
|
||||
} else {
|
||||
adjustedRescheduleToDate = doStandardMonthlyCheck(adjustedRescheduleToDate, rescheduleToDate,
|
||||
loanRepaymentScheduleInstallment);
|
||||
}
|
||||
}
|
||||
return adjustedRescheduleToDate;
|
||||
}
|
||||
|
||||
private LocalDate doStandardMonthlyCheck(LocalDate adjustedRescheduleToDate, LocalDate rescheduleToDate,
|
||||
LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment) {
|
||||
// Standard Monthly Loan Holiday check
|
||||
if (rescheduleToDate.isAfter(loanRepaymentScheduleInstallment.getDueDate())
|
||||
&& rescheduleToDate.isBefore(loanRepaymentScheduleInstallment.getDueDate().plusDays(30))) {
|
||||
adjustedRescheduleToDate = loanRepaymentScheduleInstallment.getDueDate();
|
||||
}
|
||||
return adjustedRescheduleToDate;
|
||||
}
|
||||
}
|
||||
|
||||
+14
-20
@@ -23,10 +23,13 @@ import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder;
|
||||
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
|
||||
import org.apache.fineract.infrastructure.event.business.domain.loan.LoanScheduleVariationsAddedBusinessEvent;
|
||||
import org.apache.fineract.infrastructure.event.business.domain.loan.LoanScheduleVariationsDeletedBusinessEvent;
|
||||
import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.LoanTermVariationsData;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.ScheduleGeneratorDTO;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
@@ -34,41 +37,30 @@ import org.apache.fineract.portfolio.loanaccount.domain.LoanAccountDomainService
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTermVariations;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanAssembler;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanUtilService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Service
|
||||
@Transactional
|
||||
@RequiredArgsConstructor
|
||||
public class LoanScheduleWritePlatformServiceImpl implements LoanScheduleWritePlatformService {
|
||||
|
||||
private final LoanAccountDomainService loanAccountDomainService;
|
||||
private final LoanAssembler loanAssembler;
|
||||
private final LoanScheduleAssembler loanScheduleAssembler;
|
||||
private final PlatformSecurityContext context;
|
||||
private final LoanUtilService loanUtilService;
|
||||
|
||||
@Autowired
|
||||
public LoanScheduleWritePlatformServiceImpl(final LoanAccountDomainService loanAccountDomainService,
|
||||
final LoanScheduleAssembler loanScheduleAssembler, final LoanAssembler loanAssembler, final PlatformSecurityContext context,
|
||||
final LoanUtilService loanUtilService) {
|
||||
this.loanAccountDomainService = loanAccountDomainService;
|
||||
this.loanScheduleAssembler = loanScheduleAssembler;
|
||||
this.loanAssembler = loanAssembler;
|
||||
this.context = context;
|
||||
this.loanUtilService = loanUtilService;
|
||||
}
|
||||
private final BusinessEventNotifierService businessEventNotifierService;
|
||||
|
||||
@Override
|
||||
public CommandProcessingResult addLoanScheduleVariations(final Long loanId, final JsonCommand command) {
|
||||
final Loan loan = this.loanAssembler.assembleFrom(loanId);
|
||||
final Loan loan = loanAssembler.assembleFrom(loanId);
|
||||
Map<Long, LoanTermVariations> loanTermVariations = new HashMap<>();
|
||||
for (LoanTermVariations termVariations : loan.getLoanTermVariations()) {
|
||||
loanTermVariations.put(termVariations.getId(), termVariations);
|
||||
}
|
||||
this.loanScheduleAssembler.assempleVariableScheduleFrom(loan, command.json());
|
||||
loanScheduleAssembler.assempleVariableScheduleFrom(loan, command.json());
|
||||
|
||||
this.loanAccountDomainService.saveLoanWithDataIntegrityViolationChecks(loan);
|
||||
loanAccountDomainService.saveLoanWithDataIntegrityViolationChecks(loan);
|
||||
final Map<String, Object> changes = new HashMap<>();
|
||||
List<LoanTermVariationsData> newVariationsData = new ArrayList<>();
|
||||
List<LoanTermVariations> modifiedVariations = loan.getLoanTermVariations();
|
||||
@@ -83,6 +75,7 @@ public class LoanScheduleWritePlatformServiceImpl implements LoanScheduleWritePl
|
||||
changes.put("removedVariations", loanTermVariations.keySet());
|
||||
}
|
||||
changes.put("loanTermVariations", newVariationsData);
|
||||
businessEventNotifierService.notifyPostBusinessEvent(new LoanScheduleVariationsAddedBusinessEvent(loan));
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withCommandId(command.commandId()) //
|
||||
.withLoanId(loanId) //
|
||||
@@ -92,7 +85,7 @@ public class LoanScheduleWritePlatformServiceImpl implements LoanScheduleWritePl
|
||||
|
||||
@Override
|
||||
public CommandProcessingResult deleteLoanScheduleVariations(final Long loanId) {
|
||||
final Loan loan = this.loanAssembler.assembleFrom(loanId);
|
||||
final Loan loan = loanAssembler.assembleFrom(loanId);
|
||||
List<LoanTermVariations> variations = loan.getLoanTermVariations();
|
||||
List<Long> deletedVariations = new ArrayList<>(variations.size());
|
||||
for (LoanTermVariations loanTermVariations : variations) {
|
||||
@@ -102,9 +95,10 @@ public class LoanScheduleWritePlatformServiceImpl implements LoanScheduleWritePl
|
||||
changes.put("removedEntityIds", deletedVariations);
|
||||
loan.getLoanTermVariations().clear();
|
||||
final LocalDate recalculateFrom = null;
|
||||
ScheduleGeneratorDTO scheduleGeneratorDTO = this.loanUtilService.buildScheduleGeneratorDTO(loan, recalculateFrom);
|
||||
ScheduleGeneratorDTO scheduleGeneratorDTO = loanUtilService.buildScheduleGeneratorDTO(loan, recalculateFrom);
|
||||
loan.regenerateRepaymentSchedule(scheduleGeneratorDTO);
|
||||
this.loanAccountDomainService.saveLoanWithDataIntegrityViolationChecks(loan);
|
||||
loanAccountDomainService.saveLoanWithDataIntegrityViolationChecks(loan);
|
||||
businessEventNotifierService.notifyPostBusinessEvent(new LoanScheduleVariationsDeletedBusinessEvent(loan));
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withLoanId(loanId) //
|
||||
.with(changes) //
|
||||
|
||||
+9
-90
@@ -25,13 +25,14 @@ import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.temporal.ChronoField;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import javax.persistence.PersistenceException;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||
import org.apache.fineract.infrastructure.accountnumberformat.domain.AccountNumberFormat;
|
||||
@@ -87,7 +88,6 @@ import org.apache.fineract.portfolio.client.domain.Client;
|
||||
import org.apache.fineract.portfolio.client.domain.ClientRepositoryWrapper;
|
||||
import org.apache.fineract.portfolio.client.exception.ClientNotActiveException;
|
||||
import org.apache.fineract.portfolio.collateralmanagement.domain.ClientCollateralManagement;
|
||||
import org.apache.fineract.portfolio.collateralmanagement.domain.ClientCollateralManagementRepository;
|
||||
import org.apache.fineract.portfolio.collateralmanagement.service.LoanCollateralAssembler;
|
||||
import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
|
||||
import org.apache.fineract.portfolio.fund.domain.Fund;
|
||||
@@ -104,10 +104,8 @@ import org.apache.fineract.portfolio.loanaccount.domain.GroupLoanIndividualMonit
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanCollateralManagement;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanCollateralManagementRepository;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanDisbursementDetails;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanLifecycleStateMachine;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallmentRepository;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleTransactionProcessorFactory;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper;
|
||||
@@ -144,9 +142,6 @@ import org.apache.fineract.portfolio.savings.domain.SavingsAccount;
|
||||
import org.apache.fineract.portfolio.savings.domain.SavingsAccountAssembler;
|
||||
import org.apache.fineract.portfolio.savings.service.GSIMReadPlatformService;
|
||||
import org.apache.fineract.useradministration.domain.AppUser;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.dao.DataIntegrityViolationException;
|
||||
import org.springframework.orm.jpa.JpaSystemException;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -154,10 +149,10 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements LoanApplicationWritePlatformService {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(LoanApplicationWritePlatformServiceJpaRepositoryImpl.class);
|
||||
|
||||
private final PlatformSecurityContext context;
|
||||
private final FromJsonHelper fromJsonHelper;
|
||||
private final LoanApplicationTransitionApiJsonValidator loanApplicationTransitionApiJsonValidator;
|
||||
@@ -181,7 +176,6 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
||||
private final SavingsAccountAssembler savingsAccountAssembler;
|
||||
private final AccountAssociationsRepository accountAssociationsRepository;
|
||||
private final LoanReadPlatformService loanReadPlatformService;
|
||||
private final LoanRepaymentScheduleInstallmentRepository repaymentScheduleInstallmentRepository;
|
||||
private final AccountNumberFormatRepositoryWrapper accountNumberFormatRepository;
|
||||
private final BusinessEventNotifierService businessEventNotifierService;
|
||||
private final ConfigurationDomainService configurationDomainService;
|
||||
@@ -190,7 +184,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
||||
private final CalendarReadPlatformService calendarReadPlatformService;
|
||||
private final EntityDatatableChecksWritePlatformService entityDatatableChecksWritePlatformService;
|
||||
private final GlobalConfigurationRepositoryWrapper globalConfigurationRepository;
|
||||
private final FineractEntityToEntityMappingRepository repository;
|
||||
private final FineractEntityToEntityMappingRepository entityMappingRepository;
|
||||
private final FineractEntityRelationRepository fineractEntityRelationRepository;
|
||||
private final LoanProductReadPlatformService loanProductReadPlatformService;
|
||||
|
||||
@@ -199,84 +193,9 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
||||
private final GLIMAccountInfoRepository glimRepository;
|
||||
private final LoanRepository loanRepository;
|
||||
private final GSIMReadPlatformService gsimReadPlatformService;
|
||||
private final LoanCollateralManagementRepository loanCollateralManagementRepository;
|
||||
private final ClientCollateralManagementRepository clientCollateralManagementRepository;
|
||||
|
||||
@Autowired
|
||||
public LoanApplicationWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final FromJsonHelper fromJsonHelper,
|
||||
final LoanApplicationTransitionApiJsonValidator loanApplicationTransitionApiJsonValidator,
|
||||
final LoanApplicationCommandFromApiJsonHelper fromApiJsonDeserializer,
|
||||
final LoanProductDataValidator loanProductCommandFromApiJsonDeserializer, final AprCalculator aprCalculator,
|
||||
final LoanAssembler loanAssembler, final LoanChargeAssembler loanChargeAssembler,
|
||||
final LoanCollateralAssembler loanCollateralAssembler, final LoanRepositoryWrapper loanRepositoryWrapper,
|
||||
final NoteRepository noteRepository, final LoanScheduleCalculationPlatformService calculationPlatformService,
|
||||
final ClientRepositoryWrapper clientRepository, final LoanProductRepository loanProductRepository,
|
||||
final AccountNumberGenerator accountNumberGenerator, final LoanSummaryWrapper loanSummaryWrapper,
|
||||
final GroupRepositoryWrapper groupRepository,
|
||||
final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory,
|
||||
final CalendarRepository calendarRepository, final CalendarInstanceRepository calendarInstanceRepository,
|
||||
final SavingsAccountAssembler savingsAccountAssembler, final AccountAssociationsRepository accountAssociationsRepository,
|
||||
final LoanRepaymentScheduleInstallmentRepository repaymentScheduleInstallmentRepository,
|
||||
final LoanReadPlatformService loanReadPlatformService, final AccountNumberFormatRepositoryWrapper accountNumberFormatRepository,
|
||||
final BusinessEventNotifierService businessEventNotifierService, final ConfigurationDomainService configurationDomainService,
|
||||
final LoanScheduleAssembler loanScheduleAssembler, final LoanUtilService loanUtilService,
|
||||
final CalendarReadPlatformService calendarReadPlatformService,
|
||||
final GlobalConfigurationRepositoryWrapper globalConfigurationRepository,
|
||||
final FineractEntityToEntityMappingRepository repository,
|
||||
final FineractEntityRelationRepository fineractEntityRelationRepository,
|
||||
final EntityDatatableChecksWritePlatformService entityDatatableChecksWritePlatformService,
|
||||
final GLIMAccountInfoWritePlatformService glimAccountInfoWritePlatformService, final GLIMAccountInfoRepository glimRepository,
|
||||
final LoanRepository loanRepository, final GSIMReadPlatformService gsimReadPlatformService, final RateAssembler rateAssembler,
|
||||
final LoanProductReadPlatformService loanProductReadPlatformService,
|
||||
final LoanCollateralManagementRepository loanCollateralManagementRepository,
|
||||
final ClientCollateralManagementRepository clientCollateralManagementRepository) {
|
||||
this.context = context;
|
||||
this.fromJsonHelper = fromJsonHelper;
|
||||
this.loanApplicationTransitionApiJsonValidator = loanApplicationTransitionApiJsonValidator;
|
||||
this.fromApiJsonDeserializer = fromApiJsonDeserializer;
|
||||
this.loanProductCommandFromApiJsonDeserializer = loanProductCommandFromApiJsonDeserializer;
|
||||
this.aprCalculator = aprCalculator;
|
||||
this.loanAssembler = loanAssembler;
|
||||
this.loanChargeAssembler = loanChargeAssembler;
|
||||
this.loanCollateralAssembler = loanCollateralAssembler;
|
||||
this.loanRepositoryWrapper = loanRepositoryWrapper;
|
||||
this.noteRepository = noteRepository;
|
||||
this.calculationPlatformService = calculationPlatformService;
|
||||
this.clientRepository = clientRepository;
|
||||
this.loanProductRepository = loanProductRepository;
|
||||
this.accountNumberGenerator = accountNumberGenerator;
|
||||
this.loanSummaryWrapper = loanSummaryWrapper;
|
||||
this.groupRepository = groupRepository;
|
||||
this.loanRepaymentScheduleTransactionProcessorFactory = loanRepaymentScheduleTransactionProcessorFactory;
|
||||
this.calendarRepository = calendarRepository;
|
||||
this.calendarInstanceRepository = calendarInstanceRepository;
|
||||
this.savingsAccountAssembler = savingsAccountAssembler;
|
||||
this.accountAssociationsRepository = accountAssociationsRepository;
|
||||
this.repaymentScheduleInstallmentRepository = repaymentScheduleInstallmentRepository;
|
||||
this.loanReadPlatformService = loanReadPlatformService;
|
||||
this.accountNumberFormatRepository = accountNumberFormatRepository;
|
||||
this.businessEventNotifierService = businessEventNotifierService;
|
||||
this.configurationDomainService = configurationDomainService;
|
||||
this.loanScheduleAssembler = loanScheduleAssembler;
|
||||
this.loanUtilService = loanUtilService;
|
||||
this.calendarReadPlatformService = calendarReadPlatformService;
|
||||
this.entityDatatableChecksWritePlatformService = entityDatatableChecksWritePlatformService;
|
||||
this.globalConfigurationRepository = globalConfigurationRepository;
|
||||
this.repository = repository;
|
||||
this.fineractEntityRelationRepository = fineractEntityRelationRepository;
|
||||
this.loanProductReadPlatformService = loanProductReadPlatformService;
|
||||
this.rateAssembler = rateAssembler;
|
||||
this.glimAccountInfoWritePlatformService = glimAccountInfoWritePlatformService;
|
||||
this.glimRepository = glimRepository;
|
||||
this.loanRepository = loanRepository;
|
||||
this.gsimReadPlatformService = gsimReadPlatformService;
|
||||
this.loanCollateralManagementRepository = loanCollateralManagementRepository;
|
||||
this.clientCollateralManagementRepository = clientCollateralManagementRepository;
|
||||
}
|
||||
|
||||
private LoanLifecycleStateMachine defaultLoanLifecycleStateMachine() {
|
||||
final List<LoanStatus> allowedLoanStatuses = Arrays.asList(LoanStatus.values());
|
||||
return new DefaultLoanLifecycleStateMachine(allowedLoanStatuses);
|
||||
return new DefaultLoanLifecycleStateMachine(LoanStatus.values(), businessEventNotifierService);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@@ -1287,7 +1206,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
||||
}
|
||||
|
||||
private void logAsErrorUnexpectedDataIntegrityException(final Exception dve) {
|
||||
LOG.error("Error occured.", dve);
|
||||
log.error("Error occured.", dve);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@@ -1775,8 +1694,8 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
||||
if (restrictToUserOfficeProperty.isEnabled()) {
|
||||
FineractEntityRelation fineractEntityRelation = fineractEntityRelationRepository
|
||||
.findOneByCodeName(FineractEntityAccessType.OFFICE_ACCESS_TO_LOAN_PRODUCTS.toStr());
|
||||
FineractEntityToEntityMapping officeToLoanProductMappingList = this.repository.findListByProductId(fineractEntityRelation,
|
||||
productId, officeId);
|
||||
FineractEntityToEntityMapping officeToLoanProductMappingList = this.entityMappingRepository
|
||||
.findListByProductId(fineractEntityRelation, productId, officeId);
|
||||
if (officeToLoanProductMappingList == null) {
|
||||
throw new NotOfficeSpecificProductException(productId, officeId);
|
||||
}
|
||||
|
||||
+5
-36
@@ -22,11 +22,11 @@ import com.google.gson.JsonElement;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.fineract.infrastructure.codes.domain.CodeValue;
|
||||
import org.apache.fineract.infrastructure.codes.domain.CodeValueRepositoryWrapper;
|
||||
@@ -34,6 +34,7 @@ import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDoma
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
|
||||
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
|
||||
import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService;
|
||||
import org.apache.fineract.organisation.holiday.domain.Holiday;
|
||||
import org.apache.fineract.organisation.holiday.domain.HolidayRepository;
|
||||
import org.apache.fineract.organisation.holiday.domain.HolidayStatusType;
|
||||
@@ -87,10 +88,10 @@ import org.apache.fineract.portfolio.loanproduct.exception.LinkedAccountRequired
|
||||
import org.apache.fineract.portfolio.loanproduct.exception.LoanProductNotFoundException;
|
||||
import org.apache.fineract.portfolio.rate.domain.Rate;
|
||||
import org.apache.fineract.portfolio.rate.service.RateAssembler;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class LoanAssembler {
|
||||
|
||||
private final FromJsonHelper fromApiJsonHelper;
|
||||
@@ -112,38 +113,7 @@ public class LoanAssembler {
|
||||
private final WorkingDaysRepositoryWrapper workingDaysRepository;
|
||||
private final LoanUtilService loanUtilService;
|
||||
private final RateAssembler rateAssembler;
|
||||
|
||||
@Autowired
|
||||
public LoanAssembler(final FromJsonHelper fromApiJsonHelper, final LoanRepositoryWrapper loanRepository,
|
||||
final LoanProductRepository loanProductRepository, final ClientRepositoryWrapper clientRepository,
|
||||
final GroupRepository groupRepository, final FundRepository fundRepository,
|
||||
final LoanTransactionProcessingStrategyRepository loanTransactionProcessingStrategyRepository,
|
||||
final StaffRepository staffRepository, final CodeValueRepositoryWrapper codeValueRepository,
|
||||
final LoanScheduleAssembler loanScheduleAssembler, final LoanChargeAssembler loanChargeAssembler,
|
||||
final LoanCollateralAssembler collateralAssembler, final LoanSummaryWrapper loanSummaryWrapper,
|
||||
final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory,
|
||||
final HolidayRepository holidayRepository, final ConfigurationDomainService configurationDomainService,
|
||||
final WorkingDaysRepositoryWrapper workingDaysRepository, final LoanUtilService loanUtilService, RateAssembler rateAssembler) {
|
||||
this.fromApiJsonHelper = fromApiJsonHelper;
|
||||
this.loanRepository = loanRepository;
|
||||
this.loanProductRepository = loanProductRepository;
|
||||
this.clientRepository = clientRepository;
|
||||
this.groupRepository = groupRepository;
|
||||
this.fundRepository = fundRepository;
|
||||
this.loanTransactionProcessingStrategyRepository = loanTransactionProcessingStrategyRepository;
|
||||
this.staffRepository = staffRepository;
|
||||
this.codeValueRepository = codeValueRepository;
|
||||
this.loanScheduleAssembler = loanScheduleAssembler;
|
||||
this.loanChargeAssembler = loanChargeAssembler;
|
||||
this.collateralAssembler = collateralAssembler;
|
||||
this.loanSummaryWrapper = loanSummaryWrapper;
|
||||
this.loanRepaymentScheduleTransactionProcessorFactory = loanRepaymentScheduleTransactionProcessorFactory;
|
||||
this.holidayRepository = holidayRepository;
|
||||
this.configurationDomainService = configurationDomainService;
|
||||
this.workingDaysRepository = workingDaysRepository;
|
||||
this.loanUtilService = loanUtilService;
|
||||
this.rateAssembler = rateAssembler;
|
||||
}
|
||||
private final BusinessEventNotifierService businessEventNotifierService;
|
||||
|
||||
public Loan assembleFrom(final Long accountId) {
|
||||
final Loan loanAccount = this.loanRepository.findOneWithNotFoundDetection(accountId, true);
|
||||
@@ -354,8 +324,7 @@ public class LoanAssembler {
|
||||
}
|
||||
|
||||
private LoanLifecycleStateMachine defaultLoanLifecycleStateMachine() {
|
||||
final List<LoanStatus> allowedLoanStatuses = Arrays.asList(LoanStatus.values());
|
||||
return new DefaultLoanLifecycleStateMachine(allowedLoanStatuses);
|
||||
return new DefaultLoanLifecycleStateMachine(LoanStatus.values(), businessEventNotifierService);
|
||||
}
|
||||
|
||||
public CodeValue findCodeValueByIdIfProvided(final Long codeValueId) {
|
||||
|
||||
+14
-85
@@ -66,15 +66,17 @@ import org.apache.fineract.infrastructure.event.business.domain.loan.LoanInteres
|
||||
import org.apache.fineract.infrastructure.event.business.domain.loan.LoanReassignOfficerBusinessEvent;
|
||||
import org.apache.fineract.infrastructure.event.business.domain.loan.LoanRejectTransferBusinessEvent;
|
||||
import org.apache.fineract.infrastructure.event.business.domain.loan.LoanRemoveOfficerBusinessEvent;
|
||||
import org.apache.fineract.infrastructure.event.business.domain.loan.LoanRescheduledDueCalendarChangeBusinessEvent;
|
||||
import org.apache.fineract.infrastructure.event.business.domain.loan.LoanUndoDisbursalBusinessEvent;
|
||||
import org.apache.fineract.infrastructure.event.business.domain.loan.LoanUndoLastDisbursalBusinessEvent;
|
||||
import org.apache.fineract.infrastructure.event.business.domain.loan.LoanUpdateDisbursementDataBusinessEvent;
|
||||
import org.apache.fineract.infrastructure.event.business.domain.loan.LoanWithdrawTransferBusinessEvent;
|
||||
import org.apache.fineract.infrastructure.event.business.domain.loan.charge.LoanAddChargeBusinessEvent;
|
||||
import org.apache.fineract.infrastructure.event.business.domain.loan.charge.LoanDeleteChargeBusinessEvent;
|
||||
import org.apache.fineract.infrastructure.event.business.domain.loan.charge.LoanUpdateChargeBusinessEvent;
|
||||
import org.apache.fineract.infrastructure.event.business.domain.loan.charge.LoanWaiveChargeBusinessEvent;
|
||||
import org.apache.fineract.infrastructure.event.business.domain.loan.charge.LoanWaiveChargeUndoBusinessEvent;
|
||||
import org.apache.fineract.infrastructure.event.business.domain.loan.transaction.LoanChargePaymentPostBusinessEvent;
|
||||
import org.apache.fineract.infrastructure.event.business.domain.loan.transaction.LoanChargeRefundBusinessEvent;
|
||||
import org.apache.fineract.infrastructure.event.business.domain.loan.transaction.LoanUndoWrittenOffBusinessEvent;
|
||||
import org.apache.fineract.infrastructure.event.business.domain.loan.transaction.LoanWaiveInterestBusinessEvent;
|
||||
import org.apache.fineract.infrastructure.event.business.domain.loan.transaction.LoanWrittenOffPostBusinessEvent;
|
||||
@@ -269,8 +271,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
private final LoanRepaymentScheduleInstallmentRepository loanRepaymentScheduleInstallmentRepository;
|
||||
|
||||
private LoanLifecycleStateMachine defaultLoanLifecycleStateMachine() {
|
||||
final List<LoanStatus> allowedLoanStatuses = Arrays.asList(LoanStatus.values());
|
||||
return new DefaultLoanLifecycleStateMachine(allowedLoanStatuses);
|
||||
return new DefaultLoanLifecycleStateMachine(LoanStatus.values(), businessEventNotifierService);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@@ -795,8 +796,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult undoGLIMLoanDisbursal(final Long loanId, final JsonCommand command) {
|
||||
// GroupLoanIndividualMonitoringAccount
|
||||
// glimAccount=glimRepository.findOne(loanId);
|
||||
final Long parentLoanId = loanId;
|
||||
GroupLoanIndividualMonitoringAccount parentLoan = glimRepository.findById(parentLoanId).orElseThrow();
|
||||
List<Loan> childLoans = this.loanRepository.findByGlimId(loanId);
|
||||
@@ -1727,7 +1726,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
}
|
||||
}
|
||||
|
||||
businessEventNotifierService.notifyPostBusinessEvent(new LoanChargePaymentPostBusinessEvent(newChargeRefundTxn));
|
||||
businessEventNotifierService.notifyPostBusinessEvent(new LoanChargeRefundBusinessEvent(newChargeRefundTxn));
|
||||
return result;
|
||||
|
||||
}
|
||||
@@ -2196,7 +2195,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
.withSavingsId(portfolioAccountData.getId()).build();
|
||||
}
|
||||
|
||||
public void disburseLoanToLoan(final Loan loan, final JsonCommand command, final BigDecimal amount) {
|
||||
private void disburseLoanToLoan(final Loan loan, final JsonCommand command, final BigDecimal amount) {
|
||||
|
||||
final LocalDate transactionDate = command.localDateValueOfParameterNamed("actualDisbursementDate");
|
||||
final String txnExternalId = command.stringValueOfParameterNamedAllowingNull("externalId");
|
||||
@@ -2211,7 +2210,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
loan.getTopupLoanDetails().setTopupAmount(amount);
|
||||
}
|
||||
|
||||
public void disburseLoanToSavings(final Loan loan, final JsonCommand command, final Money amount, final PaymentDetail paymentDetail) {
|
||||
private void disburseLoanToSavings(final Loan loan, final JsonCommand command, final Money amount, final PaymentDetail paymentDetail) {
|
||||
|
||||
final LocalDate transactionDate = command.localDateValueOfParameterNamed("actualDisbursementDate");
|
||||
final String txnExternalId = command.stringValueOfParameterNamedAllowingNull("externalId");
|
||||
@@ -2518,6 +2517,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
}
|
||||
|
||||
saveLoanWithDataIntegrityViolationChecks(loan);
|
||||
businessEventNotifierService.notifyPostBusinessEvent(new LoanRescheduledDueCalendarChangeBusinessEvent(loan));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2971,7 +2971,9 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
loan.loanProduct().maxTrancheCount(), loan.getDisbursementDetails().size());
|
||||
}
|
||||
LoanDisbursementDetails updateDetails = null;
|
||||
return processLoanDisbursementDetail(loan, loanId, command, updateDetails);
|
||||
CommandProcessingResult result = processLoanDisbursementDetail(loan, loanId, command, updateDetails);
|
||||
businessEventNotifierService.notifyPostBusinessEvent(new LoanUpdateDisbursementDataBusinessEvent(loan));
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
@@ -3040,85 +3042,12 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
LoanDisbursementDetails loanDisbursementDetails = loan.fetchLoanDisbursementsById(disbursementId);
|
||||
this.loanEventApiJsonValidator.validateUpdateDisbursementDateAndAmount(command.json(), loanDisbursementDetails);
|
||||
|
||||
return processLoanDisbursementDetail(loan, loanId, command, loanDisbursementDetails);
|
||||
CommandProcessingResult result = processLoanDisbursementDetail(loan, loanId, command, loanDisbursementDetails);
|
||||
businessEventNotifierService.notifyPostBusinessEvent(new LoanUpdateDisbursementDataBusinessEvent(loan));
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
public LoanTransaction disburseLoanAmountToSavings(final Long loanId, Long loanChargeId, final JsonCommand command,
|
||||
final boolean isChargeIdIncludedInJson) {
|
||||
|
||||
LoanTransaction transaction = null;
|
||||
|
||||
this.loanEventApiJsonValidator.validateChargePaymentTransaction(command.json(), isChargeIdIncludedInJson);
|
||||
if (isChargeIdIncludedInJson) {
|
||||
loanChargeId = command.longValueOfParameterNamed("chargeId");
|
||||
}
|
||||
final Loan loan = this.loanAssembler.assembleFrom(loanId);
|
||||
checkClientOrGroupActive(loan);
|
||||
final LoanCharge loanCharge = retrieveLoanChargeBy(loanId, loanChargeId);
|
||||
|
||||
// Charges may be waived only when the loan associated with them are
|
||||
// active
|
||||
if (!loan.status().isActive()) {
|
||||
throw new LoanChargeCannotBePayedException(LoanChargeCannotBePayedReason.LOAN_INACTIVE, loanCharge.getId());
|
||||
}
|
||||
|
||||
// validate loan charge is not already paid or waived
|
||||
if (loanCharge.isWaived()) {
|
||||
throw new LoanChargeCannotBePayedException(LoanChargeCannotBePayedReason.ALREADY_WAIVED, loanCharge.getId());
|
||||
} else if (loanCharge.isPaid()) {
|
||||
throw new LoanChargeCannotBePayedException(LoanChargeCannotBePayedReason.ALREADY_PAID, loanCharge.getId());
|
||||
}
|
||||
|
||||
if (!loanCharge.getChargePaymentMode().isPaymentModeAccountTransfer()) {
|
||||
throw new LoanChargeCannotBePayedException(LoanChargeCannotBePayedReason.CHARGE_NOT_ACCOUNT_TRANSFER, loanCharge.getId());
|
||||
}
|
||||
|
||||
final LocalDate transactionDate = command.localDateValueOfParameterNamed("transactionDate");
|
||||
|
||||
final Locale locale = command.extractLocale();
|
||||
final DateTimeFormatter fmt = DateTimeFormatter.ofPattern(command.dateFormat()).withLocale(locale);
|
||||
Integer loanInstallmentNumber = null;
|
||||
BigDecimal amount = loanCharge.amountOutstanding();
|
||||
if (loanCharge.isInstalmentFee()) {
|
||||
LoanInstallmentCharge chargePerInstallment = null;
|
||||
final LocalDate dueDate = command.localDateValueOfParameterNamed("dueDate");
|
||||
final Integer installmentNumber = command.integerValueOfParameterNamed("installmentNumber");
|
||||
if (dueDate != null) {
|
||||
chargePerInstallment = loanCharge.getInstallmentLoanCharge(dueDate);
|
||||
} else if (installmentNumber != null) {
|
||||
chargePerInstallment = loanCharge.getInstallmentLoanCharge(installmentNumber);
|
||||
}
|
||||
if (chargePerInstallment == null) {
|
||||
chargePerInstallment = loanCharge.getUnpaidInstallmentLoanCharge();
|
||||
}
|
||||
if (chargePerInstallment.isWaived()) {
|
||||
throw new LoanChargeCannotBePayedException(LoanChargeCannotBePayedReason.ALREADY_WAIVED, loanCharge.getId());
|
||||
} else if (chargePerInstallment.isPaid()) {
|
||||
throw new LoanChargeCannotBePayedException(LoanChargeCannotBePayedReason.ALREADY_PAID, loanCharge.getId());
|
||||
}
|
||||
loanInstallmentNumber = chargePerInstallment.getRepaymentInstallment().getInstallmentNumber();
|
||||
amount = chargePerInstallment.getAmountOutstanding();
|
||||
}
|
||||
|
||||
final PortfolioAccountData portfolioAccountData = this.accountAssociationsReadPlatformService.retriveLoanLinkedAssociation(loanId);
|
||||
if (portfolioAccountData == null) {
|
||||
final String errorMessage = "Charge with id:" + loanChargeId + " requires linked savings account for payment";
|
||||
throw new LinkedAccountRequiredException("loanCharge.pay", errorMessage, loanChargeId);
|
||||
}
|
||||
final SavingsAccount fromSavingsAccount = null;
|
||||
final boolean isRegularTransaction = true;
|
||||
final boolean isExceptionForBalanceCheck = false;
|
||||
final AccountTransferDTO accountTransferDTO = new AccountTransferDTO(transactionDate, amount, PortfolioAccountType.SAVINGS,
|
||||
PortfolioAccountType.LOAN, portfolioAccountData.getId(), loanId, "Loan Charge Payment", locale, fmt, null, null,
|
||||
LoanTransactionType.CHARGE_PAYMENT.getValue(), loanChargeId, loanInstallmentNumber,
|
||||
AccountTransferType.CHARGE_PAYMENT.getValue(), null, null, null, null, null, fromSavingsAccount, isRegularTransaction,
|
||||
isExceptionForBalanceCheck);
|
||||
this.accountTransfersWritePlatformService.transferFunds(accountTransferDTO);
|
||||
|
||||
return transaction;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public void recalculateInterest(final long loanId) {
|
||||
|
||||
+5
-2
@@ -29,6 +29,7 @@ import java.time.LocalDate;
|
||||
import java.time.ZoneId;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import javax.persistence.EntityManager;
|
||||
import org.apache.fineract.avro.loan.v1.LoanAccountDataV1;
|
||||
import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
|
||||
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
|
||||
@@ -43,7 +44,6 @@ import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
@@ -57,12 +57,15 @@ class ExternalEventServiceTest {
|
||||
private ExternalEventIdempotencyKeyGenerator idempotencyKeyGenerator;
|
||||
@Mock
|
||||
private BusinessEventSerializerFactory serializerFactory;
|
||||
@Mock
|
||||
private EntityManager entityManager;
|
||||
|
||||
@InjectMocks
|
||||
private ExternalEventService underTest;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
underTest = new ExternalEventService(repository, idempotencyKeyGenerator, serializerFactory);
|
||||
underTest.setEntityManager(entityManager);
|
||||
FineractPlatformTenant tenant = new FineractPlatformTenant(1L, "default", "Default Tenant", "Europe/Budapest", null);
|
||||
ThreadLocalContextUtil.setTenant(tenant);
|
||||
ThreadLocalContextUtil
|
||||
|
||||
Reference in New Issue
Block a user