FINERACT-849: Switch to EclipseLink

This commit is contained in:
Arnold Galovics
2022-03-10 09:33:01 +01:00
committed by Aleksandar Vidakovic
parent 7f8148e166
commit d5c611564f
129 changed files with 717 additions and 771 deletions
+8 -4
View File
@@ -45,7 +45,8 @@ buildscript {
dependencies {
classpath 'com.bmuschko:gradle-cargo-plugin:2.9.0'
classpath 'org.apache.openjpa:openjpa:3.2.1' // when upgrading, also change OpenJPA version repeated in fineract-provider/build.gradle!
classpath 'org.eclipse.persistence:eclipselink:2.7.10'
classpath 'jakarta.ws.rs:jakarta.ws.rs-api:2.1.6'
classpath('com.google.cloud.tools:jib-layer-filter-extension-gradle:0.1.0')
}
}
@@ -119,7 +120,7 @@ allprojects {
// We do not use :+ to get the latest available version available on Maven Central, as that could suddenly break things.
// We use the Renovate Bot to automatically propose Pull Requests (PRs) when upgrades for all of these versions are available.
dependency 'org.apache.openjpa:openjpa:3.2.1' // when upgrading, also change OpenJPA version repeated above in buildscript!
dependency 'org.eclipse.persistence:org.eclipse.persistence.jpa:2.7.10'
dependency 'com.google.guava:guava:31.1-jre'
dependency 'com.google.code.gson:gson:2.9.0'
dependency 'com.google.truth:truth:1.1.3'
@@ -415,7 +416,9 @@ configure(project.fineractJavaProjects) {
"-Xlint:varargs",
"-Xlint:preview",
"-Xlint:static",
"-Werror",
// -Werror needs to be disabled because EclipseLink's static weaving doesn't generate warning-free code
// and during an IntelliJ recompilation, it fails
//"-Werror",
"-Xmaxwarns",
1500,
"-Xmaxerrs",
@@ -477,7 +480,7 @@ configure(project.fineractJavaProjects) {
licenseMain.dependsOn compileJava
processResources.dependsOn compileJava
// If we are running Gradle within Eclipse to enhance classes with OpenJPA,
// If we are running Gradle within Eclipse to enhance classes,
// set the classes directory to point to Eclipse's default build directory
if (project.hasProperty('env') && project.getProperty('env') == 'eclipse') {
sourceSets.main.java.outputDir = file("$projectDir/bin/main")
@@ -632,6 +635,7 @@ configure(project.fineractJavaProjects) {
spotbugs {
reportLevel = 'high'
showProgress = false
excludeFilter = file("$rootDir/config/spotbugs/exclude.xml")
}
// https://github.com/spotbugs/spotbugs-gradle-plugin/issues/242
spotbugsMain {
+9
View File
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<FindBugsFilter
xmlns="https://github.com/spotbugs/filter/3.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://github.com/spotbugs/filter/3.0.0 https://raw.githubusercontent.com/spotbugs/spotbugs/3.1.0/spotbugs/etc/findbugsfilter.xsd">
<Match>
<Package name="~.*\.domain"/>
</Match>
</FindBugsFilter>
+14 -62
View File
@@ -26,70 +26,21 @@ apply plugin: 'com.gorylenko.gradle-git-properties'
apply plugin: 'io.swagger.core.v3.swagger-gradle-plugin'
apply plugin: 'com.google.cloud.tools.jib'
// Custom OpenJPA enhancement
compileJava.doLast {
def enhanceIncludes = [
'**/AbstractPersistableCustom.class',
'**/domain/*.class'
]
def classesToEnhance = project.sourceSets.main.output.classesDirs.collectMany { classesDir ->
project.fileTree(classesDir).matching {
enhanceIncludes.forEach { include it }
}.files
def mainSS = sourceSets.main
def source = mainSS.java.classesDirectory.get()
copy {
from "src/main/resources/"
into source
}
String persistenceXml = "META-INF/persistence.xml"
def persistenceXmlFile
// Check if persistence.xml is in the resource dirs.
project.sourceSets.main.resources.srcDirs.collect { resourceDir ->
def persistenceXmlFileCandidate = project.fileTree(resourceDir).matching {
include persistenceXml
}
if (!persistenceXmlFileCandidate.isEmpty()) {
if (persistenceXmlFile == null) {
persistenceXmlFile = persistenceXmlFileCandidate.singleFile
} else {
throw new InvalidUserDataException("Multiple persistence.xml files found in path: " +
persistenceXmlFile + ", " + persistenceXmlFileCandidate)
}
}
// Nothing found. Fallback to plain file.
if (persistenceXmlFile == null) {
persistenceXmlFile = project.file(persistenceXml)
if (!persistenceXmlFile.exists()) {
throw new InvalidUserDataException(
"Could not find valid persistence.xml in path " + this.persistenceXml)
}
}
javaexec {
description = 'Performs EclipseLink static weaving of entity classes'
def target = source
main 'org.eclipse.persistence.tools.weaving.jpa.StaticWeave'
args '-persistenceinfo', source, '-classpath', configurations.runtimeClasspath, source, target
classpath configurations.runtimeClasspath
}
org.apache.openjpa.lib.util.Options options = new org.apache.openjpa.lib.util.Options([
"addDefaultConstructor" : true,
"enforcePropertyRestrictions": true,
"tmpClassLoader" : false,
"propertiesFile" : persistenceXmlFile
])
def classes = project.sourceSets.main.output.classesDirs.collect { it.toURI().toURL() }
def compileJars = project.configurations.compileClasspath.files.collect { jar ->
jar.toURI().toURL()
}
def resources = project.sourceSets.main.resources.srcDirs.collect { resource ->
resource.toURI().toURL()
}
def urls = (classes + compileJars + resources)
ClassLoader currentClassLoader = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(new URLClassLoader((URL[])urls, currentClassLoader));
org.apache.openjpa.enhance.PCEnhancer.run((String []) classesToEnhance, options);
Thread.currentThread().setContextClassLoader(currentClassLoader);
}
// Configuration for Swagger documentation generation task
@@ -151,7 +102,8 @@ apply from: 'dependencies.gradle'
modernizer {
ignoreClassNamePatterns = [
'.*AbstractPersistableCustom',
'.*EntityTables'
'.*EntityTables',
'.*domain.*'
]
}
+2 -3
View File
@@ -89,9 +89,8 @@ dependencies {
implementation ('org.springframework.boot:spring-boot-starter-data-jpa') {
exclude group: 'org.hibernate'
}
implementation ('org.apache.openjpa:openjpa') {
exclude group: 'org.eclipse.persistence'
exclude group: 'org.apache.geronimo.specs'
implementation('org.eclipse.persistence:org.eclipse.persistence.jpa:2.7.10') {
exclude group: 'org.eclipse.persistence', module: 'jakarta.persistence'
}
implementation ('org.quartz-scheduler:quartz') {
exclude group: 'com.zaxxer', module: 'HikariCP-java7'
@@ -74,7 +74,7 @@ public class FinancialActivityAccountWritePlatformServiceImpl implements Financi
FinancialActivityAccount financialActivityAccount = FinancialActivityAccount.createNew(glAccount, financialActivityId);
validateFinancialActivityAndAccountMapping(financialActivityAccount);
this.financialActivityAccountRepository.save(financialActivityAccount);
this.financialActivityAccountRepository.saveAndFlush(financialActivityAccount);
return new CommandProcessingResultBuilder() //
.withCommandId(command.commandId()) //
.withEntityId(financialActivityAccount.getId()) //
@@ -122,7 +122,7 @@ public class FinancialActivityAccountWritePlatformServiceImpl implements Financi
if (!changes.isEmpty()) {
validateFinancialActivityAndAccountMapping(financialActivityAccount);
this.financialActivityAccountRepository.save(financialActivityAccount);
this.financialActivityAccountRepository.saveAndFlush(financialActivityAccount);
}
return new CommandProcessingResultBuilder() //
.withCommandId(command.commandId()) //
@@ -107,7 +107,7 @@ public class GLAccountWritePlatformServiceJpaRepositoryImpl implements GLAccount
glAccount.generateHierarchy();
this.glAccountRepository.save(glAccount);
this.glAccountRepository.saveAndFlush(glAccount);
return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(glAccount.getId()).build();
} catch (final JpaSystemException | DataIntegrityViolationException dve) {
@@ -1098,7 +1098,7 @@ public class AccountingProcessorHelper {
final JournalEntry journalEntry = JournalEntry.createNew(office, paymentDetail, account, currencyCode, modifiedTransactionId,
manualEntry, transactionDate, JournalEntryType.DEBIT, amount, null, PortfolioProductType.SHARES.getValue(), shareAccountId,
null, loanTransaction, savingsAccountTransaction, clientTransaction, shareTransactionId);
this.glJournalEntryRepository.save(journalEntry);
this.glJournalEntryRepository.saveAndFlush(journalEntry);
}
private void createCreditJournalEntryForShares(final Office office, final String currencyCode, final GLAccount account,
@@ -1117,7 +1117,7 @@ public class AccountingProcessorHelper {
final JournalEntry journalEntry = JournalEntry.createNew(office, paymentDetail, account, currencyCode, modifiedTransactionId,
manualEntry, transactionDate, JournalEntryType.CREDIT, amount, null, PortfolioProductType.SHARES.getValue(), shareAccountId,
null, loanTransaction, savingsAccountTransaction, clientTransaction, shareTransactionId);
this.glJournalEntryRepository.save(journalEntry);
this.glJournalEntryRepository.saveAndFlush(journalEntry);
}
public GLAccount getLinkedGLAccountForLoanProduct(final Long loanProductId, final int accountMappingTypeId, final Long paymentTypeId) {
@@ -412,11 +412,11 @@ public class JournalEntryWritePlatformServiceJpaRepositoryImpl implements Journa
journalEntry.getShareTransactionId());
}
// save the reversal entry
this.glJournalEntryRepository.save(reversalJournalEntry);
this.glJournalEntryRepository.saveAndFlush(reversalJournalEntry);
journalEntry.setReversalJournalEntry(reversalJournalEntry);
journalEntry.setReversed(true);
// save the updated journal entry
this.glJournalEntryRepository.save(journalEntry);
this.glJournalEntryRepository.saveAndFlush(journalEntry);
}
return reversalTransactionId;
@@ -580,11 +580,11 @@ public class JournalEntryWritePlatformServiceJpaRepositoryImpl implements Journa
journalEntry.getShareTransactionId());
}
// save the reversal entry
this.glJournalEntryRepository.save(reversalJournalEntry);
this.glJournalEntryRepository.saveAndFlush(reversalJournalEntry);
journalEntry.setReversalJournalEntry(reversalJournalEntry);
journalEntry.setReversed(true);
// save the updated journal entry
this.glJournalEntryRepository.save(journalEntry);
this.glJournalEntryRepository.saveAndFlush(journalEntry);
}
}
}
@@ -78,7 +78,7 @@ public class ProductToGLAccountMappingHelper {
final ProductToGLAccountMapping accountMapping = new ProductToGLAccountMapping(glAccount, productId,
portfolioProductType.getValue(), placeHolderTypeId);
this.accountMappingRepository.save(accountMapping);
this.accountMappingRepository.saveAndFlush(accountMapping);
}
public void mergeProductToAccountMappingChanges(final JsonElement element, final String paramName, final Long productId,
@@ -97,7 +97,7 @@ public class ProductToGLAccountMappingHelper {
final GLAccount glAccount = getAccountByIdAndType(paramName, expectedAccountType, accountId);
changes.put(paramName, accountId);
accountMapping.setGlAccount(glAccount);
this.accountMappingRepository.save(accountMapping);
this.accountMappingRepository.saveAndFlush(accountMapping);
}
}
}
@@ -116,12 +116,12 @@ public class ProductToGLAccountMappingHelper {
changes.put(paramName, accountId);
ProductToGLAccountMapping newAccountMapping = new ProductToGLAccountMapping(glAccount, productId,
portfolioProductType.getValue(), accountTypeId);
this.accountMappingRepository.save(newAccountMapping);
this.accountMappingRepository.saveAndFlush(newAccountMapping);
} else if (!accountMapping.getGlAccount().getId().equals(accountId)) {
final GLAccount glAccount = getAccountByIdAndType(paramName, expectedAccountType, accountId);
changes.put(paramName, accountId);
accountMapping.setGlAccount(glAccount);
this.accountMappingRepository.save(accountMapping);
this.accountMappingRepository.saveAndFlush(accountMapping);
}
}
}
@@ -258,7 +258,7 @@ public class ProductToGLAccountMappingHelper {
allowedAccountTypes, newGLAccountId);
}
chargeToIncomeAccountMapping.setGlAccount(glAccount);
this.accountMappingRepository.save(chargeToIncomeAccountMapping);
this.accountMappingRepository.saveAndFlush(chargeToIncomeAccountMapping);
}
} // deleted payment type
else {
@@ -334,7 +334,7 @@ public class ProductToGLAccountMappingHelper {
if (!newGLAccountId.equals(existingPaymentChannelToFundSourceMapping.getGlAccount().getId())) {
final GLAccount glAccount = getAccountById(LoanProductAccountingParams.FUND_SOURCE.getValue(), newGLAccountId);
existingPaymentChannelToFundSourceMapping.setGlAccount(glAccount);
this.accountMappingRepository.save(existingPaymentChannelToFundSourceMapping);
this.accountMappingRepository.saveAndFlush(existingPaymentChannelToFundSourceMapping);
}
} // deleted payment type
else {
@@ -364,7 +364,7 @@ public class ProductToGLAccountMappingHelper {
final GLAccount glAccount = getAccountById(LoanProductAccountingParams.FUND_SOURCE.getValue(), paymentTypeSpecificFundAccountId);
final ProductToGLAccountMapping accountMapping = new ProductToGLAccountMapping(glAccount, productId,
portfolioProductType.getValue(), CashAccountsForLoan.FUND_SOURCE.getValue(), paymentType);
this.accountMappingRepository.save(accountMapping);
this.accountMappingRepository.saveAndFlush(accountMapping);
}
/**
@@ -395,7 +395,7 @@ public class ProductToGLAccountMappingHelper {
}
final ProductToGLAccountMapping accountMapping = new ProductToGLAccountMapping(glAccount, productId,
portfolioProductType.getValue(), placeHolderAccountType.getValue(), charge);
this.accountMappingRepository.save(accountMapping);
this.accountMappingRepository.saveAndFlush(accountMapping);
}
private List<GLAccountType> getAllowedAccountTypesForFeeMapping() {
@@ -128,7 +128,7 @@ public class ProvisioningEntriesWritePlatformServiceJpaRepositoryImpl implements
requestedEntry.setJournalEntryCreated(Boolean.TRUE);
}
this.provisioningEntryRepository.save(requestedEntry);
this.provisioningEntryRepository.saveAndFlush(requestedEntry);
this.journalEntryWritePlatformService.createProvisioningJournalEntries(requestedEntry);
}
@@ -210,7 +210,7 @@ public class ProvisioningEntriesWritePlatformServiceJpaRepositoryImpl implements
.retrieveExistingProvisioningIdDateWithJournals();
revertAndAddJournalEntries(exisProvisioningEntryData, requestedEntry);
} else {
this.provisioningEntryRepository.save(requestedEntry);
this.provisioningEntryRepository.saveAndFlush(requestedEntry);
}
return requestedEntry;
}
@@ -220,10 +220,10 @@ public class ProvisioningEntriesWritePlatformServiceJpaRepositoryImpl implements
ProvisioningEntry requestedEntry = this.provisioningEntryRepository.findById(provisioningEntryId)
.orElseThrow(() -> new ProvisioningEntryNotfoundException(provisioningEntryId));
requestedEntry.getLoanProductProvisioningEntries().clear();
this.provisioningEntryRepository.save(requestedEntry);
this.provisioningEntryRepository.saveAndFlush(requestedEntry);
Collection<LoanProductProvisioningEntry> entries = generateLoanProvisioningEntry(requestedEntry, requestedEntry.getCreatedDate());
requestedEntry.setProvisioningEntries(entries);
this.provisioningEntryRepository.save(requestedEntry);
this.provisioningEntryRepository.saveAndFlush(requestedEntry);
return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(requestedEntry.getId()).build();
}
@@ -63,7 +63,7 @@ public class AdHocWritePlatformServiceJpaRepositoryImpl implements AdHocWritePla
this.adHocCommandFromApiJsonDeserializer.validateForCreate(command.json());
final AdHoc entity = AdHoc.fromJson(command);
this.adHocRepository.save(entity);
this.adHocRepository.saveAndFlush(entity);
return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(entity.getId()).build();
} catch (final JpaSystemException | DataIntegrityViolationException dve) {
@@ -152,7 +152,7 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer
public CommandProcessingResult logCommand(CommandSource commandSourceResult) {
commandSourceResult.markAsAwaitingApproval();
commandSourceResult = this.commandSourceRepository.save(commandSourceResult);
commandSourceResult = this.commandSourceRepository.saveAndFlush(commandSourceResult);
return new CommandProcessingResultBuilder().withCommandId(commandSourceResult.getId())
.withEntityId(commandSourceResult.getResourceId()).build();
@@ -72,7 +72,7 @@ public class AccountNumberFormatWritePlatformServiceJpaRepositoryImpl implements
AccountNumberFormat accountNumberFormat = new AccountNumberFormat(entityAccountType, accountNumberPrefixType, prefixCharacter);
this.accountNumberFormatRepository.save(accountNumberFormat);
this.accountNumberFormatRepository.saveAndFlush(accountNumberFormat);
return new CommandProcessingResultBuilder() //
.withEntityId(accountNumberFormat.getId()) //
@@ -140,7 +140,7 @@ public class BulkImportEventListener implements ApplicationListener<BulkImportEv
final Workbook workbook = event.getWorkbook();
final Count count = importHandler.process(workbook, event.getLocale(), event.getDateFormat());
importDocument.update(DateUtils.getLocalDateTimeOfTenant(), count.getSuccessCount(), count.getErrorCount());
this.importRepository.save(importDocument);
this.importRepository.saveAndFlush(importDocument);
final Set<String> modifiedParams = new HashSet<>();
modifiedParams.add("fileName");
@@ -177,7 +177,7 @@ public class EmailCampaignWritePlatformCommandHandlerImpl implements EmailCampai
emailCampaign.setStretchyReportParamMap(new Gson().toJson(stretchyReportParams));
}
this.emailCampaignRepository.save(emailCampaign);
this.emailCampaignRepository.saveAndFlush(emailCampaign);
return new CommandProcessingResultBuilder() //
.withCommandId(command.commandId()) //
@@ -67,7 +67,7 @@ public class EmailWritePlatformServiceJpaRepositoryImpl implements EmailWritePla
// TODO: decision to be made on wheter we 'wait' for response or use
// 'future/promise' to capture response and update the EmailMessage
// table
this.repository.save(message);
this.repository.saveAndFlush(message);
return new CommandProcessingResultBuilder() //
.withCommandId(command.commandId()) //
@@ -150,7 +150,7 @@ public class SmsCampaignWritePlatformServiceJpaImpl implements SmsCampaignWriteP
throw new GeneralPlatformDomainRuleException("error.msg.campaign.recurrenceStartDate.in.the.past",
"Recurrence start date cannot be the past date.", smsCampaign.getRecurrenceStartDate());
}
this.smsCampaignRepository.save(smsCampaign);
this.smsCampaignRepository.saveAndFlush(smsCampaign);
return new CommandProcessingResultBuilder() //
.withCommandId(command.commandId()) //
@@ -76,7 +76,7 @@ public class CodeValueWritePlatformServiceJpaRepositoryImpl implements CodeValue
final Long codeId = command.entityId();
final Code code = this.codeRepository.findById(codeId).orElseThrow(() -> new CodeNotFoundException(codeId));
final CodeValue codeValue = CodeValue.fromJson(code, command);
this.codeValueRepository.save(codeValue);
this.codeValueRepository.saveAndFlush(codeValue);
return new CommandProcessingResultBuilder() //
.withCommandId(command.commandId()) //
@@ -68,7 +68,7 @@ public class CodeWritePlatformServiceJpaRepositoryImpl implements CodeWritePlatf
this.fromApiJsonDeserializer.validateForCreate(command.json());
final Code code = Code.fromJson(command);
this.codeRepository.save(code);
this.codeRepository.saveAndFlush(code);
return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(code.getId()).build();
} catch (final JpaSystemException | DataIntegrityViolationException dve) {
@@ -95,7 +95,7 @@ public class CodeWritePlatformServiceJpaRepositoryImpl implements CodeWritePlatf
final Map<String, Object> changes = code.update(command);
if (!changes.isEmpty()) {
this.codeRepository.save(code);
this.codeRepository.saveAndFlush(code);
}
return new CommandProcessingResultBuilder() //
@@ -0,0 +1,115 @@
/**
* 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.core.config;
import java.util.Map;
import org.apache.fineract.infrastructure.core.domain.AuditorAwareImpl;
import org.apache.fineract.infrastructure.core.persistence.DatabaseSelectingPersistenceUnitPostProcessor;
import org.apache.fineract.infrastructure.core.persistence.ExtendedJpaTransactionManager;
import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
import org.apache.fineract.infrastructure.core.service.database.DatabaseTypeResolver;
import org.apache.fineract.useradministration.domain.AppUser;
import org.eclipse.persistence.config.PersistenceUnitProperties;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.orm.jpa.EntityManagerFactoryBuilderCustomizer;
import org.springframework.boot.autoconfigure.orm.jpa.JpaBaseConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
import org.springframework.boot.autoconfigure.transaction.TransactionManagerCustomizers;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.context.annotation.Primary;
import org.springframework.data.domain.AuditorAware;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.persistenceunit.PersistenceUnitManager;
import org.springframework.orm.jpa.vendor.AbstractJpaVendorAdapter;
import org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.jta.JtaTransactionManager;
import org.springframework.transaction.support.TransactionTemplate;
@Configuration
@EnableJpaAuditing
@EnableJpaRepositories(basePackages = "org.apache.fineract.**.domain")
public class JPAConfig extends JpaBaseConfiguration {
private final DatabaseTypeResolver databaseTypeResolver;
public JPAConfig(RoutingDataSource dataSource, JpaProperties properties, ObjectProvider<JtaTransactionManager> jtaTransactionManager,
DatabaseTypeResolver databaseTypeResolver) {
super(dataSource, properties, jtaTransactionManager);
this.databaseTypeResolver = databaseTypeResolver;
}
@Override
@Bean
@Primary
@DependsOn("tenantDatabaseUpgradeService")
public LocalContainerEntityManagerFactoryBean entityManagerFactory(EntityManagerFactoryBuilder factoryBuilder) {
Map<String, Object> vendorProperties = getVendorProperties();
customizeVendorProperties(vendorProperties);
return factoryBuilder.dataSource(getDataSource()).packages(getPackagesToScan()).properties(vendorProperties)
.persistenceUnit("jpa-pu").packages("org.apache.fineract").jta(false).build();
}
@Override
public EntityManagerFactoryBuilder entityManagerFactoryBuilder(JpaVendorAdapter jpaVendorAdapter,
ObjectProvider<PersistenceUnitManager> persistenceUnitManager,
ObjectProvider<EntityManagerFactoryBuilderCustomizer> customizers) {
EntityManagerFactoryBuilder builder = super.entityManagerFactoryBuilder(jpaVendorAdapter, persistenceUnitManager, customizers);
builder.setPersistenceUnitPostProcessors(new DatabaseSelectingPersistenceUnitPostProcessor(databaseTypeResolver));
return builder;
}
@Override
protected AbstractJpaVendorAdapter createJpaVendorAdapter() {
return new EclipseLinkJpaVendorAdapter();
}
@Override
protected Map<String, Object> getVendorProperties() {
return Map.of(PersistenceUnitProperties.WEAVING, "static", PersistenceUnitProperties.PERSISTENCE_CONTEXT_CLOSE_ON_COMMIT, "true",
PersistenceUnitProperties.CACHE_SHARED_DEFAULT, "false");
}
@Bean
public AuditorAware<AppUser> auditorAware() {
return new AuditorAwareImpl();
}
@Override
@Bean
public PlatformTransactionManager transactionManager(ObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers) {
ExtendedJpaTransactionManager transactionManager = new ExtendedJpaTransactionManager();
transactionManagerCustomizers.ifAvailable((customizers) -> customizers.customize(transactionManager));
return transactionManager;
}
@Bean
public TransactionTemplate txTemplate(PlatformTransactionManager transactionManager) {
TransactionTemplate tt = new TransactionTemplate();
tt.setTransactionManager(transactionManager);
return tt;
}
}
@@ -1,80 +0,0 @@
/**
* 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.core.config;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import org.apache.fineract.infrastructure.core.domain.AuditorAwareImpl;
import org.apache.fineract.infrastructure.openjpa.OpenJpaTransactionManager;
import org.apache.fineract.infrastructure.openjpa.OpenJpaVendorAdapter;
import org.apache.fineract.useradministration.domain.AppUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.data.domain.AuditorAware;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.support.TransactionTemplate;
@Configuration
@EnableJpaAuditing
@EnableJpaRepositories(basePackages = "org.apache.fineract.**.domain")
public class PersistenceConfig {
@Autowired
DataSource routingDataSource;
@Bean
@DependsOn("tenantDatabaseUpgradeService")
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
final LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(routingDataSource);
// NOTE: very important to set this explicitly when building Docker images with Jib; otherwise complains about
// duplicate resources
em.setPersistenceXmlLocation("classpath:META-INF/persistence.xml");
em.setJpaVendorAdapter(new OpenJpaVendorAdapter());
em.setPersistenceUnitName("jpa-pu");
em.afterPropertiesSet();
return em;
}
@Bean
public OpenJpaTransactionManager transactionManager(EntityManagerFactory emf) {
OpenJpaTransactionManager jtm = new OpenJpaTransactionManager();
jtm.setEntityManagerFactory(emf);
return jtm;
}
@Bean
public TransactionTemplate txTemplate(JpaTransactionManager jtm) {
TransactionTemplate tt = new TransactionTemplate();
tt.setTransactionManager(jtm);
return tt;
}
@Bean
public AuditorAware<AppUser> auditorAware() {
return new AuditorAwareImpl();
}
}
@@ -23,6 +23,8 @@ import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
import javax.persistence.PostLoad;
import javax.persistence.PrePersist;
import javax.persistence.Transient;
import org.springframework.data.domain.Persistable;
@@ -45,6 +47,9 @@ public abstract class AbstractPersistableCustom implements Persistable<Long>, Se
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Transient
private boolean isNew = true;
@Override
public Long getId() {
return id;
@@ -55,8 +60,13 @@ public abstract class AbstractPersistableCustom implements Persistable<Long>, Se
}
@Override
@Transient // DATAJPA-622
public boolean isNew() {
return null == this.id;
return isNew;
}
@PrePersist
@PostLoad
void markNotNew() {
this.isNew = false;
}
}
@@ -0,0 +1,49 @@
/**
* 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.core.persistence;
import java.util.Map;
import org.apache.fineract.infrastructure.core.service.database.DatabaseType;
import org.apache.fineract.infrastructure.core.service.database.DatabaseTypeResolver;
import org.eclipse.persistence.config.PersistenceUnitProperties;
import org.eclipse.persistence.config.TargetDatabase;
import org.springframework.orm.jpa.persistenceunit.MutablePersistenceUnitInfo;
import org.springframework.orm.jpa.persistenceunit.PersistenceUnitPostProcessor;
public class DatabaseSelectingPersistenceUnitPostProcessor implements PersistenceUnitPostProcessor {
private static final Map<DatabaseType, String> TARGET_DATABASE_MAP = Map.of(DatabaseType.MYSQL, TargetDatabase.MySQL,
DatabaseType.POSTGRESQL, TargetDatabase.PostgreSQL);
private final DatabaseTypeResolver databaseTypeResolver;
public DatabaseSelectingPersistenceUnitPostProcessor(DatabaseTypeResolver databaseTypeResolver) {
this.databaseTypeResolver = databaseTypeResolver;
}
@Override
public void postProcessPersistenceUnitInfo(MutablePersistenceUnitInfo pui) {
DatabaseType databaseType = databaseTypeResolver.databaseType();
String targetDatabase = TARGET_DATABASE_MAP.get(databaseType);
if (targetDatabase == null) {
throw new IllegalStateException("Unsupported database: " + databaseType);
}
pui.addProperty(PersistenceUnitProperties.TARGET_DATABASE, targetDatabase);
}
}
@@ -0,0 +1,73 @@
/**
* 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.core.persistence;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.persistence.Entity;
import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.orm.jpa.persistenceunit.MutablePersistenceUnitInfo;
import org.springframework.orm.jpa.persistenceunit.PersistenceUnitPostProcessor;
public class EntityScanningPersistenceUnitPostProcessor implements PersistenceUnitPostProcessor, InitializingBean {
private static final Logger LOG = LoggerFactory.getLogger(EntityScanningPersistenceUnitPostProcessor.class);
private List<String> packages;
private final Set<Class<?>> persistentClasses = new HashSet<>();
@Override
public void afterPropertiesSet() throws Exception {
if (CollectionUtils.isEmpty(packages)) {
throw new IllegalArgumentException("packages must be set");
}
LOG.debug("Looking for @Entity in {} ", packages);
ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false);
scanner.addIncludeFilter(new AnnotationTypeFilter(Entity.class));
for (String p : packages) {
for (BeanDefinition bd : scanner.findCandidateComponents(p)) {
persistentClasses.add(Class.forName(bd.getBeanClassName()));
}
}
if (persistentClasses.isEmpty()) {
throw new IllegalArgumentException("No class annotated with @Entity found in: " + packages);
}
}
@Override
public void postProcessPersistenceUnitInfo(MutablePersistenceUnitInfo persistenceUnitInfo) {
for (Class<?> c : persistentClasses) {
persistenceUnitInfo.addManagedClassName(c.getName());
}
}
public void setPackages(List<String> packages) {
this.packages = packages;
}
}
@@ -16,27 +16,52 @@
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.infrastructure.openjpa;
package org.apache.fineract.infrastructure.core.persistence;
import javax.persistence.EntityManager;
import javax.persistence.FlushModeType;
import org.springframework.jdbc.datasource.JdbcTransactionObjectSupport;
import org.springframework.orm.jpa.EntityManagerHolder;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.support.DefaultTransactionStatus;
import org.springframework.transaction.support.TransactionSynchronizationManager;
public class OpenJpaTransactionManager extends JpaTransactionManager {
public class ExtendedJpaTransactionManager extends JpaTransactionManager {
@Override
protected void doBegin(Object transaction, TransactionDefinition definition) {
super.doBegin(transaction, definition);
if (isReadOnlyTx(transaction)) {
EntityManager entityManager = getCurrentEntityManager();
if (entityManager != null) {
entityManager.setFlushMode(FlushModeType.COMMIT);
}
}
}
@Override
protected void doCommit(DefaultTransactionStatus status) {
JdbcTransactionObjectSupport txObject = (JdbcTransactionObjectSupport) status.getTransaction();
if (txObject.isReadOnly()) {
EntityManagerHolder holder = (EntityManagerHolder) TransactionSynchronizationManager.getResource(obtainEntityManagerFactory());
if (holder != null) {
EntityManager entityManager = holder.getEntityManager();
if (isReadOnlyTx(status.getTransaction())) {
EntityManager entityManager = getCurrentEntityManager();
if (entityManager != null) {
entityManager.clear();
}
}
super.doCommit(status);
}
private boolean isReadOnlyTx(Object transaction) {
JdbcTransactionObjectSupport txObject = (JdbcTransactionObjectSupport) transaction;
return txObject.isReadOnly();
}
private EntityManager getCurrentEntityManager() {
EntityManagerHolder holder = (EntityManagerHolder) TransactionSynchronizationManager.getResource(obtainEntityManagerFactory());
if (holder != null) {
return holder.getEntityManager();
}
return null;
}
}
@@ -23,6 +23,7 @@ import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.Table;
@@ -36,6 +37,7 @@ public class OrganisationCreditBureau extends AbstractPersistableCustom {
private String alias;
@OneToOne
@JoinColumn(name = "creditbureau_id", nullable = false)
private CreditBureau creditbureau;
@Column(name = "is_active")
@@ -69,7 +69,7 @@ public class CreditBureauConfigurationWritePlatformServiceImpl implements Credit
final CreditBureauConfiguration cb_config = CreditBureauConfiguration.fromJson(command, orgcb);
this.creditBureauConfigurationRepository.save(cb_config);
this.creditBureauConfigurationRepository.saveAndFlush(cb_config);
return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(cb_config.getId()).build();
@@ -74,7 +74,7 @@ public class CreditBureauLoanProductMappingWritePlatformServiceImpl implements C
final CreditBureauLoanProductMapping cb_lp = CreditBureauLoanProductMapping.fromJson(command, orgcb, lp);
this.creditBureauLoanProductMappingRepository.save(cb_lp);
this.creditBureauLoanProductMappingRepository.saveAndFlush(cb_lp);
return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(cb_lp.getId()).build();
@@ -110,7 +110,7 @@ public class CreditReportWritePlatformServiceImpl implements CreditReportWritePl
throw new PlatformApiDataValidationException("creditBureau.has.not.been.Integrated", "creditBureau.has.not.been.Integrated",
dataValidationErrors);
} catch (final DataIntegrityViolationException dve) {
} catch (final JpaSystemException | DataIntegrityViolationException dve) {
handleTokenDataIntegrityIssues(command, dve.getMostSpecificCause(), dve);
return CommandProcessingResult.empty();
} catch (final PersistenceException ee) {
@@ -189,7 +189,7 @@ public class CreditReportWritePlatformServiceImpl implements CreditReportWritePl
}
return new CommandProcessingResultBuilder().withEntityId(creditReport.getId()).build();
} catch (final DataIntegrityViolationException dve) {
} catch (final JpaSystemException | DataIntegrityViolationException dve) {
handleTokenDataIntegrityIssues(command, dve.getMostSpecificCause(), dve);
return CommandProcessingResult.empty();
} catch (final PersistenceException ee) {
@@ -62,7 +62,7 @@ public class OrganisationCreditBureauWritePlatflormServiceImpl implements Organi
final OrganisationCreditBureau organisationCreditBureau = OrganisationCreditBureau.fromJson(command, creditBureau);
this.organisationCreditBureauRepository.save(organisationCreditBureau);
this.organisationCreditBureauRepository.saveAndFlush(organisationCreditBureau);
return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(organisationCreditBureau.getId())
.build();
@@ -182,6 +182,7 @@ public class EntityDatatableChecksWritePlatformServiceImpl implements EntityData
}
@Transactional(readOnly = true)
@Override
public void runTheCheckForProduct(final Long entityId, final String entityName, final Long statusCode, String foreignKeyColumn,
long productId) {
@@ -92,7 +92,7 @@ public class ReportWritePlatformServiceImpl implements ReportWritePlatformServic
final Set<ReportParameterUsage> reportParameterUsages = assembleSetOfReportParameterUsages(report, command);
report.update(reportParameterUsages);
this.reportRepository.save(report);
this.reportRepository.saveAndFlush(report);
final Permission permission = new Permission("report", report.getReportName(), "READ");
this.permissionRepository.save(permission);
@@ -77,7 +77,7 @@ public class DocumentWritePlatformServiceJpaRepositoryImpl implements DocumentWr
documentCommand.getName(), documentCommand.getFileName(), documentCommand.getSize(), documentCommand.getType(),
documentCommand.getDescription(), fileLocation, contentRepository.getStorageType());
this.documentRepository.save(document);
this.documentRepository.saveAndFlush(document);
return document.getId();
} catch (final JpaSystemException | DataIntegrityViolationException dve) {
@@ -107,7 +107,7 @@ public class FineractEntityAccessWriteServiceImpl implements FineractEntityAcces
final FineractEntityToEntityMapping newMap = FineractEntityToEntityMapping.newMap(mapId, fromId, toId, startDate, endDate);
this.fineractEntityToEntityMappingRepository.save(newMap);
this.fineractEntityToEntityMappingRepository.saveAndFlush(newMap);
return new CommandProcessingResultBuilder().withEntityId(newMap.getId()).withCommandId(command.commandId()).build();
} catch (final JpaSystemException | DataIntegrityViolationException dve) {
@@ -19,6 +19,7 @@
package org.apache.fineract.infrastructure.gcm.service;
import java.util.Date;
import javax.persistence.EntityExistsException;
import javax.persistence.PersistenceException;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException;
@@ -28,7 +29,6 @@ import org.apache.fineract.infrastructure.gcm.domain.DeviceRegistrationRepositor
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.portfolio.client.domain.Client;
import org.apache.fineract.portfolio.client.domain.ClientRepositoryWrapper;
import org.apache.openjpa.persistence.EntityExistsException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.orm.jpa.JpaSystemException;
@@ -119,7 +119,7 @@ public class HookWritePlatformServiceJpaRepositoryImpl implements HookWritePlatf
validateHookRules(template, config, allEvents);
this.hookRepository.save(hook);
this.hookRepository.saveAndFlush(hook);
return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(hook.getId()).build();
} catch (final JpaSystemException | DataIntegrityViolationException dve) {
@@ -1,159 +0,0 @@
/**
* 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.openjpa;
import java.sql.Connection;
import java.sql.SQLException;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceException;
import org.apache.commons.logging.LogFactory;
import org.apache.openjpa.persistence.FetchPlan;
import org.apache.openjpa.persistence.OpenJPAEntityManager;
import org.apache.openjpa.persistence.OpenJPAPersistence;
import org.apache.openjpa.persistence.jdbc.IsolationLevel;
import org.apache.openjpa.persistence.jdbc.JDBCFetchPlan;
import org.springframework.jdbc.datasource.ConnectionHandle;
import org.springframework.jdbc.datasource.ConnectionHolder;
import org.springframework.jdbc.support.JdbcUtils;
import org.springframework.orm.jpa.DefaultJpaDialect;
import org.springframework.transaction.SavepointManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionException;
/**
* {@link org.springframework.orm.jpa.JpaDialect} implementation for Apache OpenJPA. Developed and tested against
* OpenJPA 2.2.
*
* @author Costin Leau
* @author Juergen Hoeller
* @since 2.0
*/
public class OpenJpaDialect extends DefaultJpaDialect {
@Override
public Object beginTransaction(EntityManager entityManager, TransactionDefinition definition)
throws PersistenceException, SQLException, TransactionException {
OpenJPAEntityManager openJpaEntityManager = getOpenJPAEntityManager(entityManager);
if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) {
// Pass custom isolation level on to OpenJPA's JDBCFetchPlan
// configuration
FetchPlan fetchPlan = openJpaEntityManager.getFetchPlan();
if (fetchPlan instanceof JDBCFetchPlan) {
IsolationLevel isolation = IsolationLevel.fromConnectionConstant(definition.getIsolationLevel());
((JDBCFetchPlan) fetchPlan).setIsolation(isolation);
}
}
entityManager.getTransaction().begin();
if (!definition.isReadOnly()) {
// Like with EclipseLink, make sure to start the logic transaction
// early so that other
// participants using the connection (such as JdbcTemplate) run in a
// transaction.
openJpaEntityManager.beginStore();
}
// Custom implementation for OpenJPA savepoint handling
return new OpenJpaTransactionData(openJpaEntityManager);
}
@Override
public ConnectionHandle getJdbcConnection(EntityManager entityManager, boolean readOnly) throws PersistenceException, SQLException {
return new OpenJpaConnectionHandle(getOpenJPAEntityManager(entityManager));
}
/**
* Return the OpenJPA-specific variant of {@code EntityManager}.
*
* @param em
* the generic {@code EntityManager} instance
* @return the OpenJPA-specific variant of {@code EntityManager}
*/
protected OpenJPAEntityManager getOpenJPAEntityManager(EntityManager em) {
return OpenJPAPersistence.cast(em);
}
/**
* Transaction data Object exposed from {@code beginTransaction}, implementing the {@link SavepointManager}
* interface.
*/
private static class OpenJpaTransactionData implements SavepointManager {
private final OpenJPAEntityManager entityManager;
private int savepointCounter = 0;
OpenJpaTransactionData(OpenJPAEntityManager entityManager) {
this.entityManager = entityManager;
}
@Override
public Object createSavepoint() throws TransactionException {
this.savepointCounter++;
String savepointName = ConnectionHolder.SAVEPOINT_NAME_PREFIX + this.savepointCounter;
this.entityManager.setSavepoint(savepointName);
return savepointName;
}
@Override
public void rollbackToSavepoint(Object savepoint) throws TransactionException {
this.entityManager.rollbackToSavepoint((String) savepoint);
}
@Override
public void releaseSavepoint(Object savepoint) throws TransactionException {
try {
this.entityManager.releaseSavepoint((String) savepoint);
} catch (Throwable ex) {
LogFactory.getLog(OpenJpaTransactionData.class).debug("Could not explicitly release OpenJPA savepoint", ex);
}
}
}
/**
* {@link ConnectionHandle} implementation that fetches a new OpenJPA-provided Connection for every
* {@code getConnection} call and closes the Connection on {@code releaseConnection}. This is necessary because
* OpenJPA requires the fetched Connection to be closed before continuing EntityManager work.
*
* @see org.apache.openjpa.persistence.OpenJPAEntityManager#getConnection()
*/
private static class OpenJpaConnectionHandle implements ConnectionHandle {
private final OpenJPAEntityManager entityManager;
OpenJpaConnectionHandle(OpenJPAEntityManager entityManager) {
this.entityManager = entityManager;
}
@Override
public Connection getConnection() {
return (Connection) this.entityManager.getConnection();
}
@Override
public void releaseConnection(Connection con) {
JdbcUtils.closeConnection(con);
}
}
}
@@ -1,134 +0,0 @@
/**
* 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.openjpa;
import java.util.HashMap;
import java.util.Map;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.spi.PersistenceProvider;
import org.apache.openjpa.persistence.OpenJPAEntityManagerFactorySPI;
import org.apache.openjpa.persistence.OpenJPAEntityManagerSPI;
import org.apache.openjpa.persistence.PersistenceProviderImpl;
import org.springframework.orm.jpa.vendor.AbstractJpaVendorAdapter;
import org.springframework.orm.jpa.vendor.Database;
/**
* {@link org.springframework.orm.jpa.JpaVendorAdapter} implementation for Apache OpenJPA. Developed and tested against
* OpenJPA 2.2.
*
* <p>
* Exposes OpenJPA's persistence provider and EntityManager extension interface, and supports
* {@link AbstractJpaVendorAdapter}'s common configuration settings.
*
* @author Costin Leau
* @author Juergen Hoeller
* @since 2.0
* @see org.apache.openjpa.persistence.PersistenceProviderImpl
* @see org.apache.openjpa.persistence.OpenJPAEntityManager
*/
public class OpenJpaVendorAdapter extends AbstractJpaVendorAdapter {
private final PersistenceProvider persistenceProvider = new PersistenceProviderImpl();
private final OpenJpaDialect jpaDialect = new OpenJpaDialect();
@Override
public PersistenceProvider getPersistenceProvider() {
return this.persistenceProvider;
}
@Override
public String getPersistenceProviderRootPackage() {
return "org.apache.openjpa";
}
@Override
public Map<String, Object> getJpaPropertyMap() {
Map<String, Object> jpaProperties = new HashMap<String, Object>();
if (getDatabasePlatform() != null) {
jpaProperties.put("openjpa.jdbc.DBDictionary", getDatabasePlatform());
} else if (getDatabase() != null) {
String databaseDictonary = determineDatabaseDictionary(getDatabase());
if (databaseDictonary != null) {
jpaProperties.put("openjpa.jdbc.DBDictionary", databaseDictonary);
}
}
if (isGenerateDdl()) {
jpaProperties.put("openjpa.jdbc.SynchronizeMappings", "buildSchema(ForeignKeys=true)");
}
if (isShowSql()) {
// Taken from the OpenJPA 0.9.6 docs ("Standard OpenJPA Log
// Configuration + All SQL Statements")
jpaProperties.put("openjpa.Log", "DefaultLevel=WARN, Runtime=INFO, Tool=INFO, SQL=TRACE");
}
return jpaProperties;
}
/**
* Determine the OpenJPA database dictionary name for the given database.
*
* @param database
* the specified database
* @return the OpenJPA database dictionary name, or {@code null} if none found
*/
protected String determineDatabaseDictionary(Database database) {
switch (database) {
case DB2:
return "db2";
case DERBY:
return "derby";
case HSQL:
return "hsql(SimulateLocking=true)";
case INFORMIX:
return "informix";
case MYSQL:
return "mysql";
case ORACLE:
return "oracle";
case POSTGRESQL:
return "postgres";
case SQL_SERVER:
return "sqlserver";
case SYBASE:
return "sybase";
default:
return null;
}
}
@Override
public OpenJpaDialect getJpaDialect() {
return this.jpaDialect;
}
@Override
public Class<? extends EntityManagerFactory> getEntityManagerFactoryInterface() {
return OpenJPAEntityManagerFactorySPI.class;
}
@Override
public Class<? extends EntityManager> getEntityManagerInterface() {
return OpenJPAEntityManagerSPI.class;
}
}
@@ -124,7 +124,7 @@ public class ReportMailingJobWritePlatformServiceImpl implements ReportMailingJo
final ReportMailingJob reportMailingJob = ReportMailingJob.newInstance(jsonCommand, stretchyReport, appUser);
// save entity
this.reportMailingJobRepository.save(reportMailingJob);
this.reportMailingJobRepository.saveAndFlush(reportMailingJob);
return new CommandProcessingResultBuilder().withCommandId(jsonCommand.commandId()).withEntityId(reportMailingJob.getId())
.build();
@@ -67,7 +67,7 @@ public class SmsWritePlatformServiceJpaRepositoryImpl implements SmsWritePlatfor
// TODO: decision to be made on wheter we 'wait' for response or use
// 'future/promise' to capture response and update the SmsMessage
// table
this.repository.save(message);
this.repository.saveAndFlush(message);
return new CommandProcessingResultBuilder() //
.withCommandId(command.commandId()) //
@@ -288,7 +288,7 @@ public class InteropServiceImpl implements InteropService {
InteropIdentifier identifier = new InteropIdentifier(savingsAccount, request.getIdType(), request.getIdValue(),
request.getSubIdOrType(), createdBy.getUsername(), DateUtils.getDateOfTenant());
identifierRepository.save(identifier);
identifierRepository.saveAndFlush(identifier);
return InteropIdentifierAccountResponseData.build(identifier.getId(), savingsAccount.getExternalId());
} catch (final JpaSystemException | DataIntegrityViolationException dve) {
@@ -35,7 +35,7 @@ public class NotificationGeneratorWritePlatformServiceImpl implements Notificati
@Override
public Long create(Notification notification) {
this.notificationRepository.save(notification);
this.notificationRepository.saveAndFlush(notification);
return notification.getId();
}
}
@@ -35,7 +35,7 @@ public class NotificationMapperWritePlatformServiceImpl implements NotificationM
@Override
public Long create(NotificationMapper notificationMapper) {
this.notificationMapperRepository.save(notificationMapper);
this.notificationMapperRepository.saveAndFlush(notificationMapper);
return notificationMapper.getId();
}
}
@@ -35,7 +35,7 @@ public class TopicSubscriberWritePlatformServiceJpaRepositoryImpl implements Top
@Override
public Long create(TopicSubscriber topicSubscriber) {
topicSubscriberRepository.save(topicSubscriber);
topicSubscriberRepository.saveAndFlush(topicSubscriber);
return topicSubscriber.getId();
}
@@ -35,7 +35,7 @@ public class TopicWritePlatformServiceJpaRepositoryImpl implements TopicWritePla
@Override
public Long create(Topic topic) {
topicRepository.save(topic);
topicRepository.saveAndFlush(topic);
return topic.getId();
}
@@ -91,7 +91,7 @@ public class HolidayWritePlatformServiceJpaRepositoryImpl implements HolidayWrit
final Holiday holiday = Holiday.createNew(offices, command);
this.holidayRepository.save(holiday);
this.holidayRepository.saveAndFlush(holiday);
return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(holiday.getId()).build();
} catch (final JpaSystemException | DataIntegrityViolationException dve) {
@@ -98,7 +98,7 @@ public class OfficeWritePlatformServiceJpaRepositoryImpl implements OfficeWriteP
final Office office = Office.fromJson(parent, command);
// pre save to generate id for use in office hierarchy
this.officeRepositoryWrapper.save(office);
this.officeRepositoryWrapper.saveAndFlush(office);
office.generateHierarchy();
@@ -63,7 +63,7 @@ public class ProvisioningCategoryWritePlatformServiceJpaRepositoryImpl implement
try {
this.fromApiJsonDeserializer.validateForCreate(command.json());
final ProvisioningCategory provisioningCategory = ProvisioningCategory.fromJson(command);
this.provisioningCategoryRepository.save(provisioningCategory);
this.provisioningCategoryRepository.saveAndFlush(provisioningCategory);
return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(provisioningCategory.getId())
.build();
} catch (final JpaSystemException | DataIntegrityViolationException dve) {
@@ -98,7 +98,7 @@ public class ProvisioningCategoryWritePlatformServiceJpaRepositoryImpl implement
.orElseThrow(() -> new ProvisioningCategoryNotFoundException(categoryId));
final Map<String, Object> changes = provisioningCategoryForUpdate.update(command);
if (!changes.isEmpty()) {
this.provisioningCategoryRepository.save(provisioningCategoryForUpdate);
this.provisioningCategoryRepository.saveAndFlush(provisioningCategoryForUpdate);
}
return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(categoryId).with(changes).build();
} catch (final JpaSystemException | DataIntegrityViolationException dve) {
@@ -83,7 +83,7 @@ public class ProvisioningCriteriaWritePlatformServiceJpaRepositoryImpl implement
try {
this.fromApiJsonDeserializer.validateForCreate(command.json());
ProvisioningCriteria provisioningCriteria = provisioningCriteriaAssembler.fromParsedJson(command.parsedJson());
this.provisioningCriteriaRepository.save(provisioningCriteria);
this.provisioningCriteriaRepository.saveAndFlush(provisioningCriteria);
return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(provisioningCriteria.getId())
.build();
} catch (final JpaSystemException | DataIntegrityViolationException dve) {
@@ -69,7 +69,7 @@ public class StaffWritePlatformServiceJpaRepositoryImpl implements StaffWritePla
final Office staffOffice = this.officeRepositoryWrapper.findOneWithNotFoundDetection(officeId);
final Staff staff = Staff.fromJson(staffOffice, command);
this.staffRepository.save(staff);
this.staffRepository.saveAndFlush(staff);
return new CommandProcessingResultBuilder() //
.withCommandId(command.commandId()) //
@@ -113,7 +113,7 @@ public class TellerWritePlatformServiceJpaImpl implements TellerWritePlatformSer
final Teller teller = Teller.fromJson(tellerOffice, command);
// pre save to generate id for use in office hierarchy
this.tellerRepositoryWrapper.save(teller);
this.tellerRepositoryWrapper.saveAndFlush(teller);
return new CommandProcessingResultBuilder() //
.withCommandId(command.commandId()) //
@@ -125,16 +125,16 @@ public class StandingInstructionWritePlatformServiceImpl implements StandingInst
if (isSavingsToSavingsAccountTransfer(fromAccountType, toAccountType)) {
final AccountTransferDetails standingInstruction = this.standingInstructionAssembler
.assembleSavingsToSavingsTransfer(command);
this.accountTransferDetailRepository.save(standingInstruction);
this.accountTransferDetailRepository.saveAndFlush(standingInstruction);
standingInstructionId = standingInstruction.accountTransferStandingInstruction().getId();
} else if (isSavingsToLoanAccountTransfer(fromAccountType, toAccountType)) {
final AccountTransferDetails standingInstruction = this.standingInstructionAssembler.assembleSavingsToLoanTransfer(command);
this.accountTransferDetailRepository.save(standingInstruction);
this.accountTransferDetailRepository.saveAndFlush(standingInstruction);
standingInstructionId = standingInstruction.accountTransferStandingInstruction().getId();
} else if (isLoanToSavingsAccountTransfer(fromAccountType, toAccountType)) {
final AccountTransferDetails standingInstruction = this.standingInstructionAssembler.assembleLoanToSavingsTransfer(command);
this.accountTransferDetailRepository.save(standingInstruction);
this.accountTransferDetailRepository.saveAndFlush(standingInstruction);
standingInstructionId = standingInstruction.accountTransferStandingInstruction().getId();
}
@@ -100,7 +100,7 @@ public class AddressWritePlatformServiceImpl implements AddressWritePlatformServ
final boolean isActive = command.booleanPrimitiveValueOfParameterNamed("isActive");
final ClientAddress clientAddressobj = ClientAddress.fromJson(isActive, client, addobj, addressTypeIdObj);
this.clientAddressRepository.save(clientAddressobj);
this.clientAddressRepository.saveAndFlush(clientAddressobj);
return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(clientAddressobj.getId()).build();
}
@@ -152,7 +152,7 @@ public class AddressWritePlatformServiceImpl implements AddressWritePlatformServ
}
clientAddressobj = ClientAddress.fromJson(isActive, client, addobj, addressTypeIdObj);
this.clientAddressRepository.save(clientAddressobj);
this.clientAddressRepository.saveAndFlush(clientAddressobj);
}
}
@@ -31,10 +31,10 @@ import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Temporal;
@@ -98,8 +98,7 @@ public class Calendar extends AbstractAuditableCustom {
@Temporal(TemporalType.TIME)
private Date meetingtime;
@OneToMany(fetch = FetchType.EAGER)
@JoinColumn(name = "calendar_id")
@OneToMany(mappedBy = "calendar", fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true)
private Set<CalendarHistory> calendarHistory = new HashSet<>();
protected Calendar() {
@@ -153,7 +153,7 @@ public class CalendarWritePlatformServiceJpaRepositoryImpl implements CalendarWr
throw new PlatformApiDataValidationException(dataValidationErrors);
}
this.calendarRepository.save(newCalendar);
this.calendarRepository.saveAndFlush(newCalendar);
final CalendarInstance newCalendarInstance = CalendarInstance.from(newCalendar, entityId, entityTypeId);
this.calendarInstanceRepository.save(newCalendarInstance);
@@ -122,7 +122,7 @@ public class ChargeWritePlatformServiceJpaRepositoryImpl implements ChargeWriteP
}
final Charge charge = Charge.fromJson(command, glAccount, taxGroup, paymentType);
this.chargeRepository.save(charge);
this.chargeRepository.saveAndFlush(charge);
// check if the office specific products are enabled. If yes, then
// save this savings product against a specific office
@@ -21,9 +21,9 @@ package org.apache.fineract.portfolio.client.domain;
import org.apache.fineract.organisation.office.domain.OrganisationCurrencyRepositoryWrapper;
import org.apache.fineract.portfolio.charge.exception.ChargeNotFoundException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
@Repository
@Service
public class ClientChargeRepositoryWrapper {
private final ClientChargeRepository repository;
@@ -21,9 +21,9 @@ package org.apache.fineract.portfolio.client.domain;
import org.apache.fineract.organisation.office.domain.OrganisationCurrencyRepositoryWrapper;
import org.apache.fineract.portfolio.client.exception.ClientTransactionNotFoundException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
@Repository
@Service
public class ClientTransactionRepositoryWrapper {
private final ClientTransactionRepository repository;
@@ -218,7 +218,7 @@ public class ClientChargeWritePlatformServiceJpaRepositoryImpl implements Client
// create Waiver Transaction
ClientTransaction clientTransaction = ClientTransaction.waiver(client, client.getOffice(), transactionDate, waivedAmount,
clientCharge.getCurrency().getCode(), getAppUserIfPresent());
this.clientTransactionRepository.save(clientTransaction);
this.clientTransactionRepository.saveAndFlush(clientTransaction);
// update charge paid by associations
final ClientChargePaidBy chargePaidBy = ClientChargePaidBy.instance(clientTransaction, clientCharge, waivedAmount.getAmount());
@@ -145,7 +145,7 @@ public class ClientFamilyMembersWritePlatformServiceImpl implements ClientFamily
ClientFamilyMembers clientFamilyMembers = ClientFamilyMembers.fromJson(client, firstName, middleName, lastName, qualification,
mobileNumber, age, isDependent, relationship, maritalStatus, gender, dateOfBirth, profession);
this.clientFamilyRepository.save(clientFamilyMembers);
this.clientFamilyRepository.saveAndFlush(clientFamilyMembers);
return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(clientFamilyMembers.getId()).build();
@@ -257,7 +257,7 @@ public class ClientFamilyMembersWritePlatformServiceImpl implements ClientFamily
familyMember = ClientFamilyMembers.fromJson(client, firstName, middleName, lastName, qualification, mobileNumber, age,
isDependent, relationship, maritalStatus, gender, dateOfBirth, profession);
this.clientFamilyRepository.save(familyMember);
this.clientFamilyRepository.saveAndFlush(familyMember);
}
@@ -370,7 +370,7 @@ public class ClientFamilyMembersWritePlatformServiceImpl implements ClientFamily
// middleName, lastName, qualification, relationship, maritalStatus,
// gender, dateOfBirth, profession);
this.clientFamilyRepository.save(clientFamilyMember);
this.clientFamilyRepository.saveAndFlush(clientFamilyMember);
return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(clientFamilyMember.getId()).build();
}
@@ -90,7 +90,7 @@ public class ClientIdentifierWritePlatformServiceJpaRepositoryImpl implements Cl
final ClientIdentifier clientIdentifier = ClientIdentifier.fromJson(client, documentType, command);
this.clientIdentifierRepository.save(clientIdentifier);
this.clientIdentifierRepository.saveAndFlush(clientIdentifier);
return new CommandProcessingResultBuilder() //
.withCommandId(command.commandId()) //
@@ -294,7 +294,7 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
final Client newClient = Client.createNew(currentUser, clientOffice, clientParentGroup, staff, savingsProductId, gender,
clientType, clientClassification, legalFormValue, command);
this.clientRepository.save(newClient);
this.clientRepository.saveAndFlush(newClient);
boolean rollbackTransaction = false;
if (newClient.isActive()) {
validateParentGroupRulesBeforeClientActivation(newClient);
@@ -303,7 +303,7 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
rollbackTransaction = this.commandProcessingService.validateCommand(commandWrapper, currentUser);
}
this.clientRepository.save(newClient);
this.clientRepository.saveAndFlush(newClient);
if (newClient.isActive()) {
this.businessEventNotifierService.notifyBusinessEventWasExecuted(BusinessEvents.CLIENTS_ACTIVATE,
constructEntityMap(BusinessEntity.CLIENT, newClient));
@@ -311,14 +311,14 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
if (newClient.isAccountNumberRequiresAutoGeneration()) {
AccountNumberFormat accountNumberFormat = this.accountNumberFormatRepository.findByAccountType(EntityAccountType.CLIENT);
newClient.updateAccountNo(accountNumberGenerator.generate(newClient, accountNumberFormat));
this.clientRepository.save(newClient);
this.clientRepository.saveAndFlush(newClient);
}
final Locale locale = command.extractLocale();
final DateTimeFormatter fmt = DateTimeFormatter.ofPattern(command.dateFormat()).withLocale(locale);
CommandProcessingResult result = openSavingsAccount(newClient, fmt);
if (result.getSavingsId() != null) {
this.clientRepository.save(newClient);
this.clientRepository.saveAndFlush(newClient);
}
@@ -95,7 +95,7 @@ public class CollateralWritePlatformServiceJpaRepositoryImpl implements Collater
LoanCollateralCannotBeCreatedReason.LOAN_NOT_IN_SUBMITTED_AND_PENDING_APPROVAL_STAGE, loan.getId());
}
this.collateralRepository.save(collateral);
this.collateralRepository.saveAndFlush(collateral);
return new CommandProcessingResultBuilder() //
.withCommandId(command.commandId()) //
@@ -34,7 +34,7 @@ public class CollateralManagementRepositoryWrapper {
}
public CollateralManagementDomain create(CollateralManagementDomain collateralData) {
return this.collateralManagementDomainRepository.save(collateralData);
return this.collateralManagementDomainRepository.saveAndFlush(collateralData);
}
public CollateralManagementDomain getCollateral(Long collateralId) {
@@ -73,7 +73,7 @@ public class ClientCollateralManagementWritePlatformServiceImpl implements Clien
final CollateralManagementDomain collateralManagementData = this.collateralManagementRepositoryWrapper.getCollateral(collateralId);
final ClientCollateralManagement clientCollateralManagement = ClientCollateralManagement.createNew(quantity, client,
collateralManagementData);
this.clientCollateralManagementRepositoryWrapper.save(clientCollateralManagement);
this.clientCollateralManagementRepositoryWrapper.saveAndFlush(clientCollateralManagement);
return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withClientId(command.getClientId())
.withEntityId(clientCollateralManagement.getId()).build();
}
@@ -61,7 +61,7 @@ public class FloatingRateWritePlatformServiceImpl implements FloatingRateWritePl
this.fromApiJsonDeserializer.validateForCreate(command.json());
final AppUser currentUser = this.context.authenticatedUser();
final FloatingRate newFloatingRate = FloatingRate.createNew(currentUser, command);
this.floatingRateRepository.save(newFloatingRate);
this.floatingRateRepository.saveAndFlush(newFloatingRate);
return new CommandProcessingResultBuilder() //
.withCommandId(command.commandId()) //
.withEntityId(newFloatingRate.getId()) //
@@ -68,7 +68,7 @@ public class FundWritePlatformServiceJpaRepositoryImpl implements FundWritePlatf
final Fund fund = Fund.fromJson(command);
this.fundRepository.save(fund);
this.fundRepository.saveAndFlush(fund);
return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(fund.getId()).build();
} catch (final JpaSystemException | DataIntegrityViolationException dve) {
@@ -113,11 +113,11 @@ public class FundWritePlatformServiceJpaRepositoryImpl implements FundWritePlatf
* Guaranteed to throw an exception no matter what the data integrity issue is.
*/
private void handleFundDataIntegrityIssues(final JsonCommand command, final Throwable realCause, final Exception dve) {
if (realCause.getMessage().contains("fund_externalid_org")) {
if (realCause.getMessage().contains("m_fund_external_id_key")) {
final String externalId = command.stringValueOfParameterNamed("externalId");
throw new PlatformDataIntegrityException("error.msg.fund.duplicate.externalId",
"A fund with external id '" + externalId + "' already exists", "externalId", externalId);
} else if (realCause.getMessage().contains("fund_name_org")) {
} else if (realCause.getMessage().contains("m_fund_external_id_name")) {
final String name = command.stringValueOfParameterNamed("name");
throw new PlatformDataIntegrityException("error.msg.fund.duplicate.name", "A fund with name '" + name + "' already exists",
"name", name);
@@ -86,7 +86,7 @@ public class GroupRolesWritePlatformServiceJpaRepositoryImpl implements GroupRol
throw new ClientNotInGroupException(clientId, command.getGroupId());
}
final GroupRole groupRole = GroupRole.createGroupRole(group, client, role);
this.groupRoleRepository.save(groupRole);
this.groupRoleRepository.saveAndFlush(groupRole);
return new CommandProcessingResultBuilder().withClientId(client.getId()).withGroupId(group.getId())
.withEntityId(groupRole.getId()).build();
@@ -201,7 +201,7 @@ public class GroupingTypesWritePlatformServiceJpaRepositoryImpl implements Group
boolean rollbackTransaction = false;
if (newGroup.isActive()) {
this.groupRepository.save(newGroup);
this.groupRepository.saveAndFlush(newGroup);
// validate Group creation rules for Group
if (newGroup.isGroup()) {
validateGroupRulesBeforeActivation(newGroup);
@@ -76,7 +76,7 @@ public class InterestRateChartSlabWritePlatformServiceJpaRepositoryImpl implemen
final InterestRateChartSlab interestRateChartSlab = this.interestRateChartSlabAssembler.assembleFrom(command);
this.chartSlabRepository.save(interestRateChartSlab);
this.chartSlabRepository.saveAndFlush(interestRateChartSlab);
final Long interestRateChartId = interestRateChartSlab.getId();
@@ -44,6 +44,7 @@ import java.util.List;
import java.util.ListIterator;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
@@ -1245,8 +1246,17 @@ public class Loan extends AbstractPersistableCustom {
}
public void updateLoanSchedule(final Collection<LoanRepaymentScheduleInstallment> installments, AppUser currentUser) {
this.repaymentScheduleInstallments.clear();
List<LoanRepaymentScheduleInstallment> existingInstallments = new ArrayList<>(this.repaymentScheduleInstallments);
repaymentScheduleInstallments.clear();
for (final LoanRepaymentScheduleInstallment installment : installments) {
LoanRepaymentScheduleInstallment existingInstallment = findByInstallmentNumber(existingInstallments,
installment.getInstallmentNumber());
if (existingInstallment != null) {
Set<LoanInstallmentCharge> existingCharges = existingInstallment.getInstallmentCharges();
installment.getInstallmentCharges().addAll(existingCharges);
existingCharges.forEach(c -> c.setInstallment(installment));
existingInstallment.getInstallmentCharges().clear();
}
addLoanRepaymentScheduleInstallment(installment);
}
updateLoanScheduleDependentDerivedFields();
@@ -1255,6 +1265,16 @@ public class Loan extends AbstractPersistableCustom {
}
private LoanRepaymentScheduleInstallment findByInstallmentNumber(Collection<LoanRepaymentScheduleInstallment> installments,
Integer installmentNumber) {
for (LoanRepaymentScheduleInstallment installment : installments) {
if (Objects.equals(installment.getInstallmentNumber(), installmentNumber)) {
return installment;
}
}
return null;
}
/**
* method updates accrual derived fields on installments and reverse the unprocessed transactions
*/
@@ -4984,6 +5004,7 @@ public class Loan extends AbstractPersistableCustom {
.getAmount();
}
final LoanInstallmentCharge loanInstallmentCharge = new LoanInstallmentCharge(amount, loanCharge, installment);
installment.getInstallmentCharges().add(loanInstallmentCharge);
loanChargePerInstallments.add(loanInstallmentCharge);
}
}
@@ -286,8 +286,7 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
private void saveLoanTransactionWithDataIntegrityViolationChecks(LoanTransaction newRepaymentTransaction) {
try {
LoanTransaction loanTransaction = this.loanTransactionRepository.save(newRepaymentTransaction);
this.loanTransactionRepository.saveAndFlush(newRepaymentTransaction);
} catch (final JpaSystemException | DataIntegrityViolationException e) {
final Throwable realCause = e.getCause();
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
@@ -305,12 +304,6 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
private void saveAndFlushLoanWithDataIntegrityViolationChecks(final Loan loan) {
try {
List<LoanRepaymentScheduleInstallment> installments = loan.getRepaymentScheduleInstallments();
for (LoanRepaymentScheduleInstallment installment : installments) {
if (installment.getId() == null) {
this.repaymentScheduleInstallmentRepository.save(installment);
}
}
this.loanRepositoryWrapper.saveAndFlush(loan);
} catch (final JpaSystemException | DataIntegrityViolationException e) {
final Throwable realCause = e.getCause();
@@ -329,12 +322,6 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
@Override
public void saveLoanWithDataIntegrityViolationChecks(final Loan loan) {
try {
List<LoanRepaymentScheduleInstallment> installments = loan.getRepaymentScheduleInstallments();
for (LoanRepaymentScheduleInstallment installment : installments) {
if (installment.getId() == null) {
this.repaymentScheduleInstallmentRepository.save(installment);
}
}
this.loanRepositoryWrapper.save(loan);
} catch (final JpaSystemException | DataIntegrityViolationException e) {
final Throwable realCause = e.getCause();
@@ -462,7 +449,7 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
allowTransactionsOnHoliday, holidays, workingDays, allowTransactionsOnNonWorkingDay);
saveLoanTransactionWithDataIntegrityViolationChecks(newRefundTransaction);
this.loanRepositoryWrapper.save(loan);
this.loanRepositoryWrapper.saveAndFlush(loan);
if (StringUtils.isNotBlank(noteText)) {
final Note note = Note.loanTransactionNote(loan, newRefundTransaction, noteText);
@@ -659,8 +646,7 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
loan.makeRefundForActiveLoan(newRefundTransaction, defaultLoanLifecycleStateMachine(), existingTransactionIds,
existingReversedTransactionIds, allowTransactionsOnHoliday, holidays, workingDays, allowTransactionsOnNonWorkingDay);
this.loanTransactionRepository.save(newRefundTransaction);
this.loanRepositoryWrapper.save(loan);
this.loanTransactionRepository.saveAndFlush(newRefundTransaction);
if (StringUtils.isNotBlank(noteText)) {
final Note note = Note.loanTransactionNote(loan, newRefundTransaction, noteText);
@@ -543,9 +543,11 @@ public class LoanCharge extends AbstractPersistableCustom {
for (final LoanInstallmentCharge chargePerInstallment : oldChargeInstallments) {
if (index == loanChargePerInstallmentArray.length) {
remove.add(chargePerInstallment);
chargePerInstallment.updateInstallment(null);
chargePerInstallment.getInstallment().getInstallmentCharges().remove(chargePerInstallment);
} else {
chargePerInstallment.copyFrom(loanChargePerInstallmentArray[index++]);
LoanInstallmentCharge newLoanInstallmentCharge = loanChargePerInstallmentArray[index++];
newLoanInstallmentCharge.getInstallment().getInstallmentCharges().remove(newLoanInstallmentCharge);
chargePerInstallment.copyFrom(newLoanInstallmentCharge);
}
}
this.loanInstallmentCharge.removeAll(remove);
@@ -319,4 +319,7 @@ public class LoanInstallmentCharge extends AbstractPersistableCustom implements
return this.installment;
}
public void setInstallment(LoanRepaymentScheduleInstallment installment) {
this.installment = installment;
}
}
@@ -24,6 +24,8 @@ import java.time.ZoneId;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
@@ -34,6 +36,10 @@ import org.apache.fineract.infrastructure.core.service.DateUtils;
@Table(name = "m_loan_interest_recalculation_additional_details")
public class LoanInterestRecalcualtionAdditionalDetails extends AbstractPersistableCustom {
@ManyToOne(optional = false)
@JoinColumn(name = "loan_repayment_schedule_id", nullable = false)
private LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment;
@Temporal(TemporalType.DATE)
@Column(name = "effective_date")
private Date effectiveDate;
@@ -59,4 +65,12 @@ public class LoanInterestRecalcualtionAdditionalDetails extends AbstractPersista
public BigDecimal getAmount() {
return this.amount;
}
public LoanRepaymentScheduleInstallment getLoanRepaymentScheduleInstallment() {
return loanRepaymentScheduleInstallment;
}
public void setLoanRepaymentScheduleInstallment(LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment) {
this.loanRepaymentScheduleInstallment = loanRepaymentScheduleInstallment;
}
}
@@ -134,13 +134,15 @@ public final class LoanRepaymentScheduleInstallment extends AbstractAuditableCus
@Column(name = "recalculated_interest_component", nullable = false)
private boolean recalculatedInterestComponent;
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER)
@JoinColumn(name = "loan_repayment_schedule_id", referencedColumnName = "id", nullable = false)
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER, mappedBy = "loanRepaymentScheduleInstallment")
private Set<LoanInterestRecalcualtionAdditionalDetails> loanCompoundingDetails = new HashSet<>();
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER, mappedBy = "loanRepaymentScheduleInstallment")
private Set<PostDatedChecks> postDatedChecks;
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY, mappedBy = "installment")
private Set<LoanInstallmentCharge> installmentCharges = new HashSet<>();
LoanRepaymentScheduleInstallment() {
this.installmentNumber = null;
this.fromDate = null;
@@ -162,6 +164,9 @@ public final class LoanRepaymentScheduleInstallment extends AbstractAuditableCus
this.penaltyCharges = defaultToNullIfZero(penaltyCharges);
this.obligationsMet = false;
this.recalculatedInterestComponent = recalculatedInterestComponent;
if (compoundingDetails != null) {
compoundingDetails.forEach(cd -> cd.setLoanRepaymentScheduleInstallment(this));
}
this.loanCompoundingDetails = compoundingDetails;
this.rescheduleInterestPortion = rescheduleInterestPortion;
}
@@ -180,6 +185,9 @@ public final class LoanRepaymentScheduleInstallment extends AbstractAuditableCus
this.penaltyCharges = defaultToNullIfZero(penaltyCharges);
this.obligationsMet = false;
this.recalculatedInterestComponent = recalculatedInterestComponent;
if (compoundingDetails != null) {
compoundingDetails.forEach(cd -> cd.setLoanRepaymentScheduleInstallment(this));
}
this.loanCompoundingDetails = compoundingDetails;
}
@@ -861,4 +869,7 @@ public final class LoanRepaymentScheduleInstallment extends AbstractAuditableCus
this.feeChargesWaived = newFeeChargesCharged;
}
public Set<LoanInstallmentCharge> getInstallmentCharges() {
return installmentCharges;
}
}
@@ -24,11 +24,16 @@ import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
import org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleRequest;
@Entity
@Table(name = "m_loan_reschedule_request_term_variations_mapping")
public class LoanRescheduleRequestToTermVariationMapping extends AbstractPersistableCustom {
@ManyToOne(optional = false, cascade = CascadeType.ALL)
@JoinColumn(name = "loan_reschedule_request_id", nullable = false)
private LoanRescheduleRequest loanRescheduleRequest;
@ManyToOne(optional = false, cascade = CascadeType.PERSIST)
@JoinColumn(name = "loan_term_variations_id", nullable = false)
private LoanTermVariations loanTermVariations;
@@ -37,16 +42,22 @@ public class LoanRescheduleRequestToTermVariationMapping extends AbstractPersist
}
private LoanRescheduleRequestToTermVariationMapping(final LoanTermVariations loanTermVariations) {
private LoanRescheduleRequestToTermVariationMapping(final LoanRescheduleRequest loanRescheduleRequest,
final LoanTermVariations loanTermVariations) {
this.loanRescheduleRequest = loanRescheduleRequest;
this.loanTermVariations = loanTermVariations;
}
public static LoanRescheduleRequestToTermVariationMapping createNew(final LoanTermVariations loanTermVariation) {
return new LoanRescheduleRequestToTermVariationMapping(loanTermVariation);
public static LoanRescheduleRequestToTermVariationMapping createNew(final LoanRescheduleRequest loanRescheduleRequest,
final LoanTermVariations loanTermVariation) {
return new LoanRescheduleRequestToTermVariationMapping(loanRescheduleRequest, loanTermVariation);
}
public LoanTermVariations getLoanTermVariations() {
return this.loanTermVariations;
}
public LoanRescheduleRequest getLoanRescheduleRequest() {
return loanRescheduleRequest;
}
}
@@ -133,8 +133,7 @@ public class LoanTransaction extends AbstractPersistableCustom {
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY, mappedBy = "loanTransaction")
private Set<LoanCollateralManagement> loanCollateralManagementSet = new HashSet<>();
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER)
@JoinColumn(name = "loan_transaction_id", referencedColumnName = "id", nullable = false)
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER, mappedBy = "loanTransaction")
private Set<LoanTransactionToRepaymentScheduleMapping> loanTransactionToRepaymentScheduleMappings = new HashSet<>();
protected LoanTransaction() {
@@ -793,6 +792,7 @@ public class LoanTransaction extends AbstractPersistableCustom {
}
}
if (!isMappingUpdated) {
updatedrepaymentScheduleMapping.setLoanTransaction(this);
this.loanTransactionToRepaymentScheduleMappings.add(updatedrepaymentScheduleMapping);
retainMappings.add(updatedrepaymentScheduleMapping);
}
@@ -33,6 +33,10 @@ import org.apache.fineract.organisation.monetary.domain.Money;
@Table(name = "m_loan_transaction_repayment_schedule_mapping")
public class LoanTransactionToRepaymentScheduleMapping extends AbstractPersistableCustom {
@ManyToOne(optional = false, cascade = CascadeType.PERSIST)
@JoinColumn(name = "loan_transaction_id", nullable = false)
private LoanTransaction loanTransaction;
@ManyToOne(optional = false, cascade = CascadeType.PERSIST)
@JoinColumn(name = "loan_repayment_schedule_id", nullable = false)
private LoanRepaymentScheduleInstallment installment;
@@ -56,9 +60,10 @@ public class LoanTransactionToRepaymentScheduleMapping extends AbstractPersistab
}
private LoanTransactionToRepaymentScheduleMapping(final LoanRepaymentScheduleInstallment installment, final BigDecimal principalPortion,
final BigDecimal interestPortion, final BigDecimal feeChargesPortion, final BigDecimal penaltyChargesPortion,
final BigDecimal amount) {
private LoanTransactionToRepaymentScheduleMapping(final LoanTransaction loanTransaction,
final LoanRepaymentScheduleInstallment installment, final BigDecimal principalPortion, final BigDecimal interestPortion,
final BigDecimal feeChargesPortion, final BigDecimal penaltyChargesPortion, final BigDecimal amount) {
this.loanTransaction = loanTransaction;
this.installment = installment;
this.principalPortion = principalPortion;
this.interestPortion = interestPortion;
@@ -67,9 +72,10 @@ public class LoanTransactionToRepaymentScheduleMapping extends AbstractPersistab
this.amount = amount;
}
public static LoanTransactionToRepaymentScheduleMapping createFrom(final LoanRepaymentScheduleInstallment installment,
final Money principalPortion, final Money interestPortion, final Money feeChargesPortion, final Money penaltyChargesPortion) {
return new LoanTransactionToRepaymentScheduleMapping(installment, defaultToNullIfZero(principalPortion),
public static LoanTransactionToRepaymentScheduleMapping createFrom(final LoanTransaction loanTransaction,
final LoanRepaymentScheduleInstallment installment, final Money principalPortion, final Money interestPortion,
final Money feeChargesPortion, final Money penaltyChargesPortion) {
return new LoanTransactionToRepaymentScheduleMapping(loanTransaction, installment, defaultToNullIfZero(principalPortion),
defaultToNullIfZero(interestPortion), defaultToNullIfZero(feeChargesPortion), defaultToNullIfZero(penaltyChargesPortion),
defaultToNullIfZero(principalPortion.plus(interestPortion).plus(feeChargesPortion).plus(penaltyChargesPortion)));
}
@@ -138,6 +144,10 @@ public class LoanTransactionToRepaymentScheduleMapping extends AbstractPersistab
return Money.of(currency, this.penaltyChargesPortion);
}
public LoanTransaction getLoanTransaction() {
return loanTransaction;
}
public BigDecimal getPrincipalPortion() {
return this.principalPortion;
}
@@ -153,4 +163,8 @@ public class LoanTransactionToRepaymentScheduleMapping extends AbstractPersistab
public BigDecimal getPenaltyChargesPortion() {
return this.penaltyChargesPortion;
}
public void setLoanTransaction(LoanTransaction loanTransaction) {
this.loanTransaction = loanTransaction;
}
}
@@ -131,8 +131,8 @@ public class CreocoreLoanRepaymentScheduleTransactionProcessor extends AbstractL
transactionAmountRemaining = transactionAmountRemaining.minus(principalPortion);
}
if (principalPortion.plus(interestPortion).plus(feeChargesPortion).plus(penaltyChargesPortion).isGreaterThanZero()) {
transactionMappings.add(LoanTransactionToRepaymentScheduleMapping.createFrom(currentInstallment, principalPortion,
interestPortion, feeChargesPortion, penaltyChargesPortion));
transactionMappings.add(LoanTransactionToRepaymentScheduleMapping.createFrom(loanTransaction, currentInstallment,
principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion));
}
loanTransaction.updateComponents(principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion);
return transactionAmountRemaining;
@@ -175,8 +175,8 @@ public class CreocoreLoanRepaymentScheduleTransactionProcessor extends AbstractL
}
loanTransaction.updateComponents(principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion);
if (principalPortion.plus(interestPortion).plus(feeChargesPortion).plus(penaltyChargesPortion).isGreaterThanZero()) {
transactionMappings.add(LoanTransactionToRepaymentScheduleMapping.createFrom(currentInstallment, principalPortion,
interestPortion, feeChargesPortion, penaltyChargesPortion));
transactionMappings.add(LoanTransactionToRepaymentScheduleMapping.createFrom(loanTransaction, currentInstallment,
principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion));
}
return transactionAmountRemaining;
}
@@ -84,8 +84,8 @@ public class EarlyPaymentLoanRepaymentScheduleTransactionProcessor extends Abstr
loanTransaction.updateComponents(principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion);
}
if (principalPortion.plus(interestPortion).plus(feeChargesPortion).plus(penaltyChargesPortion).isGreaterThanZero()) {
transactionMappings.add(LoanTransactionToRepaymentScheduleMapping.createFrom(currentInstallment, principalPortion,
interestPortion, feeChargesPortion, penaltyChargesPortion));
transactionMappings.add(LoanTransactionToRepaymentScheduleMapping.createFrom(loanTransaction, currentInstallment,
principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion));
}
return transactionAmountRemaining;
@@ -153,8 +153,8 @@ public class EarlyPaymentLoanRepaymentScheduleTransactionProcessor extends Abstr
loanTransaction.updateComponents(principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion);
}
if (principalPortion.plus(interestPortion).plus(feeChargesPortion).plus(penaltyChargesPortion).isGreaterThanZero()) {
transactionMappings.add(LoanTransactionToRepaymentScheduleMapping.createFrom(currentInstallment, principalPortion,
interestPortion, feeChargesPortion, penaltyChargesPortion));
transactionMappings.add(LoanTransactionToRepaymentScheduleMapping.createFrom(loanTransaction, currentInstallment,
principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion));
}
return transactionAmountRemaining;
}
@@ -195,8 +195,8 @@ public class EarlyPaymentLoanRepaymentScheduleTransactionProcessor extends Abstr
loanTransaction.updateComponents(principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion);
if (principalPortion.plus(interestPortion).plus(feeChargesPortion).plus(penaltyChargesPortion).isGreaterThanZero()) {
transactionMappings.add(LoanTransactionToRepaymentScheduleMapping.createFrom(currentInstallment, principalPortion,
interestPortion, feeChargesPortion, penaltyChargesPortion));
transactionMappings.add(LoanTransactionToRepaymentScheduleMapping.createFrom(loanTransaction, currentInstallment,
principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion));
}
return transactionAmountRemaining;
}
@@ -129,8 +129,8 @@ public class FineractStyleLoanRepaymentScheduleTransactionProcessor extends Abst
loanTransaction.updateComponents(principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion);
}
if (principalPortion.plus(interestPortion).plus(feeChargesPortion).plus(penaltyChargesPortion).isGreaterThanZero()) {
transactionMappings.add(LoanTransactionToRepaymentScheduleMapping.createFrom(currentInstallment, principalPortion,
interestPortion, feeChargesPortion, penaltyChargesPortion));
transactionMappings.add(LoanTransactionToRepaymentScheduleMapping.createFrom(loanTransaction, currentInstallment,
principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion));
}
return transactionAmountRemaining;
}
@@ -172,8 +172,8 @@ public class FineractStyleLoanRepaymentScheduleTransactionProcessor extends Abst
}
loanTransaction.updateComponents(principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion);
if (principalPortion.plus(interestPortion).plus(feeChargesPortion).plus(penaltyChargesPortion).isGreaterThanZero()) {
transactionMappings.add(LoanTransactionToRepaymentScheduleMapping.createFrom(currentInstallment, principalPortion,
interestPortion, feeChargesPortion, penaltyChargesPortion));
transactionMappings.add(LoanTransactionToRepaymentScheduleMapping.createFrom(loanTransaction, currentInstallment,
principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion));
}
return transactionAmountRemaining;
}
@@ -132,8 +132,8 @@ public class HeavensFamilyLoanRepaymentScheduleTransactionProcessor extends Abst
loanTransaction.updateComponents(principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion);
if (principalPortion.plus(interestPortion).plus(feeChargesPortion).plus(penaltyChargesPortion).isGreaterThanZero()) {
transactionMappings.add(LoanTransactionToRepaymentScheduleMapping.createFrom(currentInstallment, principalPortion,
interestPortion, feeChargesPortion, penaltyChargesPortion));
transactionMappings.add(LoanTransactionToRepaymentScheduleMapping.createFrom(loanTransaction, currentInstallment,
principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion));
}
return transactionAmountRemaining;
}
@@ -193,8 +193,8 @@ public class HeavensFamilyLoanRepaymentScheduleTransactionProcessor extends Abst
loanTransaction.updateComponents(principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion);
if (principalPortion.plus(interestPortion).plus(feeChargesPortion).plus(penaltyChargesPortion).isGreaterThanZero()) {
transactionMappings.add(LoanTransactionToRepaymentScheduleMapping.createFrom(currentInstallment, principalPortion,
interestPortion, feeChargesPortion, penaltyChargesPortion));
transactionMappings.add(LoanTransactionToRepaymentScheduleMapping.createFrom(loanTransaction, currentInstallment,
principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion));
}
return transactionAmountRemaining;
}
@@ -237,8 +237,8 @@ public class HeavensFamilyLoanRepaymentScheduleTransactionProcessor extends Abst
loanTransaction.updateComponents(principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion);
if (principalPortion.plus(interestPortion).plus(feeChargesPortion).plus(penaltyChargesPortion).isGreaterThanZero()) {
transactionMappings.add(LoanTransactionToRepaymentScheduleMapping.createFrom(currentInstallment, principalPortion,
interestPortion, feeChargesPortion, penaltyChargesPortion));
transactionMappings.add(LoanTransactionToRepaymentScheduleMapping.createFrom(loanTransaction, currentInstallment,
principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion));
}
return transactionAmountRemaining;
}
@@ -118,8 +118,8 @@ public class InterestPrincipalPenaltyFeesOrderLoanRepaymentScheduleTransactionPr
loanTransaction.updateComponents(principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion);
}
if (principalPortion.plus(interestPortion).plus(feeChargesPortion).plus(penaltyChargesPortion).isGreaterThanZero()) {
transactionMappings.add(LoanTransactionToRepaymentScheduleMapping.createFrom(currentInstallment, principalPortion,
interestPortion, feeChargesPortion, penaltyChargesPortion));
transactionMappings.add(LoanTransactionToRepaymentScheduleMapping.createFrom(loanTransaction, currentInstallment,
principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion));
}
return transactionAmountRemaining;
}
@@ -158,8 +158,8 @@ public class InterestPrincipalPenaltyFeesOrderLoanRepaymentScheduleTransactionPr
loanTransaction.updateComponents(principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion);
if (principalPortion.plus(interestPortion).plus(feeChargesPortion).plus(penaltyChargesPortion).isGreaterThanZero()) {
transactionMappings.add(LoanTransactionToRepaymentScheduleMapping.createFrom(currentInstallment, principalPortion,
interestPortion, feeChargesPortion, penaltyChargesPortion));
transactionMappings.add(LoanTransactionToRepaymentScheduleMapping.createFrom(loanTransaction, currentInstallment,
principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion));
}
return transactionAmountRemaining;
}
@@ -118,8 +118,8 @@ public class PrincipalInterestPenaltyFeesOrderLoanRepaymentScheduleTransactionPr
loanTransaction.updateComponents(principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion);
}
if (principalPortion.plus(interestPortion).plus(feeChargesPortion).plus(penaltyChargesPortion).isGreaterThanZero()) {
transactionMappings.add(LoanTransactionToRepaymentScheduleMapping.createFrom(currentInstallment, principalPortion,
interestPortion, feeChargesPortion, penaltyChargesPortion));
transactionMappings.add(LoanTransactionToRepaymentScheduleMapping.createFrom(loanTransaction, currentInstallment,
principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion));
}
return transactionAmountRemaining;
@@ -161,8 +161,8 @@ public class PrincipalInterestPenaltyFeesOrderLoanRepaymentScheduleTransactionPr
loanTransaction.updateComponents(principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion);
if (principalPortion.plus(interestPortion).plus(feeChargesPortion).plus(penaltyChargesPortion).isGreaterThanZero()) {
transactionMappings.add(LoanTransactionToRepaymentScheduleMapping.createFrom(currentInstallment, principalPortion,
interestPortion, feeChargesPortion, penaltyChargesPortion));
transactionMappings.add(LoanTransactionToRepaymentScheduleMapping.createFrom(loanTransaction, currentInstallment,
principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion));
}
return transactionAmountRemaining;
}
@@ -93,8 +93,8 @@ public class RBILoanRepaymentScheduleTransactionProcessor extends AbstractLoanRe
final Money principalPortion = Money.zero(transactionAmountRemaining.getCurrency());
loanTransaction.updateComponents(principalPortion, interestWaivedPortion, feeChargesPortion, penaltyChargesPortion);
if (interestWaivedPortion.isGreaterThanZero()) {
transactionMappings.add(LoanTransactionToRepaymentScheduleMapping.createFrom(currentInstallment, principalPortion,
interestWaivedPortion, feeChargesPortion, penaltyChargesPortion));
transactionMappings.add(LoanTransactionToRepaymentScheduleMapping.createFrom(loanTransaction, currentInstallment,
principalPortion, interestWaivedPortion, feeChargesPortion, penaltyChargesPortion));
}
} else if (loanTransaction.isChargePayment()) {
final Money principalPortion = Money.zero(currency);
@@ -108,8 +108,8 @@ public class RBILoanRepaymentScheduleTransactionProcessor extends AbstractLoanRe
}
loanTransaction.updateComponents(principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion);
if (principalPortion.plus(interestPortion).plus(feeChargesPortion).plus(penaltyChargesPortion).isGreaterThanZero()) {
transactionMappings.add(LoanTransactionToRepaymentScheduleMapping.createFrom(currentInstallment, principalPortion,
interestPortion, feeChargesPortion, penaltyChargesPortion));
transactionMappings.add(LoanTransactionToRepaymentScheduleMapping.createFrom(loanTransaction, currentInstallment,
principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion));
}
} else {
@@ -133,8 +133,8 @@ public class RBILoanRepaymentScheduleTransactionProcessor extends AbstractLoanRe
final Money principalPortion = Money.zero(currency);
loanTransaction.updateComponents(principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion);
if (principalPortion.plus(interestPortion).plus(feeChargesPortion).plus(penaltyChargesPortion).isGreaterThanZero()) {
transactionMappings.add(LoanTransactionToRepaymentScheduleMapping.createFrom(installment, principalPortion,
interestPortion, feeChargesPortion, penaltyChargesPortion));
transactionMappings.add(LoanTransactionToRepaymentScheduleMapping.createFrom(loanTransaction, installment,
principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion));
}
}
}
@@ -159,8 +159,8 @@ public class RBILoanRepaymentScheduleTransactionProcessor extends AbstractLoanRe
}
if (!isMappingUpdated && principalPortion.plus(interestPortion).plus(feeChargesPortion).plus(penaltyChargesPortion)
.isGreaterThanZero()) {
transactionMappings.add(LoanTransactionToRepaymentScheduleMapping.createFrom(installment, principalPortion,
interestPortion, feeChargesPortion, penaltyChargesPortion));
transactionMappings.add(LoanTransactionToRepaymentScheduleMapping.createFrom(loanTransaction, installment,
principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion));
}
}
}
@@ -237,8 +237,8 @@ public class RBILoanRepaymentScheduleTransactionProcessor extends AbstractLoanRe
loanTransaction.updateComponents(principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion);
if (principalPortion.plus(interestPortion).plus(feeChargesPortion).plus(penaltyChargesPortion).isGreaterThanZero()) {
transactionMappings.add(LoanTransactionToRepaymentScheduleMapping.createFrom(currentInstallment, principalPortion,
interestPortion, feeChargesPortion, penaltyChargesPortion));
transactionMappings.add(LoanTransactionToRepaymentScheduleMapping.createFrom(loanTransaction, currentInstallment,
principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion));
}
return transactionAmountRemaining;
}
@@ -290,8 +290,8 @@ public class RBILoanRepaymentScheduleTransactionProcessor extends AbstractLoanRe
loanTransaction.updateComponents(principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion);
if (principalPortion.plus(interestPortion).plus(feeChargesPortion).plus(penaltyChargesPortion).isGreaterThanZero()) {
transactionMappings.add(LoanTransactionToRepaymentScheduleMapping.createFrom(currentInstallment, principalPortion,
interestPortion, feeChargesPortion, penaltyChargesPortion));
transactionMappings.add(LoanTransactionToRepaymentScheduleMapping.createFrom(loanTransaction, currentInstallment,
principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion));
}
return transactionAmountRemaining;
}
@@ -27,7 +27,7 @@ import org.springframework.data.repository.query.Param;
public interface GuarantorFundingTransactionRepository
extends JpaRepository<GuarantorFundingTransaction, Long>, JpaSpecificationExecutor<GuarantorFundingTransaction> {
@Query("select ft from GuarantorFundingTransaction ft where ft.loanTransaction.id in (:loanTransactions)")
@Query("select ft from GuarantorFundingTransaction ft where ft.loanTransaction.id in :loanTransactions")
List<GuarantorFundingTransaction> fetchGuarantorFundingTransactions(@Param("loanTransactions") List<Long> loanTransactions);
}
@@ -185,7 +185,7 @@ public class GuarantorDomainServiceImpl implements GuarantorDomainService {
GuarantorFundingTransaction guarantorFundingTransaction = new GuarantorFundingTransaction(guarantorFundingDetails, null,
onHoldTransaction);
guarantorFundingDetails.addGuarantorFundingTransactions(guarantorFundingTransaction);
this.depositAccountOnHoldTransactionRepository.save(onHoldTransaction);
this.depositAccountOnHoldTransactionRepository.saveAndFlush(onHoldTransaction);
}
}
@@ -206,8 +206,8 @@ public class GuarantorDomainServiceImpl implements GuarantorDomainService {
guarantorFundingDetails.releaseFunds(amoutForWithdraw);
guarantorFundingDetails.withdrawFunds(amoutForWithdraw);
guarantorFundingDetails.getLoanAccount().updateGuaranteeAmount(amoutForWithdraw.negate());
this.depositAccountOnHoldTransactionRepository.save(onHoldTransaction);
this.guarantorFundingRepository.save(guarantorFundingDetails);
this.depositAccountOnHoldTransactionRepository.saveAndFlush(onHoldTransaction);
this.guarantorFundingRepository.saveAndFlush(guarantorFundingDetails);
}
}
@@ -482,7 +482,7 @@ public class GuarantorDomainServiceImpl implements GuarantorDomainService {
calculateAndRelaseGuarantorFunds(guarantorList, guarantorGuarantee, amountForRelease, loanTransaction,
accountOnHoldTransactions);
this.depositAccountOnHoldTransactionRepository.saveAll(accountOnHoldTransactions);
this.guarantorFundingRepository.save(guarantorFundingDetails);
this.guarantorFundingRepository.saveAndFlush(guarantorFundingDetails);
}
}
@@ -174,9 +174,9 @@ public class GuarantorWritePlatformServiceJpaRepositoryIImpl implements Guaranto
}
if (accountAssociations != null) {
this.accountAssociationsRepository.save(accountAssociations);
this.accountAssociationsRepository.saveAndFlush(accountAssociations);
}
this.guarantorRepository.save(guarantor);
this.guarantorRepository.saveAndFlush(guarantor);
return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withOfficeId(guarantor.getOfficeId())
.withEntityId(guarantor.getId()).withLoanId(loan.getId()).build();
} catch (final JpaSystemException | DataIntegrityViolationException dve) {
@@ -245,7 +245,7 @@ public class GuarantorWritePlatformServiceJpaRepositoryIImpl implements Guaranto
}
if (!changesOnly.isEmpty()) {
this.guarantorRepository.save(guarantorForUpdate);
this.guarantorRepository.saveAndFlush(guarantorForUpdate);
}
return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withOfficeId(guarantorForUpdate.getOfficeId())
@@ -930,7 +930,6 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
* @param currency
* @param scheduleParams
* @param lastRestDate
* @param periodStartDateApplicableForInterest
* @param detail
*/
private void handleLatePayments(final LoanApplicationTerms loanApplicationTerms, final HolidayDetailDTO holidayDetailDTO,
@@ -991,15 +990,10 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
/**
* @param loanApplicationTerms
* @param scheduleParams
* @param priviousScheduledDueDate
* @param previousRepaymentDate
* @param scheduledDueDate
* @param interestRatesForInstallments
* @param mc
* @param paymentPeriodsInOneYearCalculator
* @param interestRates
* @param periodsApplicableForGrace
* @param scheduleDateForReversal
* @return
*/
private LoanTermVariationParams applyLoanTermVariations(final LoanApplicationTerms loanApplicationTerms,
@@ -1139,7 +1133,6 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
* TODO
* @param mc
* TODO
* @param periodNumber
* @return
*/
private LoanTermVariationParams applyExceptionLoanTermVariations(final LoanApplicationTerms loanApplicationTerms,
@@ -1222,7 +1215,6 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
* @param scheduleParams
* @param interestRates
* @param interestRatesForInstallments
* @param periodsApplicableForGrace
*/
private void applyLoanVariationsForPartialScheduleGenerate(final LoanApplicationTerms loanApplicationTerms,
LoanScheduleParams scheduleParams, final Collection<LoanTermVariationsData> interestRates,
@@ -1317,13 +1309,6 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
* Method calculates interest on not paid outstanding principal and interest (if compounding is enabled) till
* current date and adds new repayment schedule detail
*
* @param compoundingMap
* TODO
* @param loanCharges
* TODO
* @param principalPortioMap
* TODO
*
*/
private Money addInterestOnlyRepaymentScheduleForCurrentdate(final MathContext mc, final LoanApplicationTerms loanApplicationTerms,
final HolidayDetailDTO holidayDetailDTO, final MonetaryCurrency currency, final Collection<LoanScheduleModelPeriod> periods,
@@ -1869,8 +1854,6 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
*
* @param firstRepaymentdate
* TODO
* @param boolean1
* @param localDate
*/
private LocalDate calculateInterestStartDateForPeriod(final LoanApplicationTerms loanApplicationTerms, LocalDate periodStartDate,
final LocalDate idealDisbursementDate, final LocalDate firstRepaymentdate,
@@ -95,8 +95,7 @@ public class LoanRescheduleRequest extends AbstractPersistableCustom {
@JoinColumn(name = "rejected_by_user_id")
private AppUser rejectedByUser;
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER)
@JoinColumn(name = "loan_reschedule_request_id", nullable = false)
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER, mappedBy = "loanRescheduleRequest")
private Set<LoanRescheduleRequestToTermVariationMapping> loanRescheduleRequestToTermVariationMappings = new HashSet<>();
/**
@@ -284,8 +284,8 @@ public class LoanRescheduleRequestWritePlatformServiceImpl implements LoanResche
decimalValue, dueDate, endDate, emi);
// create a new entry in the m_loan_reschedule_request table
this.loanRescheduleRequestRepository.save(loanRescheduleRequest);
this.loanRepositoryWrapper.save(loan);
this.loanRescheduleRequestRepository.saveAndFlush(loanRescheduleRequest);
return new CommandProcessingResultBuilder().withCommandId(jsonCommand.commandId()).withEntityId(loanRescheduleRequest.getId())
.withLoanId(loan.getId()).withClientId(loan.getClientId()).withOfficeId(loan.getOfficeId())
@@ -316,7 +316,7 @@ public class LoanRescheduleRequestWritePlatformServiceImpl implements LoanResche
for (LoanRepaymentScheduleInstallment installment : installments) {
if (installment.getDueDate().isEqual(rescheduleFromLocDate) || installment.getDueDate().isEqual(endDateLocDate)
|| (installment.getDueDate().isAfter(rescheduleFromLocDate) && installment.getDueDate().isBefore(endDateLocDate))) {
createLoanTermVariations(termType, loan,
createLoanTermVariations(loanRescheduleRequest, termType, loan,
Date.from(installment.getDueDate().atStartOfDay(ZoneId.systemDefault()).toInstant()),
Date.from(installment.getDueDate().atStartOfDay(ZoneId.systemDefault()).toInstant()),
loanRescheduleRequestToTermVariationMappings, isActive, true, emi, parent);
@@ -330,51 +330,57 @@ public class LoanRescheduleRequestWritePlatformServiceImpl implements LoanResche
if (rescheduleFromDate != null && adjustedDueDate != null) {
LoanTermVariations parent = null;
final Integer termType = LoanTermVariationType.DUE_DATE.getValue();
createLoanTermVariations(termType, loan, rescheduleFromDate, adjustedDueDate, loanRescheduleRequestToTermVariationMappings,
isActive, isSpecificToInstallment, decimalValue, parent);
createLoanTermVariations(loanRescheduleRequest, termType, loan, rescheduleFromDate, adjustedDueDate,
loanRescheduleRequestToTermVariationMappings, isActive, isSpecificToInstallment, decimalValue, parent);
}
if (rescheduleFromDate != null && interestRate != null) {
LoanTermVariations parent = null;
final Integer termType = LoanTermVariationType.INTEREST_RATE_FROM_INSTALLMENT.getValue();
createLoanTermVariations(termType, loan, rescheduleFromDate, dueDate, loanRescheduleRequestToTermVariationMappings, isActive,
isSpecificToInstallment, interestRate, parent);
createLoanTermVariations(loanRescheduleRequest, termType, loan, rescheduleFromDate, dueDate,
loanRescheduleRequestToTermVariationMappings, isActive, isSpecificToInstallment, interestRate, parent);
}
if (rescheduleFromDate != null && graceOnPrincipal != null) {
final Integer termType = LoanTermVariationType.GRACE_ON_PRINCIPAL.getValue();
LoanTermVariations parent = null;
parent = createLoanTermVariations(termType, loan, rescheduleFromDate, dueDate, loanRescheduleRequestToTermVariationMappings,
isActive, isSpecificToInstallment, BigDecimal.valueOf(graceOnPrincipal), parent);
parent = createLoanTermVariations(loanRescheduleRequest, termType, loan, rescheduleFromDate, dueDate,
loanRescheduleRequestToTermVariationMappings, isActive, isSpecificToInstallment, BigDecimal.valueOf(graceOnPrincipal),
parent);
BigDecimal extraTermsBasedOnGracePeriods = BigDecimal.valueOf(graceOnPrincipal);
createLoanTermVariations(LoanTermVariationType.EXTEND_REPAYMENT_PERIOD.getValue(), loan, rescheduleFromDate, dueDate,
loanRescheduleRequestToTermVariationMappings, isActive, isSpecificToInstallment, extraTermsBasedOnGracePeriods, parent);
createLoanTermVariations(loanRescheduleRequest, LoanTermVariationType.EXTEND_REPAYMENT_PERIOD.getValue(), loan,
rescheduleFromDate, dueDate, loanRescheduleRequestToTermVariationMappings, isActive, isSpecificToInstallment,
extraTermsBasedOnGracePeriods, parent);
}
if (rescheduleFromDate != null && graceOnInterest != null) {
LoanTermVariations parent = null;
final Integer termType = LoanTermVariationType.GRACE_ON_INTEREST.getValue();
createLoanTermVariations(termType, loan, rescheduleFromDate, dueDate, loanRescheduleRequestToTermVariationMappings, isActive,
isSpecificToInstallment, BigDecimal.valueOf(graceOnInterest), parent);
createLoanTermVariations(loanRescheduleRequest, termType, loan, rescheduleFromDate, dueDate,
loanRescheduleRequestToTermVariationMappings, isActive, isSpecificToInstallment, BigDecimal.valueOf(graceOnInterest),
parent);
}
if (rescheduleFromDate != null && extraTerms != null) {
LoanTermVariations parent = null;
final Integer termType = LoanTermVariationType.EXTEND_REPAYMENT_PERIOD.getValue();
createLoanTermVariations(termType, loan, rescheduleFromDate, dueDate, loanRescheduleRequestToTermVariationMappings, isActive,
isSpecificToInstallment, BigDecimal.valueOf(extraTerms), parent);
createLoanTermVariations(loanRescheduleRequest, termType, loan, rescheduleFromDate, dueDate,
loanRescheduleRequestToTermVariationMappings, isActive, isSpecificToInstallment, BigDecimal.valueOf(extraTerms),
parent);
}
loanRescheduleRequest.updateLoanRescheduleRequestToTermVariationMappings(loanRescheduleRequestToTermVariationMappings);
}
private LoanTermVariations createLoanTermVariations(final Integer termType, final Loan loan, Date rescheduleFromDate,
Date adjustedDueDate, List<LoanRescheduleRequestToTermVariationMapping> loanRescheduleRequestToTermVariationMappings,
final Boolean isActive, final boolean isSpecificToInstallment, final BigDecimal decimalValue, LoanTermVariations parent) {
private LoanTermVariations createLoanTermVariations(LoanRescheduleRequest loanRescheduleRequest, final Integer termType,
final Loan loan, Date rescheduleFromDate, Date adjustedDueDate,
List<LoanRescheduleRequestToTermVariationMapping> loanRescheduleRequestToTermVariationMappings, final Boolean isActive,
final boolean isSpecificToInstallment, final BigDecimal decimalValue, LoanTermVariations parent) {
LoanTermVariations loanTermVariation = new LoanTermVariations(termType, rescheduleFromDate, decimalValue, adjustedDueDate,
isSpecificToInstallment, loan, loan.status().getValue(), isActive, parent);
loanRescheduleRequestToTermVariationMappings.add(LoanRescheduleRequestToTermVariationMapping.createNew(loanTermVariation));
loanRescheduleRequestToTermVariationMappings
.add(LoanRescheduleRequestToTermVariationMapping.createNew(loanRescheduleRequest, loanTermVariation));
return loanTermVariation;
}
@@ -105,7 +105,6 @@ 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.LoanRepaymentScheduleInstallment;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallmentRepository;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleTransactionProcessorFactory;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
@@ -392,7 +391,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
}
}
this.loanRepositoryWrapper.save(newLoanApplication);
this.loanRepositoryWrapper.saveAndFlush(newLoanApplication);
if (loanProduct.isInterestRecalculationEnabled()) {
this.fromApiJsonDeserializer.validateLoanForInterestRecalculation(newLoanApplication);
@@ -487,7 +486,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
}
} else { // for applications other than GLIM
newLoanApplication.updateAccountNo(this.accountNumberGenerator.generate(newLoanApplication, accountNumberFormat));
this.loanRepositoryWrapper.save(newLoanApplication);
this.loanRepositoryWrapper.saveAndFlush(newLoanApplication);
}
}
@@ -582,6 +581,8 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
command.arrayOfParameterNamed(LoanApiConstants.datatables));
}
loanRepositoryWrapper.flush();
this.entityDatatableChecksWritePlatformService.runTheCheckForProduct(newLoanApplication.getId(), EntityTables.LOAN.getName(),
StatusEnum.CREATE.getCode().longValue(), EntityTables.LOAN.getForeignKeyColumnNameOnDatatable(),
newLoanApplication.productId());
@@ -1224,7 +1225,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
// updating loan interest recalculation details throwing null
// pointer exception after saveAndFlush
// http://stackoverflow.com/questions/17151757/hibernate-cascade-update-gives-null-pointer/17334374#17334374
this.loanRepositoryWrapper.save(existingLoanApplication);
this.loanRepositoryWrapper.saveAndFlush(existingLoanApplication);
if (productRelatedDetail.isInterestRecalculationEnabled()) {
this.fromApiJsonDeserializer.validateLoanForInterestRecalculation(existingLoanApplication);
@@ -1616,7 +1617,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
final Map<String, Object> changes = loan.loanApplicationRejection(currentUser, command, defaultLoanLifecycleStateMachine());
if (!changes.isEmpty()) {
this.loanRepositoryWrapper.save(loan);
this.loanRepositoryWrapper.saveAndFlush(loan);
final String noteText = command.stringValueOfParameterNamed("note");
if (StringUtils.isNotBlank(noteText)) {
@@ -1668,7 +1669,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
}
if (!changes.isEmpty()) {
this.loanRepositoryWrapper.save(loan);
this.loanRepositoryWrapper.saveAndFlush(loan);
final String noteText = command.stringValueOfParameterNamed("note");
if (StringUtils.isNotBlank(noteText)) {
@@ -1737,12 +1738,6 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
private void saveAndFlushLoanWithDataIntegrityViolationChecks(final Loan loan) {
try {
List<LoanRepaymentScheduleInstallment> installments = loan.getRepaymentScheduleInstallments();
for (LoanRepaymentScheduleInstallment installment : installments) {
if (installment.getId() == null) {
this.repaymentScheduleInstallmentRepository.save(installment);
}
}
this.loanRepositoryWrapper.saveAndFlush(loan);
} catch (final JpaSystemException | DataIntegrityViolationException e) {
final Throwable realCause = e.getCause();
@@ -667,13 +667,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
private void saveAndFlushLoanWithDataIntegrityViolationChecks(final Loan loan) {
try {
List<LoanRepaymentScheduleInstallment> installments = loan.getRepaymentScheduleInstallments();
for (LoanRepaymentScheduleInstallment installment : installments) {
// installment.setPostDatedChecksToNull();
if (installment.getId() == null) {
this.repaymentScheduleInstallmentRepository.save(installment);
}
}
this.loanRepositoryWrapper.saveAndFlush(loan);
} catch (final JpaSystemException | DataIntegrityViolationException e) {
final Throwable realCause = e.getCause();
@@ -691,12 +684,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
private void saveLoanWithDataIntegrityViolationChecks(final Loan loan) {
try {
List<LoanRepaymentScheduleInstallment> installments = loan.getRepaymentScheduleInstallments();
for (LoanRepaymentScheduleInstallment installment : installments) {
if (installment.getId() == null) {
this.repaymentScheduleInstallmentRepository.save(installment);
}
}
this.loanRepositoryWrapper.save(loan);
} catch (final JpaSystemException | DataIntegrityViolationException e) {
final Throwable realCause = e.getCause();
@@ -1145,7 +1132,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
if (paymentDetail != null) {
this.paymentDetailWritePlatformService.persistPaymentDetail(paymentDetail);
}
this.loanTransactionRepository.save(newTransactionDetail);
this.loanTransactionRepository.saveAndFlush(newTransactionDetail);
}
/***
@@ -1252,7 +1239,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
defaultLoanLifecycleStateMachine(), existingTransactionIds, existingReversedTransactionIds, scheduleGeneratorDTO,
currentUser);
this.loanTransactionRepository.save(waiveInterestTransaction);
this.loanTransactionRepository.saveAndFlush(waiveInterestTransaction);
/***
* TODO Vishwas Batch save is giving me a HibernateOptimisticLockingFailureException, looping and saving for the
@@ -1328,7 +1315,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final ChangedTransactionDetail changedTransactionDetail = loan.closeAsWrittenOff(command, defaultLoanLifecycleStateMachine(),
changes, existingTransactionIds, existingReversedTransactionIds, currentUser, scheduleGeneratorDTO);
LoanTransaction writeoff = changedTransactionDetail.getNewTransactionMappings().remove(0L);
this.loanTransactionRepository.save(writeoff);
this.loanTransactionRepository.saveAndFlush(writeoff);
for (final Map.Entry<Long, LoanTransaction> mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) {
this.loanTransactionRepository.save(mapEntry.getValue());
this.accountTransfersWritePlatformService.updateLoanTransaction(mapEntry.getKey(), mapEntry.getValue());
@@ -1383,7 +1370,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
existingTransactionIds, existingReversedTransactionIds, scheduleGeneratorDTO, currentUser);
final LoanTransaction possibleClosingTransaction = changedTransactionDetail.getNewTransactionMappings().remove(0L);
if (possibleClosingTransaction != null) {
this.loanTransactionRepository.save(possibleClosingTransaction);
this.loanTransactionRepository.saveAndFlush(possibleClosingTransaction);
}
for (final Map.Entry<Long, LoanTransaction> mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) {
this.loanTransactionRepository.save(mapEntry.getValue());
@@ -1682,7 +1669,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
loan.addLoanCharge(loanCharge);
this.loanChargeRepository.save(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
@@ -1690,7 +1677,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
**/
if (loan.status().isActive() && loan.isNoneOrCashOrUpfrontAccrualAccountingEnabledOnLoanProduct()) {
final LoanTransaction applyLoanChargeTransaction = loan.handleChargeAppliedTransaction(loanCharge, null, currentUser);
this.loanTransactionRepository.save(applyLoanChargeTransaction);
this.loanTransactionRepository.saveAndFlush(applyLoanChargeTransaction);
}
boolean isAppliedOnBackDate = false;
if (loanCharge.getDueLocalDate() == null || DateUtils.getLocalDateOfTenant().isAfter(loanCharge.getDueLocalDate())) {
@@ -1952,7 +1939,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
existingTransactionIds, existingReversedTransactionIds, loanInstallmentNumber, scheduleGeneratorDTO, accruedCharge,
currentUser);
this.loanTransactionRepository.save(waiveTransaction);
this.loanTransactionRepository.saveAndFlush(waiveTransaction);
saveLoanWithDataIntegrityViolationChecks(loan);
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
@@ -2214,7 +2201,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
loan.addLoanTransaction(newTransferTransaction);
loan.setLoanStatus(LoanStatus.TRANSFER_IN_PROGRESS.getValue());
this.loanTransactionRepository.save(newTransferTransaction);
this.loanTransactionRepository.saveAndFlush(newTransferTransaction);
saveLoanWithDataIntegrityViolationChecks(loan);
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
@@ -2246,7 +2233,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
loan.reassignLoanOfficer(loanOfficer, transferDate);
}
this.loanTransactionRepository.save(newTransferAcceptanceTransaction);
this.loanTransactionRepository.saveAndFlush(newTransferAcceptanceTransaction);
saveLoanWithDataIntegrityViolationChecks(loan);
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
@@ -2272,7 +2259,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
loan.addLoanTransaction(newTransferAcceptanceTransaction);
loan.setLoanStatus(LoanStatus.ACTIVE.getValue());
this.loanTransactionRepository.save(newTransferAcceptanceTransaction);
this.loanTransactionRepository.saveAndFlush(newTransferAcceptanceTransaction);
saveLoanWithDataIntegrityViolationChecks(loan);
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
@@ -185,9 +185,6 @@ public class LoanProduct extends AbstractPersistableCustom {
@Column(name = "can_use_for_topup", nullable = false)
private boolean canUseForTopup = false;
@Column(name = "is_equal_amortization", nullable = false)
private boolean isEqualAmortization = false;
@Column(name = "fixed_principal_percentage_per_installment", scale = 2, precision = 5, nullable = true)
private BigDecimal fixedPrincipalPercentagePerInstallment;
@@ -690,7 +687,6 @@ public class LoanProduct extends AbstractPersistableCustom {
this.installmentAmountInMultiplesOf = installmentAmountInMultiplesOf;
this.syncExpectedWithDisbursementDate = syncExpectedWithDisbursementDate;
this.canUseForTopup = canUseForTopup;
this.isEqualAmortization = isEqualAmortization;
this.fixedPrincipalPercentagePerInstallment = fixedPrincipalPercentagePerInstallment;
if (rates != null) {
@@ -1455,11 +1451,7 @@ public class LoanProduct extends AbstractPersistableCustom {
}
public boolean isEqualAmortization() {
return isEqualAmortization;
}
public void setEqualAmortization(boolean isEqualAmortization) {
this.isEqualAmortization = isEqualAmortization;
return loanProductRelatedDetail.isEqualAmortization();
}
public List<Rate> getRates() {
@@ -141,7 +141,7 @@ public class LoanProductWritePlatformServiceJpaRepositoryImpl implements LoanPro
this.aprCalculator, floatingRate, rates);
loanproduct.updateLoanProductInRelatedClasses();
this.loanProductRepository.save(loanproduct);
this.loanProductRepository.saveAndFlush(loanproduct);
// save accounting mappings
this.accountMappingWritePlatformService.createLoanProductToGLAccountMapping(loanproduct.getId(), command);
@@ -130,7 +130,7 @@ public class MeetingWritePlatformServiceJpaRepositoryImpl implements MeetingWrit
newMeeting.associateClientsAttendance(clientsAttendance);
}
// save meeting details
this.meetingRepositoryWrapper.save(newMeeting);
this.meetingRepositoryWrapper.saveAndFlush(newMeeting);
final Long groupId = newMeeting.isGroupEntity() ? newMeeting.entityId() : null;
return new CommandProcessingResultBuilder() //
.withEntityId(newMeeting.getId()) //
@@ -78,7 +78,7 @@ public class NoteWritePlatformServiceJpaRepositoryImpl implements NoteWritePlatf
}
final Note newNote = Note.clientNoteFromJson(client, command);
this.noteRepository.save(newNote);
this.noteRepository.saveAndFlush(newNote);
return new CommandProcessingResultBuilder() //
.withCommandId(command.commandId()) //
@@ -105,7 +105,7 @@ public class NoteWritePlatformServiceJpaRepositoryImpl implements NoteWritePlatf
final Group group = this.groupRepository.findById(resourceId).orElseThrow(() -> new GroupNotFoundException(resourceId));
final Note newNote = Note.groupNoteFromJson(group, command);
this.noteRepository.save(newNote);
this.noteRepository.saveAndFlush(newNote);
return new CommandProcessingResultBuilder() //
.withCommandId(command.commandId()) //
@@ -123,7 +123,7 @@ public class NoteWritePlatformServiceJpaRepositoryImpl implements NoteWritePlatf
final String note = command.stringValueOfParameterNamed("note");
final Note newNote = Note.loanNote(loan, note);
this.noteRepository.save(newNote);
this.noteRepository.saveAndFlush(newNote);
return new CommandProcessingResultBuilder() //
.withCommandId(command.commandId()) //
@@ -145,7 +145,7 @@ public class NoteWritePlatformServiceJpaRepositoryImpl implements NoteWritePlatf
final String note = command.stringValueOfParameterNamed("note");
final Note newNote = Note.loanTransactionNote(loan, loanTransaction, note);
this.noteRepository.save(newNote);
this.noteRepository.saveAndFlush(newNote);
return new CommandProcessingResultBuilder() //
.withCommandId(command.commandId()) //
@@ -58,7 +58,7 @@ public class PaymentTypeWriteServiceImpl implements PaymentTypeWriteService {
Long position = command.longValueOfParameterNamed(PaymentTypeApiResourceConstants.POSITION);
PaymentType newPaymentType = PaymentType.create(name, description, isCashPayment, position);
this.repository.save(newPaymentType);
this.repository.saveAndFlush(newPaymentType);
return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(newPaymentType.getId()).build();
}
@@ -78,7 +78,7 @@ public class RateWriteServiceImpl implements RateWriteService {
}
final Rate rate = Rate.fromJson(command, approveUser);
this.rateRepository.save(rate);
this.rateRepository.saveAndFlush(rate);
return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(rate.getId()).build();

Some files were not shown because too many files have changed in this diff Show More