FINERACT-1865: Decrease optimistic lock exception probability
This commit is contained in:
+3
-3
@@ -77,11 +77,11 @@ public interface LoanAccountDomainService {
|
||||
boolean isRecoveryRepayment, String chargeRefundChargeType, boolean isAccountTransfer, HolidayDetailDTO holidayDetailDto,
|
||||
Boolean isHolidayValidationDone, boolean isLoanToLoanTransfer);
|
||||
|
||||
void saveLoanTransactionWithDataIntegrityViolationChecks(LoanTransaction newRepaymentTransaction);
|
||||
LoanTransaction saveLoanTransactionWithDataIntegrityViolationChecks(LoanTransaction newRepaymentTransaction);
|
||||
|
||||
void saveAndFlushLoanWithDataIntegrityViolationChecks(Loan loan);
|
||||
Loan saveAndFlushLoanWithDataIntegrityViolationChecks(Loan loan);
|
||||
|
||||
void saveLoanWithDataIntegrityViolationChecks(Loan loan);
|
||||
Loan saveLoanWithDataIntegrityViolationChecks(Loan loan);
|
||||
|
||||
LoanTransaction foreCloseLoan(Loan loan, LocalDate foreClourseDate, String noteText, ExternalId externalId,
|
||||
Map<String, Object> changes);
|
||||
|
||||
+13
-16
@@ -156,11 +156,10 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public LoanTransaction makeRepayment(final LoanTransactionType repaymentTransactionType, final Loan loan,
|
||||
final LocalDate transactionDate, final BigDecimal transactionAmount, final PaymentDetail paymentDetail, final String noteText,
|
||||
final ExternalId txnExternalId, final boolean isRecoveryRepayment, final String chargeRefundChargeType,
|
||||
boolean isAccountTransfer, HolidayDetailDTO holidayDetailDto, Boolean isHolidayValidationDone,
|
||||
final boolean isLoanToLoanTransfer) {
|
||||
public LoanTransaction makeRepayment(final LoanTransactionType repaymentTransactionType, Loan loan, final LocalDate transactionDate,
|
||||
final BigDecimal transactionAmount, final PaymentDetail paymentDetail, final String noteText, final ExternalId txnExternalId,
|
||||
final boolean isRecoveryRepayment, final String chargeRefundChargeType, boolean isAccountTransfer,
|
||||
HolidayDetailDTO holidayDetailDto, Boolean isHolidayValidationDone, final boolean isLoanToLoanTransfer) {
|
||||
checkClientOrGroupActive(loan);
|
||||
|
||||
LoanBusinessEvent repaymentEvent = getLoanRepaymentTypeBusinessEvent(repaymentTransactionType, isRecoveryRepayment, loan);
|
||||
@@ -206,13 +205,10 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
|
||||
* time being, not a major issue for now as this loop is entered only in edge cases (when a payment is made
|
||||
* before the latest payment recorded against the loan)
|
||||
***/
|
||||
|
||||
saveAndFlushLoanWithDataIntegrityViolationChecks(loan);
|
||||
|
||||
if (changedTransactionDetail != null) {
|
||||
for (Map.Entry<Long, LoanTransaction> mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) {
|
||||
|
||||
saveLoanTransactionWithDataIntegrityViolationChecks(mapEntry.getValue());
|
||||
loanTransactionRepository.save(mapEntry.getValue());
|
||||
// update loan with references to the newly created transactions
|
||||
loan.addLoanTransaction(mapEntry.getValue());
|
||||
updateLoanTransaction(mapEntry.getKey(), mapEntry.getValue());
|
||||
@@ -220,6 +216,7 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
|
||||
// Trigger transaction replayed event
|
||||
replayedTransactionBusinessEventService.raiseTransactionReplayedEvents(changedTransactionDetail);
|
||||
}
|
||||
loan = saveAndFlushLoanWithDataIntegrityViolationChecks(loan);
|
||||
|
||||
if (StringUtils.isNotBlank(noteText)) {
|
||||
final Note note = Note.loanTransactionNote(loan, newRepaymentTransaction, noteText);
|
||||
@@ -314,9 +311,9 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveLoanTransactionWithDataIntegrityViolationChecks(LoanTransaction newRepaymentTransaction) {
|
||||
public LoanTransaction saveLoanTransactionWithDataIntegrityViolationChecks(LoanTransaction newRepaymentTransaction) {
|
||||
try {
|
||||
this.loanTransactionRepository.saveAndFlush(newRepaymentTransaction);
|
||||
return this.loanTransactionRepository.saveAndFlush(newRepaymentTransaction);
|
||||
} catch (final JpaSystemException | DataIntegrityViolationException e) {
|
||||
raiseValidationExceptionForUniqueConstraintViolation(e);
|
||||
throw e;
|
||||
@@ -324,9 +321,9 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveAndFlushLoanWithDataIntegrityViolationChecks(final Loan loan) {
|
||||
public Loan saveAndFlushLoanWithDataIntegrityViolationChecks(final Loan loan) {
|
||||
try {
|
||||
this.loanRepositoryWrapper.saveAndFlush(loan);
|
||||
return this.loanRepositoryWrapper.saveAndFlush(loan);
|
||||
} catch (final JpaSystemException | DataIntegrityViolationException e) {
|
||||
raiseValidationExceptionForUniqueConstraintViolation(e);
|
||||
throw e;
|
||||
@@ -334,9 +331,9 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveLoanWithDataIntegrityViolationChecks(final Loan loan) {
|
||||
public Loan saveLoanWithDataIntegrityViolationChecks(final Loan loan) {
|
||||
try {
|
||||
this.loanRepositoryWrapper.save(loan);
|
||||
return this.loanRepositoryWrapper.save(loan);
|
||||
} catch (final JpaSystemException | DataIntegrityViolationException e) {
|
||||
raiseValidationExceptionForUniqueConstraintViolation(e);
|
||||
throw e;
|
||||
@@ -795,7 +792,7 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
|
||||
|
||||
if (changedTransactionDetail != null) {
|
||||
for (Map.Entry<Long, LoanTransaction> mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) {
|
||||
saveLoanTransactionWithDataIntegrityViolationChecks(mapEntry.getValue());
|
||||
loanTransactionRepository.save(mapEntry.getValue());
|
||||
// update loan with references to the newly created transactions
|
||||
loan.getLoanTransactions().add(mapEntry.getValue());
|
||||
updateLoanTransaction(mapEntry.getKey(), mapEntry.getValue());
|
||||
|
||||
-6
@@ -25,14 +25,11 @@ import javax.persistence.Enumerated;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Version;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDateTimeCustom;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@Entity
|
||||
@Table(name = "m_loan_transaction_relation")
|
||||
public class LoanTransactionRelation extends AbstractAuditableWithUTCDateTimeCustom {
|
||||
@@ -53,9 +50,6 @@ public class LoanTransactionRelation extends AbstractAuditableWithUTCDateTimeCus
|
||||
@Column(name = "relation_type_enum", nullable = false)
|
||||
private LoanTransactionRelationTypeEnum relationType;
|
||||
|
||||
@Version
|
||||
private Long version;
|
||||
|
||||
protected LoanTransactionRelation() {}
|
||||
|
||||
protected LoanTransactionRelation(@NotNull LoanTransaction fromTransaction, LoanTransaction toTransaction, LoanCharge toCharge,
|
||||
|
||||
+5
-5
@@ -443,9 +443,6 @@ public class LoanRescheduleRequestWritePlatformServiceImpl implements LoanResche
|
||||
// update the status of the request
|
||||
loanRescheduleRequest.approve(appUser, approvedOnDate);
|
||||
|
||||
// update the loan object
|
||||
saveAndFlushLoanWithDataIntegrityViolationChecks(loan);
|
||||
|
||||
if (changedTransactionDetail != null) {
|
||||
for (final Map.Entry<Long, LoanTransaction> mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) {
|
||||
this.loanTransactionRepository.save(mapEntry.getValue());
|
||||
@@ -457,6 +454,8 @@ public class LoanRescheduleRequestWritePlatformServiceImpl implements LoanResche
|
||||
// Trigger transaction replayed event
|
||||
replayedTransactionBusinessEventService.raiseTransactionReplayedEvents(changedTransactionDetail);
|
||||
}
|
||||
// update the loan object
|
||||
loan = saveAndFlushLoanWithDataIntegrityViolationChecks(loan);
|
||||
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
|
||||
|
||||
this.loanAccountDomainService.recalculateAccruals(loan, true);
|
||||
@@ -475,7 +474,7 @@ public class LoanRescheduleRequestWritePlatformServiceImpl implements LoanResche
|
||||
}
|
||||
}
|
||||
|
||||
private void saveAndFlushLoanWithDataIntegrityViolationChecks(final Loan loan) {
|
||||
private Loan saveAndFlushLoanWithDataIntegrityViolationChecks(final Loan loan) {
|
||||
try {
|
||||
List<LoanRepaymentScheduleInstallment> installments = loan.getRepaymentScheduleInstallments();
|
||||
for (LoanRepaymentScheduleInstallment installment : installments) {
|
||||
@@ -483,7 +482,7 @@ public class LoanRescheduleRequestWritePlatformServiceImpl implements LoanResche
|
||||
this.repaymentScheduleInstallmentRepository.save(installment);
|
||||
}
|
||||
}
|
||||
this.loanRepositoryWrapper.saveAndFlush(loan);
|
||||
return this.loanRepositoryWrapper.saveAndFlush(loan);
|
||||
} catch (final JpaSystemException | DataIntegrityViolationException e) {
|
||||
final Throwable realCause = e.getCause();
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
||||
@@ -495,6 +494,7 @@ public class LoanRescheduleRequestWritePlatformServiceImpl implements LoanResche
|
||||
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.",
|
||||
dataValidationErrors, e);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+5
-4
@@ -165,7 +165,7 @@ public class LoanChargeWritePlatformServiceImpl implements LoanChargeWritePlatfo
|
||||
|
||||
this.loanChargeApiJsonValidator.validateAddLoanCharge(command.json());
|
||||
|
||||
final Loan loan = this.loanAssembler.assembleFrom(loanId);
|
||||
Loan loan = this.loanAssembler.assembleFrom(loanId);
|
||||
checkClientOrGroupActive(loan);
|
||||
|
||||
List<LoanDisbursementDetails> loanDisburseDetails = loan.getDisbursementDetails();
|
||||
@@ -248,8 +248,9 @@ public class LoanChargeWritePlatformServiceImpl implements LoanChargeWritePlatfo
|
||||
// Trigger transaction replayed event
|
||||
replayedTransactionBusinessEventService.raiseTransactionReplayedEvents(changedTransactionDetail);
|
||||
}
|
||||
this.loanRepositoryWrapper.save(loan);
|
||||
|
||||
}
|
||||
loan = loanAccountDomainService.saveAndFlushLoanWithDataIntegrityViolationChecks(loan);
|
||||
|
||||
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
|
||||
|
||||
@@ -936,7 +937,7 @@ public class LoanChargeWritePlatformServiceImpl implements LoanChargeWritePlatfo
|
||||
}
|
||||
}
|
||||
|
||||
private boolean addCharge(final Loan loan, final Charge chargeDefinition, final LoanCharge loanCharge) {
|
||||
private boolean addCharge(final Loan loan, final Charge chargeDefinition, LoanCharge loanCharge) {
|
||||
|
||||
if (!loan.hasCurrencyCodeOf(chargeDefinition.getCurrencyCode())) {
|
||||
final String errorMessage = "Charge and Loan must have the same currency.";
|
||||
@@ -970,7 +971,7 @@ public class LoanChargeWritePlatformServiceImpl implements LoanChargeWritePlatfo
|
||||
|
||||
loan.addLoanCharge(loanCharge);
|
||||
|
||||
this.loanChargeRepository.saveAndFlush(loanCharge);
|
||||
loanCharge = this.loanChargeRepository.saveAndFlush(loanCharge);
|
||||
|
||||
/**
|
||||
* we want to apply charge transactions only for those loans charges that are applied when a loan is active and
|
||||
|
||||
+13
-17
@@ -448,15 +448,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
loan.adjustNetDisbursalAmount(amountToDisburse.getAmount());
|
||||
}
|
||||
if (!changes.isEmpty()) {
|
||||
|
||||
loan = saveAndFlushLoanWithDataIntegrityViolationChecks(loan);
|
||||
|
||||
final String noteText = command.stringValueOfParameterNamed("note");
|
||||
if (StringUtils.isNotBlank(noteText)) {
|
||||
final Note note = Note.loanNote(loan, noteText);
|
||||
this.noteRepository.save(note);
|
||||
}
|
||||
|
||||
if (changedTransactionDetail != null) {
|
||||
for (final Map.Entry<Long, LoanTransaction> mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) {
|
||||
this.loanTransactionRepository.save(mapEntry.getValue());
|
||||
@@ -466,6 +457,13 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
replayedTransactionBusinessEventService.raiseTransactionReplayedEvents(changedTransactionDetail);
|
||||
}
|
||||
|
||||
loan = saveAndFlushLoanWithDataIntegrityViolationChecks(loan);
|
||||
|
||||
final String noteText = command.stringValueOfParameterNamed("note");
|
||||
if (StringUtils.isNotBlank(noteText)) {
|
||||
final Note note = Note.loanNote(loan, noteText);
|
||||
this.noteRepository.save(note);
|
||||
}
|
||||
// auto create standing instruction
|
||||
createStandingInstruction(loan);
|
||||
|
||||
@@ -729,8 +727,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
}
|
||||
if (!changes.isEmpty()) {
|
||||
|
||||
loan = saveAndFlushLoanWithDataIntegrityViolationChecks(loan);
|
||||
|
||||
final String noteText = command.stringValueOfParameterNamed("note");
|
||||
if (StringUtils.isNotBlank(noteText)) {
|
||||
final Note note = Note.loanNote(loan, noteText);
|
||||
@@ -745,6 +741,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
// Trigger transaction replayed event
|
||||
replayedTransactionBusinessEventService.raiseTransactionReplayedEvents(changedTransactionDetail);
|
||||
}
|
||||
loan = saveAndFlushLoanWithDataIntegrityViolationChecks(loan);
|
||||
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
|
||||
}
|
||||
final Set<LoanCharge> loanCharges = loan.getActiveCharges();
|
||||
@@ -1136,7 +1133,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
* time being, not a major issue for now as this loop is entered only in edge cases (when a adjustment is made
|
||||
* before the latest payment recorded against the loan)
|
||||
***/
|
||||
loan = saveAndFlushLoanWithDataIntegrityViolationChecks(loan);
|
||||
if (changedTransactionDetail != null) {
|
||||
for (final Map.Entry<Long, LoanTransaction> mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) {
|
||||
this.loanTransactionRepository.save(mapEntry.getValue());
|
||||
@@ -1147,6 +1143,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
// Trigger transaction replayed event
|
||||
replayedTransactionBusinessEventService.raiseTransactionReplayedEvents(changedTransactionDetail);
|
||||
}
|
||||
loan = saveAndFlushLoanWithDataIntegrityViolationChecks(loan);
|
||||
|
||||
final String noteText = command.stringValueOfParameterNamed("note");
|
||||
if (StringUtils.isNotBlank(noteText)) {
|
||||
@@ -1370,7 +1367,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
* time being, not a major issue for now as this loop is entered only in edge cases (when a waiver is made
|
||||
* before the latest payment recorded against the loan)
|
||||
***/
|
||||
loan = saveAndFlushLoanWithDataIntegrityViolationChecks(loan);
|
||||
|
||||
if (changedTransactionDetail != null) {
|
||||
for (final Map.Entry<Long, LoanTransaction> mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) {
|
||||
this.loanTransactionRepository.save(mapEntry.getValue());
|
||||
@@ -1381,6 +1378,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
// Trigger transaction replayed event
|
||||
replayedTransactionBusinessEventService.raiseTransactionReplayedEvents(changedTransactionDetail);
|
||||
}
|
||||
loan = saveAndFlushLoanWithDataIntegrityViolationChecks(loan);
|
||||
|
||||
final String noteText = command.stringValueOfParameterNamed("note");
|
||||
if (StringUtils.isNotBlank(noteText)) {
|
||||
@@ -2290,8 +2288,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
}
|
||||
}
|
||||
|
||||
loan = saveAndFlushLoanWithDataIntegrityViolationChecks(loan);
|
||||
|
||||
if (command.entityId() != null && changedTransactionDetail != null) {
|
||||
for (Map.Entry<Long, LoanTransaction> mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) {
|
||||
this.loanTransactionRepository.save(mapEntry.getValue());
|
||||
@@ -2300,6 +2296,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
// Trigger transaction replayed event
|
||||
replayedTransactionBusinessEventService.raiseTransactionReplayedEvents(changedTransactionDetail);
|
||||
}
|
||||
loan = saveAndFlushLoanWithDataIntegrityViolationChecks(loan);
|
||||
if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
||||
createLoanScheduleArchive(loan, scheduleGeneratorDTO);
|
||||
}
|
||||
@@ -2345,8 +2342,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
ChangedTransactionDetail changedTransactionDetail = loan.recalculateScheduleFromLastTransaction(generatorDTO,
|
||||
existingTransactionIds, existingReversedTransactionIds);
|
||||
|
||||
saveLoanWithDataIntegrityViolationChecks(loan);
|
||||
|
||||
if (changedTransactionDetail != null) {
|
||||
for (final Map.Entry<Long, LoanTransaction> mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) {
|
||||
this.loanTransactionRepository.save(mapEntry.getValue());
|
||||
@@ -2358,6 +2353,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
// Trigger transaction replayed event
|
||||
replayedTransactionBusinessEventService.raiseTransactionReplayedEvents(changedTransactionDetail);
|
||||
}
|
||||
saveLoanWithDataIntegrityViolationChecks(loan);
|
||||
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
|
||||
loanAccountDomainService.recalculateAccruals(loan);
|
||||
businessEventNotifierService.notifyPostBusinessEvent(new LoanInterestRecalculationBusinessEvent(loan));
|
||||
|
||||
@@ -107,4 +107,5 @@
|
||||
<include file="parts/0085_add_aggregate_root_id_external_events.xml" relativeToChangelogFile="true" />
|
||||
<include file="parts/0086_add_cob_business_date_to_loan_account_locks.xml" relativeToChangelogFile="true" />
|
||||
<include file="parts/0087_update_dashboard_table_reports.xml" relativeToChangelogFile="true" />
|
||||
<include file="parts/0088_drop_m_loan_transaction_version_column.xml" relativeToChangelogFile="true" />
|
||||
</databaseChangeLog>
|
||||
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
|
||||
-->
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.3.xsd">
|
||||
<changeSet author="fineract" id="1">
|
||||
<dropColumn tableName="m_loan_transaction_relation" columnName="version"/>
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
||||
Reference in New Issue
Block a user